aboutsummaryrefslogtreecommitdiff
path: root/services/outside_network.h
blob: dda9d6f5a235d503c0aab696bc606a0100de1689 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
/*
 * services/outside_network.h - listen to answers from the network
 *
 * Copyright (c) 2007, NLnet Labs. All rights reserved.
 *
 * This software is open source.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * 
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * 
 * Neither the name of the NLNET LABS nor the names of its contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * \file
 *
 * This file has functions to send queries to authoritative servers,
 * and wait for the pending answer, with timeouts.
 */

#ifndef OUTSIDE_NETWORK_H
#define OUTSIDE_NETWORK_H

#include "util/rbtree.h"
#include "util/netevent.h"
struct pending;
struct pending_timeout;
struct ub_randstate;
struct pending_tcp;
struct waiting_tcp;
struct waiting_udp;
struct infra_cache;
struct port_comm;
struct port_if;
struct sldns_buffer;

/**
 * Send queries to outside servers and wait for answers from servers.
 * Contains answer-listen sockets.
 */
struct outside_network {
	/** Base for select calls */
	struct comm_base* base;
	/** pointer to time in seconds */
	time_t* now_secs;
	/** pointer to time in microseconds */
	struct timeval* now_tv;

	/** buffer shared by UDP connections, since there is only one
	    datagram at any time. */
	struct sldns_buffer* udp_buff;
	/** serviced_callbacks malloc overhead when processing multiple
	 * identical serviced queries to the same server. */
	size_t svcd_overhead;
	/** use x20 bits to encode additional ID random bits */
	int use_caps_for_id;
	/** outside network wants to quit. Stop queued msgs from sent. */
	int want_to_quit;

	/** number of unwanted replies received (for statistics) */
	size_t unwanted_replies;
	/** cumulative total of unwanted replies (for defense) */
	size_t unwanted_total;
	/** threshold when to take defensive action. If 0 then never. */
	size_t unwanted_threshold;
	/** what action to take, called when defensive action is needed */
	void (*unwanted_action)(void*);
	/** user param for action */
	void* unwanted_param;

	/** linked list of available commpoints, unused file descriptors,
	 * for use as outgoing UDP ports. cp.fd=-1 in them. */
	struct port_comm* unused_fds;
	/** if udp is done */
	int do_udp;
	/** if udp is delay-closed (delayed answers do not meet closed port)*/
	int delayclose;
	/** timeout for delayclose */
	struct timeval delay_tv;

	/** array of outgoing IP4 interfaces */
	struct port_if* ip4_ifs;
	/** number of outgoing IP4 interfaces */
	int num_ip4;

	/** array of outgoing IP6 interfaces */
	struct port_if* ip6_ifs;
	/** number of outgoing IP6 interfaces */
	int num_ip6;

	/** pending udp queries waiting to be sent out, waiting for fd */
	struct pending* udp_wait_first;
	/** last pending udp query in list */
	struct pending* udp_wait_last;

	/** pending udp answers. sorted by id, addr */
	rbtree_t* pending;
	/** serviced queries, sorted by qbuf, addr, dnssec */
	rbtree_t* serviced;
	/** host cache, pointer but not owned by outnet. */
	struct infra_cache* infra;
	/** where to get random numbers */
	struct ub_randstate* rnd;
	/** ssl context to create ssl wrapped TCP with DNS connections */
	void* sslctx;

	/**
	 * Array of tcp pending used for outgoing TCP connections.
	 * Each can be used to establish a TCP connection with a server.
	 * The file descriptors are -1 if they are free, and need to be 
	 * opened for the tcp connection. Can be used for ip4 and ip6.
	 */
	struct pending_tcp **tcp_conns;
	/** number of tcp communication points. */
	size_t num_tcp;
	/** list of tcp comm points that are free for use */
	struct pending_tcp* tcp_free;
	/** list of tcp queries waiting for a buffer */
	struct waiting_tcp* tcp_wait_first;
	/** last of waiting query list */
	struct waiting_tcp* tcp_wait_last;
};

/**
 * Outgoing interface. Ports available and currently used are tracked
 * per interface
 */
struct port_if {
	/** address ready to allocate new socket (except port no). */
	struct sockaddr_storage addr;
	/** length of addr field */
	socklen_t addrlen;

	/** the available ports array. These are unused.
	 * Only the first total-inuse part is filled. */
	int* avail_ports;
	/** the total number of available ports (size of the array) */
	int avail_total;

	/** array of the commpoints currently in use. 
	 * allocated for max number of fds, first part in use. */
	struct port_comm** out;
	/** max number of fds, size of out array */
	int maxout;
	/** number of commpoints (and thus also ports) in use */
	int inuse;
};

/**
 * Outgoing commpoint for UDP port.
 */
struct port_comm {
	/** next in free list */
	struct port_comm* next;
	/** which port number (when in use) */
	int number;
	/** interface it is used in */
	struct port_if* pif;
	/** index in the out array of the interface */
	int index;
	/** number of outstanding queries on this port */
	int num_outstanding;
	/** UDP commpoint, fd=-1 if not in use */
	struct comm_point* cp;
};

/**
 * A query that has an answer pending for it.
 */
struct pending {
	/** redblacktree entry, key is the pending struct(id, addr). */
	rbnode_t node;
	/** the ID for the query. int so that a value out of range can
	 * be used to signify a pending that is for certain not present in
	 * the rbtree. (and for which deletion is safe). */
	unsigned int id;
	/** remote address. */
	struct sockaddr_storage addr;
	/** length of addr field in use. */
	socklen_t addrlen;
	/** comm point it was sent on (and reply must come back on). */
	struct port_comm* pc;
	/** timeout event */
	struct comm_timer* timer;
	/** callback for the timeout, error or reply to the message */
	comm_point_callback_t* cb;
	/** callback user argument */
	void* cb_arg;
	/** the outside network it is part of */
	struct outside_network* outnet;

	/*---- filled if udp pending is waiting -----*/
	/** next in waiting list. */
	struct pending* next_waiting;
	/** timeout in msec */
	int timeout;
	/** The query itself, the query packet to send. */
	uint8_t* pkt;
	/** length of query packet. */
	size_t pkt_len;
};

/**
 * Pending TCP query to server.
 */
struct pending_tcp {
	/** next in list of free tcp comm points, or NULL. */
	struct pending_tcp* next_free;
	/** the ID for the query; checked in reply */
	uint16_t id;
	/** tcp comm point it was sent on (and reply must come back on). */
	struct comm_point* c;
	/** the query being serviced, NULL if the pending_tcp is unused. */
	struct waiting_tcp* query;
};

/**
 * Query waiting for TCP buffer.
 */
struct waiting_tcp {
	/** 
	 * next in waiting list.
	 * if pkt==0, this points to the pending_tcp structure.
	 */
	struct waiting_tcp* next_waiting;
	/** timeout event; timer keeps running whether the query is
	 * waiting for a buffer or the tcp reply is pending */
	struct comm_timer* timer;
	/** the outside network it is part of */
	struct outside_network* outnet;
	/** remote address. */
	struct sockaddr_storage addr;
	/** length of addr field in use. */
	socklen_t addrlen;
	/** 
	 * The query itself, the query packet to send.
	 * allocated after the waiting_tcp structure.
	 * set to NULL when the query is serviced and it part of pending_tcp.
	 * if this is NULL, the next_waiting points to the pending_tcp.
	 */
	uint8_t* pkt;
	/** length of query packet. */
	size_t pkt_len;
	/** callback for the timeout, error or reply to the message */
	comm_point_callback_t* cb;
	/** callback user argument */
	void* cb_arg;
	/** if it uses ssl upstream */
	int ssl_upstream;
};

/**
 * Callback to party interested in serviced query results.
 */
struct service_callback {
	/** next in callback list */
	struct service_callback* next;
	/** callback function */
	comm_point_callback_t* cb;
	/** user argument for callback function */
	void* cb_arg;
};

/** fallback size for fragmentation for EDNS in IPv4 */
#define EDNS_FRAG_SIZE_IP4 1472
/** fallback size for EDNS in IPv6, fits one fragment with ip6-tunnel-ids */
#define EDNS_FRAG_SIZE_IP6 1232

/**
 * Query service record.
 * Contains query and destination. UDP, TCP, EDNS are all tried.
 * complete with retries and timeouts. A number of interested parties can
 * receive a callback.
 */
struct serviced_query {
	/** The rbtree node, key is this record */
	rbnode_t node;
	/** The query that needs to be answered. Starts with flags u16,
	 * then qdcount, ..., including qname, qtype, qclass. Does not include
	 * EDNS record. */
	uint8_t* qbuf;
	/** length of qbuf. */
	size_t qbuflen;
	/** If an EDNS section is included, the DO/CD bit will be turned on. */
	int dnssec;
	/** We want signatures, or else the answer is likely useless */
	int want_dnssec;
	/** tcp upstream used, use tcp, or ssl_upstream for SSL */
	int tcp_upstream, ssl_upstream;
	/** where to send it */
	struct sockaddr_storage addr;
	/** length of addr field in use. */
	socklen_t addrlen;
	/** zone name, uncompressed domain name in wireformat */
	uint8_t* zone;
	/** length of zone name */
	size_t zonelen;
	/** qtype */
	int qtype;
	/** current status */
	enum serviced_query_status {
		/** initial status */
		serviced_initial,
		/** UDP with EDNS sent */
		serviced_query_UDP_EDNS,
		/** UDP without EDNS sent */
		serviced_query_UDP,
		/** TCP with EDNS sent */
		serviced_query_TCP_EDNS,
		/** TCP without EDNS sent */
		serviced_query_TCP,
		/** probe to test EDNS lameness (EDNS is dropped) */
		serviced_query_PROBE_EDNS,
		/** probe to test noEDNS0 (EDNS gives FORMERRorNOTIMP) */
		serviced_query_UDP_EDNS_fallback,
		/** probe to test TCP noEDNS0 (EDNS gives FORMERRorNOTIMP) */
		serviced_query_TCP_EDNS_fallback,
		/** send UDP query with EDNS1480 (or 1280) */
		serviced_query_UDP_EDNS_FRAG
	} 	
		/** variable with current status */ 
		status;
	/** true if serviced_query is scheduled for deletion already */
	int to_be_deleted;
	/** number of UDP retries */
	int retry;
	/** time last UDP was sent */
	struct timeval last_sent_time;
	/** rtt of last (UDP) message */
	int last_rtt;
	/** do we know edns probe status already, for UDP_EDNS queries */
	int edns_lame_known;
	/** outside network this is part of */
	struct outside_network* outnet;
	/** list of interested parties that need callback on results. */
	struct service_callback* cblist;
	/** the UDP or TCP query that is pending, see status which */
	void* pending;
};

/**
 * Create outside_network structure with N udp ports.
 * @param base: the communication base to use for event handling.
 * @param bufsize: size for network buffers.
 * @param num_ports: number of udp ports to open per interface.
 * @param ifs: interface names (or NULL for default interface).
 *    These interfaces must be able to access all authoritative servers.
 * @param num_ifs: number of names in array ifs.
 * @param do_ip4: service IP4.
 * @param do_ip6: service IP6.
 * @param num_tcp: number of outgoing tcp buffers to preallocate.
 * @param infra: pointer to infra cached used for serviced queries.
 * @param rnd: stored to create random numbers for serviced queries.
 * @param use_caps_for_id: enable to use 0x20 bits to encode id randomness.
 * @param availports: array of available ports. 
 * @param numavailports: number of available ports in array.
 * @param unwanted_threshold: when to take defensive action.
 * @param unwanted_action: the action to take.
 * @param unwanted_param: user parameter to action.
 * @param do_udp: if udp is done.
 * @param sslctx: context to create outgoing connections with (if enabled).
 * @param delayclose: if not 0, udp sockets are delayed before timeout closure.
 * 	msec to wait on timeouted udp sockets.
 * @return: the new structure (with no pending answers) or NULL on error.
 */
struct outside_network* outside_network_create(struct comm_base* base,
	size_t bufsize, size_t num_ports, char** ifs, int num_ifs,
	int do_ip4, int do_ip6, size_t num_tcp, struct infra_cache* infra, 
	struct ub_randstate* rnd, int use_caps_for_id, int* availports, 
	int numavailports, size_t unwanted_threshold,
	void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
	void* sslctx, int delayclose);

/**
 * Delete outside_network structure.
 * @param outnet: object to delete.
 */
void outside_network_delete(struct outside_network* outnet);

/**
 * Prepare for quit. Sends no more queries, even if queued up.
 * @param outnet: object to prepare for removal
 */
void outside_network_quit_prepare(struct outside_network* outnet);

/**
 * Send UDP query, create pending answer.
 * Changes the ID for the query to be random and unique for that destination.
 * @param outnet: provides the event handling
 * @param packet: wireformat query to send to destination.
 * @param addr: address to send to.
 * @param addrlen: length of addr.
 * @param timeout: in milliseconds from now.
 * @param callback: function to call on error, timeout or reply.
 * @param callback_arg: user argument for callback function.
 * @return: NULL on error for malloc or socket. Else the pending query object.
 */
struct pending* pending_udp_query(struct outside_network* outnet, 
	struct sldns_buffer* packet, struct sockaddr_storage* addr, 
	socklen_t addrlen, int timeout, comm_point_callback_t* callback, 
	void* callback_arg);

/**
 * Send TCP query. May wait for TCP buffer. Selects ID to be random, and 
 * checks id.
 * @param outnet: provides the event handling.
 * @param packet: wireformat query to send to destination. copied from.
 * @param addr: address to send to.
 * @param addrlen: length of addr.
 * @param timeout: in seconds from now.
 *    Timer starts running now. Timer may expire if all buffers are used,
 *    without any query been sent to the server yet.
 * @param callback: function to call on error, timeout or reply.
 * @param callback_arg: user argument for callback function.
 * @param ssl_upstream: if the tcp connection must use SSL.
 * @return: false on error for malloc or socket. Else the pending TCP object.
 */
struct waiting_tcp* pending_tcp_query(struct outside_network* outnet, 
	struct sldns_buffer* packet, struct sockaddr_storage* addr, 
	socklen_t addrlen, int timeout, comm_point_callback_t* callback, 
	void* callback_arg, int ssl_upstream);

/**
 * Delete pending answer.
 * @param outnet: outside network the pending query is part of.
 *    Internal feature: if outnet is NULL, p is not unlinked from rbtree.
 * @param p: deleted
 */
void pending_delete(struct outside_network* outnet, struct pending* p);

/**
 * Perform a serviced query to the authoritative servers.
 * Duplicate efforts are detected, and EDNS, TCP and UDP retry is performed.
 * @param outnet: outside network, with rbtree of serviced queries.
 * @param qname: what qname to query.
 * @param qnamelen: length of qname in octets including 0 root label.
 * @param qtype: rrset type to query (host format)
 * @param qclass: query class. (host format)
 * @param flags: flags u16 (host format), includes opcode, CD bit.
 * @param dnssec: if set, DO bit is set in EDNS queries.
 *	If the value includes BIT_CD, CD bit is set when in EDNS queries.
 *	If the value includes BIT_DO, DO bit is set when in EDNS queries.
 * @param want_dnssec: signatures are needed, without EDNS the answer is
 * 	likely to be useless.
 * @param tcp_upstream: use TCP for upstream queries.
 * @param ssl_upstream: use SSL for upstream queries.
 * @param callback: callback function.
 * @param callback_arg: user argument to callback function.
 * @param addr: to which server to send the query.
 * @param addrlen: length of addr.
 * @param zone: name of the zone of the delegation point. wireformat dname.
	This is the delegation point name for which the server is deemed
	authoritative.
 * @param zonelen: length of zone.
 * @param buff: scratch buffer to create query contents in. Empty on exit.
 * @return 0 on error, or pointer to serviced query that is used to answer
 *	this serviced query may be shared with other callbacks as well.
 */
struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
	uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
	uint16_t flags, int dnssec, int want_dnssec, int tcp_upstream,
	int ssl_upstream, struct sockaddr_storage* addr, socklen_t addrlen,
	uint8_t* zone, size_t zonelen, comm_point_callback_t* callback,
	void* callback_arg, struct sldns_buffer* buff);

/**
 * Remove service query callback.
 * If that leads to zero callbacks, the query is completely cancelled.
 * @param sq: serviced query to adjust.
 * @param cb_arg: callback argument of callback that needs removal.
 *	same as the callback_arg to outnet_serviced_query().
 */
void outnet_serviced_query_stop(struct serviced_query* sq, void* cb_arg);

/**
 * Get memory size in use by outside network.
 * Counts buffers and outstanding query (serviced queries) malloced data.
 * @param outnet: outside network structure.
 * @return size in bytes.
 */
size_t outnet_get_mem(struct outside_network* outnet);

/**
 * Get memory size in use by serviced query while it is servicing callbacks.
 * This takes into account the pre-deleted status of it; it will be deleted
 * when the callbacks are done.
 * @param sq: serviced query. 
 * @return size in bytes.
 */
size_t serviced_get_mem(struct serviced_query* sq);

/** callback for incoming udp answers from the network */
int outnet_udp_cb(struct comm_point* c, void* arg, int error,
	struct comm_reply *reply_info);

/** callback for pending tcp connections */
int outnet_tcp_cb(struct comm_point* c, void* arg, int error,
	struct comm_reply *reply_info);

/** callback for udp timeout */
void pending_udp_timer_cb(void *arg);

/** callback for udp delay for timeout */
void pending_udp_timer_delay_cb(void *arg);

/** callback for outgoing TCP timer event */
void outnet_tcptimer(void* arg);

/** callback for serviced query UDP answers */
int serviced_udp_callback(struct comm_point* c, void* arg, int error,
        struct comm_reply* rep);

/** TCP reply or error callback for serviced queries */
int serviced_tcp_callback(struct comm_point* c, void* arg, int error,
        struct comm_reply* rep);

/** compare function of pending rbtree */
int pending_cmp(const void* key1, const void* key2);

/** compare function of serviced query rbtree */
int serviced_cmp(const void* key1, const void* key2);

#endif /* OUTSIDE_NETWORK_H */