diff --git a/src/libcharon/plugins/dhcp/dhcp_socket.c b/src/libcharon/plugins/dhcp/dhcp_socket.c index 02aa29853..765171ff4 100644 --- a/src/libcharon/plugins/dhcp/dhcp_socket.c +++ b/src/libcharon/plugins/dhcp/dhcp_socket.c @@ -1,4 +1,7 @@ /* + * Copyright (C) 2012-2018 Tobias Brunner + * HSR Hochschule fuer Technik Rapperswil + * * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG * @@ -179,6 +182,16 @@ typedef struct __attribute__((packed)) { u_char options[252]; } dhcp_t; +/** + * Check if the given address equals the broadcast address + */ +static inline bool is_broadcast(host_t *host) +{ + chunk_t broadcast = chunk_from_chars(0xFF,0xFF,0xFF,0xFF); + + return chunk_equals(broadcast, host->get_address(host)); +} + /** * Prepare a DHCP message for a given transaction */ @@ -186,7 +199,7 @@ static int prepare_dhcp(private_dhcp_socket_t *this, dhcp_transaction_t *transaction, dhcp_message_type_t type, dhcp_t *dhcp) { - chunk_t chunk, broadcast = chunk_from_chars(0xFF,0xFF,0xFF,0xFF); + chunk_t chunk; identification_t *identity; dhcp_option_t *option; int optlen = 0; @@ -198,7 +211,7 @@ static int prepare_dhcp(private_dhcp_socket_t *this, dhcp->hw_type = ARPHRD_ETHER; dhcp->hw_addr_len = 6; dhcp->transaction_id = transaction->get_id(transaction); - if (chunk_equals(broadcast, this->dst->get_address(this->dst))) + if (is_broadcast(this->dst)) { /* Set broadcast flag to get broadcasted replies, as we actually * do not own the MAC we request an address for. */ @@ -766,6 +779,17 @@ dhcp_socket_t *dhcp_socket_create() destroy(this); return NULL; } + if (!is_broadcast(this->dst)) + { + /* when setting giaddr (which we do when we don't broadcast), the server + * should respond to the server port on that IP, according to RFC 2131, + * section 4.1. while we do receive such messages via raw socket, the + * kernel will respond with an ICMP port unreachable if there is no + * socket bound to that port, which might be problematic with certain + * DHCP servers. instead of opening an additional socket, that we don't + * actually use, we can also just send our requests from port 67 */ + src.sin_port = htons(DHCP_SERVER_PORT); + } if (bind(this->send, (struct sockaddr*)&src, sizeof(src)) == -1) { DBG1(DBG_CFG, "unable to bind DHCP send socket: %s", strerror(errno)); diff --git a/testing/tests/ikev2/dhcp-dynamic/hosts/moon/etc/iptables.rules b/testing/tests/ikev2/dhcp-dynamic/hosts/moon/etc/iptables.rules index 2d9a466b0..792fc56bc 100644 --- a/testing/tests/ikev2/dhcp-dynamic/hosts/moon/etc/iptables.rules +++ b/testing/tests/ikev2/dhcp-dynamic/hosts/moon/etc/iptables.rules @@ -5,8 +5,8 @@ -P OUTPUT DROP -P FORWARD DROP -# allow bootpc and bootps --A OUTPUT -p udp --sport bootpc --dport bootps -j ACCEPT +# allow bootps (in relay mode also in OUTPUT) +-A OUTPUT -p udp --sport bootps --dport bootps -j ACCEPT -A INPUT -p udp --sport bootps --dport bootps -j ACCEPT # allow broadcasts from eth1 diff --git a/testing/tests/ikev2/dhcp-static-client-id/hosts/moon/etc/iptables.rules b/testing/tests/ikev2/dhcp-static-client-id/hosts/moon/etc/iptables.rules index 2d9a466b0..792fc56bc 100644 --- a/testing/tests/ikev2/dhcp-static-client-id/hosts/moon/etc/iptables.rules +++ b/testing/tests/ikev2/dhcp-static-client-id/hosts/moon/etc/iptables.rules @@ -5,8 +5,8 @@ -P OUTPUT DROP -P FORWARD DROP -# allow bootpc and bootps --A OUTPUT -p udp --sport bootpc --dport bootps -j ACCEPT +# allow bootps (in relay mode also in OUTPUT) +-A OUTPUT -p udp --sport bootps --dport bootps -j ACCEPT -A INPUT -p udp --sport bootps --dport bootps -j ACCEPT # allow broadcasts from eth1 diff --git a/testing/tests/ikev2/dhcp-static-mac/hosts/moon/etc/iptables.rules b/testing/tests/ikev2/dhcp-static-mac/hosts/moon/etc/iptables.rules index 2d9a466b0..792fc56bc 100644 --- a/testing/tests/ikev2/dhcp-static-mac/hosts/moon/etc/iptables.rules +++ b/testing/tests/ikev2/dhcp-static-mac/hosts/moon/etc/iptables.rules @@ -5,8 +5,8 @@ -P OUTPUT DROP -P FORWARD DROP -# allow bootpc and bootps --A OUTPUT -p udp --sport bootpc --dport bootps -j ACCEPT +# allow bootps (in relay mode also in OUTPUT) +-A OUTPUT -p udp --sport bootps --dport bootps -j ACCEPT -A INPUT -p udp --sport bootps --dport bootps -j ACCEPT # allow broadcasts from eth1 diff --git a/testing/tests/swanctl/dhcp-dynamic/hosts/moon/etc/iptables.rules b/testing/tests/swanctl/dhcp-dynamic/hosts/moon/etc/iptables.rules index 2d9a466b0..792fc56bc 100644 --- a/testing/tests/swanctl/dhcp-dynamic/hosts/moon/etc/iptables.rules +++ b/testing/tests/swanctl/dhcp-dynamic/hosts/moon/etc/iptables.rules @@ -5,8 +5,8 @@ -P OUTPUT DROP -P FORWARD DROP -# allow bootpc and bootps --A OUTPUT -p udp --sport bootpc --dport bootps -j ACCEPT +# allow bootps (in relay mode also in OUTPUT) +-A OUTPUT -p udp --sport bootps --dport bootps -j ACCEPT -A INPUT -p udp --sport bootps --dport bootps -j ACCEPT # allow broadcasts from eth1