/src/kamailio/src/core/resolve.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2001-2003 FhG Fokus |
3 | | * |
4 | | * This file is part of Kamailio, a free SIP server. |
5 | | * |
6 | | * SPDX-License-Identifier: GPL-2.0-or-later |
7 | | * |
8 | | * Kamailio is free software; you can redistribute it and/or modify |
9 | | * it under the terms of the GNU General Public License as published by |
10 | | * the Free Software Foundation; either version 2 of the License, or |
11 | | * (at your option) any later version |
12 | | * |
13 | | * Kamailio is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | * GNU General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU General Public License |
19 | | * along with this program; if not, write to the Free Software |
20 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 | | */ |
22 | | |
23 | | /*! |
24 | | * \file |
25 | | * \brief Kamailio core :: DNS resolver |
26 | | * \ingroup core |
27 | | * Module: \ref core |
28 | | */ |
29 | | |
30 | | |
31 | | #include <sys/types.h> |
32 | | #include <netinet/in.h> |
33 | | #include <arpa/nameser.h> |
34 | | #include <resolv.h> |
35 | | #include <string.h> |
36 | | |
37 | | /* |
38 | | * Older glibc < 2.25 does not include T_OPT in nameser_compat.h yet. |
39 | | * On alpine linux musl library it is also not defined. There is no |
40 | | * musl feature test macro, so we look for glibc instead. |
41 | | */ |
42 | | #if(defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ < 25) \ |
43 | | || !defined __GLIBC__ |
44 | | #ifndef T_OPT |
45 | | #define T_OPT ns_t_opt |
46 | | #endif |
47 | | #endif |
48 | | |
49 | | #include "resolve.h" |
50 | | #include "compiler_opt.h" |
51 | | #include "dprint.h" |
52 | | #include "mem/mem.h" |
53 | | #include "ip_addr.h" |
54 | | #include "ut.h" |
55 | | #include "error.h" |
56 | | #include "globals.h" /* tcp_disable, tls_disable a.s.o */ |
57 | | #include "cfg_core.h" |
58 | | #include "socket_info.h" |
59 | | |
60 | | #ifdef USE_DNS_CACHE |
61 | | #include "dns_cache.h" |
62 | | #endif |
63 | | |
64 | 0 | #define KSR_IPADDR_LIST_SIZE 6 |
65 | | static ip_addr_t _ksr_ipaddr_list[KSR_IPADDR_LIST_SIZE]; |
66 | | static int _ksr_ipaddr_list_idx = 0; |
67 | | |
68 | | static ip_addr_t *get_next_ipaddr_buf(void) |
69 | 0 | { |
70 | 0 | ip_addr_t *ipb; |
71 | |
|
72 | 0 | ipb = &_ksr_ipaddr_list[_ksr_ipaddr_list_idx]; |
73 | 0 | _ksr_ipaddr_list_idx = (_ksr_ipaddr_list_idx + 1) % KSR_IPADDR_LIST_SIZE; |
74 | |
|
75 | 0 | return ipb; |
76 | 0 | } |
77 | | |
78 | | /* counters framework */ |
79 | | struct dns_counters_h dns_cnts_h; |
80 | | counter_def_t dns_cnt_defs[] = { |
81 | | {&dns_cnts_h.failed_dns_req, "failed_dns_request", 0, 0, 0, |
82 | | "incremented each time a DNS request has failed."}, |
83 | | {&dns_cnts_h.slow_dns_req, "slow_dns_request", 0, 0, 0, |
84 | | "incremented each time a DNS request took longer than " |
85 | | "dns_slow_query_ms."}, |
86 | | {0, 0, 0, 0, 0, 0}}; |
87 | | |
88 | | |
89 | | #ifdef USE_NAPTR |
90 | | static int naptr_proto_pref[PROTO_LAST + 1]; |
91 | | #endif |
92 | | static int srv_proto_pref[PROTO_LAST + 1]; |
93 | | |
94 | | #ifdef USE_NAPTR |
95 | | static void init_naptr_proto_prefs() |
96 | 0 | { |
97 | 0 | int ignore_rfc, udp, tcp, tls, sctp; |
98 | |
|
99 | 0 | if((PROTO_UDP > PROTO_LAST) || (PROTO_TCP > PROTO_LAST) |
100 | 0 | || (PROTO_TLS > PROTO_LAST) || (PROTO_SCTP > PROTO_LAST)) { |
101 | 0 | BUG("init_naptr_proto_prefs: array too small \n"); |
102 | 0 | return; |
103 | 0 | } |
104 | | |
105 | 0 | ignore_rfc = cfg_get(core, core_cfg, dns_naptr_ignore_rfc); |
106 | 0 | udp = cfg_get(core, core_cfg, dns_udp_pref); |
107 | 0 | tcp = cfg_get(core, core_cfg, dns_tcp_pref); |
108 | 0 | tls = cfg_get(core, core_cfg, dns_tls_pref); |
109 | 0 | sctp = cfg_get(core, core_cfg, dns_sctp_pref); |
110 | | |
111 | | /* Old implementation ignored the Order field in the NAPTR RR and |
112 | | * thus violated a MUST in RFC 2915. Currently still the default. */ |
113 | 0 | if(ignore_rfc) { |
114 | 0 | naptr_proto_pref[PROTO_UDP] = udp; |
115 | 0 | naptr_proto_pref[PROTO_TCP] = tcp; |
116 | 0 | naptr_proto_pref[PROTO_TLS] = tls; |
117 | 0 | naptr_proto_pref[PROTO_SCTP] = sctp; |
118 | 0 | } else { |
119 | | /* If value is less than 0, proto is disabled, otherwise |
120 | | * ignored. */ |
121 | 0 | naptr_proto_pref[PROTO_UDP] = udp < 0 ? udp : 1; |
122 | 0 | naptr_proto_pref[PROTO_TCP] = tcp < 0 ? tcp : 1; |
123 | 0 | naptr_proto_pref[PROTO_TLS] = tls < 0 ? tls : 1; |
124 | 0 | naptr_proto_pref[PROTO_SCTP] = sctp < 0 ? sctp : 1; |
125 | 0 | } |
126 | 0 | } |
127 | | |
128 | | #endif /* USE_NAPTR */ |
129 | | |
130 | | static void init_srv_proto_prefs() |
131 | 0 | { |
132 | 0 | if((PROTO_UDP > PROTO_LAST) || (PROTO_TCP > PROTO_LAST) |
133 | 0 | || (PROTO_TLS > PROTO_LAST) || (PROTO_SCTP > PROTO_LAST)) { |
134 | 0 | BUG("init_srv_proto_prefs: array too small \n"); |
135 | 0 | return; |
136 | 0 | } |
137 | | |
138 | 0 | srv_proto_pref[PROTO_UDP] = cfg_get(core, core_cfg, dns_udp_pref); |
139 | 0 | srv_proto_pref[PROTO_TCP] = cfg_get(core, core_cfg, dns_tcp_pref); |
140 | 0 | srv_proto_pref[PROTO_TLS] = cfg_get(core, core_cfg, dns_tls_pref); |
141 | 0 | srv_proto_pref[PROTO_SCTP] = cfg_get(core, core_cfg, dns_sctp_pref); |
142 | 0 | } |
143 | | |
144 | | #ifdef DNS_WATCHDOG_SUPPORT |
145 | | static on_resolv_reinit on_resolv_reinit_cb = NULL; |
146 | | |
147 | | /* register the callback function */ |
148 | | int register_resolv_reinit_cb(on_resolv_reinit cb) |
149 | | { |
150 | | if(on_resolv_reinit_cb) { |
151 | | LM_ERR("callback function has been already registered\n"); |
152 | | return -1; |
153 | | } |
154 | | on_resolv_reinit_cb = cb; |
155 | | return 0; |
156 | | } |
157 | | #endif |
158 | | |
159 | | /* counter init function |
160 | | must be called before fork |
161 | | */ |
162 | | static int stat_init(void) |
163 | 0 | { |
164 | 0 | if(counter_register_array("dns", dns_cnt_defs) < 0) |
165 | 0 | goto error; |
166 | 0 | return 0; |
167 | 0 | error: |
168 | 0 | return -1; |
169 | 0 | } |
170 | | |
171 | | /** init. the resolver |
172 | | * params: retr_time - time before retransmitting (must be >0) |
173 | | * retr_no - retransmissions number |
174 | | * servers_no - how many dns servers will be used |
175 | | * (from the one listed in /etc/resolv.conf) |
176 | | * search - if 0 the search list in /etc/resolv.conf will |
177 | | * be ignored (HINT: even if you don't have a |
178 | | * search list in resolv.conf, it's still better |
179 | | * to set search to 0, because an empty seachlist |
180 | | * means in fact search "" => it takes more time) |
181 | | * If any of the parameters <0, the default (system specific) value |
182 | | * will be used. See also resolv.conf(5). |
183 | | * returns: 0 on success, -1 on error |
184 | | */ |
185 | | static int _resolv_init(void) |
186 | 0 | { |
187 | 0 | dns_func.sr_res_init(); |
188 | 0 | #ifdef HAVE_RESOLV_RES |
189 | 0 | if(cfg_get(core, core_cfg, dns_retr_time) > 0) |
190 | 0 | _res.retrans = cfg_get(core, core_cfg, dns_retr_time); |
191 | 0 | if(cfg_get(core, core_cfg, dns_retr_no) > 0) |
192 | 0 | _res.retry = cfg_get(core, core_cfg, dns_retr_no); |
193 | 0 | if((cfg_get(core, core_cfg, dns_servers_no) >= 0) |
194 | 0 | && (cfg_get(core, core_cfg, dns_servers_no) < _res.nscount)) |
195 | 0 | _res.nscount = cfg_get(core, core_cfg, dns_servers_no); |
196 | 0 | if(cfg_get(core, core_cfg, dns_search_list) == 0) |
197 | 0 | _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); |
198 | | #else |
199 | | #warning "no resolv timeout support" |
200 | | LM_WARN("no resolv options support - resolv options will be ignored\n"); |
201 | | #endif |
202 | 0 | return 0; |
203 | 0 | } |
204 | | |
205 | | /** wrapper function to initialize the resolver at startup */ |
206 | | int resolv_init(void) |
207 | 0 | { |
208 | 0 | int res = -1; |
209 | 0 | _resolv_init(); |
210 | |
|
211 | 0 | reinit_proto_prefs(NULL, NULL); |
212 | | /* init counter API only at startup |
213 | | * This function must be called before DNS cache init method (if available) |
214 | | */ |
215 | 0 | res = stat_init(); |
216 | 0 | return res; |
217 | 0 | } |
218 | | |
219 | | /** wrapper function to reinitialize the resolver |
220 | | * This function must be called by each child process whenever |
221 | | * a resolver option changes |
222 | | */ |
223 | | void resolv_reinit(str *gname, str *name) |
224 | 0 | { |
225 | 0 | _resolv_init(); |
226 | |
|
227 | | #ifdef DNS_WATCHDOG_SUPPORT |
228 | | if(on_resolv_reinit_cb) |
229 | | on_resolv_reinit_cb(name); |
230 | | #endif |
231 | 0 | LM_DBG("DNS resolver has been reinitialized\n"); |
232 | 0 | } |
233 | | |
234 | | /** fixup function for dns_reinit variable |
235 | | * (resets the variable to 0) |
236 | | */ |
237 | | int dns_reinit_fixup(void *handle, str *gname, str *name, void **val) |
238 | 0 | { |
239 | 0 | *val = (void *)(long)0; |
240 | 0 | return 0; |
241 | 0 | } |
242 | | |
243 | | /** wrapper function to recalculate the naptr and srv protocol preferences */ |
244 | | void reinit_proto_prefs(str *gname, str *name) |
245 | 0 | { |
246 | 0 | #ifdef USE_NAPTR |
247 | 0 | init_naptr_proto_prefs(); |
248 | 0 | #endif |
249 | 0 | init_srv_proto_prefs(); |
250 | 0 | } |
251 | | |
252 | | /** fixup function for dns_try_ipv6 |
253 | | * verifies that Kamailio really listens on an ipv6 interface |
254 | | */ |
255 | | int dns_try_ipv6_fixup(void *handle, str *gname, str *name, void **val) |
256 | 0 | { |
257 | 0 | if((int)(long)(*val) && !(socket_types & SOCKET_T_IPV6)) { |
258 | 0 | LM_ERR("SER does not listen on any ipv6 interface, " |
259 | 0 | "there is no point in resolving ipv6 addresses\n"); |
260 | 0 | return -1; |
261 | 0 | } |
262 | 0 | return 0; |
263 | 0 | } |
264 | | |
265 | | /** skips over a domain name in a dns message |
266 | | * (it can be a sequence of labels ending in \0, a pointer or |
267 | | * a sequence of labels ending in a pointer -- see rfc1035 |
268 | | * returns pointer after the domain name or null on error*/ |
269 | | unsigned char *dns_skipname(unsigned char *p, unsigned char *end) |
270 | 0 | { |
271 | 0 | while(p < end) { |
272 | | /* check if \0 (root label length) */ |
273 | 0 | if(*p == 0) { |
274 | 0 | p += 1; |
275 | 0 | break; |
276 | 0 | } |
277 | | /* check if we found a pointer */ |
278 | 0 | if(((*p) & 0xc0) == 0xc0) { |
279 | | /* if pointer skip over it (2 bytes) & we found the end */ |
280 | 0 | p += 2; |
281 | 0 | break; |
282 | 0 | } |
283 | | /* normal label */ |
284 | 0 | p += *p + 1; |
285 | 0 | } |
286 | 0 | return (p > end) ? 0 : p; |
287 | 0 | } |
288 | | |
289 | | |
290 | | /** parses the srv record into a srv_rdata structure |
291 | | * msg - pointer to the dns message |
292 | | * end - pointer to the end of the message |
293 | | * eor - pointer to the end of the record/rdata |
294 | | * rdata - pointer to the rdata part of the srv answer |
295 | | * returns 0 on error, or a dyn. alloc'ed srv_rdata structure |
296 | | * |
297 | | * SRV rdata format: |
298 | | * 111111 |
299 | | * 0123456789012345 |
300 | | * +----------------+ |
301 | | * | priority | |
302 | | * |----------------| |
303 | | * | weight | |
304 | | * |----------------| |
305 | | * | port number | |
306 | | * |----------------| |
307 | | * | | |
308 | | * ~ name ~ |
309 | | * | | |
310 | | * +----------------+ |
311 | | */ |
312 | | struct srv_rdata *dns_srv_parser(unsigned char *msg, unsigned char *end, |
313 | | unsigned char *eor, unsigned char *rdata) |
314 | 0 | { |
315 | 0 | struct srv_rdata *srv; |
316 | 0 | unsigned short priority; |
317 | 0 | unsigned short weight; |
318 | 0 | unsigned short port; |
319 | 0 | int len; |
320 | 0 | char name[MAX_DNS_NAME]; |
321 | |
|
322 | 0 | srv = 0; |
323 | 0 | if((rdata + 6 + 1) > eor) |
324 | 0 | goto error; |
325 | | |
326 | 0 | memcpy((void *)&priority, rdata, 2); |
327 | 0 | memcpy((void *)&weight, rdata + 2, 2); |
328 | 0 | memcpy((void *)&port, rdata + 4, 2); |
329 | 0 | rdata += 6; |
330 | 0 | if(dn_expand(msg, end, rdata, name, MAX_DNS_NAME - 1) < 0) |
331 | 0 | goto error; |
332 | 0 | len = strlen(name); |
333 | 0 | if(len > 255) |
334 | 0 | goto error; |
335 | | /* alloc enought space for the struct + null terminated name */ |
336 | 0 | srv = pkg_malloc(sizeof(struct srv_rdata) - 1 + len + 1); |
337 | 0 | if(srv == 0) { |
338 | 0 | PKG_MEM_ERROR; |
339 | 0 | goto error; |
340 | 0 | } |
341 | 0 | srv->priority = ntohs(priority); |
342 | 0 | srv->weight = ntohs(weight); |
343 | 0 | srv->port = ntohs(port); |
344 | 0 | srv->name_len = len; |
345 | 0 | memcpy(srv->name, name, srv->name_len); |
346 | 0 | srv->name[srv->name_len] = 0; |
347 | |
|
348 | 0 | return srv; |
349 | 0 | error: |
350 | 0 | if(srv) |
351 | 0 | pkg_free(srv); |
352 | 0 | return 0; |
353 | 0 | } |
354 | | |
355 | | |
356 | | /** parses the naptr record into a naptr_rdata structure |
357 | | * msg - pointer to the dns message |
358 | | * end - pointer to the end of the message |
359 | | * eor - pointer to the end of the record/rdata |
360 | | * rdata - pointer to the rdata part of the naptr answer |
361 | | * returns 0 on error, or a dyn. alloc'ed naptr_rdata structure */ |
362 | | |
363 | | /* NAPTR rdata format: |
364 | | * 111111 |
365 | | * 0123456789012345 |
366 | | * +----------------+ |
367 | | * | order | |
368 | | * |----------------| |
369 | | * | preference | |
370 | | * |----------------| |
371 | | * ~ flags ~ |
372 | | * | (string) | |
373 | | * |----------------| |
374 | | * ~ services ~ |
375 | | * | (string) | |
376 | | * |----------------| |
377 | | * ~ regexp ~ |
378 | | * | (string) | |
379 | | * |----------------| |
380 | | * ~ replacement ~ |
381 | | | (name) | |
382 | | * +----------------+ |
383 | | */ |
384 | | struct naptr_rdata *dns_naptr_parser(unsigned char *msg, unsigned char *end, |
385 | | unsigned char *eor, unsigned char *rdata) |
386 | 0 | { |
387 | 0 | struct naptr_rdata *naptr; |
388 | 0 | unsigned char *flags; |
389 | 0 | unsigned char *services; |
390 | 0 | unsigned char *regexp; |
391 | 0 | unsigned short order; |
392 | 0 | unsigned short pref; |
393 | 0 | unsigned char flags_len; |
394 | 0 | unsigned char services_len; |
395 | 0 | unsigned char regexp_len; |
396 | 0 | int len; |
397 | 0 | char repl[MAX_DNS_NAME]; |
398 | |
|
399 | 0 | naptr = 0; |
400 | 0 | if((rdata + 7 + 1) > eor) |
401 | 0 | goto error; |
402 | | |
403 | 0 | memcpy((void *)&order, rdata, 2); |
404 | 0 | memcpy((void *)&pref, rdata + 2, 2); |
405 | 0 | flags_len = rdata[4]; |
406 | 0 | if((rdata + 7 + 1 + flags_len) > eor) |
407 | 0 | goto error; |
408 | 0 | flags = rdata + 5; |
409 | 0 | services_len = rdata[5 + flags_len]; |
410 | 0 | if((rdata + 7 + 1 + flags_len + services_len) > eor) |
411 | 0 | goto error; |
412 | 0 | services = rdata + 6 + flags_len; |
413 | 0 | regexp_len = rdata[6 + flags_len + services_len]; |
414 | 0 | if((rdata + 7 + 1 + flags_len + services_len + regexp_len) > eor) |
415 | 0 | goto error; |
416 | 0 | regexp = rdata + 7 + flags_len + services_len; |
417 | 0 | rdata = rdata + 7 + flags_len + services_len + regexp_len; |
418 | 0 | if(dn_expand(msg, end, rdata, repl, MAX_DNS_NAME - 1) == -1) |
419 | 0 | goto error; |
420 | 0 | len = strlen(repl); |
421 | 0 | if(len > 255) |
422 | 0 | goto error; |
423 | 0 | naptr = pkg_malloc(sizeof(struct naptr_rdata) + flags_len + services_len |
424 | 0 | + regexp_len + len + 1 - 1); |
425 | 0 | if(naptr == 0) { |
426 | 0 | PKG_MEM_ERROR; |
427 | 0 | goto error; |
428 | 0 | } |
429 | 0 | naptr->skip_record = 0; |
430 | 0 | naptr->order = ntohs(order); |
431 | 0 | naptr->pref = ntohs(pref); |
432 | |
|
433 | 0 | naptr->flags = &naptr->str_table[0]; |
434 | 0 | naptr->flags_len = flags_len; |
435 | 0 | memcpy(naptr->flags, flags, naptr->flags_len); |
436 | 0 | naptr->services = &naptr->str_table[flags_len]; |
437 | 0 | naptr->services_len = services_len; |
438 | 0 | memcpy(naptr->services, services, naptr->services_len); |
439 | 0 | naptr->regexp = &naptr->str_table[flags_len + services_len]; |
440 | 0 | naptr->regexp_len = regexp_len; |
441 | 0 | memcpy(naptr->regexp, regexp, naptr->regexp_len); |
442 | 0 | naptr->repl = &naptr->str_table[flags_len + services_len + regexp_len]; |
443 | 0 | naptr->repl_len = len; |
444 | 0 | memcpy(naptr->repl, repl, len); |
445 | 0 | naptr->repl[len] = 0; /* null term. */ |
446 | |
|
447 | 0 | return naptr; |
448 | 0 | error: |
449 | 0 | if(naptr) |
450 | 0 | pkg_free(naptr); |
451 | 0 | return 0; |
452 | 0 | } |
453 | | |
454 | | |
455 | | /** parses a CNAME record into a cname_rdata structure */ |
456 | | struct cname_rdata *dns_cname_parser( |
457 | | unsigned char *msg, unsigned char *end, unsigned char *rdata) |
458 | 0 | { |
459 | 0 | struct cname_rdata *cname; |
460 | 0 | int len; |
461 | 0 | char name[MAX_DNS_NAME]; |
462 | |
|
463 | 0 | cname = 0; |
464 | 0 | if(dn_expand(msg, end, rdata, name, MAX_DNS_NAME - 1) == -1) |
465 | 0 | goto error; |
466 | 0 | len = strlen(name); |
467 | 0 | if(len > 255) |
468 | 0 | goto error; |
469 | | /* alloc sizeof struct + space for the null terminated name */ |
470 | 0 | cname = pkg_malloc(sizeof(struct cname_rdata) - 1 + len + 1); |
471 | 0 | if(cname == 0) { |
472 | 0 | PKG_MEM_ERROR; |
473 | 0 | goto error; |
474 | 0 | } |
475 | 0 | cname->name_len = len; |
476 | 0 | memcpy(cname->name, name, cname->name_len); |
477 | 0 | cname->name[cname->name_len] = 0; |
478 | 0 | return cname; |
479 | 0 | error: |
480 | 0 | if(cname) |
481 | 0 | pkg_free(cname); |
482 | 0 | return 0; |
483 | 0 | } |
484 | | |
485 | | |
486 | | /** parses an A record rdata into an a_rdata structure |
487 | | * returns 0 on error or a dyn. alloc'ed a_rdata struct |
488 | | */ |
489 | | struct a_rdata *dns_a_parser(unsigned char *rdata, unsigned char *eor) |
490 | 0 | { |
491 | 0 | struct a_rdata *a; |
492 | |
|
493 | 0 | if(rdata + 4 > eor) |
494 | 0 | goto error; |
495 | 0 | a = (struct a_rdata *)pkg_malloc(sizeof(struct a_rdata)); |
496 | 0 | if(a == 0) { |
497 | 0 | PKG_MEM_ERROR; |
498 | 0 | goto error; |
499 | 0 | } |
500 | 0 | memcpy(a->ip, rdata, 4); |
501 | 0 | return a; |
502 | 0 | error: |
503 | 0 | return 0; |
504 | 0 | } |
505 | | |
506 | | |
507 | | /** parses an AAAA (ipv6) record rdata into an aaaa_rdata structure |
508 | | * returns 0 on error or a dyn. alloc'ed aaaa_rdata struct */ |
509 | | struct aaaa_rdata *dns_aaaa_parser(unsigned char *rdata, unsigned char *eor) |
510 | 0 | { |
511 | 0 | struct aaaa_rdata *aaaa; |
512 | |
|
513 | 0 | if(rdata + 16 > eor) |
514 | 0 | goto error; |
515 | 0 | aaaa = (struct aaaa_rdata *)pkg_malloc(sizeof(struct aaaa_rdata)); |
516 | 0 | if(aaaa == 0) { |
517 | 0 | PKG_MEM_ERROR; |
518 | 0 | goto error; |
519 | 0 | } |
520 | 0 | memcpy(aaaa->ip6, rdata, 16); |
521 | 0 | return aaaa; |
522 | 0 | error: |
523 | 0 | return 0; |
524 | 0 | } |
525 | | |
526 | | |
527 | | /** parses a TXT record into a txt_rdata structure. |
528 | | * @param msg - pointer to the dns message |
529 | | * @param end - pointer to the end of the record (rdata end) |
530 | | * @param rdata - pointer to the rdata part of the txt answer |
531 | | * returns 0 on error, or a dyn. alloc'ed txt_rdata structure */ |
532 | | /* TXT rdata format: |
533 | | * |
534 | | * one or several character strings: |
535 | | * 01234567 |
536 | | * +--------------------+ |
537 | | * | len | string / ... |
538 | | * |------------------+ |
539 | | */ |
540 | | static struct txt_rdata *dns_txt_parser( |
541 | | unsigned char *msg, unsigned char *end, unsigned char *rdata) |
542 | 0 | { |
543 | 0 | struct txt_rdata *txt; |
544 | 0 | int len, n, i; |
545 | 0 | int str_size; |
546 | 0 | unsigned char *p; |
547 | 0 | unsigned char *st; |
548 | |
|
549 | 0 | txt = 0; |
550 | 0 | if(unlikely((rdata + 1) > end)) |
551 | 0 | goto error; |
552 | 0 | n = 0; |
553 | 0 | str_size = 0; |
554 | | /* count the number of strings */ |
555 | 0 | p = rdata; |
556 | 0 | do { |
557 | 0 | len = *p; |
558 | 0 | p += len + 1; |
559 | 0 | str_size += len + 1; /* 1 for the term. 0 */ |
560 | 0 | if(unlikely(p > end)) |
561 | 0 | goto error; |
562 | 0 | n++; |
563 | 0 | } while(p < end); |
564 | | /* alloc sizeof struct + space for the dns_cstr array + space for |
565 | | the strings */ |
566 | 0 | txt = pkg_malloc(sizeof(struct txt_rdata) |
567 | 0 | + (n - 1) * sizeof(struct dns_cstr) + str_size); |
568 | 0 | if(unlikely(txt == 0)) { |
569 | 0 | PKG_MEM_ERROR; |
570 | 0 | goto error; |
571 | 0 | } |
572 | | /* string table */ |
573 | 0 | st = (unsigned char *)txt + sizeof(struct txt_rdata) |
574 | 0 | + (n - 1) * sizeof(struct dns_cstr); |
575 | 0 | txt->cstr_no = n; |
576 | 0 | txt->tslen = str_size; |
577 | | /* fill the structure */ |
578 | 0 | p = rdata; |
579 | 0 | for(i = 0; i < n; i++) { |
580 | 0 | len = *p; |
581 | 0 | memcpy(st, p + 1, len); |
582 | 0 | st[len] = 0; |
583 | 0 | txt->txt[i].cstr_len = len; |
584 | 0 | txt->txt[i].cstr = (char *)st; |
585 | 0 | st += len + 1; |
586 | 0 | p += len + 1; |
587 | 0 | } |
588 | 0 | return txt; |
589 | 0 | error: |
590 | 0 | if(txt) |
591 | 0 | pkg_free(txt); |
592 | 0 | return 0; |
593 | 0 | } |
594 | | |
595 | | |
596 | | /** parses an EBL record into a txt_rdata structure. |
597 | | * @param msg - pointer to the dns message |
598 | | * @param end - pointer to the end of the dns message |
599 | | * @param eor - pointer to the end of the record (rdata end) |
600 | | * @param rdata - pointer to the rdata part of the txt answer |
601 | | * returns 0 on error, or a dyn. alloc'ed txt_rdata structure */ |
602 | | /* EBL rdata format: |
603 | | * (see http://tools.ietf.org/html/draft-ietf-enum-branch-location-record-03) |
604 | | * one or several character strings: |
605 | | * 01234567 |
606 | | * +---------+ |
607 | | * | position| |
608 | | * +-----------+ |
609 | | * / separator / |
610 | | * +-----------+ |
611 | | * / apex / |
612 | | * +----------+ |
613 | | * |
614 | | * where separator is a character string ( 8 bit len, followed by len chars) |
615 | | * and apex is a domain-name. |
616 | | */ |
617 | | static struct ebl_rdata *dns_ebl_parser(unsigned char *msg, unsigned char *end, |
618 | | unsigned char *eor, unsigned char *rdata) |
619 | 0 | { |
620 | 0 | struct ebl_rdata *ebl; |
621 | 0 | int sep_len; |
622 | 0 | int apex_len; |
623 | 0 | char apex[MAX_DNS_NAME]; |
624 | |
|
625 | 0 | ebl = 0; |
626 | | /* check if len is at least 4 chars (minimum possible): |
627 | | pos (1 byte) + sep. (min 1 byte) + apex (min. 2 bytes) |
628 | | and also check if rdata+1 (pos) + 1 (sep. len) + sep_len + 1 is ok*/ |
629 | 0 | if(unlikely(((rdata + 4) > eor) || ((rdata + 1 + 1 + rdata[1] + 2) > eor))) |
630 | 0 | goto error; |
631 | 0 | sep_len = rdata[1]; |
632 | 0 | if(unlikely(dn_expand(msg, end, rdata + 1 + 1 + sep_len, apex, |
633 | 0 | MAX_DNS_NAME - 1) |
634 | 0 | == -1)) |
635 | 0 | goto error; |
636 | 0 | apex_len = strlen(apex); |
637 | | /* alloc sizeof struct + space for the 2 null-terminated strings */ |
638 | 0 | ebl = pkg_malloc(sizeof(struct ebl_rdata) - 1 + sep_len + 1 + apex_len + 1); |
639 | 0 | if(ebl == 0) { |
640 | 0 | PKG_MEM_ERROR; |
641 | 0 | goto error; |
642 | 0 | } |
643 | 0 | ebl->position = rdata[0]; |
644 | 0 | ebl->separator = &ebl->str_table[0]; |
645 | 0 | ebl->apex = ebl->separator + sep_len + 1; |
646 | 0 | ebl->separator_len = sep_len; |
647 | 0 | ebl->apex_len = apex_len; |
648 | 0 | memcpy(ebl->separator, rdata + 2, sep_len); |
649 | 0 | ebl->separator[sep_len] = 0; |
650 | 0 | memcpy(ebl->apex, apex, apex_len); |
651 | 0 | ebl->apex[apex_len] = 0; |
652 | |
|
653 | 0 | return ebl; |
654 | 0 | error: |
655 | 0 | if(ebl) |
656 | 0 | pkg_free(ebl); |
657 | 0 | return 0; |
658 | 0 | } |
659 | | |
660 | | |
661 | | /** parses a PTR record into a ptr_rdata structure */ |
662 | | struct ptr_rdata *dns_ptr_parser( |
663 | | unsigned char *msg, unsigned char *end, unsigned char *rdata) |
664 | 0 | { |
665 | 0 | struct ptr_rdata *pname; |
666 | 0 | int len; |
667 | 0 | char name[MAX_DNS_NAME]; |
668 | |
|
669 | 0 | pname = 0; |
670 | 0 | if(dn_expand(msg, end, rdata, name, MAX_DNS_NAME - 1) == -1) |
671 | 0 | goto error; |
672 | 0 | len = strlen(name); |
673 | 0 | if(len > 255) |
674 | 0 | goto error; |
675 | | /* alloc sizeof struct + space for the null terminated name */ |
676 | 0 | pname = pkg_malloc(sizeof(struct ptr_rdata) - 1 + len + 1); |
677 | 0 | if(pname == 0) { |
678 | 0 | PKG_MEM_ERROR; |
679 | 0 | goto error; |
680 | 0 | } |
681 | 0 | pname->ptrdname_len = len; |
682 | 0 | memcpy(pname->ptrdname, name, pname->ptrdname_len); |
683 | 0 | pname->ptrdname[pname->ptrdname_len] = 0; |
684 | 0 | return pname; |
685 | 0 | error: |
686 | 0 | if(pname) |
687 | 0 | pkg_free(pname); |
688 | 0 | return 0; |
689 | 0 | } |
690 | | |
691 | | |
692 | | /** frees completely a struct rdata list */ |
693 | | void free_rdata_list(struct rdata *head) |
694 | 0 | { |
695 | 0 | struct rdata *l; |
696 | 0 | struct rdata *next_l; |
697 | 0 | l = head; |
698 | 0 | while(l != 0) { |
699 | 0 | next_l = l->next; |
700 | | /* free the parsed rdata*/ |
701 | 0 | if(l->rdata) |
702 | 0 | pkg_free(l->rdata); |
703 | 0 | pkg_free(l); |
704 | 0 | l = next_l; |
705 | 0 | } |
706 | 0 | } |
707 | | |
708 | | #ifdef HAVE_RESOLV_RES |
709 | | /** checks whether supplied name exists in the resolver search list |
710 | | * returns 1 if found |
711 | | * 0 if not found |
712 | | */ |
713 | | int match_search_list(const struct __res_state *res, char *name) |
714 | 0 | { |
715 | 0 | int i; |
716 | 0 | for(i = 0; (i < MAXDNSRCH) && (res->dnsrch[i]); i++) { |
717 | 0 | if(strcasecmp(name, res->dnsrch[i]) == 0) |
718 | 0 | return 1; |
719 | 0 | } |
720 | 0 | return 0; |
721 | 0 | } |
722 | | #endif |
723 | | |
724 | | #ifndef SR_DNS_MAX_QNO |
725 | 0 | #define SR_DNS_MAX_QNO 10 |
726 | | #endif |
727 | | #ifndef SR_DNS_MAX_ANO |
728 | 0 | #define SR_DNS_MAX_ANO 100 |
729 | | #endif |
730 | | |
731 | | /** gets the DNS records for name:type |
732 | | * returns a dyn. alloc'ed struct rdata linked list with the parsed responses |
733 | | * or 0 on error |
734 | | * see rfc1035 for the query/response format */ |
735 | | struct rdata *get_record(char *name, int type, int flags) |
736 | 0 | { |
737 | 0 | int size; |
738 | 0 | int skip; |
739 | 0 | unsigned short qno, answers_no, r; |
740 | 0 | int i; |
741 | 0 | static union dns_query buff; |
742 | 0 | unsigned char *p; |
743 | 0 | unsigned char *end; |
744 | 0 | unsigned char *rd_end; |
745 | 0 | static char rec_name[MAX_DNS_NAME]; /* placeholder for the record name */ |
746 | 0 | int rec_name_len; |
747 | 0 | unsigned short rtype, class, rdlength; |
748 | 0 | unsigned int ttl; |
749 | 0 | struct rdata *head; |
750 | 0 | struct rdata **crt; |
751 | 0 | struct rdata **last; |
752 | 0 | struct rdata *rd; |
753 | 0 | struct srv_rdata *srv_rd; |
754 | 0 | struct srv_rdata *crt_srv; |
755 | 0 | int search_list_used; |
756 | 0 | int name_len; |
757 | 0 | struct rdata *fullname_rd; |
758 | 0 | char c; |
759 | 0 | struct timeval start, stop; |
760 | 0 | int slow_query_ms = cfg_get(core, core_cfg, dns_slow_query_ms); |
761 | |
|
762 | 0 | name_len = strlen(name); |
763 | |
|
764 | 0 | for(i = 0; i < name_len; i++) { |
765 | 0 | c = name[i]; |
766 | 0 | if(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) |
767 | 0 | || ((c >= '0') && (c <= '9')) || (name[i] == '.') |
768 | 0 | || (name[i] == '-') || (name[i] == '_')) |
769 | 0 | continue; |
770 | 0 | LM_DBG("'%s' is not domain name\n", name); |
771 | 0 | return 0; |
772 | 0 | } |
773 | | |
774 | 0 | if(cfg_get(core, core_cfg, dns_search_list) == 0) { |
775 | 0 | search_list_used = 0; |
776 | 0 | name_len = 0; |
777 | 0 | } else { |
778 | 0 | search_list_used = 1; |
779 | 0 | } |
780 | 0 | fullname_rd = 0; |
781 | |
|
782 | 0 | if(slow_query_ms > 0) |
783 | 0 | gettimeofday(&start, NULL); |
784 | |
|
785 | 0 | size = dns_func.sr_res_search(name, C_IN, type, buff.buff, sizeof(buff)); |
786 | |
|
787 | 0 | if(slow_query_ms > 0) { |
788 | 0 | gettimeofday(&stop, NULL); |
789 | 0 | int latency_ms = (stop.tv_sec - start.tv_sec) * 1000 |
790 | 0 | + (stop.tv_usec - start.tv_usec) / 1000; |
791 | 0 | if(slow_query_ms < latency_ms) { |
792 | 0 | LOG(cfg_get(core, core_cfg, latency_log), |
793 | 0 | "res_search[%d][%s]elapsed[%dms]\n", type, name, |
794 | 0 | latency_ms); |
795 | 0 | counter_inc(dns_cnts_h.slow_dns_req); |
796 | 0 | } |
797 | 0 | } |
798 | |
|
799 | 0 | if(unlikely(size < 0)) { |
800 | 0 | LM_DBG("lookup(%s, %d) failed\n", name, type); |
801 | 0 | goto not_found; |
802 | 0 | } else if(unlikely(size > sizeof(buff))) |
803 | 0 | size = sizeof(buff); |
804 | 0 | head = rd = 0; |
805 | 0 | last = crt = &head; |
806 | |
|
807 | 0 | p = buff.buff + DNS_HDR_SIZE; |
808 | 0 | end = buff.buff + size; |
809 | 0 | if(unlikely(p >= end)) |
810 | 0 | goto error_boundary; |
811 | 0 | qno = ntohs((unsigned short)buff.hdr.qdcount); |
812 | |
|
813 | 0 | if(qno != 1) { |
814 | | /* usually the query is with a single domain name */ |
815 | 0 | LM_INFO("dns questions number is: %u\n", (uint32_t)qno); |
816 | 0 | if(qno > SR_DNS_MAX_QNO) { |
817 | | /* early safe check against broken results */ |
818 | 0 | LM_ERR("dns questions number is too high: %u\n", (uint32_t)qno); |
819 | 0 | goto error; |
820 | 0 | } |
821 | 0 | } |
822 | 0 | for(r = 0; r < qno; r++) { |
823 | | /* skip the name of the question */ |
824 | 0 | if(unlikely((p = dns_skipname(p, end)) == 0)) { |
825 | 0 | LM_ERR("skipname==0\n"); |
826 | 0 | goto error; |
827 | 0 | } |
828 | 0 | p += 2 + 2; /* skip QCODE & QCLASS */ |
829 | | #if 0 |
830 | | for (;(p<end && (*p)); p++); |
831 | | p+=1+2+2; /* skip the ending '\0, QCODE and QCLASS */ |
832 | | #endif |
833 | 0 | if(unlikely(p > end)) { |
834 | 0 | LM_ERR("p>=end\n"); |
835 | 0 | goto error; |
836 | 0 | } |
837 | 0 | } |
838 | 0 | answers_no = ntohs((unsigned short)buff.hdr.ancount); |
839 | 0 | if(answers_no > SR_DNS_MAX_ANO) { |
840 | | /* early safety check on answers number */ |
841 | 0 | LM_ERR("dns answers number is too high: %u\n", (uint32_t)answers_no); |
842 | 0 | goto error; |
843 | 0 | } |
844 | 0 | again: |
845 | 0 | for(r = 0; (r < answers_no) && (p < end); r++) { |
846 | | #if 0 |
847 | | /* ignore it the default domain name */ |
848 | | if ((p=dns_skipname(p, end))==0) { |
849 | | LM_ERR("get_record: skip_name=0 (#2)\n"); |
850 | | goto error; |
851 | | } |
852 | | #else |
853 | 0 | if(unlikely((skip = dn_expand( |
854 | 0 | buff.buff, end, p, rec_name, MAX_DNS_NAME - 1)) |
855 | 0 | == -1)) { |
856 | 0 | LM_ERR("dn_expand(rec_name) failed\n"); |
857 | 0 | goto error; |
858 | 0 | } |
859 | 0 | #endif |
860 | 0 | p += skip; |
861 | 0 | rec_name_len = strlen(rec_name); |
862 | 0 | if(unlikely(rec_name_len > MAX_DNS_NAME - 2)) { |
863 | 0 | LM_ERR("dn_expand(rec_name): name too long (%d)\n", rec_name_len); |
864 | 0 | goto error; |
865 | 0 | } |
866 | | /* check if enough space is left for type, class, ttl & size */ |
867 | 0 | if(unlikely((p + 2 + 2 + 4 + 2) > end)) |
868 | 0 | goto error_boundary; |
869 | | /* get type */ |
870 | 0 | memcpy((void *)&rtype, (void *)p, 2); |
871 | 0 | rtype = ntohs(rtype); |
872 | 0 | p += 2; |
873 | | /* get class */ |
874 | 0 | memcpy((void *)&class, (void *)p, 2); |
875 | 0 | class = ntohs(class); |
876 | 0 | p += 2; |
877 | | /* get ttl*/ |
878 | 0 | memcpy((void *)&ttl, (void *)p, 4); |
879 | 0 | ttl = ntohl(ttl); |
880 | 0 | p += 4; |
881 | | /* get size */ |
882 | 0 | memcpy((void *)&rdlength, (void *)p, 2); |
883 | 0 | rdlength = ntohs(rdlength); |
884 | 0 | p += 2; |
885 | 0 | rd_end = p + rdlength; |
886 | 0 | if(unlikely((rd_end) > end)) |
887 | 0 | goto error_boundary; |
888 | 0 | if((flags & RES_ONLY_TYPE) && (rtype != type)) { |
889 | | /* skip */ |
890 | 0 | p = rd_end; |
891 | 0 | continue; |
892 | 0 | } |
893 | | /* expand the "type" record (rdata)*/ |
894 | | |
895 | 0 | rd = (struct rdata *)pkg_malloc( |
896 | 0 | sizeof(struct rdata) + rec_name_len + 1 - 1); |
897 | 0 | if(rd == 0) { |
898 | 0 | PKG_MEM_ERROR; |
899 | 0 | goto error; |
900 | 0 | } |
901 | 0 | rd->type = rtype; |
902 | 0 | rd->pclass = class; |
903 | 0 | rd->ttl = ttl; |
904 | 0 | rd->next = 0; |
905 | 0 | memcpy(rd->name, rec_name, rec_name_len); |
906 | 0 | rd->name[rec_name_len] = 0; |
907 | 0 | rd->name_len = rec_name_len; |
908 | | /* check if full name matches */ |
909 | 0 | if((search_list_used == 1) && (fullname_rd == 0) |
910 | 0 | && (rec_name_len >= name_len) |
911 | 0 | && (strncasecmp(rec_name, name, name_len) == 0)) { |
912 | | /* now we have record whose name is the same (up-to the |
913 | | * name_len with the searched one): |
914 | | * if the length is the same - we found full match, no fake |
915 | | * cname needed, just clear the flag |
916 | | * if the length of the name differs - it has matched using |
917 | | * search list remember the rd, so we can create fake CNAME |
918 | | * record when all answers are used and no better match found |
919 | | */ |
920 | 0 | if(rec_name_len == name_len) |
921 | 0 | search_list_used = 0; |
922 | | /* this is safe.... here was rec_name_len > name_len */ |
923 | 0 | else if(rec_name[name_len] == '.') { |
924 | 0 | #ifdef HAVE_RESOLV_RES |
925 | 0 | if((cfg_get(core, core_cfg, dns_search_fmatch) == 0) |
926 | 0 | || (match_search_list(&_res, rec_name + name_len + 1) |
927 | 0 | != 0)) |
928 | 0 | #endif |
929 | 0 | fullname_rd = rd; |
930 | 0 | } |
931 | 0 | } |
932 | 0 | switch(rtype) { |
933 | 0 | case T_SRV: |
934 | 0 | srv_rd = dns_srv_parser(buff.buff, end, rd_end, p); |
935 | 0 | rd->rdata = (void *)srv_rd; |
936 | 0 | if(unlikely(srv_rd == 0)) |
937 | 0 | goto error_parse; |
938 | | |
939 | | /* insert sorted into the list */ |
940 | 0 | for(crt = &head; *crt; crt = &((*crt)->next)) { |
941 | 0 | if((*crt)->type != T_SRV) |
942 | 0 | continue; |
943 | 0 | crt_srv = (struct srv_rdata *)(*crt)->rdata; |
944 | 0 | if((srv_rd->priority < crt_srv->priority) |
945 | 0 | || ((srv_rd->priority == crt_srv->priority) |
946 | 0 | && (srv_rd->weight > crt_srv->weight))) { |
947 | | /* insert here */ |
948 | 0 | goto skip; |
949 | 0 | } |
950 | 0 | } |
951 | 0 | last = &(rd->next); /*end of for => this will be the last |
952 | | element*/ |
953 | 0 | skip: |
954 | | /* insert here */ |
955 | 0 | rd->next = *crt; |
956 | 0 | *crt = rd; |
957 | 0 | break; |
958 | 0 | case T_A: |
959 | 0 | rd->rdata = (void *)dns_a_parser(p, rd_end); |
960 | 0 | if(unlikely(rd->rdata == 0)) |
961 | 0 | goto error_parse; |
962 | 0 | *last = rd; /* last points to the last "next" or the list |
963 | | head*/ |
964 | 0 | last = &(rd->next); |
965 | 0 | break; |
966 | 0 | case T_AAAA: |
967 | 0 | rd->rdata = (void *)dns_aaaa_parser(p, rd_end); |
968 | 0 | if(unlikely(rd->rdata == 0)) |
969 | 0 | goto error_parse; |
970 | 0 | *last = rd; |
971 | 0 | last = &(rd->next); |
972 | 0 | break; |
973 | 0 | case T_CNAME: |
974 | 0 | rd->rdata = (void *)dns_cname_parser(buff.buff, end, p); |
975 | 0 | if(unlikely(rd->rdata == 0)) |
976 | 0 | goto error_parse; |
977 | 0 | *last = rd; |
978 | 0 | last = &(rd->next); |
979 | 0 | break; |
980 | 0 | case T_NAPTR: |
981 | 0 | rd->rdata = (void *)dns_naptr_parser(buff.buff, end, rd_end, p); |
982 | 0 | if(unlikely(rd->rdata == 0)) |
983 | 0 | goto error_parse; |
984 | 0 | *last = rd; |
985 | 0 | last = &(rd->next); |
986 | 0 | break; |
987 | 0 | case T_TXT: |
988 | 0 | rd->rdata = dns_txt_parser(buff.buff, rd_end, p); |
989 | 0 | if(rd->rdata == 0) |
990 | 0 | goto error_parse; |
991 | 0 | *last = rd; |
992 | 0 | last = &(rd->next); |
993 | 0 | break; |
994 | 0 | case T_EBL: |
995 | 0 | rd->rdata = dns_ebl_parser(buff.buff, end, rd_end, p); |
996 | 0 | if(rd->rdata == 0) |
997 | 0 | goto error_parse; |
998 | 0 | *last = rd; |
999 | 0 | last = &(rd->next); |
1000 | 0 | break; |
1001 | 0 | case T_PTR: |
1002 | 0 | rd->rdata = (void *)dns_ptr_parser(buff.buff, end, p); |
1003 | 0 | if(unlikely(rd->rdata == 0)) |
1004 | 0 | goto error_parse; |
1005 | 0 | *last = rd; |
1006 | 0 | last = &(rd->next); |
1007 | 0 | break; |
1008 | 0 | case T_OPT: |
1009 | | /* skip DNS extensions, e.g. EDNS0 */ |
1010 | 0 | rd->rdata = 0; |
1011 | 0 | *last = rd; |
1012 | 0 | last = &(rd->next); |
1013 | 0 | break; |
1014 | 0 | default: |
1015 | 0 | LM_ERR("unknown type %d\n", rtype); |
1016 | 0 | rd->rdata = 0; |
1017 | 0 | *last = rd; |
1018 | 0 | last = &(rd->next); |
1019 | 0 | } |
1020 | | |
1021 | 0 | p += rdlength; |
1022 | 0 | } |
1023 | 0 | if(flags & RES_AR) { |
1024 | 0 | flags &= ~RES_AR; |
1025 | 0 | answers_no = ntohs((unsigned short)buff.hdr.nscount); |
1026 | 0 | LM_DBG("skipping %d NS (p=%p, end=%p)\n", answers_no, p, end); |
1027 | 0 | for(r = 0; (r < answers_no) && (p < end); r++) { |
1028 | | /* skip over the ns records */ |
1029 | 0 | if((p = dns_skipname(p, end)) == 0) { |
1030 | 0 | LM_ERR("skip_name=0 (#3)\n"); |
1031 | 0 | goto error; |
1032 | 0 | } |
1033 | | /* check if enough space is left for type, class, ttl & size */ |
1034 | 0 | if(unlikely((p + 2 + 2 + 4 + 2) > end)) |
1035 | 0 | goto error_boundary; |
1036 | 0 | memcpy((void *)&rdlength, (void *)(p + 2 + 2 + 4), 2); |
1037 | 0 | p += 2 + 2 + 4 + 2 + ntohs(rdlength); |
1038 | 0 | } |
1039 | 0 | answers_no = ntohs((unsigned short)buff.hdr.arcount); |
1040 | 0 | LM_DBG("parsing %d ARs (p=%p, end=%p)\n", answers_no, p, end); |
1041 | 0 | goto again; /* add also the additional records */ |
1042 | 0 | } |
1043 | | |
1044 | | /* if the name was expanded using DNS search list |
1045 | | * create fake CNAME record to convert the short name |
1046 | | * (queried) to long name (answered) |
1047 | | */ |
1048 | 0 | if((search_list_used == 1) && (fullname_rd != 0)) { |
1049 | 0 | rd = (struct rdata *)pkg_malloc( |
1050 | 0 | sizeof(struct rdata) + name_len + 1 - 1); |
1051 | 0 | if(unlikely(rd == 0)) { |
1052 | 0 | PKG_MEM_ERROR; |
1053 | 0 | goto error; |
1054 | 0 | } |
1055 | 0 | rd->type = T_CNAME; |
1056 | 0 | rd->pclass = fullname_rd->pclass; |
1057 | 0 | rd->ttl = fullname_rd->ttl; |
1058 | 0 | rd->next = head; |
1059 | 0 | memcpy(rd->name, name, name_len); |
1060 | 0 | rd->name[name_len] = 0; |
1061 | 0 | rd->name_len = name_len; |
1062 | | /* alloc sizeof struct + space for the null terminated name */ |
1063 | 0 | rd->rdata = (void *)pkg_malloc( |
1064 | 0 | sizeof(struct cname_rdata) - 1 + fullname_rd->name_len + 1); |
1065 | 0 | if(unlikely(rd->rdata == 0)) { |
1066 | 0 | PKG_MEM_ERROR; |
1067 | 0 | goto error_rd; |
1068 | 0 | } |
1069 | 0 | ((struct cname_rdata *)(rd->rdata))->name_len = fullname_rd->name_len; |
1070 | 0 | memcpy(((struct cname_rdata *)(rd->rdata))->name, fullname_rd->name, |
1071 | 0 | fullname_rd->name_len); |
1072 | 0 | ((struct cname_rdata *)(rd->rdata))->name[head->name_len] = 0; |
1073 | 0 | head = rd; |
1074 | 0 | } |
1075 | | |
1076 | 0 | return head; |
1077 | 0 | error_boundary: |
1078 | 0 | LM_ERR("end of query buff reached\n"); |
1079 | 0 | if(head) |
1080 | 0 | free_rdata_list(head); |
1081 | 0 | return 0; |
1082 | 0 | error_parse: |
1083 | 0 | LM_ERR("rdata parse error (%s, %d), %p-%p" |
1084 | 0 | " rtype=%d, class=%d, ttl=%d, rdlength=%d\n", |
1085 | 0 | name, type, p, end, rtype, class, ttl, rdlength); |
1086 | 0 | error_rd: |
1087 | 0 | if(rd) |
1088 | 0 | pkg_free(rd); /* rd->rdata=0 & rd is not linked yet into |
1089 | | the list */ |
1090 | 0 | error: |
1091 | 0 | LM_ERR("get_record\n"); |
1092 | 0 | if(head) |
1093 | 0 | free_rdata_list(head); |
1094 | 0 | not_found: |
1095 | | /* increment error counter */ |
1096 | 0 | counter_inc(dns_cnts_h.failed_dns_req); |
1097 | 0 | return 0; |
1098 | 0 | } |
1099 | | |
1100 | | #ifdef USE_NAPTR |
1101 | | |
1102 | | /* service matching constants, lowercase */ |
1103 | 0 | #define SIP_SCH 0x2b706973 |
1104 | 0 | #define SIPS_SCH 0x73706973 |
1105 | 0 | #define SIP_D2U 0x00753264 |
1106 | 0 | #define SIP_D2T 0x00743264 |
1107 | 0 | #define SIP_D2S 0x00733264 |
1108 | 0 | #define SIPS_D2T 0x7432642b |
1109 | | |
1110 | | |
1111 | | /** get protocol from a naptr rdata and check for validity |
1112 | | * returns > 0 (PROTO_UDP, PROTO_TCP, PROTO_SCTP or PROTO_TLS) |
1113 | | * <=0 on error |
1114 | | */ |
1115 | | char naptr_get_sip_proto(struct naptr_rdata *n) |
1116 | 0 | { |
1117 | 0 | unsigned int s; |
1118 | 0 | char proto; |
1119 | |
|
1120 | 0 | proto = -1; |
1121 | |
|
1122 | 0 | if((n->flags_len != 1) || ((*n->flags | 0x20) != 's')) |
1123 | 0 | return -1; |
1124 | 0 | if(n->regexp_len != 0) |
1125 | 0 | return -1; |
1126 | | /* SIP+D2U, SIP+D2T, SIP+D2S, SIPS+D2T */ |
1127 | 0 | if(n->services_len == 7) { /* SIP+D2X */ |
1128 | 0 | s = n->services[0] + (n->services[1] << 8) + (n->services[2] << 16) |
1129 | 0 | + (n->services[3] << 24); |
1130 | 0 | s |= 0x20202020; |
1131 | 0 | if(s == SIP_SCH) { |
1132 | 0 | s = n->services[4] + (n->services[5] << 8) + (n->services[6] << 16); |
1133 | 0 | s |= 0x00202020; |
1134 | 0 | switch(s) { |
1135 | 0 | case SIP_D2U: |
1136 | 0 | proto = PROTO_UDP; |
1137 | 0 | break; |
1138 | 0 | case SIP_D2T: |
1139 | 0 | proto = PROTO_TCP; |
1140 | 0 | break; |
1141 | 0 | case SIP_D2S: |
1142 | 0 | proto = PROTO_SCTP; |
1143 | 0 | break; |
1144 | 0 | default: |
1145 | 0 | return -1; |
1146 | 0 | } |
1147 | 0 | } else { |
1148 | 0 | return -1; |
1149 | 0 | } |
1150 | 0 | } else if(n->services_len == 8) { /*SIPS+D2T */ |
1151 | 0 | s = n->services[0] + (n->services[1] << 8) + (n->services[2] << 16) |
1152 | 0 | + (n->services[3] << 24); |
1153 | 0 | s |= 0x20202020; |
1154 | 0 | if(s == SIPS_SCH) { |
1155 | 0 | s = n->services[4] + (n->services[5] << 8) + (n->services[6] << 16) |
1156 | 0 | + (n->services[7] << 24); |
1157 | 0 | s |= 0x20202020; |
1158 | 0 | if(s == SIPS_D2T) { |
1159 | 0 | proto = PROTO_TLS; |
1160 | 0 | } |
1161 | 0 | } else { |
1162 | 0 | return -1; |
1163 | 0 | } |
1164 | 0 | } else { |
1165 | 0 | return -1; |
1166 | 0 | } |
1167 | 0 | return proto; |
1168 | 0 | } |
1169 | | |
1170 | | |
1171 | | inline static int naptr_proto_pref_score(char proto) |
1172 | 0 | { |
1173 | 0 | if((proto >= PROTO_UDP) && (proto <= PROTO_LAST)) |
1174 | 0 | return naptr_proto_pref[(int)proto]; |
1175 | 0 | return 0; |
1176 | 0 | } |
1177 | | |
1178 | | inline static int srv_proto_pref_score(char proto) |
1179 | 0 | { |
1180 | 0 | if((proto >= PROTO_UDP) && (proto <= PROTO_LAST)) |
1181 | 0 | return srv_proto_pref[(int)proto]; |
1182 | 0 | return 0; |
1183 | 0 | } |
1184 | | |
1185 | | |
1186 | | /** returns true if we support the protocol */ |
1187 | | int naptr_proto_supported(char proto) |
1188 | 0 | { |
1189 | 0 | if(naptr_proto_pref_score(proto) < 0) |
1190 | 0 | return 0; |
1191 | 0 | switch(proto) { |
1192 | 0 | case PROTO_UDP: |
1193 | 0 | return 1; |
1194 | 0 | #ifdef USE_TCP |
1195 | 0 | case PROTO_TCP: |
1196 | 0 | return !tcp_disable; |
1197 | 0 | #ifdef USE_TLS |
1198 | 0 | case PROTO_TLS: |
1199 | 0 | return !tls_disable; |
1200 | 0 | #endif /* USE_TLS */ |
1201 | 0 | #endif /* USE_TCP */ |
1202 | 0 | #ifdef USE_SCTP |
1203 | 0 | case PROTO_SCTP: |
1204 | 0 | return !sctp_disable; |
1205 | 0 | #endif |
1206 | 0 | } |
1207 | 0 | return 0; |
1208 | 0 | } |
1209 | | |
1210 | | |
1211 | | /** returns true if new_proto is preferred over old_proto */ |
1212 | | int naptr_proto_preferred(char new_proto, char old_proto) |
1213 | 0 | { |
1214 | 0 | return naptr_proto_pref_score(new_proto) |
1215 | 0 | > naptr_proto_pref_score(old_proto); |
1216 | 0 | } |
1217 | | |
1218 | | |
1219 | | /** choose between 2 naptr records, should take into account local |
1220 | | * preferences too |
1221 | | * returns 1 if the new record was selected, 0 otherwise */ |
1222 | | int naptr_choose(struct naptr_rdata **crt, char *crt_proto, |
1223 | | struct naptr_rdata *n, char n_proto) |
1224 | 0 | { |
1225 | 0 | LM_DBG("o:%d w:%d p:%d, o:%d w:%d p:%d\n", *crt ? (int)(*crt)->order : -1, |
1226 | 0 | *crt ? (int)(*crt)->pref : -1, (int)*crt_proto, (int)n->order, |
1227 | 0 | (int)n->pref, (int)n_proto); |
1228 | 0 | if((*crt == 0) |
1229 | 0 | || ((*crt_proto != n_proto) |
1230 | 0 | && (naptr_proto_preferred(n_proto, *crt_proto)))) |
1231 | 0 | goto change; |
1232 | 0 | if(!naptr_proto_preferred(*crt_proto, n_proto) |
1233 | 0 | && ((n->order < (*crt)->order) |
1234 | 0 | || ((n->order == (*crt)->order) |
1235 | 0 | && (n->pref < (*crt)->pref)))) { |
1236 | 0 | goto change; |
1237 | 0 | } |
1238 | 0 | LM_DBG("no change\n"); |
1239 | 0 | return 0; |
1240 | 0 | change: |
1241 | 0 | LM_DBG("changed\n"); |
1242 | 0 | *crt_proto = n_proto; |
1243 | 0 | *crt = n; |
1244 | 0 | return 1; |
1245 | 0 | } |
1246 | | #endif /* USE_NAPTR */ |
1247 | | |
1248 | | |
1249 | | /** internal sip srv resolver: resolves a host name trying: |
1250 | | * - SRV lookup if the address is not an ip *port==0. The result of the SRV |
1251 | | * query will be used for an A/AAAA lookup. |
1252 | | * - normal A/AAAA lookup (either fallback from the above or if *port!=0 |
1253 | | * and *proto!=0 or port==0 && proto==0) |
1254 | | * when performing SRV lookup (*port==0) it will use *proto to look for |
1255 | | * tcp or udp hosts, otherwise proto is unused; if proto==0 => no SRV lookup |
1256 | | * If zt is set, name will be assumed to be 0 terminated and some copy |
1257 | | * operations will be avoided. |
1258 | | * If is_srv is set it will assume name has the srv prefixes for sip already |
1259 | | * appended and it's already 0-term'ed; if not it will append them internally. |
1260 | | * If ars !=0, it will first try to look through them and only if the SRV |
1261 | | * record is not found it will try doing a DNS query (ars will not be |
1262 | | * freed, the caller should take care of them) |
1263 | | * returns: hostent struct & *port filled with the port from the SRV record; |
1264 | | * 0 on error |
1265 | | */ |
1266 | | struct hostent *srv_sip_resolvehost(str *name, int zt, unsigned short *port, |
1267 | | char *proto, int is_srv, struct rdata *ars) |
1268 | 0 | { |
1269 | 0 | struct hostent *he; |
1270 | 0 | struct ip_addr *ip; |
1271 | 0 | static char tmp[MAX_DNS_NAME]; /* tmp. buff. for SRV lookups and |
1272 | | null. term strings */ |
1273 | 0 | struct rdata *l; |
1274 | 0 | struct srv_rdata *srv; |
1275 | 0 | struct rdata *srv_head; |
1276 | 0 | char *srv_target; |
1277 | 0 | char srv_proto; |
1278 | | |
1279 | | /* init */ |
1280 | 0 | srv_head = 0; |
1281 | 0 | srv_target = 0; |
1282 | 0 | if(name->len >= MAX_DNS_NAME) { |
1283 | 0 | LM_ERR("domain name too long\n"); |
1284 | 0 | he = 0; |
1285 | 0 | goto end; |
1286 | 0 | } |
1287 | 0 | LM_DBG("%.*s:%d proto=%d\n", name->len, name->s, port ? (int)*port : -1, |
1288 | 0 | proto ? (int)*proto : -1); |
1289 | 0 | if(is_srv) { |
1290 | | /* skip directly to srv resolving */ |
1291 | 0 | srv_proto = (proto) ? *proto : 0; |
1292 | 0 | if(port) |
1293 | 0 | *port = (srv_proto == PROTO_TLS) ? SIPS_PORT : SIP_PORT; |
1294 | 0 | if(zt) { |
1295 | 0 | srv_target = name->s; /* name.s must be 0 terminated in |
1296 | | this case */ |
1297 | 0 | } else { |
1298 | 0 | memcpy(tmp, name->s, name->len); |
1299 | 0 | tmp[name->len] = '\0'; |
1300 | 0 | srv_target = tmp; |
1301 | 0 | } |
1302 | 0 | goto do_srv; /* skip to the actual srv query */ |
1303 | 0 | } |
1304 | 0 | if(proto) { /* makes sure we have a protocol set*/ |
1305 | 0 | if(*proto == 0) |
1306 | 0 | *proto = srv_proto = PROTO_UDP; /* default */ |
1307 | 0 | else |
1308 | 0 | srv_proto = *proto; |
1309 | 0 | } else { |
1310 | 0 | srv_proto = PROTO_UDP; |
1311 | 0 | } |
1312 | | /* try SRV if no port specified (draft-ietf-sip-srv-06) */ |
1313 | 0 | if((port) && (*port == 0)) { |
1314 | 0 | *port = (srv_proto == PROTO_TLS) ? SIPS_PORT |
1315 | 0 | : SIP_PORT; /* just in case we |
1316 | | don't find another */ |
1317 | | /* check if it's an ip address */ |
1318 | 0 | if(((ip = str2ip(name)) != 0) || ((ip = str2ip6(name)) != 0)) { |
1319 | | /* we are lucky, this is an ip address */ |
1320 | 0 | he = ip_addr2he(name, ip); |
1321 | 0 | goto end; |
1322 | 0 | } |
1323 | 0 | if((name->len + SRV_MAX_PREFIX_LEN + 1) > MAX_DNS_NAME) { |
1324 | 0 | LM_WARN("domain name too long (%d), unable to perform SRV lookup\n", |
1325 | 0 | name->len); |
1326 | 0 | } else { |
1327 | |
|
1328 | 0 | switch(srv_proto) { |
1329 | 0 | case PROTO_UDP: |
1330 | 0 | case PROTO_TCP: |
1331 | 0 | case PROTO_TLS: |
1332 | 0 | case PROTO_SCTP: |
1333 | 0 | create_srv_name(srv_proto, name, tmp); |
1334 | 0 | break; |
1335 | 0 | default: |
1336 | 0 | LM_CRIT("unknown proto %d\n", srv_proto); |
1337 | 0 | he = 0; |
1338 | 0 | goto end; |
1339 | 0 | } |
1340 | 0 | srv_target = tmp; |
1341 | 0 | do_srv: |
1342 | | /* try to find the SRV records inside previous ARs first*/ |
1343 | 0 | for(l = ars; l; l = l->next) { |
1344 | 0 | if(l->type != T_SRV) |
1345 | 0 | continue; |
1346 | 0 | srv = (struct srv_rdata *)l->rdata; |
1347 | 0 | if(srv == 0) { |
1348 | 0 | LM_CRIT("null rdata\n"); |
1349 | | /* cleanup on exit only */ |
1350 | 0 | break; |
1351 | 0 | } |
1352 | 0 | he = resolvehost(srv->name); |
1353 | 0 | if(he != 0) { |
1354 | | /* we found it*/ |
1355 | 0 | LM_DBG("found SRV(%s) = %s:%d in AR\n", srv_target, |
1356 | 0 | srv->name, srv->port); |
1357 | 0 | if(port) |
1358 | 0 | *port = srv->port; |
1359 | | /* cleanup on exit */ |
1360 | 0 | goto end; |
1361 | 0 | } |
1362 | 0 | } |
1363 | 0 | srv_head = get_record(srv_target, T_SRV, RES_ONLY_TYPE); |
1364 | 0 | for(l = srv_head; l; l = l->next) { |
1365 | 0 | if(l->type != T_SRV) |
1366 | 0 | continue; /*should never happen*/ |
1367 | 0 | srv = (struct srv_rdata *)l->rdata; |
1368 | 0 | if(srv == 0) { |
1369 | 0 | LM_CRIT("null rdata\n"); |
1370 | | /* cleanup on exit only */ |
1371 | 0 | break; |
1372 | 0 | } |
1373 | 0 | he = resolvehost(srv->name); |
1374 | 0 | if(he != 0) { |
1375 | | /* we found it*/ |
1376 | 0 | LM_DBG("SRV(%s) = %s:%d\n", srv_target, srv->name, |
1377 | 0 | srv->port); |
1378 | 0 | if(port) |
1379 | 0 | *port = srv->port; |
1380 | | /* cleanup on exit */ |
1381 | 0 | goto end; |
1382 | 0 | } |
1383 | 0 | } |
1384 | 0 | if(is_srv) { |
1385 | | /* if the name was already into SRV format it doesn't make |
1386 | | * any sense to fall back to A/AAAA */ |
1387 | 0 | he = 0; |
1388 | 0 | goto end; |
1389 | 0 | } |
1390 | | /* cleanup on exit */ |
1391 | 0 | LM_DBG("no SRV record found for %.*s," |
1392 | 0 | " trying 'normal' lookup...\n", |
1393 | 0 | name->len, name->s); |
1394 | 0 | } |
1395 | 0 | } |
1396 | 0 | if(likely(!zt)) { |
1397 | 0 | memcpy(tmp, name->s, name->len); |
1398 | 0 | tmp[name->len] = '\0'; |
1399 | 0 | he = resolvehost(tmp); |
1400 | 0 | } else { |
1401 | 0 | he = resolvehost(name->s); |
1402 | 0 | } |
1403 | 0 | end: |
1404 | 0 | LM_DBG("returning %p (%.*s:%d proto=%d)\n", he, name->len, name->s, |
1405 | 0 | port ? (int)*port : -1, proto ? (int)*proto : -1); |
1406 | 0 | if(srv_head) |
1407 | 0 | free_rdata_list(srv_head); |
1408 | 0 | return he; |
1409 | 0 | } |
1410 | | |
1411 | | |
1412 | | #ifdef USE_NAPTR |
1413 | | |
1414 | | |
1415 | | /** iterates over a naptr rr list, returning each time a "good" naptr record |
1416 | | * is found.( srv type, no regex and a supported protocol) |
1417 | | * params: |
1418 | | * naptr_head - naptr rr list head |
1419 | | * tried - bitmap used to keep track of the already tried records |
1420 | | * (no more than sizeof(tried)*8 valid records are |
1421 | | * ever walked |
1422 | | * srv_name - if successful, it will be set to the selected record |
1423 | | * srv name (naptr repl.) |
1424 | | * proto - if successful it will be set to the selected record |
1425 | | * protocol |
1426 | | * returns 0 if no more records found or a pointer to the selected record |
1427 | | * and sets protocol and srv_name |
1428 | | * WARNING: when calling first time make sure you run first |
1429 | | * naptr_iterate_init(&tried) |
1430 | | */ |
1431 | | struct rdata *naptr_sip_iterate(struct rdata *naptr_head, naptr_bmp_t *tried, |
1432 | | str *srv_name, char *proto) |
1433 | 0 | { |
1434 | 0 | int i, idx; |
1435 | 0 | struct rdata *l; |
1436 | 0 | struct rdata *l_saved; |
1437 | 0 | struct naptr_rdata *naptr; |
1438 | 0 | struct naptr_rdata *naptr_saved; |
1439 | 0 | char saved_proto; |
1440 | 0 | char naptr_proto; |
1441 | |
|
1442 | 0 | idx = 0; |
1443 | 0 | naptr_proto = PROTO_NONE; |
1444 | 0 | naptr_saved = 0; |
1445 | 0 | l_saved = 0; |
1446 | 0 | saved_proto = 0; |
1447 | 0 | i = 0; |
1448 | 0 | for(l = naptr_head; l && (i < MAX_NAPTR_RRS); l = l->next) { |
1449 | 0 | if(l->type != T_NAPTR) |
1450 | 0 | continue; |
1451 | 0 | naptr = (struct naptr_rdata *)l->rdata; |
1452 | 0 | if(naptr == 0) { |
1453 | 0 | LM_CRIT("null rdata\n"); |
1454 | 0 | goto end; |
1455 | 0 | } |
1456 | | /* check if valid and get proto */ |
1457 | 0 | if((naptr_proto = naptr_get_sip_proto(naptr)) <= 0) |
1458 | 0 | continue; |
1459 | 0 | if(*tried & (1 << i)) { |
1460 | 0 | i++; |
1461 | 0 | continue; /* already tried */ |
1462 | 0 | } |
1463 | 0 | LM_DBG("found a valid sip NAPTR rr %.*s, proto %d\n", naptr->repl_len, |
1464 | 0 | naptr->repl, (int)naptr_proto); |
1465 | 0 | if((naptr_proto_supported(naptr_proto))) { |
1466 | 0 | if(naptr_choose(&naptr_saved, &saved_proto, naptr, naptr_proto)) { |
1467 | 0 | idx = i; |
1468 | 0 | l_saved = l; |
1469 | 0 | } |
1470 | 0 | } |
1471 | 0 | i++; |
1472 | 0 | } |
1473 | 0 | if(naptr_saved) { |
1474 | | /* found something */ |
1475 | 0 | LM_DBG("choosed NAPTR rr %.*s, proto %d tried: 0x%x\n", |
1476 | 0 | naptr_saved->repl_len, naptr_saved->repl, (int)saved_proto, |
1477 | 0 | *tried); |
1478 | 0 | *tried |= 1 << idx; |
1479 | 0 | *proto = saved_proto; |
1480 | 0 | srv_name->s = naptr_saved->repl; |
1481 | 0 | srv_name->len = naptr_saved->repl_len; |
1482 | 0 | return l_saved; |
1483 | 0 | } |
1484 | 0 | end: |
1485 | 0 | return 0; |
1486 | 0 | } |
1487 | | |
1488 | | /** Prepend srv prefix according to the proto. */ |
1489 | | void create_srv_name(char proto, str *name, char *srv) |
1490 | 0 | { |
1491 | 0 | switch(proto) { |
1492 | 0 | case PROTO_UDP: |
1493 | 0 | memcpy(srv, SRV_UDP_PREFIX, SRV_UDP_PREFIX_LEN); |
1494 | 0 | memcpy(srv + SRV_UDP_PREFIX_LEN, name->s, name->len); |
1495 | 0 | srv[SRV_UDP_PREFIX_LEN + name->len] = '\0'; |
1496 | 0 | break; |
1497 | 0 | case PROTO_TCP: |
1498 | 0 | memcpy(srv, SRV_TCP_PREFIX, SRV_TCP_PREFIX_LEN); |
1499 | 0 | memcpy(srv + SRV_TCP_PREFIX_LEN, name->s, name->len); |
1500 | 0 | srv[SRV_TCP_PREFIX_LEN + name->len] = '\0'; |
1501 | 0 | break; |
1502 | 0 | case PROTO_TLS: |
1503 | 0 | memcpy(srv, SRV_TLS_PREFIX, SRV_TLS_PREFIX_LEN); |
1504 | 0 | memcpy(srv + SRV_TLS_PREFIX_LEN, name->s, name->len); |
1505 | 0 | srv[SRV_TLS_PREFIX_LEN + name->len] = '\0'; |
1506 | 0 | break; |
1507 | 0 | case PROTO_SCTP: |
1508 | 0 | memcpy(srv, SRV_SCTP_PREFIX, SRV_SCTP_PREFIX_LEN); |
1509 | 0 | memcpy(srv + SRV_SCTP_PREFIX_LEN, name->s, name->len); |
1510 | 0 | srv[SRV_SCTP_PREFIX_LEN + name->len] = '\0'; |
1511 | 0 | break; |
1512 | 0 | default: |
1513 | 0 | LM_CRIT("%s: unknown proto %d\n", __func__, proto); |
1514 | 0 | } |
1515 | 0 | } |
1516 | | |
1517 | | size_t create_srv_pref_list(char *proto, struct dns_srv_proto *list) |
1518 | 0 | { |
1519 | 0 | struct dns_srv_proto tmp; |
1520 | 0 | size_t i, j, list_len; |
1521 | 0 | int default_order = 1, max; |
1522 | | |
1523 | | /* if proto available, then add only the forced protocol to the list */ |
1524 | 0 | if(proto && *proto != PROTO_NONE) { |
1525 | 0 | list[0].proto = *proto; |
1526 | 0 | list_len = 1; |
1527 | 0 | } else { |
1528 | 0 | list_len = 0; |
1529 | | /*get protocols and preference scores, and add available protocol(s) and score(s) to the list*/ |
1530 | 0 | for(i = PROTO_UDP; i < PROTO_LAST; i++) { |
1531 | 0 | tmp.proto_pref = srv_proto_pref_score(i); |
1532 | | /* if -1 so disabled continue with next protocol*/ |
1533 | 0 | if(naptr_proto_supported(i) == 0) { |
1534 | 0 | continue; |
1535 | 0 | } else { |
1536 | 0 | list[list_len].proto_pref = tmp.proto_pref; |
1537 | 0 | list[list_len].proto = i; |
1538 | 0 | list_len++; |
1539 | 0 | } |
1540 | 0 | }; |
1541 | | |
1542 | | /* if all protocol preference scores equal, then set the preference to default values: udp,tcp,tls,sctp */ |
1543 | 0 | for(i = 1; i < list_len; i++) { |
1544 | 0 | if(list[0].proto_pref != list[i].proto_pref) { |
1545 | 0 | default_order = 0; |
1546 | 0 | } |
1547 | 0 | } |
1548 | 0 | if(default_order) { |
1549 | 0 | for(i = 0; i < list_len; i++) { |
1550 | 0 | list[i].proto_pref = srv_proto_pref_score(i); |
1551 | 0 | } |
1552 | 0 | } |
1553 | | |
1554 | | /* sorting the list */ |
1555 | 0 | for(i = 0; i < list_len - 1; i++) { |
1556 | 0 | max = i; |
1557 | 0 | for(j = i + 1; j < list_len; j++) { |
1558 | 0 | if(list[j].proto_pref > list[max].proto_pref) { |
1559 | 0 | max = j; |
1560 | 0 | } |
1561 | 0 | } |
1562 | 0 | if(i != max) { |
1563 | 0 | tmp = list[i]; |
1564 | 0 | list[i] = list[max]; |
1565 | 0 | list[max] = tmp; |
1566 | 0 | } |
1567 | 0 | } |
1568 | 0 | } |
1569 | 0 | return list_len; |
1570 | 0 | } |
1571 | | |
1572 | | /** Resolves SRV if no naptr found. |
1573 | | * It reuse dns_pref values and according that resolves supported protocols. |
1574 | | * If dns_pref are equal then it use udp,tcp,tls,sctp order. |
1575 | | * returns: hostent struct & *port filled with the port from the SRV record; |
1576 | | * 0 on error |
1577 | | */ |
1578 | | struct hostent *no_naptr_srv_sip_resolvehost( |
1579 | | str *name, unsigned short *port, char *proto) |
1580 | 0 | { |
1581 | 0 | struct dns_srv_proto srv_proto_list[PROTO_LAST]; |
1582 | 0 | struct hostent *he; |
1583 | 0 | struct ip_addr *ip; |
1584 | 0 | str srv_name; |
1585 | 0 | static char tmp_srv[MAX_DNS_NAME]; /* tmp. buff. for SRV lookups */ |
1586 | 0 | size_t i, list_len; |
1587 | | /* init variables */ |
1588 | 0 | he = 0; |
1589 | | |
1590 | | /* check if it's an ip address */ |
1591 | 0 | if(((ip = str2ip(name)) != 0) || ((ip = str2ip6(name)) != 0)) { |
1592 | | /* we are lucky, this is an ip address */ |
1593 | | /* set proto if needed - default udp */ |
1594 | 0 | if((proto) && (*proto == PROTO_NONE)) |
1595 | 0 | *proto = PROTO_UDP; |
1596 | | /* set port if needed - default 5060/5061 */ |
1597 | 0 | if((port) && (*port == 0)) |
1598 | 0 | *port = ((proto) && (*proto == PROTO_TLS)) ? SIPS_PORT : SIP_PORT; |
1599 | 0 | he = ip_addr2he(name, ip); |
1600 | 0 | return he; |
1601 | 0 | } |
1602 | | |
1603 | 0 | if((name->len + SRV_MAX_PREFIX_LEN + 1) > MAX_DNS_NAME) { |
1604 | 0 | LM_WARN("domain name too long (%d), unable to perform SRV lookup\n", |
1605 | 0 | name->len); |
1606 | 0 | } else { |
1607 | | /* looping on the ordered list until we found a protocol what has srv record */ |
1608 | 0 | list_len = create_srv_pref_list(proto, srv_proto_list); |
1609 | 0 | for(i = 0; i < list_len; i++) { |
1610 | 0 | switch(srv_proto_list[i].proto) { |
1611 | 0 | case PROTO_UDP: |
1612 | 0 | case PROTO_TCP: |
1613 | 0 | case PROTO_TLS: |
1614 | 0 | case PROTO_SCTP: |
1615 | 0 | create_srv_name(srv_proto_list[i].proto, name, tmp_srv); |
1616 | 0 | break; |
1617 | 0 | default: |
1618 | 0 | LM_CRIT("unknown proto %d\n", (int)srv_proto_list[i].proto); |
1619 | 0 | return 0; |
1620 | 0 | } |
1621 | | /* set default port */ |
1622 | 0 | if((port) && (*port == 0)) { |
1623 | 0 | *port = (srv_proto_list[i].proto == PROTO_TLS) |
1624 | 0 | ? SIPS_PORT |
1625 | 0 | : SIP_PORT; /* just in case we don't find another */ |
1626 | 0 | } |
1627 | 0 | if((proto) && (*proto == 0)) { |
1628 | 0 | *proto = PROTO_UDP; |
1629 | 0 | } |
1630 | 0 | srv_name.s = tmp_srv; |
1631 | 0 | srv_name.len = strlen(tmp_srv); |
1632 | 0 | #ifdef USE_DNS_CACHE |
1633 | 0 | if(dns_cache_init) { |
1634 | 0 | he = dns_srv_get_he(&srv_name, port, dns_flags); |
1635 | 0 | } else { |
1636 | 0 | he = srv_sip_resolvehost(&srv_name, 0, port, proto, 1, 0); |
1637 | 0 | } |
1638 | | #else |
1639 | | he = srv_sip_resolvehost(&srv_name, 0, port, proto, 1, 0); |
1640 | | #endif |
1641 | 0 | if(he != 0) { |
1642 | 0 | if(proto) |
1643 | 0 | *proto = srv_proto_list[i].proto; |
1644 | 0 | return he; |
1645 | 0 | } |
1646 | 0 | } |
1647 | 0 | } |
1648 | 0 | return 0; |
1649 | 0 | } |
1650 | | |
1651 | | /** internal sip naptr resolver function: resolves a host name trying: |
1652 | | * - NAPTR lookup if the address is not an ip and *proto==0 and *port==0. |
1653 | | * The result of the NAPTR query will be used for a SRV lookup |
1654 | | * - SRV lookup if the address is not an ip *port==0. The result of the SRV |
1655 | | * query will be used for an A/AAAA lookup. |
1656 | | * - normal A/AAAA lookup (either fallback from the above or if *port!=0 |
1657 | | * and *proto!=0 or port==0 && proto==0) |
1658 | | * when performing SRV lookup (*port==0) it will use proto to look for |
1659 | | * tcp or udp hosts, otherwise proto is unused; if proto==0 => no SRV lookup |
1660 | | * returns: hostent struct & *port filled with the port from the SRV record; |
1661 | | * 0 on error |
1662 | | */ |
1663 | | struct hostent *naptr_sip_resolvehost( |
1664 | | str *name, unsigned short *port, char *proto) |
1665 | 0 | { |
1666 | 0 | struct hostent *he; |
1667 | 0 | struct ip_addr *ip; |
1668 | 0 | static char tmp[MAX_DNS_NAME]; /* tmp. buff. for SRV lookups and |
1669 | | null. term strings */ |
1670 | 0 | struct rdata *l; |
1671 | 0 | struct rdata *naptr_head; |
1672 | 0 | char n_proto; |
1673 | 0 | str srv_name; |
1674 | 0 | str *name_copy = 0; |
1675 | 0 | naptr_bmp_t tried_bmp; /* tried bitmap */ |
1676 | 0 | char origproto = PROTO_NONE; |
1677 | |
|
1678 | 0 | if(proto) |
1679 | 0 | origproto = *proto; |
1680 | 0 | naptr_head = 0; |
1681 | 0 | he = 0; |
1682 | 0 | if(name->len >= MAX_DNS_NAME) { |
1683 | 0 | LM_ERR("domain name too long\n"); |
1684 | 0 | goto end; |
1685 | 0 | } |
1686 | | /* try NAPTR if no port or protocol is specified and NAPTR lookup is |
1687 | | * enabled */ |
1688 | 0 | if(port && proto && (*proto == 0) && (*port == 0)) { |
1689 | 0 | *proto = PROTO_UDP; /* just in case we don't find another */ |
1690 | 0 | if(((ip = str2ip(name)) != 0) || ((ip = str2ip6(name)) != 0)) { |
1691 | | /* we are lucky, this is an ip address */ |
1692 | 0 | he = ip_addr2he(name, ip); |
1693 | 0 | *port = SIP_PORT; |
1694 | 0 | goto end; |
1695 | 0 | } |
1696 | 0 | memcpy(tmp, name->s, name->len); |
1697 | 0 | tmp[name->len] = '\0'; |
1698 | 0 | naptr_head = get_record(tmp, T_NAPTR, RES_AR); |
1699 | 0 | naptr_iterate_init(&tried_bmp); |
1700 | 0 | while((l = naptr_sip_iterate( |
1701 | 0 | naptr_head, &tried_bmp, &srv_name, &n_proto)) |
1702 | 0 | != 0) { |
1703 | 0 | if((he = srv_sip_resolvehost(&srv_name, 1, port, proto, 1, l)) |
1704 | 0 | != 0) { |
1705 | 0 | *proto = n_proto; |
1706 | 0 | return he; |
1707 | 0 | } |
1708 | 0 | } |
1709 | | /*clean up on exit*/ |
1710 | 0 | LM_DBG("no NAPTR record found for %.*s, trying SRV lookup...\n", |
1711 | 0 | name->len, name->s); |
1712 | 0 | } |
1713 | | /* fallback to srv lookup */ |
1714 | 0 | if(proto) |
1715 | 0 | *proto = origproto; |
1716 | 0 | he = no_naptr_srv_sip_resolvehost(name, port, proto); |
1717 | | /* fallback all the way down to A/AAAA */ |
1718 | 0 | if(he == 0) { |
1719 | 0 | if(dns_cache_init) { |
1720 | 0 | he = dns_get_he(name, dns_flags); |
1721 | 0 | } else { |
1722 | | /* We need a zero terminated char* */ |
1723 | 0 | name_copy = shm_malloc(name->len + 1); |
1724 | 0 | shm_str_dup(name_copy, name); |
1725 | 0 | he = resolvehost(name_copy->s); |
1726 | 0 | shm_free(name_copy); |
1727 | 0 | } |
1728 | 0 | } |
1729 | 0 | end: |
1730 | 0 | if(naptr_head) |
1731 | 0 | free_rdata_list(naptr_head); |
1732 | 0 | return he; |
1733 | 0 | } |
1734 | | #endif /* USE_NAPTR */ |
1735 | | |
1736 | | |
1737 | | /** resolves a host name trying: |
1738 | | * - NAPTR lookup if enabled, the address is not an ip and *proto==0 and |
1739 | | * *port==0. The result of the NAPTR query will be used for a SRV lookup |
1740 | | * - SRV lookup if the address is not an ip *port==0. The result of the SRV |
1741 | | * query will be used for an A/AAAA lookup. |
1742 | | * - normal A/AAAA lookup (either fallback from the above or if *port!=0 |
1743 | | * and *proto!=0 or port==0 && proto==0) |
1744 | | * when performing SRV lookup (*port==0) it will use *proto to look for |
1745 | | * tcp or udp hosts, otherwise proto is unused; if proto==0 => no SRV lookup |
1746 | | * |
1747 | | * returns: hostent struct & *port filled with the port from the SRV record; |
1748 | | * 0 on error |
1749 | | */ |
1750 | | struct hostent *_sip_resolvehost(str *name, unsigned short *port, char *proto) |
1751 | 0 | { |
1752 | 0 | struct hostent *res = NULL; |
1753 | 0 | #ifdef USE_NAPTR |
1754 | 0 | if(cfg_get(core, core_cfg, dns_try_naptr)) |
1755 | 0 | res = naptr_sip_resolvehost(name, port, proto); |
1756 | 0 | else |
1757 | 0 | #endif |
1758 | 0 | res = srv_sip_resolvehost(name, 0, port, proto, 0, 0); |
1759 | 0 | if(unlikely(!res)) { |
1760 | | /* failed DNS request */ |
1761 | 0 | counter_inc(dns_cnts_h.failed_dns_req); |
1762 | 0 | } |
1763 | 0 | return res; |
1764 | 0 | } |
1765 | | |
1766 | | |
1767 | | /** resolve host, port, proto using sip rules (e.g. use SRV if port=0 a.s.o) |
1768 | | * and write the result in the sockaddr_union to |
1769 | | * returns -1 on error (resolve failed), 0 on success */ |
1770 | | int sip_hostport2su( |
1771 | | union sockaddr_union *su, str *name, unsigned short port, char *proto) |
1772 | 0 | { |
1773 | 0 | struct hostent *he; |
1774 | |
|
1775 | 0 | he = sip_resolvehost(name, &port, proto); |
1776 | 0 | if(he == 0) { |
1777 | 0 | ser_error = E_BAD_ADDRESS; |
1778 | 0 | LM_ERR("could not resolve hostname: \"%.*s\"\n", name->len, name->s); |
1779 | 0 | goto error; |
1780 | 0 | } |
1781 | | /* port filled by sip_resolvehost if empty*/ |
1782 | 0 | if(hostent2su(su, he, 0, port) < 0) { |
1783 | 0 | ser_error = E_BAD_ADDRESS; |
1784 | 0 | goto error; |
1785 | 0 | } |
1786 | 0 | return 0; |
1787 | 0 | error: |
1788 | 0 | return -1; |
1789 | 0 | } |
1790 | | |
1791 | | /* converts a str to an ipv4 address struct stored in ipb |
1792 | | * - ipb must be already allocated |
1793 | | * - return 0 on success; <0 on failure */ |
1794 | | int str2ipbuf(str *st, ip_addr_t *ipb) |
1795 | 0 | { |
1796 | 0 | int i; |
1797 | 0 | unsigned char *limit; |
1798 | 0 | unsigned char *s; |
1799 | | |
1800 | | /* just in case that e.g. the VIA parser get confused */ |
1801 | 0 | if(unlikely(!st->s || st->len <= 0)) { |
1802 | 0 | LM_ERR("invalid name (%p,%d), no conversion to IP address possible\n", |
1803 | 0 | st->s, st->len); |
1804 | 0 | return -1; |
1805 | 0 | } |
1806 | 0 | s = (unsigned char *)st->s; |
1807 | | |
1808 | | /*init*/ |
1809 | 0 | ipb->u.addr32[0] = 0; |
1810 | 0 | i = 0; |
1811 | 0 | limit = (unsigned char *)(st->s + st->len); |
1812 | |
|
1813 | 0 | for(; s < limit; s++) { |
1814 | 0 | if(*s == '.') { |
1815 | 0 | i++; |
1816 | 0 | if(i > 3) |
1817 | 0 | goto error_dots; |
1818 | 0 | } else if((*s <= '9') && (*s >= '0')) { |
1819 | 0 | ipb->u.addr[i] = ipb->u.addr[i] * 10 + *s - '0'; |
1820 | 0 | } else { |
1821 | | //error unknown char |
1822 | 0 | goto error_char; |
1823 | 0 | } |
1824 | 0 | } |
1825 | 0 | if(i < 3) |
1826 | 0 | goto error_dots; |
1827 | 0 | ipb->af = AF_INET; |
1828 | 0 | ipb->len = 4; |
1829 | |
|
1830 | 0 | return 0; |
1831 | | |
1832 | 0 | error_dots: |
1833 | 0 | DBG("error - too %s dots in [%.*s]\n", (i > 3) ? "many" : "few", st->len, |
1834 | 0 | st->s); |
1835 | 0 | return -1; |
1836 | 0 | error_char: |
1837 | | /* |
1838 | | DBG("warning - unexpected char %c in [%.*s]\n", *s, st->len, st->s); |
1839 | | */ |
1840 | 0 | return -2; |
1841 | 0 | } |
1842 | | |
1843 | | /* converts a str to an ipv4 address, returns the address or 0 on error |
1844 | | Warning: the result is a pointer to a statically allocated structure */ |
1845 | | ip_addr_t *str2ip(str *st) |
1846 | 0 | { |
1847 | 0 | ip_addr_t *ipb; |
1848 | |
|
1849 | 0 | ipb = get_next_ipaddr_buf(); |
1850 | 0 | if(str2ipbuf(st, ipb) < 0) { |
1851 | 0 | return NULL; |
1852 | 0 | } |
1853 | | |
1854 | 0 | return ipb; |
1855 | 0 | } |
1856 | | |
1857 | | /* |
1858 | | * Resolve a host name to a hostent. |
1859 | | * @param[in] name: the host name to resolve |
1860 | | * @return the hostent structure or NULL on error |
1861 | | * |
1862 | | * @note |
1863 | | * This function is a wrapper to choose between the DNS cache and the |
1864 | | * system resolver. If the DNS cache is enabled, it will use the DNS cache |
1865 | | * to resolve the host name. Otherwise, it will use the system resolver. |
1866 | | */ |
1867 | | struct hostent *__resolvehost(char *name) |
1868 | 0 | { |
1869 | 0 | #ifdef USE_DNS_CACHE |
1870 | 0 | if(dns_cache_init) { |
1871 | 0 | return dns_resolvehost(name); |
1872 | 0 | } else { |
1873 | 0 | #endif |
1874 | 0 | return _resolvehost(name); |
1875 | 0 | #ifdef USE_DNS_CACHE |
1876 | 0 | } |
1877 | 0 | #endif |
1878 | 0 | } |
1879 | | |
1880 | | /* |
1881 | | * Resolve a host name to a hostent. |
1882 | | * @param[in] name: the host name to resolve |
1883 | | * @param[in] port: the port number |
1884 | | * @param[in] proto: the protocol |
1885 | | * @return the hostent structure or NULL on error |
1886 | | * |
1887 | | * @note |
1888 | | * This function is a wrapper to choose between the DNS cache and the |
1889 | | * system resolver. If the DNS cache is enabled, it will use the DNS cache |
1890 | | * to resolve the host name. Otherwise, it will use the system resolver. |
1891 | | */ |
1892 | | struct hostent *__sip_resolvehost(str *name, unsigned short *port, char *proto) |
1893 | 0 | { |
1894 | 0 | #ifdef USE_DNS_CACHE |
1895 | 0 | if(dns_cache_init) { |
1896 | 0 | return dns_sip_resolvehost(name, port, proto); |
1897 | 0 | } else { |
1898 | 0 | #endif |
1899 | 0 | return _sip_resolvehost(name, port, proto); |
1900 | 0 | #ifdef USE_DNS_CACHE |
1901 | 0 | } |
1902 | 0 | #endif |
1903 | 0 | } |
1904 | | /* converts a str to an ipv6 address struct stored in ipb |
1905 | | * - ipb must be already allocated |
1906 | | * - return 0 on success; <0 on failure */ |
1907 | | int str2ip6buf(str *st, ip_addr_t *ipb) |
1908 | 0 | { |
1909 | 0 | int i, idx1, rest; |
1910 | 0 | int no_colons; |
1911 | 0 | int double_colon; |
1912 | 0 | int hex; |
1913 | 0 | unsigned short *addr_start; |
1914 | 0 | unsigned short addr_end[8]; |
1915 | 0 | unsigned short *addr; |
1916 | 0 | unsigned char *limit; |
1917 | 0 | unsigned char *s; |
1918 | | |
1919 | | /* just in case that e.g. the VIA parser get confused */ |
1920 | 0 | if(unlikely(!st->s || st->len <= 0)) { |
1921 | 0 | LM_ERR("invalid name (%p,%d), no conversion to IP address possible\n", |
1922 | 0 | st->s, st->len); |
1923 | 0 | return -1; |
1924 | 0 | } |
1925 | | /* init */ |
1926 | 0 | if((st->len) && (st->s[0] == '[')) { |
1927 | | /* skip over [ ] */ |
1928 | 0 | if(st->s[st->len - 1] != ']') |
1929 | 0 | goto error_char; |
1930 | 0 | s = (unsigned char *)(st->s + 1); |
1931 | 0 | limit = (unsigned char *)(st->s + st->len - 1); |
1932 | 0 | } else { |
1933 | 0 | s = (unsigned char *)st->s; |
1934 | 0 | limit = (unsigned char *)(st->s + st->len); |
1935 | 0 | } |
1936 | 0 | i = idx1 = rest = 0; |
1937 | 0 | double_colon = 0; |
1938 | 0 | no_colons = 0; |
1939 | 0 | ipb->af = AF_INET6; |
1940 | 0 | ipb->len = 16; |
1941 | 0 | addr_start = ipb->u.addr16; |
1942 | 0 | addr = addr_start; |
1943 | 0 | memset(addr_start, 0, 8 * sizeof(unsigned short)); |
1944 | 0 | memset(addr_end, 0, 8 * sizeof(unsigned short)); |
1945 | 0 | for(; s < limit; s++) { |
1946 | 0 | if(*s == ':') { |
1947 | 0 | no_colons++; |
1948 | 0 | if(no_colons > 7) |
1949 | 0 | goto error_too_many_colons; |
1950 | 0 | if(double_colon) { |
1951 | 0 | idx1 = i; |
1952 | 0 | i = 0; |
1953 | 0 | if(addr == addr_end) |
1954 | 0 | goto error_colons; |
1955 | 0 | addr = addr_end; |
1956 | 0 | } else { |
1957 | 0 | double_colon = 1; |
1958 | 0 | addr[i] = htons(addr[i]); |
1959 | 0 | i++; |
1960 | 0 | } |
1961 | 0 | } else if((hex = HEX2I(*s)) >= 0) { |
1962 | 0 | addr[i] = addr[i] * 16 + hex; |
1963 | 0 | double_colon = 0; |
1964 | 0 | } else { |
1965 | | /* error, unknown char */ |
1966 | 0 | goto error_char; |
1967 | 0 | } |
1968 | 0 | } |
1969 | 0 | if(!double_colon) { /* not ending in ':' */ |
1970 | 0 | addr[i] = htons(addr[i]); |
1971 | 0 | i++; |
1972 | 0 | } |
1973 | | /* if address contained '::' fix it */ |
1974 | 0 | if(addr == addr_end) { |
1975 | 0 | rest = 8 - i - idx1; |
1976 | 0 | memcpy(addr_start + idx1 + rest, addr_end, i * sizeof(unsigned short)); |
1977 | 0 | } else { |
1978 | | /* no double colons inside */ |
1979 | 0 | if(no_colons < 7) |
1980 | 0 | goto error_too_few_colons; |
1981 | 0 | } |
1982 | | /* |
1983 | | DBG("idx1=%d, rest=%d, no_colons=%d, hex=%x\n", |
1984 | | idx1, rest, no_colons, hex); |
1985 | | DBG("address %x:%x:%x:%x:%x:%x:%x:%x\n", |
1986 | | addr_start[0], addr_start[1], addr_start[2], |
1987 | | addr_start[3], addr_start[4], addr_start[5], |
1988 | | addr_start[6], addr_start[7] ); |
1989 | | */ |
1990 | 0 | return 0; |
1991 | | |
1992 | 0 | error_too_many_colons: |
1993 | 0 | DBG("error - too many colons in [%.*s]\n", st->len, st->s); |
1994 | 0 | return -1; |
1995 | | |
1996 | 0 | error_too_few_colons: |
1997 | 0 | DBG("error - too few colons in [%.*s]\n", st->len, st->s); |
1998 | 0 | return -2; |
1999 | | |
2000 | 0 | error_colons: |
2001 | 0 | DBG("error - too many double colons in [%.*s]\n", st->len, st->s); |
2002 | 0 | return -3; |
2003 | | |
2004 | 0 | error_char: |
2005 | | /* |
2006 | | DBG("warning - unexpected char %c in [%.*s]\n", *s, st->len, |
2007 | | st->s);*/ |
2008 | 0 | return -4; |
2009 | 0 | } |
2010 | | |
2011 | | /* returns an ip_addr struct.; on error returns 0 |
2012 | | * the ip_addr struct is static, so subsequent calls will destroy its content*/ |
2013 | | ip_addr_t *str2ip6(str *st) |
2014 | 0 | { |
2015 | 0 | ip_addr_t *ipb; |
2016 | |
|
2017 | 0 | ipb = get_next_ipaddr_buf(); |
2018 | 0 | if(str2ip6buf(st, ipb) < 0) { |
2019 | 0 | return NULL; |
2020 | 0 | } |
2021 | | |
2022 | 0 | return ipb; |
2023 | 0 | } |
2024 | | |
2025 | | /* converts a str to an ipvv/6 address struct stored in ipb |
2026 | | * - ipb must be already allocated |
2027 | | * - return 0 on success; <0 on failure */ |
2028 | | int str2ipxbuf(str *st, ip_addr_t *ipb) |
2029 | 0 | { |
2030 | 0 | if(str2ipbuf(st, ipb) < 0) { |
2031 | 0 | if(str2ip6buf(st, ipb) < 0) { |
2032 | 0 | return -1; |
2033 | 0 | } |
2034 | 0 | } |
2035 | | |
2036 | 0 | return 0; |
2037 | 0 | } |
2038 | | |
2039 | | /* returns an ip_addr struct converted from ipv4/6 str; on error returns 0 |
2040 | | * the ip_addr struct is static, so subsequent calls will destroy its content*/ |
2041 | | struct ip_addr *str2ipx(str *st) |
2042 | 0 | { |
2043 | 0 | ip_addr_t *ipb; |
2044 | |
|
2045 | 0 | ipb = get_next_ipaddr_buf(); |
2046 | 0 | if(str2ipbuf(st, ipb) < 0) { |
2047 | 0 | if(str2ip6buf(st, ipb) < 0) { |
2048 | 0 | return NULL; |
2049 | 0 | } |
2050 | 0 | } |
2051 | | |
2052 | 0 | return ipb; |
2053 | 0 | } |