forward.c revision ffd68729961f7383f2e35494a03ccdef20f86c98
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 } 321ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 322ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 323ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (sendto(fd, (char *)header, plen, 0, 324ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat &start->addr.sa, 325ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat sa_len(&start->addr)) == -1) 326ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 327ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (retry_send()) 328ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 329ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 330ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 331ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 332ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Keep info in case we want to re-send this packet */ 333ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->srv_save = start; 334ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->packet_len = plen; 335ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 336ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!gotname) 337ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat strcpy(daemon->namebuff, "query"); 338ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (start->addr.sa.sa_family == AF_INET) 339ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff, 340ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (struct all_addr *)&start->addr.in.sin_addr, NULL); 341ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6 342ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 343ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff, 344ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (struct all_addr *)&start->addr.in6.sin6_addr, NULL); 345ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 346ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat start->queries++; 347ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat forwarded = 1; 348ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat forward->sentto = start; 349ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!forward->forwardall) 350ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 351ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat forward->forwardall++; 352ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 353ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 354ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 355ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(start = start->next)) 356ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat start = daemon->servers; 357ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 358ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (start == firstsentto) 359ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 360ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 361ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 362ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (forwarded) 363ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 1; 364ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 365ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* could not send on, prepare to return */ 366ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header->id = htons(forward->orig_id); 367ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free_frec(forward); /* cancel */ 368ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 369ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 370ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* could not send on, return empty answer or address if known for whole domain */ 371ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (udpfd != -1) 372ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 373ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl); 374ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat send_from(udpfd, daemon->options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr, dst_iface); 375ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 376ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 377ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 0; 378ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 379ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 380ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic size_t process_reply(HEADER *header, time_t now, 381ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct server *server, size_t n) 382ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 383ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned char *pheader, *sizep; 384ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int munged = 0, is_sign; 385ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat size_t plen; 386ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 387ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* If upstream is advertising a larger UDP packet size 388ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat than we allow, trim it so that we don't get overlarge 389ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat requests for the client. We can't do this for signed packets. */ 390ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 391ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)) && !is_sign) 392ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 393ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned short udpsz; 394ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned char *psave = sizep; 395ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 396ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat GETSHORT(udpsz, sizep); 397ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (udpsz > daemon->edns_pktsz) 398ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat PUTSHORT(daemon->edns_pktsz, psave); 399ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 400ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 401ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (header->opcode != QUERY || (header->rcode != NOERROR && header->rcode != NXDOMAIN)) 402ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return n; 403ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 404ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Complain loudly if the upstream server is non-recursive. */ 405ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!header->ra && header->rcode == NOERROR && ntohs(header->ancount) == 0 && 406ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat server && !(server->flags & SERV_WARNED_RECURSIVE)) 407ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 408ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat prettyprint_addr(&server->addr, daemon->namebuff); 409ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff); 410ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(daemon->options & OPT_LOG)) 411ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat server->flags |= SERV_WARNED_RECURSIVE; 412ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 413ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 414ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (daemon->bogus_addr && header->rcode != NXDOMAIN && 415ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now)) 416ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 417ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat munged = 1; 418ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header->rcode = NXDOMAIN; 419ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header->aa = 0; 420ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 421ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 422ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 423ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (header->rcode == NXDOMAIN && 424ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat extract_request(header, n, daemon->namebuff, NULL) && 425ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat check_for_local_domain(daemon->namebuff, now)) 426ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 427ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* if we forwarded a query for a locally known name (because it was for 428ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat an unknown type) and the answer is NXDOMAIN, convert that to NODATA, 429ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat since we know that the domain exists, even if upstream doesn't */ 430ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat munged = 1; 431ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header->aa = 1; 432ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header->rcode = NOERROR; 433ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 434ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 435ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (extract_addresses(header, n, daemon->namebuff, now)) 436ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 437ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected")); 438ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat munged = 1; 439ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 440ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 441ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 442ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* do this after extract_addresses. Ensure NODATA reply and remove 443ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat nameserver info. */ 444ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 445ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (munged) 446ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 447ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header->ancount = htons(0); 448ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header->nscount = htons(0); 449ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header->arcount = htons(0); 450ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 451ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 452ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide 453ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat sections of the packet. Find the new length here and put back pseudoheader 454ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if it was removed. */ 455ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return resize_packet(header, n, pheader, plen); 456ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 457ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 458ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* sets new last_server */ 459ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid reply_query(int fd, int family, time_t now) 460ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 461ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* packet from peer server, extract data for cache, and send to 462ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat original requester */ 463ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat HEADER *header; 464ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat union mysockaddr serveraddr; 465ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct frec *forward; 466ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat socklen_t addrlen = sizeof(serveraddr); 467ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ssize_t n = recvfrom(fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen); 468ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat size_t nn; 469ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct server *server; 470ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 471ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* packet buffer overwritten */ 472ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->srv_save = NULL; 473ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 474ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Determine the address of the server replying so that we can mark that as good */ 475ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat serveraddr.sa.sa_family = family; 476ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6 477ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (serveraddr.sa.sa_family == AF_INET6) 478ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat serveraddr.in6.sin6_flowinfo = 0; 479ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 480ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 481ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* spoof check: answer must come from known server, */ 482ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (server = daemon->servers; server; server = server->next) 483ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) && 484ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat sockaddr_isequal(&server->addr, &serveraddr)) 485ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 486ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 487ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header = (HEADER *)daemon->packet; 488ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 489ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!server || 490ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat n < (int)sizeof(HEADER) || !header->qr || 491ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !(forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff)))) 492ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 493ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 494ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat server = forward->sentto; 495ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 496ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((header->rcode == SERVFAIL || header->rcode == REFUSED) && 497ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !(daemon->options & OPT_ORDER) && 498ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat forward->forwardall == 0) 499ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* for broken servers, attempt to send to another one. */ 500ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 501ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned char *pheader; 502ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat size_t plen; 503ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int is_sign; 504ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 505ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* recreate query from reply */ 506ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign); 507ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!is_sign) 508ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 509ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header->ancount = htons(0); 510ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header->nscount = htons(0); 511ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header->arcount = htons(0); 512ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((nn = resize_packet(header, (size_t)n, pheader, plen))) 513ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 514ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header->qr = 0; 515ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header->tc = 0; 516ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat forward_query(-1, NULL, NULL, 0, header, nn, now, forward); 517ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 518ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 519ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 520ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 521ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 522ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((forward->sentto->flags & SERV_TYPE) == 0) 523ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 524ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (header->rcode == SERVFAIL || header->rcode == REFUSED) 525ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat server = NULL; 526ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 527ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 528ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct server *last_server; 529ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 530ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* find good server by address if possible, otherwise assume the last one we sent to */ 531ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (last_server = daemon->servers; last_server; last_server = last_server->next) 532ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) && 533ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat sockaddr_isequal(&last_server->addr, &serveraddr)) 534ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 535ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat server = last_server; 536ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 537ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 538ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 539ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(daemon->options & OPT_ALL_SERVERS)) 540ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->last_server = server; 541ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 542ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 543ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* If the answer is an error, keep the forward record in place in case 544ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat we get a good reply from another server. Kill it when we've 545ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat had replies from all to avoid filling the forwarding table when 546ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat everything is broken */ 547ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (forward->forwardall == 0 || --forward->forwardall == 1 || 548ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (header->rcode != REFUSED && header->rcode != SERVFAIL)) 549ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 550ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((nn = process_reply(header, now, server, (size_t)n))) 551ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 552ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header->id = htons(forward->orig_id); 553ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header->ra = 1; /* recursion if available */ 554ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, nn, 555ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat &forward->source, &forward->dest, forward->iface); 556ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 557ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free_frec(forward); /* cancel */ 558ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 559ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 560ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 561ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 562ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid receive_query(struct listener *listen, time_t now) 563ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 564ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat HEADER *header = (HEADER *)daemon->packet; 565ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat union mysockaddr source_addr; 566ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned short type; 567ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct all_addr dst_addr; 568ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct in_addr netmask, dst_addr_4; 569ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat size_t m; 570ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ssize_t n; 571ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int if_index = 0; 572ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct iovec iov[1]; 573ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct msghdr msg; 574ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct cmsghdr *cmptr; 575ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat union { 576ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct cmsghdr align; /* this ensures alignment */ 577ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6 578ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; 579ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 580ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(HAVE_LINUX_NETWORK) 581ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char control[CMSG_SPACE(sizeof(struct in_pktinfo))]; 582ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK) 583ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char control[CMSG_SPACE(sizeof(struct in_addr)) + 584ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat CMSG_SPACE(sizeof(unsigned int))]; 585ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(IP_RECVDSTADDR) 586ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char control[CMSG_SPACE(sizeof(struct in_addr)) + 587ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat CMSG_SPACE(sizeof(struct sockaddr_dl))]; 588ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 589ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } control_u; 590ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 591ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* packet buffer overwritten */ 592ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->srv_save = NULL; 593ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 594ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (listen->family == AF_INET && (daemon->options & OPT_NOWILD)) 595ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 596ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dst_addr_4 = listen->iface->addr.in.sin_addr; 597ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat netmask = listen->iface->netmask; 598ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 599ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 600ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 601ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dst_addr_4.s_addr = 0; 602ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat netmask.s_addr = 0; 603ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 604ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 605ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat iov[0].iov_base = daemon->packet; 606ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat iov[0].iov_len = daemon->edns_pktsz; 607ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 608ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_control = control_u.control; 609ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_controllen = sizeof(control_u); 610ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_flags = 0; 611ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_name = &source_addr; 612ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_namelen = sizeof(source_addr); 613ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_iov = iov; 614ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_iovlen = 1; 615ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 616ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((n = recvmsg(listen->fd, &msg, 0)) == -1) 617ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 618ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 619ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (n < (int)sizeof(HEADER) || 620ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (msg.msg_flags & MSG_TRUNC) || 621ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header->qr) 622ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 623ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 624ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat source_addr.sa.sa_family = listen->family; 625ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6 626ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (listen->family == AF_INET6) 627ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat source_addr.in6.sin6_flowinfo = 0; 628ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 629ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 630ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(daemon->options & OPT_NOWILD)) 631ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 632ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct ifreq ifr; 633ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 634ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (msg.msg_controllen < sizeof(struct cmsghdr)) 635ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 636ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 637ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(HAVE_LINUX_NETWORK) 638ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (listen->family == AF_INET) 639ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) 640ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO) 641ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 642ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dst_addr_4 = dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst; 643ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex; 644ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 645ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF) 646ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (listen->family == AF_INET) 647ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 648ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) 649ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR) 650ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dst_addr_4 = dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr)); 651ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF) 652ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_SOLARIS_NETWORK 653ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if_index = *((unsigned int *)CMSG_DATA(cmptr)); 654ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#else 655ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index; 656ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 657ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 658ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 659ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 660ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6 661ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (listen->family == AF_INET6) 662ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 663ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) 664ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO) 665ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 666ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr; 667ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex; 668ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 669ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 670ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 671ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 672ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* enforce available interface configuration */ 673ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 674ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!indextoname(listen->fd, if_index, ifr.ifr_name) || 675ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !iface_check(listen->family, &dst_addr, ifr.ifr_name, &if_index)) 676ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 677ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 678ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (listen->family == AF_INET && 679ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (daemon->options & OPT_LOCALISE) && 680ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ioctl(listen->fd, SIOCGIFNETMASK, &ifr) == -1) 681ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 682ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 683ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; 684ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 685ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 686ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (extract_request(header, (size_t)n, daemon->namebuff, &type)) 687ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 688ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char types[20]; 689ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 690ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat querystr(types, type); 691ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 692ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (listen->family == AF_INET) 693ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff, 694ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (struct all_addr *)&source_addr.in.sin_addr, types); 695ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6 696ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 697ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff, 698ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (struct all_addr *)&source_addr.in6.sin6_addr, types); 699ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 700ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 701ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 702ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat m = answer_request (header, ((char *) header) + PACKETSZ, (size_t)n, 703ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dst_addr_4, netmask, now); 704ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (m >= 1) 705ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 706ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat send_from(listen->fd, daemon->options & OPT_NOWILD, (char *)header, 707ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat m, &source_addr, &dst_addr, if_index); 708ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->local_answer++; 709ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 710ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index, 711ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header, (size_t)n, now, NULL)) 712ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->queries_forwarded++; 713ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 714ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->local_answer++; 715ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 716ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 717ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* The daemon forks before calling this: it should deal with one connection, 718ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat blocking as neccessary, and then return. Note, need to be a bit careful 719ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat about resources for debug mode, when the fork is suppressed: that's 720ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat done by the caller. */ 721ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatunsigned char *tcp_request(int confd, time_t now, 722ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct in_addr local_addr, struct in_addr netmask) 723ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 724ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int size = 0; 725ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat size_t m; 726ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned short qtype, gotname; 727ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned char c1, c2; 728ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Max TCP packet + slop */ 729ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ); 730ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat HEADER *header; 731ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct server *last_server; 732ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 733ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while (1) 734ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 735ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!packet || 736ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) || 737ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !(size = c1 << 8 | c2) || 738ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !read_write(confd, packet, size, 1)) 739ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return packet; 740ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 741ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (size < (int)sizeof(HEADER)) 742ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 743ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 744ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat header = (HEADER *)packet; 745ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 746ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype))) 747ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 748ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat union mysockaddr peer_addr; 749ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat socklen_t peer_len = sizeof(union mysockaddr); 750ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 751ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1) 752ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 753ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char types[20]; 754ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 755ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat querystr(types, qtype); 756ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 757ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (peer_addr.sa.sa_family == AF_INET) 758ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff, 759ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (struct all_addr *)&peer_addr.in.sin_addr, types); 760ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6 761ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 762ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff, 763ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (struct all_addr *)&peer_addr.in6.sin6_addr, types); 764ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 765ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 766ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 767ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 768ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* m > 0 if answered from cache */ 769ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat m = answer_request(header, ((char *) header) + 65536, (unsigned int)size, 770ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat local_addr, netmask, now); 771ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 772ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Do this by steam now we're not in the select() loop */ 773ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat check_log_writer(NULL); 774ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 775ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (m == 0) 776ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 777ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned short flags = 0; 778ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct all_addr *addrp = NULL; 779ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int type = 0; 780ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *domain = NULL; 781ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 782ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (gotname) 783ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain); 784ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 785ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (type != 0 || (daemon->options & OPT_ORDER) || !daemon->last_server) 786ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat last_server = daemon->servers; 787ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 788ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat last_server = daemon->last_server; 789ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 790ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!flags && last_server) 791ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 792ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct server *firstsendto = NULL; 793ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff); 794ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 795ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Loop round available servers until we succeed in connecting to one. 796ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat Note that this code subtley ensures that consecutive queries on this connection 797ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat which can go to the same server, do so. */ 798ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while (1) 799ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 800ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!firstsendto) 801ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat firstsendto = last_server; 802ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 803ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 804ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(last_server = last_server->next)) 805ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat last_server = daemon->servers; 806ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 807ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (last_server == firstsendto) 808ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 809ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 810ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 811ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* server for wrong domain */ 812ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (type != (last_server->flags & SERV_TYPE) || 813ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain))) 814ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 815ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 816ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((last_server->tcpfd == -1) && 817ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) != -1 && 818ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) || 819ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1)) 820ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 821ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat close(last_server->tcpfd); 822ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat last_server->tcpfd = -1; 823ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 824ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 825ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (last_server->tcpfd == -1) 826ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 827ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 828ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat c1 = size >> 8; 829ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat c2 = size; 830ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 831ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!read_write(last_server->tcpfd, &c1, 1, 0) || 832ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !read_write(last_server->tcpfd, &c2, 1, 0) || 833ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !read_write(last_server->tcpfd, packet, size, 0) || 834ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !read_write(last_server->tcpfd, &c1, 1, 1) || 835ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !read_write(last_server->tcpfd, &c2, 1, 1)) 836ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 837ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat close(last_server->tcpfd); 838ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat last_server->tcpfd = -1; 839ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 840ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 841ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 842ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat m = (c1 << 8) | c2; 843ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!read_write(last_server->tcpfd, packet, m, 1)) 844ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return packet; 845ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 846ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!gotname) 847ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat strcpy(daemon->namebuff, "query"); 848ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (last_server->addr.sa.sa_family == AF_INET) 849ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff, 850ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (struct all_addr *)&last_server->addr.in.sin_addr, NULL); 851ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6 852ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 853ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff, 854ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (struct all_addr *)&last_server->addr.in6.sin6_addr, NULL); 855ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 856ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 857ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* There's no point in updating the cache, since this process will exit and 858ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat lose the information after a few queries. We make this call for the alias and 859ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat bogus-nxdomain side-effects. */ 860ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* If the crc of the question section doesn't match the crc we sent, then 861ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat someone might be attempting to insert bogus values into the cache by 862ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat sending replies containing questions and bogus answers. */ 863ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff)) 864ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat m = process_reply(header, now, last_server, (unsigned int)m); 865ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 866ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 867ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 868ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 869ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 870ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* In case of local answer or no connections made. */ 871ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (m == 0) 872ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl); 873ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 874ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 875ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat check_log_writer(NULL); 876ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 877ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat c1 = m>>8; 878ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat c2 = m; 879ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!read_write(confd, &c1, 1, 0) || 880ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !read_write(confd, &c2, 1, 0) || 881ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !read_write(confd, packet, m, 0)) 882ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return packet; 883ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 884ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 885ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 886ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct frec *allocate_frec(time_t now) 887ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 888ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct frec *f; 889ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 890ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((f = (struct frec *)whine_malloc(sizeof(struct frec)))) 891ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 892ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat f->next = daemon->frec_list; 893ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat f->time = now; 894ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat f->sentto = NULL; 895ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat f->rfd4 = NULL; 896ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6 897ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat f->rfd6 = NULL; 898ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 899ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->frec_list = f; 900ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 901ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 902ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return f; 903ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 904ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 905ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct randfd *allocate_rfd(int family) 906ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 907ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat static int finger = 0; 908ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int i; 909ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 910ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* limit the number of sockets we have open to avoid starvation of 911ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (eg) TFTP. Once we have a reasonable number, randomness should be OK */ 912ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 913ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (i = 0; i < RANDOM_SOCKS; i++) 914ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (daemon->randomsocks[i].refcount == 0) 915ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 916ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((daemon->randomsocks[i].fd = random_sock(family)) == -1) 917ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 918ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 919ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->randomsocks[i].refcount = 1; 920ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->randomsocks[i].family = family; 921ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return &daemon->randomsocks[i]; 922ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 923ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 924ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* No free ones or cannot get new socket, grab an existing one */ 925ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (i = 0; i < RANDOM_SOCKS; i++) 926ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 927ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int j = (i+finger) % RANDOM_SOCKS; 928ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (daemon->randomsocks[j].refcount != 0 && 929ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->randomsocks[j].family == family && 930ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->randomsocks[j].refcount != 0xffff) 931ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 932ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat finger = j; 933ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->randomsocks[j].refcount++; 934ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return &daemon->randomsocks[j]; 935ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 936ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 937ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 938ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return NULL; /* doom */ 939ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 940ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 941ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic void free_frec(struct frec *f) 942ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 943ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (f->rfd4 && --(f->rfd4->refcount) == 0) 944ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat close(f->rfd4->fd); 945ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 946ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat f->rfd4 = NULL; 947ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat f->sentto = NULL; 948ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 949ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_IPV6 950ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (f->rfd6 && --(f->rfd6->refcount) == 0) 951ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat close(f->rfd6->fd); 952ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 953ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat f->rfd6 = NULL; 954ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 955ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 956ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 957ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* if wait==NULL return a free or older than TIMEOUT record. 958ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else return *wait zero if one available, or *wait is delay to 959ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat when the oldest in-use record will expire. Impose an absolute 960ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat limit of 4*TIMEOUT before we wipe things (for random sockets) */ 961ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstruct frec *get_new_frec(time_t now, int *wait) 962ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 963ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct frec *f, *oldest, *target; 964ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int count; 965ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 966ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (wait) 967ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *wait = 0; 968ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 969ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next, count++) 970ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!f->sentto) 971ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat target = f; 972ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 973ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 974ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (difftime(now, f->time) >= 4*TIMEOUT) 975ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 976ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free_frec(f); 977ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat target = f; 978ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 979ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 980ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!oldest || difftime(f->time, oldest->time) <= 0) 981ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat oldest = f; 982ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 983ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 984ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (target) 985ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 986ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat target->time = now; 987ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return target; 988ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 989ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 990ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* can't find empty one, use oldest if there is one 991ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat and it's older than timeout */ 992ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT) 993ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 994ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* keep stuff for twice timeout if we can by allocating a new 995ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat record instead */ 996ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (difftime(now, oldest->time) < 2*TIMEOUT && 997ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat count <= daemon->ftabsize && 998ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (f = allocate_frec(now))) 999ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return f; 1000ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1001ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!wait) 1002ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 1003ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free_frec(oldest); 1004ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat oldest->time = now; 1005ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 1006ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return oldest; 1007ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 1008ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1009ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* none available, calculate time 'till oldest record expires */ 1010ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (count > daemon->ftabsize) 1011ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 1012ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (oldest && wait) 1013ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *wait = oldest->time + (time_t)TIMEOUT - now; 1014ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return NULL; 1015ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 1016ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1017ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(f = allocate_frec(now)) && wait) 1018ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* wait one second on malloc failure */ 1019ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *wait = 1; 1020ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1021ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return f; /* OK if malloc fails and this is NULL */ 1022ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 1023ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1024ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* crc is all-ones if not known. */ 1025ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct frec *lookup_frec(unsigned short id, unsigned int crc) 1026ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 1027ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct frec *f; 1028ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1029ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for(f = daemon->frec_list; f; f = f->next) 1030ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (f->sentto && f->new_id == id && 1031ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (f->crc == crc || crc == 0xffffffff)) 1032ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return f; 1033ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1034ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return NULL; 1035ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 1036ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1037ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct frec *lookup_frec_by_sender(unsigned short id, 1038ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat union mysockaddr *addr, 1039ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned int crc) 1040ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 1041ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct frec *f; 1042ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1043ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for(f = daemon->frec_list; f; f = f->next) 1044ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (f->sentto && 1045ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat f->orig_id == id && 1046ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat f->crc == crc && 1047ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat sockaddr_isequal(&f->source, addr)) 1048ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return f; 1049ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1050ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return NULL; 1051ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 1052ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1053ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* A server record is going away, remove references to it */ 1054ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid server_gone(struct server *server) 1055ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 1056ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct frec *f; 1057ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1058ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (f = daemon->frec_list; f; f = f->next) 1059ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (f->sentto && f->sentto == server) 1060ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free_frec(f); 1061ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1062ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (daemon->last_server == server) 1063ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->last_server = NULL; 1064ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1065ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (daemon->srv_save == server) 1066ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->srv_save = NULL; 1067ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 1068ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1069ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* return unique random ids. 1070ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat For signed packets we can't change the ID without breaking the 1071ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat signing, so we keep the same one. In this case force is set, and this 1072ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat routine degenerates into killing any conflicting forward record. */ 1073ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic unsigned short get_id(int force, unsigned short force_id, unsigned int crc) 1074ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 1075ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned short ret = 0; 1076ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1077ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (force) 1078ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 1079ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct frec *f = lookup_frec(force_id, crc); 1080ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (f) 1081ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free_frec(f); /* free */ 1082ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ret = force_id; 1083ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 1084ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else do 1085ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ret = rand16(); 1086ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while (lookup_frec(ret, crc)); 1087ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1088ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return ret; 1089ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 1090ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1091ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1092ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1093ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1094ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1095