--- embedaddon/dnsmasq/src/network.c 2014/06/15 16:31:38 1.1.1.2 +++ embedaddon/dnsmasq/src/network.c 2016/11/02 09:57:01 1.1.1.3 @@ -1,4 +1,4 @@ -/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley +/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,10 +16,6 @@ #include "dnsmasq.h" -#ifndef IN6_IS_ADDR_ULA -#define IN6_IS_ADDR_ULA(a) ((((__const uint32_t *) (a))[0] & htonl (0xfe00000)) == htonl (0xfc000000)) -#endif - #ifdef HAVE_LINUX_NETWORK int indextoname(int fd, int index, char *name) @@ -240,7 +236,7 @@ struct iface_param { }; static int iface_allowed(struct iface_param *param, int if_index, char *label, - union mysockaddr *addr, struct in_addr netmask, int prefixlen, int dad) + union mysockaddr *addr, struct in_addr netmask, int prefixlen, int iface_flags) { struct irec *iface; int mtu = 0, loopback; @@ -392,6 +388,10 @@ static int iface_allowed(struct iface_param *param, in { al->addr.addr.addr6 = addr->in6.sin6_addr; al->flags = ADDRLIST_IPV6; + /* Privacy addresses and addresses still undergoing DAD and deprecated addresses + don't appear in forward queries, but will in reverse ones. */ + if (!(iface_flags & IFACE_PERMANENT) || (iface_flags & (IFACE_DEPRECATED | IFACE_TENTATIVE))) + al->flags |= ADDRLIST_REVONLY; } #endif } @@ -403,7 +403,7 @@ static int iface_allowed(struct iface_param *param, in for (iface = daemon->interfaces; iface; iface = iface->next) if (sockaddr_isequal(&iface->addr, addr)) { - iface->dad = dad; + iface->dad = !!(iface_flags & IFACE_TENTATIVE); iface->found = 1; /* for garbage collection */ return 1; } @@ -478,7 +478,7 @@ static int iface_allowed(struct iface_param *param, in iface->dhcp_ok = dhcp_ok; iface->dns_auth = auth_dns; iface->mtu = mtu; - iface->dad = dad; + iface->dad = !!(iface_flags & IFACE_TENTATIVE); iface->found = 1; iface->done = iface->multicast_done = iface->warned = 0; iface->index = if_index; @@ -523,7 +523,7 @@ static int iface_allowed_v6(struct in6_addr *local, in else addr.in6.sin6_scope_id = 0; - return iface_allowed((struct iface_param *)vparam, if_index, NULL, &addr, netmask, prefix, !!(flags & IFACE_TENTATIVE)); + return iface_allowed((struct iface_param *)vparam, if_index, NULL, &addr, netmask, prefix, flags); } #endif @@ -532,13 +532,14 @@ static int iface_allowed_v4(struct in_addr local, int { union mysockaddr addr; int prefix, bit; + + (void)broadcast; /* warning */ memset(&addr, 0, sizeof(addr)); #ifdef HAVE_SOCKADDR_SA_LEN addr.in.sin_len = sizeof(addr.in); #endif addr.in.sin_family = AF_INET; - addr.in.sin_addr = broadcast; /* warning */ addr.in.sin_addr = local; addr.in.sin_port = htons(daemon->port); @@ -551,7 +552,7 @@ static int iface_allowed_v4(struct in_addr local, int int enumerate_interfaces(int reset) { static struct addrlist *spare = NULL; - static int done = 0, active = 0; + static int done = 0; struct iface_param param; int errsave, ret = 1; struct addrlist *addr, *tmp; @@ -570,14 +571,11 @@ int enumerate_interfaces(int reset) return 1; } - if (done || active) + if (done) return 1; done = 1; - /* protect against recusive calls from iface_enumerate(); */ - active = 1; - if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) return 0; @@ -677,10 +675,8 @@ int enumerate_interfaces(int reset) } errno = errsave; - spare = param.spare; - active = 0; - + return ret; } @@ -814,10 +810,11 @@ int tcp_interface(int fd, int af) int opt = 1; struct cmsghdr *cmptr; struct msghdr msg; + socklen_t len; - /* use mshdr do that the CMSDG_* macros are available */ + /* use mshdr so that the CMSDG_* macros are available */ msg.msg_control = daemon->packet; - msg.msg_controllen = daemon->packet_buff_sz; + msg.msg_controllen = len = daemon->packet_buff_sz; /* we overwrote the buffer... */ daemon->srv_save = NULL; @@ -825,18 +822,21 @@ int tcp_interface(int fd, int af) if (af == AF_INET) { if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) != -1 && - getsockopt(fd, IPPROTO_IP, IP_PKTOPTIONS, msg.msg_control, (socklen_t *)&msg.msg_controllen) != -1) - for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) - if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO) - { - union { - unsigned char *c; - struct in_pktinfo *p; - } p; - - p.c = CMSG_DATA(cmptr); - if_index = p.p->ipi_ifindex; - } + getsockopt(fd, IPPROTO_IP, IP_PKTOPTIONS, msg.msg_control, &len) != -1) + { + msg.msg_controllen = len; + for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) + if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO) + { + union { + unsigned char *c; + struct in_pktinfo *p; + } p; + + p.c = CMSG_DATA(cmptr); + if_index = p.p->ipi_ifindex; + } + } } #ifdef HAVE_IPV6 else @@ -854,9 +854,10 @@ int tcp_interface(int fd, int af) #endif if (set_ipv6pktinfo(fd) && - getsockopt(fd, IPPROTO_IPV6, PKTOPTIONS, msg.msg_control, (socklen_t *)&msg.msg_controllen) != -1) + getsockopt(fd, IPPROTO_IPV6, PKTOPTIONS, msg.msg_control, &len) != -1) { - for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) + msg.msg_controllen = len; + for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo) { union { @@ -1081,23 +1082,30 @@ void join_multicast(int dienow) if ((daemon->doing_dhcp6 || daemon->relay6) && setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1) - err = 1; + err = errno; inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr); if (daemon->doing_dhcp6 && setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1) - err = 1; + err = errno; inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr); if (daemon->doing_ra && setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1) - err = 1; + err = errno; if (err) { char *s = _("interface %s failed to join DHCPv6 multicast group: %s"); + errno = err; + +#ifdef HAVE_LINUX_NETWORK + if (errno == ENOMEM) + my_syslog(LOG_ERR, _("try increasing /proc/sys/net/core/optmem_max")); +#endif + if (dienow) die(s, iface->name, EC_BADNET); else @@ -1117,7 +1125,7 @@ int random_sock(int family) if ((fd = socket(family, SOCK_DGRAM, 0)) != -1) { union mysockaddr addr; - unsigned int ports_avail = 65536u - (unsigned short)daemon->min_port; + unsigned int ports_avail = ((unsigned short)daemon->max_port - (unsigned short)daemon->min_port) + 1; int tries = ports_avail < 30 ? 3 * ports_avail : 100; memset(&addr, 0, sizeof(addr)); @@ -1130,8 +1138,8 @@ int random_sock(int family) { unsigned short port = rand16(); - if (daemon->min_port != 0) - port = htons(daemon->min_port + (port % ((unsigned short)ports_avail))); + if (daemon->min_port != 0 || daemon->max_port != MAX_PORT) + port = htons(daemon->min_port + (port % ((unsigned short)ports_avail))); if (family == AF_INET) { @@ -1302,8 +1310,14 @@ void mark_servers(int flag) /* mark everything with argument flag */ for (serv = daemon->servers; serv; serv = serv->next) - if (serv->flags & flag) - serv->flags |= SERV_MARK; + { + if (serv->flags & flag) + serv->flags |= SERV_MARK; +#ifdef HAVE_LOOP + /* Give looped servers another chance */ + serv->flags &= ~SERV_LOOP; +#endif + } } void cleanup_servers(void) @@ -1325,6 +1339,11 @@ void cleanup_servers(void) else up = &serv->next; } + +#ifdef HAVE_LOOP + /* Now we have a new set of servers, test for loops. */ + loop_send_probes(); +#endif } void add_update_server(int flags, @@ -1390,7 +1409,10 @@ void add_update_server(int flags, serv->domain = domain_str; serv->next = next; serv->queries = serv->failed_queries = 0; - +#ifdef HAVE_LOOP + serv->uid = rand32(); +#endif + if (domain) serv->flags |= SERV_HAS_DOMAIN; @@ -1407,18 +1429,53 @@ void check_servers(void) { struct irec *iface; struct server *serv; - int port = 0; + int port = 0, count; /* interface may be new since startup */ if (!option_bool(OPT_NOWILD)) enumerate_interfaces(0); +#ifdef HAVE_DNSSEC + /* Disable DNSSEC validation when using server=/domain/.... servers + unless there's a configured trust anchor. */ for (serv = daemon->servers; serv; serv = serv->next) + serv->flags |= SERV_DO_DNSSEC; +#endif + + for (count = 0, serv = daemon->servers; serv; serv = serv->next) { - if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND))) + if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND))) { - port = prettyprint_addr(&serv->addr, daemon->namebuff); + /* Init edns_pktsz for newly created server records. */ + if (serv->edns_pktsz == 0) + serv->edns_pktsz = daemon->edns_pktsz; + +#ifdef HAVE_DNSSEC + if (option_bool(OPT_DNSSEC_VALID)) + { + if (serv->flags & SERV_HAS_DOMAIN) + { + struct ds_config *ds; + char *domain = serv->domain; + + /* .example.com is valid */ + while (*domain == '.') + domain++; + + for (ds = daemon->ds; ds; ds = ds->next) + if (ds->name[0] != 0 && hostname_isequal(domain, ds->name)) + break; + + if (!ds) + serv->flags &= ~SERV_DO_DNSSEC; + } + else if (serv->flags & SERV_FOR_NODOTS) + serv->flags &= ~SERV_DO_DNSSEC; + } +#endif + port = prettyprint_addr(&serv->addr, daemon->namebuff); + /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */ if (serv->addr.sa.sa_family == AF_INET && serv->addr.in.sin_addr.s_addr == 0) @@ -1450,11 +1507,18 @@ void check_servers(void) } } - if (!(serv->flags & SERV_NO_REBIND)) + if (!(serv->flags & SERV_NO_REBIND) && !(serv->flags & SERV_LITERAL_ADDRESS)) { + if (++count > SERVERS_LOGGED) + continue; + if (serv->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV)) { - char *s1, *s2; + char *s1, *s2, *s3 = ""; +#ifdef HAVE_DNSSEC + if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC)) + s3 = _("(no DNSSEC)"); +#endif if (!(serv->flags & SERV_HAS_DOMAIN)) s1 = _("unqualified"), s2 = _("names"); else if (strlen(serv->domain) == 0) @@ -1466,15 +1530,22 @@ void check_servers(void) my_syslog(LOG_INFO, _("using local addresses only for %s %s"), s1, s2); else if (serv->flags & SERV_USE_RESOLV) my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2); - else if (!(serv->flags & SERV_LITERAL_ADDRESS)) - my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2); + else + my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s %s"), daemon->namebuff, port, s1, s2, s3); } +#ifdef HAVE_LOOP + else if (serv->flags & SERV_LOOP) + my_syslog(LOG_INFO, _("NOT using nameserver %s#%d - query loop detected"), daemon->namebuff, port); +#endif else if (serv->interface[0] != 0) my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, serv->interface); else my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port); } } + + if (count - 1 > SERVERS_LOGGED) + my_syslog(LOG_INFO, _("using %d more nameservers"), count - SERVERS_LOGGED - 1); cleanup_servers(); } @@ -1564,7 +1635,6 @@ int reload_servers(char *fname) return gotone; } -#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_BSD_NETWORK) /* Called when addresses are added or deleted from an interface */ void newaddress(time_t now) { @@ -1589,7 +1659,6 @@ void newaddress(time_t now) #endif } -#endif