#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
+#include <poll.h>
#include <alloca.h>
#include <resolv.h>
#include <limits.h>
for (size_t i = 0; i < addrlen; ++i) {
if (addrs[i].prefix > 96)
continue;
+ if (c->valid_until <= now)
+ continue;
addr = addrs[i].addr;
if (c->length == 128)
md5_hash(c->hostname, strlen(c->hostname), &md5);
}
- l += snprintf(leasebuf + l, sizeof(leasebuf) - l, "%s/%hhu ", ipbuf,
+ l += snprintf(leasebuf + l, sizeof(leasebuf) - l, "%s/%d ", ipbuf,
(c->managed_size) ? addrs[i].prefix : c->length);
}
leasebuf[l - 1] = '\n';
assign->managed_size = -1;
assign->valid_until = odhcpd_time() + 15;
list_add(&assign->head, &iface->ia_assignments);
+
+ // Wait initial period of up to 250ms for immediate assignment
+ struct pollfd pfd = { .fd = fd, .events = POLLIN };
+ poll(&pfd, 1, 250);
+ managed_handle_pd_data(&assign->managed_sock.stream, 0);
+
+ if (fcntl(fd, F_GETFL) >= 0 && assign->managed_size > 0)
+ return true;
}
return false;
datalen += sizeof(stat);
} else {
if (a) {
- uint32_t pref = 3600;
- uint32_t valid = 3600;
+ uint32_t leasetime = iface->dhcpv4_leasetime;
+ if (leasetime == 0)
+ leasetime = 3600;
+ else if (leasetime < 60)
+ leasetime = 60;
+
+ uint32_t pref = leasetime;
+ uint32_t valid = leasetime;
struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->ia_addr;
size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->ia_addr_len;
char hostname[256];
size_t hostname_len = 0;
bool class_oro = false;
+ bool notonlink = false;
+
dhcpv6_for_each_option(start, end, otype, olen, odata) {
if (otype == DHCPV6_OPT_CLIENTID) {
clid_data = odata;
dhcpv6_for_each_option(start, end, otype, olen, odata) {
bool is_pd = (otype == DHCPV6_OPT_IA_PD);
bool is_na = (otype == DHCPV6_OPT_IA_NA);
+ bool ia_addr_present = false;
if (!is_pd && !is_na)
continue;
if (stype != DHCPV6_OPT_IA_ADDR || slen < sizeof(struct dhcpv6_ia_addr) - 4)
continue;
+ ia_addr_present = true;
#ifdef DHCPV6_OPT_PREFIX_CLASS
uint8_t *xdata;
uint16_t xtype, xlen;
a->valid_until = now + 3600; // Block address for 1h
update_state = true;
}
- } else if (hdr->msg_type == DHCPV6_MSG_CONFIRM) {
- // Always send NOTONLINK for CONFIRM so that clients restart connection
+ } else if (hdr->msg_type == DHCPV6_MSG_CONFIRM && ia_addr_present) {
+ // Send NOTONLINK for CONFIRM with addr present so that clients restart connection
status = DHCPV6_STATUS_NOTONLINK;
ia_response_len = append_reply(buf, buflen, status, ia, a, iface, true);
+ notonlink = true;
}
buf += ia_response_len;
response_len += ia_response_len;
}
- if (hdr->msg_type == DHCPV6_MSG_RELEASE && response_len + 6 < buflen) {
+ if ((hdr->msg_type == DHCPV6_MSG_RELEASE || hdr->msg_type == DHCPV6_MSG_DECLINE || notonlink) &&
+ response_len + 6 < buflen) {
buf[0] = 0;
buf[1] = DHCPV6_OPT_STATUS;
buf[2] = 0;
buf[3] = 2;
buf[4] = 0;
- buf[5] = DHCPV6_STATUS_OK;
+ buf[5] = (notonlink) ? DHCPV6_STATUS_NOTONLINK : DHCPV6_STATUS_OK;
response_len += 6;
}