1ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
2ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
3ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   This program is free software; you can redistribute it and/or modify
4ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   it under the terms of the GNU General Public License as published by
5ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   the Free Software Foundation; version 2 dated June, 1991, or
6ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   (at your option) version 3 dated 29 June, 2007.
7ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
8ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   This program is distributed in the hope that it will be useful,
9ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   but WITHOUT ANY WARRANTY; without even the implied warranty of
10ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   GNU General Public License for more details.
12ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
13ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   You should have received a copy of the GNU General Public License
14ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   along with this program.  If not, see <http://www.gnu.org/licenses/>.
15ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat*/
16ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
17ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include "dnsmasq.h"
18ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
19ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct frec *lookup_frec(unsigned short id, unsigned int crc);
20ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct frec *lookup_frec_by_sender(unsigned short id,
21ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat					  union mysockaddr *addr,
22ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat					  unsigned int crc);
23ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic unsigned short get_id(int force, unsigned short force_id, unsigned int crc);
24ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic void free_frec(struct frec *f);
25ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct randfd *allocate_rfd(int family);
26ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
27ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* Send a UDP packet with its source address set as "source"
28ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   unless nowild is true, when we just send it with the kernel default */
29ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic void send_from(int fd, int nowild, char *packet, size_t len,
30ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      union mysockaddr *to, struct all_addr *source,
31ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      unsigned int iface)
32ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
33ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct msghdr msg;
34ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct iovec iov[1];
35ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  union {
36ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    struct cmsghdr align; /* this ensures alignment */
37ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(HAVE_LINUX_NETWORK)
38ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
39ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(IP_SENDSRCADDR)
40ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    char control[CMSG_SPACE(sizeof(struct in_addr))];
41ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
42ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6
43ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
44ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
45ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  } control_u;
46ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
47ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  iov[0].iov_base = packet;
48ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  iov[0].iov_len = len;
49ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
50ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_control = NULL;
51ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_controllen = 0;
52ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_flags = 0;
53ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_name = to;
54ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_namelen = sa_len(to);
55ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_iov = iov;
56ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_iovlen = 1;
57ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
58ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (!nowild)
59ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
60ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      struct cmsghdr *cmptr;
61ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      msg.msg_control = &control_u;
62ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      msg.msg_controllen = sizeof(control_u);
63ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      cmptr = CMSG_FIRSTHDR(&msg);
64ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
65ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (to->sa.sa_family == AF_INET)
66ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
67ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(HAVE_LINUX_NETWORK)
68ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  struct in_pktinfo *pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
69ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  pkt->ipi_ifindex = 0;
70ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  pkt->ipi_spec_dst = source->addr.addr4;
71ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
72ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  cmptr->cmsg_level = SOL_IP;
73ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  cmptr->cmsg_type = IP_PKTINFO;
74ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(IP_SENDSRCADDR)
75ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  struct in_addr *a = (struct in_addr *)CMSG_DATA(cmptr);
76ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  *a = source->addr.addr4;
77ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
78ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  cmptr->cmsg_level = IPPROTO_IP;
79ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  cmptr->cmsg_type = IP_SENDSRCADDR;
80ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
81ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
82ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      else
83ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6
84ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
85ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
86ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  pkt->ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
87ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  pkt->ipi6_addr = source->addr.addr6;
88ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
89ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  cmptr->cmsg_type = IPV6_PKTINFO;
90ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  cmptr->cmsg_level = IPV6_LEVEL;
91ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
92ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#else
93ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      iface = 0; /* eliminate warning */
94ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
95ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
96ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
97ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat retry:
98ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (sendmsg(fd, &msg, 0) == -1)
99ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
100ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* certain Linux kernels seem to object to setting the source address in the IPv6 stack
101ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	 by returning EINVAL from sendmsg. In that case, try again without setting the
102ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	 source address, since it will nearly alway be correct anyway.  IPv6 stinks. */
103ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (errno == EINVAL && msg.msg_controllen)
104ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
105ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  msg.msg_controllen = 0;
106ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  goto retry;
107ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
108ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (retry_send())
109ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	goto retry;
110ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
111ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
112ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
113ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic unsigned short search_servers(time_t now, struct all_addr **addrpp,
114ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat				     unsigned short qtype, char *qdomain, int *type, char **domain)
115ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
116ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
117ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* If the query ends in the domain in one of our servers, set
118ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     domain to point to that name. We find the largest match to allow both
119ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     domain.org and sub.domain.org to exist. */
120ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
121ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  unsigned int namelen = strlen(qdomain);
122ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  unsigned int matchlen = 0;
123ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct server *serv;
124ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  unsigned short flags = 0;
125ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
126ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (serv = daemon->servers; serv; serv=serv->next)
127ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    /* domain matches take priority over NODOTS matches */
128ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
129ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      {
130ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
131ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	*type = SERV_FOR_NODOTS;
132ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	if (serv->flags & SERV_NO_ADDR)
133ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  flags = F_NXDOMAIN;
134ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	else if (serv->flags & SERV_LITERAL_ADDRESS)
135ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  {
136ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    if (sflag & qtype)
137ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      {
138ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		flags = sflag;
139ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		if (serv->addr.sa.sa_family == AF_INET)
140ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
141ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6
142ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		else
143ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
144ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
145ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      }
146ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    else if (!flags || (flags & F_NXDOMAIN))
147ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      flags = F_NOERR;
148ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  }
149ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      }
150ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    else if (serv->flags & SERV_HAS_DOMAIN)
151ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      {
152ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	unsigned int domainlen = strlen(serv->domain);
153ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	char *matchstart = qdomain + namelen - domainlen;
154ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	if (namelen >= domainlen &&
155ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    hostname_isequal(matchstart, serv->domain) &&
156ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    domainlen >= matchlen &&
157ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    (domainlen == 0 || namelen == domainlen || *(serv->domain) == '.' || *(matchstart-1) == '.' ))
158ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  {
159ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
160ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    *type = SERV_HAS_DOMAIN;
161ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    *domain = serv->domain;
162ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    matchlen = domainlen;
163ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    if (serv->flags & SERV_NO_ADDR)
164ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      flags = F_NXDOMAIN;
165ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    else if (serv->flags & SERV_LITERAL_ADDRESS)
166ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      {
167ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		if (sflag & qtype)
168ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  {
169ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    flags = sflag;
170ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    if (serv->addr.sa.sa_family == AF_INET)
171ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
172ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6
173ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    else
174ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
175ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
176ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  }
177ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		else if (!flags || (flags & F_NXDOMAIN))
178ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  flags = F_NOERR;
179ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      }
180ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  }
181ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      }
182ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
183ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (flags == 0 && !(qtype & F_BIGNAME) &&
184ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      (daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
185ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    /* don't forward simple names, make exception for NS queries and empty name. */
186ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    flags = F_NXDOMAIN;
187ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
188ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
189ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    flags = F_NOERR;
190ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
191ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (flags)
192ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
193ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      int logflags = 0;
194ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
195ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (flags == F_NXDOMAIN || flags == F_NOERR)
196ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	logflags = F_NEG | qtype;
197ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
198ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      log_query(logflags | flags | F_CONFIG | F_FORWARD, qdomain, *addrpp, NULL);
199ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
200ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
201ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return  flags;
202ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
203ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
204ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic int forward_query(int udpfd, union mysockaddr *udpaddr,
205ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			 struct all_addr *dst_addr, unsigned int dst_iface,
206ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			 HEADER *header, size_t plen, time_t now, struct frec *forward)
207ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
208ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  char *domain = NULL;
209ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  int type = 0;
210ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct all_addr *addrp = NULL;
211ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  unsigned int crc = questions_crc(header, plen, daemon->namebuff);
212ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  unsigned short flags = 0;
213ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  unsigned short gotname = extract_request(header, plen, daemon->namebuff, NULL);
214ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct server *start = NULL;
215ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
216ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* may be no servers available. */
217ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (!daemon->servers)
218ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    forward = NULL;
219ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  else if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, crc)))
220ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
221ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* retry on existing query, send to all available servers  */
222ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      domain = forward->sentto->domain;
223ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      forward->sentto->failed_queries++;
224ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (!(daemon->options & OPT_ORDER))
225ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
226ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  forward->forwardall = 1;
227ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  daemon->last_server = NULL;
228ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
229ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      type = forward->sentto->flags & SERV_TYPE;
230ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (!(start = forward->sentto->next))
231ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	start = daemon->servers; /* at end of list, recycle */
232ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      header->id = htons(forward->new_id);
233ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
234ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  else
235ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
236ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (gotname)
237ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain);
238ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
239ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (!flags && !(forward = get_new_frec(now, NULL)))
240ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	/* table full - server failure. */
241ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	flags = F_NEG;
242ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
243ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (forward)
244ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
245ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  /* force unchanging id for signed packets */
246ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  int is_sign;
247ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  find_pseudoheader(header, plen, NULL, NULL, &is_sign);
248ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
249ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  forward->source = *udpaddr;
250ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  forward->dest = *dst_addr;
251ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  forward->iface = dst_iface;
252ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  forward->orig_id = ntohs(header->id);
253ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  forward->new_id = get_id(is_sign, forward->orig_id, crc);
254ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  forward->fd = udpfd;
255ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  forward->crc = crc;
256ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  forward->forwardall = 0;
257ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  header->id = htons(forward->new_id);
258ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
259ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  /* In strict_order mode, or when using domain specific servers
260ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	     always try servers in the order specified in resolv.conf,
261ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	     otherwise, use the one last known to work. */
262ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
263ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (type != 0  || (daemon->options & OPT_ORDER))
264ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    start = daemon->servers;
265ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  else if (!(start = daemon->last_server) ||
266ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		   daemon->forwardcount++ > FORWARD_TEST ||
267ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		   difftime(now, daemon->forwardtime) > FORWARD_TIME)
268ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
269ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      start = daemon->servers;
270ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      forward->forwardall = 1;
271ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      daemon->forwardcount = 0;
272ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      daemon->forwardtime = now;
273ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
274ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
275ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
276ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
277ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* check for send errors here (no route to host)
278ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     if we fail to send to all nameservers, send back an error
279ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     packet straight away (helps modem users when offline)  */
280ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
281ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (!flags && forward)
282ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
283ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      struct server *firstsentto = start;
284ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      int forwarded = 0;
285ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
286ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      while (1)
287ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
288ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  /* only send to servers dealing with our domain.
289ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	     domain may be NULL, in which case server->domain
290ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	     must be NULL also. */
291ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
292ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (type == (start->flags & SERV_TYPE) &&
293ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
294ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      !(start->flags & SERV_LITERAL_ADDRESS))
295ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
296ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      int fd;
297ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
298ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      /* find server socket to use, may need to get random one. */
299ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      if (start->sfd)
300ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		fd = start->sfd->fd;
301ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      else
302ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		{
303ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6
304ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if (start->addr.sa.sa_family == AF_INET6)
305ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    {
306ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      if (!forward->rfd6 &&
307ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			  !(forward->rfd6 = allocate_rfd(AF_INET6)))
308ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			break;
309ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      daemon->rfd_save = forward->rfd6;
310ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      fd = forward->rfd6->fd;
311ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    }
312ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  else
313ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
314ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    {
315ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      if (!forward->rfd4 &&
316ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			  !(forward->rfd4 = allocate_rfd(AF_INET)))
317ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			break;
318ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      daemon->rfd_save = forward->rfd4;
319ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      fd = forward->rfd4->fd;
320ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    }
32168eff53e7ed9df06f194478930f39b31c7a32458Lorenzo Colitti
32268eff53e7ed9df06f194478930f39b31c7a32458Lorenzo Colitti#ifdef ANDROID
32368eff53e7ed9df06f194478930f39b31c7a32458Lorenzo Colitti		  // Mark the socket so it goes out on the correct network. Note
32468eff53e7ed9df06f194478930f39b31c7a32458Lorenzo Colitti		  // that we never clear the mark, only re-set it the next time we
32568eff53e7ed9df06f194478930f39b31c7a32458Lorenzo Colitti		  // allocate a new random fd. This is because we buffer DNS
32668eff53e7ed9df06f194478930f39b31c7a32458Lorenzo Colitti		  // queries (in daemon->srv_save, daemon->packet_len) and socket
32768eff53e7ed9df06f194478930f39b31c7a32458Lorenzo Colitti		  // file descriptors (in daemon->rfd_save) with the expectation of
32868eff53e7ed9df06f194478930f39b31c7a32458Lorenzo Colitti		  // being able to use them again.
32968eff53e7ed9df06f194478930f39b31c7a32458Lorenzo Colitti		  //
33068eff53e7ed9df06f194478930f39b31c7a32458Lorenzo Colitti		  // Server fds are marked separately in allocate_sfd.
33168eff53e7ed9df06f194478930f39b31c7a32458Lorenzo Colitti		  setsockopt(fd, SOL_SOCKET, SO_MARK, &start->mark, sizeof(start->mark));
33268eff53e7ed9df06f194478930f39b31c7a32458Lorenzo Colitti#endif
333ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		}
33468eff53e7ed9df06f194478930f39b31c7a32458Lorenzo Colitti
335ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      if (sendto(fd, (char *)header, plen, 0,
336ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			 &start->addr.sa,
337ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			 sa_len(&start->addr)) == -1)
338ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		{
339ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if (retry_send())
340ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    continue;
341ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		}
342ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      else
343ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		{
344ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  /* Keep info in case we want to re-send this packet */
345ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  daemon->srv_save = start;
346ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  daemon->packet_len = plen;
347ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
348ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if (!gotname)
349ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    strcpy(daemon->namebuff, "query");
350ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if (start->addr.sa.sa_family == AF_INET)
351ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
352ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			      (struct all_addr *)&start->addr.in.sin_addr, NULL);
353ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6
354ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  else
355ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
356ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			      (struct all_addr *)&start->addr.in6.sin6_addr, NULL);
357ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
358ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  start->queries++;
359ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  forwarded = 1;
360ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  forward->sentto = start;
361ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if (!forward->forwardall)
362ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    break;
363ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  forward->forwardall++;
364ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		}
365ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
366ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
367ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (!(start = start->next))
368ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 	    start = daemon->servers;
369ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
370ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (start == firstsentto)
371ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    break;
372ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
373ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
374ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (forwarded)
375ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	return 1;
376ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
377ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* could not send on, prepare to return */
378ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      header->id = htons(forward->orig_id);
379ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      free_frec(forward); /* cancel */
380ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
381ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
382ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* could not send on, return empty answer or address if known for whole domain */
383ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (udpfd != -1)
384ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
385ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
386ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      send_from(udpfd, daemon->options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr, dst_iface);
387ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
388ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
389ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return 0;
390ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
391ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
392ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic size_t process_reply(HEADER *header, time_t now,
393ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			    struct server *server, size_t n)
394ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
395ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  unsigned char *pheader, *sizep;
396ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  int munged = 0, is_sign;
397ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  size_t plen;
398ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
399ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* If upstream is advertising a larger UDP packet size
400ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     than we allow, trim it so that we don't get overlarge
401ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     requests for the client. We can't do this for signed packets. */
402ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
403ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)) && !is_sign)
404ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
405ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      unsigned short udpsz;
406ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      unsigned char *psave = sizep;
407ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
408ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      GETSHORT(udpsz, sizep);
409ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (udpsz > daemon->edns_pktsz)
410ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	PUTSHORT(daemon->edns_pktsz, psave);
411ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
412ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
413ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (header->opcode != QUERY || (header->rcode != NOERROR && header->rcode != NXDOMAIN))
414ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    return n;
415ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
416ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* Complain loudly if the upstream server is non-recursive. */
417ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (!header->ra && header->rcode == NOERROR && ntohs(header->ancount) == 0 &&
418ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      server && !(server->flags & SERV_WARNED_RECURSIVE))
419ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
420ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      prettyprint_addr(&server->addr, daemon->namebuff);
421ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
422ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (!(daemon->options & OPT_LOG))
423ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	server->flags |= SERV_WARNED_RECURSIVE;
424ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
425ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
426ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (daemon->bogus_addr && header->rcode != NXDOMAIN &&
427ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
428ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
429ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      munged = 1;
430ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      header->rcode = NXDOMAIN;
431ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      header->aa = 0;
432ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
433ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  else
434ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
435ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (header->rcode == NXDOMAIN &&
436ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  extract_request(header, n, daemon->namebuff, NULL) &&
437ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  check_for_local_domain(daemon->namebuff, now))
438ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
439ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  /* if we forwarded a query for a locally known name (because it was for
440ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	     an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
441ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	     since we know that the domain exists, even if upstream doesn't */
442ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  munged = 1;
443ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  header->aa = 1;
444ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  header->rcode = NOERROR;
445ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
446ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
447ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (extract_addresses(header, n, daemon->namebuff, now))
448ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
449ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected"));
450ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  munged = 1;
451ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
452ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
453ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
454ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* do this after extract_addresses. Ensure NODATA reply and remove
455ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     nameserver info. */
456ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
457ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (munged)
458ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
459ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      header->ancount = htons(0);
460ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      header->nscount = htons(0);
461ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      header->arcount = htons(0);
462ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
463ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
464ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
465ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     sections of the packet. Find the new length here and put back pseudoheader
466ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     if it was removed. */
467ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return resize_packet(header, n, pheader, plen);
468ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
469ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
470ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* sets new last_server */
471ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid reply_query(int fd, int family, time_t now)
472ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
473ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* packet from peer server, extract data for cache, and send to
474ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     original requester */
475ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  HEADER *header;
476ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  union mysockaddr serveraddr;
477ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct frec *forward;
478ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  socklen_t addrlen = sizeof(serveraddr);
479ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ssize_t n = recvfrom(fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen);
480ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  size_t nn;
481ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct server *server;
482ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
483ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* packet buffer overwritten */
484ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  daemon->srv_save = NULL;
485ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
486ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* Determine the address of the server replying  so that we can mark that as good */
487ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  serveraddr.sa.sa_family = family;
488ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6
489ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (serveraddr.sa.sa_family == AF_INET6)
490ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    serveraddr.in6.sin6_flowinfo = 0;
491ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
492ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
493ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* spoof check: answer must come from known server, */
494ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (server = daemon->servers; server; server = server->next)
495ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
496ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	sockaddr_isequal(&server->addr, &serveraddr))
497ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      break;
498ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
499ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  header = (HEADER *)daemon->packet;
500ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
501ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (!server ||
502ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      n < (int)sizeof(HEADER) || !header->qr ||
503ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      !(forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff))))
504ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    return;
505ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
506ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  server = forward->sentto;
507ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
508ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
509ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      !(daemon->options & OPT_ORDER) &&
510ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      forward->forwardall == 0)
511ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    /* for broken servers, attempt to send to another one. */
512ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
513ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      unsigned char *pheader;
514ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      size_t plen;
515ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      int is_sign;
516ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
517ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* recreate query from reply */
518ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign);
519ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (!is_sign)
520ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
521ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  header->ancount = htons(0);
522ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  header->nscount = htons(0);
523ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  header->arcount = htons(0);
524ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
525ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
526ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      header->qr = 0;
527ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      header->tc = 0;
528ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      forward_query(-1, NULL, NULL, 0, header, nn, now, forward);
529ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      return;
530ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
531ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
532ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
533ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
534ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if ((forward->sentto->flags & SERV_TYPE) == 0)
535ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
536ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (header->rcode == SERVFAIL || header->rcode == REFUSED)
537ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	server = NULL;
538ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      else
539ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
540ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  struct server *last_server;
541ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
542ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  /* find good server by address if possible, otherwise assume the last one we sent to */
543ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  for (last_server = daemon->servers; last_server; last_server = last_server->next)
544ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
545ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		sockaddr_isequal(&last_server->addr, &serveraddr))
546ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      {
547ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		server = last_server;
548ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		break;
549ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      }
550ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
551ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (!(daemon->options & OPT_ALL_SERVERS))
552ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	daemon->last_server = server;
553ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
554ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
555ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* If the answer is an error, keep the forward record in place in case
556ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     we get a good reply from another server. Kill it when we've
557ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     had replies from all to avoid filling the forwarding table when
558ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     everything is broken */
559ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (forward->forwardall == 0 || --forward->forwardall == 1 ||
560ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      (header->rcode != REFUSED && header->rcode != SERVFAIL))
561ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
562ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if ((nn = process_reply(header, now, server, (size_t)n)))
563ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
564ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  header->id = htons(forward->orig_id);
565ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  header->ra = 1; /* recursion if available */
566ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, nn,
567ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    &forward->source, &forward->dest, forward->iface);
568ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
569ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      free_frec(forward); /* cancel */
570ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
571ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
572ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
573ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
574ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid receive_query(struct listener *listen, time_t now)
575ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
576ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  HEADER *header = (HEADER *)daemon->packet;
577ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  union mysockaddr source_addr;
578ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  unsigned short type;
579ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct all_addr dst_addr;
580ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct in_addr netmask, dst_addr_4;
581ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  size_t m;
582ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  ssize_t n;
583ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  int if_index = 0;
584ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct iovec iov[1];
585ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct msghdr msg;
586ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct cmsghdr *cmptr;
587ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  union {
588ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    struct cmsghdr align; /* this ensures alignment */
589ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6
590ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
591ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
592ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(HAVE_LINUX_NETWORK)
593ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
594ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
595ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    char control[CMSG_SPACE(sizeof(struct in_addr)) +
596ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		 CMSG_SPACE(sizeof(unsigned int))];
597ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(IP_RECVDSTADDR)
598ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    char control[CMSG_SPACE(sizeof(struct in_addr)) +
599ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		 CMSG_SPACE(sizeof(struct sockaddr_dl))];
600ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
601ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  } control_u;
602ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
603ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* packet buffer overwritten */
604ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  daemon->srv_save = NULL;
605ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
606ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (listen->family == AF_INET && (daemon->options & OPT_NOWILD))
607ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
608ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      dst_addr_4 = listen->iface->addr.in.sin_addr;
609ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      netmask = listen->iface->netmask;
610ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
611ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  else
612ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
613ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      dst_addr_4.s_addr = 0;
614ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      netmask.s_addr = 0;
615ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
616ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
617ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  iov[0].iov_base = daemon->packet;
618ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  iov[0].iov_len = daemon->edns_pktsz;
619ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
620ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_control = control_u.control;
621ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_controllen = sizeof(control_u);
622ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_flags = 0;
623ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_name = &source_addr;
624ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_namelen = sizeof(source_addr);
625ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_iov = iov;
626ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  msg.msg_iovlen = 1;
627ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
628ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
629ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    return;
630ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
631ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (n < (int)sizeof(HEADER) ||
632ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      (msg.msg_flags & MSG_TRUNC) ||
633ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      header->qr)
634ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    return;
635ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
636ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  source_addr.sa.sa_family = listen->family;
637ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6
638ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (listen->family == AF_INET6)
639ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    source_addr.in6.sin6_flowinfo = 0;
640ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
641ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
642ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (!(daemon->options & OPT_NOWILD))
643ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
644ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      struct ifreq ifr;
645ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
646ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (msg.msg_controllen < sizeof(struct cmsghdr))
647ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	return;
648ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
649ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(HAVE_LINUX_NETWORK)
650ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (listen->family == AF_INET)
651ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
652ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
653ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
654ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      dst_addr_4 = dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
655ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
656ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
657ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
658ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (listen->family == AF_INET)
659ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
660ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
661ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
662ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      dst_addr_4 = dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
663ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
664ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_SOLARIS_NETWORK
665ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      if_index = *((unsigned int *)CMSG_DATA(cmptr));
666ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#else
667ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
668ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
669ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
670ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
671ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
672ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6
673ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (listen->family == AF_INET6)
674ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
675ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
676ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO)
677ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      {
678ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr;
679ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex;
680ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      }
681ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
682ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
683ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
684ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* enforce available interface configuration */
685ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
686ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
687ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  !iface_check(listen->family, &dst_addr, ifr.ifr_name, &if_index))
688ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	return;
689ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
690ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (listen->family == AF_INET &&
691ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  (daemon->options & OPT_LOCALISE) &&
692ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  ioctl(listen->fd, SIOCGIFNETMASK, &ifr) == -1)
693ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	return;
694ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
695ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
696ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
697ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
698ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (extract_request(header, (size_t)n, daemon->namebuff, &type))
699ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
700ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      char types[20];
701ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
702ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      querystr(types, type);
703ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
704ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (listen->family == AF_INET)
705ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
706ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  (struct all_addr *)&source_addr.in.sin_addr, types);
707ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6
708ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      else
709ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
710ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  (struct all_addr *)&source_addr.in6.sin6_addr, types);
711ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
712ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
713ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
714ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  m = answer_request (header, ((char *) header) + PACKETSZ, (size_t)n,
715ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      dst_addr_4, netmask, now);
716ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (m >= 1)
717ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
718ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      send_from(listen->fd, daemon->options & OPT_NOWILD, (char *)header,
719ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		m, &source_addr, &dst_addr, if_index);
720ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      daemon->local_answer++;
721ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
722ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
723ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			 header, (size_t)n, now, NULL))
724ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    daemon->queries_forwarded++;
725ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  else
726ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    daemon->local_answer++;
727ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
728ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
729ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* The daemon forks before calling this: it should deal with one connection,
730ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   blocking as neccessary, and then return. Note, need to be a bit careful
731ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   about resources for debug mode, when the fork is suppressed: that's
732ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   done by the caller. */
733ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatunsigned char *tcp_request(int confd, time_t now,
734ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			   struct in_addr local_addr, struct in_addr netmask)
735ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
736ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  int size = 0;
737ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  size_t m;
738ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  unsigned short qtype, gotname;
739ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  unsigned char c1, c2;
740ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* Max TCP packet + slop */
741ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
742ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  HEADER *header;
743ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct server *last_server;
744ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
745ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  while (1)
746ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
747ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (!packet ||
748ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
749ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  !(size = c1 << 8 | c2) ||
750ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  !read_write(confd, packet, size, 1))
751ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat       	return packet;
752ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
753ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (size < (int)sizeof(HEADER))
754ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	continue;
755ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
756ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      header = (HEADER *)packet;
757ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
758ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
759ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
760ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  union mysockaddr peer_addr;
761ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  socklen_t peer_len = sizeof(union mysockaddr);
762ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
763ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
764ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
765ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      char types[20];
766ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
767ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      querystr(types, qtype);
768ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
769ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      if (peer_addr.sa.sa_family == AF_INET)
770ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
771ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			  (struct all_addr *)&peer_addr.in.sin_addr, types);
772ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6
773ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      else
774ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
775ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			  (struct all_addr *)&peer_addr.in6.sin6_addr, types);
776ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
777ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
778ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
779ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
780ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* m > 0 if answered from cache */
781ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      m = answer_request(header, ((char *) header) + 65536, (unsigned int)size,
782ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			 local_addr, netmask, now);
783ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
784ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* Do this by steam now we're not in the select() loop */
785ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      check_log_writer(NULL);
786ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
787ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (m == 0)
788ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
789ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  unsigned short flags = 0;
790ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  struct all_addr *addrp = NULL;
791ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  int type = 0;
792ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  char *domain = NULL;
793ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
794ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (gotname)
795ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain);
796ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
797ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (type != 0  || (daemon->options & OPT_ORDER) || !daemon->last_server)
798ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    last_server = daemon->servers;
799ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  else
800ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    last_server = daemon->last_server;
801ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
802ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (!flags && last_server)
803ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    {
804ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      struct server *firstsendto = NULL;
805ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
806ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
807ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      /* Loop round available servers until we succeed in connecting to one.
808ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	         Note that this code subtley ensures that consecutive queries on this connection
809ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	         which can go to the same server, do so. */
810ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	      while (1)
811ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		{
812ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if (!firstsendto)
813ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    firstsendto = last_server;
814ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  else
815ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    {
816ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      if (!(last_server = last_server->next))
817ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			last_server = daemon->servers;
818ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
819ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      if (last_server == firstsendto)
820ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			break;
821ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    }
822ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
823ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  /* server for wrong domain */
824ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if (type != (last_server->flags & SERV_TYPE) ||
825ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
826ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    continue;
827ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
828ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if ((last_server->tcpfd == -1) &&
829ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      (last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) != -1 &&
83068eff53e7ed9df06f194478930f39b31c7a32458Lorenzo Colitti		      (!local_bind(last_server->tcpfd, &last_server->source_addr,
83168eff53e7ed9df06f194478930f39b31c7a32458Lorenzo Colitti				   last_server->interface, last_server->mark, 1) ||
832ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		       connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
833ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    {
834ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      close(last_server->tcpfd);
835ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      last_server->tcpfd = -1;
836ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    }
837ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
838ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if (last_server->tcpfd == -1)
839ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    continue;
840ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
841ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  c1 = size >> 8;
842ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  c2 = size;
843ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
844ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if (!read_write(last_server->tcpfd, &c1, 1, 0) ||
845ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      !read_write(last_server->tcpfd, &c2, 1, 0) ||
846ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      !read_write(last_server->tcpfd, packet, size, 0) ||
847ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      !read_write(last_server->tcpfd, &c1, 1, 1) ||
848ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      !read_write(last_server->tcpfd, &c2, 1, 1))
849ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    {
850ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      close(last_server->tcpfd);
851ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      last_server->tcpfd = -1;
852ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		      continue;
853ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    }
854ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
855ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  m = (c1 << 8) | c2;
856ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if (!read_write(last_server->tcpfd, packet, m, 1))
857ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    return packet;
858ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
859ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if (!gotname)
860ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    strcpy(daemon->namebuff, "query");
861ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if (last_server->addr.sa.sa_family == AF_INET)
862ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
863ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			      (struct all_addr *)&last_server->addr.in.sin_addr, NULL);
864ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6
865ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  else
866ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
867ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat			      (struct all_addr *)&last_server->addr.in6.sin6_addr, NULL);
868ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
869ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
870ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  /* There's no point in updating the cache, since this process will exit and
871ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		     lose the information after a few queries. We make this call for the alias and
872ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		     bogus-nxdomain side-effects. */
873ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  /* If the crc of the question section doesn't match the crc we sent, then
874ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		     someone might be attempting to insert bogus values into the cache by
875ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		     sending replies containing questions and bogus answers. */
876ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
877ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		    m = process_reply(header, now, last_server, (unsigned int)m);
878ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
879ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		  break;
880ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat		}
881ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    }
882ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
883ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  /* In case of local answer or no connections made. */
884ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  if (m == 0)
885ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
886ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
887ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
888ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      check_log_writer(NULL);
889ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
890ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      c1 = m>>8;
891ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      c2 = m;
892ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (!read_write(confd, &c1, 1, 0) ||
893ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  !read_write(confd, &c2, 1, 0) ||
894ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  !read_write(confd, packet, m, 0))
895ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	return packet;
896ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
897ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
898ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
899ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct frec *allocate_frec(time_t now)
900ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
901ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct frec *f;
902ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
903ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
904ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
905ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      f->next = daemon->frec_list;
906ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      f->time = now;
907ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      f->sentto = NULL;
908ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      f->rfd4 = NULL;
909ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6
910ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      f->rfd6 = NULL;
911ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
912ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      daemon->frec_list = f;
913ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
914ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
915ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return f;
916ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
917ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
918ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct randfd *allocate_rfd(int family)
919ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
920ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  static int finger = 0;
921ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  int i;
922ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
923ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* limit the number of sockets we have open to avoid starvation of
924ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     (eg) TFTP. Once we have a reasonable number, randomness should be OK */
925ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
926ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (i = 0; i < RANDOM_SOCKS; i++)
927ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    if (daemon->randomsocks[i].refcount == 0)
928ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      {
929ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	if ((daemon->randomsocks[i].fd = random_sock(family)) == -1)
930ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  break;
931ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
932ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	daemon->randomsocks[i].refcount = 1;
933ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	daemon->randomsocks[i].family = family;
934ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	return &daemon->randomsocks[i];
935ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      }
936ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
937ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* No free ones or cannot get new socket, grab an existing one */
938ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (i = 0; i < RANDOM_SOCKS; i++)
939ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
940ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      int j = (i+finger) % RANDOM_SOCKS;
941ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (daemon->randomsocks[j].refcount != 0 &&
942ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  daemon->randomsocks[j].family == family &&
943ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  daemon->randomsocks[j].refcount != 0xffff)
944ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
945ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  finger = j;
946ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  daemon->randomsocks[j].refcount++;
947ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  return &daemon->randomsocks[j];
948ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
949ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
950ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
951ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return NULL; /* doom */
952ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
953ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
954ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic void free_frec(struct frec *f)
955ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
956ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (f->rfd4 && --(f->rfd4->refcount) == 0)
957ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    close(f->rfd4->fd);
958ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
959ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  f->rfd4 = NULL;
960ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  f->sentto = NULL;
961ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
962ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6
963ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (f->rfd6 && --(f->rfd6->refcount) == 0)
964ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    close(f->rfd6->fd);
965ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
966ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  f->rfd6 = NULL;
967ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif
968ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
969ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
970ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* if wait==NULL return a free or older than TIMEOUT record.
971ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   else return *wait zero if one available, or *wait is delay to
972ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   when the oldest in-use record will expire. Impose an absolute
973ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   limit of 4*TIMEOUT before we wipe things (for random sockets) */
974ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstruct frec *get_new_frec(time_t now, int *wait)
975ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
976ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct frec *f, *oldest, *target;
977ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  int count;
978ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
979ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (wait)
980ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    *wait = 0;
981ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
982ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (f = daemon->frec_list, oldest = NULL, target =  NULL, count = 0; f; f = f->next, count++)
983ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    if (!f->sentto)
984ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      target = f;
985ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    else
986ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      {
987ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	if (difftime(now, f->time) >= 4*TIMEOUT)
988ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  {
989ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    free_frec(f);
990ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	    target = f;
991ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  }
992ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
993ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	if (!oldest || difftime(f->time, oldest->time) <= 0)
994ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  oldest = f;
995ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      }
996ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
997ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (target)
998ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
999ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      target->time = now;
1000ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      return target;
1001ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
1002ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1003ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* can't find empty one, use oldest if there is one
1004ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat     and it's older than timeout */
1005ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
1006ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
1007ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      /* keep stuff for twice timeout if we can by allocating a new
1008ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	 record instead */
1009ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (difftime(now, oldest->time) < 2*TIMEOUT &&
1010ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  count <= daemon->ftabsize &&
1011ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  (f = allocate_frec(now)))
1012ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	return f;
1013ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1014ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (!wait)
1015ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	{
1016ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  free_frec(oldest);
1017ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	  oldest->time = now;
1018ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	}
1019ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      return oldest;
1020ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
1021ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1022ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  /* none available, calculate time 'till oldest record expires */
1023ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (count > daemon->ftabsize)
1024ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
1025ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (oldest && wait)
1026ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	*wait = oldest->time + (time_t)TIMEOUT - now;
1027ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      return NULL;
1028ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
1029ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1030ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (!(f = allocate_frec(now)) && wait)
1031ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    /* wait one second on malloc failure */
1032ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    *wait = 1;
1033ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1034ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return f; /* OK if malloc fails and this is NULL */
1035ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
1036ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1037ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* crc is all-ones if not known. */
1038ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct frec *lookup_frec(unsigned short id, unsigned int crc)
1039ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
1040ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct frec *f;
1041ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1042ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for(f = daemon->frec_list; f; f = f->next)
1043ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    if (f->sentto && f->new_id == id &&
1044ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	(f->crc == crc || crc == 0xffffffff))
1045ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      return f;
1046ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1047ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return NULL;
1048ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
1049ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1050ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct frec *lookup_frec_by_sender(unsigned short id,
1051ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat					  union mysockaddr *addr,
1052ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat					  unsigned int crc)
1053ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
1054ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct frec *f;
1055ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1056ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for(f = daemon->frec_list; f; f = f->next)
1057ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    if (f->sentto &&
1058ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	f->orig_id == id &&
1059ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	f->crc == crc &&
1060ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	sockaddr_isequal(&f->source, addr))
1061ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      return f;
1062ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1063ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return NULL;
1064ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
1065ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1066ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* A server record is going away, remove references to it */
1067ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid server_gone(struct server *server)
1068ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
1069ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  struct frec *f;
1070ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1071ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  for (f = daemon->frec_list; f; f = f->next)
1072ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    if (f->sentto && f->sentto == server)
1073ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      free_frec(f);
1074ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1075ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (daemon->last_server == server)
1076ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    daemon->last_server = NULL;
1077ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1078ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (daemon->srv_save == server)
1079ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    daemon->srv_save = NULL;
1080ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
1081ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1082ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* return unique random ids.
1083ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   For signed packets we can't change the ID without breaking the
1084ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   signing, so we keep the same one. In this case force is set, and this
1085ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat   routine degenerates into killing any conflicting forward record. */
1086ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic unsigned short get_id(int force, unsigned short force_id, unsigned int crc)
1087ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{
1088ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  unsigned short ret = 0;
1089ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1090ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  if (force)
1091ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    {
1092ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      struct frec *f = lookup_frec(force_id, crc);
1093ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      if (f)
1094ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat	free_frec(f); /* free */
1095ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat      ret = force_id;
1096ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    }
1097ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  else do
1098ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat    ret = rand16();
1099ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  while (lookup_frec(ret, crc));
1100ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1101ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat  return ret;
1102ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}
1103ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1104ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1105ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1106ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1107ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat
1108