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