diff --git a/CHANGELOG b/CHANGELOG index 1561fe1..60f8cd7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -64,7 +64,14 @@ version 2.91 175 to iPXE. Thanks to Jason Berry for finding the requirement for this. - + Support PXE proxy-DHCP and DHCP-relay at the same time. + When using PXE proxy-DHCP, dnsmasq supplies PXE information to + the client, which also talks to another "normal" DHCP server + for address allocation and similar. The normal DHCP server may + be on the local network, but it may also be remote, and accessed via + a DHCP relay. This change allows dnsmasq to act as both a + PXE proxy-DHCP server AND a DHCP relay for the same network. + version 2.90 Fix reversion in --rev-server introduced in 2.88 which diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 390c851..250db1c 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -1680,6 +1680,11 @@ to allow netbooting. This mode is enabled using the .B proxy keyword in .B --dhcp-range. +If the "other" DHCP server is on a remote network, it is +possible, and useful, to configure dnsmasq as both a PXE proxy-DHCP server +and a DHCP relay to the remote DHCP server. See +.B --dhcp-relay +for details. PXE is only supported over IPv4 at this time. .TP .B --dhcp-pxe-vendor=[,...] According to UEFI and PXE specifications, DHCP packets between PXE clients and diff --git a/src/dhcp.c b/src/dhcp.c index 8606e71..cbc9dc0 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -32,7 +32,7 @@ static int complete_context(struct in_addr local, int if_index, char *label, struct in_addr netmask, struct in_addr broadcast, void *vparam); static int check_listen_addrs(struct in_addr local, int if_index, char *label, struct in_addr netmask, struct in_addr broadcast, void *vparam); -static int relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz); +static void relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz); static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface); static int make_fd(int port) @@ -327,17 +327,10 @@ void dhcp_packet(time_t now, int pxe_fd) complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm); } - if (relay_upstream4(iface_index, mess, (size_t)sz)) - return; - if (!iface_enumerate(AF_INET, &parm, (callback_t){.af_inet=complete_context})) return; - /* Check for a relay again after iface_enumerate/complete_context has had - chance to fill in relay->iface_index fields. This handles first time through - and any changes in interface config. */ - if (relay_upstream4(iface_index, mess, (size_t)sz)) - return; + relay_upstream4(iface_index, mess, (size_t)sz); /* May have configured relay, but not DHCP server */ if (!daemon->dhcp) @@ -1077,14 +1070,14 @@ char *host_from_dns(struct in_addr addr) return NULL; } -static int relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz) +static void relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz) { struct in_addr giaddr = mess->giaddr; u8 hops = mess->hops; struct dhcp_relay *relay; if (mess->op != BOOTREQUEST) - return 0; + return; for (relay = daemon->relay4; relay; relay = relay->next) if (relay->iface_index != 0 && relay->iface_index == iface_index) @@ -1092,7 +1085,7 @@ static int relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz) /* No relay config. */ if (!relay) - return 0; + return; for (; relay; relay = relay->next) if (relay->iface_index != 0 && relay->iface_index == iface_index) @@ -1171,7 +1164,8 @@ static int relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz) } } - return 1; + /* restore in case of a local reply. */ + mess->giaddr = giaddr; }