[Dnsmasq-discuss] ProxyDHCP with UEFI systems

Michael Kuron michael-lists at physcip.uni-stuttgart.de
Sat Oct 24 14:21:22 BST 2015


More wiresharking helped me figure this out. So when UEFI receives a DHCP Offer or Proxy DHCP Offer with Vendor Class Identifier (option 60) set to PXEClient, it sends a DHCP Request to the siaddr from the offer, but on port 4011. If the server then sends a DHCP ACK back to port 4011, containing an siaddr and file name, that file is then booted. The PXE menu system does not appear to be supported by UEFI.

So here’s a new patch. It does two things if there is only one applicable --pxe-service specified:
- If it receives a Discover on port 68 with a Vendor class identifier equal to PXEClient, it sets the siaddr in the Offer to the local address.
- If it receives a Request on port 4011 with a Vendor class identifier equal to PXEClient, it sets the siaddr and file as specified using the --pxe-service option.

This is actually working for me with VMware Fusion 8 and with a recent Asus laptop. This is also backwards compatible with BIOS PXE booting (the port 4011 stuff was specified a long time ago).

Regards,
Michael



diff --git a/src/rfc2131.c b/src/rfc2131.c
index 9f69ed5..32f18d1 100644
--- a/src/rfc2131.c
+++ b/src/rfc2131.c
@@ -859,6 +859,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
 	      
 	      if (tmp)
 		{
+		  int num_services = 0;
 		  struct dhcp_boot *boot;
 		  
 		  if (tmp->netid.net)
@@ -890,13 +891,44 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
 		      if (boot->file)
 			strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
 		    }
+		  else
+		    {
+				struct pxe_service *service;
+				for (service = daemon->pxe_services; service; service = service->next)
+					if (pxearch == service->CSA && match_netid(service->netid, netid, 1))
+						++num_services;
+				
+				if (num_services == 1 && !pxe)
+					mess->siaddr = tmp->local;
+				else if (num_services == 1)
+				{
+					for (service = daemon->pxe_services; service; service = service->next)
+						if (pxearch == service->CSA && match_netid(service->netid, netid, 1))
+					{
+						if (service->sname)
+							mess->siaddr = a_record_from_hosts(service->sname, now);
+						else if (service->server.s_addr != 0)
+							mess->siaddr = service->server; 
+						else
+							mess->siaddr = tmp->local;
+						
+						if (service->CSA == 0)
+							snprintf((char *)mess->file, sizeof(mess->file), "%s.0", service->basename);
+						else if (service->CSA == 6 || service->CSA == 7 || service->CSA == 8 || service->CSA == 9)
+							snprintf((char *)mess->file, sizeof(mess->file), "%s.efi", service->basename);
+						else
+							strncpy((char *)mess->file, service->basename, sizeof(mess->file)-1);
+					}
+				}
+		    }
 		  
 		  option_put(mess, end, OPTION_MESSAGE_TYPE, 1, 
 			     mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
 		  option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
 		  pxe_misc(mess, end, uuid);
 		  prune_vendor_opts(tagif_netid);
-		  do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
+		  if (num_services != 1)
+		    do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
 		  
 		  log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);
 		  log_tags(tagif_netid, ntohl(mess->xid));





More information about the Dnsmasq-discuss mailing list