summaryrefslogtreecommitdiff
path: root/services/outside_network.c
diff options
context:
space:
mode:
Diffstat (limited to 'services/outside_network.c')
-rw-r--r--services/outside_network.c72
1 files changed, 64 insertions, 8 deletions
diff --git a/services/outside_network.c b/services/outside_network.c
index d9e34f46999d..dd25ab39ba70 100644
--- a/services/outside_network.c
+++ b/services/outside_network.c
@@ -243,7 +243,33 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt, size_t pkt_len)
return 0;
fd_set_nonblock(s);
+#ifdef USE_OSX_MSG_FASTOPEN
+ /* API for fast open is different here. We use a connectx() function and
+ then writes can happen as normal even using SSL.*/
+ /* connectx requires that the len be set in the sockaddr struct*/
+ struct sockaddr_in *addr_in = (struct sockaddr_in *)&w->addr;
+ addr_in->sin_len = w->addrlen;
+ sa_endpoints_t endpoints;
+ endpoints.sae_srcif = 0;
+ endpoints.sae_srcaddr = NULL;
+ endpoints.sae_srcaddrlen = 0;
+ endpoints.sae_dstaddr = (struct sockaddr *)&w->addr;
+ endpoints.sae_dstaddrlen = w->addrlen;
+ if (connectx(s, &endpoints, SAE_ASSOCID_ANY,
+ CONNECT_DATA_IDEMPOTENT | CONNECT_RESUME_ON_READ_WRITE,
+ NULL, 0, NULL, NULL) == -1) {
+#else /* USE_OSX_MSG_FASTOPEN*/
+#ifdef USE_MSG_FASTOPEN
+ pend->c->tcp_do_fastopen = 1;
+ /* Only do TFO for TCP in which case no connect() is required here.
+ Don't combine client TFO with SSL, since OpenSSL can't
+ currently support doing a handshake on fd that already isn't connected*/
+ if (w->outnet->sslctx && w->ssl_upstream) {
+ if(connect(s, (struct sockaddr*)&w->addr, w->addrlen) == -1) {
+#else /* USE_MSG_FASTOPEN*/
if(connect(s, (struct sockaddr*)&w->addr, w->addrlen) == -1) {
+#endif /* USE_MSG_FASTOPEN*/
+#endif /* USE_OSX_MSG_FASTOPEN*/
#ifndef USE_WINSOCK
#ifdef EINPROGRESS
if(errno != EINPROGRESS) {
@@ -263,6 +289,9 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt, size_t pkt_len)
return 0;
}
}
+#ifdef USE_MSG_FASTOPEN
+ }
+#endif /* USE_MSG_FASTOPEN */
if(w->outnet->sslctx && w->ssl_upstream) {
pend->c->ssl = outgoing_ssl_fd(w->outnet->sslctx, s);
if(!pend->c->ssl) {
@@ -591,7 +620,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 +924,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] = (uint8_t)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 +1032,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;
@@ -1361,6 +1416,7 @@ serviced_perturb_qname(struct ub_randstate* rnd, uint8_t* qbuf, size_t len)
long int random = 0;
int bits = 0;
log_assert(len >= 10 + 5 /* offset qname, root, qtype, qclass */);
+ (void)len;
lablen = *d++;
while(lablen) {
while(lablen--) {