Description
Clients expecting Option 67 / bootfile-name in DHCP can anticipate either a URL including the protocol, IP address or FQDN, port, and path to a file (ex: http://192.0.2.1:8080/path/to/bootfile.py), a file path (ex: /path/to/bootfile.py), or a simple filename (ex: bootfile.py, sometimes paired with Option 66 / tftp-server-name).
Currently, the dhcp-server configuration mode interface in VyOS only accepts values matching the pattern [-_a-zA-Z0-9./]+. This limitation notably rejects values with a : character, effectively disallowing URLs that specify schema or port numbers. This issue hinders the use of VyOS's DHCP server for tasks like zero-touch provisioning of network devices, which rely on Option 67 to fetch their boot instructions.
ISC DHCP's definition:
option bootfile-name text; This option is used to identify a bootstrap file. If supported by the client, it should have the same effect as the filename declaration. BOOTP clients are unlikely to support this option. Some DHCP clients will support it, and others actually require it.
ISC DHCP's manual mentions that in this context, text is any valid ASCII string:
The text data type specifies an NVT ASCII string, which must be enclosed in double quotes - for example, to specify a root-path option, the syntax would be
option root-path "10.0.1.4:/var/tmp/rootfs";
And is additionally corroborated by the following references in ISC DHCP's source:
The current issue seems to have originated from T782, as indicated in this commit.
Impact
This bug affects DHCP server configurations where a bootfile-name needs to be specified, particularly when the name is a full URL or includes a : character. In its current state, the system may reject valid configurations, causing booting issues for clients that rely on these settings. This limitation particularly hampers the usage of VyOS's DHCP server for functions like zero-touch provisioning of network devices, where clients expect Option 67 to fetch their boot instructions.
The significance of maintaining the functionality of these DHCP options is highlighted in another issue (T1129), where a user stresses the importance of these options for provisioning phones and other network devices.
This bug also prevents all service dhcp-server config with an "invalid" bootfile-name parameter present (from configs prior to the regex being implement) from being migrated during VyOS upgrade.
Workaround limitations
The possible workaround of using subnet-parameters is also blocked due to a constraint on the usage of the double quote (") character in the value string:
eric@vyos# set service dhcp-server shared-network-name TESTNET subnet 203.0.113.0/24 subnet-parameters 'option bootfile-name "http://example.com/path/to/file.py";' Cannot use the double quote (") character in a value string Value validation failed Set failed
Proposed solution
Change the constraint regex pattern to: [-_a-zA-Z0-9.:/~#@!$&*+,;=~%\\\\]+
This adjustment expands the existing pattern to accommodate full URLs, file paths, and bare filenames. It also adds a subset of RFC 3886 "reserved" characters (gen-delims and sub-delims), excluding [] ' () , due to their rarity and negative interactions with the command line. Additionally, it adds simple handling of "% encoding".
Finally, the double-escaped \ enables support for Windows paths like those used for Windows Deployment Services (ex: boot\x64\wdsnbp.com). These land in dhcpd.conf as boot\\x64\\wdsnbp.com, which passes dhcpd -t. An explanation of string handling in ISC DHCP's documentation suggests that this is the correct format. See also: PXE Boot from WDS using ISC DHCPd (r/networking).
Test commands
The following commands test the proposed pattern against input validation and against dhcpd -t upon commit:
configure cp /opt/vyatta/share/vyatta-cfg/templates/service/dhcp-server/shared-network-name/node.tag/subnet/node.tag/bootfile-name/node.def /tmp/bootfile-name-node.def.bak # manually edit the regex in node.def to [-_a-zA-Z0-9./:?#@!$&*+,;=~%\\\\]+ sudo vi /opt/vyatta/share/vyatta-cfg/templates/service/dhcp-server/shared-network-name/node.tag/subnet/node.tag/bootfile-name/node.def sudo systemctl restart vyos-configd set service dhcp-server shared-network-name TESTNET subnet 203.0.113.0/24 range 0 start 203.0.113.2 set service dhcp-server shared-network-name TESTNET subnet 203.0.113.0/24 range 0 stop 203.0.113.254 set service dhcp-server shared-network-name TESTNET subnet 203.0.113.0/24 bootfile-name "http://example.com/path/to/file.py" commit grep "shared-network TESTNET" -A9 /run/dhcp-server/dhcpd.conf set service dhcp-server shared-network-name TESTNET subnet 203.0.113.0/24 bootfile-name "https://192.0.2.1/path/to/file.py" commit grep "shared-network TESTNET" -A9 /run/dhcp-server/dhcpd.conf set service dhcp-server shared-network-name TESTNET subnet 203.0.113.0/24 bootfile-name "/pxelinux.0" commit grep "shared-network TESTNET" -A9 /run/dhcp-server/dhcpd.conf set service dhcp-server shared-network-name TESTNET subnet 203.0.113.0/24 bootfile-name "boot\x64\wdsnbp.com" commit grep "shared-network TESTNET" -A9 /run/dhcp-server/dhcpd.conf delete service dhcp-server shared-network-name TESTNET commit sudo mv /tmp/bootfile-name-node.def.bak /opt/vyatta/share/vyatta-cfg/templates/service/dhcp-server/shared-network-name/node.tag/subnet/node.tag/bootfile-name/node.def sudo systemctl restart vyos-configd exit