Configuring dnsmasq to serve different tftp boot files depending on the client architecture

Hi!
I have been reading this guide to configure a iPXE server: Configuring PXE Network Boot Server on Ubuntu 22.04 LTS
and I followed the exact steps except for the dhcp server. This is when the problem starts.
Let me tell you my home installation. I have a PC running Ubuntu server 22.04.1 - call it "FreeBNT". It has a big zfs filesystem I use to serve SAMBA shares and other things. now I want to use it as PXE server too. But I can't configure DHCP in this server, because, I power it on and off from time to time. (the electricity is expensive now!). So I think I need to setup a router I have with OpenWRT installed - call it TP-LINK. So I configured it to serve DHCP and also BOOTP. But the TFTP server is in FreeBNT. also NFS and iPXE firmware and config files are in FreeBNT.
The problem arrives when I arrived at the point of the tutorial when dnsmasq should be configured with these options:

/etc/dnsmasq.conf

interface=ens33

bind-interfaces

domain=linuxhint.local

dhcp-range=ens38,192.168.0.180,192.168.0.200,255.255.255.0,8h

dhcp-option=option:router,192.168.0.1

dhcp-option=option:dns-server,1.1.1.1

dhcp-option=option:dns-server,8.8.8.8

enable-tftp

tftp-root=/pxeboot

# boot config for BIOS systems

dhcp-match=set:bios-x86,option:client-arch,0

dhcp-boot=tag:bios-x86,firmware/ipxe.pxe

# boot config for UEFI systems

dhcp-match=set:efi-x86_64,option:client-arch,7

dhcp-match=set:efi-x86_64,option:client-arch,9

dhcp-boot=tag:efi-x86_64,firmware/ipxe.efi

There are 5 effective lines at the bottom, preceded by # boot config for BIOS systems and # boot config for UEFI systems.
Since those options are part of the dhcp part of dnsmasq, I think I should include them in the dhcp configuration in TP-LINK. But I didn't get it to work. The configuration for DHCP in TP-LINK is located at

/etc/config/dhcp

and the config file syntax is different.
Initially I have done this - to make it to work with the BIOS settings, serving only the ipxe.pxe file. It actually works, but I'd like to have the BIOS option and also the UEFI option. Now, what I did:

config dnsmasq
        option domainneeded '1'
        option boguspriv '1'
        option filterwin2k '0'
        option localise_queries '1'
        option rebind_protection '1'
        option rebind_localhost '1'
        option local '/lan/'
        option domain 'lan'
        option expandhosts '1'
        option nonegcache '0'
        option authoritative '1'
        option readethers '1'
        option leasefile '/tmp/dhcp.leases'
        option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto'
        option nonwildcard '1'
        option localservice '1'
        option ednspacket_max '1232'

config dhcp 'lan'
        option interface 'lan'
        option start '100'
        option limit '150'
        option leasetime '12h'
        option dhcpv4 'server'
        list dhcp_option '6,172.26.23.3'
        list dhcp_option '240,:::::239.0.2.10:22222:v6.0:239.0.2.30:22222'
        list dhcp_option '3,192.168.1.3'
        list ra_flags 'none'

config odhcpd 'odhcpd'
        option maindhcp '0'
        option leasefile '/tmp/hosts/odhcpd'
        option leasetrigger '/usr/sbin/odhcpd-update'
        option loglevel '4'

config boot 'linux'
        option filename 'firmware/ipxe.pxe'
        option serveraddress '192.168.1.2'
        option servername 'FreeBNT'

Also see my dnsmasq configuration (/etc/dnsmasq.conf) in FreeBNT, for the sake of completeness:

#interface=ens33

#bind-interfaces

port=0

enable-tftp

tftp-root=/free/pxe

# boot config for BIOS systems

#dhcp-match=set:bios-x86,option:client-arch,0

#dhcp-boot=tag:bios-x86,firmware/ipxe.pxe

# boot config for UEFI systems

#dhcp-match=set:efi-x86_64,option:client-arch,7

#dhcp-match=set:efi-x86_64,option:client-arch,9

#dhcp-boot=tag:efi-x86_64,firmware/ipxe.efi

After seeing that the ipxe.pxe file worked well with the BIOS PXE, I tried also with ipxe.efi , and it does some progress but I don't get it to work. So I have 2 problems.

  1. How can I adapt the dhcp-match ... configuration to TP-LINK dhcp configuration so that the TP-LINK serves ipxe.pxe to BIOS PXE clients and it serves ipxe.efi to UEFI PXE clients.
  2. Once I see the first problem is resolved, I would try to go further and try to make UEFI PXE to work.

I have been reading a lot of information from google searches an I found this, from here


That gave me a clue and I tried to configure /etc/config/dhcp as follows (the previous sections are unchanged, I only edit the (config boot 'linux') section/sections:

config boot 'linux'
        option filename 'firmware/ipxe.pxe'
        option serveraddress '192.168.1.2'
        option servername 'FreeBNT'
        option network-id 'bios-x86'
        option dhcp_option 'client-arch,6'

config boot 'linux'
        option filename 'firmware/ipxe.efi'
        option serveraddress '192.168.1.2'
        option servername 'FreeBNT'
        option network-id 'efi-x86_64-1'
        option dhcp_option 'client-arch,7'

config boot 'linux'
        option filename 'firmware/ipxe.efi'
        option serveraddress '192.168.1.2'
        option servername 'FreeBNT'
        option network-id 'efi-x86_64-2'
        option dhcp_option 'client-arch,9'

But it didn't work for BIOS PXE, and neither for UEFI PXE (not sure but almost sure).
--EDIT FROM HERE--
I have seen, with this configuration, TP-LINK is pointing to ipxe.efi, whether I connect from BIOS PXE computer or I connect with UEFI PXE computer. With UEFI profile I see the same error I saw when I tried to connect when I configured only one "config boot 'linux'" section, with 'firmware/ipxe.efi'. With BIOS profile it gives me the same error I saw when I configured only one "config boot 'linux'" section, with 'firmware/ipxe.efi' too, but connecting from BIOS profile. If you need to clarify something, or photos of the screen when I try to boot, please ask. I don't want to overwhelm with too much information.
--EDIT TO HERE--
I don't understand, from the OpenWRT documentation - DHCP , the networkid. In one place it says networkid is to differentiate eth0, eth1, wlan0, etc. But in other place (Booting options) it says:

you can use network-ids to map options to each client

I don't know if there is networkid parameter and network-id parameter, or other thing that I didn't understand.

If someone could please help me, giving me some recommendations or steps I can follow to configure the DHCP server in TP-LINK, I would really appreciate it. also I'd like to know whether I can, instead of doing 3 (config boot 'linux') sections, doing 2 sections, grouping the two sections of UEFI PXE into one that would be applied to architectures 7 or 9.
Thanks a lot for your time reading this, I will be available to give more information if needed. I will now suscribe to this thread.
Cheers!

borhacker

You could create additional configuration files using the standard dnsmasq syntax.

Have a look at this topic for more information.

Hi @pavelgl ! thanks a lot.
I have followed your steps in the other thread, but I didn't get it to work. Let me explain what I did.
First, I executed:

uci set dhcp.@dnsmasq[0].confdir='/etc/dnsmasq.d'

and it gave me a parse error, so I cleaned up my /etc/config/dhcp , like this:

config boot 'linux'
        option serveraddress '192.168.1.2'
        option servername 'FreeBNT'

the previous lines are unchanged, like before. As you see I removed option filename 'firmware/ipxe.pxe'
Now I executed:

uci set dhcp.@dnsmasq[0].confdir='/etc/dnsmasq.d'
uci commit dhcp
/etc/init.d/dnsmasq restart

everything seems to be fine.
Now, I executed the later command, but with my intended content:

cat << "EOF" > /etc/dnsmasq.d/client_arch.conf
dhcp-match=set:bios-x86,option:client-arch,0
dhcp-boot=tag:bios-x86,firmware/ipxe.pxe
dhcp-match=set:efi-x86_64,option:client-arch,7
dhcp-match=set:efi-x86_64,option:client-arch,9
dhcp-boot=tag:efi-x86_64,firmware/ipxe.efi
EOF
/etc/init.d/dnsmasq restart

Then, just in case, I rebooted TP-LINK. And then I tried to PXE boot from BIOS machine, and it didn't work. Also tried to PXE boot from UEFI. It didn't work, and the error wasn't like the previous times when it got to load the ipxe.efi, I mean, the progress ended in less time and less lines of progress were shown.

So, do you know what did I do wrong? did you see some erroneous detail in my explanation?
Cheers
Borhacker

In my experience, the combination of /etc/config/dhcp and custom files does not work.

Remove this and set the server name/IP address in the custom file.

--dhcp-boot=[tag:<tag>,]<filename>,[<servername>[,<server address>|<tftp_servername>]]
dhcp-match=set:bios-x86,option:client-arch,0
dhcp-boot=tag:bios-x86,firmware/ipxe.pxe,FreeBNT,192.168.1.2

Install tcpdump on the router and check what is offered to the client.

root@Home:~# tcpdump -i any port 67 or port 68 -vv | grep 'Server-IP\|sname\|file'
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 bytes
          Server-IP 192.168.1.185
          sname "Server"
          file "firmware/ipxe.pxe"

Hi @pavelgl
I have configured dnsmasq as you said - in /etc/config/dhcp I deleted the lines you said, and this is the output of /etc/dnsmasq.d/client_arch.conf

root@TPLINK_FLORDELIS:/etc/dnsmasq.d# cat client_arch.conf 
dhcp-match=set:bios-x86,option:client-arch,0
dhcp-boot=tag:bios-x86,firmware/ipxe.pxe,FreeBNT,192.168.1.2
dhcp-match=set:efi-x86_64,option:client-arch,7
dhcp-match=set:efi-x86_64,option:client-arch,9
dhcp-boot=tag:efi-x86_64,firmware/ipxe.efi,FreeBNT,192.168.1.2

Clarification: when I say I try BIOS or UEFI boot, I mean booting my desktop computer - call it TACENS - and selecting 'boot menu' - and there there are two PXE options - one is Realtek PXE B02 D00 and the other is UEFI: IP4 Realtek PCIe GBE Family Controller. So when I'm saying I try the BIOS PXE boot is when I choose Realtek PXE B02 D00 and when I'm saying I try the UEFI PXE boot is when I choose UEFI: IP4 Realtek PCIe GBE Family Controller.
Then,
The output of the tcpdump command is this. First, I tried BIOS PXE and this is the output:

root@TPLINK_FLORDELIS:~# tcpdump -i any port 67 or port 68 -vv | grep 'Server-IP\|sname\|file'
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 bytes
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2

^C28 packets captured
28 packets received by filter
0 packets dropped by kernel

After, I tried the UEFI PXE and this is the output (it is quite the same):

root@TPLINK_FLORDELIS:~# tcpdump -i any port 67 or port 68 -vv | grep 'Server-IP\|sname\|file'
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 bytes
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
          Server-IP 192.168.1.2
            
^C35 packets captured
35 packets received by filter
0 packets dropped by kernel

I'm doing this capture connecting from my laptop - call it PORTEGE, connecting via SSH to my TP-LINK.

Anyway, even if you don't see filename ipxe.pxe or whatever, I have seen the screen of TACENS, and it seems that it gets to load the firmware, see here:


I don't know where could be the problem...

before to finish this message, I tell you, I tried deleting the FreeBNT part, like this:

dhcp-boot=tag:bios-x86,firmware/ipxe.pxe,192.168.1.2

and also this:

dhcp-boot=tag:bios-x86,firmware/ipxe.pxe,freebnt,192.168.1.2

and none of those worked. Is the server name important? I'm not sure how should I type. for example, the prompt when I connect to FreeBNT is:

borhacker@freebnt:~$ 

cheers

Borhacker

Hi again,
just let me give an additional detail:
I made a video of the PXE booting screen and I could take from the video a screenshot showing the error. Anyway I don't understand exactly what it's happening. See:


That's the last image I could see in that screen. After that I see the Windows logo.

Cheers

Hi! I finally discovered the problem.
Anyway, @pavelgl , know that your help was the most important part of the solution.
After configuring well the dnsmasq server, another problem arose. It was the boot.ipxe configuration file. At the beggining, it was like this:

#!ipxe

#initial configurations

set server_ip  192.168.1.2

set root_path  /free/pxe

#here the menus

#menu 1
menu Ubuntu Desktop Live systems
item ubuntu-16.04.7-desktop-amd64         Install Ubuntu Desktop 16.04.7 amd64 LTS
item ubuntu-18.04.6-desktop-amd64         Install Ubuntu Desktop 18.04.6 amd64 LTS
item ubuntu-20.04.5-desktop-amd64         Install Ubuntu Desktop 20.04.5 amd64 LTS
item ubuntu-22.04.1-desktop-amd64         Install Ubuntu Desktop 22.04.1 amd64 LTS

#menu 2
menu Ubuntu Server Installers
item ubuntu-16.04.7-server-amd64         Install Ubuntu Server 16.04.7 amd64 LTS
item ubuntu-18.04.6-live-server-amd64         Install Ubuntu Server 18.04.6 amd64 LTS
item ubuntu-20.04.5-live-server-amd64         Install Ubuntu Server 20.04.5 amd64 LTS
item ubuntu-22.04.1-live-server-amd64         Install Ubuntu Server 22.04.1 amd64 LTS

#menu 3
menu Lubuntu Live systems

choose --default exit --timeout 10000 option && goto ${option}

#here the available systems begin

#system 1.1 - ubuntu 16.04.7 desktop amd64

:ubuntu-16.04.7-desktop-amd64

set os_root os-images/ubuntu-16.04.7-desktop-amd64

kernel tftp://${server_ip}/${os_root}/casper/vmlinuz

initrd tftp://${server_ip}/${os_root}/casper/initrd

imgargs vmlinuz initrd=initrd boot=casper maybe-ubiquity netboot=nfs ip=dhcp nfsroot=${server_ip}:${root_path}/${os_root} quiet splash ---

boot

#system 1.2 - ubuntu 18.04.6 desktop amd64

:ubuntu-18.04.6-desktop-amd64

[...]

Then I commented out menu Lubuntu Live systems and tried again. Now I see a menu showing the Ubuntu Server installers. So I deduce there can only be one menu abcd entry.
So now I'm editing the file as shown here:

!ipxe

#initial configurations

set server_ip  192.168.1.2

set root_path  /free/pxe

#here the menus

menu Available systems

#category 1
item ubuntu-16.04.7-desktop-amd64         Install Ubuntu Desktop 16.04.7 amd64 LTS
item ubuntu-18.04.6-desktop-amd64         Install Ubuntu Desktop 18.04.6 amd64 LTS
item ubuntu-20.04.5-desktop-amd64         Install Ubuntu Desktop 20.04.5 amd64 LTS
item ubuntu-22.04.1-desktop-amd64         Install Ubuntu Desktop 22.04.1 amd64 LTS

#category 2
item ubuntu-16.04.7-server-amd64         Install Ubuntu Server 16.04.7 amd64 LTS
item ubuntu-18.04.6-live-server-amd64         Install Ubuntu Server 18.04.6 amd64 LTS
item ubuntu-20.04.5-live-server-amd64         Install Ubuntu Server 20.04.5 amd64 LTS
item ubuntu-22.04.1-live-server-amd64         Install Ubuntu Server 22.04.1 amd64 LTS

#category 3
#...

choose --default exit --timeout 10000 option && goto ${option}

#here the available systems begin

#system 1.1 - ubuntu 16.04.7 desktop amd64

:ubuntu-16.04.7-desktop-amd64

set os_root os-images/ubuntu-16.04.7-desktop-amd64

kernel tftp://${server_ip}/${os_root}/casper/vmlinuz

initrd tftp://${server_ip}/${os_root}/casper/initrd

imgargs vmlinuz initrd=initrd boot=casper maybe-ubiquity netboot=nfs ip=dhcp nfsroot=${server_ip}:${root_path}/${os_root} quiet splash ---

boot

#system 1.2 - ubuntu 18.04.6 desktop amd64

:ubuntu-18.04.6-desktop-amd64

set os_root os-images/ubuntu-18.04.6-desktop-amd64

kernel tftp://${server_ip}/${os_root}/casper/vmlinuz

initrd tftp://${server_ip}/${os_root}/casper/initrd

imgargs vmlinuz initrd=initrd boot=casper maybe-ubiquity netboot=nfs ip=dhcp nfsroot=${server_ip}:${root_path}/${os_root} quiet splash ---

boot

#system 1.3 - ubuntu 20.04.5 desktop amd64

:ubuntu-20.04.5-desktop-amd64

set os_root os-images/ubuntu-20.04.5-desktop-amd64

kernel tftp://${server_ip}/${os_root}/casper/vmlinuz

initrd tftp://${server_ip}/${os_root}/casper/initrd

imgargs vmlinuz initrd=initrd boot=casper maybe-ubiquity netboot=nfs ip=dhcp nfsroot=${server_ip}:${root_path}/${os_root} quiet splash ---

boot

[...]

By the way, do you know how can I show a title to head the 'Ubuntu Desktop' entries, and another to head the 'Ubuntu Server' entries, ...?

cheers