diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 2fb4907634..99283813fd 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -984,6 +984,13 @@ + + + ListenPort= + + Allow setting custom port for the DHCP client to listen on. + + diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h index 99f690897d..5aa8aca426 100644 --- a/src/libsystemd-network/dhcp-internal.h +++ b/src/libsystemd-network/dhcp-internal.h @@ -32,7 +32,8 @@ int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, uint32_t xid, const uint8_t *mac_addr, - size_t mac_addr_len, uint16_t arp_type); + size_t mac_addr_len, uint16_t arp_type, + uint16_t port); int dhcp_network_bind_udp_socket(be32_t address, uint16_t port); int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const void *packet, size_t len); @@ -57,7 +58,7 @@ void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr, uint16_t source, be32_t destination_addr, uint16_t destination, uint16_t len); -int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum); +int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port); /* If we are invoking callbacks of a dhcp-client, ensure unreffing the * client from the callback doesn't destroy the object we are working diff --git a/src/libsystemd-network/dhcp-network.c b/src/libsystemd-network/dhcp-network.c index a9f5a0a5de..3c85bb0b54 100644 --- a/src/libsystemd-network/dhcp-network.c +++ b/src/libsystemd-network/dhcp-network.c @@ -36,7 +36,8 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, size_t mac_addr_len, const uint8_t *bcast_addr, const struct ether_addr *eth_mac, - uint16_t arp_type, uint8_t dhcp_hlen) { + uint16_t arp_type, uint8_t dhcp_hlen, + uint16_t port) { struct sock_filter filter[] = { BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(DHCPPacket), 1, 0), /* packet >= DHCPPacket ? */ @@ -53,7 +54,7 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, udp.dest)), /* A <- UDP destination port */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_PORT_CLIENT, 1, 0), /* UDP destination port == DHCP client port ? */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, port, 1, 0), /* UDP destination port == DHCP client port ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.op)), /* A <- DHCP op */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTREPLY, 1, 0), /* op == BOOTREPLY ? */ @@ -125,7 +126,8 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid, const uint8_t *mac_addr, - size_t mac_addr_len, uint16_t arp_type) { + size_t mac_addr_len, uint16_t arp_type, + uint16_t port) { static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* Default broadcast address for IPoIB */ static const uint8_t ib_bcast[] = { @@ -151,7 +153,7 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, return -EINVAL; return _bind_raw_socket(ifindex, link, xid, mac_addr, mac_addr_len, - bcast_addr, ð_mac, arp_type, dhcp_hlen); + bcast_addr, ð_mac, arp_type, dhcp_hlen, port); } int dhcp_network_bind_udp_socket(be32_t address, uint16_t port) { diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c index 8be774061d..40442b3636 100644 --- a/src/libsystemd-network/dhcp-packet.c +++ b/src/libsystemd-network/dhcp-packet.c @@ -114,7 +114,7 @@ void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr, packet->ip.check = dhcp_packet_checksum((uint8_t*)&packet->ip, DHCP_IP_SIZE); } -int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum) { +int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port) { size_t hdrlen; assert(packet); @@ -160,10 +160,10 @@ int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum) { return -EINVAL; } - if (be16toh(packet->udp.dest) != DHCP_PORT_CLIENT) { + if (be16toh(packet->udp.dest) != port) { log_debug("ignoring packet: to port %u, which " "is not the DHCP client port (%u)", - be16toh(packet->udp.dest), DHCP_PORT_CLIENT); + be16toh(packet->udp.dest), port); return -EINVAL; } diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 5ccb23922c..6475da2c2a 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -55,6 +55,7 @@ struct sd_dhcp_client { sd_event_source *timeout_resend; int ifindex; int fd; + uint16_t port; union sockaddr_union link; sd_event_source *receive_message; bool request_broadcast; @@ -426,6 +427,17 @@ int sd_dhcp_client_set_vendor_class_identifier( return 0; } +int sd_dhcp_client_set_client_port( + sd_dhcp_client *client, + uint16_t port) { + + assert_return(client, -EINVAL); + + client->port = port; + + return 0; +} + int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) { assert_return(client, -EINVAL); assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE); @@ -668,7 +680,7 @@ static int dhcp_client_send_raw( DHCPPacket *packet, size_t len) { - dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT, + dhcp_packet_append_ip_headers(packet, INADDR_ANY, client->port, INADDR_BROADCAST, DHCP_PORT_SERVER, len); return dhcp_network_send_raw_socket(client->fd, &client->link, @@ -1120,7 +1132,7 @@ static int client_start_delayed(sd_dhcp_client *client) { r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid, client->mac_addr, - client->mac_addr_len, client->arp_type); + client->mac_addr_len, client->arp_type, client->port); if (r < 0) { client_stop(client, r); return r; @@ -1170,7 +1182,8 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid, client->mac_addr, - client->mac_addr_len, client->arp_type); + client->mac_addr_len, client->arp_type, + client->port); if (r < 0) { client_stop(client, r); return 0; @@ -1555,8 +1568,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i goto error; } - r = dhcp_network_bind_udp_socket(client->lease->address, - DHCP_PORT_CLIENT); + r = dhcp_network_bind_udp_socket(client->lease->address, client->port); if (r < 0) { log_dhcp_client(client, "could not bind UDP socket"); goto error; @@ -1766,7 +1778,7 @@ static int client_receive_message_raw( } } - r = dhcp_packet_verify_headers(packet, len, checksum); + r = dhcp_packet_verify_headers(packet, len, checksum, client->port); if (r < 0) return 0; @@ -1891,6 +1903,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret) { client->fd = -1; client->attempt = 1; client->mtu = DHCP_DEFAULT_MIN_SIZE; + client->port = DHCP_PORT_CLIENT; client->req_opts_size = ELEMENTSOF(default_req_opts); client->req_opts = memdup(default_req_opts, client->req_opts_size); diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c index 2a101cb1fe..c10ca74b86 100644 --- a/src/libsystemd-network/test-dhcp-client.c +++ b/src/libsystemd-network/test-dhcp-client.c @@ -195,7 +195,7 @@ int dhcp_network_bind_raw_socket( union sockaddr_union *link, uint32_t id, const uint8_t *addr, size_t addr_len, - uint16_t arp_type) { + uint16_t arp_type, uint16_t port) { if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0) return -errno; diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 76d3d132ea..3feb158642 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -630,6 +630,12 @@ int dhcp4_configure(Link *link) { return r; } + if (link->network->dhcp_client_port) { + r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port); + if (r < 0) + return r; + } + switch (link->network->dhcp_client_identifier) { case DHCP_CLIENT_ID_DUID: { /* If configured, apply user specified DUID and/or IAID */ diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index bcf8186c33..814f435fc1 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -100,6 +100,7 @@ DHCP.RouteMetric, config_parse_unsigned, DHCP.RouteTable, config_parse_dhcp_route_table, 0, offsetof(Network, dhcp_route_table) DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone) DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid) +DHCP.ListenPort, config_parse_uint32, 0, offsetof(Network, dhcp_client_port) IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns) IPv6AcceptRA.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains) IPv6AcceptRA.RouteTable, config_parse_dhcp_route_table, 0, offsetof(Network, ipv6_accept_ra_route_table) diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 42fc82d392..4df8c37979 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -124,6 +124,7 @@ struct Network { bool dhcp_use_timezone; unsigned dhcp_route_metric; uint32_t dhcp_route_table; + uint32_t dhcp_client_port; /* DHCP Server Support */ bool dhcp_server; diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index 9a90c2ed42..ffe7f836de 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -126,6 +126,9 @@ int sd_dhcp_client_get_client_id( int sd_dhcp_client_set_mtu( sd_dhcp_client *client, uint32_t mtu); +int sd_dhcp_client_set_client_port( + sd_dhcp_client *client, + uint16_t port); int sd_dhcp_client_set_hostname( sd_dhcp_client *client, const char *hostname);