From: Tobias Brunner Date: Fri, 10 Mar 2023 09:43:24 +0000 (+0100) Subject: dhcp: Don't use get_source_addr() to determine source address X-Git-Tag: 5.9.11dr1~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3c8887326aecc29db332e7d63a1103e08ff64741;p=thirdparty%2Fstrongswan.git dhcp: Don't use get_source_addr() to determine source address That method is subject to interface filtering, which isn't ideal for DHCP traffic that probably uses an internal interface on which the IKE daemon might be disabled. In that case `giaddr` is set to an incorrect public IP, which in turn might prevent the plugin from receiving the DHCP server's unicast response, in particular if the DHCP socket is bound to the internal interface. This new approach connects the client socket and thereby determines the source address to reach the DHCP server. Closes strongswan/strongswan#1573 --- diff --git a/src/libcharon/plugins/dhcp/dhcp_socket.c b/src/libcharon/plugins/dhcp/dhcp_socket.c index 815d2c65c8..a3572766da 100644 --- a/src/libcharon/plugins/dhcp/dhcp_socket.c +++ b/src/libcharon/plugins/dhcp/dhcp_socket.c @@ -111,6 +111,11 @@ struct private_dhcp_socket_t { * Force configured destination address */ bool force_dst; + + /** + * Source IP if destination address is unicast + */ + struct sockaddr_in src; }; /** @@ -202,7 +207,6 @@ static int prepare_dhcp(private_dhcp_socket_t *this, identification_t *identity; dhcp_option_t *option; int optlen = 0, remaining; - host_t *src; uint32_t id; memset(dhcp, 0, sizeof(*dhcp)); @@ -219,14 +223,8 @@ static int prepare_dhcp(private_dhcp_socket_t *this, } else { - /* act as relay agent */ - src = charon->kernel->get_source_addr(charon->kernel, this->dst, NULL); - if (src) - { - memcpy(&dhcp->gateway_address, src->get_address(src).ptr, - sizeof(dhcp->gateway_address)); - src->destroy(src); - } + memcpy(&dhcp->gateway_address, &this->src.sin_addr, + sizeof(dhcp->gateway_address)); } identity = transaction->get_identity(transaction); @@ -736,6 +734,7 @@ dhcp_socket_t *dhcp_socket_create() .s_addr = INADDR_ANY, }, }; + socklen_t addr_len; char *iface; int on = 1, rcvbuf = 0; struct sock_filter dhcp_filter_code[] = { @@ -888,6 +887,25 @@ dhcp_socket_t *dhcp_socket_create() return NULL; } } + if (!is_broadcast(this->dst)) + { + if (connect(this->send, this->dst->get_sockaddr(this->dst), + *this->dst->get_sockaddr_len(this->dst)) < 0) + { + DBG1(DBG_CFG, "unable to connect DHCP send socket: %s", + strerror(errno)); + destroy(this); + return NULL; + } + addr_len = sizeof(this->src); + if (getsockname(this->send, &this->src, &addr_len) < 0) + { + DBG1(DBG_CFG, "unable to determine source address for DHCP: %s", + strerror(errno)); + destroy(this); + return NULL; + } + } lib->watcher->add(lib->watcher, this->receive, WATCHER_READ, (watcher_cb_t)receive_dhcp, this);