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

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

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