mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
udp4 and udp6.
git-svn-id: file:///svn/unbound/trunk@51 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
27efb224e4
commit
bedda58490
3 changed files with 171 additions and 59 deletions
|
|
@ -1,3 +1,7 @@
|
||||||
|
2 February 2007: Wouter
|
||||||
|
- Created udp4 and udp6 port arrays to provide service for both
|
||||||
|
address families.
|
||||||
|
|
||||||
1 February 2007: Wouter
|
1 February 2007: Wouter
|
||||||
- outside network more UDP work.
|
- outside network more UDP work.
|
||||||
- moved * closer to type.
|
- moved * closer to type.
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ static int open_udp_port_range(const char* ifname, struct addrinfo* hints,
|
||||||
|
|
||||||
if((r=getaddrinfo(ifname, ((porthint==-1)?NULL:portstr), hints,
|
if((r=getaddrinfo(ifname, ((porthint==-1)?NULL:portstr), hints,
|
||||||
&res)) != 0 || !res) {
|
&res)) != 0 || !res) {
|
||||||
log_err("node %s:%s getaddrinfo: %s %s",
|
log_err("node %s %s getaddrinfo: %s %s",
|
||||||
ifname?ifname:"default", (porthint!=-1)?portstr:"eph",
|
ifname?ifname:"default", (porthint!=-1)?portstr:"eph",
|
||||||
gai_strerror(r), r==EAI_SYSTEM?strerror(errno):"");
|
gai_strerror(r), r==EAI_SYSTEM?strerror(errno):"");
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -141,12 +141,15 @@ static int open_udp_port_range(const char* ifname, struct addrinfo* hints,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create range of UDP ports on the given interface.
|
* Create range of UDP ports on the given interface.
|
||||||
|
* Returns number of ports bound.
|
||||||
*/
|
*/
|
||||||
static int
|
static size_t
|
||||||
make_udp_range(struct outside_network* outnet, const char* ifname,
|
make_udp_range(struct comm_point** coms, const char* ifname,
|
||||||
size_t num_ports, size_t off, int do_ip4, int do_ip6, int porthint)
|
size_t num_ports, int do_ip4, int do_ip6, int porthint,
|
||||||
|
struct outside_network* outnet)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
size_t done = 0;
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
memset(&hints, 0, sizeof(hints));
|
memset(&hints, 0, sizeof(hints));
|
||||||
hints.ai_flags = AI_PASSIVE;
|
hints.ai_flags = AI_PASSIVE;
|
||||||
|
|
@ -162,25 +165,58 @@ make_udp_range(struct outside_network* outnet, const char* ifname,
|
||||||
hints.ai_socktype = SOCK_DGRAM;
|
hints.ai_socktype = SOCK_DGRAM;
|
||||||
for(i=0; i<num_ports; i++) {
|
for(i=0; i<num_ports; i++) {
|
||||||
int fd = open_udp_port_range(ifname, &hints, porthint);
|
int fd = open_udp_port_range(ifname, &hints, porthint);
|
||||||
if(fd == -1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(porthint != -1)
|
if(porthint != -1)
|
||||||
porthint++;
|
porthint++;
|
||||||
outnet->udp_ports[i+off] = comm_point_create_udp(
|
if(fd == -1)
|
||||||
outnet->base, fd, outnet->udp_buff, outnet_udp_cb,
|
continue;
|
||||||
outnet);
|
coms[done] = comm_point_create_udp(outnet->base, fd,
|
||||||
if(!outnet->udp_ports[i+off]) {
|
outnet->udp_buff, outnet_udp_cb, outnet);
|
||||||
return 0;
|
if(coms[done])
|
||||||
|
done++;
|
||||||
|
}
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** returns true is string addr is an ip6 specced address. */
|
||||||
|
static int str_is_ip6(const char* str)
|
||||||
|
{
|
||||||
|
if(strchr(str, ':'))
|
||||||
|
return 1;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** calculate number of ip4 and ip6 interfaces, times multiplier. */
|
||||||
|
static void calc_num46(const char** ifs, int num_ifs,
|
||||||
|
int do_ip4, int do_ip6, size_t multiplier,
|
||||||
|
size_t* num_ip4, size_t* num_ip6)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
*num_ip4 = 0;
|
||||||
|
*num_ip6 = 0;
|
||||||
|
if(num_ifs <= 0) {
|
||||||
|
if(do_ip4)
|
||||||
|
*num_ip4 = multiplier;
|
||||||
|
if(do_ip6)
|
||||||
|
*num_ip6 = multiplier;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for(i=0; i<num_ifs; i++)
|
||||||
|
{
|
||||||
|
if(str_is_ip6(ifs[i])) {
|
||||||
|
if(do_ip6)
|
||||||
|
*num_ip6 += multiplier;
|
||||||
|
} else {
|
||||||
|
if(do_ip4)
|
||||||
|
*num_ip4 += multiplier;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** callback for udp timeout */
|
/** callback for udp timeout */
|
||||||
static void pending_udp_timer_cb(void *arg)
|
static void pending_udp_timer_cb(void *arg)
|
||||||
{
|
{
|
||||||
struct pending* p = (struct pending*)arg;
|
/* struct pending* p = (struct pending*)arg; */
|
||||||
/* it timed out . TODO handle it. */
|
/* it timed out . TODO handle it. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -197,28 +233,56 @@ outside_network_create(struct comm_base *base, size_t bufsize,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
outnet->base = base;
|
outnet->base = base;
|
||||||
outnet->num_udp = (num_ifs?num_ports * num_ifs:num_ports);
|
calc_num46(ifs, num_ifs, do_ip4, do_ip6, num_ports,
|
||||||
|
&outnet->num_udp4, &outnet->num_udp6);
|
||||||
if( !(outnet->udp_buff = ldns_buffer_new(bufsize)) ||
|
if( !(outnet->udp_buff = ldns_buffer_new(bufsize)) ||
|
||||||
!(outnet->udp_ports = (struct comm_point **)calloc(
|
!(outnet->udp4_ports = (struct comm_point **)calloc(
|
||||||
outnet->num_udp, sizeof(struct comm_point*))) ||
|
outnet->num_udp4+1, sizeof(struct comm_point*))) ||
|
||||||
|
!(outnet->udp6_ports = (struct comm_point **)calloc(
|
||||||
|
outnet->num_udp6+1, sizeof(struct comm_point*))) ||
|
||||||
!(outnet->pending = rbtree_create(pending_cmp)) ) {
|
!(outnet->pending = rbtree_create(pending_cmp)) ) {
|
||||||
log_err("malloc failed");
|
log_err("malloc failed");
|
||||||
outside_network_delete(outnet);
|
outside_network_delete(outnet);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
/* open ip4 ports first, to get them apart from ip6 ports. */
|
||||||
if(num_ifs == 0) {
|
if(num_ifs == 0) {
|
||||||
if(!make_udp_range(outnet, NULL, num_ports, 0, do_ip4,
|
if(do_ip4) {
|
||||||
do_ip6, port_base)) {
|
outnet->num_udp4 = make_udp_range(outnet->udp4_ports,
|
||||||
|
NULL, num_ports, 1, 0, port_base, outnet);
|
||||||
|
}
|
||||||
|
if(do_ip6) {
|
||||||
|
outnet->num_udp6 = make_udp_range(outnet->udp6_ports,
|
||||||
|
NULL, num_ports, 0, 1, port_base, outnet);
|
||||||
|
}
|
||||||
|
if(outnet->num_udp4 != num_ports ||
|
||||||
|
outnet->num_udp6 != num_ports) {
|
||||||
|
log_err("Could not open all networkside ports");
|
||||||
outside_network_delete(outnet);
|
outside_network_delete(outnet);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else for(k=0; k<num_ifs; k++) {
|
else {
|
||||||
if(!make_udp_range(outnet, ifs[k], num_ports, k*num_ports,
|
size_t done_4 = 0, done_6 = 0;
|
||||||
do_ip4, do_ip6, port_base)) {
|
for(k=0; k<num_ifs; k++) {
|
||||||
|
if(!str_is_ip6(ifs[k]) && do_ip4) {
|
||||||
|
done_4 += make_udp_range(
|
||||||
|
outnet->udp4_ports+done_4, ifs[k],
|
||||||
|
num_ports, 1, 0, port_base, outnet);
|
||||||
|
}
|
||||||
|
if(str_is_ip6(ifs[k]) && do_ip6) {
|
||||||
|
done_6 += make_udp_range(
|
||||||
|
outnet->udp6_ports+done_6, ifs[k],
|
||||||
|
num_ports, 0, 1, port_base, outnet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(done_6 != outnet->num_udp6 || done_4 != outnet->num_udp4) {
|
||||||
|
log_err("Could not open all ports on all interfaces");
|
||||||
outside_network_delete(outnet);
|
outside_network_delete(outnet);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
outnet->num_udp6 = done_6;
|
||||||
|
outnet->num_udp4 = done_4;
|
||||||
}
|
}
|
||||||
return outnet;
|
return outnet;
|
||||||
}
|
}
|
||||||
|
|
@ -240,13 +304,17 @@ void outside_network_delete(struct outside_network* outnet)
|
||||||
}
|
}
|
||||||
if(outnet->udp_buff)
|
if(outnet->udp_buff)
|
||||||
ldns_buffer_free(outnet->udp_buff);
|
ldns_buffer_free(outnet->udp_buff);
|
||||||
if(outnet->udp_ports) {
|
if(outnet->udp4_ports) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for(i=0; i<outnet->num_udp; i++) {
|
for(i=0; i<outnet->num_udp4; i++)
|
||||||
if(outnet->udp_ports[i])
|
comm_point_delete(outnet->udp4_ports[i]);
|
||||||
comm_point_delete(outnet->udp_ports[i]);
|
free(outnet->udp4_ports);
|
||||||
}
|
}
|
||||||
free(outnet->udp_ports);
|
if(outnet->udp6_ports) {
|
||||||
|
size_t i;
|
||||||
|
for(i=0; i<outnet->num_udp6; i++)
|
||||||
|
comm_point_delete(outnet->udp6_ports[i]);
|
||||||
|
free(outnet->udp6_ports);
|
||||||
}
|
}
|
||||||
free(outnet);
|
free(outnet);
|
||||||
}
|
}
|
||||||
|
|
@ -266,12 +334,10 @@ void pending_delete(struct outside_network* outnet, struct pending* p)
|
||||||
/** create a new pending item with given characteristics, false on failure */
|
/** create a new pending item with given characteristics, false on failure */
|
||||||
static struct pending*
|
static struct pending*
|
||||||
new_pending(struct outside_network* outnet, ldns_buffer* packet,
|
new_pending(struct outside_network* outnet, ldns_buffer* packet,
|
||||||
struct sockaddr_storage* addr, socklen_t addrlen, int timeout,
|
struct sockaddr_storage* addr, socklen_t addrlen)
|
||||||
struct comm_point* c)
|
|
||||||
{
|
{
|
||||||
/* alloc */
|
/* alloc */
|
||||||
int id_tries = 0;
|
int id_tries = 0;
|
||||||
struct timeval tv;
|
|
||||||
struct pending* pend = (struct pending*)calloc(1,
|
struct pending* pend = (struct pending*)calloc(1,
|
||||||
sizeof(struct pending));
|
sizeof(struct pending));
|
||||||
if(!pend) {
|
if(!pend) {
|
||||||
|
|
@ -288,7 +354,6 @@ new_pending(struct outside_network* outnet, ldns_buffer* packet,
|
||||||
pend->id = LDNS_ID_WIRE(ldns_buffer_begin(packet));
|
pend->id = LDNS_ID_WIRE(ldns_buffer_begin(packet));
|
||||||
memcpy(&pend->addr, addr, addrlen);
|
memcpy(&pend->addr, addr, addrlen);
|
||||||
pend->addrlen = addrlen;
|
pend->addrlen = addrlen;
|
||||||
pend->c = c;
|
|
||||||
|
|
||||||
/* insert in tree */
|
/* insert in tree */
|
||||||
pend->node.key = pend;
|
pend->node.key = pend;
|
||||||
|
|
@ -303,45 +368,81 @@ new_pending(struct outside_network* outnet, ldns_buffer* packet,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tv.tv_sec = (int)time(NULL) + timeout;
|
|
||||||
tv.tv_usec = 0;
|
|
||||||
comm_timer_set(pend->timer, &tv);
|
|
||||||
return pend;
|
return pend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** return true if sockaddr is ip6 */
|
||||||
|
static int addr_is_ip6(struct sockaddr_storage* addr)
|
||||||
|
{
|
||||||
|
short family = *(short*)addr;
|
||||||
|
if(family == AF_INET6)
|
||||||
|
return 1;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** select outgoing comm point for a query. Fills in c. */
|
||||||
|
static void select_port(struct outside_network* outnet, struct pending* pend)
|
||||||
|
{
|
||||||
|
double precho;
|
||||||
|
int chosen, nummax;
|
||||||
|
|
||||||
|
log_assert(outnet && pend);
|
||||||
|
/* first select ip4 or ip6. */
|
||||||
|
if(addr_is_ip6(&pend->addr))
|
||||||
|
nummax = (int)outnet->num_udp6;
|
||||||
|
else nummax = (int)outnet->num_udp4;
|
||||||
|
|
||||||
|
if(nummax == 0) {
|
||||||
|
/* could try ip4to6 mapping if no ip4 ports available */
|
||||||
|
log_err("Need to send query but have no ports of that family");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* choose a random outgoing port and interface */
|
||||||
|
/* uses lousy random() function. TODO: entropy source. */
|
||||||
|
precho = (double)random() * (double)nummax /
|
||||||
|
((double)RAND_MAX + 1.0);
|
||||||
|
chosen = (int)precho;
|
||||||
|
|
||||||
|
/* don't trust in perfect double rounding */
|
||||||
|
if(chosen < 0) chosen = 0;
|
||||||
|
if(chosen >= nummax) chosen = nummax-1;
|
||||||
|
|
||||||
|
if(addr_is_ip6(&pend->addr))
|
||||||
|
pend->c = outnet->udp6_ports[chosen];
|
||||||
|
else pend->c = outnet->udp4_ports[chosen];
|
||||||
|
log_assert(pend->c);
|
||||||
|
|
||||||
|
log_info("chose query %x outbound %d of %d",
|
||||||
|
pend->id, chosen, nummax);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void pending_udp_query(struct outside_network* outnet, ldns_buffer* packet,
|
void pending_udp_query(struct outside_network* outnet, ldns_buffer* packet,
|
||||||
struct sockaddr_storage* addr, socklen_t addrlen, int timeout)
|
struct sockaddr_storage* addr, socklen_t addrlen, int timeout)
|
||||||
{
|
{
|
||||||
struct pending* pend;
|
struct pending* pend;
|
||||||
/* choose a random outgoing port and interface */
|
struct timeval tv;
|
||||||
/* uses lousy random() function. TODO: entropy source. */
|
|
||||||
double precho = (double)random() * (double)outnet->num_udp /
|
|
||||||
((double)RAND_MAX + 1.0);
|
|
||||||
int chosen = (int)precho;
|
|
||||||
struct comm_point *c;
|
|
||||||
log_assert(outnet && outnet->udp_ports);
|
|
||||||
/* don't trust in perfect double rounding */
|
|
||||||
if(chosen < 0) chosen = 0;
|
|
||||||
if(chosen >= (int)outnet->num_udp) chosen = (int)outnet->num_udp-1;
|
|
||||||
c = outnet->udp_ports[chosen];
|
|
||||||
log_assert(c);
|
|
||||||
|
|
||||||
/* create pending struct (and possibly change ID to be unique) */
|
/* create pending struct (and possibly change ID to be unique) */
|
||||||
if(!(pend=new_pending(outnet, packet, addr, addrlen, timeout, c))) {
|
if(!(pend=new_pending(outnet, packet, addr, addrlen))) {
|
||||||
(void)(*c->callback)(c, c->cb_arg, 1, NULL);
|
/* callback user for the error */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log_info("chose query %x outbound %d of %d",
|
select_port(outnet, pend);
|
||||||
LDNS_ID_WIRE(ldns_buffer_begin(packet)), chosen,
|
|
||||||
outnet->num_udp);
|
|
||||||
|
|
||||||
/* send it over the commlink */
|
/* send it over the commlink */
|
||||||
if(!comm_point_send_udp_msg(c, packet, (struct sockaddr*)addr,
|
if(!comm_point_send_udp_msg(pend->c, packet, (struct sockaddr*)addr,
|
||||||
addrlen)) {
|
addrlen)) {
|
||||||
/* error, call error callback function */
|
/* error, call error callback function */
|
||||||
pending_delete(outnet, pend);
|
pending_delete(outnet, pend);
|
||||||
(void)(*c->callback)(c, c->cb_arg, 1, NULL);
|
/* callback user for the error */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* system calls to set timeout after sending UDP to make roundtrip
|
||||||
|
smaller. */
|
||||||
|
tv.tv_sec = (int)time(NULL) + timeout;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
comm_timer_set(pend->timer, &tv);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,11 +64,18 @@ struct outside_network {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array of udp comm point* that are used to listen to pending events.
|
* Array of udp comm point* that are used to listen to pending events.
|
||||||
* Each is on a different port.
|
* Each is on a different port. This is for ip4 ports.
|
||||||
*/
|
*/
|
||||||
struct comm_point **udp_ports;
|
struct comm_point **udp4_ports;
|
||||||
/** number of udp ports */
|
/** number of udp4 ports */
|
||||||
size_t num_udp;
|
size_t num_udp4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The opened ip6 ports.
|
||||||
|
*/
|
||||||
|
struct comm_point **udp6_ports;
|
||||||
|
/** number of udp6 ports */
|
||||||
|
size_t num_udp6;
|
||||||
|
|
||||||
/** pending answers. sorted by id, addr */
|
/** pending answers. sorted by id, addr */
|
||||||
rbtree_t *pending;
|
rbtree_t *pending;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue