Re: [Dnsmasq-discuss] ProxyDHCP with UEFI systems

2015-10-31 Thread Michael Kuron
As it turns out, UEFI does support PXE menus, but the implementations are 
rather buggy in that regard. VMware often does not render the menu on the 
screen, but you can blindly select the menu entry using the arrow keys and boot 
it with the return key. A recent Asus laptop renders the menu, but ignores the 
TFTP server IP specified in the PXE service and instead tries to open a TFTP 
connection to the DHCP server’s IP. There probably are some fully-working 
implementations out there as well.
Below is a patch that combines the work from my previous emails with this new 
discovery. It always redirects to port 4011. If only one service is specified, 
it puts that into the siaddr and file fields directly, which should work for 
all UEFI implementations. If more than one service is specified, it sends a 
menu, which might reveal bugs in the UEFI implementation. All of this is 
backwards compatible with BIOS because the port 4011 redirect is part of the 
PXE spec.

How can I submit this patch for inclusion in dnsmasq?


diff --git a/src/rfc2131.c b/src/rfc2131.c
index 9f69ed5..bdc0f78 100644
--- a/src/rfc2131.c
+++ b/src/rfc2131.c
@@ -824,7 +824,10 @@ size_t dhcp_reply(struct dhcp_context *context, char 
*iface_name, int int_index,
  else
mess->siaddr = context->local; 
  
- snprintf((char *)mess->file, sizeof(mess->file), "%s.%d", 
service->basename, layer);
+ 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
+   snprintf((char *)mess->file, sizeof(mess->file), "%s.%d", 
service->basename, layer);
  option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
  option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, 
htonl(context->local.s_addr));
  pxe_misc(mess, end, uuid);
@@ -859,6 +862,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 +894,42 @@ 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)
+   {
+   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, 

Re: [Dnsmasq-discuss] ProxyDHCP with UEFI systems

2015-10-24 Thread Michael Kuron
Actually, I shouldn’t set the siaddr in the initial Offer. It’s fine for VMware 
UEFI and BIOS, but the Asus UEFI will end up trying to download the boot file 
from the Offer’s siaddr instead of the ACK’s siaddr if it’s present. So the 
small additional modification below will also allow the TFTP server to be on a 
different machine than the proxy DHCP server.

--- a/src/rfc2131.c
+++ b/src/rfc2131.c
@@ -898,9 +898,7 @@ size_t dhcp_reply(struct dhcp_context *context, char 
*iface_name, int int_index,
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)
+   if (num_services == 1 && pxe)
{
for (service = daemon->pxe_services; 
service; service = service->next)
if (pxearch == service->CSA && 
match_netid(service->netid, netid, 1))


> On 24.10.2015, at 15:21, Michael Kuron 
>  wrote:
> 
> 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 
> 

Re: [Dnsmasq-discuss] ProxyDHCP with UEFI systems

2015-10-24 Thread Michael Kuron
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));



___
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk

Re: [Dnsmasq-discuss] ProxyDHCP with UEFI systems

2015-10-20 Thread Simon Kelley
Is there any sort of standards document that explains how this is
supposed to work in EFI?

Cheers,

Simon.



On 19/10/15 12:54, Michael Kuron wrote:
> I made some changes to dnsmasq (patch below) that remove the PXE menu system 
> (the option 43 stuff) if there’s only one menu entry and put the boot file 
> name and server address directly into the file and siaddr fields. This works 
> fine for BIOS systems, but doesn’t work for UEFI either.
> Next thing I tried was to copy the boot file name and server address into 
> options 66 and 67, but that doesn’t work either.
> 
> So far, it really seems like proxyDHCP support in UEFI systems is completely 
> missing. I used VMware Fusion 8.0.1 and a recent Asus laptop for testing. If 
> anybody could supply a Wireshark of a different implementation that works 
> (Windows Deployment Services maybe?), it should be easy to adapt my patch.
> 
> It’s really easy to set up a test system in any modern version of VMware: 
> just create a new VM and add the following to the .vmx file:
> firmware = "efi"
> 
> 
> 
> diff --git a/src/rfc2131.c b/src/rfc2131.c
> index 9f69ed5..27b2573 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,49 @@ 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)
> + {
> + 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)
> + {
> + char sname[16];
> + snprintf((char 
> *)mess->file, sizeof(mess->file), "%s.efi", service->basename);
> + inet_ntop(AF_INET, 
> >siaddr, , 16);
> + // Option 66 and 67 
> necessary according to 
> http://www-01.ibm.com/support/docview.wss?uid=swg27027022=1
> + option_put_string(mess, 
> end, OPTION_SNAME, sname, 0);
> + option_put_string(mess, 
> end, OPTION_FILENAME, >file, 0);
> + }
> + 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, 

Re: [Dnsmasq-discuss] ProxyDHCP with UEFI systems

2015-10-19 Thread Michael Kuron
I made some changes to dnsmasq (patch below) that remove the PXE menu system 
(the option 43 stuff) if there’s only one menu entry and put the boot file name 
and server address directly into the file and siaddr fields. This works fine 
for BIOS systems, but doesn’t work for UEFI either.
Next thing I tried was to copy the boot file name and server address into 
options 66 and 67, but that doesn’t work either.

So far, it really seems like proxyDHCP support in UEFI systems is completely 
missing. I used VMware Fusion 8.0.1 and a recent Asus laptop for testing. If 
anybody could supply a Wireshark of a different implementation that works 
(Windows Deployment Services maybe?), it should be easy to adapt my patch.

It’s really easy to set up a test system in any modern version of VMware: just 
create a new VM and add the following to the .vmx file:
firmware = "efi"



diff --git a/src/rfc2131.c b/src/rfc2131.c
index 9f69ed5..27b2573 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,49 @@ 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)
+   {
+   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)
+   {
+   char sname[16];
+   snprintf((char 
*)mess->file, sizeof(mess->file), "%s.efi", service->basename);
+   inet_ntop(AF_INET, 
>siaddr, , 16);
+   // Option 66 and 67 
necessary according to 
http://www-01.ibm.com/support/docview.wss?uid=swg27027022=1
+   option_put_string(mess, 
end, OPTION_SNAME, sname, 0);
+   option_put_string(mess, 
end, OPTION_FILENAME, >file, 0);
+   }
+   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);
  
  

Re: [Dnsmasq-discuss] ProxyDHCP with UEFI systems

2015-10-05 Thread Simon Kelley
The problem in known, but not the solution. I did start working on that
about six months ago, but got bogged down in creating a test system.

What would be really useful would be to find an implementation that
works with UEFI and proxy DHCP, and getting for packet captures to show
what should be sent.


Cheers,

Simon.



On 03/10/15 01:03, Wayne Workman wrote:
> Hello,
> 
> I've been trying to get dnsmasq to work as ProxyDHCP with UEFI enabled
> systems. So far I've not had much luck.
> 
> I originally thought it was a configuration issue, so I tried to include
> every single architecture type and hand out an .efi file to it. I've
> confirmed that DHCP Option 067 does get passed to the clients but they
> simply will not network boot.
> 
> This is the configuration I was trying:
> 
> port=0
> log-dhcp
> tftp-root=/tftpboot
> dhcp-boot=,10.0.0.3,10.0.0.3
> dhcp-option=17,/images
> dhcp-option=vendor:PXEClient,6,2b
> dhcp-no-override
> pxe-prompt="Press F8 for boot menu", 3
> pxe-service=X86PC, “Boot from network”, ipxe
> pxe-service=PC98, “Boot from network” ipxe
> pxe-service=IA64_EFI, “Boot from network”, ipxe
> pxe-service=Alpha, “Boot from network”, ipxe
> pxe-service=Arc_x86, “Boot from network”, ipxe
> pxe-service=Intel_Lean_Client, “Boot from network”, ipxe
> pxe-service=IA32_EFI, “Boot from network”, ipxe
> pxe-service=BC_EFI, “Boot from network”, ipxe
> pxe-service=Xscale_EFI, “Boot from network”,
> ipxe pxe-service=X86-64_EFI, “Boot from network”, ipxe
> dhcp-range=10.0.0.3,proxy
> 
> I'm trying to get this going for fogproject.org
> There is an ongoing conversation about it here:
> https://forums.fogproject.org/topic/4628/undionly-kpxe-and-ipxe-efi
> 
> Thanks for any help, it would be greatly appreciated.
> Wayne
> 
> 
> 
> ___
> Dnsmasq-discuss mailing list
> Dnsmasq-discuss@lists.thekelleys.org.uk
> http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss
> 


___
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss