Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 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 | |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame^] | 17 | void dhcp_init(int *fdp, int* rfdp) |
| 18 | { |
| 19 | int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); |
| 20 | struct sockaddr_in saddr; |
| 21 | int opt = 1; |
| 22 | |
| 23 | if (fd == -1) |
| 24 | die ("Cannot create DHCP socket : %s", NULL); |
| 25 | |
| 26 | if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || |
| 27 | #if defined(IP_PKTINFO) |
| 28 | setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 || |
| 29 | #elif defined(IP_RECVIF) |
| 30 | setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 || |
| 31 | #endif |
| 32 | setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) == -1) |
| 33 | die("failed to set options on DHCP socket: %s", NULL); |
| 34 | |
| 35 | saddr.sin_family = AF_INET; |
| 36 | saddr.sin_port = htons(DHCP_SERVER_PORT); |
| 37 | saddr.sin_addr.s_addr = INADDR_ANY; |
| 38 | if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in))) |
| 39 | die("failed to bind DHCP server socket: %s", NULL); |
| 40 | |
| 41 | *fdp = fd; |
| 42 | |
| 43 | #ifdef HAVE_BPF |
| 44 | opt = 0; |
| 45 | while (1) |
| 46 | { |
| 47 | char filename[50]; |
| 48 | sprintf(filename, "/dev/bpf%d", opt++); |
| 49 | if ((fd = open(filename, O_RDWR, 0)) != -1) |
| 50 | break; |
| 51 | if (errno != EBUSY) |
| 52 | die("Cannot create DHCP BPF socket: %s", NULL); |
| 53 | } |
| 54 | #else |
| 55 | if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETHERTYPE_IP))) == -1) |
| 56 | die("Cannot create DHCP packet socket: %s", NULL); |
| 57 | #endif |
| 58 | |
| 59 | *rfdp = fd; |
| 60 | } |
| 61 | |
| 62 | void dhcp_packet(struct dhcp_context *contexts, char *packet, |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 63 | struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs, |
| 64 | time_t now, char *namebuff, char *domain_suffix, |
| 65 | char *dhcp_file, char *dhcp_sname, |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame^] | 66 | struct in_addr dhcp_next_server, int dhcp_fd, int raw_fd, |
| 67 | struct iname *names, struct iname *addrs, struct iname *except) |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 68 | { |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame^] | 69 | struct udp_dhcp_packet *rawpacket = (struct udp_dhcp_packet *)packet; |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 70 | struct dhcp_packet *mess = (struct dhcp_packet *)&rawpacket->data; |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame^] | 71 | struct dhcp_context *context; |
| 72 | struct iname *tmp; |
| 73 | struct ifreq ifr; |
| 74 | struct msghdr msg; |
| 75 | struct iovec iov[2]; |
| 76 | struct cmsghdr *cmptr; |
| 77 | int sz, newlen, iface_index = 0; |
| 78 | struct in_addr source, real_netmask, iface_addr, netmask_save, broadcast_save; |
| 79 | #ifdef HAVE_BPF |
| 80 | unsigned char iface_hwaddr[ETHER_ADDR_LEN]; |
| 81 | #endif |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 82 | |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame^] | 83 | union { |
| 84 | struct cmsghdr align; /* this ensures alignment */ |
| 85 | #ifdef IP_PKTINFO |
| 86 | char control[CMSG_SPACE(sizeof(struct in_pktinfo))]; |
| 87 | #else |
| 88 | char control[CMSG_SPACE(sizeof(struct sockaddr_dl))]; |
| 89 | #endif |
| 90 | } control_u; |
| 91 | |
| 92 | iov[0].iov_base = (char *)&rawpacket->data; |
| 93 | iov[0].iov_len = DNSMASQ_PACKETSZ - (sizeof(struct ip) + sizeof(struct udphdr)); |
| 94 | |
| 95 | msg.msg_control = control_u.control; |
| 96 | msg.msg_controllen = sizeof(control_u); |
| 97 | msg.msg_flags = 0; |
| 98 | msg.msg_name = NULL; |
| 99 | msg.msg_namelen = 0; |
| 100 | msg.msg_iov = iov; |
| 101 | msg.msg_iovlen = 1; |
| 102 | |
| 103 | sz = recvmsg(dhcp_fd, &msg, 0); |
| 104 | |
| 105 | if (sz < (int)(sizeof(*mess) - sizeof(mess->options))) |
| 106 | return; |
| 107 | |
| 108 | #if defined (IP_PKTINFO) |
| 109 | if (msg.msg_controllen < sizeof(struct cmsghdr)) |
| 110 | return; |
| 111 | for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) |
| 112 | if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO) |
| 113 | iface_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex; |
| 114 | |
| 115 | if (!iface_index || !if_indextoname(iface_index, ifr.ifr_name)) |
| 116 | return; |
| 117 | |
| 118 | #elif defined(IP_RECVIF) |
| 119 | if (msg.msg_controllen < sizeof(struct cmsghdr)) |
| 120 | return; |
| 121 | for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) |
| 122 | if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF) |
| 123 | iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index; |
| 124 | |
| 125 | if (!iface_index || !if_indextoname(iface_index, ifr.ifr_name)) |
| 126 | return; |
| 127 | |
| 128 | #else |
| 129 | if (!names || !names->name || names->next) |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 130 | { |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame^] | 131 | syslog(LOG_ERR, "must set exactly one interface on broken systems without IP_RECVIF"); |
| 132 | return; |
| 133 | } |
| 134 | else |
| 135 | strcpy(ifr.ifr_name, names->name); |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 136 | #endif |
| 137 | |
| 138 | #ifdef HAVE_BPF |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame^] | 139 | ifr.ifr_addr.sa_family = AF_LINK; |
| 140 | if (ioctl(dhcp_fd, SIOCGIFADDR, &ifr) < 0) |
| 141 | return; |
| 142 | memcpy(iface_hwaddr, LLADDR((struct sockaddr_dl *)&ifr.ifr_addr), ETHER_ADDR_LEN); |
| 143 | #endif |
| 144 | |
| 145 | ifr.ifr_addr.sa_family = AF_INET; |
| 146 | if (ioctl(dhcp_fd, SIOCGIFADDR, &ifr) < 0 ) |
| 147 | return; |
| 148 | iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; |
| 149 | |
| 150 | /* enforce available interface configuration */ |
| 151 | for (tmp = except; tmp; tmp = tmp->next) |
| 152 | if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0)) |
| 153 | return; |
| 154 | |
| 155 | if (names || addrs) |
| 156 | { |
| 157 | for (tmp = names; tmp; tmp = tmp->next) |
| 158 | if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0)) |
| 159 | break; |
| 160 | if (!tmp) |
| 161 | for (tmp = addrs; tmp; tmp = tmp->next) |
| 162 | if (tmp->addr.sa.sa_family == AF_INET && |
| 163 | tmp->addr.in.sin_addr.s_addr == iface_addr.s_addr) |
| 164 | break; |
| 165 | if (!tmp) |
| 166 | return; |
| 167 | } |
| 168 | |
| 169 | /* If the packet came via a relay, use that address to look up the context, |
| 170 | else use the address of the interface is arrived on. */ |
| 171 | source = mess->giaddr.s_addr ? mess->giaddr : iface_addr; |
| 172 | |
| 173 | for (context = contexts; context; context = context->next) |
| 174 | { |
| 175 | if (!context->netmask.s_addr && !mess->giaddr.s_addr && ioctl(dhcp_fd, SIOCGIFNETMASK, &ifr) != -1) |
| 176 | real_netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; |
| 177 | else |
| 178 | real_netmask = context->netmask; |
| 179 | |
| 180 | if (real_netmask.s_addr && |
| 181 | (source.s_addr & real_netmask.s_addr) == (context->start.s_addr & real_netmask.s_addr) && |
| 182 | (source.s_addr & real_netmask.s_addr) == (context->end.s_addr & real_netmask.s_addr)) |
| 183 | break; |
| 184 | } |
| 185 | |
| 186 | if (!context) |
| 187 | { |
| 188 | syslog(LOG_WARNING, "no address range available for DHCP request via %s", inet_ntoa(source)); |
| 189 | return; |
| 190 | } |
| 191 | |
| 192 | netmask_save = context->netmask; |
| 193 | broadcast_save = context->broadcast; |
| 194 | |
| 195 | context->netmask = real_netmask; |
| 196 | |
| 197 | if (!context->broadcast.s_addr) |
| 198 | { |
| 199 | if (mess->giaddr.s_addr) |
| 200 | context->broadcast.s_addr = (mess->giaddr.s_addr & real_netmask.s_addr) | ~real_netmask.s_addr; |
| 201 | else if (ioctl(dhcp_fd, SIOCGIFBRDADDR, &ifr) != -1) |
| 202 | context->broadcast = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; |
| 203 | else |
| 204 | context->broadcast.s_addr = (iface_addr.s_addr & real_netmask.s_addr) | ~real_netmask.s_addr; |
| 205 | } |
| 206 | |
| 207 | if (ioctl(dhcp_fd, SIOCGIFMTU, &ifr) == -1) |
| 208 | ifr.ifr_mtu = ETHERMTU; |
| 209 | |
| 210 | lease_prune(NULL, now); /* lose any expired leases */ |
| 211 | newlen = dhcp_reply(context, iface_addr, ifr.ifr_name, ifr.ifr_mtu, |
| 212 | rawpacket, sz, now, namebuff, |
| 213 | dhcp_opts, dhcp_configs, domain_suffix, dhcp_file, |
| 214 | dhcp_sname, dhcp_next_server); |
| 215 | lease_update_file(0, now); |
| 216 | lease_update_dns(); |
| 217 | |
| 218 | context->netmask = netmask_save; |
| 219 | context->broadcast = broadcast_save; |
| 220 | |
| 221 | if (newlen == 0) |
| 222 | return; |
| 223 | |
| 224 | if (mess->giaddr.s_addr || mess->ciaddr.s_addr) |
| 225 | { |
| 226 | /* To send to BOOTP relay or configured client, use |
| 227 | the IP packet */ |
| 228 | |
| 229 | struct sockaddr_in dest; |
| 230 | dest.sin_family = AF_INET; |
| 231 | |
| 232 | if (mess->giaddr.s_addr) |
| 233 | { |
| 234 | dest.sin_port = htons(DHCP_SERVER_PORT); |
| 235 | dest.sin_addr = mess->giaddr; |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 236 | } |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame^] | 237 | else |
| 238 | { |
| 239 | dest.sin_port = htons(DHCP_CLIENT_PORT); |
| 240 | dest.sin_addr = mess->ciaddr; |
| 241 | } |
| 242 | |
| 243 | sendto(dhcp_fd, mess, newlen, 0, (struct sockaddr *)&dest, sizeof(dest)); |
| 244 | } |
| 245 | else |
| 246 | { |
| 247 | /* Hairy stuff, packet either has to go to the |
| 248 | net broadcast or the destination can't reply to ARP yet, |
| 249 | but we do know the physical address. |
| 250 | Build the packet by steam, and send directly, bypassing |
| 251 | the kernel IP stack */ |
| 252 | |
| 253 | u32 i, sum; |
| 254 | unsigned char hwdest[ETHER_ADDR_LEN]; |
| 255 | |
| 256 | if (ntohs(mess->flags) & 0x8000) |
| 257 | { |
| 258 | memset(hwdest, 255, ETHER_ADDR_LEN); |
| 259 | rawpacket->ip.ip_dst.s_addr = INADDR_BROADCAST; |
| 260 | } |
| 261 | else |
| 262 | { |
| 263 | memcpy(hwdest, mess->chaddr, ETHER_ADDR_LEN); |
| 264 | rawpacket->ip.ip_dst.s_addr = mess->yiaddr.s_addr; |
| 265 | } |
| 266 | |
| 267 | rawpacket->ip.ip_p = IPPROTO_UDP; |
| 268 | rawpacket->ip.ip_src.s_addr = iface_addr.s_addr; |
| 269 | rawpacket->ip.ip_len = htons(sizeof(struct ip) + |
| 270 | sizeof(struct udphdr) + |
| 271 | newlen) ; |
| 272 | rawpacket->ip.ip_hl = sizeof(struct ip) / 4; |
| 273 | rawpacket->ip.ip_v = IPVERSION; |
| 274 | rawpacket->ip.ip_tos = 0; |
| 275 | rawpacket->ip.ip_id = htons(0); |
| 276 | rawpacket->ip.ip_off = htons(0x4000); /* don't fragment */ |
| 277 | rawpacket->ip.ip_ttl = IPDEFTTL; |
| 278 | rawpacket->ip.ip_sum = 0; |
| 279 | for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++) |
| 280 | sum += ((u16 *)&rawpacket->ip)[i]; |
| 281 | while (sum>>16) |
| 282 | sum = (sum & 0xffff) + (sum >> 16); |
| 283 | rawpacket->ip.ip_sum = (sum == 0xffff) ? sum : ~sum; |
| 284 | |
| 285 | rawpacket->udp.uh_sport = htons(DHCP_SERVER_PORT); |
| 286 | rawpacket->udp.uh_dport = htons(DHCP_CLIENT_PORT); |
| 287 | ((u8 *)&rawpacket->data)[newlen] = 0; /* for checksum, in case length is odd. */ |
| 288 | rawpacket->udp.uh_sum = 0; |
| 289 | rawpacket->udp.uh_ulen = sum = htons(sizeof(struct udphdr) + newlen); |
| 290 | sum += htons(IPPROTO_UDP); |
| 291 | for (i = 0; i < 4; i++) |
| 292 | sum += ((u16 *)&rawpacket->ip.ip_src)[i]; |
| 293 | for (i = 0; i < (sizeof(struct udphdr) + newlen + 1) / 2; i++) |
| 294 | sum += ((u16 *)&rawpacket->udp)[i]; |
| 295 | while (sum>>16) |
| 296 | sum = (sum & 0xffff) + (sum >> 16); |
| 297 | rawpacket->udp.uh_sum = (sum == 0xffff) ? sum : ~sum; |
| 298 | |
| 299 | { |
| 300 | #ifdef HAVE_BPF |
| 301 | struct ether_header header; |
| 302 | |
| 303 | header.ether_type = htons(ETHERTYPE_IP); |
| 304 | memcpy(header.ether_shost, iface_hwaddr, ETHER_ADDR_LEN); |
| 305 | memcpy(header.ether_dhost, hwdest, ETHER_ADDR_LEN); |
| 306 | |
| 307 | ioctl(raw_fd, BIOCSETIF, &ifr); |
| 308 | |
| 309 | iov[0].iov_base = (char *)&header; |
| 310 | iov[0].iov_len = sizeof(struct ether_header); |
| 311 | iov[1].iov_base = (char *)rawpacket; |
| 312 | iov[1].iov_len = ntohs(rawpacket->ip.ip_len); |
| 313 | writev(raw_fd, iov, 2); |
| 314 | #else |
| 315 | struct sockaddr_ll dest; |
| 316 | |
| 317 | dest.sll_family = AF_PACKET; |
| 318 | dest.sll_halen = ETHER_ADDR_LEN; |
| 319 | dest.sll_ifindex = iface_index; |
| 320 | dest.sll_protocol = htons(ETHERTYPE_IP); |
| 321 | memcpy(dest.sll_addr, hwdest, ETHER_ADDR_LEN); |
| 322 | sendto(raw_fd, rawpacket, ntohs(rawpacket->ip.ip_len), |
| 323 | 0, (struct sockaddr *)&dest, sizeof(dest)); |
| 324 | |
| 325 | #endif |
| 326 | } |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 327 | } |
| 328 | } |
| 329 | |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame^] | 330 | |
Simon Kelley | 9e4abcb | 2004-01-22 19:47:41 +0000 | [diff] [blame] | 331 | int address_available(struct dhcp_context *context, struct in_addr taddr) |
| 332 | { |
| 333 | /* Check is an address is OK for this network, ie |
| 334 | within allowable range and not in an existing lease */ |
| 335 | |
| 336 | unsigned int addr, start, end; |
| 337 | |
| 338 | addr = ntohl(taddr.s_addr); |
| 339 | start = ntohl(context->start.s_addr); |
| 340 | end = ntohl(context->end.s_addr); |
| 341 | |
| 342 | if (addr < start) |
| 343 | return 0; |
| 344 | |
| 345 | if (addr > end) |
| 346 | return 0; |
| 347 | |
| 348 | if (lease_find_by_addr(taddr)) |
| 349 | return 0; |
| 350 | |
| 351 | return 1; |
| 352 | } |
| 353 | |
| 354 | int address_allocate(struct dhcp_context *context, struct dhcp_config *configs, |
| 355 | struct in_addr *addrp) |
| 356 | { |
| 357 | /* Find a free address: exlude anything in use and anything allocated to |
| 358 | a particular hwaddr/clientid/hostname in our configuration */ |
| 359 | |
| 360 | struct dhcp_config *config; |
| 361 | struct in_addr start = context->last; |
| 362 | |
| 363 | do { |
| 364 | if (context->last.s_addr == context->end.s_addr) |
| 365 | context->last = context->start; |
| 366 | else |
| 367 | context->last.s_addr = htonl(ntohl(context->last.s_addr) + 1); |
| 368 | |
| 369 | |
| 370 | if (!lease_find_by_addr(context->last)) |
| 371 | { |
| 372 | for (config = configs; config; config = config->next) |
| 373 | if (config->addr.s_addr == context->last.s_addr) |
| 374 | break; |
| 375 | |
| 376 | if (!config) |
| 377 | { |
| 378 | *addrp = context->last; |
| 379 | return 1; |
| 380 | } |
| 381 | } |
| 382 | } while (context->last.s_addr != start.s_addr); |
| 383 | |
| 384 | return 0; |
| 385 | } |
| 386 | |
| 387 | static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *config) |
| 388 | { |
| 389 | if (!context) |
| 390 | return 1; |
| 391 | if (config->addr.s_addr == 0) |
| 392 | return 1; |
| 393 | if ((config->addr.s_addr & context->netmask.s_addr) == (context->start.s_addr & context->netmask.s_addr)) |
| 394 | return 1; |
| 395 | |
| 396 | return 0; |
| 397 | } |
| 398 | |
| 399 | struct dhcp_config *find_config(struct dhcp_config *configs, |
| 400 | struct dhcp_context *context, |
| 401 | unsigned char *clid, int clid_len, |
| 402 | unsigned char *hwaddr, char *hostname) |
| 403 | { |
| 404 | struct dhcp_config *config; |
| 405 | |
| 406 | if (clid_len) |
| 407 | for (config = configs; config; config = config->next) |
| 408 | { |
| 409 | if (config->clid_len == clid_len && |
| 410 | memcmp(config->clid, clid, clid_len) == 0 && |
| 411 | is_addr_in_context(context, config)) |
| 412 | return config; |
| 413 | |
| 414 | /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and |
| 415 | cope with that here */ |
| 416 | if (*clid == 0 && config->clid_len == clid_len-1 && |
| 417 | memcmp(config->clid, clid+1, clid_len-1) == 0 && |
| 418 | is_addr_in_context(context, config)) |
| 419 | return config; |
| 420 | } |
| 421 | |
| 422 | for (config = configs; config; config = config->next) |
| 423 | if (memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0 && |
| 424 | is_addr_in_context(context, config)) |
| 425 | return config; |
| 426 | |
| 427 | if (hostname) |
| 428 | for (config = configs; config; config = config->next) |
| 429 | if (config->hostname && strcmp(config->hostname, hostname) == 0 && |
| 430 | is_addr_in_context(context, config)) |
| 431 | return config; |
| 432 | |
| 433 | return NULL; |
| 434 | } |
| 435 | |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame^] | 436 | struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff) |
Simon Kelley | 1ab84e2 | 2004-01-29 16:48:35 +0000 | [diff] [blame] | 437 | { |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame^] | 438 | FILE *f = fopen(ETHERSFILE, "r"); |
| 439 | unsigned int e0, e1, e2, e3, e4, e5; |
| 440 | char *ip, *cp, *name; |
| 441 | struct in_addr addr; |
| 442 | struct dhcp_config *new; |
| 443 | |
| 444 | if (!f) |
| 445 | die("Failed to open " ETHERSFILE ":%s", NULL); |
| 446 | |
| 447 | while (fgets(buff, MAXDNAME, f)) |
| 448 | { |
| 449 | while (strlen(buff) > 0 && |
| 450 | (buff[strlen(buff)-1] == '\n' || |
| 451 | buff[strlen(buff)-1] == ' ' || |
| 452 | buff[strlen(buff)-1] == '\t')) |
| 453 | buff[strlen(buff)-1] = 0; |
| 454 | |
| 455 | if ((*buff == '#') || (*buff == '+')) |
| 456 | continue; |
| 457 | |
| 458 | for (ip = buff; *ip && *ip != ' '; ip++); |
| 459 | for(; *ip && *ip == ' '; ip++) |
| 460 | *ip = 0; |
| 461 | if (!*ip) |
| 462 | continue; |
| 463 | |
| 464 | if (!sscanf(buff, "%x:%x:%x:%x:%x:%x", &e0, &e1, &e2, &e3, &e4, &e5)) |
| 465 | continue; |
| 466 | |
| 467 | /* check for name or dotted-quad */ |
| 468 | for (cp = ip; *cp; cp++) |
| 469 | if (!(*cp == '.' || (*cp >='0' && *cp <= '9'))) |
| 470 | break; |
| 471 | |
| 472 | if (!*cp) |
| 473 | { |
| 474 | name = NULL; |
| 475 | if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1) |
| 476 | continue; |
| 477 | } |
| 478 | else |
| 479 | { |
| 480 | name = safe_string_alloc(ip); |
| 481 | addr.s_addr = 0; |
| 482 | } |
| 483 | |
| 484 | new = safe_malloc(sizeof(struct dhcp_config)); |
| 485 | new->clid_len = 0; |
| 486 | new->clid = NULL; |
| 487 | new->hwaddr[0] = e0; |
| 488 | new->hwaddr[1] = e1; |
| 489 | new->hwaddr[2] = e2; |
| 490 | new->hwaddr[3] = e3; |
| 491 | new->hwaddr[4] = e4; |
| 492 | new->hwaddr[5] = e5; |
| 493 | new->hostname = name; |
| 494 | new->addr = addr; |
| 495 | new->lease_time = 0; |
| 496 | new->next = configs; |
| 497 | |
| 498 | configs = new; |
| 499 | } |
| 500 | |
| 501 | fclose(f); |
| 502 | return configs; |
| 503 | } |
| 504 | |
| 505 | void dhcp_update_configs(struct dhcp_config *configs) |
| 506 | { |
| 507 | /* Some people like to keep all static IP addresses in /etc/hosts. |
| 508 | This goes through /etc/hosts and sets static addresses for any DHCP config |
| 509 | records which don't have an address and whose name matches. */ |
| 510 | |
Simon Kelley | 1ab84e2 | 2004-01-29 16:48:35 +0000 | [diff] [blame] | 511 | struct dhcp_config *config; |
| 512 | struct crec *crec; |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame^] | 513 | |
Simon Kelley | 1ab84e2 | 2004-01-29 16:48:35 +0000 | [diff] [blame] | 514 | for (config = configs; config; config = config->next) |
| 515 | if (config->addr.s_addr == 0 && config->hostname && |
| 516 | (crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) && |
| 517 | (crec->flags & F_HOSTS)) |
| 518 | config->addr = crec->addr.addr.addr4; |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame^] | 519 | |
Simon Kelley | 1ab84e2 | 2004-01-29 16:48:35 +0000 | [diff] [blame] | 520 | } |
Simon Kelley | 44a2a31 | 2004-03-10 20:04:35 +0000 | [diff] [blame^] | 521 | |