mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
- Fix #787: outgoing-interface netblock/64 ipv6 option to use linux
freebind to use 64bits of entropy for every query with random local part. git-svn-id: file:///svn/unbound/trunk@3804 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
b6b3e2b914
commit
1394dcba69
6 changed files with 65 additions and 19 deletions
|
|
@ -1,6 +1,9 @@
|
||||||
4 July 2016: Wouter
|
4 July 2016: Wouter
|
||||||
- For #787: prefer-ip6 option for unbound.conf prefers to send
|
- For #787: prefer-ip6 option for unbound.conf prefers to send
|
||||||
upstream queries to ipv6 servers.
|
upstream queries to ipv6 servers.
|
||||||
|
- Fix #787: outgoing-interface netblock/64 ipv6 option to use linux
|
||||||
|
freebind to use 64bits of entropy for every query with random local
|
||||||
|
part.
|
||||||
|
|
||||||
30 June 2016: Wouter
|
30 June 2016: Wouter
|
||||||
- Document always_transparent, always_refuse, always_nxdomain types.
|
- Document always_transparent, always_refuse, always_nxdomain types.
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ Detect source interface on UDP queries and copy them to replies. This
|
||||||
feature is experimental, and needs support in your OS for particular socket
|
feature is experimental, and needs support in your OS for particular socket
|
||||||
options. Default value is no.
|
options. Default value is no.
|
||||||
.TP
|
.TP
|
||||||
.B outgoing\-interface: \fI<ip address>
|
.B outgoing\-interface: \fI<ip address or ip6 netblock>
|
||||||
Interface to use to connect to the network. This interface is used to send
|
Interface to use to connect to the network. This interface is used to send
|
||||||
queries to authoritative servers and receive their replies. Can be given
|
queries to authoritative servers and receive their replies. Can be given
|
||||||
multiple times to work on several interfaces. If none are given the
|
multiple times to work on several interfaces. If none are given the
|
||||||
|
|
@ -137,6 +137,18 @@ and
|
||||||
.B outgoing\-interface:
|
.B outgoing\-interface:
|
||||||
lines, the interfaces are then used for both purposes. Outgoing queries are
|
lines, the interfaces are then used for both purposes. Outgoing queries are
|
||||||
sent via a random outgoing interface to counter spoofing.
|
sent via a random outgoing interface to counter spoofing.
|
||||||
|
.IP
|
||||||
|
If an IPv6 netblock is specified instead of an individual IPv6 address,
|
||||||
|
outgoing UDP queries will use a randomised source address taken from the
|
||||||
|
netblock to counter spoofing. Requires the IPv6 netblock to be routed to the
|
||||||
|
host running unbound, and requires OS support for unprivileged non-local binds
|
||||||
|
(currently only supported on Linux). Several netblocks may be specified with
|
||||||
|
multiple
|
||||||
|
.B outgoing\-interface:
|
||||||
|
options, but do not specify both an individual IPv6 address and an IPv6
|
||||||
|
netblock, or the randomisation will be compromised. Consider combining with
|
||||||
|
.B prefer\-ip6: yes
|
||||||
|
to increase the likelihood of IPv6 nameservers being selected for queries.
|
||||||
.TP
|
.TP
|
||||||
.B outgoing\-range: \fI<number>
|
.B outgoing\-range: \fI<number>
|
||||||
Number of ports to open. This number of file descriptors can be opened per
|
Number of ports to open. This number of file descriptors can be opened per
|
||||||
|
|
|
||||||
|
|
@ -184,14 +184,6 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
|
||||||
#else
|
#else
|
||||||
(void)reuseport;
|
(void)reuseport;
|
||||||
#endif /* defined(SO_REUSEPORT) */
|
#endif /* defined(SO_REUSEPORT) */
|
||||||
#ifdef IP_FREEBIND
|
|
||||||
if (freebind &&
|
|
||||||
setsockopt(s, IPPROTO_IP, IP_FREEBIND, (void*)&on,
|
|
||||||
(socklen_t)sizeof(on)) < 0) {
|
|
||||||
log_warn("setsockopt(.. IP_FREEBIND ..) failed: %s",
|
|
||||||
strerror(errno));
|
|
||||||
}
|
|
||||||
#endif /* IP_FREEBIND */
|
|
||||||
#ifdef IP_TRANSPARENT
|
#ifdef IP_TRANSPARENT
|
||||||
if (transparent &&
|
if (transparent &&
|
||||||
setsockopt(s, IPPROTO_IP, IP_TRANSPARENT, (void*)&on,
|
setsockopt(s, IPPROTO_IP, IP_TRANSPARENT, (void*)&on,
|
||||||
|
|
@ -209,6 +201,14 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
|
||||||
}
|
}
|
||||||
#endif /* IP_TRANSPARENT || IP_BINDANY */
|
#endif /* IP_TRANSPARENT || IP_BINDANY */
|
||||||
}
|
}
|
||||||
|
#ifdef IP_FREEBIND
|
||||||
|
if(freebind &&
|
||||||
|
setsockopt(s, IPPROTO_IP, IP_FREEBIND, (void*)&on,
|
||||||
|
(socklen_t)sizeof(on)) < 0) {
|
||||||
|
log_warn("setsockopt(.. IP_FREEBIND ..) failed: %s",
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
#endif /* IP_FREEBIND */
|
||||||
if(rcv) {
|
if(rcv) {
|
||||||
#ifdef SO_RCVBUF
|
#ifdef SO_RCVBUF
|
||||||
int got;
|
int got;
|
||||||
|
|
|
||||||
|
|
@ -591,7 +591,9 @@ static int setup_if(struct port_if* pif, const char* addrstr,
|
||||||
pif->avail_ports = (int*)memdup(avail, (size_t)numavail*sizeof(int));
|
pif->avail_ports = (int*)memdup(avail, (size_t)numavail*sizeof(int));
|
||||||
if(!pif->avail_ports)
|
if(!pif->avail_ports)
|
||||||
return 0;
|
return 0;
|
||||||
if(!ipstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen))
|
if(!ipstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen) &&
|
||||||
|
!netblockstrtoaddr(addrstr, UNBOUND_DNS_PORT,
|
||||||
|
&pif->addr, &pif->addrlen, &pif->pfxlen))
|
||||||
return 0;
|
return 0;
|
||||||
pif->maxout = (int)numfd;
|
pif->maxout = (int)numfd;
|
||||||
pif->inuse = 0;
|
pif->inuse = 0;
|
||||||
|
|
@ -893,26 +895,49 @@ pending_delete(struct outside_network* outnet, struct pending* p)
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sai6_putrandom(struct sockaddr_in6 *sa, int pfxlen, struct ub_randstate *rnd)
|
||||||
|
{
|
||||||
|
int i, last;
|
||||||
|
if(!(pfxlen > 0 && pfxlen < 128))
|
||||||
|
return;
|
||||||
|
for(i = 0; i < (128 - pfxlen) / 8; i++) {
|
||||||
|
sa->sin6_addr.s6_addr[15-i] = ub_random_max(rnd, 256);
|
||||||
|
}
|
||||||
|
last = pfxlen & 7;
|
||||||
|
if(last != 0) {
|
||||||
|
sa->sin6_addr.s6_addr[15-i] |=
|
||||||
|
((0xFF >> last) & ub_random_max(rnd, 256));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to open a UDP socket for outgoing communication.
|
* Try to open a UDP socket for outgoing communication.
|
||||||
* Sets sockets options as needed.
|
* Sets sockets options as needed.
|
||||||
* @param addr: socket address.
|
* @param addr: socket address.
|
||||||
* @param addrlen: length of address.
|
* @param addrlen: length of address.
|
||||||
|
* @param pfxlen: length of network prefix (for address randomisation).
|
||||||
* @param port: port override for addr.
|
* @param port: port override for addr.
|
||||||
* @param inuse: if -1 is returned, this bool means the port was in use.
|
* @param inuse: if -1 is returned, this bool means the port was in use.
|
||||||
|
* @param rnd: random state (for address randomisation).
|
||||||
* @return fd or -1
|
* @return fd or -1
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
udp_sockport(struct sockaddr_storage* addr, socklen_t addrlen, int port,
|
udp_sockport(struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen,
|
||||||
int* inuse)
|
int port, int* inuse, struct ub_randstate* rnd)
|
||||||
{
|
{
|
||||||
int fd, noproto;
|
int fd, noproto;
|
||||||
if(addr_is_ip6(addr, addrlen)) {
|
if(addr_is_ip6(addr, addrlen)) {
|
||||||
struct sockaddr_in6* sa = (struct sockaddr_in6*)addr;
|
int freebind = 0;
|
||||||
sa->sin6_port = (in_port_t)htons((uint16_t)port);
|
struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr;
|
||||||
|
sa.sin6_port = (in_port_t)htons((uint16_t)port);
|
||||||
|
if(pfxlen != 0) {
|
||||||
|
freebind = 1;
|
||||||
|
sai6_putrandom(&sa, pfxlen, rnd);
|
||||||
|
}
|
||||||
fd = create_udp_sock(AF_INET6, SOCK_DGRAM,
|
fd = create_udp_sock(AF_INET6, SOCK_DGRAM,
|
||||||
(struct sockaddr*)addr, addrlen, 1, inuse, &noproto,
|
(struct sockaddr*)&sa, addrlen, 1, inuse, &noproto,
|
||||||
0, 0, 0, NULL, 0, 0);
|
0, 0, 0, NULL, 0, freebind);
|
||||||
} else {
|
} else {
|
||||||
struct sockaddr_in* sa = (struct sockaddr_in*)addr;
|
struct sockaddr_in* sa = (struct sockaddr_in*)addr;
|
||||||
sa->sin_port = (in_port_t)htons((uint16_t)port);
|
sa->sin_port = (in_port_t)htons((uint16_t)port);
|
||||||
|
|
@ -978,7 +1003,8 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
|
||||||
/* try to open new port, if fails, loop to try again */
|
/* try to open new port, if fails, loop to try again */
|
||||||
log_assert(pif->inuse < pif->maxout);
|
log_assert(pif->inuse < pif->maxout);
|
||||||
portno = pif->avail_ports[my_port - pif->inuse];
|
portno = pif->avail_ports[my_port - pif->inuse];
|
||||||
fd = udp_sockport(&pif->addr, pif->addrlen, portno, &inuse);
|
fd = udp_sockport(&pif->addr, pif->addrlen, pif->pfxlen,
|
||||||
|
portno, &inuse, outnet->rnd);
|
||||||
if(fd == -1 && !inuse) {
|
if(fd == -1 && !inuse) {
|
||||||
/* nonrecoverable error making socket */
|
/* nonrecoverable error making socket */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,10 @@ struct port_if {
|
||||||
/** length of addr field */
|
/** length of addr field */
|
||||||
socklen_t addrlen;
|
socklen_t addrlen;
|
||||||
|
|
||||||
|
/** prefix length of network address (in bits), for randomisation.
|
||||||
|
* if 0, no randomisation. */
|
||||||
|
int pfxlen;
|
||||||
|
|
||||||
/** the available ports array. These are unused.
|
/** the available ports array. These are unused.
|
||||||
* Only the first total-inuse part is filled. */
|
* Only the first total-inuse part is filled. */
|
||||||
int* avail_ports;
|
int* avail_ports;
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,7 @@ warn_hosts(const char* typ, struct config_stub* list)
|
||||||
static void
|
static void
|
||||||
interfacechecks(struct config_file* cfg)
|
interfacechecks(struct config_file* cfg)
|
||||||
{
|
{
|
||||||
|
int d;
|
||||||
struct sockaddr_storage a;
|
struct sockaddr_storage a;
|
||||||
socklen_t alen;
|
socklen_t alen;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
@ -177,8 +178,8 @@ interfacechecks(struct config_file* cfg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(i=0; i<cfg->num_out_ifs; i++) {
|
for(i=0; i<cfg->num_out_ifs; i++) {
|
||||||
if(!ipstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT,
|
if(!ipstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen) &&
|
||||||
&a, &alen)) {
|
!netblockstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen, &d)) {
|
||||||
fatal_exit("cannot parse outgoing-interface "
|
fatal_exit("cannot parse outgoing-interface "
|
||||||
"specified as '%s'", cfg->out_ifs[i]);
|
"specified as '%s'", cfg->out_ifs[i]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue