1/* dnsmasq is Copyright (c) 2000-2003 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. 6 7 This program is distributed in the hope that it will be useful, 8 but WITHOUT ANY WARRANTY; without even the implied warranty of 9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 GNU General Public License for more details. 11*/ 12 13/* Author's email: simon@thekelleys.org.uk */ 14 15#include "dnsmasq.h" 16 17void dhcp_init(struct daemon *daemon) 18{ 19 int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 20 struct sockaddr_in saddr; 21 int oneopt = 1, zeroopt = 0; 22 struct dhcp_config *configs, *cp; 23 24 if (fd == -1) 25 die ("cannot create DHCP socket : %s", NULL); 26 27 if ( 28#if defined(IP_PKTINFO) 29 setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 || 30#elif defined(IP_RECVIF) 31 setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 || 32#endif 33 setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1) 34 die("failed to set options on DHCP socket: %s", NULL); 35 36 saddr.sin_family = AF_INET; 37 saddr.sin_port = htons(DHCP_SERVER_PORT); 38 saddr.sin_addr.s_addr = INADDR_ANY; 39#ifdef HAVE_SOCKADDR_SA_LEN 40 saddr.sin_len = sizeof(struct sockaddr_in); 41#endif 42 43 if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in))) 44 die("failed to bind DHCP server socket: %s", NULL); 45 46 daemon->dhcpfd = fd; 47 48 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1 || 49 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) || 50 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1) 51 die("cannot create ICMP raw socket: %s.", NULL); 52 53 daemon->dhcp_icmp_fd = fd; 54 55#ifdef HAVE_BPF 56 { 57 int i = 0; 58 while (1) 59 { 60 char filename[50]; 61 sprintf(filename, "/dev/bpf%d", i++); 62 if ((fd = open(filename, O_RDWR, 0)) != -1) 63 break; 64 if (errno != EBUSY) 65 die("cannot create DHCP BPF socket: %s", NULL); 66 } 67 } 68#else 69 /* since we don't ever use the packet socket for reception, 70 and it receives copies of _all_ IP packets, then that data 71 will build up in kernel buffers, wasting memory. Set the 72 socket receive buffer size to one to avoid that. (zero is 73 rejected as non-sensical by some BSD kernels) */ 74 if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETHERTYPE_IP))) == -1 || 75 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1) 76 die("cannot create DHCP packet socket: %s. " 77 "Is CONFIG_PACKET enabled in your kernel?", NULL); 78#endif 79 80 daemon->dhcp_raw_fd = fd; 81 82 /* If the same IP appears in more than one host config, then DISCOVER 83 for one of the hosts will get the address, but REQUEST will be NAKed, 84 since the address is reserved by the other one -> protocol loop. */ 85 for (configs = daemon->dhcp_conf; configs; configs = configs->next) 86 for (cp = configs->next; cp; cp = cp->next) 87 if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr) 88 die("duplicate IP address %s in dhcp-config directive.", inet_ntoa(cp->addr)); 89 90 daemon->dhcp_packet = safe_malloc(sizeof(struct udp_dhcp_packet)); 91 /* These two each hold a DHCP option max size 256 92 and get a terminating zero added */ 93 daemon->dhcp_buff = safe_malloc(257); 94 daemon->dhcp_buff2 = safe_malloc(257); 95 96} 97 98void dhcp_packet(struct daemon *daemon, time_t now) 99{ 100 struct udp_dhcp_packet *rawpacket = daemon->dhcp_packet; 101 struct dhcp_packet *mess = &rawpacket->data; 102 struct dhcp_context *context; 103 struct iname *tmp; 104 struct ifreq ifr; 105 struct msghdr msg; 106 struct iovec iov[2]; 107 struct cmsghdr *cmptr; 108 int sz, newlen, iface_index = 0; 109 struct in_addr iface_netmask, iface_addr, iface_broadcast; 110#ifdef HAVE_BPF 111 unsigned char iface_hwaddr[ETHER_ADDR_LEN]; 112#endif 113 114 union { 115 struct cmsghdr align; /* this ensures alignment */ 116#ifdef IP_PKTINFO 117 char control[CMSG_SPACE(sizeof(struct in_pktinfo))]; 118#else 119 char control[CMSG_SPACE(sizeof(struct sockaddr_dl))]; 120#endif 121 } control_u; 122 123 iov[0].iov_base = (char *)mess; 124 iov[0].iov_len = sizeof(struct dhcp_packet); 125 126 msg.msg_control = control_u.control; 127 msg.msg_controllen = sizeof(control_u); 128 msg.msg_flags = 0; 129 msg.msg_name = NULL; 130 msg.msg_namelen = 0; 131 msg.msg_iov = iov; 132 msg.msg_iovlen = 1; 133 134 sz = recvmsg(daemon->dhcpfd, &msg, 0); 135 136 if (sz < (int)(sizeof(*mess) - sizeof(mess->options))) 137 return; 138 139#if defined (IP_PKTINFO) 140 if (msg.msg_controllen < sizeof(struct cmsghdr)) 141 return; 142 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) 143 if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO) 144 iface_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex; 145 146 if (!(ifr.ifr_ifindex = iface_index) || 147 ioctl(daemon->dhcpfd, SIOCGIFNAME, &ifr) == -1) 148 return; 149 150#elif defined(IP_RECVIF) 151 if (msg.msg_controllen < sizeof(struct cmsghdr)) 152 return; 153 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) 154 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF) 155 iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index; 156 157 if (!iface_index || !if_indextoname(iface_index, ifr.ifr_name)) 158 return; 159 160#else 161 { 162 struct iname *name; 163 for (name = daemon->if_names; names->isloop; names = names->next); 164 strcpy(ifr.ifr_name, name->name); 165 } 166#endif 167 168#ifdef HAVE_BPF 169 ifr.ifr_addr.sa_family = AF_LINK; 170 if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) < 0) 171 return; 172 memcpy(iface_hwaddr, LLADDR((struct sockaddr_dl *)&ifr.ifr_addr), ETHER_ADDR_LEN); 173#endif 174 175 ifr.ifr_addr.sa_family = AF_INET; 176 if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) < 0 ) 177 return; 178 iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; 179 180 /* enforce available interface configuration */ 181 for (tmp = daemon->if_except; tmp; tmp = tmp->next) 182 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0)) 183 return; 184 185 if (daemon->if_names || daemon->if_addrs) 186 { 187 for (tmp = daemon->if_names; tmp; tmp = tmp->next) 188 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0)) 189 break; 190 if (!tmp) 191 for (tmp = daemon->if_addrs; tmp; tmp = tmp->next) 192 if (tmp->addr.sa.sa_family == AF_INET && 193 tmp->addr.in.sin_addr.s_addr == iface_addr.s_addr) 194 break; 195 if (!tmp) 196 return; 197 } 198 199 iface_netmask.s_addr = 0; 200 iface_broadcast.s_addr = 0; 201 202 for (context = daemon->dhcp; context; context = context->next) 203 { 204 /* Fill in missing netmask and broadcast address values for any approriate 205 dhcp-ranges which match this interface and don't have them. */ 206 if (!context->netmask.s_addr) 207 { 208 if (!iface_netmask.s_addr && ioctl(daemon->dhcpfd, SIOCGIFNETMASK, &ifr) != -1) 209 iface_netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; 210 211 if (iface_netmask.s_addr && 212 (is_same_net(iface_addr, context->start, iface_netmask) || 213 is_same_net(iface_addr, context->end, iface_netmask))) 214 { 215 context->netmask = iface_netmask; 216 if (!(is_same_net(iface_addr, context->start, iface_netmask) && 217 is_same_net(iface_addr, context->end, iface_netmask))) 218 { 219 strcpy(daemon->dhcp_buff, inet_ntoa(context->start)); 220 strcpy(daemon->dhcp_buff2, inet_ntoa(context->end)); 221 syslog(LOG_WARNING, "DHCP range %s -- %s is not consistent with netmask %s", 222 daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(iface_netmask)); 223 } 224 } 225 } 226 227 /* Determine "default" default routes. These are to this server or the relay agent. 228 Also broadcast addresses, if not specified */ 229 if (context->netmask.s_addr) 230 { 231 if (is_same_net(iface_addr, context->start, context->netmask)) 232 { 233 if (!context->router.s_addr) 234 context->router = iface_addr; 235 if (!context->broadcast.s_addr) 236 { 237 if (!iface_broadcast.s_addr && ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) != -1) 238 iface_broadcast = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; 239 if (iface_broadcast.s_addr && 240 is_same_net(iface_broadcast, context->start, context->netmask)) 241 context->broadcast = iface_broadcast; 242 else 243 context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr; 244 } 245 } 246 else if (mess->giaddr.s_addr && is_same_net(mess->giaddr, context->start, context->netmask)) 247 { 248 if (!context->router.s_addr) 249 context->router = mess->giaddr; 250 /* fill in missing broadcast addresses for relayed ranges */ 251 if (!context->broadcast.s_addr) 252 context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr; 253 } 254 } 255 } 256 257 lease_prune(NULL, now); /* lose any expired leases */ 258 newlen = dhcp_reply(daemon, iface_addr, ifr.ifr_name, sz, now); 259 lease_update_file(0, now); 260 lease_update_dns(); 261 262 if (newlen == 0) 263 return; 264 265 if (mess->giaddr.s_addr || mess->ciaddr.s_addr) 266 { 267 /* To send to BOOTP relay or configured client, use the IP packet */ 268 269 struct sockaddr_in dest; 270 dest.sin_family = AF_INET; 271#ifdef HAVE_SOCKADDR_SA_LEN 272 dest.sin_len = sizeof(struct sockaddr_in); 273#endif 274 275 if (mess->giaddr.s_addr) 276 { 277 dest.sin_port = htons(DHCP_SERVER_PORT); 278 dest.sin_addr = mess->giaddr; 279 } 280 else 281 { 282 dest.sin_port = htons(DHCP_CLIENT_PORT); 283 dest.sin_addr = mess->ciaddr; 284 } 285 286 sendto(daemon->dhcpfd, mess, newlen, 0, (struct sockaddr *)&dest, sizeof(dest)); 287 } 288 else 289 { 290 /* Hairy stuff, packet either has to go to the 291 net broadcast or the destination can't reply to ARP yet, 292 but we do know the physical address. 293 Build the packet by steam, and send directly, bypassing 294 the kernel IP stack */ 295 296 u32 i, sum; 297 unsigned char hwdest[ETHER_ADDR_LEN]; 298 299 if (ntohs(mess->flags) & 0x8000) 300 { 301 memset(hwdest, 255, ETHER_ADDR_LEN); 302 rawpacket->ip.ip_dst.s_addr = INADDR_BROADCAST; 303 } 304 else 305 { 306 memcpy(hwdest, mess->chaddr, ETHER_ADDR_LEN); 307 rawpacket->ip.ip_dst.s_addr = mess->yiaddr.s_addr; 308 } 309 310 rawpacket->ip.ip_p = IPPROTO_UDP; 311 rawpacket->ip.ip_src.s_addr = iface_addr.s_addr; 312 rawpacket->ip.ip_len = htons(sizeof(struct ip) + 313 sizeof(struct udphdr) + 314 newlen) ; 315 rawpacket->ip.ip_hl = sizeof(struct ip) / 4; 316 rawpacket->ip.ip_v = IPVERSION; 317 rawpacket->ip.ip_tos = 0; 318 rawpacket->ip.ip_id = htons(0); 319 rawpacket->ip.ip_off = htons(0x4000); /* don't fragment */ 320 rawpacket->ip.ip_ttl = IPDEFTTL; 321 rawpacket->ip.ip_sum = 0; 322 for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++) 323 sum += ((u16 *)&rawpacket->ip)[i]; 324 while (sum>>16) 325 sum = (sum & 0xffff) + (sum >> 16); 326 rawpacket->ip.ip_sum = (sum == 0xffff) ? sum : ~sum; 327 328 rawpacket->udp.uh_sport = htons(DHCP_SERVER_PORT); 329 rawpacket->udp.uh_dport = htons(DHCP_CLIENT_PORT); 330 ((u8 *)&rawpacket->data)[newlen] = 0; /* for checksum, in case length is odd. */ 331 rawpacket->udp.uh_sum = 0; 332 rawpacket->udp.uh_ulen = sum = htons(sizeof(struct udphdr) + newlen); 333 sum += htons(IPPROTO_UDP); 334 for (i = 0; i < 4; i++) 335 sum += ((u16 *)&rawpacket->ip.ip_src)[i]; 336 for (i = 0; i < (sizeof(struct udphdr) + newlen + 1) / 2; i++) 337 sum += ((u16 *)&rawpacket->udp)[i]; 338 while (sum>>16) 339 sum = (sum & 0xffff) + (sum >> 16); 340 rawpacket->udp.uh_sum = (sum == 0xffff) ? sum : ~sum; 341 342 { 343#ifdef HAVE_BPF 344 struct ether_header header; 345 346 header.ether_type = htons(ETHERTYPE_IP); 347 memcpy(header.ether_shost, iface_hwaddr, ETHER_ADDR_LEN); 348 memcpy(header.ether_dhost, hwdest, ETHER_ADDR_LEN); 349 350 ioctl(daemon->dhcp_raw_fd, BIOCSETIF, &ifr); 351 352 iov[0].iov_base = (char *)&header; 353 iov[0].iov_len = sizeof(struct ether_header); 354 iov[1].iov_base = (char *)rawpacket; 355 iov[1].iov_len = ntohs(rawpacket->ip.ip_len); 356 writev(daemon->dhcp_raw_fd, iov, 2); 357#else 358 struct sockaddr_ll dest; 359 360 dest.sll_family = AF_PACKET; 361 dest.sll_halen = ETHER_ADDR_LEN; 362 dest.sll_ifindex = iface_index; 363 dest.sll_protocol = htons(ETHERTYPE_IP); 364 memcpy(dest.sll_addr, hwdest, ETHER_ADDR_LEN); 365 sendto(daemon->dhcp_raw_fd, rawpacket, ntohs(rawpacket->ip.ip_len), 366 0, (struct sockaddr *)&dest, sizeof(dest)); 367 368#endif 369 } 370 } 371} 372 373int address_available(struct dhcp_context *context, struct in_addr taddr) 374{ 375 /* Check is an address is OK for this network, check all 376 possible ranges. */ 377 378 unsigned int start, end, addr = ntohl(taddr.s_addr); 379 380 for (; context; context = context->current) 381 { 382 start = ntohl(context->start.s_addr); 383 end = ntohl(context->end.s_addr); 384 385 if (!context->static_only && 386 addr >= start && 387 addr <= end) 388 return 1; 389 } 390 391 return 0; 392} 393 394struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr) 395{ 396 struct dhcp_config *config; 397 398 for (config = configs; config; config = config->next) 399 if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr) 400 return config; 401 402 return NULL; 403} 404 405int address_allocate(struct dhcp_context *context, struct daemon *daemon, 406 struct in_addr *addrp, unsigned char *hwaddr) 407{ 408 /* Find a free address: exclude anything in use and anything allocated to 409 a particular hwaddr/clientid/hostname in our configuration */ 410 411 struct in_addr start, addr ; 412 unsigned int i, j; 413 414 for (; context; context = context->current) 415 if (!context->static_only) 416 { 417 /* pick a seed based on hwaddr then iterate until we find a free address. */ 418 for (j = context->addr_epoch, i = 0; i < ETHER_ADDR_LEN; i++) 419 j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16); 420 421 start.s_addr = addr.s_addr = 422 htonl(ntohl(context->start.s_addr) + 423 (j % (1 + ntohl(context->end.s_addr) - ntohl(context->start.s_addr)))); 424 425 do { 426 if (!lease_find_by_addr(addr) && 427 !config_find_by_address(daemon->dhcp_conf, addr)) 428 { 429 if (icmp_ping(daemon, addr)) 430 /* perturb address selection so that we are 431 less likely to try this address again. */ 432 context->addr_epoch++; 433 else 434 { 435 *addrp = addr; 436 return 1; 437 } 438 } 439 440 addr.s_addr = htonl(ntohl(addr.s_addr) + 1); 441 442 if (addr.s_addr == htonl(ntohl(context->end.s_addr) + 1)) 443 addr = context->start; 444 445 } while (addr.s_addr != start.s_addr); 446 } 447 return 0; 448} 449 450static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *config) 451{ 452 if (!context) 453 return 1; 454 if (!(config->flags & CONFIG_ADDR)) 455 return 1; 456 if (is_same_net(config->addr, context->start, context->netmask)) 457 return 1; 458 459 return 0; 460} 461 462struct dhcp_config *find_config(struct dhcp_config *configs, 463 struct dhcp_context *context, 464 unsigned char *clid, int clid_len, 465 unsigned char *hwaddr, char *hostname) 466{ 467 struct dhcp_config *config; 468 469 if (clid_len) 470 for (config = configs; config; config = config->next) 471 if (config->flags & CONFIG_CLID) 472 { 473 if (config->clid_len == clid_len && 474 memcmp(config->clid, clid, clid_len) == 0 && 475 is_addr_in_context(context, config)) 476 return config; 477 478 /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and 479 cope with that here */ 480 if (*clid == 0 && config->clid_len == clid_len-1 && 481 memcmp(config->clid, clid+1, clid_len-1) == 0 && 482 is_addr_in_context(context, config)) 483 return config; 484 } 485 486 for (config = configs; config; config = config->next) 487 if ((config->flags & CONFIG_HWADDR) && 488 memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0 && 489 is_addr_in_context(context, config)) 490 return config; 491 492 if (hostname) 493 for (config = configs; config; config = config->next) 494 if ((config->flags & CONFIG_NAME) && 495 hostname_isequal(config->hostname, hostname) && 496 is_addr_in_context(context, config)) 497 return config; 498 499 return NULL; 500} 501 502void dhcp_read_ethers(struct daemon *daemon) 503{ 504 FILE *f = fopen(ETHERSFILE, "r"); 505 unsigned int flags, e0, e1, e2, e3, e4, e5; 506 char *buff = daemon->namebuff; 507 char *ip, *cp; 508 struct in_addr addr; 509 unsigned char hwaddr[ETHER_ADDR_LEN]; 510 struct dhcp_config *config, *configs = daemon->dhcp_conf; 511 int count = 0; 512 513 if (!f) 514 { 515 syslog(LOG_ERR, "failed to read " ETHERSFILE ":%m"); 516 return; 517 } 518 519 while (fgets(buff, MAXDNAME, f)) 520 { 521 while (strlen(buff) > 0 && isspace(buff[strlen(buff)-1])) 522 buff[strlen(buff)-1] = 0; 523 524 if ((*buff == '#') || (*buff == '+')) 525 continue; 526 527 for (ip = buff; *ip && !isspace(*ip); ip++); 528 for(; *ip && isspace(*ip); ip++) 529 *ip = 0; 530 if (!*ip) 531 continue; 532 533 if (!sscanf(buff, "%x:%x:%x:%x:%x:%x", &e0, &e1, &e2, &e3, &e4, &e5)) 534 continue; 535 536 hwaddr[0] = e0; 537 hwaddr[1] = e1; 538 hwaddr[2] = e2; 539 hwaddr[3] = e3; 540 hwaddr[4] = e4; 541 hwaddr[5] = e5; 542 543 /* check for name or dotted-quad */ 544 for (cp = ip; *cp; cp++) 545 if (!(*cp == '.' || (*cp >='0' && *cp <= '9'))) 546 break; 547 548 if (!*cp) 549 { 550 if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1) 551 continue; 552 flags = CONFIG_ADDR; 553 554 for (config = configs; config; config = config->next) 555 if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr) 556 break; 557 } 558 else 559 { 560 if (!canonicalise(ip)) 561 continue; 562 flags = CONFIG_NAME; 563 564 for (config = configs; config; config = config->next) 565 if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, ip)) 566 break; 567 } 568 569 if (!config) 570 { 571 for (config = configs; config; config = config->next) 572 if ((config->flags & CONFIG_HWADDR) && 573 memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0) 574 break; 575 576 if (!config) 577 { 578 if (!(config = malloc(sizeof(struct dhcp_config)))) 579 continue; 580 config->flags = 0; 581 config->next = configs; 582 configs = config; 583 } 584 585 config->flags |= flags; 586 587 if (flags & CONFIG_NAME) 588 { 589 if ((config->hostname = malloc(strlen(ip)+1))) 590 strcpy(config->hostname, ip); 591 else 592 config->flags &= ~CONFIG_NAME; 593 } 594 595 if (flags & CONFIG_ADDR) 596 config->addr = addr; 597 } 598 599 config->flags |= CONFIG_HWADDR | CONFIG_NOCLID; 600 memcpy(config->hwaddr, hwaddr, ETHER_ADDR_LEN); 601 602 count++; 603 } 604 605 fclose(f); 606 607 syslog(LOG_INFO, "read " ETHERSFILE " - %d addresses", count); 608 609 daemon->dhcp_conf = configs; 610} 611 612void dhcp_update_configs(struct dhcp_config *configs) 613{ 614 /* Some people like to keep all static IP addresses in /etc/hosts. 615 This goes through /etc/hosts and sets static addresses for any DHCP config 616 records which don't have an address and whose name matches. */ 617 618 struct dhcp_config *config; 619 struct crec *crec; 620 621 for (config = configs; config; config = config->next) 622 if (!(config->flags & CONFIG_ADDR) && 623 (config->flags & CONFIG_NAME) && 624 (crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) && 625 (crec->flags & F_HOSTS)) 626 { 627 config->addr = crec->addr.addr.addr4; 628 config->flags |= CONFIG_ADDR; 629 } 630} 631 632