mirror of
https://github.com/NLnetLabs/unbound.git
synced 2024-09-21 14:47:09 +00: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
@ -1,6 +1,9 @@
|
||||
4 July 2016: Wouter
|
||||
- For #787: prefer-ip6 option for unbound.conf prefers to send
|
||||
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
|
||||
- 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
|
||||
options. Default value is no.
|
||||
.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
|
||||
queries to authoritative servers and receive their replies. Can be given
|
||||
multiple times to work on several interfaces. If none are given the
|
||||
@ -137,6 +137,18 @@ and
|
||||
.B outgoing\-interface:
|
||||
lines, the interfaces are then used for both purposes. Outgoing queries are
|
||||
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
|
||||
.B outgoing\-range: \fI<number>
|
||||
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
|
||||
(void)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
|
||||
if (transparent &&
|
||||
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 */
|
||||
}
|
||||
#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) {
|
||||
#ifdef SO_RCVBUF
|
||||
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));
|
||||
if(!pif->avail_ports)
|
||||
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;
|
||||
pif->maxout = (int)numfd;
|
||||
pif->inuse = 0;
|
||||
@ -893,26 +895,49 @@ pending_delete(struct outside_network* outnet, struct pending* 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.
|
||||
* Sets sockets options as needed.
|
||||
* @param addr: socket address.
|
||||
* @param addrlen: length of address.
|
||||
* @param pfxlen: length of network prefix (for address randomisation).
|
||||
* @param port: port override for addr.
|
||||
* @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
|
||||
*/
|
||||
static int
|
||||
udp_sockport(struct sockaddr_storage* addr, socklen_t addrlen, int port,
|
||||
int* inuse)
|
||||
udp_sockport(struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen,
|
||||
int port, int* inuse, struct ub_randstate* rnd)
|
||||
{
|
||||
int fd, noproto;
|
||||
if(addr_is_ip6(addr, addrlen)) {
|
||||
struct sockaddr_in6* sa = (struct sockaddr_in6*)addr;
|
||||
sa->sin6_port = (in_port_t)htons((uint16_t)port);
|
||||
int freebind = 0;
|
||||
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,
|
||||
(struct sockaddr*)addr, addrlen, 1, inuse, &noproto,
|
||||
0, 0, 0, NULL, 0, 0);
|
||||
(struct sockaddr*)&sa, addrlen, 1, inuse, &noproto,
|
||||
0, 0, 0, NULL, 0, freebind);
|
||||
} else {
|
||||
struct sockaddr_in* sa = (struct sockaddr_in*)addr;
|
||||
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 */
|
||||
log_assert(pif->inuse < pif->maxout);
|
||||
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) {
|
||||
/* nonrecoverable error making socket */
|
||||
return 0;
|
||||
|
@ -165,6 +165,10 @@ struct port_if {
|
||||
/** length of addr field */
|
||||
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.
|
||||
* Only the first total-inuse part is filled. */
|
||||
int* avail_ports;
|
||||
|
@ -161,6 +161,7 @@ warn_hosts(const char* typ, struct config_stub* list)
|
||||
static void
|
||||
interfacechecks(struct config_file* cfg)
|
||||
{
|
||||
int d;
|
||||
struct sockaddr_storage a;
|
||||
socklen_t alen;
|
||||
int i, j;
|
||||
@ -177,8 +178,8 @@ interfacechecks(struct config_file* cfg)
|
||||
}
|
||||
}
|
||||
for(i=0; i<cfg->num_out_ifs; i++) {
|
||||
if(!ipstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT,
|
||||
&a, &alen)) {
|
||||
if(!ipstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen) &&
|
||||
!netblockstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen, &d)) {
|
||||
fatal_exit("cannot parse outgoing-interface "
|
||||
"specified as '%s'", cfg->out_ifs[i]);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user