"Fossies" - the Fresh Open Source Software Archive

Member "dnsmasq-2.85/src/lease.c" (7 Apr 2021, 31152 Bytes) of package /linux/misc/dns/dnsmasq-2.85.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "lease.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.84_vs_2.85.

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