File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / dhcp-common.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:02:07 2023 UTC (9 months, 1 week ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v8_2p1, HEAD
Version 8.2p1

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

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