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

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

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