From dfab0fad85c8b705c483343c99907c229413f7b2 Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Tue, 7 Feb 2023 16:53:00 +0000 Subject: [PATCH] dhcpv4: detect noarp interfaces Don't add ARP entries to interfaces with IFF_NOARP, it causes problems with for example WireGuard interfaces (which requires this change to be usable with DHCPv4-over-DHCPv6). Signed-off-by: Mikael Magnusson --- src/config.c | 3 +++ src/dhcpv4.c | 12 +++++++----- src/netlink.c | 7 ++++++- src/odhcpd.c | 12 ++++++++++++ src/odhcpd.h | 2 ++ 5 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/config.c b/src/config.c index 4e3db86..9b1f659 100644 --- a/src/config.c +++ b/src/config.c @@ -582,6 +582,9 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr if (!iface->ifindex && (iface->ifindex = if_nametoindex(iface->ifname)) <= 0) goto err; + + if ((iface->ifflags = odhcpd_get_flags(iface)) < 0) + goto err; } if (get_addrs) { diff --git a/src/dhcpv4.c b/src/dhcpv4.c index 7ac7af9..2b2f41e 100644 --- a/src/dhcpv4.c +++ b/src/dhcpv4.c @@ -897,12 +897,14 @@ void dhcpv4_handle_msg(void *addr, void *data, size_t len, 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 (send_reply(&reply, PACKET_SIZE(&reply, cookie), diff --git a/src/netlink.c b/src/netlink.c index 63a0f8b..4a352a6 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -308,7 +308,12 @@ static int handle_rtm_link(struct nlmsghdr *hdr) ifname = nla_get_string(nla[IFLA_IFNAME]); avl_for_each_element(&interfaces, iface, avl) { - if (strcmp(iface->ifname, ifname) || iface->ifindex == ifi->ifi_index) + if (strcmp(iface->ifname, ifname)) + continue; + + iface->ifflags = ifi->ifi_flags; + + if (iface->ifindex == ifi->ifi_index) continue; iface->ifindex = ifi->ifi_index; diff --git a/src/odhcpd.c b/src/odhcpd.c index 9797507..554e5f1 100644 --- a/src/odhcpd.c +++ b/src/odhcpd.c @@ -171,6 +171,18 @@ int odhcpd_get_mac(const struct interface *iface, uint8_t mac[6]) return 0; } +int odhcpd_get_flags(const struct interface *iface) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name) - 1); + if (ioctl(ioctl_sock, SIOCGIFFLAGS, &ifr) < 0) + return -1; + + return ifr.ifr_flags; +} + /* Forwards a packet on a specific interface */ ssize_t odhcpd_send(int socket, struct sockaddr_in6 *dest, diff --git a/src/odhcpd.h b/src/odhcpd.h index 5ba6854..d829033 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -238,6 +238,7 @@ struct dhcp_assignment { struct interface { struct avl_node avl; + int ifflags; int ifindex; char *ifname; const char *name; @@ -401,6 +402,7 @@ int odhcpd_get_interface_dns_addr(const struct interface *iface, struct in6_addr *addr); int odhcpd_get_interface_config(const char *ifname, const char *what); int odhcpd_get_mac(const struct interface *iface, uint8_t mac[6]); +int odhcpd_get_flags(const struct interface *iface); struct interface* odhcpd_get_interface_by_index(int ifindex); int odhcpd_urandom(void *data, size_t len); -- 2.30.2