opensips/modules/enum/enum.c

Wed, 10 Feb 2010 21:21:24 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 10 Feb 2010 21:21:24 +0100
changeset 17
733187d496d0
parent 12
a3ac912f2857
permissions
-rw-r--r--

Introduce authentication credential logic into the LCR module.
This logic is meant to complement that of changeset 18, adding
additional authentication flexibility to the UAC module.

     1 /*
     2  * $Id: enum.c 5901 2009-07-21 07:45:05Z bogdan_iancu $
     3  *
     4  * Enum and E164 related functions
     5  *
     6  * Copyright (C) 2002-2008 Juha Heinanen
     7  *
     8  * This file is part of opensips, a free SIP server.
     9  *
    10  * opensips is free software; you can redistribute it and/or modify
    11  * it under the terms of the GNU General Public License as published by
    12  * the Free Software Foundation; either version 2 of the License, or
    13  * (at your option) any later version
    14  *
    15  * opensips is distributed in the hope that it will be useful,
    16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    18  * GNU General Public License for more details.
    19  *
    20  * You should have received a copy of the GNU General Public License 
    21  * along with this program; if not, write to the Free Software 
    22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    23  *
    24  */
    26 #include <stdlib.h>
    28 #include "enum.h"
    29 #include "../../parser/parse_uri.h"
    30 #include "../../parser/parse_from.h"
    31 #include "../../ut.h"
    32 #include "../../resolve.h"
    33 #include "../../mem/mem.h"
    34 #include "../../dset.h"
    35 #include "../../qvalue.h"
    36 #include "enum_mod.h"
    37 #include "../../regexp.h"
    38 #include "../../pvar.h"
    40 /*
    41  * Input: E.164 number w/o leading +
    42  *
    43  * Output: number of digits in the country code
    44  * 	   0 on invalid number
    45  *
    46  * convention:
    47  *   3 digits is the default length of a country code.
    48  *   country codes 1 and 7 are a single digit.
    49  *   the following country codes are two digits: 20, 27, 30-34, 36, 39,
    50  *     40, 41, 43-49, 51-58, 60-66, 81, 82, 84, 86, 90-95, 98.
    51  */
    52 static int cclen(const char *number)
    53 {
    54 	char d1,d2;
    56 	if (!number || (strlen(number) < 3))
    57 		return(0);
    59 	d1 = number[0];
    60 	d2 = number[1];
    62 	if (!isdigit((int)d2)) 
    63 		return(0);
    65 	switch(d1) {
    66 		case '1':
    67 		case '7':
    68 			return(1);
    69 		case '2':
    70 			if ((d2 == '0') || (d1 == '7'))
    71 				return(2);
    72 			break;
    73 		case '3':
    74 			if ((d2 >= '0') && (d1 <= '4'))
    75 				return(2);
    76 			if ((d2 == '6') || (d1 == '9'))
    77 				return(2);
    78 			break;
    79 		case '4':
    80 			if (d2 != '2')
    81 				return(2);
    82 			break;
    83 		case '5':
    84 			if ((d2 >= '1') && (d1 <= '8'))
    85 				return(2);
    86 			break;
    87 		case '6':
    88 			if (d1 <= '6')
    89 				return(2);
    90 			break;
    91 		case '8':
    92 			if ((d2 == '1') || (d1 == '2') || (d1 == '4') || (d1 == '6')) 
    93 				return(2);
    94 			break;
    95 		case '9':
    96 			if (d1 <= '5')
    97 				return(2);
    98 			if (d2 == '8')
    99 				return(2);
   100 			break;
   101 		default:
   102 			return(0);
   103 	}
   105 	return(3);
   106 }
   110 /* return the length of the string until c, if not found returns n */
   111 static inline int findchr(char* p, int c, unsigned int size)
   112 {
   113 	int len=0;
   115 	for(;len<size;p++){
   116 		if (*p==(unsigned char)c) {
   117 			return len;
   118 		}
   119 		len++;   
   120 	}
   121 	return len;
   122 }
   125 /* Parse NAPTR regexp field of the form !pattern!replacement! and return its
   126  * components in pattern and replacement parameters.  Regexp field starts at
   127  * address first and is len characters long.
   128  */
   129 static inline int parse_naptr_regexp(char* first, int len, str* pattern,
   130 										str* replacement)
   131 {
   132 	char *second, *third;
   134 	if (len > 0) {
   135 		if (*first == '!') {
   136 			second = (char *)memchr((void *)(first + 1), '!', len - 1);
   137 			if (second) {
   138 				len = len - (second - first + 1);
   139 				if (len > 0) {
   140 					third = memchr(second + 1, '!', len);
   141 					if (third) {
   142 						pattern->len = second - first - 1;
   143 						pattern->s = first + 1;
   144 						replacement->len = third - second - 1;
   145 						replacement->s = second + 1;
   146 						return 1;
   147 					} else {
   148 						LM_ERR("Third ! missing from regexp\n");
   149 						return -1;
   150 					}
   151 				} else {
   152 					LM_ERR("Third ! missing from regexp\n");
   153 					return -2;
   154 				}
   155 			} else {
   156 				LM_ERR("Second ! missing from regexp\n");
   157 				return -3;
   158 			}
   159 		} else {
   160 			LM_ERR("First ! missing from regexp\n");
   161 			return -4;
   162 		}
   163 	} else {
   164 		LM_ERR("Regexp missing\n");
   165 		return -5;
   166 	}
   167 }
   168 /* Checks if NAPTR record has flag u and its services field
   169  * e2u+[service:]sip or
   170  * e2u+service[+service[+service[+...]]]
   171  */
   172 static inline int sip_match( struct naptr_rdata* naptr, str* service)
   173 {
   174   if (service->len == 0) {
   175     return (naptr->flags_len == 1) &&
   176       ((naptr->flags[0] == 'u') || (naptr->flags[0] == 'U')) &&
   177       (naptr->services_len == 7) &&
   178       ((strncasecmp(naptr->services, "e2u+sip", 7) == 0) ||
   179        (strncasecmp(naptr->services, "sip+e2u", 7) == 0));
   180   } else if (service->s[0] != '+') {
   181     return (naptr->flags_len == 1) &&
   182       ((naptr->flags[0] == 'u') || (naptr->flags[0] == 'U')) &&
   183       (naptr->services_len == service->len + 8) &&
   184       (strncasecmp(naptr->services, "e2u+", 4) == 0) &&
   185       (strncasecmp(naptr->services + 4, service->s, service->len) == 0) &&
   186       (strncasecmp(naptr->services + 4 + service->len, ":sip", 4) == 0);
   187   } else { /* handle compound NAPTRs and multiple services */
   188     str bakservice, baknaptr; /* we bakup the str */
   189     int naptrlen, len;        /* length of the extracted service */
   191     /* RFC 3761, NAPTR service field must start with E2U+ */
   192     if (strncasecmp(naptr->services, "e2u+", 4) != 0) {
   193       return 0;
   194     }
   195     baknaptr.s   = naptr->services + 4; /* leading 'e2u+' */
   196     baknaptr.len = naptr->services_len - 4;
   197     for (;;) { /* iterate over services in NAPTR */
   198       bakservice.s   = service->s + 1; /* leading '+' */
   199       bakservice.len = service->len - 1;
   200       naptrlen = findchr(baknaptr.s,'+',baknaptr.len);
   202       for (;;) { /* iterate over services in enum_query */
   203         len = findchr(bakservice.s,'+',bakservice.len);
   204         if ((naptrlen == len ) && !strncasecmp(baknaptr.s, bakservice.s, len)){
   205           return 1;
   206         }
   207         if ( (bakservice.len -= len+1) > 0) {
   208           bakservice.s += len+1;
   209           continue;
   210         }
   211         break;
   212       }
   213       if ( (baknaptr.len -= naptrlen+1) > 0) {
   214         baknaptr.s += naptrlen+1;
   215         continue;
   216       }
   217       break;
   218     }
   219     /* no matching service found */
   220     return 0;
   221   }
   222 }
   225 /*
   226  * Checks if argument is an e164 number starting with +
   227  */
   228 static inline int is_e164(str* _user)
   229 {
   230 	int i;
   231 	char c;
   233 	if ((_user->len > 2) && (_user->len < 17) && ((_user->s)[0] == '+')) {
   234 		for (i = 1; i < _user->len; i++) {
   235 			c = (_user->s)[i];
   236 			if ((c < '0') || (c > '9')) return -1;
   237 		}
   238 		return 1;
   239 	} else {
   240 	    return -1;
   241 	}
   242 }
   245 /*
   246  * Call is_from_user_enum_2 with module parameter suffix and default service.
   247  */
   248 int is_from_user_enum_0(struct sip_msg* _msg, char* _str1, char* _str2)
   249 {
   250 	return is_from_user_enum_2(_msg, (char *)(&suffix), (char *)(&service));
   251 }
   253 /*
   254  * Call is_from_user_enum_2 with given suffix and default service.
   255  */
   256 int is_from_user_enum_1(struct sip_msg* _msg, char* _suffix, char* _str2)
   257 {
   258 	return is_from_user_enum_2(_msg, _suffix, (char *)(&service));
   259 }
   261 /*
   262  * Check if from user is a valid enum based user, and check to make sure
   263  * that the src_ip == an srv record that maps to the enum from user.
   264  */
   265 int is_from_user_enum_2(struct sip_msg* _msg, char* _suffix, char* _service)
   266 {
   267 	struct ip_addr addr;
   268 	struct hostent* he;
   269 	unsigned short zp;
   270 	unsigned short proto;
   271 	char *user_s;
   272 	int user_len, i, j;
   273 	char name[MAX_DOMAIN_SIZE];
   274 	char uri[MAX_URI_SIZE];
   275 	struct sip_uri *furi;
   276 	struct sip_uri luri;
   277 	struct rdata* head;
   279 	str* suffix;
   280 	str* service;
   282 	struct rdata* l;
   283 	struct naptr_rdata* naptr;
   285 	str pattern, replacement, result;
   286 	char string[17];
   288 	if (parse_from_header(_msg) < 0) {
   289 	    LM_ERR("Failed to parse From header\n");
   290 	    return -1;
   291 	}
   293 	if(_msg->from==NULL || get_from(_msg)==NULL) {
   294 	    LM_DBG("No From header\n");
   295 	    return -1;
   296 	}
   298 	if ((furi = parse_from_uri(_msg)) == NULL) {
   299 	    LM_ERR("Failed to parse From URI\n");
   300 	    return -1;
   301 	}
   303 	suffix = (str*)_suffix;
   304 	service = (str*)_service;
   306 	if (is_e164(&(furi->user)) == -1) {
   307 	    LM_ERR("From URI user is not an E164 number\n");
   308 	    return -1;
   309 	}
   311 	/* assert: the from user is a valid formatted e164 string */
   313 	user_s = furi->user.s;
   314 	user_len = furi->user.len;
   316 	j = 0;
   317 	for (i = user_len - 1; i > 0; i--) {
   318 		name[j] = user_s[i];
   319 		name[j + 1] = '.';
   320 		j = j + 2;
   321 	}
   323 	memcpy(name + j, suffix->s, suffix->len + 1);
   325 	head = get_record(name, T_NAPTR);
   327 	if (head == 0) {
   328 		LM_DBG("No NAPTR record found for %s.\n", name);
   329 		return -3;
   330 	}
   332 	/* we have the naptr records, loop and find an srv record with */
   333 	/* same ip address as source ip address, if we do then true is returned */
   335 	for (l = head; l; l = l->next) {
   337 		if (l->type != T_NAPTR) continue; /*should never happen*/
   338 		naptr = (struct naptr_rdata*)l->rdata;
   339 		if (naptr == 0) {
   340 			LM_ERR("Null rdata in DNS response\n");
   341 			free_rdata_list(head);
   342 			return -4;
   343 		}
   345 		LM_DBG("ENUM query on %s: order %u, pref %u, flen %u, flags "
   346 		       "'%.*s', slen %u, services '%.*s', rlen %u, "
   347 		       "regexp '%.*s'\n",
   348 		       name, naptr->order, naptr->pref,
   349 		    naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags), naptr->services_len,
   350 		    (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len,
   351 		    (int)(naptr->regexp_len), ZSW(naptr->regexp));
   353 		if (sip_match(naptr, service) != 0) {
   354 			if (parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len,
   355 					 &pattern, &replacement) < 0) {
   356 				free_rdata_list(head); /*clean up*/
   357 				LM_ERR("Parsing of NAPTR regexp failed\n");
   358 				return -5;
   359 			}
   360 #ifdef LATER
   361 			if ((pattern.len == 4) && (strncmp(pattern.s, "^.*$", 4) == 0)) {
   362 				LM_DBG("Resulted in replacement: '%.*s'\n",
   363 				       replacement.len, ZSW(replacement.s));				
   364 				retval = set_uri(_msg, replacement.s, replacement.len);
   365 				free_rdata_list(head); /*clean up*/
   366 				return retval;
   367 			}
   368 #endif
   369 			result.s = &(uri[0]);
   370 			result.len = MAX_URI_SIZE;
   371 			/* Avoid making copies of pattern and replacement */
   372 			pattern.s[pattern.len] = (char)0;
   373 			replacement.s[replacement.len] = (char)0;
   374 			/* We have already checked the size of
   375 			   _msg->parsed_uri.user.s */ 
   376 			memcpy(&(string[0]), user_s, user_len);
   377 			string[user_len] = (char)0;
   378 			if (reg_replace(pattern.s, replacement.s, &(string[0]),
   379 					&result) < 0) {
   380 				pattern.s[pattern.len] = '!';
   381 				replacement.s[replacement.len] = '!';
   382 				LM_ERR("Regexp replace failed\n");
   383 				free_rdata_list(head); /*clean up*/
   384 				return -6;
   385 			}
   386 			LM_DBG("Resulted in replacement: '%.*s'\n",
   387 			    result.len, ZSW(result.s));
   389 			if(parse_uri(result.s, result.len, &luri) < 0)
   390 			{
   391 				LM_ERR("Parsing of URI <%.*s> failed\n",
   392 				       result.len, result.s);
   393 				free_rdata_list(head); /*clean up*/
   394 				return -7;
   395 			}
   397 			pattern.s[pattern.len] = '!';
   398 			replacement.s[replacement.len] = '!';
   400 			zp = 0;
   401 			proto = PROTO_NONE;
   402 			he = sip_resolvehost(&luri.host, &zp, &proto,
   403 				(luri.type==SIPS_URI_T)?1:0 , 0);
   405 			hostent2ip_addr(&addr, he, 0);
   407 			if(ip_addr_cmp(&addr, &_msg->rcv.src_ip))
   408 			{
   409 				free_rdata_list(head);
   410 				return(1);
   411 			}
   412 		}
   413 	}
   414 	free_rdata_list(head); /*clean up*/
   415 	LM_DBG("FAIL\n");
   417     /* must not have found the record */
   418     return(-8);
   419 }
   423 /* 
   424  * Add parameter to URI.
   425  */
   426 int add_uri_param(str *uri, str *param, str *new_uri)
   427 {
   428 	struct sip_uri puri;
   429 	char *at;
   431 	if (parse_uri(uri->s, uri->len, &puri) < 0) {
   432 		return 0;
   433 	}
   435 	/* if current uri has no headers, pad param to the end of uri */
   436 	if (puri.headers.len == 0) {
   437 		memcpy(uri->s + uri->len, param->s, param->len);
   438 		uri->len = uri->len + param->len;
   439 		new_uri->len = 0;
   440 		return 1;
   441 	}
   443 	/* otherwise take the long path and create new_uri */
   444 	at = new_uri->s;
   445 	switch (puri.type) {
   446 	case SIP_URI_T:
   447 	    memcpy(at, "sip:", 4);
   448 	    at = at + 4;
   449 	    break;
   450 	case SIPS_URI_T:
   451 	    memcpy(at, "sips:", 5);
   452 	    at = at + 5;
   453 	    break;
   454 	case TEL_URI_T:
   455 	    memcpy(at, "tel:", 4);
   456 	    at = at + 4;
   457 	    break;
   458 	case TELS_URI_T:
   459 	    memcpy(at, "tels:", 5);
   460 	    at = at + 5;
   461 	    break;
   462 	default:
   463 	    LM_ERR("Unknown URI scheme <%d>\n", puri.type);
   464 	    return 0;
   465 	}
   466 	if (puri.user.len) {
   467 		memcpy(at, puri.user.s, puri.user.len);
   468 		at = at + puri.user.len;
   469 		if (puri.passwd.len) {
   470 			*at = ':';
   471 			at = at + 1;
   472 			memcpy(at, puri.passwd.s, puri.passwd.len);
   473 			at = at + puri.passwd.len;
   474 		};
   475 		*at = '@';
   476 		at = at + 1;
   477 	}
   478 	memcpy(at, puri.host.s, puri.host.len);
   479 	at = at + puri.host.len;
   480 	if (puri.port.len) {
   481 		*at = ':';
   482 		at = at + 1;
   483 		memcpy(at, puri.port.s, puri.port.len);
   484 		at = at + puri.port.len;
   485 	}
   486 	if (puri.params.len) {
   487 		*at = ';';
   488 		at = at + 1;
   489 		memcpy(at, puri.params.s, puri.params.len);
   490 		at = at + puri.params.len;
   491 	}
   492 	memcpy(at, param->s, param->len);
   493 	at = at + param->len;
   494 	*at = '?';
   495 	at = at + 1;
   496 	memcpy(at, puri.headers.s, puri.headers.len);
   497 	at = at + puri.headers.len;
   498 	new_uri->len = at - new_uri->s;
   499 	return 1;
   500 }
   502 /*
   503  * Tests if one result record is "greater" that the other.  Non-NAPTR records
   504  * greater that NAPTR record.  An invalid NAPTR record is greater than a 
   505  * valid one.  Valid NAPTR records are compared based on their
   506  * (order,preference).
   507  */
   508 static inline int naptr_greater(struct rdata* a, struct rdata* b)
   509 {
   510 	struct naptr_rdata *na, *nb;
   512 	if (a->type != T_NAPTR) return 1;
   513 	if (b->type != T_NAPTR) return 0;
   515 	na = (struct naptr_rdata*)a->rdata;
   516 	if (na == 0) return 1;
   518 	nb = (struct naptr_rdata*)b->rdata;
   519 	if (nb == 0) return 0;
   521 	return (((na->order) << 16) + na->pref) >
   522 		(((nb->order) << 16) + nb->pref);
   523 }
   526 /*
   527  * Bubble sorts result record list according to naptr (order,preference).
   528  */
   529 static inline void naptr_sort(struct rdata** head)
   530 {
   531 	struct rdata *p, *q, *r, *s, *temp, *start;
   533         /* r precedes p and s points to the node up to which comparisons
   534          are to be made */ 
   536 	s = NULL;
   537 	start = *head;
   538 	while ( s != start -> next ) { 
   539 		r = p = start ; 
   540 		q = p -> next ;
   541 		while ( p != s ) { 
   542 			if ( naptr_greater(p, q) ) { 
   543 				if ( p == start ) { 
   544 					temp = q -> next ; 
   545 					q -> next = p ; 
   546 					p -> next = temp ;
   547 					start = q ; 
   548 					r = q ; 
   549 				} else {
   550 					temp = q -> next ; 
   551 					q -> next = p ; 
   552 					p -> next = temp ;
   553 					r -> next = q ; 
   554 					r = q ; 
   555 				} 
   556 			} else {
   557 				r = p ; 
   558 				p = p -> next ; 
   559 			} 
   560 			q = p -> next ; 
   561 			if ( q == s ) s = p ; 
   562 		}
   563 	}
   564 	*head = start;
   565 }	
   568 /*
   569  * Makes enum query on name.  On success, rewrites user part and 
   570  * replaces Request-URI.
   571  */
   572 int do_query(struct sip_msg* _msg, char *user, char *name, str *service) {
   574     char uri[MAX_URI_SIZE];
   575     char new_uri[MAX_URI_SIZE];
   576     unsigned int priority, curr_prio, first;
   577     qvalue_t q;
   578     struct rdata* head;
   579     struct rdata* l;
   580     struct naptr_rdata* naptr;
   581     str pattern, replacement, result, new_result;
   583     head = get_record(name, T_NAPTR);
   585     if (head == 0) {
   586 	LM_DBG("No NAPTR record found for %s.\n", name);
   587 	return -1;
   588     }
   590     naptr_sort(&head);
   592     q = MAX_Q - 10;
   593     curr_prio = 0;
   594     first = 1;
   596     for (l = head; l; l = l->next) {
   598 	if (l->type != T_NAPTR) continue; /*should never happen*/
   599 	naptr = (struct naptr_rdata*)l->rdata;
   600 	if (naptr == 0) {
   601 	    LM_ERR("Null rdata in DNS response\n");
   602 	    continue;
   603 	}
   605 	LM_DBG("ENUM query on %s: order %u, pref %u, flen %u, flags '%.*s', "
   606 	       "slen %u, services '%.*s', rlen %u, regexp '%.*s'\n",
   607 	       name, naptr->order, naptr->pref,
   608 	    naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags),
   609 	    naptr->services_len,
   610 	    (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len,
   611 	    (int)(naptr->regexp_len), ZSW(naptr->regexp));
   613 	if (sip_match(naptr, service) == 0) continue;
   615 	if (parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len,
   616 			       &pattern, &replacement) < 0) {
   617 	    LM_ERR("Parsing of NAPTR regexp failed\n");
   618 	    continue;
   619 	}
   620 	result.s = &(uri[0]);
   621 	result.len = MAX_URI_SIZE;
   622 	/* Avoid making copies of pattern and replacement */
   623 	pattern.s[pattern.len] = (char)0;
   624 	replacement.s[replacement.len] = (char)0;
   625 	if (reg_replace(pattern.s, replacement.s, user, &result) < 0) {
   626 	    pattern.s[pattern.len] = '!';
   627 	    replacement.s[replacement.len] = '!';
   628 	    LM_ERR("Regexp replace failed\n");
   629 	    continue;
   630 	}
   631 	LM_DBG("Resulted in replacement: '%.*s'\n", result.len, ZSW(result.s));
   632 	pattern.s[pattern.len] = '!';
   633 	replacement.s[replacement.len] = '!';
   635 	if (param.len > 0) {
   636 	    if (result.len + param.len > MAX_URI_SIZE - 1) {
   637 		LM_ERR("URI is too long\n");
   638 		continue;
   639 	    }
   640 	    new_result.s = &(new_uri[0]);
   641 	    new_result.len = MAX_URI_SIZE;
   642 	    if (add_uri_param(&result, &param, &new_result) == 0) {
   643 		LM_ERR("Parsing of URI <%.*s> failed\n",
   644 		       result.len, result.s);
   645 		continue;
   646 	    }
   647 	    if (new_result.len > 0) {
   648 		result = new_result;
   649 	    }
   650 	}
   652 	if (first) {
   653 	    if (set_ruri(_msg, &result) == -1) {
   654 		goto done;
   655 	    }
   656 	    set_ruri_q(q);
   657 	    first = 0;
   658 	    curr_prio = ((naptr->order) << 16) + naptr->pref;
   659 	} else {
   660 	    priority = ((naptr->order) << 16) + naptr->pref;
   661 	    if (priority > curr_prio) {
   662 		q = q - 10;
   663 		curr_prio = priority;
   664 	    }
   665 	    if (append_branch(_msg, &result, 0, 0, q, 0, 0) == -1) {
   666 		goto done;
   667 	    }
   668 	}
   669     }
   671 done:
   672     free_rdata_list(head);
   673     return first ? -1 : 1;
   674 }
   677 /*
   678  * Call enum_query_2 with module parameter suffix and default service.
   679  */
   680 int enum_query_0(struct sip_msg* _msg, char* _str1, char* _str2)
   681 {
   682 	return enum_query_2(_msg, (char *)(&suffix), (char *)(&service));
   683 }
   686 /*
   687  * Call enum_query_2 with given suffix and default service.
   688  */
   689 int enum_query_1(struct sip_msg* _msg, char* _suffix, char* _str2)
   690 {
   691 	return enum_query_2(_msg, _suffix, (char *)(&service));
   692 }
   695 /*
   696  * See documentation in README file.
   697  */
   698 int enum_query_2(struct sip_msg* _msg, char* _suffix, char* _service)
   699 {
   700 	char *user_s;
   701 	int user_len, i, j;
   702 	char name[MAX_DOMAIN_SIZE];
   703 	char string[17];
   705 	str *suffix, *service;
   707 	suffix = (str*)_suffix;
   708 	service = (str*)_service;
   710 	if (parse_sip_msg_uri(_msg) < 0) {
   711 		LM_ERR("Parsing of R-URI failed\n");
   712 		return -1;
   713 	}
   715 	if (is_e164(&(_msg->parsed_uri.user)) == -1) {
   716 		LM_ERR("R-URI user is not an E164 number\n");
   717 		return -1;
   718 	}
   720 	user_s = _msg->parsed_uri.user.s;
   721 	user_len = _msg->parsed_uri.user.len;
   723 	memcpy(&(string[0]), user_s, user_len);
   724 	string[user_len] = (char)0;
   726 	j = 0;
   727 	for (i = user_len - 1; i > 0; i--) {
   728 		name[j] = user_s[i];
   729 		name[j + 1] = '.';
   730 		j = j + 2;
   731 	}
   733 	memcpy(name + j, suffix->s, suffix->len + 1);
   735 	return do_query(_msg, string, name, service);
   736 }
   739 /*
   740  * Call isn_query_2 with module parameter suffix and default service.
   741  */
   742 int isn_query_0(struct sip_msg* _msg, char* _str1, char* _str2)
   743 {
   744 	return isn_query_2(_msg, (char *)(&isnsuffix), (char *)(&service));
   745 }
   748 /*
   749  * Call isn_query_2 with given suffix and default service.
   750  */
   751 int isn_query_1(struct sip_msg* _msg, char* _suffix, char* _str2)
   752 {
   753 	return isn_query_2(_msg, _suffix, (char *)(&service));
   754 }
   757 /*
   758  * See documentation in README file.
   759  */
   760 int isn_query_2(struct sip_msg* _msg, char* _suffix, char* _service)
   761 {
   762 	char *user_s = NULL;
   763 	int user_len, i, j;
   764 	char name[MAX_DOMAIN_SIZE] = {0};
   765 	char string[17] = {0};
   766 	char szItad[17] = {0};
   767 	size_t nItlen = 0;
   769 	str *suffix, *service;
   771 	suffix = (str*)_suffix;
   772 	service = (str*)_service;
   774 	if (parse_sip_msg_uri(_msg) < 0) {
   775 		LM_ERR("Parsing of R-URI failed\n");
   776 		return -1;
   777 	}
   779 	user_s = _msg->parsed_uri.user.s;
   780 	user_len = _msg->parsed_uri.user.len;
   782 	memcpy(&(string[0]), user_s, user_len);
   783 	string[user_len] = (char)0;
   785 	/* Do primitive test for correct ISN format, */
   786 	/* and set szItad to the ISN ITAD (RFC 3872/2871). */
   787 	/* Correct ISN format guessed from freenum.org and IANA */
   788 	/* doc http://www.iana.org/assignments/trip-parameters/ */
   789 	{
   790 		char *pAster = strchr(string, '*');
   791 		if (pAster && (nItlen = strspn(pAster + sizeof(char), "0123456789")))
   792 			strncpy(szItad, pAster + sizeof(char), nItlen);
   793 		else {
   794 			LM_ERR("R-URI user does not contain a valid ISN\n");
   795 			return -1;
   796 		}
   797 	}
   799 	/* Ammend the original ENUM E.164 string logic to process */
   800 	/* ISN numbers instead, which include a nonreversed ITAD. */
   801 	i = user_len - nItlen - sizeof(char); /* Ex: *1212 */
   802 	j = 0;
   803 	while (i--) {
   804 		name[j] = user_s[i];
   805 		name[j + 1] = '.';
   806 		j = j + 2;
   807 	}
   809 	strcat(name + j, szItad);  /* Copy the unreversed ITAD, */
   810 	name[j + nItlen] = '.';    /* and append a trailing dot. */
   811 	memcpy(name + j + nItlen + sizeof(char), suffix->s, suffix->len + 1);
   813 	return do_query(_msg, string, name, service);
   814 }
   817 /*********** INFRASTRUCTURE ENUM ***************/
   819 /*
   820  * Call enum_query_2 with default suffix and service.
   821  */
   822 int i_enum_query_0(struct sip_msg* _msg, char* _suffix, char* _service)
   823 {
   824 	return i_enum_query_2(_msg, (char *)(&i_suffix), (char *)(&service));
   825 }
   827 /*
   828  * Call enum_query_2 with given suffix and default service.
   829  */
   830 int i_enum_query_1(struct sip_msg* _msg, char* _suffix, char* _service)
   831 {
   832 	return i_enum_query_2(_msg, _suffix, (char *)(&service));
   833 }
   836 int i_enum_query_2(struct sip_msg* _msg, char* _suffix, char* _service)
   837 {
   838 	char *user_s;
   839 	int user_len, i, j;
   840 	char name[MAX_DOMAIN_SIZE];
   841 	char apex[MAX_COMPONENT_SIZE + 1];
   842 	char separator[MAX_COMPONENT_SIZE + 1];
   843 	int sdl = 0;    /* subdomain location: infrastructure enum offset */
   844 	int cc_len;
   845 	struct rdata* head;
   847 	char string[17];
   849 	str *suffix, *service;
   851 	suffix = (str*)_suffix;
   852 	service = (str*)_service;
   854 	if (parse_sip_msg_uri(_msg) < 0) {
   855 		LM_ERR("Parsing of R-URI failed\n");
   856 		return -1;
   857 	}
   859 	if (is_e164(&(_msg->parsed_uri.user)) == -1) {
   860 		LM_ERR("R-URI user is not an E164 number\n");
   861 		return -1;
   862 	}
   864 	user_s = _msg->parsed_uri.user.s;
   865 	user_len = _msg->parsed_uri.user.len;
   867 	/* make sure we don't run out of space in strings */
   868 	if (( 2*user_len + MAX_COMPONENT_SIZE + MAX_COMPONENT_SIZE + 4) > MAX_DOMAIN_SIZE) {
   869 		LM_ERR("Strings too long\n");
   870 		return -1;
   871 	}
   872 	if ( i_branchlabel.len > MAX_COMPONENT_SIZE ) {
   873 		LM_ERR("i_branchlabel too long\n");
   874 		return -1;
   875 	}
   876 	if ( suffix->len > MAX_COMPONENT_SIZE ) {
   877 		LM_ERR("Suffix too long\n");
   878 		return -1;
   879 	}
   882 	memcpy(&(string[0]), user_s, user_len);
   883 	string[user_len] = (char)0;
   885 	/* Set up parameters as for user-enum */
   886 	memcpy(apex,  suffix->s , suffix->len);
   887 	apex[suffix->len] = (char)0;
   888 	sdl = 0;		/* where to insert i-enum separator */
   889 	separator[0] = 0;	/* don't insert anything */
   891 	cc_len = cclen(string + 1);
   893 	if (!strncasecmp(i_bl_alg.s,"ebl",i_bl_alg.len)) {
   894 		sdl = cc_len; /* default */
   896 		j = 0;
   897 		memcpy(name, i_branchlabel.s, i_branchlabel.len);
   898 		j += i_branchlabel.len;
   899 		name[j++] = '.';
   901 		for (i = cc_len ; i > 0; i--) {
   902 			name[j++] = user_s[i];
   903 			name[j++] = '.';
   904 		}
   905 		memcpy(name + j, suffix->s, suffix->len + 1);
   907 		LM_DBG("Looking for EBL record for %s.\n", name); 
   908 		head = get_record(name, T_EBL);
   909 		if (head == 0) {
   910 			LM_DBG("No EBL found for %s. Defaulting to user ENUM.\n",name);
   911 		} else {
   912 		    	struct ebl_rdata* ebl;
   913 			ebl = (struct ebl_rdata *) head->rdata;
   915 			LM_DBG("EBL record for %s is %d / %.*s / %.*s.\n",
   916 			       name, ebl->position, (int)ebl->separator_len,
   917 			       ebl->separator,(int)ebl->apex_len, ebl->apex);
   919 			if ((ebl->apex_len > MAX_COMPONENT_SIZE) || (ebl->separator_len > MAX_COMPONENT_SIZE)) {
   920 				LM_ERR("EBL strings too long\n"); 
   921 				return -1;
   922 			}
   924 			if (ebl->position > 15)  {
   925 				LM_ERR("EBL position too large (%d)\n",
   926 				       ebl->position); 
   927 				return -1;
   928 			}
   930 			sdl = ebl->position;
   932 			memcpy(separator, ebl->separator, ebl->separator_len);
   933 			separator[ebl->separator_len] = 0;
   935 			memcpy(apex, ebl->apex, ebl->apex_len);
   936 			apex[ebl->apex_len] = 0;
   937 			free_rdata_list(head);
   938 		}
   939 	} else if (!strncasecmp(i_bl_alg.s,"txt",i_bl_alg.len)) {
   940 		sdl = cc_len; /* default */
   941 		memcpy(separator, i_branchlabel.s, i_branchlabel.len);
   942 		separator[i_branchlabel.len] = 0;
   943 		/* no change to apex */
   945 		j = 0;
   946 		memcpy(name, i_branchlabel.s, i_branchlabel.len);
   947 		j += i_branchlabel.len;
   948 		name[j++] = '.';
   950 		for (i = cc_len ; i > 0; i--) {
   951 			name[j++] = user_s[i];
   952 			name[j++] = '.';
   953 		}
   954 		memcpy(name + j, suffix->s, suffix->len + 1);
   956 		head = get_record(name, T_TXT);
   957 		if (head == 0) {
   958 			LM_DBG("TXT found for %s. Defaulting to %d\n",
   959 			       name, cc_len);
   960 		} else {
   961 			sdl = atoi(((struct txt_rdata*)head->rdata)->txt);
   962 			LM_DBG("TXT record for %s is %d.\n", name, sdl);
   964 			if ((sdl < 0) || (sdl > 10)) {
   965 				LM_ERR("Sdl %d out of bounds. Set back to cc_len.\n", sdl);
   966 				sdl = cc_len;
   967 			}
   968 			free_rdata_list(head);
   969 		}
   970 	} else {	/* defaults to CC */
   971 		sdl = cc_len;
   972 		memcpy(separator, i_branchlabel.s, i_branchlabel.len);
   973 		separator[i_branchlabel.len] = 0;
   974 		/* no change to apex */
   975 	}
   977 	j = 0;
   978 	sdl++; /* to avoid comparing i to (sdl+1) */
   979 	for (i = user_len - 1; i > 0; i--) {
   980 		name[j] = user_s[i];
   981 		name[j + 1] = '.';
   982 		j = j + 2;
   983 		if (separator[0] && (i == sdl)) { /* insert the I-ENUM separator here? */
   984 			strcpy(name + j, separator);  /* we've checked string sizes. */
   985 			j += strlen(separator);
   986 			name[j++] = '.';
   987 		}
   988 	}
   990 	memcpy(name + j, apex, strlen(apex)+1);
   992 	return do_query(_msg, string, name, service);
   993 }
   997 /******************* FQUERY *******************/
  1000 /*
  1001  * Call enum_pv_query_3 with pv arg, module parameter suffix,
  1002  * and default service.
  1003  */
  1004 int enum_pv_query_1(struct sip_msg* _msg, char* _sp)
  1006     return enum_pv_query_3(_msg, _sp, (char *)(&suffix), (char *)(&service));
  1009 /*
  1010  * Call enum_pv_query_3 with pv and suffix args and default service.
  1011  */
  1012 int enum_pv_query_2(struct sip_msg* _msg, char* _sp, char* _suffix)
  1014     return enum_pv_query_3(_msg, _sp, _suffix, (char *)(&service));
  1017 /*
  1018  * See documentation in README file.
  1019  */
  1021 int enum_pv_query_3(struct sip_msg* _msg, char* _sp, char* _suffix,
  1022 		    char* _service)
  1024 	char *user_s;
  1025 	int user_len, i, j, first;
  1026 	char name[MAX_DOMAIN_SIZE];
  1027 	char uri[MAX_URI_SIZE];
  1028 	char new_uri[MAX_URI_SIZE];
  1029 	unsigned int priority, curr_prio;
  1030 	qvalue_t q;
  1031 	char tostring[17];
  1032 	struct rdata* head;
  1033 	struct rdata* l;
  1034 	struct naptr_rdata* naptr;
  1035 	str pattern, replacement, result, new_result;
  1036 	str *suffix, *service;
  1037 	char string[17];
  1038 	pv_spec_t *sp;
  1039 	pv_value_t pv_val;
  1041 	sp = (pv_spec_t *)_sp;
  1042 	suffix = (str*)_suffix;
  1043 	service = (str*)_service;
  1045 	/*
  1046 	 *  Get R-URI user to tostring
  1047 	 */
  1048 	if (parse_sip_msg_uri(_msg) < 0) {
  1049 		LM_ERR("R-URI parsing failed\n");
  1050 		return -1;
  1053 	if (is_e164(&(_msg->parsed_uri.user)) == -1) {
  1054 		LM_ERR("R-URI user is not an E164 number\n");
  1055 		return -1;
  1058 	user_s = _msg->parsed_uri.user.s;
  1059 	user_len = _msg->parsed_uri.user.len;
  1061 	memcpy(&(tostring[0]), user_s, user_len);
  1062 	tostring[user_len] = (char)0;
  1064 	/*
  1065 	 * Get E.164 number from pseudo variable
  1066          */
  1067 	if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) {
  1068 	    if (pv_val.flags & PV_VAL_STR) {
  1069 		if (pv_val.rs.len == 0 || pv_val.rs.s == NULL) {
  1070 		    LM_DBG("Missing E.164 number\n");
  1071 		    return -1;
  1073 	    } else {
  1074 		LM_DBG("Pseudo variable value is not string\n");
  1075 		return -1;
  1077 	} else {
  1078 	    LM_DBG("Cannot get pseudo variable value\n");
  1079 	    return -1;
  1081 	if (is_e164(&(pv_val.rs)) == -1) {
  1082 	    LM_ERR("pseudo variable does not contain an E164 number\n");
  1083 	    return -1;
  1086 	user_s = pv_val.rs.s;
  1087 	user_len = pv_val.rs.len;
  1089 	memcpy(&(string[0]), user_s, user_len);
  1090 	string[user_len] = (char)0;
  1092 	j = 0;
  1093 	for (i = user_len - 1; i > 0; i--) {
  1094 		name[j] = user_s[i];
  1095 		name[j + 1] = '.';
  1096 		j = j + 2;
  1099 	memcpy(name + j, suffix->s, suffix->len + 1);
  1101 	head = get_record(name, T_NAPTR);
  1103 	if (head == 0) {
  1104 		LM_DBG("No NAPTR record found for %s.\n", name);
  1105 		return -1;
  1108 	naptr_sort(&head);
  1110 	q = MAX_Q - 10;
  1111 	curr_prio = 0;
  1112 	first = 1;
  1114 	for (l = head; l; l = l->next) {
  1116 		if (l->type != T_NAPTR) continue; /*should never happen*/
  1117 		naptr = (struct naptr_rdata*)l->rdata;
  1118 		if (naptr == 0) {
  1119 			LM_ERR("Null rdata in DNS response\n");
  1120 			continue;
  1123 		LM_DBG("ENUM query on %s: order %u, pref %u, flen %u, flags "
  1124 		       "'%.*s', slen %u, services '%.*s', rlen %u, "
  1125 		       "regexp '%.*s'\n",
  1126 		       name, naptr->order, naptr->pref,
  1127 		    naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags),
  1128 		    naptr->services_len,
  1129 		    (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len,
  1130 		    (int)(naptr->regexp_len), ZSW(naptr->regexp));
  1132 		if (sip_match(naptr, service) == 0) continue;
  1134 		if (parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len,
  1135 				       &pattern, &replacement) < 0) {
  1136 			LM_ERR("Parsing of NAPTR regexp failed\n");
  1137 			continue;
  1139 		result.s = &(uri[0]);
  1140 		result.len = MAX_URI_SIZE;
  1141 		/* Avoid making copies of pattern and replacement */
  1142 		pattern.s[pattern.len] = (char)0;
  1143 		replacement.s[replacement.len] = (char)0;
  1144 		if (reg_replace(pattern.s, replacement.s, &(tostring[0]),
  1145 				&result) < 0) {
  1146 			pattern.s[pattern.len] = '!';
  1147 			replacement.s[replacement.len] = '!';
  1148 			LM_ERR("Regexp replace failed\n");
  1149 			continue;
  1151 		LM_DBG("Resulted in replacement: '%.*s'\n",
  1152 		       result.len, ZSW(result.s));
  1153 		pattern.s[pattern.len] = '!';
  1154 		replacement.s[replacement.len] = '!';
  1156 		if (param.len > 0) {
  1157 			if (result.len + param.len > MAX_URI_SIZE - 1) {
  1158 				LM_ERR("URI is too long\n");
  1159 				continue;
  1161 			new_result.s = &(new_uri[0]);
  1162 			new_result.len = MAX_URI_SIZE;
  1163 			if (add_uri_param(&result, &param, &new_result) == 0) {
  1164 				LM_ERR("Parsing of URI <%.*s> failed\n",
  1165 				       result.len, result.s);
  1166 				continue;
  1168 			if (new_result.len > 0) {
  1169 				result = new_result;
  1173 		if (first) {
  1174 			if (set_ruri(_msg, &result) == -1) {
  1175 				goto done;
  1177 			set_ruri_q(q);
  1178 			first = 0;
  1179 			curr_prio = ((naptr->order) << 16) + naptr->pref;
  1180 		} else {
  1181 			priority = ((naptr->order) << 16) + naptr->pref;
  1182 			if (priority > curr_prio) {
  1183 				q = q - 10;
  1184 				curr_prio = priority;
  1186 			if (append_branch(_msg, &result, 0, 0, q, 0, 0) == -1) {
  1187 				goto done;
  1192 done:
  1193 	free_rdata_list(head);
  1194 	return first ? -1 : 1;

mercurial