Annotation of embedaddon/dnsmasq/src/lease.c, revision 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>