File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / dhcp-common.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:56:46 2021 UTC (3 years, 6 months ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_84, HEAD
dnsmasq 2.84

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

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