ipxe / ipxe

iPXE network bootloader
https://ipxe.org
Other
1.52k stars 652 forks source link

Misc. proxyDHCP issues #954

Closed deliciouslytyped closed 1 year ago

deliciouslytyped commented 1 year ago

@mcb30 Attached is a PCAP file (renamed .txt for upload) with packets from the issue we were discussing on IRC. Specifically packets 3 and 16, and the pcap was generated by running ipxe's dhcp command once for each of the two following dhcp server instances (the difference is the ip address added to dhcp-boot):

The first fails to load the tftp filename under proxydhcp/filename, the second does load it. (checked via the config command)

The issue appears to be that dnsmasq doesn't set siaddr for the DHCPOFFER (nor the proxy DHCPACKs if it goes that far). 1) should ipxe then fail to set filename? (and I guess it logically, doesnt set next-addr, because then I guess the spec doesnt say it should default to the dhcp server address? so its up to dnsmasq to set a default explicit-in-the-packet value?) 2) is this a bug in dnsmasq?

The dnsmasq (v2.89) documentation states for dhcp-boot:

       -M, --dhcp-boot=[tag:<tag>,]<filename>,[<servername>[,<server address>|<tftp_servername>]]
              (IPv4 only) Set BOOTP options to be returned by the DHCP server. Server name and address
              are  optional:  if  not provided, the name is left empty, and the address set to the ad‐
              dress of the machine running dnsmasq. [...snipped...]

[1]

sudo /nix/store/6rnl636ayiy18927ivr3wvy9vwnyq9ak-dnsmasq-2.89/bin/dnsmasq -d --bind-interface --port=0 -l leases --dhcp-range=192.168.101.1,proxy --log-dhcp --log-queries --log-debug --enable-tftp --tftp-root="$(realpath ./files)" --pxe-service=254,dummy --dhcp-boot=pxelinux.0

iPXE output:

iPXE> dhcp
DHCP 0x222b4 entering discovery state
Configuring (net0 52:54:00:12:34:56)...DHCP 0x222b4 DHCPDISCOVER
DHCP 0x222b4 DHCPOFFER from 192.168.101.1:67 for 192.168.101.239
DHCP 0x222b4 DHCPOFFER from 192.168.101.1:67 proxy
DHCP 0x222b4 entering request state
DHCP 0x222b4 DHCPREQUEST to 192.168.101.1:67 for 192.168.101.239
.DHCP 0x222b4 DHCPACK from 192.168.101.1:67 for 192.168.101.239
DHCP 0x222b4 entering ProxyDHCP state
DHCP 0x222b4 ProxyDHCP REQUEST to 192.168.101.1
DHCP 0x222b4 DHCPACK from 192.168.101.1:4011
DHCP 0x222b4 ProxyDHCP REQUEST to 192.168.101.1
DHCP 0x222b4 DHCPACK from 192.168.101.1:4011
DHCP 0x222b4 ProxyDHCP REQUEST to 192.168.101.1
DHCP 0x222b4 DHCPACK from 192.168.101.1:4011
.DHCP 0x222b4 ProxyDHCP REQUEST to 192.168.101.1
DHCP 0x222b4 DHCPACK from 192.168.101.1:4011
.. ok
iPXE>

[2]

sudo /nix/store/6rnl636ayiy18927ivr3wvy9vwnyq9ak-dnsmasq-2.89/bin/dnsmasq -d --bind-interface --port=0 -l leases --dhcp-range=192.168.101.1,proxy --log-dhcp --log-queries --log-debug --enable-tftp --tftp-root="$(realpath ./files)" --pxe-service=254,dummy --dhcp-boot=pxelinux.0,,192.168.101.1

virbr2--2023-05-23--10-50-51.pcap.txt

deliciouslytyped commented 1 year ago

I failed to notice that option 54 is set everywhere, however has_pxe_opts specifically checks for dhcppkt->dhcphdr->siaddr.s_addr https://github.com/ipxe/ipxe/blob/95b8338f0d4674b9f8bb51adf6886212d2b97e4b/src/net/udp/dhcp.c#L308

mcb30 commented 1 year ago

The ProxyDHCPACK is rejected because it does not contain any usable boot configuration: this is visible from the absence of the pxe flag in the DHCPACK lines, which should show e.g. DHCPACK from 192.168.101.1:4011 pxe for a valid ProxyDHCPACK.

The relevant logic is in dhcp_has_pxeopts():

    /* Check for a next-server and boot filename */
    if ( dhcppkt->dhcphdr->siaddr.s_addr &&
         ( dhcppkt_fetch ( dhcppkt, DHCP_BOOTFILE_NAME, NULL, 0 ) > 0 ) )
        return 1;

    /* Check for a PXE boot menu */
    if ( dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU, NULL, 0 ) > 0 )
        return 1;

So, a packet is considered to have valid PXE options if either:

  1. it contains a next-server IP address and boot filename, or
  2. it contains a PXE boot menu.

Looking at your packet capture:

  1. the boot filename is present, but the next-server IP address is empty and so there is no valid "TFTP server + filename" present
  2. a PXE boot menu prompt (option 43.10) is present, but no PXE boot menu list (option 43.9), so no valid PXE boot menu is present

Hence the packet fails both tests, and so does not contain usable PXE options. iPXE therefore discards it and continues attempting ProxyDHCP (waiting for a valid response) until it eventually times out.

deliciouslytyped commented 1 year ago

Right, I mostly figured that out.

I'm explicitly trying to not care about having a boot menu set (because it doesn't make sense?), so that's just something dnsmasq adds (IDK if its by spec or just something they do).

So I guess my question is what can be done about siaddr not being set?

This looks like a dnsmasq (documentation) bug? Per the quote in the documentation above it looks like it should be set right?

mcb30 commented 1 year ago

So I guess my question is what can be done about siaddr not being set? This looks like a dnsmasq (documentation) bug? Per the quote in the documentation above it looks like it should be set right?

Yes, the dnsmasq documentation suggests that it should be setting siaddr to its own IP address. You'd have to dig through the dnsmasq code to figure out precisely what it's doing here.

deliciouslytyped commented 1 year ago

The relevant code seems to be around these areas but I can't tell if they really just forgot to set a default.

https://github.com/imp/dnsmasq/blob/770bce967cfc9967273d0acfb3ea018fb7b17522/src/option.c#L3966 https://github.com/imp/dnsmasq/blob/770bce967cfc9967273d0acfb3ea018fb7b17522/src/rfc2131.c#L2440 (option 66 should be set around here if they were going to set it, but it's not set in the packets)