Home | History | Annotate | Download | only in src
      1 /* dnsmasq is Copyright (c) 2000-2009 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 struct iface_param {
     22     struct in_addr relay, primary;
     23     struct dhcp_context* current;
     24     int ind;
     25 };
     26 
     27 static int complete_context(struct in_addr local, int if_index, struct in_addr netmask,
     28                             struct in_addr broadcast, void* vparam);
     29 
     30 void dhcp_init(void) {
     31     int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
     32     struct sockaddr_in saddr;
     33     int oneopt = 1;
     34 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
     35     int mtu = IP_PMTUDISC_DONT;
     36 #endif
     37 
     38     if (fd == -1) die(_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
     39 
     40     if (!fix_fd(fd) ||
     41 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
     42         setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
     43 #endif
     44 #if defined(HAVE_LINUX_NETWORK)
     45         setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
     46 #else
     47         setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
     48 #endif
     49         setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
     50         die(_("failed to set options on DHCP socket: %s"), NULL, EC_BADNET);
     51 
     52     /* When bind-interfaces is set, there might be more than one dnmsasq
     53        instance binding port 67. That's OK if they serve different networks.
     54        Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
     55     if (daemon->options & OPT_NOWILD) {
     56 #ifdef SO_REUSEPORT
     57         int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
     58 #else
     59         int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
     60 #endif
     61         if (rc == -1)
     62             die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
     63     }
     64 
     65     memset(&saddr, 0, sizeof(saddr));
     66     saddr.sin_family = AF_INET;
     67     saddr.sin_port = htons(daemon->dhcp_server_port);
     68     saddr.sin_addr.s_addr = INADDR_ANY;
     69 
     70     if (bind(fd, (struct sockaddr*) &saddr, sizeof(struct sockaddr_in)))
     71         die(_("failed to bind DHCP server socket: %s"), NULL, EC_BADNET);
     72 
     73 #ifdef __ANDROID__
     74     if (setsockopt(fd, SOL_SOCKET, SO_MARK, &daemon->listen_mark, sizeof(daemon->listen_mark)) == -1)
     75         die(_("failed to set DHCP socket mark: %s"), NULL, EC_BADNET);
     76 #endif /* __ANDROID__ */
     77 
     78     daemon->dhcpfd = fd;
     79 
     80     check_dhcp_hosts(1);
     81 
     82     daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet);
     83     daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
     84 }
     85 
     86 void dhcp_packet(time_t now) {
     87     struct dhcp_packet* mess;
     88     struct dhcp_context* context;
     89     struct iname* tmp;
     90     struct ifreq ifr;
     91     struct msghdr msg;
     92     struct sockaddr_in dest;
     93     struct cmsghdr* cmptr;
     94     struct iovec iov;
     95     ssize_t sz;
     96     int iface_index = 0, unicast_dest = 0, is_inform = 0;
     97     struct in_addr iface_addr, *addrp = NULL;
     98     struct iface_param parm;
     99 
    100     union {
    101         struct cmsghdr align; /* this ensures alignment */
    102 #if defined(HAVE_LINUX_NETWORK)
    103         char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
    104 #endif
    105     } control_u;
    106 
    107     msg.msg_control = NULL;
    108     msg.msg_controllen = 0;
    109     msg.msg_name = NULL;
    110     msg.msg_namelen = 0;
    111     msg.msg_iov = &daemon->dhcp_packet;
    112     msg.msg_iovlen = 1;
    113 
    114     while (1) {
    115         msg.msg_flags = 0;
    116         while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR)
    117             ;
    118 
    119         if (sz == -1) return;
    120 
    121         if (!(msg.msg_flags & MSG_TRUNC)) break;
    122 
    123         /* Very new Linux kernels return the actual size needed,
    124        older ones always return truncated size */
    125         if ((size_t) sz == daemon->dhcp_packet.iov_len) {
    126             if (!expand_buf(&daemon->dhcp_packet, sz + 100)) return;
    127         } else {
    128             expand_buf(&daemon->dhcp_packet, sz);
    129             break;
    130         }
    131     }
    132 
    133     /* expand_buf may have moved buffer */
    134     mess = (struct dhcp_packet*) daemon->dhcp_packet.iov_base;
    135     msg.msg_controllen = sizeof(control_u);
    136     msg.msg_control = control_u.control;
    137     msg.msg_flags = 0;
    138     msg.msg_name = &dest;
    139     msg.msg_namelen = sizeof(dest);
    140 
    141     while ((sz = recvmsg(daemon->dhcpfd, &msg, 0)) == -1 && errno == EINTR)
    142         ;
    143 
    144     if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
    145         return;
    146 
    147 #if defined(HAVE_LINUX_NETWORK)
    148     if (msg.msg_controllen >= sizeof(struct cmsghdr))
    149         for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
    150             if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO) {
    151                 iface_index = ((struct in_pktinfo*) CMSG_DATA(cmptr))->ipi_ifindex;
    152                 if (((struct in_pktinfo*) CMSG_DATA(cmptr))->ipi_addr.s_addr != INADDR_BROADCAST)
    153                     unicast_dest = 1;
    154             }
    155 #endif
    156 
    157     if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name)) return;
    158 
    159 #ifdef MSG_BCAST
    160     /* OpenBSD tells us when a packet was broadcast */
    161     if (!(msg.msg_flags & MSG_BCAST)) unicast_dest = 1;
    162 #endif
    163 
    164     ifr.ifr_addr.sa_family = AF_INET;
    165     if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1) {
    166         addrp = &iface_addr;
    167         iface_addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr;
    168     }
    169 
    170     if (!iface_check(AF_INET, (struct all_addr*) addrp, ifr.ifr_name, &iface_index)) return;
    171 
    172     for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
    173         if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0)) return;
    174 
    175     /* interface may have been changed by alias in iface_check */
    176     if (!addrp) {
    177         if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1) {
    178             my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"),
    179                       ifr.ifr_name);
    180             return;
    181         } else
    182             iface_addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr;
    183     }
    184 
    185     /* unlinked contexts are marked by context->current == context */
    186     for (context = daemon->dhcp; context; context = context->next) context->current = context;
    187 
    188     parm.relay = mess->giaddr;
    189     parm.primary = iface_addr;
    190     parm.current = NULL;
    191     parm.ind = iface_index;
    192 
    193     if (!iface_enumerate(&parm, complete_context, NULL)) return;
    194     lease_prune(NULL, now); /* lose any expired leases */
    195     iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t) sz, now,
    196                              unicast_dest, &is_inform);
    197     lease_update_file(now);
    198     lease_update_dns();
    199 
    200     if (iov.iov_len == 0) return;
    201 
    202     msg.msg_name = &dest;
    203     msg.msg_namelen = sizeof(dest);
    204     msg.msg_control = NULL;
    205     msg.msg_controllen = 0;
    206     msg.msg_iov = &iov;
    207     iov.iov_base = daemon->dhcp_packet.iov_base;
    208 
    209     /* packet buffer may have moved */
    210     mess = (struct dhcp_packet*) daemon->dhcp_packet.iov_base;
    211 
    212     if (mess->giaddr.s_addr) {
    213         /* Send to BOOTP relay  */
    214         dest.sin_port = htons(daemon->dhcp_server_port);
    215         dest.sin_addr = mess->giaddr;
    216     } else if (mess->ciaddr.s_addr) {
    217         /* If the client's idea of its own address tallys with
    218        the source address in the request packet, we believe the
    219        source port too, and send back to that.  If we're replying
    220        to a DHCPINFORM, trust the source address always. */
    221         if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) || dest.sin_port == 0 ||
    222             dest.sin_addr.s_addr == 0) {
    223             dest.sin_port = htons(daemon->dhcp_client_port);
    224             dest.sin_addr = mess->ciaddr;
    225         }
    226     }
    227 #if defined(HAVE_LINUX_NETWORK)
    228     else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
    229              mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0) {
    230         /* broadcast to 255.255.255.255 (or mac address invalid) */
    231         struct in_pktinfo* pkt;
    232         msg.msg_control = control_u.control;
    233         msg.msg_controllen = sizeof(control_u);
    234         cmptr = CMSG_FIRSTHDR(&msg);
    235         pkt = (struct in_pktinfo*) CMSG_DATA(cmptr);
    236         pkt->ipi_ifindex = iface_index;
    237         pkt->ipi_spec_dst.s_addr = 0;
    238         msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
    239         cmptr->cmsg_level = SOL_IP;
    240         cmptr->cmsg_type = IP_PKTINFO;
    241         dest.sin_addr.s_addr = INADDR_BROADCAST;
    242         dest.sin_port = htons(daemon->dhcp_client_port);
    243     } else {
    244         /* unicast to unconfigured client. Inject mac address direct into ARP cache.
    245        struct sockaddr limits size to 14 bytes. */
    246         struct arpreq req;
    247         dest.sin_addr = mess->yiaddr;
    248         dest.sin_port = htons(daemon->dhcp_client_port);
    249         *((struct sockaddr_in*) &req.arp_pa) = dest;
    250         req.arp_ha.sa_family = mess->htype;
    251         memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
    252         strncpy(req.arp_dev, ifr.ifr_name, 16);
    253         req.arp_flags = ATF_COM;
    254         ioctl(daemon->dhcpfd, SIOCSARP, &req);
    255     }
    256 #endif
    257 
    258     while (sendmsg(daemon->dhcpfd, &msg, 0) == -1 && retry_send())
    259         ;
    260 }
    261 
    262 /* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
    263    of each interface (and any relay address) and does the  following things:
    264 
    265    1) Discards stuff for interfaces other than the one on which a DHCP packet just arrived.
    266    2) Fills in any netmask and broadcast addresses which have not been explicitly configured.
    267    3) Fills in local (this host) and router (this host or relay) addresses.
    268    4) Links contexts which are valid for hosts directly connected to the arrival interface on
    269    ->current.
    270 
    271    Note that the current chain may be superceded later for configured hosts or those coming via
    272    gateways. */
    273 
    274 static int complete_context(struct in_addr local, int if_index, struct in_addr netmask,
    275                             struct in_addr broadcast, void* vparam) {
    276     struct dhcp_context* context;
    277     struct iface_param* param = vparam;
    278 
    279     for (context = daemon->dhcp; context; context = context->next) {
    280         if (!(context->flags & CONTEXT_NETMASK) && (is_same_net(local, context->start, netmask) ||
    281                                                     is_same_net(local, context->end, netmask))) {
    282             if (context->netmask.s_addr != netmask.s_addr &&
    283                 !(is_same_net(local, context->start, netmask) &&
    284                   is_same_net(local, context->end, netmask))) {
    285                 strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
    286                 strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
    287                 my_syslog(MS_DHCP | LOG_WARNING,
    288                           _("DHCP range %s -- %s is not consistent with netmask %s"),
    289                           daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
    290             }
    291             context->netmask = netmask;
    292         }
    293 
    294         if (context->netmask.s_addr) {
    295             if (is_same_net(local, context->start, context->netmask) &&
    296                 is_same_net(local, context->end, context->netmask)) {
    297                 /* link it onto the current chain if we've not seen it before */
    298                 if (if_index == param->ind && context->current == context) {
    299                     context->router = local;
    300                     context->local = local;
    301                     context->current = param->current;
    302                     param->current = context;
    303                 }
    304 
    305                 if (!(context->flags & CONTEXT_BRDCAST)) {
    306                     if (is_same_net(broadcast, context->start, context->netmask))
    307                         context->broadcast = broadcast;
    308                     else
    309                         context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
    310                 }
    311             } else if (param->relay.s_addr &&
    312                        is_same_net(param->relay, context->start, context->netmask)) {
    313                 context->router = param->relay;
    314                 context->local = param->primary;
    315                 /* fill in missing broadcast addresses for relayed ranges */
    316                 if (!(context->flags & CONTEXT_BRDCAST))
    317                     context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
    318             }
    319         }
    320     }
    321 
    322     return 1;
    323 }
    324 
    325 struct dhcp_context* address_available(struct dhcp_context* context, struct in_addr taddr,
    326                                        struct dhcp_netid* netids) {
    327     /* Check is an address is OK for this network, check all
    328        possible ranges. Make sure that the address isn't in use
    329        by the server itself. */
    330 
    331     unsigned int start, end, addr = ntohl(taddr.s_addr);
    332     struct dhcp_context* tmp;
    333 
    334     for (tmp = context; tmp; tmp = tmp->current)
    335         if (taddr.s_addr == context->router.s_addr) return NULL;
    336 
    337     for (tmp = context; tmp; tmp = tmp->current) {
    338         start = ntohl(tmp->start.s_addr);
    339         end = ntohl(tmp->end.s_addr);
    340 
    341         if (!(tmp->flags & CONTEXT_STATIC) && addr >= start && addr <= end &&
    342             match_netid(tmp->filter, netids, 1))
    343             return tmp;
    344     }
    345 
    346     return NULL;
    347 }
    348 
    349 struct dhcp_context* narrow_context(struct dhcp_context* context, struct in_addr taddr,
    350                                     struct dhcp_netid* netids) {
    351     /* We start of with a set of possible contexts, all on the current physical interface.
    352        These are chained on ->current.
    353        Here we have an address, and return the actual context correponding to that
    354        address. Note that none may fit, if the address came a dhcp-host and is outside
    355        any dhcp-range. In that case we return a static range if possible, or failing that,
    356        any context on the correct subnet. (If there's more than one, this is a dodgy
    357        configuration: maybe there should be a warning.) */
    358 
    359     struct dhcp_context* tmp;
    360 
    361     if (!(tmp = address_available(context, taddr, netids))) {
    362         for (tmp = context; tmp; tmp = tmp->current)
    363             if (is_same_net(taddr, tmp->start, tmp->netmask) && (tmp->flags & CONTEXT_STATIC))
    364                 break;
    365 
    366         if (!tmp)
    367             for (tmp = context; tmp; tmp = tmp->current)
    368                 if (is_same_net(taddr, tmp->start, tmp->netmask)) break;
    369     }
    370 
    371     /* Only one context allowed now */
    372     if (tmp) tmp->current = NULL;
    373 
    374     return tmp;
    375 }
    376 
    377 struct dhcp_config* config_find_by_address(struct dhcp_config* configs, struct in_addr addr) {
    378     struct dhcp_config* config;
    379 
    380     for (config = configs; config; config = config->next)
    381         if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr) return config;
    382 
    383     return NULL;
    384 }
    385 
    386 /* Is every member of check matched by a member of pool?
    387    If tagnotneeded, untagged is OK */
    388 int match_netid(struct dhcp_netid* check, struct dhcp_netid* pool, int tagnotneeded) {
    389     struct dhcp_netid* tmp1;
    390 
    391     if (!check && !tagnotneeded) return 0;
    392 
    393     for (; check; check = check->next) {
    394         if (check->net[0] != '#') {
    395             for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
    396                 if (strcmp(check->net, tmp1->net) == 0) break;
    397             if (!tmp1) return 0;
    398         } else
    399             for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
    400                 if (strcmp((check->net) + 1, tmp1->net) == 0) return 0;
    401     }
    402     return 1;
    403 }
    404 
    405 int address_allocate(struct dhcp_context* context, struct in_addr* addrp, unsigned char* hwaddr,
    406                      int hw_len, struct dhcp_netid* netids, time_t now) {
    407     /* Find a free address: exclude anything in use and anything allocated to
    408        a particular hwaddr/clientid/hostname in our configuration.
    409        Try to return from contexts which match netids first. */
    410 
    411     struct in_addr start, addr;
    412     struct dhcp_context *c, *d;
    413     int i, pass;
    414     unsigned int j;
    415 
    416     /* hash hwaddr */
    417     for (j = 0, i = 0; i < hw_len; i++) j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
    418 
    419     for (pass = 0; pass <= 1; pass++)
    420         for (c = context; c; c = c->current)
    421             if (c->flags & CONTEXT_STATIC)
    422                 continue;
    423             else if (!match_netid(c->filter, netids, pass))
    424                 continue;
    425             else {
    426                 /* pick a seed based on hwaddr then iterate until we find a free address. */
    427                 start.s_addr = addr.s_addr = htonl(
    428                     ntohl(c->start.s_addr) +
    429                     ((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
    430 
    431                 do {
    432                     /* eliminate addresses in use by the server. */
    433                     for (d = context; d; d = d->current)
    434                         if (addr.s_addr == d->router.s_addr) break;
    435 
    436                     /* Addresses which end in .255 and .0 are broken in Windows even when using
    437                        supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0
    438                        then 192.168.0.255 is a valid IP address, but not for Windows as it's
    439                        in the class C range. See  KB281579. We therefore don't allocate these
    440                        addresses to avoid hard-to-diagnose problems. Thanks Bill. */
    441                     if (!d && !lease_find_by_addr(addr) &&
    442                         !config_find_by_address(daemon->dhcp_conf, addr) &&
    443                         (!IN_CLASSC(ntohl(addr.s_addr)) || ((ntohl(addr.s_addr) & 0xff) != 0xff &&
    444                                                             ((ntohl(addr.s_addr) & 0xff) != 0x0)))) {
    445                         struct ping_result *r, *victim = NULL;
    446                         int count,
    447                             max = (int) (0.6 * (((float) PING_CACHE_TIME) / ((float) PING_WAIT)));
    448 
    449                         *addrp = addr;
    450 
    451                         if (daemon->options & OPT_NO_PING) return 1;
    452 
    453                         /* check if we failed to ping addr sometime in the last
    454                            PING_CACHE_TIME seconds. If so, assume the same situation still exists.
    455                            This avoids problems when a stupid client bangs
    456                            on us repeatedly. As a final check, if we did more
    457                            than 60% of the possible ping checks in the last
    458                            PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
    459                         for (count = 0, r = daemon->ping_results; r; r = r->next)
    460                             if (difftime(now, r->time) > (float) PING_CACHE_TIME)
    461                                 victim = r; /* old record */
    462                             else if (++count == max || r->addr.s_addr == addr.s_addr)
    463                                 return 1;
    464 
    465                         if (icmp_ping(addr))
    466                             /* address in use: perturb address selection so that we are
    467                                less likely to try this address again. */
    468                             c->addr_epoch++;
    469                         else {
    470                             /* at this point victim may hold an expired record */
    471                             if (!victim) {
    472                                 if ((victim = whine_malloc(sizeof(struct ping_result)))) {
    473                                     victim->next = daemon->ping_results;
    474                                     daemon->ping_results = victim;
    475                                 }
    476                             }
    477 
    478                             /* record that this address is OK for 30s
    479                                without more ping checks */
    480                             if (victim) {
    481                                 victim->addr = addr;
    482                                 victim->time = now;
    483                             }
    484                             return 1;
    485                         }
    486                     }
    487 
    488                     addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
    489 
    490                     if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1)) addr = c->start;
    491 
    492                 } while (addr.s_addr != start.s_addr);
    493             }
    494     return 0;
    495 }
    496 
    497 static int is_addr_in_context(struct dhcp_context* context, struct dhcp_config* config) {
    498     if (!context) /* called via find_config() from lease_update_from_configs() */
    499         return 1;
    500     if (!(config->flags & CONFIG_ADDR)) return 1;
    501     for (; context; context = context->current)
    502         if (is_same_net(config->addr, context->start, context->netmask)) return 1;
    503 
    504     return 0;
    505 }
    506 
    507 int config_has_mac(struct dhcp_config* config, unsigned char* hwaddr, int len, int type) {
    508     struct hwaddr_config* conf_addr;
    509 
    510     for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
    511         if (conf_addr->wildcard_mask == 0 && conf_addr->hwaddr_len == len &&
    512             (conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
    513             memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
    514             return 1;
    515 
    516     return 0;
    517 }
    518 
    519 struct dhcp_config* find_config(struct dhcp_config* configs, struct dhcp_context* context,
    520                                 unsigned char* clid, int clid_len, unsigned char* hwaddr,
    521                                 int hw_len, int hw_type, char* hostname) {
    522     int count, new;
    523     struct dhcp_config *config, *candidate;
    524     struct hwaddr_config* conf_addr;
    525 
    526     if (clid)
    527         for (config = configs; config; config = config->next)
    528             if (config->flags & CONFIG_CLID) {
    529                 if (config->clid_len == clid_len && memcmp(config->clid, clid, clid_len) == 0 &&
    530                     is_addr_in_context(context, config))
    531                     return config;
    532 
    533                 /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
    534                    cope with that here */
    535                 if (*clid == 0 && config->clid_len == clid_len - 1 &&
    536                     memcmp(config->clid, clid + 1, clid_len - 1) == 0 &&
    537                     is_addr_in_context(context, config))
    538                     return config;
    539             }
    540 
    541     for (config = configs; config; config = config->next)
    542         if (config_has_mac(config, hwaddr, hw_len, hw_type) && is_addr_in_context(context, config))
    543             return config;
    544 
    545     if (hostname && context)
    546         for (config = configs; config; config = config->next)
    547             if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, hostname) &&
    548                 is_addr_in_context(context, config))
    549                 return config;
    550 
    551     /* use match with fewest wildcast octets */
    552     for (candidate = NULL, count = 0, config = configs; config; config = config->next)
    553         if (is_addr_in_context(context, config))
    554             for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
    555                 if (conf_addr->wildcard_mask != 0 && conf_addr->hwaddr_len == hw_len &&
    556                     (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
    557                     (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len,
    558                                          conf_addr->wildcard_mask)) > count) {
    559                     count = new;
    560                     candidate = config;
    561                 }
    562 
    563     return candidate;
    564 }
    565 
    566 void check_dhcp_hosts(int fatal) {
    567     /* If the same IP appears in more than one host config, then DISCOVER
    568        for one of the hosts will get the address, but REQUEST will be NAKed,
    569        since the address is reserved by the other one -> protocol loop.
    570        Also check that FQDNs match the domain we are using. */
    571 
    572     struct dhcp_config *configs, *cp;
    573 
    574     for (configs = daemon->dhcp_conf; configs; configs = configs->next) {
    575         char* domain;
    576 
    577         if ((configs->flags & DHOPT_BANK) || fatal) {
    578             for (cp = configs->next; cp; cp = cp->next)
    579                 if ((configs->flags & cp->flags & CONFIG_ADDR) &&
    580                     configs->addr.s_addr == cp->addr.s_addr) {
    581                     if (fatal)
    582                         die(_("duplicate IP address %s in dhcp-config directive."),
    583                             inet_ntoa(cp->addr), EC_BADCONF);
    584                     else
    585                         my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."),
    586                                   inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
    587                     configs->flags &= ~CONFIG_ADDR;
    588                 }
    589 
    590             /* split off domain part */
    591             if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
    592                 configs->domain = domain;
    593         }
    594     }
    595 }
    596 
    597 void dhcp_update_configs(struct dhcp_config* configs) {
    598     /* Some people like to keep all static IP addresses in /etc/hosts.
    599        This goes through /etc/hosts and sets static addresses for any DHCP config
    600        records which don't have an address and whose name matches.
    601        We take care to maintain the invariant that any IP address can appear
    602        in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
    603        restore the status-quo ante first. */
    604 
    605     struct dhcp_config* config;
    606     struct crec* crec;
    607 
    608     for (config = configs; config; config = config->next)
    609         if (config->flags & CONFIG_ADDR_HOSTS) config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS);
    610 
    611     if (daemon->port != 0)
    612         for (config = configs; config; config = config->next)
    613             if (!(config->flags & CONFIG_ADDR) && (config->flags & CONFIG_NAME) &&
    614                 (crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
    615                 (crec->flags & F_HOSTS)) {
    616                 if (cache_find_by_name(crec, config->hostname, 0, F_IPV4)) {
    617                     /* use primary (first) address */
    618                     while (crec && !(crec->flags & F_REVERSE))
    619                         crec = cache_find_by_name(crec, config->hostname, 0, F_IPV4);
    620                     if (!crec) continue; /* should be never */
    621                     my_syslog(MS_DHCP | LOG_WARNING,
    622                               _("%s has more than one address in hostsfile, using %s for DHCP"),
    623                               config->hostname, inet_ntoa(crec->addr.addr.addr.addr4));
    624                 }
    625 
    626                 if (config_find_by_address(configs, crec->addr.addr.addr.addr4))
    627                     my_syslog(MS_DHCP | LOG_WARNING,
    628                               _("duplicate IP address %s (%s) in dhcp-config directive"),
    629                               inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
    630                 else {
    631                     config->addr = crec->addr.addr.addr.addr4;
    632                     config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
    633                 }
    634             }
    635 }
    636 
    637 /* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
    638    for this address. If it has a domain part, that must match the set domain and
    639    it gets stripped. The set of legal domain names is bigger than the set of legal hostnames
    640    so check here that the domain name is legal as a hostname. */
    641 char* host_from_dns(struct in_addr addr) {
    642     struct crec* lookup;
    643     char* hostname = NULL;
    644     char *d1, *d2;
    645 
    646     if (daemon->port == 0) return NULL; /* DNS disabled. */
    647 
    648     lookup = cache_find_by_addr(NULL, (struct all_addr*) &addr, 0, F_IPV4);
    649     if (lookup && (lookup->flags & F_HOSTS)) {
    650         hostname = daemon->dhcp_buff;
    651         strncpy(hostname, cache_get_name(lookup), 256);
    652         hostname[255] = 0;
    653         d1 = strip_hostname(hostname);
    654         d2 = get_domain(addr);
    655         if (!legal_hostname(hostname) || (d1 && (!d2 || !hostname_isequal(d1, d2))))
    656             hostname = NULL;
    657     }
    658 
    659     return hostname;
    660 }
    661 
    662 /* return domain or NULL if none. */
    663 char* strip_hostname(char* hostname) {
    664     char* dot = strchr(hostname, '.');
    665 
    666     if (!dot) return NULL;
    667 
    668     *dot = 0; /* truncate */
    669     if (strlen(dot + 1) != 0) return dot + 1;
    670 
    671     return NULL;
    672 }
    673 
    674 #endif
    675