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