#define PACKET_SIZE(start, end) (((uint8_t *)end - (uint8_t *)start) < DHCPV4_MIN_PACKET_SIZE ? \
DHCPV4_MIN_PACKET_SIZE : (uint8_t *)end - (uint8_t *)start)
+#define MAX_PREFIX_LEN 28
static void dhcpv4_netevent_cb(unsigned long event, struct netevent_handler_info *info);
static int setup_dhcpv4_addresses(struct interface *iface);
{
int ret = 0;
+ enable = enable && (iface->dhcpv4 != MODE_DISABLED);
+
if (iface->dhcpv4_event.uloop.fd >= 0) {
uloop_fd_delete(&iface->dhcpv4_event.uloop);
close(iface->dhcpv4_event.uloop.fd);
iface->dhcpv4_event.uloop.fd = -1;
}
- if (iface->dhcpv4 && enable) {
+ if (enable) {
struct sockaddr_in bind_addr = {AF_INET, htons(DHCPV4_SERVER_PORT),
{INADDR_ANY}, {0}};
int val = 1;
if (iface->dhcpv4_start.s_addr & htonl(0xffff0000) ||
iface->dhcpv4_end.s_addr & htonl(0xffff0000) ||
ntohl(iface->dhcpv4_start.s_addr) > ntohl(iface->dhcpv4_end.s_addr)) {
- syslog(LOG_ERR, "Invalid DHCP range for %s", iface->name);
+ syslog(LOG_WARNING, "Invalid DHCP range for %s", iface->name);
return -1;
}
if (!iface->addr4_len) {
- syslog(LOG_ERR, "No network(s) available on %s", iface->name);
+ syslog(LOG_WARNING, "No network(s) available on %s", iface->name);
return -1;
}
}
}
- /* Don't allocate IP range for subnets bigger than 28 */
- if (iface->addr4[0].prefix > 28) {
- syslog(LOG_ERR, "Auto allocation of DHCP range fails on %s", iface->name);
+ /* Don't allocate IP range for subnets smaller than /28 */
+ if (iface->addr4[0].prefix > MAX_PREFIX_LEN) {
+ syslog(LOG_WARNING, "Auto allocation of DHCP range fails on %s (prefix length must be < %d).", iface->name, MAX_PREFIX_LEN + 1);
return -1;
}
a = list_first_entry(&iface->dhcpv4_fr_ips, struct odhcpd_ref_ip, head);
if (netlink_setup_addr(&a->addr, iface->ifindex, false, true)) {
- syslog(LOG_ERR, "Failed to add ip address on %s", iface->name);
+ syslog(LOG_WARNING, "Failed to add ip address on %s", iface->name);
return;
}
syslog(LOG_ERR, "Failed to send %s to %s - %s: %m", dhcpv4_msg_to_string(msg),
odhcpd_print_mac(a->hwaddr, sizeof(a->hwaddr)), inet_ntoa(dest.sin_addr));
else
- syslog(LOG_NOTICE, "Sent %s to %s - %s", dhcpv4_msg_to_string(msg),
+ syslog(LOG_DEBUG, "Sent %s to %s - %s", dhcpv4_msg_to_string(msg),
odhcpd_print_mac(a->hwaddr, sizeof(a->hwaddr)), inet_ntoa(dest.sin_addr));
}
a->fr_timer.cb = NULL;
}
+static int dhcpv4_send_reply(const void *buf, size_t len,
+ const struct sockaddr *dest, socklen_t dest_len,
+ void *opaque)
+{
+ int *sock = opaque;
+
+ return sendto(*sock, buf, len, MSG_DONTWAIT, dest, dest_len);
+}
+
/* Handler for DHCPv4 messages */
static void handle_dhcpv4(void *addr, void *data, size_t len,
struct interface *iface, _unused void *dest_addr)
+{
+ int sock = iface->dhcpv4_event.uloop.fd;
+
+ dhcpv4_handle_msg(addr, data, len, iface, dest_addr, dhcpv4_send_reply, &sock);
+}
+
+void dhcpv4_handle_msg(void *addr, void *data, size_t len,
+ struct interface *iface, _unused void *dest_addr,
+ send_reply_cb_t send_reply, void *opaque)
{
struct dhcpv4_message *req = data;
- if (!iface->dhcpv4)
+ if (iface->dhcpv4 == MODE_DISABLED)
return;
if (len < offsetof(struct dhcpv4_message, options) + 4 ||
req->op != DHCPV4_BOOTREQUEST || req->hlen != 6)
return;
- syslog(LOG_NOTICE, "Got DHCPv4 request on %s", iface->name);
+ syslog(LOG_DEBUG, "Got DHCPv4 request on %s", iface->name);
if (!iface->dhcpv4_start_ip.s_addr && !iface->dhcpv4_end_ip.s_addr) {
- syslog(LOG_ERR, "No DHCP range available on %s", iface->name);
+ syslog(LOG_WARNING, "No DHCP range available on %s", iface->name);
return;
}
req->ciaddr.s_addr = INADDR_ANY;
}
- syslog(LOG_NOTICE, "Received %s from %s on %s", dhcpv4_msg_to_string(reqmsg),
+ syslog(LOG_INFO, "Received %s from %s on %s", dhcpv4_msg_to_string(reqmsg),
odhcpd_print_mac(req->chaddr, req->hlen), iface->name);
#ifdef WITH_UBUS
if (reqmsg == DHCPV4_MSG_RELEASE)
ubus_bcast_dhcp_event("dhcp.release", req->chaddr, req->hlen,
- &req->ciaddr, hostname, iface->ifname);
+ &req->ciaddr, a ? a->hostname : NULL, iface->ifname);
#endif
if (reqmsg == DHCPV4_MSG_DECLINE || reqmsg == DHCPV4_MSG_RELEASE)
return;
4 * iface->dhcpv4_router_cnt, iface->dhcpv4_router);
- if (iface->dhcpv4_dns_cnt == 0)
- dhcpv4_put(&reply, &cookie, DHCPV4_OPT_DNSSERVER, 4, &iface->dhcpv4_local);
- else
+ if (iface->dhcpv4_dns_cnt == 0) {
+ if (iface->dns_service)
+ dhcpv4_put(&reply, &cookie, DHCPV4_OPT_DNSSERVER, 4, &iface->dhcpv4_local);
+ } else
dhcpv4_put(&reply, &cookie, DHCPV4_OPT_DNSSERVER,
4 * iface->dhcpv4_dns_cnt, iface->dhcpv4_dns);
+ if (a && a->reqopts && iface->dhcpv4_ntp_cnt != 0) {
+ for(size_t opts = 0; a->reqopts[opts]; opts++) {
+ if (a->reqopts[opts] == DHCPV4_OPT_NTPSERVER) {
+ dhcpv4_put(&reply, &cookie, DHCPV4_OPT_NTPSERVER,
+ 4 * iface->dhcpv4_ntp_cnt, iface->dhcpv4_ntp);
+ }
+ }
+ }
dhcpv4_put(&reply, &cookie, DHCPV4_OPT_END, 0, NULL);
dest.sin_addr = reply.yiaddr;
dest.sin_port = htons(DHCPV4_CLIENT_PORT);
- memcpy(arp.arp_ha.sa_data, req->chaddr, 6);
- memcpy(&arp.arp_pa, &dest, sizeof(arp.arp_pa));
- memcpy(arp.arp_dev, iface->ifname, sizeof(arp.arp_dev));
+ if (!(iface->ifflags & IFF_NOARP)) {
+ memcpy(arp.arp_ha.sa_data, req->chaddr, 6);
+ memcpy(&arp.arp_pa, &dest, sizeof(arp.arp_pa));
+ memcpy(arp.arp_dev, iface->ifname, sizeof(arp.arp_dev));
- if (ioctl(sock, SIOCSARP, &arp) < 0)
- syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
+ if (ioctl(sock, SIOCSARP, &arp) < 0)
+ syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
+ }
}
- if (sendto(sock, &reply, PACKET_SIZE(&reply, cookie), MSG_DONTWAIT,
- (struct sockaddr*)&dest, sizeof(dest)) < 0)
+ if (send_reply(&reply, PACKET_SIZE(&reply, cookie),
+ (struct sockaddr*)&dest, sizeof(dest), opaque) < 0)
syslog(LOG_ERR, "Failed to send %s to %s - %s: %m",
dhcpv4_msg_to_string(msg),
dest.sin_addr.s_addr == INADDR_BROADCAST ?
"ff:ff:ff:ff:ff:ff": odhcpd_print_mac(req->chaddr, req->hlen),
inet_ntoa(dest.sin_addr));
else
- syslog(LOG_NOTICE, "Sent %s to %s - %s",
+ syslog(LOG_DEBUG, "Sent %s to %s - %s",
dhcpv4_msg_to_string(msg),
dest.sin_addr.s_addr == INADDR_BROADCAST ?
"ff:ff:ff:ff:ff:ff": odhcpd_print_mac(req->chaddr, req->hlen),
#ifdef WITH_UBUS
if (msg == DHCPV4_MSG_ACK)
ubus_bcast_dhcp_event("dhcp.ack", req->chaddr, req->hlen, &reply.yiaddr,
- hostname, iface->ifname);
+ a ? a->hostname : NULL, iface->ifname);
#endif
}
a, a->addr);
if (assigned)
- syslog(LOG_INFO, "Assigning static IP: %s", ip4toa(a->addr));
+ syslog(LOG_DEBUG, "Assigning static IP: %s", ip4toa(a->addr));
return assigned;
}
a, raddr);
if (assigned) {
- syslog(LOG_INFO, "Assigning the IP the client asked for: %s",
+ syslog(LOG_DEBUG, "Assigning the IP the client asked for: %s",
ip4toa(a->addr));
return true;
a, n_try);
if (assigned) {
- syslog(LOG_INFO, "Assigning mapped IP: %s (try %u of %u)",
+ syslog(LOG_DEBUG, "Assigning mapped IP: %s (try %u of %u)",
ip4toa(a->addr), i + 1, count);
return true;
}
}
- syslog(LOG_WARNING, "Can't assign any IP address -> address space is full");
+ syslog(LOG_NOTICE, "Can't assign any IP address -> address space is full");
+
return false;
}
/* Create new binding */
a = alloc_assignment(0);
if (!a) {
- syslog(LOG_ERR, "Failed to alloc assignment on interface %s",
- iface->ifname);
+ syslog(LOG_WARNING, "Failed to alloc assignment on interface %s",
+ iface->ifname);
return NULL;
}
memcpy(a->hwaddr, mac, sizeof(a->hwaddr));
if (a->leasetime)
my_leasetime = a->leasetime;
else
- my_leasetime = iface->dhcpv4_leasetime;
+ my_leasetime = iface->dhcp_leasetime;
if ((*leasetime == 0) || (my_leasetime < *leasetime))
*leasetime = my_leasetime;
a->flags &= ~OAF_BOUND;
*incl_fr_opt = accept_fr_nonce;
- if (!(a->flags & OAF_STATIC))
- a->valid_until = now;
+ a->valid_until = now;
} else {
if ((!(a->flags & OAF_STATIC) || !a->hostname) && hostname_len > 0) {
a->hostname = realloc(a->hostname, hostname_len + 1);
} else
*incl_fr_opt = false;
- if (!(a->flags & OAF_STATIC))
- a->valid_until = ((*leasetime == UINT32_MAX) ? 0 : (time_t)(now + *leasetime));
+ a->valid_until = ((*leasetime == UINT32_MAX) ? 0 : (time_t)(now + *leasetime));
}
} else if (!assigned && a) {
/* Cleanup failed assignment */
} else if (msg == DHCPV4_MSG_RELEASE && a) {
a->flags &= ~OAF_BOUND;
-
- if (!(a->flags & OAF_STATIC))
- a->valid_until = now - 1;
+ a->valid_until = now - 1;
} else if (msg == DHCPV4_MSG_DECLINE && a) {
a->flags &= ~OAF_BOUND;
- if (!(a->flags & OAF_STATIC)) {
+ if (!(a->flags & OAF_STATIC) || a->lease->ipaddr != a->addr) {
memset(a->hwaddr, 0, sizeof(a->hwaddr));
a->valid_until = now + 3600; /* Block address for 1h */
- }
+ } else
+ a->valid_until = now - 1;
}
dhcpv6_ia_write_statefile();