1/*	$OpenBSD: radiusd_ipcp.c,v 1.12 2024/08/16 09:54:21 yasuoka Exp $	*/
2
3/*
4 * Copyright (c) 2024 Internet Initiative Japan Inc.
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/queue.h>
21#include <sys/socket.h>
22#include <sys/time.h>
23#include <sys/tree.h>
24#include <arpa/inet.h>
25
26#include <inttypes.h>
27#include <netdb.h>
28#include <db.h>
29#include <err.h>
30#include <errno.h>
31#include <event.h>
32#include <fcntl.h>
33#include <pwd.h>
34#include <radius.h>
35#include <stdbool.h>
36#include <stddef.h>
37#include <stdint.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <time.h>
42#include <unistd.h>
43#include <imsg.h>
44
45#include "radiusd.h"
46#include "radiusd_module.h"
47#include "radiusd_ipcp.h"
48#include "log.h"
49
50#define RADIUSD_IPCP_START_WAIT	60
51
52enum ipcp_address_type {
53	ADDRESS_TYPE_POOL,
54	ADDRESS_TYPE_STATIC
55};
56
57struct ipcp_address {
58	enum ipcp_address_type		 type;
59	struct in_addr			 start;
60	struct in_addr			 end;
61	int				 naddrs;
62	TAILQ_ENTRY(ipcp_address)	 next;
63};
64
65struct user {
66	TAILQ_HEAD(, assigned_ipv4)	 ipv4s;
67	RB_ENTRY(user)			 tree;
68	char				 name[0];
69};
70
71struct radiusctl_client {
72	int				 peerid;
73	TAILQ_ENTRY(radiusctl_client)	 entry;
74};
75
76struct module_ipcp_dae;
77
78struct assigned_ipv4 {
79	struct in_addr			 ipv4;
80	unsigned			 seq;
81	char				 session_id[256];
82	char				 auth_method[16];
83	struct user			*user;
84	uint32_t			 session_timeout;
85	struct timespec			 start;
86	struct timespec			 timeout;
87	struct in_addr			 nas_ipv4;
88	struct in6_addr			 nas_ipv6;
89	char				 nas_id[256];
90	const char			*tun_type;
91	union {
92		struct sockaddr_in	 sin4;
93		struct sockaddr_in6	 sin6;
94	}				 tun_client;
95
96	struct timespec			 authtime;
97	RB_ENTRY(assigned_ipv4)		 tree;
98	TAILQ_ENTRY(assigned_ipv4)	 next;
99
100	/* RFC 5176 Dynamic Authorization Extensions for RADIUS */
101	struct module_ipcp_dae		*dae;
102	RADIUS_PACKET			*dae_reqpkt;
103	TAILQ_ENTRY(assigned_ipv4)	 dae_next;
104	int				 dae_ntry;
105	struct event			 dae_evtimer;
106	TAILQ_HEAD(, radiusctl_client)	 dae_clients;
107};
108
109struct module_ipcp_ctrlconn {
110	uint32_t			 peerid;
111	TAILQ_ENTRY(module_ipcp_ctrlconn)
112					 next;
113};
114
115struct module_ipcp_dae {
116	struct module_ipcp		*ipcp;
117	int				 sock;
118	char				 nas_id[256];
119	char				 secret[80];
120	union {
121		struct sockaddr_in	 sin4;
122		struct sockaddr_in6	 sin6;
123	}				 nas_addr;
124	struct event			 ev_sock;
125	TAILQ_ENTRY(module_ipcp_dae)	 next;
126	TAILQ_HEAD(, assigned_ipv4)	 reqs;
127};
128
129struct module_ipcp {
130	struct module_base		*base;
131	int				 nsessions;
132	unsigned			 seq;
133	int				 max_sessions;
134	int				 user_max_sessions;
135	int				 start_wait;
136	int				 session_timeout;
137	bool				 no_session_timeout;
138	struct timespec			 uptime;
139	struct in_addr			 name_server[2];
140	struct in_addr			 netbios_server[2];
141	RB_HEAD(assigned_ipv4_tree, assigned_ipv4)
142					 ipv4s;
143	RB_HEAD(user_tree, user)	 users;
144	int				 npools;
145	TAILQ_HEAD(,ipcp_address)	 addrs;
146	TAILQ_HEAD(,module_ipcp_ctrlconn)
147					 ctrls;
148	TAILQ_HEAD(,module_ipcp_dae)	 daes;
149	struct event			 ev_timer;
150};
151
152#ifndef nitems
153#define nitems(_x)    (sizeof((_x)) / sizeof((_x)[0]))
154#endif
155
156#ifndef MAXIMUM
157#define MAXIMUM(_a, _b)	(((_a) > (_b))? (_a) : (_b))
158#endif
159
160static void	 ipcp_init(struct module_ipcp *);
161static void	 ipcp_start(void *);
162static void	 ipcp_stop(void *);
163static void	 ipcp_fini(struct module_ipcp *);
164static void	 ipcp_config_set(void *, const char *, int, char * const *);
165static void	 ipcp_dispatch_control(void *, struct imsg *);
166static int	 ipcp_notice_startstop(struct module_ipcp *,
167		    struct assigned_ipv4 *, int,
168		    struct radiusd_ipcp_statistics *);
169static void	 ipcp_resdeco(void *, u_int, const u_char *, size_t reqlen,
170		    const u_char *, size_t reslen);
171static void	 ipcp_reject(struct module_ipcp *, RADIUS_PACKET *,
172		    unsigned int, RADIUS_PACKET *, int);
173static void	 ipcp_accounting_request(void *, u_int, const u_char *,
174		    size_t);
175
176struct assigned_ipv4
177		*ipcp_ipv4_assign(struct module_ipcp *, struct user *,
178		    struct in_addr);
179static struct assigned_ipv4
180		*ipcp_ipv4_find(struct module_ipcp *, struct in_addr);
181static void	 ipcp_ipv4_release(struct module_ipcp *,
182		    struct assigned_ipv4 *);
183static int	 assigned_ipv4_compar(struct assigned_ipv4 *,
184		    struct assigned_ipv4 *);
185static struct user
186		*ipcp_user_get(struct module_ipcp *, const char *);
187static int	 user_compar(struct user *, struct user *);
188static int	 ipcp_prepare_db(void);
189static int	 ipcp_restore_from_db(struct module_ipcp *);
190static void	 ipcp_put_db(struct module_ipcp *, struct assigned_ipv4 *);
191static void	 ipcp_del_db(struct module_ipcp *, struct assigned_ipv4 *);
192static void	 ipcp_db_dump_fill_record(struct radiusd_ipcp_db_dump *, int,
193		    struct assigned_ipv4 *);
194static void	 ipcp_update_time(struct module_ipcp *);
195static void	 ipcp_on_timer(int, short, void *);
196static void	 ipcp_schedule_timer(struct module_ipcp *);
197static void	 ipcp_dae_send_disconnect_request(struct assigned_ipv4 *);
198static void	 ipcp_dae_request_on_timeout(int, short, void *);
199static void	 ipcp_dae_on_event(int, short, void *);
200static void	 ipcp_dae_reset_request(struct assigned_ipv4 *);
201static struct ipcp_address
202		*parse_address_range(const char *);
203static const char
204		*radius_tunnel_type_string(unsigned, const char *);
205static const char
206		*radius_terminate_cause_string(unsigned);
207static const char
208		*radius_error_cause_string(unsigned);
209static int	 parse_addr(const char *, int, struct sockaddr *, socklen_t);
210static const char
211		*print_addr(struct sockaddr *, char *, size_t);
212
213RB_PROTOTYPE_STATIC(assigned_ipv4_tree, assigned_ipv4, tree,
214    assigned_ipv4_compar);
215RB_PROTOTYPE_STATIC(user_tree, user, tree, user_compar);
216
217int
218main(int argc, char *argv[])
219{
220	struct module_ipcp	 module_ipcp;
221	struct module_handlers	 handlers = {
222		.start =		ipcp_start,
223		.stop =			ipcp_stop,
224		.config_set =		ipcp_config_set,
225		.response_decoration =	ipcp_resdeco,
226		.accounting_request =	ipcp_accounting_request,
227		.dispatch_control =	ipcp_dispatch_control
228	};
229
230	ipcp_init(&module_ipcp);
231
232	if ((module_ipcp.base = module_create(STDIN_FILENO, &module_ipcp,
233	    &handlers)) == NULL)
234		err(1, "Could not create a module instance");
235
236	if (ipcp_prepare_db() == -1)
237		err(1, "ipcp_prepare_db");
238
239	module_drop_privilege(module_ipcp.base, 1);
240	if (unveil(_PATH_RADIUSD_IPCP_DB, "rw") == -1)
241		err(1, "unveil");
242	if (pledge("stdio inet rpath wpath flock", NULL) == -1)
243		err(1, "pledge");
244	setproctitle("[main]");
245
246	module_load(module_ipcp.base);
247	log_init(0);
248	event_init();
249
250	module_start(module_ipcp.base);
251	event_loop(0);
252
253	ipcp_fini(&module_ipcp);
254
255	event_loop(0);
256	event_base_free(NULL);
257
258	exit(EXIT_SUCCESS);
259}
260
261void
262ipcp_init(struct module_ipcp *self)
263{
264	memset(self, 0, sizeof(struct module_ipcp));
265	TAILQ_INIT(&self->addrs);
266	RB_INIT(&self->ipv4s);
267	RB_INIT(&self->users);
268	TAILQ_INIT(&self->ctrls);
269	TAILQ_INIT(&self->daes);
270	self->seq = 1;
271	self->no_session_timeout = true;
272	ipcp_update_time(self);
273}
274
275void
276ipcp_start(void *ctx)
277{
278	struct module_ipcp	*self = ctx;
279	struct ipcp_address	*addr;
280	struct module_ipcp_dae	*dae;
281	int			 sock;
282
283	ipcp_update_time(self);
284	if (self->start_wait == 0)
285		self->start_wait = RADIUSD_IPCP_START_WAIT;
286
287	/* count pool address*/
288	TAILQ_FOREACH(addr, &self->addrs, next) {
289		if (addr->type == ADDRESS_TYPE_POOL)
290			self->npools += addr->naddrs;
291	}
292	log_info("number of pooled IP addresses = %d", self->npools);
293
294	if (ipcp_restore_from_db(self) == -1) {
295		module_send_message(self->base, IMSG_NG,
296		    "Restoring the database failed: %s", strerror(errno));
297		module_stop(self->base);
298		return;
299	}
300	ipcp_schedule_timer(self);
301
302	/* prepare socket for DAE */
303	TAILQ_FOREACH(dae, &self->daes, next) {
304		if ((sock = socket(dae->nas_addr.sin4.sin_family,
305		    SOCK_DGRAM, IPPROTO_UDP)) == -1) {
306			log_warn("could not start dae: %s", strerror(errno));
307			return;
308		}
309		if (connect(sock, (struct sockaddr *)&dae->nas_addr,
310		    dae->nas_addr.sin4.sin_len) == -1) {
311			log_warn("could not start dae: %s", strerror(errno));
312			return;
313		}
314		dae->sock = sock;
315		event_set(&dae->ev_sock, sock, EV_READ | EV_PERSIST,
316		    ipcp_dae_on_event, dae);
317		event_add(&dae->ev_sock, NULL);
318	}
319
320	module_send_message(self->base, IMSG_OK, NULL);
321}
322
323void
324ipcp_stop(void *ctx)
325{
326	struct module_ipcp		*self = ctx;
327	struct module_ipcp_dae		*dae;
328
329	ipcp_update_time(self);
330	/* stop the sockets for DAE */
331	TAILQ_FOREACH(dae, &self->daes, next) {
332		if (dae->sock >= 0) {
333			event_del(&dae->ev_sock);
334			close(dae->sock);
335			dae->sock = -1;
336		}
337	}
338	if (evtimer_pending(&self->ev_timer, NULL))
339		evtimer_del(&self->ev_timer);
340}
341
342void
343ipcp_fini(struct module_ipcp *self)
344{
345	struct assigned_ipv4		*assign, *assignt;
346	struct user			*user, *usert;
347	struct module_ipcp_ctrlconn	*ctrl, *ctrlt;
348	struct module_ipcp_dae		*dae, *daet;
349	struct ipcp_address		*addr, *addrt;
350
351	RB_FOREACH_SAFE(assign, assigned_ipv4_tree, &self->ipv4s, assignt)
352		ipcp_ipv4_release(self, assign);
353	RB_FOREACH_SAFE(user, user_tree, &self->users, usert) {
354		RB_REMOVE(user_tree, &self->users, user);
355		free(user);
356	}
357	TAILQ_FOREACH_SAFE(ctrl, &self->ctrls, next, ctrlt)
358		free(ctrl);
359	TAILQ_FOREACH_SAFE(dae, &self->daes, next, daet) {
360		if (dae->sock >= 0) {
361			event_del(&dae->ev_sock);
362			close(dae->sock);
363		}
364		free(dae);
365	}
366	TAILQ_FOREACH_SAFE(addr, &self->addrs, next, addrt)
367		free(addr);
368	if (evtimer_pending(&self->ev_timer, NULL))
369		evtimer_del(&self->ev_timer);
370	module_destroy(self->base);
371}
372
373void
374ipcp_config_set(void *ctx, const char *name, int argc, char * const * argv)
375{
376	struct module_ipcp	*module = ctx;
377	const char		*errmsg = "none";
378	int			 i;
379	struct ipcp_address	*addr;
380	struct in_addr		 ina;
381	struct module_ipcp_dae	 dae, *dae0;
382
383	if (strcmp(name, "address") == 0) {
384		SYNTAX_ASSERT(argc >= 1,
385		    "specify one of pool, server, nas-select, or user-select");
386		if (strcmp(argv[0], "pool") == 0) {
387			SYNTAX_ASSERT(argc >= 2,
388			    "`address pool' must have one address range at "
389			    "least");
390			addr = TAILQ_FIRST(&module->addrs);
391			for (i = 0; i < argc - 1; i++) {
392				if ((addr = parse_address_range(argv[i + 1]))
393				    == NULL) {
394					module_send_message(module->base,
395					    IMSG_NG, "Invalid address range: "
396					    "%s", argv[i + 1]);
397					return;
398				}
399				addr->type = ADDRESS_TYPE_POOL;
400				TAILQ_INSERT_TAIL(&module->addrs, addr, next);
401			}
402		} else if (strcmp(argv[0], "static") == 0) {
403			SYNTAX_ASSERT(argc >= 2,
404			    "`address static' must have one address range at "
405			    "least");
406			addr = TAILQ_FIRST(&module->addrs);
407			for (i = 0; i < argc - 1; i++) {
408				if ((addr = parse_address_range(argv[i + 1]))
409				    == NULL) {
410					module_send_message(module->base,
411					    IMSG_NG, "Invalid address range: "
412					    "%s", argv[i + 1]);
413					return;
414				}
415				addr->type = ADDRESS_TYPE_STATIC;
416				TAILQ_INSERT_TAIL(&module->addrs, addr, next);
417			}
418		} else
419			SYNTAX_ASSERT(0, "specify pool or static");
420	} else if (strcmp(name, "max-sessions") == 0) {
421		SYNTAX_ASSERT(argc == 1,
422		    "`max-sessions' must have an argument");
423		module->max_sessions = strtonum(argv[0], 0, INT_MAX, &errmsg);
424		if (errmsg != NULL) {
425			module_send_message(module->base, IMSG_NG,
426			    "could not parse `max-sessions': %s", errmsg);
427			return;
428		}
429	} else if (strcmp(name, "user-max-sessions") == 0) {
430		SYNTAX_ASSERT(argc == 1, "`max-session' must have an argument");
431		module->user_max_sessions = strtonum(argv[0], 0, INT_MAX,
432		    &errmsg);
433		if (errmsg != NULL) {
434			module_send_message(module->base, IMSG_NG,
435			    "could not parse `user-max-session': %s", errmsg);
436			return;
437		}
438	} else if (strcmp(name, "start-wait") == 0) {
439		SYNTAX_ASSERT(argc == 1, "`start-wait' must have an argument");
440		module->start_wait = strtonum(argv[0], 1, INT_MAX, &errmsg);
441		if (errmsg != NULL) {
442			module_send_message(module->base, IMSG_NG,
443			    "could not parse `start-wait': %s", errmsg);
444			return;
445		}
446	} else if (strcmp(name, "name-server") == 0) {
447		SYNTAX_ASSERT(argc == 1 || argc == 2,
448		    "specify 1 or 2 addresses for `name-server'");
449		for (i = 0; i < argc; i++) {
450			if (inet_aton(argv[i], &ina) != 1) {
451				module_send_message(module->base, IMSG_NG,
452				    "Invalid IP address: %s", argv[i]);
453				return;
454			}
455			if (module->name_server[0].s_addr == 0)
456				module->name_server[0] = ina;
457			else if (module->name_server[1].s_addr == 0)
458				module->name_server[1] = ina;
459			else
460				SYNTAX_ASSERT(0,
461				    "too many `name-server' is configured");
462		}
463	} else if (strcmp(name, "netbios-server") == 0) {
464		SYNTAX_ASSERT(argc == 1 || argc == 2,
465		    "specify 1 or 2 addresses for `name-server'");
466		for (i = 0; i < argc; i++) {
467			if (inet_aton(argv[i], &ina) != 1) {
468				module_send_message(module->base, IMSG_NG,
469				    "Invalid IP address: %s", argv[i]);
470				return;
471			}
472			if (module->netbios_server[0].s_addr == 0)
473				module->netbios_server[0] = ina;
474			else if (module->netbios_server[1].s_addr == 0)
475				module->netbios_server[1] = ina;
476			else
477				SYNTAX_ASSERT(0,
478				    "too many `name-server' is configured");
479		}
480	} else if (strcmp(name, "session-timeout") == 0) {
481		SYNTAX_ASSERT(argc == 1,
482		    "`session-timeout' must have an argument");
483		if (strcmp(argv[0], "radius") == 0) {
484			module->no_session_timeout = false;
485			module->session_timeout = 0;
486		} else {
487			module->no_session_timeout = false;
488			module->session_timeout = strtonum(argv[0], 1, INT_MAX,
489			    &errmsg);
490			if (errmsg != NULL) {
491				module_send_message(module->base, IMSG_NG,
492				    "could not parse `session-timeout': %s",
493				    errmsg);
494				return;
495			}
496		}
497	} else if (strcmp(name, "dae") == 0) {
498		memset(&dae, 0, sizeof(dae));
499		dae.sock = -1;
500		if (!(argc >= 1 || strcmp(argv[1], "server") == 0)) {
501			module_send_message(module->base, IMSG_NG,
502			    "`%s' is unknown", argv[1]);
503			return;
504		}
505		i = 1;
506		SYNTAX_ASSERT(i < argc, "no address[:port] for dae server");
507		if (i < argc &&
508		    parse_addr(argv[i], AF_UNSPEC, (struct sockaddr *)
509		    &dae.nas_addr, sizeof(dae.nas_addr)) == -1) {
510			module_send_message(module->base, IMSG_NG,
511			    "failed to parse dae server's address, %s",
512			    argv[i]);
513			return;
514		}
515		if (ntohs(dae.nas_addr.sin4.sin_port) == 0)
516			dae.nas_addr.sin4.sin_port =
517			    htons(RADIUS_DAE_DEFAULT_PORT);
518		i++;
519		SYNTAX_ASSERT(i < argc, "no secret for dae server");
520		if (strlcpy(dae.secret, argv[i++], sizeof(dae.secret)) >=
521		    sizeof(dae.secret)) {
522			module_send_message(module->base, IMSG_NG,
523			    "dae server's secret must be < %d bytes",
524			    (int)sizeof(dae.secret) - 1);
525			return;
526		}
527		if (i < argc)
528			strlcpy(dae.nas_id, argv[i++], sizeof(dae.nas_id));
529		if ((dae0 = calloc(1, sizeof(struct module_ipcp_dae))) == NULL)
530		{
531			module_send_message(module->base, IMSG_NG,
532			    "%s", strerror(errno));
533			return;
534		}
535		*dae0 = dae;
536		TAILQ_INIT(&dae0->reqs);
537		TAILQ_INSERT_TAIL(&module->daes, dae0, next);
538		dae0->ipcp = module;
539	} else if (strcmp(name, "_debug") == 0)
540		log_init(1);
541	else if (strncmp(name, "_", 1) == 0)
542		/* ignore */;
543	else {
544		module_send_message(module->base, IMSG_NG,
545		    "Unknown config parameter name `%s'", name);
546		return;
547	}
548	module_send_message(module->base, IMSG_OK, NULL);
549
550	return;
551 syntax_error:
552	module_send_message(module->base, IMSG_NG, "%s", errmsg);
553}
554
555void
556ipcp_dispatch_control(void *ctx, struct imsg *imsg)
557{
558	struct module_ipcp		*self = ctx;
559	struct assigned_ipv4		*assign;
560	struct radiusd_ipcp_db_dump	*dump;
561	struct module_ipcp_ctrlconn	*ctrl, *ctrlt;
562	int				 i;
563	size_t				 dumpsiz;
564	u_int				 datalen;
565	unsigned			 seq;
566	struct radiusctl_client		*client;
567	const char			*cause;
568
569	ipcp_update_time(self);
570	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
571	switch (imsg->hdr.type) {
572	case IMSG_RADIUSD_MODULE_CTRL_UNBIND:
573		TAILQ_FOREACH_SAFE(ctrl, &self->ctrls, next, ctrlt) {
574			if (ctrl->peerid == imsg->hdr.peerid) {
575				TAILQ_REMOVE(&self->ctrls, ctrl, next);
576				free(ctrl);
577				break;
578			}
579		}
580		break;
581	case IMSG_RADIUSD_MODULE_IPCP_MONITOR:
582	case IMSG_RADIUSD_MODULE_IPCP_DUMP_AND_MONITOR:
583		if ((ctrl = calloc(1, sizeof(struct module_ipcp_ctrlconn)))
584		    == NULL) {
585			log_warn("%s: calloc()", __func__);
586			goto fail;
587		}
588		ctrl->peerid = imsg->hdr.peerid;
589		TAILQ_INSERT_TAIL(&self->ctrls, ctrl, next);
590		module_imsg_compose(self->base, IMSG_RADIUSD_MODULE_CTRL_BIND,
591		    imsg->hdr.peerid, 0, -1, NULL, 0);
592		if (imsg->hdr.type == IMSG_RADIUSD_MODULE_IPCP_MONITOR)
593			break;
594		/* FALLTROUGH */
595	case IMSG_RADIUSD_MODULE_IPCP_DUMP:
596		dumpsiz = MAX_IMSGSIZE;
597		if ((dump = calloc(1, dumpsiz)) == NULL) {
598			log_warn("%s: calloc()", __func__);
599			goto fail;
600		}
601		i = 0;
602		RB_FOREACH(assign, assigned_ipv4_tree, &self->ipv4s) {
603			if (!timespecisset(&assign->start))
604				/* not started yet */
605				continue;
606			ipcp_db_dump_fill_record(dump, i++, assign);
607			if (RB_NEXT(assigned_ipv4_tree, &self->ipv4s, assign)
608			    == NULL)
609				break;
610			if (offsetof(struct radiusd_ipcp_db_dump,
611			    records[i + 1]) >= dumpsiz) {
612				module_imsg_compose(self->base,
613				    IMSG_RADIUSD_MODULE_IPCP_DUMP,
614				    imsg->hdr.peerid, 0, -1,
615				    dump, offsetof(struct radiusd_ipcp_db_dump,
616				    records[i]));
617				i = 0;
618			}
619		}
620		dump->islast = 1;
621		module_imsg_compose(self->base, IMSG_RADIUSD_MODULE_IPCP_DUMP,
622		    imsg->hdr.peerid, 0, -1, dump, offsetof(
623		    struct radiusd_ipcp_db_dump, records[i]));
624		freezero(dump ,dumpsiz);
625		break;
626	case IMSG_RADIUSD_MODULE_IPCP_DISCONNECT:
627		if (datalen < sizeof(unsigned)) {
628			log_warn("%s: received "
629			    "IMSG_RADIUSD_MODULE_IPCP_DISCONNECT message size "
630			    "is wrong", __func__);
631			goto fail;
632		}
633		seq = *(unsigned *)imsg->data;
634		RB_FOREACH(assign, assigned_ipv4_tree, &self->ipv4s) {
635			if (!timespecisset(&assign->start))
636				/* not started yet */
637				continue;
638			if (assign->seq == seq)
639				break;
640		}
641		if (assign == NULL) {
642			cause = "session not found";
643			log_warnx("Disconnect seq=%u requested, but the "
644			    "session is not found", seq);
645			module_imsg_compose(self->base, IMSG_NG,
646			    imsg->hdr.peerid, 0, -1, cause, strlen(cause) + 1);
647		}
648		else {
649			if (assign->dae == NULL)
650				log_warnx("Disconnect seq=%u requested, but "
651				    "DAE is not configured", assign->seq);
652			else {
653				log_info("Disconnect seq=%u requested",
654				    assign->seq);
655				if ((client = calloc(1, sizeof(struct
656				    radiusctl_client))) == NULL) {
657					log_warn("%s: calloc: %m",
658					    __func__);
659					goto fail;
660				}
661				client->peerid = imsg->hdr.peerid;
662				if (assign->dae_ntry == 0)
663					ipcp_dae_send_disconnect_request(
664					    assign);
665				TAILQ_INSERT_TAIL(&assign->dae_clients,
666				    client, entry);
667			}
668		}
669		break;
670	}
671	return;
672 fail:
673	module_stop(self->base);
674}
675
676int
677ipcp_notice_startstop(struct module_ipcp *self, struct assigned_ipv4 *assign,
678    int start, struct radiusd_ipcp_statistics *stat)
679{
680	struct module_ipcp_ctrlconn	*ctrl;
681	struct radiusd_ipcp_db_dump	*dump;
682	size_t				 dumpsiz;
683	struct iovec			 iov[2];
684	int				 niov = 0;
685
686	dumpsiz = offsetof(struct radiusd_ipcp_db_dump, records[1]);
687	if ((dump = calloc(1, dumpsiz)) == NULL) {
688		log_warn("%s: calloc()", __func__);
689		return (-1);
690	}
691	dump->islast = 1;
692	ipcp_db_dump_fill_record(dump, 0, assign);
693
694	iov[niov].iov_base = dump;
695	iov[niov].iov_len = dumpsiz;
696	if (start == 0) {
697		iov[++niov].iov_base = stat;
698		iov[niov].iov_len = sizeof(struct radiusd_ipcp_statistics);
699	}
700	TAILQ_FOREACH(ctrl, &self->ctrls, next)
701		module_imsg_composev(self->base,
702		    (start)? IMSG_RADIUSD_MODULE_IPCP_START :
703		    IMSG_RADIUSD_MODULE_IPCP_STOP, ctrl->peerid, 0, -1, iov,
704		    niov + 1);
705	freezero(dump, dumpsiz);
706	return (0);
707}
708
709void
710ipcp_resdeco(void *ctx, u_int q_id, const u_char *req, size_t reqlen,
711    const u_char *res, size_t reslen)
712{
713	struct module_ipcp	*self = ctx;
714	RADIUS_PACKET		*radres = NULL, *radreq = NULL;
715	struct in_addr		 addr4;
716	const struct in_addr	 mask4 = { .s_addr = 0xffffffffUL };
717	int			 res_code, msraserr = 935;
718	struct ipcp_address	*addr;
719	int			 i, j, n;
720	bool			 found = false;
721	char			 username[256], buf[128];
722	struct user		*user = NULL;
723	struct assigned_ipv4	*assigned = NULL, *assign;
724
725	ipcp_update_time(self);
726
727	if ((radres = radius_convert_packet(res, reslen)) == NULL) {
728		log_warn("%s: radius_convert_packet() failed", __func__);
729		goto fatal;
730	}
731	res_code = radius_get_code(radres);
732	if (res_code != RADIUS_CODE_ACCESS_ACCEPT)
733		goto accept;
734
735	if ((radreq = radius_convert_packet(req, reqlen)) == NULL) {
736		log_warn("%s: radius_convert_packet() failed", __func__);
737		goto fatal;
738	}
739
740	/*
741	 * prefer User-Name of the response rather than the request,
742	 * since it must be the authenticated user.
743	 */
744	if (radius_get_string_attr(radres, RADIUS_TYPE_USER_NAME, username,
745	    sizeof(username)) != 0 &&
746	    radius_get_string_attr(radreq, RADIUS_TYPE_USER_NAME, username,
747	    sizeof(username)) != 0) {
748		log_warnx("q=%u unexpected request: no user-name", q_id);
749		goto fatal;
750	}
751
752	if ((addr = TAILQ_FIRST(&self->addrs)) != NULL) {
753		/* The address assignment is configured */
754
755		if ((user = ipcp_user_get(self, username)) == NULL) {
756			log_warn("%s: ipcp_user_get()", __func__);
757			goto fatal;
758		}
759
760		msraserr = 935;
761		if (self->max_sessions != 0) {
762			if (self->nsessions >= self->max_sessions) {
763				log_info("q=%u rejected: number of "
764				    "sessions reached the limit(%d)", q_id,
765				    self->max_sessions);
766				goto reject;
767			}
768		}
769		if (self->user_max_sessions != 0) {
770			n = 0;
771			TAILQ_FOREACH(assign, &user->ipv4s, next)
772				n++;
773			if (n >= self->user_max_sessions) {
774				log_info("q=%u rejected: number of "
775				    "sessions per a user reached the limit(%d)",
776				    q_id, self->user_max_sessions);
777				goto reject;
778			}
779		}
780
781		msraserr = 716;
782		if (radius_get_ipv4_attr(radres,
783		    RADIUS_TYPE_FRAMED_IP_ADDRESS, &addr4) == 0) {
784			if (ipcp_ipv4_find(self, addr4) != NULL)
785				log_info("q=%u rejected: server requested IP "
786				    "address is busy", q_id);
787			else {
788				/* compare in host byte order */
789				addr4.s_addr = ntohl(addr4.s_addr);
790				TAILQ_FOREACH(addr, &self->addrs, next) {
791					if (addr->type != ADDRESS_TYPE_STATIC &&
792					    addr->type != ADDRESS_TYPE_POOL)
793						continue;
794					if (addr->start.s_addr <= addr4.s_addr
795					    && addr4.s_addr <= addr->end.s_addr)
796						break;
797				}
798				if (addr == NULL)
799					log_info("q=%u rejected: server "
800					    "requested IP address is out of "
801					    "the range", q_id);
802				else
803					found = true;
804				/* revert the addr to the network byte order */
805				addr4.s_addr = htonl(addr4.s_addr);
806			}
807			if (!found)
808				goto reject;
809		} else {
810			n = arc4random_uniform(self->npools);
811			i = 0;
812			TAILQ_FOREACH(addr, &self->addrs, next) {
813				if (addr->type == ADDRESS_TYPE_POOL) {
814					if (i <= n && n < i + addr->naddrs) {
815						j = n - i;
816						break;
817					}
818					i += addr->naddrs;
819				}
820			}
821			for (i = 0; i < self->npools; i++, j++) {
822				if (addr == NULL)
823					break;
824				if (j >= addr->naddrs) { /* next pool */
825					if ((addr = TAILQ_NEXT(addr, next))
826					    == NULL)
827						addr = TAILQ_FIRST(
828						    &self->addrs);
829					j = 0;
830				}
831				addr4.s_addr = htonl(addr->start.s_addr + j);
832				if (ipcp_ipv4_find(self, addr4) == NULL) {
833					found = true;
834					break;
835				}
836			}
837			if (!found) {
838				log_info("q=%u rejected: ran out of the "
839				    "address pool", q_id);
840				goto reject;
841			}
842		}
843		if ((assigned = ipcp_ipv4_assign(self, user, addr4)) == NULL) {
844			log_warn("%s: ipcp_ipv4_assign()", __func__);
845			goto fatal;
846		}
847		radius_set_ipv4_attr(radres, RADIUS_TYPE_FRAMED_IP_NETMASK,
848		    mask4);
849		radius_del_attr_all(radres, RADIUS_TYPE_FRAMED_IP_ADDRESS);
850		radius_put_ipv4_attr(radres, RADIUS_TYPE_FRAMED_IP_ADDRESS,
851		    addr4);
852		log_info("q=%u Assign %s for %s", q_id,
853		    inet_ntop(AF_INET, &addr4, buf, sizeof(buf)), username);
854		if (radius_has_attr(radreq, RADIUS_TYPE_USER_PASSWORD))
855			strlcpy(assigned->auth_method, "PAP",
856			    sizeof(assigned->auth_method));
857		else if (radius_has_attr(radreq, RADIUS_TYPE_CHAP_PASSWORD))
858			strlcpy(assigned->auth_method, "CHAP",
859			    sizeof(assigned->auth_method));
860		else if (radius_has_vs_attr(radreq, RADIUS_VENDOR_MICROSOFT,
861		    RADIUS_VTYPE_MS_CHAP_RESPONSE))
862			strlcpy(assigned->auth_method, "MS-CHAP",
863			    sizeof(assigned->auth_method));
864		else if (radius_has_vs_attr(radreq, RADIUS_VENDOR_MICROSOFT,
865		    RADIUS_VTYPE_MS_CHAP2_RESPONSE))
866			strlcpy(assigned->auth_method, "MS-CHAP-V2",
867			    sizeof(assigned->auth_method));
868		else if (radius_has_attr(radreq, RADIUS_TYPE_EAP_MESSAGE))
869			strlcpy(assigned->auth_method, "EAP",
870			    sizeof(assigned->auth_method));
871	}
872
873	if (self->name_server[0].s_addr != 0) {
874		addr4.s_addr = htonl(self->name_server[0].s_addr);
875		radius_del_vs_attr_all(radres,
876		    RADIUS_VENDOR_MICROSOFT,
877		    RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER);
878		radius_put_vs_ipv4_attr(radres,
879		    RADIUS_VENDOR_MICROSOFT,
880		    RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER, self->name_server[0]);
881	}
882	if (self->name_server[1].s_addr != 0) {
883		addr4.s_addr = htonl(self->name_server[1].s_addr);
884		radius_del_vs_attr_all(radres,
885		    RADIUS_VENDOR_MICROSOFT,
886		    RADIUS_VTYPE_MS_SECONDARY_DNS_SERVER);
887		radius_put_vs_ipv4_attr(radres,
888		    RADIUS_VENDOR_MICROSOFT,
889		    RADIUS_VTYPE_MS_SECONDARY_DNS_SERVER, self->name_server[1]);
890	}
891	if (self->netbios_server[0].s_addr != 0) {
892		addr4.s_addr = htonl(self->netbios_server[0].s_addr);
893		radius_del_vs_attr_all(radres,
894		    RADIUS_VENDOR_MICROSOFT,
895		    RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER);
896		radius_put_vs_ipv4_attr(radres,
897		    RADIUS_VENDOR_MICROSOFT,
898		    RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER,
899		    self->netbios_server[0]);
900	}
901	if (self->netbios_server[1].s_addr != 0) {
902		addr4.s_addr = htonl(self->netbios_server[1].s_addr);
903		radius_del_vs_attr_all(radres,
904		    RADIUS_VENDOR_MICROSOFT,
905		    RADIUS_VTYPE_MS_SECONDARY_NBNS_SERVER);
906		radius_put_vs_ipv4_attr(radres,
907		    RADIUS_VENDOR_MICROSOFT,
908		    RADIUS_VTYPE_MS_SECONDARY_NBNS_SERVER,
909		    self->netbios_server[1]);
910	}
911	if (!self->no_session_timeout &&
912	    radius_has_attr(radres, RADIUS_TYPE_SESSION_TIMEOUT)) {
913		radius_get_uint32_attr(radres, RADIUS_TYPE_SESSION_TIMEOUT,
914		    &assigned->session_timeout);
915		/* we handle this session-timeout */
916		radius_del_attr_all(radres, RADIUS_TYPE_SESSION_TIMEOUT);
917	}
918
919 accept:
920	if (module_resdeco_done(self->base, q_id, radius_get_data(radres),
921	    radius_get_length(radres)) == -1) {
922		log_warn("%s: module_resdeco_done() failed", __func__);
923		module_stop(self->base);
924	}
925	if (radreq != NULL)
926		radius_delete_packet(radreq);
927	radius_delete_packet(radres);
928	return;
929 reject:
930	ipcp_reject(self, radreq, q_id, radres, msraserr);
931	radius_delete_packet(radreq);
932	radius_delete_packet(radres);
933	return;
934 fatal:
935	if (radreq != NULL)
936		radius_delete_packet(radreq);
937	if (radres != NULL)
938		radius_delete_packet(radres);
939	module_stop(self->base);
940}
941
942void
943ipcp_reject(struct module_ipcp *self, RADIUS_PACKET *reqp, unsigned int q_id,
944    RADIUS_PACKET *orig_resp, int mserr)
945{
946	bool			 is_eap, is_mschap, is_mschap2;
947	uint8_t			 attr[256];
948	size_t			 attrlen;
949	RADIUS_PACKET		*resp;
950	struct {
951		uint8_t		 code;
952		uint8_t		 id;
953		uint16_t	 length;
954	} __packed		 eap;
955
956	resp = radius_new_response_packet(RADIUS_CODE_ACCESS_REJECT, reqp);
957	if (resp == NULL) {
958		log_warn("%s: radius_new_response_packet() failed", __func__);
959		module_accsreq_aborted(self->base, q_id);
960		return;
961	}
962
963	is_eap = radius_has_attr(reqp, RADIUS_TYPE_EAP_MESSAGE);
964	if (radius_get_vs_raw_attr(reqp, RADIUS_VENDOR_MICROSOFT,
965	    RADIUS_VTYPE_MS_CHAP_RESPONSE, attr, &attrlen) == 0)
966		is_mschap = true;
967	else if (radius_get_vs_raw_attr(reqp, RADIUS_VENDOR_MICROSOFT,
968	    RADIUS_VTYPE_MS_CHAP2_RESPONSE, attr, &attrlen) == 0)
969		is_mschap2 = true;
970
971	if (is_eap) {
972		memset(&eap, 0, sizeof(eap));	/* just in case */
973		eap.code = 1;	/* EAP Request */
974		attrlen = sizeof(attr);
975		if (orig_resp != NULL && radius_get_raw_attr(orig_resp,
976		    RADIUS_TYPE_EAP_MESSAGE, &attr, &attrlen) == 0)
977			eap.id = attr[1];
978		else
979			eap.id = 0;
980		eap.length = htons(sizeof(eap));
981		radius_put_raw_attr(resp, RADIUS_TYPE_EAP_MESSAGE, &eap,
982		    ntohs(eap.length));
983	} else if (is_mschap || is_mschap2) {
984		attr[0] = attr[1];	/* Copy the ident of the request */
985		snprintf(attr + 1, sizeof(attr) - 1, "E=%d R=0 V=3", mserr);
986		radius_put_vs_raw_attr(resp, RADIUS_VENDOR_MICROSOFT,
987		    RADIUS_VTYPE_MS_CHAP_ERROR, attr, strlen(attr + 1) + 1);
988	}
989
990	module_resdeco_done(self->base, q_id, radius_get_data(resp),
991	    radius_get_length(resp));
992	radius_delete_packet(resp);
993}
994
995/***********************************************************************
996 * RADIUS Accounting
997 ***********************************************************************/
998void
999ipcp_accounting_request(void *ctx, u_int q_id, const u_char *pkt,
1000    size_t pktlen)
1001{
1002	RADIUS_PACKET		*radpkt = NULL;
1003	int			 code, af;
1004	uint32_t		 type, delay, uval;
1005	struct in_addr		 addr4, nas_ipv4;
1006	struct in6_addr		 nas_ipv6, ipv6_zero;
1007	struct module_ipcp	*self = ctx;
1008	struct assigned_ipv4	*assign, *assignt;
1009	char			 username[256], nas_id[256], buf[256],
1010				    buf1[384];
1011	struct timespec		 dur;
1012	struct radiusd_ipcp_statistics
1013				 stat;
1014	struct module_ipcp_dae	*dae;
1015
1016	ipcp_update_time(self);
1017
1018	if ((radpkt = radius_convert_packet(pkt, pktlen)) == NULL) {
1019		log_warn("%s: radius_convert_packet() failed", __func__);
1020		module_stop(self->base);
1021		return;
1022	}
1023	code = radius_get_code(radpkt);
1024	if (code != RADIUS_CODE_ACCOUNTING_REQUEST &&
1025	    code != RADIUS_CODE_ACCOUNTING_RESPONSE)
1026		goto out;
1027
1028	if (radius_get_uint32_attr(radpkt, RADIUS_TYPE_ACCT_STATUS_TYPE, &type)
1029	    != 0)
1030		goto out;
1031
1032	/* identifier for the NAS */
1033	memset(&ipv6_zero, 0, sizeof(ipv6_zero));
1034	memset(&nas_ipv4, 0, sizeof(nas_ipv4));
1035	memset(&nas_ipv6, 0, sizeof(nas_ipv6));
1036	memset(&nas_id, 0, sizeof(nas_id));
1037
1038	radius_get_ipv4_attr(radpkt, RADIUS_TYPE_NAS_IP_ADDRESS, &nas_ipv4);
1039	radius_get_ipv6_attr(radpkt, RADIUS_TYPE_NAS_IPV6_ADDRESS, &nas_ipv6);
1040	radius_get_string_attr(radpkt, RADIUS_TYPE_NAS_IDENTIFIER, nas_id,
1041	    sizeof(nas_id));
1042
1043	if (nas_ipv4.s_addr == 0 && IN6_ARE_ADDR_EQUAL(&nas_ipv6, &ipv6_zero) &&
1044	    nas_id[0] == '\0') {
1045		log_warnx("q=%u no NAS-IP-Address, NAS-IPV6-Address, or "
1046		    "NAS-Identifier", q_id);
1047		goto out;
1048	}
1049
1050	if (type == RADIUS_ACCT_STATUS_TYPE_ACCT_ON ||
1051	    type == RADIUS_ACCT_STATUS_TYPE_ACCT_OFF) {
1052		/*
1053		 * NAS or daemon is restarted.  Delete all assigned records
1054		 * from it
1055		 */
1056		RB_FOREACH_SAFE(assign, assigned_ipv4_tree, &self->ipv4s,
1057		    assignt) {
1058			if (assign->nas_ipv4.s_addr != nas_ipv4.s_addr ||
1059			    !IN6_ARE_ADDR_EQUAL(&assign->nas_ipv6, &nas_ipv6) ||
1060			    strcmp(assign->nas_id, nas_id) != 0)
1061				continue;
1062			log_info("Delete record for %s", inet_ntop(AF_INET,
1063			    &assign->ipv4, buf, sizeof(buf)));
1064			ipcp_del_db(self, assign);
1065			ipcp_ipv4_release(self, assign);
1066		}
1067		return;
1068	}
1069
1070	if (radius_get_ipv4_attr(radpkt, RADIUS_TYPE_FRAMED_IP_ADDRESS, &addr4)
1071	    != 0)
1072		goto out;
1073	if (radius_get_string_attr(radpkt, RADIUS_TYPE_USER_NAME, username,
1074	    sizeof(username)) != 0)
1075		goto out;
1076	if ((assign = ipcp_ipv4_find(self, addr4)) == NULL)
1077		/* not assigned by this */
1078		goto out;
1079
1080	if (radius_get_uint32_attr(radpkt, RADIUS_TYPE_ACCT_DELAY_TIME, &delay)
1081	    != 0)
1082		delay = 0;
1083
1084	if (type == RADIUS_ACCT_STATUS_TYPE_START) {
1085		assign->start = self->uptime;
1086		assign->start.tv_sec -= delay;
1087
1088		if (!self->no_session_timeout && (self->session_timeout > 0 ||
1089		    assign->session_timeout > 0)) {
1090			assign->timeout = assign->start;
1091			if (self->session_timeout > 0)
1092				assign->timeout.tv_sec += self->session_timeout;
1093			else
1094				assign->timeout.tv_sec +=
1095				    assign->session_timeout;
1096		}
1097		assign->nas_ipv4 = nas_ipv4;
1098		assign->nas_ipv6 = nas_ipv6;
1099		strlcpy(assign->nas_id, nas_id, sizeof(assign->nas_id));
1100
1101		if (radius_get_string_attr(radpkt, RADIUS_TYPE_ACCT_SESSION_ID,
1102		    assign->session_id, sizeof(assign->session_id)) != 0)
1103			assign->session_id[0] = '\0';
1104		if (radius_get_uint32_attr(radpkt, RADIUS_TYPE_TUNNEL_TYPE,
1105		    &uval) == 0)
1106			assign->tun_type = radius_tunnel_type_string(uval,
1107			    NULL);
1108		if (assign->tun_type == NULL)
1109			assign->tun_type = "";
1110
1111		/*
1112		 * Get "tunnel from" from Tunnel-Client-Endpoint or Calling-
1113		 * Station-Id
1114		 */
1115		af = AF_UNSPEC;
1116		if (radius_get_string_attr(radpkt,
1117		    RADIUS_TYPE_TUNNEL_CLIENT_ENDPOINT, buf, sizeof(buf)) == 0)
1118		    {
1119			if (radius_get_uint32_attr(radpkt,
1120			    RADIUS_TYPE_TUNNEL_MEDIUM_TYPE, &uval) == 0) {
1121				if (uval == RADIUS_TUNNEL_MEDIUM_TYPE_IPV4)
1122					af = AF_INET;
1123				else if (uval == RADIUS_TUNNEL_MEDIUM_TYPE_IPV6)
1124					af = AF_INET6;
1125			}
1126			parse_addr(buf, af, (struct sockaddr *)
1127			    &assign->tun_client, sizeof(assign->tun_client));
1128		}
1129		if (assign->tun_client.sin4.sin_family == 0 &&
1130		    radius_get_string_attr(radpkt,
1131		    RADIUS_TYPE_CALLING_STATION_ID, buf, sizeof(buf)) == 0)
1132			parse_addr(buf, af, (struct sockaddr *)
1133			    &assign->tun_client, sizeof(assign->tun_client));
1134
1135		TAILQ_FOREACH(dae, &self->daes, next) {
1136			if (dae->nas_id[0] == '\0' ||
1137			    strcmp(dae->nas_id, assign->nas_id) == 0)
1138				break;
1139		}
1140		assign->dae = dae;
1141
1142		ipcp_put_db(self, assign);
1143		ipcp_schedule_timer(self);
1144
1145		if (ipcp_notice_startstop(self, assign, 1, NULL) != 0)
1146			goto fail;
1147		log_info("Start seq=%u user=%s duration=%dsec session=%s "
1148		    "tunnel=%s from=%s auth=%s ip=%s", assign->seq,
1149		    assign->user->name, delay, assign->session_id,
1150		    assign->tun_type, print_addr((struct sockaddr *)
1151		    &assign->tun_client, buf1, sizeof(buf1)),
1152		    assign->auth_method, inet_ntop(AF_INET, &addr4, buf,
1153		    sizeof(buf)));
1154	} else if (type == RADIUS_ACCT_STATUS_TYPE_STOP) {
1155		memset(&stat, 0, sizeof(stat));
1156
1157		dur = self->uptime;
1158		dur.tv_sec -= delay;
1159		timespecsub(&dur, &assign->start, &dur);
1160
1161		if (radius_get_uint32_attr(radpkt,
1162		    RADIUS_TYPE_ACCT_INPUT_OCTETS, &uval) == 0)
1163			stat.ibytes = uval;
1164		if (radius_get_uint32_attr(radpkt,
1165		    RADIUS_TYPE_ACCT_INPUT_GIGAWORDS, &uval) == 0)
1166			stat.ibytes = ((uint64_t)uval << 32) | stat.ibytes;
1167		if (radius_get_uint32_attr(radpkt,
1168		    RADIUS_TYPE_ACCT_OUTPUT_OCTETS, &uval) == 0)
1169			stat.obytes = uval;
1170		if (radius_get_uint32_attr(radpkt,
1171		    RADIUS_TYPE_ACCT_OUTPUT_GIGAWORDS, &uval) == 0)
1172			stat.obytes = ((uint64_t)uval << 32) | stat.obytes;
1173		radius_get_uint32_attr(radpkt, RADIUS_TYPE_ACCT_INPUT_PACKETS,
1174		    &stat.ipackets);
1175		radius_get_uint32_attr(radpkt, RADIUS_TYPE_ACCT_OUTPUT_PACKETS,
1176		    &stat.opackets);
1177
1178		if (radius_get_uint32_attr(radpkt,
1179		    RADIUS_TYPE_ACCT_TERMINATE_CAUSE, &uval) == 0)
1180			strlcpy(stat.cause, radius_terminate_cause_string(uval),
1181			    sizeof(stat.cause));
1182
1183		log_info("Stop seq=%u user=%s duration=%lldsec session=%s "
1184		    "tunnel=%s from=%s auth=%s ip=%s datain=%"PRIu64"bytes,%"
1185		    PRIu32"packets dataout=%"PRIu64"bytes,%"PRIu32"packets "
1186		    "cause=\"%s\"",
1187		    assign->seq, assign->user->name, dur.tv_sec,
1188		    assign->session_id, assign->tun_type, print_addr(
1189		    (struct sockaddr *)&assign->tun_client, buf1, sizeof(buf1)),
1190		    assign->auth_method, inet_ntop(AF_INET, &addr4, buf,
1191		    sizeof(buf)), stat.ibytes, stat.ipackets, stat.obytes,
1192		    stat.opackets, stat.cause);
1193
1194		ipcp_del_db(self, assign);
1195		if (ipcp_notice_startstop(self, assign, 0, &stat) != 0)
1196			goto fail;
1197		ipcp_ipv4_release(self, ipcp_ipv4_find(self, addr4));
1198	}
1199 out:
1200	radius_delete_packet(radpkt);
1201	return;
1202 fail:
1203	module_stop(self->base);
1204	radius_delete_packet(radpkt);
1205	return;
1206}
1207
1208/***********************************************************************
1209 * On memory database to manage IP address assignment
1210 ***********************************************************************/
1211struct assigned_ipv4 *
1212ipcp_ipv4_assign(struct module_ipcp *self, struct user *user,
1213    struct in_addr ina)
1214{
1215	struct assigned_ipv4 *ip;
1216
1217	ip = calloc(1, sizeof(struct assigned_ipv4));
1218	if (ip == NULL) {
1219		log_warn("%s: calloc()", __func__);
1220		return (NULL);
1221	}
1222	ip->ipv4 = ina;
1223	ip->user = user;
1224	ip->authtime = self->uptime;
1225	RB_INSERT(assigned_ipv4_tree, &self->ipv4s, ip);
1226	TAILQ_INSERT_TAIL(&user->ipv4s, ip, next);
1227	TAILQ_INIT(&ip->dae_clients);
1228	self->nsessions++;
1229	ip->seq = self->seq++;
1230
1231	return (ip);
1232}
1233
1234struct assigned_ipv4 *
1235ipcp_ipv4_find(struct module_ipcp *self, struct in_addr ina)
1236{
1237	struct assigned_ipv4	 key, *ret;
1238	struct timespec		 dif;
1239
1240	key.ipv4 = ina;
1241	ret = RB_FIND(assigned_ipv4_tree, &self->ipv4s, &key);
1242	if (ret != NULL && ret->start.tv_sec == 0) {
1243		/* not yet assigned */
1244		timespecsub(&self->uptime, &ret->authtime, &dif);
1245		if (dif.tv_sec >= self->start_wait) {
1246			/* assumed NAS finally didn't use the address */
1247			TAILQ_REMOVE(&ret->user->ipv4s, ret, next);
1248			RB_REMOVE(assigned_ipv4_tree, &self->ipv4s, ret);
1249			free(ret);
1250			ret = NULL;
1251			self->nsessions--;
1252		}
1253	}
1254	return (ret);
1255}
1256
1257void
1258ipcp_ipv4_release(struct module_ipcp *self, struct assigned_ipv4 *assign)
1259{
1260	if (assign != NULL) {
1261		TAILQ_REMOVE(&assign->user->ipv4s, assign, next);
1262		RB_REMOVE(assigned_ipv4_tree, &self->ipv4s, assign);
1263		self->nsessions--;
1264		ipcp_dae_reset_request(assign);
1265		free(assign);
1266	}
1267}
1268
1269int
1270assigned_ipv4_compar(struct assigned_ipv4 *a, struct assigned_ipv4 *b)
1271{
1272	return (b->ipv4.s_addr - a->ipv4.s_addr);
1273}
1274
1275struct user *
1276ipcp_user_get(struct module_ipcp *self, const char *username)
1277{
1278	struct {
1279		struct user	 user;
1280		char		 name[256];
1281	} key;
1282	struct user		*elm;
1283
1284	strlcpy(key.user.name, username, 256);
1285	elm = RB_FIND(user_tree, &self->users, &key.user);
1286	if (elm == NULL) {
1287		if ((elm = calloc(1, offsetof(struct user, name[
1288		    strlen(username) + 1]))) == NULL)
1289			return (NULL);
1290		memcpy(elm->name, username, strlen(username));
1291		RB_INSERT(user_tree, &self->users, elm);
1292		TAILQ_INIT(&elm->ipv4s);
1293	}
1294
1295	return (elm);
1296}
1297
1298int
1299user_compar(struct user *a, struct user *b)
1300{
1301	return (strcmp(a->name, b->name));
1302}
1303
1304RB_GENERATE_STATIC(assigned_ipv4_tree, assigned_ipv4, tree,
1305    assigned_ipv4_compar);
1306RB_GENERATE_STATIC(user_tree, user, tree, user_compar);
1307
1308/***********************************************************************
1309 * DB for the persistent over processes
1310 ***********************************************************************/
1311int
1312ipcp_prepare_db(void)
1313{
1314	struct passwd	*pw;
1315	DB		*db;
1316
1317	if ((db = dbopen(_PATH_RADIUSD_IPCP_DB, O_CREAT | O_RDWR | O_EXLOCK,
1318	    0600, DB_BTREE, NULL)) == NULL)
1319		return (-1);
1320	if ((pw = getpwnam(RADIUSD_USER)) == NULL)
1321		return (-1);
1322	fchown(db->fd(db), pw->pw_uid, pw->pw_gid);
1323	db->close(db);
1324
1325	return (0);
1326}
1327
1328int
1329ipcp_restore_from_db(struct module_ipcp *self)
1330{
1331	DB			*db;
1332	DBT			 key, val;
1333	char			 keybuf[128];
1334	struct user		*user;
1335	struct radiusd_ipcp_db_record
1336				*record;
1337	struct assigned_ipv4	*assigned;
1338	struct in_addr		 ipv4;
1339	struct module_ipcp_dae	*dae;
1340
1341	if ((db = dbopen(_PATH_RADIUSD_IPCP_DB, O_RDONLY | O_SHLOCK, 0600,
1342	    DB_BTREE, NULL)) == NULL)
1343		return (-1);
1344
1345	key.data = "ipv4/";
1346	key.size = 5;
1347	if (db->seq(db, &key, &val, R_CURSOR) == 0) {
1348		do {
1349			if (key.size >= sizeof(keybuf))
1350				break;
1351			memcpy(keybuf, key.data, key.size);
1352			keybuf[key.size] = '\0';
1353			if (strncmp(keybuf, "ipv4/", 5) != 0)
1354				break;
1355			inet_pton(AF_INET, keybuf + 5, &ipv4);
1356			record = (struct radiusd_ipcp_db_record *)val.data;
1357			if ((user = ipcp_user_get(self, record->username))
1358			    == NULL)
1359				return (-1);
1360			if ((assigned = ipcp_ipv4_assign(self, user, ipv4))
1361			    == NULL)
1362				return (-1);
1363			assigned->seq = record->seq;
1364			self->seq = MAXIMUM(assigned->seq + 1, self->seq);
1365			strlcpy(assigned->auth_method, record->auth_method,
1366			    sizeof(assigned->auth_method));
1367			strlcpy(assigned->session_id, record->session_id,
1368			    sizeof(assigned->session_id));
1369			assigned->start = record->start;
1370			assigned->timeout = record->timeout;
1371			assigned->nas_ipv4 = record->nas_ipv4;
1372			assigned->nas_ipv6 = record->nas_ipv6;
1373			strlcpy(assigned->nas_id, record->nas_id,
1374			    sizeof(assigned->nas_id));
1375			assigned->tun_type = radius_tunnel_type_string(0,
1376			    record->tun_type);
1377			memcpy(&assigned->tun_client, &record->tun_client,
1378			    sizeof(assigned->tun_client));
1379
1380			TAILQ_FOREACH(dae, &self->daes, next) {
1381				if (dae->nas_id[0] == '\0' ||
1382				    strcmp(dae->nas_id, assigned->nas_id) == 0)
1383					break;
1384			}
1385			assigned->dae = dae;
1386		} while (db->seq(db, &key, &val, R_NEXT) == 0);
1387	}
1388	db->close(db);
1389
1390	return (0);
1391}
1392
1393void
1394ipcp_put_db(struct module_ipcp *self, struct assigned_ipv4 *assigned)
1395{
1396	DB			*db;
1397	DBT			 key, val;
1398	char			 keybuf[128];
1399	struct radiusd_ipcp_db_record
1400				 record;
1401
1402	strlcpy(keybuf, "ipv4/", sizeof(keybuf));
1403	inet_ntop(AF_INET, &assigned->ipv4, keybuf + 5, sizeof(keybuf) - 5);
1404	key.data = keybuf;
1405	key.size = strlen(keybuf);
1406	strlcpy(record.session_id, assigned->session_id,
1407	    sizeof(record.session_id));
1408	strlcpy(record.auth_method, assigned->auth_method,
1409	    sizeof(record.auth_method));
1410	strlcpy(record.username, assigned->user->name, sizeof(record.username));
1411	record.seq = assigned->seq;
1412	record.start = assigned->start;
1413	record.timeout = assigned->timeout;
1414	record.nas_ipv4 = assigned->nas_ipv4;
1415	record.nas_ipv6 = assigned->nas_ipv6;
1416	strlcpy(record.nas_id, assigned->nas_id, sizeof(record.nas_id));
1417	if (assigned->tun_type != NULL)
1418		strlcpy(record.tun_type, assigned->tun_type,
1419		    sizeof(record.tun_type));
1420	memcpy(&record.tun_client, &assigned->tun_client,
1421	    sizeof(record.tun_client));
1422
1423	val.data = &record;
1424	val.size = sizeof(record);
1425	if ((db = dbopen(_PATH_RADIUSD_IPCP_DB, O_RDWR | O_EXLOCK, 0600,
1426	    DB_BTREE, NULL)) == NULL)
1427		return;
1428	db->put(db, &key, &val, 0);
1429	db->close(db);
1430}
1431
1432void
1433ipcp_del_db(struct module_ipcp *self, struct assigned_ipv4 *assigned)
1434{
1435	DB			*db;
1436	DBT			 key;
1437	char			 keybuf[128];
1438
1439	strlcpy(keybuf, "ipv4/", sizeof(keybuf));
1440	inet_ntop(AF_INET, &assigned->ipv4, keybuf + 5, sizeof(keybuf) - 5);
1441	key.data = keybuf;
1442	key.size = strlen(keybuf);
1443
1444	if ((db = dbopen(_PATH_RADIUSD_IPCP_DB, O_RDWR | O_EXLOCK, 0600,
1445	    DB_BTREE, NULL)) == NULL)
1446		return;
1447	db->del(db, &key, 0);
1448	db->close(db);
1449}
1450
1451void
1452ipcp_db_dump_fill_record(struct radiusd_ipcp_db_dump *dump, int idx,
1453    struct assigned_ipv4 *assign)
1454{
1455	dump->records[idx].af = AF_INET;
1456	dump->records[idx].addr.ipv4 = assign->ipv4;
1457	dump->records[idx].rec.seq = assign->seq;
1458	strlcpy(dump->records[idx].rec.session_id, assign->session_id,
1459	    sizeof(dump->records[idx].rec.session_id));
1460	strlcpy(dump->records[idx].rec.auth_method, assign->auth_method,
1461	    sizeof(dump->records[idx].rec.auth_method));
1462	strlcpy(dump->records[idx].rec.username, assign->user->name,
1463	    sizeof(dump->records[idx].rec.username));
1464	dump->records[idx].rec.start = assign->start;
1465	dump->records[idx].rec.timeout = assign->timeout;
1466	dump->records[idx].rec.nas_ipv4 = assign->nas_ipv4;
1467	dump->records[idx].rec.nas_ipv6 = assign->nas_ipv6;
1468	strlcpy(dump->records[idx].rec.nas_id, assign->nas_id,
1469	    sizeof(dump->records[idx].rec.nas_id));
1470	if (assign->tun_type != NULL)
1471		strlcpy(dump->records[idx].rec.tun_type, assign->tun_type,
1472		    sizeof(dump->records[idx].rec.tun_type));
1473	memcpy(&dump->records[idx].rec.tun_client, &assign->tun_client,
1474	    sizeof(dump->records[idx].rec.tun_client));
1475}
1476
1477/***********************************************************************
1478 * Timer
1479 ***********************************************************************/
1480void
1481ipcp_update_time(struct module_ipcp *self)
1482{
1483	clock_gettime(CLOCK_BOOTTIME, &self->uptime);
1484}
1485
1486void
1487ipcp_on_timer(int fd, short ev, void *ctx)
1488{
1489	struct module_ipcp *self = ctx;
1490
1491	ipcp_update_time(self);
1492	ipcp_schedule_timer(self);
1493}
1494
1495void
1496ipcp_schedule_timer(struct module_ipcp *self)
1497{
1498	struct assigned_ipv4	*assign, *min_assign = NULL;
1499	struct timespec		 tsd;
1500	struct timeval		 tv;
1501
1502	/* check session timeout */
1503	RB_FOREACH(assign, assigned_ipv4_tree, &self->ipv4s) {
1504		if (assign->timeout.tv_sec == 0)
1505			continue;
1506		if (timespeccmp(&assign->timeout, &self->uptime, <=)) {
1507			log_info("Reached session timeout seq=%u", assign->seq);
1508			ipcp_dae_send_disconnect_request(assign);
1509			memset(&assign->timeout, 0, sizeof(assign->timeout));
1510			ipcp_put_db(self, assign);
1511		}
1512		if (min_assign == NULL ||
1513		    timespeccmp(&min_assign->timeout, &assign->timeout, >))
1514			min_assign = assign;
1515	}
1516	if (evtimer_pending(&self->ev_timer, NULL))
1517		evtimer_del(&self->ev_timer);
1518
1519	if (min_assign != NULL) {
1520		timespecsub(&min_assign->timeout, &self->uptime, &tsd);
1521		TIMESPEC_TO_TIMEVAL(&tv, &tsd);
1522		evtimer_set(&self->ev_timer, ipcp_on_timer, self);
1523		evtimer_add(&self->ev_timer, &tv);
1524	}
1525}
1526
1527/***********************************************************************
1528 * Dynamic Authorization Extension for RAIDUS (RFC 5176)
1529 ***********************************************************************/
1530static const int dae_request_timeouts[] = { 2, 4, 8, 8 };
1531
1532void
1533ipcp_dae_send_disconnect_request(struct assigned_ipv4 *assign)
1534{
1535	RADIUS_PACKET		*reqpkt = NULL;
1536	struct timeval		 tv;
1537	char			 buf[80];
1538
1539	if (assign->dae == NULL)
1540		return;		/* DAE is not configured */
1541
1542	if (assign->dae_reqpkt == NULL) {
1543		if ((reqpkt = radius_new_request_packet(
1544		    RADIUS_CODE_DISCONNECT_REQUEST)) == NULL) {
1545			log_warn("%s: radius_new_request_packet(): %m",
1546			    __func__);
1547			return;
1548		}
1549		radius_put_string_attr(reqpkt, RADIUS_TYPE_ACCT_SESSION_ID,
1550		    assign->session_id);
1551		/*
1552		 * RFC 5176 Section 3, "either the User-Name or
1553		 * Chargeable-User-Identity attribute SHOULD be present in
1554		 * Disconnect-Request and CoA-Request packets."
1555		 */
1556		radius_put_string_attr(reqpkt, RADIUS_TYPE_USER_NAME,
1557		    assign->user->name);
1558		if (assign->nas_id[0] != '\0')
1559			radius_put_string_attr(reqpkt,
1560			    RADIUS_TYPE_NAS_IDENTIFIER, assign->nas_id);
1561		if (ntohl(assign->nas_ipv4.s_addr) != 0)
1562			radius_put_ipv4_attr(reqpkt,
1563			    RADIUS_TYPE_NAS_IP_ADDRESS, assign->nas_ipv4);
1564		if (!IN6_IS_ADDR_UNSPECIFIED(&assign->nas_ipv6))
1565			radius_put_ipv6_attr(reqpkt,
1566			    RADIUS_TYPE_NAS_IPV6_ADDRESS, &assign->nas_ipv6);
1567		radius_set_accounting_request_authenticator(reqpkt,
1568		    assign->dae->secret);
1569		assign->dae_reqpkt = reqpkt;
1570	}
1571
1572	if (assign->dae_ntry == 0) {
1573		log_info("Sending Disconnect-Request seq=%u to %s",
1574		    assign->seq, print_addr((struct sockaddr *)
1575		    &assign->dae->nas_addr, buf, sizeof(buf)));
1576		TAILQ_INSERT_TAIL(&assign->dae->reqs, assign, dae_next);
1577	}
1578
1579	if (radius_send(assign->dae->sock, assign->dae_reqpkt, 0) < 0)
1580		log_warn("%s: sendto: %m", __func__);
1581
1582	tv.tv_sec = dae_request_timeouts[assign->dae_ntry++];
1583	tv.tv_usec = 0;
1584	evtimer_set(&assign->dae_evtimer, ipcp_dae_request_on_timeout, assign);
1585	evtimer_add(&assign->dae_evtimer, &tv);
1586}
1587
1588void
1589ipcp_dae_request_on_timeout(int fd, short ev, void *ctx)
1590{
1591	struct assigned_ipv4	*assign = ctx;
1592	char			 buf[80];
1593	struct radiusctl_client	*client;
1594
1595	if (assign->dae_ntry >= (int)nitems(dae_request_timeouts)) {
1596		log_warnx("No answer for Disconnect-Request seq=%u from %s",
1597		    assign->seq, print_addr((struct sockaddr *)
1598		    &assign->dae->nas_addr, buf, sizeof(buf)));
1599		TAILQ_FOREACH(client, &assign->dae_clients, entry)
1600			module_imsg_compose(assign->dae->ipcp->base, IMSG_NG,
1601			    client->peerid, 0, -1, NULL, 0);
1602		ipcp_dae_reset_request(assign);
1603	} else
1604		ipcp_dae_send_disconnect_request(assign);
1605}
1606
1607void
1608ipcp_dae_on_event(int fd, short ev, void *ctx)
1609{
1610	struct module_ipcp_dae	*dae = ctx;
1611	struct module_ipcp	*self = dae->ipcp;
1612	RADIUS_PACKET		*radres = NULL;
1613	int			 code;
1614	uint32_t		 u32;
1615	struct assigned_ipv4	*assign;
1616	char			 buf[80], causestr[80];
1617	const char		*cause = "";
1618	struct radiusctl_client	*client;
1619
1620	ipcp_update_time(self);
1621
1622	if ((ev & EV_READ) == 0)
1623		return;
1624
1625	if ((radres = radius_recv(dae->sock, 0)) == NULL) {
1626		if (errno == EAGAIN)
1627			return;
1628		log_warn("Failed to receive from %s", print_addr(
1629		    (struct sockaddr *)&dae->nas_addr, buf, sizeof(buf)));
1630		return;
1631	}
1632	TAILQ_FOREACH(assign, &dae->reqs, dae_next) {
1633		if (radius_get_id(assign->dae_reqpkt) == radius_get_id(radres))
1634			break;
1635	}
1636	if (assign == NULL) {
1637		log_warnx("Received RADIUS packet from %s has unknown id=%d",
1638		    print_addr((struct sockaddr *)&dae->nas_addr, buf,
1639		    sizeof(buf)), radius_get_id(radres));
1640		goto out;
1641	}
1642
1643	radius_set_request_packet(radres, assign->dae_reqpkt);
1644	if ((radius_check_response_authenticator(radres, dae->secret)) != 0) {
1645		log_warnx("Received RADIUS packet for seq=%u from %s has a bad "
1646		    "authenticator", assign->seq, print_addr(
1647			(struct sockaddr *)&dae->nas_addr, buf,
1648		    sizeof(buf)));
1649		goto out;
1650	}
1651	causestr[0] = '\0';
1652	if (radius_get_uint32_attr(radres, RADIUS_TYPE_ERROR_CAUSE, &u32) == 0){
1653		cause = radius_error_cause_string(u32);
1654		if (cause != NULL)
1655			snprintf(causestr, sizeof(causestr), " cause=%u(%s)",
1656			    u32, cause);
1657		else
1658			snprintf(causestr, sizeof(causestr), " cause=%u", u32);
1659		cause = causestr;
1660	}
1661
1662	code = radius_get_code(radres);
1663	switch (code) {
1664	case RADIUS_CODE_DISCONNECT_ACK:
1665		log_info("Received Disconnect-ACK for seq=%u from %s%s",
1666		    assign->seq, print_addr((struct sockaddr *)
1667		    &dae->nas_addr, buf, sizeof(buf)), cause);
1668		break;
1669	case RADIUS_CODE_DISCONNECT_NAK:
1670		log_warnx("Received Disconnect-NAK for seq=%u from %s%s",
1671		    assign->seq, print_addr((struct sockaddr *)
1672		    &dae->nas_addr, buf, sizeof(buf)), cause);
1673		break;
1674	default:
1675		log_warn("Received unknown code=%d for id=%u from %s",
1676		    code, assign->seq, print_addr((struct sockaddr *)
1677		    &dae->nas_addr, buf, sizeof(buf)));
1678		break;
1679	}
1680
1681	TAILQ_FOREACH(client, &assign->dae_clients, entry) {
1682		if (*cause != '\0')
1683			module_imsg_compose(self->base,
1684			    (code == RADIUS_CODE_DISCONNECT_ACK)
1685			    ? IMSG_OK : IMSG_NG, client->peerid, 0, -1,
1686			    cause + 1, strlen(cause + 1) + 1);
1687		else
1688			module_imsg_compose(self->base,
1689			    (code == RADIUS_CODE_DISCONNECT_ACK)
1690			    ? IMSG_OK : IMSG_NG, client->peerid, 0, -1,
1691			    NULL, 0);
1692	}
1693	ipcp_dae_reset_request(assign);
1694 out:
1695	if (radres != NULL)
1696		radius_delete_packet(radres);
1697}
1698
1699void
1700ipcp_dae_reset_request(struct assigned_ipv4 *assign)
1701{
1702	struct radiusctl_client		*client, *clientt;
1703
1704	if (assign->dae != NULL) {
1705		if (assign->dae_ntry > 0)
1706			TAILQ_REMOVE(&assign->dae->reqs, assign, dae_next);
1707	}
1708	if (assign->dae_reqpkt != NULL)
1709		radius_delete_packet(assign->dae_reqpkt);
1710	assign->dae_reqpkt = NULL;
1711	if (evtimer_pending(&assign->dae_evtimer, NULL))
1712		evtimer_del(&assign->dae_evtimer);
1713	TAILQ_FOREACH_SAFE(client, &assign->dae_clients, entry, clientt) {
1714		TAILQ_REMOVE(&assign->dae_clients, client, entry);
1715		free(client);
1716	}
1717	assign->dae_ntry = 0;
1718}
1719
1720/***********************************************************************
1721 * Miscellaneous functions
1722 ***********************************************************************/
1723struct ipcp_address *
1724parse_address_range(const char *range)
1725{
1726	char			*buf, *sep;
1727	int			 masklen;
1728	uint32_t		 mask;
1729	struct in_addr		 start, end;
1730	struct ipcp_address	*ret;
1731	const char		*errstr;
1732
1733	buf = strdup(range);
1734	if (buf == NULL)
1735		goto error;
1736	if ((sep = strchr(buf, '-')) != NULL) {
1737		*sep = '\0';
1738		if (inet_aton(buf, &start) != 1)
1739			goto error;
1740		else if (inet_aton(++sep, &end) != 1)
1741			goto error;
1742		start.s_addr = ntohl(start.s_addr);
1743		end.s_addr = ntohl(end.s_addr);
1744	} else {
1745		if ((sep = strchr(buf, '/')) != NULL) {
1746			*sep = '\0';
1747			if (inet_aton(buf, &start) != 1)
1748				goto error;
1749			masklen = strtonum(++sep, 0, 32, &errstr);
1750			if (errstr != NULL)
1751				goto error;
1752		} else {
1753			if (inet_aton(buf, &start) != 1)
1754				goto error;
1755			masklen = 32;
1756		}
1757		mask = 0xFFFFFFFFUL;
1758		if (masklen < 32)
1759			mask <<= (32 - masklen);
1760		start.s_addr = ntohl(start.s_addr) & mask;
1761		if (masklen == 32)
1762			end = start;
1763		else if (masklen == 31)
1764			end.s_addr = start.s_addr + 1;
1765		else {
1766			end.s_addr = start.s_addr + (1 << (32 - masklen)) - 2;
1767			start.s_addr = start.s_addr + 1;
1768		}
1769	}
1770	free(buf);
1771	if ((ret = calloc(1, sizeof(struct ipcp_address))) == NULL)
1772		return (NULL);
1773	ret->start = start;
1774	ret->end = end;
1775	ret->naddrs = end.s_addr - start.s_addr + 1;
1776	return (ret);
1777 error:
1778	free(buf);
1779	return (NULL);
1780}
1781
1782const char *
1783radius_tunnel_type_string(unsigned val, const char *label)
1784{
1785	unsigned int		 i;
1786	struct {
1787		const unsigned	 constval;
1788		const char	*label;
1789	} tunnel_types[] = {
1790		{ RADIUS_TUNNEL_TYPE_PPTP,	"PPTP" },
1791		{ RADIUS_TUNNEL_TYPE_L2F,	"L2F" },
1792		{ RADIUS_TUNNEL_TYPE_L2TP,	"L2TP" },
1793		{ RADIUS_TUNNEL_TYPE_ATMP,	"ATMP" },
1794		{ RADIUS_TUNNEL_TYPE_VTP,	"VTP" },
1795		{ RADIUS_TUNNEL_TYPE_AH,	"AH" },
1796		{ RADIUS_TUNNEL_TYPE_IP,	"IP" },
1797		{ RADIUS_TUNNEL_TYPE_MOBILE,	"MIN-IP-IP" },
1798		{ RADIUS_TUNNEL_TYPE_ESP,	"ESP" },
1799		{ RADIUS_TUNNEL_TYPE_GRE,	"GRE" },
1800		{ RADIUS_TUNNEL_TYPE_VDS,	"DVS" },
1801		/* [MS-RNAS] 3.3.5.1.9 Tunnel-Type */
1802		{ RADIUS_VENDOR_MICROSOFT << 8 | 1,
1803						"SSTP" }
1804	};
1805
1806	if (label != NULL) {	/* for conversion to the const value */
1807		for (i = 0; i < nitems(tunnel_types); i++) {
1808			if (strcmp(tunnel_types[i].label, label) == 0)
1809				return (tunnel_types[i].label);
1810		}
1811	}
1812
1813	for (i = 0; i < nitems(tunnel_types); i++) {
1814		if (tunnel_types[i].constval == val)
1815			return (tunnel_types[i].label);
1816	}
1817
1818	return (NULL);
1819}
1820
1821const char *
1822radius_terminate_cause_string(unsigned val)
1823{
1824	unsigned int		 i;
1825	struct {
1826		const unsigned	 constval;
1827		const char	*label;
1828	} terminate_causes[] = {
1829	    { RADIUS_TERMNATE_CAUSE_USER_REQUEST,	"User Request" },
1830	    { RADIUS_TERMNATE_CAUSE_LOST_CARRIER,	"Lost Carrier" },
1831	    { RADIUS_TERMNATE_CAUSE_LOST_SERVICE,	"Lost Service" },
1832	    { RADIUS_TERMNATE_CAUSE_IDLE_TIMEOUT,	"Idle Timeout" },
1833	    { RADIUS_TERMNATE_CAUSE_SESSION_TIMEOUT,	"Session Timeout" },
1834	    { RADIUS_TERMNATE_CAUSE_ADMIN_RESET,	"Admin Reset" },
1835	    { RADIUS_TERMNATE_CAUSE_ADMIN_REBOOT,	"Admin Reboot" },
1836	    { RADIUS_TERMNATE_CAUSE_PORT_ERROR,		"Port Error" },
1837	    { RADIUS_TERMNATE_CAUSE_NAS_ERROR,		"NAS Error" },
1838	    { RADIUS_TERMNATE_CAUSE_NAS_RESET,		"NAS Request" },
1839	    { RADIUS_TERMNATE_CAUSE_NAS_REBOOT,		"NAS Reboot" },
1840	    { RADIUS_TERMNATE_CAUSE_PORT_UNNEEDED,	"Port Unneeded" },
1841	    { RADIUS_TERMNATE_CAUSE_PORT_PREEMPTED,	"Port Preempted" },
1842	    { RADIUS_TERMNATE_CAUSE_PORT_SUSPENDED,	"Port Suspended" },
1843	    { RADIUS_TERMNATE_CAUSE_SERVICE_UNAVAIL,	"Service Unavailable" },
1844	    { RADIUS_TERMNATE_CAUSE_CALLBACK,		"Callback" },
1845	    { RADIUS_TERMNATE_CAUSE_USER_ERROR,		"User Error" },
1846	    { RADIUS_TERMNATE_CAUSE_HOST_REQUEST,	"Host Request" },
1847	};
1848
1849	for (i = 0; i < nitems(terminate_causes); i++) {
1850		if (terminate_causes[i].constval == val)
1851			return (terminate_causes[i].label);
1852	}
1853
1854	return (NULL);
1855}
1856
1857const char *
1858radius_error_cause_string(unsigned val)
1859{
1860	unsigned int		 i;
1861	struct {
1862		const unsigned	 constval;
1863		const char	*label;
1864	} error_causes[] = {
1865	    { RADIUS_ERROR_CAUSE_RESIDUAL_SESSION_REMOVED,
1866	      "Residual Session Context Removed" },
1867	    { RADIUS_ERROR_CAUSE_INVALID_EAP_PACKET,
1868	      "Invalid EAP Packet (Ignored)" },
1869	    { RADIUS_ERROR_CAUSE_UNSUPPORTED_ATTRIBUTE,
1870	      "Unsupported Attribute" },
1871	    { RADIUS_ERROR_CAUSE_MISSING_ATTRIBUTE,
1872	      "Missing Attribute" },
1873	    { RADIUS_ERROR_CAUSE_NAS_IDENTIFICATION_MISMATCH,
1874	      "NAS Identification Mismatch" },
1875	    { RADIUS_ERROR_CAUSE_INVALID_REQUEST,
1876	      "Invalid Request" },
1877	    { RADIUS_ERROR_CAUSE_UNSUPPORTED_SERVICE,
1878	      "Unsupported Service" },
1879	    { RADIUS_ERROR_CAUSE_UNSUPPORTED_EXTENSION,
1880	      "Unsupported Extension" },
1881	    { RADIUS_ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE,
1882	      "Invalid Attribute Value" },
1883	    { RADIUS_ERROR_CAUSE_ADMINISTRATIVELY_PROHIBITED,
1884	      "Administratively Prohibited" },
1885	    { RADIUS_ERROR_CAUSE_REQUEST_NOT_ROUTABLE,
1886	      "Request Not Routable (Proxy)" },
1887	    { RADIUS_ERROR_CAUSE_SESSION_NOT_FOUND,
1888	      "Session Context Not Found" },
1889	    { RADIUS_ERROR_CAUSE_SESSION_NOT_REMOVABLE,
1890	      "Session Context Not Removable" },
1891	    { RADIUS_ERROR_CAUSE_OTHER_PROXY_PROCESSING_ERROR,
1892	      "Other Proxy Processing Error" },
1893	    { RADIUS_ERROR_CAUSE_RESOURCES_UNAVAILABLE,
1894	      "Resources Unavailable" },
1895	    { RADIUS_ERROR_CAUSE_REQUEST_INITIATED,
1896	      "equest Initiated" },
1897	    { RADIUS_ERROR_CAUSE_MULTI_SELECTION_UNSUPPORTED,
1898	      "Multiple Session Selection Unsupported" }
1899	};
1900
1901	for (i = 0; i < nitems(error_causes); i++) {
1902		if (error_causes[i].constval == val)
1903			return (error_causes[i].label);
1904	}
1905
1906	return (NULL);
1907}
1908
1909int
1910parse_addr(const char *str0, int af, struct sockaddr *sa, socklen_t salen)
1911{
1912	int		 error;
1913	char		*str, *end, *colon, *colon0, *addr = NULL, *port = NULL;
1914	char		*sb, *sb0;
1915	struct addrinfo	 hints, *ai;
1916
1917	if ((str = strdup(str0)) == NULL)
1918		return (-1);
1919	if (*str == '[' && (end = strchr(str + 1, ']')) != NULL) {
1920		addr = str + 1;
1921		*end = '\0';
1922		if (*(end + 1) == ':')
1923			port = end + 2;
1924		else if (*(end + 1) == '[' && (sb = strrchr(end + 2, ']'))
1925		    != NULL) {
1926			port = end + 2;
1927			*sb = '\0';
1928		}
1929	} else if ((sb0 = strchr(str, '[')) != NULL &&
1930	    (sb = strrchr(sb0 + 1, ']')) != NULL && sb0 < sb) {
1931		addr = str;
1932		*sb0 = '\0';
1933		port = sb0 + 1;
1934		*sb = '\0';
1935	} else if ((colon0 = strchr(str, ':')) != NULL &&
1936	    (colon = strrchr(str, ':')) != NULL && colon0 == colon) {
1937		/* has one : */
1938		addr = str;
1939		*colon = '\0';
1940		port = colon + 1;
1941	} else {
1942		addr = str;
1943		port = NULL;
1944	}
1945
1946	memset(&hints, 0, sizeof(hints));
1947	hints.ai_family = af;
1948	hints.ai_socktype = SOCK_DGRAM;
1949	hints.ai_flags = AI_NUMERICHOST;
1950	if (port != NULL)
1951		hints.ai_flags |= AI_NUMERICSERV;
1952	if ((error = getaddrinfo(addr, port, &hints, &ai)) != 0) {
1953		free(str);
1954		return (-1);
1955	}
1956	free(str);
1957	if (salen < ai->ai_addrlen) {
1958		freeaddrinfo(ai);
1959		return (-1);
1960	}
1961	memcpy(sa, ai->ai_addr, ai->ai_addrlen);
1962	freeaddrinfo(ai);
1963
1964	return (0);
1965}
1966
1967const char *
1968print_addr(struct sockaddr *sa, char *buf, size_t bufsiz)
1969{
1970	int	noport, ret;
1971	char	hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
1972
1973	if (ntohs(((struct sockaddr_in *)sa)->sin_port) == 0) {
1974		noport = 1;
1975		ret = getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0,
1976		    NI_NUMERICHOST);
1977	} else {
1978		noport = 0;
1979		ret = getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), sbuf,
1980		    sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
1981	}
1982	if (ret != 0)
1983		return "";
1984	if (noport)
1985		strlcpy(buf, hbuf, bufsiz);
1986	else if (sa->sa_family == AF_INET6)
1987		snprintf(buf, bufsiz, "[%s]:%s", hbuf, sbuf);
1988	else
1989		snprintf(buf, bufsiz, "%s:%s", hbuf, sbuf);
1990
1991	return (buf);
1992}
1993