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.

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

mercurial