From 1f49833d4fc449d54c95c3235b5c18523e6f8d69 Mon Sep 17 00:00:00 2001 From: Riccardo Spagni Date: Thu, 2 Apr 2015 11:16:18 +0200 Subject: update unbound from upstream --- external/unbound/services/cache/dns.c | 6 +- external/unbound/services/cache/infra.c | 2 +- external/unbound/services/cache/rrset.c | 9 +- external/unbound/services/listen_dnsport.c | 179 ++++++++++++++++++++++------ external/unbound/services/listen_dnsport.h | 15 ++- external/unbound/services/localzone.c | 33 ++++- external/unbound/services/localzone.h | 9 +- external/unbound/services/mesh.c | 2 +- external/unbound/services/outside_network.c | 6 +- 9 files changed, 208 insertions(+), 53 deletions(-) (limited to 'external/unbound/services') diff --git a/external/unbound/services/cache/dns.c b/external/unbound/services/cache/dns.c index 4692744a1..cec2629e1 100644 --- a/external/unbound/services/cache/dns.c +++ b/external/unbound/services/cache/dns.c @@ -50,7 +50,7 @@ #include "util/net_help.h" #include "util/regional.h" #include "util/config_file.h" -#include "ldns/sbuffer.h" +#include "sldns/sbuffer.h" /** store rrsets in the rrset cache. * @param env: module environment with caches. @@ -366,6 +366,8 @@ dns_msg_create(uint8_t* qname, size_t qnamelen, uint16_t qtype, sizeof(struct reply_info)-sizeof(struct rrset_ref)); if(!msg->rep) return NULL; + if(capacity > RR_COUNT_MAX) + return NULL; /* integer overflow protection */ msg->rep->flags = BIT_QR; /* with QR, no AA */ msg->rep->qdcount = 1; msg->rep->rrsets = (struct ub_packed_rrset_key**) @@ -453,6 +455,8 @@ gen_dns_msg(struct regional* region, struct query_info* q, size_t num) sizeof(struct reply_info) - sizeof(struct rrset_ref)); if(!msg->rep) return NULL; + if(num > RR_COUNT_MAX) + return NULL; /* integer overflow protection */ msg->rep->rrsets = (struct ub_packed_rrset_key**) regional_alloc(region, num * sizeof(struct ub_packed_rrset_key*)); diff --git a/external/unbound/services/cache/infra.c b/external/unbound/services/cache/infra.c index 07f2103d7..61bab3fe5 100644 --- a/external/unbound/services/cache/infra.c +++ b/external/unbound/services/cache/infra.c @@ -39,7 +39,7 @@ * This file contains the infrastructure cache. */ #include "config.h" -#include "ldns/rrdef.h" +#include "sldns/rrdef.h" #include "services/cache/infra.h" #include "util/storage/slabhash.h" #include "util/storage/lookup3.h" diff --git a/external/unbound/services/cache/rrset.c b/external/unbound/services/cache/rrset.c index 5f52dbce1..2c8552953 100644 --- a/external/unbound/services/cache/rrset.c +++ b/external/unbound/services/cache/rrset.c @@ -40,7 +40,7 @@ */ #include "config.h" #include "services/cache/rrset.h" -#include "ldns/rrdef.h" +#include "sldns/rrdef.h" #include "util/storage/slabhash.h" #include "util/config_file.h" #include "util/data/packed_rrset.h" @@ -304,10 +304,11 @@ rrset_array_unlock_touch(struct rrset_cache* r, struct regional* scratch, { hashvalue_t* h; size_t i; - if(!(h = (hashvalue_t*)regional_alloc(scratch, - sizeof(hashvalue_t)*count))) + if(count > RR_COUNT_MAX || !(h = (hashvalue_t*)regional_alloc(scratch, + sizeof(hashvalue_t)*count))) { log_warn("rrset LRU: memory allocation failed"); - else /* store hash values */ + h = NULL; + } else /* store hash values */ for(i=0; ientry.hash; /* unlock */ diff --git a/external/unbound/services/listen_dnsport.c b/external/unbound/services/listen_dnsport.c index b7ffb6d3f..276c0fb32 100644 --- a/external/unbound/services/listen_dnsport.c +++ b/external/unbound/services/listen_dnsport.c @@ -49,13 +49,17 @@ #include "util/log.h" #include "util/config_file.h" #include "util/net_help.h" -#include "ldns/sbuffer.h" +#include "sldns/sbuffer.h" #ifdef HAVE_NETDB_H #include #endif #include +#ifdef HAVE_SYS_UN_H +#include +#endif + /** number of queued TCP connections for listen() */ #define TCP_BACKLOG 256 @@ -92,10 +96,10 @@ verbose_print_addr(struct addrinfo *addr) int create_udp_sock(int family, int socktype, struct sockaddr* addr, socklen_t addrlen, int v6only, int* inuse, int* noproto, - int rcv, int snd, int listen, int* reuseport) + int rcv, int snd, int listen, int* reuseport, int transparent) { int s; -#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_USE_MIN_MTU) +#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_USE_MIN_MTU) || defined(IP_TRANSPARENT) int on=1; #endif #ifdef IPV6_MTU @@ -109,6 +113,9 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, #endif #ifndef IPV6_V6ONLY (void)v6only; +#endif +#ifndef IP_TRANSPARENT + (void)transparent; #endif if((s = socket(family, socktype, 0)) == -1) { *inuse = 0; @@ -173,6 +180,14 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, #else (void)reuseport; #endif /* defined(SO_REUSEPORT) */ +#ifdef IP_TRANSPARENT + if (transparent && + setsockopt(s, IPPROTO_IP, IP_TRANSPARENT, (void*)&on, + (socklen_t)sizeof(on)) < 0) { + log_warn("setsockopt(.. IP_TRANSPARENT ..) failed: %s", + strerror(errno)); + } +#endif /* IP_TRANSPARENT */ } if(rcv) { #ifdef SO_RCVBUF @@ -368,29 +383,47 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, * (and also uses the interface mtu to determine the size of the packets). * So there won't be any EMSGSIZE error. Against DNS fragmentation attacks. * FreeBSD already has same semantics without setting the option. */ -# if defined(IP_PMTUDISC_OMIT) - int action = IP_PMTUDISC_OMIT; -# else - int action = IP_PMTUDISC_DONT; -# endif + int omit_set = 0; + int action; +# if defined(IP_PMTUDISC_OMIT) + action = IP_PMTUDISC_OMIT; if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action, (socklen_t)sizeof(action)) < 0) { - log_err("setsockopt(..., IP_MTU_DISCOVER, " -# if defined(IP_PMTUDISC_OMIT) - "IP_PMTUDISC_OMIT" + + if (errno != EINVAL) { + log_err("setsockopt(..., IP_MTU_DISCOVER, IP_PMTUDISC_OMIT...) failed: %s", + strerror(errno)); + +# ifndef USE_WINSOCK + close(s); # else - "IP_PMTUDISC_DONT" + closesocket(s); # endif - "...) failed: %s", - strerror(errno)); + *noproto = 0; + *inuse = 0; + return -1; + } + } + else + { + omit_set = 1; + } +# endif + if (omit_set == 0) { + action = IP_PMTUDISC_DONT; + if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, + &action, (socklen_t)sizeof(action)) < 0) { + log_err("setsockopt(..., IP_MTU_DISCOVER, IP_PMTUDISC_DONT...) failed: %s", + strerror(errno)); # ifndef USE_WINSOCK - close(s); + close(s); # else - closesocket(s); + closesocket(s); # endif - *noproto = 0; - *inuse = 0; - return -1; + *noproto = 0; + *inuse = 0; + return -1; + } } # elif defined(IP_DONTFRAG) int off = 0; @@ -450,12 +483,15 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, - int* reuseport) + int* reuseport, int transparent) { int s; -#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_V6ONLY) +#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_V6ONLY) || defined(IP_TRANSPARENT) int on = 1; -#endif /* SO_REUSEADDR || IPV6_V6ONLY */ +#endif +#ifndef IP_TRANSPARENT + (void)transparent; +#endif verbose_print_addr(addr); *noproto = 0; if((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) { @@ -530,6 +566,14 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, #else (void)v6only; #endif /* IPV6_V6ONLY */ +#ifdef IP_TRANSPARENT + if (transparent && + setsockopt(s, IPPROTO_IP, IP_TRANSPARENT, (void*)&on, + (socklen_t)sizeof(on)) < 0) { + log_warn("setsockopt(.. IP_TRANSPARENT ..) failed: %s", + strerror(errno)); + } +#endif /* IP_TRANSPARENT */ if(bind(s, addr->ai_addr, addr->ai_addrlen) != 0) { #ifndef USE_WINSOCK /* detect freebsd jail with no ipv6 permission */ @@ -571,13 +615,70 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, return s; } +int +create_local_accept_sock(const char *path, int* noproto) +{ +#ifdef HAVE_SYS_UN_H + int s; + struct sockaddr_un usock; + + verbose(VERB_ALGO, "creating unix socket %s", path); +#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN + /* this member exists on BSDs, not Linux */ + usock.sun_len = (socklen_t)sizeof(usock); +#endif + usock.sun_family = AF_LOCAL; + /* length is 92-108, 104 on FreeBSD */ + (void)strlcpy(usock.sun_path, path, sizeof(usock.sun_path)); + + if ((s = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) { + log_err("Cannot create local socket %s (%s)", + path, strerror(errno)); + return -1; + } + + if (unlink(path) && errno != ENOENT) { + /* The socket already exists and cannot be removed */ + log_err("Cannot remove old local socket %s (%s)", + path, strerror(errno)); + return -1; + } + + if (bind(s, (struct sockaddr *)&usock, + (socklen_t)sizeof(struct sockaddr_un)) == -1) { + log_err("Cannot bind local socket %s (%s)", + path, strerror(errno)); + return -1; + } + + if (!fd_set_nonblock(s)) { + log_err("Cannot set non-blocking mode"); + return -1; + } + + if (listen(s, TCP_BACKLOG) == -1) { + log_err("can't listen: %s", strerror(errno)); + return -1; + } + + (void)noproto; /*unused*/ + return s; +#else + (void)path; + log_err("Local sockets are not supported"); + *noproto = 1; + return -1; +#endif +} + + /** * Create socket from getaddrinfo results */ static int make_sock(int stype, const char* ifname, const char* port, struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd, - int* reuseport) + int* reuseport, int transparent) { struct addrinfo *res = NULL; int r, s, inuse, noproto; @@ -605,14 +706,15 @@ make_sock(int stype, const char* ifname, const char* port, s = create_udp_sock(res->ai_family, res->ai_socktype, (struct sockaddr*)res->ai_addr, res->ai_addrlen, v6only, &inuse, &noproto, (int)rcv, (int)snd, 1, - reuseport); + reuseport, transparent); if(s == -1 && inuse) { log_err("bind: address already in use"); } else if(s == -1 && noproto && hints->ai_family == AF_INET6){ *noip6 = 1; } } else { - s = create_tcp_accept_sock(res, v6only, &noproto, reuseport); + s = create_tcp_accept_sock(res, v6only, &noproto, reuseport, + transparent); if(s == -1 && noproto && hints->ai_family == AF_INET6){ *noip6 = 1; } @@ -625,7 +727,7 @@ make_sock(int stype, const char* ifname, const char* port, static int make_sock_port(int stype, const char* ifname, const char* port, struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd, - int* reuseport) + int* reuseport, int transparent) { char* s = strchr(ifname, '@'); if(s) { @@ -647,10 +749,10 @@ make_sock_port(int stype, const char* ifname, const char* port, (void)strlcpy(p, s+1, sizeof(p)); p[strlen(s+1)]=0; return make_sock(stype, newif, p, hints, v6only, noip6, - rcv, snd, reuseport); + rcv, snd, reuseport, transparent); } return make_sock(stype, ifname, port, hints, v6only, noip6, rcv, snd, - reuseport); + reuseport, transparent); } /** @@ -744,19 +846,20 @@ set_recvpktinfo(int s, int family) * @param ssl_port: ssl service port number * @param reuseport: try to set SO_REUSEPORT if nonNULL and true. * set to false on exit if reuseport failed due to no kernel support. + * @param transparent: set IP_TRANSPARENT socket option. * @return: returns false on error. */ static int ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, struct addrinfo *hints, const char* port, struct listen_port** list, - size_t rcv, size_t snd, int ssl_port, int* reuseport) + size_t rcv, size_t snd, int ssl_port, int* reuseport, int transparent) { int s, noip6=0; if(!do_udp && !do_tcp) return 0; if(do_auto) { if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1, - &noip6, rcv, snd, reuseport)) == -1) { + &noip6, rcv, snd, reuseport, transparent)) == -1) { if(noip6) { log_warn("IPv6 protocol not available"); return 1; @@ -783,7 +886,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, } else if(do_udp) { /* regular udp socket */ if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1, - &noip6, rcv, snd, reuseport)) == -1) { + &noip6, rcv, snd, reuseport, transparent)) == -1) { if(noip6) { log_warn("IPv6 protocol not available"); return 1; @@ -804,7 +907,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, atoi(strchr(ifname, '@')+1) == ssl_port) || (!strchr(ifname, '@') && atoi(port) == ssl_port)); if((s = make_sock_port(SOCK_STREAM, ifname, port, hints, 1, - &noip6, 0, 0, reuseport)) == -1) { + &noip6, 0, 0, reuseport, transparent)) == -1) { if(noip6) { /*log_warn("IPv6 protocol not available");*/ return 1; @@ -960,7 +1063,8 @@ listening_ports_open(struct config_file* cfg, int* reuseport) do_auto, cfg->do_udp, do_tcp, &hints, portbuf, &list, cfg->so_rcvbuf, cfg->so_sndbuf, - cfg->ssl_port, reuseport)) { + cfg->ssl_port, reuseport, + cfg->ip_transparent)) { listening_ports_free(list); return NULL; } @@ -971,7 +1075,8 @@ listening_ports_open(struct config_file* cfg, int* reuseport) do_auto, cfg->do_udp, do_tcp, &hints, portbuf, &list, cfg->so_rcvbuf, cfg->so_sndbuf, - cfg->ssl_port, reuseport)) { + cfg->ssl_port, reuseport, + cfg->ip_transparent)) { listening_ports_free(list); return NULL; } @@ -984,7 +1089,8 @@ listening_ports_open(struct config_file* cfg, int* reuseport) if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp, do_tcp, &hints, portbuf, &list, cfg->so_rcvbuf, cfg->so_sndbuf, - cfg->ssl_port, reuseport)) { + cfg->ssl_port, reuseport, + cfg->ip_transparent)) { listening_ports_free(list); return NULL; } @@ -995,7 +1101,8 @@ listening_ports_open(struct config_file* cfg, int* reuseport) if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp, do_tcp, &hints, portbuf, &list, cfg->so_rcvbuf, cfg->so_sndbuf, - cfg->ssl_port, reuseport)) { + cfg->ssl_port, reuseport, + cfg->ip_transparent)) { listening_ports_free(list); return NULL; } diff --git a/external/unbound/services/listen_dnsport.h b/external/unbound/services/listen_dnsport.h index 075f6d281..676f0c638 100644 --- a/external/unbound/services/listen_dnsport.h +++ b/external/unbound/services/listen_dnsport.h @@ -189,11 +189,12 @@ void listen_start_accept(struct listen_dnsport* listen); * set SO_REUSEADDR on it. * @param reuseport: if nonNULL and true, try to set SO_REUSEPORT on * listening UDP port. Set to false on return if it failed to do so. + * @param transparent: set IP_TRANSPARENT socket option. * @return: the socket. -1 on error. */ int create_udp_sock(int family, int socktype, struct sockaddr* addr, socklen_t addrlen, int v6only, int* inuse, int* noproto, int rcv, - int snd, int listen, int* reuseport); + int snd, int listen, int* reuseport, int transparent); /** * Create and bind TCP listening socket @@ -202,9 +203,19 @@ int create_udp_sock(int family, int socktype, struct sockaddr* addr, * @param noproto: if error caused by lack of protocol support. * @param reuseport: if nonNULL and true, try to set SO_REUSEPORT on * listening UDP port. Set to false on return if it failed to do so. + * @param transparent: set IP_TRANSPARENT socket option. * @return: the socket. -1 on error. */ int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, - int* reuseport); + int* reuseport, int transparent); + +/** + * Create and bind local listening socket + * @param path: path to the socket. + * @param noproto: on error, this is set true if cause is that local sockets + * are not supported. + * @return: the socket. -1 on error. + */ +int create_local_accept_sock(const char* path, int* noproto); #endif /* LISTEN_DNSPORT_H */ diff --git a/external/unbound/services/localzone.c b/external/unbound/services/localzone.c index d285a127c..51491656f 100644 --- a/external/unbound/services/localzone.c +++ b/external/unbound/services/localzone.c @@ -40,14 +40,15 @@ */ #include "config.h" #include "services/localzone.h" -#include "ldns/str2wire.h" -#include "ldns/sbuffer.h" +#include "sldns/str2wire.h" +#include "sldns/sbuffer.h" #include "util/regional.h" #include "util/config_file.h" #include "util/data/dname.h" #include "util/data/packed_rrset.h" #include "util/data/msgencode.h" #include "util/net_help.h" +#include "util/netevent.h" #include "util/data/msgreply.h" #include "util/data/msgparse.h" @@ -1022,6 +1023,10 @@ void local_zones_print(struct local_zones* zones) log_nametypeclass(0, "static zone", z->name, 0, z->dclass); break; + case local_zone_inform: + log_nametypeclass(0, "inform zone", + z->name, 0, z->dclass); + break; default: log_nametypeclass(0, "badtyped zone", z->name, 0, z->dclass); @@ -1169,9 +1174,25 @@ lz_zone_answer(struct local_zone* z, struct query_info* qinfo, return 0; } +/** print log information for an inform zone query */ +static void +lz_inform_print(struct local_zone* z, struct query_info* qinfo, + struct comm_reply* repinfo) +{ + char ip[128], txt[512]; + char zname[LDNS_MAX_DOMAINLEN+1]; + uint16_t port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port); + dname_str(z->name, zname); + addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip)); + snprintf(txt, sizeof(txt), "%s inform %s@%u", zname, ip, + (unsigned)port); + log_nametypeclass(0, txt, qinfo->qname, qinfo->qtype, qinfo->qclass); +} + int local_zones_answer(struct local_zones* zones, struct query_info* qinfo, - struct edns_data* edns, sldns_buffer* buf, struct regional* temp) + struct edns_data* edns, sldns_buffer* buf, struct regional* temp, + struct comm_reply* repinfo) { /* see if query is covered by a zone, * if so: - try to match (exact) local data @@ -1190,6 +1211,9 @@ local_zones_answer(struct local_zones* zones, struct query_info* qinfo, lock_rw_rdlock(&z->lock); lock_rw_unlock(&zones->lock); + if(z->type == local_zone_inform && repinfo) + lz_inform_print(z, qinfo, repinfo); + if(local_data_answer(z, qinfo, edns, buf, temp, labs, &ld)) { lock_rw_unlock(&z->lock); return 1; @@ -1209,6 +1233,7 @@ const char* local_zone_type2str(enum localzone_type t) case local_zone_typetransparent: return "typetransparent"; case local_zone_static: return "static"; case local_zone_nodefault: return "nodefault"; + case local_zone_inform: return "inform"; } return "badtyped"; } @@ -1227,6 +1252,8 @@ int local_zone_str2type(const char* type, enum localzone_type* t) *t = local_zone_typetransparent; else if(strcmp(type, "redirect") == 0) *t = local_zone_redirect; + else if(strcmp(type, "inform") == 0) + *t = local_zone_inform; else return 0; return 1; } diff --git a/external/unbound/services/localzone.h b/external/unbound/services/localzone.h index 788fbfb3b..29ba8663f 100644 --- a/external/unbound/services/localzone.h +++ b/external/unbound/services/localzone.h @@ -49,6 +49,7 @@ struct config_file; struct edns_data; struct query_info; struct sldns_buffer; +struct comm_reply; /** * Local zone type @@ -70,7 +71,9 @@ enum localzone_type { local_zone_redirect, /** remove default AS112 blocking contents for zone * nodefault is used in config not during service. */ - local_zone_nodefault + local_zone_nodefault, + /** log client address, but no block (transparent) */ + local_zone_inform }; /** @@ -220,12 +223,14 @@ void local_zones_print(struct local_zones* zones); * @param edns: edns info (parsed). * @param buf: buffer with query ID and flags, also for reply. * @param temp: temporary storage region. + * @param repinfo: source address for checks. may be NULL. * @return true if answer is in buffer. false if query is not answered * by authority data. If the reply should be dropped altogether, the return * value is true, but the buffer is cleared (empty). */ int local_zones_answer(struct local_zones* zones, struct query_info* qinfo, - struct edns_data* edns, struct sldns_buffer* buf, struct regional* temp); + struct edns_data* edns, struct sldns_buffer* buf, struct regional* temp, + struct comm_reply* repinfo); /** * Parse the string into localzone type. diff --git a/external/unbound/services/mesh.c b/external/unbound/services/mesh.c index a69aced22..8076874ae 100644 --- a/external/unbound/services/mesh.c +++ b/external/unbound/services/mesh.c @@ -55,7 +55,7 @@ #include "util/fptr_wlist.h" #include "util/alloc.h" #include "util/config_file.h" -#include "ldns/sbuffer.h" +#include "sldns/sbuffer.h" /** subtract timers and the values do not overflow or become negative */ static void diff --git a/external/unbound/services/outside_network.c b/external/unbound/services/outside_network.c index 5bb52ff9f..dc3d2f404 100644 --- a/external/unbound/services/outside_network.c +++ b/external/unbound/services/outside_network.c @@ -57,7 +57,7 @@ #include "util/net_help.h" #include "util/random.h" #include "util/fptr_wlist.h" -#include "ldns/sbuffer.h" +#include "sldns/sbuffer.h" #include "dnstap/dnstap.h" #ifdef HAVE_OPENSSL_SSL_H #include @@ -893,13 +893,13 @@ udp_sockport(struct sockaddr_storage* addr, socklen_t addrlen, int port, sa->sin6_port = (in_port_t)htons((uint16_t)port); fd = create_udp_sock(AF_INET6, SOCK_DGRAM, (struct sockaddr*)addr, addrlen, 1, inuse, &noproto, - 0, 0, 0, NULL); + 0, 0, 0, NULL, 0); } else { struct sockaddr_in* sa = (struct sockaddr_in*)addr; sa->sin_port = (in_port_t)htons((uint16_t)port); fd = create_udp_sock(AF_INET, SOCK_DGRAM, (struct sockaddr*)addr, addrlen, 1, inuse, &noproto, - 0, 0, 0, NULL); + 0, 0, 0, NULL, 0); } return fd; } -- cgit v1.2.3