Annotation of embedaddon/dnsmasq/src/dhcp-common.c, revision 1.1.1.5

1.1.1.5 ! misho       1: /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
1.1       misho       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_DHCP
                     20: 
                     21: void dhcp_common_init(void)
                     22: {
1.1.1.4   misho      23:   /* These each hold a DHCP option max size 255
                     24:      and get a terminating zero added */
                     25:   daemon->dhcp_buff = safe_malloc(DHCP_BUFF_SZ);
                     26:   daemon->dhcp_buff2 = safe_malloc(DHCP_BUFF_SZ); 
                     27:   daemon->dhcp_buff3 = safe_malloc(DHCP_BUFF_SZ);
1.1       misho      28:   
                     29:   /* dhcp_packet is used by v4 and v6, outpacket only by v6 
                     30:      sizeof(struct dhcp_packet) is as good an initial size as any,
                     31:      even for v6 */
                     32:   expand_buf(&daemon->dhcp_packet, sizeof(struct dhcp_packet));
                     33: #ifdef HAVE_DHCP6
                     34:   if (daemon->dhcp6)
                     35:     expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
                     36: #endif
                     37: }
                     38: 
                     39: ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
                     40: {  
1.1.1.4   misho      41:   ssize_t sz, new_sz;
1.1       misho      42:  
                     43:   while (1)
                     44:     {
                     45:       msg->msg_flags = 0;
                     46:       while ((sz = recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
                     47:       
                     48:       if (sz == -1)
                     49:        return -1;
                     50:       
                     51:       if (!(msg->msg_flags & MSG_TRUNC))
                     52:        break;
                     53: 
                     54:       /* Very new Linux kernels return the actual size needed, 
                     55:         older ones always return truncated size */
                     56:       if ((size_t)sz == msg->msg_iov->iov_len)
                     57:        {
                     58:          if (!expand_buf(msg->msg_iov, sz + 100))
                     59:            return -1;
                     60:        }
                     61:       else
                     62:        {
                     63:          expand_buf(msg->msg_iov, sz);
                     64:          break;
                     65:        }
                     66:     }
                     67:   
1.1.1.4   misho      68:   while ((new_sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
                     69: 
                     70:   /* Some kernels seem to ignore MSG_PEEK, and dequeue the packet anyway. 
                     71:      If that happens we get EAGAIN here because the socket is non-blocking.
                     72:      Use the result of the original testing recvmsg as long as the buffer
                     73:      was big enough. There's a small race here that may lose the odd packet,
                     74:      but it's UDP anyway. */
                     75:   
                     76:   if (new_sz == -1 && (errno == EWOULDBLOCK || errno == EAGAIN))
                     77:     new_sz = sz;
1.1       misho      78:   
1.1.1.4   misho      79:   return (msg->msg_flags & MSG_TRUNC) ? -1 : new_sz;
1.1       misho      80: }
                     81: 
1.1.1.5 ! misho      82: /* like match_netid() except that the check can have a trailing * for wildcard */
        !            83: /* started as a direct copy of match_netid() */
        !            84: int match_netid_wild(struct dhcp_netid *check, struct dhcp_netid *pool)
        !            85: {
        !            86:   struct dhcp_netid *tmp1;
        !            87:   
        !            88:   for (; check; check = check->next)
        !            89:     {
        !            90:       const int check_len = strlen(check->net);
        !            91:       const int is_wc = (check_len > 0 && check->net[check_len - 1] == '*');
        !            92:       
        !            93:       /* '#' for not is for backwards compat. */
        !            94:       if (check->net[0] != '!' && check->net[0] != '#')
        !            95:        {
        !            96:          for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
        !            97:            if (is_wc ? (strncmp(check->net, tmp1->net, check_len-1) == 0) :
        !            98:                (strcmp(check->net, tmp1->net) == 0))
        !            99:              break;
        !           100:          if (!tmp1)
        !           101:            return 0;
        !           102:        }
        !           103:       else
        !           104:        for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
        !           105:          if (is_wc ? (strncmp((check->net)+1, tmp1->net, check_len-2) == 0) :
        !           106:              (strcmp((check->net)+1, tmp1->net) == 0))
        !           107:            return 0;
        !           108:     }
        !           109:   return 1;
        !           110: }
        !           111: 
1.1       misho     112: struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
                    113: {
                    114:   struct tag_if *exprs;
                    115:   struct dhcp_netid_list *list;
                    116: 
1.1.1.5 ! misho     117:   /* this now uses match_netid_wild() above so that tag_if can
        !           118:    * be used to set a 'group of interfaces' tag.
        !           119:    */
1.1       misho     120:   for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
1.1.1.5 ! misho     121:     if (match_netid_wild(exprs->tag, tags))
1.1       misho     122:       for (list = exprs->set; list; list = list->next)
                    123:        {
                    124:          list->list->next = tags;
                    125:          tags = list->list;
                    126:        }
                    127: 
                    128:   return tags;
                    129: }
                    130: 
                    131: 
                    132: struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *context_tags, struct dhcp_opt *opts)
                    133: {
                    134:   struct dhcp_netid *tagif = run_tag_if(tags);
                    135:   struct dhcp_opt *opt;
                    136:   struct dhcp_opt *tmp;  
                    137: 
                    138:   /* flag options which are valid with the current tag set (sans context tags) */
                    139:   for (opt = opts; opt; opt = opt->next)
                    140:     {
                    141:       opt->flags &= ~DHOPT_TAGOK;
                    142:       if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
                    143:          match_netid(opt->netid, tagif, 0))
                    144:        opt->flags |= DHOPT_TAGOK;
                    145:     }
                    146: 
                    147:   /* now flag options which are valid, including the context tags,
                    148:      otherwise valid options are inhibited if we found a higher priority one above */
                    149:   if (context_tags)
                    150:     {
                    151:       struct dhcp_netid *last_tag;
                    152: 
                    153:       for (last_tag = context_tags; last_tag->next; last_tag = last_tag->next);
                    154:       last_tag->next = tags;
                    155:       tagif = run_tag_if(context_tags);
                    156:       
                    157:       /* reset stuff with tag:!<tag> which now matches. */
                    158:       for (opt = opts; opt; opt = opt->next)
                    159:        if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
                    160:            (opt->flags & DHOPT_TAGOK) &&
                    161:            !match_netid(opt->netid, tagif, 0))
                    162:          opt->flags &= ~DHOPT_TAGOK;
                    163: 
                    164:       for (opt = opts; opt; opt = opt->next)
                    165:        if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) &&
                    166:            match_netid(opt->netid, tagif, 0))
                    167:          {
                    168:            struct dhcp_opt *tmp;  
                    169:            for (tmp = opts; tmp; tmp = tmp->next) 
                    170:              if (tmp->opt == opt->opt && opt->netid && (tmp->flags & DHOPT_TAGOK))
                    171:                break;
                    172:            if (!tmp)
                    173:              opt->flags |= DHOPT_TAGOK;
                    174:          }      
                    175:     }
                    176:   
                    177:   /* now flag untagged options which are not overridden by tagged ones */
                    178:   for (opt = opts; opt; opt = opt->next)
                    179:     if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
                    180:       {
                    181:        for (tmp = opts; tmp; tmp = tmp->next) 
                    182:          if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
                    183:            break;
                    184:        if (!tmp)
                    185:          opt->flags |= DHOPT_TAGOK;
                    186:        else if (!tmp->netid)
                    187:          my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt); 
                    188:       }
                    189: 
                    190:   /* Finally, eliminate duplicate options later in the chain, and therefore earlier in the config file. */
                    191:   for (opt = opts; opt; opt = opt->next)
                    192:     if (opt->flags & DHOPT_TAGOK)
                    193:       for (tmp = opt->next; tmp; tmp = tmp->next) 
                    194:        if (tmp->opt == opt->opt)
                    195:          tmp->flags &= ~DHOPT_TAGOK;
                    196:   
                    197:   return tagif;
                    198: }
                    199:        
                    200: /* Is every member of check matched by a member of pool? 
                    201:    If tagnotneeded, untagged is OK */
                    202: int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded)
                    203: {
                    204:   struct dhcp_netid *tmp1;
                    205:   
                    206:   if (!check && !tagnotneeded)
                    207:     return 0;
                    208: 
                    209:   for (; check; check = check->next)
                    210:     {
                    211:       /* '#' for not is for backwards compat. */
                    212:       if (check->net[0] != '!' && check->net[0] != '#')
                    213:        {
                    214:          for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
                    215:            if (strcmp(check->net, tmp1->net) == 0)
                    216:              break;
                    217:          if (!tmp1)
                    218:            return 0;
                    219:        }
                    220:       else
                    221:        for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
                    222:          if (strcmp((check->net)+1, tmp1->net) == 0)
                    223:            return 0;
                    224:     }
                    225:   return 1;
                    226: }
                    227: 
                    228: /* return domain or NULL if none. */
                    229: char *strip_hostname(char *hostname)
                    230: {
                    231:   char *dot = strchr(hostname, '.');
                    232:  
                    233:   if (!dot)
                    234:     return NULL;
                    235:   
                    236:   *dot = 0; /* truncate */
                    237:   if (strlen(dot+1) != 0)
                    238:     return dot+1;
                    239:   
                    240:   return NULL;
                    241: }
                    242: 
                    243: void log_tags(struct dhcp_netid *netid, u32 xid)
                    244: {
                    245:   if (netid && option_bool(OPT_LOG_OPTS))
                    246:     {
                    247:       char *s = daemon->namebuff;
                    248:       for (*s = 0; netid; netid = netid->next)
                    249:        {
                    250:          /* kill dupes. */
                    251:          struct dhcp_netid *n;
                    252:          
                    253:          for (n = netid->next; n; n = n->next)
                    254:            if (strcmp(netid->net, n->net) == 0)
                    255:              break;
                    256:          
                    257:          if (!n)
                    258:            {
                    259:              strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
                    260:              if (netid->next)
                    261:                strncat (s, ", ", (MAXDNAME-1) - strlen(s));
                    262:            }
                    263:        }
                    264:       my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), xid, s);
                    265:     } 
                    266: }   
                    267:   
                    268: int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
                    269: {
                    270:   int i;
                    271:   
                    272:   if (o->len > len)
                    273:     return 0;
                    274:   
                    275:   if (o->len == 0)
                    276:     return 1;
                    277:      
                    278:   if (o->flags & DHOPT_HEX)
                    279:     { 
                    280:       if (memcmp_masked(o->val, p, o->len, o->u.wildcard_mask))
                    281:        return 1;
                    282:     }
                    283:   else 
                    284:     for (i = 0; i <= (len - o->len); ) 
                    285:       {
                    286:        if (memcmp(o->val, p + i, o->len) == 0)
                    287:          return 1;
                    288:            
                    289:        if (o->flags & DHOPT_STRING)
                    290:          i++;
                    291:        else
                    292:          i += o->len;
                    293:       }
                    294:   
                    295:   return 0;
                    296: }
                    297: 
1.1.1.2   misho     298: int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
                    299: {
                    300:   struct hwaddr_config *conf_addr;
                    301:   
                    302:   for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
                    303:     if (conf_addr->wildcard_mask == 0 &&
                    304:        conf_addr->hwaddr_len == len &&
                    305:        (conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
                    306:        memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
                    307:       return 1;
                    308:   
                    309:   return 0;
                    310: }
                    311: 
                    312: static int is_config_in_context(struct dhcp_context *context, struct dhcp_config *config)
                    313: {
                    314:   if (!context) /* called via find_config() from lease_update_from_configs() */
                    315:     return 1; 
1.1.1.5 ! misho     316: 
        !           317:   if (!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6)))
        !           318:     return 1;
1.1.1.2   misho     319:   
                    320: #ifdef HAVE_DHCP6
1.1.1.4   misho     321:   if (context->flags & CONTEXT_V6)
                    322:     {
                    323:        struct addrlist *addr_list;
1.1.1.2   misho     324: 
1.1.1.5 ! misho     325:        if (config->flags & CONFIG_ADDR6)
        !           326:         for (; context; context = context->current)
        !           327:           for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
        !           328:             {
        !           329:               if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64)
        !           330:                 return 1;
        !           331:               
        !           332:               if (is_same_net6(&addr_list->addr.addr6, &context->start6, context->prefix))
        !           333:                 return 1;
        !           334:             }
1.1.1.4   misho     335:     }
                    336:   else
1.1.1.2   misho     337: #endif
1.1.1.4   misho     338:     {
                    339:       for (; context; context = context->current)
                    340:        if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
                    341:          return 1;
                    342:     }
1.1.1.2   misho     343: 
                    344:   return 0;
                    345: }
                    346: 
1.1.1.4   misho     347: static struct dhcp_config *find_config_match(struct dhcp_config *configs,
                    348:                                             struct dhcp_context *context,
                    349:                                             unsigned char *clid, int clid_len,
                    350:                                             unsigned char *hwaddr, int hw_len, 
                    351:                                             int hw_type, char *hostname,
                    352:                                             struct dhcp_netid *tags, int tag_not_needed)
1.1.1.2   misho     353: {
                    354:   int count, new;
                    355:   struct dhcp_config *config, *candidate; 
                    356:   struct hwaddr_config *conf_addr;
                    357: 
                    358:   if (clid)
                    359:     for (config = configs; config; config = config->next)
                    360:       if (config->flags & CONFIG_CLID)
                    361:        {
                    362:          if (config->clid_len == clid_len && 
                    363:              memcmp(config->clid, clid, clid_len) == 0 &&
1.1.1.4   misho     364:              is_config_in_context(context, config) &&
                    365:              match_netid(config->filter, tags, tag_not_needed))
                    366:            
1.1.1.2   misho     367:            return config;
                    368:          
                    369:          /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
                    370:             cope with that here. This is IPv4 only. context==NULL implies IPv4, 
                    371:             see lease_update_from_configs() */
                    372:          if ((!context || !(context->flags & CONTEXT_V6)) && *clid == 0 && config->clid_len == clid_len-1  &&
                    373:              memcmp(config->clid, clid+1, clid_len-1) == 0 &&
1.1.1.4   misho     374:              is_config_in_context(context, config) &&
                    375:              match_netid(config->filter, tags, tag_not_needed))
1.1.1.2   misho     376:            return config;
                    377:        }
                    378:   
                    379: 
                    380:   if (hwaddr)
                    381:     for (config = configs; config; config = config->next)
                    382:       if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
1.1.1.4   misho     383:          is_config_in_context(context, config) &&
                    384:          match_netid(config->filter, tags, tag_not_needed))
1.1.1.2   misho     385:        return config;
                    386:   
                    387:   if (hostname && context)
                    388:     for (config = configs; config; config = config->next)
                    389:       if ((config->flags & CONFIG_NAME) && 
                    390:          hostname_isequal(config->hostname, hostname) &&
1.1.1.4   misho     391:          is_config_in_context(context, config) &&
                    392:          match_netid(config->filter, tags, tag_not_needed))
1.1.1.2   misho     393:        return config;
                    394: 
                    395:   
                    396:   if (!hwaddr)
                    397:     return NULL;
                    398: 
                    399:   /* use match with fewest wildcard octets */
                    400:   for (candidate = NULL, count = 0, config = configs; config; config = config->next)
1.1.1.4   misho     401:     if (is_config_in_context(context, config) &&
                    402:        match_netid(config->filter, tags, tag_not_needed))
1.1.1.2   misho     403:       for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
                    404:        if (conf_addr->wildcard_mask != 0 &&
                    405:            conf_addr->hwaddr_len == hw_len &&  
                    406:            (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
                    407:            (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
                    408:          {
                    409:              count = new;
                    410:              candidate = config;
                    411:          }
                    412:   
                    413:   return candidate;
                    414: }
                    415: 
1.1.1.4   misho     416: /* Find tagged configs first. */
                    417: struct dhcp_config *find_config(struct dhcp_config *configs,
                    418:                                struct dhcp_context *context,
                    419:                                unsigned char *clid, int clid_len,
                    420:                                unsigned char *hwaddr, int hw_len, 
                    421:                                int hw_type, char *hostname, struct dhcp_netid *tags)
                    422: {
                    423:   struct dhcp_config *ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 0);
                    424: 
                    425:   if (!ret)
                    426:     ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 1);
                    427: 
                    428:   return ret;
                    429: }
                    430: 
1.1       misho     431: void dhcp_update_configs(struct dhcp_config *configs)
                    432: {
                    433:   /* Some people like to keep all static IP addresses in /etc/hosts.
                    434:      This goes through /etc/hosts and sets static addresses for any DHCP config
                    435:      records which don't have an address and whose name matches. 
                    436:      We take care to maintain the invariant that any IP address can appear
                    437:      in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP, 
                    438:      restore the status-quo ante first. */
                    439:   
                    440:   struct dhcp_config *config, *conf_tmp;
                    441:   struct crec *crec;
                    442:   int prot = AF_INET;
                    443: 
                    444:   for (config = configs; config; config = config->next)
1.1.1.4   misho     445:   {
1.1       misho     446:     if (config->flags & CONFIG_ADDR_HOSTS)
1.1.1.4   misho     447:       config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS);
                    448: #ifdef HAVE_DHCP6
                    449:     if (config->flags & CONFIG_ADDR6_HOSTS)
                    450:       config->flags &= ~(CONFIG_ADDR6 | CONFIG_ADDR6_HOSTS);
                    451: #endif
                    452:   }
1.1       misho     453: 
                    454: #ifdef HAVE_DHCP6 
                    455:  again:  
                    456: #endif
                    457: 
                    458:   if (daemon->port != 0)
                    459:     for (config = configs; config; config = config->next)
                    460:       {
                    461:        int conflags = CONFIG_ADDR;
                    462:        int cacheflags = F_IPV4;
                    463: 
                    464: #ifdef HAVE_DHCP6
                    465:        if (prot == AF_INET6)
                    466:          {
                    467:            conflags = CONFIG_ADDR6;
                    468:            cacheflags = F_IPV6;
                    469:          }
                    470: #endif
                    471:        if (!(config->flags & conflags) &&
                    472:            (config->flags & CONFIG_NAME) && 
                    473:            (crec = cache_find_by_name(NULL, config->hostname, 0, cacheflags)) &&
                    474:            (crec->flags & F_HOSTS))
                    475:          {
                    476:            if (cache_find_by_name(crec, config->hostname, 0, cacheflags))
                    477:              {
                    478:                /* use primary (first) address */
1.1.1.2   misho     479:                while (crec && !(crec->flags & F_REVERSE))
                    480:                  crec = cache_find_by_name(crec, config->hostname, 0, cacheflags);
                    481:                if (!crec)
                    482:                  continue; /* should be never */
1.1.1.4   misho     483:                inet_ntop(prot, &crec->addr, daemon->addrbuff, ADDRSTRLEN);
1.1.1.2   misho     484:                my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"), 
                    485:                          config->hostname, daemon->addrbuff);
1.1       misho     486:              }
                    487:            
                    488:            if (prot == AF_INET && 
1.1.1.4   misho     489:                (!(conf_tmp = config_find_by_address(configs, crec->addr.addr4)) || conf_tmp == config))
1.1       misho     490:              {
1.1.1.4   misho     491:                config->addr = crec->addr.addr4;
1.1       misho     492:                config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
                    493:                continue;
                    494:              }
                    495: 
                    496: #ifdef HAVE_DHCP6
                    497:            if (prot == AF_INET6 && 
1.1.1.4   misho     498:                (!(conf_tmp = config_find_by_address6(configs, NULL, 0, &crec->addr.addr6)) || conf_tmp == config))
1.1       misho     499:              {
1.1.1.4   misho     500:                /* host must have exactly one address if comming from /etc/hosts. */
                    501:                if (!config->addr6 && (config->addr6 = whine_malloc(sizeof(struct addrlist))))
                    502:                  {
                    503:                    config->addr6->next = NULL;
                    504:                    config->addr6->flags = 0;
                    505:                  }
                    506: 
                    507:                if (config->addr6 && !config->addr6->next && !(config->addr6->flags & (ADDRLIST_WILDCARD|ADDRLIST_PREFIX)))
                    508:                  {
                    509:                    memcpy(&config->addr6->addr.addr6, &crec->addr.addr6, IN6ADDRSZ);
                    510:                    config->flags |= CONFIG_ADDR6 | CONFIG_ADDR6_HOSTS;
                    511:                  }
                    512:            
1.1       misho     513:                continue;
                    514:              }
                    515: #endif
                    516: 
1.1.1.4   misho     517:            inet_ntop(prot, &crec->addr, daemon->addrbuff, ADDRSTRLEN);
1.1       misho     518:            my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"), 
                    519:                      daemon->addrbuff, config->hostname);
                    520:            
                    521:            
                    522:          }
                    523:       }
                    524: 
                    525: #ifdef HAVE_DHCP6
                    526:   if (prot == AF_INET)
                    527:     {
                    528:       prot = AF_INET6;
                    529:       goto again;
                    530:     }
                    531: #endif
                    532: 
                    533: }
                    534: 
                    535: #ifdef HAVE_LINUX_NETWORK 
1.1.1.2   misho     536: char *whichdevice(void)
1.1       misho     537: {
                    538:   /* If we are doing DHCP on exactly one interface, and running linux, do SO_BINDTODEVICE
                    539:      to that device. This is for the use case of  (eg) OpenStack, which runs a new
                    540:      dnsmasq instance for each VLAN interface it creates. Without the BINDTODEVICE, 
                    541:      individual processes don't always see the packets they should.
1.1.1.2   misho     542:      SO_BINDTODEVICE is only available Linux. 
                    543: 
                    544:      Note that if wildcards are used in --interface, or --interface is not used at all,
                    545:      or a configured interface doesn't yet exist, then more interfaces may arrive later, 
                    546:      so we can't safely assert there is only one interface and proceed.
                    547: */
1.1       misho     548:   
                    549:   struct irec *iface, *found;
1.1.1.2   misho     550:   struct iname *if_tmp;
                    551:   
                    552:   if (!daemon->if_names)
                    553:     return NULL;
1.1       misho     554:   
1.1.1.2   misho     555:   for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
                    556:     if (if_tmp->name && (!if_tmp->used || strchr(if_tmp->name, '*')))
                    557:       return NULL;
                    558: 
1.1       misho     559:   for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
                    560:     if (iface->dhcp_ok)
                    561:       {
                    562:        if (!found)
                    563:          found = iface;
                    564:        else if (strcmp(found->name, iface->name) != 0) 
1.1.1.2   misho     565:          return NULL; /* more than one. */
1.1       misho     566:       }
1.1.1.2   misho     567: 
1.1       misho     568:   if (found)
1.1.1.5 ! misho     569:     {
        !           570:       char *ret = safe_malloc(strlen(found->name)+1);
        !           571:       strcpy(ret, found->name);
        !           572:       return ret;
        !           573:     }
        !           574:   
1.1.1.2   misho     575:   return NULL;
                    576: }
                    577:  
1.1.1.5 ! misho     578: static int bindtodevice(char *device, int fd)
1.1.1.2   misho     579: {
1.1.1.4   misho     580:   size_t len = strlen(device)+1;
                    581:   if (len > IFNAMSIZ)
                    582:     len = IFNAMSIZ;
1.1.1.2   misho     583:   /* only allowed by root. */
1.1.1.4   misho     584:   if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, device, len) == -1 &&
1.1.1.2   misho     585:       errno != EPERM)
1.1.1.5 ! misho     586:     return 2;
        !           587:   
        !           588:   return 1;
        !           589: }
        !           590: 
        !           591: int bind_dhcp_devices(char *bound_device)
        !           592: {
        !           593:   int ret = 0;
        !           594: 
        !           595:   if (bound_device)
        !           596:     {
        !           597:       if (daemon->dhcp)
        !           598:        {
        !           599:          if (!daemon->relay4)
        !           600:            ret |= bindtodevice(bound_device, daemon->dhcpfd);
        !           601:          
        !           602:          if (daemon->enable_pxe && daemon->pxefd != -1)
        !           603:            ret |= bindtodevice(bound_device, daemon->pxefd);
        !           604:        }
        !           605:       
        !           606: #if defined(HAVE_DHCP6)
        !           607:       if (daemon->doing_dhcp6 && !daemon->relay6)
        !           608:        ret |= bindtodevice(bound_device, daemon->dhcp6fd);
        !           609: #endif
        !           610:     }
        !           611:   
        !           612:   return ret;
1.1       misho     613: }
                    614: #endif
                    615: 
                    616: static const struct opttab_t {
                    617:   char *name;
                    618:   u16 val, size;
                    619: } opttab[] = {
                    620:   { "netmask", 1, OT_ADDR_LIST },
                    621:   { "time-offset", 2, 4 },
                    622:   { "router", 3, OT_ADDR_LIST  },
                    623:   { "dns-server", 6, OT_ADDR_LIST },
                    624:   { "log-server", 7, OT_ADDR_LIST },
                    625:   { "lpr-server", 9, OT_ADDR_LIST },
                    626:   { "hostname", 12, OT_INTERNAL | OT_NAME },
                    627:   { "boot-file-size", 13, 2 | OT_DEC },
                    628:   { "domain-name", 15, OT_NAME },
                    629:   { "swap-server", 16, OT_ADDR_LIST },
                    630:   { "root-path", 17, OT_NAME },
                    631:   { "extension-path", 18, OT_NAME },
                    632:   { "ip-forward-enable", 19, 1 },
                    633:   { "non-local-source-routing", 20, 1 },
                    634:   { "policy-filter", 21, OT_ADDR_LIST },
                    635:   { "max-datagram-reassembly", 22, 2 | OT_DEC },
                    636:   { "default-ttl", 23, 1 | OT_DEC },
                    637:   { "mtu", 26, 2 | OT_DEC },
                    638:   { "all-subnets-local", 27, 1 },
                    639:   { "broadcast", 28, OT_INTERNAL | OT_ADDR_LIST },
                    640:   { "router-discovery", 31, 1 },
                    641:   { "router-solicitation", 32, OT_ADDR_LIST },
                    642:   { "static-route", 33, OT_ADDR_LIST },
                    643:   { "trailer-encapsulation", 34, 1 },
                    644:   { "arp-timeout", 35, 4 | OT_DEC },
                    645:   { "ethernet-encap", 36, 1 },
                    646:   { "tcp-ttl", 37, 1 },
                    647:   { "tcp-keepalive", 38, 4 | OT_DEC },
                    648:   { "nis-domain", 40, OT_NAME },
                    649:   { "nis-server", 41, OT_ADDR_LIST },
                    650:   { "ntp-server", 42, OT_ADDR_LIST },
                    651:   { "vendor-encap", 43, OT_INTERNAL },
                    652:   { "netbios-ns", 44, OT_ADDR_LIST },
                    653:   { "netbios-dd", 45, OT_ADDR_LIST },
                    654:   { "netbios-nodetype", 46, 1 },
                    655:   { "netbios-scope", 47, 0 },
                    656:   { "x-windows-fs", 48, OT_ADDR_LIST },
                    657:   { "x-windows-dm", 49, OT_ADDR_LIST },
                    658:   { "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
                    659:   { "lease-time", 51, OT_INTERNAL | OT_TIME },
                    660:   { "option-overload", 52, OT_INTERNAL },
                    661:   { "message-type", 53, OT_INTERNAL | OT_DEC },
                    662:   { "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
                    663:   { "parameter-request", 55, OT_INTERNAL },
                    664:   { "message", 56, OT_INTERNAL },
                    665:   { "max-message-size", 57, OT_INTERNAL },
1.1.1.3   misho     666:   { "T1", 58, OT_TIME},
                    667:   { "T2", 59, OT_TIME},
1.1       misho     668:   { "vendor-class", 60, 0 },
                    669:   { "client-id", 61, OT_INTERNAL },
                    670:   { "nis+-domain", 64, OT_NAME },
                    671:   { "nis+-server", 65, OT_ADDR_LIST },
                    672:   { "tftp-server", 66, OT_NAME },
                    673:   { "bootfile-name", 67, OT_NAME },
                    674:   { "mobile-ip-home", 68, OT_ADDR_LIST }, 
                    675:   { "smtp-server", 69, OT_ADDR_LIST }, 
                    676:   { "pop3-server", 70, OT_ADDR_LIST }, 
                    677:   { "nntp-server", 71, OT_ADDR_LIST }, 
                    678:   { "irc-server", 74, OT_ADDR_LIST }, 
                    679:   { "user-class", 77, 0 },
1.1.1.4   misho     680:   { "rapid-commit", 80, 0 },
1.1       misho     681:   { "FQDN", 81, OT_INTERNAL },
                    682:   { "agent-id", 82, OT_INTERNAL },
                    683:   { "client-arch", 93, 2 | OT_DEC },
                    684:   { "client-interface-id", 94, 0 },
                    685:   { "client-machine-id", 97, 0 },
1.1.1.5 ! misho     686:   { "posix-timezone", 100, OT_NAME }, /* RFC 4833, Sec. 2 */
        !           687:   { "tzdb-timezone", 101, OT_NAME }, /* RFC 4833, Sec. 2 */
        !           688:   { "ipv6-only", 108, 4 | OT_DEC },  /* RFC 8925 */ 
1.1       misho     689:   { "subnet-select", 118, OT_INTERNAL },
                    690:   { "domain-search", 119, OT_RFC1035_NAME },
                    691:   { "sip-server", 120, 0 },
                    692:   { "classless-static-route", 121, 0 },
                    693:   { "vendor-id-encap", 125, 0 },
1.1.1.4   misho     694:   { "tftp-server-address", 150, OT_ADDR_LIST },
1.1       misho     695:   { "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
                    696:   { NULL, 0, 0 }
                    697: };
                    698: 
                    699: #ifdef HAVE_DHCP6
                    700: static const struct opttab_t opttab6[] = {
                    701:   { "client-id", 1, OT_INTERNAL },
                    702:   { "server-id", 2, OT_INTERNAL },
                    703:   { "ia-na", 3, OT_INTERNAL },
                    704:   { "ia-ta", 4, OT_INTERNAL },
                    705:   { "iaaddr", 5, OT_INTERNAL },
                    706:   { "oro", 6, OT_INTERNAL },
                    707:   { "preference", 7, OT_INTERNAL | OT_DEC },
                    708:   { "unicast", 12, OT_INTERNAL },
                    709:   { "status", 13, OT_INTERNAL },
                    710:   { "rapid-commit", 14, OT_INTERNAL },
                    711:   { "user-class", 15, OT_INTERNAL | OT_CSTRING },
                    712:   { "vendor-class", 16, OT_INTERNAL | OT_CSTRING },
                    713:   { "vendor-opts", 17, OT_INTERNAL },
                    714:   { "sip-server-domain", 21,  OT_RFC1035_NAME },
                    715:   { "sip-server", 22, OT_ADDR_LIST },
                    716:   { "dns-server", 23, OT_ADDR_LIST },
                    717:   { "domain-search", 24, OT_RFC1035_NAME },
                    718:   { "nis-server", 27, OT_ADDR_LIST },
                    719:   { "nis+-server", 28, OT_ADDR_LIST },
                    720:   { "nis-domain", 29,  OT_RFC1035_NAME },
                    721:   { "nis+-domain", 30, OT_RFC1035_NAME },
                    722:   { "sntp-server", 31,  OT_ADDR_LIST },
                    723:   { "information-refresh-time", 32, OT_TIME },
                    724:   { "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
1.1.1.5 ! misho     725:   { "posix-timezone", 41, OT_NAME }, /* RFC 4833, Sec. 3 */
        !           726:   { "tzdb-timezone", 42, OT_NAME }, /* RFC 4833, Sec. 3 */
1.1.1.4   misho     727:   { "ntp-server", 56, 0 /* OT_ADDR_LIST | OT_RFC1035_NAME */ },
1.1       misho     728:   { "bootfile-url", 59, OT_NAME },
                    729:   { "bootfile-param", 60, OT_CSTRING },
                    730:   { NULL, 0, 0 }
                    731: };
                    732: #endif
                    733: 
                    734: 
                    735: 
                    736: void display_opts(void)
                    737: {
                    738:   int i;
                    739:   
                    740:   printf(_("Known DHCP options:\n"));
                    741:   
                    742:   for (i = 0; opttab[i].name; i++)
                    743:     if (!(opttab[i].size & OT_INTERNAL))
                    744:       printf("%3d %s\n", opttab[i].val, opttab[i].name);
                    745: }
                    746: 
                    747: #ifdef HAVE_DHCP6
                    748: void display_opts6(void)
                    749: {
                    750:   int i;
                    751:   printf(_("Known DHCPv6 options:\n"));
                    752:   
                    753:   for (i = 0; opttab6[i].name; i++)
                    754:     if (!(opttab6[i].size & OT_INTERNAL))
                    755:       printf("%3d %s\n", opttab6[i].val, opttab6[i].name);
                    756: }
                    757: #endif
                    758: 
1.1.1.2   misho     759: int lookup_dhcp_opt(int prot, char *name)
1.1       misho     760: {
                    761:   const struct opttab_t *t;
                    762:   int i;
                    763: 
1.1.1.2   misho     764:   (void)prot;
                    765: 
1.1       misho     766: #ifdef HAVE_DHCP6
                    767:   if (prot == AF_INET6)
                    768:     t = opttab6;
                    769:   else
                    770: #endif
                    771:     t = opttab;
                    772: 
                    773:   for (i = 0; t[i].name; i++)
                    774:     if (strcasecmp(t[i].name, name) == 0)
                    775:       return t[i].val;
                    776:   
1.1.1.2   misho     777:   return -1;
1.1       misho     778: }
                    779: 
1.1.1.2   misho     780: int lookup_dhcp_len(int prot, int val)
1.1       misho     781: {
                    782:   const struct opttab_t *t;
                    783:   int i;
                    784: 
1.1.1.2   misho     785:   (void)prot;
                    786: 
1.1       misho     787: #ifdef HAVE_DHCP6
                    788:   if (prot == AF_INET6)
                    789:     t = opttab6;
                    790:   else
                    791: #endif
                    792:     t = opttab;
                    793: 
                    794:   for (i = 0; t[i].name; i++)
                    795:     if (val == t[i].val)
                    796:       return t[i].size & ~OT_DEC;
                    797: 
                    798:    return 0;
                    799: }
                    800: 
                    801: char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
                    802: {
                    803:   int o, i, j, nodecode = 0;
                    804:   const struct opttab_t *ot = opttab;
                    805: 
                    806: #ifdef HAVE_DHCP6
                    807:   if (prot == AF_INET6)
                    808:     ot = opttab6;
                    809: #endif
                    810: 
                    811:   for (o = 0; ot[o].name; o++)
                    812:     if (ot[o].val == opt)
                    813:       {
                    814:        if (buf)
                    815:          {
                    816:            memset(buf, 0, buf_len);
                    817:            
                    818:            if (ot[o].size & OT_ADDR_LIST) 
                    819:              {
1.1.1.4   misho     820:                union all_addr addr;
1.1       misho     821:                int addr_len = INADDRSZ;
                    822: 
                    823: #ifdef HAVE_DHCP6
                    824:                if (prot == AF_INET6)
                    825:                  addr_len = IN6ADDRSZ;
                    826: #endif
                    827:                for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len) 
                    828:                  {
                    829:                    if (i != 0)
                    830:                      strncat(buf, ", ", buf_len - strlen(buf));
                    831:                    /* align */
                    832:                    memcpy(&addr, &val[i], addr_len); 
                    833:                    inet_ntop(prot, &val[i], daemon->addrbuff, ADDRSTRLEN);
                    834:                    strncat(buf, daemon->addrbuff, buf_len - strlen(buf));
                    835:                  }
                    836:              }
                    837:            else if (ot[o].size & OT_NAME)
                    838:                for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
                    839:                  {
                    840:                    char c = val[i];
1.1.1.5 ! misho     841:                    if (isprint((unsigned char)c))
1.1       misho     842:                      buf[j++] = c;
                    843:                  }
                    844: #ifdef HAVE_DHCP6
                    845:            /* We don't handle compressed rfc1035 names, so no good in IPv4 land */
                    846:            else if ((ot[o].size & OT_RFC1035_NAME) && prot == AF_INET6)
                    847:              {
                    848:                i = 0, j = 0;
                    849:                while (i < opt_len && val[i] != 0)
                    850:                  {
                    851:                    int k, l = i + val[i] + 1;
                    852:                    for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
                    853:                     {
                    854:                       char c = val[k];
1.1.1.5 ! misho     855:                       if (isprint((unsigned char)c))
1.1       misho     856:                         buf[j++] = c;
                    857:                     }
                    858:                    i = l;
                    859:                    if (val[i] != 0 && j < buf_len)
                    860:                      buf[j++] = '.';
                    861:                  }
                    862:              }
                    863:            else if ((ot[o].size & OT_CSTRING))
                    864:              {
                    865:                int k, len;
                    866:                unsigned char *p;
                    867: 
                    868:                i = 0, j = 0;
                    869:                while (1)
                    870:                  {
                    871:                    p = &val[i];
                    872:                    GETSHORT(len, p);
                    873:                    for (k = 0; k < len && j < buf_len; k++)
                    874:                      {
                    875:                       char c = *p++;
1.1.1.5 ! misho     876:                       if (isprint((unsigned char)c))
1.1       misho     877:                         buf[j++] = c;
                    878:                     }
                    879:                    i += len +2;
                    880:                    if (i >= opt_len)
                    881:                      break;
                    882: 
                    883:                    if (j < buf_len)
                    884:                      buf[j++] = ',';
                    885:                  }
                    886:              }       
                    887: #endif
                    888:            else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
                    889:              {
                    890:                unsigned int dec = 0;
                    891:                
                    892:                for (i = 0; i < opt_len; i++)
                    893:                  dec = (dec << 8) | val[i]; 
                    894: 
                    895:                if (ot[o].size & OT_TIME)
                    896:                  prettyprint_time(buf, dec);
                    897:                else
                    898:                  sprintf(buf, "%u", dec);
                    899:              }
                    900:            else
                    901:              nodecode = 1;
                    902:          }
                    903:        break;
                    904:       }
                    905: 
                    906:   if (opt_len != 0 && buf && (!ot[o].name || nodecode))
                    907:     {
                    908:       int trunc  = 0;
                    909:       if (opt_len > 14)
                    910:        {
                    911:          trunc = 1;
                    912:          opt_len = 14;
                    913:        }
                    914:       print_mac(buf, val, opt_len);
                    915:       if (trunc)
                    916:        strncat(buf, "...", buf_len - strlen(buf));
                    917:     
                    918: 
                    919:     }
                    920: 
                    921:   return ot[o].name ? ot[o].name : "";
                    922: 
                    923: }
                    924: 
                    925: void log_context(int family, struct dhcp_context *context)
                    926: {
                    927:   /* Cannot use dhcp_buff* for RA contexts */
                    928: 
                    929:   void *start = &context->start;
                    930:   void *end = &context->end;
                    931:   char *template = "", *p = daemon->namebuff;
                    932:   
                    933:   *p = 0;
                    934:     
                    935: #ifdef HAVE_DHCP6
                    936:   if (family == AF_INET6)
                    937:     {
                    938:       struct in6_addr subnet = context->start6;
                    939:       if (!(context->flags & CONTEXT_TEMPLATE))
                    940:        setaddr6part(&subnet, 0);
                    941:       inet_ntop(AF_INET6, &subnet, daemon->addrbuff, ADDRSTRLEN); 
                    942:       start = &context->start6;
                    943:       end = &context->end6;
                    944:     }
                    945: #endif
                    946: 
                    947:   if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
                    948:     strcpy(daemon->namebuff, _(", prefix deprecated"));
                    949:   else
                    950:     {
                    951:       p += sprintf(p, _(", lease time "));
                    952:       prettyprint_time(p, context->lease_time);
                    953:       p += strlen(p);
                    954:     }  
                    955: 
                    956: #ifdef HAVE_DHCP6
                    957:   if (context->flags & CONTEXT_CONSTRUCTED)
                    958:     {
                    959:       char ifrn_name[IFNAMSIZ];
                    960:       
                    961:       template = p;
                    962:       p += sprintf(p, ", ");
                    963:       
1.1.1.2   misho     964:       if (indextoname(daemon->icmp6fd, context->if_index, ifrn_name))
                    965:        sprintf(p, "%s for %s", (context->flags & CONTEXT_OLD) ? "old prefix" : "constructed", ifrn_name);
1.1       misho     966:     }
1.1.1.2   misho     967:   else if (context->flags & CONTEXT_TEMPLATE && !(context->flags & CONTEXT_RA_STATELESS))
1.1       misho     968:     {
                    969:       template = p;
                    970:       p += sprintf(p, ", ");
1.1.1.2   misho     971:       
1.1       misho     972:       sprintf(p, "template for %s", context->template_interface);  
                    973:     }
                    974: #endif
                    975:      
1.1.1.2   misho     976:   if (!(context->flags & CONTEXT_OLD) &&
                    977:       ((context->flags & CONTEXT_DHCP) || family == AF_INET)) 
1.1       misho     978:     {
1.1.1.2   misho     979: #ifdef HAVE_DHCP6
                    980:       if (context->flags & CONTEXT_RA_STATELESS)
                    981:        {
                    982:          if (context->flags & CONTEXT_TEMPLATE)
1.1.1.4   misho     983:            strncpy(daemon->dhcp_buff, context->template_interface, DHCP_BUFF_SZ);
1.1.1.2   misho     984:          else
                    985:            strcpy(daemon->dhcp_buff, daemon->addrbuff);
                    986:        }
                    987:       else 
                    988: #endif
1.1.1.4   misho     989:        inet_ntop(family, start, daemon->dhcp_buff, DHCP_BUFF_SZ);
                    990:       inet_ntop(family, end, daemon->dhcp_buff3, DHCP_BUFF_SZ);
1.1       misho     991:       my_syslog(MS_DHCP | LOG_INFO, 
1.1.1.2   misho     992:                (context->flags & CONTEXT_RA_STATELESS) ? 
                    993:                _("%s stateless on %s%.0s%.0s%s") :
                    994:                (context->flags & CONTEXT_STATIC) ? 
                    995:                _("%s, static leases only on %.0s%s%s%.0s") :
                    996:                (context->flags & CONTEXT_PROXY) ?
                    997:                _("%s, proxy on subnet %.0s%s%.0s%.0s") :
                    998:                _("%s, IP range %s -- %s%s%.0s"),
                    999:                (family != AF_INET) ? "DHCPv6" : "DHCP",
1.1       misho    1000:                daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
                   1001:     }
                   1002:   
                   1003: #ifdef HAVE_DHCP6
1.1.1.2   misho    1004:   if (context->flags & CONTEXT_TEMPLATE)
                   1005:     {
                   1006:       strcpy(daemon->addrbuff, context->template_interface);
                   1007:       template = "";
                   1008:     }
                   1009: 
                   1010:   if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
1.1       misho    1011:     my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
1.1.1.2   misho    1012:   
1.1       misho    1013:   if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6)) 
                   1014:     my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
                   1015: #endif
                   1016: 
                   1017: }
                   1018: 
1.1.1.2   misho    1019: void log_relay(int family, struct dhcp_relay *relay)
                   1020: {
1.1.1.5 ! misho    1021:   int broadcast = relay->server.addr4.s_addr == 0;
1.1.1.2   misho    1022:   inet_ntop(family, &relay->local, daemon->addrbuff, ADDRSTRLEN);
1.1.1.5 ! misho    1023:   inet_ntop(family, &relay->server, daemon->namebuff, ADDRSTRLEN);
        !          1024: 
        !          1025:   if (family == AF_INET && relay->port != DHCP_SERVER_PORT)
        !          1026:     sprintf(daemon->namebuff + strlen(daemon->namebuff), "#%u", relay->port);
        !          1027: 
        !          1028: #ifdef HAVE_DHCP6
        !          1029:   struct in6_addr multicast;
1.1.1.2   misho    1030: 
1.1.1.5 ! misho    1031:   inet_pton(AF_INET6, ALL_SERVERS, &multicast);
        !          1032: 
        !          1033:   if (family == AF_INET6)
        !          1034:     {
        !          1035:       broadcast = IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast);
        !          1036:       if (relay->port != DHCPV6_SERVER_PORT)
        !          1037:        sprintf(daemon->namebuff + strlen(daemon->namebuff), "#%u", relay->port);
        !          1038:     }
        !          1039: #endif
        !          1040:   
        !          1041:   
1.1.1.2   misho    1042:   if (relay->interface)
1.1.1.5 ! misho    1043:     {
        !          1044:       if (broadcast)
        !          1045:        my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s via %s"), daemon->addrbuff, relay->interface);
        !          1046:       else
        !          1047:        my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
        !          1048:     }
1.1.1.2   misho    1049:   else
                   1050:     my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s"), daemon->addrbuff, daemon->namebuff);
                   1051: }
                   1052:    
1.1       misho    1053: #endif

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