Annotation of embedaddon/dnsmasq/src/network.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: #ifdef HAVE_LINUX_NETWORK
        !            20: 
        !            21: int indextoname(int fd, int index, char *name)
        !            22: {
        !            23:   struct ifreq ifr;
        !            24:   
        !            25:   if (index == 0)
        !            26:     return 0;
        !            27: 
        !            28:   ifr.ifr_ifindex = index;
        !            29:   if (ioctl(fd, SIOCGIFNAME, &ifr) == -1)
        !            30:     return 0;
        !            31: 
        !            32:   strncpy(name, ifr.ifr_name, IF_NAMESIZE);
        !            33: 
        !            34:   return 1;
        !            35: }
        !            36: 
        !            37: 
        !            38: #elif defined(HAVE_SOLARIS_NETWORK)
        !            39: 
        !            40: #include <zone.h>
        !            41: #include <alloca.h>
        !            42: #ifndef LIFC_UNDER_IPMP
        !            43: #  define LIFC_UNDER_IPMP 0
        !            44: #endif
        !            45: 
        !            46: int indextoname(int fd, int index, char *name)
        !            47: {
        !            48:   int64_t lifc_flags;
        !            49:   struct lifnum lifn;
        !            50:   int numifs, bufsize, i;
        !            51:   struct lifconf lifc;
        !            52:   struct lifreq *lifrp;
        !            53:   
        !            54:   if (index == 0)
        !            55:     return 0;
        !            56:   
        !            57:   if (getzoneid() == GLOBAL_ZONEID) 
        !            58:     {
        !            59:       if (!if_indextoname(index, name))
        !            60:        return 0;
        !            61:       return 1;
        !            62:     }
        !            63:   
        !            64:   lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES | LIFC_UNDER_IPMP;
        !            65:   lifn.lifn_family = AF_UNSPEC;
        !            66:   lifn.lifn_flags = lifc_flags;
        !            67:   if (ioctl(fd, SIOCGLIFNUM, &lifn) < 0) 
        !            68:     return 0;
        !            69:   
        !            70:   numifs = lifn.lifn_count;
        !            71:   bufsize = numifs * sizeof(struct lifreq);
        !            72:   
        !            73:   lifc.lifc_family = AF_UNSPEC;
        !            74:   lifc.lifc_flags = lifc_flags;
        !            75:   lifc.lifc_len = bufsize;
        !            76:   lifc.lifc_buf = alloca(bufsize);
        !            77:   
        !            78:   if (ioctl(fd, SIOCGLIFCONF, &lifc) < 0)  
        !            79:     return 0;
        !            80:   
        !            81:   lifrp = lifc.lifc_req;
        !            82:   for (i = lifc.lifc_len / sizeof(struct lifreq); i; i--, lifrp++) 
        !            83:     {
        !            84:       struct lifreq lifr;
        !            85:       strncpy(lifr.lifr_name, lifrp->lifr_name, IF_NAMESIZE);
        !            86:       if (ioctl(fd, SIOCGLIFINDEX, &lifr) < 0) 
        !            87:        return 0;
        !            88:       
        !            89:       if (lifr.lifr_index == index) {
        !            90:        strncpy(name, lifr.lifr_name, IF_NAMESIZE);
        !            91:        return 1;
        !            92:       }
        !            93:     }
        !            94:   return 0;
        !            95: }
        !            96: 
        !            97: 
        !            98: #else
        !            99: 
        !           100: int indextoname(int fd, int index, char *name)
        !           101: { 
        !           102:   if (index == 0 || !if_indextoname(index, name))
        !           103:     return 0;
        !           104: 
        !           105:   return 1;
        !           106: }
        !           107: 
        !           108: #endif
        !           109: 
        !           110: int iface_check(int family, struct all_addr *addr, char *name, int *auth)
        !           111: {
        !           112:   struct iname *tmp;
        !           113:   int ret = 1;
        !           114: 
        !           115:   /* Note: have to check all and not bail out early, so that we set the
        !           116:      "used" flags. */
        !           117:   
        !           118:   if (auth)
        !           119:     *auth = 0;
        !           120:   
        !           121:   if (daemon->if_names || daemon->if_addrs)
        !           122:     {
        !           123:       ret = 0;
        !           124: 
        !           125:       for (tmp = daemon->if_names; tmp; tmp = tmp->next)
        !           126:        if (tmp->name && wildcard_match(tmp->name, name))
        !           127:          ret = tmp->used = 1;
        !           128:                
        !           129:       if (addr)
        !           130:        for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
        !           131:          if (tmp->addr.sa.sa_family == family)
        !           132:            {
        !           133:              if (family == AF_INET &&
        !           134:                  tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
        !           135:                ret = tmp->used = 1;
        !           136: #ifdef HAVE_IPV6
        !           137:              else if (family == AF_INET6 &&
        !           138:                       IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, 
        !           139:                                          &addr->addr.addr6))
        !           140:                ret = tmp->used = 1;
        !           141: #endif
        !           142:            }          
        !           143:     }
        !           144:   
        !           145:   for (tmp = daemon->if_except; tmp; tmp = tmp->next)
        !           146:     if (tmp->name && wildcard_match(tmp->name, name))
        !           147:       ret = 0;
        !           148:     
        !           149: 
        !           150:   for (tmp = daemon->authinterface; tmp; tmp = tmp->next)
        !           151:     if (tmp->name)
        !           152:       {
        !           153:        if (strcmp(tmp->name, name) == 0)
        !           154:          break;
        !           155:       }
        !           156:     else if (addr && tmp->addr.sa.sa_family == AF_INET && family == AF_INET &&
        !           157:             tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
        !           158:       break;
        !           159: #ifdef HAVE_IPV6
        !           160:     else if (addr && tmp->addr.sa.sa_family == AF_INET6 && family == AF_INET6 &&
        !           161:             IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, &addr->addr.addr6))
        !           162:       break;
        !           163: #endif      
        !           164: 
        !           165:   if (tmp && auth) 
        !           166:     {
        !           167:       *auth = 1;
        !           168:       ret = 1;
        !           169:     }
        !           170: 
        !           171:   return ret; 
        !           172: }
        !           173: 
        !           174: 
        !           175: /* Fix for problem that the kernel sometimes reports the loopback inerface as the
        !           176:    arrival interface when a packet originates locally, even when sent to address of 
        !           177:    an interface other than the loopback. Accept packet if it arrived via a loopback 
        !           178:    interface, even when we're not accepting packets that way, as long as the destination
        !           179:    address is one we're believing. Interface list must be up-to-date before calling. */
        !           180: int loopback_exception(int fd, int family, struct all_addr *addr, char *name)    
        !           181: {
        !           182:   struct ifreq ifr;
        !           183:   struct irec *iface;
        !           184: 
        !           185:   strncpy(ifr.ifr_name, name, IF_NAMESIZE);
        !           186:   if (ioctl(fd, SIOCGIFFLAGS, &ifr) != -1 &&
        !           187:       ifr.ifr_flags & IFF_LOOPBACK)
        !           188:     {
        !           189:       for (iface = daemon->interfaces; iface; iface = iface->next)
        !           190:        if (iface->addr.sa.sa_family == family)
        !           191:          {
        !           192:            if (family == AF_INET)
        !           193:              {
        !           194:                if (iface->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
        !           195:                  return 1;
        !           196:              }
        !           197: #ifdef HAVE_IPV6
        !           198:            else if (IN6_ARE_ADDR_EQUAL(&iface->addr.in6.sin6_addr, &addr->addr.addr6))
        !           199:              return 1;
        !           200: #endif
        !           201:            
        !           202:          }
        !           203:     }
        !           204:   return 0;
        !           205: }
        !           206: 
        !           207: static int iface_allowed(struct irec **irecp, int if_index, 
        !           208:                         union mysockaddr *addr, struct in_addr netmask, int dad) 
        !           209: {
        !           210:   struct irec *iface;
        !           211:   int fd, mtu = 0, loopback;
        !           212:   struct ifreq ifr;
        !           213:   int tftp_ok = !!option_bool(OPT_TFTP);
        !           214:   int dhcp_ok = 1;
        !           215:   int auth_dns = 0;
        !           216: #ifdef HAVE_DHCP
        !           217:   struct iname *tmp;
        !           218: #endif
        !           219: 
        !           220:   /* check whether the interface IP has been added already 
        !           221:      we call this routine multiple times. */
        !           222:   for (iface = *irecp; iface; iface = iface->next) 
        !           223:     if (sockaddr_isequal(&iface->addr, addr))
        !           224:       {
        !           225:        iface->dad = dad;
        !           226:        return 1;
        !           227:       }
        !           228: 
        !           229:   if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
        !           230:       !indextoname(fd, if_index, ifr.ifr_name) ||
        !           231:       ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
        !           232:     {
        !           233:       if (fd != -1)
        !           234:        {
        !           235:          int errsave = errno;
        !           236:          close(fd);
        !           237:          errno = errsave;
        !           238:        }
        !           239:       return 0;
        !           240:     }
        !           241:    
        !           242:   loopback = ifr.ifr_flags & IFF_LOOPBACK;
        !           243:   
        !           244:   if (loopback)
        !           245:      dhcp_ok = 0;
        !           246: 
        !           247:   if (ioctl(fd, SIOCGIFMTU, &ifr) != -1)
        !           248:     mtu = ifr.ifr_mtu;
        !           249:   
        !           250:   close(fd);
        !           251:   
        !           252:   /* If we are restricting the set of interfaces to use, make
        !           253:      sure that loopback interfaces are in that set. */
        !           254:   if (daemon->if_names && loopback)
        !           255:     {
        !           256:       struct iname *lo;
        !           257:       for (lo = daemon->if_names; lo; lo = lo->next)
        !           258:        if (lo->name && strcmp(lo->name, ifr.ifr_name) == 0)
        !           259:          break;
        !           260:       
        !           261:       if (!lo && (lo = whine_malloc(sizeof(struct iname)))) 
        !           262:        {
        !           263:          if ((lo->name = whine_malloc(strlen(ifr.ifr_name)+1)))
        !           264:            {
        !           265:              strcpy(lo->name, ifr.ifr_name);
        !           266:              lo->used = 1;
        !           267:              lo->next = daemon->if_names;
        !           268:              daemon->if_names = lo;
        !           269:            }
        !           270:          else
        !           271:            free(lo);
        !           272:        }
        !           273:     }
        !           274:   
        !           275:   if (addr->sa.sa_family == AF_INET &&
        !           276:       !iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name, &auth_dns))
        !           277:     return 1;
        !           278: 
        !           279: #ifdef HAVE_IPV6
        !           280:   if (addr->sa.sa_family == AF_INET6 &&
        !           281:       !iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name, &auth_dns))
        !           282:     return 1;
        !           283: #endif
        !           284:     
        !           285: #ifdef HAVE_DHCP
        !           286:   /* No DHCP where we're doing auth DNS. */
        !           287:   if (auth_dns)
        !           288:     {
        !           289:       tftp_ok = 0;
        !           290:       dhcp_ok = 0;
        !           291:     }
        !           292:   else
        !           293:     for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
        !           294:       if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
        !           295:        {
        !           296:          tftp_ok = 0;
        !           297:          dhcp_ok = 0;
        !           298:        }
        !           299: #endif
        !           300:  
        !           301:   /* add to list */
        !           302:   if ((iface = whine_malloc(sizeof(struct irec))))
        !           303:     {
        !           304:       iface->addr = *addr;
        !           305:       iface->netmask = netmask;
        !           306:       iface->tftp_ok = tftp_ok;
        !           307:       iface->dhcp_ok = dhcp_ok;
        !           308:       iface->dns_auth = auth_dns;
        !           309:       iface->mtu = mtu;
        !           310:       iface->dad = dad;
        !           311:       iface->done = iface->multicast_done = 0;
        !           312:       iface->index = if_index;
        !           313:       if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
        !           314:        {
        !           315:          strcpy(iface->name, ifr.ifr_name);
        !           316:          iface->next = *irecp;
        !           317:          *irecp = iface;
        !           318:          return 1;
        !           319:        }
        !           320:       free(iface);
        !           321: 
        !           322:     }
        !           323:   
        !           324:   errno = ENOMEM; 
        !           325:   return 0;
        !           326: }
        !           327: 
        !           328: #ifdef HAVE_IPV6
        !           329: static int iface_allowed_v6(struct in6_addr *local, int prefix, 
        !           330:                            int scope, int if_index, int flags, 
        !           331:                            int preferred, int valid, void *vparam)
        !           332: {
        !           333:   union mysockaddr addr;
        !           334:   struct in_addr netmask; /* dummy */
        !           335:   netmask.s_addr = 0;
        !           336: 
        !           337:   (void)prefix; /* warning */
        !           338:   (void)scope; /* warning */
        !           339:   (void)preferred;
        !           340:   (void)valid;
        !           341:   
        !           342:   memset(&addr, 0, sizeof(addr));
        !           343: #ifdef HAVE_SOCKADDR_SA_LEN
        !           344:   addr.in6.sin6_len = sizeof(addr.in6);
        !           345: #endif
        !           346:   addr.in6.sin6_family = AF_INET6;
        !           347:   addr.in6.sin6_addr = *local;
        !           348:   addr.in6.sin6_port = htons(daemon->port);
        !           349:   addr.in6.sin6_scope_id = if_index;
        !           350:   
        !           351:   return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, !!(flags & IFACE_TENTATIVE));
        !           352: }
        !           353: #endif
        !           354: 
        !           355: static int iface_allowed_v4(struct in_addr local, int if_index, 
        !           356:                            struct in_addr netmask, struct in_addr broadcast, void *vparam)
        !           357: {
        !           358:   union mysockaddr addr;
        !           359: 
        !           360:   memset(&addr, 0, sizeof(addr));
        !           361: #ifdef HAVE_SOCKADDR_SA_LEN
        !           362:   addr.in.sin_len = sizeof(addr.in);
        !           363: #endif
        !           364:   addr.in.sin_family = AF_INET;
        !           365:   addr.in.sin_addr = broadcast; /* warning */
        !           366:   addr.in.sin_addr = local;
        !           367:   addr.in.sin_port = htons(daemon->port);
        !           368: 
        !           369:   return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, 0);
        !           370: }
        !           371:    
        !           372: int enumerate_interfaces(void)
        !           373: {
        !           374: #ifdef HAVE_IPV6
        !           375:   if (!iface_enumerate(AF_INET6, &daemon->interfaces, iface_allowed_v6))
        !           376:     return 0; 
        !           377: #endif
        !           378: 
        !           379:   return iface_enumerate(AF_INET, &daemon->interfaces, iface_allowed_v4); 
        !           380: }
        !           381: 
        !           382: /* set NONBLOCK bit on fd: See Stevens 16.6 */
        !           383: int fix_fd(int fd)
        !           384: {
        !           385:   int flags;
        !           386: 
        !           387:   if ((flags = fcntl(fd, F_GETFL)) == -1 ||
        !           388:       fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
        !           389:     return 0;
        !           390:   
        !           391:   return 1;
        !           392: }
        !           393: 
        !           394: static int make_sock(union mysockaddr *addr, int type, int dienow)
        !           395: {
        !           396:   int family = addr->sa.sa_family;
        !           397:   int fd, rc, opt = 1;
        !           398:   
        !           399:   if ((fd = socket(family, type, 0)) == -1)
        !           400:     {
        !           401:       int port;
        !           402:       char *s;
        !           403: 
        !           404:       /* No error if the kernel just doesn't support this IP flavour */
        !           405:       if (errno == EPROTONOSUPPORT ||
        !           406:          errno == EAFNOSUPPORT ||
        !           407:          errno == EINVAL)
        !           408:        return -1;
        !           409:       
        !           410:     err:
        !           411:       port = prettyprint_addr(addr, daemon->addrbuff);
        !           412:       if (!option_bool(OPT_NOWILD) && !option_bool(OPT_CLEVERBIND))
        !           413:        sprintf(daemon->addrbuff, "port %d", port);
        !           414:       s = _("failed to create listening socket for %s: %s");
        !           415:       
        !           416:       if (fd != -1)
        !           417:        close (fd);
        !           418:       
        !           419:       if (dienow)
        !           420:        {
        !           421:          /* failure to bind addresses given by --listen-address at this point
        !           422:             is OK if we're doing bind-dynamic */
        !           423:          if (!option_bool(OPT_CLEVERBIND))
        !           424:            die(s, daemon->addrbuff, EC_BADNET);
        !           425:        }
        !           426:       else
        !           427:        my_syslog(LOG_WARNING, s, daemon->addrbuff, strerror(errno));
        !           428:       
        !           429:       return -1;
        !           430:     }  
        !           431:   
        !           432:   if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))
        !           433:     goto err;
        !           434:   
        !           435: #ifdef HAVE_IPV6
        !           436:   if (family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
        !           437:     goto err;
        !           438: #endif
        !           439:   
        !           440:   if ((rc = bind(fd, (struct sockaddr *)addr, sa_len(addr))) == -1)
        !           441:     goto err;
        !           442:   
        !           443:   if (type == SOCK_STREAM)
        !           444:     {
        !           445:       if (listen(fd, 5) == -1)
        !           446:        goto err;
        !           447:     }
        !           448:   else if (!option_bool(OPT_NOWILD))
        !           449:     {
        !           450:       if (family == AF_INET)
        !           451:        {
        !           452: #if defined(HAVE_LINUX_NETWORK) 
        !           453:          if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1)
        !           454:            goto err;
        !           455: #elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
        !           456:          if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
        !           457:              setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1)
        !           458:            goto err;
        !           459: #endif
        !           460:        }
        !           461: #ifdef HAVE_IPV6
        !           462:       else if (!set_ipv6pktinfo(fd))
        !           463:        goto err;
        !           464: #endif
        !           465:     }
        !           466:   
        !           467:   return fd;
        !           468: }
        !           469: 
        !           470: #ifdef HAVE_IPV6  
        !           471: int set_ipv6pktinfo(int fd)
        !           472: {
        !           473:   int opt = 1;
        !           474: 
        !           475:   /* The API changed around Linux 2.6.14 but the old ABI is still supported:
        !           476:      handle all combinations of headers and kernel.
        !           477:      OpenWrt note that this fixes the problem addressed by your very broken patch. */
        !           478:   daemon->v6pktinfo = IPV6_PKTINFO;
        !           479:   
        !           480: #ifdef IPV6_RECVPKTINFO
        !           481:   if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof(opt)) != -1)
        !           482:     return 1;
        !           483: # ifdef IPV6_2292PKTINFO
        !           484:   else if (errno == ENOPROTOOPT && setsockopt(fd, IPPROTO_IPV6, IPV6_2292PKTINFO, &opt, sizeof(opt)) != -1)
        !           485:     {
        !           486:       daemon->v6pktinfo = IPV6_2292PKTINFO;
        !           487:       return 1;
        !           488:     }
        !           489: # endif 
        !           490: #else
        !           491:   if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &opt, sizeof(opt)) != -1)
        !           492:     return 1;
        !           493: #endif
        !           494: 
        !           495:   return 0;
        !           496: }
        !           497: #endif
        !           498: 
        !           499: 
        !           500: /* Find the interface on which a TCP connection arrived, if possible, or zero otherwise. */
        !           501: int tcp_interface(int fd, int af)
        !           502: { 
        !           503:   int if_index = 0;
        !           504: 
        !           505: #ifdef HAVE_LINUX_NETWORK
        !           506:   int opt = 1;
        !           507:   struct cmsghdr *cmptr;
        !           508:   struct msghdr msg;
        !           509:   
        !           510:   /* use mshdr do that the CMSDG_* macros are available */
        !           511:   msg.msg_control = daemon->packet;
        !           512:   msg.msg_controllen = daemon->packet_buff_sz;
        !           513:   
        !           514:   /* we overwrote the buffer... */
        !           515:   daemon->srv_save = NULL;
        !           516:   
        !           517:   if (af == AF_INET)
        !           518:     {
        !           519:       if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) != -1 &&
        !           520:          getsockopt(fd, IPPROTO_IP, IP_PKTOPTIONS, msg.msg_control, (socklen_t *)&msg.msg_controllen) != -1)
        !           521:        for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
        !           522:          if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
        !           523:             {
        !           524:               union {
        !           525:                 unsigned char *c;
        !           526:                 struct in_pktinfo *p;
        !           527:               } p;
        !           528:              
        !           529:              p.c = CMSG_DATA(cmptr);
        !           530:              if_index = p.p->ipi_ifindex;
        !           531:            }
        !           532:     }
        !           533: #ifdef HAVE_IPV6
        !           534:   else
        !           535:     {
        !           536:       /* Only the RFC-2292 API has the ability to find the interface for TCP connections,
        !           537:         it was removed in RFC-3542 !!!! 
        !           538: 
        !           539:         Fortunately, Linux kept the 2292 ABI when it moved to 3542. The following code always
        !           540:         uses the old ABI, and should work with pre- and post-3542 kernel headers */
        !           541: 
        !           542: #ifdef IPV6_2292PKTOPTIONS   
        !           543: #  define PKTOPTIONS IPV6_2292PKTOPTIONS
        !           544: #else
        !           545: #  define PKTOPTIONS IPV6_PKTOPTIONS
        !           546: #endif
        !           547: 
        !           548:       if (set_ipv6pktinfo(fd) &&
        !           549:          getsockopt(fd, IPPROTO_IPV6, PKTOPTIONS, msg.msg_control, (socklen_t *)&msg.msg_controllen) != -1)
        !           550:        {
        !           551:           for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
        !           552:             if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
        !           553:               {
        !           554:                 union {
        !           555:                   unsigned char *c;
        !           556:                   struct in6_pktinfo *p;
        !           557:                 } p;
        !           558:                 p.c = CMSG_DATA(cmptr);
        !           559:                
        !           560:                if_index = p.p->ipi6_ifindex;
        !           561:               }
        !           562:        }
        !           563:     }
        !           564: #endif /* IPV6 */
        !           565: #endif /* Linux */
        !           566:  
        !           567:   return if_index;
        !           568: }
        !           569:       
        !           570: static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, int dienow)
        !           571: {
        !           572:   struct listener *l = NULL;
        !           573:   int fd = -1, tcpfd = -1, tftpfd = -1;
        !           574: 
        !           575:   if (daemon->port != 0)
        !           576:     {
        !           577:       fd = make_sock(addr, SOCK_DGRAM, dienow);
        !           578:       tcpfd = make_sock(addr, SOCK_STREAM, dienow);
        !           579:     }
        !           580:   
        !           581: #ifdef HAVE_TFTP
        !           582:   if (do_tftp)
        !           583:     {
        !           584:       if (addr->sa.sa_family == AF_INET)
        !           585:        {
        !           586:          /* port must be restored to DNS port for TCP code */
        !           587:          short save = addr->in.sin_port;
        !           588:          addr->in.sin_port = htons(TFTP_PORT);
        !           589:          tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
        !           590:          addr->in.sin_port = save;
        !           591:        }
        !           592: #  ifdef HAVE_IPV6
        !           593:       else
        !           594:        {
        !           595:          short save = addr->in6.sin6_port;
        !           596:          addr->in6.sin6_port = htons(TFTP_PORT);
        !           597:          tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
        !           598:          addr->in6.sin6_port = save;
        !           599:        }  
        !           600: #  endif
        !           601:     }
        !           602: #endif
        !           603: 
        !           604:   if (fd != -1 || tcpfd != -1 || tftpfd != -1)
        !           605:     {
        !           606:       l = safe_malloc(sizeof(struct listener));
        !           607:       l->next = NULL;
        !           608:       l->family = addr->sa.sa_family;
        !           609:       l->fd = fd;
        !           610:       l->tcpfd = tcpfd;
        !           611:       l->tftpfd = tftpfd;
        !           612:     }
        !           613: 
        !           614:   return l;
        !           615: }
        !           616: 
        !           617: void create_wildcard_listeners(void)
        !           618: {
        !           619:   union mysockaddr addr;
        !           620:   struct listener *l, *l6;
        !           621: 
        !           622:   memset(&addr, 0, sizeof(addr));
        !           623: #ifdef HAVE_SOCKADDR_SA_LEN
        !           624:   addr.in.sin_len = sizeof(addr.in);
        !           625: #endif
        !           626:   addr.in.sin_family = AF_INET;
        !           627:   addr.in.sin_addr.s_addr = INADDR_ANY;
        !           628:   addr.in.sin_port = htons(daemon->port);
        !           629: 
        !           630:   l = create_listeners(&addr, !!option_bool(OPT_TFTP), 1);
        !           631: 
        !           632: #ifdef HAVE_IPV6
        !           633:   memset(&addr, 0, sizeof(addr));
        !           634: #  ifdef HAVE_SOCKADDR_SA_LEN
        !           635:   addr.in6.sin6_len = sizeof(addr.in6);
        !           636: #  endif
        !           637:   addr.in6.sin6_family = AF_INET6;
        !           638:   addr.in6.sin6_addr = in6addr_any;
        !           639:   addr.in6.sin6_port = htons(daemon->port);
        !           640:  
        !           641:   l6 = create_listeners(&addr, !!option_bool(OPT_TFTP), 1);
        !           642:   if (l) 
        !           643:     l->next = l6;
        !           644:   else 
        !           645:     l = l6;
        !           646: #endif
        !           647: 
        !           648:   daemon->listeners = l;
        !           649: }
        !           650: 
        !           651: void create_bound_listeners(int dienow)
        !           652: {
        !           653:   struct listener *new;
        !           654:   struct irec *iface;
        !           655:   struct iname *if_tmp;
        !           656: 
        !           657:   for (iface = daemon->interfaces; iface; iface = iface->next)
        !           658:     if (!iface->done && !iface->dad && 
        !           659:        (new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
        !           660:       {
        !           661:        new->iface = iface;
        !           662:        new->next = daemon->listeners;
        !           663:        daemon->listeners = new;
        !           664:        iface->done = 1;
        !           665:       }
        !           666: 
        !           667:   /* Check for --listen-address options that haven't been used because there's
        !           668:      no interface with a matching address. These may be valid: eg it's possible
        !           669:      to listen on 127.0.1.1 even if the loopback interface is 127.0.0.1
        !           670: 
        !           671:      If the address isn't valid the bind() will fail and we'll die() 
        !           672:      (except in bind-dynamic mode, when we'll complain but keep trying.)
        !           673: 
        !           674:      The resulting listeners have the ->iface field NULL, and this has to be
        !           675:      handled by the DNS and TFTP code. It disables --localise-queries processing
        !           676:      (no netmask) and some MTU login the tftp code. */
        !           677: 
        !           678:   for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
        !           679:     if (!if_tmp->used && 
        !           680:        (new = create_listeners(&if_tmp->addr, !!option_bool(OPT_TFTP), dienow)))
        !           681:       {
        !           682:        new->iface = NULL;
        !           683:        new->next = daemon->listeners;
        !           684:        daemon->listeners = new;
        !           685:       }
        !           686: }
        !           687: 
        !           688: int is_dad_listeners(void)
        !           689: {
        !           690:   struct irec *iface;
        !           691:   
        !           692:   if (option_bool(OPT_NOWILD))
        !           693:     for (iface = daemon->interfaces; iface; iface = iface->next)
        !           694:       if (iface->dad && !iface->done)
        !           695:        return 1;
        !           696:   
        !           697:   return 0;
        !           698: }
        !           699: 
        !           700: #ifdef HAVE_DHCP6
        !           701: void join_multicast(int dienow)      
        !           702: {
        !           703:   struct irec *iface, *tmp;
        !           704: 
        !           705:   for (iface = daemon->interfaces; iface; iface = iface->next)
        !           706:     if (iface->addr.sa.sa_family == AF_INET6 && iface->dhcp_ok && !iface->multicast_done)
        !           707:       {
        !           708:        /* There's an irec per address but we only want to join for multicast 
        !           709:           once per interface. Weed out duplicates. */
        !           710:        for (tmp = daemon->interfaces; tmp; tmp = tmp->next)
        !           711:          if (tmp->multicast_done && tmp->index == iface->index)
        !           712:            break;
        !           713:        
        !           714:        iface->multicast_done = 1;
        !           715:        
        !           716:        if (!tmp)
        !           717:          {
        !           718:            struct ipv6_mreq mreq;
        !           719:            int err = 0;
        !           720: 
        !           721:            mreq.ipv6mr_interface = iface->index;
        !           722:            
        !           723:            inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
        !           724:            
        !           725:            if (daemon->doing_dhcp6 &&
        !           726:                setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
        !           727:              err = 1;
        !           728:            
        !           729:            inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
        !           730:            
        !           731:            if (daemon->doing_dhcp6 && 
        !           732:                setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
        !           733:              err = 1;
        !           734:            
        !           735:            inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
        !           736:            
        !           737:            if (daemon->doing_ra &&
        !           738:                setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
        !           739:              err = 1;
        !           740:            
        !           741:            if (err)
        !           742:              {
        !           743:                char *s = _("interface %s failed to join DHCPv6 multicast group: %s");
        !           744:                if (dienow)
        !           745:                  die(s, iface->name, EC_BADNET);
        !           746:                else
        !           747:                  my_syslog(LOG_ERR, s, iface->name, strerror(errno));
        !           748:              }
        !           749:          }
        !           750:       }
        !           751: }
        !           752: #endif
        !           753: 
        !           754: /* return a UDP socket bound to a random port, have to cope with straying into
        !           755:    occupied port nos and reserved ones. */
        !           756: int random_sock(int family)
        !           757: {
        !           758:   int fd;
        !           759: 
        !           760:   if ((fd = socket(family, SOCK_DGRAM, 0)) != -1)
        !           761:     {
        !           762:       union mysockaddr addr;
        !           763:       unsigned int ports_avail = 65536u - (unsigned short)daemon->min_port;
        !           764:       int tries = ports_avail < 30 ? 3 * ports_avail : 100;
        !           765: 
        !           766:       memset(&addr, 0, sizeof(addr));
        !           767:       addr.sa.sa_family = family;
        !           768: 
        !           769:       /* don't loop forever if all ports in use. */
        !           770: 
        !           771:       if (fix_fd(fd))
        !           772:        while(tries--)
        !           773:          {
        !           774:            unsigned short port = rand16();
        !           775:            
        !           776:            if (daemon->min_port != 0)
        !           777:              port = htons(daemon->min_port + (port % ((unsigned short)ports_avail)));
        !           778:            
        !           779:            if (family == AF_INET) 
        !           780:              {
        !           781:                addr.in.sin_addr.s_addr = INADDR_ANY;
        !           782:                addr.in.sin_port = port;
        !           783: #ifdef HAVE_SOCKADDR_SA_LEN
        !           784:                addr.in.sin_len = sizeof(struct sockaddr_in);
        !           785: #endif
        !           786:              }
        !           787: #ifdef HAVE_IPV6
        !           788:            else
        !           789:              {
        !           790:                addr.in6.sin6_addr = in6addr_any; 
        !           791:                addr.in6.sin6_port = port;
        !           792: #ifdef HAVE_SOCKADDR_SA_LEN
        !           793:                addr.in6.sin6_len = sizeof(struct sockaddr_in6);
        !           794: #endif
        !           795:              }
        !           796: #endif
        !           797:            
        !           798:            if (bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == 0)
        !           799:              return fd;
        !           800:            
        !           801:            if (errno != EADDRINUSE && errno != EACCES)
        !           802:              break;
        !           803:          }
        !           804: 
        !           805:       close(fd);
        !           806:     }
        !           807: 
        !           808:   return -1; 
        !           809: }
        !           810:   
        !           811: 
        !           812: int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
        !           813: {
        !           814:   union mysockaddr addr_copy = *addr;
        !           815: 
        !           816:   /* cannot set source _port_ for TCP connections. */
        !           817:   if (is_tcp)
        !           818:     {
        !           819:       if (addr_copy.sa.sa_family == AF_INET)
        !           820:        addr_copy.in.sin_port = 0;
        !           821: #ifdef HAVE_IPV6
        !           822:       else
        !           823:        addr_copy.in6.sin6_port = 0;
        !           824: #endif
        !           825:     }
        !           826:   
        !           827:   if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) == -1)
        !           828:     return 0;
        !           829:     
        !           830: #if defined(SO_BINDTODEVICE)
        !           831:   if (intname[0] != 0 &&
        !           832:       setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE) == -1)
        !           833:     return 0;
        !           834: #endif
        !           835: 
        !           836:   return 1;
        !           837: }
        !           838: 
        !           839: static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
        !           840: {
        !           841:   struct serverfd *sfd;
        !           842:   int errsave;
        !           843: 
        !           844:   /* when using random ports, servers which would otherwise use
        !           845:      the INADDR_ANY/port0 socket have sfd set to NULL */
        !           846:   if (!daemon->osport && intname[0] == 0)
        !           847:     {
        !           848:       errno = 0;
        !           849:       
        !           850:       if (addr->sa.sa_family == AF_INET &&
        !           851:          addr->in.sin_addr.s_addr == INADDR_ANY &&
        !           852:          addr->in.sin_port == htons(0)        !           853:        return NULL;
        !           854: 
        !           855: #ifdef HAVE_IPV6
        !           856:       if (addr->sa.sa_family == AF_INET6 &&
        !           857:          memcmp(&addr->in6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0 &&
        !           858:          addr->in6.sin6_port == htons(0)        !           859:        return NULL;
        !           860: #endif
        !           861:     }
        !           862:       
        !           863:   /* may have a suitable one already */
        !           864:   for (sfd = daemon->sfds; sfd; sfd = sfd->next )
        !           865:     if (sockaddr_isequal(&sfd->source_addr, addr) &&
        !           866:        strcmp(intname, sfd->interface) == 0)
        !           867:       return sfd;
        !           868:   
        !           869:   /* need to make a new one. */
        !           870:   errno = ENOMEM; /* in case malloc fails. */
        !           871:   if (!(sfd = whine_malloc(sizeof(struct serverfd))))
        !           872:     return NULL;
        !           873:   
        !           874:   if ((sfd->fd = socket(addr->sa.sa_family, SOCK_DGRAM, 0)) == -1)
        !           875:     {
        !           876:       free(sfd);
        !           877:       return NULL;
        !           878:     }
        !           879:   
        !           880:   if (!local_bind(sfd->fd, addr, intname, 0) || !fix_fd(sfd->fd))
        !           881:     { 
        !           882:       errsave = errno; /* save error from bind. */
        !           883:       close(sfd->fd);
        !           884:       free(sfd);
        !           885:       errno = errsave;
        !           886:       return NULL;
        !           887:     }
        !           888:     
        !           889:   strcpy(sfd->interface, intname); 
        !           890:   sfd->source_addr = *addr;
        !           891:   sfd->next = daemon->sfds;
        !           892:   daemon->sfds = sfd;
        !           893:   return sfd; 
        !           894: }
        !           895: 
        !           896: /* create upstream sockets during startup, before root is dropped which may be needed
        !           897:    this allows query_port to be a low port and interface binding */
        !           898: void pre_allocate_sfds(void)
        !           899: {
        !           900:   struct server *srv;
        !           901:   
        !           902:   if (daemon->query_port != 0)
        !           903:     {
        !           904:       union  mysockaddr addr;
        !           905:       memset(&addr, 0, sizeof(addr));
        !           906:       addr.in.sin_family = AF_INET;
        !           907:       addr.in.sin_addr.s_addr = INADDR_ANY;
        !           908:       addr.in.sin_port = htons(daemon->query_port);
        !           909: #ifdef HAVE_SOCKADDR_SA_LEN
        !           910:       addr.in.sin_len = sizeof(struct sockaddr_in);
        !           911: #endif
        !           912:       allocate_sfd(&addr, "");
        !           913: #ifdef HAVE_IPV6
        !           914:       memset(&addr, 0, sizeof(addr));
        !           915:       addr.in6.sin6_family = AF_INET6;
        !           916:       addr.in6.sin6_addr = in6addr_any;
        !           917:       addr.in6.sin6_port = htons(daemon->query_port);
        !           918: #ifdef HAVE_SOCKADDR_SA_LEN
        !           919:       addr.in6.sin6_len = sizeof(struct sockaddr_in6);
        !           920: #endif
        !           921:       allocate_sfd(&addr, "");
        !           922: #endif
        !           923:     }
        !           924:   
        !           925:   for (srv = daemon->servers; srv; srv = srv->next)
        !           926:     if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
        !           927:        !allocate_sfd(&srv->source_addr, srv->interface) &&
        !           928:        errno != 0 &&
        !           929:        option_bool(OPT_NOWILD))
        !           930:       {
        !           931:        prettyprint_addr(&srv->source_addr, daemon->namebuff);
        !           932:        if (srv->interface[0] != 0)
        !           933:          {
        !           934:            strcat(daemon->namebuff, " ");
        !           935:            strcat(daemon->namebuff, srv->interface);
        !           936:          }
        !           937:        die(_("failed to bind server socket for %s: %s"),
        !           938:            daemon->namebuff, EC_BADNET);
        !           939:       }  
        !           940: }
        !           941: 
        !           942: 
        !           943: void check_servers(void)
        !           944: {
        !           945:   struct irec *iface;
        !           946:   struct server *new, *tmp, *ret = NULL;
        !           947:   int port = 0;
        !           948: 
        !           949:   /* interface may be new since startup */
        !           950:   if (!option_bool(OPT_NOWILD))
        !           951:     enumerate_interfaces();
        !           952:   
        !           953:   for (new = daemon->servers; new; new = tmp)
        !           954:     {
        !           955:       tmp = new->next;
        !           956:       
        !           957:       if (!(new->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
        !           958:        {
        !           959:          port = prettyprint_addr(&new->addr, daemon->namebuff);
        !           960: 
        !           961:          /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
        !           962:          if (new->addr.sa.sa_family == AF_INET &&
        !           963:              new->addr.in.sin_addr.s_addr == 0)
        !           964:            {
        !           965:              free(new);
        !           966:              continue;
        !           967:            }
        !           968: 
        !           969:          for (iface = daemon->interfaces; iface; iface = iface->next)
        !           970:            if (sockaddr_isequal(&new->addr, &iface->addr))
        !           971:              break;
        !           972:          if (iface)
        !           973:            {
        !           974:              my_syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);
        !           975:              free(new);
        !           976:              continue;
        !           977:            }
        !           978:          
        !           979:          /* Do we need a socket set? */
        !           980:          if (!new->sfd && 
        !           981:              !(new->sfd = allocate_sfd(&new->source_addr, new->interface)) &&
        !           982:              errno != 0)
        !           983:            {
        !           984:              my_syslog(LOG_WARNING, 
        !           985:                        _("ignoring nameserver %s - cannot make/bind socket: %s"),
        !           986:                        daemon->namebuff, strerror(errno));
        !           987:              free(new);
        !           988:              continue;
        !           989:            }
        !           990:        }
        !           991:       
        !           992:       /* reverse order - gets it right. */
        !           993:       new->next = ret;
        !           994:       ret = new;
        !           995:       
        !           996:       if (!(new->flags & SERV_NO_REBIND))
        !           997:        {
        !           998:          if (new->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV))
        !           999:            {
        !          1000:              char *s1, *s2;
        !          1001:              if (!(new->flags & SERV_HAS_DOMAIN))
        !          1002:                s1 = _("unqualified"), s2 = _("names");
        !          1003:              else if (strlen(new->domain) == 0)
        !          1004:                s1 = _("default"), s2 = "";
        !          1005:              else
        !          1006:                s1 = _("domain"), s2 = new->domain;
        !          1007:              
        !          1008:              if (new->flags & SERV_NO_ADDR)
        !          1009:                my_syslog(LOG_INFO, _("using local addresses only for %s %s"), s1, s2);
        !          1010:              else if (new->flags & SERV_USE_RESOLV)
        !          1011:                my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2);
        !          1012:              else if (!(new->flags & SERV_LITERAL_ADDRESS))
        !          1013:                my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2);
        !          1014:            }
        !          1015:          else if (new->interface[0] != 0)
        !          1016:            my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, new->interface); 
        !          1017:          else
        !          1018:            my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port); 
        !          1019:        }
        !          1020:     }
        !          1021:   
        !          1022:   daemon->servers = ret;
        !          1023: }
        !          1024: 
        !          1025: /* Return zero if no servers found, in that case we keep polling.
        !          1026:    This is a protection against an update-time/write race on resolv.conf */
        !          1027: int reload_servers(char *fname)
        !          1028: {
        !          1029:   FILE *f;
        !          1030:   char *line;
        !          1031:   struct server *old_servers = NULL;
        !          1032:   struct server *new_servers = NULL;
        !          1033:   struct server *serv;
        !          1034:   int gotone = 0;
        !          1035: 
        !          1036:   /* buff happens to be MAXDNAME long... */
        !          1037:   if (!(f = fopen(fname, "r")))
        !          1038:     {
        !          1039:       my_syslog(LOG_ERR, _("failed to read %s: %s"), fname, strerror(errno));
        !          1040:       return 0;
        !          1041:     }
        !          1042:   
        !          1043:   /* move old servers to free list - we can reuse the memory 
        !          1044:      and not risk malloc if there are the same or fewer new servers. 
        !          1045:      Servers which were specced on the command line go to the new list. */
        !          1046:   for (serv = daemon->servers; serv;)
        !          1047:     {
        !          1048:       struct server *tmp = serv->next;
        !          1049:       if (serv->flags & SERV_FROM_RESOLV)
        !          1050:        {
        !          1051:          serv->next = old_servers;
        !          1052:          old_servers = serv; 
        !          1053:          /* forward table rules reference servers, so have to blow them away */
        !          1054:          server_gone(serv);
        !          1055:        }
        !          1056:       else
        !          1057:        {
        !          1058:          serv->next = new_servers;
        !          1059:          new_servers = serv;
        !          1060:        }
        !          1061:       serv = tmp;
        !          1062:     }
        !          1063:   
        !          1064:   while ((line = fgets(daemon->namebuff, MAXDNAME, f)))
        !          1065:     {
        !          1066:       union mysockaddr addr, source_addr;
        !          1067:       char *token = strtok(line, " \t\n\r");
        !          1068:       
        !          1069:       if (!token)
        !          1070:        continue;
        !          1071:       if (strcmp(token, "nameserver") != 0 && strcmp(token, "server") != 0)
        !          1072:        continue;
        !          1073:       if (!(token = strtok(NULL, " \t\n\r")))
        !          1074:        continue;
        !          1075:       
        !          1076:       memset(&addr, 0, sizeof(addr));
        !          1077:       memset(&source_addr, 0, sizeof(source_addr));
        !          1078:       
        !          1079:       if ((addr.in.sin_addr.s_addr = inet_addr(token)) != (in_addr_t) -1)
        !          1080:        {
        !          1081: #ifdef HAVE_SOCKADDR_SA_LEN
        !          1082:          source_addr.in.sin_len = addr.in.sin_len = sizeof(source_addr.in);
        !          1083: #endif
        !          1084:          source_addr.in.sin_family = addr.in.sin_family = AF_INET;
        !          1085:          addr.in.sin_port = htons(NAMESERVER_PORT);
        !          1086:          source_addr.in.sin_addr.s_addr = INADDR_ANY;
        !          1087:          source_addr.in.sin_port = htons(daemon->query_port);
        !          1088:        }
        !          1089: #ifdef HAVE_IPV6
        !          1090:       else 
        !          1091:        {       
        !          1092:          int scope_index = 0;
        !          1093:          char *scope_id = strchr(token, '%');
        !          1094:          
        !          1095:          if (scope_id)
        !          1096:            {
        !          1097:              *(scope_id++) = 0;
        !          1098:              scope_index = if_nametoindex(scope_id);
        !          1099:            }
        !          1100:          
        !          1101:          if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
        !          1102:            {
        !          1103: #ifdef HAVE_SOCKADDR_SA_LEN
        !          1104:              source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6);
        !          1105: #endif
        !          1106:              source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
        !          1107:              source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = 0;
        !          1108:              addr.in6.sin6_port = htons(NAMESERVER_PORT);
        !          1109:              addr.in6.sin6_scope_id = scope_index;
        !          1110:              source_addr.in6.sin6_addr = in6addr_any;
        !          1111:              source_addr.in6.sin6_port = htons(daemon->query_port);
        !          1112:              source_addr.in6.sin6_scope_id = 0;
        !          1113:            }
        !          1114:          else
        !          1115:            continue;
        !          1116:        }
        !          1117: #else /* IPV6 */
        !          1118:       else
        !          1119:        continue;
        !          1120: #endif 
        !          1121: 
        !          1122:       if (old_servers)
        !          1123:        {
        !          1124:          serv = old_servers;
        !          1125:          old_servers = old_servers->next;
        !          1126:        }
        !          1127:       else if (!(serv = whine_malloc(sizeof (struct server))))
        !          1128:        continue;
        !          1129:       
        !          1130:       /* this list is reverse ordered: 
        !          1131:         it gets reversed again in check_servers */
        !          1132:       serv->next = new_servers;
        !          1133:       new_servers = serv;
        !          1134:       serv->addr = addr;
        !          1135:       serv->source_addr = source_addr;
        !          1136:       serv->domain = NULL;
        !          1137:       serv->interface[0] = 0;
        !          1138:       serv->sfd = NULL;
        !          1139:       serv->flags = SERV_FROM_RESOLV;
        !          1140:       serv->queries = serv->failed_queries = 0;
        !          1141:       gotone = 1;
        !          1142:     }
        !          1143:   
        !          1144:   /* Free any memory not used. */
        !          1145:   while (old_servers)
        !          1146:     {
        !          1147:       struct server *tmp = old_servers->next;
        !          1148:       free(old_servers);
        !          1149:       old_servers = tmp;
        !          1150:     }
        !          1151: 
        !          1152:   daemon->servers = new_servers;
        !          1153:   fclose(f);
        !          1154: 
        !          1155:   return gotone;
        !          1156: }
        !          1157: 
        !          1158: 
        !          1159: /* Use an IPv4 listener socket for ioctling */
        !          1160: struct in_addr get_ifaddr(char *intr)
        !          1161: {
        !          1162:   struct listener *l;
        !          1163:   struct ifreq ifr;
        !          1164:   struct sockaddr_in ret;
        !          1165:   
        !          1166:   ret.sin_addr.s_addr = -1;
        !          1167: 
        !          1168:   for (l = daemon->listeners; 
        !          1169:        l && (l->family != AF_INET || l->fd == -1);
        !          1170:        l = l->next);
        !          1171:   
        !          1172:   strncpy(ifr.ifr_name, intr, IF_NAMESIZE);
        !          1173:   ifr.ifr_addr.sa_family = AF_INET;
        !          1174:   
        !          1175:   if (l &&  ioctl(l->fd, SIOCGIFADDR, &ifr) != -1)
        !          1176:     memcpy(&ret, &ifr.ifr_addr, sizeof(ret)); 
        !          1177:   
        !          1178:   return ret.sin_addr;
        !          1179: }
        !          1180: 
        !          1181: 
        !          1182: 

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