Loading content...
By the mid-1980s, RARP was proving inadequate for the growing needs of networked computing. Diskless workstations needed more than just an IP address—they needed complete boot configurations including subnet masks, gateways, DNS servers, and boot file locations. Network administrators struggled with the requirement to maintain RARP servers on every network segment.
Bootstrap Protocol (BOOTP), defined in RFC 951 (1985), emerged as the solution to these limitations. BOOTP represented a fundamental architectural shift: instead of a Layer 2 protocol limited to local segments, it introduced a Layer 3 approach using UDP/IP that could be relayed across routers, centralized for easier administration, and extended with vendor-specific options.
BOOTP wasn't just an incremental improvement—it was a paradigm shift that laid the foundation for modern network auto-configuration. Every DHCP server you've ever used traces its lineage directly to BOOTP.
By the end of this page, you will understand BOOTP's architectural design and how it solved RARP's limitations, the complete packet format and every field's purpose, the critical concept of relay agents, vendor extensions that enable arbitrary configuration, and why BOOTP became the precursor to modern DHCP.
BOOTP was designed by Bill Croft (Stanford) and John Gilmore as RFC 951 in September 1985. The designers explicitly addressed RARP's shortcomings while maintaining conceptual simplicity.
Design Goals:
Architectural Comparison:
| Aspect | RARP | BOOTP |
|---|---|---|
| Layer | Data Link (Layer 2) | Network/Transport (Layer 3/4) |
| Transport | Ethernet frames directly | UDP datagrams |
| Ports | N/A (EtherType only) | UDP 67 (server), UDP 68 (client) |
| Crosses routers | No (broadcast) | Yes (with relay agent) |
| Server per segment | Required | Centralized possible |
| Information provided | IP address only | Complete boot configuration |
| Extensibility | None | Vendor extensions field |
| Boot file specification | No | Yes (filename + server) |
| Message size | 28 bytes | 300 bytes minimum |
The Layer 3 Breakthrough:
BOOTP's move to UDP/IP fundamentally changed what was possible:
Before (RARP - Layer 2):
After (BOOTP - Layer 3):
You might wonder: 'How can the client use UDP/IP if it doesn't have an IP address yet?' BOOTP solves this cleverly. The client uses 0.0.0.0 as the source IP and 255.255.255.255 (limited broadcast) as the destination. Routers and relay agents handle special cases for these addresses, allowing the protocol to function even before the client has any IP configuration.
The BOOTP packet format is considerably more complex than RARP, reflecting its expanded capabilities. Every field was carefully designed to support the complete boot configuration process.
BOOTP Packet Format (Minimum 300 bytes): 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| op (1) | htype (1) | hlen (1) | hops (1) |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| xid (4) |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| secs (2) | flags (2) |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| ciaddr (4) |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| yiaddr (4) |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| siaddr (4) |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| giaddr (4) |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| || chaddr (16) || || |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| || sname (64) || (server name) || |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| || file (128) || (boot file name) || |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| || vend (64) || (vendor-specific area) || |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+Complete Field Reference:
| Field | Size | Description | Values/Usage |
|---|---|---|---|
| op | 1 byte | Operation code | 1 = BOOTREQUEST, 2 = BOOTREPLY |
| htype | 1 byte | Hardware address type | 1 = Ethernet (10 Mbps) |
| hlen | 1 byte | Hardware address length | 6 for Ethernet MAC |
| hops | 1 byte | Relay agent hop count | 0 initially, incremented by each relay |
| xid | 4 bytes | Transaction ID | Random, matches request to reply |
| secs | 2 bytes | Seconds since boot started | Client waiting time |
| flags | 2 bytes | Flags | 0x8000 = broadcast reply requested |
| ciaddr | 4 bytes | Client IP address | 0.0.0.0 if unknown (requesting) |
| yiaddr | 4 bytes | Your IP address | IP assigned by server |
| siaddr | 4 bytes | Server IP address | TFTP server for boot file |
| giaddr | 4 bytes | Gateway IP address | Relay agent address (if relayed) |
| chaddr | 16 bytes | Client hardware address | MAC address (6 bytes used for Ethernet) |
| sname | 64 bytes | Server host name | Optional, null-terminated string |
| file | 128 bytes | Boot file name | Path to boot image, null-terminated |
| vend | 64 bytes | Vendor-specific options | Extended configuration (RFC 1497) |
'yiaddr' stands for 'Your Internet Address'—the IP being assigned to the client. 'siaddr' is the 'Server Internet Address' where the boot file can be downloaded. 'giaddr' is the 'Gateway Internet Address' used by relay agents. These abbreviated names have persisted into DHCP and are commonly used in network documentation and debugging output.
The Transaction ID (xid):
The 4-byte transaction ID serves a crucial function: it matches replies to requests. Consider the scenario:
Without xid, clients could accept replies intended for other clients.
Generation guidelines:
BOOTP uses a single request/reply exchange to provide all boot configuration. Unlike DHCP's multi-step handshake, BOOTP's simplicity was both a strength and, eventually, a limitation.
The Complete Exchange Sequence:
BOOTREQUEST Details:
The client constructs and sends a BOOTREQUEST:
op: 1 (BOOTREQUEST)
htype: 1 (Ethernet)
hlen: 6
hops: 0
xid: 0x12345678 (random)
secs: 0 (just started)
flags: 0x8000 (request broadcast reply)
ciaddr: 0.0.0.0 (don't know my IP)
yiaddr: 0.0.0.0 (server will fill this)
siaddr: 0.0.0.0 (server will fill this)
giaddr: 0.0.0.0 (relay will fill if needed)
chaddr: 00:1A:2B:3C:4D:5E (my MAC)
sname: (zeros - server name optional)
file: (zeros - server will provide)
vend: (zeros or magic cookie)
BOOTREPLY Details:
The server responds with complete configuration:
op: 2 (BOOTREPLY)
htype: 1 (Ethernet)
hlen: 6
hops: 0
xid: 0x12345678 (matches request)
secs: 0
flags: 0x8000
ciaddr: 0.0.0.0
yiaddr: 192.168.1.100 (your IP!)
siaddr: 192.168.1.1 (TFTP server)
giaddr: 10.0.1.1 (if relayed)
chaddr: 00:1A:2B:3C:4D:5E (your MAC)
sname: "tftp-server.example.com"
file: "/boot/sunos/C0A80164"
vend: (subnet mask, gateway, etc.)
The flags field's broadcast bit (0x8000) addresses a subtle problem: the client doesn't have an IP address yet, so how can the server unicast to it? Some clients can receive unicast frames addressed to their soon-to-be IP before it's fully configured; others cannot. The broadcast flag lets the client request that replies be broadcast, ensuring reception regardless of IP stack capabilities.
UDP Port Usage:
| Direction | Source Port | Destination Port |
|---|---|---|
| BOOTREQUEST | 68 | 67 |
| BOOTREPLY | 67 | 68 |
Why specific ports for both client and server?
Unlike most protocols where the client uses an ephemeral port, BOOTP uses fixed ports for both sides. This enables:
IP Address Usage:
| Packet | Source IP | Destination IP |
|---|---|---|
| BOOTREQUEST (direct) | 0.0.0.0 | 255.255.255.255 |
| BOOTREQUEST (via relay) | 0.0.0.0 | 255.255.255.255 (local), then unicast to server |
| BOOTREPLY (direct) | Server IP | Client IP or 255.255.255.255 |
| BOOTREPLY (via relay) | Server IP | Relay giaddr, then forwarded to client |
The BOOTP Relay Agent (also called a helper or forwarder) is the key innovation that enabled centralized server deployment. A relay agent is typically a router or Layer 3 switch configured to forward BOOTP broadcasts to a unicast server address.
How Relay Agents Work:
1234567891011121314151617181920212223242526272829303132333435363738
// BOOTP Relay Agent Operation function processIncomingBootpPacket(packet): if packet.op == 1: // BOOTREQUEST handleClientRequest(packet) else if packet.op == 2: // BOOTREPLY handleServerReply(packet) function handleClientRequest(packet): // Step 1: Verify we should relay this if packet.hops > 16: drop(packet) // Too many hops, prevent loops return // Step 2: Insert our address so server knows return path packet.giaddr = myInterfaceIP // e.g., 10.0.1.1 // Step 3: Increment hop count packet.hops = packet.hops + 1 // Step 4: Forward to configured BOOTP server(s) for server in configuredBootpServers: send(packet, server, UDP_PORT_67) // e.g., server = 192.168.1.1 function handleServerReply(packet): // Reply from server includes giaddr we set earlier // Step 1: Determine how to reach client if packet.flags & 0x8000: // Broadcast flag set // Client requested broadcast sendBroadcast(packet, interfaceForSubnet(packet.giaddr)) else if packet.ciaddr != 0.0.0.0: // Client knows its IP, can receive unicast sendUnicast(packet, packet.ciaddr) else: // Use client's MAC address sendToMac(packet, packet.chaddr)The giaddr Field in Action:
The Gateway Internet Address (giaddr) field is crucial for relay operation:
| Scenario | giaddr Value | Purpose |
|---|---|---|
| Client to local server | 0.0.0.0 | No relay involved |
| Client via relay | Relay's IP | Server knows client's subnet |
| Server reply via relay | Original relay's IP | Reply routes back through relay |
Why giaddr Matters for Subnet Determination:
The server uses giaddr to determine which IP pool to allocate from:
Client on 10.0.1.0/24 sends via relay at 10.0.1.1
Server receives: giaddr = 10.0.1.1
Server logic: "Client is on the 10.0.1.0/24 network"
Server allocates IP from the 10.0.1.0/24 pool
Without giaddr, the server wouldn't know which subnet the client is on.
On multi-interface routers, the relay agent function is configured per interface. Traffic received on an interface without relay configuration will not be forwarded. This is intentional—it prevents BOOTP traffic from being relayed where centralized servers shouldn't assign addresses (e.g., a DMZ network that should use local BOOTP servers).
Cisco IOS Relay Configuration Example:
! Enable BOOTP/DHCP relay on an interface
interface GigabitEthernet0/1
ip address 10.0.1.1 255.255.255.0
ip helper-address 192.168.1.1
ip helper-address 192.168.1.2 ! Backup server
!
! Note: ip helper-address forwards multiple UDP ports by default:
! - BOOTP/DHCP (67, 68)
! - TFTP (69)
! - DNS (53)
! - Time (37)
! - NetBIOS (137, 138)
! - TACACS (49)
Multiple Relay Hops:
BOOTP supports relaying through multiple intermediate routers, tracked by the hops field:
The original BOOTP specification provided 64 bytes for vendor-specific extensions. RFC 1497 (BOOTP Vendor Extensions) and later RFC 2132 standardized the encoding of these options, creating the foundation that DHCP would later expand.
The Magic Cookie:
Vendor extensions begin with a 4-byte 'magic cookie' that identifies the format:
Magic Cookie: 99.130.83.99 (0x63825363)
This specific value was chosen to be unlikely to appear by accident and to be memorable (it's 99.130.83.99 in dotted decimal).
Option Format:
+--------+--------+--------+--------+--------+-----
| Code | Length | Data...
+--------+--------+--------+--------+--------+-----
1 byte 1 byte 'Length' bytes
Common BOOTP Options:
| Code | Name | Length | Description |
|---|---|---|---|
| 0 | Pad | 0 | Padding for alignment |
| 1 | Subnet Mask | 4 | Client's subnet mask |
| 2 | Time Offset | 4 | UTC offset in seconds |
| 3 | Router | 4n | Default gateway(s) |
| 4 | Time Server | 4n | RFC 868 time server(s) |
| 5 | Name Server | 4n | IEN 116 name servers |
| 6 | DNS Server | 4n | DNS server(s) |
| 7 | Log Server | 4n | MIT-LCS UDP log servers |
| 8 | Cookie Server | 4n | Quote of the Day servers |
| 9 | LPR Server | 4n | Line printer servers |
| 12 | Hostname | n | Client's hostname |
| 15 | Domain Name | n | DNS domain name |
| 17 | Root Path | n | NFS root path |
| 18 | Extensions Path | n | File for more options |
| 255 | End | 0 | End of options |
Example Vendor Options Encoding:
Vendor Options for client at 192.168.1.100:
Raw bytes:
63 82 53 63 Magic Cookie (99.130.83.99)
01 04 FF FF FF 00 Option 1 (Subnet Mask): 255.255.255.0
03 04 C0 A8 01 01 Option 3 (Router): 192.168.1.1
06 08 08 08 08 08 08 08 04 04 Option 6 (DNS): 8.8.8.8, 8.8.4.4
0C 0B 77 6F 72 6B 73 74 61 74 69 6F 6E Option 12 (Hostname): "workstation"
FF End Option
00 00 00 ... Padding to fill vend field
Decoded:
Subnet Mask: 255.255.255.0
Default Gateway: 192.168.1.1
DNS Servers: 8.8.8.8, 8.8.4.4
Hostname: workstation
The 64-byte vendor extension field in BOOTP was often insufficient for complex configurations. Workarounds included using the 'Extensions Path' option (code 18) to point to a file containing additional options. Later, DHCP expanded this field and allowed options to overflow into the sname and file fields, effectively providing kilobytes of option space.
Vendor-Specific Options (Code 43):
Option 43 allows vendors to define their own sub-options:
43 <length> <vendor-specific-data>
The interpretation of vendor-specific data depends on the client's vendor class identifier. Sun workstations, Cisco devices, and Microsoft clients all use different encodings within option 43.
Option 43 Structure:
+--------+--------+--------+--------+--------+-----
| 43 | Length | Sub-opt| Sub-len| Data...
+--------+--------+--------+--------+--------+-----
\\--- Sub-option repeats ---//
Evolution to DHCP:
The vendor extension mechanism pioneered by BOOTP became the foundation for DHCP's extensive option system. DHCP expanded the option space, added new option codes (e.g., lease time, server identifier), and standardized option negotiation. Every DHCP option you've ever configured traces its heritage to BOOTP's vendor extensions.
BOOTP servers maintain static databases mapping hardware addresses to complete boot configurations. Unlike DHCP's dynamic allocation, every BOOTP client must be pre-configured.
Traditional bootptab Format:
The /etc/bootptab file follows a text-based format with entries separated by colons:
# /etc/bootptab - BOOTP server configuration
# Format: hostname:tag=value:tag=value:...
# Global defaults
.default:
:sm=255.255.255.0:
:gw=192.168.1.1:
:ds=8.8.8.8 8.8.4.4:
:dn=example.com:
:sa=192.168.1.1:
:hd=/tftpboot:
# Individual hosts
workstation01:
:tc=.default:
:ha=001A2B3C4D5E:
:ip=192.168.1.100:
:bf=sunos/kernel:
workstation02:
:tc=.default:
:ha=001A2B3C4D5F:
:ip=192.168.1.101:
:bf=sunos/kernel:
printer-floor3:
:tc=.default:
:ha=00AABBCCDD01:
:ip=192.168.1.200:
:bf=hp/printer-boot:
| Tag | Meaning | Example |
|---|---|---|
| ha | Hardware address (MAC) | ha=001A2B3C4D5E |
| ip | IP address to assign | ip=192.168.1.100 |
| sm | Subnet mask | sm=255.255.255.0 |
| gw | Default gateway | gw=192.168.1.1 |
| ds | DNS servers | ds=8.8.8.8 8.8.4.4 |
| dn | Domain name | dn=example.com |
| sa | TFTP server address | sa=192.168.1.1 |
| bf | Boot file path | bf=/boot/sunos |
| hd | Home directory (TFTP root) | hd=/tftpboot |
| hn | Send hostname to client | hn (no value) |
| tc | Template/defaults to inherit | tc=.default |
The 'tc' (table continuation) tag enables inheritance from template entries. A common pattern defines a '.default' entry with shared settings, then each host entry uses 'tc=.default' to inherit these. This reduces redundancy and makes configuration changes easier—update the default once, all hosts inherit the change.
Modern ISC DHCP Server Format:
Modern servers like ISC DHCP use a more readable format that supports both BOOTP and DHCP:
# /etc/dhcpd.conf - ISC DHCP server (BOOTP-compatible)
# Global options
option domain-name \"example.com\";
option domain-name-servers 8.8.8.8, 8.8.4.4;
# Subnet declaration
subnet 192.168.1.0 netmask 255.255.255.0 {
option routers 192.168.1.1;
next-server 192.168.1.1; # TFTP server
}
# Static BOOTP hosts
host workstation01 {
hardware ethernet 00:1A:2B:3C:4D:5E;
fixed-address 192.168.1.100;
filename \"/boot/sunos\";
}
host workstation02 {
hardware ethernet 00:1A:2B:3C:4D:5F;
fixed-address 192.168.1.101;
filename \"/boot/sunos\";
}
host printer-floor3 {
hardware ethernet 00:AA:BB:CC:DD:01;
fixed-address 192.168.1.200;
filename \"/boot/hp-printer\";
}
Server Operation:
We have explored the architecture, packet format, and operation of BOOTP. Let's consolidate the key concepts:
What's Next:
In the next page, we will explore the bootstrap process in detail—how a diskless workstation uses BOOTP in conjunction with TFTP (and optionally NFS) to go from power-on to a running operating system. Understanding this complete boot sequence is essential for troubleshooting and for appreciating the elegance of network-based system initialization.
You now understand BOOTP's architecture, packet format, relay agent mechanism, and vendor extensions. You can explain how BOOTP solved RARP's limitations and why it became the foundation for modern DHCP. Next, we examine the complete bootstrap process that BOOTP enables.