belle_sip_resolver.c 11.2 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) {
28
#ifndef _WIN32
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 46 47 48 49 50 51
	if (error) {
		belle_sip_error("%s dns_resconf_loadwin error", __FUNCTION__);
	}
#else
#ifdef ANDROID
	error = dns_resconf_loadandroid(ctx->resconf);
	if (error) {
		belle_sip_error("%s dns_resconf_loadandroid error", __FUNCTION__);
	}
52
#else
53 54 55 56 57 58 59 60 61 62
	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) {
63
		belle_sip_message("%s dns_nssconf_loadpath error [%s]: %s", __FUNCTION__, path, dns_strerror(error));
64
	}
Ghislain MARY's avatar
Ghislain MARY committed
65
#endif
66
#endif
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

	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) {
90 91
	char host[NI_MAXHOST + 1];
	char service[NI_MAXSERV + 1];
92 93 94
	struct dns_packet *ans;
	struct dns_rr_i *I;
	int error;
95 96 97
#ifndef HAVE_C99
	struct dns_rr_i dns_rr_it;
#endif
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113

	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);
114
#ifdef HAVE_C99
115
		I = dns_rr_i_new(ans, .section = 0);
116 117 118 119
#else
		memset(&dns_rr_it, 0, sizeof dns_rr_it);
		I = dns_rr_i_init(&dns_rr_it, ans);
#endif
120 121 122 123 124 125 126
		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;
				}
127 128
				if ((ctx->family == AF_INET6) && (rr.class == DNS_C_IN) && (rr.type == DNS_T_AAAA)) {
					struct dns_aaaa *aaaa = &any.aaaa;
129 130 131 132 133 134 135 136
					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);
137 138
					belle_sip_message("%s has address %s", ctx->name, host);
					break;
139 140 141
				} else {
					if ((rr.class == DNS_C_IN) && (rr.type == DNS_T_A)) {
						struct dns_a *a = &any.a;
142 143 144 145 146 147 148 149
						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);
150 151 152
						belle_sip_message("%s has address %s", ctx->name, host);
						break;
					}
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
				}
			}
		}
		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;
}

169 170 171
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;

172
	if (!ctx->stack->resolver_send_error) {
173 174 175 176 177
		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 */
178
		error = ctx->stack->resolver_send_error;
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
		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;
}

205 206
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;
207 208 209 210
	struct dns_options *opts;
#ifndef HAVE_C99
	struct dns_options opts_st;
#endif
211 212 213 214 215 216 217 218 219 220 221
	int error;

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

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

222 223 224 225 226 227 228
#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))) {
229 230 231 232
		belle_sip_error("%s dns_res_open error [%s]: %s", __FUNCTION__, ctx->name, dns_strerror(error));
		return -1;
	}

233
	if (ctx->stack->resolver_tx_delay > 0) {
234 235 236 237 238
		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;
239
		belle_sip_main_loop_add_timeout(ctx->stack->ml, (belle_sip_source_func_t)on_delayed_send_do, ds, ctx->stack->resolver_tx_delay);
240
		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);
241
		belle_sip_message("%s DNS resolution delayed by %d ms", __FUNCTION__, ctx->stack->resolver_tx_delay);
242 243 244
		return 0;
	} else {
		return _resolver_start_query(ctx, datafunc, type, timeout);
245 246 247 248
	}
}


Simon Morlat's avatar
Simon Morlat committed
249 250 251 252 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

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


278
static void belle_sip_resolver_context_destroy(belle_sip_resolver_context_t *ctx){
279 280
	/* 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
281 282
	if (ctx->name)
		belle_sip_free(ctx->name);
283 284 285 286 287 288
	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
289 290
}

291
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_resolver_context_t);
Simon Morlat's avatar
Simon Morlat committed
292
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
293

294 295 296 297 298
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);
299
		ctx->stack = stack;
300 301 302 303 304 305 306
		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;
307 308 309 310
		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) {
311 312 313
			belle_sip_object_unref(ctx);
			return 0;
		}
314

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

325 326 327 328 329 330 331 332 333 334
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;
		}
	}
}

335
void belle_sip_get_src_addr_for(const struct sockaddr *dest, socklen_t destlen, struct sockaddr *src, socklen_t *srclen){
336
	int af_type=dest->sa_family;
337 338
	int sock=socket(af_type,SOCK_DGRAM,IPPROTO_UDP);
	
339
	if (sock==(belle_sip_socket_t)-1){
340 341
		belle_sip_fatal("Could not create socket: %s",belle_sip_get_socket_error_string());
		goto fail;
342 343
	}
	if (connect(sock,dest,destlen)==-1){
344 345
		belle_sip_error("belle_sip_get_src_addr_for: connect() failed: %s",belle_sip_get_socket_error_string());
		goto fail;
346 347
	}
	if (getsockname(sock,src,srclen)==-1){
348 349 350 351 352 353 354 355 356 357 358 359
		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));
360
		memcpy(src,res->ai_addr,MIN((size_t)*srclen,res->ai_addrlen));
361 362
		*srclen=res->ai_addrlen;
		freeaddrinfo(res);
363
	}
364
	if (sock==(belle_sip_socket_t)-1) close_socket(sock);
365
}