"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/forward.c" between
dnsmasq-2.80.tar.gz and dnsmasq-2.81.tar.xz

About: Dnsmasq is a lightweight caching DNS forwarder and DHCP server.

forward.c  (dnsmasq-2.80):forward.c  (dnsmasq-2.81.tar.xz)
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley /* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007. (at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
skipping to change at line 29 skipping to change at line 29
static struct frec *lookup_frec(unsigned short id, void *hash); static struct frec *lookup_frec(unsigned short id, void *hash);
static struct frec *lookup_frec_by_sender(unsigned short id, static struct frec *lookup_frec_by_sender(unsigned short id,
union mysockaddr *addr, union mysockaddr *addr,
void *hash); void *hash);
static unsigned short get_id(void); static unsigned short get_id(void);
static void free_frec(struct frec *f); static void free_frec(struct frec *f);
/* Send a UDP packet with its source address set as "source" /* Send a UDP packet with its source address set as "source"
unless nowild is true, when we just send it with the kernel default */ unless nowild is true, when we just send it with the kernel default */
int send_from(int fd, int nowild, char *packet, size_t len, int send_from(int fd, int nowild, char *packet, size_t len,
union mysockaddr *to, struct all_addr *source, union mysockaddr *to, union all_addr *source,
unsigned int iface) unsigned int iface)
{ {
struct msghdr msg; struct msghdr msg;
struct iovec iov[1]; struct iovec iov[1];
union { union {
struct cmsghdr align; /* this ensures alignment */ struct cmsghdr align; /* this ensures alignment */
#if defined(HAVE_LINUX_NETWORK) #if defined(HAVE_LINUX_NETWORK)
char control[CMSG_SPACE(sizeof(struct in_pktinfo))]; char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
#elif defined(IP_SENDSRCADDR) #elif defined(IP_SENDSRCADDR)
char control[CMSG_SPACE(sizeof(struct in_addr))]; char control[CMSG_SPACE(sizeof(struct in_addr))];
#endif #endif
#ifdef HAVE_IPV6
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
#endif
} control_u; } control_u;
iov[0].iov_base = packet; iov[0].iov_base = packet;
iov[0].iov_len = len; iov[0].iov_len = len;
msg.msg_control = NULL; msg.msg_control = NULL;
msg.msg_controllen = 0; msg.msg_controllen = 0;
msg.msg_flags = 0; msg.msg_flags = 0;
msg.msg_name = to; msg.msg_name = to;
msg.msg_namelen = sa_len(to); msg.msg_namelen = sa_len(to);
skipping to change at line 69 skipping to change at line 67
struct cmsghdr *cmptr; struct cmsghdr *cmptr;
msg.msg_control = &control_u; msg.msg_control = &control_u;
msg.msg_controllen = sizeof(control_u); msg.msg_controllen = sizeof(control_u);
cmptr = CMSG_FIRSTHDR(&msg); cmptr = CMSG_FIRSTHDR(&msg);
if (to->sa.sa_family == AF_INET) if (to->sa.sa_family == AF_INET)
{ {
#if defined(HAVE_LINUX_NETWORK) #if defined(HAVE_LINUX_NETWORK)
struct in_pktinfo p; struct in_pktinfo p;
p.ipi_ifindex = 0; p.ipi_ifindex = 0;
p.ipi_spec_dst = source->addr.addr4; p.ipi_spec_dst = source->addr4;
msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
memcpy(CMSG_DATA(cmptr), &p, sizeof(p)); memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinf o)); cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
cmptr->cmsg_level = IPPROTO_IP; cmptr->cmsg_level = IPPROTO_IP;
cmptr->cmsg_type = IP_PKTINFO; cmptr->cmsg_type = IP_PKTINFO;
#elif defined(IP_SENDSRCADDR) #elif defined(IP_SENDSRCADDR)
memcpy(CMSG_DATA(cmptr), &(source->addr.addr4), sizeof(source->addr.add msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
r4)); memcpy(CMSG_DATA(cmptr), &(source->addr4), sizeof(source->addr4));
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr)) cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
;
cmptr->cmsg_level = IPPROTO_IP; cmptr->cmsg_level = IPPROTO_IP;
cmptr->cmsg_type = IP_SENDSRCADDR; cmptr->cmsg_type = IP_SENDSRCADDR;
#endif #endif
} }
else else
#ifdef HAVE_IPV6
{ {
struct in6_pktinfo p; struct in6_pktinfo p;
p.ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local add rs */ p.ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local add rs */
p.ipi6_addr = source->addr.addr6; p.ipi6_addr = source->addr6;
msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
memcpy(CMSG_DATA(cmptr), &p, sizeof(p)); memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktin fo)); cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
cmptr->cmsg_type = daemon->v6pktinfo; cmptr->cmsg_type = daemon->v6pktinfo;
cmptr->cmsg_level = IPPROTO_IPV6; cmptr->cmsg_level = IPPROTO_IPV6;
} }
#else
(void)iface; /* eliminate warning */
#endif
} }
while (retry_send(sendmsg(fd, &msg, 0))); while (retry_send(sendmsg(fd, &msg, 0)));
/* If interface is still in DAD, EINVAL results - ignore that. */ if (errno != 0)
if (errno != 0 && errno != EINVAL)
{ {
my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno)); #ifdef HAVE_LINUX_NETWORK
/* If interface is still in DAD, EINVAL results - ignore that. */
if (errno != EINVAL)
my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno));
#endif
return 0; return 0;
} }
return 1; return 1;
} }
static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne d int qtype, static unsigned int search_servers(time_t now, union all_addr **addrpp, unsigned int qtype,
char *qdomain, int *type, char **domain, int * norebind) char *qdomain, int *type, char **domain, int * norebind)
{ {
/* If the query ends in the domain in one of our servers, set /* If the query ends in the domain in one of our servers, set
domain to point to that name. We find the largest match to allow both domain to point to that name. We find the largest match to allow both
domain.org and sub.domain.org to exist. */ domain.org and sub.domain.org to exist. */
unsigned int namelen = strlen(qdomain); unsigned int namelen = strlen(qdomain);
unsigned int matchlen = 0; unsigned int matchlen = 0;
struct server *serv; struct server *serv;
unsigned int flags = 0; unsigned int flags = 0;
static struct all_addr zero; static union all_addr zero;
for (serv = daemon->servers; serv; serv=serv->next) for (serv = daemon->servers; serv; serv=serv->next)
if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC)) if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC))
continue; continue;
/* domain matches take priority over NODOTS matches */ /* domain matches take priority over NODOTS matches */
else if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !str chr(qdomain, '.') && namelen != 0) else if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !str chr(qdomain, '.') && namelen != 0)
{ {
unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6 ; unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6 ;
*type = SERV_FOR_NODOTS; *type = SERV_FOR_NODOTS;
if (serv->flags & SERV_NO_ADDR) if ((serv->flags & SERV_NO_REBIND) && norebind)
*norebind = 1;
else if (serv->flags & SERV_NO_ADDR)
flags = F_NXDOMAIN; flags = F_NXDOMAIN;
else if (serv->flags & SERV_LITERAL_ADDRESS) else if (serv->flags & SERV_LITERAL_ADDRESS)
{ {
/* literal address = '#' -> return all-zero address for IPv4 and IPv6 */ /* literal address = '#' -> return all-zero address for IPv4 and IPv6 */
if ((serv->flags & SERV_USE_RESOLV) && (qtype & (F_IPV6 | F_IPV4))) if ((serv->flags & SERV_USE_RESOLV) && (qtype & (F_IPV6 | F_IPV4)))
{ {
memset(&zero, 0, sizeof(zero)); memset(&zero, 0, sizeof(zero));
flags = qtype; flags = qtype;
*addrpp = &zero; *addrpp = &zero;
} }
else if (sflag & qtype) else if (sflag & qtype)
{ {
flags = sflag; flags = sflag;
if (serv->addr.sa.sa_family == AF_INET) if (serv->addr.sa.sa_family == AF_INET)
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr; *addrpp = (union all_addr *)&serv->addr.in.sin_addr;
#ifdef HAVE_IPV6
else else
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr; *addrpp = (union all_addr *)&serv->addr.in6.sin6_addr;
#endif
} }
else if (!flags || (flags & F_NXDOMAIN)) else if (!flags || (flags & F_NXDOMAIN))
flags = F_NOERR; flags = F_NOERR;
} }
} }
else if (serv->flags & SERV_HAS_DOMAIN) else if (serv->flags & SERV_HAS_DOMAIN)
{ {
unsigned int domainlen = strlen(serv->domain); unsigned int domainlen = strlen(serv->domain);
char *matchstart = qdomain + namelen - domainlen; char *matchstart = qdomain + namelen - domainlen;
if (namelen >= domainlen && if (namelen >= domainlen &&
skipping to change at line 206 skipping to change at line 206
if ((serv->flags & SERV_USE_RESOLV) && (qtype & (F_IPV6 | F_IPV4))) if ((serv->flags & SERV_USE_RESOLV) && (qtype & (F_IPV6 | F_IPV4)))
{ {
memset(&zero, 0, sizeof(zero)); memset(&zero, 0, sizeof(zero));
flags = qtype; flags = qtype;
*addrpp = &zero; *addrpp = &zero;
} }
else if (sflag & qtype) else if (sflag & qtype)
{ {
flags = sflag; flags = sflag;
if (serv->addr.sa.sa_family == AF_INET) if (serv->addr.sa.sa_family == AF_INET)
*addrpp = (struct all_addr *)&serv->addr.in.sin_add *addrpp = (union all_addr *)&serv->addr.in.sin_addr
r; ;
#ifdef HAVE_IPV6
else else
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_a *addrpp = (union all_addr *)&serv->addr.in6.sin6_ad
ddr; dr;
#endif
} }
else if (!flags || (flags & F_NXDOMAIN)) else if (!flags || (flags & F_NXDOMAIN))
flags = F_NOERR; flags = F_NOERR;
} }
else else
flags = 0; flags = 0;
} }
} }
} }
} }
skipping to change at line 239 skipping to change at line 237
if (flags) if (flags)
{ {
if (flags == F_NXDOMAIN || flags == F_NOERR) if (flags == F_NXDOMAIN || flags == F_NOERR)
log_query(flags | qtype | F_NEG | F_CONFIG | F_FORWARD, qdomain, NULL, N ULL); log_query(flags | qtype | F_NEG | F_CONFIG | F_FORWARD, qdomain, NULL, N ULL);
else else
{ {
/* handle F_IPV4 and F_IPV6 set on ANY query to 0.0.0.0/:: domain. */ /* handle F_IPV4 and F_IPV6 set on ANY query to 0.0.0.0/:: domain. */
if (flags & F_IPV4) if (flags & F_IPV4)
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, qdomain, *addrpp , NULL); log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, qdomain, *addrpp , NULL);
#ifdef HAVE_IPV6
if (flags & F_IPV6) if (flags & F_IPV6)
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, qdomain, *addrpp , NULL); log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, qdomain, *addrpp , NULL);
#endif
} }
} }
else if ((*type) & SERV_USE_RESOLV) else if ((*type) & SERV_USE_RESOLV)
{ {
*type = 0; /* use normal servers for this domain */ *type = 0; /* use normal servers for this domain */
*domain = NULL; *domain = NULL;
} }
return flags; return flags;
} }
static int forward_query(int udpfd, union mysockaddr *udpaddr, static int forward_query(int udpfd, union mysockaddr *udpaddr,
struct all_addr *dst_addr, unsigned int dst_iface, union all_addr *dst_addr, unsigned int dst_iface,
struct dns_header *header, size_t plen, time_t now, struct dns_header *header, size_t plen, time_t now,
struct frec *forward, int ad_reqd, int do_bit) struct frec *forward, int ad_reqd, int do_bit)
{ {
char *domain = NULL; char *domain = NULL;
int type = SERV_DO_DNSSEC, norebind = 0; int type = SERV_DO_DNSSEC, norebind = 0;
struct all_addr *addrp = NULL; union all_addr *addrp = NULL;
unsigned int flags = 0; unsigned int flags = 0;
struct server *start = NULL; struct server *start = NULL;
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
void *hash = hash_questions(header, plen, daemon->namebuff); void *hash = hash_questions(header, plen, daemon->namebuff);
int do_dnssec = 0; int do_dnssec = 0;
#else #else
unsigned int crc = questions_crc(header, plen, daemon->namebuff); unsigned int crc = questions_crc(header, plen, daemon->namebuff);
void *hash = &crc; void *hash = &crc;
#endif #endif
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL); unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
skipping to change at line 304 skipping to change at line 300
forward = forward->blocking_query; forward = forward->blocking_query;
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header); blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
plen = forward->stash_len; plen = forward->stash_len;
forward->flags |= FREC_TEST_PKTSZ; forward->flags |= FREC_TEST_PKTSZ;
if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign) if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
PUTSHORT(SAFE_PKTSZ, pheader); PUTSHORT(SAFE_PKTSZ, pheader);
if (forward->sentto->addr.sa.sa_family == AF_INET) if (forward->sentto->addr.sa.sa_family == AF_INET)
log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *) log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (union all_addr *)&
&forward->sentto->addr.in.sin_addr, "dnssec"); forward->sentto->addr.in.sin_addr, "dnssec");
#ifdef HAVE_IPV6
else else
log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (struct all_addr *) log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (union all_addr *)&
&forward->sentto->addr.in6.sin6_addr, "dnssec"); forward->sentto->addr.in6.sin6_addr, "dnssec");
#endif
if (forward->sentto->sfd) if (forward->sentto->sfd)
fd = forward->sentto->sfd->fd; fd = forward->sentto->sfd->fd;
else else
{ {
#ifdef HAVE_IPV6
if (forward->sentto->addr.sa.sa_family == AF_INET6) if (forward->sentto->addr.sa.sa_family == AF_INET6)
fd = forward->rfd6->fd; fd = forward->rfd6->fd;
else else
#endif
fd = forward->rfd4->fd; fd = forward->rfd4->fd;
} }
while (retry_send(sendto(fd, (char *)header, plen, 0, while (retry_send(sendto(fd, (char *)header, plen, 0,
&forward->sentto->addr.sa, &forward->sentto->addr.sa,
sa_len(&forward->sentto->addr)))); sa_len(&forward->sentto->addr))));
return 1; return 1;
} }
#endif #endif
skipping to change at line 358 skipping to change at line 350
{ {
if (gotname) if (gotname)
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &do main, &norebind); flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &do main, &norebind);
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
do_dnssec = type & SERV_DO_DNSSEC; do_dnssec = type & SERV_DO_DNSSEC;
#endif #endif
type &= ~SERV_DO_DNSSEC; type &= ~SERV_DO_DNSSEC;
if (daemon->servers && !flags) if (daemon->servers && !flags)
forward = get_new_frec(now, NULL, 0); forward = get_new_frec(now, NULL, NULL);
/* table full - flags == 0, return REFUSED */ /* table full - flags == 0, return REFUSED */
if (forward) if (forward)
{ {
forward->source = *udpaddr; forward->source = *udpaddr;
forward->dest = *dst_addr; forward->dest = *dst_addr;
forward->iface = dst_iface; forward->iface = dst_iface;
forward->orig_id = ntohs(header->id); forward->orig_id = ntohs(header->id);
forward->new_id = get_id(); forward->new_id = get_id();
forward->fd = udpfd; forward->fd = udpfd;
skipping to change at line 478 skipping to change at line 470
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain) ) && (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain) ) &&
!(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP))) !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
{ {
int fd; int fd;
/* find server socket to use, may need to get random one. */ /* find server socket to use, may need to get random one. */
if (start->sfd) if (start->sfd)
fd = start->sfd->fd; fd = start->sfd->fd;
else else
{ {
#ifdef HAVE_IPV6
if (start->addr.sa.sa_family == AF_INET6) if (start->addr.sa.sa_family == AF_INET6)
{ {
if (!forward->rfd6 && if (!forward->rfd6 &&
!(forward->rfd6 = allocate_rfd(AF_INET6))) !(forward->rfd6 = allocate_rfd(AF_INET6)))
break; break;
daemon->rfd_save = forward->rfd6; daemon->rfd_save = forward->rfd6;
fd = forward->rfd6->fd; fd = forward->rfd6->fd;
} }
else else
#endif
{ {
if (!forward->rfd4 && if (!forward->rfd4 &&
!(forward->rfd4 = allocate_rfd(AF_INET))) !(forward->rfd4 = allocate_rfd(AF_INET)))
break; break;
daemon->rfd_save = forward->rfd4; daemon->rfd_save = forward->rfd4;
fd = forward->rfd4->fd; fd = forward->rfd4->fd;
} }
#ifdef HAVE_CONNTRACK #ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connectio n. */ /* Copy connection mark of incoming query to outgoing connectio n. */
skipping to change at line 543 skipping to change at line 533
#endif #endif
/* Keep info in case we want to re-send this packet */ /* Keep info in case we want to re-send this packet */
daemon->srv_save = start; daemon->srv_save = start;
daemon->packet_len = plen; daemon->packet_len = plen;
if (!gotname) if (!gotname)
strcpy(daemon->namebuff, "query"); strcpy(daemon->namebuff, "query");
if (start->addr.sa.sa_family == AF_INET) if (start->addr.sa.sa_family == AF_INET)
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff, log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&start->addr.in.sin_addr, NULL); (union all_addr *)&start->addr.in.sin_addr, NULL);
#ifdef HAVE_IPV6
else else
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff, log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&start->addr.in6.sin6_addr, NULL (union all_addr *)&start->addr.in6.sin6_addr, NULL
); );
#endif
start->queries++; start->queries++;
forwarded = 1; forwarded = 1;
forward->sentto = start; forward->sentto = start;
if (!forward->forwardall) if (!forward->forwardall)
break; break;
forward->forwardall++; forward->forwardall++;
} }
} }
if (!(start = start->next)) if (!(start = start->next))
skipping to change at line 679 skipping to change at line 667
/* RFC 4035 sect 4.6 para 3 */ /* RFC 4035 sect 4.6 para 3 */
if (!is_sign && !option_bool(OPT_DNSSEC_PROXY)) if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
header->hb4 &= ~HB4_AD; header->hb4 &= ~HB4_AD;
if (OPCODE(header) != QUERY) if (OPCODE(header) != QUERY)
return resize_packet(header, n, pheader, plen); return resize_packet(header, n, pheader, plen);
if (rcode != NOERROR && rcode != NXDOMAIN) if (rcode != NOERROR && rcode != NXDOMAIN)
{ {
struct all_addr a; union all_addr a;
a.addr.rcode.rcode = rcode; a.log.rcode = rcode;
log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL); log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
return resize_packet(header, n, pheader, plen); return resize_packet(header, n, pheader, plen);
} }
/* Complain loudly if the upstream server is non-recursive. */ /* Complain loudly if the upstream server is non-recursive. */
if (!(header->hb4 & HB4_RA) && rcode == NOERROR && if (!(header->hb4 & HB4_RA) && rcode == NOERROR &&
server && !(server->flags & SERV_WARNED_RECURSIVE)) server && !(server->flags & SERV_WARNED_RECURSIVE))
{ {
prettyprint_addr(&server->addr, daemon->namebuff); prettyprint_addr(&server->addr, daemon->namebuff);
skipping to change at line 791 skipping to change at line 779
struct server *server; struct server *server;
void *hash; void *hash;
#ifndef HAVE_DNSSEC #ifndef HAVE_DNSSEC
unsigned int crc; unsigned int crc;
#endif #endif
/* packet buffer overwritten */ /* packet buffer overwritten */
daemon->srv_save = NULL; daemon->srv_save = NULL;
/* Determine the address of the server replying so that we can mark that as g ood */ /* Determine the address of the server replying so that we can mark that as g ood */
serveraddr.sa.sa_family = family; if ((serveraddr.sa.sa_family = family) == AF_INET6)
#ifdef HAVE_IPV6
if (serveraddr.sa.sa_family == AF_INET6)
serveraddr.in6.sin6_flowinfo = 0; serveraddr.in6.sin6_flowinfo = 0;
#endif
header = (struct dns_header *)daemon->packet; header = (struct dns_header *)daemon->packet;
if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR)) if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
return; return;
/* spoof check: answer must come from known server, */ /* spoof check: answer must come from known server, */
for (server = daemon->servers; server; server = server->next) for (server = daemon->servers; server; server = server->next)
if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) && if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
sockaddr_isequal(&server->addr, &serveraddr)) sockaddr_isequal(&server->addr, &serveraddr))
skipping to change at line 880 skipping to change at line 865
if ((start->flags & SERV_TYPE) == 0 && if ((start->flags & SERV_TYPE) == 0 &&
(start->flags & SERV_DO_DNSSEC)) (start->flags & SERV_DO_DNSSEC))
break; break;
} }
if (start->sfd) if (start->sfd)
fd = start->sfd->fd; fd = start->sfd->fd;
else else
{ {
#ifdef HAVE_IPV6
if (start->addr.sa.sa_family == AF_INET6) if (start->addr.sa.sa_family == AF_INET6)
{ {
/* may have changed family */ /* may have changed family */
if (!forward->rfd6) if (!forward->rfd6)
forward->rfd6 = allocate_rfd(AF_INET6); forward->rfd6 = allocate_rfd(AF_INET6);
fd = forward->rfd6->fd; fd = forward->rfd6->fd;
} }
else else
#endif
{ {
/* may have changed family */ /* may have changed family */
if (!forward->rfd4) if (!forward->rfd4)
forward->rfd4 = allocate_rfd(AF_INET); forward->rfd4 = allocate_rfd(AF_INET);
fd = forward->rfd4->fd; fd = forward->rfd4->fd;
} }
} }
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_SEC_QUERY, (void *)header, (size_t)plen, NULL, &start-
>addr);
#endif
while (retry_send(sendto(fd, (char *)header, plen, 0, while (retry_send(sendto(fd, (char *)header, plen, 0,
&start->addr.sa, &start->addr.sa,
sa_len(&start->addr)))); sa_len(&start->addr))));
if (start->addr.sa.sa_family == AF_INET) if (start->addr.sa.sa_family == AF_INET)
log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *) log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (union all_addr *)&
&start->addr.in.sin_addr, "dnssec"); start->addr.in.sin_addr, "dnssec");
#ifdef HAVE_IPV6
else else
log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (struct all_addr *) log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (union all_addr *)&
&start->addr.in6.sin6_addr, "dnssec"); start->addr.in6.sin6_addr, "dnssec");
#endif
return; return;
} }
#endif #endif
/* In strict order mode, there must be a server later in the chain /* In strict order mode, there must be a server later in the chain
left to send to, otherwise without the forwardall mechanism, left to send to, otherwise without the forwardall mechanism,
code further on will cycle around the list forwever if they code further on will cycle around the list forwever if they
all return REFUSED. Note that server is always non-NULL before all return REFUSED. Note that server is always non-NULL before
this executes. */ this executes. */
skipping to change at line 971 skipping to change at line 956
break; break;
} }
} }
if (!option_bool(OPT_ALL_SERVERS)) if (!option_bool(OPT_ALL_SERVERS))
daemon->last_server = server; daemon->last_server = server;
} }
/* We tried resending to this server with a smaller maximum size and got an an swer. /* We tried resending to this server with a smaller maximum size and got an an swer.
Make that permanent. To avoid reduxing the packet size for a single dropped packet, Make that permanent. To avoid reduxing the packet size for a single dropped packet,
only do this when we get a truncated answer, or one larger than the safe si ze. */ only do this when we get a truncated answer, or one larger than the safe si ze. */
if (server && server->edns_pktsz > SAFE_PKTSZ && (forward->flags & FREC_TEST_P KTSZ) && if (forward->sentto->edns_pktsz > SAFE_PKTSZ && (forward->flags & FREC_TEST_PK TSZ) &&
((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ)) ((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
{ {
server->edns_pktsz = SAFE_PKTSZ; forward->sentto->edns_pktsz = SAFE_PKTSZ;
server->pktsz_reduced = now; forward->sentto->pktsz_reduced = now;
prettyprint_addr(&server->addr, daemon->addrbuff); prettyprint_addr(&forward->sentto->addr, daemon->addrbuff);
my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %d "), daemon->addrbuff, SAFE_PKTSZ); my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %d "), daemon->addrbuff, SAFE_PKTSZ);
} }
/* If the answer is an error, keep the forward record in place in case /* If the answer is an error, keep the forward record in place in case
we get a good reply from another server. Kill it when we've we get a good reply from another server. Kill it when we've
had replies from all to avoid filling the forwarding table when had replies from all to avoid filling the forwarding table when
everything is broken */ everything is broken */
if (forward->forwardall == 0 || --forward->forwardall == 1 || if (forward->forwardall == 0 || --forward->forwardall == 1 || RCODE(header) !=
(RCODE(header) != REFUSED && RCODE(header) != SERVFAIL)) REFUSED)
{ {
int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0; int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
if (option_bool(OPT_NO_REBIND)) if (option_bool(OPT_NO_REBIND))
check_rebind = !(forward->flags & FREC_NOREBIND); check_rebind = !(forward->flags & FREC_NOREBIND);
/* Don't cache replies where DNSSEC validation was turned off, either /* Don't cache replies where DNSSEC validation was turned off, either
the upstream server told us so, or the original query specified it. * / the upstream server told us so, or the original query specified it. * /
if ((header->hb4 & HB4_CD) || (forward->flags & FREC_CHECKING_DISABLED)) if ((header->hb4 & HB4_CD) || (forward->flags & FREC_CHECKING_DISABLED))
no_cache_dnssec = 1; no_cache_dnssec = 1;
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
if (server && (server->flags & SERV_DO_DNSSEC) && if ((forward->sentto->flags & SERV_DO_DNSSEC) &&
option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISAB LED)) option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISAB LED))
{ {
int status = 0; int status = 0;
/* We've had a reply already, which we're validating. Ignore this dupli cate */ /* We've had a reply already, which we're validating. Ignore this dupli cate */
if (forward->blocking_query) if (forward->blocking_query)
return; return;
/* Truncated answer can't be validated. /* Truncated answer can't be validated.
If this is an answer to a DNSSEC-generated query, we still If this is an answer to a DNSSEC-generated query, we still
skipping to change at line 1028 skipping to change at line 1012
would invite infinite loops, since the answers to DNSKEY and DS queries would invite infinite loops, since the answers to DNSKEY and DS queries
will not be cached, so they'll be repeated. */ will not be cached, so they'll be repeated. */
if (status != STAT_BOGUS && status != STAT_TRUNCATED && status != S TAT_ABANDONED) if (status != STAT_BOGUS && status != STAT_TRUNCATED && status != S TAT_ABANDONED)
{ {
if (forward->flags & FREC_DNSKEY_QUERY) if (forward->flags & FREC_DNSKEY_QUERY)
status = dnssec_validate_by_ds(now, header, n, daemon->namebu ff, daemon->keyname, forward->class); status = dnssec_validate_by_ds(now, header, n, daemon->namebu ff, daemon->keyname, forward->class);
else if (forward->flags & FREC_DS_QUERY) else if (forward->flags & FREC_DS_QUERY)
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class); status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
else else
status = dnssec_validate_reply(now, header, n, daemon->namebu ff, daemon->keyname, &forward->class, status = dnssec_validate_reply(now, header, n, daemon->namebu ff, daemon->keyname, &forward->class,
!option_bool(OPT_DNSSEC_IGN_NS !option_bool(OPT_DNSSEC_IGN_NS
) && (server->flags & SERV_DO_DNSSEC), ) && (forward->sentto->flags & SERV_DO_DNSSEC),
NULL, NULL); NULL, NULL, NULL);
#ifdef HAVE_DUMPFILE #ifdef HAVE_DUMPFILE
if (status == STAT_BOGUS) if (status == STAT_BOGUS)
dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QU ERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS, dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QU ERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
header, (size_t)n, &serveraddr, NULL); header, (size_t)n, &serveraddr, NULL);
#endif #endif
} }
/* Can't validate, as we're missing key data. Put this /* Can't validate, as we're missing key data. Put this
answer aside, whilst we get that. */ answer aside, whilst we get that. */
if (status == STAT_NEED_DS || status == STAT_NEED_KEY) if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
skipping to change at line 1055 skipping to change at line 1039
blockdata_free(forward->stash); blockdata_free(forward->stash);
/* Now save reply pending receipt of key data */ /* Now save reply pending receipt of key data */
if (!(forward->stash = blockdata_alloc((char *)header, n))) if (!(forward->stash = blockdata_alloc((char *)header, n)))
return; return;
forward->stash_len = n; forward->stash_len = n;
/* Find the original query that started it all.... */ /* Find the original query that started it all.... */
for (orig = forward; orig->dependent; orig = orig->dependent); for (orig = forward; orig->dependent; orig = orig->dependent);
if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL /* Make sure we don't expire and free the orig frec during the
, 1))) allocation of a new one. */
if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL
, orig)))
status = STAT_ABANDONED; status = STAT_ABANDONED;
else else
{ {
int querytype, fd, type = SERV_DO_DNSSEC; int querytype, fd, type = SERV_DO_DNSSEC;
struct frec *next = new->next; struct frec *next = new->next;
char *domain; char *domain;
*new = *forward; /* copy everything, then overwrite */ *new = *forward; /* copy everything, then overwrite */
new->next = next; new->next = next;
new->blocking_query = NULL; new->blocking_query = NULL;
/* Find server to forward to. This will normally be the /* Find server to forward to. This will normally be the
same as for the original query, but may be another if same as for the original query, but may be another if
servers for domains are involved. */ servers for domains are involved. */
if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0) if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0)
{ {
struct server *start = server, *new_server = NULL; struct server *start, *new_server = NULL;
start = server = forward->sentto;
while (1) while (1)
{ {
if (type == (start->flags & (SERV_TYPE | SERV_DO_DN SSEC)) && if (type == (start->flags & (SERV_TYPE | SERV_DO_DN SSEC)) &&
((type & SERV_TYPE) != SERV_HAS_DOMAIN || hostn ame_isequal(domain, start->domain)) && ((type & SERV_TYPE) != SERV_HAS_DOMAIN || hostn ame_isequal(domain, start->domain)) &&
!(start->flags & (SERV_LITERAL_ADDRESS | SERV_L OOP))) !(start->flags & (SERV_LITERAL_ADDRESS | SERV_L OOP)))
{ {
new_server = start; new_server = start;
if (server == start) if (server == start)
{ {
skipping to change at line 1100 skipping to change at line 1087
if (start == server) if (start == server)
break; break;
} }
if (new_server) if (new_server)
server = new_server; server = new_server;
} }
new->sentto = server; new->sentto = server;
new->rfd4 = NULL; new->rfd4 = NULL;
#ifdef HAVE_IPV6
new->rfd6 = NULL; new->rfd6 = NULL;
#endif
new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HA S_EXTRADATA); new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HA S_EXTRADATA);
new->forwardall = 0; new->forwardall = 0;
new->dependent = forward; /* to find query awaiting new one . */ new->dependent = forward; /* to find query awaiting new one . */
forward->blocking_query = new; /* for garbage cleaning */ forward->blocking_query = new; /* for garbage cleaning */
/* validate routines leave name of required record in daemo n->keyname */ /* validate routines leave name of required record in daemo n->keyname */
if (status == STAT_NEED_KEY) if (status == STAT_NEED_KEY)
{ {
new->flags |= FREC_DNSKEY_QUERY; new->flags |= FREC_DNSKEY_QUERY;
querytype = T_DNSKEY; querytype = T_DNSKEY;
skipping to change at line 1124 skipping to change at line 1109
else else
{ {
new->flags |= FREC_DS_QUERY; new->flags |= FREC_DS_QUERY;
querytype = T_DS; querytype = T_DS;
} }
nn = dnssec_generate_query(header,((unsigned char *) header ) + server->edns_pktsz, nn = dnssec_generate_query(header,((unsigned char *) header ) + server->edns_pktsz,
daemon->keyname, forward->class, querytype, server->edns_pktsz); daemon->keyname, forward->class, querytype, server->edns_pktsz);
if (server->addr.sa.sa_family == AF_INET) if (server->addr.sa.sa_family == AF_INET)
log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, daemon->keyname, (struct all_addr *)&(server->addr.in.sin_addr), log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, daemon->keyname, (union all_addr *)&(server->addr.in.sin_addr),
querystr("dnssec-query", querytype)); querystr("dnssec-query", querytype));
#ifdef HAVE_IPV6
else else
log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, daemon->keyname, (struct all_addr *)&(server->addr.in6.sin6_addr), log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, daemon->keyname, (union all_addr *)&(server->addr.in6.sin6_addr),
querystr("dnssec-query", querytype)); querystr("dnssec-query", querytype));
#endif
if ((hash = hash_questions(header, nn, daemon->namebuff))) if ((hash = hash_questions(header, nn, daemon->namebuff)))
memcpy(new->hash, hash, HASH_SIZE); memcpy(new->hash, hash, HASH_SIZE);
new->new_id = get_id(); new->new_id = get_id();
header->id = htons(new->new_id); header->id = htons(new->new_id);
/* Save query for retransmission */ /* Save query for retransmission */
new->stash = blockdata_alloc((char *)header, nn); new->stash = blockdata_alloc((char *)header, nn);
new->stash_len = nn; new->stash_len = nn;
/* Don't resend this. */ /* Don't resend this. */
daemon->srv_save = NULL; daemon->srv_save = NULL;
if (server->sfd) if (server->sfd)
fd = server->sfd->fd; fd = server->sfd->fd;
else else
{ {
fd = -1; fd = -1;
#ifdef HAVE_IPV6
if (server->addr.sa.sa_family == AF_INET6) if (server->addr.sa.sa_family == AF_INET6)
{ {
if (new->rfd6 || (new->rfd6 = allocate_rfd(AF_INET6 ))) if (new->rfd6 || (new->rfd6 = allocate_rfd(AF_INET6 )))
fd = new->rfd6->fd; fd = new->rfd6->fd;
} }
else else
#endif
{ {
if (new->rfd4 || (new->rfd4 = allocate_rfd(AF_INET) )) if (new->rfd4 || (new->rfd4 = allocate_rfd(AF_INET) ))
fd = new->rfd4->fd; fd = new->rfd4->fd;
} }
} }
if (fd != -1) if (fd != -1)
{ {
#ifdef HAVE_CONNTRACK #ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing c onnection. */ /* Copy connection mark of incoming query to outgoing c onnection. */
skipping to change at line 1231 skipping to change at line 1212
} }
if (status == STAT_SECURE) if (status == STAT_SECURE)
cache_secure = 1; cache_secure = 1;
else if (status == STAT_BOGUS) else if (status == STAT_BOGUS)
{ {
no_cache_dnssec = 1; no_cache_dnssec = 1;
bogusanswer = 1; bogusanswer = 1;
} }
} }
#endif #endif
/* restore CD bit to the value in the query */ /* restore CD bit to the value in the query */
if (forward->flags & FREC_CHECKING_DISABLED) if (forward->flags & FREC_CHECKING_DISABLED)
header->hb4 |= HB4_CD; header->hb4 |= HB4_CD;
else else
header->hb4 &= ~HB4_CD; header->hb4 &= ~HB4_CD;
if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_reb ind, no_cache_dnssec, cache_secure, bogusanswer, if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_reb ind, no_cache_dnssec, cache_secure, bogusanswer,
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION, forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
skipping to change at line 1276 skipping to change at line 1258
free_frec(forward); /* cancel */ free_frec(forward); /* cancel */
} }
} }
void receive_query(struct listener *listen, time_t now) void receive_query(struct listener *listen, time_t now)
{ {
struct dns_header *header = (struct dns_header *)daemon->packet; struct dns_header *header = (struct dns_header *)daemon->packet;
union mysockaddr source_addr; union mysockaddr source_addr;
unsigned char *pheader; unsigned char *pheader;
unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */ unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
struct all_addr dst_addr; union all_addr dst_addr;
struct in_addr netmask, dst_addr_4; struct in_addr netmask, dst_addr_4;
size_t m; size_t m;
ssize_t n; ssize_t n;
int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0; int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
#ifdef HAVE_AUTH #ifdef HAVE_AUTH
int local_auth = 0; int local_auth = 0;
#endif #endif
struct iovec iov[1]; struct iovec iov[1];
struct msghdr msg; struct msghdr msg;
struct cmsghdr *cmptr; struct cmsghdr *cmptr;
union { union {
struct cmsghdr align; /* this ensures alignment */ struct cmsghdr align; /* this ensures alignment */
#ifdef HAVE_IPV6
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
#endif
#if defined(HAVE_LINUX_NETWORK) #if defined(HAVE_LINUX_NETWORK)
char control[CMSG_SPACE(sizeof(struct in_pktinfo))]; char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK) #elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
char control[CMSG_SPACE(sizeof(struct in_addr)) + char control[CMSG_SPACE(sizeof(struct in_addr)) +
CMSG_SPACE(sizeof(unsigned int))]; CMSG_SPACE(sizeof(unsigned int))];
#elif defined(IP_RECVDSTADDR) #elif defined(IP_RECVDSTADDR)
char control[CMSG_SPACE(sizeof(struct in_addr)) + char control[CMSG_SPACE(sizeof(struct in_addr)) +
CMSG_SPACE(sizeof(struct sockaddr_dl))]; CMSG_SPACE(sizeof(struct sockaddr_dl))];
#endif #endif
} control_u; } control_u;
#ifdef HAVE_IPV6
/* Can always get recvd interface for IPv6 */ /* Can always get recvd interface for IPv6 */
int check_dst = !option_bool(OPT_NOWILD) || listen->family == AF_INET6; int check_dst = !option_bool(OPT_NOWILD) || listen->family == AF_INET6;
#else
int check_dst = !option_bool(OPT_NOWILD);
#endif
/* packet buffer overwritten */ /* packet buffer overwritten */
daemon->srv_save = NULL; daemon->srv_save = NULL;
dst_addr_4.s_addr = dst_addr.addr.addr4.s_addr = 0; dst_addr_4.s_addr = dst_addr.addr4.s_addr = 0;
netmask.s_addr = 0; netmask.s_addr = 0;
if (option_bool(OPT_NOWILD) && listen->iface) if (option_bool(OPT_NOWILD) && listen->iface)
{ {
auth_dns = listen->iface->dns_auth; auth_dns = listen->iface->dns_auth;
if (listen->family == AF_INET) if (listen->family == AF_INET)
{ {
dst_addr_4 = dst_addr.addr.addr4 = listen->iface->addr.in.sin_addr; dst_addr_4 = dst_addr.addr4 = listen->iface->addr.in.sin_addr;
netmask = listen->iface->netmask; netmask = listen->iface->netmask;
} }
} }
iov[0].iov_base = daemon->packet; iov[0].iov_base = daemon->packet;
iov[0].iov_len = daemon->edns_pktsz; iov[0].iov_len = daemon->edns_pktsz;
msg.msg_control = control_u.control; msg.msg_control = control_u.control;
msg.msg_controllen = sizeof(control_u); msg.msg_controllen = sizeof(control_u);
msg.msg_flags = 0; msg.msg_flags = 0;
skipping to change at line 1358 skipping to change at line 1334
source_addr.sa.sa_family = listen->family; source_addr.sa.sa_family = listen->family;
if (listen->family == AF_INET) if (listen->family == AF_INET)
{ {
/* Source-port == 0 is an error, we can't send back to that. /* Source-port == 0 is an error, we can't send back to that.
http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */ http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
if (source_addr.in.sin_port == 0) if (source_addr.in.sin_port == 0)
return; return;
} }
#ifdef HAVE_IPV6
else else
{ {
/* Source-port == 0 is an error, we can't send back to that. */ /* Source-port == 0 is an error, we can't send back to that. */
if (source_addr.in6.sin6_port == 0) if (source_addr.in6.sin6_port == 0)
return; return;
source_addr.in6.sin6_flowinfo = 0; source_addr.in6.sin6_flowinfo = 0;
} }
#endif
/* We can be configured to only accept queries from at-most-one-hop-away addre sses. */ /* We can be configured to only accept queries from at-most-one-hop-away addre sses. */
if (option_bool(OPT_LOCAL_SERVICE)) if (option_bool(OPT_LOCAL_SERVICE))
{ {
struct addrlist *addr; struct addrlist *addr;
#ifdef HAVE_IPV6
if (listen->family == AF_INET6) if (listen->family == AF_INET6)
{ {
for (addr = daemon->interface_addrs; addr; addr = addr->next) for (addr = daemon->interface_addrs; addr; addr = addr->next)
if ((addr->flags & ADDRLIST_IPV6) && if ((addr->flags & ADDRLIST_IPV6) &&
is_same_net6(&addr->addr.addr.addr6, &source_addr.in6.sin6_addr, addr->prefixlen)) is_same_net6(&addr->addr.addr6, &source_addr.in6.sin6_addr, addr- >prefixlen))
break; break;
} }
else else
#endif
{ {
struct in_addr netmask; struct in_addr netmask;
for (addr = daemon->interface_addrs; addr; addr = addr->next) for (addr = daemon->interface_addrs; addr; addr = addr->next)
{ {
netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen)); netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
if (!(addr->flags & ADDRLIST_IPV6) && if (!(addr->flags & ADDRLIST_IPV6) &&
is_same_net(addr->addr.addr.addr4, source_addr.in.sin_addr, net mask)) is_same_net(addr->addr.addr4, source_addr.in.sin_addr, netmask) )
break; break;
} }
} }
if (!addr) if (!addr)
{ {
static int warned = 0; static int warned = 0;
if (!warned) if (!warned)
{ {
my_syslog(LOG_WARNING, _("Ignoring query from non-local network")); my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
warned = 1; warned = 1;
skipping to change at line 1421 skipping to change at line 1394
#if defined(HAVE_LINUX_NETWORK) #if defined(HAVE_LINUX_NETWORK)
if (listen->family == AF_INET) if (listen->family == AF_INET)
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr) ) for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr) )
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO) if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
{ {
union { union {
unsigned char *c; unsigned char *c;
struct in_pktinfo *p; struct in_pktinfo *p;
} p; } p;
p.c = CMSG_DATA(cmptr); p.c = CMSG_DATA(cmptr);
dst_addr_4 = dst_addr.addr.addr4 = p.p->ipi_spec_dst; dst_addr_4 = dst_addr.addr4 = p.p->ipi_spec_dst;
if_index = p.p->ipi_ifindex; if_index = p.p->ipi_ifindex;
} }
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF) #elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
if (listen->family == AF_INET) if (listen->family == AF_INET)
{ {
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmpt r)) for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmpt r))
{ {
union { union {
unsigned char *c; unsigned char *c;
unsigned int *i; unsigned int *i;
struct in_addr *a; struct in_addr *a;
#ifndef HAVE_SOLARIS_NETWORK #ifndef HAVE_SOLARIS_NETWORK
struct sockaddr_dl *s; struct sockaddr_dl *s;
#endif #endif
} p; } p;
p.c = CMSG_DATA(cmptr); p.c = CMSG_DATA(cmptr);
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECV DSTADDR) if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECV DSTADDR)
dst_addr_4 = dst_addr.addr.addr4 = *(p.a); dst_addr_4 = dst_addr.addr4 = *(p.a);
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP _RECVIF) else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP _RECVIF)
#ifdef HAVE_SOLARIS_NETWORK #ifdef HAVE_SOLARIS_NETWORK
if_index = *(p.i); if_index = *(p.i);
#else #else
if_index = p.s->sdl_index; if_index = p.s->sdl_index;
#endif #endif
} }
} }
#endif #endif
#ifdef HAVE_IPV6
if (listen->family == AF_INET6) if (listen->family == AF_INET6)
{ {
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmpt r)) for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmpt r))
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon-> v6pktinfo) if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon-> v6pktinfo)
{ {
union { union {
unsigned char *c; unsigned char *c;
struct in6_pktinfo *p; struct in6_pktinfo *p;
} p; } p;
p.c = CMSG_DATA(cmptr); p.c = CMSG_DATA(cmptr);
dst_addr.addr.addr6 = p.p->ipi6_addr; dst_addr.addr6 = p.p->ipi6_addr;
if_index = p.p->ipi6_ifindex; if_index = p.p->ipi6_ifindex;
} }
} }
#endif
/* enforce available interface configuration */ /* enforce available interface configuration */
if (!indextoname(listen->fd, if_index, ifr.ifr_name)) if (!indextoname(listen->fd, if_index, ifr.ifr_name))
return; return;
if (!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns)) if (!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
{ {
if (!option_bool(OPT_CLEVERBIND)) if (!option_bool(OPT_CLEVERBIND))
enumerate_interfaces(0); enumerate_interfaces(0);
skipping to change at line 1529 skipping to change at line 1500
if (extract_request(header, (size_t)n, daemon->namebuff, &type)) if (extract_request(header, (size_t)n, daemon->namebuff, &type))
{ {
#ifdef HAVE_AUTH #ifdef HAVE_AUTH
struct auth_zone *zone; struct auth_zone *zone;
#endif #endif
char *types = querystr(auth_dns ? "auth" : "query", type); char *types = querystr(auth_dns ? "auth" : "query", type);
if (listen->family == AF_INET) if (listen->family == AF_INET)
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff, log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&source_addr.in.sin_addr, types); (union all_addr *)&source_addr.in.sin_addr, types);
#ifdef HAVE_IPV6
else else
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff, log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&source_addr.in6.sin6_addr, types); (union all_addr *)&source_addr.in6.sin6_addr, types);
#endif
#ifdef HAVE_AUTH #ifdef HAVE_AUTH
/* find queries for zones we're authoritative for, and answer them directl y */ /* find queries for zones we're authoritative for, and answer them directl y */
if (!auth_dns && !option_bool(OPT_LOCALISE)) if (!auth_dns && !option_bool(OPT_LOCALISE))
for (zone = daemon->auth_zones; zone; zone = zone->next) for (zone = daemon->auth_zones; zone; zone = zone->next)
if (in_zone(zone, daemon->namebuff, NULL)) if (in_zone(zone, daemon->namebuff, NULL))
{ {
auth_dns = 1; auth_dns = 1;
local_auth = 1; local_auth = 1;
break; break;
skipping to change at line 1643 skipping to change at line 1612
/* limit the amount of work we do, to avoid cycling forever on loops in th e DNS */ /* limit the amount of work we do, to avoid cycling forever on loops in th e DNS */
if (--(*keycount) == 0) if (--(*keycount) == 0)
new_status = STAT_ABANDONED; new_status = STAT_ABANDONED;
else if (status == STAT_NEED_KEY) else if (status == STAT_NEED_KEY)
new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class); new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
else if (status == STAT_NEED_DS) else if (status == STAT_NEED_DS)
new_status = dnssec_validate_ds(now, header, n, name, keyname, class); new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
else else
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class, new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
!option_bool(OPT_DNSSEC_IGN_NS) && (se rver->flags & SERV_DO_DNSSEC), !option_bool(OPT_DNSSEC_IGN_NS) && (se rver->flags & SERV_DO_DNSSEC),
NULL, NULL); NULL, NULL, NULL);
if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY) if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
break; break;
/* Can't validate because we need a key/DS whose name now in keyname. /* Can't validate because we need a key/DS whose name now in keyname.
Make query for same, and recurse to validate */ Make query for same, and recurse to validate */
if (!packet) if (!packet)
{ {
packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16)); packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
payload = &packet[2]; payload = &packet[2];
skipping to change at line 1680 skipping to change at line 1649
same as for the original query, but may be another if same as for the original query, but may be another if
servers for domains are involved. */ servers for domains are involved. */
if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) ! = 0) if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) ! = 0)
{ {
new_status = STAT_ABANDONED; new_status = STAT_ABANDONED;
break; break;
} }
while (1) while (1)
{ {
int data_sent = 0;
if (!firstsendto) if (!firstsendto)
firstsendto = server; firstsendto = server;
else else
{ {
if (!(server = server->next)) if (!(server = server->next))
server = daemon->servers; server = daemon->servers;
if (server == firstsendto) if (server == firstsendto)
{ {
/* can't find server to accept our query. */ /* can't find server to accept our query. */
new_status = STAT_ABANDONED; new_status = STAT_ABANDONED;
skipping to change at line 1712 skipping to change at line 1683
{ {
if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1) if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
continue; /* No good, next server */ continue; /* No good, next server */
#ifdef HAVE_CONNTRACK #ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connection. * / /* Copy connection mark of incoming query to outgoing connection. * /
if (have_mark) if (have_mark)
setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsi gned int)); setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsi gned int));
#endif #endif
if (!local_bind(server->tcpfd, &server->source_addr, server->inter if (!local_bind(server->tcpfd, &server->source_addr, server->inter
face, 0, 1) || face, 0, 1))
connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) {
== -1) close(server->tcpfd);
server->tcpfd = -1;
continue; /* No good, next server */
}
#ifdef MSG_FASTOPEN
while(retry_send(sendto(server->tcpfd, packet, m + sizeof(u16),
MSG_FASTOPEN, &server->addr.sa, sa_len(&ser
ver->addr))));
if (errno == 0)
data_sent = 1;
#endif
if (!data_sent && connect(server->tcpfd, &server->addr.sa, sa_len(&
server->addr)) == -1)
{ {
close(server->tcpfd); close(server->tcpfd);
server->tcpfd = -1; server->tcpfd = -1;
continue; /* No good, next server */ continue; /* No good, next server */
} }
server->flags &= ~SERV_GOT_TCP; server->flags &= ~SERV_GOT_TCP;
} }
if (!read_write(server->tcpfd, packet, m + sizeof(u16), 0) || if ((!data_sent && !read_write(server->tcpfd, packet, m + sizeof(u16), 0)) ||
!read_write(server->tcpfd, &c1, 1, 1) || !read_write(server->tcpfd, &c1, 1, 1) ||
!read_write(server->tcpfd, &c2, 1, 1) || !read_write(server->tcpfd, &c2, 1, 1) ||
!read_write(server->tcpfd, payload, (c1 << 8) | c2, 1)) !read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
{ {
close(server->tcpfd); close(server->tcpfd);
server->tcpfd = -1; server->tcpfd = -1;
/* We get data then EOF, reopen connection to same server, /* We get data then EOF, reopen connection to same server,
else try next. This avoids DoS from a server which accepts else try next. This avoids DoS from a server which accepts
connections and then closes them. */ connections and then closes them. */
if (server->flags & SERV_GOT_TCP) if (server->flags & SERV_GOT_TCP)
goto retry; goto retry;
else else
continue; continue;
} }
if (server->addr.sa.sa_family == AF_INET) if (server->addr.sa.sa_family == AF_INET)
log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, keyname, (struct all_addr *) &(server->addr.in.sin_addr), log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, keyname, (union all_addr *)& (server->addr.in.sin_addr),
querystr("dnssec-query", new_status == STAT_NEED_KEY ? T_DN SKEY : T_DS)); querystr("dnssec-query", new_status == STAT_NEED_KEY ? T_DN SKEY : T_DS));
#ifdef HAVE_IPV6
else else
log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, keyname, (struct all_addr *) &(server->addr.in6.sin6_addr), log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, keyname, (union all_addr *)& (server->addr.in6.sin6_addr),
querystr("dnssec-query", new_status == STAT_NEED_KEY ? T_DN SKEY : T_DS)); querystr("dnssec-query", new_status == STAT_NEED_KEY ? T_DN SKEY : T_DS));
#endif
server->flags |= SERV_GOT_TCP; server->flags |= SERV_GOT_TCP;
m = (c1 << 8) | c2; m = (c1 << 8) | c2;
new_status = tcp_key_recurse(now, new_status, new_header, m, class, nam e, keyname, server, have_mark, mark, keycount); new_status = tcp_key_recurse(now, new_status, new_header, m, class, nam e, keyname, server, have_mark, mark, keycount);
break; break;
} }
if (new_status != STAT_OK) if (new_status != STAT_OK)
break; break;
skipping to change at line 1809 skipping to change at line 1792
(void)mark; (void)mark;
(void)have_mark; (void)have_mark;
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1) if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
return packet; return packet;
#ifdef HAVE_CONNTRACK #ifdef HAVE_CONNTRACK
/* Get connection mark of incoming query to set on outgoing connections. */ /* Get connection mark of incoming query to set on outgoing connections. */
if (option_bool(OPT_CONNTRACK)) if (option_bool(OPT_CONNTRACK))
{ {
struct all_addr local; union all_addr local;
#ifdef HAVE_IPV6
if (local_addr->sa.sa_family == AF_INET6) if (local_addr->sa.sa_family == AF_INET6)
local.addr.addr6 = local_addr->in6.sin6_addr; local.addr6 = local_addr->in6.sin6_addr;
else else
#endif local.addr4 = local_addr->in.sin_addr;
local.addr.addr4 = local_addr->in.sin_addr;
have_mark = get_incoming_mark(&peer_addr, &local, 1, &mark); have_mark = get_incoming_mark(&peer_addr, &local, 1, &mark);
} }
#endif #endif
/* We can be configured to only accept queries from at-most-one-hop-away addre sses. */ /* We can be configured to only accept queries from at-most-one-hop-away addre sses. */
if (option_bool(OPT_LOCAL_SERVICE)) if (option_bool(OPT_LOCAL_SERVICE))
{ {
struct addrlist *addr; struct addrlist *addr;
#ifdef HAVE_IPV6
if (peer_addr.sa.sa_family == AF_INET6) if (peer_addr.sa.sa_family == AF_INET6)
{ {
for (addr = daemon->interface_addrs; addr; addr = addr->next) for (addr = daemon->interface_addrs; addr; addr = addr->next)
if ((addr->flags & ADDRLIST_IPV6) && if ((addr->flags & ADDRLIST_IPV6) &&
is_same_net6(&addr->addr.addr.addr6, &peer_addr.in6.sin6_addr, ad dr->prefixlen)) is_same_net6(&addr->addr.addr6, &peer_addr.in6.sin6_addr, addr->p refixlen))
break; break;
} }
else else
#endif
{ {
struct in_addr netmask; struct in_addr netmask;
for (addr = daemon->interface_addrs; addr; addr = addr->next) for (addr = daemon->interface_addrs; addr; addr = addr->next)
{ {
netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen)); netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
if (!(addr->flags & ADDRLIST_IPV6) && if (!(addr->flags & ADDRLIST_IPV6) &&
is_same_net(addr->addr.addr.addr4, peer_addr.in.sin_addr, netma sk)) is_same_net(addr->addr.addr4, peer_addr.in.sin_addr, netmask))
break; break;
} }
} }
if (!addr) if (!addr)
{ {
my_syslog(LOG_WARNING, _("Ignoring query from non-local network")); my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
return packet; return packet;
} }
} }
skipping to change at line 1888 skipping to change at line 1869
if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuf f, &qtype))) if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuf f, &qtype)))
{ {
#ifdef HAVE_AUTH #ifdef HAVE_AUTH
struct auth_zone *zone; struct auth_zone *zone;
#endif #endif
char *types = querystr(auth_dns ? "auth" : "query", qtype); char *types = querystr(auth_dns ? "auth" : "query", qtype);
if (peer_addr.sa.sa_family == AF_INET) if (peer_addr.sa.sa_family == AF_INET)
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff, log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&peer_addr.in.sin_addr, types); (union all_addr *)&peer_addr.in.sin_addr, types);
#ifdef HAVE_IPV6
else else
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff, log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&peer_addr.in6.sin6_addr, types); (union all_addr *)&peer_addr.in6.sin6_addr, types);
#endif
#ifdef HAVE_AUTH #ifdef HAVE_AUTH
/* find queries for zones we're authoritative for, and answer them dire ctly */ /* find queries for zones we're authoritative for, and answer them dire ctly */
if (!auth_dns && !option_bool(OPT_LOCALISE)) if (!auth_dns && !option_bool(OPT_LOCALISE))
for (zone = daemon->auth_zones; zone; zone = zone->next) for (zone = daemon->auth_zones; zone; zone = zone->next)
if (in_zone(zone, daemon->namebuff, NULL)) if (in_zone(zone, daemon->namebuff, NULL))
{ {
auth_dns = 1; auth_dns = 1;
local_auth = 1; local_auth = 1;
break; break;
skipping to change at line 1949 skipping to change at line 1928
/* m > 0 if answered from cache */ /* m > 0 if answered from cache */
m = answer_request(header, ((char *) header) + 65536, (size_t)size, m = answer_request(header, ((char *) header) + 65536, (size_t)size,
dst_addr_4, netmask, now, ad_reqd, do_bit, have_pse udoheader); dst_addr_4, netmask, now, ad_reqd, do_bit, have_pse udoheader);
/* Do this by steam now we're not in the select() loop */ /* Do this by steam now we're not in the select() loop */
check_log_writer(1); check_log_writer(1);
if (m == 0) if (m == 0)
{ {
unsigned int flags = 0; unsigned int flags = 0;
struct all_addr *addrp = NULL; union all_addr *addrp = NULL;
int type = SERV_DO_DNSSEC; int type = SERV_DO_DNSSEC;
char *domain = NULL; char *domain = NULL;
unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NU LL, NULL); unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NU LL, NULL);
size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet); size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
if (gotname) if (gotname)
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &t ype, &domain, &norebind); flags = search_servers(now, &addrp, gotname, daemon->namebuff, &t ype, &domain, &norebind);
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
skipping to change at line 2000 skipping to change at line 1979
else else
memset(hash, 0, HASH_SIZE); memset(hash, 0, HASH_SIZE);
#else #else
unsigned int crc = questions_crc(header, (unsigned int)size, da emon->namebuff); unsigned int crc = questions_crc(header, (unsigned int)size, da emon->namebuff);
#endif #endif
/* Loop round available servers until we succeed in connecting to one. /* Loop round available servers until we succeed in connecting to one.
Note that this code subtly ensures that consecutive queries on this connection Note that this code subtly ensures that consecutive queries on this connection
which can go to the same server, do so. */ which can go to the same server, do so. */
while (1) while (1)
{ {
int data_sent = 0;
if (!firstsendto) if (!firstsendto)
firstsendto = last_server; firstsendto = last_server;
else else
{ {
if (!(last_server = last_server->next)) if (!(last_server = last_server->next))
last_server = daemon->servers; last_server = daemon->servers;
if (last_server == firstsendto) if (last_server == firstsendto)
break; break;
} }
/* server for wrong domain */ /* server for wrong domain */
if (type != (last_server->flags & SERV_TYPE) || if (type != (last_server->flags & SERV_TYPE) ||
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, l ast_server->domain)) || (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, l ast_server->domain)) ||
(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP ))) (last_server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP )))
continue; continue;
retry: retry:
*length = htons(size);
if (last_server->tcpfd == -1) if (last_server->tcpfd == -1)
{ {
if ((last_server->tcpfd = socket(last_server->addr.sa.s a_family, SOCK_STREAM, 0)) == -1) if ((last_server->tcpfd = socket(last_server->addr.sa.s a_family, SOCK_STREAM, 0)) == -1)
continue; continue;
#ifdef HAVE_CONNTRACK #ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing c onnection. */ /* Copy connection mark of incoming query to outgoing c onnection. */
if (have_mark) if (have_mark)
setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, & mark, sizeof(unsigned int)); setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, & mark, sizeof(unsigned int));
#endif #endif
if ((!local_bind(last_server->tcpfd, &last_server->sou if ((!local_bind(last_server->tcpfd, &last_server->sou
rce_addr, last_server->interface, 0, 1) || rce_addr, last_server->interface, 0, 1)))
connect(last_server->tcpfd, &last_server->addr.sa, {
sa_len(&last_server->addr)) == -1)) close(last_server->tcpfd);
last_server->tcpfd = -1;
continue;
}
#ifdef MSG_FASTOPEN
while(retry_send(sendto(last_server->tcpfd, packet, s
ize + sizeof(u16),
MSG_FASTOPEN, &last_server->a
ddr.sa, sa_len(&last_server->addr))));
if (errno == 0)
data_sent = 1;
#endif
if (!data_sent && connect(last_server->tcpfd, &last_s
erver->addr.sa, sa_len(&last_server->addr)) == -1)
{ {
close(last_server->tcpfd); close(last_server->tcpfd);
last_server->tcpfd = -1; last_server->tcpfd = -1;
continue; continue;
} }
last_server->flags &= ~SERV_GOT_TCP; last_server->flags &= ~SERV_GOT_TCP;
} }
*length = htons(size);
/* get query name again for logging - may have been overwri tten */ /* get query name again for logging - may have been overwri tten */
if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype))) if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
strcpy(daemon->namebuff, "query"); strcpy(daemon->namebuff, "query");
if (!read_write(last_server->tcpfd, packet, size + sizeof(u 16), 0) || if ((!data_sent && !read_write(last_server->tcpfd, packet, size + sizeof(u16), 0)) ||
!read_write(last_server->tcpfd, &c1, 1, 1) || !read_write(last_server->tcpfd, &c1, 1, 1) ||
!read_write(last_server->tcpfd, &c2, 1, 1) || !read_write(last_server->tcpfd, &c2, 1, 1) ||
!read_write(last_server->tcpfd, payload, (c1 << 8) | c2 , 1)) !read_write(last_server->tcpfd, payload, (c1 << 8) | c2 , 1))
{ {
close(last_server->tcpfd); close(last_server->tcpfd);
last_server->tcpfd = -1; last_server->tcpfd = -1;
/* We get data then EOF, reopen connection to same serv er, /* We get data then EOF, reopen connection to same serv er,
else try next. This avoids DoS from a server which a ccepts else try next. This avoids DoS from a server which a ccepts
connections and then closes them. */ connections and then closes them. */
if (last_server->flags & SERV_GOT_TCP) if (last_server->flags & SERV_GOT_TCP)
skipping to change at line 2068 skipping to change at line 2063
else else
continue; continue;
} }
last_server->flags |= SERV_GOT_TCP; last_server->flags |= SERV_GOT_TCP;
m = (c1 << 8) | c2; m = (c1 << 8) | c2;
if (last_server->addr.sa.sa_family == AF_INET) if (last_server->addr.sa.sa_family == AF_INET)
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff , log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff ,
(struct all_addr *)&last_server->addr.in.sin_ad (union all_addr *)&last_server->addr.in.sin_add
dr, NULL); r, NULL);
#ifdef HAVE_IPV6
else else
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff , log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff ,
(struct all_addr *)&last_server->addr.in6.sin6_ (union all_addr *)&last_server->addr.in6.sin6_a
addr, NULL); ddr, NULL);
#endif
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC)) if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC))
{ {
int keycount = DNSSEC_WORK; /* Limit to number of DNSSE C questions, to catch loops and avoid filling cache. */ int keycount = DNSSEC_WORK; /* Limit to number of DNSSE C questions, to catch loops and avoid filling cache. */
int status = tcp_key_recurse(now, STAT_OK, header, m, 0 , daemon->namebuff, daemon->keyname, int status = tcp_key_recurse(now, STAT_OK, header, m, 0 , daemon->namebuff, daemon->keyname,
last_server, have_mark, ma rk, &keycount); last_server, have_mark, ma rk, &keycount);
char *result, *domain = "result"; char *result, *domain = "result";
if (status == STAT_ABANDONED) if (status == STAT_ABANDONED)
skipping to change at line 2172 skipping to change at line 2165
{ {
struct frec *f; struct frec *f;
if ((f = (struct frec *)whine_malloc(sizeof(struct frec)))) if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
{ {
f->next = daemon->frec_list; f->next = daemon->frec_list;
f->time = now; f->time = now;
f->sentto = NULL; f->sentto = NULL;
f->rfd4 = NULL; f->rfd4 = NULL;
f->flags = 0; f->flags = 0;
#ifdef HAVE_IPV6
f->rfd6 = NULL; f->rfd6 = NULL;
#endif
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
f->dependent = NULL; f->dependent = NULL;
f->blocking_query = NULL; f->blocking_query = NULL;
f->stash = NULL; f->stash = NULL;
#endif #endif
daemon->frec_list = f; daemon->frec_list = f;
} }
return f; return f;
} }
skipping to change at line 2234 skipping to change at line 2225
if (rfd && --(rfd->refcount) == 0) if (rfd && --(rfd->refcount) == 0)
close(rfd->fd); close(rfd->fd);
} }
static void free_frec(struct frec *f) static void free_frec(struct frec *f)
{ {
free_rfd(f->rfd4); free_rfd(f->rfd4);
f->rfd4 = NULL; f->rfd4 = NULL;
f->sentto = NULL; f->sentto = NULL;
f->flags = 0; f->flags = 0;
#ifdef HAVE_IPV6
free_rfd(f->rfd6); free_rfd(f->rfd6);
f->rfd6 = NULL; f->rfd6 = NULL;
#endif
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
if (f->stash) if (f->stash)
{ {
blockdata_free(f->stash); blockdata_free(f->stash);
f->stash = NULL; f->stash = NULL;
} }
/* Anything we're waiting on is pointless now, too */ /* Anything we're waiting on is pointless now, too */
if (f->blocking_query) if (f->blocking_query)
free_frec(f->blocking_query); free_frec(f->blocking_query);
f->blocking_query = NULL; f->blocking_query = NULL;
f->dependent = NULL; f->dependent = NULL;
#endif #endif
} }
/* if wait==NULL return a free or older than TIMEOUT record. /* if wait==NULL return a free or older than TIMEOUT record.
else return *wait zero if one available, or *wait is delay to else return *wait zero if one available, or *wait is delay to
when the oldest in-use record will expire. Impose an absolute when the oldest in-use record will expire. Impose an absolute
limit of 4*TIMEOUT before we wipe things (for random sockets). limit of 4*TIMEOUT before we wipe things (for random sockets).
If force is set, always return a result, even if we have If force is non-NULL, always return a result, even if we have
to allocate above the limit. */ to allocate above the limit, and never free the record pointed
struct frec *get_new_frec(time_t now, int *wait, int force) to by the force argument. */
struct frec *get_new_frec(time_t now, int *wait, struct frec *force)
{ {
struct frec *f, *oldest, *target; struct frec *f, *oldest, *target;
int count; int count;
if (wait) if (wait)
*wait = 0; *wait = 0;
for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f ->next, count++) for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f ->next, count++)
if (!f->sentto) if (!f->sentto)
target = f; target = f;
else else
{ {
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
/* Don't free DNSSEC sub-queries here, as we may end up with /* Don't free DNSSEC sub-queries here, as we may end up with
dangling references to them. They'll go when their "real" query dangling references to them. They'll go when their "real" query
is freed. */ is freed. */
if (!f->dependent) if (!f->dependent && f != force)
#endif #endif
{ {
if (difftime(now, f->time) >= 4*TIMEOUT) if (difftime(now, f->time) >= 4*TIMEOUT)
{ {
free_frec(f); free_frec(f);
target = f; target = f;
} }
if (!oldest || difftime(f->time, oldest->time) <= 0) if (!oldest || difftime(f->time, oldest->time) <= 0)
oldest = f; oldest = f;
 End of changes. 108 change blocks. 
157 lines changed or deleted 149 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)