xref: /openbsd-src/usr.sbin/lpd/resolver.c (revision c0101cced8fb506a486d6adae307f795bcad599f)
1*c0101cceSeric /*	$OpenBSD: resolver.c,v 1.4 2019/04/06 10:35:48 eric Exp $	*/
23b188dabSeric 
33b188dabSeric /*
4db7b06acSeric  * Copyright (c) 2017-2018 Eric Faurot <eric@openbsd.org>
53b188dabSeric  *
63b188dabSeric  * Permission to use, copy, modify, and distribute this software for any
73b188dabSeric  * purpose with or without fee is hereby granted, provided that the above
83b188dabSeric  * copyright notice and this permission notice appear in all copies.
93b188dabSeric  *
103b188dabSeric  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
113b188dabSeric  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
123b188dabSeric  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
133b188dabSeric  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
143b188dabSeric  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
153b188dabSeric  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
163b188dabSeric  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
173b188dabSeric  */
183b188dabSeric 
193b188dabSeric #include <sys/types.h>
203b188dabSeric #include <sys/socket.h>
21db7b06acSeric #include <sys/tree.h>
22db7b06acSeric #include <sys/queue.h>
233b188dabSeric #include <netinet/in.h>
243b188dabSeric 
253b188dabSeric #include <asr.h>
263b188dabSeric #include <ctype.h>
273b188dabSeric #include <errno.h>
28db7b06acSeric #include <imsg.h>
293b188dabSeric #include <limits.h>
303b188dabSeric #include <stdarg.h>
31db7b06acSeric #include <stdio.h>
323b188dabSeric #include <stdlib.h>
333b188dabSeric #include <string.h>
343b188dabSeric #include <unistd.h>
353b188dabSeric 
363b188dabSeric #include "lpd.h"
373b188dabSeric 
383b188dabSeric #include "log.h"
393b188dabSeric #include "proc.h"
403b188dabSeric 
41db7b06acSeric #define p_resolver p_engine
42db7b06acSeric 
433b188dabSeric struct request {
443b188dabSeric 	SPLAY_ENTRY(request)	 entry;
453b188dabSeric 	uint32_t		 id;
463b188dabSeric 	void			(*cb_ai)(void *, int, struct addrinfo *);
473b188dabSeric 	void			(*cb_ni)(void *, int, const char *, const char *);
483b188dabSeric 	void			*arg;
493b188dabSeric 	struct addrinfo		*ai;
503b188dabSeric };
513b188dabSeric 
523b188dabSeric struct session {
533b188dabSeric 	uint32_t	 reqid;
543b188dabSeric 	struct imsgproc	*proc;
553b188dabSeric 	char		*host;
563b188dabSeric 	char		*serv;
573b188dabSeric };
583b188dabSeric 
593b188dabSeric SPLAY_HEAD(reqtree, request);
603b188dabSeric 
613b188dabSeric static void resolver_init(void);
623b188dabSeric static void resolver_getaddrinfo_cb(struct asr_result *, void *);
633b188dabSeric static void resolver_getnameinfo_cb(struct asr_result *, void *);
643b188dabSeric 
653b188dabSeric static int request_cmp(struct request *, struct request *);
663b188dabSeric SPLAY_PROTOTYPE(reqtree, request, entry, request_cmp);
673b188dabSeric 
683b188dabSeric static struct reqtree reqs;
693b188dabSeric 
703b188dabSeric void
resolver_getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,void (* cb)(void *,int,struct addrinfo *),void * arg)713b188dabSeric resolver_getaddrinfo(const char *hostname, const char *servname,
723b188dabSeric     const struct addrinfo *hints, void (*cb)(void *, int, struct addrinfo *),
733b188dabSeric     void *arg)
743b188dabSeric {
753b188dabSeric 	struct request *req;
763b188dabSeric 
773b188dabSeric 	resolver_init();
783b188dabSeric 
793b188dabSeric 	req = calloc(1, sizeof(*req));
803b188dabSeric 	if (req == NULL) {
813b188dabSeric 		cb(arg, EAI_MEMORY, NULL);
823b188dabSeric 		return;
833b188dabSeric 	}
843b188dabSeric 
853b188dabSeric 	while (req->id == 0 || SPLAY_FIND(reqtree, &reqs, req))
863b188dabSeric 		req->id = arc4random();
873b188dabSeric 	req->cb_ai = cb;
883b188dabSeric 	req->arg = arg;
893b188dabSeric 
903b188dabSeric 	SPLAY_INSERT(reqtree, &reqs, req);
913b188dabSeric 
92db7b06acSeric 	m_create(p_resolver, IMSG_GETADDRINFO, req->id, 0, -1);
93db7b06acSeric 	m_add_int(p_resolver, hints ? hints->ai_flags : 0);
94db7b06acSeric 	m_add_int(p_resolver, hints ? hints->ai_family : 0);
95db7b06acSeric 	m_add_int(p_resolver, hints ? hints->ai_socktype : 0);
96db7b06acSeric 	m_add_int(p_resolver, hints ? hints->ai_protocol : 0);
97db7b06acSeric 	m_add_string(p_resolver, hostname);
989d855d3dSeric 	m_add_string(p_resolver, servname);
99db7b06acSeric 	m_close(p_resolver);
1003b188dabSeric }
1013b188dabSeric 
1023b188dabSeric void
resolver_getnameinfo(const struct sockaddr * sa,int flags,void (* cb)(void *,int,const char *,const char *),void * arg)1033b188dabSeric resolver_getnameinfo(const struct sockaddr *sa, int flags,
1043b188dabSeric     void(*cb)(void *, int, const char *, const char *), void *arg)
1053b188dabSeric {
1063b188dabSeric 	struct request *req;
1073b188dabSeric 
1083b188dabSeric 	resolver_init();
1093b188dabSeric 
1103b188dabSeric 	req = calloc(1, sizeof(*req));
1113b188dabSeric 	if (req == NULL) {
1123b188dabSeric 		cb(arg, EAI_MEMORY, NULL, NULL);
1133b188dabSeric 		return;
1143b188dabSeric 	}
1153b188dabSeric 
1163b188dabSeric 	while (req->id == 0 || SPLAY_FIND(reqtree, &reqs, req))
1173b188dabSeric 		req->id = arc4random();
1183b188dabSeric 	req->cb_ni = cb;
1193b188dabSeric 	req->arg = arg;
1203b188dabSeric 
121db7b06acSeric 	SPLAY_INSERT(reqtree, &reqs, req);
122db7b06acSeric 
123db7b06acSeric 	m_create(p_resolver, IMSG_GETNAMEINFO, req->id, 0, -1);
124db7b06acSeric 	m_add_sockaddr(p_resolver, sa);
125db7b06acSeric 	m_add_int(p_resolver, flags);
126db7b06acSeric 	m_close(p_resolver);
1273b188dabSeric }
1283b188dabSeric 
1293b188dabSeric void
resolver_dispatch_request(struct imsgproc * proc,struct imsg * imsg)1303b188dabSeric resolver_dispatch_request(struct imsgproc *proc, struct imsg *imsg)
1313b188dabSeric {
1323b188dabSeric 	const char *hostname, *servname;
1333b188dabSeric 	struct session *s;
1343b188dabSeric 	struct asr_query *q;
1353b188dabSeric 	struct addrinfo hints;
1363b188dabSeric 	struct sockaddr_storage ss;
1373b188dabSeric 	struct sockaddr *sa;
1383b188dabSeric 	uint32_t reqid;
1393b188dabSeric 	int flags, save_errno;
1403b188dabSeric 
1413b188dabSeric 	reqid = imsg->hdr.peerid;
1423b188dabSeric 
1433b188dabSeric 	switch (imsg->hdr.type) {
1443b188dabSeric 
145db7b06acSeric 	case IMSG_GETADDRINFO:
1463b188dabSeric 		servname = NULL;
1473b188dabSeric 		memset(&hints, 0 , sizeof(hints));
1483b188dabSeric 		m_get_int(proc, &hints.ai_flags);
1493b188dabSeric 		m_get_int(proc, &hints.ai_family);
1503b188dabSeric 		m_get_int(proc, &hints.ai_socktype);
1513b188dabSeric 		m_get_int(proc, &hints.ai_protocol);
1523b188dabSeric 		m_get_string(proc, &hostname);
1533b188dabSeric 		m_get_string(proc, &servname);
1543b188dabSeric 		m_end(proc);
1553b188dabSeric 
1563b188dabSeric 		s = NULL;
1573b188dabSeric 		q = NULL;
1583b188dabSeric 		if ((s = calloc(1, sizeof(*s))) &&
1593b188dabSeric 		    (q = getaddrinfo_async(hostname, servname, &hints, NULL)) &&
1603b188dabSeric 		    (event_asr_run(q, resolver_getaddrinfo_cb, s))) {
1613b188dabSeric 			s->reqid = reqid;
1623b188dabSeric 			s->proc = proc;
1633b188dabSeric 			break;
1643b188dabSeric 		}
1653b188dabSeric 		save_errno = errno;
1663b188dabSeric 
1673b188dabSeric 		if (q)
1683b188dabSeric 			asr_abort(q);
1693b188dabSeric 		if (s)
1703b188dabSeric 			free(s);
1713b188dabSeric 
172db7b06acSeric 		m_create(proc, IMSG_GETADDRINFO_END, reqid, 0, -1);
1733b188dabSeric 		m_add_int(proc, EAI_SYSTEM);
1743b188dabSeric 		m_add_int(proc, save_errno);
1753b188dabSeric 		m_close(proc);
1763b188dabSeric 		break;
1773b188dabSeric 
178db7b06acSeric 	case IMSG_GETNAMEINFO:
1793b188dabSeric 		sa = (struct sockaddr*)&ss;
1803b188dabSeric 		m_get_sockaddr(proc, sa);
1813b188dabSeric 		m_get_int(proc, &flags);
1823b188dabSeric 		m_end(proc);
1833b188dabSeric 
1843b188dabSeric 		s = NULL;
1853b188dabSeric 		q = NULL;
1863b188dabSeric 		if ((s = calloc(1, sizeof(*s))) &&
1873b188dabSeric 		    (s->host = malloc(NI_MAXHOST)) &&
1883b188dabSeric 		    (s->serv = malloc(NI_MAXSERV)) &&
1893b188dabSeric 		    (q = getnameinfo_async(sa, sa->sa_len, s->host, NI_MAXHOST,
1903b188dabSeric 			s->serv, NI_MAXSERV, flags, NULL)) &&
1913b188dabSeric 		    (event_asr_run(q, resolver_getnameinfo_cb, s))) {
1923b188dabSeric 			s->reqid = reqid;
1933b188dabSeric 			s->proc = proc;
1943b188dabSeric 			break;
1953b188dabSeric 		}
1963b188dabSeric 		save_errno = errno;
1973b188dabSeric 
1983b188dabSeric 		if (q)
1993b188dabSeric 			asr_abort(q);
2003b188dabSeric 		if (s) {
2013b188dabSeric 			free(s->host);
2023b188dabSeric 			free(s->serv);
2033b188dabSeric 			free(s);
2043b188dabSeric 		}
2053b188dabSeric 
206db7b06acSeric 		m_create(proc, IMSG_GETNAMEINFO, reqid, 0, -1);
2073b188dabSeric 		m_add_int(proc, EAI_SYSTEM);
2083b188dabSeric 		m_add_int(proc, save_errno);
2099d855d3dSeric 		m_add_string(proc, NULL);
2109d855d3dSeric 		m_add_string(proc, NULL);
2113b188dabSeric 		m_close(proc);
2123b188dabSeric 		break;
2133b188dabSeric 
2143b188dabSeric 	default:
2153b188dabSeric 		fatalx("%s: %s", __func__, log_fmt_imsgtype(imsg->hdr.type));
2163b188dabSeric 	}
2173b188dabSeric }
2183b188dabSeric 
2193b188dabSeric void
resolver_dispatch_result(struct imsgproc * proc,struct imsg * imsg)2203b188dabSeric resolver_dispatch_result(struct imsgproc *proc, struct imsg *imsg)
2213b188dabSeric {
2223b188dabSeric 	struct request key, *req;
2233b188dabSeric 	struct sockaddr_storage ss;
2243b188dabSeric 	struct addrinfo *ai;
2253b188dabSeric 	const char *cname, *host, *serv;
2263b188dabSeric 	int gai_errno;
2273b188dabSeric 
2283b188dabSeric 	key.id = imsg->hdr.peerid;
2293b188dabSeric 	req = SPLAY_FIND(reqtree, &reqs, &key);
2303b188dabSeric 	if (req == NULL)
2313b188dabSeric 		fatalx("%s: unknown request %08x", __func__, imsg->hdr.peerid);
2323b188dabSeric 
2333b188dabSeric 	switch (imsg->hdr.type) {
2343b188dabSeric 
235db7b06acSeric 	case IMSG_GETADDRINFO:
2363b188dabSeric 		ai = calloc(1, sizeof(*ai));
2373b188dabSeric 		if (ai == NULL) {
2383b188dabSeric 			log_warn("%s: calloc", __func__);
2393b188dabSeric 			break;
2403b188dabSeric 		}
2413b188dabSeric 		m_get_int(proc, &ai->ai_flags);
2423b188dabSeric 		m_get_int(proc, &ai->ai_family);
2433b188dabSeric 		m_get_int(proc, &ai->ai_socktype);
2443b188dabSeric 		m_get_int(proc, &ai->ai_protocol);
2453b188dabSeric 		m_get_sockaddr(proc, (struct sockaddr *)&ss);
2463b188dabSeric 		m_get_string(proc, &cname);
2473b188dabSeric 		m_end(proc);
2483b188dabSeric 
2493b188dabSeric 		ai->ai_addr = malloc(ss.ss_len);
2503b188dabSeric 		if (ai->ai_addr == NULL) {
2513b188dabSeric 			log_warn("%s: malloc", __func__);
2523b188dabSeric 			free(ai);
2533b188dabSeric 			break;
2543b188dabSeric 		}
2553b188dabSeric 
2563b188dabSeric 		memmove(ai->ai_addr, &ss, ss.ss_len);
2573b188dabSeric 
2589d855d3dSeric 		if (cname) {
2593b188dabSeric 			ai->ai_canonname = strdup(cname);
2603b188dabSeric 			if (ai->ai_canonname == NULL) {
2613b188dabSeric 				log_warn("%s: strdup", __func__);
2623b188dabSeric 				free(ai->ai_addr);
2633b188dabSeric 				free(ai);
2643b188dabSeric 				break;
2653b188dabSeric 			}
2663b188dabSeric 		}
2673b188dabSeric 
2683b188dabSeric 		ai->ai_next = req->ai;
2693b188dabSeric 		req->ai = ai;
2703b188dabSeric 		break;
2713b188dabSeric 
272db7b06acSeric 	case IMSG_GETADDRINFO_END:
2733b188dabSeric 		m_get_int(proc, &gai_errno);
2743b188dabSeric 		m_get_int(proc, &errno);
2753b188dabSeric 		m_end(proc);
2763b188dabSeric 
2773b188dabSeric 		SPLAY_REMOVE(reqtree, &reqs, req);
2783b188dabSeric 		req->cb_ai(req->arg, gai_errno, req->ai);
2793b188dabSeric 		free(req);
2803b188dabSeric 		break;
2813b188dabSeric 
282db7b06acSeric 	case IMSG_GETNAMEINFO:
2833b188dabSeric 		m_get_int(proc, &gai_errno);
2843b188dabSeric 		m_get_int(proc, &errno);
2853b188dabSeric 		m_get_string(proc, &host);
2863b188dabSeric 		m_get_string(proc, &serv);
2873b188dabSeric 		m_end(proc);
2883b188dabSeric 
2893b188dabSeric 		SPLAY_REMOVE(reqtree, &reqs, req);
2909d855d3dSeric 		req->cb_ni(req->arg, gai_errno, host, serv);
2913b188dabSeric 		free(req);
2923b188dabSeric 		break;
2933b188dabSeric 	}
2943b188dabSeric }
2953b188dabSeric 
2963b188dabSeric static void
resolver_init(void)2973b188dabSeric resolver_init(void)
2983b188dabSeric {
2993b188dabSeric 	static int init = 0;
3003b188dabSeric 
3013b188dabSeric 	if (init == 0) {
3023b188dabSeric 		SPLAY_INIT(&reqs);
3033b188dabSeric 		init = 1;
3043b188dabSeric 	}
3053b188dabSeric }
3063b188dabSeric 
3073b188dabSeric static void
resolver_getaddrinfo_cb(struct asr_result * ar,void * arg)3083b188dabSeric resolver_getaddrinfo_cb(struct asr_result *ar, void *arg)
3093b188dabSeric {
3103b188dabSeric 	struct session *s = arg;
3113b188dabSeric 	struct addrinfo *ai;
3123b188dabSeric 
3133b188dabSeric 	for (ai = ar->ar_addrinfo; ai; ai = ai->ai_next) {
314db7b06acSeric 		m_create(s->proc, IMSG_GETADDRINFO, s->reqid, 0, -1);
3153b188dabSeric 		m_add_int(s->proc, ai->ai_flags);
3163b188dabSeric 		m_add_int(s->proc, ai->ai_family);
3173b188dabSeric 		m_add_int(s->proc, ai->ai_socktype);
3183b188dabSeric 		m_add_int(s->proc, ai->ai_protocol);
3193b188dabSeric 		m_add_sockaddr(s->proc, ai->ai_addr);
3209d855d3dSeric 		m_add_string(s->proc, ai->ai_canonname);
3213b188dabSeric 		m_close(s->proc);
3223b188dabSeric 	}
3233b188dabSeric 
324db7b06acSeric 	m_create(s->proc, IMSG_GETADDRINFO_END, s->reqid, 0, -1);
3253b188dabSeric 	m_add_int(s->proc, ar->ar_gai_errno);
3263b188dabSeric 	m_add_int(s->proc, ar->ar_errno);
3273b188dabSeric 	m_close(s->proc);
3283b188dabSeric 
329*c0101cceSeric 	if (ar->ar_addrinfo)
3303b188dabSeric 		freeaddrinfo(ar->ar_addrinfo);
3313b188dabSeric 	free(s);
3323b188dabSeric }
3333b188dabSeric 
3343b188dabSeric static void
resolver_getnameinfo_cb(struct asr_result * ar,void * arg)3353b188dabSeric resolver_getnameinfo_cb(struct asr_result *ar, void *arg)
3363b188dabSeric {
3373b188dabSeric 	struct session *s = arg;
3383b188dabSeric 
339db7b06acSeric 	m_create(s->proc, IMSG_GETNAMEINFO, s->reqid, 0, -1);
3403b188dabSeric 	m_add_int(s->proc, ar->ar_gai_errno);
3413b188dabSeric 	m_add_int(s->proc, ar->ar_errno);
3429d855d3dSeric 	m_add_string(s->proc, ar->ar_gai_errno ? NULL : s->host);
3439d855d3dSeric 	m_add_string(s->proc, ar->ar_gai_errno ? NULL : s->serv);
3443b188dabSeric 	m_close(s->proc);
3453b188dabSeric 
3463b188dabSeric 	free(s->host);
3473b188dabSeric 	free(s->serv);
3483b188dabSeric 	free(s);
3493b188dabSeric }
3503b188dabSeric 
3513b188dabSeric static int
request_cmp(struct request * a,struct request * b)3523b188dabSeric request_cmp(struct request *a, struct request *b)
3533b188dabSeric {
3543b188dabSeric 	if (a->id < b->id)
355db7b06acSeric 		return -1;
3563b188dabSeric 	if (a->id > b->id)
357db7b06acSeric 		return 1;
358db7b06acSeric 	return 0;
3593b188dabSeric }
3603b188dabSeric 
3613b188dabSeric SPLAY_GENERATE(reqtree, request, entry, request_cmp);
362