Mon, 18 Jan 2010 19:59:51 +0100
Introduce ISN formatting and lookup logic into the ENUM module.
A detailed description of these changes is provided in enum-isn.txt.
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, ¶m, &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)
1005 {
1006 return enum_pv_query_3(_msg, _sp, (char *)(&suffix), (char *)(&service));
1007 }
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)
1013 {
1014 return enum_pv_query_3(_msg, _sp, _suffix, (char *)(&service));
1015 }
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)
1023 {
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;
1051 }
1053 if (is_e164(&(_msg->parsed_uri.user)) == -1) {
1054 LM_ERR("R-URI user is not an E164 number\n");
1055 return -1;
1056 }
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;
1072 }
1073 } else {
1074 LM_DBG("Pseudo variable value is not string\n");
1075 return -1;
1076 }
1077 } else {
1078 LM_DBG("Cannot get pseudo variable value\n");
1079 return -1;
1080 }
1081 if (is_e164(&(pv_val.rs)) == -1) {
1082 LM_ERR("pseudo variable does not contain an E164 number\n");
1083 return -1;
1084 }
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;
1097 }
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;
1106 }
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;
1121 }
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;
1138 }
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;
1150 }
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;
1160 }
1161 new_result.s = &(new_uri[0]);
1162 new_result.len = MAX_URI_SIZE;
1163 if (add_uri_param(&result, ¶m, &new_result) == 0) {
1164 LM_ERR("Parsing of URI <%.*s> failed\n",
1165 result.len, result.s);
1166 continue;
1167 }
1168 if (new_result.len > 0) {
1169 result = new_result;
1170 }
1171 }
1173 if (first) {
1174 if (set_ruri(_msg, &result) == -1) {
1175 goto done;
1176 }
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;
1185 }
1186 if (append_branch(_msg, &result, 0, 0, q, 0, 0) == -1) {
1187 goto done;
1188 }
1189 }
1190 }
1192 done:
1193 free_rdata_list(head);
1194 return first ? -1 : 1;
1195 }