2 * services/outside_network.c - implement sending of queries and wait answer.
4 * Copyright (c) 2007, NLnet Labs. All rights reserved.
6 * This software is open source.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
19 * Neither the name of the NLNET LABS nor the names of its contributors may
20 * be used to endorse or promote products derived from this software without
21 * specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 * This file has functions to send queries to authoritative servers and
40 * wait for the pending answer events.
44 #ifdef HAVE_SYS_TYPES_H
45 # include <sys/types.h>
48 #include "services/outside_network.h"
49 #include "services/listen_dnsport.h"
50 #include "services/cache/infra.h"
51 #include "util/data/msgparse.h"
52 #include "util/data/msgreply.h"
53 #include "util/data/msgencode.h"
54 #include "util/data/dname.h"
55 #include "util/netevent.h"
57 #include "util/net_help.h"
58 #include "util/random.h"
59 #include "util/fptr_wlist.h"
60 #include "ldns/sbuffer.h"
61 #include "dnstap/dnstap.h"
62 #ifdef HAVE_OPENSSL_SSL_H
63 #include <openssl/ssl.h>
71 /** number of times to retry making a random ID that is unique. */
72 #define MAX_ID_RETRY 1000
73 /** number of times to retry finding interface, port that can be opened. */
74 #define MAX_PORT_RETRY 10000
75 /** number of retries on outgoing UDP queries */
76 #define OUTBOUND_UDP_RETRY 1
78 /** initiate TCP transaction for serviced query */
79 static void serviced_tcp_initiate(struct serviced_query
* sq
, sldns_buffer
* buff
);
80 /** with a fd available, randomize and send UDP */
81 static int randomize_and_send_udp(struct pending
* pend
, sldns_buffer
* packet
,
84 /** remove waiting tcp from the outnet waiting list */
85 static void waiting_list_remove(struct outside_network
* outnet
,
86 struct waiting_tcp
* w
);
89 pending_cmp(const void* key1
, const void* key2
)
91 struct pending
*p1
= (struct pending
*)key1
;
92 struct pending
*p2
= (struct pending
*)key2
;
97 log_assert(p1
->id
== p2
->id
);
98 return sockaddr_cmp(&p1
->addr
, p1
->addrlen
, &p2
->addr
, p2
->addrlen
);
102 serviced_cmp(const void* key1
, const void* key2
)
104 struct serviced_query
* q1
= (struct serviced_query
*)key1
;
105 struct serviced_query
* q2
= (struct serviced_query
*)key2
;
107 if(q1
->qbuflen
< q2
->qbuflen
)
109 if(q1
->qbuflen
> q2
->qbuflen
)
111 log_assert(q1
->qbuflen
== q2
->qbuflen
);
112 log_assert(q1
->qbuflen
>= 15 /* 10 header, root, type, class */);
113 /* alternate casing of qname is still the same query */
114 if((r
= memcmp(q1
->qbuf
, q2
->qbuf
, 10)) != 0)
116 if((r
= memcmp(q1
->qbuf
+q1
->qbuflen
-4, q2
->qbuf
+q2
->qbuflen
-4, 4)) != 0)
118 if(q1
->dnssec
!= q2
->dnssec
) {
119 if(q1
->dnssec
< q2
->dnssec
)
123 if((r
= query_dname_compare(q1
->qbuf
+10, q2
->qbuf
+10)) != 0)
125 return sockaddr_cmp(&q1
->addr
, q1
->addrlen
, &q2
->addr
, q2
->addrlen
);
128 /** delete waiting_tcp entry. Does not unlink from waiting list.
129 * @param w: to delete.
132 waiting_tcp_delete(struct waiting_tcp
* w
)
136 comm_timer_delete(w
->timer
);
141 * Pick random outgoing-interface of that family, and bind it.
142 * port set to 0 so OS picks a port number for us.
143 * if it is the ANY address, do not bind.
144 * @param w: tcp structure with destination address.
145 * @param s: socket fd.
146 * @return false on error, socket closed.
149 pick_outgoing_tcp(struct waiting_tcp
* w
, int s
)
151 struct port_if
* pi
= NULL
;
154 if(addr_is_ip6(&w
->addr
, w
->addrlen
))
155 num
= w
->outnet
->num_ip6
;
158 num
= w
->outnet
->num_ip4
;
160 log_err("no TCP outgoing interfaces of family");
161 log_addr(VERB_OPS
, "for addr", &w
->addr
, w
->addrlen
);
170 if(addr_is_ip6(&w
->addr
, w
->addrlen
))
171 pi
= &w
->outnet
->ip6_ifs
[ub_random_max(w
->outnet
->rnd
, num
)];
174 pi
= &w
->outnet
->ip4_ifs
[ub_random_max(w
->outnet
->rnd
, num
)];
176 if(addr_is_any(&pi
->addr
, pi
->addrlen
)) {
177 /* binding to the ANY interface is for listening sockets */
181 if(addr_is_ip6(&pi
->addr
, pi
->addrlen
))
182 ((struct sockaddr_in6
*)&pi
->addr
)->sin6_port
= 0;
183 else ((struct sockaddr_in
*)&pi
->addr
)->sin_port
= 0;
184 if(bind(s
, (struct sockaddr
*)&pi
->addr
, pi
->addrlen
) != 0) {
186 log_err("outgoing tcp: bind: %s", strerror(errno
));
189 log_err("outgoing tcp: bind: %s",
190 wsa_strerror(WSAGetLastError()));
195 log_addr(VERB_ALGO
, "tcp bound to src", &pi
->addr
, pi
->addrlen
);
199 /** use next free buffer to service a tcp query */
201 outnet_tcp_take_into_use(struct waiting_tcp
* w
, uint8_t* pkt
, size_t pkt_len
)
203 struct pending_tcp
* pend
= w
->outnet
->tcp_free
;
207 log_assert(w
->addrlen
> 0);
210 if(addr_is_ip6(&w
->addr
, w
->addrlen
))
211 s
= socket(PF_INET6
, SOCK_STREAM
, IPPROTO_TCP
);
214 s
= socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
217 log_err_addr("outgoing tcp: socket", strerror(errno
),
218 &w
->addr
, w
->addrlen
);
220 log_err_addr("outgoing tcp: socket",
221 wsa_strerror(WSAGetLastError()), &w
->addr
, w
->addrlen
);
225 if(!pick_outgoing_tcp(w
, s
))
229 if(connect(s
, (struct sockaddr
*)&w
->addr
, w
->addrlen
) == -1) {
232 if(errno
!= EINPROGRESS
) {
236 if(tcp_connect_errno_needs_log(
237 (struct sockaddr
*)&w
->addr
, w
->addrlen
))
238 log_err_addr("outgoing tcp: connect",
239 strerror(errno
), &w
->addr
, w
->addrlen
);
241 #else /* USE_WINSOCK */
242 if(WSAGetLastError() != WSAEINPROGRESS
&&
243 WSAGetLastError() != WSAEWOULDBLOCK
) {
249 if(w
->outnet
->sslctx
&& w
->ssl_upstream
) {
250 pend
->c
->ssl
= outgoing_ssl_fd(w
->outnet
->sslctx
, s
);
253 comm_point_close(pend
->c
);
257 comm_point_tcp_win_bio_cb(pend
->c
, pend
->c
->ssl
);
259 pend
->c
->ssl_shake_state
= comm_ssl_shake_write
;
262 w
->next_waiting
= (void*)pend
;
263 pend
->id
= LDNS_ID_WIRE(pkt
);
264 w
->outnet
->num_tcp_outgoing
++;
265 w
->outnet
->tcp_free
= pend
->next_free
;
266 pend
->next_free
= NULL
;
268 pend
->c
->repinfo
.addrlen
= w
->addrlen
;
269 memcpy(&pend
->c
->repinfo
.addr
, &w
->addr
, w
->addrlen
);
270 sldns_buffer_clear(pend
->c
->buffer
);
271 sldns_buffer_write(pend
->c
->buffer
, pkt
, pkt_len
);
272 sldns_buffer_flip(pend
->c
->buffer
);
273 pend
->c
->tcp_is_reading
= 0;
274 pend
->c
->tcp_byte_count
= 0;
275 comm_point_start_listening(pend
->c
, s
, -1);
279 /** see if buffers can be used to service TCP queries */
281 use_free_buffer(struct outside_network
* outnet
)
283 struct waiting_tcp
* w
;
284 while(outnet
->tcp_free
&& outnet
->tcp_wait_first
285 && !outnet
->want_to_quit
) {
286 w
= outnet
->tcp_wait_first
;
287 outnet
->tcp_wait_first
= w
->next_waiting
;
288 if(outnet
->tcp_wait_last
== w
)
289 outnet
->tcp_wait_last
= NULL
;
290 if(!outnet_tcp_take_into_use(w
, w
->pkt
, w
->pkt_len
)) {
291 comm_point_callback_t
* cb
= w
->cb
;
292 void* cb_arg
= w
->cb_arg
;
293 waiting_tcp_delete(w
);
294 fptr_ok(fptr_whitelist_pending_tcp(cb
));
295 (void)(*cb
)(NULL
, cb_arg
, NETEVENT_CLOSED
, NULL
);
300 /** decomission a tcp buffer, closes commpoint and frees waiting_tcp entry */
302 decomission_pending_tcp(struct outside_network
* outnet
,
303 struct pending_tcp
* pend
)
307 SSL_shutdown(pend
->c
->ssl
);
308 SSL_free(pend
->c
->ssl
);
312 comm_point_close(pend
->c
);
313 pend
->next_free
= outnet
->tcp_free
;
314 outnet
->tcp_free
= pend
;
315 waiting_tcp_delete(pend
->query
);
317 use_free_buffer(outnet
);
321 outnet_tcp_cb(struct comm_point
* c
, void* arg
, int error
,
322 struct comm_reply
*reply_info
)
324 struct pending_tcp
* pend
= (struct pending_tcp
*)arg
;
325 struct outside_network
* outnet
= pend
->query
->outnet
;
326 verbose(VERB_ALGO
, "outnettcp cb");
327 if(error
!= NETEVENT_NOERROR
) {
328 verbose(VERB_QUERY
, "outnettcp got tcp error %d", error
);
329 /* pass error below and exit */
332 if(sldns_buffer_limit(c
->buffer
) < sizeof(uint16_t) ||
333 LDNS_ID_WIRE(sldns_buffer_begin(c
->buffer
))!=pend
->id
) {
335 "outnettcp: bad ID in reply, from:",
336 &pend
->query
->addr
, pend
->query
->addrlen
);
337 error
= NETEVENT_CLOSED
;
340 fptr_ok(fptr_whitelist_pending_tcp(pend
->query
->cb
));
341 (void)(*pend
->query
->cb
)(c
, pend
->query
->cb_arg
, error
, reply_info
);
342 decomission_pending_tcp(outnet
, pend
);
346 /** lower use count on pc, see if it can be closed */
348 portcomm_loweruse(struct outside_network
* outnet
, struct port_comm
* pc
)
351 pc
->num_outstanding
--;
352 if(pc
->num_outstanding
> 0) {
355 /* close it and replace in unused list */
356 verbose(VERB_ALGO
, "close of port %d", pc
->number
);
357 comm_point_close(pc
->cp
);
359 log_assert(pif
->inuse
> 0);
360 pif
->avail_ports
[pif
->avail_total
- pif
->inuse
] = pc
->number
;
362 pif
->out
[pc
->index
] = pif
->out
[pif
->inuse
];
363 pif
->out
[pc
->index
]->index
= pc
->index
;
364 pc
->next
= outnet
->unused_fds
;
365 outnet
->unused_fds
= pc
;
368 /** try to send waiting UDP queries */
370 outnet_send_wait_udp(struct outside_network
* outnet
)
372 struct pending
* pend
;
373 /* process waiting queries */
374 while(outnet
->udp_wait_first
&& outnet
->unused_fds
375 && !outnet
->want_to_quit
) {
376 pend
= outnet
->udp_wait_first
;
377 outnet
->udp_wait_first
= pend
->next_waiting
;
378 if(!pend
->next_waiting
) outnet
->udp_wait_last
= NULL
;
379 sldns_buffer_clear(outnet
->udp_buff
);
380 sldns_buffer_write(outnet
->udp_buff
, pend
->pkt
, pend
->pkt_len
);
381 sldns_buffer_flip(outnet
->udp_buff
);
382 free(pend
->pkt
); /* freeing now makes get_mem correct */
385 if(!randomize_and_send_udp(pend
, outnet
->udp_buff
,
387 /* callback error on pending */
389 fptr_ok(fptr_whitelist_pending_udp(pend
->cb
));
390 (void)(*pend
->cb
)(outnet
->unused_fds
->cp
, pend
->cb_arg
,
391 NETEVENT_CLOSED
, NULL
);
393 pending_delete(outnet
, pend
);
399 outnet_udp_cb(struct comm_point
* c
, void* arg
, int error
,
400 struct comm_reply
*reply_info
)
402 struct outside_network
* outnet
= (struct outside_network
*)arg
;
405 verbose(VERB_ALGO
, "answer cb");
407 if(error
!= NETEVENT_NOERROR
) {
408 verbose(VERB_QUERY
, "outnetudp got udp error %d", error
);
411 if(sldns_buffer_limit(c
->buffer
) < LDNS_HEADER_SIZE
) {
412 verbose(VERB_QUERY
, "outnetudp udp too short");
415 log_assert(reply_info
);
417 /* setup lookup key */
418 key
.id
= (unsigned)LDNS_ID_WIRE(sldns_buffer_begin(c
->buffer
));
419 memcpy(&key
.addr
, &reply_info
->addr
, reply_info
->addrlen
);
420 key
.addrlen
= reply_info
->addrlen
;
421 verbose(VERB_ALGO
, "Incoming reply id = %4.4x", key
.id
);
422 log_addr(VERB_ALGO
, "Incoming reply addr =",
423 &reply_info
->addr
, reply_info
->addrlen
);
425 /* find it, see if this thing is a valid query response */
426 verbose(VERB_ALGO
, "lookup size is %d entries", (int)outnet
->pending
->count
);
427 p
= (struct pending
*)rbtree_search(outnet
->pending
, &key
);
429 verbose(VERB_QUERY
, "received unwanted or unsolicited udp reply dropped.");
430 log_buf(VERB_ALGO
, "dropped message", c
->buffer
);
431 outnet
->unwanted_replies
++;
432 if(outnet
->unwanted_threshold
&& ++outnet
->unwanted_total
433 >= outnet
->unwanted_threshold
) {
434 log_warn("unwanted reply total reached threshold (%u)"
435 " you may be under attack."
436 " defensive action: clearing the cache",
437 (unsigned)outnet
->unwanted_threshold
);
438 fptr_ok(fptr_whitelist_alloc_cleanup(
439 outnet
->unwanted_action
));
440 (*outnet
->unwanted_action
)(outnet
->unwanted_param
);
441 outnet
->unwanted_total
= 0;
446 verbose(VERB_ALGO
, "received udp reply.");
447 log_buf(VERB_ALGO
, "udp message", c
->buffer
);
449 verbose(VERB_QUERY
, "received reply id,addr on wrong port. "
451 outnet
->unwanted_replies
++;
452 if(outnet
->unwanted_threshold
&& ++outnet
->unwanted_total
453 >= outnet
->unwanted_threshold
) {
454 log_warn("unwanted reply total reached threshold (%u)"
455 " you may be under attack."
456 " defensive action: clearing the cache",
457 (unsigned)outnet
->unwanted_threshold
);
458 fptr_ok(fptr_whitelist_alloc_cleanup(
459 outnet
->unwanted_action
));
460 (*outnet
->unwanted_action
)(outnet
->unwanted_param
);
461 outnet
->unwanted_total
= 0;
465 comm_timer_disable(p
->timer
);
466 verbose(VERB_ALGO
, "outnet handle udp reply");
467 /* delete from tree first in case callback creates a retry */
468 (void)rbtree_delete(outnet
->pending
, p
->node
.key
);
470 fptr_ok(fptr_whitelist_pending_udp(p
->cb
));
471 (void)(*p
->cb
)(p
->pc
->cp
, p
->cb_arg
, NETEVENT_NOERROR
, reply_info
);
473 portcomm_loweruse(outnet
, p
->pc
);
474 pending_delete(NULL
, p
);
475 outnet_send_wait_udp(outnet
);
479 /** calculate number of ip4 and ip6 interfaces*/
481 calc_num46(char** ifs
, int num_ifs
, int do_ip4
, int do_ip6
,
482 int* num_ip4
, int* num_ip6
)
494 for(i
=0; i
<num_ifs
; i
++)
496 if(str_is_ip6(ifs
[i
])) {
508 pending_udp_timer_delay_cb(void* arg
)
510 struct pending
* p
= (struct pending
*)arg
;
511 struct outside_network
* outnet
= p
->outnet
;
512 verbose(VERB_ALGO
, "timeout udp with delay");
513 portcomm_loweruse(outnet
, p
->pc
);
514 pending_delete(outnet
, p
);
515 outnet_send_wait_udp(outnet
);
519 pending_udp_timer_cb(void *arg
)
521 struct pending
* p
= (struct pending
*)arg
;
522 struct outside_network
* outnet
= p
->outnet
;
524 verbose(VERB_ALGO
, "timeout udp");
526 fptr_ok(fptr_whitelist_pending_udp(p
->cb
));
527 (void)(*p
->cb
)(p
->pc
->cp
, p
->cb_arg
, NETEVENT_TIMEOUT
, NULL
);
529 /* if delayclose, keep port open for a longer time.
530 * But if the udpwaitlist exists, then we are struggling to
531 * keep up with demand for sockets, so do not wait, but service
532 * the customer (customer service more important than portICMPs) */
533 if(outnet
->delayclose
&& !outnet
->udp_wait_first
) {
535 p
->timer
->callback
= &pending_udp_timer_delay_cb
;
536 comm_timer_set(p
->timer
, &outnet
->delay_tv
);
539 portcomm_loweruse(outnet
, p
->pc
);
540 pending_delete(outnet
, p
);
541 outnet_send_wait_udp(outnet
);
544 /** create pending_tcp buffers */
546 create_pending_tcp(struct outside_network
* outnet
, size_t bufsize
)
549 if(outnet
->num_tcp
== 0)
550 return 1; /* no tcp needed, nothing to do */
551 if(!(outnet
->tcp_conns
= (struct pending_tcp
**)calloc(
552 outnet
->num_tcp
, sizeof(struct pending_tcp
*))))
554 for(i
=0; i
<outnet
->num_tcp
; i
++) {
555 if(!(outnet
->tcp_conns
[i
] = (struct pending_tcp
*)calloc(1,
556 sizeof(struct pending_tcp
))))
558 outnet
->tcp_conns
[i
]->next_free
= outnet
->tcp_free
;
559 outnet
->tcp_free
= outnet
->tcp_conns
[i
];
560 outnet
->tcp_conns
[i
]->c
= comm_point_create_tcp_out(
561 outnet
->base
, bufsize
, outnet_tcp_cb
,
562 outnet
->tcp_conns
[i
]);
563 if(!outnet
->tcp_conns
[i
]->c
)
569 /** setup an outgoing interface, ready address */
570 static int setup_if(struct port_if
* pif
, const char* addrstr
,
571 int* avail
, int numavail
, size_t numfd
)
573 pif
->avail_total
= numavail
;
574 pif
->avail_ports
= (int*)memdup(avail
, (size_t)numavail
*sizeof(int));
575 if(!pif
->avail_ports
)
577 if(!ipstrtoaddr(addrstr
, UNBOUND_DNS_PORT
, &pif
->addr
, &pif
->addrlen
))
579 pif
->maxout
= (int)numfd
;
581 pif
->out
= (struct port_comm
**)calloc(numfd
,
582 sizeof(struct port_comm
*));
588 struct outside_network
*
589 outside_network_create(struct comm_base
*base
, size_t bufsize
,
590 size_t num_ports
, char** ifs
, int num_ifs
, int do_ip4
,
591 int do_ip6
, size_t num_tcp
, struct infra_cache
* infra
,
592 struct ub_randstate
* rnd
, int use_caps_for_id
, int* availports
,
593 int numavailports
, size_t unwanted_threshold
,
594 void (*unwanted_action
)(void*), void* unwanted_param
, int do_udp
,
595 void* sslctx
, int delayclose
, struct dt_env
* dtenv
)
597 struct outside_network
* outnet
= (struct outside_network
*)
598 calloc(1, sizeof(struct outside_network
));
601 log_err("malloc failed");
604 comm_base_timept(base
, &outnet
->now_secs
, &outnet
->now_tv
);
606 outnet
->num_tcp
= num_tcp
;
607 outnet
->num_tcp_outgoing
= 0;
608 outnet
->infra
= infra
;
610 outnet
->sslctx
= sslctx
;
612 outnet
->dtenv
= dtenv
;
616 outnet
->svcd_overhead
= 0;
617 outnet
->want_to_quit
= 0;
618 outnet
->unwanted_threshold
= unwanted_threshold
;
619 outnet
->unwanted_action
= unwanted_action
;
620 outnet
->unwanted_param
= unwanted_param
;
621 outnet
->use_caps_for_id
= use_caps_for_id
;
622 outnet
->do_udp
= do_udp
;
625 outnet
->delayclose
= 1;
626 outnet
->delay_tv
.tv_sec
= delayclose
/1000;
627 outnet
->delay_tv
.tv_usec
= (delayclose%1000
)*1000;
630 if(numavailports
== 0) {
631 log_err("no outgoing ports available");
632 outside_network_delete(outnet
);
638 calc_num46(ifs
, num_ifs
, do_ip4
, do_ip6
,
639 &outnet
->num_ip4
, &outnet
->num_ip6
);
640 if(outnet
->num_ip4
!= 0) {
641 if(!(outnet
->ip4_ifs
= (struct port_if
*)calloc(
642 (size_t)outnet
->num_ip4
, sizeof(struct port_if
)))) {
643 log_err("malloc failed");
644 outside_network_delete(outnet
);
648 if(outnet
->num_ip6
!= 0) {
649 if(!(outnet
->ip6_ifs
= (struct port_if
*)calloc(
650 (size_t)outnet
->num_ip6
, sizeof(struct port_if
)))) {
651 log_err("malloc failed");
652 outside_network_delete(outnet
);
656 if( !(outnet
->udp_buff
= sldns_buffer_new(bufsize
)) ||
657 !(outnet
->pending
= rbtree_create(pending_cmp
)) ||
658 !(outnet
->serviced
= rbtree_create(serviced_cmp
)) ||
659 !create_pending_tcp(outnet
, bufsize
)) {
660 log_err("malloc failed");
661 outside_network_delete(outnet
);
665 /* allocate commpoints */
666 for(k
=0; k
<num_ports
; k
++) {
667 struct port_comm
* pc
;
668 pc
= (struct port_comm
*)calloc(1, sizeof(*pc
));
670 log_err("malloc failed");
671 outside_network_delete(outnet
);
674 pc
->cp
= comm_point_create_udp(outnet
->base
, -1,
675 outnet
->udp_buff
, outnet_udp_cb
, outnet
);
677 log_err("malloc failed");
679 outside_network_delete(outnet
);
682 pc
->next
= outnet
->unused_fds
;
683 outnet
->unused_fds
= pc
;
686 /* allocate interfaces */
688 if(do_ip4
&& !setup_if(&outnet
->ip4_ifs
[0], "0.0.0.0",
689 availports
, numavailports
, num_ports
)) {
690 log_err("malloc failed");
691 outside_network_delete(outnet
);
694 if(do_ip6
&& !setup_if(&outnet
->ip6_ifs
[0], "::",
695 availports
, numavailports
, num_ports
)) {
696 log_err("malloc failed");
697 outside_network_delete(outnet
);
701 size_t done_4
= 0, done_6
= 0;
703 for(i
=0; i
<num_ifs
; i
++) {
704 if(str_is_ip6(ifs
[i
]) && do_ip6
) {
705 if(!setup_if(&outnet
->ip6_ifs
[done_6
], ifs
[i
],
706 availports
, numavailports
, num_ports
)){
707 log_err("malloc failed");
708 outside_network_delete(outnet
);
713 if(!str_is_ip6(ifs
[i
]) && do_ip4
) {
714 if(!setup_if(&outnet
->ip4_ifs
[done_4
], ifs
[i
],
715 availports
, numavailports
, num_ports
)){
716 log_err("malloc failed");
717 outside_network_delete(outnet
);
727 /** helper pending delete */
729 pending_node_del(rbnode_t
* node
, void* arg
)
731 struct pending
* pend
= (struct pending
*)node
;
732 struct outside_network
* outnet
= (struct outside_network
*)arg
;
733 pending_delete(outnet
, pend
);
736 /** helper serviced delete */
738 serviced_node_del(rbnode_t
* node
, void* ATTR_UNUSED(arg
))
740 struct serviced_query
* sq
= (struct serviced_query
*)node
;
741 struct service_callback
* p
= sq
->cblist
, *np
;
753 outside_network_quit_prepare(struct outside_network
* outnet
)
757 /* prevent queued items from being sent */
758 outnet
->want_to_quit
= 1;
762 outside_network_delete(struct outside_network
* outnet
)
766 outnet
->want_to_quit
= 1;
767 /* check every element, since we can be called on malloc error */
768 if(outnet
->pending
) {
769 /* free pending elements, but do no unlink from tree. */
770 traverse_postorder(outnet
->pending
, pending_node_del
, NULL
);
771 free(outnet
->pending
);
773 if(outnet
->serviced
) {
774 traverse_postorder(outnet
->serviced
, serviced_node_del
, NULL
);
775 free(outnet
->serviced
);
778 sldns_buffer_free(outnet
->udp_buff
);
779 if(outnet
->unused_fds
) {
780 struct port_comm
* p
= outnet
->unused_fds
, *np
;
783 comm_point_delete(p
->cp
);
787 outnet
->unused_fds
= NULL
;
789 if(outnet
->ip4_ifs
) {
791 for(i
=0; i
<outnet
->num_ip4
; i
++) {
792 for(k
=0; k
<outnet
->ip4_ifs
[i
].inuse
; k
++) {
793 struct port_comm
* pc
= outnet
->ip4_ifs
[i
].
795 comm_point_delete(pc
->cp
);
798 free(outnet
->ip4_ifs
[i
].avail_ports
);
799 free(outnet
->ip4_ifs
[i
].out
);
801 free(outnet
->ip4_ifs
);
803 if(outnet
->ip6_ifs
) {
805 for(i
=0; i
<outnet
->num_ip6
; i
++) {
806 for(k
=0; k
<outnet
->ip6_ifs
[i
].inuse
; k
++) {
807 struct port_comm
* pc
= outnet
->ip6_ifs
[i
].
809 comm_point_delete(pc
->cp
);
812 free(outnet
->ip6_ifs
[i
].avail_ports
);
813 free(outnet
->ip6_ifs
[i
].out
);
815 free(outnet
->ip6_ifs
);
817 if(outnet
->tcp_conns
) {
819 for(i
=0; i
<outnet
->num_tcp
; i
++)
820 if(outnet
->tcp_conns
[i
]) {
821 comm_point_delete(outnet
->tcp_conns
[i
]->c
);
822 waiting_tcp_delete(outnet
->tcp_conns
[i
]->query
);
823 free(outnet
->tcp_conns
[i
]);
825 free(outnet
->tcp_conns
);
827 if(outnet
->tcp_wait_first
) {
828 struct waiting_tcp
* p
= outnet
->tcp_wait_first
, *np
;
830 np
= p
->next_waiting
;
831 waiting_tcp_delete(p
);
835 if(outnet
->udp_wait_first
) {
836 struct pending
* p
= outnet
->udp_wait_first
, *np
;
838 np
= p
->next_waiting
;
839 pending_delete(NULL
, p
);
847 pending_delete(struct outside_network
* outnet
, struct pending
* p
)
851 if(outnet
&& outnet
->udp_wait_first
&&
852 (p
->next_waiting
|| p
== outnet
->udp_wait_last
) ) {
853 /* delete from waiting list, if it is in the waiting list */
854 struct pending
* prev
= NULL
, *x
= outnet
->udp_wait_first
;
862 prev
->next_waiting
= p
->next_waiting
;
863 else outnet
->udp_wait_first
= p
->next_waiting
;
864 if(outnet
->udp_wait_last
== p
)
865 outnet
->udp_wait_last
= prev
;
869 (void)rbtree_delete(outnet
->pending
, p
->node
.key
);
872 comm_timer_delete(p
->timer
);
878 * Try to open a UDP socket for outgoing communication.
879 * Sets sockets options as needed.
880 * @param addr: socket address.
881 * @param addrlen: length of address.
882 * @param port: port override for addr.
883 * @param inuse: if -1 is returned, this bool means the port was in use.
887 udp_sockport(struct sockaddr_storage
* addr
, socklen_t addrlen
, int port
,
891 if(addr_is_ip6(addr
, addrlen
)) {
892 struct sockaddr_in6
* sa
= (struct sockaddr_in6
*)addr
;
893 sa
->sin6_port
= (in_port_t
)htons((uint16_t)port
);
894 fd
= create_udp_sock(AF_INET6
, SOCK_DGRAM
,
895 (struct sockaddr
*)addr
, addrlen
, 1, inuse
, &noproto
,
898 struct sockaddr_in
* sa
= (struct sockaddr_in
*)addr
;
899 sa
->sin_port
= (in_port_t
)htons((uint16_t)port
);
900 fd
= create_udp_sock(AF_INET
, SOCK_DGRAM
,
901 (struct sockaddr
*)addr
, addrlen
, 1, inuse
, &noproto
,
907 /** Select random ID */
909 select_id(struct outside_network
* outnet
, struct pending
* pend
,
910 sldns_buffer
* packet
)
913 pend
->id
= ((unsigned)ub_random(outnet
->rnd
)>>8) & 0xffff;
914 LDNS_ID_SET(sldns_buffer_begin(packet
), pend
->id
);
917 pend
->node
.key
= pend
;
918 while(!rbtree_insert(outnet
->pending
, &pend
->node
)) {
919 /* change ID to avoid collision */
920 pend
->id
= ((unsigned)ub_random(outnet
->rnd
)>>8) & 0xffff;
921 LDNS_ID_SET(sldns_buffer_begin(packet
), pend
->id
);
923 if(id_tries
== MAX_ID_RETRY
) {
924 pend
->id
=99999; /* non existant ID */
925 log_err("failed to generate unique ID, drop msg");
929 verbose(VERB_ALGO
, "inserted new pending reply id=%4.4x", pend
->id
);
933 /** Select random interface and port */
935 select_ifport(struct outside_network
* outnet
, struct pending
* pend
,
936 int num_if
, struct port_if
* ifs
)
938 int my_if
, my_port
, fd
, portno
, inuse
, tries
=0;
940 /* randomly select interface and port */
942 verbose(VERB_QUERY
, "Need to send query but have no "
943 "outgoing interfaces of that family");
946 log_assert(outnet
->unused_fds
);
949 my_if
= ub_random_max(outnet
->rnd
, num_if
);
951 my_port
= ub_random_max(outnet
->rnd
, pif
->avail_total
);
952 if(my_port
< pif
->inuse
) {
953 /* port already open */
954 pend
->pc
= pif
->out
[my_port
];
955 verbose(VERB_ALGO
, "using UDP if=%d port=%d",
956 my_if
, pend
->pc
->number
);
959 /* try to open new port, if fails, loop to try again */
960 log_assert(pif
->inuse
< pif
->maxout
);
961 portno
= pif
->avail_ports
[my_port
- pif
->inuse
];
962 fd
= udp_sockport(&pif
->addr
, pif
->addrlen
, portno
, &inuse
);
963 if(fd
== -1 && !inuse
) {
964 /* nonrecoverable error making socket */
968 verbose(VERB_ALGO
, "opened UDP if=%d port=%d",
971 pend
->pc
= outnet
->unused_fds
;
972 outnet
->unused_fds
= pend
->pc
->next
;
975 pend
->pc
->next
= NULL
;
976 pend
->pc
->number
= portno
;
978 pend
->pc
->index
= pif
->inuse
;
979 pend
->pc
->num_outstanding
= 0;
980 comm_point_start_listening(pend
->pc
->cp
, fd
, -1);
982 /* grab port in interface */
983 pif
->out
[pif
->inuse
] = pend
->pc
;
984 pif
->avail_ports
[my_port
- pif
->inuse
] =
985 pif
->avail_ports
[pif
->avail_total
-pif
->inuse
-1];
989 /* failed, already in use */
990 verbose(VERB_QUERY
, "port %d in use, trying another", portno
);
992 if(tries
== MAX_PORT_RETRY
) {
993 log_err("failed to find an open port, drop msg");
997 log_assert(pend
->pc
);
998 pend
->pc
->num_outstanding
++;
1004 randomize_and_send_udp(struct pending
* pend
, sldns_buffer
* packet
, int timeout
)
1007 struct outside_network
* outnet
= pend
->sq
->outnet
;
1010 if(!select_id(outnet
, pend
, packet
)) {
1014 /* select src_if, port */
1015 if(addr_is_ip6(&pend
->addr
, pend
->addrlen
)) {
1016 if(!select_ifport(outnet
, pend
,
1017 outnet
->num_ip6
, outnet
->ip6_ifs
))
1020 if(!select_ifport(outnet
, pend
,
1021 outnet
->num_ip4
, outnet
->ip4_ifs
))
1024 log_assert(pend
->pc
&& pend
->pc
->cp
);
1026 /* send it over the commlink */
1027 if(!comm_point_send_udp_msg(pend
->pc
->cp
, packet
,
1028 (struct sockaddr
*)&pend
->addr
, pend
->addrlen
)) {
1029 portcomm_loweruse(outnet
, pend
->pc
);
1033 /* system calls to set timeout after sending UDP to make roundtrip
1036 tv
.tv_sec
= timeout
/1000;
1037 tv
.tv_usec
= (timeout%1000
)*1000;
1039 comm_timer_set(pend
->timer
, &tv
);
1043 (outnet
->dtenv
->log_resolver_query_messages
||
1044 outnet
->dtenv
->log_forwarder_query_messages
))
1045 dt_msg_send_outside_query(outnet
->dtenv
, &pend
->addr
, comm_udp
,
1046 pend
->sq
->zone
, pend
->sq
->zonelen
, packet
);
1052 pending_udp_query(struct serviced_query
* sq
, struct sldns_buffer
* packet
,
1053 int timeout
, comm_point_callback_t
* cb
, void* cb_arg
)
1055 struct pending
* pend
= (struct pending
*)calloc(1, sizeof(*pend
));
1056 if(!pend
) return NULL
;
1057 pend
->outnet
= sq
->outnet
;
1059 pend
->addrlen
= sq
->addrlen
;
1060 memmove(&pend
->addr
, &sq
->addr
, sq
->addrlen
);
1062 pend
->cb_arg
= cb_arg
;
1063 pend
->node
.key
= pend
;
1064 pend
->timer
= comm_timer_create(sq
->outnet
->base
, pending_udp_timer_cb
,
1071 if(sq
->outnet
->unused_fds
== NULL
) {
1072 /* no unused fd, cannot create a new port (randomly) */
1073 verbose(VERB_ALGO
, "no fds available, udp query waiting");
1074 pend
->timeout
= timeout
;
1075 pend
->pkt_len
= sldns_buffer_limit(packet
);
1076 pend
->pkt
= (uint8_t*)memdup(sldns_buffer_begin(packet
),
1079 comm_timer_delete(pend
->timer
);
1083 /* put at end of waiting list */
1084 if(sq
->outnet
->udp_wait_last
)
1085 sq
->outnet
->udp_wait_last
->next_waiting
= pend
;
1087 sq
->outnet
->udp_wait_first
= pend
;
1088 sq
->outnet
->udp_wait_last
= pend
;
1091 if(!randomize_and_send_udp(pend
, packet
, timeout
)) {
1092 pending_delete(sq
->outnet
, pend
);
1099 outnet_tcptimer(void* arg
)
1101 struct waiting_tcp
* w
= (struct waiting_tcp
*)arg
;
1102 struct outside_network
* outnet
= w
->outnet
;
1103 comm_point_callback_t
* cb
;
1106 /* it is on the waiting list */
1107 waiting_list_remove(outnet
, w
);
1110 struct pending_tcp
* pend
=(struct pending_tcp
*)w
->next_waiting
;
1111 comm_point_close(pend
->c
);
1113 pend
->next_free
= outnet
->tcp_free
;
1114 outnet
->tcp_free
= pend
;
1118 waiting_tcp_delete(w
);
1119 fptr_ok(fptr_whitelist_pending_tcp(cb
));
1120 (void)(*cb
)(NULL
, cb_arg
, NETEVENT_TIMEOUT
, NULL
);
1121 use_free_buffer(outnet
);
1125 pending_tcp_query(struct serviced_query
* sq
, sldns_buffer
* packet
,
1126 int timeout
, comm_point_callback_t
* callback
, void* callback_arg
)
1128 struct pending_tcp
* pend
= sq
->outnet
->tcp_free
;
1129 struct waiting_tcp
* w
;
1132 /* if no buffer is free allocate space to store query */
1133 w
= (struct waiting_tcp
*)malloc(sizeof(struct waiting_tcp
)
1134 + (pend
?0:sldns_buffer_limit(packet
)));
1138 if(!(w
->timer
= comm_timer_create(sq
->outnet
->base
, outnet_tcptimer
, w
))) {
1144 id
= ((unsigned)ub_random(sq
->outnet
->rnd
)>>8) & 0xffff;
1145 LDNS_ID_SET(sldns_buffer_begin(packet
), id
);
1146 memcpy(&w
->addr
, &sq
->addr
, sq
->addrlen
);
1147 w
->addrlen
= sq
->addrlen
;
1148 w
->outnet
= sq
->outnet
;
1150 w
->cb_arg
= callback_arg
;
1151 w
->ssl_upstream
= sq
->ssl_upstream
;
1153 tv
.tv_sec
= timeout
;
1156 comm_timer_set(w
->timer
, &tv
);
1158 /* we have a buffer available right now */
1159 if(!outnet_tcp_take_into_use(w
, sldns_buffer_begin(packet
),
1160 sldns_buffer_limit(packet
))) {
1161 waiting_tcp_delete(w
);
1165 if(sq
->outnet
->dtenv
&&
1166 (sq
->outnet
->dtenv
->log_resolver_query_messages
||
1167 sq
->outnet
->dtenv
->log_forwarder_query_messages
))
1168 dt_msg_send_outside_query(sq
->outnet
->dtenv
, &sq
->addr
,
1169 comm_tcp
, sq
->zone
, sq
->zonelen
, packet
);
1173 w
->pkt
= (uint8_t*)w
+ sizeof(struct waiting_tcp
);
1174 w
->pkt_len
= sldns_buffer_limit(packet
);
1175 memmove(w
->pkt
, sldns_buffer_begin(packet
), w
->pkt_len
);
1176 w
->next_waiting
= NULL
;
1177 if(sq
->outnet
->tcp_wait_last
)
1178 sq
->outnet
->tcp_wait_last
->next_waiting
= w
;
1179 else sq
->outnet
->tcp_wait_first
= w
;
1180 sq
->outnet
->tcp_wait_last
= w
;
1185 /** create query for serviced queries */
1187 serviced_gen_query(sldns_buffer
* buff
, uint8_t* qname
, size_t qnamelen
,
1188 uint16_t qtype
, uint16_t qclass
, uint16_t flags
)
1190 sldns_buffer_clear(buff
);
1192 sldns_buffer_write_u16(buff
, flags
);
1193 sldns_buffer_write_u16(buff
, 1); /* qdcount */
1194 sldns_buffer_write_u16(buff
, 0); /* ancount */
1195 sldns_buffer_write_u16(buff
, 0); /* nscount */
1196 sldns_buffer_write_u16(buff
, 0); /* arcount */
1197 sldns_buffer_write(buff
, qname
, qnamelen
);
1198 sldns_buffer_write_u16(buff
, qtype
);
1199 sldns_buffer_write_u16(buff
, qclass
);
1200 sldns_buffer_flip(buff
);
1203 /** lookup serviced query in serviced query rbtree */
1204 static struct serviced_query
*
1205 lookup_serviced(struct outside_network
* outnet
, sldns_buffer
* buff
, int dnssec
,
1206 struct sockaddr_storage
* addr
, socklen_t addrlen
)
1208 struct serviced_query key
;
1209 key
.node
.key
= &key
;
1210 key
.qbuf
= sldns_buffer_begin(buff
);
1211 key
.qbuflen
= sldns_buffer_limit(buff
);
1212 key
.dnssec
= dnssec
;
1213 memcpy(&key
.addr
, addr
, addrlen
);
1214 key
.addrlen
= addrlen
;
1215 key
.outnet
= outnet
;
1216 return (struct serviced_query
*)rbtree_search(outnet
->serviced
, &key
);
1219 /** Create new serviced entry */
1220 static struct serviced_query
*
1221 serviced_create(struct outside_network
* outnet
, sldns_buffer
* buff
, int dnssec
,
1222 int want_dnssec
, int nocaps
, int tcp_upstream
, int ssl_upstream
,
1223 struct sockaddr_storage
* addr
, socklen_t addrlen
, uint8_t* zone
,
1224 size_t zonelen
, int qtype
)
1226 struct serviced_query
* sq
= (struct serviced_query
*)malloc(sizeof(*sq
));
1227 #ifdef UNBOUND_DEBUG
1233 sq
->qbuf
= memdup(sldns_buffer_begin(buff
), sldns_buffer_limit(buff
));
1238 sq
->qbuflen
= sldns_buffer_limit(buff
);
1239 sq
->zone
= memdup(zone
, zonelen
);
1245 sq
->zonelen
= zonelen
;
1247 sq
->dnssec
= dnssec
;
1248 sq
->want_dnssec
= want_dnssec
;
1249 sq
->nocaps
= nocaps
;
1250 sq
->tcp_upstream
= tcp_upstream
;
1251 sq
->ssl_upstream
= ssl_upstream
;
1252 memcpy(&sq
->addr
, addr
, addrlen
);
1253 sq
->addrlen
= addrlen
;
1254 sq
->outnet
= outnet
;
1257 sq
->status
= serviced_initial
;
1259 sq
->to_be_deleted
= 0;
1260 #ifdef UNBOUND_DEBUG
1265 rbtree_insert(outnet
->serviced
, &sq
->node
);
1266 log_assert(ins
!= NULL
); /* must not be already present */
1270 /** remove waiting tcp from the outnet waiting list */
1272 waiting_list_remove(struct outside_network
* outnet
, struct waiting_tcp
* w
)
1274 struct waiting_tcp
* p
= outnet
->tcp_wait_first
, *prev
= NULL
;
1279 prev
->next_waiting
= w
->next_waiting
;
1280 else outnet
->tcp_wait_first
= w
->next_waiting
;
1281 if(outnet
->tcp_wait_last
== w
)
1282 outnet
->tcp_wait_last
= prev
;
1286 p
= p
->next_waiting
;
1290 /** cleanup serviced query entry */
1292 serviced_delete(struct serviced_query
* sq
)
1295 /* clear up the pending query */
1296 if(sq
->status
== serviced_query_UDP_EDNS
||
1297 sq
->status
== serviced_query_UDP
||
1298 sq
->status
== serviced_query_PROBE_EDNS
||
1299 sq
->status
== serviced_query_UDP_EDNS_FRAG
||
1300 sq
->status
== serviced_query_UDP_EDNS_fallback
) {
1301 struct pending
* p
= (struct pending
*)sq
->pending
;
1303 portcomm_loweruse(sq
->outnet
, p
->pc
);
1304 pending_delete(sq
->outnet
, p
);
1305 /* this call can cause reentrant calls back into the
1307 outnet_send_wait_udp(sq
->outnet
);
1309 struct waiting_tcp
* p
= (struct waiting_tcp
*)
1311 if(p
->pkt
== NULL
) {
1312 decomission_pending_tcp(sq
->outnet
,
1313 (struct pending_tcp
*)p
->next_waiting
);
1315 waiting_list_remove(sq
->outnet
, p
);
1316 waiting_tcp_delete(p
);
1320 /* does not delete from tree, caller has to do that */
1321 serviced_node_del(&sq
->node
, NULL
);
1324 /** perturb a dname capitalization randomly */
1326 serviced_perturb_qname(struct ub_randstate
* rnd
, uint8_t* qbuf
, size_t len
)
1329 uint8_t* d
= qbuf
+ 10;
1330 long int random
= 0;
1332 log_assert(len
>= 10 + 5 /* offset qname, root, qtype, qclass */);
1336 /* only perturb A-Z, a-z */
1337 if(isalpha((unsigned char)*d
)) {
1338 /* get a random bit */
1340 random
= ub_random(rnd
);
1344 *d
= (uint8_t)toupper((unsigned char)*d
);
1346 *d
= (uint8_t)tolower((unsigned char)*d
);
1355 if(verbosity
>= VERB_ALGO
) {
1356 char buf
[LDNS_MAX_DOMAINLEN
+1];
1357 dname_str(qbuf
+10, buf
);
1358 verbose(VERB_ALGO
, "qname perturbed to %s", buf
);
1362 /** put serviced query into a buffer */
1364 serviced_encode(struct serviced_query
* sq
, sldns_buffer
* buff
, int with_edns
)
1366 /* if we are using 0x20 bits for ID randomness, perturb them */
1367 if(sq
->outnet
->use_caps_for_id
&& !sq
->nocaps
) {
1368 serviced_perturb_qname(sq
->outnet
->rnd
, sq
->qbuf
, sq
->qbuflen
);
1370 /* generate query */
1371 sldns_buffer_clear(buff
);
1372 sldns_buffer_write_u16(buff
, 0); /* id placeholder */
1373 sldns_buffer_write(buff
, sq
->qbuf
, sq
->qbuflen
);
1374 sldns_buffer_flip(buff
);
1376 /* add edns section */
1377 struct edns_data edns
;
1378 edns
.edns_present
= 1;
1380 edns
.edns_version
= EDNS_ADVERTISED_VERSION
;
1381 if(sq
->status
== serviced_query_UDP_EDNS_FRAG
) {
1382 if(addr_is_ip6(&sq
->addr
, sq
->addrlen
)) {
1383 if(EDNS_FRAG_SIZE_IP6
< EDNS_ADVERTISED_SIZE
)
1384 edns
.udp_size
= EDNS_FRAG_SIZE_IP6
;
1385 else edns
.udp_size
= EDNS_ADVERTISED_SIZE
;
1387 if(EDNS_FRAG_SIZE_IP4
< EDNS_ADVERTISED_SIZE
)
1388 edns
.udp_size
= EDNS_FRAG_SIZE_IP4
;
1389 else edns
.udp_size
= EDNS_ADVERTISED_SIZE
;
1392 edns
.udp_size
= EDNS_ADVERTISED_SIZE
;
1395 if(sq
->dnssec
& EDNS_DO
)
1396 edns
.bits
= EDNS_DO
;
1397 if(sq
->dnssec
& BIT_CD
)
1398 LDNS_CD_SET(sldns_buffer_begin(buff
));
1399 attach_edns_record(buff
, &edns
);
1404 * Perform serviced query UDP sending operation.
1405 * Sends UDP with EDNS, unless infra host marked non EDNS.
1406 * @param sq: query to send.
1407 * @param buff: buffer scratch space.
1408 * @return 0 on error.
1411 serviced_udp_send(struct serviced_query
* sq
, sldns_buffer
* buff
)
1414 uint8_t edns_lame_known
;
1415 time_t now
= *sq
->outnet
->now_secs
;
1417 if(!infra_host(sq
->outnet
->infra
, &sq
->addr
, sq
->addrlen
, sq
->zone
,
1418 sq
->zonelen
, now
, &vs
, &edns_lame_known
, &rtt
))
1421 verbose(VERB_ALGO
, "EDNS lookup known=%d vs=%d", edns_lame_known
, vs
);
1422 if(sq
->status
== serviced_initial
) {
1423 if(edns_lame_known
== 0 && rtt
> 5000 && rtt
< 10001) {
1424 /* perform EDNS lame probe - check if server is
1425 * EDNS lame (EDNS queries to it are dropped) */
1426 verbose(VERB_ALGO
, "serviced query: send probe to see "
1427 " if use of EDNS causes timeouts");
1428 /* even 700 msec may be too small */
1430 sq
->status
= serviced_query_PROBE_EDNS
;
1431 } else if(vs
!= -1) {
1432 sq
->status
= serviced_query_UDP_EDNS
;
1434 sq
->status
= serviced_query_UDP
;
1437 serviced_encode(sq
, buff
, (sq
->status
== serviced_query_UDP_EDNS
) ||
1438 (sq
->status
== serviced_query_UDP_EDNS_FRAG
));
1439 sq
->last_sent_time
= *sq
->outnet
->now_tv
;
1440 sq
->edns_lame_known
= (int)edns_lame_known
;
1441 verbose(VERB_ALGO
, "serviced query UDP timeout=%d msec", rtt
);
1442 sq
->pending
= pending_udp_query(sq
, buff
, rtt
,
1443 serviced_udp_callback
, sq
);
1449 /** check that perturbed qname is identical */
1451 serviced_check_qname(sldns_buffer
* pkt
, uint8_t* qbuf
, size_t qbuflen
)
1453 uint8_t* d1
= sldns_buffer_at(pkt
, 12);
1454 uint8_t* d2
= qbuf
+10;
1457 log_assert(qbuflen
>= 15 /* 10 header, root, type, class */);
1460 if(sldns_buffer_limit(pkt
) < 12+1+4) /* packet too small for qname */
1462 while(len1
!= 0 || len2
!= 0) {
1463 if(LABEL_IS_PTR(len1
)) {
1464 d1
= sldns_buffer_at(pkt
, PTR_OFFSET(len1
, *d1
));
1465 if(d1
>= sldns_buffer_at(pkt
, sldns_buffer_limit(pkt
)))
1468 if(count
++ > MAX_COMPRESS_PTRS
)
1472 if(d2
> qbuf
+qbuflen
)
1476 if(len1
> LDNS_MAX_LABELLEN
)
1478 log_assert(len1
<= LDNS_MAX_LABELLEN
);
1479 log_assert(len2
<= LDNS_MAX_LABELLEN
);
1480 log_assert(len1
== len2
&& len1
!= 0);
1481 /* compare the labels - bitwise identical */
1482 if(memcmp(d1
, d2
, len1
) != 0)
1492 /** call the callbacks for a serviced query */
1494 serviced_callbacks(struct serviced_query
* sq
, int error
, struct comm_point
* c
,
1495 struct comm_reply
* rep
)
1497 struct service_callback
* p
;
1498 int dobackup
= (sq
->cblist
&& sq
->cblist
->next
); /* >1 cb*/
1499 uint8_t *backup_p
= NULL
;
1501 #ifdef UNBOUND_DEBUG
1506 /* remove from tree, and schedule for deletion, so that callbacks
1507 * can safely deregister themselves and even create new serviced
1508 * queries that are identical to this one. */
1509 rbtree_delete(sq
->outnet
->serviced
, sq
);
1510 log_assert(rem
); /* should have been present */
1511 sq
->to_be_deleted
= 1;
1512 verbose(VERB_ALGO
, "svcd callbacks start");
1513 if(sq
->outnet
->use_caps_for_id
&& error
== NETEVENT_NOERROR
&& c
) {
1514 /* noerror and nxdomain must have a qname in reply */
1515 if(sldns_buffer_read_u16_at(c
->buffer
, 4) == 0 &&
1516 (LDNS_RCODE_WIRE(sldns_buffer_begin(c
->buffer
))
1517 == LDNS_RCODE_NOERROR
||
1518 LDNS_RCODE_WIRE(sldns_buffer_begin(c
->buffer
))
1519 == LDNS_RCODE_NXDOMAIN
)) {
1520 verbose(VERB_DETAIL
, "no qname in reply to check 0x20ID");
1521 log_addr(VERB_DETAIL
, "from server",
1522 &sq
->addr
, sq
->addrlen
);
1523 log_buf(VERB_DETAIL
, "for packet", c
->buffer
);
1524 error
= NETEVENT_CLOSED
;
1526 } else if(sldns_buffer_read_u16_at(c
->buffer
, 4) > 0 &&
1527 !serviced_check_qname(c
->buffer
, sq
->qbuf
,
1529 verbose(VERB_DETAIL
, "wrong 0x20-ID in reply qname");
1530 log_addr(VERB_DETAIL
, "from server",
1531 &sq
->addr
, sq
->addrlen
);
1532 log_buf(VERB_DETAIL
, "for packet", c
->buffer
);
1533 error
= NETEVENT_CAPSFAIL
;
1534 /* and cleanup too */
1535 pkt_dname_tolower(c
->buffer
,
1536 sldns_buffer_at(c
->buffer
, 12));
1538 verbose(VERB_ALGO
, "good 0x20-ID in reply qname");
1539 /* cleanup caps, prettier cache contents. */
1540 pkt_dname_tolower(c
->buffer
,
1541 sldns_buffer_at(c
->buffer
, 12));
1545 /* make a backup of the query, since the querystate processing
1546 * may send outgoing queries that overwrite the buffer.
1547 * use secondary buffer to store the query.
1548 * This is a data copy, but faster than packet to server */
1549 backlen
= sldns_buffer_limit(c
->buffer
);
1550 backup_p
= memdup(sldns_buffer_begin(c
->buffer
), backlen
);
1552 log_err("malloc failure in serviced query callbacks");
1553 error
= NETEVENT_CLOSED
;
1556 sq
->outnet
->svcd_overhead
= backlen
;
1558 /* test the actual sq->cblist, because the next elem could be deleted*/
1559 while((p
=sq
->cblist
) != NULL
) {
1560 sq
->cblist
= p
->next
; /* remove this element */
1562 sldns_buffer_clear(c
->buffer
);
1563 sldns_buffer_write(c
->buffer
, backup_p
, backlen
);
1564 sldns_buffer_flip(c
->buffer
);
1566 fptr_ok(fptr_whitelist_serviced_query(p
->cb
));
1567 (void)(*p
->cb
)(c
, p
->cb_arg
, error
, rep
);
1572 sq
->outnet
->svcd_overhead
= 0;
1574 verbose(VERB_ALGO
, "svcd callbacks end");
1575 log_assert(sq
->cblist
== NULL
);
1576 serviced_delete(sq
);
1580 serviced_tcp_callback(struct comm_point
* c
, void* arg
, int error
,
1581 struct comm_reply
* rep
)
1583 struct serviced_query
* sq
= (struct serviced_query
*)arg
;
1584 struct comm_reply r2
;
1585 sq
->pending
= NULL
; /* removed after this callback */
1586 if(error
!= NETEVENT_NOERROR
)
1587 log_addr(VERB_QUERY
, "tcp error for address",
1588 &sq
->addr
, sq
->addrlen
);
1589 if(error
==NETEVENT_NOERROR
)
1590 infra_update_tcp_works(sq
->outnet
->infra
, &sq
->addr
,
1591 sq
->addrlen
, sq
->zone
, sq
->zonelen
);
1593 if(sq
->outnet
->dtenv
&&
1594 (sq
->outnet
->dtenv
->log_resolver_response_messages
||
1595 sq
->outnet
->dtenv
->log_forwarder_response_messages
))
1596 dt_msg_send_outside_response(sq
->outnet
->dtenv
, &sq
->addr
,
1597 c
->type
, sq
->zone
, sq
->zonelen
, sq
->qbuf
, sq
->qbuflen
,
1598 &sq
->last_sent_time
, sq
->outnet
->now_tv
, c
->buffer
);
1600 if(error
==NETEVENT_NOERROR
&& sq
->status
== serviced_query_TCP_EDNS
&&
1601 (LDNS_RCODE_WIRE(sldns_buffer_begin(c
->buffer
)) ==
1602 LDNS_RCODE_FORMERR
|| LDNS_RCODE_WIRE(sldns_buffer_begin(
1603 c
->buffer
)) == LDNS_RCODE_NOTIMPL
) ) {
1604 /* attempt to fallback to nonEDNS */
1605 sq
->status
= serviced_query_TCP_EDNS_fallback
;
1606 serviced_tcp_initiate(sq
, c
->buffer
);
1608 } else if(error
==NETEVENT_NOERROR
&&
1609 sq
->status
== serviced_query_TCP_EDNS_fallback
&&
1610 (LDNS_RCODE_WIRE(sldns_buffer_begin(c
->buffer
)) ==
1611 LDNS_RCODE_NOERROR
|| LDNS_RCODE_WIRE(
1612 sldns_buffer_begin(c
->buffer
)) == LDNS_RCODE_NXDOMAIN
1613 || LDNS_RCODE_WIRE(sldns_buffer_begin(c
->buffer
))
1614 == LDNS_RCODE_YXDOMAIN
)) {
1615 /* the fallback produced a result that looks promising, note
1616 * that this server should be approached without EDNS */
1617 /* only store noEDNS in cache if domain is noDNSSEC */
1618 if(!sq
->want_dnssec
)
1619 if(!infra_edns_update(sq
->outnet
->infra
, &sq
->addr
,
1620 sq
->addrlen
, sq
->zone
, sq
->zonelen
, -1,
1621 *sq
->outnet
->now_secs
))
1622 log_err("Out of memory caching no edns for host");
1623 sq
->status
= serviced_query_TCP
;
1625 if(sq
->tcp_upstream
|| sq
->ssl_upstream
) {
1626 struct timeval now
= *sq
->outnet
->now_tv
;
1627 if(now
.tv_sec
> sq
->last_sent_time
.tv_sec
||
1628 (now
.tv_sec
== sq
->last_sent_time
.tv_sec
&&
1629 now
.tv_usec
> sq
->last_sent_time
.tv_usec
)) {
1630 /* convert from microseconds to milliseconds */
1631 int roundtime
= ((int)(now
.tv_sec
- sq
->last_sent_time
.tv_sec
))*1000
1632 + ((int)now
.tv_usec
- (int)sq
->last_sent_time
.tv_usec
)/1000;
1633 verbose(VERB_ALGO
, "measured TCP-time at %d msec", roundtime
);
1634 log_assert(roundtime
>= 0);
1635 /* only store if less then AUTH_TIMEOUT seconds, it could be
1636 * huge due to system-hibernated and we woke up */
1637 if(roundtime
< TCP_AUTH_QUERY_TIMEOUT
*1000) {
1638 if(!infra_rtt_update(sq
->outnet
->infra
, &sq
->addr
,
1639 sq
->addrlen
, sq
->zone
, sq
->zonelen
, sq
->qtype
,
1640 roundtime
, sq
->last_rtt
, (time_t)now
.tv_sec
))
1641 log_err("out of memory noting rtt.");
1645 /* insert address into reply info */
1647 /* create one if there isn't (on errors) */
1651 memcpy(&rep
->addr
, &sq
->addr
, sq
->addrlen
);
1652 rep
->addrlen
= sq
->addrlen
;
1653 serviced_callbacks(sq
, error
, c
, rep
);
1658 serviced_tcp_initiate(struct serviced_query
* sq
, sldns_buffer
* buff
)
1660 verbose(VERB_ALGO
, "initiate TCP query %s",
1661 sq
->status
==serviced_query_TCP_EDNS
?"EDNS":"");
1662 serviced_encode(sq
, buff
, sq
->status
== serviced_query_TCP_EDNS
);
1663 sq
->last_sent_time
= *sq
->outnet
->now_tv
;
1664 sq
->pending
= pending_tcp_query(sq
, buff
, TCP_AUTH_QUERY_TIMEOUT
,
1665 serviced_tcp_callback
, sq
);
1667 /* delete from tree so that a retry by above layer does not
1668 * clash with this entry */
1669 log_err("serviced_tcp_initiate: failed to send tcp query");
1670 serviced_callbacks(sq
, NETEVENT_CLOSED
, NULL
, NULL
);
1674 /** Send serviced query over TCP return false on initial failure */
1676 serviced_tcp_send(struct serviced_query
* sq
, sldns_buffer
* buff
)
1679 uint8_t edns_lame_known
;
1680 if(!infra_host(sq
->outnet
->infra
, &sq
->addr
, sq
->addrlen
, sq
->zone
,
1681 sq
->zonelen
, *sq
->outnet
->now_secs
, &vs
, &edns_lame_known
,
1685 sq
->status
= serviced_query_TCP_EDNS
;
1686 else sq
->status
= serviced_query_TCP
;
1687 serviced_encode(sq
, buff
, sq
->status
== serviced_query_TCP_EDNS
);
1688 sq
->last_sent_time
= *sq
->outnet
->now_tv
;
1689 sq
->pending
= pending_tcp_query(sq
, buff
, TCP_AUTH_QUERY_TIMEOUT
,
1690 serviced_tcp_callback
, sq
);
1691 return sq
->pending
!= NULL
;
1695 serviced_udp_callback(struct comm_point
* c
, void* arg
, int error
,
1696 struct comm_reply
* rep
)
1698 struct serviced_query
* sq
= (struct serviced_query
*)arg
;
1699 struct outside_network
* outnet
= sq
->outnet
;
1700 struct timeval now
= *sq
->outnet
->now_tv
;
1701 int fallback_tcp
= 0;
1703 sq
->pending
= NULL
; /* removed after callback */
1704 if(error
== NETEVENT_TIMEOUT
) {
1706 if(sq
->status
== serviced_query_PROBE_EDNS
) {
1707 /* non-EDNS probe failed; we do not know its status,
1708 * keep trying with EDNS, timeout may not be caused
1710 sq
->status
= serviced_query_UDP_EDNS
;
1712 if(sq
->status
== serviced_query_UDP_EDNS
&& sq
->last_rtt
< 5000) {
1713 /* fallback to 1480/1280 */
1714 sq
->status
= serviced_query_UDP_EDNS_FRAG
;
1715 log_name_addr(VERB_ALGO
, "try edns1xx0", sq
->qbuf
+10,
1716 &sq
->addr
, sq
->addrlen
);
1717 if(!serviced_udp_send(sq
, c
->buffer
)) {
1718 serviced_callbacks(sq
, NETEVENT_CLOSED
, c
, rep
);
1722 if(sq
->status
== serviced_query_UDP_EDNS_FRAG
) {
1723 /* fragmentation size did not fix it */
1724 sq
->status
= serviced_query_UDP_EDNS
;
1727 if(!(rto
=infra_rtt_update(outnet
->infra
, &sq
->addr
, sq
->addrlen
,
1728 sq
->zone
, sq
->zonelen
, sq
->qtype
, -1, sq
->last_rtt
,
1729 (time_t)now
.tv_sec
)))
1730 log_err("out of memory in UDP exponential backoff");
1731 if(sq
->retry
< OUTBOUND_UDP_RETRY
) {
1732 log_name_addr(VERB_ALGO
, "retry query", sq
->qbuf
+10,
1733 &sq
->addr
, sq
->addrlen
);
1734 if(!serviced_udp_send(sq
, c
->buffer
)) {
1735 serviced_callbacks(sq
, NETEVENT_CLOSED
, c
, rep
);
1739 if(rto
>= RTT_MAX_TIMEOUT
) {
1741 /* UDP does not work, fallback to TCP below */
1743 serviced_callbacks(sq
, NETEVENT_TIMEOUT
, c
, rep
);
1746 } else if(error
!= NETEVENT_NOERROR
) {
1747 /* udp returns error (due to no ID or interface available) */
1748 serviced_callbacks(sq
, error
, c
, rep
);
1753 (outnet
->dtenv
->log_resolver_response_messages
||
1754 outnet
->dtenv
->log_forwarder_response_messages
))
1755 dt_msg_send_outside_response(outnet
->dtenv
, &sq
->addr
, c
->type
,
1756 sq
->zone
, sq
->zonelen
, sq
->qbuf
, sq
->qbuflen
,
1757 &sq
->last_sent_time
, sq
->outnet
->now_tv
, c
->buffer
);
1760 if( (sq
->status
== serviced_query_UDP_EDNS
1761 ||sq
->status
== serviced_query_UDP_EDNS_FRAG
)
1762 && (LDNS_RCODE_WIRE(sldns_buffer_begin(c
->buffer
))
1763 == LDNS_RCODE_FORMERR
|| LDNS_RCODE_WIRE(
1764 sldns_buffer_begin(c
->buffer
)) == LDNS_RCODE_NOTIMPL
)) {
1765 /* try to get an answer by falling back without EDNS */
1766 verbose(VERB_ALGO
, "serviced query: attempt without EDNS");
1767 sq
->status
= serviced_query_UDP_EDNS_fallback
;
1769 if(!serviced_udp_send(sq
, c
->buffer
)) {
1770 serviced_callbacks(sq
, NETEVENT_CLOSED
, c
, rep
);
1773 } else if(sq
->status
== serviced_query_PROBE_EDNS
) {
1774 /* probe without EDNS succeeds, so we conclude that this
1775 * host likely has EDNS packets dropped */
1776 log_addr(VERB_DETAIL
, "timeouts, concluded that connection to "
1777 "host drops EDNS packets", &sq
->addr
, sq
->addrlen
);
1778 /* only store noEDNS in cache if domain is noDNSSEC */
1779 if(!sq
->want_dnssec
)
1780 if(!infra_edns_update(outnet
->infra
, &sq
->addr
, sq
->addrlen
,
1781 sq
->zone
, sq
->zonelen
, -1, (time_t)now
.tv_sec
)) {
1782 log_err("Out of memory caching no edns for host");
1784 sq
->status
= serviced_query_UDP
;
1785 } else if(sq
->status
== serviced_query_UDP_EDNS
&&
1786 !sq
->edns_lame_known
) {
1787 /* now we know that edns queries received answers store that */
1788 log_addr(VERB_ALGO
, "serviced query: EDNS works for",
1789 &sq
->addr
, sq
->addrlen
);
1790 if(!infra_edns_update(outnet
->infra
, &sq
->addr
, sq
->addrlen
,
1791 sq
->zone
, sq
->zonelen
, 0, (time_t)now
.tv_sec
)) {
1792 log_err("Out of memory caching edns works");
1794 sq
->edns_lame_known
= 1;
1795 } else if(sq
->status
== serviced_query_UDP_EDNS_fallback
&&
1796 !sq
->edns_lame_known
&& (LDNS_RCODE_WIRE(
1797 sldns_buffer_begin(c
->buffer
)) == LDNS_RCODE_NOERROR
||
1798 LDNS_RCODE_WIRE(sldns_buffer_begin(c
->buffer
)) ==
1799 LDNS_RCODE_NXDOMAIN
|| LDNS_RCODE_WIRE(sldns_buffer_begin(
1800 c
->buffer
)) == LDNS_RCODE_YXDOMAIN
)) {
1801 /* the fallback produced a result that looks promising, note
1802 * that this server should be approached without EDNS */
1803 /* only store noEDNS in cache if domain is noDNSSEC */
1804 if(!sq
->want_dnssec
) {
1805 log_addr(VERB_ALGO
, "serviced query: EDNS fails for",
1806 &sq
->addr
, sq
->addrlen
);
1807 if(!infra_edns_update(outnet
->infra
, &sq
->addr
, sq
->addrlen
,
1808 sq
->zone
, sq
->zonelen
, -1, (time_t)now
.tv_sec
)) {
1809 log_err("Out of memory caching no edns for host");
1812 log_addr(VERB_ALGO
, "serviced query: EDNS fails, but "
1813 "not stored because need DNSSEC for", &sq
->addr
,
1816 sq
->status
= serviced_query_UDP
;
1818 if(now
.tv_sec
> sq
->last_sent_time
.tv_sec
||
1819 (now
.tv_sec
== sq
->last_sent_time
.tv_sec
&&
1820 now
.tv_usec
> sq
->last_sent_time
.tv_usec
)) {
1821 /* convert from microseconds to milliseconds */
1822 int roundtime
= ((int)(now
.tv_sec
- sq
->last_sent_time
.tv_sec
))*1000
1823 + ((int)now
.tv_usec
- (int)sq
->last_sent_time
.tv_usec
)/1000;
1824 verbose(VERB_ALGO
, "measured roundtrip at %d msec", roundtime
);
1825 log_assert(roundtime
>= 0);
1826 /* in case the system hibernated, do not enter a huge value,
1827 * above this value gives trouble with server selection */
1828 if(roundtime
< 60000) {
1829 if(!infra_rtt_update(outnet
->infra
, &sq
->addr
, sq
->addrlen
,
1830 sq
->zone
, sq
->zonelen
, sq
->qtype
, roundtime
,
1831 sq
->last_rtt
, (time_t)now
.tv_sec
))
1832 log_err("out of memory noting rtt.");
1835 } /* end of if_!fallback_tcp */
1836 /* perform TC flag check and TCP fallback after updating our
1837 * cache entries for EDNS status and RTT times */
1838 if(LDNS_TC_WIRE(sldns_buffer_begin(c
->buffer
)) || fallback_tcp
) {
1839 /* fallback to TCP */
1840 /* this discards partial UDP contents */
1841 if(sq
->status
== serviced_query_UDP_EDNS
||
1842 sq
->status
== serviced_query_UDP_EDNS_FRAG
||
1843 sq
->status
== serviced_query_UDP_EDNS_fallback
)
1844 /* if we have unfinished EDNS_fallback, start again */
1845 sq
->status
= serviced_query_TCP_EDNS
;
1846 else sq
->status
= serviced_query_TCP
;
1847 serviced_tcp_initiate(sq
, c
->buffer
);
1850 /* yay! an answer */
1851 serviced_callbacks(sq
, error
, c
, rep
);
1855 struct serviced_query
*
1856 outnet_serviced_query(struct outside_network
* outnet
,
1857 uint8_t* qname
, size_t qnamelen
, uint16_t qtype
, uint16_t qclass
,
1858 uint16_t flags
, int dnssec
, int want_dnssec
, int nocaps
,
1859 int tcp_upstream
, int ssl_upstream
, struct sockaddr_storage
* addr
,
1860 socklen_t addrlen
, uint8_t* zone
, size_t zonelen
,
1861 comm_point_callback_t
* callback
, void* callback_arg
,
1864 struct serviced_query
* sq
;
1865 struct service_callback
* cb
;
1866 serviced_gen_query(buff
, qname
, qnamelen
, qtype
, qclass
, flags
);
1867 sq
= lookup_serviced(outnet
, buff
, dnssec
, addr
, addrlen
);
1868 /* duplicate entries are included in the callback list, because
1869 * there is a counterpart registration by our caller that needs to
1870 * be doubly-removed (with callbacks perhaps). */
1871 if(!(cb
= (struct service_callback
*)malloc(sizeof(*cb
))))
1874 /* make new serviced query entry */
1875 sq
= serviced_create(outnet
, buff
, dnssec
, want_dnssec
, nocaps
,
1876 tcp_upstream
, ssl_upstream
, addr
, addrlen
, zone
,
1877 zonelen
, (int)qtype
);
1882 /* perform first network action */
1883 if(outnet
->do_udp
&& !(tcp_upstream
|| ssl_upstream
)) {
1884 if(!serviced_udp_send(sq
, buff
)) {
1885 (void)rbtree_delete(outnet
->serviced
, sq
);
1893 if(!serviced_tcp_send(sq
, buff
)) {
1894 (void)rbtree_delete(outnet
->serviced
, sq
);
1903 /* add callback to list of callbacks */
1905 cb
->cb_arg
= callback_arg
;
1906 cb
->next
= sq
->cblist
;
1911 /** remove callback from list */
1913 callback_list_remove(struct serviced_query
* sq
, void* cb_arg
)
1915 struct service_callback
** pp
= &sq
->cblist
;
1917 if((*pp
)->cb_arg
== cb_arg
) {
1918 struct service_callback
* del
= *pp
;
1927 void outnet_serviced_query_stop(struct serviced_query
* sq
, void* cb_arg
)
1931 callback_list_remove(sq
, cb_arg
);
1932 /* if callbacks() routine scheduled deletion, let it do that */
1933 if(!sq
->cblist
&& !sq
->to_be_deleted
) {
1934 #ifdef UNBOUND_DEBUG
1939 rbtree_delete(sq
->outnet
->serviced
, sq
);
1940 log_assert(rem
); /* should be present */
1941 serviced_delete(sq
);
1945 /** get memory used by waiting tcp entry (in use or not) */
1947 waiting_tcp_get_mem(struct waiting_tcp
* w
)
1951 s
= sizeof(*w
) + w
->pkt_len
;
1953 s
+= comm_timer_get_mem(w
->timer
);
1957 /** get memory used by port if */
1959 if_get_mem(struct port_if
* pif
)
1963 s
= sizeof(*pif
) + sizeof(int)*pif
->avail_total
+
1964 sizeof(struct port_comm
*)*pif
->maxout
;
1965 for(i
=0; i
<pif
->inuse
; i
++)
1966 s
+= sizeof(*pif
->out
[i
]) +
1967 comm_point_get_mem(pif
->out
[i
]->cp
);
1971 /** get memory used by waiting udp */
1973 waiting_udp_get_mem(struct pending
* w
)
1976 s
= sizeof(*w
) + comm_timer_get_mem(w
->timer
) + w
->pkt_len
;
1980 size_t outnet_get_mem(struct outside_network
* outnet
)
1984 struct waiting_tcp
* w
;
1986 struct serviced_query
* sq
;
1987 struct service_callback
* sb
;
1988 struct port_comm
* pc
;
1989 size_t s
= sizeof(*outnet
) + sizeof(*outnet
->base
) +
1990 sizeof(*outnet
->udp_buff
) +
1991 sldns_buffer_capacity(outnet
->udp_buff
);
1992 /* second buffer is not ours */
1993 for(pc
= outnet
->unused_fds
; pc
; pc
= pc
->next
) {
1994 s
+= sizeof(*pc
) + comm_point_get_mem(pc
->cp
);
1996 for(k
=0; k
<outnet
->num_ip4
; k
++)
1997 s
+= if_get_mem(&outnet
->ip4_ifs
[k
]);
1998 for(k
=0; k
<outnet
->num_ip6
; k
++)
1999 s
+= if_get_mem(&outnet
->ip6_ifs
[k
]);
2000 for(u
=outnet
->udp_wait_first
; u
; u
=u
->next_waiting
)
2001 s
+= waiting_udp_get_mem(u
);
2003 s
+= sizeof(struct pending_tcp
*)*outnet
->num_tcp
;
2004 for(i
=0; i
<outnet
->num_tcp
; i
++) {
2005 s
+= sizeof(struct pending_tcp
);
2006 s
+= comm_point_get_mem(outnet
->tcp_conns
[i
]->c
);
2007 if(outnet
->tcp_conns
[i
]->query
)
2008 s
+= waiting_tcp_get_mem(outnet
->tcp_conns
[i
]->query
);
2010 for(w
=outnet
->tcp_wait_first
; w
; w
= w
->next_waiting
)
2011 s
+= waiting_tcp_get_mem(w
);
2012 s
+= sizeof(*outnet
->pending
);
2013 s
+= (sizeof(struct pending
) + comm_timer_get_mem(NULL
)) *
2014 outnet
->pending
->count
;
2015 s
+= sizeof(*outnet
->serviced
);
2016 s
+= outnet
->svcd_overhead
;
2017 RBTREE_FOR(sq
, struct serviced_query
*, outnet
->serviced
) {
2018 s
+= sizeof(*sq
) + sq
->qbuflen
;
2019 for(sb
= sq
->cblist
; sb
; sb
= sb
->next
)
2026 serviced_get_mem(struct serviced_query
* sq
)
2028 struct service_callback
* sb
;
2030 s
= sizeof(*sq
) + sq
->qbuflen
;
2031 for(sb
= sq
->cblist
; sb
; sb
= sb
->next
)
2033 if(sq
->status
== serviced_query_UDP_EDNS
||
2034 sq
->status
== serviced_query_UDP
||
2035 sq
->status
== serviced_query_PROBE_EDNS
||
2036 sq
->status
== serviced_query_UDP_EDNS_FRAG
||
2037 sq
->status
== serviced_query_UDP_EDNS_fallback
) {
2038 s
+= sizeof(struct pending
);
2039 s
+= comm_timer_get_mem(NULL
);
2041 /* does not have size of the pkt pointer */
2042 /* always has a timer except on malloc failures */
2044 /* these sizes are part of the main outside network mem */
2046 s += sizeof(struct waiting_tcp);
2047 s += comm_timer_get_mem(NULL);