File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / dhcp-common.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 29 19:37:40 2013 UTC (11 years ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_66p0, v2_66, HEAD
dnsmasq

    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>