outside_network.c revision 361435
1148330Snetchild/*
2148330Snetchild * services/outside_network.c - implement sending of queries and wait answer.
3148330Snetchild *
4148330Snetchild * Copyright (c) 2007, NLnet Labs. All rights reserved.
5148330Snetchild *
6148330Snetchild * This software is open source.
7148330Snetchild *
8148330Snetchild * Redistribution and use in source and binary forms, with or without
9148330Snetchild * modification, are permitted provided that the following conditions
10148330Snetchild * are met:
11148330Snetchild *
12148330Snetchild * Redistributions of source code must retain the above copyright notice,
13148330Snetchild * this list of conditions and the following disclaimer.
14148543Snetchild *
15148543Snetchild * Redistributions in binary form must reproduce the above copyright notice,
16148330Snetchild * this list of conditions and the following disclaimer in the documentation
17178924Santoine * and/or other materials provided with the distribution.
18178924Santoine *
19178924Santoine * Neither the name of the NLNET LABS nor the names of its contributors may
20178924Santoine * be used to endorse or promote products derived from this software without
21178924Santoine * specific prior written permission.
22177831Sflz *
23177831Sflz * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24177831Sflz * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25177831Sflz * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26177831Sflz * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27178331Santoine * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28178331Santoine * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29178331Santoine * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30178331Santoine * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31178331Santoine * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32178331Santoine * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33178331Santoine * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34178331Santoine */
35178331Santoine
36178331Santoine/**
37178331Santoine * \file
38178331Santoine *
39178331Santoine * This file has functions to send queries to authoritative servers and
40178331Santoine * wait for the pending answer events.
41178331Santoine */
42178331Santoine#include "config.h"
43178924Santoine#include <ctype.h>
44178924Santoine#ifdef HAVE_SYS_TYPES_H
45178924Santoine#  include <sys/types.h>
46178924Santoine#endif
47176422Sthompsa#include <sys/time.h>
48176422Sthompsa#include "services/outside_network.h"
49175690Sbrueffer#include "services/listen_dnsport.h"
50175690Sbrueffer#include "services/cache/infra.h"
51175690Sbrueffer#include "iterator/iterator.h"
52175576Sattilio#include "util/data/msgparse.h"
53175576Sattilio#include "util/data/msgreply.h"
54175227Sjhb#include "util/data/msgencode.h"
55175227Sjhb#include "util/data/dname.h"
56175227Sjhb#include "util/netevent.h"
57174426Sdougb#include "util/log.h"
58174426Sdougb#include "util/net_help.h"
59174426Sdougb#include "util/random.h"
60177153Sbrueffer#include "util/fptr_wlist.h"
61177153Sbrueffer#include "sldns/sbuffer.h"
62174092Sbrooks#include "dnstap/dnstap.h"
63174092Sbrooks#ifdef HAVE_OPENSSL_SSL_H
64174092Sbrooks#include <openssl/ssl.h>
65174092Sbrooks#endif
66176956Santoine#ifdef HAVE_X509_VERIFY_PARAM_SET1_HOST
67176956Santoine#include <openssl/x509v3.h>
68176956Santoine#endif
69176956Santoine
70174092Sbrooks#ifdef HAVE_NETDB_H
71174061Sjb#include <netdb.h>
72174061Sjb#endif
73175227Sjhb#include <fcntl.h>
74175227Sjhb
75173466Simp/** number of times to retry making a random ID that is unique. */
76173466Simp#define MAX_ID_RETRY 1000
77173662Smarcel/** number of times to retry finding interface, port that can be opened. */
78173662Smarcel#define MAX_PORT_RETRY 10000
79173662Smarcel/** number of retries on outgoing UDP queries */
80173662Smarcel#define OUTBOUND_UDP_RETRY 1
81173662Smarcel
82173662Smarcel/** initiate TCP transaction for serviced query */
83175227Sjhbstatic void serviced_tcp_initiate(struct serviced_query* sq, sldns_buffer* buff);
84175227Sjhb/** with a fd available, randomize and send UDP */
85172983Smtmstatic int randomize_and_send_udp(struct pending* pend, sldns_buffer* packet,
86172983Smtm	int timeout);
87172390Sbushman
88173176Sbushman/** remove waiting tcp from the outnet waiting list */
89172390Sbushmanstatic void waiting_list_remove(struct outside_network* outnet,
90172390Sbushman	struct waiting_tcp* w);
91172570Sru
92172570Sruint
93171786Smarcelpending_cmp(const void* key1, const void* key2)
94171786Smarcel{
95171786Smarcel	struct pending *p1 = (struct pending*)key1;
96171786Smarcel	struct pending *p2 = (struct pending*)key2;
97171696Sbz	if(p1->id < p2->id)
98171696Sbz		return -1;
99171461Srwatson	if(p1->id > p2->id)
100171461Srwatson		return 1;
101171461Srwatson	log_assert(p1->id == p2->id);
102171461Srwatson	return sockaddr_cmp(&p1->addr, p1->addrlen, &p2->addr, p2->addrlen);
103171461Srwatson}
104171461Srwatson
105171461Srwatsonint
106171461Srwatsonserviced_cmp(const void* key1, const void* key2)
107171461Srwatson{
108171461Srwatson	struct serviced_query* q1 = (struct serviced_query*)key1;
109171461Srwatson	struct serviced_query* q2 = (struct serviced_query*)key2;
110171461Srwatson	int r;
111171461Srwatson	if(q1->qbuflen < q2->qbuflen)
112171461Srwatson		return -1;
113171461Srwatson	if(q1->qbuflen > q2->qbuflen)
114171461Srwatson		return 1;
115171461Srwatson	log_assert(q1->qbuflen == q2->qbuflen);
116171461Srwatson	log_assert(q1->qbuflen >= 15 /* 10 header, root, type, class */);
117171461Srwatson	/* alternate casing of qname is still the same query */
118171461Srwatson	if((r = memcmp(q1->qbuf, q2->qbuf, 10)) != 0)
119171461Srwatson		return r;
120171461Srwatson	if((r = memcmp(q1->qbuf+q1->qbuflen-4, q2->qbuf+q2->qbuflen-4, 4)) != 0)
121171461Srwatson		return r;
122171461Srwatson	if(q1->dnssec != q2->dnssec) {
123171461Srwatson		if(q1->dnssec < q2->dnssec)
124171461Srwatson			return -1;
125171461Srwatson		return 1;
126171461Srwatson	}
127171461Srwatson	if((r = query_dname_compare(q1->qbuf+10, q2->qbuf+10)) != 0)
128171461Srwatson		return r;
129171461Srwatson	if((r = edns_opt_list_compare(q1->opt_list, q2->opt_list)) != 0)
130171461Srwatson		return r;
131171461Srwatson	return sockaddr_cmp(&q1->addr, q1->addrlen, &q2->addr, q2->addrlen);
132171461Srwatson}
133171461Srwatson
134171461Srwatson/** delete waiting_tcp entry. Does not unlink from waiting list.
135171461Srwatson * @param w: to delete.
136171461Srwatson */
137171461Srwatsonstatic void
138171461Srwatsonwaiting_tcp_delete(struct waiting_tcp* w)
139171461Srwatson{
140171461Srwatson	if(!w) return;
141171461Srwatson	if(w->timer)
142171461Srwatson		comm_timer_delete(w->timer);
143171461Srwatson	free(w);
144171461Srwatson}
145171461Srwatson
146171461Srwatson/**
147171461Srwatson * Pick random outgoing-interface of that family, and bind it.
148171461Srwatson * port set to 0 so OS picks a port number for us.
149171461Srwatson * if it is the ANY address, do not bind.
150171461Srwatson * @param w: tcp structure with destination address.
151171461Srwatson * @param s: socket fd.
152171461Srwatson * @return false on error, socket closed.
153171461Srwatson */
154171461Srwatsonstatic int
155171461Srwatsonpick_outgoing_tcp(struct waiting_tcp* w, int s)
156171461Srwatson{
157171461Srwatson	struct port_if* pi = NULL;
158171461Srwatson	int num;
159171461Srwatson#ifdef INET6
160171461Srwatson	if(addr_is_ip6(&w->addr, w->addrlen))
161171461Srwatson		num = w->outnet->num_ip6;
162171461Srwatson	else
163171461Srwatson#endif
164171461Srwatson		num = w->outnet->num_ip4;
165171461Srwatson	if(num == 0) {
166171461Srwatson		log_err("no TCP outgoing interfaces of family");
167171461Srwatson		log_addr(VERB_OPS, "for addr", &w->addr, w->addrlen);
168171461Srwatson#ifndef USE_WINSOCK
169171461Srwatson		close(s);
170171461Srwatson#else
171171461Srwatson		closesocket(s);
172176956Santoine#endif
173176956Santoine		return 0;
174176956Santoine	}
175176956Santoine#ifdef INET6
176176956Santoine	if(addr_is_ip6(&w->addr, w->addrlen))
177176956Santoine		pi = &w->outnet->ip6_ifs[ub_random_max(w->outnet->rnd, num)];
178171274Sbz	else
179171274Sbz#endif
180171274Sbz		pi = &w->outnet->ip4_ifs[ub_random_max(w->outnet->rnd, num)];
181171274Sbz	log_assert(pi);
182171274Sbz	if(addr_is_any(&pi->addr, pi->addrlen)) {
183171274Sbz		/* binding to the ANY interface is for listening sockets */
184171274Sbz		return 1;
185171274Sbz	}
186171274Sbz	/* set port to 0 */
187171205Sbz	if(addr_is_ip6(&pi->addr, pi->addrlen))
188171205Sbz		((struct sockaddr_in6*)&pi->addr)->sin6_port = 0;
189171205Sbz	else	((struct sockaddr_in*)&pi->addr)->sin_port = 0;
190171205Sbz	if(bind(s, (struct sockaddr*)&pi->addr, pi->addrlen) != 0) {
191171205Sbz#ifndef USE_WINSOCK
192171205Sbz		log_err("outgoing tcp: bind: %s", strerror(errno));
193171175Smlaier		close(s);
194171175Smlaier#else
195171137Sbz		log_err("outgoing tcp: bind: %s",
196171137Sbz			wsa_strerror(WSAGetLastError()));
197171137Sbz		closesocket(s);
198171137Sbz#endif
199171137Sbz		return 0;
200171137Sbz	}
201171137Sbz	log_addr(VERB_ALGO, "tcp bound to src", &pi->addr, pi->addrlen);
202171137Sbz	return 1;
203171137Sbz}
204171137Sbz
205171137Sbz/** get TCP file descriptor for address, returns -1 on failure,
206171137Sbz * tcp_mss is 0 or maxseg size to set for TCP packets. */
207171137Sbzint
208171137Sbzoutnet_get_tcp_fd(struct sockaddr_storage* addr, socklen_t addrlen, int tcp_mss)
209171137Sbz{
210171137Sbz	int s;
211171137Sbz#ifdef SO_REUSEADDR
212171137Sbz	int on = 1;
213171137Sbz#endif
214171131Sthompsa#ifdef INET6
215171131Sthompsa	if(addr_is_ip6(addr, addrlen))
216171143Sthompsa		s = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
217171023Srafan	else
218171023Srafan#endif
219171023Srafan		s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
220171023Srafan	if(s == -1) {
221171023Srafan#ifndef USE_WINSOCK
222171023Srafan		log_err_addr("outgoing tcp: socket", strerror(errno),
223171388Sdougb			addr, addrlen);
224171388Sdougb#else
225171388Sdougb		log_err_addr("outgoing tcp: socket",
226171388Sdougb			wsa_strerror(WSAGetLastError()), addr, addrlen);
227170926Srafan#endif
228170926Srafan		return -1;
229170926Srafan	}
230170926Srafan
231170926Srafan#ifdef SO_REUSEADDR
232170926Srafan	if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&on,
233170926Srafan		(socklen_t)sizeof(on)) < 0) {
234170926Srafan		verbose(VERB_ALGO, "outgoing tcp:"
235170926Srafan			" setsockopt(.. SO_REUSEADDR ..) failed");
236170926Srafan	}
237170926Srafan#endif
238170926Srafan
239170926Srafan	if(tcp_mss > 0) {
240170926Srafan#if defined(IPPROTO_TCP) && defined(TCP_MAXSEG)
241170926Srafan		if(setsockopt(s, IPPROTO_TCP, TCP_MAXSEG,
242170926Srafan			(void*)&tcp_mss, (socklen_t)sizeof(tcp_mss)) < 0) {
243170926Srafan			verbose(VERB_ALGO, "outgoing tcp:"
244170926Srafan				" setsockopt(.. TCP_MAXSEG ..) failed");
245170926Srafan		}
246170926Srafan#else
247170926Srafan		verbose(VERB_ALGO, "outgoing tcp:"
248170926Srafan			" setsockopt(TCP_MAXSEG) unsupported");
249170926Srafan#endif /* defined(IPPROTO_TCP) && defined(TCP_MAXSEG) */
250170926Srafan	}
251170926Srafan
252170926Srafan	return s;
253170926Srafan}
254170926Srafan
255170926Srafan/** connect tcp connection to addr, 0 on failure */
256170926Srafanint
257170926Srafanoutnet_tcp_connect(int s, struct sockaddr_storage* addr, socklen_t addrlen)
258170926Srafan{
259170926Srafan	if(connect(s, (struct sockaddr*)addr, addrlen) == -1) {
260170926Srafan#ifndef USE_WINSOCK
261170926Srafan#ifdef EINPROGRESS
262170926Srafan		if(errno != EINPROGRESS) {
263170926Srafan#endif
264170926Srafan			if(tcp_connect_errno_needs_log(
265170926Srafan				(struct sockaddr*)addr, addrlen))
266170926Srafan				log_err_addr("outgoing tcp: connect",
267170926Srafan					strerror(errno), addr, addrlen);
268176956Santoine			close(s);
269176956Santoine			return 0;
270176956Santoine#ifdef EINPROGRESS
271176956Santoine		}
272176956Santoine#endif
273176956Santoine#else /* USE_WINSOCK */
274176956Santoine		if(WSAGetLastError() != WSAEINPROGRESS &&
275176956Santoine			WSAGetLastError() != WSAEWOULDBLOCK) {
276176956Santoine			closesocket(s);
277176956Santoine			return 0;
278176956Santoine		}
279176956Santoine#endif
280176956Santoine	}
281176956Santoine	return 1;
282176956Santoine}
283176956Santoine
284176956Santoine/** use next free buffer to service a tcp query */
285176956Santoinestatic int
286176956Santoineoutnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt, size_t pkt_len)
287176956Santoine{
288176956Santoine	struct pending_tcp* pend = w->outnet->tcp_free;
289176956Santoine	int s;
290176956Santoine	log_assert(pend);
291176956Santoine	log_assert(pkt);
292176956Santoine	log_assert(w->addrlen > 0);
293176956Santoine	/* open socket */
294176956Santoine	s = outnet_get_tcp_fd(&w->addr, w->addrlen, w->outnet->tcp_mss);
295176956Santoine
296176956Santoine	if(s == -1)
297176956Santoine		return 0;
298176956Santoine
299176956Santoine	if(!pick_outgoing_tcp(w, s))
300176956Santoine		return 0;
301176956Santoine
302176956Santoine	fd_set_nonblock(s);
303176956Santoine#ifdef USE_OSX_MSG_FASTOPEN
304171476Sdelphij	/* API for fast open is different here. We use a connectx() function and
305171476Sdelphij	   then writes can happen as normal even using SSL.*/
306170312Sdelphij	/* connectx requires that the len be set in the sockaddr struct*/
307170312Sdelphij	struct sockaddr_in *addr_in = (struct sockaddr_in *)&w->addr;
308170926Srafan	addr_in->sin_len = w->addrlen;
309173816Sru	sa_endpoints_t endpoints;
310169815Sdelphij	endpoints.sae_srcif = 0;
311169815Sdelphij	endpoints.sae_srcaddr = NULL;
312169815Sdelphij	endpoints.sae_srcaddrlen = 0;
313169815Sdelphij	endpoints.sae_dstaddr = (struct sockaddr *)&w->addr;
314169815Sdelphij	endpoints.sae_dstaddrlen = w->addrlen;
315169815Sdelphij	if (connectx(s, &endpoints, SAE_ASSOCID_ANY,
316169815Sdelphij	             CONNECT_DATA_IDEMPOTENT | CONNECT_RESUME_ON_READ_WRITE,
317169815Sdelphij	             NULL, 0, NULL, NULL) == -1) {
318169815Sdelphij		/* if fails, failover to connect for OSX 10.10 */
319169815Sdelphij#ifdef EINPROGRESS
320169815Sdelphij		if(errno != EINPROGRESS) {
321169815Sdelphij#else
322170204Sru		if(1) {
323169815Sdelphij#endif
324169815Sdelphij			if(connect(s, (struct sockaddr*)&w->addr, w->addrlen) == -1) {
325169815Sdelphij#else /* USE_OSX_MSG_FASTOPEN*/
326169815Sdelphij#ifdef USE_MSG_FASTOPEN
327170204Sru	pend->c->tcp_do_fastopen = 1;
328169815Sdelphij	/* Only do TFO for TCP in which case no connect() is required here.
329169815Sdelphij	   Don't combine client TFO with SSL, since OpenSSL can't
330169815Sdelphij	   currently support doing a handshake on fd that already isn't connected*/
331169815Sdelphij	if (w->outnet->sslctx && w->ssl_upstream) {
332169815Sdelphij		if(connect(s, (struct sockaddr*)&w->addr, w->addrlen) == -1) {
333169815Sdelphij#else /* USE_MSG_FASTOPEN*/
334169815Sdelphij	if(connect(s, (struct sockaddr*)&w->addr, w->addrlen) == -1) {
335169815Sdelphij#endif /* USE_MSG_FASTOPEN*/
336169815Sdelphij#endif /* USE_OSX_MSG_FASTOPEN*/
337169815Sdelphij#ifndef USE_WINSOCK
338169815Sdelphij#ifdef EINPROGRESS
339169815Sdelphij		if(errno != EINPROGRESS) {
340169815Sdelphij#else
341169815Sdelphij		if(1) {
342169815Sdelphij#endif
343169815Sdelphij			if(tcp_connect_errno_needs_log(
344169815Sdelphij				(struct sockaddr*)&w->addr, w->addrlen))
345169815Sdelphij				log_err_addr("outgoing tcp: connect",
346169815Sdelphij					strerror(errno), &w->addr, w->addrlen);
347169815Sdelphij			close(s);
348169815Sdelphij#else /* USE_WINSOCK */
349169815Sdelphij		if(WSAGetLastError() != WSAEINPROGRESS &&
350169815Sdelphij			WSAGetLastError() != WSAEWOULDBLOCK) {
351169815Sdelphij			closesocket(s);
352169815Sdelphij#endif
353169815Sdelphij			return 0;
354169815Sdelphij		}
355169815Sdelphij	}
356169815Sdelphij#ifdef USE_MSG_FASTOPEN
357169815Sdelphij	}
358169815Sdelphij#endif /* USE_MSG_FASTOPEN */
359169815Sdelphij#ifdef USE_OSX_MSG_FASTOPEN
360169815Sdelphij		}
361169815Sdelphij	}
362169815Sdelphij#endif /* USE_OSX_MSG_FASTOPEN */
363169815Sdelphij	if(w->outnet->sslctx && w->ssl_upstream) {
364170204Sru		pend->c->ssl = outgoing_ssl_fd(w->outnet->sslctx, s);
365169815Sdelphij		if(!pend->c->ssl) {
366169815Sdelphij			pend->c->fd = s;
367169815Sdelphij			comm_point_close(pend->c);
368170917Srafan			return 0;
369169815Sdelphij		}
370169815Sdelphij		verbose(VERB_ALGO, "the query is using TLS encryption, for %s",
371169815Sdelphij			(w->tls_auth_name?w->tls_auth_name:"an unauthenticated connection"));
372169815Sdelphij#ifdef USE_WINSOCK
373169815Sdelphij		comm_point_tcp_win_bio_cb(pend->c, pend->c->ssl);
374169815Sdelphij#endif
375169815Sdelphij		pend->c->ssl_shake_state = comm_ssl_shake_write;
376169815Sdelphij		if(w->tls_auth_name) {
377169815Sdelphij#ifdef HAVE_SSL
378169815Sdelphij			(void)SSL_set_tlsext_host_name(pend->c->ssl, w->tls_auth_name);
379169815Sdelphij#endif
380169815Sdelphij		}
381169815Sdelphij#ifdef HAVE_SSL_SET1_HOST
382169815Sdelphij		if(w->tls_auth_name) {
383169815Sdelphij			SSL_set_verify(pend->c->ssl, SSL_VERIFY_PEER, NULL);
384169815Sdelphij			/* setting the hostname makes openssl verify the
385169815Sdelphij                         * host name in the x509 certificate in the
386169815Sdelphij                         * SSL connection*/
387169815Sdelphij                        if(!SSL_set1_host(pend->c->ssl, w->tls_auth_name)) {
388169815Sdelphij                                log_err("SSL_set1_host failed");
389169815Sdelphij				pend->c->fd = s;
390169815Sdelphij				SSL_free(pend->c->ssl);
391169815Sdelphij				pend->c->ssl = NULL;
392169815Sdelphij				comm_point_close(pend->c);
393169815Sdelphij				return 0;
394169815Sdelphij			}
395169815Sdelphij		}
396169815Sdelphij#elif defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
397169815Sdelphij		/* openssl 1.0.2 has this function that can be used for
398169815Sdelphij		 * set1_host like verification */
399169815Sdelphij		if(w->tls_auth_name) {
400169815Sdelphij			X509_VERIFY_PARAM* param = SSL_get0_param(pend->c->ssl);
401169815Sdelphij			X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
402169815Sdelphij			if(!X509_VERIFY_PARAM_set1_host(param, w->tls_auth_name, strlen(w->tls_auth_name))) {
403169815Sdelphij				log_err("X509_VERIFY_PARAM_set1_host failed");
404169815Sdelphij				pend->c->fd = s;
405169815Sdelphij				SSL_free(pend->c->ssl);
406169815Sdelphij				pend->c->ssl = NULL;
407169815Sdelphij				comm_point_close(pend->c);
408169815Sdelphij				return 0;
409169815Sdelphij			}
410169815Sdelphij			SSL_set_verify(pend->c->ssl, SSL_VERIFY_PEER, NULL);
411169815Sdelphij		}
412169815Sdelphij#else
413169815Sdelphij		verbose(VERB_ALGO, "the query has an auth_name, but libssl has no call to perform TLS authentication");
414169815Sdelphij#endif /* HAVE_SSL_SET1_HOST */
415169815Sdelphij	}
416169815Sdelphij	w->pkt = NULL;
417169815Sdelphij	w->next_waiting = (void*)pend;
418170204Sru	pend->id = LDNS_ID_WIRE(pkt);
419169815Sdelphij	w->outnet->num_tcp_outgoing++;
420169815Sdelphij	w->outnet->tcp_free = pend->next_free;
421169815Sdelphij	pend->next_free = NULL;
422169815Sdelphij	pend->query = w;
423169815Sdelphij	pend->c->repinfo.addrlen = w->addrlen;
424170190Sru	memcpy(&pend->c->repinfo.addr, &w->addr, w->addrlen);
425169815Sdelphij	sldns_buffer_clear(pend->c->buffer);
426169815Sdelphij	sldns_buffer_write(pend->c->buffer, pkt, pkt_len);
427169815Sdelphij	sldns_buffer_flip(pend->c->buffer);
428169815Sdelphij	pend->c->tcp_is_reading = 0;
429169815Sdelphij	pend->c->tcp_byte_count = 0;
430169815Sdelphij	comm_point_start_listening(pend->c, s, -1);
431169815Sdelphij	return 1;
432169815Sdelphij}
433169815Sdelphij
434169815Sdelphij/** see if buffers can be used to service TCP queries */
435169815Sdelphijstatic void
436169815Sdelphijuse_free_buffer(struct outside_network* outnet)
437170190Sru{
438170190Sru	struct waiting_tcp* w;
439170190Sru	while(outnet->tcp_free && outnet->tcp_wait_first
440170190Sru		&& !outnet->want_to_quit) {
441170190Sru		w = outnet->tcp_wait_first;
442170190Sru		outnet->tcp_wait_first = w->next_waiting;
443170190Sru		if(outnet->tcp_wait_last == w)
444171476Sdelphij			outnet->tcp_wait_last = NULL;
445171476Sdelphij		if(!outnet_tcp_take_into_use(w, w->pkt, w->pkt_len)) {
446171476Sdelphij			comm_point_callback_type* cb = w->cb;
447171476Sdelphij			void* cb_arg = w->cb_arg;
448171476Sdelphij			waiting_tcp_delete(w);
449171476Sdelphij			fptr_ok(fptr_whitelist_pending_tcp(cb));
450171476Sdelphij			(void)(*cb)(NULL, cb_arg, NETEVENT_CLOSED, NULL);
451171476Sdelphij		}
452171476Sdelphij	}
453171476Sdelphij}
454171476Sdelphij
455171476Sdelphij/** decommission a tcp buffer, closes commpoint and frees waiting_tcp entry */
456171476Sdelphijstatic void
457171476Sdelphijdecommission_pending_tcp(struct outside_network* outnet,
458171476Sdelphij	struct pending_tcp* pend)
459171476Sdelphij{
460171476Sdelphij	if(pend->c->ssl) {
461171476Sdelphij#ifdef HAVE_SSL
462171476Sdelphij		SSL_shutdown(pend->c->ssl);
463171476Sdelphij		SSL_free(pend->c->ssl);
464171476Sdelphij		pend->c->ssl = NULL;
465171476Sdelphij#endif
466171476Sdelphij	}
467171476Sdelphij	comm_point_close(pend->c);
468171476Sdelphij	pend->next_free = outnet->tcp_free;
469171476Sdelphij	outnet->tcp_free = pend;
470171476Sdelphij	waiting_tcp_delete(pend->query);
471171476Sdelphij	pend->query = NULL;
472171476Sdelphij	use_free_buffer(outnet);
473171476Sdelphij}
474171476Sdelphij
475171476Sdelphijint
476171476Sdelphijoutnet_tcp_cb(struct comm_point* c, void* arg, int error,
477171476Sdelphij	struct comm_reply *reply_info)
478171476Sdelphij{
479171476Sdelphij	struct pending_tcp* pend = (struct pending_tcp*)arg;
480171476Sdelphij	struct outside_network* outnet = pend->query->outnet;
481171476Sdelphij	verbose(VERB_ALGO, "outnettcp cb");
482171476Sdelphij	if(error != NETEVENT_NOERROR) {
483171476Sdelphij		verbose(VERB_QUERY, "outnettcp got tcp error %d", error);
484171476Sdelphij		/* pass error below and exit */
485171476Sdelphij	} else {
486171476Sdelphij		/* check ID */
487171476Sdelphij		if(sldns_buffer_limit(c->buffer) < sizeof(uint16_t) ||
488171476Sdelphij			LDNS_ID_WIRE(sldns_buffer_begin(c->buffer))!=pend->id) {
489171476Sdelphij			log_addr(VERB_QUERY,
490171476Sdelphij				"outnettcp: bad ID in reply, from:",
491171476Sdelphij				&pend->query->addr, pend->query->addrlen);
492171476Sdelphij			error = NETEVENT_CLOSED;
493171476Sdelphij		}
494171476Sdelphij	}
495171476Sdelphij	fptr_ok(fptr_whitelist_pending_tcp(pend->query->cb));
496171476Sdelphij	(void)(*pend->query->cb)(c, pend->query->cb_arg, error, reply_info);
497171476Sdelphij	decommission_pending_tcp(outnet, pend);
498171476Sdelphij	return 0;
499171476Sdelphij}
500171476Sdelphij
501171476Sdelphij/** lower use count on pc, see if it can be closed */
502171476Sdelphijstatic void
503171476Sdelphijportcomm_loweruse(struct outside_network* outnet, struct port_comm* pc)
504171476Sdelphij{
505171476Sdelphij	struct port_if* pif;
506171476Sdelphij	pc->num_outstanding--;
507171476Sdelphij	if(pc->num_outstanding > 0) {
508171476Sdelphij		return;
509171476Sdelphij	}
510171476Sdelphij	/* close it and replace in unused list */
511171476Sdelphij	verbose(VERB_ALGO, "close of port %d", pc->number);
512171476Sdelphij	comm_point_close(pc->cp);
513171476Sdelphij	pif = pc->pif;
514171476Sdelphij	log_assert(pif->inuse > 0);
515171476Sdelphij	pif->avail_ports[pif->avail_total - pif->inuse] = pc->number;
516171476Sdelphij	pif->inuse--;
517171476Sdelphij	pif->out[pc->index] = pif->out[pif->inuse];
518171476Sdelphij	pif->out[pc->index]->index = pc->index;
519171476Sdelphij	pc->next = outnet->unused_fds;
520171476Sdelphij	outnet->unused_fds = pc;
521171476Sdelphij}
522171476Sdelphij
523171476Sdelphij/** try to send waiting UDP queries */
524171476Sdelphijstatic void
525171476Sdelphijoutnet_send_wait_udp(struct outside_network* outnet)
526171476Sdelphij{
527171476Sdelphij	struct pending* pend;
528171476Sdelphij	/* process waiting queries */
529171476Sdelphij	while(outnet->udp_wait_first && outnet->unused_fds
530171476Sdelphij		&& !outnet->want_to_quit) {
531171476Sdelphij		pend = outnet->udp_wait_first;
532171476Sdelphij		outnet->udp_wait_first = pend->next_waiting;
533171476Sdelphij		if(!pend->next_waiting) outnet->udp_wait_last = NULL;
534171476Sdelphij		sldns_buffer_clear(outnet->udp_buff);
535171476Sdelphij		sldns_buffer_write(outnet->udp_buff, pend->pkt, pend->pkt_len);
536171476Sdelphij		sldns_buffer_flip(outnet->udp_buff);
537171476Sdelphij		free(pend->pkt); /* freeing now makes get_mem correct */
538171476Sdelphij		pend->pkt = NULL;
539171476Sdelphij		pend->pkt_len = 0;
540171476Sdelphij		if(!randomize_and_send_udp(pend, outnet->udp_buff,
541171476Sdelphij			pend->timeout)) {
542171476Sdelphij			/* callback error on pending */
543171476Sdelphij			if(pend->cb) {
544171476Sdelphij				fptr_ok(fptr_whitelist_pending_udp(pend->cb));
545171476Sdelphij				(void)(*pend->cb)(outnet->unused_fds->cp, pend->cb_arg,
546171476Sdelphij					NETEVENT_CLOSED, NULL);
547171476Sdelphij			}
548171476Sdelphij			pending_delete(outnet, pend);
549171476Sdelphij		}
550171476Sdelphij	}
551171476Sdelphij}
552171476Sdelphij
553171476Sdelphijint
554171476Sdelphijoutnet_udp_cb(struct comm_point* c, void* arg, int error,
555171476Sdelphij	struct comm_reply *reply_info)
556171476Sdelphij{
557171476Sdelphij	struct outside_network* outnet = (struct outside_network*)arg;
558171476Sdelphij	struct pending key;
559171476Sdelphij	struct pending* p;
560171476Sdelphij	verbose(VERB_ALGO, "answer cb");
561171476Sdelphij
562171476Sdelphij	if(error != NETEVENT_NOERROR) {
563171476Sdelphij		verbose(VERB_QUERY, "outnetudp got udp error %d", error);
564171476Sdelphij		return 0;
565171476Sdelphij	}
566171476Sdelphij	if(sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) {
567171476Sdelphij		verbose(VERB_QUERY, "outnetudp udp too short");
568171476Sdelphij		return 0;
569171476Sdelphij	}
570171476Sdelphij	log_assert(reply_info);
571171476Sdelphij
572171476Sdelphij	/* setup lookup key */
573171476Sdelphij	key.id = (unsigned)LDNS_ID_WIRE(sldns_buffer_begin(c->buffer));
574171476Sdelphij	memcpy(&key.addr, &reply_info->addr, reply_info->addrlen);
575171476Sdelphij	key.addrlen = reply_info->addrlen;
576171476Sdelphij	verbose(VERB_ALGO, "Incoming reply id = %4.4x", key.id);
577171476Sdelphij	log_addr(VERB_ALGO, "Incoming reply addr =",
578171476Sdelphij		&reply_info->addr, reply_info->addrlen);
579171476Sdelphij
580171476Sdelphij	/* find it, see if this thing is a valid query response */
581171476Sdelphij	verbose(VERB_ALGO, "lookup size is %d entries", (int)outnet->pending->count);
582171476Sdelphij	p = (struct pending*)rbtree_search(outnet->pending, &key);
583171476Sdelphij	if(!p) {
584171476Sdelphij		verbose(VERB_QUERY, "received unwanted or unsolicited udp reply dropped.");
585171476Sdelphij		log_buf(VERB_ALGO, "dropped message", c->buffer);
586171476Sdelphij		outnet->unwanted_replies++;
587171476Sdelphij		if(outnet->unwanted_threshold && ++outnet->unwanted_total
588171476Sdelphij			>= outnet->unwanted_threshold) {
589171476Sdelphij			log_warn("unwanted reply total reached threshold (%u)"
590171476Sdelphij				" you may be under attack."
591171476Sdelphij				" defensive action: clearing the cache",
592171476Sdelphij				(unsigned)outnet->unwanted_threshold);
593171476Sdelphij			fptr_ok(fptr_whitelist_alloc_cleanup(
594171476Sdelphij				outnet->unwanted_action));
595171476Sdelphij			(*outnet->unwanted_action)(outnet->unwanted_param);
596171476Sdelphij			outnet->unwanted_total = 0;
597171476Sdelphij		}
598171476Sdelphij		return 0;
599171476Sdelphij	}
600171476Sdelphij
601171476Sdelphij	verbose(VERB_ALGO, "received udp reply.");
602171476Sdelphij	log_buf(VERB_ALGO, "udp message", c->buffer);
603171476Sdelphij	if(p->pc->cp != c) {
604171476Sdelphij		verbose(VERB_QUERY, "received reply id,addr on wrong port. "
605171476Sdelphij			"dropped.");
606171476Sdelphij		outnet->unwanted_replies++;
607171476Sdelphij		if(outnet->unwanted_threshold && ++outnet->unwanted_total
608171476Sdelphij			>= outnet->unwanted_threshold) {
609171476Sdelphij			log_warn("unwanted reply total reached threshold (%u)"
610171476Sdelphij				" you may be under attack."
611171476Sdelphij				" defensive action: clearing the cache",
612171476Sdelphij				(unsigned)outnet->unwanted_threshold);
613171476Sdelphij			fptr_ok(fptr_whitelist_alloc_cleanup(
614171476Sdelphij				outnet->unwanted_action));
615171476Sdelphij			(*outnet->unwanted_action)(outnet->unwanted_param);
616171476Sdelphij			outnet->unwanted_total = 0;
617171476Sdelphij		}
618171476Sdelphij		return 0;
619171476Sdelphij	}
620171476Sdelphij	comm_timer_disable(p->timer);
621171476Sdelphij	verbose(VERB_ALGO, "outnet handle udp reply");
622171476Sdelphij	/* delete from tree first in case callback creates a retry */
623171476Sdelphij	(void)rbtree_delete(outnet->pending, p->node.key);
624171476Sdelphij	if(p->cb) {
625171476Sdelphij		fptr_ok(fptr_whitelist_pending_udp(p->cb));
626171476Sdelphij		(void)(*p->cb)(p->pc->cp, p->cb_arg, NETEVENT_NOERROR, reply_info);
627171476Sdelphij	}
628171476Sdelphij	portcomm_loweruse(outnet, p->pc);
629171476Sdelphij	pending_delete(NULL, p);
630171476Sdelphij	outnet_send_wait_udp(outnet);
631171476Sdelphij	return 0;
632171476Sdelphij}
633171476Sdelphij
634171476Sdelphij/** calculate number of ip4 and ip6 interfaces*/
635171476Sdelphijstatic void
636171476Sdelphijcalc_num46(char** ifs, int num_ifs, int do_ip4, int do_ip6,
637171476Sdelphij	int* num_ip4, int* num_ip6)
638171476Sdelphij{
639171476Sdelphij	int i;
640171476Sdelphij	*num_ip4 = 0;
641171476Sdelphij	*num_ip6 = 0;
642171476Sdelphij	if(num_ifs <= 0) {
643171476Sdelphij		if(do_ip4)
644171476Sdelphij			*num_ip4 = 1;
645171476Sdelphij		if(do_ip6)
646171476Sdelphij			*num_ip6 = 1;
647171476Sdelphij		return;
648171476Sdelphij	}
649171476Sdelphij	for(i=0; i<num_ifs; i++)
650171476Sdelphij	{
651171476Sdelphij		if(str_is_ip6(ifs[i])) {
652171476Sdelphij			if(do_ip6)
653171476Sdelphij				(*num_ip6)++;
654171476Sdelphij		} else {
655171476Sdelphij			if(do_ip4)
656171476Sdelphij				(*num_ip4)++;
657171476Sdelphij		}
658171476Sdelphij	}
659171476Sdelphij
660171476Sdelphij}
661171476Sdelphij
662171476Sdelphijvoid
663171476Sdelphijpending_udp_timer_delay_cb(void* arg)
664171476Sdelphij{
665171476Sdelphij	struct pending* p = (struct pending*)arg;
666171476Sdelphij	struct outside_network* outnet = p->outnet;
667171476Sdelphij	verbose(VERB_ALGO, "timeout udp with delay");
668169445Sroberto	portcomm_loweruse(outnet, p->pc);
669169445Sroberto	pending_delete(outnet, p);
670169445Sroberto	outnet_send_wait_udp(outnet);
671169026Semax}
672169026Semax
673168916Sbrueffervoid
674168916Sbruefferpending_udp_timer_cb(void *arg)
675168796Sthompsa{
676168796Sthompsa	struct pending* p = (struct pending*)arg;
677168544Spjd	struct outside_network* outnet = p->outnet;
678168544Spjd	/* it timed out */
679167980Sdelphij	verbose(VERB_ALGO, "timeout udp");
680167980Sdelphij	if(p->cb) {
681167699Sdelphij		fptr_ok(fptr_whitelist_pending_udp(p->cb));
682167699Sdelphij		(void)(*p->cb)(p->pc->cp, p->cb_arg, NETEVENT_TIMEOUT, NULL);
683176956Santoine	}
684176956Santoine	/* if delayclose, keep port open for a longer time.
685176956Santoine	 * But if the udpwaitlist exists, then we are struggling to
686167137Sbms	 * keep up with demand for sockets, so do not wait, but service
687167137Sbms	 * the customer (customer service more important than portICMPs) */
688170190Sru	if(outnet->delayclose && !outnet->udp_wait_first) {
689166981Sru		p->cb = NULL;
690166981Sru		p->timer->callback = &pending_udp_timer_delay_cb;
691170192Sru		comm_timer_set(p->timer, &outnet->delay_tv);
692170218Struckman		return;
693166668Sbrueffer	}
694166668Sbrueffer	portcomm_loweruse(outnet, p->pc);
695166389Srafan	pending_delete(outnet, p);
696166389Srafan	outnet_send_wait_udp(outnet);
697166389Srafan}
698172882Sru
699172882Sru/** create pending_tcp buffers */
700172882Srustatic int
701172882Srucreate_pending_tcp(struct outside_network* outnet, size_t bufsize)
702170190Sru{
703170190Sru	size_t i;
704170190Sru	if(outnet->num_tcp == 0)
705170190Sru		return 1; /* no tcp needed, nothing to do */
706172882Sru	if(!(outnet->tcp_conns = (struct pending_tcp **)calloc(
707172882Sru			outnet->num_tcp, sizeof(struct pending_tcp*))))
708172882Sru		return 0;
709170190Sru	for(i=0; i<outnet->num_tcp; i++) {
710166308Sphk		if(!(outnet->tcp_conns[i] = (struct pending_tcp*)calloc(1,
711166308Sphk			sizeof(struct pending_tcp))))
712170192Sru			return 0;
713170192Sru		outnet->tcp_conns[i]->next_free = outnet->tcp_free;
714166246Speter		outnet->tcp_free = outnet->tcp_conns[i];
715166246Speter		outnet->tcp_conns[i]->c = comm_point_create_tcp_out(
716166246Speter			outnet->base, bufsize, outnet_tcp_cb,
717166246Speter			outnet->tcp_conns[i]);
718166246Speter		if(!outnet->tcp_conns[i]->c)
719164796Spiso			return 0;
720164796Spiso	}
721164796Spiso	return 1;
722164796Spiso}
723164796Spiso
724164796Spiso/** setup an outgoing interface, ready address */
725164796Spisostatic int setup_if(struct port_if* pif, const char* addrstr,
726164796Spiso	int* avail, int numavail, size_t numfd)
727164796Spiso{
728166672Sbrueffer	pif->avail_total = numavail;
729164796Spiso	pif->avail_ports = (int*)memdup(avail, (size_t)numavail*sizeof(int));
730164796Spiso	if(!pif->avail_ports)
731164796Spiso		return 0;
732164796Spiso	if(!ipstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen) &&
733164796Spiso	   !netblockstrtoaddr(addrstr, UNBOUND_DNS_PORT,
734164796Spiso			      &pif->addr, &pif->addrlen, &pif->pfxlen))
735164796Spiso		return 0;
736164796Spiso	pif->maxout = (int)numfd;
737165726Skientzle	pif->inuse = 0;
738165726Skientzle	pif->out = (struct port_comm**)calloc(numfd,
739164610Simp		sizeof(struct port_comm*));
740164610Simp	if(!pif->out)
741164537Srodrigc		return 0;
742164537Srodrigc	return 1;
743164537Srodrigc}
744164537Srodrigc
745164537Srodrigcstruct outside_network*
746164537Srodrigcoutside_network_create(struct comm_base *base, size_t bufsize,
747164537Srodrigc	size_t num_ports, char** ifs, int num_ifs, int do_ip4,
748170190Sru	int do_ip6, size_t num_tcp, struct infra_cache* infra,
749170190Sru	struct ub_randstate* rnd, int use_caps_for_id, int* availports,
750170190Sru	int numavailports, size_t unwanted_threshold, int tcp_mss,
751170190Sru	void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
752170190Sru	void* sslctx, int delayclose, struct dt_env* dtenv)
753170190Sru{
754164537Srodrigc	struct outside_network* outnet = (struct outside_network*)
755164537Srodrigc		calloc(1, sizeof(struct outside_network));
756164537Srodrigc	size_t k;
757164537Srodrigc	if(!outnet) {
758164537Srodrigc		log_err("malloc failed");
759164537Srodrigc		return NULL;
760164344Sbrueffer	}
761164344Sbrueffer	comm_base_timept(base, &outnet->now_secs, &outnet->now_tv);
762170220Struckman	outnet->base = base;
763170220Struckman	outnet->num_tcp = num_tcp;
764164088Smarcel	outnet->num_tcp_outgoing = 0;
765164088Smarcel	outnet->infra = infra;
766164088Smarcel	outnet->rnd = rnd;
767164088Smarcel	outnet->sslctx = sslctx;
768163570Sru#ifdef USE_DNSTAP
769163570Sru	outnet->dtenv = dtenv;
770162837Sdelphij#else
771162837Sdelphij	(void)dtenv;
772162780Sbms#endif
773162780Sbms	outnet->svcd_overhead = 0;
774162780Sbms	outnet->want_to_quit = 0;
775162780Sbms	outnet->unwanted_threshold = unwanted_threshold;
776162780Sbms	outnet->unwanted_action = unwanted_action;
777162780Sbms	outnet->unwanted_param = unwanted_param;
778162780Sbms	outnet->use_caps_for_id = use_caps_for_id;
779162780Sbms	outnet->do_udp = do_udp;
780162780Sbms	outnet->tcp_mss = tcp_mss;
781162598Ssimon#ifndef S_SPLINT_S
782162598Ssimon	if(delayclose) {
783162598Ssimon		outnet->delayclose = 1;
784162716Sdelphij		outnet->delay_tv.tv_sec = delayclose/1000;
785162716Sdelphij		outnet->delay_tv.tv_usec = (delayclose%1000)*1000;
786161529Sflz	}
787161529Sflz#endif
788161529Sflz	if(numavailports == 0 || num_ports == 0) {
789170192Sru		log_err("no outgoing ports available");
790170192Sru		outside_network_delete(outnet);
791170192Sru		return NULL;
792170192Sru	}
793170192Sru#ifndef INET6
794170192Sru	do_ip6 = 0;
795170192Sru#endif
796170192Sru	calc_num46(ifs, num_ifs, do_ip4, do_ip6,
797170192Sru		&outnet->num_ip4, &outnet->num_ip6);
798170192Sru	if(outnet->num_ip4 != 0) {
799170192Sru		if(!(outnet->ip4_ifs = (struct port_if*)calloc(
800170192Sru			(size_t)outnet->num_ip4, sizeof(struct port_if)))) {
801170192Sru			log_err("malloc failed");
802160983Sbrooks			outside_network_delete(outnet);
803160983Sbrooks			return NULL;
804170255Struckman		}
805170255Struckman	}
806170255Struckman	if(outnet->num_ip6 != 0) {
807170255Struckman		if(!(outnet->ip6_ifs = (struct port_if*)calloc(
808158687Sphk			(size_t)outnet->num_ip6, sizeof(struct port_if)))) {
809158687Sphk			log_err("malloc failed");
810158687Sphk			outside_network_delete(outnet);
811158687Sphk			return NULL;
812158687Sphk		}
813158687Sphk	}
814158687Sphk	if(	!(outnet->udp_buff = sldns_buffer_new(bufsize)) ||
815158687Sphk		!(outnet->pending = rbtree_create(pending_cmp)) ||
816158687Sphk		!(outnet->serviced = rbtree_create(serviced_cmp)) ||
817158687Sphk		!create_pending_tcp(outnet, bufsize)) {
818158687Sphk		log_err("malloc failed");
819158687Sphk		outside_network_delete(outnet);
820158687Sphk		return NULL;
821158687Sphk	}
822158687Sphk
823158687Sphk	/* allocate commpoints */
824158687Sphk	for(k=0; k<num_ports; k++) {
825158687Sphk		struct port_comm* pc;
826158687Sphk		pc = (struct port_comm*)calloc(1, sizeof(*pc));
827158687Sphk		if(!pc) {
828158687Sphk			log_err("malloc failed");
829158687Sphk			outside_network_delete(outnet);
830158687Sphk			return NULL;
831158687Sphk		}
832158687Sphk		pc->cp = comm_point_create_udp(outnet->base, -1,
833158687Sphk			outnet->udp_buff, outnet_udp_cb, outnet);
834158687Sphk		if(!pc->cp) {
835158687Sphk			log_err("malloc failed");
836158687Sphk			free(pc);
837158687Sphk			outside_network_delete(outnet);
838158687Sphk			return NULL;
839158687Sphk		}
840158687Sphk		pc->next = outnet->unused_fds;
841158687Sphk		outnet->unused_fds = pc;
842158687Sphk	}
843158687Sphk
844158687Sphk	/* allocate interfaces */
845158687Sphk	if(num_ifs == 0) {
846158687Sphk		if(do_ip4 && !setup_if(&outnet->ip4_ifs[0], "0.0.0.0",
847158687Sphk			availports, numavailports, num_ports)) {
848158687Sphk			log_err("malloc failed");
849158687Sphk			outside_network_delete(outnet);
850158687Sphk			return NULL;
851158687Sphk		}
852158687Sphk		if(do_ip6 && !setup_if(&outnet->ip6_ifs[0], "::",
853158687Sphk			availports, numavailports, num_ports)) {
854158687Sphk			log_err("malloc failed");
855158687Sphk			outside_network_delete(outnet);
856158687Sphk			return NULL;
857158687Sphk		}
858158687Sphk	} else {
859158687Sphk		size_t done_4 = 0, done_6 = 0;
860158687Sphk		int i;
861158618Smaxim		for(i=0; i<num_ifs; i++) {
862158618Smaxim			if(str_is_ip6(ifs[i]) && do_ip6) {
863158618Smaxim				if(!setup_if(&outnet->ip6_ifs[done_6], ifs[i],
864158512Smlaier					availports, numavailports, num_ports)){
865158512Smlaier					log_err("malloc failed");
866158512Smlaier					outside_network_delete(outnet);
867158512Smlaier					return NULL;
868158512Smlaier				}
869158754Smarcel				done_6++;
870158754Smarcel			}
871157221Ssimon			if(!str_is_ip6(ifs[i]) && do_ip4) {
872157221Ssimon				if(!setup_if(&outnet->ip4_ifs[done_4], ifs[i],
873156676Sharti					availports, numavailports, num_ports)){
874156676Sharti					log_err("malloc failed");
875170190Sru					outside_network_delete(outnet);
876170190Sru					return NULL;
877170190Sru				}
878170190Sru				done_4++;
879170190Sru			}
880170190Sru		}
881170190Sru	}
882170190Sru	return outnet;
883153662Sjhb}
884153662Sjhb
885153430Siedowse/** helper pending delete */
886153430Siedowsestatic void
887153430Siedowsepending_node_del(rbnode_type* node, void* arg)
888153430Siedowse{
889153430Siedowse	struct pending* pend = (struct pending*)node;
890151845Syar	struct outside_network* outnet = (struct outside_network*)arg;
891151845Syar	pending_delete(outnet, pend);
892151271Spjd}
893151271Spjd
894162025Smatusita/** helper serviced delete */
895162025Smatusitastatic void
896162025Smatusitaserviced_node_del(rbnode_type* node, void* ATTR_UNUSED(arg))
897162025Smatusita{
898150676Smlaier	struct serviced_query* sq = (struct serviced_query*)node;
899150677Smlaier	struct service_callback* p = sq->cblist, *np;
900150002Snetchild	free(sq->qbuf);
901150002Snetchild	free(sq->zone);
902150002Snetchild	free(sq->tls_auth_name);
903150002Snetchild	edns_opt_list_free(sq->opt_list);
904149454Sglebius	while(p) {
905148808Sru		np = p->next;
906148808Sru		free(p);
907148825Snetchild		p = np;
908148825Snetchild	}
909148356Sdougb	free(sq);
910148356Sdougb}
911148572Snetchild
912170220Struckmanvoid
913170220Struckmanoutside_network_quit_prepare(struct outside_network* outnet)
914170220Struckman{
915170220Struckman	if(!outnet)
916170220Struckman		return;
917148330Snetchild	/* prevent queued items from being sent */
918148330Snetchild	outnet->want_to_quit = 1;
919148330Snetchild}
920148330Snetchild
921148572Snetchildvoid
922148572Snetchildoutside_network_delete(struct outside_network* outnet)
923149105Simp{
924148572Snetchild	if(!outnet)
925148572Snetchild		return;
926148572Snetchild	outnet->want_to_quit = 1;
927172026Syar	/* check every element, since we can be called on malloc error */
928172026Syar	if(outnet->pending) {
929172026Syar		/* free pending elements, but do no unlink from tree. */
930172026Syar		traverse_postorder(outnet->pending, pending_node_del, NULL);
931148572Snetchild		free(outnet->pending);
932148572Snetchild	}
933148572Snetchild	if(outnet->serviced) {
934148572Snetchild		traverse_postorder(outnet->serviced, serviced_node_del, NULL);
935148572Snetchild		free(outnet->serviced);
936148572Snetchild	}
937148572Snetchild	if(outnet->udp_buff)
938148572Snetchild		sldns_buffer_free(outnet->udp_buff);
939148572Snetchild	if(outnet->unused_fds) {
940148572Snetchild		struct port_comm* p = outnet->unused_fds, *np;
941148572Snetchild		while(p) {
942153939Snetchild			np = p->next;
943153939Snetchild			comm_point_delete(p->cp);
944153939Snetchild			free(p);
945153939Snetchild			p = np;
946148330Snetchild		}
947148330Snetchild		outnet->unused_fds = NULL;
948148423Sdougb	}
949148423Sdougb	if(outnet->ip4_ifs) {
950148330Snetchild		int i, k;
951148330Snetchild		for(i=0; i<outnet->num_ip4; i++) {
952148330Snetchild			for(k=0; k<outnet->ip4_ifs[i].inuse; k++) {
953148330Snetchild				struct port_comm* pc = outnet->ip4_ifs[i].
954148572Snetchild					out[k];
955148572Snetchild				comm_point_delete(pc->cp);
956148353Sdougb				free(pc);
957148353Sdougb			}
958149105Simp			free(outnet->ip4_ifs[i].avail_ports);
959149105Simp			free(outnet->ip4_ifs[i].out);
960148572Snetchild		}
961148572Snetchild		free(outnet->ip4_ifs);
962172026Syar	}
963149105Simp	if(outnet->ip6_ifs) {
964148572Snetchild		int i, k;
965155813Snetchild		for(i=0; i<outnet->num_ip6; i++) {
966155813Snetchild			for(k=0; k<outnet->ip6_ifs[i].inuse; k++) {
967155813Snetchild				struct port_comm* pc = outnet->ip6_ifs[i].
968155813Snetchild					out[k];
969148330Snetchild				comm_point_delete(pc->cp);
970148330Snetchild				free(pc);
971148330Snetchild			}
972163991Strhodes			free(outnet->ip6_ifs[i].avail_ports);
973163991Strhodes			free(outnet->ip6_ifs[i].out);
974163991Strhodes		}
975163991Strhodes		free(outnet->ip6_ifs);
976163991Strhodes	}
977163991Strhodes	if(outnet->tcp_conns) {
978163991Strhodes		size_t i;
979163991Strhodes		for(i=0; i<outnet->num_tcp; i++)
980163991Strhodes			if(outnet->tcp_conns[i]) {
981163991Strhodes				comm_point_delete(outnet->tcp_conns[i]->c);
982163991Strhodes				waiting_tcp_delete(outnet->tcp_conns[i]->query);
983148330Snetchild				free(outnet->tcp_conns[i]);
984148330Snetchild			}
985148330Snetchild		free(outnet->tcp_conns);
986148330Snetchild	}
987155813Snetchild	if(outnet->tcp_wait_first) {
988148330Snetchild		struct waiting_tcp* p = outnet->tcp_wait_first, *np;
989148330Snetchild		while(p) {
990148330Snetchild			np = p->next_waiting;
991148330Snetchild			waiting_tcp_delete(p);
992148330Snetchild			p = np;
993148330Snetchild		}
994148543Snetchild	}
995148543Snetchild	if(outnet->udp_wait_first) {
996148543Snetchild		struct pending* p = outnet->udp_wait_first, *np;
997148543Snetchild		while(p) {
998148543Snetchild			np = p->next_waiting;
999148543Snetchild			pending_delete(NULL, p);
1000148543Snetchild			p = np;
1001148543Snetchild		}
1002148543Snetchild	}
1003148543Snetchild	free(outnet);
1004148543Snetchild}
1005148543Snetchild
1006148543Snetchildvoid
1007148543Snetchildpending_delete(struct outside_network* outnet, struct pending* p)
1008148543Snetchild{
1009148543Snetchild	if(!p)
1010148543Snetchild		return;
1011148543Snetchild	if(outnet && outnet->udp_wait_first &&
1012148543Snetchild		(p->next_waiting || p == outnet->udp_wait_last) ) {
1013148543Snetchild		/* delete from waiting list, if it is in the waiting list */
1014148543Snetchild		struct pending* prev = NULL, *x = outnet->udp_wait_first;
1015148572Snetchild		while(x && x != p) {
1016148572Snetchild			prev = x;
1017148572Snetchild			x = x->next_waiting;
1018148572Snetchild		}
1019148572Snetchild		if(x) {
1020148572Snetchild			log_assert(x == p);
1021148572Snetchild			if(prev)
1022148572Snetchild				prev->next_waiting = p->next_waiting;
1023148572Snetchild			else	outnet->udp_wait_first = p->next_waiting;
1024148572Snetchild			if(outnet->udp_wait_last == p)
1025148572Snetchild				outnet->udp_wait_last = prev;
1026148572Snetchild		}
1027148572Snetchild	}
1028148572Snetchild	if(outnet) {
1029148572Snetchild		(void)rbtree_delete(outnet->pending, p->node.key);
1030148572Snetchild	}
1031148572Snetchild	if(p->timer)
1032148572Snetchild		comm_timer_delete(p->timer);
1033148572Snetchild	free(p->pkt);
1034148572Snetchild	free(p);
1035148572Snetchild}
1036148572Snetchild
1037148572Snetchildstatic void
1038148572Snetchildsai6_putrandom(struct sockaddr_in6 *sa, int pfxlen, struct ub_randstate *rnd)
1039148572Snetchild{
1040148572Snetchild	int i, last;
1041148572Snetchild	if(!(pfxlen > 0 && pfxlen < 128))
1042148572Snetchild		return;
1043148572Snetchild	for(i = 0; i < (128 - pfxlen) / 8; i++) {
1044148572Snetchild		sa->sin6_addr.s6_addr[15-i] = (uint8_t)ub_random_max(rnd, 256);
1045148572Snetchild	}
1046148572Snetchild	last = pfxlen & 7;
1047148572Snetchild	if(last != 0) {
1048148572Snetchild		sa->sin6_addr.s6_addr[15-i] |=
1049148572Snetchild			((0xFF >> last) & ub_random_max(rnd, 256));
1050148572Snetchild	}
1051148572Snetchild}
1052148572Snetchild
1053148572Snetchild/**
1054148572Snetchild * Try to open a UDP socket for outgoing communication.
1055148572Snetchild * Sets sockets options as needed.
1056148572Snetchild * @param addr: socket address.
1057148572Snetchild * @param addrlen: length of address.
1058148572Snetchild * @param pfxlen: length of network prefix (for address randomisation).
1059148572Snetchild * @param port: port override for addr.
1060148572Snetchild * @param inuse: if -1 is returned, this bool means the port was in use.
1061148572Snetchild * @param rnd: random state (for address randomisation).
1062148572Snetchild * @return fd or -1
1063148572Snetchild */
1064148572Snetchildstatic int
1065148572Snetchildudp_sockport(struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen,
1066148572Snetchild	int port, int* inuse, struct ub_randstate* rnd)
1067148572Snetchild{
1068148572Snetchild	int fd, noproto;
1069148572Snetchild	if(addr_is_ip6(addr, addrlen)) {
1070148572Snetchild		int freebind = 0;
1071148572Snetchild		struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr;
1072148572Snetchild		sa.sin6_port = (in_port_t)htons((uint16_t)port);
1073148572Snetchild		sa.sin6_flowinfo = 0;
1074148572Snetchild		sa.sin6_scope_id = 0;
1075148572Snetchild		if(pfxlen != 0) {
1076148572Snetchild			freebind = 1;
1077148572Snetchild			sai6_putrandom(&sa, pfxlen, rnd);
1078148572Snetchild		}
1079148572Snetchild		fd = create_udp_sock(AF_INET6, SOCK_DGRAM,
1080148572Snetchild			(struct sockaddr*)&sa, addrlen, 1, inuse, &noproto,
1081148572Snetchild			0, 0, 0, NULL, 0, freebind, 0);
1082148572Snetchild	} else {
1083148572Snetchild		struct sockaddr_in* sa = (struct sockaddr_in*)addr;
1084148572Snetchild		sa->sin_port = (in_port_t)htons((uint16_t)port);
1085148572Snetchild		fd = create_udp_sock(AF_INET, SOCK_DGRAM,
1086148572Snetchild			(struct sockaddr*)addr, addrlen, 1, inuse, &noproto,
1087148572Snetchild			0, 0, 0, NULL, 0, 0, 0);
1088148572Snetchild	}
1089148572Snetchild	return fd;
1090148572Snetchild}
1091148572Snetchild
1092148572Snetchild/** Select random ID */
1093148572Snetchildstatic int
1094148572Snetchildselect_id(struct outside_network* outnet, struct pending* pend,
1095148572Snetchild	sldns_buffer* packet)
1096148572Snetchild{
1097148572Snetchild	int id_tries = 0;
1098148572Snetchild	pend->id = ((unsigned)ub_random(outnet->rnd)>>8) & 0xffff;
1099148572Snetchild	LDNS_ID_SET(sldns_buffer_begin(packet), pend->id);
1100148572Snetchild
1101148572Snetchild	/* insert in tree */
1102148572Snetchild	pend->node.key = pend;
1103148572Snetchild	while(!rbtree_insert(outnet->pending, &pend->node)) {
1104148572Snetchild		/* change ID to avoid collision */
1105148572Snetchild		pend->id = ((unsigned)ub_random(outnet->rnd)>>8) & 0xffff;
1106148572Snetchild		LDNS_ID_SET(sldns_buffer_begin(packet), pend->id);
1107148572Snetchild		id_tries++;
1108148572Snetchild		if(id_tries == MAX_ID_RETRY) {
1109148572Snetchild			pend->id=99999; /* non existant ID */
1110148572Snetchild			log_err("failed to generate unique ID, drop msg");
1111148572Snetchild			return 0;
1112148572Snetchild		}
1113148572Snetchild	}
1114148572Snetchild	verbose(VERB_ALGO, "inserted new pending reply id=%4.4x", pend->id);
1115148572Snetchild	return 1;
1116148572Snetchild}
1117148572Snetchild
1118148572Snetchild/** Select random interface and port */
1119148572Snetchildstatic int
1120148572Snetchildselect_ifport(struct outside_network* outnet, struct pending* pend,
1121148572Snetchild	int num_if, struct port_if* ifs)
1122148572Snetchild{
1123148330Snetchild	int my_if, my_port, fd, portno, inuse, tries=0;
1124148330Snetchild	struct port_if* pif;
1125148330Snetchild	/* randomly select interface and port */
1126148330Snetchild	if(num_if == 0) {
1127148330Snetchild		verbose(VERB_QUERY, "Need to send query but have no "
1128148572Snetchild			"outgoing interfaces of that family");
1129148572Snetchild		return 0;
1130148572Snetchild	}
1131148572Snetchild	log_assert(outnet->unused_fds);
1132148572Snetchild	tries = 0;
1133148572Snetchild	while(1) {
1134177625Sremko		my_if = ub_random_max(outnet->rnd, num_if);
1135177625Sremko		pif = &ifs[my_if];
1136177625Sremko		my_port = ub_random_max(outnet->rnd, pif->avail_total);
1137148572Snetchild		if(my_port < pif->inuse) {
1138148572Snetchild			/* port already open */
1139148572Snetchild			pend->pc = pif->out[my_port];
1140148572Snetchild			verbose(VERB_ALGO, "using UDP if=%d port=%d",
1141149113Simp				my_if, pend->pc->number);
1142149113Simp			break;
1143149113Simp		}
1144149113Simp		/* try to open new port, if fails, loop to try again */
1145149113Simp		log_assert(pif->inuse < pif->maxout);
1146149113Simp		portno = pif->avail_ports[my_port - pif->inuse];
1147149113Simp		fd = udp_sockport(&pif->addr, pif->addrlen, pif->pfxlen,
1148148572Snetchild			portno, &inuse, outnet->rnd);
1149148572Snetchild		if(fd == -1 && !inuse) {
1150148572Snetchild			/* nonrecoverable error making socket */
1151148572Snetchild			return 0;
1152148572Snetchild		}
1153149105Simp		if(fd != -1) {
1154148572Snetchild			verbose(VERB_ALGO, "opened UDP if=%d port=%d",
1155148572Snetchild				my_if, portno);
1156148572Snetchild			/* grab fd */
1157148572Snetchild			pend->pc = outnet->unused_fds;
1158148572Snetchild			outnet->unused_fds = pend->pc->next;
1159148572Snetchild
1160148572Snetchild			/* setup portcomm */
1161148572Snetchild			pend->pc->next = NULL;
1162170220Struckman			pend->pc->number = portno;
1163170220Struckman			pend->pc->pif = pif;
1164156385Syar			pend->pc->index = pif->inuse;
1165156385Syar			pend->pc->num_outstanding = 0;
1166148330Snetchild			comm_point_start_listening(pend->pc->cp, fd, -1);
1167148330Snetchild
1168148330Snetchild			/* grab port in interface */
1169148330Snetchild			pif->out[pif->inuse] = pend->pc;
1170148330Snetchild			pif->avail_ports[my_port - pif->inuse] =
1171148330Snetchild				pif->avail_ports[pif->avail_total-pif->inuse-1];
1172148330Snetchild			pif->inuse++;
1173148330Snetchild			break;
1174148330Snetchild		}
1175148330Snetchild		/* failed, already in use */
1176148330Snetchild		verbose(VERB_QUERY, "port %d in use, trying another", portno);
1177148330Snetchild		tries++;
1178148330Snetchild		if(tries == MAX_PORT_RETRY) {
1179148330Snetchild			log_err("failed to find an open port, drop msg");
1180148330Snetchild			return 0;
1181148330Snetchild		}
1182148330Snetchild	}
1183148330Snetchild	log_assert(pend->pc);
1184148330Snetchild	pend->pc->num_outstanding++;
1185148330Snetchild
1186148330Snetchild	return 1;
1187148572Snetchild}
1188148572Snetchild
1189149105Simpstatic int
1190148572Snetchildrandomize_and_send_udp(struct pending* pend, sldns_buffer* packet, int timeout)
1191148572Snetchild{
1192148572Snetchild	struct timeval tv;
1193148572Snetchild	struct outside_network* outnet = pend->sq->outnet;
1194148572Snetchild
1195148572Snetchild	/* select id */
1196148572Snetchild	if(!select_id(outnet, pend, packet)) {
1197155279Savatar		return 0;
1198155279Savatar	}
1199155279Savatar
1200155279Savatar	/* select src_if, port */
1201148572Snetchild	if(addr_is_ip6(&pend->addr, pend->addrlen)) {
1202148572Snetchild		if(!select_ifport(outnet, pend,
1203148572Snetchild			outnet->num_ip6, outnet->ip6_ifs))
1204148330Snetchild			return 0;
1205148330Snetchild	} else {
1206148330Snetchild		if(!select_ifport(outnet, pend,
1207148330Snetchild			outnet->num_ip4, outnet->ip4_ifs))
1208148330Snetchild			return 0;
1209148330Snetchild	}
1210148330Snetchild	log_assert(pend->pc && pend->pc->cp);
1211148330Snetchild
1212148330Snetchild	/* send it over the commlink */
1213148330Snetchild	if(!comm_point_send_udp_msg(pend->pc->cp, packet,
1214148330Snetchild		(struct sockaddr*)&pend->addr, pend->addrlen)) {
1215148330Snetchild		portcomm_loweruse(outnet, pend->pc);
1216148330Snetchild		return 0;
1217148330Snetchild	}
1218148330Snetchild
1219148330Snetchild	/* system calls to set timeout after sending UDP to make roundtrip
1220149105Simp	   smaller. */
1221149105Simp#ifndef S_SPLINT_S
1222148572Snetchild	tv.tv_sec = timeout/1000;
1223170219Struckman	tv.tv_usec = (timeout%1000)*1000;
1224148572Snetchild#endif
1225148572Snetchild	comm_timer_set(pend->timer, &tv);
1226148572Snetchild
1227148330Snetchild#ifdef USE_DNSTAP
1228148330Snetchild	if(outnet->dtenv &&
1229148330Snetchild	   (outnet->dtenv->log_resolver_query_messages ||
1230148330Snetchild	    outnet->dtenv->log_forwarder_query_messages))
1231148330Snetchild		dt_msg_send_outside_query(outnet->dtenv, &pend->addr, comm_udp,
1232148330Snetchild		pend->sq->zone, pend->sq->zonelen, packet);
1233148330Snetchild#endif
1234148330Snetchild	return 1;
1235148330Snetchild}
1236148330Snetchild
1237148330Snetchildstruct pending*
1238148330Snetchildpending_udp_query(struct serviced_query* sq, struct sldns_buffer* packet,
1239148330Snetchild	int timeout, comm_point_callback_type* cb, void* cb_arg)
1240148330Snetchild{
1241148330Snetchild	struct pending* pend = (struct pending*)calloc(1, sizeof(*pend));
1242148330Snetchild	if(!pend) return NULL;
1243148330Snetchild	pend->outnet = sq->outnet;
1244148330Snetchild	pend->sq = sq;
1245148330Snetchild	pend->addrlen = sq->addrlen;
1246148330Snetchild	memmove(&pend->addr, &sq->addr, sq->addrlen);
1247148330Snetchild	pend->cb = cb;
1248148330Snetchild	pend->cb_arg = cb_arg;
1249148330Snetchild	pend->node.key = pend;
1250148572Snetchild	pend->timer = comm_timer_create(sq->outnet->base, pending_udp_timer_cb,
1251148572Snetchild		pend);
1252148572Snetchild	if(!pend->timer) {
1253148572Snetchild		free(pend);
1254148572Snetchild		return NULL;
1255148572Snetchild	}
1256148572Snetchild
1257148572Snetchild	if(sq->outnet->unused_fds == NULL) {
1258148572Snetchild		/* no unused fd, cannot create a new port (randomly) */
1259148572Snetchild		verbose(VERB_ALGO, "no fds available, udp query waiting");
1260148572Snetchild		pend->timeout = timeout;
1261148572Snetchild		pend->pkt_len = sldns_buffer_limit(packet);
1262148572Snetchild		pend->pkt = (uint8_t*)memdup(sldns_buffer_begin(packet),
1263148572Snetchild			pend->pkt_len);
1264148572Snetchild		if(!pend->pkt) {
1265148572Snetchild			comm_timer_delete(pend->timer);
1266148572Snetchild			free(pend);
1267148572Snetchild			return NULL;
1268148572Snetchild		}
1269148572Snetchild		/* put at end of waiting list */
1270148572Snetchild		if(sq->outnet->udp_wait_last)
1271148572Snetchild			sq->outnet->udp_wait_last->next_waiting = pend;
1272148572Snetchild		else
1273148572Snetchild			sq->outnet->udp_wait_first = pend;
1274148572Snetchild		sq->outnet->udp_wait_last = pend;
1275148572Snetchild		return pend;
1276148572Snetchild	}
1277148572Snetchild	if(!randomize_and_send_udp(pend, packet, timeout)) {
1278148572Snetchild		pending_delete(sq->outnet, pend);
1279148572Snetchild		return NULL;
1280148572Snetchild	}
1281148572Snetchild	return pend;
1282148572Snetchild}
1283148572Snetchild
1284148572Snetchildvoid
1285148572Snetchildoutnet_tcptimer(void* arg)
1286148572Snetchild{
1287148572Snetchild	struct waiting_tcp* w = (struct waiting_tcp*)arg;
1288148572Snetchild	struct outside_network* outnet = w->outnet;
1289148572Snetchild	comm_point_callback_type* cb;
1290148572Snetchild	void* cb_arg;
1291148572Snetchild	if(w->pkt) {
1292148572Snetchild		/* it is on the waiting list */
1293148572Snetchild		waiting_list_remove(outnet, w);
1294148572Snetchild	} else {
1295148572Snetchild		/* it was in use */
1296148572Snetchild		struct pending_tcp* pend=(struct pending_tcp*)w->next_waiting;
1297148572Snetchild		if(pend->c->ssl) {
1298148572Snetchild#ifdef HAVE_SSL
1299148572Snetchild			SSL_shutdown(pend->c->ssl);
1300148572Snetchild			SSL_free(pend->c->ssl);
1301148572Snetchild			pend->c->ssl = NULL;
1302148572Snetchild#endif
1303148572Snetchild		}
1304148572Snetchild		comm_point_close(pend->c);
1305148572Snetchild		pend->query = NULL;
1306148572Snetchild		pend->next_free = outnet->tcp_free;
1307148572Snetchild		outnet->tcp_free = pend;
1308148572Snetchild	}
1309148572Snetchild	cb = w->cb;
1310148572Snetchild	cb_arg = w->cb_arg;
1311148572Snetchild	waiting_tcp_delete(w);
1312148572Snetchild	fptr_ok(fptr_whitelist_pending_tcp(cb));
1313148572Snetchild	(void)(*cb)(NULL, cb_arg, NETEVENT_TIMEOUT, NULL);
1314148572Snetchild	use_free_buffer(outnet);
1315148572Snetchild}
1316148572Snetchild
1317148572Snetchildstruct waiting_tcp*
1318148572Snetchildpending_tcp_query(struct serviced_query* sq, sldns_buffer* packet,
1319148572Snetchild	int timeout, comm_point_callback_type* callback, void* callback_arg)
1320148572Snetchild{
1321148572Snetchild	struct pending_tcp* pend = sq->outnet->tcp_free;
1322148572Snetchild	struct waiting_tcp* w;
1323148572Snetchild	struct timeval tv;
1324148572Snetchild	uint16_t id;
1325148572Snetchild	/* if no buffer is free allocate space to store query */
1326148572Snetchild	w = (struct waiting_tcp*)malloc(sizeof(struct waiting_tcp)
1327148572Snetchild		+ (pend?0:sldns_buffer_limit(packet)));
1328148572Snetchild	if(!w) {
1329148572Snetchild		return NULL;
1330148572Snetchild	}
1331148572Snetchild	if(!(w->timer = comm_timer_create(sq->outnet->base, outnet_tcptimer, w))) {
1332148572Snetchild		free(w);
1333148572Snetchild		return NULL;
1334148572Snetchild	}
1335148572Snetchild	w->pkt = NULL;
1336148572Snetchild	w->pkt_len = 0;
1337148572Snetchild	id = ((unsigned)ub_random(sq->outnet->rnd)>>8) & 0xffff;
1338148572Snetchild	LDNS_ID_SET(sldns_buffer_begin(packet), id);
1339148572Snetchild	memcpy(&w->addr, &sq->addr, sq->addrlen);
1340148572Snetchild	w->addrlen = sq->addrlen;
1341148572Snetchild	w->outnet = sq->outnet;
1342148572Snetchild	w->cb = callback;
1343148572Snetchild	w->cb_arg = callback_arg;
1344148572Snetchild	w->ssl_upstream = sq->ssl_upstream;
1345148572Snetchild	w->tls_auth_name = sq->tls_auth_name;
1346148572Snetchild#ifndef S_SPLINT_S
1347148572Snetchild	tv.tv_sec = timeout/1000;
1348148572Snetchild	tv.tv_usec = (timeout%1000)*1000;
1349149105Simp#endif
1350149105Simp	comm_timer_set(w->timer, &tv);
1351149105Simp	if(pend) {
1352149105Simp		/* we have a buffer available right now */
1353148572Snetchild		if(!outnet_tcp_take_into_use(w, sldns_buffer_begin(packet),
1354164619Snetchild			sldns_buffer_limit(packet))) {
1355164619Snetchild			waiting_tcp_delete(w);
1356148572Snetchild			return NULL;
1357148572Snetchild		}
1358148572Snetchild#ifdef USE_DNSTAP
1359148572Snetchild		if(sq->outnet->dtenv &&
1360148572Snetchild		   (sq->outnet->dtenv->log_resolver_query_messages ||
1361148572Snetchild		    sq->outnet->dtenv->log_forwarder_query_messages))
1362148572Snetchild		dt_msg_send_outside_query(sq->outnet->dtenv, &sq->addr,
1363148572Snetchild		comm_tcp, sq->zone, sq->zonelen, packet);
1364148572Snetchild#endif
1365148572Snetchild	} else {
1366148572Snetchild		/* queue up */
1367148572Snetchild		w->pkt = (uint8_t*)w + sizeof(struct waiting_tcp);
1368148572Snetchild		w->pkt_len = sldns_buffer_limit(packet);
1369148572Snetchild		memmove(w->pkt, sldns_buffer_begin(packet), w->pkt_len);
1370148572Snetchild		w->next_waiting = NULL;
1371148572Snetchild		if(sq->outnet->tcp_wait_last)
1372148572Snetchild			sq->outnet->tcp_wait_last->next_waiting = w;
1373148572Snetchild		else	sq->outnet->tcp_wait_first = w;
1374148572Snetchild		sq->outnet->tcp_wait_last = w;
1375148572Snetchild	}
1376148572Snetchild	return w;
1377148572Snetchild}
1378148572Snetchild
1379148572Snetchild/** create query for serviced queries */
1380148572Snetchildstatic void
1381148572Snetchildserviced_gen_query(sldns_buffer* buff, uint8_t* qname, size_t qnamelen,
1382148572Snetchild	uint16_t qtype, uint16_t qclass, uint16_t flags)
1383148572Snetchild{
1384148572Snetchild	sldns_buffer_clear(buff);
1385148572Snetchild	/* skip id */
1386148572Snetchild	sldns_buffer_write_u16(buff, flags);
1387148572Snetchild	sldns_buffer_write_u16(buff, 1); /* qdcount */
1388148572Snetchild	sldns_buffer_write_u16(buff, 0); /* ancount */
1389148572Snetchild	sldns_buffer_write_u16(buff, 0); /* nscount */
1390148572Snetchild	sldns_buffer_write_u16(buff, 0); /* arcount */
1391148572Snetchild	sldns_buffer_write(buff, qname, qnamelen);
1392148572Snetchild	sldns_buffer_write_u16(buff, qtype);
1393148572Snetchild	sldns_buffer_write_u16(buff, qclass);
1394148572Snetchild	sldns_buffer_flip(buff);
1395148572Snetchild}
1396148572Snetchild
1397148572Snetchild/** lookup serviced query in serviced query rbtree */
1398148572Snetchildstatic struct serviced_query*
1399148572Snetchildlookup_serviced(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
1400148572Snetchild	struct sockaddr_storage* addr, socklen_t addrlen,
1401148572Snetchild	struct edns_option* opt_list)
1402148572Snetchild{
1403148572Snetchild	struct serviced_query key;
1404148572Snetchild	key.node.key = &key;
1405148572Snetchild	key.qbuf = sldns_buffer_begin(buff);
1406148572Snetchild	key.qbuflen = sldns_buffer_limit(buff);
1407148572Snetchild	key.dnssec = dnssec;
1408148572Snetchild	memcpy(&key.addr, addr, addrlen);
1409148572Snetchild	key.addrlen = addrlen;
1410148572Snetchild	key.outnet = outnet;
1411148572Snetchild	key.opt_list = opt_list;
1412148572Snetchild	return (struct serviced_query*)rbtree_search(outnet->serviced, &key);
1413148572Snetchild}
1414149105Simp
1415149105Simp/** Create new serviced entry */
1416149105Simpstatic struct serviced_query*
1417149105Simpserviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
1418149105Simp	int want_dnssec, int nocaps, int tcp_upstream, int ssl_upstream,
1419149105Simp	char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen,
1420149105Simp	uint8_t* zone, size_t zonelen, int qtype, struct edns_option* opt_list)
1421149105Simp{
1422148572Snetchild	struct serviced_query* sq = (struct serviced_query*)malloc(sizeof(*sq));
1423148572Snetchild#ifdef UNBOUND_DEBUG
1424160165Savatar	rbnode_type* ins;
1425160165Savatar#endif
1426148330Snetchild	if(!sq)
1427148330Snetchild		return NULL;
1428148330Snetchild	sq->node.key = sq;
1429149105Simp	sq->qbuf = memdup(sldns_buffer_begin(buff), sldns_buffer_limit(buff));
1430149105Simp	if(!sq->qbuf) {
1431163831Sjmg		free(sq);
1432149105Simp		return NULL;
1433163831Sjmg	}
1434149105Simp	sq->qbuflen = sldns_buffer_limit(buff);
1435149105Simp	sq->zone = memdup(zone, zonelen);
1436149105Simp	if(!sq->zone) {
1437149105Simp		free(sq->qbuf);
1438149105Simp		free(sq);
1439149105Simp		return NULL;
1440149105Simp	}
1441149105Simp	sq->zonelen = zonelen;
1442149105Simp	sq->qtype = qtype;
1443149105Simp	sq->dnssec = dnssec;
1444149105Simp	sq->want_dnssec = want_dnssec;
1445149105Simp	sq->nocaps = nocaps;
1446149105Simp	sq->tcp_upstream = tcp_upstream;
1447149105Simp	sq->ssl_upstream = ssl_upstream;
1448149105Simp	if(tls_auth_name) {
1449149105Simp		sq->tls_auth_name = strdup(tls_auth_name);
1450149105Simp		if(!sq->tls_auth_name) {
1451149105Simp			free(sq->zone);
1452149105Simp			free(sq->qbuf);
1453149105Simp			free(sq);
1454149105Simp			return NULL;
1455149105Simp		}
1456160165Savatar	} else {
1457160165Savatar		sq->tls_auth_name = NULL;
1458160165Savatar	}
1459148330Snetchild	memcpy(&sq->addr, addr, addrlen);
1460148330Snetchild	sq->addrlen = addrlen;
1461148330Snetchild	sq->opt_list = NULL;
1462148330Snetchild	if(opt_list) {
1463148330Snetchild		sq->opt_list = edns_opt_copy_alloc(opt_list);
1464148330Snetchild		if(!sq->opt_list) {
1465148330Snetchild			free(sq->tls_auth_name);
1466148330Snetchild			free(sq->zone);
1467149105Simp			free(sq->qbuf);
1468149105Simp			free(sq);
1469149105Simp			return NULL;
1470149105Simp		}
1471149105Simp	}
1472148330Snetchild	sq->outnet = outnet;
1473149105Simp	sq->cblist = NULL;
1474149105Simp	sq->pending = NULL;
1475149105Simp	sq->status = serviced_initial;
1476149105Simp	sq->retry = 0;
1477149105Simp	sq->to_be_deleted = 0;
1478149105Simp#ifdef UNBOUND_DEBUG
1479149105Simp	ins =
1480149105Simp#else
1481149105Simp	(void)
1482149105Simp#endif
1483149105Simp	rbtree_insert(outnet->serviced, &sq->node);
1484149105Simp	log_assert(ins != NULL); /* must not be already present */
1485149105Simp	return sq;
1486164971Savatar}
1487164971Savatar
1488164971Savatar/** remove waiting tcp from the outnet waiting list */
1489164971Savatarstatic void
1490164971Savatarwaiting_list_remove(struct outside_network* outnet, struct waiting_tcp* w)
1491164971Savatar{
1492164971Savatar	struct waiting_tcp* p = outnet->tcp_wait_first, *prev = NULL;
1493164971Savatar	while(p) {
1494164971Savatar		if(p == w) {
1495164971Savatar			/* remove w */
1496164971Savatar			if(prev)
1497164971Savatar				prev->next_waiting = w->next_waiting;
1498164971Savatar			else	outnet->tcp_wait_first = w->next_waiting;
1499164971Savatar			if(outnet->tcp_wait_last == w)
1500164971Savatar				outnet->tcp_wait_last = prev;
1501164971Savatar			return;
1502164971Savatar		}
1503164971Savatar		prev = p;
1504164971Savatar		p = p->next_waiting;
1505164971Savatar	}
1506164971Savatar}
1507164971Savatar
1508164971Savatar/** cleanup serviced query entry */
1509164971Savatarstatic void
1510164971Savatarserviced_delete(struct serviced_query* sq)
1511160165Savatar{
1512160165Savatar	if(sq->pending) {
1513160165Savatar		/* clear up the pending query */
1514148330Snetchild		if(sq->status == serviced_query_UDP_EDNS ||
1515148330Snetchild			sq->status == serviced_query_UDP ||
1516148330Snetchild			sq->status == serviced_query_UDP_EDNS_FRAG ||
1517148330Snetchild			sq->status == serviced_query_UDP_EDNS_fallback) {
1518149105Simp			struct pending* p = (struct pending*)sq->pending;
1519149105Simp			if(p->pc)
1520149105Simp				portcomm_loweruse(sq->outnet, p->pc);
1521164302Smatteo			pending_delete(sq->outnet, p);
1522164302Smatteo			/* this call can cause reentrant calls back into the
1523148330Snetchild			 * mesh */
1524148330Snetchild			outnet_send_wait_udp(sq->outnet);
1525148330Snetchild		} else {
1526148330Snetchild			struct waiting_tcp* p = (struct waiting_tcp*)
1527148330Snetchild				sq->pending;
1528148330Snetchild			if(p->pkt == NULL) {
1529148330Snetchild				decommission_pending_tcp(sq->outnet,
1530148330Snetchild					(struct pending_tcp*)p->next_waiting);
1531148330Snetchild			} else {
1532148330Snetchild				waiting_list_remove(sq->outnet, p);
1533148330Snetchild				waiting_tcp_delete(p);
1534148330Snetchild			}
1535148330Snetchild		}
1536148330Snetchild	}
1537148330Snetchild	/* does not delete from tree, caller has to do that */
1538148330Snetchild	serviced_node_del(&sq->node, NULL);
1539148543Snetchild}
1540149113Simp
1541149113Simp/** perturb a dname capitalization randomly */
1542149113Simpstatic void
1543149113Simpserviced_perturb_qname(struct ub_randstate* rnd, uint8_t* qbuf, size_t len)
1544149113Simp{
1545149113Simp	uint8_t lablen;
1546149113Simp	uint8_t* d = qbuf + 10;
1547149113Simp	long int random = 0;
1548149113Simp	int bits = 0;
1549149113Simp	log_assert(len >= 10 + 5 /* offset qname, root, qtype, qclass */);
1550149113Simp	(void)len;
1551148330Snetchild	lablen = *d++;
1552148330Snetchild	while(lablen) {
1553149113Simp		while(lablen--) {
1554149113Simp			/* only perturb A-Z, a-z */
1555149113Simp			if(isalpha((unsigned char)*d)) {
1556149113Simp				/* get a random bit */
1557149113Simp				if(bits == 0) {
1558149113Simp					random = ub_random(rnd);
1559149113Simp					bits = 30;
1560149113Simp				}
1561149113Simp				if(random & 0x1) {
1562149113Simp					*d = (uint8_t)toupper((unsigned char)*d);
1563149113Simp				} else {
1564149113Simp					*d = (uint8_t)tolower((unsigned char)*d);
1565149113Simp				}
1566149113Simp				random >>= 1;
1567149113Simp				bits--;
1568149113Simp			}
1569149113Simp			d++;
1570149113Simp		}
1571149113Simp		lablen = *d++;
1572149113Simp	}
1573149113Simp	if(verbosity >= VERB_ALGO) {
1574149113Simp		char buf[LDNS_MAX_DOMAINLEN+1];
1575149113Simp		dname_str(qbuf+10, buf);
1576149113Simp		verbose(VERB_ALGO, "qname perturbed to %s", buf);
1577149113Simp	}
1578149113Simp}
1579149113Simp
1580149113Simp/** put serviced query into a buffer */
1581149113Simpstatic void
1582149113Simpserviced_encode(struct serviced_query* sq, sldns_buffer* buff, int with_edns)
1583149113Simp{
1584149113Simp	/* if we are using 0x20 bits for ID randomness, perturb them */
1585148330Snetchild	if(sq->outnet->use_caps_for_id && !sq->nocaps) {
1586148330Snetchild		serviced_perturb_qname(sq->outnet->rnd, sq->qbuf, sq->qbuflen);
1587148330Snetchild	}
1588148330Snetchild	/* generate query */
1589148330Snetchild	sldns_buffer_clear(buff);
1590148330Snetchild	sldns_buffer_write_u16(buff, 0); /* id placeholder */
1591148330Snetchild	sldns_buffer_write(buff, sq->qbuf, sq->qbuflen);
1592151378Snetchild	sldns_buffer_flip(buff);
1593151378Snetchild	if(with_edns) {
1594151378Snetchild		/* add edns section */
1595151378Snetchild		struct edns_data edns;
1596151378Snetchild		edns.edns_present = 1;
1597151378Snetchild		edns.ext_rcode = 0;
1598151378Snetchild		edns.edns_version = EDNS_ADVERTISED_VERSION;
1599151378Snetchild		edns.opt_list = sq->opt_list;
1600151378Snetchild		if(sq->status == serviced_query_UDP_EDNS_FRAG) {
1601151378Snetchild			if(addr_is_ip6(&sq->addr, sq->addrlen)) {
1602161201Snetchild				if(EDNS_FRAG_SIZE_IP6 < EDNS_ADVERTISED_SIZE)
1603151378Snetchild					edns.udp_size = EDNS_FRAG_SIZE_IP6;
1604151378Snetchild				else	edns.udp_size = EDNS_ADVERTISED_SIZE;
1605151378Snetchild			} else {
1606151378Snetchild				if(EDNS_FRAG_SIZE_IP4 < EDNS_ADVERTISED_SIZE)
1607151378Snetchild					edns.udp_size = EDNS_FRAG_SIZE_IP4;
1608151378Snetchild				else	edns.udp_size = EDNS_ADVERTISED_SIZE;
1609151378Snetchild			}
1610151378Snetchild		} else {
1611151378Snetchild			edns.udp_size = EDNS_ADVERTISED_SIZE;
1612151378Snetchild		}
1613151378Snetchild		edns.bits = 0;
1614151378Snetchild		if(sq->dnssec & EDNS_DO)
1615151378Snetchild			edns.bits = EDNS_DO;
1616151378Snetchild		if(sq->dnssec & BIT_CD)
1617151378Snetchild			LDNS_CD_SET(sldns_buffer_begin(buff));
1618151378Snetchild		attach_edns_record(buff, &edns);
1619151378Snetchild	}
1620151378Snetchild}
1621151378Snetchild
1622151378Snetchild/**
1623151378Snetchild * Perform serviced query UDP sending operation.
1624151378Snetchild * Sends UDP with EDNS, unless infra host marked non EDNS.
1625151378Snetchild * @param sq: query to send.
1626151378Snetchild * @param buff: buffer scratch space.
1627151378Snetchild * @return 0 on error.
1628151378Snetchild */
1629151378Snetchildstatic int
1630151378Snetchildserviced_udp_send(struct serviced_query* sq, sldns_buffer* buff)
1631151378Snetchild{
1632151378Snetchild	int rtt, vs;
1633151378Snetchild	uint8_t edns_lame_known;
1634151378Snetchild	time_t now = *sq->outnet->now_secs;
1635151378Snetchild
1636151378Snetchild	if(!infra_host(sq->outnet->infra, &sq->addr, sq->addrlen, sq->zone,
1637151378Snetchild		sq->zonelen, now, &vs, &edns_lame_known, &rtt))
1638151378Snetchild		return 0;
1639151378Snetchild	sq->last_rtt = rtt;
1640151378Snetchild	verbose(VERB_ALGO, "EDNS lookup known=%d vs=%d", edns_lame_known, vs);
1641151378Snetchild	if(sq->status == serviced_initial) {
1642151378Snetchild		if(vs != -1) {
1643151378Snetchild			sq->status = serviced_query_UDP_EDNS;
1644151378Snetchild		} else {
1645151378Snetchild			sq->status = serviced_query_UDP;
1646151378Snetchild		}
1647151378Snetchild	}
1648151378Snetchild	serviced_encode(sq, buff, (sq->status == serviced_query_UDP_EDNS) ||
1649151378Snetchild		(sq->status == serviced_query_UDP_EDNS_FRAG));
1650151378Snetchild	sq->last_sent_time = *sq->outnet->now_tv;
1651151378Snetchild	sq->edns_lame_known = (int)edns_lame_known;
1652151378Snetchild	verbose(VERB_ALGO, "serviced query UDP timeout=%d msec", rtt);
1653151378Snetchild	sq->pending = pending_udp_query(sq, buff, rtt,
1654151378Snetchild		serviced_udp_callback, sq);
1655151378Snetchild	if(!sq->pending)
1656151378Snetchild		return 0;
1657151378Snetchild	return 1;
1658151378Snetchild}
1659151378Snetchild
1660151378Snetchild/** check that perturbed qname is identical */
1661151378Snetchildstatic int
1662151378Snetchildserviced_check_qname(sldns_buffer* pkt, uint8_t* qbuf, size_t qbuflen)
1663151378Snetchild{
1664151378Snetchild	uint8_t* d1 = sldns_buffer_begin(pkt)+12;
1665151378Snetchild	uint8_t* d2 = qbuf+10;
1666151378Snetchild	uint8_t len1, len2;
1667151378Snetchild	int count = 0;
1668151378Snetchild	if(sldns_buffer_limit(pkt) < 12+1+4) /* packet too small for qname */
1669151378Snetchild		return 0;
1670151378Snetchild	log_assert(qbuflen >= 15 /* 10 header, root, type, class */);
1671151378Snetchild	len1 = *d1++;
1672151378Snetchild	len2 = *d2++;
1673151378Snetchild	while(len1 != 0 || len2 != 0) {
1674151378Snetchild		if(LABEL_IS_PTR(len1)) {
1675151378Snetchild			/* check if we can read *d1 with compression ptr rest */
1676151378Snetchild			if(d1 >= sldns_buffer_at(pkt, sldns_buffer_limit(pkt)))
1677151378Snetchild				return 0;
1678151378Snetchild			d1 = sldns_buffer_begin(pkt)+PTR_OFFSET(len1, *d1);
1679151378Snetchild			/* check if we can read the destination *d1 */
1680151378Snetchild			if(d1 >= sldns_buffer_at(pkt, sldns_buffer_limit(pkt)))
1681151378Snetchild				return 0;
1682151378Snetchild			len1 = *d1++;
1683151378Snetchild			if(count++ > MAX_COMPRESS_PTRS)
1684151378Snetchild				return 0;
1685151378Snetchild			continue;
1686151378Snetchild		}
1687151378Snetchild		if(d2 > qbuf+qbuflen)
1688151378Snetchild			return 0;
1689151378Snetchild		if(len1 != len2)
1690151378Snetchild			return 0;
1691151378Snetchild		if(len1 > LDNS_MAX_LABELLEN)
1692151378Snetchild			return 0;
1693151378Snetchild		/* check len1 + 1(next length) are okay to read */
1694151378Snetchild		if(d1+len1 >= sldns_buffer_at(pkt, sldns_buffer_limit(pkt)))
1695151378Snetchild			return 0;
1696151378Snetchild		log_assert(len1 <= LDNS_MAX_LABELLEN);
1697151378Snetchild		log_assert(len2 <= LDNS_MAX_LABELLEN);
1698151378Snetchild		log_assert(len1 == len2 && len1 != 0);
1699151378Snetchild		/* compare the labels - bitwise identical */
1700151378Snetchild		if(memcmp(d1, d2, len1) != 0)
1701151378Snetchild			return 0;
1702151378Snetchild		d1 += len1;
1703151378Snetchild		d2 += len2;
1704151378Snetchild		len1 = *d1++;
1705151378Snetchild		len2 = *d2++;
1706151378Snetchild	}
1707151378Snetchild	return 1;
1708151378Snetchild}
1709151378Snetchild
1710151378Snetchild/** call the callbacks for a serviced query */
1711151378Snetchildstatic void
1712151378Snetchildserviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c,
1713151378Snetchild	struct comm_reply* rep)
1714151378Snetchild{
1715151378Snetchild	struct service_callback* p;
1716151378Snetchild	int dobackup = (sq->cblist && sq->cblist->next); /* >1 cb*/
1717151378Snetchild	uint8_t *backup_p = NULL;
1718151378Snetchild	size_t backlen = 0;
1719151378Snetchild#ifdef UNBOUND_DEBUG
1720151378Snetchild	rbnode_type* rem =
1721151378Snetchild#else
1722151378Snetchild	(void)
1723151378Snetchild#endif
1724151378Snetchild	/* remove from tree, and schedule for deletion, so that callbacks
1725151378Snetchild	 * can safely deregister themselves and even create new serviced
1726151378Snetchild	 * queries that are identical to this one. */
1727151378Snetchild	rbtree_delete(sq->outnet->serviced, sq);
1728151378Snetchild	log_assert(rem); /* should have been present */
1729151378Snetchild	sq->to_be_deleted = 1;
1730151378Snetchild	verbose(VERB_ALGO, "svcd callbacks start");
1731151378Snetchild	if(sq->outnet->use_caps_for_id && error == NETEVENT_NOERROR && c &&
1732151378Snetchild		!sq->nocaps && sq->qtype != LDNS_RR_TYPE_PTR) {
1733151378Snetchild		/* for type PTR do not check perturbed name in answer,
1734151378Snetchild		 * compatibility with cisco dns guard boxes that mess up
1735151378Snetchild		 * reverse queries 0x20 contents */
1736151378Snetchild		/* noerror and nxdomain must have a qname in reply */
1737151378Snetchild		if(sldns_buffer_read_u16_at(c->buffer, 4) == 0 &&
1738151378Snetchild			(LDNS_RCODE_WIRE(sldns_buffer_begin(c->buffer))
1739151378Snetchild				== LDNS_RCODE_NOERROR ||
1740151378Snetchild			 LDNS_RCODE_WIRE(sldns_buffer_begin(c->buffer))
1741151378Snetchild				== LDNS_RCODE_NXDOMAIN)) {
1742151378Snetchild			verbose(VERB_DETAIL, "no qname in reply to check 0x20ID");
1743151378Snetchild			log_addr(VERB_DETAIL, "from server",
1744151378Snetchild				&sq->addr, sq->addrlen);
1745151378Snetchild			log_buf(VERB_DETAIL, "for packet", c->buffer);
1746151378Snetchild			error = NETEVENT_CLOSED;
1747151378Snetchild			c = NULL;
1748151378Snetchild		} else if(sldns_buffer_read_u16_at(c->buffer, 4) > 0 &&
1749151378Snetchild			!serviced_check_qname(c->buffer, sq->qbuf,
1750151378Snetchild			sq->qbuflen)) {
1751151378Snetchild			verbose(VERB_DETAIL, "wrong 0x20-ID in reply qname");
1752151378Snetchild			log_addr(VERB_DETAIL, "from server",
1753151378Snetchild				&sq->addr, sq->addrlen);
1754151378Snetchild			log_buf(VERB_DETAIL, "for packet", c->buffer);
1755151378Snetchild			error = NETEVENT_CAPSFAIL;
1756151378Snetchild			/* and cleanup too */
1757151378Snetchild			pkt_dname_tolower(c->buffer,
1758151378Snetchild				sldns_buffer_at(c->buffer, 12));
1759151378Snetchild		} else {
1760151378Snetchild			verbose(VERB_ALGO, "good 0x20-ID in reply qname");
1761151378Snetchild			/* cleanup caps, prettier cache contents. */
1762151378Snetchild			pkt_dname_tolower(c->buffer,
1763151378Snetchild				sldns_buffer_at(c->buffer, 12));
1764151378Snetchild		}
1765151378Snetchild	}
1766151378Snetchild	if(dobackup && c) {
1767151378Snetchild		/* make a backup of the query, since the querystate processing
1768151378Snetchild		 * may send outgoing queries that overwrite the buffer.
1769151378Snetchild		 * use secondary buffer to store the query.
1770151378Snetchild		 * This is a data copy, but faster than packet to server */
1771151378Snetchild		backlen = sldns_buffer_limit(c->buffer);
1772151378Snetchild		backup_p = memdup(sldns_buffer_begin(c->buffer), backlen);
1773151378Snetchild		if(!backup_p) {
1774151378Snetchild			log_err("malloc failure in serviced query callbacks");
1775151378Snetchild			error = NETEVENT_CLOSED;
1776151378Snetchild			c = NULL;
1777151378Snetchild		}
1778151378Snetchild		sq->outnet->svcd_overhead = backlen;
1779151378Snetchild	}
1780151378Snetchild	/* test the actual sq->cblist, because the next elem could be deleted*/
1781151378Snetchild	while((p=sq->cblist) != NULL) {
1782151378Snetchild		sq->cblist = p->next; /* remove this element */
1783151378Snetchild		if(dobackup && c) {
1784151378Snetchild			sldns_buffer_clear(c->buffer);
1785151378Snetchild			sldns_buffer_write(c->buffer, backup_p, backlen);
1786151378Snetchild			sldns_buffer_flip(c->buffer);
1787151378Snetchild		}
1788151378Snetchild		fptr_ok(fptr_whitelist_serviced_query(p->cb));
1789151378Snetchild		(void)(*p->cb)(c, p->cb_arg, error, rep);
1790151378Snetchild		free(p);
1791151378Snetchild	}
1792151378Snetchild	if(backup_p) {
1793151378Snetchild		free(backup_p);
1794151378Snetchild		sq->outnet->svcd_overhead = 0;
1795151378Snetchild	}
1796151378Snetchild	verbose(VERB_ALGO, "svcd callbacks end");
1797151378Snetchild	log_assert(sq->cblist == NULL);
1798151378Snetchild	serviced_delete(sq);
1799151378Snetchild}
1800151378Snetchild
1801151378Snetchildint
1802151378Snetchildserviced_tcp_callback(struct comm_point* c, void* arg, int error,
1803151378Snetchild        struct comm_reply* rep)
1804151378Snetchild{
1805151378Snetchild	struct serviced_query* sq = (struct serviced_query*)arg;
1806151378Snetchild	struct comm_reply r2;
1807151378Snetchild	sq->pending = NULL; /* removed after this callback */
1808151378Snetchild	if(error != NETEVENT_NOERROR)
1809151378Snetchild		log_addr(VERB_QUERY, "tcp error for address",
1810151378Snetchild			&sq->addr, sq->addrlen);
1811151378Snetchild	if(error==NETEVENT_NOERROR)
1812151378Snetchild		infra_update_tcp_works(sq->outnet->infra, &sq->addr,
1813151378Snetchild			sq->addrlen, sq->zone, sq->zonelen);
1814151378Snetchild#ifdef USE_DNSTAP
1815151378Snetchild	if(error==NETEVENT_NOERROR && sq->outnet->dtenv &&
1816151378Snetchild	   (sq->outnet->dtenv->log_resolver_response_messages ||
1817151378Snetchild	    sq->outnet->dtenv->log_forwarder_response_messages))
1818151378Snetchild		dt_msg_send_outside_response(sq->outnet->dtenv, &sq->addr,
1819151378Snetchild		c->type, sq->zone, sq->zonelen, sq->qbuf, sq->qbuflen,
1820151378Snetchild		&sq->last_sent_time, sq->outnet->now_tv, c->buffer);
1821151378Snetchild#endif
1822151378Snetchild	if(error==NETEVENT_NOERROR && sq->status == serviced_query_TCP_EDNS &&
1823151378Snetchild		(LDNS_RCODE_WIRE(sldns_buffer_begin(c->buffer)) ==
1824151378Snetchild		LDNS_RCODE_FORMERR || LDNS_RCODE_WIRE(sldns_buffer_begin(
1825151378Snetchild		c->buffer)) == LDNS_RCODE_NOTIMPL) ) {
1826151378Snetchild		/* attempt to fallback to nonEDNS */
1827151378Snetchild		sq->status = serviced_query_TCP_EDNS_fallback;
1828151378Snetchild		serviced_tcp_initiate(sq, c->buffer);
1829151378Snetchild		return 0;
1830151378Snetchild	} else if(error==NETEVENT_NOERROR &&
1831151378Snetchild		sq->status == serviced_query_TCP_EDNS_fallback &&
1832151378Snetchild			(LDNS_RCODE_WIRE(sldns_buffer_begin(c->buffer)) ==
1833151378Snetchild			LDNS_RCODE_NOERROR || LDNS_RCODE_WIRE(
1834151378Snetchild			sldns_buffer_begin(c->buffer)) == LDNS_RCODE_NXDOMAIN
1835151378Snetchild			|| LDNS_RCODE_WIRE(sldns_buffer_begin(c->buffer))
1836151378Snetchild			== LDNS_RCODE_YXDOMAIN)) {
1837151378Snetchild		/* the fallback produced a result that looks promising, note
1838151378Snetchild		 * that this server should be approached without EDNS */
1839151378Snetchild		/* only store noEDNS in cache if domain is noDNSSEC */
1840151378Snetchild		if(!sq->want_dnssec)
1841151378Snetchild		  if(!infra_edns_update(sq->outnet->infra, &sq->addr,
1842151378Snetchild			sq->addrlen, sq->zone, sq->zonelen, -1,
1843151378Snetchild			*sq->outnet->now_secs))
1844151378Snetchild			log_err("Out of memory caching no edns for host");
1845151378Snetchild		sq->status = serviced_query_TCP;
1846151378Snetchild	}
1847151378Snetchild	if(sq->tcp_upstream || sq->ssl_upstream) {
1848151378Snetchild	    struct timeval now = *sq->outnet->now_tv;
1849151378Snetchild	    if(error!=NETEVENT_NOERROR) {
1850151378Snetchild	        if(!infra_rtt_update(sq->outnet->infra, &sq->addr,
1851151378Snetchild		    sq->addrlen, sq->zone, sq->zonelen, sq->qtype,
1852151378Snetchild		    -1, sq->last_rtt, (time_t)now.tv_sec))
1853151378Snetchild		    log_err("out of memory in TCP exponential backoff.");
1854151378Snetchild	    } else if(now.tv_sec > sq->last_sent_time.tv_sec ||
1855151378Snetchild		(now.tv_sec == sq->last_sent_time.tv_sec &&
1856151378Snetchild		now.tv_usec > sq->last_sent_time.tv_usec)) {
1857151378Snetchild		/* convert from microseconds to milliseconds */
1858151378Snetchild		int roundtime = ((int)(now.tv_sec - sq->last_sent_time.tv_sec))*1000
1859151378Snetchild		  + ((int)now.tv_usec - (int)sq->last_sent_time.tv_usec)/1000;
1860151378Snetchild		verbose(VERB_ALGO, "measured TCP-time at %d msec", roundtime);
1861151378Snetchild		log_assert(roundtime >= 0);
1862151378Snetchild		/* only store if less then AUTH_TIMEOUT seconds, it could be
1863151378Snetchild		 * huge due to system-hibernated and we woke up */
1864151378Snetchild		if(roundtime < 60000) {
1865151378Snetchild		    if(!infra_rtt_update(sq->outnet->infra, &sq->addr,
1866151378Snetchild			sq->addrlen, sq->zone, sq->zonelen, sq->qtype,
1867151378Snetchild			roundtime, sq->last_rtt, (time_t)now.tv_sec))
1868151378Snetchild			log_err("out of memory noting rtt.");
1869151378Snetchild		}
1870151378Snetchild	    }
1871151378Snetchild	}
1872151378Snetchild	/* insert address into reply info */
1873151378Snetchild	if(!rep) {
1874151378Snetchild		/* create one if there isn't (on errors) */
1875151378Snetchild		rep = &r2;
1876151378Snetchild		r2.c = c;
1877151378Snetchild	}
1878151378Snetchild	memcpy(&rep->addr, &sq->addr, sq->addrlen);
1879151378Snetchild	rep->addrlen = sq->addrlen;
1880151378Snetchild	serviced_callbacks(sq, error, c, rep);
1881151378Snetchild	return 0;
1882151378Snetchild}
1883151378Snetchild
1884151378Snetchildstatic void
1885151378Snetchildserviced_tcp_initiate(struct serviced_query* sq, sldns_buffer* buff)
1886151378Snetchild{
1887151378Snetchild	verbose(VERB_ALGO, "initiate TCP query %s",
1888151378Snetchild		sq->status==serviced_query_TCP_EDNS?"EDNS":"");
1889151378Snetchild	serviced_encode(sq, buff, sq->status == serviced_query_TCP_EDNS);
1890151378Snetchild	sq->last_sent_time = *sq->outnet->now_tv;
1891151378Snetchild	sq->pending = pending_tcp_query(sq, buff, TCP_AUTH_QUERY_TIMEOUT,
1892151378Snetchild		serviced_tcp_callback, sq);
1893151378Snetchild	if(!sq->pending) {
1894151378Snetchild		/* delete from tree so that a retry by above layer does not
1895151378Snetchild		 * clash with this entry */
1896151378Snetchild		verbose(VERB_ALGO, "serviced_tcp_initiate: failed to send tcp query");
1897151378Snetchild		serviced_callbacks(sq, NETEVENT_CLOSED, NULL, NULL);
1898151378Snetchild	}
1899151378Snetchild}
1900151378Snetchild
1901151378Snetchild/** Send serviced query over TCP return false on initial failure */
1902151378Snetchildstatic int
1903151378Snetchildserviced_tcp_send(struct serviced_query* sq, sldns_buffer* buff)
1904151378Snetchild{
1905151378Snetchild	int vs, rtt, timeout;
1906151378Snetchild	uint8_t edns_lame_known;
1907151378Snetchild	if(!infra_host(sq->outnet->infra, &sq->addr, sq->addrlen, sq->zone,
1908151378Snetchild		sq->zonelen, *sq->outnet->now_secs, &vs, &edns_lame_known,
1909151378Snetchild		&rtt))
1910151378Snetchild		return 0;
1911151378Snetchild	sq->last_rtt = rtt;
1912151378Snetchild	if(vs != -1)
1913151378Snetchild		sq->status = serviced_query_TCP_EDNS;
1914151378Snetchild	else 	sq->status = serviced_query_TCP;
1915151378Snetchild	serviced_encode(sq, buff, sq->status == serviced_query_TCP_EDNS);
1916151378Snetchild	sq->last_sent_time = *sq->outnet->now_tv;
1917151378Snetchild	if(sq->tcp_upstream || sq->ssl_upstream) {
1918151378Snetchild		timeout = rtt;
1919151378Snetchild		if(rtt >= UNKNOWN_SERVER_NICENESS && rtt < TCP_AUTH_QUERY_TIMEOUT)
1920151378Snetchild			timeout = TCP_AUTH_QUERY_TIMEOUT;
1921151378Snetchild	} else {
1922151378Snetchild		timeout = TCP_AUTH_QUERY_TIMEOUT;
1923151378Snetchild	}
1924151378Snetchild	sq->pending = pending_tcp_query(sq, buff, timeout,
1925151378Snetchild		serviced_tcp_callback, sq);
1926151378Snetchild	return sq->pending != NULL;
1927151378Snetchild}
1928151378Snetchild
1929151378Snetchild/* see if packet is edns malformed; got zeroes at start.
1930151378Snetchild * This is from servers that return malformed packets to EDNS0 queries,
1931151378Snetchild * but they return good packets for nonEDNS0 queries.
1932151378Snetchild * We try to detect their output; without resorting to a full parse or
1933151378Snetchild * check for too many bytes after the end of the packet. */
1934151378Snetchildstatic int
1935151378Snetchildpacket_edns_malformed(struct sldns_buffer* buf, int qtype)
1936151378Snetchild{
1937151378Snetchild	size_t len;
1938151378Snetchild	if(sldns_buffer_limit(buf) < LDNS_HEADER_SIZE)
1939151378Snetchild		return 1; /* malformed */
1940151378Snetchild	/* they have NOERROR rcode, 1 answer. */
1941151378Snetchild	if(LDNS_RCODE_WIRE(sldns_buffer_begin(buf)) != LDNS_RCODE_NOERROR)
1942151378Snetchild		return 0;
1943151378Snetchild	/* one query (to skip) and answer records */
1944151378Snetchild	if(LDNS_QDCOUNT(sldns_buffer_begin(buf)) != 1 ||
1945151378Snetchild		LDNS_ANCOUNT(sldns_buffer_begin(buf)) == 0)
1946151378Snetchild		return 0;
1947151378Snetchild	/* skip qname */
1948151378Snetchild	len = dname_valid(sldns_buffer_at(buf, LDNS_HEADER_SIZE),
1949151378Snetchild		sldns_buffer_limit(buf)-LDNS_HEADER_SIZE);
1950151378Snetchild	if(len == 0)
1951151378Snetchild		return 0;
1952151378Snetchild	if(len == 1 && qtype == 0)
1953151378Snetchild		return 0; /* we asked for '.' and type 0 */
1954151378Snetchild	/* and then 4 bytes (type and class of query) */
1955151378Snetchild	if(sldns_buffer_limit(buf) < LDNS_HEADER_SIZE + len + 4 + 3)
1956151378Snetchild		return 0;
1957151378Snetchild
1958151378Snetchild	/* and start with 11 zeroes as the answer RR */
1959151378Snetchild	/* so check the qtype of the answer record, qname=0, type=0 */
1960151378Snetchild	if(sldns_buffer_at(buf, LDNS_HEADER_SIZE+len+4)[0] == 0 &&
1961151378Snetchild	   sldns_buffer_at(buf, LDNS_HEADER_SIZE+len+4)[1] == 0 &&
1962151378Snetchild	   sldns_buffer_at(buf, LDNS_HEADER_SIZE+len+4)[2] == 0)
1963151378Snetchild		return 1;
1964151378Snetchild	return 0;
1965151378Snetchild}
1966151378Snetchild
1967151378Snetchildint
1968151378Snetchildserviced_udp_callback(struct comm_point* c, void* arg, int error,
1969151378Snetchild        struct comm_reply* rep)
1970151378Snetchild{
1971151378Snetchild	struct serviced_query* sq = (struct serviced_query*)arg;
1972151378Snetchild	struct outside_network* outnet = sq->outnet;
1973151378Snetchild	struct timeval now = *sq->outnet->now_tv;
1974151378Snetchild
1975151378Snetchild	sq->pending = NULL; /* removed after callback */
1976151378Snetchild	if(error == NETEVENT_TIMEOUT) {
1977151378Snetchild		if(sq->status == serviced_query_UDP_EDNS && sq->last_rtt < 5000) {
1978151378Snetchild			/* fallback to 1480/1280 */
1979151378Snetchild			sq->status = serviced_query_UDP_EDNS_FRAG;
1980151378Snetchild			log_name_addr(VERB_ALGO, "try edns1xx0", sq->qbuf+10,
1981151378Snetchild				&sq->addr, sq->addrlen);
1982151378Snetchild			if(!serviced_udp_send(sq, c->buffer)) {
1983151378Snetchild				serviced_callbacks(sq, NETEVENT_CLOSED, c, rep);
1984151378Snetchild			}
1985151378Snetchild			return 0;
1986151378Snetchild		}
1987151378Snetchild		if(sq->status == serviced_query_UDP_EDNS_FRAG) {
1988151378Snetchild			/* fragmentation size did not fix it */
1989151378Snetchild			sq->status = serviced_query_UDP_EDNS;
1990151378Snetchild		}
1991151378Snetchild		sq->retry++;
1992151378Snetchild		if(!infra_rtt_update(outnet->infra, &sq->addr, sq->addrlen,
1993151378Snetchild			sq->zone, sq->zonelen, sq->qtype, -1, sq->last_rtt,
1994151378Snetchild			(time_t)now.tv_sec))
1995151378Snetchild			log_err("out of memory in UDP exponential backoff");
1996151378Snetchild		if(sq->retry < OUTBOUND_UDP_RETRY) {
1997151378Snetchild			log_name_addr(VERB_ALGO, "retry query", sq->qbuf+10,
1998151378Snetchild				&sq->addr, sq->addrlen);
1999151378Snetchild			if(!serviced_udp_send(sq, c->buffer)) {
2000151378Snetchild				serviced_callbacks(sq, NETEVENT_CLOSED, c, rep);
2001151378Snetchild			}
2002151378Snetchild			return 0;
2003151378Snetchild		}
2004151378Snetchild	}
2005151378Snetchild	if(error != NETEVENT_NOERROR) {
2006151378Snetchild		/* udp returns error (due to no ID or interface available) */
2007151378Snetchild		serviced_callbacks(sq, error, c, rep);
2008151378Snetchild		return 0;
2009151378Snetchild	}
2010151378Snetchild#ifdef USE_DNSTAP
2011151378Snetchild	if(error == NETEVENT_NOERROR && outnet->dtenv &&
2012151378Snetchild	   (outnet->dtenv->log_resolver_response_messages ||
2013151378Snetchild	    outnet->dtenv->log_forwarder_response_messages))
2014151378Snetchild		dt_msg_send_outside_response(outnet->dtenv, &sq->addr, c->type,
2015151378Snetchild		sq->zone, sq->zonelen, sq->qbuf, sq->qbuflen,
2016151378Snetchild		&sq->last_sent_time, sq->outnet->now_tv, c->buffer);
2017151378Snetchild#endif
2018151378Snetchild	if( (sq->status == serviced_query_UDP_EDNS
2019151378Snetchild		||sq->status == serviced_query_UDP_EDNS_FRAG)
2020151378Snetchild		&& (LDNS_RCODE_WIRE(sldns_buffer_begin(c->buffer))
2021151378Snetchild			== LDNS_RCODE_FORMERR || LDNS_RCODE_WIRE(
2022151378Snetchild			sldns_buffer_begin(c->buffer)) == LDNS_RCODE_NOTIMPL
2023151378Snetchild		    || packet_edns_malformed(c->buffer, sq->qtype)
2024151378Snetchild			)) {
2025151378Snetchild		/* try to get an answer by falling back without EDNS */
2026151378Snetchild		verbose(VERB_ALGO, "serviced query: attempt without EDNS");
2027151378Snetchild		sq->status = serviced_query_UDP_EDNS_fallback;
2028151378Snetchild		sq->retry = 0;
2029151378Snetchild		if(!serviced_udp_send(sq, c->buffer)) {
2030151378Snetchild			serviced_callbacks(sq, NETEVENT_CLOSED, c, rep);
2031151378Snetchild		}
2032151378Snetchild		return 0;
2033151378Snetchild	} else if(sq->status == serviced_query_UDP_EDNS &&
2034151378Snetchild		!sq->edns_lame_known) {
2035151378Snetchild		/* now we know that edns queries received answers store that */
2036151378Snetchild		log_addr(VERB_ALGO, "serviced query: EDNS works for",
2037151378Snetchild			&sq->addr, sq->addrlen);
2038151378Snetchild		if(!infra_edns_update(outnet->infra, &sq->addr, sq->addrlen,
2039151378Snetchild			sq->zone, sq->zonelen, 0, (time_t)now.tv_sec)) {
2040151378Snetchild			log_err("Out of memory caching edns works");
2041151378Snetchild		}
2042151378Snetchild		sq->edns_lame_known = 1;
2043151378Snetchild	} else if(sq->status == serviced_query_UDP_EDNS_fallback &&
2044151378Snetchild		!sq->edns_lame_known && (LDNS_RCODE_WIRE(
2045151378Snetchild		sldns_buffer_begin(c->buffer)) == LDNS_RCODE_NOERROR ||
2046151378Snetchild		LDNS_RCODE_WIRE(sldns_buffer_begin(c->buffer)) ==
2047151378Snetchild		LDNS_RCODE_NXDOMAIN || LDNS_RCODE_WIRE(sldns_buffer_begin(
2048151378Snetchild		c->buffer)) == LDNS_RCODE_YXDOMAIN)) {
2049151378Snetchild		/* the fallback produced a result that looks promising, note
2050151378Snetchild		 * that this server should be approached without EDNS */
2051151378Snetchild		/* only store noEDNS in cache if domain is noDNSSEC */
2052151378Snetchild		if(!sq->want_dnssec) {
2053151378Snetchild		  log_addr(VERB_ALGO, "serviced query: EDNS fails for",
2054151378Snetchild			&sq->addr, sq->addrlen);
2055151378Snetchild		  if(!infra_edns_update(outnet->infra, &sq->addr, sq->addrlen,
2056151378Snetchild			sq->zone, sq->zonelen, -1, (time_t)now.tv_sec)) {
2057151378Snetchild			log_err("Out of memory caching no edns for host");
2058151378Snetchild		  }
2059151378Snetchild		} else {
2060151378Snetchild		  log_addr(VERB_ALGO, "serviced query: EDNS fails, but "
2061151378Snetchild			"not stored because need DNSSEC for", &sq->addr,
2062151378Snetchild			sq->addrlen);
2063151378Snetchild		}
2064151378Snetchild		sq->status = serviced_query_UDP;
2065151378Snetchild	}
2066151378Snetchild	if(now.tv_sec > sq->last_sent_time.tv_sec ||
2067151378Snetchild		(now.tv_sec == sq->last_sent_time.tv_sec &&
2068151378Snetchild		now.tv_usec > sq->last_sent_time.tv_usec)) {
2069151378Snetchild		/* convert from microseconds to milliseconds */
2070151378Snetchild		int roundtime = ((int)(now.tv_sec - sq->last_sent_time.tv_sec))*1000
2071151378Snetchild		  + ((int)now.tv_usec - (int)sq->last_sent_time.tv_usec)/1000;
2072151378Snetchild		verbose(VERB_ALGO, "measured roundtrip at %d msec", roundtime);
2073151378Snetchild		log_assert(roundtime >= 0);
2074151378Snetchild		/* in case the system hibernated, do not enter a huge value,
2075151378Snetchild		 * above this value gives trouble with server selection */
2076151378Snetchild		if(roundtime < 60000) {
2077151378Snetchild		    if(!infra_rtt_update(outnet->infra, &sq->addr, sq->addrlen,
2078151378Snetchild			sq->zone, sq->zonelen, sq->qtype, roundtime,
2079151378Snetchild			sq->last_rtt, (time_t)now.tv_sec))
2080151378Snetchild			log_err("out of memory noting rtt.");
2081151378Snetchild		}
2082151378Snetchild	}
2083151378Snetchild	/* perform TC flag check and TCP fallback after updating our
2084151378Snetchild	 * cache entries for EDNS status and RTT times */
2085151378Snetchild	if(LDNS_TC_WIRE(sldns_buffer_begin(c->buffer))) {
2086151378Snetchild		/* fallback to TCP */
2087151378Snetchild		/* this discards partial UDP contents */
2088151378Snetchild		if(sq->status == serviced_query_UDP_EDNS ||
2089151378Snetchild			sq->status == serviced_query_UDP_EDNS_FRAG ||
2090151378Snetchild			sq->status == serviced_query_UDP_EDNS_fallback)
2091151378Snetchild			/* if we have unfinished EDNS_fallback, start again */
2092151378Snetchild			sq->status = serviced_query_TCP_EDNS;
2093151378Snetchild		else	sq->status = serviced_query_TCP;
2094151378Snetchild		serviced_tcp_initiate(sq, c->buffer);
2095151378Snetchild		return 0;
2096151378Snetchild	}
2097151378Snetchild	/* yay! an answer */
2098151378Snetchild	serviced_callbacks(sq, error, c, rep);
2099151378Snetchild	return 0;
2100151378Snetchild}
2101151378Snetchild
2102151378Snetchildstruct serviced_query*
2103151378Snetchildoutnet_serviced_query(struct outside_network* outnet,
2104151378Snetchild	struct query_info* qinfo, uint16_t flags, int dnssec, int want_dnssec,
2105151378Snetchild	int nocaps, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
2106151378Snetchild	struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
2107151378Snetchild	size_t zonelen, struct module_qstate* qstate,
2108151378Snetchild	comm_point_callback_type* callback, void* callback_arg, sldns_buffer* buff,
2109151378Snetchild	struct module_env* env)
2110151378Snetchild{
2111151378Snetchild	struct serviced_query* sq;
2112151378Snetchild	struct service_callback* cb;
2113151378Snetchild	if(!inplace_cb_query_call(env, qinfo, flags, addr, addrlen, zone, zonelen,
2114151378Snetchild		qstate, qstate->region))
2115151378Snetchild			return NULL;
2116151378Snetchild	serviced_gen_query(buff, qinfo->qname, qinfo->qname_len, qinfo->qtype,
2117151378Snetchild		qinfo->qclass, flags);
2118151378Snetchild	sq = lookup_serviced(outnet, buff, dnssec, addr, addrlen,
2119151378Snetchild		qstate->edns_opts_back_out);
2120151378Snetchild	/* duplicate entries are included in the callback list, because
2121151378Snetchild	 * there is a counterpart registration by our caller that needs to
2122151378Snetchild	 * be doubly-removed (with callbacks perhaps). */
2123151378Snetchild	if(!(cb = (struct service_callback*)malloc(sizeof(*cb))))
2124151378Snetchild		return NULL;
2125151378Snetchild	if(!sq) {
2126151378Snetchild		/* make new serviced query entry */
2127151378Snetchild		sq = serviced_create(outnet, buff, dnssec, want_dnssec, nocaps,
2128151378Snetchild			tcp_upstream, ssl_upstream, tls_auth_name, addr,
2129151378Snetchild			addrlen, zone, zonelen, (int)qinfo->qtype,
2130151378Snetchild			qstate->edns_opts_back_out);
2131151378Snetchild		if(!sq) {
2132151378Snetchild			free(cb);
2133151378Snetchild			return NULL;
2134151378Snetchild		}
2135151378Snetchild		/* perform first network action */
2136151378Snetchild		if(outnet->do_udp && !(tcp_upstream || ssl_upstream)) {
2137151378Snetchild			if(!serviced_udp_send(sq, buff)) {
2138151378Snetchild				(void)rbtree_delete(outnet->serviced, sq);
2139151378Snetchild				serviced_node_del(&sq->node, NULL);
2140151378Snetchild				free(cb);
2141151378Snetchild				return NULL;
2142151378Snetchild			}
2143151378Snetchild		} else {
2144151378Snetchild			if(!serviced_tcp_send(sq, buff)) {
2145151378Snetchild				(void)rbtree_delete(outnet->serviced, sq);
2146151378Snetchild				serviced_node_del(&sq->node, NULL);
2147151378Snetchild				free(cb);
2148151378Snetchild				return NULL;
2149151378Snetchild			}
2150151378Snetchild		}
2151151378Snetchild	}
2152151378Snetchild	/* add callback to list of callbacks */
2153151378Snetchild	cb->cb = callback;
2154151378Snetchild	cb->cb_arg = callback_arg;
2155151378Snetchild	cb->next = sq->cblist;
2156151378Snetchild	sq->cblist = cb;
2157151378Snetchild	return sq;
2158151378Snetchild}
2159151378Snetchild
2160151378Snetchild/** remove callback from list */
2161151378Snetchildstatic void
2162151378Snetchildcallback_list_remove(struct serviced_query* sq, void* cb_arg)
2163151378Snetchild{
2164151378Snetchild	struct service_callback** pp = &sq->cblist;
2165151378Snetchild	while(*pp) {
2166151378Snetchild		if((*pp)->cb_arg == cb_arg) {
2167151378Snetchild			struct service_callback* del = *pp;
2168151378Snetchild			*pp = del->next;
2169151378Snetchild			free(del);
2170151378Snetchild			return;
2171151378Snetchild		}
2172151378Snetchild		pp = &(*pp)->next;
2173151378Snetchild	}
2174151378Snetchild}
2175151378Snetchild
2176151378Snetchildvoid outnet_serviced_query_stop(struct serviced_query* sq, void* cb_arg)
2177151378Snetchild{
2178151378Snetchild	if(!sq)
2179151378Snetchild		return;
2180151378Snetchild	callback_list_remove(sq, cb_arg);
2181151378Snetchild	/* if callbacks() routine scheduled deletion, let it do that */
2182151378Snetchild	if(!sq->cblist && !sq->to_be_deleted) {
2183151378Snetchild		(void)rbtree_delete(sq->outnet->serviced, sq);
2184151378Snetchild		serviced_delete(sq);
2185151378Snetchild	}
2186151378Snetchild}
2187151378Snetchild
2188151378Snetchild/** create fd to send to this destination */
2189151378Snetchildstatic int
2190151378Snetchildfd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr,
2191151378Snetchild	socklen_t to_addrlen)
2192151378Snetchild{
2193151378Snetchild	struct sockaddr_storage* addr;
2194151378Snetchild	socklen_t addrlen;
2195151378Snetchild	int i, try, pnum;
2196151378Snetchild	struct port_if* pif;
2197151378Snetchild
2198151378Snetchild	/* create fd */
2199151378Snetchild	for(try = 0; try<1000; try++) {
2200151378Snetchild		int port = 0;
2201151378Snetchild		int freebind = 0;
2202151378Snetchild		int noproto = 0;
2203151378Snetchild		int inuse = 0;
2204151378Snetchild		int fd = -1;
2205151378Snetchild
2206151378Snetchild		/* select interface */
2207151378Snetchild		if(addr_is_ip6(to_addr, to_addrlen)) {
2208151378Snetchild			if(outnet->num_ip6 == 0) {
2209151378Snetchild				char to[64];
2210151378Snetchild				addr_to_str(to_addr, to_addrlen, to, sizeof(to));
2211151378Snetchild				verbose(VERB_QUERY, "need ipv6 to send, but no ipv6 outgoing interfaces, for %s", to);
2212151378Snetchild				return -1;
2213151378Snetchild			}
2214151378Snetchild			i = ub_random_max(outnet->rnd, outnet->num_ip6);
2215151378Snetchild			pif = &outnet->ip6_ifs[i];
2216151378Snetchild		} else {
2217151378Snetchild			if(outnet->num_ip4 == 0) {
2218151378Snetchild				char to[64];
2219151378Snetchild				addr_to_str(to_addr, to_addrlen, to, sizeof(to));
2220151378Snetchild				verbose(VERB_QUERY, "need ipv4 to send, but no ipv4 outgoing interfaces, for %s", to);
2221151378Snetchild				return -1;
2222151378Snetchild			}
2223151378Snetchild			i = ub_random_max(outnet->rnd, outnet->num_ip4);
2224151378Snetchild			pif = &outnet->ip4_ifs[i];
2225151378Snetchild		}
2226151378Snetchild		addr = &pif->addr;
2227151378Snetchild		addrlen = pif->addrlen;
2228151378Snetchild		pnum = ub_random_max(outnet->rnd, pif->avail_total);
2229151378Snetchild		if(pnum < pif->inuse) {
2230151378Snetchild			/* port already open */
2231151378Snetchild			port = pif->out[pnum]->number;
2232151378Snetchild		} else {
2233151378Snetchild			/* unused ports in start part of array */
2234151378Snetchild			port = pif->avail_ports[pnum - pif->inuse];
2235151378Snetchild		}
2236151378Snetchild
2237151378Snetchild		if(addr_is_ip6(to_addr, to_addrlen)) {
2238151378Snetchild			struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr;
2239151378Snetchild			sa.sin6_port = (in_port_t)htons((uint16_t)port);
2240151378Snetchild			fd = create_udp_sock(AF_INET6, SOCK_DGRAM,
2241151378Snetchild				(struct sockaddr*)&sa, addrlen, 1, &inuse, &noproto,
2242151378Snetchild				0, 0, 0, NULL, 0, freebind, 0);
2243151378Snetchild		} else {
2244151378Snetchild			struct sockaddr_in* sa = (struct sockaddr_in*)addr;
2245151378Snetchild			sa->sin_port = (in_port_t)htons((uint16_t)port);
2246151378Snetchild			fd = create_udp_sock(AF_INET, SOCK_DGRAM,
2247151378Snetchild				(struct sockaddr*)addr, addrlen, 1, &inuse, &noproto,
2248151378Snetchild				0, 0, 0, NULL, 0, freebind, 0);
2249151378Snetchild		}
2250151378Snetchild		if(fd != -1) {
2251151378Snetchild			return fd;
2252151378Snetchild		}
2253151378Snetchild		if(!inuse) {
2254151378Snetchild			return -1;
2255151378Snetchild		}
2256151378Snetchild	}
2257151378Snetchild	/* too many tries */
2258151378Snetchild	log_err("cannot send probe, ports are in use");
2259151378Snetchild	return -1;
2260151378Snetchild}
2261151378Snetchild
2262151378Snetchildstruct comm_point*
2263151378Snetchildoutnet_comm_point_for_udp(struct outside_network* outnet,
2264151378Snetchild	comm_point_callback_type* cb, void* cb_arg,
2265151378Snetchild	struct sockaddr_storage* to_addr, socklen_t to_addrlen)
2266151378Snetchild{
2267151378Snetchild	struct comm_point* cp;
2268151378Snetchild	int fd = fd_for_dest(outnet, to_addr, to_addrlen);
2269151378Snetchild	if(fd == -1) {
2270151378Snetchild		return NULL;
2271151378Snetchild	}
2272151378Snetchild	cp = comm_point_create_udp(outnet->base, fd, outnet->udp_buff,
2273151378Snetchild		cb, cb_arg);
2274151378Snetchild	if(!cp) {
2275151378Snetchild		log_err("malloc failure");
2276151378Snetchild		close(fd);
2277151378Snetchild		return NULL;
2278151378Snetchild	}
2279151378Snetchild	return cp;
2280151378Snetchild}
2281151378Snetchild
2282151378Snetchild/** setup SSL for comm point */
2283151378Snetchildstatic int
2284151378Snetchildsetup_comm_ssl(struct comm_point* cp, struct outside_network* outnet,
2285151378Snetchild	int fd, char* host)
2286151378Snetchild{
2287151378Snetchild	cp->ssl = outgoing_ssl_fd(outnet->sslctx, fd);
2288151378Snetchild	if(!cp->ssl) {
2289151378Snetchild		log_err("cannot create SSL object");
2290151378Snetchild		return 0;
2291151378Snetchild	}
2292151378Snetchild#ifdef USE_WINSOCK
2293151378Snetchild	comm_point_tcp_win_bio_cb(cp, cp->ssl);
2294151378Snetchild#endif
2295151378Snetchild	cp->ssl_shake_state = comm_ssl_shake_write;
2296151378Snetchild	/* https verification */
2297151378Snetchild#ifdef HAVE_SSL_SET1_HOST
2298151378Snetchild	if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) {
2299151378Snetchild		/* because we set SSL_VERIFY_PEER, in netevent in
2300151378Snetchild		 * ssl_handshake, it'll check if the certificate
2301151378Snetchild		 * verification has succeeded */
2302151378Snetchild		/* SSL_VERIFY_PEER is set on the sslctx */
2303151378Snetchild		/* and the certificates to verify with are loaded into
2304151378Snetchild		 * it with SSL_load_verify_locations or
2305151378Snetchild		 * SSL_CTX_set_default_verify_paths */
2306151378Snetchild		/* setting the hostname makes openssl verify the
2307151378Snetchild		 * host name in the x509 certificate in the
2308151378Snetchild		 * SSL connection*/
2309151378Snetchild		if(!SSL_set1_host(cp->ssl, host)) {
2310151378Snetchild			log_err("SSL_set1_host failed");
2311151378Snetchild			return 0;
2312151378Snetchild		}
2313151378Snetchild	}
2314151378Snetchild#elif defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
2315151378Snetchild	/* openssl 1.0.2 has this function that can be used for
2316151378Snetchild	 * set1_host like verification */
2317151378Snetchild	if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) {
2318151378Snetchild		X509_VERIFY_PARAM* param = SSL_get0_param(cp->ssl);
2319151378Snetchild		X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
2320151378Snetchild		if(!X509_VERIFY_PARAM_set1_host(param, host, strlen(host))) {
2321151378Snetchild			log_err("X509_VERIFY_PARAM_set1_host failed");
2322151378Snetchild			return 0;
2323151378Snetchild		}
2324151378Snetchild	}
2325151378Snetchild#else
2326151378Snetchild	(void)host;
2327151378Snetchild#endif /* HAVE_SSL_SET1_HOST */
2328151378Snetchild	return 1;
2329151378Snetchild}
2330151378Snetchild
2331151378Snetchildstruct comm_point*
2332151378Snetchildoutnet_comm_point_for_tcp(struct outside_network* outnet,
2333151378Snetchild	comm_point_callback_type* cb, void* cb_arg,
2334151378Snetchild	struct sockaddr_storage* to_addr, socklen_t to_addrlen,
2335151378Snetchild	sldns_buffer* query, int timeout, int ssl, char* host)
2336151378Snetchild{
2337151378Snetchild	struct comm_point* cp;
2338151378Snetchild	int fd = outnet_get_tcp_fd(to_addr, to_addrlen, outnet->tcp_mss);
2339151378Snetchild	if(fd == -1) {
2340151378Snetchild		return 0;
2341151378Snetchild	}
2342151378Snetchild	fd_set_nonblock(fd);
2343151378Snetchild	if(!outnet_tcp_connect(fd, to_addr, to_addrlen)) {
2344151378Snetchild		/* outnet_tcp_connect has closed fd on error for us */
2345151378Snetchild		return 0;
2346151378Snetchild	}
2347151378Snetchild	cp = comm_point_create_tcp_out(outnet->base, 65552, cb, cb_arg);
2348151378Snetchild	if(!cp) {
2349151378Snetchild		log_err("malloc failure");
2350151378Snetchild		close(fd);
2351151378Snetchild		return 0;
2352151378Snetchild	}
2353151378Snetchild	cp->repinfo.addrlen = to_addrlen;
2354151378Snetchild	memcpy(&cp->repinfo.addr, to_addr, to_addrlen);
2355151378Snetchild
2356151378Snetchild	/* setup for SSL (if needed) */
2357151378Snetchild	if(ssl) {
2358151378Snetchild		if(!setup_comm_ssl(cp, outnet, fd, host)) {
2359151378Snetchild			log_err("cannot setup XoT");
2360151378Snetchild			comm_point_delete(cp);
2361151378Snetchild			return NULL;
2362151378Snetchild		}
2363151378Snetchild	}
2364151378Snetchild
2365151378Snetchild	/* set timeout on TCP connection */
2366151378Snetchild	comm_point_start_listening(cp, fd, timeout);
2367151378Snetchild	/* copy scratch buffer to cp->buffer */
2368151378Snetchild	sldns_buffer_copy(cp->buffer, query);
2369151378Snetchild	return cp;
2370151378Snetchild}
2371151378Snetchild
2372151378Snetchild/** setup http request headers in buffer for sending query to destination */
2373151378Snetchildstatic int
2374151378Snetchildsetup_http_request(sldns_buffer* buf, char* host, char* path)
2375151378Snetchild{
2376151378Snetchild	sldns_buffer_clear(buf);
2377151378Snetchild	sldns_buffer_printf(buf, "GET /%s HTTP/1.1\r\n", path);
2378151378Snetchild	sldns_buffer_printf(buf, "Host: %s\r\n", host);
2379151378Snetchild	sldns_buffer_printf(buf, "User-Agent: unbound/%s\r\n",
2380151378Snetchild		PACKAGE_VERSION);
2381151378Snetchild	/* We do not really do multiple queries per connection,
2382151378Snetchild	 * but this header setting is also not needed.
2383151378Snetchild	 * sldns_buffer_printf(buf, "Connection: close\r\n") */
2384151378Snetchild	sldns_buffer_printf(buf, "\r\n");
2385151378Snetchild	if(sldns_buffer_position(buf)+10 > sldns_buffer_capacity(buf))
2386151378Snetchild		return 0; /* somehow buffer too short, but it is about 60K
2387151378Snetchild		and the request is only a couple bytes long. */
2388151378Snetchild	sldns_buffer_flip(buf);
2389151378Snetchild	return 1;
2390151378Snetchild}
2391151378Snetchild
2392151378Snetchildstruct comm_point*
2393151378Snetchildoutnet_comm_point_for_http(struct outside_network* outnet,
2394151378Snetchild	comm_point_callback_type* cb, void* cb_arg,
2395151378Snetchild	struct sockaddr_storage* to_addr, socklen_t to_addrlen, int timeout,
2396151378Snetchild	int ssl, char* host, char* path)
2397151378Snetchild{
2398151378Snetchild	/* cp calls cb with err=NETEVENT_DONE when transfer is done */
2399151378Snetchild	struct comm_point* cp;
2400151378Snetchild	int fd = outnet_get_tcp_fd(to_addr, to_addrlen, outnet->tcp_mss);
2401151378Snetchild	if(fd == -1) {
2402151378Snetchild		return 0;
2403151378Snetchild	}
2404151378Snetchild	fd_set_nonblock(fd);
2405151378Snetchild	if(!outnet_tcp_connect(fd, to_addr, to_addrlen)) {
2406151378Snetchild		/* outnet_tcp_connect has closed fd on error for us */
2407151378Snetchild		return 0;
2408151378Snetchild	}
2409151378Snetchild	cp = comm_point_create_http_out(outnet->base, 65552, cb, cb_arg,
2410151378Snetchild		outnet->udp_buff);
2411151378Snetchild	if(!cp) {
2412151378Snetchild		log_err("malloc failure");
2413151378Snetchild		close(fd);
2414151378Snetchild		return 0;
2415151378Snetchild	}
2416151378Snetchild	cp->repinfo.addrlen = to_addrlen;
2417151378Snetchild	memcpy(&cp->repinfo.addr, to_addr, to_addrlen);
2418151378Snetchild
2419151378Snetchild	/* setup for SSL (if needed) */
2420151378Snetchild	if(ssl) {
2421151378Snetchild		if(!setup_comm_ssl(cp, outnet, fd, host)) {
2422151378Snetchild			log_err("cannot setup https");
2423151378Snetchild			comm_point_delete(cp);
2424151378Snetchild			return NULL;
2425151378Snetchild		}
2426151378Snetchild	}
2427151378Snetchild
2428151378Snetchild	/* set timeout on TCP connection */
2429151378Snetchild	comm_point_start_listening(cp, fd, timeout);
2430151378Snetchild
2431151378Snetchild	/* setup http request in cp->buffer */
2432151378Snetchild	if(!setup_http_request(cp->buffer, host, path)) {
2433151378Snetchild		log_err("error setting up http request");
2434151378Snetchild		comm_point_delete(cp);
2435151378Snetchild		return NULL;
2436151378Snetchild	}
2437151378Snetchild	return cp;
2438151378Snetchild}
2439151378Snetchild
2440151378Snetchild/** get memory used by waiting tcp entry (in use or not) */
2441151378Snetchildstatic size_t
2442151378Snetchildwaiting_tcp_get_mem(struct waiting_tcp* w)
2443151378Snetchild{
2444151378Snetchild	size_t s;
2445151378Snetchild	if(!w) return 0;
2446151378Snetchild	s = sizeof(*w) + w->pkt_len;
2447151378Snetchild	if(w->timer)
2448151378Snetchild		s += comm_timer_get_mem(w->timer);
2449151378Snetchild	return s;
2450151378Snetchild}
2451151378Snetchild
2452151378Snetchild/** get memory used by port if */
2453151378Snetchildstatic size_t
2454151378Snetchildif_get_mem(struct port_if* pif)
2455151378Snetchild{
2456151378Snetchild	size_t s;
2457151378Snetchild	int i;
2458151378Snetchild	s = sizeof(*pif) + sizeof(int)*pif->avail_total +
2459151378Snetchild		sizeof(struct port_comm*)*pif->maxout;
2460151378Snetchild	for(i=0; i<pif->inuse; i++)
2461151378Snetchild		s += sizeof(*pif->out[i]) +
2462151378Snetchild			comm_point_get_mem(pif->out[i]->cp);
2463151378Snetchild	return s;
2464151378Snetchild}
2465151378Snetchild
2466151378Snetchild/** get memory used by waiting udp */
2467151378Snetchildstatic size_t
2468151378Snetchildwaiting_udp_get_mem(struct pending* w)
2469151378Snetchild{
2470151378Snetchild	size_t s;
2471151378Snetchild	s = sizeof(*w) + comm_timer_get_mem(w->timer) + w->pkt_len;
2472151378Snetchild	return s;
2473151378Snetchild}
2474151378Snetchild
2475151378Snetchildsize_t outnet_get_mem(struct outside_network* outnet)
2476151378Snetchild{
2477151378Snetchild	size_t i;
2478151378Snetchild	int k;
2479151378Snetchild	struct waiting_tcp* w;
2480151378Snetchild	struct pending* u;
2481151378Snetchild	struct serviced_query* sq;
2482151378Snetchild	struct service_callback* sb;
2483151378Snetchild	struct port_comm* pc;
2484151378Snetchild	size_t s = sizeof(*outnet) + sizeof(*outnet->base) +
2485151378Snetchild		sizeof(*outnet->udp_buff) +
2486151378Snetchild		sldns_buffer_capacity(outnet->udp_buff);
2487151378Snetchild	/* second buffer is not ours */
2488151378Snetchild	for(pc = outnet->unused_fds; pc; pc = pc->next) {
2489151378Snetchild		s += sizeof(*pc) + comm_point_get_mem(pc->cp);
2490151378Snetchild	}
2491151378Snetchild	for(k=0; k<outnet->num_ip4; k++)
2492151378Snetchild		s += if_get_mem(&outnet->ip4_ifs[k]);
2493151378Snetchild	for(k=0; k<outnet->num_ip6; k++)
2494151378Snetchild		s += if_get_mem(&outnet->ip6_ifs[k]);
2495151378Snetchild	for(u=outnet->udp_wait_first; u; u=u->next_waiting)
2496151378Snetchild		s += waiting_udp_get_mem(u);
2497151378Snetchild
2498151378Snetchild	s += sizeof(struct pending_tcp*)*outnet->num_tcp;
2499151378Snetchild	for(i=0; i<outnet->num_tcp; i++) {
2500151378Snetchild		s += sizeof(struct pending_tcp);
2501151378Snetchild		s += comm_point_get_mem(outnet->tcp_conns[i]->c);
2502151378Snetchild		if(outnet->tcp_conns[i]->query)
2503151378Snetchild			s += waiting_tcp_get_mem(outnet->tcp_conns[i]->query);
2504151378Snetchild	}
2505151378Snetchild	for(w=outnet->tcp_wait_first; w; w = w->next_waiting)
2506151378Snetchild		s += waiting_tcp_get_mem(w);
2507151378Snetchild	s += sizeof(*outnet->pending);
2508151378Snetchild	s += (sizeof(struct pending) + comm_timer_get_mem(NULL)) *
2509151378Snetchild		outnet->pending->count;
2510151378Snetchild	s += sizeof(*outnet->serviced);
2511151378Snetchild	s += outnet->svcd_overhead;
2512151378Snetchild	RBTREE_FOR(sq, struct serviced_query*, outnet->serviced) {
2513151378Snetchild		s += sizeof(*sq) + sq->qbuflen;
2514151378Snetchild		for(sb = sq->cblist; sb; sb = sb->next)
2515151378Snetchild			s += sizeof(*sb);
2516151378Snetchild	}
2517151378Snetchild	return s;
2518151378Snetchild}
2519151378Snetchild
2520151378Snetchildsize_t
2521151378Snetchildserviced_get_mem(struct serviced_query* sq)
2522151378Snetchild{
2523151378Snetchild	struct service_callback* sb;
2524151378Snetchild	size_t s;
2525151378Snetchild	s = sizeof(*sq) + sq->qbuflen;
2526151378Snetchild	for(sb = sq->cblist; sb; sb = sb->next)
2527151378Snetchild		s += sizeof(*sb);
2528151378Snetchild	if(sq->status == serviced_query_UDP_EDNS ||
2529151378Snetchild		sq->status == serviced_query_UDP ||
2530151378Snetchild		sq->status == serviced_query_UDP_EDNS_FRAG ||
2531151378Snetchild		sq->status == serviced_query_UDP_EDNS_fallback) {
2532151378Snetchild		s += sizeof(struct pending);
2533151378Snetchild		s += comm_timer_get_mem(NULL);
2534151378Snetchild	} else {
2535151378Snetchild		/* does not have size of the pkt pointer */
2536151378Snetchild		/* always has a timer except on malloc failures */
2537151378Snetchild
2538151378Snetchild		/* these sizes are part of the main outside network mem */
2539151378Snetchild		/*
2540151378Snetchild		s += sizeof(struct waiting_tcp);
2541151378Snetchild		s += comm_timer_get_mem(NULL);
2542151378Snetchild		*/
2543151378Snetchild	}
2544151378Snetchild	return s;
2545151378Snetchild}
2546151378Snetchild
2547151378Snetchild