static void process_lease(struct crec **empty_cache, char *host_name, struct in_addr host_address, time_t ttd, int flags) { struct crec *crec; if ((crec = cache_find_by_name(NULL, host_name, 0, F_IPV4))) { if (crec->flags & F_HOSTS) syslog(LOG_WARNING, "Ignoring DHCP lease for %s because it clashes with an /etc/hosts entry.", cache_get_name(crec)); else if (!(crec->flags & F_DHCP)) { if (crec->flags & F_NEG) { /* name may have been searched for before being allocated to DHCP and therefore got a negative cache entry. If so delete it and continue. */ crec->flags &= ~F_FORWARD; goto newrec; } else syslog(LOG_WARNING, "Ignoring DHCP lease for %s because it clashes with a cached name.", cache_get_name(crec)); } else if (ttd > crec->ttd || ttd == (time_t)-1) { /* simply a later entry in the leases file which supercedes and earlier one. */ memcpy(&crec->addr, &host_address, INADDRSZ); if (ttd == (time_t)-1) crec->flags |= F_IMMORTAL; else crec->ttd = ttd; } } else { /* can't find it in cache. */ newrec: crec = *empty_cache; if ((strlen (host_name) < SMALLDNAME-1) && crec) /* old entries to reuse (will not fit large names) */ *empty_cache =(*empty_cache)->next; else /* need new one */ { if ((strlen(host_name) < SMALLDNAME-1)) crec = safe_malloc(sizeof(struct crec)); else crec = safe_malloc(sizeof(struct crec) + strlen(host_name)+1-SMALLDNAME); } if (crec) /* malloc may fail */ { crec->flags = F_DHCP | F_FORWARD | F_IPV4 | flags; if (ttd == (time_t)-1) crec->flags |= F_IMMORTAL; else crec->ttd = ttd; memcpy(&crec->addr, &host_address, INADDRSZ); strcpy(cache_get_name(crec), host_name); cache_link(crec); } } }
void dhcp_update_configs(struct dhcp_config *configs) { /* Some people like to keep all static IP addresses in /etc/hosts. This goes through /etc/hosts and sets static addresses for any DHCP config records which don't have an address and whose name matches. We take care to maintain the invariant that any IP address can appear in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP, restore the status-quo ante first. */ struct dhcp_config *config, *conf_tmp; struct crec *crec; int prot = AF_INET; for (config = configs; config; config = config->next) if (config->flags & CONFIG_ADDR_HOSTS) config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR6 | CONFIG_ADDR_HOSTS); #ifdef HAVE_DHCP6 again: #endif if (daemon->port != 0) for (config = configs; config; config = config->next) { int conflags = CONFIG_ADDR; int cacheflags = F_IPV4; #ifdef HAVE_DHCP6 if (prot == AF_INET6) { conflags = CONFIG_ADDR6; cacheflags = F_IPV6; } #endif if (!(config->flags & conflags) && (config->flags & CONFIG_NAME) && (crec = cache_find_by_name(NULL, config->hostname, 0, cacheflags)) && (crec->flags & F_HOSTS)) { if (cache_find_by_name(crec, config->hostname, 0, cacheflags)) { /* use primary (first) address */ while (crec && !(crec->flags & F_REVERSE)) crec = cache_find_by_name(crec, config->hostname, 0, cacheflags); if (!crec) continue; /* should be never */ inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN); my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"), config->hostname, daemon->addrbuff); } if (prot == AF_INET && (!(conf_tmp = config_find_by_address(configs, crec->addr.addr.addr.addr4)) || conf_tmp == config)) { config->addr = crec->addr.addr.addr.addr4; config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS; continue; } #ifdef HAVE_DHCP6 if (prot == AF_INET6 && (!(conf_tmp = config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0)) || conf_tmp == config)) { memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ); config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS; continue; } #endif inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN); my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"), daemon->addrbuff, config->hostname); } } #ifdef HAVE_DHCP6 if (prot == AF_INET) { prot = AF_INET6; goto again; } #endif }