enum.c

Go to the documentation of this file.
00001 /*
00002  * $Id: enum.c 4518 2008-07-28 15:39:28Z henningw $
00003  *
00004  * Enum and E164 related functions
00005  *
00006  * Copyright (C) 2002-2008 Juha Heinanen
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  */
00025 
00026 #include <stdlib.h>
00027 
00028 #include "enum.h"
00029 #include "../../parser/parse_uri.h"
00030 #include "../../parser/parse_from.h"
00031 #include "../../ut.h"
00032 #include "../../resolve.h"
00033 #include "../../mem/mem.h"
00034 #include "../../dset.h"
00035 #include "../../qvalue.h"
00036 #include "enum_mod.h"
00037 #include "../../regexp.h"
00038 #include "../../pvar.h"
00039 
00040 /*
00041  * Input: E.164 number w/o leading +
00042  *
00043  * Output: number of digits in the country code
00044  *       0 on invalid number
00045  *
00046  * convention:
00047  *   3 digits is the default length of a country code.
00048  *   country codes 1 and 7 are a single digit.
00049  *   the following country codes are two digits: 20, 27, 30-34, 36, 39,
00050  *     40, 41, 43-49, 51-58, 60-66, 81, 82, 84, 86, 90-95, 98.
00051  */
00052 static int cclen(const char *number)
00053 {
00054    char d1,d2;
00055 
00056    if (!number || (strlen(number) < 3))
00057       return(0);
00058 
00059    d1 = number[0];
00060    d2 = number[1];
00061    
00062    if (!isdigit((int)d2)) 
00063       return(0);
00064 
00065    switch(d1) {
00066       case '1':
00067       case '7':
00068          return(1);
00069       case '2':
00070          if ((d2 == '0') || (d1 == '7'))
00071             return(2);
00072          break;
00073       case '3':
00074          if ((d2 >= '0') && (d1 <= '4'))
00075             return(2);
00076          if ((d2 == '6') || (d1 == '9'))
00077             return(2);
00078          break;
00079       case '4':
00080          if (d2 != '2')
00081             return(2);
00082          break;
00083       case '5':
00084          if ((d2 >= '1') && (d1 <= '8'))
00085             return(2);
00086          break;
00087       case '6':
00088          if (d1 <= '6')
00089             return(2);
00090          break;
00091       case '8':
00092          if ((d2 == '1') || (d1 == '2') || (d1 == '4') || (d1 == '6')) 
00093             return(2);
00094          break;
00095       case '9':
00096          if (d1 <= '5')
00097             return(2);
00098          if (d2 == '8')
00099             return(2);
00100          break;
00101       default:
00102          return(0);
00103    }
00104 
00105    return(3);
00106 }
00107 
00108 
00109 
00110 /* return the length of the string until c, if not found returns n */
00111 static inline int findchr(char* p, int c, unsigned int size)
00112 {
00113    int len=0;
00114 
00115    for(;len<size;p++){
00116       if (*p==(unsigned char)c) {
00117          return len;
00118       }
00119       len++;   
00120    }
00121    return len;
00122 }
00123 
00124 
00125 /* Parse NAPTR regexp field of the form !pattern!replacement! and return its
00126  * components in pattern and replacement parameters.  Regexp field starts at
00127  * address first and is len characters long.
00128  */
00129 static inline int parse_naptr_regexp(char* first, int len, str* pattern,
00130                               str* replacement)
00131 {
00132    char *second, *third;
00133 
00134    if (len > 0) {
00135       if (*first == '!') {
00136          second = (char *)memchr((void *)(first + 1), '!', len - 1);
00137          if (second) {
00138             len = len - (second - first + 1);
00139             if (len > 0) {
00140                third = memchr(second + 1, '!', len);
00141                if (third) {
00142                   pattern->len = second - first - 1;
00143                   pattern->s = first + 1;
00144                   replacement->len = third - second - 1;
00145                   replacement->s = second + 1;
00146                   return 1;
00147                } else {
00148                   LM_ERR("Third ! missing from regexp\n");
00149                   return -1;
00150                }
00151             } else {
00152                LM_ERR("Third ! missing from regexp\n");
00153                return -2;
00154             }
00155          } else {
00156             LM_ERR("Second ! missing from regexp\n");
00157             return -3;
00158          }
00159       } else {
00160          LM_ERR("First ! missing from regexp\n");
00161          return -4;
00162       }
00163    } else {
00164       LM_ERR("Regexp missing\n");
00165       return -5;
00166    }
00167 }
00168 /* Checks if NAPTR record has flag u and its services field
00169  * e2u+[service:]sip or
00170  * e2u+service[+service[+service[+...]]]
00171  */
00172 static inline int sip_match( struct naptr_rdata* naptr, str* service)
00173 {
00174   if (service->len == 0) {
00175     return (naptr->flags_len == 1) &&
00176       ((naptr->flags[0] == 'u') || (naptr->flags[0] == 'U')) &&
00177       (naptr->services_len == 7) &&
00178       ((strncasecmp(naptr->services, "e2u+sip", 7) == 0) ||
00179        (strncasecmp(naptr->services, "sip+e2u", 7) == 0));
00180   } else if (service->s[0] != '+') {
00181     return (naptr->flags_len == 1) &&
00182       ((naptr->flags[0] == 'u') || (naptr->flags[0] == 'U')) &&
00183       (naptr->services_len == service->len + 8) &&
00184       (strncasecmp(naptr->services, "e2u+", 4) == 0) &&
00185       (strncasecmp(naptr->services + 4, service->s, service->len) == 0) &&
00186       (strncasecmp(naptr->services + 4 + service->len, ":sip", 4) == 0);
00187   } else { /* handle compound NAPTRs and multiple services */
00188     str bakservice, baknaptr; /* we bakup the str */
00189     int naptrlen, len;        /* length of the extracted service */
00190 
00191     /* RFC 3761, NAPTR service field must start with E2U+ */
00192     if (strncasecmp(naptr->services, "e2u+", 4) != 0) {
00193       return 0;
00194     }
00195     baknaptr.s   = naptr->services + 4; /* leading 'e2u+' */
00196     baknaptr.len = naptr->services_len - 4;
00197     for (;;) { /* iterate over services in NAPTR */
00198       bakservice.s   = service->s + 1; /* leading '+' */
00199       bakservice.len = service->len - 1;
00200       naptrlen = findchr(baknaptr.s,'+',baknaptr.len);
00201 
00202       for (;;) { /* iterate over services in enum_query */
00203         len = findchr(bakservice.s,'+',bakservice.len);
00204         if ((naptrlen == len ) && !strncasecmp(baknaptr.s, bakservice.s, len)){
00205           return 1;
00206         }
00207         if ( (bakservice.len -= len+1) > 0) {
00208           bakservice.s += len+1;
00209           continue;
00210         }
00211         break;
00212       }
00213       if ( (baknaptr.len -= naptrlen+1) > 0) {
00214         baknaptr.s += naptrlen+1;
00215         continue;
00216       }
00217       break;
00218     }
00219     /* no matching service found */
00220     return 0;
00221   }
00222 }
00223 
00224 
00225 /*
00226  * Checks if argument is an e164 number starting with +
00227  */
00228 static inline int is_e164(str* _user)
00229 {
00230    int i;
00231    char c;
00232    
00233    if ((_user->len > 2) && (_user->len < 17) && ((_user->s)[0] == '+')) {
00234       for (i = 1; i < _user->len; i++) {
00235          c = (_user->s)[i];
00236          if ((c < '0') || (c > '9')) return -1;
00237       }
00238       return 1;
00239    } else {
00240        return -1;
00241    }
00242 }
00243             
00244 
00245 /*
00246  * Call is_from_user_enum_2 with module parameter suffix and default service.
00247  */
00248 int is_from_user_enum_0(struct sip_msg* _msg, char* _str1, char* _str2)
00249 {
00250    return is_from_user_enum_2(_msg, (char *)(&suffix), (char *)(&service));
00251 }
00252 
00253 /*
00254  * Call is_from_user_enum_2 with given suffix and default service.
00255  */
00256 int is_from_user_enum_1(struct sip_msg* _msg, char* _suffix, char* _str2)
00257 {
00258    return is_from_user_enum_2(_msg, _suffix, (char *)(&service));
00259 }
00260 
00261 /*
00262  * Check if from user is a valid enum based user, and check to make sure
00263  * that the src_ip == an srv record that maps to the enum from user.
00264  */
00265 int is_from_user_enum_2(struct sip_msg* _msg, char* _suffix, char* _service)
00266 {
00267    struct ip_addr addr;
00268    struct hostent* he;
00269    unsigned short zp;
00270    unsigned short proto;
00271    char *user_s;
00272    int user_len, i, j;
00273    char name[MAX_DOMAIN_SIZE];
00274    char uri[MAX_URI_SIZE];
00275    struct sip_uri *furi;
00276    struct sip_uri luri;
00277    struct rdata* head;
00278 
00279    str* suffix;
00280    str* service;
00281 
00282    struct rdata* l;
00283    struct naptr_rdata* naptr;
00284 
00285    str pattern, replacement, result;
00286    char string[17];
00287 
00288    if (parse_from_header(_msg) < 0) {
00289        LM_ERR("Failed to parse From header\n");
00290        return -1;
00291    }
00292    
00293    if(_msg->from==NULL || get_from(_msg)==NULL) {
00294        LM_DBG("No From header\n");
00295        return -1;
00296    }
00297 
00298    if ((furi = parse_from_uri(_msg)) == NULL) {
00299        LM_ERR("Failed to parse From URI\n");
00300        return -1;
00301    }
00302 
00303    suffix = (str*)_suffix;
00304    service = (str*)_service;
00305 
00306    if (is_e164(&(furi->user)) == -1) {
00307        LM_ERR("From URI user is not an E164 number\n");
00308        return -1;
00309    }
00310 
00311    /* assert: the from user is a valid formatted e164 string */
00312 
00313    user_s = furi->user.s;
00314    user_len = furi->user.len;
00315 
00316    j = 0;
00317    for (i = user_len - 1; i > 0; i--) {
00318       name[j] = user_s[i];
00319       name[j + 1] = '.';
00320       j = j + 2;
00321    }
00322 
00323    memcpy(name + j, suffix->s, suffix->len + 1);
00324 
00325    head = get_record(name, T_NAPTR);
00326 
00327    if (head == 0) {
00328       LM_DBG("No NAPTR record found for %s.\n", name);
00329       return -3;
00330    }
00331 
00332    /* we have the naptr records, loop and find an srv record with */
00333    /* same ip address as source ip address, if we do then true is returned */
00334 
00335    for (l = head; l; l = l->next) {
00336 
00337       if (l->type != T_NAPTR) continue; /*should never happen*/
00338       naptr = (struct naptr_rdata*)l->rdata;
00339       if (naptr == 0) {
00340          LM_ERR("Null rdata in DNS response\n");
00341          free_rdata_list(head);
00342          return -4;
00343       }
00344 
00345       LM_DBG("ENUM query on %s: order %u, pref %u, flen %u, flags "
00346              "'%.*s', slen %u, services '%.*s', rlen %u, "
00347              "regexp '%.*s'\n",
00348              name, naptr->order, naptr->pref,
00349           naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags), naptr->services_len,
00350           (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len,
00351           (int)(naptr->regexp_len), ZSW(naptr->regexp));
00352 
00353       if (sip_match(naptr, service) != 0) {
00354          if (parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len,
00355                 &pattern, &replacement) < 0) {
00356             free_rdata_list(head); /*clean up*/
00357             LM_ERR("Parsing of NAPTR regexp failed\n");
00358             return -5;
00359          }
00360 #ifdef LATER
00361          if ((pattern.len == 4) && (strncmp(pattern.s, "^.*$", 4) == 0)) {
00362             LM_DBG("Resulted in replacement: '%.*s'\n",
00363                    replacement.len, ZSW(replacement.s));          
00364             retval = set_uri(_msg, replacement.s, replacement.len);
00365             free_rdata_list(head); /*clean up*/
00366             return retval;
00367          }
00368 #endif
00369          result.s = &(uri[0]);
00370          result.len = MAX_URI_SIZE;
00371          /* Avoid making copies of pattern and replacement */
00372          pattern.s[pattern.len] = (char)0;
00373          replacement.s[replacement.len] = (char)0;
00374          /* We have already checked the size of
00375             _msg->parsed_uri.user.s */ 
00376          memcpy(&(string[0]), user_s, user_len);
00377          string[user_len] = (char)0;
00378          if (reg_replace(pattern.s, replacement.s, &(string[0]),
00379                &result) < 0) {
00380             pattern.s[pattern.len] = '!';
00381             replacement.s[replacement.len] = '!';
00382             LM_ERR("Regexp replace failed\n");
00383             free_rdata_list(head); /*clean up*/
00384             return -6;
00385          }
00386          LM_DBG("Resulted in replacement: '%.*s'\n",
00387              result.len, ZSW(result.s));
00388 
00389          if(parse_uri(result.s, result.len, &luri) < 0)
00390          {
00391             LM_ERR("Parsing of URI <%.*s> failed\n",
00392                    result.len, result.s);
00393             free_rdata_list(head); /*clean up*/
00394             return -7;
00395          }
00396 
00397          pattern.s[pattern.len] = '!';
00398          replacement.s[replacement.len] = '!';
00399 
00400          zp = 0;
00401          proto = PROTO_NONE;
00402          he = sip_resolvehost(&luri.host, &zp, &proto,
00403             (luri.type==SIPS_URI_T)?1:0 , 0);
00404 
00405          hostent2ip_addr(&addr, he, 0);
00406 
00407          if(ip_addr_cmp(&addr, &_msg->rcv.src_ip))
00408          {
00409             free_rdata_list(head);
00410             return(1);
00411          }
00412       }
00413    }
00414    free_rdata_list(head); /*clean up*/
00415    LM_DBG("FAIL\n");
00416 
00417     /* must not have found the record */
00418     return(-8);
00419 }
00420 
00421 
00422 
00423 /* 
00424  * Add parameter to URI.
00425  */
00426 int add_uri_param(str *uri, str *param, str *new_uri)
00427 {
00428    struct sip_uri puri;
00429    char *at;
00430 
00431    if (parse_uri(uri->s, uri->len, &puri) < 0) {
00432       return 0;
00433    }
00434 
00435    /* if current uri has no headers, pad param to the end of uri */
00436    if (puri.headers.len == 0) {
00437       memcpy(uri->s + uri->len, param->s, param->len);
00438       uri->len = uri->len + param->len;
00439       new_uri->len = 0;
00440       return 1;
00441    }
00442 
00443    /* otherwise take the long path and create new_uri */
00444    at = new_uri->s;
00445    switch (puri.type) {
00446    case SIP_URI_T:
00447        memcpy(at, "sip:", 4);
00448        at = at + 4;
00449        break;
00450    case SIPS_URI_T:
00451        memcpy(at, "sips:", 5);
00452        at = at + 5;
00453        break;
00454    case TEL_URI_T:
00455        memcpy(at, "tel:", 4);
00456        at = at + 4;
00457        break;
00458    case TELS_URI_T:
00459        memcpy(at, "tels:", 5);
00460        at = at + 5;
00461        break;
00462    default:
00463        LM_ERR("Unknown URI scheme <%d>\n", puri.type);
00464        return 0;
00465    }
00466    if (puri.user.len) {
00467       memcpy(at, puri.user.s, puri.user.len);
00468       at = at + puri.user.len;
00469       if (puri.passwd.len) {
00470          *at = ':';
00471          at = at + 1;
00472          memcpy(at, puri.passwd.s, puri.passwd.len);
00473          at = at + puri.passwd.len;
00474       };
00475       *at = '@';
00476       at = at + 1;
00477    }
00478    memcpy(at, puri.host.s, puri.host.len);
00479    at = at + puri.host.len;
00480    if (puri.port.len) {
00481       *at = ':';
00482       at = at + 1;
00483       memcpy(at, puri.port.s, puri.port.len);
00484       at = at + puri.port.len;
00485    }
00486    if (puri.params.len) {
00487       *at = ';';
00488       at = at + 1;
00489       memcpy(at, puri.params.s, puri.params.len);
00490       at = at + puri.params.len;
00491    }
00492    memcpy(at, param->s, param->len);
00493    at = at + param->len;
00494    *at = '?';
00495    at = at + 1;
00496    memcpy(at, puri.headers.s, puri.headers.len);
00497    at = at + puri.headers.len;
00498    new_uri->len = at - new_uri->s;
00499    return 1;
00500 }
00501 
00502 /*
00503  * Tests if one result record is "greater" that the other.  Non-NAPTR records
00504  * greater that NAPTR record.  An invalid NAPTR record is greater than a 
00505  * valid one.  Valid NAPTR records are compared based on their
00506  * (order,preference).
00507  */
00508 static inline int naptr_greater(struct rdata* a, struct rdata* b)
00509 {
00510    struct naptr_rdata *na, *nb;
00511 
00512    if (a->type != T_NAPTR) return 1;
00513    if (b->type != T_NAPTR) return 0;
00514 
00515    na = (struct naptr_rdata*)a->rdata;
00516    if (na == 0) return 1;
00517 
00518    nb = (struct naptr_rdata*)b->rdata;
00519    if (nb == 0) return 0;
00520    
00521    return (((na->order) << 16) + na->pref) >
00522       (((nb->order) << 16) + nb->pref);
00523 }
00524    
00525    
00526 /*
00527  * Bubble sorts result record list according to naptr (order,preference).
00528  */
00529 static inline void naptr_sort(struct rdata** head)
00530 {
00531    struct rdata *p, *q, *r, *s, *temp, *start;
00532 
00533         /* r precedes p and s points to the node up to which comparisons
00534          are to be made */ 
00535 
00536    s = NULL;
00537    start = *head;
00538    while ( s != start -> next ) { 
00539       r = p = start ; 
00540       q = p -> next ;
00541       while ( p != s ) { 
00542          if ( naptr_greater(p, q) ) { 
00543             if ( p == start ) { 
00544                temp = q -> next ; 
00545                q -> next = p ; 
00546                p -> next = temp ;
00547                start = q ; 
00548                r = q ; 
00549             } else {
00550                temp = q -> next ; 
00551                q -> next = p ; 
00552                p -> next = temp ;
00553                r -> next = q ; 
00554                r = q ; 
00555             } 
00556          } else {
00557             r = p ; 
00558             p = p -> next ; 
00559          } 
00560          q = p -> next ; 
00561          if ( q == s ) s = p ; 
00562       }
00563    }
00564    *head = start;
00565 }  
00566    
00567 
00568 /*
00569  * Makes enum query on name.  On success, rewrites user part and 
00570  * replaces Request-URI.
00571  */
00572 int do_query(struct sip_msg* _msg, char *user, char *name, str *service) {
00573 
00574     char uri[MAX_URI_SIZE];
00575     char new_uri[MAX_URI_SIZE];
00576     unsigned int priority, curr_prio, first;
00577     qvalue_t q;
00578     struct rdata* head;
00579     struct rdata* l;
00580     struct naptr_rdata* naptr;
00581     str pattern, replacement, result, new_result;
00582 
00583     head = get_record(name, T_NAPTR);
00584     
00585     if (head == 0) {
00586    LM_DBG("No NAPTR record found for %s.\n", name);
00587    return -1;
00588     }
00589     
00590     naptr_sort(&head);
00591 
00592     q = MAX_Q - 10;
00593     curr_prio = 0;
00594     first = 1;
00595 
00596     for (l = head; l; l = l->next) {
00597 
00598    if (l->type != T_NAPTR) continue; /*should never happen*/
00599    naptr = (struct naptr_rdata*)l->rdata;
00600    if (naptr == 0) {
00601        LM_ERR("Null rdata in DNS response\n");
00602        continue;
00603    }
00604 
00605    LM_DBG("ENUM query on %s: order %u, pref %u, flen %u, flags '%.*s', "
00606           "slen %u, services '%.*s', rlen %u, regexp '%.*s'\n",
00607           name, naptr->order, naptr->pref,
00608        naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags),
00609        naptr->services_len,
00610        (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len,
00611        (int)(naptr->regexp_len), ZSW(naptr->regexp));
00612    
00613    if (sip_match(naptr, service) == 0) continue;
00614    
00615    if (parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len,
00616                 &pattern, &replacement) < 0) {
00617        LM_ERR("Parsing of NAPTR regexp failed\n");
00618        continue;
00619    }
00620    result.s = &(uri[0]);
00621    result.len = MAX_URI_SIZE;
00622    /* Avoid making copies of pattern and replacement */
00623    pattern.s[pattern.len] = (char)0;
00624    replacement.s[replacement.len] = (char)0;
00625    if (reg_replace(pattern.s, replacement.s, user, &result) < 0) {
00626        pattern.s[pattern.len] = '!';
00627        replacement.s[replacement.len] = '!';
00628        LM_ERR("Regexp replace failed\n");
00629        continue;
00630    }
00631    LM_DBG("Resulted in replacement: '%.*s'\n", result.len, ZSW(result.s));
00632    pattern.s[pattern.len] = '!';
00633    replacement.s[replacement.len] = '!';
00634    
00635    if (param.len > 0) {
00636        if (result.len + param.len > MAX_URI_SIZE - 1) {
00637       LM_ERR("URI is too long\n");
00638       continue;
00639        }
00640        new_result.s = &(new_uri[0]);
00641        new_result.len = MAX_URI_SIZE;
00642        if (add_uri_param(&result, &param, &new_result) == 0) {
00643       LM_ERR("Parsing of URI <%.*s> failed\n",
00644              result.len, result.s);
00645       continue;
00646        }
00647        if (new_result.len > 0) {
00648       result = new_result;
00649        }
00650    }
00651    
00652    if (first) {
00653        if (rewrite_uri(_msg, &result) == -1) {
00654       goto done;
00655        }
00656        set_ruri_q(q);
00657        first = 0;
00658        curr_prio = ((naptr->order) << 16) + naptr->pref;
00659    } else {
00660        priority = ((naptr->order) << 16) + naptr->pref;
00661        if (priority > curr_prio) {
00662       q = q - 10;
00663       curr_prio = priority;
00664        }
00665        if (append_branch(_msg, &result, 0, 0, q, 0, 0) == -1) {
00666       goto done;
00667        }
00668    }
00669     }
00670 
00671 done:
00672     free_rdata_list(head);
00673     return first ? -1 : 1;
00674 }
00675 
00676    
00677 /*
00678  * Call enum_query_2 with module parameter suffix and default service.
00679  */
00680 int enum_query_0(struct sip_msg* _msg, char* _str1, char* _str2)
00681 {
00682    return enum_query_2(_msg, (char *)(&suffix), (char *)(&service));
00683 }
00684 
00685 
00686 /*
00687  * Call enum_query_2 with given suffix and default service.
00688  */
00689 int enum_query_1(struct sip_msg* _msg, char* _suffix, char* _str2)
00690 {
00691    return enum_query_2(_msg, _suffix, (char *)(&service));
00692 }
00693 
00694 
00695 /*
00696  * See documentation in README file.
00697  */
00698 int enum_query_2(struct sip_msg* _msg, char* _suffix, char* _service)
00699 {
00700    char *user_s;
00701    int user_len, i, j;
00702    char name[MAX_DOMAIN_SIZE];
00703    char string[17];
00704 
00705    str *suffix, *service;
00706 
00707    suffix = (str*)_suffix;
00708    service = (str*)_service;
00709 
00710    if (parse_sip_msg_uri(_msg) < 0) {
00711       LM_ERR("Parsing of R-URI failed\n");
00712       return -1;
00713    }
00714 
00715    if (is_e164(&(_msg->parsed_uri.user)) == -1) {
00716       LM_ERR("R-URI user is not an E164 number\n");
00717       return -1;
00718    }
00719 
00720    user_s = _msg->parsed_uri.user.s;
00721    user_len = _msg->parsed_uri.user.len;
00722 
00723    memcpy(&(string[0]), user_s, user_len);
00724    string[user_len] = (char)0;
00725 
00726    j = 0;
00727    for (i = user_len - 1; i > 0; i--) {
00728       name[j] = user_s[i];
00729       name[j + 1] = '.';
00730       j = j + 2;
00731    }
00732 
00733    memcpy(name + j, suffix->s, suffix->len + 1);
00734 
00735    return do_query(_msg, string, name, service);
00736 }
00737 
00738 
00739 /*********** INFRASTRUCTURE ENUM ***************/
00740 
00741 /*
00742  * Call enum_query_2 with default suffix and service.
00743  */
00744 int i_enum_query_0(struct sip_msg* _msg, char* _suffix, char* _service)
00745 {
00746    return i_enum_query_2(_msg, (char *)(&i_suffix), (char *)(&service));
00747 }
00748 
00749 /*
00750  * Call enum_query_2 with given suffix and default service.
00751  */
00752 int i_enum_query_1(struct sip_msg* _msg, char* _suffix, char* _service)
00753 {
00754    return i_enum_query_2(_msg, _suffix, (char *)(&service));
00755 }
00756 
00757 
00758 int i_enum_query_2(struct sip_msg* _msg, char* _suffix, char* _service)
00759 {
00760    char *user_s;
00761    int user_len, i, j;
00762    char name[MAX_DOMAIN_SIZE];
00763    char apex[MAX_COMPONENT_SIZE + 1];
00764    char separator[MAX_COMPONENT_SIZE + 1];
00765    int sdl = 0;    /* subdomain location: infrastructure enum offset */
00766    int cc_len;
00767    struct rdata* head;
00768 
00769    char string[17];
00770 
00771    str *suffix, *service;
00772 
00773    suffix = (str*)_suffix;
00774    service = (str*)_service;
00775 
00776    if (parse_sip_msg_uri(_msg) < 0) {
00777       LM_ERR("Parsing of R-URI failed\n");
00778       return -1;
00779    }
00780 
00781    if (is_e164(&(_msg->parsed_uri.user)) == -1) {
00782       LM_ERR("R-URI user is not an E164 number\n");
00783       return -1;
00784    }
00785 
00786    user_s = _msg->parsed_uri.user.s;
00787    user_len = _msg->parsed_uri.user.len;
00788 
00789    /* make sure we don't run out of space in strings */
00790    if (( 2*user_len + MAX_COMPONENT_SIZE + MAX_COMPONENT_SIZE + 4) > MAX_DOMAIN_SIZE) {
00791       LM_ERR("Strings too long\n");
00792       return -1;
00793    }
00794    if ( i_branchlabel.len > MAX_COMPONENT_SIZE ) {
00795       LM_ERR("i_branchlabel too long\n");
00796       return -1;
00797    }
00798    if ( suffix->len > MAX_COMPONENT_SIZE ) {
00799       LM_ERR("Suffix too long\n");
00800       return -1;
00801    }
00802 
00803 
00804    memcpy(&(string[0]), user_s, user_len);
00805    string[user_len] = (char)0;
00806 
00807    /* Set up parameters as for user-enum */
00808    memcpy(apex,  suffix->s , suffix->len);
00809    apex[suffix->len] = (char)0;
00810    sdl = 0;    /* where to insert i-enum separator */
00811    separator[0] = 0; /* don't insert anything */
00812 
00813    cc_len = cclen(string + 1);
00814 
00815    if (!strncasecmp(i_bl_alg.s,"ebl",i_bl_alg.len)) {
00816       sdl = cc_len; /* default */
00817 
00818       j = 0;
00819       memcpy(name, i_branchlabel.s, i_branchlabel.len);
00820       j += i_branchlabel.len;
00821       name[j++] = '.';
00822 
00823       for (i = cc_len ; i > 0; i--) {
00824          name[j++] = user_s[i];
00825          name[j++] = '.';
00826       }
00827       memcpy(name + j, suffix->s, suffix->len + 1);
00828 
00829       LM_DBG("Looking for EBL record for %s.\n", name); 
00830       head = get_record(name, T_EBL);
00831       if (head == 0) {
00832          LM_DBG("No EBL found for %s. Defaulting to user ENUM.\n",name);
00833       } else {
00834             struct ebl_rdata* ebl;
00835          ebl = (struct ebl_rdata *) head->rdata;
00836 
00837          LM_DBG("EBL record for %s is %d / %.*s / %.*s.\n",
00838                 name, ebl->position, (int)ebl->separator_len,
00839                 ebl->separator,(int)ebl->apex_len, ebl->apex);
00840 
00841          if ((ebl->apex_len > MAX_COMPONENT_SIZE) || (ebl->separator_len > MAX_COMPONENT_SIZE)) {
00842             LM_ERR("EBL strings too long\n"); 
00843             return -1;
00844          }
00845 
00846          if (ebl->position > 15)  {
00847             LM_ERR("EBL position too large (%d)\n",
00848                    ebl->position); 
00849             return -1;
00850          }
00851 
00852          sdl = ebl->position;
00853 
00854          memcpy(separator, ebl->separator, ebl->separator_len);
00855          separator[ebl->separator_len] = 0;
00856 
00857          memcpy(apex, ebl->apex, ebl->apex_len);
00858          apex[ebl->apex_len] = 0;
00859          free_rdata_list(head);
00860       }
00861    } else if (!strncasecmp(i_bl_alg.s,"txt",i_bl_alg.len)) {
00862       sdl = cc_len; /* default */
00863       memcpy(separator, i_branchlabel.s, i_branchlabel.len);
00864       separator[i_branchlabel.len] = 0;
00865       /* no change to apex */
00866 
00867       j = 0;
00868       memcpy(name, i_branchlabel.s, i_branchlabel.len);
00869       j += i_branchlabel.len;
00870       name[j++] = '.';
00871 
00872       for (i = cc_len ; i > 0; i--) {
00873          name[j++] = user_s[i];
00874          name[j++] = '.';
00875       }
00876       memcpy(name + j, suffix->s, suffix->len + 1);
00877 
00878       head = get_record(name, T_TXT);
00879       if (head == 0) {
00880          LM_DBG("TXT found for %s. Defaulting to %d\n",
00881                 name, cc_len);
00882       } else {
00883          sdl = atoi(((struct txt_rdata*)head->rdata)->txt);
00884          LM_DBG("TXT record for %s is %d.\n", name, sdl);
00885 
00886          if ((sdl < 0) || (sdl > 10)) {
00887             LM_ERR("Sdl %d out of bounds. Set back to cc_len.\n", sdl);
00888             sdl = cc_len;
00889          }
00890          free_rdata_list(head);
00891       }
00892    } else { /* defaults to CC */
00893       sdl = cc_len;
00894       memcpy(separator, i_branchlabel.s, i_branchlabel.len);
00895       separator[i_branchlabel.len] = 0;
00896       /* no change to apex */
00897    }
00898 
00899    j = 0;
00900    sdl++; /* to avoid comparing i to (sdl+1) */
00901    for (i = user_len - 1; i > 0; i--) {
00902       name[j] = user_s[i];
00903       name[j + 1] = '.';
00904       j = j + 2;
00905       if (separator[0] && (i == sdl)) { /* insert the I-ENUM separator here? */
00906          strcpy(name + j, separator);  /* we've checked string sizes. */
00907          j += strlen(separator);
00908          name[j++] = '.';
00909       }
00910    }
00911 
00912    memcpy(name + j, apex, strlen(apex)+1);
00913 
00914    return do_query(_msg, string, name, service);
00915 }
00916 
00917 
00918 
00919 /******************* FQUERY *******************/
00920 
00921 
00922 /*
00923  * Call enum_pv_query_3 with pv arg, module parameter suffix,
00924  * and default service.
00925  */
00926 int enum_pv_query_1(struct sip_msg* _msg, char* _sp)
00927 {
00928     return enum_pv_query_3(_msg, _sp, (char *)(&suffix), (char *)(&service));
00929 }
00930 
00931 /*
00932  * Call enum_pv_query_3 with pv and suffix args and default service.
00933  */
00934 int enum_pv_query_2(struct sip_msg* _msg, char* _sp, char* _suffix)
00935 {
00936     return enum_pv_query_3(_msg, _sp, _suffix, (char *)(&service));
00937 }
00938 
00939 /*
00940  * See documentation in README file.
00941  */
00942 
00943 int enum_pv_query_3(struct sip_msg* _msg, char* _sp, char* _suffix,
00944           char* _service)
00945 {
00946    char *user_s;
00947    int user_len, i, j, first;
00948    char name[MAX_DOMAIN_SIZE];
00949    char uri[MAX_URI_SIZE];
00950    char new_uri[MAX_URI_SIZE];
00951    unsigned int priority, curr_prio;
00952    qvalue_t q;
00953    char tostring[17];
00954    struct rdata* head;
00955    struct rdata* l;
00956    struct naptr_rdata* naptr;
00957    str pattern, replacement, result, new_result;
00958    str *suffix, *service;
00959    char string[17];
00960    pv_spec_t *sp;
00961    pv_value_t pv_val;
00962 
00963    sp = (pv_spec_t *)_sp;
00964    suffix = (str*)_suffix;
00965    service = (str*)_service;
00966 
00967    /*
00968     *  Get R-URI user to tostring
00969     */
00970    if (parse_sip_msg_uri(_msg) < 0) {
00971       LM_ERR("R-URI parsing failed\n");
00972       return -1;
00973    }
00974 
00975    if (is_e164(&(_msg->parsed_uri.user)) == -1) {
00976       LM_ERR("R-URI user is not an E164 number\n");
00977       return -1;
00978    }
00979 
00980    user_s = _msg->parsed_uri.user.s;
00981    user_len = _msg->parsed_uri.user.len;
00982 
00983    memcpy(&(tostring[0]), user_s, user_len);
00984    tostring[user_len] = (char)0;
00985 
00986    /*
00987     * Get E.164 number from pseudo variable
00988          */
00989    if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) {
00990        if (pv_val.flags & PV_VAL_STR) {
00991       if (pv_val.rs.len == 0 || pv_val.rs.s == NULL) {
00992           LM_DBG("Missing E.164 number\n");
00993           return -1;
00994       }
00995        } else {
00996       LM_DBG("Pseudo variable value is not string\n");
00997       return -1;
00998    }
00999    } else {
01000        LM_DBG("Cannot get pseudo variable value\n");
01001        return -1;
01002    }
01003    if (is_e164(&(pv_val.rs)) == -1) {
01004        LM_ERR("pseudo variable does not contain an E164 number\n");
01005        return -1;
01006    }
01007 
01008    user_s = pv_val.rs.s;
01009    user_len = pv_val.rs.len;
01010 
01011    memcpy(&(string[0]), user_s, user_len);
01012    string[user_len] = (char)0;
01013 
01014    j = 0;
01015    for (i = user_len - 1; i > 0; i--) {
01016       name[j] = user_s[i];
01017       name[j + 1] = '.';
01018       j = j + 2;
01019    }
01020 
01021    memcpy(name + j, suffix->s, suffix->len + 1);
01022 
01023    head = get_record(name, T_NAPTR);
01024 
01025    if (head == 0) {
01026       LM_DBG("No NAPTR record found for %s.\n", name);
01027       return -1;
01028    }
01029 
01030    naptr_sort(&head);
01031 
01032    q = MAX_Q - 10;
01033    curr_prio = 0;
01034    first = 1;
01035 
01036    for (l = head; l; l = l->next) {
01037 
01038       if (l->type != T_NAPTR) continue; /*should never happen*/
01039       naptr = (struct naptr_rdata*)l->rdata;
01040       if (naptr == 0) {
01041          LM_ERR("Null rdata in DNS response\n");
01042          continue;
01043       }
01044 
01045       LM_DBG("ENUM query on %s: order %u, pref %u, flen %u, flags "
01046              "'%.*s', slen %u, services '%.*s', rlen %u, "
01047              "regexp '%.*s'\n",
01048              name, naptr->order, naptr->pref,
01049           naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags),
01050           naptr->services_len,
01051           (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len,
01052           (int)(naptr->regexp_len), ZSW(naptr->regexp));
01053 
01054       if (sip_match(naptr, service) == 0) continue;
01055 
01056       if (parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len,
01057                    &pattern, &replacement) < 0) {
01058          LM_ERR("Parsing of NAPTR regexp failed\n");
01059          continue;
01060       }
01061       result.s = &(uri[0]);
01062       result.len = MAX_URI_SIZE;
01063       /* Avoid making copies of pattern and replacement */
01064       pattern.s[pattern.len] = (char)0;
01065       replacement.s[replacement.len] = (char)0;
01066       if (reg_replace(pattern.s, replacement.s, &(tostring[0]),
01067             &result) < 0) {
01068          pattern.s[pattern.len] = '!';
01069          replacement.s[replacement.len] = '!';
01070          LM_ERR("Regexp replace failed\n");
01071          continue;
01072       }
01073       LM_DBG("Resulted in replacement: '%.*s'\n",
01074              result.len, ZSW(result.s));
01075       pattern.s[pattern.len] = '!';
01076       replacement.s[replacement.len] = '!';
01077       
01078       if (param.len > 0) {
01079          if (result.len + param.len > MAX_URI_SIZE - 1) {
01080             LM_ERR("URI is too long\n");
01081             continue;
01082          }
01083          new_result.s = &(new_uri[0]);
01084          new_result.len = MAX_URI_SIZE;
01085          if (add_uri_param(&result, &param, &new_result) == 0) {
01086             LM_ERR("Parsing of URI <%.*s> failed\n",
01087                    result.len, result.s);
01088             continue;
01089          }
01090          if (new_result.len > 0) {
01091             result = new_result;
01092          }
01093       }
01094 
01095       if (first) {
01096          if (rewrite_uri(_msg, &result) == -1) {
01097             goto done;
01098          }
01099          set_ruri_q(q);
01100          first = 0;
01101          curr_prio = ((naptr->order) << 16) + naptr->pref;
01102       } else {
01103          priority = ((naptr->order) << 16) + naptr->pref;
01104          if (priority > curr_prio) {
01105             q = q - 10;
01106             curr_prio = priority;
01107          }
01108          if (append_branch(_msg, &result, 0, 0, q, 0, 0) == -1) {
01109             goto done;
01110          }
01111       }
01112    }
01113 
01114 done:
01115    free_rdata_list(head);
01116    return first ? -1 : 1;
01117 }
01118 

Generated on Wed May 23 06:00:45 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6