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

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

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