dhcpv4: detect noarp interfaces
authorMikael Magnusson <mikma@users.sourceforge.net>
Tue, 7 Feb 2023 16:53:00 +0000 (16:53 +0000)
committerHans Dedecker <dedeckeh@gmail.com>
Thu, 16 Feb 2023 20:28:57 +0000 (21:28 +0100)
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 <mikma@users.sourceforge.net>
src/config.c
src/dhcpv4.c
src/netlink.c
src/odhcpd.c
src/odhcpd.h

index 4e3db86596b82548b8f3ac48dd73164a5cb260c1..9b1f659aa630033c27cd19a3526c75ed0daf7db2 100644 (file)
@@ -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) {
index 7ac7af9e73b7d5197bb32991d7217d850753061f..2b2f41e01cc3469f623186e425e31a835dc3eed8 100644 (file)
@@ -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),
index 63a0f8bd1f411ca579f8463612625bea662e03ad..4a352a65e4aaab16b5db14b6518998aa26594f6c 100644 (file)
@@ -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;
index 9797507db27fc2f00569de3507f57f11683643c1..554e5f1c0b880b3da4bd0eeb56c2949522b55d13 100644 (file)
@@ -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,
index 5ba68547db9efb070ccec3cf05d138c43806611b..d829033840552c1db5537733f1c520217d767ea3 100644 (file)
@@ -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);