belle_sip_resolver.c 12.9 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
#include <stdlib.h>
22 23 24
#ifdef __APPLE__
#include "TargetConditionals.h"
#endif
25 26 27 28 29

#define DNS_EAGAIN  EAGAIN


static struct dns_resolv_conf *resconf(belle_sip_resolver_context_t *ctx) {
jehan's avatar
jehan committed
30
#if !_WIN32 && !HAVE_RESINIT
31
/*#if !_WIN32 && (!HAVE_RESINIT || !TARGET_OS_IPHONE)*/
32
	const char *path;
33
#endif
34 35 36 37 38 39 40 41 42 43
	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;
	}

44 45
#ifdef _WIN32
	error = dns_resconf_loadwin(ctx->resconf);
Ghislain MARY's avatar
Ghislain MARY committed
46 47 48
	if (error) {
		belle_sip_error("%s dns_resconf_loadwin error", __FUNCTION__);
	}
jehan's avatar
jehan committed
49
#elif ANDROID
Ghislain MARY's avatar
Ghislain MARY committed
50 51 52 53
	error = dns_resconf_loadandroid(ctx->resconf);
	if (error) {
		belle_sip_error("%s dns_resconf_loadandroid error", __FUNCTION__);
	}
jehan's avatar
jehan committed
54
#elif HAVE_RESINIT
55
/*#elif HAVE_RESINIT && TARGET_OS_IPHONE*/
jehan's avatar
jehan committed
56 57 58 59
	error = dns_resconf_loadfromresolv(ctx->resconf);
	if (error) {
		belle_sip_error("%s dns_resconf_loadfromresolv error", __FUNCTION__);
	}
60
#else
61 62 63 64 65 66 67 68 69 70
	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) {
71
		belle_sip_message("%s dns_nssconf_loadpath error [%s]: %s", __FUNCTION__, path, dns_strerror(error));
72
	}
Ghislain MARY's avatar
Ghislain MARY committed
73
#endif
jehan's avatar
jehan committed
74

75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
	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) {
97 98
	char host[NI_MAXHOST + 1];
	char service[NI_MAXSERV + 1];
99 100 101
	struct dns_packet *ans;
	struct dns_rr_i *I;
	int error;
102
	struct dns_rr_i dns_rr_it;
103 104 105

	if (revents & BELLE_SIP_EVENT_TIMEOUT) {
		belle_sip_error("%s timed-out", __FUNCTION__);
jehan's avatar
jehan committed
106
		ctx->cb(ctx->cb_data, ctx->name, NULL);
107 108 109 110 111 112 113 114 115 116 117 118 119
		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);
120 121
		memset(&dns_rr_it, 0, sizeof dns_rr_it);
		I = dns_rr_i_init(&dns_rr_it, ans);
122

123 124 125 126 127 128 129
		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;
				}
130 131
				if ((ctx->family == AF_INET6) && (rr.class == DNS_C_IN) && (rr.type == DNS_T_AAAA)) {
					struct dns_aaaa *aaaa = &any.aaaa;
132 133 134 135 136 137 138
					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;
139
					ctx->ai = belle_sip_ip_address_to_addrinfo(ctx->family, host, ctx->port);
140
					ctx->done=TRUE;
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
						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;
153
						ctx->ai = belle_sip_ip_address_to_addrinfo(ctx->family, host, ctx->port);
154
						ctx->done=TRUE;
155 156 157
						belle_sip_message("%s has address %s", ctx->name, host);
						break;
					}
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
				}
			}
		}
		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;
}

174 175 176
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;

177
	if (!ctx->stack->resolver_send_error) {
178 179 180 181 182
		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 */
183
		error = ctx->stack->resolver_send_error;
184 185 186 187 188 189
		belle_sip_error("%s dns_res_submit error [%s]: simulated error %d", __FUNCTION__, ctx->name, error);
	}
	if (error < 0) {
		return -1;
	}

190 191 192 193
	if ((*datafunc)(ctx, 0) == BELLE_SIP_CONTINUE) {
		/*only init source if res inprogress*/
		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);
	}
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
	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;
}

212 213
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;
214 215 216 217
	struct dns_options *opts;
#ifndef HAVE_C99
	struct dns_options opts_st;
#endif
218 219 220 221 222 223 224 225 226 227 228
	int error;

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

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

229 230
	memset(&opts_st, 0, sizeof opts_st);
	opts = &opts_st;
231

232
	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

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;
}

265
struct addrinfo * belle_sip_ip_address_to_addrinfo(int family, const char *ipaddress, int port){
Simon Morlat's avatar
Simon Morlat committed
266 267 268 269 270 271
	struct addrinfo *res=NULL;
	struct addrinfo hints={0};
	char serv[10];
	int err;

	snprintf(serv,sizeof(serv),"%i",port);
272
	hints.ai_family=family;
Simon Morlat's avatar
Simon Morlat committed
273
	hints.ai_flags=AI_NUMERICSERV|AI_NUMERICHOST;
274
	hints.ai_socktype=SOCK_STREAM; //not used but it's needed to specify it because otherwise getaddrinfo returns one struct addrinfo per socktype.
275 276 277
	
	if (family==AF_INET6) hints.ai_flags|=AI_V4MAPPED;
	
Simon Morlat's avatar
Simon Morlat committed
278 279 280 281 282 283 284 285
	err=getaddrinfo(ipaddress,serv,&hints,&res);
	if (err!=0){
		return NULL;
	}
	return res;
}


286
static void belle_sip_resolver_context_destroy(belle_sip_resolver_context_t *ctx){
287 288
	/* 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
289 290
	if (ctx->name)
		belle_sip_free(ctx->name);
291 292
	if (ctx->R)
		dns_res_close(ctx->R);
293 294 295
	if (ctx->hosts) {
		dns_hosts_close(ctx->hosts);
	}
296 297
	if (ctx->resconf)
		free(ctx->resconf);
Simon Morlat's avatar
Simon Morlat committed
298 299
}

300
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_resolver_context_t);
Simon Morlat's avatar
Simon Morlat committed
301
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
302

303
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) {
304
	struct addrinfo *res = belle_sip_ip_address_to_addrinfo(family,name, port);
305 306 307
	if (res == NULL) {
		/* Then perform asynchronous DNS query */
		belle_sip_resolver_context_t *ctx = belle_sip_object_new(belle_sip_resolver_context_t);
308
		ctx->stack = stack;
309 310 311 312 313 314 315
		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;
316 317 318 319
		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) {
320 321 322
			belle_sip_object_unref(ctx);
			return 0;
		}
323 324 325 326 327 328 329 330
		if (ctx->done == FALSE) {
			/* The resolver context must never be removed manually from the main loop */
			belle_sip_main_loop_add_source(ml,(belle_sip_source_t*)ctx);
			belle_sip_object_unref(ctx);	/* The main loop has a ref on it */
			return ctx->source.id;
		} else {
			return 0; /*resolution done synchronously*/
		}
331 332
	} else {
		cb(data, name, res);
333 334
		return 0;
	}
Simon Morlat's avatar
Simon Morlat committed
335 336
}

337 338 339 340 341 342 343 344 345 346
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;
		}
	}
}

347 348

void belle_sip_get_src_addr_for(const struct sockaddr *dest, socklen_t destlen, struct sockaddr *src, socklen_t *srclen, int local_port){
349
	int af_type=dest->sa_family;
350 351
	int sock=socket(af_type,SOCK_DGRAM,IPPROTO_UDP);
	
352
	if (sock==(belle_sip_socket_t)-1){
353 354
		belle_sip_fatal("Could not create socket: %s",belle_sip_get_socket_error_string());
		goto fail;
355 356
	}
	if (connect(sock,dest,destlen)==-1){
357 358
		belle_sip_error("belle_sip_get_src_addr_for: connect() failed: %s",belle_sip_get_socket_error_string());
		goto fail;
359 360
	}
	if (getsockname(sock,src,srclen)==-1){
361 362 363
		belle_sip_error("belle_sip_get_src_addr_for: getsockname() failed: %s",belle_sip_get_socket_error_string());
		goto fail;
	}
364 365 366 367 368 369 370 371 372
	
	if (af_type==AF_INET6){
		struct sockaddr_in6 *sin6=(struct sockaddr_in6*)src;
		sin6->sin6_port=htons(local_port);
	}else{
		struct sockaddr_in *sin=(struct sockaddr_in*)src;
		sin->sin_port=htons(local_port);
	}
	
373 374 375 376 377 378 379 380 381
	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));
382
		memcpy(src,res->ai_addr,MIN((size_t)*srclen,res->ai_addrlen));
383 384
		*srclen=res->ai_addrlen;
		freeaddrinfo(res);
385
	}
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
	if (sock!=(belle_sip_socket_t)-1) close_socket(sock);
}

#ifndef IN6_GET_ADDR_V4MAPPED
#define IN6_GET_ADDR_V4MAPPED(sin6_addr)	*(unsigned int*)((unsigned char*)(sin6_addr)+12)
#endif


void belle_sip_address_remove_v4_mapping(const struct sockaddr *v6, struct sockaddr *result, socklen_t *result_len){
	if (v6->sa_family==AF_INET6){
		struct sockaddr_in6 *in6=(struct sockaddr_in6*)v6;
		
		if (IN6_IS_ADDR_V4MAPPED(&in6->sin6_addr)){
			struct sockaddr_in *in=(struct sockaddr_in*)result;
			result->sa_family=AF_INET;
			in->sin_addr.s_addr = IN6_GET_ADDR_V4MAPPED(&in6->sin6_addr);
			in->sin_port=in6->sin6_port;
			*result_len=sizeof(struct sockaddr_in);
		}else{
			if (v6!=result) memcpy(result,v6,sizeof(struct sockaddr_in6));
			*result_len=sizeof(struct sockaddr_in6);
		}
		
	}else{
		*result_len=sizeof(struct sockaddr_in);
		if (v6!=result) memcpy(result,v6,sizeof(struct sockaddr_in));
	}
413
}
414 415 416