belle_sip_resolver.c 11.4 KB
Newer Older
Simon Morlat's avatar
Simon Morlat committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
	belle-sip - SIP (RFC3261) library.
    Copyright (C) 2010  Belledonne Communications SARL

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "belle_sip_resolver.h"

21 22 23 24 25 26 27
#include <stdlib.h>


#define DNS_EAGAIN  EAGAIN


static struct dns_resolv_conf *resconf(belle_sip_resolver_context_t *ctx) {
jehan's avatar
jehan committed
28
#if !_WIN32 && !HAVE_RESINIT
29
	const char *path;
30
#endif
31 32 33 34 35 36 37 38 39 40
	int error;

	if (ctx->resconf)
		return ctx->resconf;

	if (!(ctx->resconf = dns_resconf_open(&error))) {
		belle_sip_error("%s dns_resconf_open error: %s", __FUNCTION__, dns_strerror(error));
		return NULL;
	}

41 42
#ifdef _WIN32
	error = dns_resconf_loadwin(ctx->resconf);
Ghislain MARY's avatar
Ghislain MARY committed
43 44 45
	if (error) {
		belle_sip_error("%s dns_resconf_loadwin error", __FUNCTION__);
	}
jehan's avatar
jehan committed
46
#elif ANDROID
Ghislain MARY's avatar
Ghislain MARY committed
47 48 49 50
	error = dns_resconf_loadandroid(ctx->resconf);
	if (error) {
		belle_sip_error("%s dns_resconf_loadandroid error", __FUNCTION__);
	}
jehan's avatar
jehan committed
51 52 53 54 55
#elif HAVE_RESINIT
	error = dns_resconf_loadfromresolv(ctx->resconf);
	if (error) {
		belle_sip_error("%s dns_resconf_loadfromresolv error", __FUNCTION__);
	}
56
#else
57 58 59 60 61 62 63 64 65 66
	path = "/etc/resolv.conf";
	error = dns_resconf_loadpath(ctx->resconf, path);
	if (error) {
		belle_sip_error("%s dns_resconf_loadpath error [%s]: %s", __FUNCTION__, path, dns_strerror(error));
		return NULL;
	}

	path = "/etc/nsswitch.conf";
	error = dns_nssconf_loadpath(ctx->resconf, path);
	if (error) {
67
		belle_sip_message("%s dns_nssconf_loadpath error [%s]: %s", __FUNCTION__, path, dns_strerror(error));
68
	}
Ghislain MARY's avatar
Ghislain MARY committed
69
#endif
jehan's avatar
jehan committed
70

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93

	return ctx->resconf;
}

static struct dns_hosts *hosts(belle_sip_resolver_context_t *ctx) {
	int error;

	if (ctx->hosts)
		return ctx->hosts;

	if (!(ctx->hosts = dns_hosts_local(&error))) {
		belle_sip_error("%s dns_hosts_local error: %s", __FUNCTION__, dns_strerror(error));
		return NULL;
	}

	return ctx->hosts;
}

struct dns_cache *cache(belle_sip_resolver_context_t *ctx) {
	return NULL;
}

static int resolver_process_a_data(belle_sip_resolver_context_t *ctx, unsigned int revents) {
94 95
	char host[NI_MAXHOST + 1];
	char service[NI_MAXSERV + 1];
96 97 98
	struct dns_packet *ans;
	struct dns_rr_i *I;
	int error;
99 100 101
#ifndef HAVE_C99
	struct dns_rr_i dns_rr_it;
#endif
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117

	if (revents & BELLE_SIP_EVENT_TIMEOUT) {
		belle_sip_error("%s timed-out", __FUNCTION__);
		return BELLE_SIP_STOP;
	}
	if (ctx->cancelled) {
		return BELLE_SIP_STOP;
	}

	error = dns_res_check(ctx->R);
	if (!error) {
		struct dns_rr rr;
		union dns_any any;
		enum dns_section section = DNS_S_AN;

		ans = dns_res_fetch(ctx->R, &error);
118
#ifdef HAVE_C99
119
		I = dns_rr_i_new(ans, .section = 0);
120 121 122 123
#else
		memset(&dns_rr_it, 0, sizeof dns_rr_it);
		I = dns_rr_i_init(&dns_rr_it, ans);
#endif
124 125 126 127 128 129 130
		while (dns_rr_grep(&rr, 1, I, ans, &error)) {
			if (rr.section == section) {
				if ((error = dns_any_parse(dns_any_init(&any, sizeof(any)), &rr, ans))) {
					belle_sip_error("%s dns_any_parse error: %s", __FUNCTION__, dns_strerror(error));
					free(ans);
					return BELLE_SIP_STOP;
				}
131 132
				if ((ctx->family == AF_INET6) && (rr.class == DNS_C_IN) && (rr.type == DNS_T_AAAA)) {
					struct dns_aaaa *aaaa = &any.aaaa;
133 134 135 136 137 138 139 140
					struct sockaddr_in6 sin6;
					memset(&sin6, 0, sizeof(sin6));
					memcpy(&sin6.sin6_addr, &aaaa->addr, sizeof(sin6.sin6_addr));
					sin6.sin6_family = AF_INET6;
					sin6.sin6_port = ctx->port;
					if (getnameinfo((struct sockaddr *)&sin6, sizeof(sin6), host, sizeof(host), service, sizeof(service), NI_NUMERICHOST) != 0)
						continue;
					ctx->ai = belle_sip_ip_address_to_addrinfo(host, ctx->port);
141 142
					belle_sip_message("%s has address %s", ctx->name, host);
					break;
143 144 145
				} else {
					if ((rr.class == DNS_C_IN) && (rr.type == DNS_T_A)) {
						struct dns_a *a = &any.a;
146 147 148 149 150 151 152 153
						struct sockaddr_in sin;
						memset(&sin, 0, sizeof(sin));
						memcpy(&sin.sin_addr, &a->addr, sizeof(sin.sin_addr));
						sin.sin_family = AF_INET;
						sin.sin_port = ctx->port;
						if (getnameinfo((struct sockaddr *)&sin, sizeof(sin), host, sizeof(host), service, sizeof(service), NI_NUMERICHOST) != 0)
							continue;
						ctx->ai = belle_sip_ip_address_to_addrinfo(host, ctx->port);
154 155 156
						belle_sip_message("%s has address %s", ctx->name, host);
						break;
					}
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
				}
			}
		}
		free(ans);
		ctx->cb(ctx->cb_data, ctx->name, ctx->ai);
		return BELLE_SIP_STOP;
	}
	if (error != DNS_EAGAIN) {
		belle_sip_error("%s dns_res_check error: %s (%d)", __FUNCTION__, dns_strerror(error), error);
		return BELLE_SIP_STOP;
	}

	dns_res_poll(ctx->R, 0);
	return BELLE_SIP_CONTINUE;
}

173 174 175
static int _resolver_start_query(belle_sip_resolver_context_t *ctx, belle_sip_source_func_t datafunc, enum dns_type type, int timeout) {
	int error;

176
	if (!ctx->stack->resolver_send_error) {
177 178 179 180 181
		error = dns_res_submit(ctx->R, ctx->name, type, DNS_C_IN);
		if (error)
			belle_sip_error("%s dns_res_submit error [%s]: %s", __FUNCTION__, ctx->name, dns_strerror(error));
	} else {
		/* Error simulation */
182
		error = ctx->stack->resolver_send_error;
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
		belle_sip_error("%s dns_res_submit error [%s]: simulated error %d", __FUNCTION__, ctx->name, error);
	}
	if (error < 0) {
		return -1;
	}

	(*datafunc)(ctx, 0);
	belle_sip_socket_source_init((belle_sip_source_t*)ctx, datafunc, ctx, dns_res_pollfd(ctx->R), BELLE_SIP_EVENT_READ | BELLE_SIP_EVENT_TIMEOUT, timeout);
	return 0;
}

typedef struct delayed_send {
	belle_sip_resolver_context_t *ctx;
	belle_sip_source_func_t datafunc;
	enum dns_type type;
	int timeout;
} delayed_send_t;

static int on_delayed_send_do(delayed_send_t *ds) {
	belle_sip_message("%s sending now", __FUNCTION__);
	_resolver_start_query(ds->ctx, ds->datafunc, ds->type, ds->timeout);
	belle_sip_object_unref(ds->ctx);
	belle_sip_free(ds);
	return FALSE;
}

209 210
static int resolver_start_query(belle_sip_resolver_context_t *ctx, belle_sip_source_func_t datafunc, enum dns_type type, int timeout) {
	struct dns_hints *(*hints)() = &dns_hints_local;
211 212 213 214
	struct dns_options *opts;
#ifndef HAVE_C99
	struct dns_options opts_st;
#endif
215 216 217 218 219 220 221 222 223 224 225
	int error;

	if (!ctx->name) return -1;

	if (resconf(ctx))
		resconf(ctx)->options.recurse = 0;
	else
		return -1;
	if (!hosts(ctx))
		return -1;

226 227 228 229 230 231 232
#ifdef HAVE_C99
	opts = dns_opts();
#else
	memset(&opts_st, 0, sizeof opts_st);
	opts = &opts_st;
#endif
	if (!(ctx->R = dns_res_open(ctx->resconf, ctx->hosts, dns_hints_mortal(hints(ctx->resconf, &error)), cache(ctx), opts, &error))) {
233 234 235 236
		belle_sip_error("%s dns_res_open error [%s]: %s", __FUNCTION__, ctx->name, dns_strerror(error));
		return -1;
	}

237
	if (ctx->stack->resolver_tx_delay > 0) {
238 239 240 241 242
		delayed_send_t *ds = belle_sip_new(delayed_send_t);
		ds->ctx = (belle_sip_resolver_context_t *)belle_sip_object_ref(ctx);
		ds->datafunc = datafunc;
		ds->type = type;
		ds->timeout = timeout;
243
		belle_sip_main_loop_add_timeout(ctx->stack->ml, (belle_sip_source_func_t)on_delayed_send_do, ds, ctx->stack->resolver_tx_delay);
244
		belle_sip_socket_source_init((belle_sip_source_t*)ctx, datafunc, ctx, dns_res_pollfd(ctx->R), BELLE_SIP_EVENT_READ | BELLE_SIP_EVENT_TIMEOUT, ctx->stack->resolver_tx_delay + 1000);
245
		belle_sip_message("%s DNS resolution delayed by %d ms", __FUNCTION__, ctx->stack->resolver_tx_delay);
246 247 248
		return 0;
	} else {
		return _resolver_start_query(ctx, datafunc, type, timeout);
249 250 251 252
	}
}


Simon Morlat's avatar
Simon Morlat committed
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281

int belle_sip_addrinfo_to_ip(const struct addrinfo *ai, char *ip, size_t ip_size, int *port){
	char serv[16];
	int err=getnameinfo(ai->ai_addr,ai->ai_addrlen,ip,ip_size,serv,sizeof(serv),NI_NUMERICHOST|NI_NUMERICSERV);
	if (err!=0){
		belle_sip_error("getnameinfo() error: %s",gai_strerror(err));
		strncpy(ip,"<bug!!>",ip_size);
	}
	if (port) *port=atoi(serv);
	return 0;
}

struct addrinfo * belle_sip_ip_address_to_addrinfo(const char *ipaddress, int port){
	struct addrinfo *res=NULL;
	struct addrinfo hints={0};
	char serv[10];
	int err;

	snprintf(serv,sizeof(serv),"%i",port);
	hints.ai_family=AF_UNSPEC;
	hints.ai_flags=AI_NUMERICSERV|AI_NUMERICHOST;
	err=getaddrinfo(ipaddress,serv,&hints,&res);
	if (err!=0){
		return NULL;
	}
	return res;
}


282
static void belle_sip_resolver_context_destroy(belle_sip_resolver_context_t *ctx){
283 284
	/* Do not free ctx->ai with freeaddrinfo(). Let the caller do it, otherwise
	   it will not be able to use it after the resolver has been destroyed. */
Simon Morlat's avatar
Simon Morlat committed
285 286
	if (ctx->name)
		belle_sip_free(ctx->name);
287 288 289 290 291 292
	if (ctx->R)
		dns_res_close(ctx->R);
	if (ctx->hosts)
		free(ctx->hosts);
	if (ctx->resconf)
		free(ctx->resconf);
Simon Morlat's avatar
Simon Morlat committed
293 294
}

295
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_resolver_context_t);
Simon Morlat's avatar
Simon Morlat committed
296
BELLE_SIP_INSTANCIATE_VPTR(belle_sip_resolver_context_t, belle_sip_source_t,belle_sip_resolver_context_destroy, NULL, NULL,FALSE);
Simon Morlat's avatar
Simon Morlat committed
297

298 299 300 301 302
unsigned long belle_sip_resolve(belle_sip_stack_t *stack, const char *name, int port, int family, belle_sip_resolver_callback_t cb , void *data, belle_sip_main_loop_t *ml) {
	struct addrinfo *res = belle_sip_ip_address_to_addrinfo(name, port);
	if (res == NULL) {
		/* Then perform asynchronous DNS query */
		belle_sip_resolver_context_t *ctx = belle_sip_object_new(belle_sip_resolver_context_t);
303
		ctx->stack = stack;
304 305 306 307 308 309 310
		ctx->cb_data = data;
		ctx->cb = cb;
		ctx->name = belle_sip_strdup(name);
		ctx->port = port;
		ctx->ai = NULL;
		if (family == 0) family = AF_UNSPEC;
		ctx->family = family;
311 312 313 314
		if (resolver_start_query(ctx,
				(belle_sip_source_func_t)resolver_process_a_data,
				(ctx->family == AF_INET6) ? DNS_T_AAAA : DNS_T_A,
				belle_sip_stack_get_dns_timeout(stack)) < 0) {
315 316 317
			belle_sip_object_unref(ctx);
			return 0;
		}
318

Ghislain MARY's avatar
Ghislain MARY committed
319
		/* The resolver context must never be removed manually from the main loop */
320
		belle_sip_main_loop_add_source(ml,(belle_sip_source_t*)ctx);
Ghislain MARY's avatar
Ghislain MARY committed
321
		belle_sip_object_unref(ctx);	/* The main loop has a ref on it */
322
		return ctx->source.id;
323 324
	} else {
		cb(data, name, res);
325 326
		return 0;
	}
Simon Morlat's avatar
Simon Morlat committed
327 328
}

329 330 331 332 333 334 335 336 337 338
void belle_sip_resolve_cancel(belle_sip_main_loop_t *ml, unsigned long id){
	if (id!=0){
		belle_sip_source_t *s=belle_sip_main_loop_find_source(ml,id);
		if (s){
			belle_sip_resolver_context_t *res=BELLE_SIP_RESOLVER_CONTEXT(s);
			res->cancelled=1;
		}
	}
}

339
void belle_sip_get_src_addr_for(const struct sockaddr *dest, socklen_t destlen, struct sockaddr *src, socklen_t *srclen){
340
	int af_type=dest->sa_family;
341 342
	int sock=socket(af_type,SOCK_DGRAM,IPPROTO_UDP);
	
343
	if (sock==(belle_sip_socket_t)-1){
344 345
		belle_sip_fatal("Could not create socket: %s",belle_sip_get_socket_error_string());
		goto fail;
346 347
	}
	if (connect(sock,dest,destlen)==-1){
348 349
		belle_sip_error("belle_sip_get_src_addr_for: connect() failed: %s",belle_sip_get_socket_error_string());
		goto fail;
350 351
	}
	if (getsockname(sock,src,srclen)==-1){
352 353 354 355 356 357 358 359 360 361 362 363
		belle_sip_error("belle_sip_get_src_addr_for: getsockname() failed: %s",belle_sip_get_socket_error_string());
		goto fail;
	}
	close_socket(sock);
	return;
fail:
	{
		struct addrinfo hints={0},*res=NULL;
		int err;
		hints.ai_family=af_type;
		err=getaddrinfo(af_type==AF_INET ? "0.0.0.0" : "::0","0",&hints,&res);
		if (err!=0) belle_sip_fatal("belle_sip_get_src_addr_for(): getaddrinfo failed: %s",belle_sip_get_socket_error_string_from_code(err));
364
		memcpy(src,res->ai_addr,MIN((size_t)*srclen,res->ai_addrlen));
365 366
		*srclen=res->ai_addrlen;
		freeaddrinfo(res);
367
	}
368
	if (sock==(belle_sip_socket_t)-1) close_socket(sock);
369
}