File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / lease.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 09:57:01 2016 UTC (7 years, 9 months ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_76p1, HEAD
dnsmasq 2.76

    1: /* dnsmasq is Copyright (c) 2000-2016 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:   int prefix = netmask_length(netmask);
  356: 
  357:   (void) label;
  358:   (void) broadcast;
  359:   (void) vparam;
  360: 
  361:   for (lease = leases; lease; lease = lease->next)
  362:     if (!(lease->flags & (LEASE_TA | LEASE_NA)) &&
  363: 	is_same_net(local, lease->addr, netmask) && 
  364: 	prefix > lease->new_prefixlen) 
  365:       {
  366: 	lease->new_interface = if_index;
  367:         lease->new_prefixlen = prefix;
  368:       }
  369: 
  370:   return 1;
  371: }
  372: 
  373: #ifdef HAVE_DHCP6
  374: static int find_interface_v6(struct in6_addr *local,  int prefix,
  375: 			     int scope, int if_index, int flags, 
  376: 			     int preferred, int valid, void *vparam)
  377: {
  378:   struct dhcp_lease *lease;
  379: 
  380:   (void)scope;
  381:   (void)flags;
  382:   (void)preferred;
  383:   (void)valid;
  384:   (void)vparam;
  385: 
  386:   for (lease = leases; lease; lease = lease->next)
  387:     if ((lease->flags & (LEASE_TA | LEASE_NA)))
  388:       if (is_same_net6(local, &lease->addr6, prefix) && prefix > lease->new_prefixlen) {
  389:         /* save prefix length for comparison, as we might get shorter matching
  390:          * prefix in upcoming netlink GETADDR responses
  391:          * */
  392:         lease->new_interface = if_index;
  393:         lease->new_prefixlen = prefix;
  394:       }
  395: 
  396:   return 1;
  397: }
  398: 
  399: void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface)
  400: {
  401:   /* We may be doing RA but not DHCPv4, in which case the lease
  402:      database may not exist and we have nothing to do anyway */
  403:   if (daemon->dhcp)
  404:     slaac_ping_reply(sender, packet, interface, leases);
  405: }
  406: 
  407: void lease_update_slaac(time_t now)
  408: {
  409:   /* Called when we contruct a new RA-names context, to add putative
  410:      new SLAAC addresses to existing leases. */
  411: 
  412:   struct dhcp_lease *lease;
  413:   
  414:   if (daemon->dhcp)
  415:     for (lease = leases; lease; lease = lease->next)
  416:       slaac_add_addrs(lease, now, 0);
  417: }
  418: 
  419: #endif
  420: 
  421: 
  422: /* Find interfaces associated with leases at start-up. This gets updated as
  423:    we do DHCP transactions, but information about directly-connected subnets
  424:    is useful from scrips and necessary for determining SLAAC addresses from
  425:    start-time. */
  426: void lease_find_interfaces(time_t now)
  427: {
  428:   struct dhcp_lease *lease;
  429:   
  430:   for (lease = leases; lease; lease = lease->next)
  431:     lease->new_prefixlen = lease->new_interface = 0;
  432: 
  433:   iface_enumerate(AF_INET, &now, find_interface_v4);
  434: #ifdef HAVE_DHCP6
  435:   iface_enumerate(AF_INET6, &now, find_interface_v6);
  436: #endif
  437: 
  438:   for (lease = leases; lease; lease = lease->next)
  439:     if (lease->new_interface != 0) 
  440:       lease_set_interface(lease, lease->new_interface, now);
  441: }
  442: 
  443: #ifdef HAVE_DHCP6
  444: void lease_make_duid(time_t now)
  445: {
  446:   /* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
  447:   if (!daemon->duid && daemon->doing_dhcp6)
  448:     {
  449:       file_dirty = 1;
  450:       make_duid(now);
  451:     }
  452: }
  453: #endif
  454: 
  455: 
  456: 
  457: 
  458: void lease_update_dns(int force)
  459: {
  460:   struct dhcp_lease *lease;
  461: 
  462:   if (daemon->port != 0 && (dns_dirty || force))
  463:     {
  464: #ifndef HAVE_BROKEN_RTC
  465:       /* force transfer to authoritative secondaries */
  466:       daemon->soa_sn++;
  467: #endif
  468:       
  469:       cache_unhash_dhcp();
  470: 
  471:       for (lease = leases; lease; lease = lease->next)
  472: 	{
  473: 	  int prot = AF_INET;
  474: 	  
  475: #ifdef HAVE_DHCP6
  476: 	  if (lease->flags & (LEASE_TA | LEASE_NA))
  477: 	    prot = AF_INET6;
  478: 	  else if (lease->hostname || lease->fqdn)
  479: 	    {
  480: 	      struct slaac_address *slaac;
  481: 
  482: 	      for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
  483: 		if (slaac->backoff == 0)
  484: 		  {
  485: 		    if (lease->fqdn)
  486: 		      cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
  487: 		    if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
  488: 		      cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
  489: 		  }
  490: 	    }
  491: 	  
  492: 	  if (lease->fqdn)
  493: 	    cache_add_dhcp_entry(lease->fqdn, prot, 
  494: 				 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
  495: 				 lease->expires);
  496: 	     
  497: 	  if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
  498: 	    cache_add_dhcp_entry(lease->hostname, prot, 
  499: 				 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6, 
  500: 				 lease->expires);
  501:        
  502: #else
  503: 	  if (lease->fqdn)
  504: 	    cache_add_dhcp_entry(lease->fqdn, prot, (struct all_addr *)&lease->addr, lease->expires);
  505: 	  
  506: 	  if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
  507: 	    cache_add_dhcp_entry(lease->hostname, prot, (struct all_addr *)&lease->addr, lease->expires);
  508: #endif
  509: 	}
  510:       
  511:       dns_dirty = 0;
  512:     }
  513: }
  514: 
  515: void lease_prune(struct dhcp_lease *target, time_t now)
  516: {
  517:   struct dhcp_lease *lease, *tmp, **up;
  518: 
  519:   for (lease = leases, up = &leases; lease; lease = tmp)
  520:     {
  521:       tmp = lease->next;
  522:       if ((lease->expires != 0 && difftime(now, lease->expires) > 0) || lease == target)
  523: 	{
  524: 	  file_dirty = 1;
  525: 	  if (lease->hostname)
  526: 	    dns_dirty = 1;
  527: 	  
  528:  	  *up = lease->next; /* unlink */
  529: 	  
  530: 	  /* Put on old_leases list 'till we
  531: 	     can run the script */
  532: 	  lease->next = old_leases;
  533: 	  old_leases = lease;
  534: 	  
  535: 	  leases_left++;
  536: 	}
  537:       else
  538: 	up = &lease->next;
  539:     }
  540: } 
  541: 	
  542:   
  543: struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
  544: 					unsigned char *clid, int clid_len)
  545: {
  546:   struct dhcp_lease *lease;
  547: 
  548:   if (clid)
  549:     for (lease = leases; lease; lease = lease->next)
  550:       {
  551: #ifdef HAVE_DHCP6
  552: 	if (lease->flags & (LEASE_TA | LEASE_NA))
  553: 	  continue;
  554: #endif
  555: 	if (lease->clid && clid_len == lease->clid_len &&
  556: 	    memcmp(clid, lease->clid, clid_len) == 0)
  557: 	  return lease;
  558:       }
  559:   
  560:   for (lease = leases; lease; lease = lease->next)	
  561:     {
  562: #ifdef HAVE_DHCP6
  563:       if (lease->flags & (LEASE_TA | LEASE_NA))
  564: 	continue;
  565: #endif   
  566:       if ((!lease->clid || !clid) && 
  567: 	  hw_len != 0 && 
  568: 	  lease->hwaddr_len == hw_len &&
  569: 	  lease->hwaddr_type == hw_type &&
  570: 	  memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
  571: 	return lease;
  572:     }
  573: 
  574:   return NULL;
  575: }
  576: 
  577: struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
  578: {
  579:   struct dhcp_lease *lease;
  580: 
  581:   for (lease = leases; lease; lease = lease->next)
  582:     {
  583: #ifdef HAVE_DHCP6
  584:       if (lease->flags & (LEASE_TA | LEASE_NA))
  585: 	continue;
  586: #endif  
  587:       if (lease->addr.s_addr == addr.s_addr)
  588: 	return lease;
  589:     }
  590: 
  591:   return NULL;
  592: }
  593: 
  594: #ifdef HAVE_DHCP6
  595: /* find address for {CLID, IAID, address} */
  596: struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len, 
  597: 			       int lease_type, int iaid, struct in6_addr *addr)
  598: {
  599:   struct dhcp_lease *lease;
  600:   
  601:   for (lease = leases; lease; lease = lease->next)
  602:     {
  603:       if (!(lease->flags & lease_type) || lease->iaid != iaid)
  604: 	continue;
  605: 
  606:       if (!IN6_ARE_ADDR_EQUAL(&lease->addr6, addr))
  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: /* reset "USED flags */
  620: void lease6_reset(void)
  621: {
  622:   struct dhcp_lease *lease;
  623:   
  624:   for (lease = leases; lease; lease = lease->next)
  625:     lease->flags &= ~LEASE_USED;
  626: }
  627: 
  628: /* enumerate all leases belonging to {CLID, IAID} */
  629: struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid)
  630: {
  631:   struct dhcp_lease *lease;
  632: 
  633:   if (!first)
  634:     first = leases;
  635:   else
  636:     first = first->next;
  637: 
  638:   for (lease = first; lease; lease = lease->next)
  639:     {
  640:       if (lease->flags & LEASE_USED)
  641: 	continue;
  642: 
  643:       if (!(lease->flags & lease_type) || lease->iaid != iaid)
  644: 	continue;
  645:  
  646:       if ((clid_len != lease->clid_len ||
  647: 	   memcmp(clid, lease->clid, clid_len) != 0))
  648: 	continue;
  649: 
  650:       return lease;
  651:     }
  652:   
  653:   return NULL;
  654: }
  655: 
  656: struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
  657: {
  658:   struct dhcp_lease *lease;
  659:     
  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, net, prefix) &&
  666: 	  (prefix == 128 || addr6part(&lease->addr6) == addr))
  667: 	return lease;
  668:     }
  669:   
  670:   return NULL;
  671: } 
  672: 
  673: /* Find largest assigned address in context */
  674: u64 lease_find_max_addr6(struct dhcp_context *context)
  675: {
  676:   struct dhcp_lease *lease;
  677:   u64 addr = addr6part(&context->start6);
  678:   
  679:   if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
  680:     for (lease = leases; lease; lease = lease->next)
  681:       {
  682: 	if (!(lease->flags & (LEASE_TA | LEASE_NA)))
  683: 	  continue;
  684: 
  685: 	if (is_same_net6(&lease->addr6, &context->start6, 64) &&
  686: 	    addr6part(&lease->addr6) > addr6part(&context->start6) &&
  687: 	    addr6part(&lease->addr6) <= addr6part(&context->end6) &&
  688: 	    addr6part(&lease->addr6) > addr)
  689: 	  addr = addr6part(&lease->addr6);
  690:       }
  691:   
  692:   return addr;
  693: }
  694: 
  695: #endif
  696: 
  697: /* Find largest assigned address in context */
  698: struct in_addr lease_find_max_addr(struct dhcp_context *context)
  699: {
  700:   struct dhcp_lease *lease;
  701:   struct in_addr addr = context->start;
  702:   
  703:   if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
  704:     for (lease = leases; lease; lease = lease->next)
  705:       {
  706: #ifdef HAVE_DHCP6
  707: 	if (lease->flags & (LEASE_TA | LEASE_NA))
  708: 	  continue;
  709: #endif
  710: 	if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
  711: 	    ((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
  712: 	    ((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
  713: 	  addr = lease->addr;
  714:       }
  715:   
  716:   return addr;
  717: }
  718: 
  719: static struct dhcp_lease *lease_allocate(void)
  720: {
  721:   struct dhcp_lease *lease;
  722:   if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
  723:     return NULL;
  724: 
  725:   memset(lease, 0, sizeof(struct dhcp_lease));
  726:   lease->flags = LEASE_NEW;
  727:   lease->expires = 1;
  728: #ifdef HAVE_BROKEN_RTC
  729:   lease->length = 0xffffffff; /* illegal value */
  730: #endif
  731:   lease->hwaddr_len = 256; /* illegal value */
  732:   lease->next = leases;
  733:   leases = lease;
  734:   
  735:   file_dirty = 1;
  736:   leases_left--;
  737: 
  738:   return lease;
  739: }
  740: 
  741: struct dhcp_lease *lease4_allocate(struct in_addr addr)
  742: {
  743:   struct dhcp_lease *lease = lease_allocate();
  744:   if (lease)
  745:     lease->addr = addr;
  746:   
  747:   return lease;
  748: }
  749: 
  750: #ifdef HAVE_DHCP6
  751: struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
  752: {
  753:   struct dhcp_lease *lease = lease_allocate();
  754: 
  755:   if (lease)
  756:     {
  757:       lease->addr6 = *addrp;
  758:       lease->flags |= lease_type;
  759:       lease->iaid = 0;
  760:     }
  761: 
  762:   return lease;
  763: }
  764: #endif
  765: 
  766: void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
  767: {
  768:   time_t exp;
  769: 
  770:   if (len == 0xffffffff)
  771:     {
  772:       exp = 0;
  773:       len = 0;
  774:     }
  775:   else
  776:     {
  777:       exp = now + (time_t)len;
  778:       /* Check for 2038 overflow. Make the lease
  779: 	 inifinite in that case, as the least disruptive
  780: 	 thing we can do. */
  781:       if (difftime(exp, now) <= 0.0)
  782: 	exp = 0;
  783:     }
  784: 
  785:   if (exp != lease->expires)
  786:     {
  787:       dns_dirty = 1;
  788:       lease->expires = exp;
  789: #ifndef HAVE_BROKEN_RTC
  790:       lease->flags |= LEASE_AUX_CHANGED;
  791:       file_dirty = 1;
  792: #endif
  793:     }
  794:   
  795: #ifdef HAVE_BROKEN_RTC
  796:   if (len != lease->length)
  797:     {
  798:       lease->length = len;
  799:       lease->flags |= LEASE_AUX_CHANGED;
  800:       file_dirty = 1; 
  801:     }
  802: #endif
  803: } 
  804: 
  805: #ifdef HAVE_DHCP6
  806: void lease_set_iaid(struct dhcp_lease *lease, int iaid)
  807: {
  808:   if (lease->iaid != iaid)
  809:     {
  810:       lease->iaid = iaid;
  811:       lease->flags |= LEASE_CHANGED;
  812:     }
  813: }
  814: #endif
  815: 
  816: void lease_set_hwaddr(struct dhcp_lease *lease, const unsigned char *hwaddr,
  817: 		      const unsigned char *clid, int hw_len, int hw_type,
  818: 		      int clid_len, time_t now, int force)
  819: {
  820: #ifdef HAVE_DHCP6
  821:   int change = force;
  822:   lease->flags |= LEASE_HAVE_HWADDR;
  823: #endif
  824: 
  825:   (void)force;
  826:   (void)now;
  827: 
  828:   if (hw_len != lease->hwaddr_len ||
  829:       hw_type != lease->hwaddr_type || 
  830:       (hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
  831:     {
  832:       if (hw_len != 0)
  833: 	memcpy(lease->hwaddr, hwaddr, hw_len);
  834:       lease->hwaddr_len = hw_len;
  835:       lease->hwaddr_type = hw_type;
  836:       lease->flags |= LEASE_CHANGED;
  837:       file_dirty = 1; /* run script on change */
  838:     }
  839: 
  840:   /* only update clid when one is available, stops packets
  841:      without a clid removing the record. Lease init uses
  842:      clid_len == 0 for no clid. */
  843:   if (clid_len != 0 && clid)
  844:     {
  845:       if (!lease->clid)
  846: 	lease->clid_len = 0;
  847: 
  848:       if (lease->clid_len != clid_len)
  849: 	{
  850: 	  lease->flags |= LEASE_AUX_CHANGED;
  851: 	  file_dirty = 1;
  852: 	  free(lease->clid);
  853: 	  if (!(lease->clid = whine_malloc(clid_len)))
  854: 	    return;
  855: #ifdef HAVE_DHCP6
  856: 	  change = 1;
  857: #endif	   
  858: 	}
  859:       else if (memcmp(lease->clid, clid, clid_len) != 0)
  860: 	{
  861: 	  lease->flags |= LEASE_AUX_CHANGED;
  862: 	  file_dirty = 1;
  863: #ifdef HAVE_DHCP6
  864: 	  change = 1;
  865: #endif	
  866: 	}
  867:       
  868:       lease->clid_len = clid_len;
  869:       memcpy(lease->clid, clid, clid_len);
  870:     }
  871:   
  872: #ifdef HAVE_DHCP6
  873:   if (change)
  874:     slaac_add_addrs(lease, now, force);
  875: #endif
  876: }
  877: 
  878: static void kill_name(struct dhcp_lease *lease)
  879: {
  880:   /* run script to say we lost our old name */
  881:   
  882:   /* this shouldn't happen unless updates are very quick and the
  883:      script very slow, we just avoid a memory leak if it does. */
  884:   free(lease->old_hostname);
  885:   
  886:   /* If we know the fqdn, pass that. The helper will derive the
  887:      unqualified name from it, free the unqualified name here. */
  888: 
  889:   if (lease->fqdn)
  890:     {
  891:       lease->old_hostname = lease->fqdn;
  892:       free(lease->hostname);
  893:     }
  894:   else
  895:     lease->old_hostname = lease->hostname;
  896: 
  897:   lease->hostname = lease->fqdn = NULL;
  898: }
  899: 
  900: void lease_set_hostname(struct dhcp_lease *lease, const char *name, int auth, char *domain, char *config_domain)
  901: {
  902:   struct dhcp_lease *lease_tmp;
  903:   char *new_name = NULL, *new_fqdn = NULL;
  904: 
  905:   if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
  906:     my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, name);
  907:   
  908:   if (lease->hostname && name && hostname_isequal(lease->hostname, name))
  909:     {
  910:       if (auth)
  911: 	lease->flags |= LEASE_AUTH_NAME;
  912:       return;
  913:     }
  914:   
  915:   if (!name && !lease->hostname)
  916:     return;
  917: 
  918:   /* If a machine turns up on a new net without dropping the old lease,
  919:      or two machines claim the same name, then we end up with two interfaces with
  920:      the same name. Check for that here and remove the name from the old lease.
  921:      Note that IPv6 leases are different. All the leases to the same DUID are 
  922:      allowed the same name.
  923: 
  924:      Don't allow a name from the client to override a name from dnsmasq config. */
  925:   
  926:   if (name)
  927:     {
  928:       if ((new_name = whine_malloc(strlen(name) + 1)))
  929: 	{
  930: 	  strcpy(new_name, name);
  931: 	  if (domain && (new_fqdn = whine_malloc(strlen(new_name) + strlen(domain) + 2)))
  932: 	    {
  933: 	      strcpy(new_fqdn, name);
  934: 	      strcat(new_fqdn, ".");
  935: 	      strcat(new_fqdn, domain);
  936: 	    }
  937: 	}
  938: 	  
  939:       /* Depending on mode, we check either unqualified name or FQDN. */
  940:       for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
  941: 	{
  942: 	  if (option_bool(OPT_DHCP_FQDN))
  943: 	    {
  944: 	      if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn))
  945: 		continue;
  946: 	    }
  947: 	  else
  948: 	    {
  949: 	      if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
  950: 		continue; 
  951: 	    }
  952: 
  953: 	  if (lease->flags & (LEASE_TA | LEASE_NA))
  954: 	    {
  955: 	      if (!(lease_tmp->flags & (LEASE_TA | LEASE_NA)))
  956: 		continue;
  957: 
  958: 	      /* another lease for the same DUID is OK for IPv6 */
  959: 	      if (lease->clid_len == lease_tmp->clid_len &&
  960: 		  lease->clid && lease_tmp->clid &&
  961: 		  memcmp(lease->clid, lease_tmp->clid, lease->clid_len) == 0)
  962: 		continue;	      
  963: 	    }
  964: 	  else if (lease_tmp->flags & (LEASE_TA | LEASE_NA))
  965: 	    continue;
  966: 		   
  967: 	  if ((lease_tmp->flags & LEASE_AUTH_NAME) && !auth)
  968: 	    {
  969: 	      free(new_name);
  970: 	      free(new_fqdn);
  971: 	      return;
  972: 	    }
  973: 	
  974: 	  kill_name(lease_tmp);
  975: 	  break;
  976: 	}
  977:     }
  978: 
  979:   if (lease->hostname)
  980:     kill_name(lease);
  981: 
  982:   lease->hostname = new_name;
  983:   lease->fqdn = new_fqdn;
  984:   
  985:   if (auth)
  986:     lease->flags |= LEASE_AUTH_NAME;
  987:   
  988:   file_dirty = 1;
  989:   dns_dirty = 1; 
  990:   lease->flags |= LEASE_CHANGED; /* run script on change */
  991: }
  992: 
  993: void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
  994: {
  995:   (void)now;
  996: 
  997:   if (lease->last_interface == interface)
  998:     return;
  999: 
 1000:   lease->last_interface = interface;
 1001:   lease->flags |= LEASE_CHANGED; 
 1002: 
 1003: #ifdef HAVE_DHCP6
 1004:   slaac_add_addrs(lease, now, 0);
 1005: #endif
 1006: }
 1007: 
 1008: void rerun_scripts(void)
 1009: {
 1010:   struct dhcp_lease *lease;
 1011:   
 1012:   for (lease = leases; lease; lease = lease->next)
 1013:     lease->flags |= LEASE_CHANGED; 
 1014: }
 1015: 
 1016: /* deleted leases get transferred to the old_leases list.
 1017:    remove them here, after calling the lease change
 1018:    script. Also run the lease change script on new/modified leases.
 1019: 
 1020:    Return zero if nothing to do. */
 1021: int do_script_run(time_t now)
 1022: {
 1023:   struct dhcp_lease *lease;
 1024: 
 1025:   (void)now;
 1026: 
 1027: #ifdef HAVE_DBUS
 1028:   /* If we're going to be sending DBus signals, but the connection is not yet up,
 1029:      delay everything until it is. */
 1030:   if (option_bool(OPT_DBUS) && !daemon->dbus)
 1031:     return 0;
 1032: #endif
 1033: 
 1034:   if (old_leases)
 1035:     {
 1036:       lease = old_leases;
 1037:                   
 1038:       /* If the lease still has an old_hostname, do the "old" action on that first */
 1039:       if (lease->old_hostname)
 1040: 	{
 1041: #ifdef HAVE_SCRIPT
 1042: 	  queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
 1043: #endif
 1044: 	  free(lease->old_hostname);
 1045: 	  lease->old_hostname = NULL;
 1046: 	  return 1;
 1047: 	}
 1048:       else 
 1049: 	{
 1050: #ifdef HAVE_DHCP6
 1051: 	  struct slaac_address *slaac, *tmp;
 1052: 	  for (slaac = lease->slaac_address; slaac; slaac = tmp)
 1053: 	    {
 1054: 	      tmp = slaac->next;
 1055: 	      free(slaac);
 1056: 	    }
 1057: #endif
 1058: 	  kill_name(lease);
 1059: #ifdef HAVE_SCRIPT
 1060: 	  queue_script(ACTION_DEL, lease, lease->old_hostname, now);
 1061: #endif
 1062: #ifdef HAVE_DBUS
 1063: 	  emit_dbus_signal(ACTION_DEL, lease, lease->old_hostname);
 1064: #endif
 1065: 	  old_leases = lease->next;
 1066: 	  
 1067: 	  free(lease->old_hostname); 
 1068: 	  free(lease->clid);
 1069: 	  free(lease->extradata);
 1070: 	  free(lease);
 1071: 	    
 1072: 	  return 1; 
 1073: 	}
 1074:     }
 1075:   
 1076:   /* make sure we announce the loss of a hostname before its new location. */
 1077:   for (lease = leases; lease; lease = lease->next)
 1078:     if (lease->old_hostname)
 1079:       {	
 1080: #ifdef HAVE_SCRIPT
 1081: 	queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
 1082: #endif
 1083: 	free(lease->old_hostname);
 1084: 	lease->old_hostname = NULL;
 1085: 	return 1;
 1086:       }
 1087:   
 1088:   for (lease = leases; lease; lease = lease->next)
 1089:     if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) || 
 1090: 	((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)))
 1091:       {
 1092: #ifdef HAVE_SCRIPT
 1093: 	queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease, 
 1094: 		     lease->fqdn ? lease->fqdn : lease->hostname, now);
 1095: #endif
 1096: #ifdef HAVE_DBUS
 1097: 	emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
 1098: 			 lease->fqdn ? lease->fqdn : lease->hostname);
 1099: #endif
 1100: 	lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED);
 1101: 	
 1102: 	/* this is used for the "add" call, then junked, since they're not in the database */
 1103: 	free(lease->extradata);
 1104: 	lease->extradata = NULL;
 1105: 	
 1106: 	return 1;
 1107:       }
 1108: 
 1109:   return 0; /* nothing to do */
 1110: }
 1111: 
 1112: #ifdef HAVE_SCRIPT
 1113: /* delim == -1 -> delim = 0, but embeded 0s, creating extra records, are OK. */
 1114: void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
 1115: {
 1116:   unsigned int i;
 1117:   
 1118:   if (delim == -1)
 1119:     delim = 0;
 1120:   else
 1121:     /* check for embeded NULLs */
 1122:     for (i = 0; i < len; i++)
 1123:       if (data[i] == 0)
 1124: 	{
 1125: 	  len = i;
 1126: 	  break;
 1127: 	}
 1128:   
 1129:   if ((lease->extradata_size - lease->extradata_len) < (len + 1))
 1130:     {
 1131:       size_t newsz = lease->extradata_len + len + 100;
 1132:       unsigned char *new = whine_malloc(newsz);
 1133:   
 1134:       if (!new)
 1135: 	return;
 1136:       
 1137:       if (lease->extradata)
 1138: 	{
 1139: 	  memcpy(new, lease->extradata, lease->extradata_len);
 1140: 	  free(lease->extradata);
 1141: 	}
 1142: 
 1143:       lease->extradata = new;
 1144:       lease->extradata_size = newsz;
 1145:     }
 1146: 
 1147:   if (len != 0)
 1148:     memcpy(lease->extradata + lease->extradata_len, data, len);
 1149:   lease->extradata[lease->extradata_len + len] = delim;
 1150:   lease->extradata_len += len + 1; 
 1151: }
 1152: #endif
 1153: 
 1154: #endif
 1155: 	  
 1156: 
 1157:       
 1158: 

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