xref: /openbsd-src/usr.sbin/unbound/testcode/delayer.c (revision 0e9b6f9f434b93ba2f11e3b38a3da379b202585e)
1712b2f30Ssthen /*
2712b2f30Ssthen  * testcode/delayer.c - debug program that delays queries to a server.
3712b2f30Ssthen  *
4712b2f30Ssthen  * Copyright (c) 2008, NLnet Labs. All rights reserved.
5712b2f30Ssthen  *
6712b2f30Ssthen  * This software is open source.
7712b2f30Ssthen  *
8712b2f30Ssthen  * Redistribution and use in source and binary forms, with or without
9712b2f30Ssthen  * modification, are permitted provided that the following conditions
10712b2f30Ssthen  * are met:
11712b2f30Ssthen  *
12712b2f30Ssthen  * Redistributions of source code must retain the above copyright notice,
13712b2f30Ssthen  * this list of conditions and the following disclaimer.
14712b2f30Ssthen  *
15712b2f30Ssthen  * Redistributions in binary form must reproduce the above copyright notice,
16712b2f30Ssthen  * this list of conditions and the following disclaimer in the documentation
17712b2f30Ssthen  * and/or other materials provided with the distribution.
18712b2f30Ssthen  *
19712b2f30Ssthen  * Neither the name of the NLNET LABS nor the names of its contributors may
20712b2f30Ssthen  * be used to endorse or promote products derived from this software without
21712b2f30Ssthen  * specific prior written permission.
22712b2f30Ssthen  *
23712b2f30Ssthen  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24712b2f30Ssthen  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25712b2f30Ssthen  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26712b2f30Ssthen  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27712b2f30Ssthen  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28712b2f30Ssthen  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29712b2f30Ssthen  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30712b2f30Ssthen  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31712b2f30Ssthen  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32712b2f30Ssthen  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33712b2f30Ssthen  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34712b2f30Ssthen  */
35712b2f30Ssthen 
36712b2f30Ssthen /**
37712b2f30Ssthen  * \file
38712b2f30Ssthen  *
39712b2f30Ssthen  * This program delays queries made. It performs as a proxy to another
40712b2f30Ssthen  * server and delays queries to it.
41712b2f30Ssthen  */
42712b2f30Ssthen 
43712b2f30Ssthen #include "config.h"
44712b2f30Ssthen #ifdef HAVE_GETOPT_H
45712b2f30Ssthen #include <getopt.h>
46712b2f30Ssthen #endif
47712b2f30Ssthen #ifdef HAVE_TIME_H
48712b2f30Ssthen #include <time.h>
49712b2f30Ssthen #endif
50712b2f30Ssthen #include <sys/time.h>
51712b2f30Ssthen #include "util/net_help.h"
52712b2f30Ssthen #include "util/config_file.h"
53712b2f30Ssthen #include "sldns/sbuffer.h"
54712b2f30Ssthen #include <signal.h>
55712b2f30Ssthen 
56712b2f30Ssthen /** number of reads per select for delayer */
57712b2f30Ssthen #define TRIES_PER_SELECT 100
58712b2f30Ssthen 
59712b2f30Ssthen /**
60712b2f30Ssthen  * The ring buffer
61712b2f30Ssthen  */
62712b2f30Ssthen struct ringbuf {
63712b2f30Ssthen 	/** base of buffer */
64712b2f30Ssthen 	uint8_t* buf;
65712b2f30Ssthen 	/** size of buffer */
66712b2f30Ssthen 	size_t size;
67712b2f30Ssthen 	/** low mark, items start here */
68712b2f30Ssthen 	size_t low;
69712b2f30Ssthen 	/** high mark, items end here */
70712b2f30Ssthen 	size_t high;
71712b2f30Ssthen };
72712b2f30Ssthen 
73712b2f30Ssthen /**
74712b2f30Ssthen  * List of proxy fds that return replies from the server to our clients.
75712b2f30Ssthen  */
76712b2f30Ssthen struct proxy {
77712b2f30Ssthen 	/** the fd to listen for replies from server */
78712b2f30Ssthen 	int s;
79712b2f30Ssthen 	/** last time this was used */
80712b2f30Ssthen 	struct timeval lastuse;
81712b2f30Ssthen 	/** remote address */
82712b2f30Ssthen 	struct sockaddr_storage addr;
83712b2f30Ssthen 	/** length of addr */
84712b2f30Ssthen 	socklen_t addr_len;
85712b2f30Ssthen 	/** number of queries waiting (in total) */
86712b2f30Ssthen 	size_t numwait;
87712b2f30Ssthen 	/** number of queries sent to server (in total) */
88712b2f30Ssthen 	size_t numsent;
89712b2f30Ssthen 	/** numberof answers returned to client (in total) */
90712b2f30Ssthen 	size_t numreturn;
91712b2f30Ssthen 	/** how many times repurposed */
92712b2f30Ssthen 	size_t numreuse;
93712b2f30Ssthen 	/** next in proxylist */
94712b2f30Ssthen 	struct proxy* next;
95712b2f30Ssthen };
96712b2f30Ssthen 
97712b2f30Ssthen /**
98712b2f30Ssthen  * An item that has to be TCP relayed
99712b2f30Ssthen  */
100712b2f30Ssthen struct tcp_send_list {
101712b2f30Ssthen 	/** the data item */
102712b2f30Ssthen 	uint8_t* item;
103712b2f30Ssthen 	/** size of item */
104712b2f30Ssthen 	size_t len;
105712b2f30Ssthen 	/** time when the item can be transmitted on */
106712b2f30Ssthen 	struct timeval wait;
107712b2f30Ssthen 	/** how much of the item has already been transmitted */
108712b2f30Ssthen 	size_t done;
109712b2f30Ssthen 	/** next in list */
110712b2f30Ssthen 	struct tcp_send_list* next;
111712b2f30Ssthen };
112712b2f30Ssthen 
113712b2f30Ssthen /**
114712b2f30Ssthen  * List of TCP proxy fd pairs to TCP connect client to server
115712b2f30Ssthen  */
116712b2f30Ssthen struct tcp_proxy {
117712b2f30Ssthen 	/** the fd to listen for client query */
118712b2f30Ssthen 	int client_s;
119712b2f30Ssthen 	/** the fd to listen for server answer */
120712b2f30Ssthen 	int server_s;
121712b2f30Ssthen 
122712b2f30Ssthen 	/** remote client address */
123712b2f30Ssthen 	struct sockaddr_storage addr;
124712b2f30Ssthen 	/** length of address */
125712b2f30Ssthen 	socklen_t addr_len;
126712b2f30Ssthen 	/** timeout on this entry */
127712b2f30Ssthen 	struct timeval timeout;
128712b2f30Ssthen 
129712b2f30Ssthen 	/** list of query items to send to server */
130712b2f30Ssthen 	struct tcp_send_list* querylist;
131712b2f30Ssthen 	/** last in query list */
132712b2f30Ssthen 	struct tcp_send_list* querylast;
133712b2f30Ssthen 	/** list of answer items to send to client */
134712b2f30Ssthen 	struct tcp_send_list* answerlist;
135712b2f30Ssthen 	/** last in answerlist */
136712b2f30Ssthen 	struct tcp_send_list* answerlast;
137712b2f30Ssthen 
138712b2f30Ssthen 	/** next in list */
139712b2f30Ssthen 	struct tcp_proxy* next;
140712b2f30Ssthen };
141712b2f30Ssthen 
142712b2f30Ssthen /** usage information for delayer */
usage(char * argv[])143712b2f30Ssthen static void usage(char* argv[])
144712b2f30Ssthen {
145712b2f30Ssthen 	printf("usage: %s [options]\n", argv[0]);
146712b2f30Ssthen 	printf("	-f addr : use addr, forward to that server, @port.\n");
147712b2f30Ssthen 	printf("	-b addr : bind to this address to listen.\n");
148712b2f30Ssthen 	printf("	-p port : bind to this port (use 0 for random).\n");
149712b2f30Ssthen 	printf("	-m mem	: use this much memory for waiting queries.\n");
150712b2f30Ssthen 	printf("	-d delay: UDP queries are delayed n milliseconds.\n");
151712b2f30Ssthen 	printf("		  TCP is delayed twice (on send, on recv).\n");
152712b2f30Ssthen 	printf("	-h 	: this help message\n");
153712b2f30Ssthen 	exit(1);
154712b2f30Ssthen }
155712b2f30Ssthen 
156712b2f30Ssthen /** timeval compare, t1 < t2 */
157712b2f30Ssthen static int
dl_tv_smaller(struct timeval * t1,const struct timeval * t2)158712b2f30Ssthen dl_tv_smaller(struct timeval* t1, const struct timeval* t2)
159712b2f30Ssthen {
160712b2f30Ssthen #ifndef S_SPLINT_S
161712b2f30Ssthen 	if(t1->tv_sec < t2->tv_sec)
162712b2f30Ssthen 		return 1;
163712b2f30Ssthen 	if(t1->tv_sec == t2->tv_sec &&
164712b2f30Ssthen 		t1->tv_usec < t2->tv_usec)
165712b2f30Ssthen 		return 1;
166712b2f30Ssthen #endif
167712b2f30Ssthen 	return 0;
168712b2f30Ssthen }
169712b2f30Ssthen 
170712b2f30Ssthen /** timeval add, t1 += t2 */
171712b2f30Ssthen static void
dl_tv_add(struct timeval * t1,const struct timeval * t2)172712b2f30Ssthen dl_tv_add(struct timeval* t1, const struct timeval* t2)
173712b2f30Ssthen {
174712b2f30Ssthen #ifndef S_SPLINT_S
175712b2f30Ssthen 	t1->tv_sec += t2->tv_sec;
176712b2f30Ssthen 	t1->tv_usec += t2->tv_usec;
177c981f76fSsthen 	while(t1->tv_usec >= 1000000) {
178712b2f30Ssthen 		t1->tv_usec -= 1000000;
179712b2f30Ssthen 		t1->tv_sec++;
180712b2f30Ssthen 	}
181712b2f30Ssthen #endif
182712b2f30Ssthen }
183712b2f30Ssthen 
184712b2f30Ssthen /** timeval subtract, t1 -= t2 */
185712b2f30Ssthen static void
dl_tv_subtract(struct timeval * t1,const struct timeval * t2)186712b2f30Ssthen dl_tv_subtract(struct timeval* t1, const struct timeval* t2)
187712b2f30Ssthen {
188712b2f30Ssthen #ifndef S_SPLINT_S
189712b2f30Ssthen 	t1->tv_sec -= t2->tv_sec;
190712b2f30Ssthen 	if(t1->tv_usec >= t2->tv_usec) {
191712b2f30Ssthen 		t1->tv_usec -= t2->tv_usec;
192712b2f30Ssthen 	} else {
193712b2f30Ssthen 		t1->tv_sec--;
194712b2f30Ssthen 		t1->tv_usec = 1000000-(t2->tv_usec-t1->tv_usec);
195712b2f30Ssthen 	}
196712b2f30Ssthen #endif
197712b2f30Ssthen }
198712b2f30Ssthen 
199712b2f30Ssthen 
200712b2f30Ssthen /** create new ring buffer */
201712b2f30Ssthen static struct ringbuf*
ring_create(size_t sz)202712b2f30Ssthen ring_create(size_t sz)
203712b2f30Ssthen {
204712b2f30Ssthen 	struct ringbuf* r = (struct ringbuf*)calloc(1, sizeof(*r));
205712b2f30Ssthen 	if(!r) fatal_exit("out of memory");
206712b2f30Ssthen 	r->buf = (uint8_t*)malloc(sz);
207712b2f30Ssthen 	if(!r->buf) fatal_exit("out of memory");
208712b2f30Ssthen 	r->size = sz;
209712b2f30Ssthen 	r->low = 0;
210712b2f30Ssthen 	r->high = 0;
211712b2f30Ssthen 	return r;
212712b2f30Ssthen }
213712b2f30Ssthen 
214712b2f30Ssthen /** delete ring buffer */
215712b2f30Ssthen static void
ring_delete(struct ringbuf * r)216712b2f30Ssthen ring_delete(struct ringbuf* r)
217712b2f30Ssthen {
218712b2f30Ssthen 	if(!r) return;
219712b2f30Ssthen 	free(r->buf);
220712b2f30Ssthen 	free(r);
221712b2f30Ssthen }
222712b2f30Ssthen 
223712b2f30Ssthen /** add entry to ringbuffer */
224712b2f30Ssthen static void
ring_add(struct ringbuf * r,sldns_buffer * pkt,struct timeval * now,struct timeval * delay,struct proxy * p)225712b2f30Ssthen ring_add(struct ringbuf* r, sldns_buffer* pkt, struct timeval* now,
226712b2f30Ssthen 	struct timeval* delay, struct proxy* p)
227712b2f30Ssthen {
228712b2f30Ssthen 	/* time -- proxy* -- 16bitlen -- message */
229712b2f30Ssthen 	uint16_t len = (uint16_t)sldns_buffer_limit(pkt);
230712b2f30Ssthen 	struct timeval when;
231712b2f30Ssthen 	size_t needed;
232712b2f30Ssthen 	uint8_t* where = NULL;
233712b2f30Ssthen 	log_assert(sldns_buffer_limit(pkt) <= 65535);
234712b2f30Ssthen 	needed = sizeof(when) + sizeof(p) + sizeof(len) + len;
235712b2f30Ssthen 	/* put item into ringbuffer */
236712b2f30Ssthen 	if(r->low < r->high) {
237712b2f30Ssthen 		/* used part is in the middle */
238712b2f30Ssthen 		if(r->size - r->high >= needed) {
239712b2f30Ssthen 			where = r->buf + r->high;
240712b2f30Ssthen 			r->high += needed;
241712b2f30Ssthen 		} else if(r->low > needed) {
242712b2f30Ssthen 			/* wrap around ringbuffer */
243712b2f30Ssthen 			/* make sure r->low == r->high means empty */
244712b2f30Ssthen 			/* so r->low == r->high cannot be used to signify
245712b2f30Ssthen 			 * a completely full ringbuf */
246712b2f30Ssthen 			if(r->size - r->high > sizeof(when)+sizeof(p)) {
247712b2f30Ssthen 				/* zero entry at end of buffer */
248712b2f30Ssthen 				memset(r->buf+r->high, 0,
249712b2f30Ssthen 					sizeof(when)+sizeof(p));
250712b2f30Ssthen 			}
251712b2f30Ssthen 			where = r->buf;
252712b2f30Ssthen 			r->high = needed;
253712b2f30Ssthen 		} else {
254712b2f30Ssthen 			/* drop message */
255712b2f30Ssthen 			log_warn("warning: mem full, dropped message");
256712b2f30Ssthen 			return;
257712b2f30Ssthen 		}
258712b2f30Ssthen 	} else {
259712b2f30Ssthen 		/* empty */
260712b2f30Ssthen 		if(r->high == r->low) {
261712b2f30Ssthen 			where = r->buf;
262712b2f30Ssthen 			r->low = 0;
263712b2f30Ssthen 			r->high = needed;
264712b2f30Ssthen 		/* unused part is in the middle */
265712b2f30Ssthen 		/* so ringbuffer has wrapped around */
266712b2f30Ssthen 		} else if(r->low - r->high > needed) {
267712b2f30Ssthen 			where = r->buf + r->high;
268712b2f30Ssthen 			r->high += needed;
269712b2f30Ssthen 		} else {
270712b2f30Ssthen 			log_warn("warning: mem full, dropped message");
271712b2f30Ssthen 			return;
272712b2f30Ssthen 		}
273712b2f30Ssthen 	}
274712b2f30Ssthen 	when = *now;
275712b2f30Ssthen 	dl_tv_add(&when, delay);
276712b2f30Ssthen 	/* copy it at where part */
277712b2f30Ssthen 	log_assert(where != NULL);
278712b2f30Ssthen 	memmove(where, &when, sizeof(when));
279712b2f30Ssthen 	memmove(where+sizeof(when), &p, sizeof(p));
280712b2f30Ssthen 	memmove(where+sizeof(when)+sizeof(p), &len, sizeof(len));
281712b2f30Ssthen 	memmove(where+sizeof(when)+sizeof(p)+sizeof(len),
282712b2f30Ssthen 		sldns_buffer_begin(pkt), len);
283712b2f30Ssthen }
284712b2f30Ssthen 
285712b2f30Ssthen /** see if the ringbuffer is empty */
286712b2f30Ssthen static int
ring_empty(struct ringbuf * r)287712b2f30Ssthen ring_empty(struct ringbuf* r)
288712b2f30Ssthen {
289712b2f30Ssthen 	return (r->low == r->high);
290712b2f30Ssthen }
291712b2f30Ssthen 
292712b2f30Ssthen /** peek at timevalue for next item in ring */
293712b2f30Ssthen static struct timeval*
ring_peek_time(struct ringbuf * r)294712b2f30Ssthen ring_peek_time(struct ringbuf* r)
295712b2f30Ssthen {
296712b2f30Ssthen 	if(ring_empty(r))
297712b2f30Ssthen 		return NULL;
298712b2f30Ssthen 	return (struct timeval*)&r->buf[r->low];
299712b2f30Ssthen }
300712b2f30Ssthen 
301712b2f30Ssthen /** get entry from ringbuffer */
302712b2f30Ssthen static int
ring_pop(struct ringbuf * r,sldns_buffer * pkt,struct timeval * tv,struct proxy ** p)303712b2f30Ssthen ring_pop(struct ringbuf* r, sldns_buffer* pkt, struct timeval* tv,
304712b2f30Ssthen 	struct proxy** p)
305712b2f30Ssthen {
306712b2f30Ssthen 	/* time -- proxy* -- 16bitlen -- message */
307712b2f30Ssthen 	uint16_t len;
308712b2f30Ssthen 	uint8_t* where = NULL;
309712b2f30Ssthen 	size_t done;
310712b2f30Ssthen 	if(r->low == r->high)
311712b2f30Ssthen 		return 0;
312712b2f30Ssthen 	where = r->buf + r->low;
313712b2f30Ssthen 	memmove(tv, where, sizeof(*tv));
314712b2f30Ssthen 	memmove(p, where+sizeof(*tv), sizeof(*p));
315712b2f30Ssthen 	memmove(&len, where+sizeof(*tv)+sizeof(*p), sizeof(len));
316712b2f30Ssthen 	memmove(sldns_buffer_begin(pkt),
317712b2f30Ssthen 		where+sizeof(*tv)+sizeof(*p)+sizeof(len), len);
318712b2f30Ssthen 	sldns_buffer_set_limit(pkt, (size_t)len);
319712b2f30Ssthen 	done = sizeof(*tv)+sizeof(*p)+sizeof(len)+len;
320712b2f30Ssthen 	/* move lowmark */
321712b2f30Ssthen 	if(r->low < r->high) {
322712b2f30Ssthen 		/* used part in middle */
323712b2f30Ssthen 		log_assert(r->high - r->low >= done);
324712b2f30Ssthen 		r->low += done;
325712b2f30Ssthen 	} else {
326712b2f30Ssthen 		/* unused part in middle */
327712b2f30Ssthen 		log_assert(r->size - r->low >= done);
328712b2f30Ssthen 		r->low += done;
329712b2f30Ssthen 		if(r->size - r->low > sizeof(*tv)+sizeof(*p)) {
330712b2f30Ssthen 			/* see if it is zeroed; means end of buffer */
331712b2f30Ssthen 			struct proxy* pz;
332712b2f30Ssthen 			memmove(&pz, r->buf+r->low+sizeof(*tv), sizeof(pz));
333712b2f30Ssthen 			if(pz == NULL)
334712b2f30Ssthen 				r->low = 0;
335712b2f30Ssthen 		} else r->low = 0;
336712b2f30Ssthen 	}
337712b2f30Ssthen 	if(r->low == r->high) {
338712b2f30Ssthen 		r->low = 0; /* reset if empty */
339712b2f30Ssthen 		r->high = 0;
340712b2f30Ssthen 	}
341712b2f30Ssthen 	return 1;
342712b2f30Ssthen }
343712b2f30Ssthen 
344712b2f30Ssthen /** signal handler global info */
345712b2f30Ssthen static volatile int do_quit = 0;
346712b2f30Ssthen 
347712b2f30Ssthen /** signal handler for user quit */
delayer_sigh(int sig)348712b2f30Ssthen static RETSIGTYPE delayer_sigh(int sig)
349712b2f30Ssthen {
350a6cc1574Ssthen 	char str[] = "exit on signal   \n";
351a6cc1574Ssthen 	str[15] = '0' + (sig/10)%10;
352a6cc1574Ssthen 	str[16] = '0' + sig%10;
353a6cc1574Ssthen 	/* simple cast to void will not silence Wunused-result */
354a6cc1574Ssthen 	(void)!write(STDOUT_FILENO, str, strlen(str));
355712b2f30Ssthen 	do_quit = 1;
356712b2f30Ssthen }
357712b2f30Ssthen 
358712b2f30Ssthen /** send out waiting packets */
359712b2f30Ssthen static void
service_send(struct ringbuf * ring,struct timeval * now,sldns_buffer * pkt,struct sockaddr_storage * srv_addr,socklen_t srv_len)360712b2f30Ssthen service_send(struct ringbuf* ring, struct timeval* now, sldns_buffer* pkt,
361712b2f30Ssthen 	struct sockaddr_storage* srv_addr, socklen_t srv_len)
362712b2f30Ssthen {
363712b2f30Ssthen 	struct proxy* p;
364712b2f30Ssthen 	struct timeval tv;
365712b2f30Ssthen 	ssize_t sent;
366712b2f30Ssthen 	while(!ring_empty(ring) &&
367712b2f30Ssthen 		dl_tv_smaller(ring_peek_time(ring), now)) {
368712b2f30Ssthen 		/* this items needs to be sent out */
369712b2f30Ssthen 		if(!ring_pop(ring, pkt, &tv, &p))
370712b2f30Ssthen 			fatal_exit("ringbuf error: pop failed");
371712b2f30Ssthen 		verbose(1, "send out query %d.%6.6d",
372712b2f30Ssthen 			(unsigned)tv.tv_sec, (unsigned)tv.tv_usec);
373712b2f30Ssthen 		log_addr(1, "from client", &p->addr, p->addr_len);
374712b2f30Ssthen 		/* send it */
375712b2f30Ssthen 		sent = sendto(p->s, (void*)sldns_buffer_begin(pkt),
376712b2f30Ssthen 			sldns_buffer_limit(pkt), 0,
377712b2f30Ssthen 			(struct sockaddr*)srv_addr, srv_len);
378712b2f30Ssthen 		if(sent == -1) {
379e2a0f313Ssthen 			log_err("sendto: %s", sock_strerror(errno));
380712b2f30Ssthen 		} else if(sent != (ssize_t)sldns_buffer_limit(pkt)) {
381712b2f30Ssthen 			log_err("sendto: partial send");
382712b2f30Ssthen 		}
383712b2f30Ssthen 		p->lastuse = *now;
384712b2f30Ssthen 		p->numsent++;
385712b2f30Ssthen 	}
386712b2f30Ssthen }
387712b2f30Ssthen 
388712b2f30Ssthen /** do proxy for one readable client */
389712b2f30Ssthen static void
do_proxy(struct proxy * p,int retsock,sldns_buffer * pkt)390712b2f30Ssthen do_proxy(struct proxy* p, int retsock, sldns_buffer* pkt)
391712b2f30Ssthen {
392712b2f30Ssthen 	int i;
393712b2f30Ssthen 	ssize_t r;
394712b2f30Ssthen 	for(i=0; i<TRIES_PER_SELECT; i++) {
395712b2f30Ssthen 		r = recv(p->s, (void*)sldns_buffer_begin(pkt),
396712b2f30Ssthen 			sldns_buffer_capacity(pkt), 0);
397712b2f30Ssthen 		if(r == -1) {
398712b2f30Ssthen #ifndef USE_WINSOCK
399712b2f30Ssthen 			if(errno == EAGAIN || errno == EINTR)
400712b2f30Ssthen 				return;
401712b2f30Ssthen #else
402712b2f30Ssthen 			if(WSAGetLastError() == WSAEINPROGRESS ||
403712b2f30Ssthen 				WSAGetLastError() == WSAEWOULDBLOCK)
404712b2f30Ssthen 				return;
405712b2f30Ssthen #endif
406e2a0f313Ssthen 			log_err("recv: %s", sock_strerror(errno));
407712b2f30Ssthen 			return;
408712b2f30Ssthen 		}
409712b2f30Ssthen 		sldns_buffer_set_limit(pkt, (size_t)r);
410712b2f30Ssthen 		log_addr(1, "return reply to client", &p->addr, p->addr_len);
411712b2f30Ssthen 		/* send reply back to the real client */
412712b2f30Ssthen 		p->numreturn++;
413712b2f30Ssthen 		r = sendto(retsock, (void*)sldns_buffer_begin(pkt), (size_t)r,
414712b2f30Ssthen 			0, (struct sockaddr*)&p->addr, p->addr_len);
415712b2f30Ssthen 		if(r == -1) {
416e2a0f313Ssthen 			log_err("sendto: %s", sock_strerror(errno));
417712b2f30Ssthen 		}
418712b2f30Ssthen 	}
419712b2f30Ssthen }
420712b2f30Ssthen 
421712b2f30Ssthen /** proxy return replies to clients */
422712b2f30Ssthen static void
service_proxy(fd_set * rset,int retsock,struct proxy * proxies,sldns_buffer * pkt,struct timeval * now)423712b2f30Ssthen service_proxy(fd_set* rset, int retsock, struct proxy* proxies,
424712b2f30Ssthen 	sldns_buffer* pkt, struct timeval* now)
425712b2f30Ssthen {
426712b2f30Ssthen 	struct proxy* p;
427712b2f30Ssthen 	for(p = proxies; p; p = p->next) {
428712b2f30Ssthen 		if(FD_ISSET(p->s, rset)) {
429712b2f30Ssthen 			p->lastuse = *now;
430712b2f30Ssthen 			do_proxy(p, retsock, pkt);
431712b2f30Ssthen 		}
432712b2f30Ssthen 	}
433712b2f30Ssthen }
434712b2f30Ssthen 
435712b2f30Ssthen /** find or else create proxy for this remote client */
436712b2f30Ssthen static struct proxy*
find_create_proxy(struct sockaddr_storage * from,socklen_t from_len,fd_set * rorig,int * max,struct proxy ** proxies,int serv_ip6,struct timeval * now,struct timeval * reuse_timeout)437712b2f30Ssthen find_create_proxy(struct sockaddr_storage* from, socklen_t from_len,
438712b2f30Ssthen 	fd_set* rorig, int* max, struct proxy** proxies, int serv_ip6,
439712b2f30Ssthen 	struct timeval* now, struct timeval* reuse_timeout)
440712b2f30Ssthen {
441712b2f30Ssthen 	struct proxy* p;
442712b2f30Ssthen 	struct timeval t;
443712b2f30Ssthen 	for(p = *proxies; p; p = p->next) {
444712b2f30Ssthen 		if(sockaddr_cmp(from, from_len, &p->addr, p->addr_len)==0)
445712b2f30Ssthen 			return p;
446712b2f30Ssthen 	}
447712b2f30Ssthen 	/* possibly: reuse lapsed entries */
448712b2f30Ssthen 	for(p = *proxies; p; p = p->next) {
449712b2f30Ssthen 		if(p->numwait > p->numsent || p->numsent > p->numreturn)
450712b2f30Ssthen 			continue;
451712b2f30Ssthen 		t = *now;
452712b2f30Ssthen 		dl_tv_subtract(&t, &p->lastuse);
453712b2f30Ssthen 		if(dl_tv_smaller(&t, reuse_timeout))
454712b2f30Ssthen 			continue;
455712b2f30Ssthen 		/* yes! */
456712b2f30Ssthen 		verbose(1, "reuse existing entry");
457712b2f30Ssthen 		memmove(&p->addr, from, from_len);
458712b2f30Ssthen 		p->addr_len = from_len;
459712b2f30Ssthen 		p->numreuse++;
460712b2f30Ssthen 		return p;
461712b2f30Ssthen 	}
462712b2f30Ssthen 	/* create new */
463712b2f30Ssthen 	p = (struct proxy*)calloc(1, sizeof(*p));
464712b2f30Ssthen 	if(!p) fatal_exit("out of memory");
465712b2f30Ssthen 	p->s = socket(serv_ip6?AF_INET6:AF_INET, SOCK_DGRAM, 0);
466712b2f30Ssthen 	if(p->s == -1) {
467e2a0f313Ssthen 		fatal_exit("socket: %s", sock_strerror(errno));
468712b2f30Ssthen 	}
469712b2f30Ssthen 	fd_set_nonblock(p->s);
470712b2f30Ssthen 	memmove(&p->addr, from, from_len);
471712b2f30Ssthen 	p->addr_len = from_len;
472712b2f30Ssthen 	p->next = *proxies;
473712b2f30Ssthen 	*proxies = p;
474712b2f30Ssthen 	FD_SET(FD_SET_T p->s, rorig);
475712b2f30Ssthen 	if(p->s+1 > *max)
476712b2f30Ssthen 		*max = p->s+1;
477712b2f30Ssthen 	return p;
478712b2f30Ssthen }
479712b2f30Ssthen 
480712b2f30Ssthen /** recv new waiting packets */
481712b2f30Ssthen static void
service_recv(int s,struct ringbuf * ring,sldns_buffer * pkt,fd_set * rorig,int * max,struct proxy ** proxies,struct sockaddr_storage * srv_addr,socklen_t srv_len,struct timeval * now,struct timeval * delay,struct timeval * reuse)482712b2f30Ssthen service_recv(int s, struct ringbuf* ring, sldns_buffer* pkt,
483712b2f30Ssthen 	fd_set* rorig, int* max, struct proxy** proxies,
484712b2f30Ssthen 	struct sockaddr_storage* srv_addr, socklen_t srv_len,
485712b2f30Ssthen 	struct timeval* now, struct timeval* delay, struct timeval* reuse)
486712b2f30Ssthen {
487712b2f30Ssthen 	int i;
488712b2f30Ssthen 	struct sockaddr_storage from;
489712b2f30Ssthen 	socklen_t from_len;
490712b2f30Ssthen 	ssize_t len;
491712b2f30Ssthen 	struct proxy* p;
492712b2f30Ssthen 	for(i=0; i<TRIES_PER_SELECT; i++) {
493712b2f30Ssthen 		from_len = (socklen_t)sizeof(from);
494712b2f30Ssthen 		len = recvfrom(s, (void*)sldns_buffer_begin(pkt),
495712b2f30Ssthen 			sldns_buffer_capacity(pkt), 0,
496712b2f30Ssthen 			(struct sockaddr*)&from, &from_len);
497712b2f30Ssthen 		if(len < 0) {
498712b2f30Ssthen #ifndef USE_WINSOCK
499712b2f30Ssthen 			if(errno == EAGAIN || errno == EINTR)
500712b2f30Ssthen 				return;
501712b2f30Ssthen #else
502712b2f30Ssthen 			if(WSAGetLastError() == WSAEWOULDBLOCK ||
503712b2f30Ssthen 				WSAGetLastError() == WSAEINPROGRESS)
504712b2f30Ssthen 				return;
505712b2f30Ssthen #endif
506e2a0f313Ssthen 			fatal_exit("recvfrom: %s", sock_strerror(errno));
507712b2f30Ssthen 		}
508712b2f30Ssthen 		sldns_buffer_set_limit(pkt, (size_t)len);
509712b2f30Ssthen 		/* find its proxy element */
510712b2f30Ssthen 		p = find_create_proxy(&from, from_len, rorig, max, proxies,
511712b2f30Ssthen 			addr_is_ip6(srv_addr, srv_len), now, reuse);
512712b2f30Ssthen 		if(!p) fatal_exit("error: cannot find or create proxy");
513712b2f30Ssthen 		p->lastuse = *now;
514712b2f30Ssthen 		ring_add(ring, pkt, now, delay, p);
515712b2f30Ssthen 		p->numwait++;
516712b2f30Ssthen 		log_addr(1, "recv from client", &p->addr, p->addr_len);
517712b2f30Ssthen 	}
518712b2f30Ssthen }
519712b2f30Ssthen 
520712b2f30Ssthen /** delete tcp proxy */
521712b2f30Ssthen static void
tcp_proxy_delete(struct tcp_proxy * p)522712b2f30Ssthen tcp_proxy_delete(struct tcp_proxy* p)
523712b2f30Ssthen {
524712b2f30Ssthen 	struct tcp_send_list* s, *sn;
525712b2f30Ssthen 	if(!p)
526712b2f30Ssthen 		return;
527712b2f30Ssthen 	log_addr(1, "delete tcp proxy", &p->addr, p->addr_len);
528712b2f30Ssthen 	s = p->querylist;
529712b2f30Ssthen 	while(s) {
530712b2f30Ssthen 		sn = s->next;
531712b2f30Ssthen 		free(s->item);
532712b2f30Ssthen 		free(s);
533712b2f30Ssthen 		s = sn;
534712b2f30Ssthen 	}
535712b2f30Ssthen 	s = p->answerlist;
536712b2f30Ssthen 	while(s) {
537712b2f30Ssthen 		sn = s->next;
538712b2f30Ssthen 		free(s->item);
539712b2f30Ssthen 		free(s);
540712b2f30Ssthen 		s = sn;
541712b2f30Ssthen 	}
542e2a0f313Ssthen 	sock_close(p->client_s);
543712b2f30Ssthen 	if(p->server_s != -1)
544e2a0f313Ssthen 		sock_close(p->server_s);
545712b2f30Ssthen 	free(p);
546712b2f30Ssthen }
547712b2f30Ssthen 
548712b2f30Ssthen /** accept new TCP connections, and set them up */
549712b2f30Ssthen static void
service_tcp_listen(int s,fd_set * rorig,int * max,struct tcp_proxy ** proxies,struct sockaddr_storage * srv_addr,socklen_t srv_len,struct timeval * now,struct timeval * tcp_timeout)550712b2f30Ssthen service_tcp_listen(int s, fd_set* rorig, int* max, struct tcp_proxy** proxies,
551712b2f30Ssthen 	struct sockaddr_storage* srv_addr, socklen_t srv_len,
552712b2f30Ssthen 	struct timeval* now, struct timeval* tcp_timeout)
553712b2f30Ssthen {
554712b2f30Ssthen 	int newfd;
555712b2f30Ssthen 	struct sockaddr_storage addr;
556712b2f30Ssthen 	struct tcp_proxy* p;
557712b2f30Ssthen 	socklen_t addr_len;
558712b2f30Ssthen 	newfd = accept(s, (struct sockaddr*)&addr, &addr_len);
559712b2f30Ssthen 	if(newfd == -1) {
560712b2f30Ssthen #ifndef USE_WINSOCK
561712b2f30Ssthen 		if(errno == EAGAIN || errno == EINTR)
562712b2f30Ssthen 			return;
563712b2f30Ssthen #else
564712b2f30Ssthen 		if(WSAGetLastError() == WSAEWOULDBLOCK ||
565712b2f30Ssthen 			WSAGetLastError() == WSAEINPROGRESS ||
566712b2f30Ssthen 			WSAGetLastError() == WSAECONNRESET)
567712b2f30Ssthen 			return;
568712b2f30Ssthen #endif
569e2a0f313Ssthen 		fatal_exit("accept: %s", sock_strerror(errno));
570712b2f30Ssthen 	}
571712b2f30Ssthen 	p = (struct tcp_proxy*)calloc(1, sizeof(*p));
572712b2f30Ssthen 	if(!p) fatal_exit("out of memory");
573712b2f30Ssthen 	memmove(&p->addr, &addr, addr_len);
574712b2f30Ssthen 	p->addr_len = addr_len;
575712b2f30Ssthen 	log_addr(1, "new tcp proxy", &p->addr, p->addr_len);
576712b2f30Ssthen 	p->client_s = newfd;
577712b2f30Ssthen 	p->server_s = socket(addr_is_ip6(srv_addr, srv_len)?AF_INET6:AF_INET,
578712b2f30Ssthen 		SOCK_STREAM, 0);
579712b2f30Ssthen 	if(p->server_s == -1) {
580e2a0f313Ssthen 		fatal_exit("tcp socket: %s", sock_strerror(errno));
581712b2f30Ssthen 	}
582712b2f30Ssthen 	fd_set_nonblock(p->client_s);
583712b2f30Ssthen 	fd_set_nonblock(p->server_s);
584712b2f30Ssthen 	if(connect(p->server_s, (struct sockaddr*)srv_addr, srv_len) == -1) {
585712b2f30Ssthen #ifndef USE_WINSOCK
586712b2f30Ssthen 		if(errno != EINPROGRESS) {
587712b2f30Ssthen 			log_err("tcp connect: %s", strerror(errno));
588712b2f30Ssthen #else
589712b2f30Ssthen 		if(WSAGetLastError() != WSAEWOULDBLOCK &&
590712b2f30Ssthen 			WSAGetLastError() != WSAEINPROGRESS) {
591712b2f30Ssthen 			log_err("tcp connect: %s",
592712b2f30Ssthen 				wsa_strerror(WSAGetLastError()));
593712b2f30Ssthen #endif
594e2a0f313Ssthen 			sock_close(p->server_s);
595e2a0f313Ssthen 			sock_close(p->client_s);
596712b2f30Ssthen 			free(p);
597712b2f30Ssthen 			return;
598712b2f30Ssthen 		}
599712b2f30Ssthen 	}
600712b2f30Ssthen 	p->timeout = *now;
601712b2f30Ssthen 	dl_tv_add(&p->timeout, tcp_timeout);
602712b2f30Ssthen 
603712b2f30Ssthen 	/* listen to client and server */
604712b2f30Ssthen 	FD_SET(FD_SET_T p->client_s, rorig);
605712b2f30Ssthen 	FD_SET(FD_SET_T p->server_s, rorig);
606712b2f30Ssthen 	if(p->client_s+1 > *max)
607712b2f30Ssthen 		*max = p->client_s+1;
608712b2f30Ssthen 	if(p->server_s+1 > *max)
609712b2f30Ssthen 		*max = p->server_s+1;
610712b2f30Ssthen 
611712b2f30Ssthen 	/* add into proxy list */
612712b2f30Ssthen 	p->next = *proxies;
613712b2f30Ssthen 	*proxies = p;
614712b2f30Ssthen }
615712b2f30Ssthen 
616712b2f30Ssthen /** relay TCP, read a part */
617712b2f30Ssthen static int
618712b2f30Ssthen tcp_relay_read(int s, struct tcp_send_list** first,
619712b2f30Ssthen 	struct tcp_send_list** last, struct timeval* now,
620712b2f30Ssthen 	struct timeval* delay, sldns_buffer* pkt)
621712b2f30Ssthen {
622712b2f30Ssthen 	struct tcp_send_list* item;
623712b2f30Ssthen 	ssize_t r = recv(s, (void*)sldns_buffer_begin(pkt),
624712b2f30Ssthen 		sldns_buffer_capacity(pkt), 0);
625712b2f30Ssthen 	if(r == -1) {
626712b2f30Ssthen #ifndef USE_WINSOCK
627712b2f30Ssthen 		if(errno == EINTR || errno == EAGAIN)
628712b2f30Ssthen 			return 1;
629712b2f30Ssthen #else
630712b2f30Ssthen 		if(WSAGetLastError() == WSAEINPROGRESS ||
631712b2f30Ssthen 			WSAGetLastError() == WSAEWOULDBLOCK)
632712b2f30Ssthen 			return 1;
633712b2f30Ssthen #endif
634e2a0f313Ssthen 		log_err("tcp read: %s", sock_strerror(errno));
635712b2f30Ssthen 		return 0;
636712b2f30Ssthen 	} else if(r == 0) {
637712b2f30Ssthen 		/* connection closed */
638712b2f30Ssthen 		return 0;
639712b2f30Ssthen 	}
640712b2f30Ssthen 	item = (struct tcp_send_list*)malloc(sizeof(*item));
641712b2f30Ssthen 	if(!item) {
642712b2f30Ssthen 		log_err("out of memory");
643712b2f30Ssthen 		return 0;
644712b2f30Ssthen 	}
645712b2f30Ssthen 	verbose(1, "read item len %d", (int)r);
646712b2f30Ssthen 	item->len = (size_t)r;
647712b2f30Ssthen 	item->item = memdup(sldns_buffer_begin(pkt), item->len);
648712b2f30Ssthen 	if(!item->item) {
649712b2f30Ssthen 		free(item);
650712b2f30Ssthen 		log_err("out of memory");
651712b2f30Ssthen 		return 0;
652712b2f30Ssthen 	}
653712b2f30Ssthen 	item->done = 0;
654712b2f30Ssthen 	item->wait = *now;
655712b2f30Ssthen 	dl_tv_add(&item->wait, delay);
656712b2f30Ssthen 	item->next = NULL;
657712b2f30Ssthen 
658712b2f30Ssthen 	/* link in */
659712b2f30Ssthen 	if(*first) {
660712b2f30Ssthen 		(*last)->next = item;
661712b2f30Ssthen 	} else {
662712b2f30Ssthen 		*first = item;
663712b2f30Ssthen 	}
664712b2f30Ssthen 	*last = item;
665712b2f30Ssthen 	return 1;
666712b2f30Ssthen }
667712b2f30Ssthen 
668712b2f30Ssthen /** relay TCP, write a part */
669712b2f30Ssthen static int
670712b2f30Ssthen tcp_relay_write(int s, struct tcp_send_list** first,
671712b2f30Ssthen 	struct tcp_send_list** last, struct timeval* now)
672712b2f30Ssthen {
673712b2f30Ssthen 	ssize_t r;
674712b2f30Ssthen 	struct tcp_send_list* p;
675712b2f30Ssthen 	while(*first) {
676712b2f30Ssthen 		p = *first;
677712b2f30Ssthen 		/* is the item ready? */
678712b2f30Ssthen 		if(!dl_tv_smaller(&p->wait, now))
679712b2f30Ssthen 			return 1;
680712b2f30Ssthen 		/* write it */
681712b2f30Ssthen 		r = send(s, (void*)(p->item + p->done), p->len - p->done, 0);
682712b2f30Ssthen 		if(r == -1) {
683712b2f30Ssthen #ifndef USE_WINSOCK
684712b2f30Ssthen 			if(errno == EAGAIN || errno == EINTR)
685712b2f30Ssthen 				return 1;
686712b2f30Ssthen #else
687712b2f30Ssthen 			if(WSAGetLastError() == WSAEWOULDBLOCK ||
688712b2f30Ssthen 				WSAGetLastError() == WSAEINPROGRESS)
689712b2f30Ssthen 				return 1;
690712b2f30Ssthen #endif
691e2a0f313Ssthen 			log_err("tcp write: %s", sock_strerror(errno));
692712b2f30Ssthen 			return 0;
693712b2f30Ssthen 		} else if(r == 0) {
694712b2f30Ssthen 			/* closed */
695712b2f30Ssthen 			return 0;
696712b2f30Ssthen 		}
697712b2f30Ssthen 		/* account it */
698712b2f30Ssthen 		p->done += (size_t)r;
699712b2f30Ssthen 		verbose(1, "write item %d of %d", (int)p->done, (int)p->len);
700712b2f30Ssthen 		if(p->done >= p->len) {
701712b2f30Ssthen 			free(p->item);
702712b2f30Ssthen 			*first = p->next;
703712b2f30Ssthen 			if(!*first)
704712b2f30Ssthen 				*last = NULL;
705712b2f30Ssthen 			free(p);
706712b2f30Ssthen 		} else {
707712b2f30Ssthen 			/* partial write */
708712b2f30Ssthen 			return 1;
709712b2f30Ssthen 		}
710712b2f30Ssthen 	}
711712b2f30Ssthen 	return 1;
712712b2f30Ssthen }
713712b2f30Ssthen 
714712b2f30Ssthen /** perform TCP relaying */
715712b2f30Ssthen static void
716712b2f30Ssthen service_tcp_relay(struct tcp_proxy** tcp_proxies, struct timeval* now,
717712b2f30Ssthen 	struct timeval* delay, struct timeval* tcp_timeout, sldns_buffer* pkt,
718712b2f30Ssthen 	fd_set* rset, fd_set* rorig, fd_set* worig)
719712b2f30Ssthen {
720712b2f30Ssthen 	struct tcp_proxy* p, **prev;
721712b2f30Ssthen 	struct timeval tout;
722712b2f30Ssthen 	int delete_it;
723712b2f30Ssthen 	p = *tcp_proxies;
724712b2f30Ssthen 	prev = tcp_proxies;
725712b2f30Ssthen 	tout = *now;
726712b2f30Ssthen 	dl_tv_add(&tout, tcp_timeout);
727712b2f30Ssthen 
728712b2f30Ssthen 	while(p) {
729712b2f30Ssthen 		delete_it = 0;
730712b2f30Ssthen 		/* can we receive further queries? */
731712b2f30Ssthen 		if(!delete_it && FD_ISSET(p->client_s, rset)) {
732712b2f30Ssthen 			p->timeout = tout;
733712b2f30Ssthen 			log_addr(1, "read tcp query", &p->addr, p->addr_len);
734712b2f30Ssthen 			if(!tcp_relay_read(p->client_s, &p->querylist,
735712b2f30Ssthen 				&p->querylast, now, delay, pkt))
736712b2f30Ssthen 				delete_it = 1;
737712b2f30Ssthen 		}
738712b2f30Ssthen 		/* can we receive further answers? */
739712b2f30Ssthen 		if(!delete_it && p->server_s != -1 &&
740712b2f30Ssthen 			FD_ISSET(p->server_s, rset)) {
741712b2f30Ssthen 			p->timeout = tout;
742712b2f30Ssthen 			log_addr(1, "read tcp answer", &p->addr, p->addr_len);
743712b2f30Ssthen 			if(!tcp_relay_read(p->server_s, &p->answerlist,
744712b2f30Ssthen 				&p->answerlast, now, delay, pkt)) {
745e2a0f313Ssthen 				sock_close(p->server_s);
746712b2f30Ssthen 				FD_CLR(FD_SET_T p->server_s, worig);
747712b2f30Ssthen 				FD_CLR(FD_SET_T p->server_s, rorig);
748712b2f30Ssthen 				p->server_s = -1;
749712b2f30Ssthen 			}
750712b2f30Ssthen 		}
751712b2f30Ssthen 		/* can we send on further queries */
752712b2f30Ssthen 		if(!delete_it && p->querylist && p->server_s != -1) {
753712b2f30Ssthen 			p->timeout = tout;
754712b2f30Ssthen 			if(dl_tv_smaller(&p->querylist->wait, now))
755712b2f30Ssthen 				log_addr(1, "write tcp query",
756712b2f30Ssthen 					&p->addr, p->addr_len);
757712b2f30Ssthen 			if(!tcp_relay_write(p->server_s, &p->querylist,
758712b2f30Ssthen 				&p->querylast, now))
759712b2f30Ssthen 				delete_it = 1;
7608771e50fSsthen 			if(p->querylist &&
761712b2f30Ssthen 				dl_tv_smaller(&p->querylist->wait, now))
762712b2f30Ssthen 				FD_SET(FD_SET_T p->server_s, worig);
763712b2f30Ssthen 			else 	FD_CLR(FD_SET_T p->server_s, worig);
764712b2f30Ssthen 		}
765712b2f30Ssthen 
766712b2f30Ssthen 		/* can we send on further answers */
767712b2f30Ssthen 		if(!delete_it && p->answerlist) {
768712b2f30Ssthen 			p->timeout = tout;
769712b2f30Ssthen 			if(dl_tv_smaller(&p->answerlist->wait, now))
770712b2f30Ssthen 				log_addr(1, "write tcp answer",
771712b2f30Ssthen 					&p->addr, p->addr_len);
772712b2f30Ssthen 			if(!tcp_relay_write(p->client_s, &p->answerlist,
773712b2f30Ssthen 				&p->answerlast, now))
774712b2f30Ssthen 				delete_it = 1;
775712b2f30Ssthen 			if(p->answerlist && dl_tv_smaller(&p->answerlist->wait,
776712b2f30Ssthen 				now))
777712b2f30Ssthen 				FD_SET(FD_SET_T p->client_s, worig);
778712b2f30Ssthen 			else 	FD_CLR(FD_SET_T p->client_s, worig);
779712b2f30Ssthen 			if(!p->answerlist && p->server_s == -1)
780712b2f30Ssthen 				delete_it = 1;
781712b2f30Ssthen 		}
782712b2f30Ssthen 
783712b2f30Ssthen 		/* does this entry timeout? (unused too long) */
784712b2f30Ssthen 		if(dl_tv_smaller(&p->timeout, now)) {
785712b2f30Ssthen 			delete_it = 1;
786712b2f30Ssthen 		}
787712b2f30Ssthen 		if(delete_it) {
788712b2f30Ssthen 			struct tcp_proxy* np = p->next;
789712b2f30Ssthen 			*prev = np;
790712b2f30Ssthen 			FD_CLR(FD_SET_T p->client_s, rorig);
791712b2f30Ssthen 			FD_CLR(FD_SET_T p->client_s, worig);
792712b2f30Ssthen 			if(p->server_s != -1) {
793712b2f30Ssthen 				FD_CLR(FD_SET_T p->server_s, rorig);
794712b2f30Ssthen 				FD_CLR(FD_SET_T p->server_s, worig);
795712b2f30Ssthen 			}
796712b2f30Ssthen 			tcp_proxy_delete(p);
797712b2f30Ssthen 			p = np;
798712b2f30Ssthen 			continue;
799712b2f30Ssthen 		}
800712b2f30Ssthen 
801712b2f30Ssthen 		prev = &p->next;
802712b2f30Ssthen 		p = p->next;
803712b2f30Ssthen 	}
804712b2f30Ssthen }
805712b2f30Ssthen 
806712b2f30Ssthen /** find waiting time */
807712b2f30Ssthen static int
808712b2f30Ssthen service_findwait(struct timeval* now, struct timeval* wait,
809712b2f30Ssthen 	struct ringbuf* ring, struct tcp_proxy* tcplist)
810712b2f30Ssthen {
811712b2f30Ssthen 	/* first item is the time to wait */
812712b2f30Ssthen 	struct timeval* peek = ring_peek_time(ring);
813712b2f30Ssthen 	struct timeval tcv;
814712b2f30Ssthen 	int have_tcpval = 0;
815712b2f30Ssthen 	struct tcp_proxy* p;
816712b2f30Ssthen 
817712b2f30Ssthen 	/* also for TCP list the first in sendlists is the time to wait */
818712b2f30Ssthen 	for(p=tcplist; p; p=p->next) {
819712b2f30Ssthen 		if(!have_tcpval)
820712b2f30Ssthen 			tcv = p->timeout;
821712b2f30Ssthen 		have_tcpval = 1;
822712b2f30Ssthen 		if(dl_tv_smaller(&p->timeout, &tcv))
823712b2f30Ssthen 			tcv = p->timeout;
824712b2f30Ssthen 		if(p->querylist && dl_tv_smaller(&p->querylist->wait, &tcv))
825712b2f30Ssthen 			tcv = p->querylist->wait;
826712b2f30Ssthen 		if(p->answerlist && dl_tv_smaller(&p->answerlist->wait, &tcv))
827712b2f30Ssthen 			tcv = p->answerlist->wait;
828712b2f30Ssthen 	}
829712b2f30Ssthen 	if(peek) {
830712b2f30Ssthen 		/* peek can be unaligned */
831712b2f30Ssthen 		/* use wait as a temp variable */
832712b2f30Ssthen 		memmove(wait, peek, sizeof(*wait));
833712b2f30Ssthen 		if(!have_tcpval)
834712b2f30Ssthen 			tcv = *wait;
835712b2f30Ssthen 		else if(dl_tv_smaller(wait, &tcv))
836712b2f30Ssthen 			tcv = *wait;
837712b2f30Ssthen 		have_tcpval = 1;
838712b2f30Ssthen 	}
839712b2f30Ssthen 	if(have_tcpval) {
840712b2f30Ssthen 		*wait = tcv;
841712b2f30Ssthen 		dl_tv_subtract(wait, now);
842712b2f30Ssthen 		return 1;
843712b2f30Ssthen 	}
844712b2f30Ssthen 	/* nothing, block */
845712b2f30Ssthen 	return 0;
846712b2f30Ssthen }
847712b2f30Ssthen 
848712b2f30Ssthen /** clear proxy list */
849712b2f30Ssthen static void
850712b2f30Ssthen proxy_list_clear(struct proxy* p)
851712b2f30Ssthen {
852712b2f30Ssthen 	char from[109];
853712b2f30Ssthen 	struct proxy* np;
854712b2f30Ssthen 	int i=0, port;
855712b2f30Ssthen 	while(p) {
856712b2f30Ssthen 		np = p->next;
857712b2f30Ssthen 		port = (int)ntohs(((struct sockaddr_in*)&p->addr)->sin_port);
858712b2f30Ssthen 		if(addr_is_ip6(&p->addr, p->addr_len)) {
859712b2f30Ssthen 			if(inet_ntop(AF_INET6,
860712b2f30Ssthen 				&((struct sockaddr_in6*)&p->addr)->sin6_addr,
861712b2f30Ssthen 				from, (socklen_t)sizeof(from)) == 0)
862712b2f30Ssthen 				(void)strlcpy(from, "err", sizeof(from));
863712b2f30Ssthen 		} else {
864712b2f30Ssthen 			if(inet_ntop(AF_INET,
865712b2f30Ssthen 				&((struct sockaddr_in*)&p->addr)->sin_addr,
866712b2f30Ssthen 				from, (socklen_t)sizeof(from)) == 0)
867712b2f30Ssthen 				(void)strlcpy(from, "err", sizeof(from));
868712b2f30Ssthen 		}
869712b2f30Ssthen 		printf("client[%d]: last %s@%d of %d : %u in, %u out, "
870712b2f30Ssthen 			"%u returned\n", i++, from, port, (int)p->numreuse+1,
871712b2f30Ssthen 			(unsigned)p->numwait, (unsigned)p->numsent,
872712b2f30Ssthen 			(unsigned)p->numreturn);
873e2a0f313Ssthen 		sock_close(p->s);
874712b2f30Ssthen 		free(p);
875712b2f30Ssthen 		p = np;
876712b2f30Ssthen 	}
877712b2f30Ssthen }
878712b2f30Ssthen 
879712b2f30Ssthen /** clear TCP proxy list */
880712b2f30Ssthen static void
881712b2f30Ssthen tcp_proxy_list_clear(struct tcp_proxy* p)
882712b2f30Ssthen {
883712b2f30Ssthen 	struct tcp_proxy* np;
884712b2f30Ssthen 	while(p) {
885712b2f30Ssthen 		np = p->next;
886712b2f30Ssthen 		tcp_proxy_delete(p);
887712b2f30Ssthen 		p = np;
888712b2f30Ssthen 	}
889712b2f30Ssthen }
890712b2f30Ssthen 
891712b2f30Ssthen /** delayer service loop */
892712b2f30Ssthen static void
893712b2f30Ssthen service_loop(int udp_s, int listen_s, struct ringbuf* ring,
894712b2f30Ssthen 	struct timeval* delay, struct timeval* reuse,
895712b2f30Ssthen 	struct sockaddr_storage* srv_addr, socklen_t srv_len,
896712b2f30Ssthen 	sldns_buffer* pkt)
897712b2f30Ssthen {
898712b2f30Ssthen 	fd_set rset, rorig;
899712b2f30Ssthen 	fd_set wset, worig;
900712b2f30Ssthen 	struct timeval now, wait;
901712b2f30Ssthen 	int max, have_wait = 0;
902712b2f30Ssthen 	struct proxy* proxies = NULL;
903712b2f30Ssthen 	struct tcp_proxy* tcp_proxies = NULL;
904712b2f30Ssthen 	struct timeval tcp_timeout;
905712b2f30Ssthen 	tcp_timeout.tv_sec = 120;
906712b2f30Ssthen 	tcp_timeout.tv_usec = 0;
907712b2f30Ssthen #ifndef S_SPLINT_S
908712b2f30Ssthen 	FD_ZERO(&rorig);
909712b2f30Ssthen 	FD_ZERO(&worig);
910712b2f30Ssthen 	FD_SET(FD_SET_T udp_s, &rorig);
911712b2f30Ssthen 	FD_SET(FD_SET_T listen_s, &rorig);
912712b2f30Ssthen #endif
913712b2f30Ssthen 	max = udp_s + 1;
914712b2f30Ssthen 	if(listen_s + 1 > max) max = listen_s + 1;
915712b2f30Ssthen 	while(!do_quit) {
916712b2f30Ssthen 		/* wait for events */
917712b2f30Ssthen 		rset = rorig;
918712b2f30Ssthen 		wset = worig;
919712b2f30Ssthen 		if(have_wait)
920712b2f30Ssthen 			verbose(1, "wait for %d.%6.6d",
921712b2f30Ssthen 			(unsigned)wait.tv_sec, (unsigned)wait.tv_usec);
922712b2f30Ssthen 		else	verbose(1, "wait");
923712b2f30Ssthen 		if(select(max, &rset, &wset, NULL, have_wait?&wait:NULL) < 0) {
924712b2f30Ssthen 			if(errno == EAGAIN || errno == EINTR)
925712b2f30Ssthen 				continue;
926712b2f30Ssthen 			fatal_exit("select: %s", strerror(errno));
927712b2f30Ssthen 		}
928712b2f30Ssthen 		/* get current time */
929712b2f30Ssthen 		if(gettimeofday(&now, NULL) < 0) {
930712b2f30Ssthen 			if(errno == EAGAIN || errno == EINTR)
931712b2f30Ssthen 				continue;
932712b2f30Ssthen 			fatal_exit("gettimeofday: %s", strerror(errno));
933712b2f30Ssthen 		}
934712b2f30Ssthen 		verbose(1, "process at %u.%6.6u\n",
935712b2f30Ssthen 			(unsigned)now.tv_sec, (unsigned)now.tv_usec);
936712b2f30Ssthen 		/* sendout delayed queries to master server (frees up buffer)*/
937712b2f30Ssthen 		service_send(ring, &now, pkt, srv_addr, srv_len);
938712b2f30Ssthen 		/* proxy return replies */
939712b2f30Ssthen 		service_proxy(&rset, udp_s, proxies, pkt, &now);
940712b2f30Ssthen 		/* see what can be received to start waiting */
941712b2f30Ssthen 		service_recv(udp_s, ring, pkt, &rorig, &max, &proxies,
942712b2f30Ssthen 			srv_addr, srv_len, &now, delay, reuse);
943712b2f30Ssthen 		/* see if there are new tcp connections */
944712b2f30Ssthen 		service_tcp_listen(listen_s, &rorig, &max, &tcp_proxies,
945712b2f30Ssthen 			srv_addr, srv_len, &now, &tcp_timeout);
946712b2f30Ssthen 		/* service tcp connections */
947712b2f30Ssthen 		service_tcp_relay(&tcp_proxies, &now, delay, &tcp_timeout,
948712b2f30Ssthen 			pkt, &rset, &rorig, &worig);
949712b2f30Ssthen 		/* see what next timeout is (if any) */
950712b2f30Ssthen 		have_wait = service_findwait(&now, &wait, ring, tcp_proxies);
951712b2f30Ssthen 	}
952712b2f30Ssthen 	proxy_list_clear(proxies);
953712b2f30Ssthen 	tcp_proxy_list_clear(tcp_proxies);
954712b2f30Ssthen }
955712b2f30Ssthen 
956712b2f30Ssthen /** delayer main service routine */
957712b2f30Ssthen static void
958712b2f30Ssthen service(const char* bind_str, int bindport, const char* serv_str,
959712b2f30Ssthen 	size_t memsize, int delay_msec)
960712b2f30Ssthen {
961712b2f30Ssthen 	struct sockaddr_storage bind_addr, srv_addr;
962712b2f30Ssthen 	socklen_t bind_len, srv_len;
963712b2f30Ssthen 	struct ringbuf* ring = ring_create(memsize);
964712b2f30Ssthen 	struct timeval delay, reuse;
965712b2f30Ssthen 	sldns_buffer* pkt;
966712b2f30Ssthen 	int i, s, listen_s;
967712b2f30Ssthen #ifndef S_SPLINT_S
968712b2f30Ssthen 	delay.tv_sec = delay_msec / 1000;
969712b2f30Ssthen 	delay.tv_usec = (delay_msec % 1000)*1000;
970712b2f30Ssthen #endif
971712b2f30Ssthen 	reuse = delay; /* reuse is max(4*delay, 1 second) */
972712b2f30Ssthen 	dl_tv_add(&reuse, &delay);
973712b2f30Ssthen 	dl_tv_add(&reuse, &delay);
974712b2f30Ssthen 	dl_tv_add(&reuse, &delay);
975712b2f30Ssthen 	if(reuse.tv_sec == 0)
976712b2f30Ssthen 		reuse.tv_sec = 1;
977*0e9b6f9fSsthen 	if(!extstrtoaddr(serv_str, &srv_addr, &srv_len, UNBOUND_DNS_PORT)) {
978712b2f30Ssthen 		printf("cannot parse forward address: %s\n", serv_str);
979712b2f30Ssthen 		exit(1);
980712b2f30Ssthen 	}
981712b2f30Ssthen 	pkt = sldns_buffer_new(65535);
982712b2f30Ssthen 	if(!pkt)
983712b2f30Ssthen 		fatal_exit("out of memory");
984712b2f30Ssthen 	if( signal(SIGINT, delayer_sigh) == SIG_ERR ||
985712b2f30Ssthen #ifdef SIGHUP
986712b2f30Ssthen 		signal(SIGHUP, delayer_sigh) == SIG_ERR ||
987712b2f30Ssthen #endif
988712b2f30Ssthen #ifdef SIGQUIT
989712b2f30Ssthen 		signal(SIGQUIT, delayer_sigh) == SIG_ERR ||
990712b2f30Ssthen #endif
991712b2f30Ssthen #ifdef SIGBREAK
992712b2f30Ssthen 		signal(SIGBREAK, delayer_sigh) == SIG_ERR ||
993712b2f30Ssthen #endif
994712b2f30Ssthen #ifdef SIGALRM
995712b2f30Ssthen 		signal(SIGALRM, delayer_sigh) == SIG_ERR ||
996712b2f30Ssthen #endif
997712b2f30Ssthen 		signal(SIGTERM, delayer_sigh) == SIG_ERR)
998712b2f30Ssthen 		fatal_exit("could not bind to signal");
999712b2f30Ssthen 	/* bind UDP port */
1000712b2f30Ssthen 	if((s = socket(str_is_ip6(bind_str)?AF_INET6:AF_INET,
1001712b2f30Ssthen 		SOCK_DGRAM, 0)) == -1) {
1002e2a0f313Ssthen 		fatal_exit("socket: %s", sock_strerror(errno));
1003712b2f30Ssthen 	}
1004712b2f30Ssthen 	i=0;
1005712b2f30Ssthen 	if(bindport == 0) {
1006b0dfc31bSsthen 		bindport = 1024 + ((int)arc4random())%64000;
1007712b2f30Ssthen 		i = 100;
1008712b2f30Ssthen 	}
1009712b2f30Ssthen 	while(1) {
1010712b2f30Ssthen 		if(!ipstrtoaddr(bind_str, bindport, &bind_addr, &bind_len)) {
1011712b2f30Ssthen 			printf("cannot parse listen address: %s\n", bind_str);
1012712b2f30Ssthen 			exit(1);
1013712b2f30Ssthen 		}
1014712b2f30Ssthen 		if(bind(s, (struct sockaddr*)&bind_addr, bind_len) == -1) {
1015e2a0f313Ssthen 			log_err("bind: %s", sock_strerror(errno));
1016712b2f30Ssthen 			if(i--==0)
1017712b2f30Ssthen 				fatal_exit("cannot bind any port");
1018b0dfc31bSsthen 			bindport = 1024 + ((int)arc4random())%64000;
1019712b2f30Ssthen 		} else break;
1020712b2f30Ssthen 	}
1021712b2f30Ssthen 	fd_set_nonblock(s);
1022712b2f30Ssthen 	/* and TCP port */
1023712b2f30Ssthen 	if((listen_s = socket(str_is_ip6(bind_str)?AF_INET6:AF_INET,
1024712b2f30Ssthen 		SOCK_STREAM, 0)) == -1) {
1025e2a0f313Ssthen 		fatal_exit("tcp socket: %s", sock_strerror(errno));
1026712b2f30Ssthen 	}
1027712b2f30Ssthen #ifdef SO_REUSEADDR
1028712b2f30Ssthen 	if(1) {
1029712b2f30Ssthen 		int on = 1;
1030712b2f30Ssthen 		if(setsockopt(listen_s, SOL_SOCKET, SO_REUSEADDR, (void*)&on,
1031712b2f30Ssthen 			(socklen_t)sizeof(on)) < 0)
1032712b2f30Ssthen 			fatal_exit("setsockopt(.. SO_REUSEADDR ..) failed: %s",
1033e2a0f313Ssthen 				sock_strerror(errno));
1034712b2f30Ssthen 	}
1035712b2f30Ssthen #endif
1036712b2f30Ssthen 	if(bind(listen_s, (struct sockaddr*)&bind_addr, bind_len) == -1) {
1037e2a0f313Ssthen 		fatal_exit("tcp bind: %s", sock_strerror(errno));
1038712b2f30Ssthen 	}
1039712b2f30Ssthen 	if(listen(listen_s, 5) == -1) {
1040e2a0f313Ssthen 		fatal_exit("tcp listen: %s", sock_strerror(errno));
1041712b2f30Ssthen 	}
1042712b2f30Ssthen 	fd_set_nonblock(listen_s);
1043712b2f30Ssthen 	printf("listening on port: %d\n", bindport);
1044712b2f30Ssthen 
1045712b2f30Ssthen 	/* process loop */
1046712b2f30Ssthen 	do_quit = 0;
1047712b2f30Ssthen 	service_loop(s, listen_s, ring, &delay, &reuse, &srv_addr, srv_len,
1048712b2f30Ssthen 		pkt);
1049712b2f30Ssthen 
1050712b2f30Ssthen 	/* cleanup */
1051712b2f30Ssthen 	verbose(1, "cleanup");
1052e2a0f313Ssthen 	sock_close(s);
1053e2a0f313Ssthen 	sock_close(listen_s);
1054712b2f30Ssthen 	sldns_buffer_free(pkt);
1055712b2f30Ssthen 	ring_delete(ring);
1056712b2f30Ssthen }
1057712b2f30Ssthen 
1058712b2f30Ssthen /** getopt global, in case header files fail to declare it. */
1059712b2f30Ssthen extern int optind;
1060712b2f30Ssthen /** getopt global, in case header files fail to declare it. */
1061712b2f30Ssthen extern char* optarg;
1062712b2f30Ssthen 
1063712b2f30Ssthen /** main program for delayer */
1064712b2f30Ssthen int main(int argc, char** argv)
1065712b2f30Ssthen {
1066712b2f30Ssthen 	int c;		/* defaults */
1067712b2f30Ssthen 	const char* server = "127.0.0.1@53";
1068712b2f30Ssthen 	const char* bindto = "0.0.0.0";
1069712b2f30Ssthen 	int bindport = 0;
1070712b2f30Ssthen 	size_t memsize = 10*1024*1024;
1071712b2f30Ssthen 	int delay = 100;
1072712b2f30Ssthen 
1073712b2f30Ssthen 	verbosity = 0;
1074712b2f30Ssthen 	log_init(0, 0, 0);
1075712b2f30Ssthen 	log_ident_set("delayer");
1076712b2f30Ssthen 	if(argc == 1) usage(argv);
1077712b2f30Ssthen 	while( (c=getopt(argc, argv, "b:d:f:hm:p:")) != -1) {
1078712b2f30Ssthen 		switch(c) {
1079712b2f30Ssthen 			case 'b':
1080712b2f30Ssthen 				bindto = optarg;
1081712b2f30Ssthen 				break;
1082712b2f30Ssthen 			case 'd':
1083712b2f30Ssthen 				if(atoi(optarg)==0 && strcmp(optarg,"0")!=0) {
1084712b2f30Ssthen 					printf("bad delay: %s\n", optarg);
1085712b2f30Ssthen 					return 1;
1086712b2f30Ssthen 				}
1087712b2f30Ssthen 				delay = atoi(optarg);
1088712b2f30Ssthen 				break;
1089712b2f30Ssthen 			case 'f':
1090712b2f30Ssthen 				server = optarg;
1091712b2f30Ssthen 				break;
1092712b2f30Ssthen 			case 'm':
1093712b2f30Ssthen 				if(!cfg_parse_memsize(optarg, &memsize)) {
1094712b2f30Ssthen 					printf("bad memsize: %s\n", optarg);
1095712b2f30Ssthen 					return 1;
1096712b2f30Ssthen 				}
1097712b2f30Ssthen 				break;
1098712b2f30Ssthen 			case 'p':
1099712b2f30Ssthen 				if(atoi(optarg)==0 && strcmp(optarg,"0")!=0) {
1100712b2f30Ssthen 					printf("bad port nr: %s\n", optarg);
1101712b2f30Ssthen 					return 1;
1102712b2f30Ssthen 				}
1103712b2f30Ssthen 				bindport = atoi(optarg);
1104712b2f30Ssthen 				break;
1105712b2f30Ssthen 			case 'h':
1106712b2f30Ssthen 			case '?':
1107712b2f30Ssthen 			default:
1108712b2f30Ssthen 				usage(argv);
1109712b2f30Ssthen 		}
1110712b2f30Ssthen 	}
1111712b2f30Ssthen 	argc -= optind;
1112712b2f30Ssthen 	argv += optind;
1113712b2f30Ssthen 	if(argc != 0)
1114712b2f30Ssthen 		usage(argv);
1115712b2f30Ssthen 
1116712b2f30Ssthen 	printf("bind to %s @ %d and forward to %s after %d msec\n",
1117712b2f30Ssthen 		bindto, bindport, server, delay);
1118712b2f30Ssthen 	service(bindto, bindport, server, memsize, delay);
1119712b2f30Ssthen 	return 0;
1120712b2f30Ssthen }
1121