diff --git a/src/libcharon/plugins/dhcp/dhcp_socket.c b/src/libcharon/plugins/dhcp/dhcp_socket.c index 815d2c65c..a3572766d 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);