Annotation of embedaddon/dnsmasq/src/forward.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>