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

1.1     ! misho       1: /* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
        !             2: 
        !             3:    This program is free software; you can redistribute it and/or modify
        !             4:    it under the terms of the GNU General Public License as published by
        !             5:    the Free Software Foundation; version 2 dated June, 1991, or
        !             6:    (at your option) version 3 dated 29 June, 2007.
        !             7:  
        !             8:    This program is distributed in the hope that it will be useful,
        !             9:    but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            10:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            11:    GNU General Public License for more details.
        !            12:      
        !            13:    You should have received a copy of the GNU General Public License
        !            14:    along with this program.  If not, see <http://www.gnu.org/licenses/>.
        !            15: */
        !            16: 
        !            17: #include "dnsmasq.h"
        !            18: 
        !            19: #ifdef HAVE_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: 
        !           256: void dhcp_update_configs(struct dhcp_config *configs)
        !           257: {
        !           258:   /* Some people like to keep all static IP addresses in /etc/hosts.
        !           259:      This goes through /etc/hosts and sets static addresses for any DHCP config
        !           260:      records which don't have an address and whose name matches. 
        !           261:      We take care to maintain the invariant that any IP address can appear
        !           262:      in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP, 
        !           263:      restore the status-quo ante first. */
        !           264:   
        !           265:   struct dhcp_config *config, *conf_tmp;
        !           266:   struct crec *crec;
        !           267:   int prot = AF_INET;
        !           268: 
        !           269:   for (config = configs; config; config = config->next)
        !           270:     if (config->flags & CONFIG_ADDR_HOSTS)
        !           271:       config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR6 | CONFIG_ADDR_HOSTS);
        !           272: 
        !           273: #ifdef HAVE_DHCP6 
        !           274:  again:  
        !           275: #endif
        !           276: 
        !           277:   if (daemon->port != 0)
        !           278:     for (config = configs; config; config = config->next)
        !           279:       {
        !           280:        int conflags = CONFIG_ADDR;
        !           281:        int cacheflags = F_IPV4;
        !           282: 
        !           283: #ifdef HAVE_DHCP6
        !           284:        if (prot == AF_INET6)
        !           285:          {
        !           286:            conflags = CONFIG_ADDR6;
        !           287:            cacheflags = F_IPV6;
        !           288:          }
        !           289: #endif
        !           290:        if (!(config->flags & conflags) &&
        !           291:            (config->flags & CONFIG_NAME) && 
        !           292:            (crec = cache_find_by_name(NULL, config->hostname, 0, cacheflags)) &&
        !           293:            (crec->flags & F_HOSTS))
        !           294:          {
        !           295:            if (cache_find_by_name(crec, config->hostname, 0, cacheflags))
        !           296:              {
        !           297:                /* use primary (first) address */
        !           298:              while (crec && !(crec->flags & F_REVERSE))
        !           299:                crec = cache_find_by_name(crec, config->hostname, 0, cacheflags);
        !           300:              if (!crec)
        !           301:                continue; /* should be never */
        !           302:              inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
        !           303:              my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"), 
        !           304:                        config->hostname, daemon->addrbuff);
        !           305:              }
        !           306:            
        !           307:            if (prot == AF_INET && 
        !           308:                (!(conf_tmp = config_find_by_address(configs, crec->addr.addr.addr.addr4)) || conf_tmp == config))
        !           309:              {
        !           310:                config->addr = crec->addr.addr.addr.addr4;
        !           311:                config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
        !           312:                continue;
        !           313:              }
        !           314: 
        !           315: #ifdef HAVE_DHCP6
        !           316:            if (prot == AF_INET6 && 
        !           317:                (!(conf_tmp = config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0)) || conf_tmp == config))
        !           318:              {
        !           319:                memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
        !           320:                config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS;
        !           321:                continue;
        !           322:              }
        !           323: #endif
        !           324: 
        !           325:            inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
        !           326:            my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"), 
        !           327:                      daemon->addrbuff, config->hostname);
        !           328:            
        !           329:            
        !           330:          }
        !           331:       }
        !           332: 
        !           333: #ifdef HAVE_DHCP6
        !           334:   if (prot == AF_INET)
        !           335:     {
        !           336:       prot = AF_INET6;
        !           337:       goto again;
        !           338:     }
        !           339: #endif
        !           340: 
        !           341: }
        !           342: 
        !           343: #ifdef HAVE_LINUX_NETWORK 
        !           344: void bindtodevice(int fd)
        !           345: {
        !           346:   /* If we are doing DHCP on exactly one interface, and running linux, do SO_BINDTODEVICE
        !           347:      to that device. This is for the use case of  (eg) OpenStack, which runs a new
        !           348:      dnsmasq instance for each VLAN interface it creates. Without the BINDTODEVICE, 
        !           349:      individual processes don't always see the packets they should.
        !           350:      SO_BINDTODEVICE is only available Linux. */
        !           351:   
        !           352:   struct irec *iface, *found;
        !           353:   
        !           354:   for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
        !           355:     if (iface->dhcp_ok)
        !           356:       {
        !           357:        if (!found)
        !           358:          found = iface;
        !           359:        else if (strcmp(found->name, iface->name) != 0) 
        !           360:          {
        !           361:            /* more than one. */
        !           362:            found = NULL;
        !           363:            break;
        !           364:          }
        !           365:       }
        !           366:   
        !           367:   if (found)
        !           368:     {
        !           369:       struct ifreq ifr;
        !           370:       strcpy(ifr.ifr_name, found->name);
        !           371:       /* only allowed by root. */
        !           372:       if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 &&
        !           373:          errno != EPERM)
        !           374:        die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
        !           375:     }
        !           376: }
        !           377: #endif
        !           378: 
        !           379: static const struct opttab_t {
        !           380:   char *name;
        !           381:   u16 val, size;
        !           382: } opttab[] = {
        !           383:   { "netmask", 1, OT_ADDR_LIST },
        !           384:   { "time-offset", 2, 4 },
        !           385:   { "router", 3, OT_ADDR_LIST  },
        !           386:   { "dns-server", 6, OT_ADDR_LIST },
        !           387:   { "log-server", 7, OT_ADDR_LIST },
        !           388:   { "lpr-server", 9, OT_ADDR_LIST },
        !           389:   { "hostname", 12, OT_INTERNAL | OT_NAME },
        !           390:   { "boot-file-size", 13, 2 | OT_DEC },
        !           391:   { "domain-name", 15, OT_NAME },
        !           392:   { "swap-server", 16, OT_ADDR_LIST },
        !           393:   { "root-path", 17, OT_NAME },
        !           394:   { "extension-path", 18, OT_NAME },
        !           395:   { "ip-forward-enable", 19, 1 },
        !           396:   { "non-local-source-routing", 20, 1 },
        !           397:   { "policy-filter", 21, OT_ADDR_LIST },
        !           398:   { "max-datagram-reassembly", 22, 2 | OT_DEC },
        !           399:   { "default-ttl", 23, 1 | OT_DEC },
        !           400:   { "mtu", 26, 2 | OT_DEC },
        !           401:   { "all-subnets-local", 27, 1 },
        !           402:   { "broadcast", 28, OT_INTERNAL | OT_ADDR_LIST },
        !           403:   { "router-discovery", 31, 1 },
        !           404:   { "router-solicitation", 32, OT_ADDR_LIST },
        !           405:   { "static-route", 33, OT_ADDR_LIST },
        !           406:   { "trailer-encapsulation", 34, 1 },
        !           407:   { "arp-timeout", 35, 4 | OT_DEC },
        !           408:   { "ethernet-encap", 36, 1 },
        !           409:   { "tcp-ttl", 37, 1 },
        !           410:   { "tcp-keepalive", 38, 4 | OT_DEC },
        !           411:   { "nis-domain", 40, OT_NAME },
        !           412:   { "nis-server", 41, OT_ADDR_LIST },
        !           413:   { "ntp-server", 42, OT_ADDR_LIST },
        !           414:   { "vendor-encap", 43, OT_INTERNAL },
        !           415:   { "netbios-ns", 44, OT_ADDR_LIST },
        !           416:   { "netbios-dd", 45, OT_ADDR_LIST },
        !           417:   { "netbios-nodetype", 46, 1 },
        !           418:   { "netbios-scope", 47, 0 },
        !           419:   { "x-windows-fs", 48, OT_ADDR_LIST },
        !           420:   { "x-windows-dm", 49, OT_ADDR_LIST },
        !           421:   { "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
        !           422:   { "lease-time", 51, OT_INTERNAL | OT_TIME },
        !           423:   { "option-overload", 52, OT_INTERNAL },
        !           424:   { "message-type", 53, OT_INTERNAL | OT_DEC },
        !           425:   { "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
        !           426:   { "parameter-request", 55, OT_INTERNAL },
        !           427:   { "message", 56, OT_INTERNAL },
        !           428:   { "max-message-size", 57, OT_INTERNAL },
        !           429:   { "T1", 58, OT_INTERNAL | OT_TIME},
        !           430:   { "T2", 59, OT_INTERNAL | OT_TIME},
        !           431:   { "vendor-class", 60, 0 },
        !           432:   { "client-id", 61, OT_INTERNAL },
        !           433:   { "nis+-domain", 64, OT_NAME },
        !           434:   { "nis+-server", 65, OT_ADDR_LIST },
        !           435:   { "tftp-server", 66, OT_NAME },
        !           436:   { "bootfile-name", 67, OT_NAME },
        !           437:   { "mobile-ip-home", 68, OT_ADDR_LIST }, 
        !           438:   { "smtp-server", 69, OT_ADDR_LIST }, 
        !           439:   { "pop3-server", 70, OT_ADDR_LIST }, 
        !           440:   { "nntp-server", 71, OT_ADDR_LIST }, 
        !           441:   { "irc-server", 74, OT_ADDR_LIST }, 
        !           442:   { "user-class", 77, 0 },
        !           443:   { "FQDN", 81, OT_INTERNAL },
        !           444:   { "agent-id", 82, OT_INTERNAL },
        !           445:   { "client-arch", 93, 2 | OT_DEC },
        !           446:   { "client-interface-id", 94, 0 },
        !           447:   { "client-machine-id", 97, 0 },
        !           448:   { "subnet-select", 118, OT_INTERNAL },
        !           449:   { "domain-search", 119, OT_RFC1035_NAME },
        !           450:   { "sip-server", 120, 0 },
        !           451:   { "classless-static-route", 121, 0 },
        !           452:   { "vendor-id-encap", 125, 0 },
        !           453:   { "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
        !           454:   { NULL, 0, 0 }
        !           455: };
        !           456: 
        !           457: #ifdef HAVE_DHCP6
        !           458: static const struct opttab_t opttab6[] = {
        !           459:   { "client-id", 1, OT_INTERNAL },
        !           460:   { "server-id", 2, OT_INTERNAL },
        !           461:   { "ia-na", 3, OT_INTERNAL },
        !           462:   { "ia-ta", 4, OT_INTERNAL },
        !           463:   { "iaaddr", 5, OT_INTERNAL },
        !           464:   { "oro", 6, OT_INTERNAL },
        !           465:   { "preference", 7, OT_INTERNAL | OT_DEC },
        !           466:   { "unicast", 12, OT_INTERNAL },
        !           467:   { "status", 13, OT_INTERNAL },
        !           468:   { "rapid-commit", 14, OT_INTERNAL },
        !           469:   { "user-class", 15, OT_INTERNAL | OT_CSTRING },
        !           470:   { "vendor-class", 16, OT_INTERNAL | OT_CSTRING },
        !           471:   { "vendor-opts", 17, OT_INTERNAL },
        !           472:   { "sip-server-domain", 21,  OT_RFC1035_NAME },
        !           473:   { "sip-server", 22, OT_ADDR_LIST },
        !           474:   { "dns-server", 23, OT_ADDR_LIST },
        !           475:   { "domain-search", 24, OT_RFC1035_NAME },
        !           476:   { "nis-server", 27, OT_ADDR_LIST },
        !           477:   { "nis+-server", 28, OT_ADDR_LIST },
        !           478:   { "nis-domain", 29,  OT_RFC1035_NAME },
        !           479:   { "nis+-domain", 30, OT_RFC1035_NAME },
        !           480:   { "sntp-server", 31,  OT_ADDR_LIST },
        !           481:   { "information-refresh-time", 32, OT_TIME },
        !           482:   { "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
        !           483:   { "ntp-server", 56,  OT_ADDR_LIST },
        !           484:   { "bootfile-url", 59, OT_NAME },
        !           485:   { "bootfile-param", 60, OT_CSTRING },
        !           486:   { NULL, 0, 0 }
        !           487: };
        !           488: #endif
        !           489: 
        !           490: 
        !           491: 
        !           492: void display_opts(void)
        !           493: {
        !           494:   int i;
        !           495:   
        !           496:   printf(_("Known DHCP options:\n"));
        !           497:   
        !           498:   for (i = 0; opttab[i].name; i++)
        !           499:     if (!(opttab[i].size & OT_INTERNAL))
        !           500:       printf("%3d %s\n", opttab[i].val, opttab[i].name);
        !           501: }
        !           502: 
        !           503: #ifdef HAVE_DHCP6
        !           504: void display_opts6(void)
        !           505: {
        !           506:   int i;
        !           507:   printf(_("Known DHCPv6 options:\n"));
        !           508:   
        !           509:   for (i = 0; opttab6[i].name; i++)
        !           510:     if (!(opttab6[i].size & OT_INTERNAL))
        !           511:       printf("%3d %s\n", opttab6[i].val, opttab6[i].name);
        !           512: }
        !           513: #endif
        !           514: 
        !           515: u16 lookup_dhcp_opt(int prot, char *name)
        !           516: {
        !           517:   const struct opttab_t *t;
        !           518:   int i;
        !           519: 
        !           520: #ifdef HAVE_DHCP6
        !           521:   if (prot == AF_INET6)
        !           522:     t = opttab6;
        !           523:   else
        !           524: #endif
        !           525:     t = opttab;
        !           526: 
        !           527:   for (i = 0; t[i].name; i++)
        !           528:     if (strcasecmp(t[i].name, name) == 0)
        !           529:       return t[i].val;
        !           530:   
        !           531:   return 0;
        !           532: }
        !           533: 
        !           534: u16 lookup_dhcp_len(int prot, u16 val)
        !           535: {
        !           536:   const struct opttab_t *t;
        !           537:   int i;
        !           538: 
        !           539: #ifdef HAVE_DHCP6
        !           540:   if (prot == AF_INET6)
        !           541:     t = opttab6;
        !           542:   else
        !           543: #endif
        !           544:     t = opttab;
        !           545: 
        !           546:   for (i = 0; t[i].name; i++)
        !           547:     if (val == t[i].val)
        !           548:       return t[i].size & ~OT_DEC;
        !           549: 
        !           550:    return 0;
        !           551: }
        !           552: 
        !           553: char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
        !           554: {
        !           555:   int o, i, j, nodecode = 0;
        !           556:   const struct opttab_t *ot = opttab;
        !           557: 
        !           558: #ifdef HAVE_DHCP6
        !           559:   if (prot == AF_INET6)
        !           560:     ot = opttab6;
        !           561: #endif
        !           562: 
        !           563:   for (o = 0; ot[o].name; o++)
        !           564:     if (ot[o].val == opt)
        !           565:       {
        !           566:        if (buf)
        !           567:          {
        !           568:            memset(buf, 0, buf_len);
        !           569:            
        !           570:            if (ot[o].size & OT_ADDR_LIST) 
        !           571:              {
        !           572:                struct all_addr addr;
        !           573:                int addr_len = INADDRSZ;
        !           574: 
        !           575: #ifdef HAVE_DHCP6
        !           576:                if (prot == AF_INET6)
        !           577:                  addr_len = IN6ADDRSZ;
        !           578: #endif
        !           579:                for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len) 
        !           580:                  {
        !           581:                    if (i != 0)
        !           582:                      strncat(buf, ", ", buf_len - strlen(buf));
        !           583:                    /* align */
        !           584:                    memcpy(&addr, &val[i], addr_len); 
        !           585:                    inet_ntop(prot, &val[i], daemon->addrbuff, ADDRSTRLEN);
        !           586:                    strncat(buf, daemon->addrbuff, buf_len - strlen(buf));
        !           587:                  }
        !           588:              }
        !           589:            else if (ot[o].size & OT_NAME)
        !           590:                for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
        !           591:                  {
        !           592:                    char c = val[i];
        !           593:                    if (isprint((int)c))
        !           594:                      buf[j++] = c;
        !           595:                  }
        !           596: #ifdef HAVE_DHCP6
        !           597:            /* We don't handle compressed rfc1035 names, so no good in IPv4 land */
        !           598:            else if ((ot[o].size & OT_RFC1035_NAME) && prot == AF_INET6)
        !           599:              {
        !           600:                i = 0, j = 0;
        !           601:                while (i < opt_len && val[i] != 0)
        !           602:                  {
        !           603:                    int k, l = i + val[i] + 1;
        !           604:                    for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
        !           605:                     {
        !           606:                       char c = val[k];
        !           607:                       if (isprint((int)c))
        !           608:                         buf[j++] = c;
        !           609:                     }
        !           610:                    i = l;
        !           611:                    if (val[i] != 0 && j < buf_len)
        !           612:                      buf[j++] = '.';
        !           613:                  }
        !           614:              }
        !           615:            else if ((ot[o].size & OT_CSTRING))
        !           616:              {
        !           617:                int k, len;
        !           618:                unsigned char *p;
        !           619: 
        !           620:                i = 0, j = 0;
        !           621:                while (1)
        !           622:                  {
        !           623:                    p = &val[i];
        !           624:                    GETSHORT(len, p);
        !           625:                    for (k = 0; k < len && j < buf_len; k++)
        !           626:                      {
        !           627:                       char c = *p++;
        !           628:                       if (isprint((int)c))
        !           629:                         buf[j++] = c;
        !           630:                     }
        !           631:                    i += len +2;
        !           632:                    if (i >= opt_len)
        !           633:                      break;
        !           634: 
        !           635:                    if (j < buf_len)
        !           636:                      buf[j++] = ',';
        !           637:                  }
        !           638:              }       
        !           639: #endif
        !           640:            else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
        !           641:              {
        !           642:                unsigned int dec = 0;
        !           643:                
        !           644:                for (i = 0; i < opt_len; i++)
        !           645:                  dec = (dec << 8) | val[i]; 
        !           646: 
        !           647:                if (ot[o].size & OT_TIME)
        !           648:                  prettyprint_time(buf, dec);
        !           649:                else
        !           650:                  sprintf(buf, "%u", dec);
        !           651:              }
        !           652:            else
        !           653:              nodecode = 1;
        !           654:          }
        !           655:        break;
        !           656:       }
        !           657: 
        !           658:   if (opt_len != 0 && buf && (!ot[o].name || nodecode))
        !           659:     {
        !           660:       int trunc  = 0;
        !           661:       if (opt_len > 14)
        !           662:        {
        !           663:          trunc = 1;
        !           664:          opt_len = 14;
        !           665:        }
        !           666:       print_mac(buf, val, opt_len);
        !           667:       if (trunc)
        !           668:        strncat(buf, "...", buf_len - strlen(buf));
        !           669:     
        !           670: 
        !           671:     }
        !           672: 
        !           673:   return ot[o].name ? ot[o].name : "";
        !           674: 
        !           675: }
        !           676: 
        !           677: void log_context(int family, struct dhcp_context *context)
        !           678: {
        !           679:   /* Cannot use dhcp_buff* for RA contexts */
        !           680: 
        !           681:   void *start = &context->start;
        !           682:   void *end = &context->end;
        !           683:   char *template = "", *p = daemon->namebuff;
        !           684:   
        !           685:   *p = 0;
        !           686:     
        !           687: #ifdef HAVE_DHCP6
        !           688:   if (family == AF_INET6)
        !           689:     {
        !           690:       struct in6_addr subnet = context->start6;
        !           691:       if (!(context->flags & CONTEXT_TEMPLATE))
        !           692:        setaddr6part(&subnet, 0);
        !           693:       inet_ntop(AF_INET6, &subnet, daemon->addrbuff, ADDRSTRLEN); 
        !           694:       start = &context->start6;
        !           695:       end = &context->end6;
        !           696:     }
        !           697: #endif
        !           698: 
        !           699:   if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
        !           700:     strcpy(daemon->namebuff, _(", prefix deprecated"));
        !           701:   else
        !           702:     {
        !           703:       p += sprintf(p, _(", lease time "));
        !           704:       prettyprint_time(p, context->lease_time);
        !           705:       p += strlen(p);
        !           706:     }  
        !           707: 
        !           708: #ifdef HAVE_DHCP6
        !           709:   if (context->flags & CONTEXT_CONSTRUCTED)
        !           710:     {
        !           711:       char ifrn_name[IFNAMSIZ];
        !           712:       
        !           713:       template = p;
        !           714:       p += sprintf(p, ", ");
        !           715:       
        !           716:       if (indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, context->if_index, ifrn_name))
        !           717:        sprintf(p, "constructed for %s", ifrn_name);
        !           718:     }
        !           719:   else if (context->flags & CONTEXT_TEMPLATE)
        !           720:     {
        !           721:       template = p;
        !           722:       p += sprintf(p, ", ");
        !           723:        
        !           724:       sprintf(p, "template for %s", context->template_interface);  
        !           725:     }
        !           726: #endif
        !           727:      
        !           728:   if ((context->flags & CONTEXT_DHCP) || family == AF_INET) 
        !           729:     {
        !           730:       inet_ntop(family, start, daemon->dhcp_buff, 256);
        !           731:       inet_ntop(family, end, daemon->dhcp_buff3, 256);
        !           732:       my_syslog(MS_DHCP | LOG_INFO, 
        !           733:              (context->flags & CONTEXT_RA_STATELESS) ? 
        !           734:              _("%s stateless on %s%.0s%.0s%s") :
        !           735:              (context->flags & CONTEXT_STATIC) ? 
        !           736:              _("%s, static leases only on %.0s%s%s%.0s") :
        !           737:              (context->flags & CONTEXT_PROXY) ?
        !           738:              _("%s, proxy on subnet %.0s%s%.0s%.0s") :
        !           739:              _("%s, IP range %s -- %s%s%.0s"),
        !           740:              (family != AF_INET) ? "DHCPv6" : "DHCP",
        !           741:                daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
        !           742:     }
        !           743:   
        !           744: #ifdef HAVE_DHCP6
        !           745:   if (context->flags & CONTEXT_RA_NAME)
        !           746:     my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
        !           747:        
        !           748:   if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6)) 
        !           749:     my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
        !           750: #endif
        !           751: 
        !           752: }
        !           753:       
        !           754: 
        !           755: #endif

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