File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / dhcp-common.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:31:38 2014 UTC (10 years, 1 month ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_71, HEAD
dnsmasq 2.71

    1: /* dnsmasq is Copyright (c) 2000-2014 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: 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: 
  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 */
  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);
  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 
  448: char *whichdevice(void)
  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.
  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: */
  460:   
  461:   struct irec *iface, *found;
  462:   struct iname *if_tmp;
  463:   
  464:   if (!daemon->if_names)
  465:     return NULL;
  466:   
  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: 
  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) 
  477: 	  return NULL; /* more than one. */
  478:       }
  479: 
  480:   if (found)
  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);
  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: 
  634: int lookup_dhcp_opt(int prot, char *name)
  635: {
  636:   const struct opttab_t *t;
  637:   int i;
  638: 
  639:   (void)prot;
  640: 
  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:   
  652:   return -1;
  653: }
  654: 
  655: int lookup_dhcp_len(int prot, int val)
  656: {
  657:   const struct opttab_t *t;
  658:   int i;
  659: 
  660:   (void)prot;
  661: 
  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:       
  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);
  841:     }
  842:   else if (context->flags & CONTEXT_TEMPLATE && !(context->flags & CONTEXT_RA_STATELESS))
  843:     {
  844:       template = p;
  845:       p += sprintf(p, ", ");
  846:       
  847:       sprintf(p, "template for %s", context->template_interface);  
  848:     }
  849: #endif
  850:      
  851:   if (!(context->flags & CONTEXT_OLD) &&
  852:       ((context->flags & CONTEXT_DHCP) || family == AF_INET)) 
  853:     {
  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);
  865:       inet_ntop(family, end, daemon->dhcp_buff3, 256);
  866:       my_syslog(MS_DHCP | LOG_INFO, 
  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",
  875: 		daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
  876:     }
  877:   
  878: #ifdef HAVE_DHCP6
  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))
  886:     my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
  887:   
  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: 
  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:    
  905: #endif

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