Navigation


Changeset 516:1c2f5ee38039 in freeDiameter


Ignore:
Timestamp:
Aug 27, 2010, 10:59:51 AM (14 years ago)
Author:
Sebastien Decugis <sdecugis@nict.go.jp>
Branch:
default
Phase:
public
Message:

Allow RADIUS Proxies with the app_radgw extension

Files:
10 edited

Legend:

Unmodified
Added
Removed
  • doc/app_radgw.conf.sample

    r271 r516  
    4949##################
    5050
    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 ;
    5253# IP can be ipv4 or ipv6
    5354# port can be additionaly restricted with brackets: IP[port] (ex: 192.168.0.1[1812])
    5455# shared-secret can be a quoted string, or a list of hexadecimal values.
    5556# 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 previously
     57# 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
    5859# 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.
    5968
    6069
  • extensions/app_radgw/radius.c

    r254 r516  
    44 * It is redistributed under the terms of the BSD license, as allowed
    55 * 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
    78 */
    89#include "rgw_common.h"
     
    218219
    219220
    220 static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
     221void radius_msg_dump_attr_val(struct radius_attr_hdr *hdr)
    221222{
    222223        struct radius_attr_type *attr;
     
    225226
    226227        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);
    230228
    231229        if (attr == NULL)
     
    283281                break;
    284282        }
     283}
     284
     285static 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);
    285295}
    286296
  • extensions/app_radgw/radius.h

    r254 r516  
    44 * It is redistributed under the terms of the BSD license, as allowed
    55 * 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);
    79 */
     10
    811/*********************************************************************************/
    912
     
    216219void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier);
    217220void radius_msg_free(struct radius_msg *msg);
     221void radius_msg_dump_attr_val(struct radius_attr_hdr *hdr);
    218222void radius_msg_dump(struct radius_msg *msg);
    219223int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
  • extensions/app_radgw/rgw.h

    r403 r516  
    5858                /* The message has a valid Message-Authenticator attribute */
    5959                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;
    6360        };
    6461       
     
    6764int rgw_msg_parse(unsigned char * buf, size_t len, struct rgw_radius_msg_meta ** msg);
    6865void 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);
    7266
    7367/* Local RADIUS server(s) configuration */
     
    9791
    9892/* Clients management */
    99 int rgw_clients_add( struct sockaddr * ip_port, unsigned char ** key, size_t keylen );
     93enum rgw_cli_type { RGW_CLI_NAS, RGW_CLI_PXY };
     94int rgw_clients_auth_check(struct rgw_radius_msg_meta * msg, struct rgw_client * cli, uint8_t * req_auth);
     95int rgw_clients_add( struct sockaddr * ip_port, unsigned char ** key, size_t keylen, enum rgw_cli_type type );
    10096int rgw_clients_getkey(struct rgw_client * cli, unsigned char **key, size_t *key_len);
     97int rgw_clients_gettype(struct rgw_client * cli, enum rgw_cli_type *type);
    10198int rgw_clients_search(struct sockaddr * ip_port, struct rgw_client ** ref);
    10299int rgw_clients_check_dup(struct rgw_radius_msg_meta **msg, struct rgw_client *cli);
    103 int rgw_clients_check_origin(struct rgw_radius_msg_meta *msg, struct rgw_client *cli);
     100int rgw_clients_create_origin(struct rgw_radius_msg_meta *msg, struct rgw_client * cli, struct msg ** diam);
    104101int rgw_client_finish_send(struct radius_msg ** msg, struct rgw_radius_msg_meta * req, struct rgw_client * cli);
    105102void rgw_clients_dispose(struct rgw_client ** ref);
    106103void rgw_clients_dump(void);
     104int rgw_clients_init(void);
    107105void rgw_clients_fini(void);
    108106int 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  
    4040#include "rgw.h"
    4141
     42#define REVERSE_DNS_SIZE_MAX    512 /* length of our buffer for reverse DNS */
     43
    4244/* Ordered lists of clients. The order relationship is a memcmp on the address zone.
    4345   For same addresses, the port is compared.
     
    6769        /* The FQDN, realm, and optional aliases */
    6870        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 ? */
    6972        char                    *fqdn;
    7073        size_t                   fqdn_len;
     
    9194
    9295/* 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 )
     96static int client_create(struct rgw_client ** res, struct sockaddr ** ip_port, unsigned char ** key, size_t keylen, enum rgw_cli_type type )
    9497{
    9598        struct rgw_client *tmp = NULL;
     
    117120        memset(tmp, 0, sizeof(struct rgw_client));
    118121        fd_list_init(&tmp->chain, NULL);
     122       
     123        tmp->type = type;
    119124       
    120125        if (loc) {
     
    231236}
    232237
     238int 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
    233246int rgw_clients_search(struct sockaddr * ip_port, struct rgw_client ** ref)
    234247{
     
    304317/* Check that the NAS-IP-Adress or NAS-Identifier is coherent with the IP the packet was received from */
    305318/* 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 */
     321int 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
     352static struct dict_object * cache_orig_host = NULL;
     353static struct dict_object * cache_orig_realm = NULL;
     354static struct dict_object * cache_route_record = NULL;
     355
     356int 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 */
     368int rgw_clients_create_origin(struct rgw_radius_msg_meta *msg, struct rgw_client * cli, struct msg ** diam)
    308369{
    309370        int idx;
     371        int valid_nas_info = 0;
    310372        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       
    315384        /* Find the relevant attributes, if any */
    316385        for (idx = 0; idx < msg->radius.attr_used; idx++) {
     
    336405        if (!nas_ip && !nas_ip6 && !nas_id) {
    337406                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;
    339412        }
    340413       
     
    342415        if (nas_ip && (cli->sa->sa_family == AF_INET) && !memcmp(nas_ip+1, &cli->sin->sin_addr, sizeof(struct in_addr))) {
    343416                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;
    345418        }
    346419        if (nas_ip6 && (cli->sa->sa_family == AF_INET6) && !memcmp(nas_ip6+1, &cli->sin6->sin6_addr, sizeof(struct in6_addr))) {
    347420                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        {
    389512                int found, ret;
    390513                struct addrinfo hint, *res, *ptr;
     
    410533                if ((cli->fqdn_len == (nas_id->length - sizeof(struct radius_attr_hdr)))
    411534                && (!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");
    413536                        found = 1;
    414537                } else {
     
    424547               
    425548                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';
    434559               
    435560                /* Now check if this alias is valid for this peer */
    436561                memset(&hint, 0, sizeof(hint));
    437                 hint.ai_family = cli->sa->sa_family;
    438562                hint.ai_flags  = AI_CANONNAME;
    439                 ret = getaddrinfo(str, NULL, &hint, &res);
     563                ret = getaddrinfo(buf, NULL, &hint, &res);
    440564                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? */
    442567                        for (ptr = res; ptr != NULL; ptr = ptr->ai_next) {
    443568                                if (cli->sa->sa_family != ptr->ai_family)
     
    446571                                        continue;
    447572                               
    448                                 /* It matches: the alias is valid */
    449573                                found = 1;
    450574                                break;
     
    453577                       
    454578                        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) );
    458605                        }
    459606                } else {
    460607                        /* 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. */
     615diameter:
     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! */
    472649        return 0;
    473650}
     
    508685}
    509686
    510 int rgw_clients_add( struct sockaddr * ip_port, unsigned char ** key, size_t keylen )
     687int rgw_clients_add( struct sockaddr * ip_port, unsigned char ** key, size_t keylen, enum rgw_cli_type type )
    511688{
    512689        struct rgw_client * prev = NULL, *new = NULL;
     
    517694        CHECK_PARAMS( ip_port && key && *key && keylen );
    518695        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) );
    519697       
    520698        /* Dump the entry in debug mode */
    521699        if (TRACE_BOOL(FULL + 1 )) {
    522                 TRACE_DEBUG(FULL, "Adding client:");
     700                TRACE_DEBUG(FULL, "Adding %s:", (type == RGW_CLI_NAS) ? "NAS" : "PROXY"  );
    523701                TRACE_DEBUG_sSA(FULL,    "\tIP : ", ip_port, NI_NUMERICHOST | NI_NUMERICSERV, "" );
    524702                TRACE_DEBUG_BUFFER(FULL, "\tKey: [", *key, keylen, "]" );
     
    532710        if (ret == ENOENT) {
    533711                /* 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 );
    535713                fd_list_insert_after(&prev->chain, &new->chain);
    536714                new->refcount++;
     
    541719        if (ret == EEXIST) {
    542720                /* 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)) {
    544722                        TRACE_DEBUG(INFO, "Skipping duplicate client description");
    545723                        ret = 0;
     
    548726               
    549727                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");
    551729                TRACE_DEBUG_sSA(NONE,    "\tIP : ", prev->sa, NI_NUMERICHOST | NI_NUMERICSERV, "" );
    552730                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");
    554732                TRACE_DEBUG_sSA(NONE,    "\tIP : ", ip_port, NI_NUMERICHOST | NI_NUMERICSERV, "" );
    555733                TRACE_DEBUG_BUFFER(NONE, "\tKey: [", *key, keylen, "]" );
  • extensions/app_radgw/rgw_conf.l

    r403 r516  
    122122
    123123        /* 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;               }
    125126
    126127        /* Match an IP (4 or 6) and optional port */
  • extensions/app_radgw/rgw_conf.y

    r304 r516  
    146146%type <string>  FINDFILEEXT
    147147
     148%token <integer> NAS_OR_PXY
     149
    148150/* simple tokens */
    149151%token          DISABLED
     
    152154
    153155%token          PLG_PREFIX
    154 %token          CLI_PREFIX
    155156
    156157%token          AUTH_ENABLE
     
    264265                                buf_reinit();
    265266                        }
    266                         CLI_PREFIX '=' IP '/' clisecret_key ';'
     267                        NAS_OR_PXY '=' IP '/' clisecret_key ';'
    267268                        {
    268269                                /* Add this client */
    269                                 if ( rgw_clients_add( $4, &buf, buf_sz ) ) {
     270                                if ( rgw_clients_add( $4, &buf, buf_sz, $2 ) ) {
    270271                                        yyerror (&yylloc, conffile, "Error parsing / adding client !");
    271272                                        YYERROR;
  • extensions/app_radgw/rgw_main.c

    r258 r516  
    4242static int rgw_main(char * conffile)
    4343{
    44         CHECK_FCT( rgw_msg_init() );
     44        CHECK_FCT( rgw_clients_init() );
    4545       
    4646        CHECK_FCT( rgw_servers_init() );
  • extensions/app_radgw/rgw_msg.c

    r356 r516  
    7979}
    8080
    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 
    11381/* 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) */
    11482void rgw_msg_dump(struct rgw_radius_msg_meta * msg)
     
    132100                struct radius_attr_hdr *attr = (struct radius_attr_hdr *)(msg->radius.buf + msg->radius.attr_pos[i]);
    133101                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);
    135103        }
    136104        fd_log_debug("-----------------------------\n");
    137105}
    138106
    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  
    9797               
    9898                /* 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),
    100100                        {
    101101                                /* An error occurred, discard message */
     
    118118                }
    119119               
    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),
    122125                        {
    123126                                /* 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                                }
    136130                                rgw_msg_free(&msg);
    137131                                rgw_clients_dispose(&cli);
Note: See TracChangeset for help on using the changeset viewer.