blob: fb23b538e73d2b8812990f5aa73721b1784840c6 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <pjsip/sip_resolve.h>
21#include <pjsip/sip_transport.h>
22#include <pjsip/sip_errno.h>
23#include <pjlib-util/errno.h>
24#include <pjlib-util/srv_resolver.h>
25#include <pj/addr_resolv.h>
26#include <pj/array.h>
27#include <pj/assert.h>
28#include <pj/ctype.h>
29#include <pj/log.h>
30#include <pj/pool.h>
31#include <pj/rand.h>
32#include <pj/string.h>
33
34
35#define THIS_FILE "sip_resolve.c"
36
37#define ADDR_MAX_COUNT 8
38
39struct naptr_target
40{
41 pj_str_t res_type; /**< e.g. "_sip._udp" */
42 pj_str_t name; /**< Domain name. */
43 pjsip_transport_type_e type; /**< Transport type. */
44 unsigned order; /**< Order */
45 unsigned pref; /**< Preference. */
46};
47
48struct query
49{
50 char *objname;
51
52 pj_dns_type query_type;
53 void *token;
54 pjsip_resolver_callback *cb;
55 pj_dns_async_query *object;
56 pj_status_t last_error;
57
58 /* Original request: */
59 struct {
60 pjsip_host_info target;
61 unsigned def_port;
62 } req;
63
64 /* NAPTR records: */
65 unsigned naptr_cnt;
66 struct naptr_target naptr[8];
67};
68
69
70struct pjsip_resolver_t
71{
72 pj_dns_resolver *res;
73};
74
75
76static void srv_resolver_cb(void *user_data,
77 pj_status_t status,
78 const pj_dns_srv_record *rec);
79static void dns_a_callback(void *user_data,
80 pj_status_t status,
81 pj_dns_parsed_packet *response);
82
83
84/*
85 * Public API to create the resolver.
86 */
87PJ_DEF(pj_status_t) pjsip_resolver_create( pj_pool_t *pool,
88 pjsip_resolver_t **p_res)
89{
90 pjsip_resolver_t *resolver;
91
92 PJ_ASSERT_RETURN(pool && p_res, PJ_EINVAL);
93 resolver = PJ_POOL_ZALLOC_T(pool, pjsip_resolver_t);
94 *p_res = resolver;
95
96 return PJ_SUCCESS;
97}
98
99
100/*
101 * Public API to set the DNS resolver instance for the SIP resolver.
102 */
103PJ_DEF(pj_status_t) pjsip_resolver_set_resolver(pjsip_resolver_t *res,
104 pj_dns_resolver *dns_res)
105{
106#if PJSIP_HAS_RESOLVER
107 res->res = dns_res;
108 return PJ_SUCCESS;
109#else
110 PJ_UNUSED_ARG(res);
111 PJ_UNUSED_ARG(dns_res);
112 pj_assert(!"Resolver is disabled (PJSIP_HAS_RESOLVER==0)");
113 return PJ_EINVALIDOP;
114#endif
115}
116
117
118/*
119 * Public API to get the internal DNS resolver.
120 */
121PJ_DEF(pj_dns_resolver*) pjsip_resolver_get_resolver(pjsip_resolver_t *res)
122{
123 return res->res;
124}
125
126
127/*
128 * Public API to create destroy the resolver
129 */
130PJ_DEF(void) pjsip_resolver_destroy(pjsip_resolver_t *resolver)
131{
132 if (resolver->res) {
133#if PJSIP_HAS_RESOLVER
134 pj_dns_resolver_destroy(resolver->res, PJ_FALSE);
135#endif
136 resolver->res = NULL;
137 }
138}
139
140/*
141 * Internal:
142 * determine if an address is a valid IP address, and if it is,
143 * return the IP version (4 or 6).
144 */
145static int get_ip_addr_ver(const pj_str_t *host)
146{
147 pj_in_addr dummy;
148 pj_in6_addr dummy6;
149
150 /* First check with inet_aton() */
151 if (pj_inet_aton(host, &dummy) > 0)
152 return 4;
153
154 /* Then check if this is an IPv6 address */
155 if (pj_inet_pton(pj_AF_INET6(), host, &dummy6) == PJ_SUCCESS)
156 return 6;
157
158 /* Not an IP address */
159 return 0;
160}
161
162
163/*
164 * This is the main function for performing server resolution.
165 */
166PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver,
167 pj_pool_t *pool,
168 const pjsip_host_info *target,
169 void *token,
170 pjsip_resolver_callback *cb)
171{
172 pjsip_server_addresses svr_addr;
173 pj_status_t status = PJ_SUCCESS;
174 int ip_addr_ver;
175 struct query *query;
176 pjsip_transport_type_e type = target->type;
177
178 /* Is it IP address or hostname? And if it's an IP, which version? */
179 ip_addr_ver = get_ip_addr_ver(&target->addr.host);
180
181 /* Set the transport type if not explicitly specified.
182 * RFC 3263 section 4.1 specify rules to set up this.
183 */
184 if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
185 if (ip_addr_ver || (target->addr.port != 0)) {
186#if PJ_HAS_TCP
187 if (target->flag & PJSIP_TRANSPORT_SECURE)
188 {
189 type = PJSIP_TRANSPORT_TLS;
190 } else if (target->flag & PJSIP_TRANSPORT_RELIABLE)
191 {
192 type = PJSIP_TRANSPORT_TCP;
193 } else
194#endif
195 {
196 type = PJSIP_TRANSPORT_UDP;
197 }
198 } else {
199 /* No type or explicit port is specified, and the address is
200 * not IP address.
201 * In this case, full NAPTR resolution must be performed.
202 * But we don't support it (yet).
203 */
204#if PJ_HAS_TCP
205 if (target->flag & PJSIP_TRANSPORT_SECURE)
206 {
207 type = PJSIP_TRANSPORT_TLS;
208 } else if (target->flag & PJSIP_TRANSPORT_RELIABLE)
209 {
210 type = PJSIP_TRANSPORT_TCP;
211 } else
212#endif
213 {
214 type = PJSIP_TRANSPORT_UDP;
215 }
216 }
217
218 /* Add IPv6 flag for IPv6 address */
219 if (ip_addr_ver == 6)
220 type = (pjsip_transport_type_e)((int)type + PJSIP_TRANSPORT_IPV6);
221 }
222
223
224 /* If target is an IP address, or if resolver is not configured,
225 * we can just finish the resolution now using pj_gethostbyname()
226 */
227 if (ip_addr_ver || resolver->res == NULL) {
228 char addr_str[PJ_INET6_ADDRSTRLEN+10];
229 pj_uint16_t srv_port;
230
231 if (ip_addr_ver != 0) {
232 /* Target is an IP address, no need to resolve */
233 if (ip_addr_ver == 4) {
234 pj_sockaddr_init(pj_AF_INET(), &svr_addr.entry[0].addr,
235 NULL, 0);
236 pj_inet_aton(&target->addr.host,
237 &svr_addr.entry[0].addr.ipv4.sin_addr);
238 } else {
239 pj_sockaddr_init(pj_AF_INET6(), &svr_addr.entry[0].addr,
240 NULL, 0);
241 pj_inet_pton(pj_AF_INET6(), &target->addr.host,
242 &svr_addr.entry[0].addr.ipv6.sin6_addr);
243 }
244 } else {
245 pj_addrinfo ai;
246 unsigned count;
247 int af;
248
249 PJ_LOG(5,(THIS_FILE,
250 "DNS resolver not available, target '%.*s:%d' type=%s "
251 "will be resolved with getaddrinfo()",
252 target->addr.host.slen,
253 target->addr.host.ptr,
254 target->addr.port,
255 pjsip_transport_get_type_name(target->type)));
256
257 if (type & PJSIP_TRANSPORT_IPV6) {
258 af = pj_AF_INET6();
259 } else {
260 af = pj_AF_INET();
261 }
262
263 /* Resolve */
264 count = 1;
265 status = pj_getaddrinfo(af, &target->addr.host, &count, &ai);
266 if (status != PJ_SUCCESS) {
267 /* "Normalize" error to PJ_ERESOLVE. This is a special error
268 * because it will be translated to SIP status 502 by
269 * sip_transaction.c
270 */
271 status = PJ_ERESOLVE;
272 goto on_error;
273 }
274
275 svr_addr.entry[0].addr.addr.sa_family = (pj_uint16_t)af;
276 pj_memcpy(&svr_addr.entry[0].addr, &ai.ai_addr,
277 sizeof(pj_sockaddr));
278 }
279
280 /* Set the port number */
281 if (target->addr.port == 0) {
282 srv_port = (pj_uint16_t)
283 pjsip_transport_get_default_port_for_type(type);
284 } else {
285 srv_port = (pj_uint16_t)target->addr.port;
286 }
287 pj_sockaddr_set_port(&svr_addr.entry[0].addr, srv_port);
288
289 /* Call the callback. */
290 PJ_LOG(5,(THIS_FILE,
291 "Target '%.*s:%d' type=%s resolved to "
292 "'%s' type=%s (%s)",
293 (int)target->addr.host.slen,
294 target->addr.host.ptr,
295 target->addr.port,
296 pjsip_transport_get_type_name(target->type),
297 pj_sockaddr_print(&svr_addr.entry[0].addr, addr_str,
298 sizeof(addr_str), 3),
299 pjsip_transport_get_type_name(type),
300 pjsip_transport_get_type_desc(type)));
301 svr_addr.count = 1;
302 svr_addr.entry[0].priority = 0;
303 svr_addr.entry[0].weight = 0;
304 svr_addr.entry[0].type = type;
305 svr_addr.entry[0].addr_len = pj_sockaddr_get_len(&svr_addr.entry[0].addr);
306 (*cb)(status, token, &svr_addr);
307
308 /* Done. */
309 return;
310 }
311
312 /* Target is not an IP address so we need to resolve it. */
313#if PJSIP_HAS_RESOLVER
314
315 /* Build the query state */
316 query = PJ_POOL_ZALLOC_T(pool, struct query);
317 query->objname = THIS_FILE;
318 query->token = token;
319 query->cb = cb;
320 query->req.target = *target;
321 pj_strdup(pool, &query->req.target.addr.host, &target->addr.host);
322
323 /* If port is not specified, start with SRV resolution
324 * (should be with NAPTR, but we'll do that later)
325 */
326 PJ_TODO(SUPPORT_DNS_NAPTR);
327
328 /* Build dummy NAPTR entry */
329 query->naptr_cnt = 1;
330 pj_bzero(&query->naptr[0], sizeof(query->naptr[0]));
331 query->naptr[0].order = 0;
332 query->naptr[0].pref = 0;
333 query->naptr[0].type = type;
334 pj_strdup(pool, &query->naptr[0].name, &target->addr.host);
335
336
337 /* Start DNS SRV or A resolution, depending on whether port is specified */
338 if (target->addr.port == 0) {
339 query->query_type = PJ_DNS_TYPE_SRV;
340
341 query->req.def_port = 5060;
342
343 if (type == PJSIP_TRANSPORT_TLS) {
344 query->naptr[0].res_type = pj_str("_sips._tcp.");
345 query->req.def_port = 5061;
346 } else if (type == PJSIP_TRANSPORT_TCP)
347 query->naptr[0].res_type = pj_str("_sip._tcp.");
348 else if (type == PJSIP_TRANSPORT_UDP)
349 query->naptr[0].res_type = pj_str("_sip._udp.");
350 else {
351 pj_assert(!"Unknown transport type");
352 query->naptr[0].res_type = pj_str("_sip._udp.");
353
354 }
355
356 } else {
357 /* Otherwise if port is specified, start with A (or AAAA) host
358 * resolution
359 */
360 query->query_type = PJ_DNS_TYPE_A;
361 query->naptr[0].res_type.slen = 0;
362 query->req.def_port = target->addr.port;
363 }
364
365 /* Start the asynchronous query */
366 PJ_LOG(5, (query->objname,
367 "Starting async DNS %s query: target=%.*s%.*s, transport=%s, "
368 "port=%d",
369 pj_dns_get_type_name(query->query_type),
370 (int)query->naptr[0].res_type.slen,
371 query->naptr[0].res_type.ptr,
372 (int)query->naptr[0].name.slen, query->naptr[0].name.ptr,
373 pjsip_transport_get_type_name(target->type),
374 target->addr.port));
375
376 if (query->query_type == PJ_DNS_TYPE_SRV) {
377
378 status = pj_dns_srv_resolve(&query->naptr[0].name,
379 &query->naptr[0].res_type,
380 query->req.def_port, pool, resolver->res,
381 PJ_TRUE, query, &srv_resolver_cb, NULL);
382
383 } else if (query->query_type == PJ_DNS_TYPE_A) {
384
385 status = pj_dns_resolver_start_query(resolver->res,
386 &query->naptr[0].name,
387 PJ_DNS_TYPE_A, 0,
388 &dns_a_callback,
389 query, &query->object);
390
391 } else {
392 pj_assert(!"Unexpected");
393 status = PJ_EBUG;
394 }
395
396 if (status != PJ_SUCCESS)
397 goto on_error;
398
399 return;
400
401#else /* PJSIP_HAS_RESOLVER */
402 PJ_UNUSED_ARG(pool);
403 PJ_UNUSED_ARG(query);
404 PJ_UNUSED_ARG(srv_name);
405#endif /* PJSIP_HAS_RESOLVER */
406
407on_error:
408 if (status != PJ_SUCCESS) {
409 char errmsg[PJ_ERR_MSG_SIZE];
410 PJ_LOG(4,(THIS_FILE, "Failed to resolve '%.*s'. Err=%d (%s)",
411 (int)target->addr.host.slen,
412 target->addr.host.ptr,
413 status,
414 pj_strerror(status,errmsg,sizeof(errmsg)).ptr));
415 (*cb)(status, token, NULL);
416 return;
417 }
418}
419
420#if PJSIP_HAS_RESOLVER
421
422/*
423 * This callback is called when target is resolved with DNS A query.
424 */
425static void dns_a_callback(void *user_data,
426 pj_status_t status,
427 pj_dns_parsed_packet *pkt)
428{
429 struct query *query = (struct query*) user_data;
430 pjsip_server_addresses srv;
431 pj_dns_a_record rec;
432 unsigned i;
433
434 rec.addr_count = 0;
435
436 /* Parse the response */
437 if (status == PJ_SUCCESS) {
438 status = pj_dns_parse_a_response(pkt, &rec);
439 }
440
441 if (status != PJ_SUCCESS) {
442 char errmsg[PJ_ERR_MSG_SIZE];
443
444 /* Log error */
445 pj_strerror(status, errmsg, sizeof(errmsg));
446 PJ_LOG(4,(query->objname, "DNS A record resolution failed: %s",
447 errmsg));
448
449 /* Call the callback */
450 (*query->cb)(status, query->token, NULL);
451 return;
452 }
453
454 /* Build server addresses and call callback */
455 srv.count = 0;
456 for (i=0; i<rec.addr_count; ++i) {
457 srv.entry[srv.count].type = query->naptr[0].type;
458 srv.entry[srv.count].priority = 0;
459 srv.entry[srv.count].weight = 0;
460 srv.entry[srv.count].addr_len = sizeof(pj_sockaddr_in);
461 pj_sockaddr_in_init(&srv.entry[srv.count].addr.ipv4,
462 0, (pj_uint16_t)query->req.def_port);
463 srv.entry[srv.count].addr.ipv4.sin_addr.s_addr =
464 rec.addr[i].s_addr;
465
466 ++srv.count;
467 }
468
469 /* Call the callback */
470 (*query->cb)(PJ_SUCCESS, query->token, &srv);
471}
472
473
474/* Callback to be called by DNS SRV resolution */
475static void srv_resolver_cb(void *user_data,
476 pj_status_t status,
477 const pj_dns_srv_record *rec)
478{
479 struct query *query = (struct query*) user_data;
480 pjsip_server_addresses srv;
481 unsigned i;
482
483 if (status != PJ_SUCCESS) {
484 char errmsg[PJ_ERR_MSG_SIZE];
485
486 /* Log error */
487 pj_strerror(status, errmsg, sizeof(errmsg));
488 PJ_LOG(4,(query->objname, "DNS A record resolution failed: %s",
489 errmsg));
490
491 /* Call the callback */
492 (*query->cb)(status, query->token, NULL);
493 return;
494 }
495
496 /* Build server addresses and call callback */
497 srv.count = 0;
498 for (i=0; i<rec->count; ++i) {
499 unsigned j;
500
501 for (j=0; j<rec->entry[i].server.addr_count; ++j) {
502 srv.entry[srv.count].type = query->naptr[0].type;
503 srv.entry[srv.count].priority = rec->entry[i].priority;
504 srv.entry[srv.count].weight = rec->entry[i].weight;
505 srv.entry[srv.count].addr_len = sizeof(pj_sockaddr_in);
506 pj_sockaddr_in_init(&srv.entry[srv.count].addr.ipv4,
507 0, (pj_uint16_t)rec->entry[i].port);
508 srv.entry[srv.count].addr.ipv4.sin_addr.s_addr =
509 rec->entry[i].server.addr[j].s_addr;
510
511 ++srv.count;
512 }
513 }
514
515 /* Call the callback */
516 (*query->cb)(PJ_SUCCESS, query->token, &srv);
517}
518
519#endif /* PJSIP_HAS_RESOLVER */
520