Navigation



Ignore:
Timestamp:
Feb 9, 2011, 3:26:58 PM (13 years ago)
Author:
Sebastien Decugis <sdecugis@nict.go.jp>
Branch:
default
Phase:
public
Message:

Large UNTESTED commit with the following changes:

  • Improved DiameterIdentity? handling (esp. interationalization issues), and improve efficiency of some string operations in peers, sessions, and dictionary modules (closes #7)
  • Cleanup in the session module to free only unreferenced sessions (#16)
  • Removed fd_cpu_flush_cache(), replaced by more robust alternatives.
  • Improved peer state machine algorithm to counter SCTP multistream race condition.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • extensions/app_radgw/rgw_clients.c

    r554 r706  
    8686        int                      is_local; /* true if the RADIUS client runs on the same host -- we use Diameter Identity in that case */
    8787        enum rgw_cli_type        type; /* is it a proxy ? */
    88         char                    *fqdn;
     88        DiamId_t                 fqdn; /* malloc'd here */
    8989        size_t                   fqdn_len;
    90         char                    *realm;
    91         char                    **aliases;
     90        DiamId_t                 realm; /* references another string, do not free */
     91        size_t                   realm_len;
     92        struct {
     93                os0_t            name;
     94                size_t           len;
     95        }                       *aliases; /* Received aliases */
    9296        size_t                   aliases_nb;
    9397       
     
    210214{
    211215        struct rgw_client *tmp = NULL;
    212         char buf[255];
     216        DiamId_t fqdn;
     217        size_t fqdn_len;
    213218        int ret, i;
    214219        int loc = 0;
     
    220225                loc = 1;
    221226        } else {
     227                char buf[255];
    222228       
    223229                /* Search FQDN for the client */
     
    227233                        return EINVAL;
    228234                }
     235                fqdn = &buf[0];
     236                CHECK_FCT_DO( ret = fd_os_validate_DiameterIdentity(&fqdn, &fqdn_len, 1),
     237                        {
     238                                TRACE_DEBUG(INFO, "Unable to use resolved peer name '%s' as DiameterIdentity: %s", buf, strerror(ret));
     239                                return ret;
     240                        } );
    229241        }
    230242       
     
    246258        } else {
    247259                /* Copy the fqdn */
    248                 CHECK_MALLOC( tmp->fqdn = strdup(buf) );
    249                 tmp->fqdn_len = strlen(tmp->fqdn);
     260                tmp->fqdn = fqdn;
     261                tmp->fqdn_len = fqdn_len;
     262
    250263                /* Find an appropriate realm */
    251                 tmp->realm = strchr(tmp->fqdn, '.');
    252                 if (tmp->realm)
     264                tmp->realm = strchr(fqdn, '.');
     265                if (tmp->realm) {
    253266                        tmp->realm += 1;
    254                 if ((!tmp->realm) || (*tmp->realm == '\0')) /* in case the fqdn was "localhost." for example, if it is possible... */
     267                        tmp->realm_len = tmp->fqdn_len - (tmp->realm - fqdn);
     268                }
     269                if ((!tmp->realm) || (*tmp->realm == '\0')) { /* in case the fqdn was "localhost." for example, if it is possible... */
    255270                        tmp->realm = fd_g_config->cnf_diamrlm;
     271                        tmp->realm_len = fd_g_config->cnf_diamrlm_len;
     272                }
    256273        }
    257274       
     
    282299                /* Free the data */
    283300                for (idx = 0; idx < client->aliases_nb; idx++)
    284                         free(client->aliases[idx]);
     301                        free(client->aliases[idx].name);
    285302                free(client->aliases);
    286303                free(client->fqdn);
     
    532549        int valid_nas_info = 0;
    533550        struct radius_attr_hdr *nas_ip = NULL, *nas_ip6 = NULL, *nas_id = NULL;
    534         char * oh_str = NULL;
    535         char * or_str = NULL;
    536         char * rr_str = NULL;
     551        size_t nas_id_len;
     552        char * oh_str = NULL; size_t oh_strlen; int oh_free = 0;
     553        char * or_str = NULL; size_t or_strlen;
     554        char * rr_str = NULL; size_t rr_strlen;
    537555        char buf[REVERSE_DNS_SIZE_MAX]; /* to store DNS lookups results */
    538556       
     
    555573                if ((attr->type == RADIUS_ATTR_NAS_IDENTIFIER) && (attr_len > 0)) {
    556574                        nas_id = attr;
     575                        nas_id_len = attr_len;
    557576                        continue;
    558577                }
     
    568587               
    569588                /* Get information on this peer */
    570                 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
     589                CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
    571590               
    572591                goto diameter;
     
    619638                                return EINVAL;
    620639                        } else {
     640                                int ret;
     641                                sSS ss;
    621642                                /* the peer is configured as a proxy, or running on localhost, so accept the message */
    622                                 sSS ss;
    623643                               
    624644                                /* In that case, the cli will be stored as Route-Record and the NAS-IP-Address as origin */
    625645                                if (!cli->is_local) {
    626646                                        rr_str = cli->fqdn;
     647                                        rr_strlen = cli->fqdn_len;
    627648                                }
    628649                               
     
    641662                                        {
    642663                                                if (cli->is_local) {
    643                                                         CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
     664                                                        CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
    644665                                                        goto diameter;
    645666                                                }
     
    648669                                                return EINVAL;
    649670                                        } );
     671                                       
     672                                oh_str = &buf[0];
     673                                CHECK_FCT_DO( ret = fd_os_validate_DiameterIdentity(&oh_str, &oh_strlen, 1),
     674                                        {
     675                                                if (cli->is_local) {
     676                                                        CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
     677                                                        goto diameter;
     678                                                }
     679                                               
     680                                                TRACE_DEBUG(INFO, "Unable to use resolved client name '%s' as DiameterIdentity: %s", buf, strerror(ret));
     681                                                return ret;
     682                                        } );
     683                                oh_free = 1;
    650684                               
    651                                 oh_str = &buf[0];
    652685                                or_str = strchr(oh_str, '.');
    653686                                if (or_str) {
     
    655688                                        if (*or_str == '\0')
    656689                                                or_str = NULL; /* Discard this realm, we will use the local realm later */
     690                                        else
     691                                                or_strlen = oh_strlen - (or_str - oh_str);
    657692                                }
    658693                        }
    659694                } else {
    660695                        /* The attribute matches the source address, just use this in origin-host */
    661                         CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
     696                        CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
    662697                }
    663698               
     
    668703        if (cli->is_local) {
    669704                /* Simple: we use our own configuration */
    670                 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
     705                CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
    671706                goto diameter;
    672707        }
     
    697732               
    698733                /* first, check if the nas_id is the fqdn of the peer or a known alias */
    699                 if ((cli->fqdn_len == (nas_id->length - sizeof(struct radius_attr_hdr)))
    700                 && (!strncasecmp((char *)(nas_id + 1), cli->fqdn, nas_id->length - sizeof(struct radius_attr_hdr)))) {
     734                if (!fd_os_almostcasecmp(nas_id + 1, nas_id_len,
     735                                                cli->fqdn, cli->fqdn_len)) {
    701736                        TRACE_DEBUG(FULL, "NAS-Identifier contains the fqdn of the client");
    702737                        found = 1;
    703738                } else {
    704739                        for (idx = 0; idx < cli->aliases_nb; idx++) {
    705                                 if (((nas_id->length - sizeof(struct radius_attr_hdr)) == strlen(cli->aliases[idx]))
    706                                 && (!strncasecmp((char *)(nas_id + 1), cli->aliases[idx], nas_id->length - sizeof(struct radius_attr_hdr)))) {
     740                                if (!fd_os_cmp(nas_id + 1, nas_id_len,
     741                                                cli->aliases[idx].name, cli->aliases[idx].len)) {
    707742                                        TRACE_DEBUG(FULL, "NAS-Identifier valid value found in the cache");
    708743                                        found = 1;
     
    714749                if (found) {
    715750                        /* The NAS-Identifier matches the source IP */
    716                         CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
     751                        CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
    717752
    718753                        goto diameter;
     
    720755               
    721756                /* Attempt DNS resolution of the identifier */
    722                 ASSERT( nas_id->length - sizeof(struct radius_attr_hdr) < sizeof(buf) );
    723                 memcpy(buf, nas_id + 1, nas_id->length - sizeof(struct radius_attr_hdr));
     757                ASSERT( nas_id_len < sizeof(buf) );
     758                memcpy(buf, nas_id + 1, nas_id_len);
    724759                buf[nas_id->length - sizeof(struct radius_attr_hdr)] = '\0';
    725760               
     
    745780                                if (cli->type == RGW_CLI_NAS) {
    746781                                        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.",
    747                                                 nas_id->length - sizeof(struct radius_attr_hdr), nas_id + 1);
     782                                                nas_id_len, nas_id + 1);
    748783                                        return EINVAL;
    749784                                } else {
     
    751786                                        if (!cli->is_local) {
    752787                                                rr_str = cli->fqdn;
     788                                                rr_strlen = cli->fqdn_len;
    753789                                        }
    754790                                        oh_str = &buf[0]; /* The canonname resolved */
     791                                        CHECK_FCT_DO( ret = fd_os_validate_DiameterIdentity(&oh_str, &oh_strlen, 1),
     792                                                {
     793                                                        TRACE_DEBUG(INFO, "Unable to use resolved client name '%s' as DiameterIdentity: %s", buf, strerror(ret));
     794                                                        return ret;
     795                                                } );
     796                                        oh_free = 1;
    755797                                        or_str = strchr(oh_str, '.');
    756798                                        if (or_str) {
     
    758800                                                if (*or_str == '\0')
    759801                                                        or_str = NULL; /* Discard this realm, we will use the local realm later */
     802                                                else
     803                                                        or_strlen = oh_strlen - (or_str - oh_str);
    760804                                        }
    761805                                }
    762806                        } else {
    763807                                /* It is a valid alias, save it */
    764                                 CHECK_MALLOC( cli->aliases = realloc(cli->aliases, (cli->aliases_nb + 1) * sizeof(char *)) );
    765                                 CHECK_MALLOC( cli->aliases[cli->aliases_nb + 1] = malloc( 1 + nas_id->length - sizeof(struct radius_attr_hdr) ));
    766                                 memcpy( cli->aliases[cli->aliases_nb + 1], nas_id + 1, nas_id->length - sizeof(struct radius_attr_hdr));
    767                                 *(cli->aliases[cli->aliases_nb + 1] + nas_id->length - sizeof(struct radius_attr_hdr)) = '\0';
     808                                CHECK_MALLOC( cli->aliases = realloc(cli->aliases, (cli->aliases_nb + 1) * sizeof(cli->aliases[0])) );
     809                               
     810                                CHECK_MALLOC( cli->aliases[cli->aliases_nb + 1].name = os0dup(nas_id + 1, nas_id_len ) );
     811                                cli->aliases[cli->aliases_nb + 1].len = nas_id_len;
     812
    768813                                cli->aliases_nb ++;
    769                                 TRACE_DEBUG(FULL, "Saved valid alias for client: '%s' -> '%s'", cli->aliases[cli->aliases_nb + 1], cli->fqdn);
    770                                 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
     814                                TRACE_DEBUG(FULL, "Saved valid alias for client: '%.*s' -> '%s'", nas_id_len, nas_id + 1, cli->fqdn);
     815                                CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
    771816                        }
    772817                } else {
     
    774819                        TRACE_DEBUG(INFO, "NAS-Identifier '%s' cannot be resolved: %s. Ignoring...", buf, gai_strerror(ret));
    775820                        /* Assume this is a valid identifier for the client */
    776                         CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
     821                        CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
    777822                }
    778823        }
     
    781826diameter:
    782827        ASSERT(oh_str); /* If it is not defined here, there is a bug... */
    783         if (!or_str)
     828        if (!or_str) {
    784829                or_str = fd_g_config->cnf_diamrlm; /* Use local realm in that case */
     830                or_strlen = fd_g_config->cnf_diamrlm_len;
     831        }
    785832       
    786833        /* Create an empty Diameter message so that extensions can store their AVPs */
     
    791838        memset(&avp_val, 0, sizeof(avp_val));
    792839        avp_val.os.data = (unsigned char *)oh_str;
    793         avp_val.os.len = strlen(oh_str);
     840        avp_val.os.len = oh_strlen;
    794841        CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
    795842        CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );
     
    799846        memset(&avp_val, 0, sizeof(avp_val));
    800847        avp_val.os.data = (unsigned char *)or_str;
    801         avp_val.os.len = strlen(or_str);
     848        avp_val.os.len = or_strlen;
    802849        CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
    803850        CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );
     
    807854                memset(&avp_val, 0, sizeof(avp_val));
    808855                avp_val.os.data = (unsigned char *)rr_str;
    809                 avp_val.os.len = strlen(rr_str);
     856                avp_val.os.len = rr_strlen;
    810857                CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
    811858                CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );
    812859        }
    813860       
     861        if (oh_free)
     862                free(oh_str);
     863       
    814864        /* Done! */
    815865        return 0;
    816866}
    817867
    818 int rgw_clients_get_origin(struct rgw_client *cli, char **fqdn, char **realm)
    819 {
    820         TRACE_ENTRY("%p %p %p", cli, fqdn, realm);
    821         CHECK_PARAMS(cli && fqdn);
     868int rgw_clients_get_origin(struct rgw_client *cli, DiamId_t *fqdn, size_t *fqdnlen, DiamId_t *realm, size_t *realmlen)
     869{
     870        TRACE_ENTRY("%p %p %p %p %p", cli, fqdn, fqdnlen, realm, realmlen);
     871        CHECK_PARAMS(cli && fqdn && fqdnlen);
    822872       
    823873        if (cli->is_local) {
    824874                *fqdn = fd_g_config->cnf_diamid;
     875                *fqdnlen = fd_g_config->cnf_diamid_len;
    825876                if (realm)
    826877                        *realm= fd_g_config->cnf_diamrlm;
     878                if (realmlen)
     879                        *realmlen= fd_g_config->cnf_diamrlm_len;
    827880        } else {
    828881                *fqdn = cli->fqdn;
     882                *fqdnlen = cli->fqdn_len;
    829883                if (realm)
    830884                        *realm= cli->realm;
     885                if (realmlen)
     886                        *realmlen= cli->realm_len;
    831887        }
    832888               
Note: See TracChangeset for help on using the changeset viewer.