File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / lease.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: static struct dhcp_lease *leases = NULL, *old_leases = NULL;
   22: static int dns_dirty, file_dirty, leases_left;
   23: 
   24: static int read_leases(time_t now, FILE *leasestream)
   25: {
   26:   unsigned long ei;
   27:   union all_addr addr;
   28:   struct dhcp_lease *lease;
   29:   int clid_len, hw_len, hw_type;
   30:   int items;
   31:   char *domain = NULL;
   32: 
   33:   *daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0';
   34: 
   35:   /* client-id max length is 255 which is 255*2 digits + 254 colons
   36:      borrow DNS packet buffer which is always larger than 1000 bytes
   37: 
   38:      Check various buffers are big enough for the code below */
   39: 
   40: #if (DHCP_BUFF_SZ < 255) || (MAXDNAME < 64) || (PACKETSZ+MAXDNAME+RRFIXEDSZ  < 764)
   41: # error Buffer size breakage in leasefile parsing.
   42: #endif
   43: 
   44:     while ((items=fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2)) == 2)
   45:       {
   46: 	*daemon->namebuff = *daemon->dhcp_buff = *daemon->packet = '\0';
   47: 	hw_len = hw_type = clid_len = 0;
   48: 	
   49: #ifdef HAVE_DHCP6
   50: 	if (strcmp(daemon->dhcp_buff3, "duid") == 0)
   51: 	  {
   52: 	    daemon->duid_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, 130, NULL, NULL);
   53: 	    if (daemon->duid_len < 0)
   54: 	      return 0;
   55: 	    daemon->duid = safe_malloc(daemon->duid_len);
   56: 	    memcpy(daemon->duid, daemon->dhcp_buff2, daemon->duid_len);
   57: 	    continue;
   58: 	  }
   59: #endif
   60: 	
   61: 	if (fscanf(leasestream, " %64s %255s %764s",
   62: 		   daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3)
   63: 	  {
   64: 	    my_syslog(MS_DHCP | LOG_WARNING, _("ignoring invalid line in lease database: %s %s %s %s ..."),
   65: 		      daemon->dhcp_buff3, daemon->dhcp_buff2,
   66: 		      daemon->namebuff, daemon->dhcp_buff);
   67: 	    continue;
   68: 	  }
   69: 		
   70: 	if (inet_pton(AF_INET, daemon->namebuff, &addr.addr4))
   71: 	  {
   72: 	    if ((lease = lease4_allocate(addr.addr4)))
   73: 	      domain = get_domain(lease->addr);
   74: 	    
   75: 	    hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
   76: 	    /* For backwards compatibility, no explicit MAC address type means ether. */
   77: 	    if (hw_type == 0 && hw_len != 0)
   78: 	      hw_type = ARPHRD_ETHER; 
   79: 	  }
   80: #ifdef HAVE_DHCP6
   81: 	else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr6))
   82: 	  {
   83: 	    char *s = daemon->dhcp_buff2;
   84: 	    int lease_type = LEASE_NA;
   85: 
   86: 	    if (s[0] == 'T')
   87: 	      {
   88: 		lease_type = LEASE_TA;
   89: 		s++;
   90: 	      }
   91: 	    
   92: 	    if ((lease = lease6_allocate(&addr.addr6, lease_type)))
   93: 	      {
   94: 		lease_set_iaid(lease, strtoul(s, NULL, 10));
   95: 		domain = get_domain6(&lease->addr6);
   96: 	      }
   97: 	  }
   98: #endif
   99: 	else
  100: 	  {
  101: 	    my_syslog(MS_DHCP | LOG_WARNING, _("ignoring invalid line in lease database, bad address: %s"),
  102: 		      daemon->namebuff);
  103: 	    continue;
  104: 	  }
  105: 	
  106: 
  107: 	if (!lease)
  108: 	  die (_("too many stored leases"), NULL, EC_MISC);
  109: 
  110: 	if (strcmp(daemon->packet, "*") != 0)
  111: 	  clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
  112: 	
  113: 	lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, 
  114: 			 hw_len, hw_type, clid_len, now, 0);
  115: 	
  116: 	if (strcmp(daemon->dhcp_buff, "*") !=  0)
  117: 	  lease_set_hostname(lease, daemon->dhcp_buff, 0, domain, NULL);
  118: 
  119: 	ei = atol(daemon->dhcp_buff3);
  120: 
  121: #ifdef HAVE_BROKEN_RTC
  122: 	if (ei != 0)
  123: 	  lease->expires = (time_t)ei + now;
  124: 	else
  125: 	  lease->expires = (time_t)0;
  126: 	lease->length = ei;
  127: #else
  128: 	/* strictly time_t is opaque, but this hack should work on all sane systems,
  129: 	   even when sizeof(time_t) == 8 */
  130: 	lease->expires = (time_t)ei;
  131: #endif
  132: 	
  133: 	/* set these correctly: the "old" events are generated later from
  134: 	   the startup synthesised SIGHUP. */
  135: 	lease->flags &= ~(LEASE_NEW | LEASE_CHANGED);
  136: 	
  137: 	*daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0';
  138:       }
  139:     
  140:     return (items == 0 || items == EOF);
  141: }
  142: 
  143: void lease_init(time_t now)
  144: {
  145:   FILE *leasestream;
  146: 
  147:   leases_left = daemon->dhcp_max;
  148: 
  149:   if (option_bool(OPT_LEASE_RO))
  150:     {
  151:       /* run "<lease_change_script> init" once to get the
  152: 	 initial state of the database. If leasefile-ro is
  153: 	 set without a script, we just do without any
  154: 	 lease database. */
  155: #ifdef HAVE_SCRIPT
  156:       if (daemon->lease_change_command)
  157: 	{
  158: 	  strcpy(daemon->dhcp_buff, daemon->lease_change_command);
  159: 	  strcat(daemon->dhcp_buff, " init");
  160: 	  leasestream = popen(daemon->dhcp_buff, "r");
  161: 	}
  162:       else
  163: #endif
  164: 	{
  165:           file_dirty = dns_dirty = 0;
  166:           return;
  167:         }
  168: 
  169:     }
  170:   else
  171:     {
  172:       /* NOTE: need a+ mode to create file if it doesn't exist */
  173:       leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+");
  174: 
  175:       if (!leasestream)
  176: 	die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE);
  177: 
  178:       /* a+ mode leaves pointer at end. */
  179:       rewind(leasestream);
  180:     }
  181: 
  182:   if (leasestream)
  183:     {
  184:       if (!read_leases(now, leasestream))
  185: 	my_syslog(MS_DHCP | LOG_ERR, _("failed to parse lease database cleanly"));
  186:       
  187:       if (ferror(leasestream))
  188: 	die(_("failed to read lease file %s: %s"), daemon->lease_file, EC_FILE);
  189:     }
  190:   
  191: #ifdef HAVE_SCRIPT
  192:   if (!daemon->lease_stream)
  193:     {
  194:       int rc = 0;
  195: 
  196:       /* shell returns 127 for "command not found", 126 for bad permissions. */
  197:       if (!leasestream || (rc = pclose(leasestream)) == -1 || WEXITSTATUS(rc) == 127 || WEXITSTATUS(rc) == 126)
  198: 	{
  199: 	  if (WEXITSTATUS(rc) == 127)
  200: 	    errno = ENOENT;
  201: 	  else if (WEXITSTATUS(rc) == 126)
  202: 	    errno = EACCES;
  203: 
  204: 	  die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command, EC_FILE);
  205: 	}
  206:       
  207:       if (WEXITSTATUS(rc) != 0)
  208: 	{
  209: 	  sprintf(daemon->dhcp_buff, "%d", WEXITSTATUS(rc));
  210: 	  die(_("lease-init script returned exit code %s"), daemon->dhcp_buff, WEXITSTATUS(rc) + EC_INIT_OFFSET);
  211: 	}
  212:     }
  213: #endif
  214: 
  215:   /* Some leases may have expired */
  216:   file_dirty = 0;
  217:   lease_prune(NULL, now);
  218:   dns_dirty = 1;
  219: }
  220: 
  221: void lease_update_from_configs(void)
  222: {
  223:   /* changes to the config may change current leases. */
  224:   
  225:   struct dhcp_lease *lease;
  226:   struct dhcp_config *config;
  227:   char *name;
  228:   
  229:   for (lease = leases; lease; lease = lease->next)
  230:     if (lease->flags & (LEASE_TA | LEASE_NA))
  231:       continue;
  232:     else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len, 
  233: 				   lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL, NULL)) && 
  234: 	     (config->flags & CONFIG_NAME) &&
  235: 	     (!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
  236:       lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
  237:     else if ((name = host_from_dns(lease->addr)))
  238:       lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */
  239: }
  240: 
  241: static void ourprintf(int *errp, char *format, ...)
  242: {
  243:   va_list ap;
  244:   
  245:   va_start(ap, format);
  246:   if (!(*errp) && vfprintf(daemon->lease_stream, format, ap) < 0)
  247:     *errp = errno;
  248:   va_end(ap);
  249: }
  250: 
  251: void lease_update_file(time_t now)
  252: {
  253:   struct dhcp_lease *lease;
  254:   time_t next_event;
  255:   int i, err = 0;
  256: 
  257:   if (file_dirty != 0 && daemon->lease_stream)
  258:     {
  259:       errno = 0;
  260:       rewind(daemon->lease_stream);
  261:       if (errno != 0 || ftruncate(fileno(daemon->lease_stream), 0) != 0)
  262: 	err = errno;
  263:       
  264:       for (lease = leases; lease; lease = lease->next)
  265: 	{
  266: 
  267: #ifdef HAVE_DHCP6
  268: 	  if (lease->flags & (LEASE_TA | LEASE_NA))
  269: 	    continue;
  270: #endif
  271: 
  272: #ifdef HAVE_BROKEN_RTC
  273: 	  ourprintf(&err, "%u ", lease->length);
  274: #else
  275: 	  ourprintf(&err, "%lu ", (unsigned long)lease->expires);
  276: #endif
  277: 
  278: 	  if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0) 
  279: 	    ourprintf(&err, "%.2x-", lease->hwaddr_type);
  280: 	  for (i = 0; i < lease->hwaddr_len; i++)
  281: 	    {
  282: 	      ourprintf(&err, "%.2x", lease->hwaddr[i]);
  283: 	      if (i != lease->hwaddr_len - 1)
  284: 		ourprintf(&err, ":");
  285: 	    }
  286: 	  
  287: 	  inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN); 
  288: 
  289: 	  ourprintf(&err, " %s ", daemon->addrbuff);
  290: 	  ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
  291: 	  	  
  292: 	  if (lease->clid && lease->clid_len != 0)
  293: 	    {
  294: 	      for (i = 0; i < lease->clid_len - 1; i++)
  295: 		ourprintf(&err, "%.2x:", lease->clid[i]);
  296: 	      ourprintf(&err, "%.2x\n", lease->clid[i]);
  297: 	    }
  298: 	  else
  299: 	    ourprintf(&err, "*\n");	  
  300: 	}
  301:       
  302: #ifdef HAVE_DHCP6  
  303:       if (daemon->duid)
  304: 	{
  305: 	  ourprintf(&err, "duid ");
  306: 	  for (i = 0; i < daemon->duid_len - 1; i++)
  307: 	    ourprintf(&err, "%.2x:", daemon->duid[i]);
  308: 	  ourprintf(&err, "%.2x\n", daemon->duid[i]);
  309: 	  
  310: 	  for (lease = leases; lease; lease = lease->next)
  311: 	    {
  312: 	      
  313: 	      if (!(lease->flags & (LEASE_TA | LEASE_NA)))
  314: 		continue;
  315: 
  316: #ifdef HAVE_BROKEN_RTC
  317: 	      ourprintf(&err, "%u ", lease->length);
  318: #else
  319: 	      ourprintf(&err, "%lu ", (unsigned long)lease->expires);
  320: #endif
  321:     
  322: 	      inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
  323: 	 
  324: 	      ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "",
  325: 			lease->iaid, daemon->addrbuff);
  326: 	      ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
  327: 	      
  328: 	      if (lease->clid && lease->clid_len != 0)
  329: 		{
  330: 		  for (i = 0; i < lease->clid_len - 1; i++)
  331: 		    ourprintf(&err, "%.2x:", lease->clid[i]);
  332: 		  ourprintf(&err, "%.2x\n", lease->clid[i]);
  333: 		}
  334: 	      else
  335: 		ourprintf(&err, "*\n");	  
  336: 	    }
  337: 	}
  338: #endif      
  339: 	  
  340:       if (fflush(daemon->lease_stream) != 0 ||
  341: 	  fsync(fileno(daemon->lease_stream)) < 0)
  342: 	err = errno;
  343:       
  344:       if (!err)
  345: 	file_dirty = 0;
  346:     }
  347:   
  348:   /* Set alarm for when the first lease expires. */
  349:   next_event = 0;
  350: 
  351: #ifdef HAVE_DHCP6
  352:   /* do timed RAs and determine when the next is, also pings to potential SLAAC addresses */
  353:   if (daemon->doing_ra)
  354:     {
  355:       time_t event;
  356:       
  357:       if ((event = periodic_slaac(now, leases)) != 0)
  358: 	{
  359: 	  if (next_event == 0 || difftime(next_event, event) > 0.0)
  360: 	    next_event = event;
  361: 	}
  362:       
  363:       if ((event = periodic_ra(now)) != 0)
  364: 	{
  365: 	  if (next_event == 0 || difftime(next_event, event) > 0.0)
  366: 	    next_event = event;
  367: 	}
  368:     }
  369: #endif
  370: 
  371:   for (lease = leases; lease; lease = lease->next)
  372:     if (lease->expires != 0 &&
  373: 	(next_event == 0 || difftime(next_event, lease->expires) > 0.0))
  374:       next_event = lease->expires;
  375:    
  376:   if (err)
  377:     {
  378:       if (next_event == 0 || difftime(next_event, LEASE_RETRY + now) > 0.0)
  379: 	next_event = LEASE_RETRY + now;
  380:       
  381:       my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %u s)"), 
  382: 		daemon->lease_file, strerror(err),
  383: 		(unsigned int)difftime(next_event, now));
  384:     }
  385: 
  386:   send_alarm(next_event, now);
  387: }
  388: 
  389: 
  390: static int find_interface_v4(struct in_addr local, int if_index, char *label,
  391: 			     struct in_addr netmask, struct in_addr broadcast, void *vparam)
  392: {
  393:   struct dhcp_lease *lease;
  394:   int prefix = netmask_length(netmask);
  395: 
  396:   (void) label;
  397:   (void) broadcast;
  398:   (void) vparam;
  399: 
  400:   for (lease = leases; lease; lease = lease->next)
  401:     if (!(lease->flags & (LEASE_TA | LEASE_NA)) &&
  402: 	is_same_net(local, lease->addr, netmask) && 
  403: 	prefix > lease->new_prefixlen) 
  404:       {
  405: 	lease->new_interface = if_index;
  406:         lease->new_prefixlen = prefix;
  407:       }
  408: 
  409:   return 1;
  410: }
  411: 
  412: #ifdef HAVE_DHCP6
  413: static int find_interface_v6(struct in6_addr *local,  int prefix,
  414: 			     int scope, int if_index, int flags, 
  415: 			     int preferred, int valid, void *vparam)
  416: {
  417:   struct dhcp_lease *lease;
  418: 
  419:   (void)scope;
  420:   (void)flags;
  421:   (void)preferred;
  422:   (void)valid;
  423:   (void)vparam;
  424: 
  425:   for (lease = leases; lease; lease = lease->next)
  426:     if ((lease->flags & (LEASE_TA | LEASE_NA)))
  427:       if (is_same_net6(local, &lease->addr6, prefix) && prefix > lease->new_prefixlen) {
  428:         /* save prefix length for comparison, as we might get shorter matching
  429:          * prefix in upcoming netlink GETADDR responses
  430:          * */
  431:         lease->new_interface = if_index;
  432:         lease->new_prefixlen = prefix;
  433:       }
  434: 
  435:   return 1;
  436: }
  437: 
  438: void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface)
  439: {
  440:   /* We may be doing RA but not DHCPv4, in which case the lease
  441:      database may not exist and we have nothing to do anyway */
  442:   if (daemon->dhcp)
  443:     slaac_ping_reply(sender, packet, interface, leases);
  444: }
  445: 
  446: void lease_update_slaac(time_t now)
  447: {
  448:   /* Called when we construct a new RA-names context, to add putative
  449:      new SLAAC addresses to existing leases. */
  450: 
  451:   struct dhcp_lease *lease;
  452:   
  453:   if (daemon->dhcp)
  454:     for (lease = leases; lease; lease = lease->next)
  455:       slaac_add_addrs(lease, now, 0);
  456: }
  457: 
  458: #endif
  459: 
  460: 
  461: /* Find interfaces associated with leases at start-up. This gets updated as
  462:    we do DHCP transactions, but information about directly-connected subnets
  463:    is useful from scrips and necessary for determining SLAAC addresses from
  464:    start-time. */
  465: void lease_find_interfaces(time_t now)
  466: {
  467:   struct dhcp_lease *lease;
  468:   
  469:   for (lease = leases; lease; lease = lease->next)
  470:     lease->new_prefixlen = lease->new_interface = 0;
  471: 
  472:   iface_enumerate(AF_INET, &now, find_interface_v4);
  473: #ifdef HAVE_DHCP6
  474:   iface_enumerate(AF_INET6, &now, find_interface_v6);
  475: #endif
  476: 
  477:   for (lease = leases; lease; lease = lease->next)
  478:     if (lease->new_interface != 0) 
  479:       lease_set_interface(lease, lease->new_interface, now);
  480: }
  481: 
  482: #ifdef HAVE_DHCP6
  483: void lease_make_duid(time_t now)
  484: {
  485:   /* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
  486:   if (!daemon->duid && daemon->doing_dhcp6)
  487:     {
  488:       file_dirty = 1;
  489:       make_duid(now);
  490:     }
  491: }
  492: #endif
  493: 
  494: 
  495: 
  496: 
  497: void lease_update_dns(int force)
  498: {
  499:   struct dhcp_lease *lease;
  500: 
  501:   if (daemon->port != 0 && (dns_dirty || force))
  502:     {
  503: #ifndef HAVE_BROKEN_RTC
  504:       /* force transfer to authoritative secondaries */
  505:       daemon->soa_sn++;
  506: #endif
  507:       
  508:       cache_unhash_dhcp();
  509: 
  510:       for (lease = leases; lease; lease = lease->next)
  511: 	{
  512: 	  int prot = AF_INET;
  513: 	  
  514: #ifdef HAVE_DHCP6
  515: 	  if (lease->flags & (LEASE_TA | LEASE_NA))
  516: 	    prot = AF_INET6;
  517: 	  else if (lease->hostname || lease->fqdn)
  518: 	    {
  519: 	      struct slaac_address *slaac;
  520: 
  521: 	      for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
  522: 		if (slaac->backoff == 0)
  523: 		  {
  524: 		    if (lease->fqdn)
  525: 		      cache_add_dhcp_entry(lease->fqdn, AF_INET6, (union all_addr *)&slaac->addr, lease->expires);
  526: 		    if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
  527: 		      cache_add_dhcp_entry(lease->hostname, AF_INET6, (union all_addr *)&slaac->addr, lease->expires);
  528: 		  }
  529: 	    }
  530: 	  
  531: 	  if (lease->fqdn)
  532: 	    cache_add_dhcp_entry(lease->fqdn, prot, 
  533: 				 prot == AF_INET ? (union all_addr *)&lease->addr : (union all_addr *)&lease->addr6,
  534: 				 lease->expires);
  535: 	     
  536: 	  if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
  537: 	    cache_add_dhcp_entry(lease->hostname, prot, 
  538: 				 prot == AF_INET ? (union all_addr *)&lease->addr : (union all_addr *)&lease->addr6, 
  539: 				 lease->expires);
  540:        
  541: #else
  542: 	  if (lease->fqdn)
  543: 	    cache_add_dhcp_entry(lease->fqdn, prot, (union all_addr *)&lease->addr, lease->expires);
  544: 	  
  545: 	  if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
  546: 	    cache_add_dhcp_entry(lease->hostname, prot, (union all_addr *)&lease->addr, lease->expires);
  547: #endif
  548: 	}
  549:       
  550:       dns_dirty = 0;
  551:     }
  552: }
  553: 
  554: void lease_prune(struct dhcp_lease *target, time_t now)
  555: {
  556:   struct dhcp_lease *lease, *tmp, **up;
  557: 
  558:   for (lease = leases, up = &leases; lease; lease = tmp)
  559:     {
  560:       tmp = lease->next;
  561:       if ((lease->expires != 0 && difftime(now, lease->expires) >= 0) || lease == target)
  562: 	{
  563: 	  file_dirty = 1;
  564: 	  if (lease->hostname)
  565: 	    dns_dirty = 1;
  566: 
  567: 	  daemon->metrics[lease->addr.s_addr ? METRIC_LEASES_PRUNED_4 : METRIC_LEASES_PRUNED_6]++;
  568: 
  569:  	  *up = lease->next; /* unlink */
  570: 	  
  571: 	  /* Put on old_leases list 'till we
  572: 	     can run the script */
  573: 	  lease->next = old_leases;
  574: 	  old_leases = lease;
  575: 	  
  576: 	  leases_left++;
  577: 	}
  578:       else
  579: 	up = &lease->next;
  580:     }
  581: } 
  582: 	
  583:   
  584: struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
  585: 					unsigned char *clid, int clid_len)
  586: {
  587:   struct dhcp_lease *lease;
  588: 
  589:   if (clid)
  590:     for (lease = leases; lease; lease = lease->next)
  591:       {
  592: #ifdef HAVE_DHCP6
  593: 	if (lease->flags & (LEASE_TA | LEASE_NA))
  594: 	  continue;
  595: #endif
  596: 	if (lease->clid && clid_len == lease->clid_len &&
  597: 	    memcmp(clid, lease->clid, clid_len) == 0)
  598: 	  return lease;
  599:       }
  600:   
  601:   for (lease = leases; lease; lease = lease->next)	
  602:     {
  603: #ifdef HAVE_DHCP6
  604:       if (lease->flags & (LEASE_TA | LEASE_NA))
  605: 	continue;
  606: #endif   
  607:       if ((!lease->clid || !clid) && 
  608: 	  hw_len != 0 && 
  609: 	  lease->hwaddr_len == hw_len &&
  610: 	  lease->hwaddr_type == hw_type &&
  611: 	  memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
  612: 	return lease;
  613:     }
  614: 
  615:   return NULL;
  616: }
  617: 
  618: struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
  619: {
  620:   struct dhcp_lease *lease;
  621: 
  622:   for (lease = leases; lease; lease = lease->next)
  623:     {
  624: #ifdef HAVE_DHCP6
  625:       if (lease->flags & (LEASE_TA | LEASE_NA))
  626: 	continue;
  627: #endif  
  628:       if (lease->addr.s_addr == addr.s_addr)
  629: 	return lease;
  630:     }
  631: 
  632:   return NULL;
  633: }
  634: 
  635: #ifdef HAVE_DHCP6
  636: /* find address for {CLID, IAID, address} */
  637: struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len, 
  638: 			       int lease_type, unsigned int iaid,
  639: 			       struct in6_addr *addr)
  640: {
  641:   struct dhcp_lease *lease;
  642:   
  643:   for (lease = leases; lease; lease = lease->next)
  644:     {
  645:       if (!(lease->flags & lease_type) || lease->iaid != iaid)
  646: 	continue;
  647: 
  648:       if (!IN6_ARE_ADDR_EQUAL(&lease->addr6, addr))
  649: 	continue;
  650:       
  651:       if ((clid_len != lease->clid_len ||
  652: 	   memcmp(clid, lease->clid, clid_len) != 0))
  653: 	continue;
  654:       
  655:       return lease;
  656:     }
  657:   
  658:   return NULL;
  659: }
  660: 
  661: /* reset "USED flags */
  662: void lease6_reset(void)
  663: {
  664:   struct dhcp_lease *lease;
  665:   
  666:   for (lease = leases; lease; lease = lease->next)
  667:     lease->flags &= ~LEASE_USED;
  668: }
  669: 
  670: /* enumerate all leases belonging to {CLID, IAID} */
  671: struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type,
  672: 					 unsigned char *clid, int clid_len,
  673: 					 unsigned int iaid)
  674: {
  675:   struct dhcp_lease *lease;
  676: 
  677:   if (!first)
  678:     first = leases;
  679:   else
  680:     first = first->next;
  681: 
  682:   for (lease = first; lease; lease = lease->next)
  683:     {
  684:       if (lease->flags & LEASE_USED)
  685: 	continue;
  686: 
  687:       if (!(lease->flags & lease_type) || lease->iaid != iaid)
  688: 	continue;
  689:  
  690:       if ((clid_len != lease->clid_len ||
  691: 	   memcmp(clid, lease->clid, clid_len) != 0))
  692: 	continue;
  693: 
  694:       return lease;
  695:     }
  696:   
  697:   return NULL;
  698: }
  699: 
  700: struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
  701: {
  702:   struct dhcp_lease *lease;
  703:     
  704:   for (lease = leases; lease; lease = lease->next)
  705:     {
  706:       if (!(lease->flags & (LEASE_TA | LEASE_NA)))
  707: 	continue;
  708:       
  709:       if (is_same_net6(&lease->addr6, net, prefix) &&
  710: 	  (prefix == 128 || addr6part(&lease->addr6) == addr))
  711: 	return lease;
  712:     }
  713:   
  714:   return NULL;
  715: } 
  716: 
  717: /* Find largest assigned address in context */
  718: u64 lease_find_max_addr6(struct dhcp_context *context)
  719: {
  720:   struct dhcp_lease *lease;
  721:   u64 addr = addr6part(&context->start6);
  722:   
  723:   if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
  724:     for (lease = leases; lease; lease = lease->next)
  725:       {
  726: 	if (!(lease->flags & (LEASE_TA | LEASE_NA)))
  727: 	  continue;
  728: 
  729: 	if (is_same_net6(&lease->addr6, &context->start6, 64) &&
  730: 	    addr6part(&lease->addr6) > addr6part(&context->start6) &&
  731: 	    addr6part(&lease->addr6) <= addr6part(&context->end6) &&
  732: 	    addr6part(&lease->addr6) > addr)
  733: 	  addr = addr6part(&lease->addr6);
  734:       }
  735:   
  736:   return addr;
  737: }
  738: 
  739: #endif
  740: 
  741: /* Find largest assigned address in context */
  742: struct in_addr lease_find_max_addr(struct dhcp_context *context)
  743: {
  744:   struct dhcp_lease *lease;
  745:   struct in_addr addr = context->start;
  746:   
  747:   if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
  748:     for (lease = leases; lease; lease = lease->next)
  749:       {
  750: #ifdef HAVE_DHCP6
  751: 	if (lease->flags & (LEASE_TA | LEASE_NA))
  752: 	  continue;
  753: #endif
  754: 	if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
  755: 	    ((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
  756: 	    ((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
  757: 	  addr = lease->addr;
  758:       }
  759:   
  760:   return addr;
  761: }
  762: 
  763: static struct dhcp_lease *lease_allocate(void)
  764: {
  765:   struct dhcp_lease *lease;
  766:   if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
  767:     return NULL;
  768: 
  769:   memset(lease, 0, sizeof(struct dhcp_lease));
  770:   lease->flags = LEASE_NEW;
  771:   lease->expires = 1;
  772: #ifdef HAVE_BROKEN_RTC
  773:   lease->length = 0xffffffff; /* illegal value */
  774: #endif
  775:   lease->hwaddr_len = 256; /* illegal value */
  776:   lease->next = leases;
  777:   leases = lease;
  778:   
  779:   file_dirty = 1;
  780:   leases_left--;
  781: 
  782:   return lease;
  783: }
  784: 
  785: struct dhcp_lease *lease4_allocate(struct in_addr addr)
  786: {
  787:   struct dhcp_lease *lease = lease_allocate();
  788:   if (lease)
  789:     {
  790:       lease->addr = addr;
  791:       daemon->metrics[METRIC_LEASES_ALLOCATED_4]++;
  792:     }
  793:   
  794:   return lease;
  795: }
  796: 
  797: #ifdef HAVE_DHCP6
  798: struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
  799: {
  800:   struct dhcp_lease *lease = lease_allocate();
  801: 
  802:   if (lease)
  803:     {
  804:       lease->addr6 = *addrp;
  805:       lease->flags |= lease_type;
  806:       lease->iaid = 0;
  807: 
  808:       daemon->metrics[METRIC_LEASES_ALLOCATED_6]++;
  809:     }
  810: 
  811:   return lease;
  812: }
  813: #endif
  814: 
  815: void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
  816: {
  817:   time_t exp;
  818: 
  819:   if (len == 0xffffffff)
  820:     {
  821:       exp = 0;
  822:       len = 0;
  823:     }
  824:   else
  825:     {
  826:       exp = now + (time_t)len;
  827:       /* Check for 2038 overflow. Make the lease
  828: 	 infinite in that case, as the least disruptive
  829: 	 thing we can do. */
  830:       if (difftime(exp, now) <= 0.0)
  831: 	exp = 0;
  832:     }
  833: 
  834:   if (exp != lease->expires)
  835:     {
  836:       dns_dirty = 1;
  837:       lease->expires = exp;
  838: #ifndef HAVE_BROKEN_RTC
  839:       lease->flags |= LEASE_AUX_CHANGED | LEASE_EXP_CHANGED;
  840:       file_dirty = 1;
  841: #endif
  842:     }
  843:   
  844: #ifdef HAVE_BROKEN_RTC
  845:   if (len != lease->length)
  846:     {
  847:       lease->length = len;
  848:       lease->flags |= LEASE_AUX_CHANGED;
  849:       file_dirty = 1; 
  850:     }
  851: #endif
  852: } 
  853: 
  854: #ifdef HAVE_DHCP6
  855: void lease_set_iaid(struct dhcp_lease *lease, unsigned int iaid)
  856: {
  857:   if (lease->iaid != iaid)
  858:     {
  859:       lease->iaid = iaid;
  860:       lease->flags |= LEASE_CHANGED;
  861:     }
  862: }
  863: #endif
  864: 
  865: void lease_set_hwaddr(struct dhcp_lease *lease, const unsigned char *hwaddr,
  866: 		      const unsigned char *clid, int hw_len, int hw_type,
  867: 		      int clid_len, time_t now, int force)
  868: {
  869: #ifdef HAVE_DHCP6
  870:   int change = force;
  871:   lease->flags |= LEASE_HAVE_HWADDR;
  872: #endif
  873: 
  874:   (void)force;
  875:   (void)now;
  876: 
  877:   if (hw_len != lease->hwaddr_len ||
  878:       hw_type != lease->hwaddr_type || 
  879:       (hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
  880:     {
  881:       if (hw_len != 0)
  882: 	memcpy(lease->hwaddr, hwaddr, hw_len);
  883:       lease->hwaddr_len = hw_len;
  884:       lease->hwaddr_type = hw_type;
  885:       lease->flags |= LEASE_CHANGED;
  886:       file_dirty = 1; /* run script on change */
  887:     }
  888: 
  889:   /* only update clid when one is available, stops packets
  890:      without a clid removing the record. Lease init uses
  891:      clid_len == 0 for no clid. */
  892:   if (clid_len != 0 && clid)
  893:     {
  894:       if (!lease->clid)
  895: 	lease->clid_len = 0;
  896: 
  897:       if (lease->clid_len != clid_len)
  898: 	{
  899: 	  lease->flags |= LEASE_AUX_CHANGED;
  900: 	  file_dirty = 1;
  901: 	  free(lease->clid);
  902: 	  if (!(lease->clid = whine_malloc(clid_len)))
  903: 	    return;
  904: #ifdef HAVE_DHCP6
  905: 	  change = 1;
  906: #endif	   
  907: 	}
  908:       else if (memcmp(lease->clid, clid, clid_len) != 0)
  909: 	{
  910: 	  lease->flags |= LEASE_AUX_CHANGED;
  911: 	  file_dirty = 1;
  912: #ifdef HAVE_DHCP6
  913: 	  change = 1;
  914: #endif	
  915: 	}
  916:       
  917:       lease->clid_len = clid_len;
  918:       memcpy(lease->clid, clid, clid_len);
  919:     }
  920:   
  921: #ifdef HAVE_DHCP6
  922:   if (change)
  923:     slaac_add_addrs(lease, now, force);
  924: #endif
  925: }
  926: 
  927: static void kill_name(struct dhcp_lease *lease)
  928: {
  929:   /* run script to say we lost our old name */
  930:   
  931:   /* this shouldn't happen unless updates are very quick and the
  932:      script very slow, we just avoid a memory leak if it does. */
  933:   free(lease->old_hostname);
  934:   
  935:   /* If we know the fqdn, pass that. The helper will derive the
  936:      unqualified name from it, free the unqualified name here. */
  937: 
  938:   if (lease->fqdn)
  939:     {
  940:       lease->old_hostname = lease->fqdn;
  941:       free(lease->hostname);
  942:     }
  943:   else
  944:     lease->old_hostname = lease->hostname;
  945: 
  946:   lease->hostname = lease->fqdn = NULL;
  947: }
  948: 
  949: void lease_set_hostname(struct dhcp_lease *lease, const char *name, int auth, char *domain, char *config_domain)
  950: {
  951:   struct dhcp_lease *lease_tmp;
  952:   char *new_name = NULL, *new_fqdn = NULL;
  953: 
  954:   if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
  955:     my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, name);
  956:   
  957:   if (lease->hostname && name && hostname_isequal(lease->hostname, name))
  958:     {
  959:       if (auth)
  960: 	lease->flags |= LEASE_AUTH_NAME;
  961:       return;
  962:     }
  963:   
  964:   if (!name && !lease->hostname)
  965:     return;
  966: 
  967:   /* If a machine turns up on a new net without dropping the old lease,
  968:      or two machines claim the same name, then we end up with two interfaces with
  969:      the same name. Check for that here and remove the name from the old lease.
  970:      Note that IPv6 leases are different. All the leases to the same DUID are 
  971:      allowed the same name.
  972: 
  973:      Don't allow a name from the client to override a name from dnsmasq config. */
  974:   
  975:   if (name)
  976:     {
  977:       if ((new_name = whine_malloc(strlen(name) + 1)))
  978: 	{
  979: 	  strcpy(new_name, name);
  980: 	  if (domain && (new_fqdn = whine_malloc(strlen(new_name) + strlen(domain) + 2)))
  981: 	    {
  982: 	      strcpy(new_fqdn, name);
  983: 	      strcat(new_fqdn, ".");
  984: 	      strcat(new_fqdn, domain);
  985: 	    }
  986: 	}
  987: 	  
  988:       /* Depending on mode, we check either unqualified name or FQDN. */
  989:       for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
  990: 	{
  991: 	  if (option_bool(OPT_DHCP_FQDN))
  992: 	    {
  993: 	      if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn))
  994: 		continue;
  995: 	    }
  996: 	  else
  997: 	    {
  998: 	      if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
  999: 		continue; 
 1000: 	    }
 1001: 
 1002: 	  if (lease->flags & (LEASE_TA | LEASE_NA))
 1003: 	    {
 1004: 	      if (!(lease_tmp->flags & (LEASE_TA | LEASE_NA)))
 1005: 		continue;
 1006: 
 1007: 	      /* another lease for the same DUID is OK for IPv6 */
 1008: 	      if (lease->clid_len == lease_tmp->clid_len &&
 1009: 		  lease->clid && lease_tmp->clid &&
 1010: 		  memcmp(lease->clid, lease_tmp->clid, lease->clid_len) == 0)
 1011: 		continue;	      
 1012: 	    }
 1013: 	  else if (lease_tmp->flags & (LEASE_TA | LEASE_NA))
 1014: 	    continue;
 1015: 		   
 1016: 	  if ((lease_tmp->flags & LEASE_AUTH_NAME) && !auth)
 1017: 	    {
 1018: 	      free(new_name);
 1019: 	      free(new_fqdn);
 1020: 	      return;
 1021: 	    }
 1022: 	
 1023: 	  kill_name(lease_tmp);
 1024: 	  lease_tmp->flags |= LEASE_CHANGED; /* run script on change */
 1025: 	  break;
 1026: 	}
 1027:     }
 1028: 
 1029:   if (lease->hostname)
 1030:     kill_name(lease);
 1031: 
 1032:   lease->hostname = new_name;
 1033:   lease->fqdn = new_fqdn;
 1034:   
 1035:   if (auth)
 1036:     lease->flags |= LEASE_AUTH_NAME;
 1037:   
 1038:   file_dirty = 1;
 1039:   dns_dirty = 1; 
 1040:   lease->flags |= LEASE_CHANGED; /* run script on change */
 1041: }
 1042: 
 1043: void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
 1044: {
 1045:   (void)now;
 1046: 
 1047:   if (lease->last_interface == interface)
 1048:     return;
 1049: 
 1050:   lease->last_interface = interface;
 1051:   lease->flags |= LEASE_CHANGED; 
 1052: 
 1053: #ifdef HAVE_DHCP6
 1054:   slaac_add_addrs(lease, now, 0);
 1055: #endif
 1056: }
 1057: 
 1058: void rerun_scripts(void)
 1059: {
 1060:   struct dhcp_lease *lease;
 1061:   
 1062:   for (lease = leases; lease; lease = lease->next)
 1063:     lease->flags |= LEASE_CHANGED; 
 1064: }
 1065: 
 1066: /* deleted leases get transferred to the old_leases list.
 1067:    remove them here, after calling the lease change
 1068:    script. Also run the lease change script on new/modified leases.
 1069: 
 1070:    Return zero if nothing to do. */
 1071: int do_script_run(time_t now)
 1072: {
 1073:   struct dhcp_lease *lease;
 1074: 
 1075:   (void)now;
 1076: 
 1077: #ifdef HAVE_DBUS
 1078:   /* If we're going to be sending DBus signals, but the connection is not yet up,
 1079:      delay everything until it is. */
 1080:   if (option_bool(OPT_DBUS) && !daemon->dbus)
 1081:     return 0;
 1082: #endif
 1083: 
 1084:   if (old_leases)
 1085:     {
 1086:       lease = old_leases;
 1087:                   
 1088:       /* If the lease still has an old_hostname, do the "old" action on that first */
 1089:       if (lease->old_hostname)
 1090: 	{
 1091: #ifdef HAVE_SCRIPT
 1092: 	  queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
 1093: #endif
 1094: 	  free(lease->old_hostname);
 1095: 	  lease->old_hostname = NULL;
 1096: 	  return 1;
 1097: 	}
 1098:       else 
 1099: 	{
 1100: #ifdef HAVE_DHCP6
 1101: 	  struct slaac_address *slaac, *tmp;
 1102: 	  for (slaac = lease->slaac_address; slaac; slaac = tmp)
 1103: 	    {
 1104: 	      tmp = slaac->next;
 1105: 	      free(slaac);
 1106: 	    }
 1107: #endif
 1108: 	  kill_name(lease);
 1109: #ifdef HAVE_SCRIPT
 1110: 	  queue_script(ACTION_DEL, lease, lease->old_hostname, now);
 1111: #endif
 1112: #ifdef HAVE_DBUS
 1113: 	  emit_dbus_signal(ACTION_DEL, lease, lease->old_hostname);
 1114: #endif
 1115: 	  old_leases = lease->next;
 1116: 	  
 1117: 	  free(lease->old_hostname); 
 1118: 	  free(lease->clid);
 1119: 	  free(lease->extradata);
 1120: 	  free(lease);
 1121: 	    
 1122: 	  return 1; 
 1123: 	}
 1124:     }
 1125:   
 1126:   /* make sure we announce the loss of a hostname before its new location. */
 1127:   for (lease = leases; lease; lease = lease->next)
 1128:     if (lease->old_hostname)
 1129:       {	
 1130: #ifdef HAVE_SCRIPT
 1131: 	queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
 1132: #endif
 1133: 	free(lease->old_hostname);
 1134: 	lease->old_hostname = NULL;
 1135: 	return 1;
 1136:       }
 1137:   
 1138:   for (lease = leases; lease; lease = lease->next)
 1139:     if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) || 
 1140: 	((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)) ||
 1141: 	((lease->flags & LEASE_EXP_CHANGED) && option_bool(OPT_LEASE_RENEW)))
 1142:       {
 1143: #ifdef HAVE_SCRIPT
 1144: 	queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease, 
 1145: 		     lease->fqdn ? lease->fqdn : lease->hostname, now);
 1146: #endif
 1147: #ifdef HAVE_DBUS
 1148: 	emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
 1149: 			 lease->fqdn ? lease->fqdn : lease->hostname);
 1150: #endif
 1151: 	lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED | LEASE_EXP_CHANGED);
 1152: 	
 1153: 	/* this is used for the "add" call, then junked, since they're not in the database */
 1154: 	free(lease->extradata);
 1155: 	lease->extradata = NULL;
 1156: 	
 1157: 	return 1;
 1158:       }
 1159: 
 1160:   return 0; /* nothing to do */
 1161: }
 1162: 
 1163: #ifdef HAVE_SCRIPT
 1164: /* delim == -1 -> delim = 0, but embedded 0s, creating extra records, are OK. */
 1165: void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
 1166: {
 1167:   unsigned int i;
 1168:   
 1169:   if (delim == -1)
 1170:     delim = 0;
 1171:   else
 1172:     /* check for embedded NULLs */
 1173:     for (i = 0; i < len; i++)
 1174:       if (data[i] == 0)
 1175: 	{
 1176: 	  len = i;
 1177: 	  break;
 1178: 	}
 1179:   
 1180:   if ((lease->extradata_size - lease->extradata_len) < (len + 1))
 1181:     {
 1182:       size_t newsz = lease->extradata_len + len + 100;
 1183:       unsigned char *new = whine_realloc(lease->extradata, newsz);
 1184:   
 1185:       if (!new)
 1186: 	return;
 1187:       
 1188:       lease->extradata = new;
 1189:       lease->extradata_size = newsz;
 1190:     }
 1191: 
 1192:   if (len != 0)
 1193:     memcpy(lease->extradata + lease->extradata_len, data, len);
 1194:   lease->extradata[lease->extradata_len + len] = delim;
 1195:   lease->extradata_len += len + 1; 
 1196: }
 1197: #endif
 1198: 
 1199: #endif /* HAVE_DHCP */

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