strongswan: DHCP on lo fixes backport
authorJoel Low <[email protected]>
Fri, 31 Jan 2025 14:31:54 +0000 (22:31 +0800)
committerPhilip Prindeville <[email protected]>
Mon, 7 Apr 2025 02:06:55 +0000 (20:06 -0600)
Fixes #25801. Adds the following commits to fix DHCP behaviour on
Strongswan 5.9.14:

 - https://github.com/strongswan/strongswan/commit/abbf9d28b0032cf80b79bcacea3146a60800a6dd
 - https://github.com/strongswan/strongswan/commit/00d8c36d6fdf9e8ee99b9f92a64e7e81dbfa4432
 - https://github.com/strongswan/strongswan/commit/a50ed3006e8152eb2cf20e9f92f088ecc18081b0

Signed-off-by: Joel Low <[email protected]>
net/strongswan/Makefile
net/strongswan/patches/0005-pf-handler-Accept-loopback-interfaces-as-packet-sour.patch [new file with mode: 0644]
net/strongswan/patches/0006-pf-handler-Correctly-bind-packet-socket-to-an-interf.patch [new file with mode: 0644]
net/strongswan/patches/0007-dhcp-Add-option-to-bind-the-receive-socket-to-a-diff.patch [new file with mode: 0644]

index 6130a5b5faef9ff5abd98787a144abc408bb2bb5..672f1a809a91007e77d708a724fbb5d525b172fe 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=strongswan
 PKG_VERSION:=5.9.14
-PKG_RELEASE:=6
+PKG_RELEASE:=7
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
 PKG_SOURCE_URL:=https://download.strongswan.org/ https://download2.strongswan.org/
diff --git a/net/strongswan/patches/0005-pf-handler-Accept-loopback-interfaces-as-packet-sour.patch b/net/strongswan/patches/0005-pf-handler-Accept-loopback-interfaces-as-packet-sour.patch
new file mode 100644 (file)
index 0000000..5c8731d
--- /dev/null
@@ -0,0 +1,28 @@
+From abbf9d28b0032cf80b79bcacea3146a60800a6dd Mon Sep 17 00:00:00 2001
+From: Tobias Brunner <[email protected]>
+Date: Mon, 27 Jan 2025 09:40:56 +0100
+Subject: [PATCH 1/3] pf-handler: Accept loopback interfaces as packet source
+
+In some setups the responses from the DHCP server are sent via lo, which
+does not have an address of type `ARPHRD_ETHER` (the address length is
+the same, though, just all zeros, by default).  Note that the dhcp plugin
+doesn't actually care for the MAC address or interface details, that's
+only used by the farp plugin.
+
+Fixes: 187c72d1afdc ("dhcp: Port the plugin to FreeBSD/macOS")
+---
+ src/libcharon/network/pf_handler.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/src/libcharon/network/pf_handler.c
++++ b/src/libcharon/network/pf_handler.c
+@@ -176,7 +176,8 @@ static cached_iface_t *find_interface(pr
+       if (ioctl(fd, SIOCGIFNAME, &req) == 0 &&
+               ioctl(fd, SIOCGIFHWADDR, &req) == 0 &&
+-              req.ifr_hwaddr.sa_family == ARPHRD_ETHER)
++              (req.ifr_hwaddr.sa_family == ARPHRD_ETHER ||
++               req.ifr_hwaddr.sa_family == ARPHRD_LOOPBACK))
+       {
+               idx = find_least_used_cache_entry(this);
diff --git a/net/strongswan/patches/0006-pf-handler-Correctly-bind-packet-socket-to-an-interf.patch b/net/strongswan/patches/0006-pf-handler-Correctly-bind-packet-socket-to-an-interf.patch
new file mode 100644 (file)
index 0000000..89f6a68
--- /dev/null
@@ -0,0 +1,63 @@
+From 00d8c36d6fdf9e8ee99b9f92a64e7e81dbfa4432 Mon Sep 17 00:00:00 2001
+From: Tobias Brunner <[email protected]>
+Date: Thu, 30 Jan 2025 14:40:33 +0100
+Subject: [PATCH 2/3] pf-handler: Correctly bind packet socket to an interface
+
+Binding such sockets via SO_BINDTODEVICE does not work at all. Instead,
+bind() has to be used, as described in the packet(7) man page.
+---
+ src/libcharon/network/pf_handler.c | 31 +++++++++++++++++++++++++++---
+ 1 file changed, 28 insertions(+), 3 deletions(-)
+
+--- a/src/libcharon/network/pf_handler.c
++++ b/src/libcharon/network/pf_handler.c
+@@ -227,6 +227,30 @@ METHOD(pf_handler_t, destroy, void,
+ }
+ /**
++ * Bind the given packet socket to the a named device
++ */
++static bool bind_packet_socket_to_device(int fd, char *iface)
++{
++      struct sockaddr_ll addr = {
++              .sll_family = AF_PACKET,
++              .sll_ifindex = if_nametoindex(iface),
++      };
++
++      if (!addr.sll_ifindex)
++      {
++              DBG1(DBG_CFG, "unable to bind socket to '%s': not found", iface);
++              return FALSE;
++      }
++      if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1)
++      {
++              DBG1(DBG_CFG, "binding socket to '%s' failed: %s",
++                       iface, strerror(errno));
++              return FALSE;
++      }
++      return TRUE;
++}
++
++/**
+  * Setup capturing via AF_PACKET socket
+  */
+ static bool setup_internal(private_pf_handler_t *this, char *iface,
+@@ -248,14 +272,15 @@ static bool setup_internal(private_pf_ha
+                        this->name, strerror(errno));
+               return FALSE;
+       }
+-      if (iface && !bind_to_device(this->receive, iface))
++      if (iface && iface[0] && !bind_packet_socket_to_device(this->receive, iface))
+       {
+               return FALSE;
+       }
+       lib->watcher->add(lib->watcher, this->receive, WATCHER_READ,
+                                         receive_packet, this);
+-      DBG2(DBG_NET, "listening for %s (protocol=0x%04x) requests on fd=%d",
+-               this->name, protocol, this->receive);
++      DBG2(DBG_NET, "listening for %s (protocol=0x%04x) requests on fd=%d bound "
++               "to %s", this->name, protocol, this->receive,
++               iface && iface[0] ? iface : "no interface");
+       return TRUE;
+ }
diff --git a/net/strongswan/patches/0007-dhcp-Add-option-to-bind-the-receive-socket-to-a-diff.patch b/net/strongswan/patches/0007-dhcp-Add-option-to-bind-the-receive-socket-to-a-diff.patch
new file mode 100644 (file)
index 0000000..bb3319a
--- /dev/null
@@ -0,0 +1,66 @@
+From a50ed3006e8152eb2cf20e9f92f088ecc18081b0 Mon Sep 17 00:00:00 2001
+From: Tobias Brunner <[email protected]>
+Date: Wed, 29 Jan 2025 17:23:31 +0100
+Subject: [PATCH 3/3] dhcp: Add option to bind the receive socket to a
+ different interface
+
+This can be useful if the DHCP server runs on the same server. On Linux,
+the response is then sent via `lo`, so packets won't be received if both
+sockets are bound to e.g. a bridge interface.
+---
+ conf/plugins/dhcp.opt                    | 10 ++++++++++
+ src/libcharon/plugins/dhcp/dhcp_socket.c | 13 ++++++++-----
+ 2 files changed, 18 insertions(+), 5 deletions(-)
+
+--- a/conf/plugins/dhcp.opt
++++ b/conf/plugins/dhcp.opt
+@@ -36,3 +36,13 @@ charon.plugins.dhcp.interface
+       Interface name the plugin uses for address allocation. The default is to
+       bind to any (0.0.0.0) and let the system decide which way to route the
+       packets to the DHCP server.
++
++charon.plugins.dhcp.interface_receive = charon.plugins.dhcp.interface
++      Interface name the plugin uses to bind its receive socket.
++
++      Interface name the plugin uses to bind its receive socket. The default is
++      to use the same interface as the send socket. Set it to the empty string
++      to avoid binding the receive socket to any interface while the send socket
++      is bound to one. If the server runs on the same host and the send socket is
++      bound to an interface, it might be necessary to set this to `lo` or the
++      empty string.
+--- a/src/libcharon/plugins/dhcp/dhcp_socket.c
++++ b/src/libcharon/plugins/dhcp/dhcp_socket.c
+@@ -716,7 +716,7 @@ dhcp_socket_t *dhcp_socket_create()
+               },
+       };
+       socklen_t addr_len;
+-      char *iface;
++      char *iface, *iface_receive;
+       int on = 1, rcvbuf = 0;
+ #if !defined(__APPLE__) && !defined(__FreeBSD__)
+@@ -809,8 +809,11 @@ dhcp_socket_t *dhcp_socket_create()
+       this->dst = host_create_from_string(lib->settings->get_str(lib->settings,
+                                                               "%s.plugins.dhcp.server", "255.255.255.255",
+                                                               lib->ns), DHCP_SERVER_PORT);
+-      iface = lib->settings->get_str(lib->settings, "%s.plugins.dhcp.interface",
+-                                                                 NULL, lib->ns);
++      iface = lib->settings->get_str(lib->settings,
++                                                              "%s.plugins.dhcp.interface", NULL, lib->ns);
++      iface_receive = lib->settings->get_str(lib->settings,
++                                                              "%s.plugins.dhcp.interface_receive", NULL,
++                                                              lib->ns) ?: iface;
+       if (!this->dst)
+       {
+               DBG1(DBG_CFG, "configured DHCP server address invalid");
+@@ -873,8 +876,8 @@ dhcp_socket_t *dhcp_socket_create()
+               return NULL;
+       }
+-      this->pf_handler = pf_handler_create("DHCP", iface, receive_dhcp, this,
+-                                                                               &dhcp_filter);
++      this->pf_handler = pf_handler_create("DHCP", iface_receive, receive_dhcp,
++                                                                               this, &dhcp_filter);
+       if (!this->pf_handler)
+       {
+               destroy(this);