1 /** 2 * Copyright (C) 2012-2013 Steven Barth <steven@midlink.org> 3 * Copyright (C) 2016 Hans Dedecker <dedeckeh@gmail.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License v2 as published by 7 * the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * 15 */ 16 17 #include <time.h> 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <unistd.h> 21 #include <stddef.h> 22 #include <stdlib.h> 23 #include <resolv.h> 24 #include <limits.h> 25 #include <net/if.h> 26 #include <net/if_arp.h> 27 #include <netinet/ip.h> 28 #include <sys/ioctl.h> 29 #include <sys/timerfd.h> 30 #include <arpa/inet.h> 31 32 #include <libubox/md5.h> 33 34 #include "odhcpd.h" 35 #include "dhcpv4.h" 36 #include "dhcpv6.h" 37 38 #define PACKET_SIZE(start, end) (((uint8_t *)end - (uint8_t *)start) < DHCPV4_MIN_PACKET_SIZE ? \ 39 DHCPV4_MIN_PACKET_SIZE : (uint8_t *)end - (uint8_t *)start) 40 41 static void dhcpv4_netevent_cb(unsigned long event, struct netevent_handler_info *info); 42 static int setup_dhcpv4_addresses(struct interface *iface); 43 static bool addr_is_fr_ip(struct interface *iface, struct in_addr *addr); 44 static void valid_until_cb(struct uloop_timeout *event); 45 static void handle_addrlist_change(struct interface *iface); 46 static void dhcpv4_fr_start(struct dhcp_assignment *a); 47 static void dhcpv4_fr_rand_delay(struct dhcp_assignment *a); 48 static void dhcpv4_fr_stop(struct dhcp_assignment *a); 49 static void handle_dhcpv4(void *addr, void *data, size_t len, 50 struct interface *iface, void *dest_addr); 51 static struct dhcp_assignment* dhcpv4_lease(struct interface *iface, 52 enum dhcpv4_msg msg, const uint8_t *mac, const uint32_t reqaddr, 53 uint32_t *leasetime, const char *hostname, const size_t hostname_len, 54 const bool accept_fr_nonce, bool *incl_fr_opt, uint32_t *fr_serverid, 55 const char *reqopts, const size_t reqopts_len); 56 57 static struct netevent_handler dhcpv4_netevent_handler = { .cb = dhcpv4_netevent_cb, }; 58 static struct uloop_timeout valid_until_timeout = {.cb = valid_until_cb}; 59 static uint32_t serial = 0; 60 61 struct odhcpd_ref_ip { 62 struct list_head head; 63 int ref_cnt; 64 struct odhcpd_ipaddr addr; 65 }; 66 67 /* Create socket and register events */ 68 int dhcpv4_init(void) 69 { 70 uloop_timeout_set(&valid_until_timeout, 1000); 71 netlink_add_netevent_handler(&dhcpv4_netevent_handler); 72 73 return 0; 74 } 75 76 int dhcpv4_setup_interface(struct interface *iface, bool enable) 77 { 78 int ret = 0; 79 80 enable = enable && (iface->dhcpv4 != MODE_DISABLED); 81 82 if (iface->dhcpv4_event.uloop.fd >= 0) { 83 uloop_fd_delete(&iface->dhcpv4_event.uloop); 84 close(iface->dhcpv4_event.uloop.fd); 85 iface->dhcpv4_event.uloop.fd = -1; 86 } 87 88 if (enable) { 89 struct sockaddr_in bind_addr = {AF_INET, htons(DHCPV4_SERVER_PORT), 90 {INADDR_ANY}, {0}}; 91 int val = 1; 92 93 iface->dhcpv4_event.uloop.fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP); 94 if (iface->dhcpv4_event.uloop.fd < 0) { 95 syslog(LOG_ERR, "socket(AF_INET): %m"); 96 ret = -1; 97 goto out; 98 } 99 100 /* Basic IPv4 configuration */ 101 if (setsockopt(iface->dhcpv4_event.uloop.fd, SOL_SOCKET, SO_REUSEADDR, 102 &val, sizeof(val)) < 0) { 103 syslog(LOG_ERR, "setsockopt(SO_REUSEADDR): %m"); 104 ret = -1; 105 goto out; 106 } 107 108 if (setsockopt(iface->dhcpv4_event.uloop.fd, SOL_SOCKET, SO_BROADCAST, 109 &val, sizeof(val)) < 0) { 110 syslog(LOG_ERR, "setsockopt(SO_BROADCAST): %m"); 111 ret = -1; 112 goto out; 113 } 114 115 if (setsockopt(iface->dhcpv4_event.uloop.fd, IPPROTO_IP, IP_PKTINFO, 116 &val, sizeof(val)) < 0) { 117 syslog(LOG_ERR, "setsockopt(IP_PKTINFO): %m"); 118 ret = -1; 119 goto out; 120 } 121 122 val = IPTOS_PREC_INTERNETCONTROL; 123 if (setsockopt(iface->dhcpv4_event.uloop.fd, IPPROTO_IP, IP_TOS, 124 &val, sizeof(val)) < 0) { 125 syslog(LOG_ERR, "setsockopt(IP_TOS): %m"); 126 ret = -1; 127 goto out; 128 } 129 130 val = IP_PMTUDISC_DONT; 131 if (setsockopt(iface->dhcpv4_event.uloop.fd, IPPROTO_IP, IP_MTU_DISCOVER, 132 &val, sizeof(val)) < 0) { 133 syslog(LOG_ERR, "setsockopt(IP_MTU_DISCOVER): %m"); 134 ret = -1; 135 goto out; 136 } 137 138 if (setsockopt(iface->dhcpv4_event.uloop.fd, SOL_SOCKET, SO_BINDTODEVICE, 139 iface->ifname, strlen(iface->ifname)) < 0) { 140 syslog(LOG_ERR, "setsockopt(SO_BINDTODEVICE): %m"); 141 ret = -1; 142 goto out; 143 } 144 145 if (bind(iface->dhcpv4_event.uloop.fd, (struct sockaddr*)&bind_addr, 146 sizeof(bind_addr)) < 0) { 147 syslog(LOG_ERR, "bind(): %m"); 148 ret = -1; 149 goto out; 150 } 151 152 if (setup_dhcpv4_addresses(iface) < 0) { 153 ret = -1; 154 goto out; 155 } 156 157 iface->dhcpv4_event.handle_dgram = handle_dhcpv4; 158 odhcpd_register(&iface->dhcpv4_event); 159 } else { 160 while (!list_empty(&iface->dhcpv4_assignments)) 161 free_assignment(list_first_entry(&iface->dhcpv4_assignments, 162 struct dhcp_assignment, head)); 163 } 164 165 out: 166 if (ret < 0 && iface->dhcpv4_event.uloop.fd >= 0) { 167 close(iface->dhcpv4_event.uloop.fd); 168 iface->dhcpv4_event.uloop.fd = -1; 169 } 170 171 return ret; 172 } 173 174 175 static void dhcpv4_netevent_cb(unsigned long event, struct netevent_handler_info *info) 176 { 177 struct interface *iface = info->iface; 178 179 if (!iface || iface->dhcpv4 == MODE_DISABLED) 180 return; 181 182 switch (event) { 183 case NETEV_IFINDEX_CHANGE: 184 dhcpv4_setup_interface(iface, true); 185 break; 186 case NETEV_ADDRLIST_CHANGE: 187 handle_addrlist_change(iface); 188 break; 189 default: 190 break; 191 } 192 } 193 194 static struct dhcp_assignment *find_assignment_by_hwaddr(struct interface *iface, const uint8_t *hwaddr) 195 { 196 struct dhcp_assignment *a; 197 198 list_for_each_entry(a, &iface->dhcpv4_assignments, head) 199 if (!memcmp(a->hwaddr, hwaddr, 6)) 200 return a; 201 202 return NULL; 203 } 204 205 static int setup_dhcpv4_addresses(struct interface *iface) 206 { 207 iface->dhcpv4_start_ip.s_addr = INADDR_ANY; 208 iface->dhcpv4_end_ip.s_addr = INADDR_ANY; 209 iface->dhcpv4_local.s_addr = INADDR_ANY; 210 iface->dhcpv4_bcast.s_addr = INADDR_ANY; 211 iface->dhcpv4_mask.s_addr = INADDR_ANY; 212 213 /* Sanity checks */ 214 if (iface->dhcpv4_start.s_addr & htonl(0xffff0000) || 215 iface->dhcpv4_end.s_addr & htonl(0xffff0000) || 216 ntohl(iface->dhcpv4_start.s_addr) > ntohl(iface->dhcpv4_end.s_addr)) { 217 syslog(LOG_WARNING, "Invalid DHCP range for %s", iface->name); 218 return -1; 219 } 220 221 if (!iface->addr4_len) { 222 syslog(LOG_WARNING, "No network(s) available on %s", iface->name); 223 return -1; 224 } 225 226 uint32_t start = ntohl(iface->dhcpv4_start.s_addr); 227 uint32_t end = ntohl(iface->dhcpv4_end.s_addr); 228 229 for (size_t i = 0; i < iface->addr4_len && start && end; i++) { 230 struct in_addr *addr = &iface->addr4[i].addr.in; 231 struct in_addr mask; 232 233 if (addr_is_fr_ip(iface, addr)) 234 continue; 235 236 odhcpd_bitlen2netmask(false, iface->addr4[i].prefix, &mask); 237 if ((start & ntohl(~mask.s_addr)) == start && 238 (end & ntohl(~mask.s_addr)) == end && 239 end < ntohl(~mask.s_addr)) { /* Exclude broadcast address */ 240 iface->dhcpv4_start_ip.s_addr = htonl(start) | 241 (addr->s_addr & mask.s_addr); 242 iface->dhcpv4_end_ip.s_addr = htonl(end) | 243 (addr->s_addr & mask.s_addr); 244 iface->dhcpv4_local = *addr; 245 iface->dhcpv4_bcast = iface->addr4[i].broadcast; 246 iface->dhcpv4_mask = mask; 247 return 0; 248 } 249 } 250 251 /* Don't allocate IP range for subnets bigger than 28 */ 252 if (iface->addr4[0].prefix > 28) { 253 syslog(LOG_WARNING, "Auto allocation of DHCP range fails on %s", iface->name); 254 return -1; 255 } 256 257 iface->dhcpv4_local = iface->addr4[0].addr.in; 258 iface->dhcpv4_bcast = iface->addr4[0].broadcast; 259 odhcpd_bitlen2netmask(false, iface->addr4[0].prefix, &iface->dhcpv4_mask); 260 end = start = iface->dhcpv4_local.s_addr & iface->dhcpv4_mask.s_addr; 261 262 /* Auto allocate ranges */ 263 if (ntohl(iface->dhcpv4_mask.s_addr) <= 0xffffff00) { /* /24, 150 of 256, [100..249] */ 264 iface->dhcpv4_start_ip.s_addr = start | htonl(100); 265 iface->dhcpv4_end_ip.s_addr = end | htonl(100 + 150 - 1); 266 } else if (ntohl(iface->dhcpv4_mask.s_addr) <= 0xffffff80) { /* /25, 100 of 128, [20..119] */ 267 iface->dhcpv4_start_ip.s_addr = start | htonl(20); 268 iface->dhcpv4_end_ip.s_addr = end | htonl(20 + 100 - 1); 269 } else if (ntohl(iface->dhcpv4_mask.s_addr) <= 0xffffffc0) { /* /26, 50 of 64, [10..59] */ 270 iface->dhcpv4_start_ip.s_addr = start | htonl(10); 271 iface->dhcpv4_end_ip.s_addr = end | htonl(10 + 50 - 1); 272 } else if (ntohl(iface->dhcpv4_mask.s_addr) <= 0xffffffe0) { /* /27, 20 of 32, [10..29] */ 273 iface->dhcpv4_start_ip.s_addr = start | htonl(10); 274 iface->dhcpv4_end_ip.s_addr = end | htonl(10 + 20 - 1); 275 } else { /* /28, 10 of 16, [3..12] */ 276 iface->dhcpv4_start_ip.s_addr = start | htonl(3); 277 iface->dhcpv4_end_ip.s_addr = end | htonl(3 + 10 - 1); 278 } 279 280 return 0; 281 } 282 283 static void inc_ref_cnt_ip(struct odhcpd_ref_ip **ptr, struct odhcpd_ref_ip *ip) 284 { 285 *ptr = ip; 286 ip->ref_cnt++; 287 } 288 289 static void decr_ref_cnt_ip(struct odhcpd_ref_ip **ptr, struct interface *iface) 290 { 291 struct odhcpd_ref_ip *ip = *ptr; 292 293 if (--ip->ref_cnt == 0) { 294 netlink_setup_addr(&ip->addr, iface->ifindex, false, false); 295 296 list_del(&ip->head); 297 free(ip); 298 } 299 300 *ptr = NULL; 301 } 302 303 static bool addr_is_fr_ip(struct interface *iface, struct in_addr *addr) 304 { 305 struct odhcpd_ref_ip *p; 306 307 list_for_each_entry(p, &iface->dhcpv4_fr_ips, head) { 308 if (addr->s_addr == p->addr.addr.in.s_addr) 309 return true; 310 } 311 312 return false; 313 } 314 315 static bool leases_require_fr(struct interface *iface, struct odhcpd_ipaddr *addr, 316 uint32_t mask) 317 { 318 struct dhcp_assignment *a = NULL; 319 struct odhcpd_ref_ip *fr_ip = NULL; 320 321 list_for_each_entry(a, &iface->dhcpv4_assignments, head) { 322 if ((a->accept_fr_nonce || iface->dhcpv4_forcereconf) && 323 !a->fr_ip && 324 ((a->addr & mask) == (addr->addr.in.s_addr & mask))) { 325 if (!fr_ip) { 326 fr_ip = calloc(1, sizeof(*fr_ip)); 327 if (!fr_ip) 328 break; 329 330 list_add(&fr_ip->head, &iface->dhcpv4_fr_ips); 331 fr_ip->addr = *addr; 332 } 333 inc_ref_cnt_ip(&a->fr_ip, fr_ip); 334 } 335 } 336 337 return fr_ip ? true : false; 338 } 339 340 static void valid_until_cb(struct uloop_timeout *event) 341 { 342 struct interface *iface; 343 time_t now = odhcpd_time(); 344 345 avl_for_each_element(&interfaces, iface, avl) { 346 struct dhcp_assignment *a, *n; 347 348 if (iface->dhcpv4 != MODE_SERVER) 349 continue; 350 351 list_for_each_entry_safe(a, n, &iface->dhcpv4_assignments, head) { 352 if (!INFINITE_VALID(a->valid_until) && a->valid_until < now) 353 free_assignment(a); 354 } 355 } 356 uloop_timeout_set(event, 1000); 357 } 358 359 static void handle_addrlist_change(struct interface *iface) 360 { 361 struct odhcpd_ipaddr ip; 362 struct odhcpd_ref_ip *a; 363 struct dhcp_assignment *c; 364 uint32_t mask = iface->dhcpv4_mask.s_addr; 365 366 memset(&ip, 0, sizeof(ip)); 367 ip.addr.in = iface->dhcpv4_local; 368 ip.prefix = odhcpd_netmask2bitlen(false, &iface->dhcpv4_mask); 369 ip.broadcast = iface->dhcpv4_bcast; 370 371 setup_dhcpv4_addresses(iface); 372 373 if ((ip.addr.in.s_addr & mask) == 374 (iface->dhcpv4_local.s_addr & iface->dhcpv4_mask.s_addr)) 375 return; 376 377 if (ip.addr.in.s_addr && !leases_require_fr(iface, &ip, mask)) 378 return; 379 380 if (iface->dhcpv4_local.s_addr == INADDR_ANY || list_empty(&iface->dhcpv4_fr_ips)) 381 return; 382 383 a = list_first_entry(&iface->dhcpv4_fr_ips, struct odhcpd_ref_ip, head); 384 385 if (netlink_setup_addr(&a->addr, iface->ifindex, false, true)) { 386 syslog(LOG_WARNING, "Failed to add ip address on %s", iface->name); 387 return; 388 } 389 390 list_for_each_entry(c, &iface->dhcpv4_assignments, head) { 391 if ((c->flags & OAF_BOUND) && c->fr_ip && !c->fr_cnt) { 392 if (c->accept_fr_nonce || iface->dhcpv4_forcereconf) 393 dhcpv4_fr_rand_delay(c); 394 else 395 dhcpv4_fr_stop(c); 396 } 397 } 398 } 399 400 static char *dhcpv4_msg_to_string(uint8_t reqmsg) 401 { 402 switch (reqmsg) { 403 case (DHCPV4_MSG_DISCOVER): 404 return "DHCPV4_MSG_DISCOVER"; 405 case (DHCPV4_MSG_OFFER): 406 return "DHCPV4_MSG_OFFER"; 407 case (DHCPV4_MSG_REQUEST): 408 return "DHCPV4_MSG_REQUEST"; 409 case (DHCPV4_MSG_DECLINE): 410 return "DHCPV4_MSG_DECLINE"; 411 case (DHCPV4_MSG_ACK): 412 return "DHCPV4_MSG_ACK"; 413 case (DHCPV4_MSG_NAK): 414 return "DHCPV4_MSG_NAK"; 415 case (DHCPV4_MSG_RELEASE): 416 return "DHCPV4_MSG_RELEASE"; 417 case (DHCPV4_MSG_INFORM): 418 return "DHCPV4_MSG_INFORM"; 419 case (DHCPV4_MSG_FORCERENEW): 420 return "DHCPV4_MSG_FORCERENEW"; 421 default: 422 return "UNKNOWN"; 423 } 424 } 425 426 static void dhcpv4_free_assignment(struct dhcp_assignment *a) 427 { 428 if (a->fr_ip) 429 dhcpv4_fr_stop(a); 430 } 431 432 static void dhcpv4_put(struct dhcpv4_message *msg, uint8_t **cookie, 433 uint8_t type, uint8_t len, const void *data) 434 { 435 uint8_t *c = *cookie; 436 uint8_t *end = (uint8_t *)msg + sizeof(*msg); 437 bool tag_only = type == DHCPV4_OPT_PAD || type == DHCPV4_OPT_END; 438 int total_len = tag_only ? 1 : 2 + len; 439 440 if (*cookie + total_len > end) 441 return; 442 443 *cookie += total_len; 444 *c++ = type; 445 446 if (tag_only) 447 return; 448 449 *c++ = len; 450 memcpy(c, data, len); 451 } 452 453 static void dhcpv4_fr_send(struct dhcp_assignment *a) 454 { 455 struct dhcpv4_message fr_msg = { 456 .op = DHCPV4_BOOTREPLY, 457 .htype = 1, 458 .hlen = 6, 459 .hops = 0, 460 .secs = 0, 461 .flags = 0, 462 .ciaddr = {INADDR_ANY}, 463 .yiaddr = {INADDR_ANY}, 464 .siaddr = {INADDR_ANY}, 465 .giaddr = {INADDR_ANY}, 466 .chaddr = {0}, 467 .sname = {0}, 468 .file = {0}, 469 }; 470 struct dhcpv4_auth_forcerenew *auth_o, auth = { 471 .protocol = 3, 472 .algorithm = 1, 473 .rdm = 0, 474 .replay = {htonl(time(NULL)), htonl(++serial)}, 475 .type = 2, 476 .key = {0}, 477 }; 478 struct interface *iface = a->iface; 479 480 odhcpd_urandom(&fr_msg.xid, sizeof(fr_msg.xid)); 481 memcpy(fr_msg.chaddr, a->hwaddr, fr_msg.hlen); 482 483 fr_msg.options[0] = 0x63; 484 fr_msg.options[1] = 0x82; 485 fr_msg.options[2] = 0x53; 486 fr_msg.options[3] = 0x63; 487 488 uint8_t *cookie = &fr_msg.options[4]; 489 uint8_t msg = DHCPV4_MSG_FORCERENEW; 490 491 dhcpv4_put(&fr_msg, &cookie, DHCPV4_OPT_MESSAGE, 1, &msg); 492 if (a->accept_fr_nonce) { 493 dhcpv4_put(&fr_msg, &cookie, DHCPV4_OPT_AUTHENTICATION, sizeof(auth), &auth); 494 auth_o = (struct dhcpv4_auth_forcerenew *)(cookie - sizeof(auth)); 495 dhcpv4_put(&fr_msg, &cookie, DHCPV4_OPT_END, 0, NULL); 496 497 md5_ctx_t md5; 498 uint8_t secretbytes[64]; 499 memset(secretbytes, 0, sizeof(secretbytes)); 500 memcpy(secretbytes, a->key, sizeof(a->key)); 501 502 for (size_t i = 0; i < sizeof(secretbytes); ++i) 503 secretbytes[i] ^= 0x36; 504 505 md5_begin(&md5); 506 md5_hash(secretbytes, sizeof(secretbytes), &md5); 507 md5_hash(&fr_msg, sizeof(fr_msg), &md5); 508 md5_end(auth_o->key, &md5); 509 510 for (size_t i = 0; i < sizeof(secretbytes); ++i) { 511 secretbytes[i] ^= 0x36; 512 secretbytes[i] ^= 0x5c; 513 } 514 515 md5_begin(&md5); 516 md5_hash(secretbytes, sizeof(secretbytes), &md5); 517 md5_hash(auth_o->key, sizeof(auth_o->key), &md5); 518 md5_end(auth_o->key, &md5); 519 } else { 520 dhcpv4_put(&fr_msg, &cookie, DHCPV4_OPT_SERVERID, 4, 521 &a->fr_ip->addr.addr.in.s_addr); 522 dhcpv4_put(&fr_msg, &cookie, DHCPV4_OPT_END, 0, NULL); 523 } 524 525 struct sockaddr_in dest; 526 memset(&dest, 0, sizeof(dest)); 527 dest.sin_family = AF_INET; 528 dest.sin_port = htons(DHCPV4_CLIENT_PORT); 529 dest.sin_addr.s_addr = a->addr; 530 531 if (sendto(iface->dhcpv4_event.uloop.fd, &fr_msg, PACKET_SIZE(&fr_msg, cookie), 532 MSG_DONTWAIT, (struct sockaddr*)&dest, sizeof(dest)) < 0) 533 syslog(LOG_ERR, "Failed to send %s to %s - %s: %m", dhcpv4_msg_to_string(msg), 534 odhcpd_print_mac(a->hwaddr, sizeof(a->hwaddr)), inet_ntoa(dest.sin_addr)); 535 else 536 syslog(LOG_DEBUG, "Sent %s to %s - %s", dhcpv4_msg_to_string(msg), 537 odhcpd_print_mac(a->hwaddr, sizeof(a->hwaddr)), inet_ntoa(dest.sin_addr)); 538 } 539 540 static void dhcpv4_fr_timer(struct uloop_timeout *event) 541 { 542 struct dhcp_assignment *a = container_of(event, struct dhcp_assignment, fr_timer); 543 544 if (a->fr_cnt > 0 && a->fr_cnt < 8) { 545 dhcpv4_fr_send(a); 546 uloop_timeout_set(&a->fr_timer, 1000 << a->fr_cnt); 547 a->fr_cnt++; 548 } else 549 dhcpv4_fr_stop(a); 550 } 551 552 static void dhcpv4_fr_start(struct dhcp_assignment *a) 553 { 554 uloop_timeout_set(&a->fr_timer, 1000 << a->fr_cnt); 555 a->fr_timer.cb = dhcpv4_fr_timer; 556 a->fr_cnt++; 557 558 dhcpv4_fr_send(a); 559 } 560 561 static void dhcpv4_fr_delay_timer(struct uloop_timeout *event) 562 { 563 struct dhcp_assignment *a = container_of(event, struct dhcp_assignment, fr_timer); 564 struct interface *iface = a->iface; 565 566 (iface->dhcpv4_event.uloop.fd == -1 ? dhcpv4_fr_rand_delay(a) : dhcpv4_fr_start(a)); 567 } 568 569 static void dhcpv4_fr_rand_delay(struct dhcp_assignment *a) 570 { 571 #define MIN_DELAY 500 572 #define MAX_FUZZ 500 573 int msecs; 574 575 odhcpd_urandom(&msecs, sizeof(msecs)); 576 577 msecs = labs(msecs)%MAX_FUZZ + MIN_DELAY; 578 579 uloop_timeout_set(&a->fr_timer, msecs); 580 a->fr_timer.cb = dhcpv4_fr_delay_timer; 581 } 582 583 static void dhcpv4_fr_stop(struct dhcp_assignment *a) 584 { 585 uloop_timeout_cancel(&a->fr_timer); 586 decr_ref_cnt_ip(&a->fr_ip, a->iface); 587 a->fr_cnt = 0; 588 a->fr_timer.cb = NULL; 589 } 590 591 static int dhcpv4_send_reply(const void *buf, size_t len, 592 const struct sockaddr *dest, socklen_t dest_len, 593 void *opaque) 594 { 595 int *sock = opaque; 596 597 return sendto(*sock, buf, len, MSG_DONTWAIT, dest, dest_len); 598 } 599 600 /* Handler for DHCPv4 messages */ 601 static void handle_dhcpv4(void *addr, void *data, size_t len, 602 struct interface *iface, _unused void *dest_addr) 603 { 604 int sock = iface->dhcpv4_event.uloop.fd; 605 606 dhcpv4_handle_msg(addr, data, len, iface, dest_addr, dhcpv4_send_reply, &sock); 607 } 608 609 void dhcpv4_handle_msg(void *addr, void *data, size_t len, 610 struct interface *iface, _unused void *dest_addr, 611 send_reply_cb_t send_reply, void *opaque) 612 { 613 struct dhcpv4_message *req = data; 614 615 if (iface->dhcpv4 == MODE_DISABLED) 616 return; 617 618 if (len < offsetof(struct dhcpv4_message, options) + 4 || 619 req->op != DHCPV4_BOOTREQUEST || req->hlen != 6) 620 return; 621 622 syslog(LOG_DEBUG, "Got DHCPv4 request on %s", iface->name); 623 624 if (!iface->dhcpv4_start_ip.s_addr && !iface->dhcpv4_end_ip.s_addr) { 625 syslog(LOG_WARNING, "No DHCP range available on %s", iface->name); 626 return; 627 } 628 629 int sock = iface->dhcpv4_event.uloop.fd; 630 631 struct dhcpv4_message reply = { 632 .op = DHCPV4_BOOTREPLY, 633 .htype = req->htype, 634 .hlen = req->hlen, 635 .hops = 0, 636 .xid = req->xid, 637 .secs = 0, 638 .flags = req->flags, 639 .ciaddr = {INADDR_ANY}, 640 .giaddr = req->giaddr, 641 .siaddr = iface->dhcpv4_local, 642 }; 643 memcpy(reply.chaddr, req->chaddr, sizeof(reply.chaddr)); 644 645 reply.options[0] = 0x63; 646 reply.options[1] = 0x82; 647 reply.options[2] = 0x53; 648 reply.options[3] = 0x63; 649 650 uint8_t *cookie = &reply.options[4]; 651 uint8_t reqmsg = DHCPV4_MSG_REQUEST; 652 uint8_t msg = DHCPV4_MSG_ACK; 653 654 uint32_t reqaddr = INADDR_ANY; 655 uint32_t leasetime = 0; 656 size_t hostname_len = 0; 657 size_t reqopts_len = 0; 658 char hostname[256]; 659 char reqopts[256]; 660 bool accept_fr_nonce = false; 661 bool incl_fr_opt = false; 662 663 uint8_t *start = &req->options[4]; 664 uint8_t *end = ((uint8_t*)data) + len; 665 struct dhcpv4_option *opt; 666 dhcpv4_for_each_option(start, end, opt) { 667 if (opt->type == DHCPV4_OPT_MESSAGE && opt->len == 1) 668 reqmsg = opt->data[0]; 669 else if (opt->type == DHCPV4_OPT_REQOPTS && opt->len > 0) { 670 reqopts_len = opt->len; 671 memcpy(reqopts, opt->data, reqopts_len); 672 reqopts[reqopts_len] = 0; 673 } else if (opt->type == DHCPV4_OPT_HOSTNAME && opt->len > 0) { 674 hostname_len = opt->len; 675 memcpy(hostname, opt->data, hostname_len); 676 hostname[hostname_len] = 0; 677 } else if (opt->type == DHCPV4_OPT_IPADDRESS && opt->len == 4) 678 memcpy(&reqaddr, opt->data, 4); 679 else if (opt->type == DHCPV4_OPT_SERVERID && opt->len == 4) { 680 if (memcmp(opt->data, &iface->dhcpv4_local, 4)) 681 return; 682 } else if (iface->filter_class && opt->type == DHCPV4_OPT_USER_CLASS) { 683 uint8_t *c = opt->data, *cend = &opt->data[opt->len]; 684 for (; c < cend && &c[*c] < cend; c = &c[1 + *c]) { 685 size_t elen = strlen(iface->filter_class); 686 if (*c == elen && !memcmp(&c[1], iface->filter_class, elen)) 687 return; // Ignore from homenet 688 } 689 } else if (opt->type == DHCPV4_OPT_LEASETIME && opt->len == 4) 690 memcpy(&leasetime, opt->data, 4); 691 else if (opt->type == DHCPV4_OPT_FORCERENEW_NONCE_CAPABLE && opt->len > 0) { 692 for (uint8_t i = 0; i < opt->len; i++) { 693 if (opt->data[i] == 1) { 694 accept_fr_nonce = true; 695 break; 696 } 697 } 698 699 } 700 } 701 702 if (reqmsg != DHCPV4_MSG_DISCOVER && reqmsg != DHCPV4_MSG_REQUEST && 703 reqmsg != DHCPV4_MSG_INFORM && reqmsg != DHCPV4_MSG_DECLINE && 704 reqmsg != DHCPV4_MSG_RELEASE) 705 return; 706 707 struct dhcp_assignment *a = NULL; 708 uint32_t serverid = iface->dhcpv4_local.s_addr; 709 uint32_t fr_serverid = INADDR_ANY; 710 711 if (reqmsg != DHCPV4_MSG_INFORM) 712 a = dhcpv4_lease(iface, reqmsg, req->chaddr, reqaddr, 713 &leasetime, hostname, hostname_len, 714 accept_fr_nonce, &incl_fr_opt, &fr_serverid, 715 reqopts, reqopts_len); 716 717 if (!a) { 718 if (reqmsg == DHCPV4_MSG_REQUEST) 719 msg = DHCPV4_MSG_NAK; 720 else if (reqmsg == DHCPV4_MSG_DISCOVER) 721 return; 722 } else if (reqmsg == DHCPV4_MSG_DISCOVER) 723 msg = DHCPV4_MSG_OFFER; 724 else if (reqmsg == DHCPV4_MSG_REQUEST && 725 ((reqaddr && reqaddr != a->addr) || 726 (req->ciaddr.s_addr && req->ciaddr.s_addr != a->addr))) { 727 msg = DHCPV4_MSG_NAK; 728 /* 729 * DHCP client requested an IP which we can't offer to him. Probably the 730 * client changed the network or the network has been changed. The reply 731 * type is set to DHCPV4_MSG_NAK, because the client should not use that IP. 732 * 733 * For modern devices we build an answer that includes a valid IP, like 734 * a DHCPV4_MSG_ACK. The client will use that IP and doesn't need to 735 * perform additional DHCP round trips. 736 * 737 */ 738 739 /* 740 * 741 * Buggy clients do serverid checking in nack messages; therefore set the 742 * serverid in nack messages triggered by a previous force renew equal to 743 * the server id in use at that time by the server 744 * 745 */ 746 if (fr_serverid) 747 serverid = fr_serverid; 748 749 if (req->ciaddr.s_addr && 750 ((iface->dhcpv4_start_ip.s_addr & iface->dhcpv4_mask.s_addr) != 751 (req->ciaddr.s_addr & iface->dhcpv4_mask.s_addr))) 752 req->ciaddr.s_addr = INADDR_ANY; 753 } 754 755 syslog(LOG_INFO, "Received %s from %s on %s", dhcpv4_msg_to_string(reqmsg), 756 odhcpd_print_mac(req->chaddr, req->hlen), iface->name); 757 758 #ifdef WITH_UBUS 759 if (reqmsg == DHCPV4_MSG_RELEASE) 760 ubus_bcast_dhcp_event("dhcp.release", req->chaddr, req->hlen, 761 &req->ciaddr, a ? a->hostname : NULL, iface->ifname); 762 #endif 763 if (reqmsg == DHCPV4_MSG_DECLINE || reqmsg == DHCPV4_MSG_RELEASE) 764 return; 765 766 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_MESSAGE, 1, &msg); 767 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_SERVERID, 4, &serverid); 768 769 if (a) { 770 uint32_t val; 771 772 reply.yiaddr.s_addr = a->addr; 773 774 val = htonl(leasetime); 775 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_LEASETIME, 4, &val); 776 777 if (leasetime != UINT32_MAX) { 778 val = htonl(500 * leasetime / 1000); 779 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_RENEW, 4, &val); 780 781 val = htonl(875 * leasetime / 1000); 782 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_REBIND, 4, &val); 783 } 784 785 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_NETMASK, 4, 786 &iface->dhcpv4_mask.s_addr); 787 788 if (a->hostname) 789 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_HOSTNAME, 790 strlen(a->hostname), a->hostname); 791 792 if (iface->dhcpv4_bcast.s_addr != INADDR_ANY) 793 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_BROADCAST, 4, &iface->dhcpv4_bcast); 794 795 if (incl_fr_opt) { 796 if (reqmsg == DHCPV4_MSG_REQUEST) { 797 struct dhcpv4_auth_forcerenew auth = { 798 .protocol = 3, 799 .algorithm = 1, 800 .rdm = 0, 801 .replay = {htonl(time(NULL)), htonl(++serial)}, 802 .type = 1, 803 .key = {0}, 804 }; 805 806 memcpy(auth.key, a->key, sizeof(auth.key)); 807 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_AUTHENTICATION, sizeof(auth), &auth); 808 } else { 809 uint8_t one = 1; 810 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_FORCERENEW_NONCE_CAPABLE, 811 sizeof(one), &one); 812 } 813 } 814 } 815 816 struct ifreq ifr; 817 818 memset(&ifr, 0, sizeof(ifr)); 819 strncpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name) - 1); 820 821 if (!ioctl(sock, SIOCGIFMTU, &ifr)) { 822 uint16_t mtu = htons(ifr.ifr_mtu); 823 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_MTU, 2, &mtu); 824 } 825 826 if (iface->search && iface->search_len <= 255) 827 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_SEARCH_DOMAIN, 828 iface->search_len, iface->search); 829 else if (!res_init() && _res.dnsrch[0] && _res.dnsrch[0][0]) { 830 uint8_t search_buf[256]; 831 int len = dn_comp(_res.dnsrch[0], search_buf, 832 sizeof(search_buf), NULL, NULL); 833 if (len > 0) 834 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_SEARCH_DOMAIN, 835 len, search_buf); 836 } 837 838 if (iface->dhcpv4_router_cnt == 0) 839 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_ROUTER, 4, &iface->dhcpv4_local); 840 else 841 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_ROUTER, 842 4 * iface->dhcpv4_router_cnt, iface->dhcpv4_router); 843 844 845 if (iface->dhcpv4_dns_cnt == 0) { 846 if (iface->dns_service) 847 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_DNSSERVER, 4, &iface->dhcpv4_local); 848 } else 849 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_DNSSERVER, 850 4 * iface->dhcpv4_dns_cnt, iface->dhcpv4_dns); 851 852 if (a && a->reqopts && iface->dhcpv4_ntp_cnt != 0) { 853 for(size_t opts = 0; a->reqopts[opts]; opts++) { 854 if (a->reqopts[opts] == DHCPV4_OPT_NTPSERVER) { 855 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_NTPSERVER, 856 4 * iface->dhcpv4_ntp_cnt, iface->dhcpv4_ntp); 857 } 858 } 859 } 860 861 dhcpv4_put(&reply, &cookie, DHCPV4_OPT_END, 0, NULL); 862 863 struct sockaddr_in dest = *((struct sockaddr_in*)addr); 864 if (req->giaddr.s_addr) { 865 /* 866 * relay agent is configured, send reply to the agent 867 */ 868 dest.sin_addr = req->giaddr; 869 dest.sin_port = htons(DHCPV4_SERVER_PORT); 870 } else if (req->ciaddr.s_addr && req->ciaddr.s_addr != dest.sin_addr.s_addr) { 871 /* 872 * client has existing configuration (ciaddr is set) AND this address is 873 * not the address it used for the dhcp message 874 */ 875 dest.sin_addr = req->ciaddr; 876 dest.sin_port = htons(DHCPV4_CLIENT_PORT); 877 } else if ((ntohs(req->flags) & DHCPV4_FLAG_BROADCAST) || 878 req->hlen != reply.hlen || !reply.yiaddr.s_addr) { 879 /* 880 * client requests a broadcast reply OR we can't offer an IP 881 */ 882 dest.sin_addr.s_addr = INADDR_BROADCAST; 883 dest.sin_port = htons(DHCPV4_CLIENT_PORT); 884 } else if (!req->ciaddr.s_addr && msg == DHCPV4_MSG_NAK) { 885 /* 886 * client has no previous configuration -> no IP, so we need to reply 887 * with a broadcast packet 888 */ 889 dest.sin_addr.s_addr = INADDR_BROADCAST; 890 dest.sin_port = htons(DHCPV4_CLIENT_PORT); 891 } else { 892 struct arpreq arp = {.arp_flags = ATF_COM}; 893 894 /* 895 * send reply to the newly (in this proccess) allocated IP 896 */ 897 dest.sin_addr = reply.yiaddr; 898 dest.sin_port = htons(DHCPV4_CLIENT_PORT); 899 900 if (!(iface->ifflags & IFF_NOARP)) { 901 memcpy(arp.arp_ha.sa_data, req->chaddr, 6); 902 memcpy(&arp.arp_pa, &dest, sizeof(arp.arp_pa)); 903 memcpy(arp.arp_dev, iface->ifname, sizeof(arp.arp_dev)); 904 905 if (ioctl(sock, SIOCSARP, &arp) < 0) 906 syslog(LOG_ERR, "ioctl(SIOCSARP): %m"); 907 } 908 } 909 910 if (send_reply(&reply, PACKET_SIZE(&reply, cookie), 911 (struct sockaddr*)&dest, sizeof(dest), opaque) < 0) 912 syslog(LOG_ERR, "Failed to send %s to %s - %s: %m", 913 dhcpv4_msg_to_string(msg), 914 dest.sin_addr.s_addr == INADDR_BROADCAST ? 915 "ff:ff:ff:ff:ff:ff": odhcpd_print_mac(req->chaddr, req->hlen), 916 inet_ntoa(dest.sin_addr)); 917 else 918 syslog(LOG_DEBUG, "Sent %s to %s - %s", 919 dhcpv4_msg_to_string(msg), 920 dest.sin_addr.s_addr == INADDR_BROADCAST ? 921 "ff:ff:ff:ff:ff:ff": odhcpd_print_mac(req->chaddr, req->hlen), 922 inet_ntoa(dest.sin_addr)); 923 924 925 #ifdef WITH_UBUS 926 if (msg == DHCPV4_MSG_ACK) 927 ubus_bcast_dhcp_event("dhcp.ack", req->chaddr, req->hlen, &reply.yiaddr, 928 a ? a->hostname : NULL, iface->ifname); 929 #endif 930 } 931 932 static bool dhcpv4_insert_assignment(struct list_head *list, struct dhcp_assignment *a, 933 uint32_t addr) 934 { 935 uint32_t h_addr = ntohl(addr); 936 struct dhcp_assignment *c; 937 938 list_for_each_entry(c, list, head) { 939 uint32_t c_addr = ntohl(c->addr); 940 941 if (c_addr == h_addr) 942 return false; 943 944 if (c_addr > h_addr) 945 break; 946 } 947 948 /* Insert new node before c (might match list head) */ 949 a->addr = addr; 950 list_add_tail(&a->head, &c->head); 951 952 return true; 953 } 954 955 static char* ip4toa(uint32_t addr) 956 { 957 static char buf[16]; 958 959 snprintf(buf, sizeof(buf), "%u.%u.%u.%u", 960 ((uint8_t *)&addr)[0], ((uint8_t *)&addr)[1], 961 ((uint8_t *)&addr)[2], ((uint8_t *)&addr)[3]); 962 963 return buf; 964 } 965 966 static bool dhcpv4_assign(struct interface *iface, struct dhcp_assignment *a, 967 uint32_t raddr) 968 { 969 uint32_t start = ntohl(iface->dhcpv4_start_ip.s_addr); 970 uint32_t end = ntohl(iface->dhcpv4_end_ip.s_addr); 971 uint32_t count = end - start + 1; 972 uint32_t seed = 0; 973 bool assigned; 974 975 /* Preconfigured IP address by static lease */ 976 if (a->addr) { 977 assigned = dhcpv4_insert_assignment(&iface->dhcpv4_assignments, 978 a, a->addr); 979 980 if (assigned) 981 syslog(LOG_DEBUG, "Assigning static IP: %s", ip4toa(a->addr)); 982 983 return assigned; 984 } 985 986 /* try to assign the IP the client asked for */ 987 if (start <= ntohl(raddr) && ntohl(raddr) <= end && 988 !config_find_lease_by_ipaddr(raddr)) { 989 assigned = dhcpv4_insert_assignment(&iface->dhcpv4_assignments, 990 a, raddr); 991 992 if (assigned) { 993 syslog(LOG_DEBUG, "Assigning the IP the client asked for: %s", 994 ip4toa(a->addr)); 995 996 return true; 997 } 998 } 999 1000 /* Seed RNG with checksum of hwaddress */ 1001 for (size_t i = 0; i < sizeof(a->hwaddr); ++i) { 1002 /* Knuth's multiplicative method */ 1003 uint8_t o = a->hwaddr[i]; 1004 seed += (o*2654435761) % UINT32_MAX; 1005 } 1006 1007 srand(seed); 1008 1009 for (uint32_t i = 0, try = (((uint32_t)rand()) % count) + start; i < count; 1010 ++i, try = (((try - start) + 1) % count) + start) { 1011 uint32_t n_try = htonl(try); 1012 1013 if (config_find_lease_by_ipaddr(n_try)) 1014 continue; 1015 1016 assigned = dhcpv4_insert_assignment(&iface->dhcpv4_assignments, 1017 a, n_try); 1018 1019 if (assigned) { 1020 syslog(LOG_DEBUG, "Assigning mapped IP: %s (try %u of %u)", 1021 ip4toa(a->addr), i + 1, count); 1022 1023 return true; 1024 } 1025 } 1026 1027 syslog(LOG_NOTICE, "Can't assign any IP address -> address space is full"); 1028 1029 return false; 1030 } 1031 1032 1033 static struct dhcp_assignment* 1034 dhcpv4_lease(struct interface *iface, enum dhcpv4_msg msg, const uint8_t *mac, 1035 const uint32_t reqaddr, uint32_t *leasetime, const char *hostname, 1036 const size_t hostname_len, const bool accept_fr_nonce, bool *incl_fr_opt, 1037 uint32_t *fr_serverid, const char* reqopts, const size_t reqopts_len) 1038 { 1039 struct dhcp_assignment *a = find_assignment_by_hwaddr(iface, mac); 1040 struct lease *l = config_find_lease_by_mac(mac); 1041 time_t now = odhcpd_time(); 1042 1043 if (l && a && a->lease != l) { 1044 free_assignment(a); 1045 a = NULL; 1046 } 1047 1048 if (a && (a->flags & OAF_BOUND) && a->fr_ip) { 1049 *fr_serverid = a->fr_ip->addr.addr.in.s_addr; 1050 dhcpv4_fr_stop(a); 1051 } 1052 1053 if (msg == DHCPV4_MSG_DISCOVER || msg == DHCPV4_MSG_REQUEST) { 1054 bool assigned = !!a; 1055 1056 if (!a) { 1057 if (!iface->no_dynamic_dhcp || l) { 1058 /* Create new binding */ 1059 a = alloc_assignment(0); 1060 if (!a) { 1061 syslog(LOG_WARNING, "Failed to alloc assignment on interface %s", 1062 iface->ifname); 1063 return NULL; 1064 } 1065 memcpy(a->hwaddr, mac, sizeof(a->hwaddr)); 1066 /* Set valid time to 0 for static lease indicating */ 1067 /* infinite lifetime otherwise current time */ 1068 a->valid_until = l ? 0 : now; 1069 a->dhcp_free_cb = dhcpv4_free_assignment; 1070 a->iface = iface; 1071 a->flags = OAF_DHCPV4; 1072 a->addr = l ? l->ipaddr : INADDR_ANY; 1073 1074 assigned = dhcpv4_assign(iface, a, reqaddr); 1075 1076 if (l) { 1077 a->flags |= OAF_STATIC; 1078 1079 if (l->hostname) 1080 a->hostname = strdup(l->hostname); 1081 1082 if (l->leasetime) 1083 a->leasetime = l->leasetime; 1084 1085 list_add(&a->lease_list, &l->assignments); 1086 a->lease = l; 1087 } 1088 } 1089 } else if (((a->addr & iface->dhcpv4_mask.s_addr) != 1090 (iface->dhcpv4_start_ip.s_addr & iface->dhcpv4_mask.s_addr)) && 1091 !(a->flags & OAF_STATIC)) { 1092 list_del_init(&a->head); 1093 a->addr = INADDR_ANY; 1094 1095 assigned = dhcpv4_assign(iface, a, reqaddr); 1096 } 1097 1098 if (assigned) { 1099 uint32_t my_leasetime; 1100 1101 if (a->leasetime) 1102 my_leasetime = a->leasetime; 1103 else 1104 my_leasetime = iface->dhcp_leasetime; 1105 1106 if ((*leasetime == 0) || (my_leasetime < *leasetime)) 1107 *leasetime = my_leasetime; 1108 1109 if (msg == DHCPV4_MSG_DISCOVER) { 1110 a->flags &= ~OAF_BOUND; 1111 1112 *incl_fr_opt = accept_fr_nonce; 1113 a->valid_until = now; 1114 } else { 1115 if ((!(a->flags & OAF_STATIC) || !a->hostname) && hostname_len > 0) { 1116 a->hostname = realloc(a->hostname, hostname_len + 1); 1117 if (a->hostname) { 1118 memcpy(a->hostname, hostname, hostname_len); 1119 a->hostname[hostname_len] = 0; 1120 1121 if (odhcpd_valid_hostname(a->hostname)) 1122 a->flags &= ~OAF_BROKEN_HOSTNAME; 1123 else 1124 a->flags |= OAF_BROKEN_HOSTNAME; 1125 } 1126 } 1127 1128 if (reqopts_len > 0) { 1129 a->reqopts = realloc(a->reqopts, reqopts_len + 1); 1130 if (a->reqopts) { 1131 memcpy(a->reqopts, reqopts, reqopts_len); 1132 a->reqopts[reqopts_len] = 0; 1133 } 1134 } 1135 1136 if (!(a->flags & OAF_BOUND)) { 1137 a->accept_fr_nonce = accept_fr_nonce; 1138 *incl_fr_opt = accept_fr_nonce; 1139 odhcpd_urandom(a->key, sizeof(a->key)); 1140 a->flags |= OAF_BOUND; 1141 } else 1142 *incl_fr_opt = false; 1143 1144 a->valid_until = ((*leasetime == UINT32_MAX) ? 0 : (time_t)(now + *leasetime)); 1145 } 1146 } else if (!assigned && a) { 1147 /* Cleanup failed assignment */ 1148 free_assignment(a); 1149 a = NULL; 1150 } 1151 1152 } else if (msg == DHCPV4_MSG_RELEASE && a) { 1153 a->flags &= ~OAF_BOUND; 1154 a->valid_until = now - 1; 1155 1156 } else if (msg == DHCPV4_MSG_DECLINE && a) { 1157 a->flags &= ~OAF_BOUND; 1158 1159 if (!(a->flags & OAF_STATIC) || a->lease->ipaddr != a->addr) { 1160 memset(a->hwaddr, 0, sizeof(a->hwaddr)); 1161 a->valid_until = now + 3600; /* Block address for 1h */ 1162 } else 1163 a->valid_until = now - 1; 1164 } 1165 1166 dhcpv6_ia_write_statefile(); 1167 1168 return a; 1169 } 1170
This page was automatically generated by LXR 0.3.1. • OpenWrt