Wed, 10 Feb 2010 21:21:24 +0100
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, ¶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 |