Annotation of embedaddon/dnsmasq/src/lease.c, revision 1.1.1.3

1.1.1.3 ! misho       1: /* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
1.1       misho       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;
1.1.1.2   misho     111:            int iaid;
1.1       misho     112: 
                    113:            if (s[0] == 'T')
                    114:              {
                    115:                lease_type = LEASE_TA;
                    116:                s++;
                    117:              }
                    118:            
1.1.1.2   misho     119:            iaid = strtoul(s, NULL, 10);
1.1       misho     120:            
                    121:            if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
                    122:              {
1.1.1.2   misho     123:                lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, 0, clid_len, now, 0);
                    124:                lease_set_iaid(lease, iaid);
1.1       misho     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)
1.1.1.2   misho     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))
1.1       misho     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:     
1.1.1.2   misho     283:              inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
1.1       misho     284:         
                    285:              ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "",
1.1.1.2   misho     286:                        lease->iaid, daemon->addrbuff);
1.1       misho     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:   
1.1.1.2   misho     309:   /* Set alarm for when the first lease expires. */
1.1       misho     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 &&
1.1.1.2   misho     334:        (next_event == 0 || difftime(next_event, lease->expires) > 0.0))
                    335:       next_event = lease->expires;
1.1       misho     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: 
1.1.1.2   misho     351: static int find_interface_v4(struct in_addr local, int if_index, char *label,
1.1       misho     352:                             struct in_addr netmask, struct in_addr broadcast, void *vparam)
                    353: {
                    354:   struct dhcp_lease *lease;
1.1.1.3 ! misho     355:   int prefix = netmask_length(netmask);
        !           356: 
1.1.1.2   misho     357:   (void) label;
1.1       misho     358:   (void) broadcast;
                    359:   (void) vparam;
                    360: 
                    361:   for (lease = leases; lease; lease = lease->next)
1.1.1.3 ! misho     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: 
1.1       misho     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;
1.1.1.3 ! misho     379: 
1.1       misho     380:   (void)scope;
                    381:   (void)flags;
                    382:   (void)preferred;
                    383:   (void)valid;
1.1.1.3 ! misho     384:   (void)vparam;
1.1       misho     385: 
                    386:   for (lease = leases; lease; lease = lease->next)
                    387:     if ((lease->flags & (LEASE_TA | LEASE_NA)))
1.1.1.3 ! misho     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: 
1.1       misho     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: {
1.1.1.3 ! misho     428:   struct dhcp_lease *lease;
        !           429:   
        !           430:   for (lease = leases; lease; lease = lease->next)
        !           431:     lease->new_prefixlen = lease->new_interface = 0;
        !           432: 
1.1       misho     433:   iface_enumerate(AF_INET, &now, find_interface_v4);
                    434: #ifdef HAVE_DHCP6
                    435:   iface_enumerate(AF_INET6, &now, find_interface_v6);
1.1.1.2   misho     436: #endif
1.1.1.3 ! misho     437: 
        !           438:   for (lease = leases; lease; lease = lease->next)
        !           439:     if (lease->new_interface != 0) 
        !           440:       lease_set_interface(lease, lease->new_interface, now);
1.1.1.2   misho     441: }
1.1       misho     442: 
1.1.1.2   misho     443: #ifdef HAVE_DHCP6
                    444: void lease_make_duid(time_t now)
                    445: {
1.1       misho     446:   /* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
1.1.1.2   misho     447:   if (!daemon->duid && daemon->doing_dhcp6)
1.1       misho     448:     {
                    449:       file_dirty = 1;
                    450:       make_duid(now);
                    451:     }
                    452: }
1.1.1.2   misho     453: #endif
                    454: 
1.1       misho     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, 
1.1.1.2   misho     494:                                 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
1.1       misho     495:                                 lease->expires);
                    496:             
                    497:          if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
                    498:            cache_add_dhcp_entry(lease->hostname, prot, 
1.1.1.2   misho     499:                                 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6, 
1.1       misho     500:                                 lease->expires);
1.1.1.2   misho     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
1.1       misho     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:     {
1.1.1.2   misho     603:       if (!(lease->flags & lease_type) || lease->iaid != iaid)
1.1       misho     604:        continue;
                    605: 
1.1.1.2   misho     606:       if (!IN6_ARE_ADDR_EQUAL(&lease->addr6, addr))
1.1       misho     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: 
1.1.1.2   misho     643:       if (!(lease->flags & lease_type) || lease->iaid != iaid)
1.1       misho     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:       
1.1.1.2   misho     665:       if (is_same_net6(&lease->addr6, net, prefix) &&
                    666:          (prefix == 128 || addr6part(&lease->addr6) == addr))
1.1       misho     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: 
1.1.1.2   misho     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);
1.1       misho     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
1.1.1.2   misho     731:   lease->hwaddr_len = 256; /* illegal value */
1.1       misho     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)
1.1.1.2   misho     745:     lease->addr = addr;
                    746:   
1.1       misho     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:     {
1.1.1.2   misho     757:       lease->addr6 = *addrp;
1.1       misho     758:       lease->flags |= lease_type;
1.1.1.2   misho     759:       lease->iaid = 0;
1.1       misho     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: {
1.1.1.2   misho     768:   time_t exp;
                    769: 
1.1       misho     770:   if (len == 0xffffffff)
                    771:     {
                    772:       exp = 0;
                    773:       len = 0;
                    774:     }
1.1.1.2   misho     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: 
1.1       misho     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: 
1.1.1.2   misho     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: 
1.1.1.3 ! misho     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)
1.1       misho     819: {
                    820: #ifdef HAVE_DHCP6
                    821:   int change = force;
                    822:   lease->flags |= LEASE_HAVE_HWADDR;
                    823: #endif
                    824: 
                    825:   (void)force;
1.1.1.2   misho     826:   (void)now;
1.1       misho     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: 
1.1.1.3 ! misho     900: void lease_set_hostname(struct dhcp_lease *lease, const char *name, int auth, char *domain, char *config_domain)
1.1       misho     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: {
1.1.1.2   misho     995:   (void)now;
                    996: 
1.1       misho     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: 
1.1.1.2   misho    1025:   (void)now;
                   1026: 
1.1       misho    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
1.1.1.3 ! misho    1113: /* delim == -1 -> delim = 0, but embeded 0s, creating extra records, are OK. */
1.1       misho    1114: void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
                   1115: {
                   1116:   unsigned int i;
                   1117:   
1.1.1.3 ! misho    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:   
1.1       misho    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>