Navigation


Changeset 356:e203fc0c95e3 in freeDiameter for extensions/app_radgw/rgw_msg.c


Ignore:
Timestamp:
Jul 1, 2010, 3:47:34 PM (14 years ago)
Author:
Sebastien Decugis <sdecugis@nict.go.jp>
Branch:
default
Phase:
public
Message:

Updated the app_radgw extension to allow more souple management of sessions, and stateful gateway features.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • extensions/app_radgw/rgw_msg.c

    r278 r356  
    137137}
    138138
    139 static struct dict_object * cache_sess_id = NULL;
    140 static struct dict_object * cache_dest_host = NULL;
    141 static struct dict_object * cache_dest_realm = NULL;
    142139static struct dict_object * cache_orig_host = NULL;
    143140static struct dict_object * cache_orig_realm = NULL;
     
    146143{
    147144        TRACE_ENTRY();
    148         CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &cache_sess_id, ENOENT) );
    149         CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Host", &cache_dest_host, ENOENT) );
    150         CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Realm", &cache_dest_realm, ENOENT) );
    151145        CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &cache_orig_host, ENOENT) );
    152146        CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &cache_orig_realm, ENOENT) );
     
    154148}
    155149
    156 /* Create a msg with origin-host & realm, and session-id, and a session object from a RADIUS request message */
    157 int rgw_msg_create_base(struct rgw_radius_msg_meta * msg, struct rgw_client * cli, struct session ** session, struct msg ** diam)
     150/* Create a new Diameter msg with origin-host & realm */
     151int rgw_msg_create_base(struct rgw_client * cli, struct msg ** diam)
    158152{
    159         int idx, i;
    160         const char * prefix = "Diameter/";
    161         size_t pref_len;
    162         char * dh = NULL;
    163         size_t dh_len = 0;
    164         char * dr = NULL;
    165         size_t dr_len = 0;
    166         char * si = NULL;
    167         size_t si_len = 0;
    168         char * un = NULL;
    169         size_t un_len = 0;
    170        
    171153        char * fqdn;
    172154        char * realm;
    173         char * sess_str = NULL;
    174155       
    175156        struct avp *avp = NULL;
    176157        union avp_value avp_val;
    177158       
    178         TRACE_ENTRY("%p %p %p %p", msg, cli, session, diam);
    179         CHECK_PARAMS( msg && cli && session && (*session == NULL) && diam && (*diam == NULL) );
    180        
    181         pref_len = strlen(prefix);
    182        
    183         /* Is there a State attribute with prefix "Diameter/" in the message? (in that case: Diameter/Destination-Host/Destination-Realm/Session-Id) */
    184         /* NOTE: RFC4005 says "Origin-Host" here, but it's not coherent with the rules for answers. Destination-Host makes more sense */
    185         /* Is there a Class attribute with prefix "Diameter/" in the message? (in that case: Diameter/Session-Id) */
    186         for (idx = 0; idx < msg->radius.attr_used; idx++) {
    187                 struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(msg->radius.buf + msg->radius.attr_pos[idx]);
    188                 char * attr_val = (char *)(attr + 1);
    189                 size_t attr_len = attr->length - sizeof(struct radius_attr_hdr);
    190                
    191                 if ((attr->type == RADIUS_ATTR_USER_NAME)
    192                                 && attr_len) {
    193                         TRACE_DEBUG(ANNOYING, "Found a User-Name attribute: '%.*s'", attr_len, attr_val);
    194                         un = attr_val;
    195                         un_len = attr_len;
    196                         continue;
    197                 }
    198                
    199                 if ((attr->type == RADIUS_ATTR_STATE)
    200                                 && (attr_len > pref_len + 5 /* for the '/'s and non empty strings */ )
    201                                 && ! strncmp(attr_val, prefix, pref_len)) { /* should we make it strncasecmp? */
    202                         int i, start;
    203                
    204                         TRACE_DEBUG(ANNOYING, "Found a State attribute with '%s' prefix (attr #%d).", prefix, idx);
    205 
    206                         /* Now parse the value and check its content is valid. Unfortunately we cannot use strchr here since strings are not \0-terminated */
    207 
    208                         i = start = pref_len;
    209                         dh = attr_val + i;
    210                         for (; (i < attr_len - 2) && (attr_val[i] != '/'); i++) /* loop */;
    211                         if ( i >= attr_len - 2 ) continue; /* the attribute format is not good */
    212                         dh_len = i - start;
    213 
    214                         start = ++i;
    215                         dr = attr_val + i;
    216                         for (; (i < attr_len - 1) && (attr_val[i] != '/'); i++) /* loop */;
    217                         if ( i >= attr_len - 1 ) continue; /* the attribute format is not good */
    218                         dr_len = i - start;
    219 
    220                         i++;
    221                         si = attr_val + i;
    222                         si_len = attr_len - i;
    223 
    224                         TRACE_DEBUG(ANNOYING, "Attribute parsed successfully: DH:'%.*s' DR:'%.*s' SI:'%.*s'.", dh_len, dh, dr_len, dr, si_len, si);
    225                         /* Remove from the message */
    226                         for (i = idx + 1; i < msg->radius.attr_used; i++)
    227                                 msg->radius.attr_pos[i - 1] = msg->radius.attr_pos[i];
    228                         msg->radius.attr_used -= 1;
    229                         break;
    230                 }
    231                
    232                 if ((attr->type == RADIUS_ATTR_CLASS)
    233                                 && (attr_len > pref_len )
    234                                 && ! strncmp(attr_val, prefix, pref_len)) {
    235                         si = attr_val + pref_len;
    236                         si_len = attr_len - pref_len;
    237                         TRACE_DEBUG(ANNOYING, "Found Class attribute with '%s' prefix (attr #%d), SI:'%.*s'.", prefix, idx, si_len, si);
    238                         /* Remove from the message */
    239                         for (i = idx + 1; i < msg->radius.attr_used; i++)
    240                                 msg->radius.attr_pos[i - 1] = msg->radius.attr_pos[i];
    241                         msg->radius.attr_used -= 1;
    242                         break;
    243                 }
    244                
    245         }
     159        TRACE_ENTRY("%p %p", cli, diam);
     160        CHECK_PARAMS( cli && diam && (*diam == NULL) );
    246161       
    247162        /* Get information on this peer */
    248163        CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &realm) );
    249164       
    250         /* Create the session object */
    251         if (si_len) {
    252                 CHECK_FCT( fd_sess_fromsid ( si, si_len, session, &idx) );
    253         } else {
    254                 if (un) {
    255                         int len;
    256                         /* If not found, create a new Session-Id. The format is: {fqdn;hi32;lo32;username;diamid} */
    257                         CHECK_MALLOC( sess_str = malloc(un_len + 1 /* ';' */ + fd_g_config->cnf_diamid_len + 1 /* '\0' */) );
    258                         len = sprintf(sess_str, "%.*s;%s", un_len, un, fd_g_config->cnf_diamid);
    259                         CHECK_FCT( fd_sess_new(session, fqdn, sess_str, len) );
    260                         free(sess_str);
    261                         idx = 1;
    262                 }
    263         }
    264        
    265165        /* Create an empty Diameter message so that extensions can store their AVPs */
    266166        CHECK_FCT(  fd_msg_new ( NULL, MSGFL_ALLOC_ETEID, diam )  );
    267        
    268         if (*session) {
    269                 CHECK_FCT( fd_sess_getsid(*session, &sess_str) );
    270                 if (idx == 0) {
    271                         TRACE_DEBUG(INFO, "Another message was translated for this session ('%s') and not answered yet, discarding the new RADIUS request.", sess_str);
    272                         *session = NULL;
    273                         return EALREADY;
    274                 }
    275                
    276                 TRACE_DEBUG(FULL, "Translating new message for session '%s'...", sess_str);
    277                
    278                 /* Add the Session-Id AVP as first AVP */
    279                 CHECK_FCT( fd_msg_avp_new ( cache_sess_id, 0, &avp ) );
    280                 memset(&avp_val, 0, sizeof(avp_val));
    281                 avp_val.os.data = (unsigned char *)sess_str;
    282                 avp_val.os.len = strlen(sess_str);
    283                 CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
    284                 CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_FIRST_CHILD, avp) );
    285 
    286         } else {
    287                 TRACE_DEBUG(FULL, "No session has been created for this message");
    288         }
    289        
    290         /* Add the Destination-Realm as next AVP */
    291         CHECK_FCT( fd_msg_avp_new ( cache_dest_realm, 0, &avp ) );
    292         memset(&avp_val, 0, sizeof(avp_val));
    293         if (dr) {
    294                 avp_val.os.data = (unsigned char *)dr;
    295                 avp_val.os.len = dr_len;
    296         } else {
    297                 int i = 0;
    298                 if (un) {
    299                         /* Is there an '@' in the user name? We don't care for decorated NAI here */
    300                         for (i = un_len - 2; i > 0; i--) {
    301                                 if (un[i] == '@') {
    302                                         i++;
    303                                         break;
    304                                 }
    305                         }
    306                 }
    307                 if (i == 0) {
    308                         /* Not found in the User-Name => we use the local domain of this gateway */
    309                         avp_val.os.data = fd_g_config->cnf_diamrlm;
    310                         avp_val.os.len  = fd_g_config->cnf_diamrlm_len;
    311                 } else {
    312                         avp_val.os.data = un + i;
    313                         avp_val.os.len  = un_len - i;
    314                 }
    315         }
    316         CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
    317         CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );
    318        
    319         /* Add the Destination-Host as next AVP */
    320         if (dh) {
    321                 CHECK_FCT( fd_msg_avp_new ( cache_dest_host, 0, &avp ) );
    322                 memset(&avp_val, 0, sizeof(avp_val));
    323                 avp_val.os.data = (unsigned char *)dh;
    324                 avp_val.os.len = dh_len;
    325                 CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
    326                 CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );
    327         }
    328167       
    329168        /* Add the Origin-Host as next AVP */
Note: See TracChangeset for help on using the changeset viewer.