Wed, 10 Feb 2010 21:25:01 +0100
Extend uac_auth() of the UAC module to workaround CSEQ problems.
This logic is meant to complement that of changeset 17, which
added rich authentication credentials to the gw table and its
associated logic in the LCR 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, ¶m, &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, ¶m, &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 |