mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
outside_network start.
git-svn-id: file:///svn/unbound/trunk@48 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
b48cc913ff
commit
57aef52d48
10 changed files with 519 additions and 13 deletions
|
|
@ -300,6 +300,8 @@ AH_BOTTOM([
|
||||||
|
|
||||||
#include "ldns/ldns.h"
|
#include "ldns/ldns.h"
|
||||||
|
|
||||||
|
/** default port to listen for queries, passed to getaddrinfo */
|
||||||
|
#define UNBOUND_DNS_PORT "53"
|
||||||
])
|
])
|
||||||
|
|
||||||
AC_CONFIG_FILES([Makefile])
|
AC_CONFIG_FILES([Makefile])
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,6 @@
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
#include "daemon/worker.h"
|
#include "daemon/worker.h"
|
||||||
|
|
||||||
/** default port to listen for queries, passed to getaddrinfo */
|
|
||||||
#define UNBOUND_DNS_PORT "53"
|
|
||||||
/** buffer size for network connections */
|
/** buffer size for network connections */
|
||||||
#define BUFSZ 65552
|
#define BUFSZ 65552
|
||||||
|
|
||||||
|
|
@ -77,8 +75,12 @@ main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
struct worker* worker = NULL;
|
struct worker* worker = NULL;
|
||||||
int do_ip4=1, do_ip6=1, do_udp=1, do_tcp=1;
|
int do_ip4=1, do_ip6=1, do_udp=1, do_tcp=1;
|
||||||
|
size_t numports=3;
|
||||||
|
int baseport=10000;
|
||||||
const char* port = UNBOUND_DNS_PORT;
|
const char* port = UNBOUND_DNS_PORT;
|
||||||
int c;
|
int c;
|
||||||
|
const char* fwd = "127.0.0.1";
|
||||||
|
const char* fwdport = UNBOUND_DNS_PORT;
|
||||||
|
|
||||||
log_init();
|
log_init();
|
||||||
/* parse the options */
|
/* parse the options */
|
||||||
|
|
@ -88,6 +90,7 @@ main(int argc, char* argv[])
|
||||||
if(!atoi(optarg))
|
if(!atoi(optarg))
|
||||||
fatal_exit("invalid port '%s'", optarg);
|
fatal_exit("invalid port '%s'", optarg);
|
||||||
port = optarg;
|
port = optarg;
|
||||||
|
baseport = atoi(optarg)+2000;
|
||||||
verbose(VERB_ALGO, "using port: %s", port);
|
verbose(VERB_ALGO, "using port: %s", port);
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
|
|
@ -109,10 +112,14 @@ main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
/* setup */
|
/* setup */
|
||||||
worker = worker_init(port, do_ip4, do_ip6, do_udp, do_tcp, BUFSZ);
|
worker = worker_init(port, do_ip4, do_ip6, do_udp, do_tcp, BUFSZ,
|
||||||
|
numports, baseport);
|
||||||
if(!worker) {
|
if(!worker) {
|
||||||
fatal_exit("could not initialize");
|
fatal_exit("could not initialize");
|
||||||
}
|
}
|
||||||
|
if(!worker_set_fwd(worker, fwd, fwdport)) {
|
||||||
|
fatal_exit("could set forwarder address");
|
||||||
|
}
|
||||||
|
|
||||||
/* drop user priviliges and chroot if needed */
|
/* drop user priviliges and chroot if needed */
|
||||||
log_info("Start of %s.", PACKAGE_STRING);
|
log_info("Start of %s.", PACKAGE_STRING);
|
||||||
|
|
|
||||||
|
|
@ -44,12 +44,23 @@
|
||||||
#include "daemon/worker.h"
|
#include "daemon/worker.h"
|
||||||
#include "util/netevent.h"
|
#include "util/netevent.h"
|
||||||
#include "services/listen_dnsport.h"
|
#include "services/listen_dnsport.h"
|
||||||
|
#include "services/outside_network.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_TYPES_H
|
||||||
|
# include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/** timeout in seconds for UDP queries to auth servers. TODO: proper rtt */
|
||||||
|
#define UDP_QUERY_TIMEOUT 5
|
||||||
|
|
||||||
/** process incoming request */
|
/** process incoming request */
|
||||||
static void worker_process_query(struct worker* worker)
|
static void worker_process_query(struct worker* worker)
|
||||||
{
|
{
|
||||||
/* query the forwarding address */
|
/* query the forwarding address */
|
||||||
|
pending_udp_query(worker->back, worker->query_reply.c->buffer,
|
||||||
|
&worker->fwd_addr, worker->fwd_addrlen, UDP_QUERY_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** check request sanity. Returns error code, 0 OK, or -1 discard.
|
/** check request sanity. Returns error code, 0 OK, or -1 discard.
|
||||||
|
|
@ -124,7 +135,8 @@ static int worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct worker* worker_init(const char* port, int do_ip4, int do_ip6,
|
struct worker* worker_init(const char* port, int do_ip4, int do_ip6,
|
||||||
int do_udp, int do_tcp, size_t buffer_size)
|
int do_udp, int do_tcp, size_t buffer_size, size_t numports,
|
||||||
|
int base_port)
|
||||||
{
|
{
|
||||||
struct worker* worker = (struct worker*)calloc(1,
|
struct worker* worker = (struct worker*)calloc(1,
|
||||||
sizeof(struct worker));
|
sizeof(struct worker));
|
||||||
|
|
@ -143,10 +155,22 @@ struct worker* worker_init(const char* port, int do_ip4, int do_ip6,
|
||||||
log_err("could not create listening sockets");
|
log_err("could not create listening sockets");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
worker->back = outside_network_create(worker->base,
|
||||||
|
buffer_size, numports, NULL, 0, do_ip4, do_ip6, base_port);
|
||||||
|
if(!worker->back) {
|
||||||
|
comm_base_delete(worker->base);
|
||||||
|
log_err("could not create outgoing sockets");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* init random(), large table size. */
|
||||||
|
if(!initstate(time(NULL)^getpid(), worker->rndstate, RND_STATE_SIZE)) {
|
||||||
|
log_err("could not init random numbers.");
|
||||||
|
comm_base_delete(worker->base);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return worker;
|
return worker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void worker_work(struct worker* worker)
|
void worker_work(struct worker* worker)
|
||||||
{
|
{
|
||||||
comm_base_dispatch(worker->base);
|
comm_base_dispatch(worker->base);
|
||||||
|
|
@ -157,6 +181,26 @@ void worker_delete(struct worker* worker)
|
||||||
if(!worker)
|
if(!worker)
|
||||||
return;
|
return;
|
||||||
listen_delete(worker->front);
|
listen_delete(worker->front);
|
||||||
|
outside_network_delete(worker->back);
|
||||||
comm_base_delete(worker->base);
|
comm_base_delete(worker->base);
|
||||||
free(worker);
|
free(worker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int worker_set_fwd(struct worker* worker, const char* ip, const char* port)
|
||||||
|
{
|
||||||
|
struct addrinfo *res = NULL;
|
||||||
|
int r;
|
||||||
|
log_assert(worker && ip);
|
||||||
|
if(!port)
|
||||||
|
port = UNBOUND_DNS_PORT;
|
||||||
|
if((r=getaddrinfo(ip, port, NULL, &res)) != 0 || !res) {
|
||||||
|
log_err("failed %s:%s getaddrinfo: %s %s",
|
||||||
|
ip, port,
|
||||||
|
gai_strerror(r), r==EAI_SYSTEM?strerror(errno):"");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
worker->fwd_addrlen = res->ai_addrlen;
|
||||||
|
memcpy(&worker->fwd_addr, &res->ai_addr, res->ai_addrlen);
|
||||||
|
freeaddrinfo(res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,10 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "util/netevent.h"
|
#include "util/netevent.h"
|
||||||
struct listen_dnsport;
|
struct listen_dnsport;
|
||||||
|
struct outside_network;
|
||||||
|
|
||||||
|
/** size of table used for random numbers. large to be more secure. */
|
||||||
|
#define RND_STATE_SIZE 256
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Structure holding working information for unbound.
|
* Structure holding working information for unbound.
|
||||||
|
|
@ -58,11 +62,23 @@ struct worker {
|
||||||
/** the frontside listening interface where request events come in */
|
/** the frontside listening interface where request events come in */
|
||||||
struct listen_dnsport* front;
|
struct listen_dnsport* front;
|
||||||
|
|
||||||
|
/** the backside outside network interface to the auth servers */
|
||||||
|
struct outside_network* back;
|
||||||
|
|
||||||
/** our one and only query, packet buffer and where to send. */
|
/** our one and only query, packet buffer and where to send. */
|
||||||
struct comm_reply query_reply;
|
struct comm_reply query_reply;
|
||||||
|
|
||||||
/** number of requests currently active */
|
/** number of requests currently active */
|
||||||
int num_requests;
|
int num_requests;
|
||||||
|
|
||||||
|
/** random() table for this worker. */
|
||||||
|
char rndstate[RND_STATE_SIZE];
|
||||||
|
|
||||||
|
/** address to forward to */
|
||||||
|
struct sockaddr_storage fwd_addr;
|
||||||
|
|
||||||
|
/** length of fwd_addr */
|
||||||
|
socklen_t fwd_addrlen;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -74,10 +90,13 @@ struct worker {
|
||||||
* @param do_udp: listen to udp queries.
|
* @param do_udp: listen to udp queries.
|
||||||
* @param do_tcp: listen to tcp queries.
|
* @param do_tcp: listen to tcp queries.
|
||||||
* @param buffer_size: size of datagram buffer.
|
* @param buffer_size: size of datagram buffer.
|
||||||
|
* @param numports: number of outgoing ports.
|
||||||
|
* @param base_port: -1 or specify base of outgoing port range.
|
||||||
* @return: The worker, or NULL on error.
|
* @return: The worker, or NULL on error.
|
||||||
*/
|
*/
|
||||||
struct worker* worker_init(const char* port, int do_ip4, int do_ip6,
|
struct worker* worker_init(const char* port, int do_ip4, int do_ip6,
|
||||||
int do_udp, int do_tcp, size_t buffer_size);
|
int do_udp, int do_tcp, size_t buffer_size, size_t numports,
|
||||||
|
int base_port);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make worker work.
|
* Make worker work.
|
||||||
|
|
@ -89,4 +108,13 @@ void worker_work(struct worker* worker);
|
||||||
*/
|
*/
|
||||||
void worker_delete(struct worker* worker);
|
void worker_delete(struct worker* worker);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set forwarder
|
||||||
|
* @param worker: the worker to modify.
|
||||||
|
* @param ip: the server name.
|
||||||
|
* @param port: port on server or NULL for default 53.
|
||||||
|
* @return: false on error.
|
||||||
|
*/
|
||||||
|
int worker_set_fwd(struct worker* worker, const char* ip, const char* port);
|
||||||
|
|
||||||
#endif /* DAEMON_WORKER_H */
|
#endif /* DAEMON_WORKER_H */
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
- netevent communication reply storage structure.
|
- netevent communication reply storage structure.
|
||||||
- minimal query header sanity checking for worker.
|
- minimal query header sanity checking for worker.
|
||||||
- copied over rbtree implementation from NSD (BSD licensed too).
|
- copied over rbtree implementation from NSD (BSD licensed too).
|
||||||
|
- outgoing network query service work.
|
||||||
|
|
||||||
30 January 2007: Wouter
|
30 January 2007: Wouter
|
||||||
- links in example/ldns-testpkts.c and .h for premade packet support.
|
- links in example/ldns-testpkts.c and .h for premade packet support.
|
||||||
|
|
|
||||||
|
|
@ -79,12 +79,7 @@ verbose_print_addr(struct addrinfo *addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
int
|
||||||
* Create and bind UDP socket
|
|
||||||
* @param addr: address info ready to make socket.
|
|
||||||
* @return: the socket. -1 on error.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
create_udp_sock(struct addrinfo *addr)
|
create_udp_sock(struct addrinfo *addr)
|
||||||
{
|
{
|
||||||
int s, flag;
|
int s, flag;
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "util/netevent.h"
|
#include "util/netevent.h"
|
||||||
struct listen_list;
|
struct listen_list;
|
||||||
|
struct addrinfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listening for queries structure.
|
* Listening for queries structure.
|
||||||
|
|
@ -101,4 +102,13 @@ struct listen_dnsport* listen_create(struct comm_base* base,
|
||||||
*/
|
*/
|
||||||
void listen_delete(struct listen_dnsport* listen);
|
void listen_delete(struct listen_dnsport* listen);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and bind nonblocking UDP socket
|
||||||
|
* @param addr: address info ready to make socket.
|
||||||
|
* @return: the socket. -1 on error.
|
||||||
|
*/
|
||||||
|
int create_udp_sock(struct addrinfo *addr);
|
||||||
|
|
||||||
|
|
||||||
#endif /* LISTEN_DNSPORT_H */
|
#endif /* LISTEN_DNSPORT_H */
|
||||||
|
|
|
||||||
267
services/outside_network.c
Normal file
267
services/outside_network.c
Normal file
|
|
@ -0,0 +1,267 @@
|
||||||
|
/*
|
||||||
|
* services/outside_network.c - implement sending of queries and wait answer.
|
||||||
|
*
|
||||||
|
* 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 REGENTS 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 events.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "services/outside_network.h"
|
||||||
|
#include "services/listen_dnsport.h"
|
||||||
|
#include "util/netevent.h"
|
||||||
|
#include "util/log.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_TYPES_H
|
||||||
|
# include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
/** compare function of pending rbtree */
|
||||||
|
static int pending_cmp(const void* key1, const void* key2)
|
||||||
|
{
|
||||||
|
struct pending *p1 = (struct pending*)key1;
|
||||||
|
struct pending *p2 = (struct pending*)key2;
|
||||||
|
if(p1->id < p2->id)
|
||||||
|
return -1;
|
||||||
|
if(p1->id > p2->id)
|
||||||
|
return 1;
|
||||||
|
log_assert(p1->id == p2->id);
|
||||||
|
if(p1->addrlen < p2->addrlen)
|
||||||
|
return -1;
|
||||||
|
if(p1->addrlen > p2->addrlen)
|
||||||
|
return 1;
|
||||||
|
log_assert(p1->addrlen == p2->addrlen);
|
||||||
|
return memcmp(&p1->addr, &p2->addr, p1->addrlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** compare function of pending_timeout rbtree */
|
||||||
|
static int pending_timeout_cmp(const void* key1, const void* key2)
|
||||||
|
{
|
||||||
|
struct pending_timeout *p1 = (struct pending_timeout*)key1;
|
||||||
|
struct pending_timeout *p2 = (struct pending_timeout*)key2;
|
||||||
|
if(p1->timeout.tv_sec < p2->timeout.tv_sec)
|
||||||
|
return -1;
|
||||||
|
if(p1->timeout.tv_sec > p2->timeout.tv_sec)
|
||||||
|
return 1;
|
||||||
|
log_assert(p1->timeout.tv_sec == p2->timeout.tv_sec);
|
||||||
|
if(p1->timeout.tv_usec < p2->timeout.tv_usec)
|
||||||
|
return -1;
|
||||||
|
if(p1->timeout.tv_usec > p2->timeout.tv_usec)
|
||||||
|
return 1;
|
||||||
|
log_assert(p1->timeout.tv_usec == p2->timeout.tv_usec);
|
||||||
|
if(p1 < p2)
|
||||||
|
return -1;
|
||||||
|
if(p1 > p2)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** callback for incoming udp answers from the network. */
|
||||||
|
static int outnet_udp_cb(struct comm_point* c, void* my_arg, int error,
|
||||||
|
struct comm_reply *reply_info)
|
||||||
|
{
|
||||||
|
log_info("answer cb");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** open another udp port to listen to, every thread has its own range
|
||||||
|
* of open ports.
|
||||||
|
* @param ifname: on which interface to open the port.
|
||||||
|
* @param hints: hints on family and passiveness preset.
|
||||||
|
* @param porthint: if not -1, it gives the port to base range on.
|
||||||
|
* @return: file descriptor
|
||||||
|
*/
|
||||||
|
static int open_udp_port_range(const char* ifname, struct addrinfo* hints,
|
||||||
|
int porthint)
|
||||||
|
{
|
||||||
|
struct addrinfo *res = NULL;
|
||||||
|
int r, s;
|
||||||
|
char portstr[20];
|
||||||
|
if(porthint != -1)
|
||||||
|
snprintf(portstr, sizeof(portstr), "%d", porthint);
|
||||||
|
|
||||||
|
if((r=getaddrinfo(ifname, ((porthint==-1)?NULL:portstr), hints,
|
||||||
|
&res)) != 0 || !res) {
|
||||||
|
log_err("node %s:%s getaddrinfo: %s %s",
|
||||||
|
ifname?ifname:"default", (porthint!=-1)?portstr:"eph",
|
||||||
|
gai_strerror(r), r==EAI_SYSTEM?strerror(errno):"");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
s = create_udp_sock(res);
|
||||||
|
freeaddrinfo(res);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create range of UDP ports on the given interface.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
make_udp_range(struct outside_network* outnet, const char* ifname,
|
||||||
|
size_t num_ports, size_t off, int do_ip4, int do_ip6, int porthint)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
struct addrinfo hints;
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_flags = AI_PASSIVE;
|
||||||
|
if(ifname)
|
||||||
|
hints.ai_flags |= AI_NUMERICHOST;
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
if(do_ip4 && do_ip6)
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
else if(do_ip4)
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
else if(do_ip6)
|
||||||
|
hints.ai_family = AF_INET6;
|
||||||
|
hints.ai_socktype = SOCK_DGRAM;
|
||||||
|
for(i=0; i<num_ports; i++) {
|
||||||
|
int fd = open_udp_port_range(ifname, &hints, porthint);
|
||||||
|
if(fd == -1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(porthint != -1)
|
||||||
|
porthint++;
|
||||||
|
outnet->udp_ports[i+off] = comm_point_create_udp(
|
||||||
|
outnet->base, fd, outnet->udp_buff, outnet_udp_cb,
|
||||||
|
outnet);
|
||||||
|
if(!outnet->udp_ports[i+off]) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct outside_network*
|
||||||
|
outside_network_create(struct comm_base *base, size_t bufsize,
|
||||||
|
size_t num_ports, const char** ifs, int num_ifs, int do_ip4,
|
||||||
|
int do_ip6, int port_base)
|
||||||
|
{
|
||||||
|
struct outside_network* outnet = (struct outside_network*)
|
||||||
|
calloc(1, sizeof(struct outside_network));
|
||||||
|
int k;
|
||||||
|
if(!outnet) {
|
||||||
|
log_err("malloc failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
outnet->base = base;
|
||||||
|
outnet->num_udp = (num_ifs?num_ports * num_ifs:num_ports);
|
||||||
|
if( !(outnet->udp_buff = ldns_buffer_new(bufsize)) ||
|
||||||
|
!(outnet->udp_ports = (struct comm_point **)calloc(
|
||||||
|
outnet->num_udp, sizeof(struct comm_point*))) ||
|
||||||
|
!(outnet->pending = rbtree_create(pending_cmp)) ||
|
||||||
|
!(outnet->pending_timeout = rbtree_create(
|
||||||
|
pending_timeout_cmp))) {
|
||||||
|
log_err("malloc failed");
|
||||||
|
outside_network_delete(outnet);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(num_ifs == 0) {
|
||||||
|
if(!make_udp_range(outnet, NULL, num_ports, 0, do_ip4,
|
||||||
|
do_ip6, port_base)) {
|
||||||
|
outside_network_delete(outnet);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else for(k=0; k<num_ifs; k++) {
|
||||||
|
if(!make_udp_range(outnet, ifs[k], num_ports, k*num_ports,
|
||||||
|
do_ip4, do_ip6, port_base)) {
|
||||||
|
outside_network_delete(outnet);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return outnet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void outside_network_delete(struct outside_network* outnet)
|
||||||
|
{
|
||||||
|
if(!outnet)
|
||||||
|
return;
|
||||||
|
/* check every element, since we can be called on malloc error */
|
||||||
|
if(outnet->pending) {
|
||||||
|
struct pending *p, *np;
|
||||||
|
p = (struct pending*)rbtree_first(outnet->pending);
|
||||||
|
while(p) {
|
||||||
|
np = (struct pending*)rbtree_next((rbnode_t*)p);
|
||||||
|
pending_delete(NULL, p);
|
||||||
|
p = np;
|
||||||
|
}
|
||||||
|
free(outnet->pending);
|
||||||
|
}
|
||||||
|
if(outnet->pending_timeout) {
|
||||||
|
log_assert(outnet->pending_timeout->count == 0);
|
||||||
|
free(outnet->pending_timeout);
|
||||||
|
}
|
||||||
|
if(outnet->udp_buff)
|
||||||
|
ldns_buffer_free(outnet->udp_buff);
|
||||||
|
if(outnet->udp_ports) {
|
||||||
|
size_t i;
|
||||||
|
for(i=0; i<outnet->num_udp; i++) {
|
||||||
|
if(outnet->udp_ports[i])
|
||||||
|
comm_point_delete(outnet->udp_ports[i]);
|
||||||
|
}
|
||||||
|
free(outnet->udp_ports);
|
||||||
|
}
|
||||||
|
free(outnet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pending_delete(struct outside_network* outnet, struct pending* p)
|
||||||
|
{
|
||||||
|
if(!p)
|
||||||
|
return;
|
||||||
|
if(outnet) {
|
||||||
|
(void)rbtree_delete(outnet->pending, p->node.key);
|
||||||
|
(void)rbtree_delete(outnet->pending_timeout,
|
||||||
|
p->timeout->node.key);
|
||||||
|
}
|
||||||
|
free(p->timeout);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pending_udp_query(struct outside_network* outnet, ldns_buffer* packet,
|
||||||
|
struct sockaddr_storage* addr, socklen_t addrlen, int timeout)
|
||||||
|
{
|
||||||
|
/* choose a random outgoing port and interface */
|
||||||
|
/* uses lousy random() function. TODO: entropy source. */
|
||||||
|
double precho = (double)random() * (double)outnet->num_udp /
|
||||||
|
((double)RAND_MAX + 1.0);
|
||||||
|
int chosen = (int)precho;
|
||||||
|
/* don't trust in perfect double rounding */
|
||||||
|
if(chosen < 0) chosen = 0;
|
||||||
|
if(chosen >= (int)outnet->num_udp) chosen = (int)outnet->num_udp-1;
|
||||||
|
}
|
||||||
151
services/outside_network.h
Normal file
151
services/outside_network.h
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* 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 REGENTS 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 "config.h"
|
||||||
|
#include "util/rbtree.h"
|
||||||
|
struct pending;
|
||||||
|
struct pending_timeout;
|
||||||
|
struct comm_point;
|
||||||
|
struct comm_base;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/** buffer shared by UDP connections, since there is only one
|
||||||
|
datagram at any time. */
|
||||||
|
ldns_buffer* udp_buff;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of udp comm point* that are used to listen to pending events.
|
||||||
|
* Each is on a different port.
|
||||||
|
*/
|
||||||
|
struct comm_point **udp_ports;
|
||||||
|
/** number of udp ports */
|
||||||
|
size_t num_udp;
|
||||||
|
|
||||||
|
/** pending answers. sorted by id, addr */
|
||||||
|
rbtree_t *pending;
|
||||||
|
/** Each pending answer has a timeout, sorted by timeout. */
|
||||||
|
rbtree_t *pending_timeout;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 */
|
||||||
|
uint16_t 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 comm_point* c;
|
||||||
|
/** the timeout of the query */
|
||||||
|
struct pending_timeout *timeout;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timeout structure for pending queries
|
||||||
|
*/
|
||||||
|
struct pending_timeout {
|
||||||
|
/** entry in rbtree. key is timeout value, then pending ptr(uniq). */
|
||||||
|
rbnode_t node;
|
||||||
|
/** timeout, an absolute time value. */
|
||||||
|
struct timeval timeout;
|
||||||
|
/** pending query */
|
||||||
|
struct pending* 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).
|
||||||
|
* @param num_ifs: number of names in array ifs.
|
||||||
|
* @param do_ip4: service IP4.
|
||||||
|
* @param do_ip6: service IP6.
|
||||||
|
* @param port_base: if -1 system assigns ports, otherwise try to get
|
||||||
|
* the ports numbered from this starting number.
|
||||||
|
* @return: the new empty structure or NULL on error.
|
||||||
|
*/
|
||||||
|
struct outside_network* outside_network_create(struct comm_base *base,
|
||||||
|
size_t bufsize, size_t num_ports, const char** ifs, int num_ifs,
|
||||||
|
int do_ip4, int do_ip6, int port_base);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete outside_network structure.
|
||||||
|
* @param outnet: object to delete.
|
||||||
|
*/
|
||||||
|
void outside_network_delete(struct outside_network* outnet);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send UDP query, create pending answer.
|
||||||
|
* @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 seconds from now.
|
||||||
|
*/
|
||||||
|
void pending_udp_query(struct outside_network* outnet, ldns_buffer* packet,
|
||||||
|
struct sockaddr_storage* addr, socklen_t addrlen, int timeout);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete pending answer.
|
||||||
|
* @param outnet: outside network the pending query is part of.
|
||||||
|
* Used internal, if NULL, p is not unlinked from rbtree.
|
||||||
|
* @param p: deleted
|
||||||
|
*/
|
||||||
|
void pending_delete(struct outside_network* outnet, struct pending* p);
|
||||||
|
|
||||||
|
#endif /* OUTSIDE_NETWORK_H */
|
||||||
|
|
@ -37,6 +37,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* \file
|
||||||
* Red black tree. Implementation taken from NSD 3.0.5, adjusted for use
|
* Red black tree. Implementation taken from NSD 3.0.5, adjusted for use
|
||||||
* in unbound (memory allocation, logging and so on).
|
* in unbound (memory allocation, logging and so on).
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue