radius.c revision 1.1
1/* $OpenBSD: radius.c,v 1.1 2024/03/24 00:05:01 yasuoka Exp $ */ 2 3/* 4 * Copyright (c) 2024 Internet Initiative Japan Inc. 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/types.h> 20#include <sys/queue.h> 21#include <sys/socket.h> 22#include <sys/time.h> 23#include <arpa/inet.h> 24#include <netinet/ip_ipsp.h> 25 26#include <endian.h> 27#include <event.h> 28#include <errno.h> 29#include <imsg.h> 30#include <limits.h> 31#include <netinet/in.h> 32#include <radius.h> 33#include <stdint.h> 34#include <stdio.h> 35#include <stdlib.h> 36#include <string.h> 37#include <strings.h> 38#include <time.h> 39 40#include "iked.h" 41#include "eap.h" 42#include "ikev2.h" 43#include "types.h" 44 45void iked_radius_request_send(struct iked *, void *); 46void iked_radius_config(struct iked_radserver_req *, const RADIUS_PACKET *, 47 int, uint32_t, uint8_t); 48void iked_radius_acct_request(struct iked *, struct iked_sa *, uint8_t); 49 50const struct iked_radcfgmap radius_cfgmaps[] = { 51 { IKEV2_CFG_INTERNAL_IP4_ADDRESS, 0, RADIUS_TYPE_FRAMED_IP_ADDRESS }, 52 { IKEV2_CFG_INTERNAL_IP4_NETMASK, 0, RADIUS_TYPE_FRAMED_IP_NETMASK }, 53 { IKEV2_CFG_INTERNAL_IP4_DNS, RADIUS_VENDOR_MICROSOFT, 54 RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER }, 55 { IKEV2_CFG_INTERNAL_IP4_DNS, RADIUS_VENDOR_MICROSOFT, 56 RADIUS_VTYPE_MS_SECONDARY_DNS_SERVER }, 57 { IKEV2_CFG_INTERNAL_IP4_NBNS, RADIUS_VENDOR_MICROSOFT, 58 RADIUS_VTYPE_MS_PRIMARY_NBNS_SERVER }, 59 { IKEV2_CFG_INTERNAL_IP4_NBNS, RADIUS_VENDOR_MICROSOFT, 60 RADIUS_VTYPE_MS_SECONDARY_NBNS_SERVER }, 61 { 0 } 62}; 63 64int 65iked_radius_request(struct iked *env, struct iked_sa *sa, 66 struct iked_message *msg) 67{ 68 struct eap_message *eap; 69 RADIUS_PACKET *pkt; 70 size_t len; 71 72 eap = ibuf_data(msg->msg_eapmsg); 73 len = betoh16(eap->eap_length); 74 if (eap->eap_code != EAP_CODE_RESPONSE) { 75 log_debug("%s: eap_code is not response %u", __func__, 76 (unsigned)eap->eap_code); 77 return -1; 78 } 79 80 if (eap->eap_type == EAP_TYPE_IDENTITY) { 81 if ((sa->sa_radreq = calloc(1, 82 sizeof(struct iked_radserver_req))) == NULL) { 83 log_debug( 84 "%s: calloc failed for iked_radserver_req: %s", 85 __func__, strerror(errno)); 86 return (-1); 87 } 88 timer_set(env, &sa->sa_radreq->rr_timer, 89 iked_radius_request_send, sa->sa_radreq); 90 sa->sa_radreq->rr_user = strdup(msg->msg_eap.eam_identity); 91 } 92 93 if ((pkt = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST)) 94 == NULL) { 95 log_debug("%s: radius_new_request_packet failed %s", __func__, 96 strerror(errno)); 97 return -1; 98 } 99 100 radius_put_string_attr(pkt, RADIUS_TYPE_USER_NAME, 101 sa->sa_radreq->rr_user); 102 if (sa->sa_radreq->rr_state != NULL) 103 radius_put_raw_attr(pkt, RADIUS_TYPE_STATE, 104 ibuf_data(sa->sa_radreq->rr_state), 105 ibuf_size(sa->sa_radreq->rr_state)); 106 107 if (radius_put_raw_attr_cat(pkt, RADIUS_TYPE_EAP_MESSAGE, 108 (uint8_t *)eap, len) == -1) { 109 log_debug("%s: radius_put_raw_attr_cat failed %s", __func__, 110 strerror(errno)); 111 return -1; 112 } 113 114 /* save the request, it'll be needed for message authentication */ 115 if (sa->sa_radreq->rr_reqpkt != NULL) 116 radius_delete_packet(sa->sa_radreq->rr_reqpkt); 117 sa->sa_radreq->rr_reqpkt = pkt; 118 sa->sa_radreq->rr_sa = sa; 119 sa->sa_radreq->rr_ntry = 0; 120 121 iked_radius_request_send(env, sa->sa_radreq); 122 123 return 0; 124} 125 126void 127iked_radius_request_free(struct iked *env, struct iked_radserver_req *req) 128{ 129 if (req == NULL) 130 return; 131 timer_del(env, &req->rr_timer); 132 free(req->rr_user); 133 ibuf_free(req->rr_state); 134 if (req->rr_reqpkt) 135 radius_delete_packet(req->rr_reqpkt); 136 if (req->rr_sa) 137 req->rr_sa->sa_radreq = NULL; 138 if (req->rr_server) 139 TAILQ_REMOVE(&req->rr_server->rs_reqs, req, rr_entry); 140 free(req); 141} 142 143void 144iked_radius_on_event(int fd, short ev, void *ctx) 145{ 146 struct iked *env; 147 struct iked_radserver *server = ctx; 148 struct iked_radserver_req *req; 149 const struct iked_radcfgmap *cfgmap; 150 RADIUS_PACKET *pkt; 151 int i, resid; 152 struct ibuf *e; 153 const void *attrval; 154 size_t attrlen; 155 uint8_t code; 156 u_char eapmsk[128]; 157 /* RFC 3748 defines the MSK minimum size is 64 bytes */ 158 size_t eapmsksiz = sizeof(eapmsk); 159 160 env = server->rs_env; 161 pkt = radius_recv(server->rs_sock, 0); 162 if (pkt == NULL) { 163 log_info("%s: receiving a RADIUS message failed: %s", __func__, 164 strerror(errno)); 165 return; 166 } 167 resid = radius_get_id(pkt); 168 169 TAILQ_FOREACH(req, &server->rs_reqs, rr_entry) { 170 if (req->rr_reqid == resid) 171 break; 172 } 173 if (req == NULL) { 174 log_debug("%s: received an unknown RADIUS message: id=%u", 175 __func__, (unsigned)resid); 176 return; 177 } 178 179 radius_set_request_packet(pkt, req->rr_reqpkt); 180 if (radius_check_response_authenticator(pkt, server->rs_secret) != 0) { 181 log_info("%s: received an invalid RADIUS message: bad " 182 "response authenticator", __func__); 183 return; 184 } 185 if (req->rr_accounting) { 186 /* accounting */ 187 code = radius_get_code(pkt); 188 switch (code) { 189 case RADIUS_CODE_ACCOUNTING_RESPONSE: /* Expected */ 190 break; 191 default: 192 log_info("%s: received an invalid RADIUS message: " 193 "code %u", __func__, (unsigned)code); 194 } 195 timer_del(env, &req->rr_timer); 196 TAILQ_REMOVE(&server->rs_reqs, req, rr_entry); 197 req->rr_server = NULL; 198 free(req); 199 return; 200 } 201 202 /* authentication */ 203 if (radius_check_message_authenticator(pkt, server->rs_secret) != 0) { 204 log_info("%s: received an invalid RADIUS message: bad " 205 "message authenticator", __func__); 206 return; 207 } 208 209 timer_del(env, &req->rr_timer); 210 req->rr_ntry = 0; 211 212 if (req->rr_sa == NULL) 213 goto fail; 214 215 code = radius_get_code(pkt); 216 switch (code) { 217 case RADIUS_CODE_ACCESS_CHALLENGE: 218 if (radius_get_raw_attr_ptr(pkt, RADIUS_TYPE_STATE, &attrval, 219 &attrlen) != 0) { 220 log_info("%s: received an invalid RADIUS message: no " 221 "state attribute", __func__); 222 goto fail; 223 } 224 if ((req->rr_state != NULL && 225 ibuf_set(req->rr_state, 0, attrval, attrlen) != 0) || 226 (req->rr_state = ibuf_new(attrval, attrlen)) == NULL) { 227 log_info("%s: ibuf_new() failed: %s", __func__, 228 strerror(errno)); 229 goto fail; 230 } 231 break; 232 case RADIUS_CODE_ACCESS_ACCEPT: 233 log_info("%s: received Access-Accept for %s", 234 SPI_SA(req->rr_sa, __func__), req->rr_user); 235 /* Try to retrieve the EAP MSK from the RADIUS response */ 236 if (radius_get_eap_msk(pkt, eapmsk, &eapmsksiz, 237 server->rs_secret) == 0) { 238 ibuf_free(req->rr_sa->sa_eapmsk); 239 if ((req->rr_sa->sa_eapmsk = ibuf_new(eapmsk, 240 eapmsksiz)) == NULL) { 241 log_info("%s: ibuf_new() failed: %s", __func__, 242 strerror(errno)); 243 goto fail; 244 } 245 } else 246 log_debug("Could not retrieve the EAP MSK from the " 247 "RADIUS message"); 248 free(req->rr_sa->sa_eapid); 249 req->rr_sa->sa_eapid = req->rr_user; 250 req->rr_user = NULL; 251 sa_state(env, req->rr_sa, IKEV2_STATE_AUTH_SUCCESS); 252 253 /* Map RADIUS attributes to cp */ 254 if (TAILQ_EMPTY(&env->sc_radcfgmaps)) { 255 for (i = 0; radius_cfgmaps[i].cfg_type != 0; i++) { 256 cfgmap = &radius_cfgmaps[i]; 257 iked_radius_config(req, pkt, cfgmap->cfg_type, 258 cfgmap->vendor_id, cfgmap->attr_type); 259 } 260 } else { 261 TAILQ_FOREACH(cfgmap, &env->sc_radcfgmaps, entry) 262 iked_radius_config(req, pkt, cfgmap->cfg_type, 263 cfgmap->vendor_id, cfgmap->attr_type); 264 } 265 266 TAILQ_REMOVE(&server->rs_reqs, req, rr_entry); 267 req->rr_server = NULL; 268 break; 269 case RADIUS_CODE_ACCESS_REJECT: 270 log_info("%s: received Access-Reject for %s", 271 SPI_SA(req->rr_sa, __func__), req->rr_user); 272 TAILQ_REMOVE(&server->rs_reqs, req, rr_entry); 273 req->rr_server = NULL; 274 break; 275 default: 276 log_debug("%s: received an invalid RADIUS message: code %u", 277 __func__, (unsigned)code); 278 break; 279 } 280 281 /* get the length first */ 282 if (radius_get_raw_attr_cat(pkt, RADIUS_TYPE_EAP_MESSAGE, NULL, 283 &attrlen) != 0) { 284 log_info("%s: failed to retrieve the EAP message", __func__); 285 goto fail; 286 } 287 /* allocate a buffer */ 288 if ((e = ibuf_new(NULL, attrlen)) == NULL) { 289 log_info("%s: ibuf_new() failed: %s", __func__, 290 strerror(errno)); 291 goto fail; 292 } 293 /* copy the message to the buffer */ 294 if (radius_get_raw_attr_cat(pkt, RADIUS_TYPE_EAP_MESSAGE, 295 ibuf_data(e), &attrlen) != 0) { 296 ibuf_free(e); 297 log_info("%s: failed to retrieve the EAP message", __func__); 298 goto fail; 299 } 300 ikev2_send_ike_e(env, req->rr_sa, e, IKEV2_PAYLOAD_EAP, 301 IKEV2_EXCHANGE_IKE_AUTH, 1); 302 return; 303 fail: 304 if (req->rr_server != NULL) 305 TAILQ_REMOVE(&server->rs_reqs, req, rr_entry); 306 req->rr_server = NULL; 307 if (req->rr_sa != NULL) { 308 ikev2_ike_sa_setreason(req->rr_sa, "RADIUS request failed"); 309 sa_free(env, req->rr_sa); 310 } 311} 312 313void 314iked_radius_request_send(struct iked *env, void *ctx) 315{ 316 struct iked_radserver_req *req = ctx, *req0; 317 struct iked_radserver *server = req->rr_server; 318 const int timeouts[] = { 2, 4, 8 }; 319 uint8_t seq; 320 int i, max_tries, max_failovers; 321 struct sockaddr_storage ss; 322 socklen_t sslen; 323 struct iked_radservers *radservers; 324 struct timespec now; 325 326 if (!req->rr_accounting) { 327 max_tries = env->sc_radauth.max_tries; 328 max_failovers = env->sc_radauth.max_failovers; 329 radservers = &env->sc_radauthservers; 330 } else { 331 max_tries = env->sc_radacct.max_tries; 332 max_failovers = env->sc_radacct.max_failovers; 333 radservers = &env->sc_radacctservers; 334 } 335 336 if (req->rr_ntry > max_tries) { 337 req->rr_ntry = 0; 338 log_info("%s: RADIUS server %s failed", __func__, 339 print_addr(&server->rs_sockaddr)); 340 next_server: 341 TAILQ_REMOVE(&server->rs_reqs, req, rr_entry); 342 req->rr_server = NULL; 343 if (req->rr_nfailover >= max_failovers || 344 TAILQ_NEXT(server, rs_entry) == NULL) { 345 log_info("%s: No more RADIUS server", __func__); 346 goto fail; 347 } else if (req->rr_state != NULL) { 348 log_info("%s: Can't change RADIUS server: " 349 "client has a state already", __func__); 350 goto fail; 351 } else { 352 TAILQ_REMOVE(radservers, server, rs_entry); 353 TAILQ_INSERT_TAIL(radservers, server, rs_entry); 354 server = TAILQ_FIRST(radservers); 355 log_info("%s: RADIUS server %s is active", 356 __func__, print_addr(&server->rs_sockaddr)); 357 } 358 req->rr_nfailover++; 359 } 360 361 if (req->rr_server != NULL && 362 req->rr_server != TAILQ_FIRST(radservers)) { 363 /* Current server is marked fail */ 364 if (req->rr_state != NULL || req->rr_nfailover >= max_failovers) 365 goto fail; /* can't fail over */ 366 TAILQ_REMOVE(&server->rs_reqs, req, rr_entry); 367 req->rr_server = NULL; 368 req->rr_nfailover++; 369 } 370 371 if (req->rr_server == NULL) { 372 /* Select a new server */ 373 server = TAILQ_FIRST(radservers); 374 if (server == NULL) { 375 log_info("%s: No RADIUS server is configured", 376 __func__); 377 goto fail; 378 } 379 TAILQ_INSERT_TAIL(&server->rs_reqs, req, rr_entry); 380 req->rr_server = server; 381 382 /* Prepare NAS-IP-Address */ 383 if (server->rs_nas_ipv4.s_addr == INADDR_ANY && 384 IN6_IS_ADDR_UNSPECIFIED(&server->rs_nas_ipv6)) { 385 sslen = sizeof(ss); 386 if (getsockname(server->rs_sock, (struct sockaddr *)&ss, 387 &sslen) == 0) { 388 if (ss.ss_family == AF_INET) 389 server->rs_nas_ipv4 = 390 ((struct sockaddr_in *)&ss) 391 ->sin_addr; 392 else 393 server->rs_nas_ipv6 = 394 ((struct sockaddr_in6 *)&ss) 395 ->sin6_addr; 396 } 397 } 398 } 399 if (req->rr_ntry == 0) { 400 /* decide the ID */ 401 seq = ++server->rs_reqseq; 402 for (i = 0; i < UCHAR_MAX; i++) { 403 TAILQ_FOREACH(req0, &server->rs_reqs, rr_entry) { 404 if (req0->rr_reqid == seq) 405 break; 406 } 407 if (req0 == NULL) 408 break; 409 seq++; 410 } 411 if (i >= UCHAR_MAX) { 412 log_info("%s: RADIUS server %s failed. Too many " 413 "pending requests", __func__, 414 print_addr(&server->rs_sockaddr)); 415 if (TAILQ_NEXT(server, rs_entry) != NULL) 416 goto next_server; 417 goto fail; 418 } 419 req->rr_reqid = seq; 420 radius_set_id(req->rr_reqpkt, req->rr_reqid); 421 } 422 423 if (server->rs_nas_ipv4.s_addr != INADDR_ANY) 424 radius_put_ipv4_attr(req->rr_reqpkt, RADIUS_TYPE_NAS_IP_ADDRESS, 425 server->rs_nas_ipv4); 426 else if (!IN6_IS_ADDR_UNSPECIFIED(&server->rs_nas_ipv6)) 427 radius_put_ipv6_attr(req->rr_reqpkt, 428 RADIUS_TYPE_NAS_IPV6_ADDRESS, &server->rs_nas_ipv6); 429 /* Identifier */ 430 radius_put_string_attr(req->rr_reqpkt, RADIUS_TYPE_NAS_IDENTIFIER, 431 "OpenIKED"); 432 433 /* NAS Port Type = Virtual */ 434 radius_put_uint32_attr(req->rr_reqpkt, 435 RADIUS_TYPE_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_VIRTUAL); 436 /* Service Type = Framed */ 437 radius_put_uint32_attr(req->rr_reqpkt, 438 RADIUS_TYPE_SERVICE_TYPE, RADIUS_SERVICE_TYPE_FRAMED); 439 440 if (req->rr_accounting) { 441 if (req->rr_ntry == 0 && req->rr_nfailover == 0) 442 radius_put_uint32_attr(req->rr_reqpkt, 443 RADIUS_TYPE_ACCT_DELAY_TIME, 0); 444 else { 445 clock_gettime(CLOCK_MONOTONIC, &now); 446 timespecsub(&now, &req->rr_accttime, &now); 447 radius_put_uint32_attr(req->rr_reqpkt, 448 RADIUS_TYPE_ACCT_DELAY_TIME, now.tv_sec); 449 } 450 radius_set_accounting_request_authenticator(req->rr_reqpkt, 451 server->rs_secret); 452 } else { 453 radius_put_message_authenticator(req->rr_reqpkt, 454 server->rs_secret); 455 } 456 457 if (radius_send(server->rs_sock, req->rr_reqpkt, 0) < 0) 458 log_info("%s: sending a RADIUS message failed: %s", __func__, 459 strerror(errno)); 460 461 if (req->rr_ntry >= (int)nitems(timeouts)) 462 timer_add(env, &req->rr_timer, timeouts[nitems(timeouts) - 1]); 463 else 464 timer_add(env, &req->rr_timer, timeouts[req->rr_ntry]); 465 req->rr_ntry++; 466 return; 467 fail: 468 if (req->rr_server != NULL) 469 TAILQ_REMOVE(&server->rs_reqs, req, rr_entry); 470 req->rr_server = NULL; 471 if (req->rr_sa != NULL) { 472 ikev2_ike_sa_setreason(req->rr_sa, "RADIUS request failed"); 473 sa_free(env, req->rr_sa); 474 } 475} 476 477void 478iked_radius_config(struct iked_radserver_req *req, const RADIUS_PACKET *pkt, 479 int cfg_type, uint32_t vendor_id, uint8_t attr_type) 480{ 481 unsigned int i; 482 struct iked_sa *sa = req->rr_sa; 483 struct in_addr ia4; 484 struct in6_addr ia6; 485 struct sockaddr_in *sin4; 486 struct sockaddr_in6 *sin6; 487 struct iked_addr *addr; 488 struct iked_cfg *ikecfg; 489 490 for (i = 0; i < sa->sa_policy->pol_ncfg; i++) { 491 ikecfg = &sa->sa_policy->pol_cfg[i]; 492 if (ikecfg->cfg_type == cfg_type && 493 ikecfg->cfg_type != IKEV2_CFG_INTERNAL_IP4_ADDRESS) 494 return; /* use config rather than radius */ 495 } 496 switch (cfg_type) { 497 case IKEV2_CFG_INTERNAL_IP4_ADDRESS: 498 case IKEV2_CFG_INTERNAL_IP4_NETMASK: 499 case IKEV2_CFG_INTERNAL_IP4_DNS: 500 case IKEV2_CFG_INTERNAL_IP4_NBNS: 501 case IKEV2_CFG_INTERNAL_IP4_DHCP: 502 case IKEV2_CFG_INTERNAL_IP4_SERVER: 503 if (vendor_id == 0 && radius_has_attr(pkt, attr_type)) 504 radius_get_ipv4_attr(pkt, attr_type, &ia4); 505 else if (vendor_id != 0 && radius_has_vs_attr(pkt, vendor_id, 506 attr_type)) 507 radius_get_vs_ipv4_attr(pkt, vendor_id, attr_type, 508 &ia4); 509 else 510 break; /* no attribute contained */ 511 512 if (cfg_type == IKEV2_CFG_INTERNAL_IP4_NETMASK) { 513 /* 514 * This assumes IKEV2_CFG_INTERNAL_IP4_ADDRESS is 515 * called before IKEV2_CFG_INTERNAL_IP4_NETMASK 516 */ 517 if (sa->sa_rad_addr == NULL) { 518 /* 519 * RFC 7296, IKEV2_CFG_INTERNAL_IP4_NETMASK 520 * must be used with 521 * IKEV2_CFG_INTERNAL_IP4_ADDRESS 522 */ 523 break; 524 } 525 if (ia4.s_addr == 0) { 526 log_debug("%s: netmask is wrong", __func__); 527 break; 528 } 529 if (ia4.s_addr == htonl(0)) 530 sa->sa_rad_addr->addr_mask = 0; 531 else 532 sa->sa_rad_addr->addr_mask = 533 33 - ffs(ntohl(ia4.s_addr)); 534 if (sa->sa_rad_addr->addr_mask < 32) 535 sa->sa_rad_addr->addr_net = 1; 536 } 537 if (cfg_type == IKEV2_CFG_INTERNAL_IP4_ADDRESS) { 538 if ((addr = calloc(1, sizeof(*addr))) == NULL) { 539 log_warn("%s: calloc", __func__); 540 return; 541 } 542 sa->sa_rad_addr = addr; 543 } else { 544 req->rr_cfg[req->rr_ncfg].cfg_action = IKEV2_CP_REPLY; 545 req->rr_cfg[req->rr_ncfg].cfg_type = cfg_type; 546 addr = &req->rr_cfg[req->rr_ncfg].cfg.address; 547 req->rr_ncfg++; 548 } 549 addr->addr_af = AF_INET; 550 sin4 = (struct sockaddr_in *)&addr->addr; 551 sin4->sin_family = AF_INET; 552 sin4->sin_len = sizeof(struct sockaddr_in); 553 sin4->sin_addr = ia4; 554 break; 555 case IKEV2_CFG_INTERNAL_IP6_ADDRESS: 556 case IKEV2_CFG_INTERNAL_IP6_DNS: 557 case IKEV2_CFG_INTERNAL_IP6_NBNS: 558 case IKEV2_CFG_INTERNAL_IP6_DHCP: 559 case IKEV2_CFG_INTERNAL_IP6_SERVER: 560 if (vendor_id == 0 && radius_has_attr(pkt, attr_type)) 561 radius_get_ipv6_attr(pkt, attr_type, &ia6); 562 else if (vendor_id != 0 && radius_has_vs_attr(pkt, vendor_id, 563 attr_type)) 564 radius_get_vs_ipv6_attr(pkt, vendor_id, attr_type, 565 &ia6); 566 else 567 break; /* no attribute contained */ 568 569 if (cfg_type == IKEV2_CFG_INTERNAL_IP6_ADDRESS) { 570 if ((addr = calloc(1, sizeof(*addr))) == NULL) { 571 log_warn("%s: calloc", __func__); 572 return; 573 } 574 sa->sa_rad_addr = addr; 575 } else { 576 req->rr_cfg[req->rr_ncfg].cfg_action = IKEV2_CP_REPLY; 577 req->rr_cfg[req->rr_ncfg].cfg_type = cfg_type; 578 addr = &req->rr_cfg[req->rr_ncfg].cfg.address; 579 req->rr_ncfg++; 580 } 581 addr->addr_af = AF_INET; 582 sin6 = (struct sockaddr_in6 *)&addr->addr; 583 sin6->sin6_family = AF_INET6; 584 sin6->sin6_len = sizeof(struct sockaddr_in6); 585 sin6->sin6_addr = ia6; 586 break; 587 } 588 return; 589} 590 591void 592iked_radius_acct_on(struct iked *env) 593{ 594 if (TAILQ_EMPTY(&env->sc_radacctservers)) 595 return; 596 if (env->sc_radaccton == 0) { /* trigger once */ 597 iked_radius_acct_request(env, NULL, RADIUS_ACCT_STATUS_TYPE_ACCT_ON); 598 env->sc_radaccton = 1; 599 } 600} 601 602void 603iked_radius_acct_off(struct iked *env) 604{ 605 iked_radius_acct_request(env, NULL, RADIUS_ACCT_STATUS_TYPE_ACCT_OFF); 606} 607 608void 609iked_radius_acct_start(struct iked *env, struct iked_sa *sa) 610{ 611 iked_radius_acct_request(env, sa, RADIUS_ACCT_STATUS_TYPE_START); 612} 613 614void 615iked_radius_acct_stop(struct iked *env, struct iked_sa *sa) 616{ 617 iked_radius_acct_request(env, sa, RADIUS_ACCT_STATUS_TYPE_STOP); 618} 619 620void 621iked_radius_acct_request(struct iked *env, struct iked_sa *sa, uint8_t stype) 622{ 623 struct iked_radserver_req *req; 624 RADIUS_PACKET *pkt; 625 struct iked_addr *addr4 = NULL; 626 struct iked_addr *addr6 = NULL; 627 struct in_addr mask4; 628 char sa_id[IKED_ID_SIZE]; 629 char sid[16 + 1]; 630 struct timespec now; 631 int cause; 632 633 if (TAILQ_EMPTY(&env->sc_radacctservers)) 634 return; 635 /* 636 * In RFC2866 5.6, "Users who are delivered service without 637 * being authenticated SHOULD NOT generate Accounting records 638 */ 639 if (sa != NULL && sa->sa_eapid == NULL) { 640 /* fallback to IKEID for accounting */ 641 if (ikev2_print_id(IKESA_DSTID(sa), sa_id, sizeof(sa_id)) != -1) 642 sa->sa_eapid = strdup(sa_id); 643 if (sa->sa_eapid == NULL) 644 return; 645 } 646 647 if ((req = calloc(1, sizeof(struct iked_radserver_req))) == NULL) { 648 log_debug("%s: calloc faile for iked_radserver_req: %s", 649 __func__, strerror(errno)); 650 return; 651 } 652 req->rr_accounting = 1; 653 clock_gettime(CLOCK_MONOTONIC, &now); 654 req->rr_accttime = now; 655 timer_set(env, &req->rr_timer, iked_radius_request_send, req); 656 657 if ((pkt = radius_new_request_packet(RADIUS_CODE_ACCOUNTING_REQUEST)) 658 == NULL) { 659 log_debug("%s: radius_new_request_packet failed %s", __func__, 660 strerror(errno)); 661 return; 662 } 663 664 /* RFC 2866 5.1. Acct-Status-Type */ 665 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_STATUS_TYPE, stype); 666 667 if (sa == NULL) { 668 /* ASSERT(stype == RADIUS_ACCT_STATUS_TYPE_ACCT_ON || 669 stype == RADIUS_ACCT_STATUS_TYPE_ACCT_OFF) */ 670 req->rr_reqpkt = pkt; 671 req->rr_ntry = 0; 672 iked_radius_request_send(env, req); 673 return; 674 } 675 676 radius_put_string_attr(pkt, RADIUS_TYPE_USER_NAME, sa->sa_eapid); 677 678 /* RFC 2866 5.5. Acct-Session-Id */ 679 snprintf(sid, sizeof(sid), "%016llx", 680 (unsigned long long)sa->sa_hdr.sh_ispi); 681 radius_put_string_attr(pkt, RADIUS_TYPE_ACCT_SESSION_ID, sid); 682 683 /* Accounting Request must have Framed-IP-Address */ 684 addr4 = sa->sa_addrpool; 685 if (addr4 != NULL) { 686 radius_put_ipv4_attr(pkt, RADIUS_TYPE_FRAMED_IP_ADDRESS, 687 ((struct sockaddr_in *)&addr4->addr)->sin_addr); 688 if (addr4->addr_mask != 0) { 689 mask4.s_addr = htonl( 690 0xFFFFFFFFUL << (32 - addr4->addr_mask)); 691 radius_put_ipv4_attr(pkt, 692 RADIUS_TYPE_FRAMED_IP_NETMASK, mask4); 693 } 694 } 695 addr6 = sa->sa_addrpool6; 696 if (addr6 != NULL) 697 radius_put_ipv6_attr(pkt, RADIUS_TYPE_FRAMED_IPV6_ADDRESS, 698 &((struct sockaddr_in6 *)&addr6->addr)->sin6_addr); 699 700 /* RFC2866 5.6 Acct-Authentic */ 701 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_AUTHENTIC, 702 (sa->sa_radreq != NULL)? RADIUS_ACCT_AUTHENTIC_RADIUS : 703 RADIUS_ACCT_AUTHENTIC_LOCAL); 704 705 switch (stype) { 706 case RADIUS_ACCT_STATUS_TYPE_START: 707 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_STATUS_TYPE, 708 RADIUS_ACCT_STATUS_TYPE_START); 709 break; 710 case RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE: 711 case RADIUS_ACCT_STATUS_TYPE_STOP: 712 /* RFC 2866 5.7. Acct-Session-Time */ 713 timespecsub(&now, &sa->sa_starttime, &now); 714 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_SESSION_TIME, 715 now.tv_sec); 716 /* RFC 2866 5.10 Acct-Terminate-Cause */ 717 cause = RADIUS_TERMNATE_CAUSE_SERVICE_UNAVAIL; 718 if (sa->sa_reason) { 719 if (strcmp(sa->sa_reason, "received delete") == 0) { 720 cause = RADIUS_TERMNATE_CAUSE_USER_REQUEST; 721 } else if (strcmp(sa->sa_reason, "SA rekeyed") == 0) { 722 cause = RADIUS_TERMNATE_CAUSE_SESSION_TIMEOUT; 723 } else if (strncmp(sa->sa_reason, "retransmit", 724 strlen("retransmit")) == 0) { 725 cause = RADIUS_TERMNATE_CAUSE_LOST_SERVICE; 726 } 727 } 728 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_TERMINATE_CAUSE, 729 cause); 730 /* I/O statistics {Input,Output}-{Packets,Octets,Gigawords} */ 731 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_INPUT_PACKETS, 732 sa->sa_stats.sas_ipackets); 733 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_OUTPUT_PACKETS, 734 sa->sa_stats.sas_opackets); 735 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_INPUT_OCTETS, 736 sa->sa_stats.sas_ibytes & 0xffffffffUL); 737 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_OUTPUT_OCTETS, 738 sa->sa_stats.sas_obytes & 0xffffffffUL); 739 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_INPUT_GIGAWORDS, 740 sa->sa_stats.sas_ibytes >> 32); 741 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_OUTPUT_GIGAWORDS, 742 sa->sa_stats.sas_obytes >> 32); 743 radius_put_string_attr(pkt, RADIUS_TYPE_CALLED_STATION_ID, 744 print_addr(&sa->sa_local.addr)); 745 radius_put_string_attr(pkt, RADIUS_TYPE_CALLING_STATION_ID, 746 print_addr(&sa->sa_peer.addr)); 747 break; 748 } 749 req->rr_reqpkt = pkt; 750 req->rr_ntry = 0; 751 iked_radius_request_send(env, req); 752} 753