enum.c

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