1*aae7f363Syasuoka /* $OpenBSD: radiusd_ipcp.c,v 1.23 2025/01/29 10:16:05 yasuoka Exp $ */ 2842565f2Syasuoka 3842565f2Syasuoka /* 4842565f2Syasuoka * Copyright (c) 2024 Internet Initiative Japan Inc. 5842565f2Syasuoka * 6842565f2Syasuoka * Permission to use, copy, modify, and distribute this software for any 7842565f2Syasuoka * purpose with or without fee is hereby granted, provided that the above 8842565f2Syasuoka * copyright notice and this permission notice appear in all copies. 9842565f2Syasuoka * 10842565f2Syasuoka * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11842565f2Syasuoka * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12842565f2Syasuoka * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13842565f2Syasuoka * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14842565f2Syasuoka * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15842565f2Syasuoka * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16842565f2Syasuoka * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17842565f2Syasuoka */ 18842565f2Syasuoka 19842565f2Syasuoka #include <sys/types.h> 20842565f2Syasuoka #include <sys/queue.h> 21842565f2Syasuoka #include <sys/socket.h> 22842565f2Syasuoka #include <sys/time.h> 23842565f2Syasuoka #include <sys/tree.h> 24842565f2Syasuoka #include <arpa/inet.h> 25842565f2Syasuoka 26842565f2Syasuoka #include <inttypes.h> 27842565f2Syasuoka #include <netdb.h> 28842565f2Syasuoka #include <db.h> 29842565f2Syasuoka #include <err.h> 30842565f2Syasuoka #include <errno.h> 31842565f2Syasuoka #include <event.h> 32842565f2Syasuoka #include <fcntl.h> 33842565f2Syasuoka #include <pwd.h> 34842565f2Syasuoka #include <radius.h> 35842565f2Syasuoka #include <stdbool.h> 36842565f2Syasuoka #include <stddef.h> 37842565f2Syasuoka #include <stdint.h> 38842565f2Syasuoka #include <stdio.h> 39842565f2Syasuoka #include <stdlib.h> 40842565f2Syasuoka #include <string.h> 41842565f2Syasuoka #include <time.h> 42842565f2Syasuoka #include <unistd.h> 43842565f2Syasuoka #include <imsg.h> 44842565f2Syasuoka 45842565f2Syasuoka #include "radiusd.h" 46842565f2Syasuoka #include "radiusd_module.h" 47842565f2Syasuoka #include "radiusd_ipcp.h" 48842565f2Syasuoka #include "log.h" 49842565f2Syasuoka 50842565f2Syasuoka #define RADIUSD_IPCP_START_WAIT 60 51842565f2Syasuoka 52842565f2Syasuoka enum ipcp_address_type { 53842565f2Syasuoka ADDRESS_TYPE_POOL, 54842565f2Syasuoka ADDRESS_TYPE_STATIC 55842565f2Syasuoka }; 56842565f2Syasuoka 57842565f2Syasuoka struct ipcp_address { 58842565f2Syasuoka enum ipcp_address_type type; 59842565f2Syasuoka struct in_addr start; 60842565f2Syasuoka struct in_addr end; 61842565f2Syasuoka int naddrs; 62842565f2Syasuoka TAILQ_ENTRY(ipcp_address) next; 63842565f2Syasuoka }; 64842565f2Syasuoka 65842565f2Syasuoka struct user { 66842565f2Syasuoka TAILQ_HEAD(, assigned_ipv4) ipv4s; 67842565f2Syasuoka RB_ENTRY(user) tree; 68842565f2Syasuoka char name[0]; 69842565f2Syasuoka }; 70842565f2Syasuoka 71c0127aecSyasuoka struct radiusctl_client { 72c0127aecSyasuoka int peerid; 73c0127aecSyasuoka TAILQ_ENTRY(radiusctl_client) entry; 74c0127aecSyasuoka }; 75c0127aecSyasuoka 76842565f2Syasuoka struct module_ipcp_dae; 77842565f2Syasuoka 78842565f2Syasuoka struct assigned_ipv4 { 79842565f2Syasuoka struct in_addr ipv4; 80842565f2Syasuoka unsigned seq; 81842565f2Syasuoka char session_id[256]; 82842565f2Syasuoka char auth_method[16]; 83842565f2Syasuoka struct user *user; 84842565f2Syasuoka uint32_t session_timeout; 85842565f2Syasuoka struct timespec start; 86842565f2Syasuoka struct timespec timeout; 87842565f2Syasuoka struct in_addr nas_ipv4; 88842565f2Syasuoka struct in6_addr nas_ipv6; 89842565f2Syasuoka char nas_id[256]; 90842565f2Syasuoka const char *tun_type; 91842565f2Syasuoka union { 92842565f2Syasuoka struct sockaddr_in sin4; 93842565f2Syasuoka struct sockaddr_in6 sin6; 94842565f2Syasuoka } tun_client; 95842565f2Syasuoka 96842565f2Syasuoka struct timespec authtime; 97842565f2Syasuoka RB_ENTRY(assigned_ipv4) tree; 98842565f2Syasuoka TAILQ_ENTRY(assigned_ipv4) next; 99842565f2Syasuoka 100842565f2Syasuoka /* RFC 5176 Dynamic Authorization Extensions for RADIUS */ 101842565f2Syasuoka struct module_ipcp_dae *dae; 102842565f2Syasuoka RADIUS_PACKET *dae_reqpkt; 103842565f2Syasuoka TAILQ_ENTRY(assigned_ipv4) dae_next; 104842565f2Syasuoka int dae_ntry; 105842565f2Syasuoka struct event dae_evtimer; 106c0127aecSyasuoka TAILQ_HEAD(, radiusctl_client) dae_clients; 107842565f2Syasuoka }; 108842565f2Syasuoka 109842565f2Syasuoka struct module_ipcp_ctrlconn { 110842565f2Syasuoka uint32_t peerid; 111842565f2Syasuoka TAILQ_ENTRY(module_ipcp_ctrlconn) 112842565f2Syasuoka next; 113842565f2Syasuoka }; 114842565f2Syasuoka 115842565f2Syasuoka struct module_ipcp_dae { 116842565f2Syasuoka struct module_ipcp *ipcp; 117842565f2Syasuoka int sock; 118842565f2Syasuoka char nas_id[256]; 119842565f2Syasuoka char secret[80]; 120842565f2Syasuoka union { 121842565f2Syasuoka struct sockaddr_in sin4; 122842565f2Syasuoka struct sockaddr_in6 sin6; 123842565f2Syasuoka } nas_addr; 124842565f2Syasuoka struct event ev_sock; 125cfa11a85Syasuoka struct event ev_reqs; 126842565f2Syasuoka TAILQ_ENTRY(module_ipcp_dae) next; 127842565f2Syasuoka TAILQ_HEAD(, assigned_ipv4) reqs; 128cfa11a85Syasuoka int ninflight; 129842565f2Syasuoka }; 130842565f2Syasuoka 131842565f2Syasuoka struct module_ipcp { 132842565f2Syasuoka struct module_base *base; 133842565f2Syasuoka int nsessions; 134842565f2Syasuoka unsigned seq; 135842565f2Syasuoka int max_sessions; 136842565f2Syasuoka int user_max_sessions; 137842565f2Syasuoka int start_wait; 138842565f2Syasuoka int session_timeout; 139842565f2Syasuoka bool no_session_timeout; 140842565f2Syasuoka struct timespec uptime; 141842565f2Syasuoka struct in_addr name_server[2]; 142842565f2Syasuoka struct in_addr netbios_server[2]; 143842565f2Syasuoka RB_HEAD(assigned_ipv4_tree, assigned_ipv4) 144842565f2Syasuoka ipv4s; 145842565f2Syasuoka RB_HEAD(user_tree, user) users; 146842565f2Syasuoka int npools; 147842565f2Syasuoka TAILQ_HEAD(,ipcp_address) addrs; 148842565f2Syasuoka TAILQ_HEAD(,module_ipcp_ctrlconn) 149842565f2Syasuoka ctrls; 150842565f2Syasuoka TAILQ_HEAD(,module_ipcp_dae) daes; 151842565f2Syasuoka struct event ev_timer; 152842565f2Syasuoka }; 153842565f2Syasuoka 154842565f2Syasuoka #ifndef nitems 155842565f2Syasuoka #define nitems(_x) (sizeof((_x)) / sizeof((_x)[0])) 156842565f2Syasuoka #endif 157842565f2Syasuoka 158842565f2Syasuoka #ifndef MAXIMUM 159842565f2Syasuoka #define MAXIMUM(_a, _b) (((_a) > (_b))? (_a) : (_b)) 160842565f2Syasuoka #endif 161842565f2Syasuoka 162842565f2Syasuoka static void ipcp_init(struct module_ipcp *); 163842565f2Syasuoka static void ipcp_start(void *); 164842565f2Syasuoka static void ipcp_stop(void *); 165842565f2Syasuoka static void ipcp_fini(struct module_ipcp *); 166842565f2Syasuoka static void ipcp_config_set(void *, const char *, int, char * const *); 167842565f2Syasuoka static void ipcp_dispatch_control(void *, struct imsg *); 168842565f2Syasuoka static int ipcp_notice_startstop(struct module_ipcp *, 169842565f2Syasuoka struct assigned_ipv4 *, int, 170842565f2Syasuoka struct radiusd_ipcp_statistics *); 171842565f2Syasuoka static void ipcp_resdeco(void *, u_int, const u_char *, size_t reqlen, 172842565f2Syasuoka const u_char *, size_t reslen); 173842565f2Syasuoka static void ipcp_reject(struct module_ipcp *, RADIUS_PACKET *, 174842565f2Syasuoka unsigned int, RADIUS_PACKET *, int); 175842565f2Syasuoka static void ipcp_accounting_request(void *, u_int, const u_char *, 176842565f2Syasuoka size_t); 177842565f2Syasuoka 178842565f2Syasuoka struct assigned_ipv4 179842565f2Syasuoka *ipcp_ipv4_assign(struct module_ipcp *, struct user *, 180842565f2Syasuoka struct in_addr); 181842565f2Syasuoka static struct assigned_ipv4 182842565f2Syasuoka *ipcp_ipv4_find(struct module_ipcp *, struct in_addr); 183eff8f878Syasuoka static void ipcp_ipv4_delete(struct module_ipcp *, 184eff8f878Syasuoka struct assigned_ipv4 *, const char *); 185842565f2Syasuoka static void ipcp_ipv4_release(struct module_ipcp *, 186842565f2Syasuoka struct assigned_ipv4 *); 187842565f2Syasuoka static int assigned_ipv4_compar(struct assigned_ipv4 *, 188842565f2Syasuoka struct assigned_ipv4 *); 189842565f2Syasuoka static struct user 190842565f2Syasuoka *ipcp_user_get(struct module_ipcp *, const char *); 191842565f2Syasuoka static int user_compar(struct user *, struct user *); 192842565f2Syasuoka static int ipcp_prepare_db(void); 193842565f2Syasuoka static int ipcp_restore_from_db(struct module_ipcp *); 194842565f2Syasuoka static void ipcp_put_db(struct module_ipcp *, struct assigned_ipv4 *); 195842565f2Syasuoka static void ipcp_del_db(struct module_ipcp *, struct assigned_ipv4 *); 196842565f2Syasuoka static void ipcp_db_dump_fill_record(struct radiusd_ipcp_db_dump *, int, 197842565f2Syasuoka struct assigned_ipv4 *); 198e1af567eSyasuoka static void ipcp_update_time(struct module_ipcp *); 199842565f2Syasuoka static void ipcp_on_timer(int, short, void *); 200842565f2Syasuoka static void ipcp_schedule_timer(struct module_ipcp *); 201842565f2Syasuoka static void ipcp_dae_send_disconnect_request(struct assigned_ipv4 *); 202842565f2Syasuoka static void ipcp_dae_request_on_timeout(int, short, void *); 203842565f2Syasuoka static void ipcp_dae_on_event(int, short, void *); 2042617e43bSyasuoka static void ipcp_dae_reset_request(struct assigned_ipv4 *); 205cfa11a85Syasuoka static void ipcp_dae_send_pending_requests(int, short, void *); 206842565f2Syasuoka static struct ipcp_address 207842565f2Syasuoka *parse_address_range(const char *); 208842565f2Syasuoka static const char 209842565f2Syasuoka *radius_tunnel_type_string(unsigned, const char *); 210842565f2Syasuoka static const char 211842565f2Syasuoka *radius_terminate_cause_string(unsigned); 212842565f2Syasuoka static const char 213842565f2Syasuoka *radius_error_cause_string(unsigned); 214842565f2Syasuoka static int parse_addr(const char *, int, struct sockaddr *, socklen_t); 215842565f2Syasuoka static const char 216842565f2Syasuoka *print_addr(struct sockaddr *, char *, size_t); 217842565f2Syasuoka 218842565f2Syasuoka RB_PROTOTYPE_STATIC(assigned_ipv4_tree, assigned_ipv4, tree, 219842565f2Syasuoka assigned_ipv4_compar); 220842565f2Syasuoka RB_PROTOTYPE_STATIC(user_tree, user, tree, user_compar); 221842565f2Syasuoka 222842565f2Syasuoka int 223842565f2Syasuoka main(int argc, char *argv[]) 224842565f2Syasuoka { 225842565f2Syasuoka struct module_ipcp module_ipcp; 226842565f2Syasuoka struct module_handlers handlers = { 227842565f2Syasuoka .start = ipcp_start, 228842565f2Syasuoka .stop = ipcp_stop, 229842565f2Syasuoka .config_set = ipcp_config_set, 230842565f2Syasuoka .response_decoration = ipcp_resdeco, 231842565f2Syasuoka .accounting_request = ipcp_accounting_request, 232842565f2Syasuoka .dispatch_control = ipcp_dispatch_control 233842565f2Syasuoka }; 234842565f2Syasuoka 235842565f2Syasuoka ipcp_init(&module_ipcp); 236842565f2Syasuoka 237842565f2Syasuoka if ((module_ipcp.base = module_create(STDIN_FILENO, &module_ipcp, 238842565f2Syasuoka &handlers)) == NULL) 239842565f2Syasuoka err(1, "Could not create a module instance"); 240842565f2Syasuoka 241842565f2Syasuoka if (ipcp_prepare_db() == -1) 242842565f2Syasuoka err(1, "ipcp_prepare_db"); 243842565f2Syasuoka 244842565f2Syasuoka module_drop_privilege(module_ipcp.base, 1); 245842565f2Syasuoka if (unveil(_PATH_RADIUSD_IPCP_DB, "rw") == -1) 246842565f2Syasuoka err(1, "unveil"); 247842565f2Syasuoka if (pledge("stdio inet rpath wpath flock", NULL) == -1) 248842565f2Syasuoka err(1, "pledge"); 249842565f2Syasuoka setproctitle("[main]"); 250842565f2Syasuoka 251842565f2Syasuoka module_load(module_ipcp.base); 252842565f2Syasuoka log_init(0); 253842565f2Syasuoka event_init(); 254842565f2Syasuoka 255842565f2Syasuoka module_start(module_ipcp.base); 256842565f2Syasuoka event_loop(0); 257842565f2Syasuoka 258842565f2Syasuoka ipcp_fini(&module_ipcp); 259842565f2Syasuoka 260842565f2Syasuoka event_loop(0); 261c0c32a87Syasuoka event_base_free(NULL); 262842565f2Syasuoka 263842565f2Syasuoka exit(EXIT_SUCCESS); 264842565f2Syasuoka } 265842565f2Syasuoka 266842565f2Syasuoka void 267842565f2Syasuoka ipcp_init(struct module_ipcp *self) 268842565f2Syasuoka { 269842565f2Syasuoka memset(self, 0, sizeof(struct module_ipcp)); 270842565f2Syasuoka TAILQ_INIT(&self->addrs); 271842565f2Syasuoka RB_INIT(&self->ipv4s); 272842565f2Syasuoka RB_INIT(&self->users); 273842565f2Syasuoka TAILQ_INIT(&self->ctrls); 274842565f2Syasuoka TAILQ_INIT(&self->daes); 275842565f2Syasuoka self->seq = 1; 276842565f2Syasuoka self->no_session_timeout = true; 277e1af567eSyasuoka ipcp_update_time(self); 278842565f2Syasuoka } 279842565f2Syasuoka 280842565f2Syasuoka void 281842565f2Syasuoka ipcp_start(void *ctx) 282842565f2Syasuoka { 283842565f2Syasuoka struct module_ipcp *self = ctx; 284842565f2Syasuoka struct ipcp_address *addr; 285842565f2Syasuoka struct module_ipcp_dae *dae; 286842565f2Syasuoka int sock; 287842565f2Syasuoka 288e1af567eSyasuoka ipcp_update_time(self); 289842565f2Syasuoka if (self->start_wait == 0) 290842565f2Syasuoka self->start_wait = RADIUSD_IPCP_START_WAIT; 291842565f2Syasuoka 292842565f2Syasuoka /* count pool address*/ 293842565f2Syasuoka TAILQ_FOREACH(addr, &self->addrs, next) { 294842565f2Syasuoka if (addr->type == ADDRESS_TYPE_POOL) 295842565f2Syasuoka self->npools += addr->naddrs; 296842565f2Syasuoka } 297842565f2Syasuoka log_info("number of pooled IP addresses = %d", self->npools); 298842565f2Syasuoka 299842565f2Syasuoka if (ipcp_restore_from_db(self) == -1) { 300842565f2Syasuoka module_send_message(self->base, IMSG_NG, 301842565f2Syasuoka "Restoring the database failed: %s", strerror(errno)); 302842565f2Syasuoka module_stop(self->base); 303842565f2Syasuoka return; 304842565f2Syasuoka } 305842565f2Syasuoka ipcp_schedule_timer(self); 306842565f2Syasuoka 307842565f2Syasuoka /* prepare socket for DAE */ 308842565f2Syasuoka TAILQ_FOREACH(dae, &self->daes, next) { 309842565f2Syasuoka if ((sock = socket(dae->nas_addr.sin4.sin_family, 310842565f2Syasuoka SOCK_DGRAM, IPPROTO_UDP)) == -1) { 3114946f694Syasuoka log_warn("%s: could not start dae: socket()", __func__); 312842565f2Syasuoka return; 313842565f2Syasuoka } 314842565f2Syasuoka if (connect(sock, (struct sockaddr *)&dae->nas_addr, 315842565f2Syasuoka dae->nas_addr.sin4.sin_len) == -1) { 3164946f694Syasuoka log_warn("%s: could not start dae: connect()", 3174946f694Syasuoka __func__); 318842565f2Syasuoka return; 319842565f2Syasuoka } 320842565f2Syasuoka dae->sock = sock; 321842565f2Syasuoka event_set(&dae->ev_sock, sock, EV_READ | EV_PERSIST, 322842565f2Syasuoka ipcp_dae_on_event, dae); 323842565f2Syasuoka event_add(&dae->ev_sock, NULL); 324cfa11a85Syasuoka evtimer_set(&dae->ev_reqs, ipcp_dae_send_pending_requests, dae); 325842565f2Syasuoka } 326842565f2Syasuoka 327842565f2Syasuoka module_send_message(self->base, IMSG_OK, NULL); 328842565f2Syasuoka } 329842565f2Syasuoka 330842565f2Syasuoka void 331842565f2Syasuoka ipcp_stop(void *ctx) 332842565f2Syasuoka { 333842565f2Syasuoka struct module_ipcp *self = ctx; 334842565f2Syasuoka struct module_ipcp_dae *dae; 335842565f2Syasuoka 336e1af567eSyasuoka ipcp_update_time(self); 337842565f2Syasuoka /* stop the sockets for DAE */ 338842565f2Syasuoka TAILQ_FOREACH(dae, &self->daes, next) { 339842565f2Syasuoka if (dae->sock >= 0) { 340842565f2Syasuoka event_del(&dae->ev_sock); 341842565f2Syasuoka close(dae->sock); 342842565f2Syasuoka dae->sock = -1; 343842565f2Syasuoka } 344cfa11a85Syasuoka if (evtimer_pending(&dae->ev_reqs, NULL)) 345cfa11a85Syasuoka event_del(&dae->ev_reqs); 346842565f2Syasuoka } 347842565f2Syasuoka if (evtimer_pending(&self->ev_timer, NULL)) 348842565f2Syasuoka evtimer_del(&self->ev_timer); 349842565f2Syasuoka } 350842565f2Syasuoka 351842565f2Syasuoka void 352842565f2Syasuoka ipcp_fini(struct module_ipcp *self) 353842565f2Syasuoka { 354842565f2Syasuoka struct assigned_ipv4 *assign, *assignt; 355842565f2Syasuoka struct user *user, *usert; 356842565f2Syasuoka struct module_ipcp_ctrlconn *ctrl, *ctrlt; 357842565f2Syasuoka struct module_ipcp_dae *dae, *daet; 358c0c32a87Syasuoka struct ipcp_address *addr, *addrt; 359842565f2Syasuoka 360842565f2Syasuoka RB_FOREACH_SAFE(assign, assigned_ipv4_tree, &self->ipv4s, assignt) 361842565f2Syasuoka ipcp_ipv4_release(self, assign); 362c0c32a87Syasuoka RB_FOREACH_SAFE(user, user_tree, &self->users, usert) { 363c0c32a87Syasuoka RB_REMOVE(user_tree, &self->users, user); 364842565f2Syasuoka free(user); 365c0c32a87Syasuoka } 366842565f2Syasuoka TAILQ_FOREACH_SAFE(ctrl, &self->ctrls, next, ctrlt) 367842565f2Syasuoka free(ctrl); 368842565f2Syasuoka TAILQ_FOREACH_SAFE(dae, &self->daes, next, daet) { 369842565f2Syasuoka if (dae->sock >= 0) { 370842565f2Syasuoka event_del(&dae->ev_sock); 371842565f2Syasuoka close(dae->sock); 372842565f2Syasuoka } 373842565f2Syasuoka free(dae); 374842565f2Syasuoka } 375c0c32a87Syasuoka TAILQ_FOREACH_SAFE(addr, &self->addrs, next, addrt) 376c0c32a87Syasuoka free(addr); 377842565f2Syasuoka if (evtimer_pending(&self->ev_timer, NULL)) 378842565f2Syasuoka evtimer_del(&self->ev_timer); 379842565f2Syasuoka module_destroy(self->base); 380842565f2Syasuoka } 381842565f2Syasuoka 382842565f2Syasuoka void 383842565f2Syasuoka ipcp_config_set(void *ctx, const char *name, int argc, char * const * argv) 384842565f2Syasuoka { 385842565f2Syasuoka struct module_ipcp *module = ctx; 386842565f2Syasuoka const char *errmsg = "none"; 387842565f2Syasuoka int i; 388842565f2Syasuoka struct ipcp_address *addr; 389842565f2Syasuoka struct in_addr ina; 390842565f2Syasuoka struct module_ipcp_dae dae, *dae0; 391842565f2Syasuoka 392842565f2Syasuoka if (strcmp(name, "address") == 0) { 393842565f2Syasuoka SYNTAX_ASSERT(argc >= 1, 394842565f2Syasuoka "specify one of pool, server, nas-select, or user-select"); 395842565f2Syasuoka if (strcmp(argv[0], "pool") == 0) { 396842565f2Syasuoka SYNTAX_ASSERT(argc >= 2, 397842565f2Syasuoka "`address pool' must have one address range at " 398842565f2Syasuoka "least"); 399842565f2Syasuoka addr = TAILQ_FIRST(&module->addrs); 400842565f2Syasuoka for (i = 0; i < argc - 1; i++) { 401842565f2Syasuoka if ((addr = parse_address_range(argv[i + 1])) 402842565f2Syasuoka == NULL) { 403842565f2Syasuoka module_send_message(module->base, 404842565f2Syasuoka IMSG_NG, "Invalid address range: " 405842565f2Syasuoka "%s", argv[i + 1]); 406842565f2Syasuoka return; 407842565f2Syasuoka } 408842565f2Syasuoka addr->type = ADDRESS_TYPE_POOL; 409842565f2Syasuoka TAILQ_INSERT_TAIL(&module->addrs, addr, next); 410842565f2Syasuoka } 411842565f2Syasuoka } else if (strcmp(argv[0], "static") == 0) { 412842565f2Syasuoka SYNTAX_ASSERT(argc >= 2, 413842565f2Syasuoka "`address static' must have one address range at " 414842565f2Syasuoka "least"); 415842565f2Syasuoka addr = TAILQ_FIRST(&module->addrs); 416842565f2Syasuoka for (i = 0; i < argc - 1; i++) { 417842565f2Syasuoka if ((addr = parse_address_range(argv[i + 1])) 418842565f2Syasuoka == NULL) { 419842565f2Syasuoka module_send_message(module->base, 420842565f2Syasuoka IMSG_NG, "Invalid address range: " 421842565f2Syasuoka "%s", argv[i + 1]); 422842565f2Syasuoka return; 423842565f2Syasuoka } 424842565f2Syasuoka addr->type = ADDRESS_TYPE_STATIC; 425842565f2Syasuoka TAILQ_INSERT_TAIL(&module->addrs, addr, next); 426842565f2Syasuoka } 427842565f2Syasuoka } else 428842565f2Syasuoka SYNTAX_ASSERT(0, "specify pool or static"); 429842565f2Syasuoka } else if (strcmp(name, "max-sessions") == 0) { 430842565f2Syasuoka SYNTAX_ASSERT(argc == 1, 431842565f2Syasuoka "`max-sessions' must have an argument"); 432842565f2Syasuoka module->max_sessions = strtonum(argv[0], 0, INT_MAX, &errmsg); 433842565f2Syasuoka if (errmsg != NULL) { 434842565f2Syasuoka module_send_message(module->base, IMSG_NG, 435842565f2Syasuoka "could not parse `max-sessions': %s", errmsg); 436842565f2Syasuoka return; 437842565f2Syasuoka } 438842565f2Syasuoka } else if (strcmp(name, "user-max-sessions") == 0) { 439842565f2Syasuoka SYNTAX_ASSERT(argc == 1, "`max-session' must have an argument"); 440842565f2Syasuoka module->user_max_sessions = strtonum(argv[0], 0, INT_MAX, 441842565f2Syasuoka &errmsg); 442842565f2Syasuoka if (errmsg != NULL) { 443842565f2Syasuoka module_send_message(module->base, IMSG_NG, 444842565f2Syasuoka "could not parse `user-max-session': %s", errmsg); 445842565f2Syasuoka return; 446842565f2Syasuoka } 447842565f2Syasuoka } else if (strcmp(name, "start-wait") == 0) { 448842565f2Syasuoka SYNTAX_ASSERT(argc == 1, "`start-wait' must have an argument"); 449842565f2Syasuoka module->start_wait = strtonum(argv[0], 1, INT_MAX, &errmsg); 450842565f2Syasuoka if (errmsg != NULL) { 451842565f2Syasuoka module_send_message(module->base, IMSG_NG, 452842565f2Syasuoka "could not parse `start-wait': %s", errmsg); 453842565f2Syasuoka return; 454842565f2Syasuoka } 455842565f2Syasuoka } else if (strcmp(name, "name-server") == 0) { 456842565f2Syasuoka SYNTAX_ASSERT(argc == 1 || argc == 2, 457842565f2Syasuoka "specify 1 or 2 addresses for `name-server'"); 458842565f2Syasuoka for (i = 0; i < argc; i++) { 45984b182f8Sflorian if (inet_pton(AF_INET, argv[i], &ina) != 1) { 460842565f2Syasuoka module_send_message(module->base, IMSG_NG, 461842565f2Syasuoka "Invalid IP address: %s", argv[i]); 462842565f2Syasuoka return; 463842565f2Syasuoka } 464842565f2Syasuoka if (module->name_server[0].s_addr == 0) 465842565f2Syasuoka module->name_server[0] = ina; 466842565f2Syasuoka else if (module->name_server[1].s_addr == 0) 467842565f2Syasuoka module->name_server[1] = ina; 468842565f2Syasuoka else 469842565f2Syasuoka SYNTAX_ASSERT(0, 470842565f2Syasuoka "too many `name-server' is configured"); 471842565f2Syasuoka } 472842565f2Syasuoka } else if (strcmp(name, "netbios-server") == 0) { 473842565f2Syasuoka SYNTAX_ASSERT(argc == 1 || argc == 2, 474842565f2Syasuoka "specify 1 or 2 addresses for `name-server'"); 475842565f2Syasuoka for (i = 0; i < argc; i++) { 47684b182f8Sflorian if (inet_pton(AF_INET, argv[i], &ina) != 1) { 477842565f2Syasuoka module_send_message(module->base, IMSG_NG, 478842565f2Syasuoka "Invalid IP address: %s", argv[i]); 479842565f2Syasuoka return; 480842565f2Syasuoka } 481842565f2Syasuoka if (module->netbios_server[0].s_addr == 0) 482842565f2Syasuoka module->netbios_server[0] = ina; 483842565f2Syasuoka else if (module->netbios_server[1].s_addr == 0) 484842565f2Syasuoka module->netbios_server[1] = ina; 485842565f2Syasuoka else 486842565f2Syasuoka SYNTAX_ASSERT(0, 487842565f2Syasuoka "too many `name-server' is configured"); 488842565f2Syasuoka } 489842565f2Syasuoka } else if (strcmp(name, "session-timeout") == 0) { 490842565f2Syasuoka SYNTAX_ASSERT(argc == 1, 491842565f2Syasuoka "`session-timeout' must have an argument"); 492842565f2Syasuoka if (strcmp(argv[0], "radius") == 0) { 493842565f2Syasuoka module->no_session_timeout = false; 494842565f2Syasuoka module->session_timeout = 0; 495842565f2Syasuoka } else { 496842565f2Syasuoka module->no_session_timeout = false; 497842565f2Syasuoka module->session_timeout = strtonum(argv[0], 1, INT_MAX, 498842565f2Syasuoka &errmsg); 499842565f2Syasuoka if (errmsg != NULL) { 500842565f2Syasuoka module_send_message(module->base, IMSG_NG, 501842565f2Syasuoka "could not parse `session-timeout': %s", 502842565f2Syasuoka errmsg); 503842565f2Syasuoka return; 504842565f2Syasuoka } 505842565f2Syasuoka } 506842565f2Syasuoka } else if (strcmp(name, "dae") == 0) { 50732ed9376Syasuoka memset(&dae, 0, sizeof(dae)); 50832ed9376Syasuoka dae.sock = -1; 509842565f2Syasuoka if (!(argc >= 1 || strcmp(argv[1], "server") == 0)) { 510842565f2Syasuoka module_send_message(module->base, IMSG_NG, 511842565f2Syasuoka "`%s' is unknown", argv[1]); 512842565f2Syasuoka return; 513842565f2Syasuoka } 514842565f2Syasuoka i = 1; 515842565f2Syasuoka SYNTAX_ASSERT(i < argc, "no address[:port] for dae server"); 516842565f2Syasuoka if (i < argc && 517842565f2Syasuoka parse_addr(argv[i], AF_UNSPEC, (struct sockaddr *) 518842565f2Syasuoka &dae.nas_addr, sizeof(dae.nas_addr)) == -1) { 519842565f2Syasuoka module_send_message(module->base, IMSG_NG, 520842565f2Syasuoka "failed to parse dae server's address, %s", 521842565f2Syasuoka argv[i]); 522842565f2Syasuoka return; 523842565f2Syasuoka } 524842565f2Syasuoka if (ntohs(dae.nas_addr.sin4.sin_port) == 0) 525842565f2Syasuoka dae.nas_addr.sin4.sin_port = 526842565f2Syasuoka htons(RADIUS_DAE_DEFAULT_PORT); 527842565f2Syasuoka i++; 528842565f2Syasuoka SYNTAX_ASSERT(i < argc, "no secret for dae server"); 529842565f2Syasuoka if (strlcpy(dae.secret, argv[i++], sizeof(dae.secret)) >= 530842565f2Syasuoka sizeof(dae.secret)) { 531842565f2Syasuoka module_send_message(module->base, IMSG_NG, 532842565f2Syasuoka "dae server's secret must be < %d bytes", 533842565f2Syasuoka (int)sizeof(dae.secret) - 1); 534842565f2Syasuoka return; 535842565f2Syasuoka } 536842565f2Syasuoka if (i < argc) 537842565f2Syasuoka strlcpy(dae.nas_id, argv[i++], sizeof(dae.nas_id)); 538842565f2Syasuoka if ((dae0 = calloc(1, sizeof(struct module_ipcp_dae))) == NULL) 539842565f2Syasuoka { 540842565f2Syasuoka module_send_message(module->base, IMSG_NG, 541842565f2Syasuoka "%s", strerror(errno)); 542842565f2Syasuoka return; 543842565f2Syasuoka } 544842565f2Syasuoka *dae0 = dae; 545842565f2Syasuoka TAILQ_INIT(&dae0->reqs); 546842565f2Syasuoka TAILQ_INSERT_TAIL(&module->daes, dae0, next); 547c0127aecSyasuoka dae0->ipcp = module; 548842565f2Syasuoka } else if (strcmp(name, "_debug") == 0) 549842565f2Syasuoka log_init(1); 550842565f2Syasuoka else if (strncmp(name, "_", 1) == 0) 551842565f2Syasuoka /* ignore */; 552842565f2Syasuoka else { 553842565f2Syasuoka module_send_message(module->base, IMSG_NG, 554842565f2Syasuoka "Unknown config parameter name `%s'", name); 555842565f2Syasuoka return; 556842565f2Syasuoka } 557842565f2Syasuoka module_send_message(module->base, IMSG_OK, NULL); 558842565f2Syasuoka 559842565f2Syasuoka return; 560842565f2Syasuoka syntax_error: 561842565f2Syasuoka module_send_message(module->base, IMSG_NG, "%s", errmsg); 562842565f2Syasuoka } 563842565f2Syasuoka 564842565f2Syasuoka void 565842565f2Syasuoka ipcp_dispatch_control(void *ctx, struct imsg *imsg) 566842565f2Syasuoka { 567842565f2Syasuoka struct module_ipcp *self = ctx; 568842565f2Syasuoka struct assigned_ipv4 *assign; 569842565f2Syasuoka struct radiusd_ipcp_db_dump *dump; 570842565f2Syasuoka struct module_ipcp_ctrlconn *ctrl, *ctrlt; 571842565f2Syasuoka int i; 572842565f2Syasuoka size_t dumpsiz; 573842565f2Syasuoka u_int datalen; 574842565f2Syasuoka unsigned seq; 575c0127aecSyasuoka struct radiusctl_client *client; 576c0127aecSyasuoka const char *cause; 577842565f2Syasuoka 578e1af567eSyasuoka ipcp_update_time(self); 579842565f2Syasuoka datalen = imsg->hdr.len - IMSG_HEADER_SIZE; 580842565f2Syasuoka switch (imsg->hdr.type) { 581842565f2Syasuoka case IMSG_RADIUSD_MODULE_CTRL_UNBIND: 582842565f2Syasuoka TAILQ_FOREACH_SAFE(ctrl, &self->ctrls, next, ctrlt) { 583842565f2Syasuoka if (ctrl->peerid == imsg->hdr.peerid) { 584842565f2Syasuoka TAILQ_REMOVE(&self->ctrls, ctrl, next); 585842565f2Syasuoka free(ctrl); 586842565f2Syasuoka break; 587842565f2Syasuoka } 588842565f2Syasuoka } 589842565f2Syasuoka break; 590842565f2Syasuoka case IMSG_RADIUSD_MODULE_IPCP_MONITOR: 591842565f2Syasuoka case IMSG_RADIUSD_MODULE_IPCP_DUMP_AND_MONITOR: 592842565f2Syasuoka if ((ctrl = calloc(1, sizeof(struct module_ipcp_ctrlconn))) 593842565f2Syasuoka == NULL) { 594842565f2Syasuoka log_warn("%s: calloc()", __func__); 595842565f2Syasuoka goto fail; 596842565f2Syasuoka } 597842565f2Syasuoka ctrl->peerid = imsg->hdr.peerid; 598842565f2Syasuoka TAILQ_INSERT_TAIL(&self->ctrls, ctrl, next); 599842565f2Syasuoka module_imsg_compose(self->base, IMSG_RADIUSD_MODULE_CTRL_BIND, 600842565f2Syasuoka imsg->hdr.peerid, 0, -1, NULL, 0); 601842565f2Syasuoka if (imsg->hdr.type == IMSG_RADIUSD_MODULE_IPCP_MONITOR) 602842565f2Syasuoka break; 6037f966493Sjsg /* FALLTHROUGH */ 604842565f2Syasuoka case IMSG_RADIUSD_MODULE_IPCP_DUMP: 605842565f2Syasuoka dumpsiz = MAX_IMSGSIZE; 606842565f2Syasuoka if ((dump = calloc(1, dumpsiz)) == NULL) { 607842565f2Syasuoka log_warn("%s: calloc()", __func__); 608842565f2Syasuoka goto fail; 609842565f2Syasuoka } 610842565f2Syasuoka i = 0; 611842565f2Syasuoka RB_FOREACH(assign, assigned_ipv4_tree, &self->ipv4s) { 612842565f2Syasuoka if (!timespecisset(&assign->start)) 613842565f2Syasuoka /* not started yet */ 614842565f2Syasuoka continue; 615842565f2Syasuoka ipcp_db_dump_fill_record(dump, i++, assign); 616842565f2Syasuoka if (RB_NEXT(assigned_ipv4_tree, &self->ipv4s, assign) 617842565f2Syasuoka == NULL) 618842565f2Syasuoka break; 619842565f2Syasuoka if (offsetof(struct radiusd_ipcp_db_dump, 620842565f2Syasuoka records[i + 1]) >= dumpsiz) { 621842565f2Syasuoka module_imsg_compose(self->base, 622842565f2Syasuoka IMSG_RADIUSD_MODULE_IPCP_DUMP, 623842565f2Syasuoka imsg->hdr.peerid, 0, -1, 624842565f2Syasuoka dump, offsetof(struct radiusd_ipcp_db_dump, 625842565f2Syasuoka records[i])); 626842565f2Syasuoka i = 0; 627842565f2Syasuoka } 628842565f2Syasuoka } 629842565f2Syasuoka dump->islast = 1; 630842565f2Syasuoka module_imsg_compose(self->base, IMSG_RADIUSD_MODULE_IPCP_DUMP, 631842565f2Syasuoka imsg->hdr.peerid, 0, -1, dump, offsetof( 632842565f2Syasuoka struct radiusd_ipcp_db_dump, records[i])); 633842565f2Syasuoka freezero(dump ,dumpsiz); 634842565f2Syasuoka break; 635842565f2Syasuoka case IMSG_RADIUSD_MODULE_IPCP_DISCONNECT: 636eff8f878Syasuoka case IMSG_RADIUSD_MODULE_IPCP_DELETE: 637842565f2Syasuoka if (datalen < sizeof(unsigned)) { 638842565f2Syasuoka log_warn("%s: received " 639eff8f878Syasuoka "%s message size is wrong", __func__, 640eff8f878Syasuoka (imsg->hdr.type == 641eff8f878Syasuoka IMSG_RADIUSD_MODULE_IPCP_DISCONNECT) 642eff8f878Syasuoka ? "IMSG_RADIUSD_MODULE_IPCP_DISCONNECT" 643eff8f878Syasuoka : "IMSG_RADIUSD_MODULE_IPCP_DELETE"); 644842565f2Syasuoka goto fail; 645842565f2Syasuoka } 646842565f2Syasuoka seq = *(unsigned *)imsg->data; 647842565f2Syasuoka RB_FOREACH(assign, assigned_ipv4_tree, &self->ipv4s) { 648842565f2Syasuoka if (!timespecisset(&assign->start)) 649842565f2Syasuoka /* not started yet */ 650842565f2Syasuoka continue; 651842565f2Syasuoka if (assign->seq == seq) 652842565f2Syasuoka break; 653842565f2Syasuoka } 654c0127aecSyasuoka if (assign == NULL) { 655c0127aecSyasuoka cause = "session not found"; 656eff8f878Syasuoka log_warnx("%s seq=%u requested, but the " 657eff8f878Syasuoka "session is not found", 658eff8f878Syasuoka (imsg->hdr.type == 659eff8f878Syasuoka IMSG_RADIUSD_MODULE_IPCP_DISCONNECT)? "Disconnect" 660eff8f878Syasuoka : "Delete", seq); 661c0127aecSyasuoka module_imsg_compose(self->base, IMSG_NG, 662c0127aecSyasuoka imsg->hdr.peerid, 0, -1, cause, strlen(cause) + 1); 663eff8f878Syasuoka } else if (imsg->hdr.type == IMSG_RADIUSD_MODULE_IPCP_DELETE) { 664eff8f878Syasuoka log_info("Delete seq=%u by request", assign->seq); 665eff8f878Syasuoka ipcp_ipv4_delete(self, assign, "By control"); 666eff8f878Syasuoka module_imsg_compose(self->base, IMSG_OK, 667eff8f878Syasuoka imsg->hdr.peerid, 0, -1, NULL, 0); 668eff8f878Syasuoka } else { 669842565f2Syasuoka if (assign->dae == NULL) 670842565f2Syasuoka log_warnx("Disconnect seq=%u requested, but " 671842565f2Syasuoka "DAE is not configured", assign->seq); 672842565f2Syasuoka else { 673003dbb67Syasuoka log_info("Disconnect seq=%u requested", 674842565f2Syasuoka assign->seq); 675c0127aecSyasuoka if ((client = calloc(1, sizeof(struct 676c0127aecSyasuoka radiusctl_client))) == NULL) { 677c0127aecSyasuoka log_warn("%s: calloc: %m", 678c0127aecSyasuoka __func__); 679c0127aecSyasuoka goto fail; 680c0127aecSyasuoka } 681c0127aecSyasuoka client->peerid = imsg->hdr.peerid; 6822617e43bSyasuoka if (assign->dae_ntry == 0) 6832617e43bSyasuoka ipcp_dae_send_disconnect_request( 6842617e43bSyasuoka assign); 685c0127aecSyasuoka TAILQ_INSERT_TAIL(&assign->dae_clients, 686c0127aecSyasuoka client, entry); 687842565f2Syasuoka } 688842565f2Syasuoka } 689842565f2Syasuoka break; 690842565f2Syasuoka } 691842565f2Syasuoka return; 692842565f2Syasuoka fail: 693842565f2Syasuoka module_stop(self->base); 694842565f2Syasuoka } 695842565f2Syasuoka 696842565f2Syasuoka int 697842565f2Syasuoka ipcp_notice_startstop(struct module_ipcp *self, struct assigned_ipv4 *assign, 698842565f2Syasuoka int start, struct radiusd_ipcp_statistics *stat) 699842565f2Syasuoka { 700842565f2Syasuoka struct module_ipcp_ctrlconn *ctrl; 701842565f2Syasuoka struct radiusd_ipcp_db_dump *dump; 702842565f2Syasuoka size_t dumpsiz; 703842565f2Syasuoka struct iovec iov[2]; 704842565f2Syasuoka int niov = 0; 705842565f2Syasuoka 706842565f2Syasuoka dumpsiz = offsetof(struct radiusd_ipcp_db_dump, records[1]); 707842565f2Syasuoka if ((dump = calloc(1, dumpsiz)) == NULL) { 708842565f2Syasuoka log_warn("%s: calloc()", __func__); 709842565f2Syasuoka return (-1); 710842565f2Syasuoka } 711842565f2Syasuoka dump->islast = 1; 712842565f2Syasuoka ipcp_db_dump_fill_record(dump, 0, assign); 713842565f2Syasuoka 714842565f2Syasuoka iov[niov].iov_base = dump; 715842565f2Syasuoka iov[niov].iov_len = dumpsiz; 716842565f2Syasuoka if (start == 0) { 717842565f2Syasuoka iov[++niov].iov_base = stat; 718842565f2Syasuoka iov[niov].iov_len = sizeof(struct radiusd_ipcp_statistics); 719842565f2Syasuoka } 720842565f2Syasuoka TAILQ_FOREACH(ctrl, &self->ctrls, next) 721842565f2Syasuoka module_imsg_composev(self->base, 722842565f2Syasuoka (start)? IMSG_RADIUSD_MODULE_IPCP_START : 723842565f2Syasuoka IMSG_RADIUSD_MODULE_IPCP_STOP, ctrl->peerid, 0, -1, iov, 724842565f2Syasuoka niov + 1); 725842565f2Syasuoka freezero(dump, dumpsiz); 726842565f2Syasuoka return (0); 727842565f2Syasuoka } 728842565f2Syasuoka 729842565f2Syasuoka void 730842565f2Syasuoka ipcp_resdeco(void *ctx, u_int q_id, const u_char *req, size_t reqlen, 731842565f2Syasuoka const u_char *res, size_t reslen) 732842565f2Syasuoka { 733842565f2Syasuoka struct module_ipcp *self = ctx; 734842565f2Syasuoka RADIUS_PACKET *radres = NULL, *radreq = NULL; 735842565f2Syasuoka struct in_addr addr4; 736842565f2Syasuoka const struct in_addr mask4 = { .s_addr = 0xffffffffUL }; 737842565f2Syasuoka int res_code, msraserr = 935; 738842565f2Syasuoka struct ipcp_address *addr; 7391669612dSyasuoka int i, n; 740842565f2Syasuoka bool found = false; 741842565f2Syasuoka char username[256], buf[128]; 742842565f2Syasuoka struct user *user = NULL; 743842565f2Syasuoka struct assigned_ipv4 *assigned = NULL, *assign; 744842565f2Syasuoka 745e1af567eSyasuoka ipcp_update_time(self); 746842565f2Syasuoka 747842565f2Syasuoka if ((radres = radius_convert_packet(res, reslen)) == NULL) { 748842565f2Syasuoka log_warn("%s: radius_convert_packet() failed", __func__); 749842565f2Syasuoka goto fatal; 750842565f2Syasuoka } 751842565f2Syasuoka res_code = radius_get_code(radres); 752842565f2Syasuoka if (res_code != RADIUS_CODE_ACCESS_ACCEPT) 753842565f2Syasuoka goto accept; 754842565f2Syasuoka 755842565f2Syasuoka if ((radreq = radius_convert_packet(req, reqlen)) == NULL) { 756842565f2Syasuoka log_warn("%s: radius_convert_packet() failed", __func__); 757842565f2Syasuoka goto fatal; 758842565f2Syasuoka } 759842565f2Syasuoka 760842565f2Syasuoka /* 761842565f2Syasuoka * prefer User-Name of the response rather than the request, 762842565f2Syasuoka * since it must be the authenticated user. 763842565f2Syasuoka */ 764842565f2Syasuoka if (radius_get_string_attr(radres, RADIUS_TYPE_USER_NAME, username, 765842565f2Syasuoka sizeof(username)) != 0 && 766842565f2Syasuoka radius_get_string_attr(radreq, RADIUS_TYPE_USER_NAME, username, 767842565f2Syasuoka sizeof(username)) != 0) { 768842565f2Syasuoka log_warnx("q=%u unexpected request: no user-name", q_id); 769842565f2Syasuoka goto fatal; 770842565f2Syasuoka } 771842565f2Syasuoka 772842565f2Syasuoka if ((addr = TAILQ_FIRST(&self->addrs)) != NULL) { 773842565f2Syasuoka /* The address assignment is configured */ 774842565f2Syasuoka 775842565f2Syasuoka if ((user = ipcp_user_get(self, username)) == NULL) { 776842565f2Syasuoka log_warn("%s: ipcp_user_get()", __func__); 777842565f2Syasuoka goto fatal; 778842565f2Syasuoka } 779842565f2Syasuoka 780842565f2Syasuoka msraserr = 935; 781842565f2Syasuoka if (self->max_sessions != 0) { 782842565f2Syasuoka if (self->nsessions >= self->max_sessions) { 7837af3c895Syasuoka log_info("q=%u user=%s rejected: number of " 784842565f2Syasuoka "sessions reached the limit(%d)", q_id, 7857af3c895Syasuoka user->name, self->max_sessions); 786842565f2Syasuoka goto reject; 787842565f2Syasuoka } 788842565f2Syasuoka } 789842565f2Syasuoka if (self->user_max_sessions != 0) { 790842565f2Syasuoka n = 0; 791842565f2Syasuoka TAILQ_FOREACH(assign, &user->ipv4s, next) 792842565f2Syasuoka n++; 793842565f2Syasuoka if (n >= self->user_max_sessions) { 7947af3c895Syasuoka log_info("q=%u user=%s rejected: number of " 795842565f2Syasuoka "sessions per a user reached the limit(%d)", 7967af3c895Syasuoka q_id, user->name, self->user_max_sessions); 797842565f2Syasuoka goto reject; 798842565f2Syasuoka } 799842565f2Syasuoka } 800842565f2Syasuoka 801842565f2Syasuoka msraserr = 716; 802842565f2Syasuoka if (radius_get_ipv4_attr(radres, 803842565f2Syasuoka RADIUS_TYPE_FRAMED_IP_ADDRESS, &addr4) == 0) { 804842565f2Syasuoka if (ipcp_ipv4_find(self, addr4) != NULL) 8057af3c895Syasuoka log_info("q=%u user=%s rejected: server " 8067af3c895Syasuoka "requested IP address is busy", q_id, 8077af3c895Syasuoka user->name); 808842565f2Syasuoka else { 809842565f2Syasuoka /* compare in host byte order */ 810842565f2Syasuoka addr4.s_addr = ntohl(addr4.s_addr); 811842565f2Syasuoka TAILQ_FOREACH(addr, &self->addrs, next) { 812842565f2Syasuoka if (addr->type != ADDRESS_TYPE_STATIC && 813842565f2Syasuoka addr->type != ADDRESS_TYPE_POOL) 814842565f2Syasuoka continue; 815842565f2Syasuoka if (addr->start.s_addr <= addr4.s_addr 816842565f2Syasuoka && addr4.s_addr <= addr->end.s_addr) 817842565f2Syasuoka break; 818842565f2Syasuoka } 819842565f2Syasuoka if (addr == NULL) 8207af3c895Syasuoka log_info("q=%u user=%s rejected: " 8217af3c895Syasuoka "server requested IP address is " 8227af3c895Syasuoka "out of the range", q_id, 8237af3c895Syasuoka user->name); 824842565f2Syasuoka else 825842565f2Syasuoka found = true; 826842565f2Syasuoka /* revert the addr to the network byte order */ 827842565f2Syasuoka addr4.s_addr = htonl(addr4.s_addr); 828842565f2Syasuoka } 829842565f2Syasuoka if (!found) 830842565f2Syasuoka goto reject; 831842565f2Syasuoka } else { 832266241f9Syasuoka int inpool_idx = 0; 833266241f9Syasuoka 834266241f9Syasuoka /* select a random address */ 83577474275Syasuoka n = arc4random_uniform(self->npools); 836842565f2Syasuoka i = 0; 837842565f2Syasuoka TAILQ_FOREACH(addr, &self->addrs, next) { 838842565f2Syasuoka if (addr->type == ADDRESS_TYPE_POOL) { 839842565f2Syasuoka if (i <= n && n < i + addr->naddrs) { 840266241f9Syasuoka inpool_idx = n - i; 841842565f2Syasuoka break; 842842565f2Syasuoka } 843842565f2Syasuoka i += addr->naddrs; 844842565f2Syasuoka } 845842565f2Syasuoka } 846266241f9Syasuoka /* loop npools times until a free address is found */ 847266241f9Syasuoka for (i = 0; i < self->npools && addr != NULL; i++) { 848266241f9Syasuoka addr4.s_addr = htonl( 849266241f9Syasuoka addr->start.s_addr + inpool_idx); 850842565f2Syasuoka if (ipcp_ipv4_find(self, addr4) == NULL) { 851842565f2Syasuoka found = true; 852842565f2Syasuoka break; 853842565f2Syasuoka } 854266241f9Syasuoka /* try inpool_idx if it's in the range */ 855266241f9Syasuoka if (++inpool_idx < addr->naddrs) 856266241f9Syasuoka continue; 857266241f9Syasuoka /* iterate addr to the next pool */ 858266241f9Syasuoka do { 859266241f9Syasuoka addr = TAILQ_NEXT(addr, next); 860266241f9Syasuoka if (addr == NULL) 861266241f9Syasuoka addr = TAILQ_FIRST( 862266241f9Syasuoka &self->addrs); 863266241f9Syasuoka } while (addr->type != ADDRESS_TYPE_POOL); 864266241f9Syasuoka inpool_idx = 0; /* try the first */ 865842565f2Syasuoka } 866842565f2Syasuoka if (!found) { 8677af3c895Syasuoka log_info("q=%u user=%s rejected: ran out of " 8687af3c895Syasuoka "the address pool", q_id, user->name); 869842565f2Syasuoka goto reject; 870842565f2Syasuoka } 871842565f2Syasuoka } 872842565f2Syasuoka if ((assigned = ipcp_ipv4_assign(self, user, addr4)) == NULL) { 873842565f2Syasuoka log_warn("%s: ipcp_ipv4_assign()", __func__); 874842565f2Syasuoka goto fatal; 875842565f2Syasuoka } 876842565f2Syasuoka radius_set_ipv4_attr(radres, RADIUS_TYPE_FRAMED_IP_NETMASK, 877842565f2Syasuoka mask4); 878842565f2Syasuoka radius_del_attr_all(radres, RADIUS_TYPE_FRAMED_IP_ADDRESS); 879842565f2Syasuoka radius_put_ipv4_attr(radres, RADIUS_TYPE_FRAMED_IP_ADDRESS, 880842565f2Syasuoka addr4); 881842565f2Syasuoka log_info("q=%u Assign %s for %s", q_id, 882842565f2Syasuoka inet_ntop(AF_INET, &addr4, buf, sizeof(buf)), username); 883842565f2Syasuoka if (radius_has_attr(radreq, RADIUS_TYPE_USER_PASSWORD)) 884842565f2Syasuoka strlcpy(assigned->auth_method, "PAP", 885842565f2Syasuoka sizeof(assigned->auth_method)); 886842565f2Syasuoka else if (radius_has_attr(radreq, RADIUS_TYPE_CHAP_PASSWORD)) 887842565f2Syasuoka strlcpy(assigned->auth_method, "CHAP", 888842565f2Syasuoka sizeof(assigned->auth_method)); 889842565f2Syasuoka else if (radius_has_vs_attr(radreq, RADIUS_VENDOR_MICROSOFT, 890842565f2Syasuoka RADIUS_VTYPE_MS_CHAP_RESPONSE)) 891842565f2Syasuoka strlcpy(assigned->auth_method, "MS-CHAP", 892842565f2Syasuoka sizeof(assigned->auth_method)); 893842565f2Syasuoka else if (radius_has_vs_attr(radreq, RADIUS_VENDOR_MICROSOFT, 894842565f2Syasuoka RADIUS_VTYPE_MS_CHAP2_RESPONSE)) 895842565f2Syasuoka strlcpy(assigned->auth_method, "MS-CHAP-V2", 896842565f2Syasuoka sizeof(assigned->auth_method)); 897842565f2Syasuoka else if (radius_has_attr(radreq, RADIUS_TYPE_EAP_MESSAGE)) 898842565f2Syasuoka strlcpy(assigned->auth_method, "EAP", 899842565f2Syasuoka sizeof(assigned->auth_method)); 900*aae7f363Syasuoka 901*aae7f363Syasuoka radius_get_ipv4_attr(radreq, RADIUS_TYPE_NAS_IP_ADDRESS, 902*aae7f363Syasuoka &assigned->nas_ipv4); 903*aae7f363Syasuoka radius_get_ipv6_attr(radreq, RADIUS_TYPE_NAS_IPV6_ADDRESS, 904*aae7f363Syasuoka &assigned->nas_ipv6); 905*aae7f363Syasuoka radius_get_string_attr(radreq, RADIUS_TYPE_NAS_IDENTIFIER, 906*aae7f363Syasuoka assigned->nas_id, sizeof(assigned->nas_id)); 907842565f2Syasuoka } 908842565f2Syasuoka 909842565f2Syasuoka if (self->name_server[0].s_addr != 0) { 910842565f2Syasuoka addr4.s_addr = htonl(self->name_server[0].s_addr); 911842565f2Syasuoka radius_del_vs_attr_all(radres, 912842565f2Syasuoka RADIUS_VENDOR_MICROSOFT, 913842565f2Syasuoka RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER); 914842565f2Syasuoka radius_put_vs_ipv4_attr(radres, 915842565f2Syasuoka RADIUS_VENDOR_MICROSOFT, 916842565f2Syasuoka RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER, self->name_server[0]); 917842565f2Syasuoka } 918842565f2Syasuoka if (self->name_server[1].s_addr != 0) { 919842565f2Syasuoka addr4.s_addr = htonl(self->name_server[1].s_addr); 920842565f2Syasuoka radius_del_vs_attr_all(radres, 921842565f2Syasuoka RADIUS_VENDOR_MICROSOFT, 922842565f2Syasuoka RADIUS_VTYPE_MS_SECONDARY_DNS_SERVER); 923842565f2Syasuoka radius_put_vs_ipv4_attr(radres, 924842565f2Syasuoka RADIUS_VENDOR_MICROSOFT, 925842565f2Syasuoka RADIUS_VTYPE_MS_SECONDARY_DNS_SERVER, self->name_server[1]); 926842565f2Syasuoka } 927842565f2Syasuoka if (self->netbios_server[0].s_addr != 0) { 928842565f2Syasuoka addr4.s_addr = htonl(self->netbios_server[0].s_addr); 929842565f2Syasuoka radius_del_vs_attr_all(radres, 930842565f2Syasuoka RADIUS_VENDOR_MICROSOFT, 931842565f2Syasuoka RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER); 932842565f2Syasuoka radius_put_vs_ipv4_attr(radres, 933842565f2Syasuoka RADIUS_VENDOR_MICROSOFT, 934842565f2Syasuoka RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER, 935842565f2Syasuoka self->netbios_server[0]); 936842565f2Syasuoka } 937842565f2Syasuoka if (self->netbios_server[1].s_addr != 0) { 938842565f2Syasuoka addr4.s_addr = htonl(self->netbios_server[1].s_addr); 939842565f2Syasuoka radius_del_vs_attr_all(radres, 940842565f2Syasuoka RADIUS_VENDOR_MICROSOFT, 941842565f2Syasuoka RADIUS_VTYPE_MS_SECONDARY_NBNS_SERVER); 942842565f2Syasuoka radius_put_vs_ipv4_attr(radres, 943842565f2Syasuoka RADIUS_VENDOR_MICROSOFT, 944842565f2Syasuoka RADIUS_VTYPE_MS_SECONDARY_NBNS_SERVER, 945842565f2Syasuoka self->netbios_server[1]); 946842565f2Syasuoka } 9477a099e4dSyasuoka if (!self->no_session_timeout && assigned != NULL && 948842565f2Syasuoka radius_has_attr(radres, RADIUS_TYPE_SESSION_TIMEOUT)) { 949842565f2Syasuoka radius_get_uint32_attr(radres, RADIUS_TYPE_SESSION_TIMEOUT, 950842565f2Syasuoka &assigned->session_timeout); 951842565f2Syasuoka /* we handle this session-timeout */ 952842565f2Syasuoka radius_del_attr_all(radres, RADIUS_TYPE_SESSION_TIMEOUT); 953842565f2Syasuoka } 954842565f2Syasuoka 955842565f2Syasuoka accept: 956842565f2Syasuoka if (module_resdeco_done(self->base, q_id, radius_get_data(radres), 957842565f2Syasuoka radius_get_length(radres)) == -1) { 958842565f2Syasuoka log_warn("%s: module_resdeco_done() failed", __func__); 959842565f2Syasuoka module_stop(self->base); 960842565f2Syasuoka } 961842565f2Syasuoka if (radreq != NULL) 962842565f2Syasuoka radius_delete_packet(radreq); 963842565f2Syasuoka radius_delete_packet(radres); 964842565f2Syasuoka return; 965842565f2Syasuoka reject: 966842565f2Syasuoka ipcp_reject(self, radreq, q_id, radres, msraserr); 967842565f2Syasuoka radius_delete_packet(radreq); 968842565f2Syasuoka radius_delete_packet(radres); 969842565f2Syasuoka return; 970842565f2Syasuoka fatal: 971842565f2Syasuoka if (radreq != NULL) 972842565f2Syasuoka radius_delete_packet(radreq); 973842565f2Syasuoka if (radres != NULL) 974842565f2Syasuoka radius_delete_packet(radres); 975842565f2Syasuoka module_stop(self->base); 976842565f2Syasuoka } 977842565f2Syasuoka 978842565f2Syasuoka void 979842565f2Syasuoka ipcp_reject(struct module_ipcp *self, RADIUS_PACKET *reqp, unsigned int q_id, 980842565f2Syasuoka RADIUS_PACKET *orig_resp, int mserr) 981842565f2Syasuoka { 982842565f2Syasuoka bool is_eap, is_mschap, is_mschap2; 983842565f2Syasuoka uint8_t attr[256]; 984842565f2Syasuoka size_t attrlen; 985842565f2Syasuoka RADIUS_PACKET *resp; 986842565f2Syasuoka struct { 987842565f2Syasuoka uint8_t code; 988842565f2Syasuoka uint8_t id; 989842565f2Syasuoka uint16_t length; 990842565f2Syasuoka } __packed eap; 991842565f2Syasuoka 992842565f2Syasuoka resp = radius_new_response_packet(RADIUS_CODE_ACCESS_REJECT, reqp); 993842565f2Syasuoka if (resp == NULL) { 994842565f2Syasuoka log_warn("%s: radius_new_response_packet() failed", __func__); 995842565f2Syasuoka module_accsreq_aborted(self->base, q_id); 996842565f2Syasuoka return; 997842565f2Syasuoka } 998842565f2Syasuoka 999842565f2Syasuoka is_eap = radius_has_attr(reqp, RADIUS_TYPE_EAP_MESSAGE); 1000842565f2Syasuoka if (radius_get_vs_raw_attr(reqp, RADIUS_VENDOR_MICROSOFT, 1001842565f2Syasuoka RADIUS_VTYPE_MS_CHAP_RESPONSE, attr, &attrlen) == 0) 1002842565f2Syasuoka is_mschap = true; 1003842565f2Syasuoka else if (radius_get_vs_raw_attr(reqp, RADIUS_VENDOR_MICROSOFT, 1004842565f2Syasuoka RADIUS_VTYPE_MS_CHAP2_RESPONSE, attr, &attrlen) == 0) 1005842565f2Syasuoka is_mschap2 = true; 1006842565f2Syasuoka 1007842565f2Syasuoka if (is_eap) { 1008842565f2Syasuoka memset(&eap, 0, sizeof(eap)); /* just in case */ 1009842565f2Syasuoka eap.code = 1; /* EAP Request */ 1010842565f2Syasuoka attrlen = sizeof(attr); 1011842565f2Syasuoka if (orig_resp != NULL && radius_get_raw_attr(orig_resp, 1012842565f2Syasuoka RADIUS_TYPE_EAP_MESSAGE, &attr, &attrlen) == 0) 1013842565f2Syasuoka eap.id = attr[1]; 1014842565f2Syasuoka else 1015842565f2Syasuoka eap.id = 0; 1016842565f2Syasuoka eap.length = htons(sizeof(eap)); 1017842565f2Syasuoka radius_put_raw_attr(resp, RADIUS_TYPE_EAP_MESSAGE, &eap, 1018842565f2Syasuoka ntohs(eap.length)); 1019842565f2Syasuoka } else if (is_mschap || is_mschap2) { 1020842565f2Syasuoka attr[0] = attr[1]; /* Copy the ident of the request */ 1021842565f2Syasuoka snprintf(attr + 1, sizeof(attr) - 1, "E=%d R=0 V=3", mserr); 1022842565f2Syasuoka radius_put_vs_raw_attr(resp, RADIUS_VENDOR_MICROSOFT, 1023842565f2Syasuoka RADIUS_VTYPE_MS_CHAP_ERROR, attr, strlen(attr + 1) + 1); 1024842565f2Syasuoka } 1025842565f2Syasuoka 1026842565f2Syasuoka module_resdeco_done(self->base, q_id, radius_get_data(resp), 1027842565f2Syasuoka radius_get_length(resp)); 1028842565f2Syasuoka radius_delete_packet(resp); 1029842565f2Syasuoka } 1030842565f2Syasuoka 1031842565f2Syasuoka /*********************************************************************** 1032842565f2Syasuoka * RADIUS Accounting 1033842565f2Syasuoka ***********************************************************************/ 1034842565f2Syasuoka void 1035842565f2Syasuoka ipcp_accounting_request(void *ctx, u_int q_id, const u_char *pkt, 1036842565f2Syasuoka size_t pktlen) 1037842565f2Syasuoka { 1038842565f2Syasuoka RADIUS_PACKET *radpkt = NULL; 1039842565f2Syasuoka int code, af; 1040842565f2Syasuoka uint32_t type, delay, uval; 1041842565f2Syasuoka struct in_addr addr4, nas_ipv4; 1042842565f2Syasuoka struct in6_addr nas_ipv6, ipv6_zero; 1043842565f2Syasuoka struct module_ipcp *self = ctx; 1044842565f2Syasuoka struct assigned_ipv4 *assign, *assignt; 1045842565f2Syasuoka char username[256], nas_id[256], buf[256], 1046a6d690ccSyasuoka buf1[384]; 1047842565f2Syasuoka struct timespec dur; 1048842565f2Syasuoka struct radiusd_ipcp_statistics 1049842565f2Syasuoka stat; 1050842565f2Syasuoka struct module_ipcp_dae *dae; 1051842565f2Syasuoka 1052e1af567eSyasuoka ipcp_update_time(self); 1053842565f2Syasuoka 1054842565f2Syasuoka if ((radpkt = radius_convert_packet(pkt, pktlen)) == NULL) { 1055842565f2Syasuoka log_warn("%s: radius_convert_packet() failed", __func__); 1056842565f2Syasuoka module_stop(self->base); 1057842565f2Syasuoka return; 1058842565f2Syasuoka } 1059842565f2Syasuoka code = radius_get_code(radpkt); 1060842565f2Syasuoka if (code != RADIUS_CODE_ACCOUNTING_REQUEST && 1061842565f2Syasuoka code != RADIUS_CODE_ACCOUNTING_RESPONSE) 1062842565f2Syasuoka goto out; 1063842565f2Syasuoka 1064842565f2Syasuoka if (radius_get_uint32_attr(radpkt, RADIUS_TYPE_ACCT_STATUS_TYPE, &type) 1065842565f2Syasuoka != 0) 1066842565f2Syasuoka goto out; 1067842565f2Syasuoka 1068842565f2Syasuoka /* identifier for the NAS */ 1069842565f2Syasuoka memset(&ipv6_zero, 0, sizeof(ipv6_zero)); 1070842565f2Syasuoka memset(&nas_ipv4, 0, sizeof(nas_ipv4)); 1071842565f2Syasuoka memset(&nas_ipv6, 0, sizeof(nas_ipv6)); 1072842565f2Syasuoka memset(&nas_id, 0, sizeof(nas_id)); 1073842565f2Syasuoka 1074842565f2Syasuoka radius_get_ipv4_attr(radpkt, RADIUS_TYPE_NAS_IP_ADDRESS, &nas_ipv4); 1075842565f2Syasuoka radius_get_ipv6_attr(radpkt, RADIUS_TYPE_NAS_IPV6_ADDRESS, &nas_ipv6); 1076842565f2Syasuoka radius_get_string_attr(radpkt, RADIUS_TYPE_NAS_IDENTIFIER, nas_id, 1077842565f2Syasuoka sizeof(nas_id)); 1078842565f2Syasuoka 1079842565f2Syasuoka if (nas_ipv4.s_addr == 0 && IN6_ARE_ADDR_EQUAL(&nas_ipv6, &ipv6_zero) && 1080842565f2Syasuoka nas_id[0] == '\0') { 1081842565f2Syasuoka log_warnx("q=%u no NAS-IP-Address, NAS-IPV6-Address, or " 1082842565f2Syasuoka "NAS-Identifier", q_id); 1083842565f2Syasuoka goto out; 1084842565f2Syasuoka } 1085842565f2Syasuoka 1086842565f2Syasuoka if (type == RADIUS_ACCT_STATUS_TYPE_ACCT_ON || 1087842565f2Syasuoka type == RADIUS_ACCT_STATUS_TYPE_ACCT_OFF) { 1088842565f2Syasuoka /* 1089842565f2Syasuoka * NAS or daemon is restarted. Delete all assigned records 1090842565f2Syasuoka * from it 1091842565f2Syasuoka */ 1092842565f2Syasuoka RB_FOREACH_SAFE(assign, assigned_ipv4_tree, &self->ipv4s, 1093842565f2Syasuoka assignt) { 1094842565f2Syasuoka if (assign->nas_ipv4.s_addr != nas_ipv4.s_addr || 1095842565f2Syasuoka !IN6_ARE_ADDR_EQUAL(&assign->nas_ipv6, &nas_ipv6) || 1096842565f2Syasuoka strcmp(assign->nas_id, nas_id) != 0) 1097842565f2Syasuoka continue; 10984946f694Syasuoka log_info("q=%u Delete record for %s", q_id, 10994946f694Syasuoka inet_ntop(AF_INET, &assign->ipv4, buf, 11004946f694Syasuoka sizeof(buf))); 1101eff8f878Syasuoka ipcp_ipv4_delete(self, assign, 1102eff8f878Syasuoka (type == RADIUS_ACCT_STATUS_TYPE_ACCT_ON) 1103eff8f878Syasuoka ? "Receive Acct-On" : "Receive Acct-Off"); 1104842565f2Syasuoka } 1105842565f2Syasuoka return; 1106842565f2Syasuoka } 1107842565f2Syasuoka 1108842565f2Syasuoka if (radius_get_ipv4_attr(radpkt, RADIUS_TYPE_FRAMED_IP_ADDRESS, &addr4) 11093a9fd06cSyasuoka != 0) { 11103a9fd06cSyasuoka log_warnx("q=%u no Framed-IP-Address-Address attribute", q_id); 1111842565f2Syasuoka goto out; 11123a9fd06cSyasuoka } 1113842565f2Syasuoka if (radius_get_string_attr(radpkt, RADIUS_TYPE_USER_NAME, username, 11143a9fd06cSyasuoka sizeof(username)) != 0) { 11153a9fd06cSyasuoka log_warnx("q=%u no User-Name attribute", q_id); 1116842565f2Syasuoka goto out; 11173a9fd06cSyasuoka } 11183a9fd06cSyasuoka if ((assign = ipcp_ipv4_find(self, addr4)) == NULL) { 1119842565f2Syasuoka /* not assigned by this */ 11203a9fd06cSyasuoka log_warnx("q=%u %s is not assigned by us", q_id, 11213a9fd06cSyasuoka inet_ntop(AF_INET, &addr4, buf, sizeof(buf))); 1122842565f2Syasuoka goto out; 11233a9fd06cSyasuoka } 1124842565f2Syasuoka 1125842565f2Syasuoka if (radius_get_uint32_attr(radpkt, RADIUS_TYPE_ACCT_DELAY_TIME, &delay) 1126842565f2Syasuoka != 0) 1127842565f2Syasuoka delay = 0; 1128842565f2Syasuoka 1129842565f2Syasuoka if (type == RADIUS_ACCT_STATUS_TYPE_START) { 1130842565f2Syasuoka assign->start = self->uptime; 1131842565f2Syasuoka assign->start.tv_sec -= delay; 1132842565f2Syasuoka 1133842565f2Syasuoka if (!self->no_session_timeout && (self->session_timeout > 0 || 1134842565f2Syasuoka assign->session_timeout > 0)) { 1135842565f2Syasuoka assign->timeout = assign->start; 1136842565f2Syasuoka if (self->session_timeout > 0) 1137842565f2Syasuoka assign->timeout.tv_sec += self->session_timeout; 1138842565f2Syasuoka else 1139842565f2Syasuoka assign->timeout.tv_sec += 1140842565f2Syasuoka assign->session_timeout; 1141842565f2Syasuoka } 1142842565f2Syasuoka assign->nas_ipv4 = nas_ipv4; 114392278a01Syasuoka assign->nas_ipv6 = nas_ipv6; 1144842565f2Syasuoka strlcpy(assign->nas_id, nas_id, sizeof(assign->nas_id)); 1145842565f2Syasuoka 1146842565f2Syasuoka if (radius_get_string_attr(radpkt, RADIUS_TYPE_ACCT_SESSION_ID, 1147842565f2Syasuoka assign->session_id, sizeof(assign->session_id)) != 0) 1148842565f2Syasuoka assign->session_id[0] = '\0'; 1149842565f2Syasuoka if (radius_get_uint32_attr(radpkt, RADIUS_TYPE_TUNNEL_TYPE, 1150842565f2Syasuoka &uval) == 0) 1151842565f2Syasuoka assign->tun_type = radius_tunnel_type_string(uval, 1152842565f2Syasuoka NULL); 1153842565f2Syasuoka if (assign->tun_type == NULL) 1154842565f2Syasuoka assign->tun_type = ""; 1155842565f2Syasuoka 1156842565f2Syasuoka /* 1157842565f2Syasuoka * Get "tunnel from" from Tunnel-Client-Endpoint or Calling- 1158842565f2Syasuoka * Station-Id 1159842565f2Syasuoka */ 1160842565f2Syasuoka af = AF_UNSPEC; 1161842565f2Syasuoka if (radius_get_string_attr(radpkt, 1162842565f2Syasuoka RADIUS_TYPE_TUNNEL_CLIENT_ENDPOINT, buf, sizeof(buf)) == 0) 1163842565f2Syasuoka { 1164842565f2Syasuoka if (radius_get_uint32_attr(radpkt, 1165842565f2Syasuoka RADIUS_TYPE_TUNNEL_MEDIUM_TYPE, &uval) == 0) { 1166842565f2Syasuoka if (uval == RADIUS_TUNNEL_MEDIUM_TYPE_IPV4) 1167842565f2Syasuoka af = AF_INET; 1168842565f2Syasuoka else if (uval == RADIUS_TUNNEL_MEDIUM_TYPE_IPV6) 1169842565f2Syasuoka af = AF_INET6; 1170842565f2Syasuoka } 1171842565f2Syasuoka parse_addr(buf, af, (struct sockaddr *) 1172842565f2Syasuoka &assign->tun_client, sizeof(assign->tun_client)); 1173842565f2Syasuoka } 1174842565f2Syasuoka if (assign->tun_client.sin4.sin_family == 0 && 1175842565f2Syasuoka radius_get_string_attr(radpkt, 1176842565f2Syasuoka RADIUS_TYPE_CALLING_STATION_ID, buf, sizeof(buf)) == 0) 1177842565f2Syasuoka parse_addr(buf, af, (struct sockaddr *) 1178842565f2Syasuoka &assign->tun_client, sizeof(assign->tun_client)); 1179842565f2Syasuoka 1180842565f2Syasuoka TAILQ_FOREACH(dae, &self->daes, next) { 1181842565f2Syasuoka if (dae->nas_id[0] == '\0' || 1182842565f2Syasuoka strcmp(dae->nas_id, assign->nas_id) == 0) 1183842565f2Syasuoka break; 1184842565f2Syasuoka } 1185842565f2Syasuoka assign->dae = dae; 1186842565f2Syasuoka 1187842565f2Syasuoka ipcp_put_db(self, assign); 1188842565f2Syasuoka ipcp_schedule_timer(self); 1189842565f2Syasuoka 1190842565f2Syasuoka if (ipcp_notice_startstop(self, assign, 1, NULL) != 0) 1191842565f2Syasuoka goto fail; 11924946f694Syasuoka log_info("q=%u Start seq=%u user=%s duration=%dsec " 11934946f694Syasuoka "session=%s tunnel=%s from=%s auth=%s ip=%s", q_id, 11944946f694Syasuoka assign->seq, assign->user->name, delay, assign->session_id, 1195842565f2Syasuoka assign->tun_type, print_addr((struct sockaddr *) 1196842565f2Syasuoka &assign->tun_client, buf1, sizeof(buf1)), 1197842565f2Syasuoka assign->auth_method, inet_ntop(AF_INET, &addr4, buf, 1198842565f2Syasuoka sizeof(buf))); 1199842565f2Syasuoka } else if (type == RADIUS_ACCT_STATUS_TYPE_STOP) { 1200842565f2Syasuoka memset(&stat, 0, sizeof(stat)); 1201842565f2Syasuoka 1202842565f2Syasuoka dur = self->uptime; 1203842565f2Syasuoka dur.tv_sec -= delay; 1204842565f2Syasuoka timespecsub(&dur, &assign->start, &dur); 1205842565f2Syasuoka 1206842565f2Syasuoka if (radius_get_uint32_attr(radpkt, 1207842565f2Syasuoka RADIUS_TYPE_ACCT_INPUT_OCTETS, &uval) == 0) 1208842565f2Syasuoka stat.ibytes = uval; 1209842565f2Syasuoka if (radius_get_uint32_attr(radpkt, 1210842565f2Syasuoka RADIUS_TYPE_ACCT_INPUT_GIGAWORDS, &uval) == 0) 1211842565f2Syasuoka stat.ibytes = ((uint64_t)uval << 32) | stat.ibytes; 1212842565f2Syasuoka if (radius_get_uint32_attr(radpkt, 1213842565f2Syasuoka RADIUS_TYPE_ACCT_OUTPUT_OCTETS, &uval) == 0) 1214842565f2Syasuoka stat.obytes = uval; 1215842565f2Syasuoka if (radius_get_uint32_attr(radpkt, 1216842565f2Syasuoka RADIUS_TYPE_ACCT_OUTPUT_GIGAWORDS, &uval) == 0) 1217842565f2Syasuoka stat.obytes = ((uint64_t)uval << 32) | stat.obytes; 1218842565f2Syasuoka radius_get_uint32_attr(radpkt, RADIUS_TYPE_ACCT_INPUT_PACKETS, 1219842565f2Syasuoka &stat.ipackets); 1220842565f2Syasuoka radius_get_uint32_attr(radpkt, RADIUS_TYPE_ACCT_OUTPUT_PACKETS, 1221842565f2Syasuoka &stat.opackets); 1222842565f2Syasuoka 1223842565f2Syasuoka if (radius_get_uint32_attr(radpkt, 1224842565f2Syasuoka RADIUS_TYPE_ACCT_TERMINATE_CAUSE, &uval) == 0) 1225842565f2Syasuoka strlcpy(stat.cause, radius_terminate_cause_string(uval), 1226842565f2Syasuoka sizeof(stat.cause)); 1227842565f2Syasuoka 12284946f694Syasuoka log_info("q=%u Stop seq=%u user=%s duration=%lldsec " 12294946f694Syasuoka "session=%s tunnel=%s from=%s auth=%s ip=%s " 12304946f694Syasuoka "datain=%"PRIu64"bytes,%" PRIu32"packets dataout=%"PRIu64 12314946f694Syasuoka "bytes,%"PRIu32"packets cause=\"%s\"", q_id, 1232842565f2Syasuoka assign->seq, assign->user->name, dur.tv_sec, 1233842565f2Syasuoka assign->session_id, assign->tun_type, print_addr( 1234842565f2Syasuoka (struct sockaddr *)&assign->tun_client, buf1, sizeof(buf1)), 1235842565f2Syasuoka assign->auth_method, inet_ntop(AF_INET, &addr4, buf, 1236842565f2Syasuoka sizeof(buf)), stat.ibytes, stat.ipackets, stat.obytes, 1237842565f2Syasuoka stat.opackets, stat.cause); 1238842565f2Syasuoka 1239842565f2Syasuoka ipcp_del_db(self, assign); 1240842565f2Syasuoka if (ipcp_notice_startstop(self, assign, 0, &stat) != 0) 1241842565f2Syasuoka goto fail; 1242842565f2Syasuoka ipcp_ipv4_release(self, ipcp_ipv4_find(self, addr4)); 1243842565f2Syasuoka } 1244842565f2Syasuoka out: 1245842565f2Syasuoka radius_delete_packet(radpkt); 1246842565f2Syasuoka return; 1247842565f2Syasuoka fail: 1248842565f2Syasuoka module_stop(self->base); 1249842565f2Syasuoka radius_delete_packet(radpkt); 1250842565f2Syasuoka return; 1251842565f2Syasuoka } 1252842565f2Syasuoka 1253842565f2Syasuoka /*********************************************************************** 1254842565f2Syasuoka * On memory database to manage IP address assignment 1255842565f2Syasuoka ***********************************************************************/ 1256842565f2Syasuoka struct assigned_ipv4 * 1257842565f2Syasuoka ipcp_ipv4_assign(struct module_ipcp *self, struct user *user, 1258842565f2Syasuoka struct in_addr ina) 1259842565f2Syasuoka { 1260842565f2Syasuoka struct assigned_ipv4 *ip; 1261842565f2Syasuoka 1262842565f2Syasuoka ip = calloc(1, sizeof(struct assigned_ipv4)); 1263842565f2Syasuoka if (ip == NULL) { 1264842565f2Syasuoka log_warn("%s: calloc()", __func__); 1265842565f2Syasuoka return (NULL); 1266842565f2Syasuoka } 1267842565f2Syasuoka ip->ipv4 = ina; 1268842565f2Syasuoka ip->user = user; 1269842565f2Syasuoka ip->authtime = self->uptime; 1270842565f2Syasuoka RB_INSERT(assigned_ipv4_tree, &self->ipv4s, ip); 1271842565f2Syasuoka TAILQ_INSERT_TAIL(&user->ipv4s, ip, next); 1272c0127aecSyasuoka TAILQ_INIT(&ip->dae_clients); 1273842565f2Syasuoka self->nsessions++; 1274842565f2Syasuoka ip->seq = self->seq++; 1275842565f2Syasuoka 1276842565f2Syasuoka return (ip); 1277842565f2Syasuoka } 1278842565f2Syasuoka 1279842565f2Syasuoka struct assigned_ipv4 * 1280842565f2Syasuoka ipcp_ipv4_find(struct module_ipcp *self, struct in_addr ina) 1281842565f2Syasuoka { 1282842565f2Syasuoka struct assigned_ipv4 key, *ret; 1283842565f2Syasuoka struct timespec dif; 1284842565f2Syasuoka 1285842565f2Syasuoka key.ipv4 = ina; 1286842565f2Syasuoka ret = RB_FIND(assigned_ipv4_tree, &self->ipv4s, &key); 1287842565f2Syasuoka if (ret != NULL && ret->start.tv_sec == 0) { 1288842565f2Syasuoka /* not yet assigned */ 1289842565f2Syasuoka timespecsub(&self->uptime, &ret->authtime, &dif); 1290842565f2Syasuoka if (dif.tv_sec >= self->start_wait) { 1291842565f2Syasuoka /* assumed NAS finally didn't use the address */ 1292842565f2Syasuoka TAILQ_REMOVE(&ret->user->ipv4s, ret, next); 1293842565f2Syasuoka RB_REMOVE(assigned_ipv4_tree, &self->ipv4s, ret); 1294842565f2Syasuoka free(ret); 1295842565f2Syasuoka ret = NULL; 1296842565f2Syasuoka self->nsessions--; 1297842565f2Syasuoka } 1298842565f2Syasuoka } 1299842565f2Syasuoka return (ret); 1300842565f2Syasuoka } 1301842565f2Syasuoka 1302842565f2Syasuoka void 1303eff8f878Syasuoka ipcp_ipv4_delete(struct module_ipcp *self, struct assigned_ipv4 *assign, 1304eff8f878Syasuoka const char *cause) 1305eff8f878Syasuoka { 13061669612dSyasuoka struct radiusd_ipcp_statistics stat; 1307eff8f878Syasuoka 13081669612dSyasuoka memset(&stat, 0, sizeof(stat)); 1309eff8f878Syasuoka strlcpy(stat.cause, cause, sizeof(stat.cause)); 1310eff8f878Syasuoka 1311eff8f878Syasuoka ipcp_del_db(self, assign); 1312eff8f878Syasuoka ipcp_notice_startstop(self, assign, 0, &stat); 1313eff8f878Syasuoka ipcp_ipv4_release(self, assign); 1314eff8f878Syasuoka } 1315eff8f878Syasuoka 1316eff8f878Syasuoka void 1317842565f2Syasuoka ipcp_ipv4_release(struct module_ipcp *self, struct assigned_ipv4 *assign) 1318842565f2Syasuoka { 1319842565f2Syasuoka if (assign != NULL) { 1320842565f2Syasuoka TAILQ_REMOVE(&assign->user->ipv4s, assign, next); 1321842565f2Syasuoka RB_REMOVE(assigned_ipv4_tree, &self->ipv4s, assign); 1322842565f2Syasuoka self->nsessions--; 13232617e43bSyasuoka ipcp_dae_reset_request(assign); 1324842565f2Syasuoka free(assign); 1325842565f2Syasuoka } 1326842565f2Syasuoka } 1327842565f2Syasuoka 1328842565f2Syasuoka int 1329842565f2Syasuoka assigned_ipv4_compar(struct assigned_ipv4 *a, struct assigned_ipv4 *b) 1330842565f2Syasuoka { 13313a9fd06cSyasuoka if (a->ipv4.s_addr > b->ipv4.s_addr) 13323a9fd06cSyasuoka return (1); 13333a9fd06cSyasuoka else if (a->ipv4.s_addr < b->ipv4.s_addr) 13343a9fd06cSyasuoka return (-1); 13353a9fd06cSyasuoka return (0); 1336842565f2Syasuoka } 1337842565f2Syasuoka 1338842565f2Syasuoka struct user * 1339842565f2Syasuoka ipcp_user_get(struct module_ipcp *self, const char *username) 1340842565f2Syasuoka { 1341842565f2Syasuoka struct { 1342842565f2Syasuoka struct user user; 1343842565f2Syasuoka char name[256]; 1344842565f2Syasuoka } key; 1345842565f2Syasuoka struct user *elm; 1346842565f2Syasuoka 1347842565f2Syasuoka strlcpy(key.user.name, username, 256); 1348842565f2Syasuoka elm = RB_FIND(user_tree, &self->users, &key.user); 1349842565f2Syasuoka if (elm == NULL) { 1350842565f2Syasuoka if ((elm = calloc(1, offsetof(struct user, name[ 1351842565f2Syasuoka strlen(username) + 1]))) == NULL) 1352842565f2Syasuoka return (NULL); 1353842565f2Syasuoka memcpy(elm->name, username, strlen(username)); 1354842565f2Syasuoka RB_INSERT(user_tree, &self->users, elm); 1355842565f2Syasuoka TAILQ_INIT(&elm->ipv4s); 1356842565f2Syasuoka } 1357842565f2Syasuoka 1358842565f2Syasuoka return (elm); 1359842565f2Syasuoka } 1360842565f2Syasuoka 1361842565f2Syasuoka int 1362842565f2Syasuoka user_compar(struct user *a, struct user *b) 1363842565f2Syasuoka { 1364842565f2Syasuoka return (strcmp(a->name, b->name)); 1365842565f2Syasuoka } 1366842565f2Syasuoka 1367842565f2Syasuoka RB_GENERATE_STATIC(assigned_ipv4_tree, assigned_ipv4, tree, 1368842565f2Syasuoka assigned_ipv4_compar); 1369842565f2Syasuoka RB_GENERATE_STATIC(user_tree, user, tree, user_compar); 1370842565f2Syasuoka 1371842565f2Syasuoka /*********************************************************************** 1372842565f2Syasuoka * DB for the persistent over processes 1373842565f2Syasuoka ***********************************************************************/ 1374842565f2Syasuoka int 1375842565f2Syasuoka ipcp_prepare_db(void) 1376842565f2Syasuoka { 1377842565f2Syasuoka struct passwd *pw; 1378842565f2Syasuoka DB *db; 1379842565f2Syasuoka 1380842565f2Syasuoka if ((db = dbopen(_PATH_RADIUSD_IPCP_DB, O_CREAT | O_RDWR | O_EXLOCK, 1381842565f2Syasuoka 0600, DB_BTREE, NULL)) == NULL) 1382842565f2Syasuoka return (-1); 1383842565f2Syasuoka if ((pw = getpwnam(RADIUSD_USER)) == NULL) 1384842565f2Syasuoka return (-1); 1385842565f2Syasuoka fchown(db->fd(db), pw->pw_uid, pw->pw_gid); 1386842565f2Syasuoka db->close(db); 1387842565f2Syasuoka 1388842565f2Syasuoka return (0); 1389842565f2Syasuoka } 1390842565f2Syasuoka 1391842565f2Syasuoka int 1392842565f2Syasuoka ipcp_restore_from_db(struct module_ipcp *self) 1393842565f2Syasuoka { 1394842565f2Syasuoka DB *db; 1395842565f2Syasuoka DBT key, val; 1396842565f2Syasuoka char keybuf[128]; 1397842565f2Syasuoka struct user *user; 1398842565f2Syasuoka struct radiusd_ipcp_db_record 1399842565f2Syasuoka *record; 1400842565f2Syasuoka struct assigned_ipv4 *assigned; 1401842565f2Syasuoka struct in_addr ipv4; 1402842565f2Syasuoka struct module_ipcp_dae *dae; 1403842565f2Syasuoka 1404842565f2Syasuoka if ((db = dbopen(_PATH_RADIUSD_IPCP_DB, O_RDONLY | O_SHLOCK, 0600, 1405842565f2Syasuoka DB_BTREE, NULL)) == NULL) 1406842565f2Syasuoka return (-1); 1407842565f2Syasuoka 1408842565f2Syasuoka key.data = "ipv4/"; 1409842565f2Syasuoka key.size = 5; 1410842565f2Syasuoka if (db->seq(db, &key, &val, R_CURSOR) == 0) { 1411842565f2Syasuoka do { 1412842565f2Syasuoka if (key.size >= sizeof(keybuf)) 1413842565f2Syasuoka break; 1414842565f2Syasuoka memcpy(keybuf, key.data, key.size); 1415842565f2Syasuoka keybuf[key.size] = '\0'; 1416842565f2Syasuoka if (strncmp(keybuf, "ipv4/", 5) != 0) 1417842565f2Syasuoka break; 1418842565f2Syasuoka inet_pton(AF_INET, keybuf + 5, &ipv4); 1419842565f2Syasuoka record = (struct radiusd_ipcp_db_record *)val.data; 1420842565f2Syasuoka if ((user = ipcp_user_get(self, record->username)) 1421842565f2Syasuoka == NULL) 1422842565f2Syasuoka return (-1); 1423842565f2Syasuoka if ((assigned = ipcp_ipv4_assign(self, user, ipv4)) 1424842565f2Syasuoka == NULL) 1425842565f2Syasuoka return (-1); 1426842565f2Syasuoka assigned->seq = record->seq; 14278185dbe7Syasuoka self->seq = MAXIMUM(assigned->seq + 1, self->seq); 1428842565f2Syasuoka strlcpy(assigned->auth_method, record->auth_method, 1429842565f2Syasuoka sizeof(assigned->auth_method)); 1430842565f2Syasuoka strlcpy(assigned->session_id, record->session_id, 1431842565f2Syasuoka sizeof(assigned->session_id)); 1432842565f2Syasuoka assigned->start = record->start; 1433842565f2Syasuoka assigned->timeout = record->timeout; 1434842565f2Syasuoka assigned->nas_ipv4 = record->nas_ipv4; 1435842565f2Syasuoka assigned->nas_ipv6 = record->nas_ipv6; 1436842565f2Syasuoka strlcpy(assigned->nas_id, record->nas_id, 1437842565f2Syasuoka sizeof(assigned->nas_id)); 1438842565f2Syasuoka assigned->tun_type = radius_tunnel_type_string(0, 1439842565f2Syasuoka record->tun_type); 1440842565f2Syasuoka memcpy(&assigned->tun_client, &record->tun_client, 1441842565f2Syasuoka sizeof(assigned->tun_client)); 1442842565f2Syasuoka 1443842565f2Syasuoka TAILQ_FOREACH(dae, &self->daes, next) { 1444842565f2Syasuoka if (dae->nas_id[0] == '\0' || 1445842565f2Syasuoka strcmp(dae->nas_id, assigned->nas_id) == 0) 1446842565f2Syasuoka break; 1447842565f2Syasuoka } 1448842565f2Syasuoka assigned->dae = dae; 1449842565f2Syasuoka } while (db->seq(db, &key, &val, R_NEXT) == 0); 1450842565f2Syasuoka } 1451842565f2Syasuoka db->close(db); 1452842565f2Syasuoka 1453842565f2Syasuoka return (0); 1454842565f2Syasuoka } 1455842565f2Syasuoka 1456842565f2Syasuoka void 1457842565f2Syasuoka ipcp_put_db(struct module_ipcp *self, struct assigned_ipv4 *assigned) 1458842565f2Syasuoka { 1459842565f2Syasuoka DB *db; 1460842565f2Syasuoka DBT key, val; 1461842565f2Syasuoka char keybuf[128]; 1462842565f2Syasuoka struct radiusd_ipcp_db_record 1463842565f2Syasuoka record; 1464842565f2Syasuoka 1465842565f2Syasuoka strlcpy(keybuf, "ipv4/", sizeof(keybuf)); 1466842565f2Syasuoka inet_ntop(AF_INET, &assigned->ipv4, keybuf + 5, sizeof(keybuf) - 5); 1467842565f2Syasuoka key.data = keybuf; 1468842565f2Syasuoka key.size = strlen(keybuf); 1469842565f2Syasuoka strlcpy(record.session_id, assigned->session_id, 1470842565f2Syasuoka sizeof(record.session_id)); 1471842565f2Syasuoka strlcpy(record.auth_method, assigned->auth_method, 1472842565f2Syasuoka sizeof(record.auth_method)); 1473842565f2Syasuoka strlcpy(record.username, assigned->user->name, sizeof(record.username)); 1474842565f2Syasuoka record.seq = assigned->seq; 1475842565f2Syasuoka record.start = assigned->start; 1476842565f2Syasuoka record.timeout = assigned->timeout; 1477842565f2Syasuoka record.nas_ipv4 = assigned->nas_ipv4; 1478842565f2Syasuoka record.nas_ipv6 = assigned->nas_ipv6; 1479842565f2Syasuoka strlcpy(record.nas_id, assigned->nas_id, sizeof(record.nas_id)); 1480842565f2Syasuoka if (assigned->tun_type != NULL) 1481842565f2Syasuoka strlcpy(record.tun_type, assigned->tun_type, 1482842565f2Syasuoka sizeof(record.tun_type)); 1483842565f2Syasuoka memcpy(&record.tun_client, &assigned->tun_client, 1484842565f2Syasuoka sizeof(record.tun_client)); 1485842565f2Syasuoka 1486842565f2Syasuoka val.data = &record; 1487842565f2Syasuoka val.size = sizeof(record); 1488842565f2Syasuoka if ((db = dbopen(_PATH_RADIUSD_IPCP_DB, O_RDWR | O_EXLOCK, 0600, 1489842565f2Syasuoka DB_BTREE, NULL)) == NULL) 1490842565f2Syasuoka return; 1491842565f2Syasuoka db->put(db, &key, &val, 0); 1492842565f2Syasuoka db->close(db); 1493842565f2Syasuoka } 1494842565f2Syasuoka 1495842565f2Syasuoka void 1496842565f2Syasuoka ipcp_del_db(struct module_ipcp *self, struct assigned_ipv4 *assigned) 1497842565f2Syasuoka { 1498842565f2Syasuoka DB *db; 1499842565f2Syasuoka DBT key; 1500842565f2Syasuoka char keybuf[128]; 1501842565f2Syasuoka 1502842565f2Syasuoka strlcpy(keybuf, "ipv4/", sizeof(keybuf)); 1503842565f2Syasuoka inet_ntop(AF_INET, &assigned->ipv4, keybuf + 5, sizeof(keybuf) - 5); 1504842565f2Syasuoka key.data = keybuf; 1505842565f2Syasuoka key.size = strlen(keybuf); 1506842565f2Syasuoka 1507842565f2Syasuoka if ((db = dbopen(_PATH_RADIUSD_IPCP_DB, O_RDWR | O_EXLOCK, 0600, 1508842565f2Syasuoka DB_BTREE, NULL)) == NULL) 1509842565f2Syasuoka return; 1510842565f2Syasuoka db->del(db, &key, 0); 1511842565f2Syasuoka db->close(db); 1512842565f2Syasuoka } 1513842565f2Syasuoka 1514842565f2Syasuoka void 1515842565f2Syasuoka ipcp_db_dump_fill_record(struct radiusd_ipcp_db_dump *dump, int idx, 1516842565f2Syasuoka struct assigned_ipv4 *assign) 1517842565f2Syasuoka { 1518842565f2Syasuoka dump->records[idx].af = AF_INET; 1519842565f2Syasuoka dump->records[idx].addr.ipv4 = assign->ipv4; 1520842565f2Syasuoka dump->records[idx].rec.seq = assign->seq; 1521842565f2Syasuoka strlcpy(dump->records[idx].rec.session_id, assign->session_id, 1522842565f2Syasuoka sizeof(dump->records[idx].rec.session_id)); 1523842565f2Syasuoka strlcpy(dump->records[idx].rec.auth_method, assign->auth_method, 1524842565f2Syasuoka sizeof(dump->records[idx].rec.auth_method)); 1525842565f2Syasuoka strlcpy(dump->records[idx].rec.username, assign->user->name, 1526842565f2Syasuoka sizeof(dump->records[idx].rec.username)); 1527842565f2Syasuoka dump->records[idx].rec.start = assign->start; 1528842565f2Syasuoka dump->records[idx].rec.timeout = assign->timeout; 1529842565f2Syasuoka dump->records[idx].rec.nas_ipv4 = assign->nas_ipv4; 1530842565f2Syasuoka dump->records[idx].rec.nas_ipv6 = assign->nas_ipv6; 1531842565f2Syasuoka strlcpy(dump->records[idx].rec.nas_id, assign->nas_id, 1532842565f2Syasuoka sizeof(dump->records[idx].rec.nas_id)); 1533842565f2Syasuoka if (assign->tun_type != NULL) 1534842565f2Syasuoka strlcpy(dump->records[idx].rec.tun_type, assign->tun_type, 1535842565f2Syasuoka sizeof(dump->records[idx].rec.tun_type)); 1536842565f2Syasuoka memcpy(&dump->records[idx].rec.tun_client, &assign->tun_client, 1537842565f2Syasuoka sizeof(dump->records[idx].rec.tun_client)); 1538842565f2Syasuoka } 1539842565f2Syasuoka 1540842565f2Syasuoka /*********************************************************************** 1541842565f2Syasuoka * Timer 1542842565f2Syasuoka ***********************************************************************/ 1543842565f2Syasuoka void 1544e1af567eSyasuoka ipcp_update_time(struct module_ipcp *self) 1545e1af567eSyasuoka { 1546e1af567eSyasuoka clock_gettime(CLOCK_BOOTTIME, &self->uptime); 1547e1af567eSyasuoka } 1548e1af567eSyasuoka 1549e1af567eSyasuoka void 1550842565f2Syasuoka ipcp_on_timer(int fd, short ev, void *ctx) 1551842565f2Syasuoka { 1552842565f2Syasuoka struct module_ipcp *self = ctx; 1553842565f2Syasuoka 1554e1af567eSyasuoka ipcp_update_time(self); 1555842565f2Syasuoka ipcp_schedule_timer(self); 1556842565f2Syasuoka } 1557842565f2Syasuoka 1558842565f2Syasuoka void 1559842565f2Syasuoka ipcp_schedule_timer(struct module_ipcp *self) 1560842565f2Syasuoka { 1561842565f2Syasuoka struct assigned_ipv4 *assign, *min_assign = NULL; 1562842565f2Syasuoka struct timespec tsd; 1563842565f2Syasuoka struct timeval tv; 1564842565f2Syasuoka 1565842565f2Syasuoka /* check session timeout */ 1566842565f2Syasuoka RB_FOREACH(assign, assigned_ipv4_tree, &self->ipv4s) { 1567842565f2Syasuoka if (assign->timeout.tv_sec == 0) 1568842565f2Syasuoka continue; 1569842565f2Syasuoka if (timespeccmp(&assign->timeout, &self->uptime, <=)) { 1570842565f2Syasuoka log_info("Reached session timeout seq=%u", assign->seq); 1571842565f2Syasuoka ipcp_dae_send_disconnect_request(assign); 1572842565f2Syasuoka memset(&assign->timeout, 0, sizeof(assign->timeout)); 1573842565f2Syasuoka ipcp_put_db(self, assign); 1574842565f2Syasuoka } 1575842565f2Syasuoka if (min_assign == NULL || 1576842565f2Syasuoka timespeccmp(&min_assign->timeout, &assign->timeout, >)) 1577842565f2Syasuoka min_assign = assign; 1578842565f2Syasuoka } 1579842565f2Syasuoka if (evtimer_pending(&self->ev_timer, NULL)) 1580842565f2Syasuoka evtimer_del(&self->ev_timer); 1581842565f2Syasuoka 1582842565f2Syasuoka if (min_assign != NULL) { 1583842565f2Syasuoka timespecsub(&min_assign->timeout, &self->uptime, &tsd); 1584842565f2Syasuoka TIMESPEC_TO_TIMEVAL(&tv, &tsd); 1585842565f2Syasuoka evtimer_set(&self->ev_timer, ipcp_on_timer, self); 1586842565f2Syasuoka evtimer_add(&self->ev_timer, &tv); 1587842565f2Syasuoka } 1588842565f2Syasuoka } 1589842565f2Syasuoka 1590842565f2Syasuoka /*********************************************************************** 1591842565f2Syasuoka * Dynamic Authorization Extension for RAIDUS (RFC 5176) 1592842565f2Syasuoka ***********************************************************************/ 1593842565f2Syasuoka static const int dae_request_timeouts[] = { 2, 4, 8, 8 }; 1594842565f2Syasuoka 1595842565f2Syasuoka void 1596842565f2Syasuoka ipcp_dae_send_disconnect_request(struct assigned_ipv4 *assign) 1597842565f2Syasuoka { 1598842565f2Syasuoka RADIUS_PACKET *reqpkt = NULL; 1599842565f2Syasuoka struct timeval tv; 1600842565f2Syasuoka char buf[80]; 1601842565f2Syasuoka 1602842565f2Syasuoka if (assign->dae == NULL) 1603842565f2Syasuoka return; /* DAE is not configured */ 1604842565f2Syasuoka 16052617e43bSyasuoka if (assign->dae_reqpkt == NULL) { 16062617e43bSyasuoka if ((reqpkt = radius_new_request_packet( 16072617e43bSyasuoka RADIUS_CODE_DISCONNECT_REQUEST)) == NULL) { 16082617e43bSyasuoka log_warn("%s: radius_new_request_packet(): %m", 16092617e43bSyasuoka __func__); 16102617e43bSyasuoka return; 1611842565f2Syasuoka } 1612842565f2Syasuoka radius_put_string_attr(reqpkt, RADIUS_TYPE_ACCT_SESSION_ID, 1613842565f2Syasuoka assign->session_id); 161492278a01Syasuoka /* 161592278a01Syasuoka * RFC 5176 Section 3, "either the User-Name or 161692278a01Syasuoka * Chargeable-User-Identity attribute SHOULD be present in 161792278a01Syasuoka * Disconnect-Request and CoA-Request packets." 161892278a01Syasuoka */ 161992278a01Syasuoka radius_put_string_attr(reqpkt, RADIUS_TYPE_USER_NAME, 162092278a01Syasuoka assign->user->name); 162192278a01Syasuoka if (assign->nas_id[0] != '\0') 162292278a01Syasuoka radius_put_string_attr(reqpkt, 162392278a01Syasuoka RADIUS_TYPE_NAS_IDENTIFIER, assign->nas_id); 162492278a01Syasuoka if (ntohl(assign->nas_ipv4.s_addr) != 0) 162592278a01Syasuoka radius_put_ipv4_attr(reqpkt, 162692278a01Syasuoka RADIUS_TYPE_NAS_IP_ADDRESS, assign->nas_ipv4); 162792278a01Syasuoka if (!IN6_IS_ADDR_UNSPECIFIED(&assign->nas_ipv6)) 162892278a01Syasuoka radius_put_ipv6_attr(reqpkt, 162992278a01Syasuoka RADIUS_TYPE_NAS_IPV6_ADDRESS, &assign->nas_ipv6); 1630842565f2Syasuoka radius_set_accounting_request_authenticator(reqpkt, 1631842565f2Syasuoka assign->dae->secret); 16322617e43bSyasuoka assign->dae_reqpkt = reqpkt; 1633cfa11a85Syasuoka TAILQ_INSERT_TAIL(&assign->dae->reqs, assign, dae_next); 16342617e43bSyasuoka } 1635842565f2Syasuoka 16362617e43bSyasuoka if (assign->dae_ntry == 0) { 1637cfa11a85Syasuoka if (assign->dae->ninflight >= RADIUSD_IPCP_DAE_MAX_INFLIGHT) 1638cfa11a85Syasuoka return; 1639842565f2Syasuoka log_info("Sending Disconnect-Request seq=%u to %s", 1640842565f2Syasuoka assign->seq, print_addr((struct sockaddr *) 1641842565f2Syasuoka &assign->dae->nas_addr, buf, sizeof(buf))); 16422617e43bSyasuoka } 1643842565f2Syasuoka 16442617e43bSyasuoka if (radius_send(assign->dae->sock, assign->dae_reqpkt, 0) < 0) 16452617e43bSyasuoka log_warn("%s: sendto: %m", __func__); 16462617e43bSyasuoka 1647cfa11a85Syasuoka tv.tv_sec = dae_request_timeouts[assign->dae_ntry]; 1648842565f2Syasuoka tv.tv_usec = 0; 1649842565f2Syasuoka evtimer_set(&assign->dae_evtimer, ipcp_dae_request_on_timeout, assign); 1650842565f2Syasuoka evtimer_add(&assign->dae_evtimer, &tv); 1651cfa11a85Syasuoka if (assign->dae_ntry == 0) 1652cfa11a85Syasuoka assign->dae->ninflight++; 1653cfa11a85Syasuoka assign->dae_ntry++; 1654842565f2Syasuoka } 1655842565f2Syasuoka 1656842565f2Syasuoka void 1657842565f2Syasuoka ipcp_dae_request_on_timeout(int fd, short ev, void *ctx) 1658842565f2Syasuoka { 1659842565f2Syasuoka struct assigned_ipv4 *assign = ctx; 1660842565f2Syasuoka char buf[80]; 1661a06d4bddSyasuoka struct radiusctl_client *client; 1662842565f2Syasuoka 16632617e43bSyasuoka if (assign->dae_ntry >= (int)nitems(dae_request_timeouts)) { 1664842565f2Syasuoka log_warnx("No answer for Disconnect-Request seq=%u from %s", 1665842565f2Syasuoka assign->seq, print_addr((struct sockaddr *) 1666842565f2Syasuoka &assign->dae->nas_addr, buf, sizeof(buf))); 1667a06d4bddSyasuoka TAILQ_FOREACH(client, &assign->dae_clients, entry) 1668a06d4bddSyasuoka module_imsg_compose(assign->dae->ipcp->base, IMSG_NG, 1669a06d4bddSyasuoka client->peerid, 0, -1, NULL, 0); 16702617e43bSyasuoka ipcp_dae_reset_request(assign); 16712617e43bSyasuoka } else 1672842565f2Syasuoka ipcp_dae_send_disconnect_request(assign); 1673842565f2Syasuoka } 1674842565f2Syasuoka 1675842565f2Syasuoka void 1676842565f2Syasuoka ipcp_dae_on_event(int fd, short ev, void *ctx) 1677842565f2Syasuoka { 1678842565f2Syasuoka struct module_ipcp_dae *dae = ctx; 1679c0127aecSyasuoka struct module_ipcp *self = dae->ipcp; 1680842565f2Syasuoka RADIUS_PACKET *radres = NULL; 1681842565f2Syasuoka int code; 1682842565f2Syasuoka uint32_t u32; 1683842565f2Syasuoka struct assigned_ipv4 *assign; 1684842565f2Syasuoka char buf[80], causestr[80]; 16852617e43bSyasuoka const char *cause = ""; 1686c0127aecSyasuoka struct radiusctl_client *client; 1687842565f2Syasuoka 1688e1af567eSyasuoka ipcp_update_time(self); 1689e1af567eSyasuoka 1690842565f2Syasuoka if ((ev & EV_READ) == 0) 1691842565f2Syasuoka return; 1692842565f2Syasuoka 1693842565f2Syasuoka if ((radres = radius_recv(dae->sock, 0)) == NULL) { 1694842565f2Syasuoka if (errno == EAGAIN) 1695842565f2Syasuoka return; 16964946f694Syasuoka log_warn("%s: Failed to receive from %s", __func__, print_addr( 1697842565f2Syasuoka (struct sockaddr *)&dae->nas_addr, buf, sizeof(buf))); 1698842565f2Syasuoka return; 1699842565f2Syasuoka } 1700842565f2Syasuoka TAILQ_FOREACH(assign, &dae->reqs, dae_next) { 1701842565f2Syasuoka if (radius_get_id(assign->dae_reqpkt) == radius_get_id(radres)) 1702842565f2Syasuoka break; 1703842565f2Syasuoka } 1704842565f2Syasuoka if (assign == NULL) { 17054946f694Syasuoka log_warnx("%s: Received RADIUS packet from %s has unknown " 17064946f694Syasuoka "id=%d", __func__, print_addr((struct sockaddr *) 17074946f694Syasuoka &dae->nas_addr, buf, sizeof(buf)), radius_get_id(radres)); 17082617e43bSyasuoka goto out; 1709842565f2Syasuoka } 1710842565f2Syasuoka 1711842565f2Syasuoka radius_set_request_packet(radres, assign->dae_reqpkt); 1712842565f2Syasuoka if ((radius_check_response_authenticator(radres, dae->secret)) != 0) { 17134946f694Syasuoka log_warnx("%s: Received RADIUS packet for seq=%u from %s has " 17144946f694Syasuoka "a bad authenticator", __func__, assign->seq, print_addr( 1715842565f2Syasuoka (struct sockaddr *)&dae->nas_addr, buf, 1716842565f2Syasuoka sizeof(buf))); 17172617e43bSyasuoka goto out; 1718842565f2Syasuoka } 1719842565f2Syasuoka causestr[0] = '\0'; 1720842565f2Syasuoka if (radius_get_uint32_attr(radres, RADIUS_TYPE_ERROR_CAUSE, &u32) == 0){ 1721842565f2Syasuoka cause = radius_error_cause_string(u32); 1722842565f2Syasuoka if (cause != NULL) 1723842565f2Syasuoka snprintf(causestr, sizeof(causestr), " cause=%u(%s)", 1724842565f2Syasuoka u32, cause); 1725842565f2Syasuoka else 1726842565f2Syasuoka snprintf(causestr, sizeof(causestr), " cause=%u", u32); 17272617e43bSyasuoka cause = causestr; 1728842565f2Syasuoka } 1729842565f2Syasuoka 1730842565f2Syasuoka code = radius_get_code(radres); 1731842565f2Syasuoka switch (code) { 1732842565f2Syasuoka case RADIUS_CODE_DISCONNECT_ACK: 1733842565f2Syasuoka log_info("Received Disconnect-ACK for seq=%u from %s%s", 1734842565f2Syasuoka assign->seq, print_addr((struct sockaddr *) 1735842565f2Syasuoka &dae->nas_addr, buf, sizeof(buf)), cause); 1736842565f2Syasuoka break; 1737842565f2Syasuoka case RADIUS_CODE_DISCONNECT_NAK: 17384946f694Syasuoka log_info("Received Disconnect-NAK for seq=%u from %s%s", 1739842565f2Syasuoka assign->seq, print_addr((struct sockaddr *) 1740842565f2Syasuoka &dae->nas_addr, buf, sizeof(buf)), cause); 1741842565f2Syasuoka break; 1742842565f2Syasuoka default: 17434946f694Syasuoka log_warn("%s: Received unknown code=%d for id=%u from %s", 17444946f694Syasuoka __func__, code, assign->seq, print_addr((struct sockaddr *) 1745842565f2Syasuoka &dae->nas_addr, buf, sizeof(buf))); 1746842565f2Syasuoka break; 1747842565f2Syasuoka } 1748c0127aecSyasuoka 1749c0127aecSyasuoka TAILQ_FOREACH(client, &assign->dae_clients, entry) { 1750c0127aecSyasuoka if (*cause != '\0') 1751c0127aecSyasuoka module_imsg_compose(self->base, 1752c0127aecSyasuoka (code == RADIUS_CODE_DISCONNECT_ACK) 1753c0127aecSyasuoka ? IMSG_OK : IMSG_NG, client->peerid, 0, -1, 1754c0127aecSyasuoka cause + 1, strlen(cause + 1) + 1); 1755c0127aecSyasuoka else 1756c0127aecSyasuoka module_imsg_compose(self->base, 1757c0127aecSyasuoka (code == RADIUS_CODE_DISCONNECT_ACK) 1758c0127aecSyasuoka ? IMSG_OK : IMSG_NG, client->peerid, 0, -1, 1759c0127aecSyasuoka NULL, 0); 1760c0127aecSyasuoka } 17612617e43bSyasuoka ipcp_dae_reset_request(assign); 17622617e43bSyasuoka out: 17632617e43bSyasuoka if (radres != NULL) 17642617e43bSyasuoka radius_delete_packet(radres); 17652617e43bSyasuoka } 17662617e43bSyasuoka 17672617e43bSyasuoka void 17682617e43bSyasuoka ipcp_dae_reset_request(struct assigned_ipv4 *assign) 17692617e43bSyasuoka { 1770c0127aecSyasuoka struct radiusctl_client *client, *clientt; 1771cfa11a85Syasuoka const struct timeval zero = { 0, 0 }; 1772c0127aecSyasuoka 17732617e43bSyasuoka if (assign->dae != NULL) { 1774cfa11a85Syasuoka if (assign->dae_reqpkt != NULL) 17752617e43bSyasuoka TAILQ_REMOVE(&assign->dae->reqs, assign, dae_next); 1776cfa11a85Syasuoka if (assign->dae_ntry > 0) { 1777cfa11a85Syasuoka assign->dae->ninflight--; 1778cfa11a85Syasuoka if (!evtimer_pending(&assign->dae->ev_reqs, NULL)) 1779cfa11a85Syasuoka evtimer_add(&assign->dae->ev_reqs, &zero); 1780cfa11a85Syasuoka } 17812617e43bSyasuoka } 17822617e43bSyasuoka if (assign->dae_reqpkt != NULL) 17832617e43bSyasuoka radius_delete_packet(assign->dae_reqpkt); 17842617e43bSyasuoka assign->dae_reqpkt = NULL; 17852617e43bSyasuoka if (evtimer_pending(&assign->dae_evtimer, NULL)) 17862617e43bSyasuoka evtimer_del(&assign->dae_evtimer); 1787c0127aecSyasuoka TAILQ_FOREACH_SAFE(client, &assign->dae_clients, entry, clientt) { 1788c0127aecSyasuoka TAILQ_REMOVE(&assign->dae_clients, client, entry); 1789c0127aecSyasuoka free(client); 1790c0127aecSyasuoka } 17912617e43bSyasuoka assign->dae_ntry = 0; 1792842565f2Syasuoka } 1793842565f2Syasuoka 1794cfa11a85Syasuoka void 1795cfa11a85Syasuoka ipcp_dae_send_pending_requests(int fd, short ev, void *ctx) 1796cfa11a85Syasuoka { 1797cfa11a85Syasuoka struct module_ipcp_dae *dae = ctx; 1798cfa11a85Syasuoka struct module_ipcp *self = dae->ipcp; 1799cfa11a85Syasuoka struct assigned_ipv4 *assign, *assignt; 1800cfa11a85Syasuoka 1801cfa11a85Syasuoka ipcp_update_time(self); 1802cfa11a85Syasuoka 1803cfa11a85Syasuoka TAILQ_FOREACH_SAFE(assign, &dae->reqs, dae_next, assignt) { 1804cfa11a85Syasuoka if (dae->ninflight >= RADIUSD_IPCP_DAE_MAX_INFLIGHT) 1805cfa11a85Syasuoka break; 1806cfa11a85Syasuoka if (assign->dae_ntry == 0) /* pending */ 1807cfa11a85Syasuoka ipcp_dae_send_disconnect_request(assign); 1808cfa11a85Syasuoka } 1809cfa11a85Syasuoka } 1810cfa11a85Syasuoka 1811842565f2Syasuoka /*********************************************************************** 1812842565f2Syasuoka * Miscellaneous functions 1813842565f2Syasuoka ***********************************************************************/ 1814842565f2Syasuoka struct ipcp_address * 1815842565f2Syasuoka parse_address_range(const char *range) 1816842565f2Syasuoka { 1817842565f2Syasuoka char *buf, *sep; 1818842565f2Syasuoka int masklen; 1819842565f2Syasuoka uint32_t mask; 1820842565f2Syasuoka struct in_addr start, end; 1821842565f2Syasuoka struct ipcp_address *ret; 1822842565f2Syasuoka const char *errstr; 1823842565f2Syasuoka 1824842565f2Syasuoka buf = strdup(range); 1825842565f2Syasuoka if (buf == NULL) 1826842565f2Syasuoka goto error; 1827842565f2Syasuoka if ((sep = strchr(buf, '-')) != NULL) { 1828842565f2Syasuoka *sep = '\0'; 182984b182f8Sflorian if (inet_pton(AF_INET, buf, &start) != 1) 1830842565f2Syasuoka goto error; 183184b182f8Sflorian else if (inet_pton(AF_INET, ++sep, &end) != 1) 1832842565f2Syasuoka goto error; 1833842565f2Syasuoka start.s_addr = ntohl(start.s_addr); 1834842565f2Syasuoka end.s_addr = ntohl(end.s_addr); 1835266241f9Syasuoka if (end.s_addr < start.s_addr) 1836266241f9Syasuoka goto error; 1837842565f2Syasuoka } else { 1838842565f2Syasuoka if ((sep = strchr(buf, '/')) != NULL) { 1839842565f2Syasuoka *sep = '\0'; 184084b182f8Sflorian if (inet_pton(AF_INET, buf, &start) != 1) 1841842565f2Syasuoka goto error; 1842842565f2Syasuoka masklen = strtonum(++sep, 0, 32, &errstr); 1843842565f2Syasuoka if (errstr != NULL) 1844842565f2Syasuoka goto error; 1845842565f2Syasuoka } else { 184684b182f8Sflorian if (inet_pton(AF_INET, buf, &start) != 1) 1847842565f2Syasuoka goto error; 1848842565f2Syasuoka masklen = 32; 1849842565f2Syasuoka } 1850842565f2Syasuoka mask = 0xFFFFFFFFUL; 1851842565f2Syasuoka if (masklen < 32) 1852842565f2Syasuoka mask <<= (32 - masklen); 1853842565f2Syasuoka start.s_addr = ntohl(start.s_addr) & mask; 1854842565f2Syasuoka if (masklen == 32) 1855842565f2Syasuoka end = start; 1856842565f2Syasuoka else if (masklen == 31) 1857842565f2Syasuoka end.s_addr = start.s_addr + 1; 1858842565f2Syasuoka else { 1859842565f2Syasuoka end.s_addr = start.s_addr + (1 << (32 - masklen)) - 2; 1860842565f2Syasuoka start.s_addr = start.s_addr + 1; 1861842565f2Syasuoka } 1862842565f2Syasuoka } 1863842565f2Syasuoka free(buf); 1864842565f2Syasuoka if ((ret = calloc(1, sizeof(struct ipcp_address))) == NULL) 1865842565f2Syasuoka return (NULL); 1866842565f2Syasuoka ret->start = start; 1867842565f2Syasuoka ret->end = end; 1868842565f2Syasuoka ret->naddrs = end.s_addr - start.s_addr + 1; 1869842565f2Syasuoka return (ret); 1870842565f2Syasuoka error: 1871842565f2Syasuoka free(buf); 1872842565f2Syasuoka return (NULL); 1873842565f2Syasuoka } 1874842565f2Syasuoka 1875842565f2Syasuoka const char * 1876842565f2Syasuoka radius_tunnel_type_string(unsigned val, const char *label) 1877842565f2Syasuoka { 1878842565f2Syasuoka unsigned int i; 1879842565f2Syasuoka struct { 1880842565f2Syasuoka const unsigned constval; 1881842565f2Syasuoka const char *label; 1882842565f2Syasuoka } tunnel_types[] = { 1883842565f2Syasuoka { RADIUS_TUNNEL_TYPE_PPTP, "PPTP" }, 1884842565f2Syasuoka { RADIUS_TUNNEL_TYPE_L2F, "L2F" }, 1885842565f2Syasuoka { RADIUS_TUNNEL_TYPE_L2TP, "L2TP" }, 1886842565f2Syasuoka { RADIUS_TUNNEL_TYPE_ATMP, "ATMP" }, 1887842565f2Syasuoka { RADIUS_TUNNEL_TYPE_VTP, "VTP" }, 1888842565f2Syasuoka { RADIUS_TUNNEL_TYPE_AH, "AH" }, 1889842565f2Syasuoka { RADIUS_TUNNEL_TYPE_IP, "IP" }, 1890842565f2Syasuoka { RADIUS_TUNNEL_TYPE_MOBILE, "MIN-IP-IP" }, 1891842565f2Syasuoka { RADIUS_TUNNEL_TYPE_ESP, "ESP" }, 1892842565f2Syasuoka { RADIUS_TUNNEL_TYPE_GRE, "GRE" }, 1893842565f2Syasuoka { RADIUS_TUNNEL_TYPE_VDS, "DVS" }, 1894842565f2Syasuoka /* [MS-RNAS] 3.3.5.1.9 Tunnel-Type */ 1895842565f2Syasuoka { RADIUS_VENDOR_MICROSOFT << 8 | 1, 1896842565f2Syasuoka "SSTP" } 1897842565f2Syasuoka }; 1898842565f2Syasuoka 1899842565f2Syasuoka if (label != NULL) { /* for conversion to the const value */ 1900842565f2Syasuoka for (i = 0; i < nitems(tunnel_types); i++) { 1901842565f2Syasuoka if (strcmp(tunnel_types[i].label, label) == 0) 1902842565f2Syasuoka return (tunnel_types[i].label); 1903842565f2Syasuoka } 1904842565f2Syasuoka } 1905842565f2Syasuoka 1906842565f2Syasuoka for (i = 0; i < nitems(tunnel_types); i++) { 1907842565f2Syasuoka if (tunnel_types[i].constval == val) 1908842565f2Syasuoka return (tunnel_types[i].label); 1909842565f2Syasuoka } 1910842565f2Syasuoka 1911842565f2Syasuoka return (NULL); 1912842565f2Syasuoka } 1913842565f2Syasuoka 1914842565f2Syasuoka const char * 1915842565f2Syasuoka radius_terminate_cause_string(unsigned val) 1916842565f2Syasuoka { 1917842565f2Syasuoka unsigned int i; 1918842565f2Syasuoka struct { 1919842565f2Syasuoka const unsigned constval; 1920842565f2Syasuoka const char *label; 1921842565f2Syasuoka } terminate_causes[] = { 1922842565f2Syasuoka { RADIUS_TERMNATE_CAUSE_USER_REQUEST, "User Request" }, 1923842565f2Syasuoka { RADIUS_TERMNATE_CAUSE_LOST_CARRIER, "Lost Carrier" }, 1924842565f2Syasuoka { RADIUS_TERMNATE_CAUSE_LOST_SERVICE, "Lost Service" }, 1925842565f2Syasuoka { RADIUS_TERMNATE_CAUSE_IDLE_TIMEOUT, "Idle Timeout" }, 1926842565f2Syasuoka { RADIUS_TERMNATE_CAUSE_SESSION_TIMEOUT, "Session Timeout" }, 1927842565f2Syasuoka { RADIUS_TERMNATE_CAUSE_ADMIN_RESET, "Admin Reset" }, 1928842565f2Syasuoka { RADIUS_TERMNATE_CAUSE_ADMIN_REBOOT, "Admin Reboot" }, 1929842565f2Syasuoka { RADIUS_TERMNATE_CAUSE_PORT_ERROR, "Port Error" }, 1930842565f2Syasuoka { RADIUS_TERMNATE_CAUSE_NAS_ERROR, "NAS Error" }, 1931842565f2Syasuoka { RADIUS_TERMNATE_CAUSE_NAS_RESET, "NAS Request" }, 1932842565f2Syasuoka { RADIUS_TERMNATE_CAUSE_NAS_REBOOT, "NAS Reboot" }, 1933842565f2Syasuoka { RADIUS_TERMNATE_CAUSE_PORT_UNNEEDED, "Port Unneeded" }, 1934842565f2Syasuoka { RADIUS_TERMNATE_CAUSE_PORT_PREEMPTED, "Port Preempted" }, 1935842565f2Syasuoka { RADIUS_TERMNATE_CAUSE_PORT_SUSPENDED, "Port Suspended" }, 1936842565f2Syasuoka { RADIUS_TERMNATE_CAUSE_SERVICE_UNAVAIL, "Service Unavailable" }, 1937842565f2Syasuoka { RADIUS_TERMNATE_CAUSE_CALLBACK, "Callback" }, 1938842565f2Syasuoka { RADIUS_TERMNATE_CAUSE_USER_ERROR, "User Error" }, 1939842565f2Syasuoka { RADIUS_TERMNATE_CAUSE_HOST_REQUEST, "Host Request" }, 1940842565f2Syasuoka }; 1941842565f2Syasuoka 1942842565f2Syasuoka for (i = 0; i < nitems(terminate_causes); i++) { 1943842565f2Syasuoka if (terminate_causes[i].constval == val) 1944842565f2Syasuoka return (terminate_causes[i].label); 1945842565f2Syasuoka } 1946842565f2Syasuoka 1947842565f2Syasuoka return (NULL); 1948842565f2Syasuoka } 1949842565f2Syasuoka 1950842565f2Syasuoka const char * 1951842565f2Syasuoka radius_error_cause_string(unsigned val) 1952842565f2Syasuoka { 1953842565f2Syasuoka unsigned int i; 1954842565f2Syasuoka struct { 1955842565f2Syasuoka const unsigned constval; 1956842565f2Syasuoka const char *label; 1957842565f2Syasuoka } error_causes[] = { 1958842565f2Syasuoka { RADIUS_ERROR_CAUSE_RESIDUAL_SESSION_REMOVED, 1959842565f2Syasuoka "Residual Session Context Removed" }, 1960842565f2Syasuoka { RADIUS_ERROR_CAUSE_INVALID_EAP_PACKET, 1961842565f2Syasuoka "Invalid EAP Packet (Ignored)" }, 1962842565f2Syasuoka { RADIUS_ERROR_CAUSE_UNSUPPORTED_ATTRIBUTE, 1963842565f2Syasuoka "Unsupported Attribute" }, 1964842565f2Syasuoka { RADIUS_ERROR_CAUSE_MISSING_ATTRIBUTE, 1965842565f2Syasuoka "Missing Attribute" }, 1966842565f2Syasuoka { RADIUS_ERROR_CAUSE_NAS_IDENTIFICATION_MISMATCH, 1967842565f2Syasuoka "NAS Identification Mismatch" }, 1968842565f2Syasuoka { RADIUS_ERROR_CAUSE_INVALID_REQUEST, 1969842565f2Syasuoka "Invalid Request" }, 1970842565f2Syasuoka { RADIUS_ERROR_CAUSE_UNSUPPORTED_SERVICE, 1971842565f2Syasuoka "Unsupported Service" }, 1972842565f2Syasuoka { RADIUS_ERROR_CAUSE_UNSUPPORTED_EXTENSION, 1973842565f2Syasuoka "Unsupported Extension" }, 1974842565f2Syasuoka { RADIUS_ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE, 1975a06d4bddSyasuoka "Invalid Attribute Value" }, 1976842565f2Syasuoka { RADIUS_ERROR_CAUSE_ADMINISTRATIVELY_PROHIBITED, 1977842565f2Syasuoka "Administratively Prohibited" }, 1978842565f2Syasuoka { RADIUS_ERROR_CAUSE_REQUEST_NOT_ROUTABLE, 1979842565f2Syasuoka "Request Not Routable (Proxy)" }, 1980842565f2Syasuoka { RADIUS_ERROR_CAUSE_SESSION_NOT_FOUND, 1981842565f2Syasuoka "Session Context Not Found" }, 1982842565f2Syasuoka { RADIUS_ERROR_CAUSE_SESSION_NOT_REMOVABLE, 1983842565f2Syasuoka "Session Context Not Removable" }, 1984842565f2Syasuoka { RADIUS_ERROR_CAUSE_OTHER_PROXY_PROCESSING_ERROR, 1985842565f2Syasuoka "Other Proxy Processing Error" }, 1986842565f2Syasuoka { RADIUS_ERROR_CAUSE_RESOURCES_UNAVAILABLE, 1987842565f2Syasuoka "Resources Unavailable" }, 1988842565f2Syasuoka { RADIUS_ERROR_CAUSE_REQUEST_INITIATED, 1989842565f2Syasuoka "equest Initiated" }, 1990842565f2Syasuoka { RADIUS_ERROR_CAUSE_MULTI_SELECTION_UNSUPPORTED, 1991842565f2Syasuoka "Multiple Session Selection Unsupported" } 1992842565f2Syasuoka }; 1993842565f2Syasuoka 1994842565f2Syasuoka for (i = 0; i < nitems(error_causes); i++) { 1995842565f2Syasuoka if (error_causes[i].constval == val) 1996842565f2Syasuoka return (error_causes[i].label); 1997842565f2Syasuoka } 1998842565f2Syasuoka 1999842565f2Syasuoka return (NULL); 2000842565f2Syasuoka } 2001842565f2Syasuoka 2002842565f2Syasuoka int 2003842565f2Syasuoka parse_addr(const char *str0, int af, struct sockaddr *sa, socklen_t salen) 2004842565f2Syasuoka { 2005842565f2Syasuoka int error; 2006842565f2Syasuoka char *str, *end, *colon, *colon0, *addr = NULL, *port = NULL; 2007842565f2Syasuoka char *sb, *sb0; 2008842565f2Syasuoka struct addrinfo hints, *ai; 2009842565f2Syasuoka 2010842565f2Syasuoka if ((str = strdup(str0)) == NULL) 2011842565f2Syasuoka return (-1); 2012842565f2Syasuoka if (*str == '[' && (end = strchr(str + 1, ']')) != NULL) { 2013842565f2Syasuoka addr = str + 1; 2014842565f2Syasuoka *end = '\0'; 2015842565f2Syasuoka if (*(end + 1) == ':') 2016842565f2Syasuoka port = end + 2; 2017842565f2Syasuoka else if (*(end + 1) == '[' && (sb = strrchr(end + 2, ']')) 2018842565f2Syasuoka != NULL) { 2019842565f2Syasuoka port = end + 2; 2020842565f2Syasuoka *sb = '\0'; 2021842565f2Syasuoka } 2022842565f2Syasuoka } else if ((sb0 = strchr(str, '[')) != NULL && 2023842565f2Syasuoka (sb = strrchr(sb0 + 1, ']')) != NULL && sb0 < sb) { 2024842565f2Syasuoka addr = str; 2025842565f2Syasuoka *sb0 = '\0'; 2026842565f2Syasuoka port = sb0 + 1; 2027842565f2Syasuoka *sb = '\0'; 2028842565f2Syasuoka } else if ((colon0 = strchr(str, ':')) != NULL && 2029842565f2Syasuoka (colon = strrchr(str, ':')) != NULL && colon0 == colon) { 2030842565f2Syasuoka /* has one : */ 2031842565f2Syasuoka addr = str; 2032842565f2Syasuoka *colon = '\0'; 2033842565f2Syasuoka port = colon + 1; 2034842565f2Syasuoka } else { 2035842565f2Syasuoka addr = str; 2036842565f2Syasuoka port = NULL; 2037842565f2Syasuoka } 2038842565f2Syasuoka 2039842565f2Syasuoka memset(&hints, 0, sizeof(hints)); 2040842565f2Syasuoka hints.ai_family = af; 2041842565f2Syasuoka hints.ai_socktype = SOCK_DGRAM; 2042842565f2Syasuoka hints.ai_flags = AI_NUMERICHOST; 2043842565f2Syasuoka if (port != NULL) 2044842565f2Syasuoka hints.ai_flags |= AI_NUMERICSERV; 2045842565f2Syasuoka if ((error = getaddrinfo(addr, port, &hints, &ai)) != 0) { 2046842565f2Syasuoka free(str); 2047842565f2Syasuoka return (-1); 2048842565f2Syasuoka } 2049c0c32a87Syasuoka free(str); 2050842565f2Syasuoka if (salen < ai->ai_addrlen) { 2051842565f2Syasuoka freeaddrinfo(ai); 2052842565f2Syasuoka return (-1); 2053842565f2Syasuoka } 2054842565f2Syasuoka memcpy(sa, ai->ai_addr, ai->ai_addrlen); 2055842565f2Syasuoka freeaddrinfo(ai); 2056842565f2Syasuoka 2057842565f2Syasuoka return (0); 2058842565f2Syasuoka } 2059842565f2Syasuoka 2060842565f2Syasuoka const char * 2061842565f2Syasuoka print_addr(struct sockaddr *sa, char *buf, size_t bufsiz) 2062842565f2Syasuoka { 2063842565f2Syasuoka int noport, ret; 2064842565f2Syasuoka char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; 2065842565f2Syasuoka 2066842565f2Syasuoka if (ntohs(((struct sockaddr_in *)sa)->sin_port) == 0) { 2067842565f2Syasuoka noport = 1; 2068842565f2Syasuoka ret = getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, 2069842565f2Syasuoka NI_NUMERICHOST); 2070842565f2Syasuoka } else { 2071842565f2Syasuoka noport = 0; 2072842565f2Syasuoka ret = getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), sbuf, 2073842565f2Syasuoka sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV); 2074842565f2Syasuoka } 2075842565f2Syasuoka if (ret != 0) 2076842565f2Syasuoka return ""; 2077842565f2Syasuoka if (noport) 2078842565f2Syasuoka strlcpy(buf, hbuf, bufsiz); 2079842565f2Syasuoka else if (sa->sa_family == AF_INET6) 2080842565f2Syasuoka snprintf(buf, bufsiz, "[%s]:%s", hbuf, sbuf); 2081842565f2Syasuoka else 2082842565f2Syasuoka snprintf(buf, bufsiz, "%s:%s", hbuf, sbuf); 2083842565f2Syasuoka 2084842565f2Syasuoka return (buf); 2085842565f2Syasuoka } 2086