Diff for /embedaddon/dnsmasq/src/lease.c between versions 1.1.1.3 and 1.1.1.4

version 1.1.1.3, 2016/11/02 09:57:01 version 1.1.1.4, 2021/03/17 00:56:46
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
   
    This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
Line 21 Line 21
 static struct dhcp_lease *leases = NULL, *old_leases = NULL;  static struct dhcp_lease *leases = NULL, *old_leases = NULL;
 static int dns_dirty, file_dirty, leases_left;  static int dns_dirty, file_dirty, leases_left;
   
void lease_init(time_t now)static int read_leases(time_t now, FILE *leasestream)
 {  {
   unsigned long ei;    unsigned long ei;
  struct all_addr addr;  union all_addr addr;
   struct dhcp_lease *lease;    struct dhcp_lease *lease;
   int clid_len, hw_len, hw_type;    int clid_len, hw_len, hw_type;
  FILE *leasestream;  int items;
    char *domain = NULL;
  leases_left = daemon->dhcp_max;
    *daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0';
  if (option_bool(OPT_LEASE_RO))
    {  /* client-id max length is 255 which is 255*2 digits + 254 colons
      /* run "<lease_change_script> init" once to get the     borrow DNS packet buffer which is always larger than 1000 bytes
         initial state of the database. If leasefile-ro is
         set without a script, we just do without any      Check various buffers are big enough for the code below */
         lease database. */
#ifdef HAVE_SCRIPT#if (DHCP_BUFF_SZ < 255) || (MAXDNAME < 64) || (PACKETSZ+MAXDNAME+RRFIXEDSZ  < 764)
      if (daemon->lease_change_command)# error Buffer size breakage in leasefile parsing.
        { 
          strcpy(daemon->dhcp_buff, daemon->lease_change_command); 
          strcat(daemon->dhcp_buff, " init"); 
          leasestream = popen(daemon->dhcp_buff, "r"); 
        } 
      else 
 #endif  #endif
         {  
           file_dirty = dns_dirty = 0;  
           return;  
         }  
   
    }    while ((items=fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2)) == 2)
  else 
    { 
      /* NOTE: need a+ mode to create file if it doesn't exist */ 
      leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+"); 
       
      if (!leasestream) 
        die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE); 
       
      /* a+ mode leaves pointer at end. */ 
      rewind(leasestream); 
    } 
   
  /* client-id max length is 255 which is 255*2 digits + 254 colons  
     borrow DNS packet buffer which is always larger than 1000 bytes */ 
  if (leasestream) 
    while (fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2) == 2) 
       {        {
           *daemon->namebuff = *daemon->dhcp_buff = *daemon->packet = '\0';
           hw_len = hw_type = clid_len = 0;
           
 #ifdef HAVE_DHCP6  #ifdef HAVE_DHCP6
         if (strcmp(daemon->dhcp_buff3, "duid") == 0)          if (strcmp(daemon->dhcp_buff3, "duid") == 0)
           {            {
             daemon->duid_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, 130, NULL, NULL);              daemon->duid_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, 130, NULL, NULL);
               if (daemon->duid_len < 0)
                 return 0;
             daemon->duid = safe_malloc(daemon->duid_len);              daemon->duid = safe_malloc(daemon->duid_len);
             memcpy(daemon->duid, daemon->dhcp_buff2, daemon->duid_len);              memcpy(daemon->duid, daemon->dhcp_buff2, daemon->duid_len);
             continue;              continue;
           }            }
 #endif  #endif
   
         ei = atol(daemon->dhcp_buff3);  
                   
         if (fscanf(leasestream, " %64s %255s %764s",          if (fscanf(leasestream, " %64s %255s %764s",
                    daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3)                     daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3)
           break;  
           
         clid_len = 0;  
         if (strcmp(daemon->packet, "*") != 0)  
           clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);  
           
         if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4) &&  
             (lease = lease4_allocate(addr.addr.addr4)))  
           {            {
               my_syslog(MS_DHCP | LOG_WARNING, _("ignoring invalid line in lease database: %s %s %s %s ..."),
                         daemon->dhcp_buff3, daemon->dhcp_buff2,
                         daemon->namebuff, daemon->dhcp_buff);
               continue;
             }
                   
           if (inet_pton(AF_INET, daemon->namebuff, &addr.addr4))
             {
               if ((lease = lease4_allocate(addr.addr4)))
                 domain = get_domain(lease->addr);
               
             hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);              hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
            /* For backwards compatibility, no explict MAC address type means ether. */            /* For backwards compatibility, no explicit MAC address type means ether. */
             if (hw_type == 0 && hw_len != 0)              if (hw_type == 0 && hw_len != 0)
               hw_type = ARPHRD_ETHER;                 hw_type = ARPHRD_ETHER; 
   
             lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet,   
                              hw_len, hw_type, clid_len, now, 0);  
               
             if (strcmp(daemon->dhcp_buff, "*") !=  0)  
               lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr), NULL);  
           }            }
 #ifdef HAVE_DHCP6  #ifdef HAVE_DHCP6
        else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6))        else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr6))
           {            {
             char *s = daemon->dhcp_buff2;              char *s = daemon->dhcp_buff2;
             int lease_type = LEASE_NA;              int lease_type = LEASE_NA;
             int iaid;  
   
             if (s[0] == 'T')              if (s[0] == 'T')
               {                {
Line 116  void lease_init(time_t now) Line 89  void lease_init(time_t now)
                 s++;                  s++;
               }                }
                           
            iaid = strtoul(s, NULL, 10);            if ((lease = lease6_allocate(&addr.addr6, lease_type)))
             
            if ((lease = lease6_allocate(&addr.addr.addr6, lease_type))) 
               {                {
                lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, 0, clid_len, now, 0);                lease_set_iaid(lease, strtoul(s, NULL, 10));
                lease_set_iaid(lease, iaid);                domain = get_domain6(&lease->addr6);
                if (strcmp(daemon->dhcp_buff, "*") !=  0) 
                  lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL); 
               }                }
           }            }
 #endif  #endif
         else          else
          break;          {
             my_syslog(MS_DHCP | LOG_WARNING, _("ignoring invalid line in lease database, bad address: %s"),
                       daemon->namebuff);
             continue;
           }
         
   
         if (!lease)          if (!lease)
           die (_("too many stored leases"), NULL, EC_MISC);            die (_("too many stored leases"), NULL, EC_MISC);
        
         if (strcmp(daemon->packet, "*") != 0)
           clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
         
         lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, 
                          hw_len, hw_type, clid_len, now, 0);
         
         if (strcmp(daemon->dhcp_buff, "*") !=  0)
           lease_set_hostname(lease, daemon->dhcp_buff, 0, domain, NULL);
 
         ei = atol(daemon->dhcp_buff3);
 
 #ifdef HAVE_BROKEN_RTC  #ifdef HAVE_BROKEN_RTC
         if (ei != 0)          if (ei != 0)
           lease->expires = (time_t)ei + now;            lease->expires = (time_t)ei + now;
Line 148  void lease_init(time_t now) Line 133  void lease_init(time_t now)
         /* set these correctly: the "old" events are generated later from          /* set these correctly: the "old" events are generated later from
            the startup synthesised SIGHUP. */             the startup synthesised SIGHUP. */
         lease->flags &= ~(LEASE_NEW | LEASE_CHANGED);          lease->flags &= ~(LEASE_NEW | LEASE_CHANGED);
           
           *daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0';
       }        }
       
       return (items == 0 || items == EOF);
   }
   
   void lease_init(time_t now)
   {
     FILE *leasestream;
   
     leases_left = daemon->dhcp_max;
   
     if (option_bool(OPT_LEASE_RO))
       {
         /* run "<lease_change_script> init" once to get the
            initial state of the database. If leasefile-ro is
            set without a script, we just do without any
            lease database. */
   #ifdef HAVE_SCRIPT
         if (daemon->lease_change_command)
           {
             strcpy(daemon->dhcp_buff, daemon->lease_change_command);
             strcat(daemon->dhcp_buff, " init");
             leasestream = popen(daemon->dhcp_buff, "r");
           }
         else
   #endif
           {
             file_dirty = dns_dirty = 0;
             return;
           }
   
       }
     else
       {
         /* NOTE: need a+ mode to create file if it doesn't exist */
         leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+");
   
         if (!leasestream)
           die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE);
   
         /* a+ mode leaves pointer at end. */
         rewind(leasestream);
       }
   
     if (leasestream)
       {
         if (!read_leases(now, leasestream))
           my_syslog(MS_DHCP | LOG_ERR, _("failed to parse lease database cleanly"));
         
         if (ferror(leasestream))
           die(_("failed to read lease file %s: %s"), daemon->lease_file, EC_FILE);
       }
       
 #ifdef HAVE_SCRIPT  #ifdef HAVE_SCRIPT
   if (!daemon->lease_stream)    if (!daemon->lease_stream)
Line 162  void lease_init(time_t now) Line 200  void lease_init(time_t now)
             errno = ENOENT;              errno = ENOENT;
           else if (WEXITSTATUS(rc) == 126)            else if (WEXITSTATUS(rc) == 126)
             errno = EACCES;              errno = EACCES;
   
           die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command, EC_FILE);            die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command, EC_FILE);
         }          }
               
Line 191  void lease_update_from_configs(void) Line 230  void lease_update_from_configs(void)
     if (lease->flags & (LEASE_TA | LEASE_NA))      if (lease->flags & (LEASE_TA | LEASE_NA))
       continue;        continue;
     else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,       else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len, 
                                   lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&                                    lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL, NULL)) && 
              (config->flags & CONFIG_NAME) &&               (config->flags & CONFIG_NAME) &&
              (!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))               (!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
       lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);        lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
     else if ((name = host_from_dns(lease->addr)))      else if ((name = host_from_dns(lease->addr)))
       lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */        lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */
 }  }
 
 static void ourprintf(int *errp, char *format, ...)  static void ourprintf(int *errp, char *format, ...)
 {  {
   va_list ap;    va_list ap;
Line 406  void lease_ping_reply(struct in6_addr *sender, unsigne Line 445  void lease_ping_reply(struct in6_addr *sender, unsigne
   
 void lease_update_slaac(time_t now)  void lease_update_slaac(time_t now)
 {  {
  /* Called when we contruct a new RA-names context, to add putative  /* Called when we construct a new RA-names context, to add putative
      new SLAAC addresses to existing leases. */       new SLAAC addresses to existing leases. */
   
   struct dhcp_lease *lease;    struct dhcp_lease *lease;
Line 483  void lease_update_dns(int force) Line 522  void lease_update_dns(int force)
                 if (slaac->backoff == 0)                  if (slaac->backoff == 0)
                   {                    {
                     if (lease->fqdn)                      if (lease->fqdn)
                      cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);                      cache_add_dhcp_entry(lease->fqdn, AF_INET6, (union all_addr *)&slaac->addr, lease->expires);
                     if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)                      if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
                      cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);                      cache_add_dhcp_entry(lease->hostname, AF_INET6, (union all_addr *)&slaac->addr, lease->expires);
                   }                    }
             }              }
                       
           if (lease->fqdn)            if (lease->fqdn)
             cache_add_dhcp_entry(lease->fqdn, prot,               cache_add_dhcp_entry(lease->fqdn, prot, 
                                 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,                                 prot == AF_INET ? (union all_addr *)&lease->addr : (union all_addr *)&lease->addr6,
                                  lease->expires);                                   lease->expires);
                             
           if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)            if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
             cache_add_dhcp_entry(lease->hostname, prot,               cache_add_dhcp_entry(lease->hostname, prot, 
                                 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,                                  prot == AF_INET ? (union all_addr *)&lease->addr : (union all_addr *)&lease->addr6, 
                                  lease->expires);                                   lease->expires);
                 
 #else  #else
           if (lease->fqdn)            if (lease->fqdn)
            cache_add_dhcp_entry(lease->fqdn, prot, (struct all_addr *)&lease->addr, lease->expires);            cache_add_dhcp_entry(lease->fqdn, prot, (union all_addr *)&lease->addr, lease->expires);
                       
           if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)            if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
            cache_add_dhcp_entry(lease->hostname, prot, (struct all_addr *)&lease->addr, lease->expires);            cache_add_dhcp_entry(lease->hostname, prot, (union all_addr *)&lease->addr, lease->expires);
 #endif  #endif
         }          }
               
Line 519  void lease_prune(struct dhcp_lease *target, time_t now Line 558  void lease_prune(struct dhcp_lease *target, time_t now
   for (lease = leases, up = &leases; lease; lease = tmp)    for (lease = leases, up = &leases; lease; lease = tmp)
     {      {
       tmp = lease->next;        tmp = lease->next;
      if ((lease->expires != 0 && difftime(now, lease->expires) > 0) || lease == target)      if ((lease->expires != 0 && difftime(now, lease->expires) >= 0) || lease == target)
         {          {
           file_dirty = 1;            file_dirty = 1;
           if (lease->hostname)            if (lease->hostname)
             dns_dirty = 1;              dns_dirty = 1;
          
           daemon->metrics[lease->addr.s_addr ? METRIC_LEASES_PRUNED_4 : METRIC_LEASES_PRUNED_6]++;
 
           *up = lease->next; /* unlink */            *up = lease->next; /* unlink */
                       
           /* Put on old_leases list 'till we            /* Put on old_leases list 'till we
Line 594  struct dhcp_lease *lease_find_by_addr(struct in_addr a Line 635  struct dhcp_lease *lease_find_by_addr(struct in_addr a
 #ifdef HAVE_DHCP6  #ifdef HAVE_DHCP6
 /* find address for {CLID, IAID, address} */  /* find address for {CLID, IAID, address} */
 struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,   struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len, 
                               int lease_type, int iaid, struct in6_addr *addr)                               int lease_type, unsigned int iaid,
                                struct in6_addr *addr)
 {  {
   struct dhcp_lease *lease;    struct dhcp_lease *lease;
       
Line 626  void lease6_reset(void) Line 668  void lease6_reset(void)
 }  }
   
 /* enumerate all leases belonging to {CLID, IAID} */  /* enumerate all leases belonging to {CLID, IAID} */
struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid)struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type,
                                          unsigned char *clid, int clid_len,
                                          unsigned int iaid)
 {  {
   struct dhcp_lease *lease;    struct dhcp_lease *lease;
   
Line 742  struct dhcp_lease *lease4_allocate(struct in_addr addr Line 786  struct dhcp_lease *lease4_allocate(struct in_addr addr
 {  {
   struct dhcp_lease *lease = lease_allocate();    struct dhcp_lease *lease = lease_allocate();
   if (lease)    if (lease)
    lease->addr = addr;    {
       lease->addr = addr;
       daemon->metrics[METRIC_LEASES_ALLOCATED_4]++;
     }
       
   return lease;    return lease;
 }  }
Line 757  struct dhcp_lease *lease6_allocate(struct in6_addr *ad Line 804  struct dhcp_lease *lease6_allocate(struct in6_addr *ad
       lease->addr6 = *addrp;        lease->addr6 = *addrp;
       lease->flags |= lease_type;        lease->flags |= lease_type;
       lease->iaid = 0;        lease->iaid = 0;
   
         daemon->metrics[METRIC_LEASES_ALLOCATED_6]++;
     }      }
   
   return lease;    return lease;
Line 776  void lease_set_expires(struct dhcp_lease *lease, unsig Line 825  void lease_set_expires(struct dhcp_lease *lease, unsig
     {      {
       exp = now + (time_t)len;        exp = now + (time_t)len;
       /* Check for 2038 overflow. Make the lease        /* Check for 2038 overflow. Make the lease
         inifinite in that case, as the least disruptive         infinite in that case, as the least disruptive
          thing we can do. */           thing we can do. */
       if (difftime(exp, now) <= 0.0)        if (difftime(exp, now) <= 0.0)
         exp = 0;          exp = 0;
Line 787  void lease_set_expires(struct dhcp_lease *lease, unsig Line 836  void lease_set_expires(struct dhcp_lease *lease, unsig
       dns_dirty = 1;        dns_dirty = 1;
       lease->expires = exp;        lease->expires = exp;
 #ifndef HAVE_BROKEN_RTC  #ifndef HAVE_BROKEN_RTC
      lease->flags |= LEASE_AUX_CHANGED;      lease->flags |= LEASE_AUX_CHANGED | LEASE_EXP_CHANGED;
       file_dirty = 1;        file_dirty = 1;
 #endif  #endif
     }      }
Line 803  void lease_set_expires(struct dhcp_lease *lease, unsig Line 852  void lease_set_expires(struct dhcp_lease *lease, unsig
 }   } 
   
 #ifdef HAVE_DHCP6  #ifdef HAVE_DHCP6
void lease_set_iaid(struct dhcp_lease *lease, int iaid)void lease_set_iaid(struct dhcp_lease *lease, unsigned int iaid)
 {  {
   if (lease->iaid != iaid)    if (lease->iaid != iaid)
     {      {
Line 1087  int do_script_run(time_t now) Line 1136  int do_script_run(time_t now)
       
   for (lease = leases; lease; lease = lease->next)    for (lease = leases; lease; lease = lease->next)
     if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) ||       if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) || 
        ((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)))        ((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)) ||
         ((lease->flags & LEASE_EXP_CHANGED) && option_bool(OPT_LEASE_RENEW)))
       {        {
 #ifdef HAVE_SCRIPT  #ifdef HAVE_SCRIPT
         queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,           queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease, 
Line 1097  int do_script_run(time_t now) Line 1147  int do_script_run(time_t now)
         emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,          emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
                          lease->fqdn ? lease->fqdn : lease->hostname);                           lease->fqdn ? lease->fqdn : lease->hostname);
 #endif  #endif
        lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED);        lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED | LEASE_EXP_CHANGED);
                   
         /* this is used for the "add" call, then junked, since they're not in the database */          /* this is used for the "add" call, then junked, since they're not in the database */
         free(lease->extradata);          free(lease->extradata);
Line 1110  int do_script_run(time_t now) Line 1160  int do_script_run(time_t now)
 }  }
   
 #ifdef HAVE_SCRIPT  #ifdef HAVE_SCRIPT
/* delim == -1 -> delim = 0, but embeded 0s, creating extra records, are OK. *//* delim == -1 -> delim = 0, but embedded 0s, creating extra records, are OK. */
 void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)  void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
 {  {
   unsigned int i;    unsigned int i;
Line 1118  void lease_add_extradata(struct dhcp_lease *lease, uns Line 1168  void lease_add_extradata(struct dhcp_lease *lease, uns
   if (delim == -1)    if (delim == -1)
     delim = 0;      delim = 0;
   else    else
    /* check for embeded NULLs */    /* check for embedded NULLs */
     for (i = 0; i < len; i++)      for (i = 0; i < len; i++)
       if (data[i] == 0)        if (data[i] == 0)
         {          {

Removed from v.1.1.1.3  
changed lines
  Added in v.1.1.1.4


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