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