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

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

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