xref: /openbsd-src/usr.sbin/smtpd/resolver.c (revision d3140113bef2b86d3af61dd20c05a8630ff966c2)
1*d3140113Seric /*	$OpenBSD: resolver.c,v 1.7 2021/06/14 17:58:16 eric Exp $	*/
201eba458Seric 
301eba458Seric /*
401eba458Seric  * Copyright (c) 2017-2018 Eric Faurot <eric@openbsd.org>
501eba458Seric  *
601eba458Seric  * Permission to use, copy, modify, and distribute this software for any
701eba458Seric  * purpose with or without fee is hereby granted, provided that the above
801eba458Seric  * copyright notice and this permission notice appear in all copies.
901eba458Seric  *
1001eba458Seric  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1101eba458Seric  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1201eba458Seric  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1301eba458Seric  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1401eba458Seric  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1501eba458Seric  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1601eba458Seric  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1701eba458Seric  */
1801eba458Seric 
1901eba458Seric #include <sys/socket.h>
20*d3140113Seric 
2101eba458Seric #include <netinet/in.h>
2201eba458Seric 
2301eba458Seric #include <asr.h>
2401eba458Seric #include <errno.h>
2501eba458Seric #include <stdlib.h>
2601eba458Seric #include <string.h>
2701eba458Seric 
2801eba458Seric #include "smtpd.h"
2901eba458Seric #include "log.h"
3001eba458Seric 
3101eba458Seric #define p_resolver p_lka
3201eba458Seric 
3301eba458Seric struct request {
3401eba458Seric 	SPLAY_ENTRY(request)	 entry;
3501eba458Seric 	uint32_t		 id;
3601eba458Seric 	void			(*cb_ai)(void *, int, struct addrinfo *);
3701eba458Seric 	void			(*cb_ni)(void *, int, const char *, const char *);
3801361951Seric 	void			(*cb_res)(void *, int, int, int, const void *, int);
3901eba458Seric 	void			*arg;
4001eba458Seric 	struct addrinfo		*ai;
4101eba458Seric };
4201eba458Seric 
4301eba458Seric struct session {
4401eba458Seric 	uint32_t	 reqid;
4501eba458Seric 	struct mproc	*proc;
4601eba458Seric 	char		*host;
4701eba458Seric 	char		*serv;
4801eba458Seric };
4901eba458Seric 
5001eba458Seric SPLAY_HEAD(reqtree, request);
5101eba458Seric 
5201eba458Seric static void resolver_init(void);
5301eba458Seric static void resolver_getaddrinfo_cb(struct asr_result *, void *);
5401eba458Seric static void resolver_getnameinfo_cb(struct asr_result *, void *);
5501361951Seric static void resolver_res_query_cb(struct asr_result *, void *);
5601eba458Seric 
5701eba458Seric static int request_cmp(struct request *, struct request *);
5801eba458Seric SPLAY_PROTOTYPE(reqtree, request, entry, request_cmp);
5901eba458Seric 
6001eba458Seric static struct reqtree reqs;
6101eba458Seric 
6201eba458Seric void
resolver_getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,void (* cb)(void *,int,struct addrinfo *),void * arg)6301eba458Seric resolver_getaddrinfo(const char *hostname, const char *servname,
6401eba458Seric     const struct addrinfo *hints, void (*cb)(void *, int, struct addrinfo *),
6501eba458Seric     void *arg)
6601eba458Seric {
6701eba458Seric 	struct request *req;
6801eba458Seric 
6901eba458Seric 	resolver_init();
7001eba458Seric 
7101eba458Seric 	req = calloc(1, sizeof(*req));
7201eba458Seric 	if (req == NULL) {
7301eba458Seric 		cb(arg, EAI_MEMORY, NULL);
7401eba458Seric 		return;
7501eba458Seric 	}
7601eba458Seric 
7701eba458Seric 	while (req->id == 0 || SPLAY_FIND(reqtree, &reqs, req))
7801eba458Seric 		req->id = arc4random();
7901eba458Seric 	req->cb_ai = cb;
8001eba458Seric 	req->arg = arg;
8101eba458Seric 
8201eba458Seric 	SPLAY_INSERT(reqtree, &reqs, req);
8301eba458Seric 
8401eba458Seric 	m_create(p_resolver, IMSG_GETADDRINFO, req->id, 0, -1);
8501eba458Seric 	m_add_int(p_resolver, hints ? hints->ai_flags : 0);
8601eba458Seric 	m_add_int(p_resolver, hints ? hints->ai_family : 0);
8701eba458Seric 	m_add_int(p_resolver, hints ? hints->ai_socktype : 0);
8801eba458Seric 	m_add_int(p_resolver, hints ? hints->ai_protocol : 0);
8901eba458Seric 	m_add_string(p_resolver, hostname);
902c59994aSeric 	m_add_string(p_resolver, servname);
9101eba458Seric 	m_close(p_resolver);
9201eba458Seric }
9301eba458Seric 
9401eba458Seric void
resolver_getnameinfo(const struct sockaddr * sa,int flags,void (* cb)(void *,int,const char *,const char *),void * arg)9501eba458Seric resolver_getnameinfo(const struct sockaddr *sa, int flags,
9601eba458Seric     void(*cb)(void *, int, const char *, const char *), void *arg)
9701eba458Seric {
9801eba458Seric 	struct request *req;
9901eba458Seric 
10001eba458Seric 	resolver_init();
10101eba458Seric 
10201eba458Seric 	req = calloc(1, sizeof(*req));
10301eba458Seric 	if (req == NULL) {
10401eba458Seric 		cb(arg, EAI_MEMORY, NULL, NULL);
10501eba458Seric 		return;
10601eba458Seric 	}
10701eba458Seric 
10801eba458Seric 	while (req->id == 0 || SPLAY_FIND(reqtree, &reqs, req))
10901eba458Seric 		req->id = arc4random();
11001eba458Seric 	req->cb_ni = cb;
11101eba458Seric 	req->arg = arg;
11201eba458Seric 
11301eba458Seric 	SPLAY_INSERT(reqtree, &reqs, req);
11401eba458Seric 
11501eba458Seric 	m_create(p_resolver, IMSG_GETNAMEINFO, req->id, 0, -1);
11601eba458Seric 	m_add_sockaddr(p_resolver, sa);
11701eba458Seric 	m_add_int(p_resolver, flags);
11801eba458Seric 	m_close(p_resolver);
11901eba458Seric }
12001eba458Seric 
12101eba458Seric void
resolver_res_query(const char * dname,int class,int type,void (* cb)(void *,int,int,int,const void *,int),void * arg)12201361951Seric resolver_res_query(const char *dname, int class, int type,
12301361951Seric     void (*cb)(void *, int, int, int, const void *, int), void *arg)
12401361951Seric {
12501361951Seric 	struct request *req;
12601361951Seric 
12701361951Seric 	resolver_init();
12801361951Seric 
12901361951Seric 	req = calloc(1, sizeof(*req));
13001361951Seric 	if (req == NULL) {
13101361951Seric 		cb(arg, NETDB_INTERNAL, 0, 0, NULL, 0);
13201361951Seric 		return;
13301361951Seric 	}
13401361951Seric 
13501361951Seric 	while (req->id == 0 || SPLAY_FIND(reqtree, &reqs, req))
13601361951Seric 		req->id = arc4random();
13701361951Seric 	req->cb_res = cb;
13801361951Seric 	req->arg = arg;
13901361951Seric 
14001361951Seric 	SPLAY_INSERT(reqtree, &reqs, req);
14101361951Seric 
14201361951Seric 	m_create(p_resolver, IMSG_RES_QUERY, req->id, 0, -1);
14301361951Seric 	m_add_string(p_resolver, dname);
14401361951Seric 	m_add_int(p_resolver, class);
14501361951Seric 	m_add_int(p_resolver, type);
14601361951Seric 	m_close(p_resolver);
14701361951Seric }
14801361951Seric 
14901361951Seric void
resolver_dispatch_request(struct mproc * proc,struct imsg * imsg)15001eba458Seric resolver_dispatch_request(struct mproc *proc, struct imsg *imsg)
15101eba458Seric {
15201361951Seric 	const char *hostname, *servname, *dname;
15301eba458Seric 	struct session *s;
15401eba458Seric 	struct asr_query *q;
15501eba458Seric 	struct addrinfo hints;
15601eba458Seric 	struct sockaddr_storage ss;
15701eba458Seric 	struct sockaddr *sa;
15801eba458Seric 	struct msg m;
15901eba458Seric 	uint32_t reqid;
16001361951Seric 	int class, type, flags, save_errno;
16101eba458Seric 
16201eba458Seric 	reqid = imsg->hdr.peerid;
16301eba458Seric 	m_msg(&m, imsg);
16401eba458Seric 
16501eba458Seric 	switch (imsg->hdr.type) {
16601eba458Seric 
16701eba458Seric 	case IMSG_GETADDRINFO:
16801eba458Seric 		servname = NULL;
16901eba458Seric 		memset(&hints, 0 , sizeof(hints));
17001eba458Seric 		m_get_int(&m, &hints.ai_flags);
17101eba458Seric 		m_get_int(&m, &hints.ai_family);
17201eba458Seric 		m_get_int(&m, &hints.ai_socktype);
17301eba458Seric 		m_get_int(&m, &hints.ai_protocol);
17401eba458Seric 		m_get_string(&m, &hostname);
17501eba458Seric 		m_get_string(&m, &servname);
17601eba458Seric 		m_end(&m);
17701eba458Seric 
17801eba458Seric 		s = NULL;
17901eba458Seric 		q = NULL;
18001eba458Seric 		if ((s = calloc(1, sizeof(*s))) &&
18101eba458Seric 		    (q = getaddrinfo_async(hostname, servname, &hints, NULL)) &&
18201eba458Seric 		    (event_asr_run(q, resolver_getaddrinfo_cb, s))) {
18301eba458Seric 			s->reqid = reqid;
18401eba458Seric 			s->proc = proc;
18501eba458Seric 			break;
18601eba458Seric 		}
18701eba458Seric 		save_errno = errno;
18801eba458Seric 
18901eba458Seric 		if (q)
19001eba458Seric 			asr_abort(q);
19101eba458Seric 		if (s)
19201eba458Seric 			free(s);
19301eba458Seric 
19401eba458Seric 		m_create(proc, IMSG_GETADDRINFO_END, reqid, 0, -1);
19501eba458Seric 		m_add_int(proc, EAI_SYSTEM);
19601eba458Seric 		m_add_int(proc, save_errno);
19701eba458Seric 		m_close(proc);
19801eba458Seric 		break;
19901eba458Seric 
20001eba458Seric 	case IMSG_GETNAMEINFO:
20101eba458Seric 		sa = (struct sockaddr*)&ss;
20201eba458Seric 		m_get_sockaddr(&m, sa);
20301eba458Seric 		m_get_int(&m, &flags);
20401eba458Seric 		m_end(&m);
20501eba458Seric 
20601eba458Seric 		s = NULL;
20701eba458Seric 		q = NULL;
20801eba458Seric 		if ((s = calloc(1, sizeof(*s))) &&
20901eba458Seric 		    (s->host = malloc(NI_MAXHOST)) &&
21001eba458Seric 		    (s->serv = malloc(NI_MAXSERV)) &&
21101eba458Seric 		    (q = getnameinfo_async(sa, sa->sa_len, s->host, NI_MAXHOST,
21201eba458Seric 			s->serv, NI_MAXSERV, flags, NULL)) &&
21301eba458Seric 		    (event_asr_run(q, resolver_getnameinfo_cb, s))) {
21401eba458Seric 			s->reqid = reqid;
21501eba458Seric 			s->proc = proc;
21601eba458Seric 			break;
21701eba458Seric 		}
21801eba458Seric 		save_errno = errno;
21901eba458Seric 
22001eba458Seric 		if (q)
22101eba458Seric 			asr_abort(q);
22201eba458Seric 		if (s) {
22301eba458Seric 			free(s->host);
22401eba458Seric 			free(s->serv);
22501eba458Seric 			free(s);
22601eba458Seric 		}
22701eba458Seric 
22801eba458Seric 		m_create(proc, IMSG_GETNAMEINFO, reqid, 0, -1);
22901eba458Seric 		m_add_int(proc, EAI_SYSTEM);
23001eba458Seric 		m_add_int(proc, save_errno);
2319ec9b5d0Seric 		m_add_string(proc, NULL);
2329ec9b5d0Seric 		m_add_string(proc, NULL);
23301eba458Seric 		m_close(proc);
23401eba458Seric 		break;
23501eba458Seric 
23601361951Seric 	case IMSG_RES_QUERY:
23701361951Seric 		m_get_string(&m, &dname);
23801361951Seric 		m_get_int(&m, &class);
23901361951Seric 		m_get_int(&m, &type);
24001361951Seric 		m_end(&m);
24101361951Seric 
24201361951Seric 		s = NULL;
24301361951Seric 		q = NULL;
24401361951Seric 		if ((s = calloc(1, sizeof(*s))) &&
24501361951Seric 		    (q = res_query_async(dname, class, type, NULL)) &&
24601361951Seric 		    (event_asr_run(q, resolver_res_query_cb, s))) {
24701361951Seric 			s->reqid = reqid;
24801361951Seric 			s->proc = proc;
24901361951Seric 			break;
25001361951Seric 		}
25101361951Seric 		save_errno = errno;
25201361951Seric 
25301361951Seric 		if (q)
25401361951Seric 			asr_abort(q);
25501361951Seric 		if (s)
25601361951Seric 			free(s);
25701361951Seric 
25801361951Seric 		m_create(proc, IMSG_RES_QUERY, reqid, 0, -1);
25901361951Seric 		m_add_int(proc, NETDB_INTERNAL);
26001361951Seric 		m_add_int(proc, save_errno);
26101361951Seric 		m_add_int(proc, 0);
26201361951Seric 		m_add_int(proc, 0);
26301361951Seric 		m_add_data(proc, NULL, 0);
26401361951Seric 		m_close(proc);
26501361951Seric 		break;
26601361951Seric 
26701eba458Seric 	default:
26801eba458Seric 		fatalx("%s: %s", __func__, imsg_to_str(imsg->hdr.type));
26901eba458Seric 	}
27001eba458Seric }
27101eba458Seric 
272ce5509e4Seric static struct addrinfo *
_alloc_addrinfo(const struct addrinfo * ai0,const struct sockaddr * sa,const char * cname)273ce5509e4Seric _alloc_addrinfo(const struct addrinfo *ai0, const struct sockaddr *sa,
274ce5509e4Seric     const char *cname)
275ce5509e4Seric {
276ce5509e4Seric 	struct addrinfo *ai;
277ce5509e4Seric 
278ce5509e4Seric 	ai = calloc(1, sizeof(*ai) + sa->sa_len);
279ce5509e4Seric 	if (ai == NULL) {
280ce5509e4Seric 		log_warn("%s: calloc", __func__);
281ce5509e4Seric 		return NULL;
282ce5509e4Seric 	}
283ce5509e4Seric 	*ai = *ai0;
284ce5509e4Seric 	ai->ai_addr = (void *)(ai + 1);
285ce5509e4Seric 	memcpy(ai->ai_addr, sa, sa->sa_len);
286ce5509e4Seric 
287ce5509e4Seric 	if (cname) {
288ce5509e4Seric 		ai->ai_canonname = strdup(cname);
289ce5509e4Seric 		if (ai->ai_canonname == NULL) {
290ce5509e4Seric 			log_warn("%s: strdup", __func__);
291ce5509e4Seric 			free(ai);
292ce5509e4Seric 			return NULL;
293ce5509e4Seric 		}
294ce5509e4Seric 	}
295ce5509e4Seric 
296ce5509e4Seric 	return ai;
297ce5509e4Seric }
298ce5509e4Seric 
29901eba458Seric void
resolver_dispatch_result(struct mproc * proc,struct imsg * imsg)30001eba458Seric resolver_dispatch_result(struct mproc *proc, struct imsg *imsg)
30101eba458Seric {
30201eba458Seric 	struct request key, *req;
30301eba458Seric 	struct sockaddr_storage ss;
304ce5509e4Seric 	struct addrinfo *ai, tai;
30501eba458Seric 	struct msg m;
30601eba458Seric 	const char *cname, *host, *serv;
30701361951Seric 	const void *data;
30801361951Seric 	size_t datalen;
30901361951Seric 	int gai_errno, herrno, rcode, count;
31001eba458Seric 
31101eba458Seric 	key.id = imsg->hdr.peerid;
31201eba458Seric 	req = SPLAY_FIND(reqtree, &reqs, &key);
31301eba458Seric 	if (req == NULL)
31401eba458Seric 		fatalx("%s: unknown request %08x", __func__, imsg->hdr.peerid);
31501eba458Seric 
31601eba458Seric 	m_msg(&m, imsg);
31701eba458Seric 
31801eba458Seric 	switch (imsg->hdr.type) {
31901eba458Seric 
32001eba458Seric 	case IMSG_GETADDRINFO:
321ce5509e4Seric 		memset(&tai, 0, sizeof(tai));
322ce5509e4Seric 		m_get_int(&m, &tai.ai_flags);
323ce5509e4Seric 		m_get_int(&m, &tai.ai_family);
324ce5509e4Seric 		m_get_int(&m, &tai.ai_socktype);
325ce5509e4Seric 		m_get_int(&m, &tai.ai_protocol);
32601eba458Seric 		m_get_sockaddr(&m, (struct sockaddr *)&ss);
32701eba458Seric 		m_get_string(&m, &cname);
32801eba458Seric 		m_end(&m);
32901eba458Seric 
330ce5509e4Seric 		ai = _alloc_addrinfo(&tai, (struct sockaddr *)&ss, cname);
331ce5509e4Seric 		if (ai) {
33201eba458Seric 			ai->ai_next = req->ai;
33301eba458Seric 			req->ai = ai;
334ce5509e4Seric 		}
33501eba458Seric 		break;
33601eba458Seric 
33701eba458Seric 	case IMSG_GETADDRINFO_END:
33801eba458Seric 		m_get_int(&m, &gai_errno);
33901eba458Seric 		m_get_int(&m, &errno);
34001eba458Seric 		m_end(&m);
34101eba458Seric 
34201eba458Seric 		SPLAY_REMOVE(reqtree, &reqs, req);
34301eba458Seric 		req->cb_ai(req->arg, gai_errno, req->ai);
34401eba458Seric 		free(req);
34501eba458Seric 		break;
34601eba458Seric 
34701eba458Seric 	case IMSG_GETNAMEINFO:
34801eba458Seric 		m_get_int(&m, &gai_errno);
34901eba458Seric 		m_get_int(&m, &errno);
35001eba458Seric 		m_get_string(&m, &host);
35101eba458Seric 		m_get_string(&m, &serv);
35201eba458Seric 		m_end(&m);
35301eba458Seric 
35401eba458Seric 		SPLAY_REMOVE(reqtree, &reqs, req);
3559ec9b5d0Seric 		req->cb_ni(req->arg, gai_errno, host, serv);
35601eba458Seric 		free(req);
35701eba458Seric 		break;
35801361951Seric 
35901361951Seric 	case IMSG_RES_QUERY:
36001361951Seric 		m_get_int(&m, &herrno);
36101361951Seric 		m_get_int(&m, &errno);
36201361951Seric 		m_get_int(&m, &rcode);
36301361951Seric 		m_get_int(&m, &count);
36401361951Seric 		m_get_data(&m, &data, &datalen);
36501361951Seric 		m_end(&m);
36601361951Seric 
36701361951Seric 		SPLAY_REMOVE(reqtree, &reqs, req);
36801361951Seric 		req->cb_res(req->arg, herrno, rcode, count, data, datalen);
36901361951Seric 		free(req);
37001361951Seric 		break;
37101eba458Seric 	}
37201eba458Seric }
37301eba458Seric 
37401eba458Seric static void
resolver_init(void)37501eba458Seric resolver_init(void)
37601eba458Seric {
37701eba458Seric 	static int init = 0;
37801eba458Seric 
37901eba458Seric 	if (init == 0) {
38001eba458Seric 		SPLAY_INIT(&reqs);
38101eba458Seric 		init = 1;
38201eba458Seric 	}
38301eba458Seric }
38401eba458Seric 
38501eba458Seric static void
resolver_getaddrinfo_cb(struct asr_result * ar,void * arg)38601eba458Seric resolver_getaddrinfo_cb(struct asr_result *ar, void *arg)
38701eba458Seric {
38801eba458Seric 	struct session *s = arg;
38901eba458Seric 	struct addrinfo *ai;
39001eba458Seric 
39101eba458Seric 	for (ai = ar->ar_addrinfo; ai; ai = ai->ai_next) {
39201eba458Seric 		m_create(s->proc, IMSG_GETADDRINFO, s->reqid, 0, -1);
39301eba458Seric 		m_add_int(s->proc, ai->ai_flags);
39401eba458Seric 		m_add_int(s->proc, ai->ai_family);
39501eba458Seric 		m_add_int(s->proc, ai->ai_socktype);
39601eba458Seric 		m_add_int(s->proc, ai->ai_protocol);
39701eba458Seric 		m_add_sockaddr(s->proc, ai->ai_addr);
3982c59994aSeric 		m_add_string(s->proc, ai->ai_canonname);
39901eba458Seric 		m_close(s->proc);
40001eba458Seric 	}
40101eba458Seric 
40201eba458Seric 	m_create(s->proc, IMSG_GETADDRINFO_END, s->reqid, 0, -1);
40301eba458Seric 	m_add_int(s->proc, ar->ar_gai_errno);
40401eba458Seric 	m_add_int(s->proc, ar->ar_errno);
40501eba458Seric 	m_close(s->proc);
40601eba458Seric 
4072c59994aSeric 	if (ar->ar_addrinfo)
40801eba458Seric 		freeaddrinfo(ar->ar_addrinfo);
40901eba458Seric 	free(s);
41001eba458Seric }
41101eba458Seric 
41201eba458Seric static void
resolver_getnameinfo_cb(struct asr_result * ar,void * arg)41301eba458Seric resolver_getnameinfo_cb(struct asr_result *ar, void *arg)
41401eba458Seric {
41501eba458Seric 	struct session *s = arg;
41601eba458Seric 
41701eba458Seric 	m_create(s->proc, IMSG_GETNAMEINFO, s->reqid, 0, -1);
41801eba458Seric 	m_add_int(s->proc, ar->ar_gai_errno);
41901eba458Seric 	m_add_int(s->proc, ar->ar_errno);
4209ec9b5d0Seric 	m_add_string(s->proc, ar->ar_gai_errno ? NULL : s->host);
4219ec9b5d0Seric 	m_add_string(s->proc, ar->ar_gai_errno ? NULL : s->serv);
42201eba458Seric 	m_close(s->proc);
42301eba458Seric 
42401eba458Seric 	free(s->host);
42501eba458Seric 	free(s->serv);
42601eba458Seric 	free(s);
42701eba458Seric }
42801eba458Seric 
42901361951Seric static void
resolver_res_query_cb(struct asr_result * ar,void * arg)43001361951Seric resolver_res_query_cb(struct asr_result *ar, void *arg)
43101361951Seric {
43201361951Seric 	struct session *s = arg;
43301361951Seric 
43401361951Seric 	m_create(s->proc, IMSG_RES_QUERY, s->reqid, 0, -1);
43501361951Seric 	m_add_int(s->proc, ar->ar_h_errno);
43601361951Seric 	m_add_int(s->proc, ar->ar_errno);
43701361951Seric 	m_add_int(s->proc, ar->ar_rcode);
43801361951Seric 	m_add_int(s->proc, ar->ar_count);
43901361951Seric 	m_add_data(s->proc, ar->ar_data, ar->ar_datalen);
44001361951Seric 	m_close(s->proc);
44101361951Seric 
44201361951Seric 	free(ar->ar_data);
44301361951Seric 	free(s);
44401361951Seric }
44501361951Seric 
44601eba458Seric static int
request_cmp(struct request * a,struct request * b)44701eba458Seric request_cmp(struct request *a, struct request *b)
44801eba458Seric {
44901eba458Seric 	if (a->id < b->id)
45001eba458Seric 		return -1;
45101eba458Seric 	if (a->id > b->id)
45201eba458Seric 		return 1;
45301eba458Seric 	return 0;
45401eba458Seric }
45501eba458Seric 
45601eba458Seric SPLAY_GENERATE(reqtree, request, entry, request_cmp);
457