Changeset 516:1c2f5ee38039 in freeDiameter
- Timestamp:
- Aug 27, 2010, 10:59:51 AM (14 years ago)
- Branch:
- default
- Phase:
- public
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/app_radgw.conf.sample
r271 r516 49 49 ################## 50 50 51 # Each RADIUS client must be declared in the form: cli = IP / shared-secret ; 51 # Each RADIUS client must be declared in the form: 52 # nas = IP / shared-secret ; 52 53 # IP can be ipv4 or ipv6 53 54 # port can be additionaly restricted with brackets: IP[port] (ex: 192.168.0.1[1812]) 54 55 # shared-secret can be a quoted string, or a list of hexadecimal values. 55 56 # examples: 56 # cli= 192.168.100.1 / "secret key" ; # the shared secret buffer is 0x736563726574206b6579 (length 10 bytes)57 # cli= fe00::1 / 73 65 63 72 65 74 20 6b 65 79; # same shared secret as previously57 # nas = 192.168.100.1 / "secret key" ; # the shared secret buffer is 0x736563726574206b6579 (length 10 bytes) 58 # nas = fe00::1 / 73 65 63 72 65 74 20 6b 65 79; # same shared secret as previously 58 59 # When a packet is received from an IP not declared here, it is discarded. 60 61 # If the RADIUS client is a Proxy that forwards messages from different peers, it must be 62 # declared instead as follow: 63 # pxy = IP / shared-secret ; 64 # Note that it is not recommended to use this gateway implementation with a proxy currently, 65 # since the management of duplicate messages might be insufficient. 66 67 # The old notation cli = ... is equivalent to nas = ... and kept for backward compatibility. 59 68 60 69 -
extensions/app_radgw/radius.c
r254 r516 4 4 * It is redistributed under the terms of the BSD license, as allowed 5 5 * by the original copyright reproduced bellow. 6 * In addition to this notice, only the #include directives have been modified. 6 * In addition to this notice, the following changes have been done: 7 * - created the radius_msg_dump_attr_val function 7 8 */ 8 9 #include "rgw_common.h" … … 218 219 219 220 220 static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)221 void radius_msg_dump_attr_val(struct radius_attr_hdr *hdr) 221 222 { 222 223 struct radius_attr_type *attr; … … 225 226 226 227 attr = radius_get_attr_type(hdr->type); 227 228 printf(" Attribute %d (%s) length=%d\n",229 hdr->type, attr ? attr->name : "?Unknown?", hdr->length);230 228 231 229 if (attr == NULL) … … 283 281 break; 284 282 } 283 } 284 285 static void radius_msg_dump_attr(struct radius_attr_hdr *hdr) 286 { 287 struct radius_attr_type *attr; 288 289 attr = radius_get_attr_type(hdr->type); 290 291 printf(" Attribute %d (%s) length=%d\n", 292 hdr->type, attr ? attr->name : "?Unknown?", hdr->length); 293 294 radius_msg_dump_attr_val(hdr); 285 295 } 286 296 -
extensions/app_radgw/radius.h
r254 r516 4 4 * It is redistributed under the terms of the BSD license, as allowed 5 5 * by the original copyright reproduced bellow. 6 * The file has not been modified, except for this notice. 6 * The file has not been modified, except for this notice and 7 * declaration of: 8 * void radius_msg_dump_attr_val(struct radius_attr_hdr *hdr); 7 9 */ 10 8 11 /*********************************************************************************/ 9 12 … … 216 219 void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier); 217 220 void radius_msg_free(struct radius_msg *msg); 221 void radius_msg_dump_attr_val(struct radius_attr_hdr *hdr); 218 222 void radius_msg_dump(struct radius_msg *msg); 219 223 int radius_msg_finish(struct radius_msg *msg, const u8 *secret, -
extensions/app_radgw/rgw.h
r403 r516 58 58 /* The message has a valid Message-Authenticator attribute */ 59 59 unsigned valid_mac :1; 60 61 /* The message has a valid NAS-IP(v6)-Address (1) and/or NAS-Identifier (2) attribute */62 unsigned valid_nas_info :2;63 60 }; 64 61 … … 67 64 int rgw_msg_parse(unsigned char * buf, size_t len, struct rgw_radius_msg_meta ** msg); 68 65 void rgw_msg_dump(struct rgw_radius_msg_meta * msg); 69 int rgw_msg_auth_check(struct rgw_radius_msg_meta * msg, struct rgw_client * cli, uint8_t * req_auth);70 int rgw_msg_create_base(struct rgw_client * cli, struct msg ** diam);71 int rgw_msg_init(void);72 66 73 67 /* Local RADIUS server(s) configuration */ … … 97 91 98 92 /* Clients management */ 99 int rgw_clients_add( struct sockaddr * ip_port, unsigned char ** key, size_t keylen ); 93 enum rgw_cli_type { RGW_CLI_NAS, RGW_CLI_PXY }; 94 int rgw_clients_auth_check(struct rgw_radius_msg_meta * msg, struct rgw_client * cli, uint8_t * req_auth); 95 int rgw_clients_add( struct sockaddr * ip_port, unsigned char ** key, size_t keylen, enum rgw_cli_type type ); 100 96 int rgw_clients_getkey(struct rgw_client * cli, unsigned char **key, size_t *key_len); 97 int rgw_clients_gettype(struct rgw_client * cli, enum rgw_cli_type *type); 101 98 int rgw_clients_search(struct sockaddr * ip_port, struct rgw_client ** ref); 102 99 int rgw_clients_check_dup(struct rgw_radius_msg_meta **msg, struct rgw_client *cli); 103 int rgw_clients_c heck_origin(struct rgw_radius_msg_meta *msg, struct rgw_client *cli);100 int rgw_clients_create_origin(struct rgw_radius_msg_meta *msg, struct rgw_client * cli, struct msg ** diam); 104 101 int rgw_client_finish_send(struct radius_msg ** msg, struct rgw_radius_msg_meta * req, struct rgw_client * cli); 105 102 void rgw_clients_dispose(struct rgw_client ** ref); 106 103 void rgw_clients_dump(void); 104 int rgw_clients_init(void); 107 105 void rgw_clients_fini(void); 108 106 int rgw_client_session_add(struct rgw_client * cli, struct session *sess, char * dest_realm, char * dest_host, application_id_t appid); -
extensions/app_radgw/rgw_clients.c
r500 r516 40 40 #include "rgw.h" 41 41 42 #define REVERSE_DNS_SIZE_MAX 512 /* length of our buffer for reverse DNS */ 43 42 44 /* Ordered lists of clients. The order relationship is a memcmp on the address zone. 43 45 For same addresses, the port is compared. … … 67 69 /* The FQDN, realm, and optional aliases */ 68 70 int is_local; /* true if the RADIUS client runs on the same host -- we use Diameter Identity in that case */ 71 enum rgw_cli_type type; /* is it a proxy ? */ 69 72 char *fqdn; 70 73 size_t fqdn_len; … … 91 94 92 95 /* create a new rgw_client. the arguments are moved into the structure (to limit malloc & free calls). */ 93 static int client_create(struct rgw_client ** res, struct sockaddr ** ip_port, unsigned char ** key, size_t keylen )96 static int client_create(struct rgw_client ** res, struct sockaddr ** ip_port, unsigned char ** key, size_t keylen, enum rgw_cli_type type ) 94 97 { 95 98 struct rgw_client *tmp = NULL; … … 117 120 memset(tmp, 0, sizeof(struct rgw_client)); 118 121 fd_list_init(&tmp->chain, NULL); 122 123 tmp->type = type; 119 124 120 125 if (loc) { … … 231 236 } 232 237 238 int rgw_clients_gettype(struct rgw_client * cli, enum rgw_cli_type *type) 239 { 240 CHECK_PARAMS( cli && type ); 241 *type = cli->type; 242 return 0; 243 } 244 245 233 246 int rgw_clients_search(struct sockaddr * ip_port, struct rgw_client ** ref) 234 247 { … … 304 317 /* Check that the NAS-IP-Adress or NAS-Identifier is coherent with the IP the packet was received from */ 305 318 /* Also update the client list of aliases if needed */ 306 /* NOTE: This function will require changes to allow RADIUS Proxy on the path... */ 307 int rgw_clients_check_origin(struct rgw_radius_msg_meta *msg, struct rgw_client *cli) 319 /* NOTE: This function does nothing if the client is a RADIUS Proxy... */ 320 /* Check if the message has a valid authenticator, and update the meta-data accordingly */ 321 int rgw_clients_auth_check(struct rgw_radius_msg_meta * msg, struct rgw_client * cli, uint8_t * req_auth) 322 { 323 unsigned char * key; 324 size_t keylen; 325 int count; 326 327 TRACE_ENTRY("%p %p %p", msg, cli, req_auth); 328 329 CHECK_PARAMS(msg && cli); 330 331 CHECK_FCT(rgw_clients_getkey(cli, &key, &keylen)); 332 333 count = radius_msg_count_attr(&msg->radius, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 0); 334 if (count > 1) { 335 TRACE_DEBUG(INFO, "Too many Message-Authenticator attributes (%d), discarding message.", count); 336 return EINVAL; 337 } 338 if (count == 0) { 339 TRACE_DEBUG(FULL, "Message does not contain a Message-Authenticator attributes."); 340 msg->valid_mac = 0; 341 } else { 342 if (radius_msg_verify_msg_auth( &msg->radius, key, keylen, req_auth )) { 343 TRACE_DEBUG(INFO, "Invalid Message-Authenticator received, discarding message."); 344 return EINVAL; 345 } 346 msg->valid_mac = 1; 347 } 348 349 return 0; 350 } 351 352 static struct dict_object * cache_orig_host = NULL; 353 static struct dict_object * cache_orig_realm = NULL; 354 static struct dict_object * cache_route_record = NULL; 355 356 int rgw_clients_init(void) 357 { 358 TRACE_ENTRY(); 359 CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &cache_orig_host, ENOENT) ); 360 CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &cache_orig_realm, ENOENT) ); 361 CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Route-Record", &cache_route_record, ENOENT) ); 362 return 0; 363 } 364 365 366 /* The following function checks if a RADIUS message contains a valid NAS identifier, and initializes an empty Diameter 367 message with the appropriate routing information */ 368 int rgw_clients_create_origin(struct rgw_radius_msg_meta *msg, struct rgw_client * cli, struct msg ** diam) 308 369 { 309 370 int idx; 371 int valid_nas_info = 0; 310 372 struct radius_attr_hdr *nas_ip = NULL, *nas_ip6 = NULL, *nas_id = NULL; 311 312 TRACE_ENTRY("%p %p", msg, cli); 313 CHECK_PARAMS(msg && cli && !msg->valid_nas_info ); 314 373 char * oh_str = NULL; 374 char * or_str = NULL; 375 char * rr_str = NULL; 376 char buf[REVERSE_DNS_SIZE_MAX]; /* to store DNS lookups results */ 377 378 struct avp *avp = NULL; 379 union avp_value avp_val; 380 381 TRACE_ENTRY("%p %p %p", msg, cli, diam); 382 CHECK_PARAMS(msg && cli && diam && (*diam == NULL)); 383 315 384 /* Find the relevant attributes, if any */ 316 385 for (idx = 0; idx < msg->radius.attr_used; idx++) { … … 336 405 if (!nas_ip && !nas_ip6 && !nas_id) { 337 406 TRACE_DEBUG(FULL, "The message does not contain any NAS identification attribute."); 338 goto end; 407 408 /* Get information on this peer */ 409 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) ); 410 411 goto diameter; 339 412 } 340 413 … … 342 415 if (nas_ip && (cli->sa->sa_family == AF_INET) && !memcmp(nas_ip+1, &cli->sin->sin_addr, sizeof(struct in_addr))) { 343 416 TRACE_DEBUG(FULL, "NAS-IP-Address contains the same address as the message was received from."); 344 msg->valid_nas_info |= 1;417 valid_nas_info |= 1; 345 418 } 346 419 if (nas_ip6 && (cli->sa->sa_family == AF_INET6) && !memcmp(nas_ip6+1, &cli->sin6->sin6_addr, sizeof(struct in6_addr))) { 347 420 TRACE_DEBUG(FULL, "NAS-IPv6-Address contains the same address as the message was received from."); 348 msg->valid_nas_info |= 1; 349 } 350 351 /* If these conditions are not met, the message is probably forged (well, this might be false...) */ 352 if ((! msg->valid_nas_info) && (nas_ip || nas_ip6)) { 353 /* 354 In RADIUS it would be possible for a rogue NAS to forge the NAS-IP- 355 Address attribute value. Diameter/RADIUS translation agents MUST 356 check a received NAS-IP-Address or NAS-IPv6-Address attribute against 357 the source address of the RADIUS packet. If they do not match and 358 the Diameter/RADIUS translation agent does not know whether the 359 packet was sent by a RADIUS proxy or NAS (e.g., no Proxy-State 360 attribute), then by default it is assumed that the source address 361 corresponds to a RADIUS proxy, and that the NAS Address is behind 362 that proxy, potentially with some additional RADIUS proxies in 363 between. The Diameter/RADIUS translation agent MUST insert entries 364 in the Route-Record AVP corresponding to the apparent route. This 365 implies doing a reverse lookup on the source address and NAS-IP- 366 Address or NAS-IPv6-Address attributes to determine the corresponding 367 FQDNs. 368 369 If the source address and the NAS-IP-Address or NAS-IPv6-Address do 370 not match, and the Diameter/RADIUS translation agent knows that it is 371 talking directly to the NAS (e.g., there are no RADIUS proxies 372 between it and the NAS), then the error should be logged, and the 373 packet MUST be discarded. 374 375 Diameter agents and servers MUST check whether the NAS-IP-Address AVP 376 corresponds to an entry in the Route-Record AVP. This is done by 377 doing a reverse lookup (PTR RR) for the NAS-IP-Address to retrieve 378 the corresponding FQDN, and by checking for a match with the Route- 379 Record AVP. If no match is found, then an error is logged, but no 380 other action is taken. 381 */ 382 TRACE_DEBUG(INFO, "Message received with a NAS-IP-Address or NAS-IPv6-Address different from the sender's. Discarding..."); 383 return ENOTSUP; 384 } 385 386 /* Now check the nas_id, but only for non-local hosts */ 387 if (nas_id && (! cli->is_local) ) { 388 char * str; 421 valid_nas_info |= 2; 422 } 423 424 425 /* 426 In RADIUS it would be possible for a rogue NAS to forge the NAS-IP- 427 Address attribute value. Diameter/RADIUS translation agents MUST 428 check a received NAS-IP-Address or NAS-IPv6-Address attribute against 429 the source address of the RADIUS packet. If they do not match and 430 the Diameter/RADIUS translation agent does not know whether the 431 packet was sent by a RADIUS proxy or NAS (e.g., no Proxy-State 432 attribute), then by default it is assumed that the source address 433 corresponds to a RADIUS proxy, and that the NAS Address is behind 434 that proxy, potentially with some additional RADIUS proxies in 435 between. The Diameter/RADIUS translation agent MUST insert entries 436 in the Route-Record AVP corresponding to the apparent route. This 437 implies doing a reverse lookup on the source address and NAS-IP- 438 Address or NAS-IPv6-Address attributes to determine the corresponding 439 FQDNs. 440 441 If the source address and the NAS-IP-Address or NAS-IPv6-Address do 442 not match, and the Diameter/RADIUS translation agent knows that it is 443 talking directly to the NAS (e.g., there are no RADIUS proxies 444 between it and the NAS), then the error should be logged, and the 445 packet MUST be discarded. 446 447 Diameter agents and servers MUST check whether the NAS-IP-Address AVP 448 corresponds to an entry in the Route-Record AVP. This is done by 449 doing a reverse lookup (PTR RR) for the NAS-IP-Address to retrieve 450 the corresponding FQDN, and by checking for a match with the Route- 451 Record AVP. If no match is found, then an error is logged, but no 452 other action is taken. 453 */ 454 if (nas_ip || nas_ip6) { 455 if (!valid_nas_info) { 456 if (cli->type == RGW_CLI_NAS) { 457 TRACE_DEBUG(INFO, "Message received with a NAS-IP-Address or NAS-IPv6-Address different \nfrom the sender's. Please configure as Proxy if this is expected.\n Message discarded."); 458 return EINVAL; 459 } else { 460 /* the peer is configured as a proxy, so accept the message */ 461 sSS ss; 462 463 /* In that case, the cli will be stored as Route-Record and the NAS-IP-Address as origin */ 464 if (!cli->is_local) { 465 rr_str = cli->fqdn; 466 } 467 468 /* We must DNS-reverse the NAS-IP*-Address */ 469 memset(&ss, 0 , sizeof(sSS)); 470 if (nas_ip) { 471 sSA4 * sin = (sSA4 *)&ss; 472 sin->sin_family = AF_INET; 473 memcpy(&sin->sin_addr, nas_ip + 1, sizeof(struct in_addr)); 474 } else { 475 sSA6 * sin6 = (sSA6 *)&ss; 476 sin6->sin6_family = AF_INET6; 477 memcpy(&sin6->sin6_addr, nas_ip6 + 1, sizeof(struct in6_addr)); 478 } 479 CHECK_SYS_DO( getnameinfo( (sSA *)&ss, sSAlen(&ss), &buf[0], sizeof(buf), NULL, 0, NI_NAMEREQD), 480 { 481 TRACE_DEBUG(INFO, "The NAS-IP*-Address cannot be DNS reversed in order to create the Origin-Host AVP; rejecting the message (translation is impossible)."); 482 return EINVAL; 483 } ); 484 485 oh_str = &buf[0]; 486 or_str = strchr(oh_str, '.'); 487 if (or_str) { 488 or_str ++; /* move after the first dot */ 489 if (*or_str == '\0') 490 or_str = NULL; /* Discard this realm, we will use the local realm later */ 491 } 492 } 493 } else { 494 /* The attribute matches the source address, just use this in origin-host */ 495 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) ); 496 } 497 498 goto diameter; /* we ignore the nas_id in that case */ 499 } 500 501 /* We don't have a NAS-IP*-Address attribute if we are here */ 502 if (cli->is_local) { 503 /* Simple: we use our own configuration */ 504 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) ); 505 goto diameter; 506 } 507 508 /* At this point, we only have nas_id, and the client is not local */ 509 ASSERT(nas_id); 510 511 { 389 512 int found, ret; 390 513 struct addrinfo hint, *res, *ptr; … … 410 533 if ((cli->fqdn_len == (nas_id->length - sizeof(struct radius_attr_hdr))) 411 534 && (!strncasecmp((char *)(nas_id + 1), cli->fqdn, nas_id->length - sizeof(struct radius_attr_hdr)))) { 412 TRACE_DEBUG(FULL, "NAS-Identifier contains the fqdn of the NAS");535 TRACE_DEBUG(FULL, "NAS-Identifier contains the fqdn of the client"); 413 536 found = 1; 414 537 } else { … … 424 547 425 548 if (found) { 426 msg->valid_nas_info |= 2; 427 goto end; 428 } 429 430 /* copy the identifier, we try to DNS resolve it */ 431 CHECK_MALLOC( str = malloc(nas_id->length - sizeof(struct radius_attr_hdr) + 1) ); 432 memcpy(str, nas_id + 1, nas_id->length - sizeof(struct radius_attr_hdr)); 433 str[nas_id->length - sizeof(struct radius_attr_hdr)] = '\0'; 549 /* The NAS-Identifier matches the source IP */ 550 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) ); 551 552 goto diameter; 553 } 554 555 /* Attempt DNS resolution of the identifier */ 556 ASSERT( nas_id->length - sizeof(struct radius_attr_hdr) < sizeof(buf) ); 557 memcpy(buf, nas_id + 1, nas_id->length - sizeof(struct radius_attr_hdr)); 558 buf[nas_id->length - sizeof(struct radius_attr_hdr)] = '\0'; 434 559 435 560 /* Now check if this alias is valid for this peer */ 436 561 memset(&hint, 0, sizeof(hint)); 437 hint.ai_family = cli->sa->sa_family;438 562 hint.ai_flags = AI_CANONNAME; 439 ret = getaddrinfo( str, NULL, &hint, &res);563 ret = getaddrinfo(buf, NULL, &hint, &res); 440 564 if (ret == 0) { 441 /* The name was resolved correctly, it must match the IP of the client: */ 565 strncpy(buf, res->ai_canonname, sizeof(buf)); 566 /* The name was resolved correctly, does it match the IP of the client? */ 442 567 for (ptr = res; ptr != NULL; ptr = ptr->ai_next) { 443 568 if (cli->sa->sa_family != ptr->ai_family) … … 446 571 continue; 447 572 448 /* It matches: the alias is valid */449 573 found = 1; 450 574 break; … … 453 577 454 578 if (!found) { 455 TRACE_DEBUG(INFO, "The NAS-Identifier value '%s' resolves to a different IP from the NAS's, discarding the message.", str); 456 free(str); 457 return EINVAL; 579 if (cli->type == RGW_CLI_NAS) { 580 TRACE_DEBUG(INFO, "The NAS-Identifier value '%.*s' resolves to a different IP than the client's, discarding the message. \nConfigure this client as a Proxy if this message should be valid.", 581 nas_id->length - sizeof(struct radius_attr_hdr), nas_id + 1); 582 return EINVAL; 583 } else { 584 /* This identifier matches a different IP, assume it is a proxied message */ 585 if (!cli->is_local) { 586 rr_str = cli->fqdn; 587 } 588 oh_str = &buf[0]; /* The canonname resolved */ 589 or_str = strchr(oh_str, '.'); 590 if (or_str) { 591 or_str ++; /* move after the first dot */ 592 if (*or_str == '\0') 593 or_str = NULL; /* Discard this realm, we will use the local realm later */ 594 } 595 } 596 } else { 597 /* It is a valid alias, save it */ 598 CHECK_MALLOC( cli->aliases = realloc(cli->aliases, (cli->aliases_nb + 1) * sizeof(char *)) ); 599 CHECK_MALLOC( cli->aliases[cli->aliases_nb + 1] = malloc( 1 + nas_id->length - sizeof(struct radius_attr_hdr) )); 600 memcpy( cli->aliases[cli->aliases_nb + 1], nas_id + 1, nas_id->length - sizeof(struct radius_attr_hdr)); 601 *(cli->aliases[cli->aliases_nb + 1] + nas_id->length - sizeof(struct radius_attr_hdr)) = '\0'; 602 cli->aliases_nb ++; 603 TRACE_DEBUG(FULL, "Saved valid alias for client: '%s' -> '%s'", cli->aliases[cli->aliases_nb + 1], cli->fqdn); 604 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) ); 458 605 } 459 606 } else { 460 607 /* Error resolving the name */ 461 TRACE_DEBUG(INFO, "Error while resolving NAS-Identifier value '%s': %s. Ignoring...", str, gai_strerror(ret)); 462 } 463 464 /* It is a valid alias, save it */ 465 CHECK_MALLOC( cli->aliases = realloc(cli->aliases, (cli->aliases_nb + 1) * sizeof(char *)) ); 466 cli->aliases[cli->aliases_nb + 1] = str; 467 cli->aliases_nb ++; 468 TRACE_DEBUG(FULL, "Saved valid alias for client: '%s' -> '%s'", str, cli->fqdn); 469 msg->valid_nas_info |= 2; 470 } 471 end: 608 TRACE_DEBUG(INFO, "NAS-Identifier '%s' cannot be resolved: %s. Ignoring...", buf, gai_strerror(ret)); 609 /* Assume this is a valid identifier for the client */ 610 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) ); 611 } 612 } 613 614 /* Now, let's create the empty Diameter message with Origin-Host, -Realm, and Route-Record if needed. */ 615 diameter: 616 ASSERT(oh_str); /* If it is not defined here, there is a bug... */ 617 if (!or_str) 618 or_str = fd_g_config->cnf_diamrlm; /* Use local realm in that case */ 619 620 /* Create an empty Diameter message so that extensions can store their AVPs */ 621 CHECK_FCT( fd_msg_new ( NULL, MSGFL_ALLOC_ETEID, diam ) ); 622 623 /* Add the Origin-Host as next AVP */ 624 CHECK_FCT( fd_msg_avp_new ( cache_orig_host, 0, &avp ) ); 625 memset(&avp_val, 0, sizeof(avp_val)); 626 avp_val.os.data = (unsigned char *)oh_str; 627 avp_val.os.len = strlen(oh_str); 628 CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) ); 629 CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) ); 630 631 /* Add the Origin-Realm as next AVP */ 632 CHECK_FCT( fd_msg_avp_new ( cache_orig_realm, 0, &avp ) ); 633 memset(&avp_val, 0, sizeof(avp_val)); 634 avp_val.os.data = (unsigned char *)or_str; 635 avp_val.os.len = strlen(or_str); 636 CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) ); 637 CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) ); 638 639 if (rr_str) { 640 CHECK_FCT( fd_msg_avp_new ( cache_route_record, 0, &avp ) ); 641 memset(&avp_val, 0, sizeof(avp_val)); 642 avp_val.os.data = (unsigned char *)rr_str; 643 avp_val.os.len = strlen(rr_str); 644 CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) ); 645 CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) ); 646 } 647 648 /* Done! */ 472 649 return 0; 473 650 } … … 508 685 } 509 686 510 int rgw_clients_add( struct sockaddr * ip_port, unsigned char ** key, size_t keylen )687 int rgw_clients_add( struct sockaddr * ip_port, unsigned char ** key, size_t keylen, enum rgw_cli_type type ) 511 688 { 512 689 struct rgw_client * prev = NULL, *new = NULL; … … 517 694 CHECK_PARAMS( ip_port && key && *key && keylen ); 518 695 CHECK_PARAMS( (ip_port->sa_family == AF_INET) || (ip_port->sa_family == AF_INET6) ); 696 CHECK_PARAMS( (type == RGW_CLI_NAS) || (type == RGW_CLI_PXY) ); 519 697 520 698 /* Dump the entry in debug mode */ 521 699 if (TRACE_BOOL(FULL + 1 )) { 522 TRACE_DEBUG(FULL, "Adding client:");700 TRACE_DEBUG(FULL, "Adding %s:", (type == RGW_CLI_NAS) ? "NAS" : "PROXY" ); 523 701 TRACE_DEBUG_sSA(FULL, "\tIP : ", ip_port, NI_NUMERICHOST | NI_NUMERICSERV, "" ); 524 702 TRACE_DEBUG_BUFFER(FULL, "\tKey: [", *key, keylen, "]" ); … … 532 710 if (ret == ENOENT) { 533 711 /* No duplicate found, Ok to add */ 534 CHECK_FCT_DO( ret = client_create( &new, &ip_port, key, keylen ), goto end );712 CHECK_FCT_DO( ret = client_create( &new, &ip_port, key, keylen, type ), goto end ); 535 713 fd_list_insert_after(&prev->chain, &new->chain); 536 714 new->refcount++; … … 541 719 if (ret == EEXIST) { 542 720 /* Check if the key is the same, then skip or return an error */ 543 if ((keylen == prev->key.len ) && ( ! memcmp(*key, prev->key.data, keylen) ) ) {721 if ((keylen == prev->key.len ) && ( ! memcmp(*key, prev->key.data, keylen) ) && (type == prev->type)) { 544 722 TRACE_DEBUG(INFO, "Skipping duplicate client description"); 545 723 ret = 0; … … 548 726 549 727 fd_log_debug("ERROR: Conflicting RADIUS clients descriptions!\n"); 550 TRACE_DEBUG(NONE, "Previous entry: ");728 TRACE_DEBUG(NONE, "Previous entry: %s", (prev->type == RGW_CLI_NAS) ? "NAS" : "PROXY"); 551 729 TRACE_DEBUG_sSA(NONE, "\tIP : ", prev->sa, NI_NUMERICHOST | NI_NUMERICSERV, "" ); 552 730 TRACE_DEBUG_BUFFER(NONE, "\tKey: [", prev->key.data, prev->key.len, "]" ); 553 TRACE_DEBUG(NONE, "Conflicting entry: ");731 TRACE_DEBUG(NONE, "Conflicting entry: %s", (type == RGW_CLI_NAS) ? "NAS" : "PROXY"); 554 732 TRACE_DEBUG_sSA(NONE, "\tIP : ", ip_port, NI_NUMERICHOST | NI_NUMERICSERV, "" ); 555 733 TRACE_DEBUG_BUFFER(NONE, "\tKey: [", *key, keylen, "]" ); -
extensions/app_radgw/rgw_conf.l
r403 r516 122 122 123 123 /* Client section */ 124 (?i:"cli") { BEGIN(IN_CLI1); return CLI_PREFIX; } 124 (?i:"nas"|"cli") { BEGIN(IN_CLI1); yylval->integer=RGW_CLI_NAS; return NAS_OR_PXY; } 125 (?i:"pxy") { BEGIN(IN_CLI1); yylval->integer=RGW_CLI_PXY; return NAS_OR_PXY; } 125 126 126 127 /* Match an IP (4 or 6) and optional port */ -
extensions/app_radgw/rgw_conf.y
r304 r516 146 146 %type <string> FINDFILEEXT 147 147 148 %token <integer> NAS_OR_PXY 149 148 150 /* simple tokens */ 149 151 %token DISABLED … … 152 154 153 155 %token PLG_PREFIX 154 %token CLI_PREFIX155 156 156 157 %token AUTH_ENABLE … … 264 265 buf_reinit(); 265 266 } 266 CLI_PREFIX'=' IP '/' clisecret_key ';'267 NAS_OR_PXY '=' IP '/' clisecret_key ';' 267 268 { 268 269 /* Add this client */ 269 if ( rgw_clients_add( $4, &buf, buf_sz ) ) {270 if ( rgw_clients_add( $4, &buf, buf_sz, $2 ) ) { 270 271 yyerror (&yylloc, conffile, "Error parsing / adding client !"); 271 272 YYERROR; -
extensions/app_radgw/rgw_main.c
r258 r516 42 42 static int rgw_main(char * conffile) 43 43 { 44 CHECK_FCT( rgw_ msg_init() );44 CHECK_FCT( rgw_clients_init() ); 45 45 46 46 CHECK_FCT( rgw_servers_init() ); -
extensions/app_radgw/rgw_msg.c
r356 r516 79 79 } 80 80 81 /* Check if the message has a valid authenticator, and update the meta-data accordingly */82 int rgw_msg_auth_check(struct rgw_radius_msg_meta * msg, struct rgw_client * cli, uint8_t * req_auth)83 {84 unsigned char * key;85 size_t keylen;86 int count;87 88 TRACE_ENTRY("%p %p %p", msg, cli, req_auth);89 90 CHECK_PARAMS(msg && cli);91 92 CHECK_FCT(rgw_clients_getkey(cli, &key, &keylen));93 94 count = radius_msg_count_attr(&msg->radius, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 0);95 if (count > 1) {96 TRACE_DEBUG(INFO, "Too many Message-Authenticator attributes (%d), discarding message.", count);97 return EINVAL;98 }99 if (count == 0) {100 TRACE_DEBUG(FULL, "Message does not contain a Message-Authenticator attributes.");101 msg->valid_mac = 0;102 } else {103 if (radius_msg_verify_msg_auth( &msg->radius, key, keylen, req_auth )) {104 TRACE_DEBUG(INFO, "Invalid Message-Authenticator received, discarding message.");105 return EINVAL;106 }107 msg->valid_mac = 1;108 }109 110 return 0;111 }112 113 81 /* Dump a message (inspired from radius_msg_dump) -- can be used safely with a struct radius_msg as parameter (we don't dump the metadata) */ 114 82 void rgw_msg_dump(struct rgw_radius_msg_meta * msg) … … 132 100 struct radius_attr_hdr *attr = (struct radius_attr_hdr *)(msg->radius.buf + msg->radius.attr_pos[i]); 133 101 fd_log_debug(" - len:%3hhu, type:0x%02hhx (%s)\n", attr->length, attr->type, rgw_msg_attrtype_str(attr->type)); 134 /* If we need to dump the value, it's better to call directly radius_msg_dump instead... */102 radius_msg_dump_attr_val(attr); 135 103 } 136 104 fd_log_debug("-----------------------------\n"); 137 105 } 138 106 139 static struct dict_object * cache_orig_host = NULL;140 static struct dict_object * cache_orig_realm = NULL;141 142 int rgw_msg_init(void)143 {144 TRACE_ENTRY();145 CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &cache_orig_host, ENOENT) );146 CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &cache_orig_realm, ENOENT) );147 return 0;148 }149 150 /* Create a new Diameter msg with origin-host & realm */151 int rgw_msg_create_base(struct rgw_client * cli, struct msg ** diam)152 {153 char * fqdn;154 char * realm;155 156 struct avp *avp = NULL;157 union avp_value avp_val;158 159 TRACE_ENTRY("%p %p", cli, diam);160 CHECK_PARAMS( cli && diam && (*diam == NULL) );161 162 /* Get information on this peer */163 CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &realm) );164 165 /* Create an empty Diameter message so that extensions can store their AVPs */166 CHECK_FCT( fd_msg_new ( NULL, MSGFL_ALLOC_ETEID, diam ) );167 168 /* Add the Origin-Host as next AVP */169 CHECK_FCT( fd_msg_avp_new ( cache_orig_host, 0, &avp ) );170 memset(&avp_val, 0, sizeof(avp_val));171 avp_val.os.data = (unsigned char *)fqdn;172 avp_val.os.len = strlen(fqdn);173 CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );174 CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );175 176 /* Add the Origin-Realm as next AVP */177 CHECK_FCT( fd_msg_avp_new ( cache_orig_realm, 0, &avp ) );178 memset(&avp_val, 0, sizeof(avp_val));179 avp_val.os.data = (unsigned char *)realm;180 avp_val.os.len = strlen(realm);181 CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );182 CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );183 184 /* Done! */185 return 0;186 } -
extensions/app_radgw/rgw_worker.c
r405 r516 97 97 98 98 /* Check authenticator, if any */ 99 CHECK_FCT_DO( rgw_ msg_auth_check(msg, cli, NULL),99 CHECK_FCT_DO( rgw_clients_auth_check(msg, cli, NULL), 100 100 { 101 101 /* An error occurred, discard message */ … … 118 118 } 119 119 120 /* Check that IP is coherent with the identity in the message */ 121 CHECK_FCT_DO( rgw_clients_check_origin(msg, cli), 120 diam_msg = NULL; 121 /* Note: after this point, the radius message buffer may not be consistent with the array of attributes anymore. */ 122 123 /* Check that IP is coherent with the identity in the message, and create an empty message with only Origin information */ 124 CHECK_FCT_DO( rgw_clients_create_origin(msg, cli, &diam_msg), 122 125 { 123 126 /* An error occurred, discard message */ 124 rgw_msg_free(&msg); 125 rgw_clients_dispose(&cli); 126 continue; 127 } ); 128 129 /* Note: after this point, the radius message buffer may not be consistent with the array of attributes anymore. */ 130 diam_msg = NULL; 131 132 /* Create an empty message with only Origin information (no session, no destination -- added by the plugins) */ 133 CHECK_FCT_DO( rgw_msg_create_base(cli, &diam_msg), 134 { 135 /* An error occurred, discard message */ 127 if (diam_msg) { 128 CHECK_FCT_DO( fd_msg_free(diam_msg), ); 129 } 136 130 rgw_msg_free(&msg); 137 131 rgw_clients_dispose(&cli);
Note: See TracChangeset
for help on using the changeset viewer.