File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / lease.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Mon Jul 29 19:37:40 2013 UTC (10 years, 11 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

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

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