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

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

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