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.\n\nBootstrap 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.\n\nBOOTP 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.\n\nDesign Goals:\n\n1. Complete boot configuration in one exchange: Not just IP address, but everything needed to boot\n2. Routability: Work across routed networks via relay agents\n3. Extensibility: Support vendor-specific options for future needs\n4. Backward compatibility: Coexist with RARP deployments\n5. Simplicity: Single request/reply exchange\n\nArchitectural 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:\n\nBOOTP's move to UDP/IP fundamentally changed what was possible:\n\nBefore (RARP - Layer 2):\n- Broadcasts confined to local segment\n- Server required on every VLAN\n- 50 VLANs = 50+ RARP servers\n\nAfter (BOOTP - Layer 3):\n- Requests can be relayed across routers\n- Single centralized server possible\n- 50 VLANs = 1 BOOTP server + 50 relay configurations
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):\n\nThe 4-byte transaction ID serves a crucial function: it matches replies to requests. Consider the scenario:\n\n1. Client A sends BOOTREQUEST with xid = 0x12345678\n2. Client B sends BOOTREQUEST with xid = 0xABCDEF00\n3. Server sends two replies\n4. Client A only accepts reply with xid = 0x12345678\n5. Client B only accepts reply with xid = 0xABCDEF00\n\nWithout xid, clients could accept replies intended for other clients.\n\nGeneration guidelines:\n- Should be random\n- Must persist across retries (same xid)\n- Should change between boot cycles\n- Common approach: seed from MAC address + timer
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.\n\nThe Complete Exchange Sequence:
BOOTREQUEST Details:\n\nThe client constructs and sends a BOOTREQUEST:\n\n\nop: 1 (BOOTREQUEST)\nhtype: 1 (Ethernet)\nhlen: 6\nhops: 0\nxid: 0x12345678 (random)\nsecs: 0 (just started)\nflags: 0x8000 (request broadcast reply)\nciaddr: 0.0.0.0 (don't know my IP)\nyiaddr: 0.0.0.0 (server will fill this)\nsiaddr: 0.0.0.0 (server will fill this)\ngiaddr: 0.0.0.0 (relay will fill if needed)\nchaddr: 00:1A:2B:3C:4D:5E (my MAC)\nsname: (zeros - server name optional)\nfile: (zeros - server will provide)\nvend: (zeros or magic cookie)\n\n\nBOOTREPLY Details:\n\nThe server responds with complete configuration:\n\n\nop: 2 (BOOTREPLY)\nhtype: 1 (Ethernet)\nhlen: 6\nhops: 0\nxid: 0x12345678 (matches request)\nsecs: 0\nflags: 0x8000\nciaddr: 0.0.0.0\nyiaddr: 192.168.1.100 (your IP!)\nsiaddr: 192.168.1.1 (TFTP server)\ngiaddr: 10.0.1.1 (if relayed)\nchaddr: 00:1A:2B:3C:4D:5E (your MAC)\nsname: "tftp-server.example.com"\nfile: "/boot/sunos/C0A80164"\nvend: (subnet mask, gateway, etc.)\n
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:\n\n| Direction | Source Port | Destination Port |\n|-----------|-------------|------------------|\n| BOOTREQUEST | 68 | 67 |\n| BOOTREPLY | 67 | 68 |\n\nWhy specific ports for both client and server?\n\nUnlike most protocols where the client uses an ephemeral port, BOOTP uses fixed ports for both sides. This enables:\n\n1. Client port filtering: Firewall rules can specifically allow BOOTP client traffic\n2. Broadcast handling: The server knows exactly where to send broadcast replies\n3. Boot ROM simplicity: No ephemeral port allocation required\n4. Relay agent operation: Relay knows which port to forward to\n\nIP Address Usage:\n\n| Packet | Source IP | Destination IP |\n|--------|-----------|----------------|\n| BOOTREQUEST (direct) | 0.0.0.0 | 255.255.255.255 |\n| BOOTREQUEST (via relay) | 0.0.0.0 | 255.255.255.255 (local), then unicast to server |\n| BOOTREPLY (direct) | Server IP | Client IP or 255.255.255.255 |\n| 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.\n\nHow Relay Agents Work:\n\n1. Client broadcasts BOOTREQUEST on local segment\n2. Relay agent receives the broadcast (listening on UDP port 67)\n3. Relay inserts its own IP address in the giaddr field\n4. Relay forwards the packet as unicast to the configured BOOTP server\n5. Server processes request, sends reply to the relay agent (using giaddr)\n6. Relay agent forwards reply to the client (broadcast or unicast based on flags)
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:\n\nThe Gateway Internet Address (giaddr) field is crucial for relay operation:\n\n| Scenario | giaddr Value | Purpose |\n|----------|--------------|---------|\n| Client to local server | 0.0.0.0 | No relay involved |\n| Client via relay | Relay's IP | Server knows client's subnet |\n| Server reply via relay | Original relay's IP | Reply routes back through relay |\n\nWhy giaddr Matters for Subnet Determination:\n\nThe server uses giaddr to determine which IP pool to allocate from:\n\n\nClient on 10.0.1.0/24 sends via relay at 10.0.1.1\nServer receives: giaddr = 10.0.1.1\nServer logic: "Client is on the 10.0.1.0/24 network"\nServer allocates IP from the 10.0.1.0/24 pool\n\n\nWithout 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:\n\n\n! Enable BOOTP/DHCP relay on an interface\ninterface GigabitEthernet0/1\n ip address 10.0.1.1 255.255.255.0\n ip helper-address 192.168.1.1\n ip helper-address 192.168.1.2 ! Backup server\n!\n! Note: ip helper-address forwards multiple UDP ports by default:\n! - BOOTP/DHCP (67, 68)\n! - TFTP (69)\n! - DNS (53)\n! - Time (37)\n! - NetBIOS (137, 138)\n! - TACACS (49)\n\n\nMultiple Relay Hops:\n\nBOOTP supports relaying through multiple intermediate routers, tracked by the hops field:\n\n- Initial value: 0\n- Incremented by each relay agent\n- Usually limited to 16 hops (implementation-specific)\n- Prevents infinite loops in misconfigured networks
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.\n\nThe Magic Cookie:\n\nVendor extensions begin with a 4-byte 'magic cookie' that identifies the format:\n\n\nMagic Cookie: 99.130.83.99 (0x63825363)\n\n\nThis specific value was chosen to be unlikely to appear by accident and to be memorable (it's 99.130.83.99 in dotted decimal).\n\nOption Format:\n\n\n+--------+--------+--------+--------+--------+-----\n| Code | Length | Data... \n+--------+--------+--------+--------+--------+-----\n 1 byte 1 byte 'Length' bytes\n\n\nCommon 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:\n\n\nVendor Options for client at 192.168.1.100:\n\nRaw bytes:\n63 82 53 63 Magic Cookie (99.130.83.99)\n01 04 FF FF FF 00 Option 1 (Subnet Mask): 255.255.255.0\n03 04 C0 A8 01 01 Option 3 (Router): 192.168.1.1\n06 08 08 08 08 08 08 08 04 04 Option 6 (DNS): 8.8.8.8, 8.8.4.4\n0C 0B 77 6F 72 6B 73 74 61 74 69 6F 6E Option 12 (Hostname): "workstation"\nFF End Option\n00 00 00 ... Padding to fill vend field\n\nDecoded:\n Subnet Mask: 255.255.255.0\n Default Gateway: 192.168.1.1\n DNS Servers: 8.8.8.8, 8.8.4.4\n Hostname: workstation\n
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):\n\nOption 43 allows vendors to define their own sub-options:\n\n\n43 <length> <vendor-specific-data>\n\n\nThe 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.\n\nOption 43 Structure:\n\n\n+--------+--------+--------+--------+--------+-----\n| 43 | Length | Sub-opt| Sub-len| Data... \n+--------+--------+--------+--------+--------+-----\n \\--- Sub-option repeats ---//\n\n\nEvolution to DHCP:\n\nThe 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.\n\nTraditional bootptab Format:\n\nThe /etc/bootptab file follows a text-based format with entries separated by colons:\n\n\n# /etc/bootptab - BOOTP server configuration\n# Format: hostname:tag=value:tag=value:...\n\n# Global defaults\n.default:\\\n :sm=255.255.255.0:\\\n :gw=192.168.1.1:\\\n :ds=8.8.8.8 8.8.4.4:\\\n :dn=example.com:\\\n :sa=192.168.1.1:\\\n :hd=/tftpboot:\n\n# Individual hosts\nworkstation01:\\\n :tc=.default:\\\n :ha=001A2B3C4D5E:\\\n :ip=192.168.1.100:\\\n :bf=sunos/kernel:\n\nworkstation02:\\\n :tc=.default:\\\n :ha=001A2B3C4D5F:\\\n :ip=192.168.1.101:\\\n :bf=sunos/kernel:\n\nprinter-floor3:\\\n :tc=.default:\\\n :ha=00AABBCCDD01:\\\n :ip=192.168.1.200:\\\n :bf=hp/printer-boot:\n
| 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:\n\nModern servers like ISC DHCP use a more readable format that supports both BOOTP and DHCP:\n\n\n# /etc/dhcpd.conf - ISC DHCP server (BOOTP-compatible)\n\n# Global options\noption domain-name \"example.com\";\noption domain-name-servers 8.8.8.8, 8.8.4.4;\n\n# Subnet declaration\nsubnet 192.168.1.0 netmask 255.255.255.0 {\n option routers 192.168.1.1;\n next-server 192.168.1.1; # TFTP server\n}\n\n# Static BOOTP hosts\nhost workstation01 {\n hardware ethernet 00:1A:2B:3C:4D:5E;\n fixed-address 192.168.1.100;\n filename \"/boot/sunos\";\n}\n\nhost workstation02 {\n hardware ethernet 00:1A:2B:3C:4D:5F;\n fixed-address 192.168.1.101;\n filename \"/boot/sunos\";\n}\n\nhost printer-floor3 {\n hardware ethernet 00:AA:BB:CC:DD:01;\n fixed-address 192.168.1.200;\n filename \"/boot/hp-printer\";\n}\n\n\nServer Operation:\n\n1. Receive BOOTREQUEST on UDP port 67\n2. Extract chaddr (client hardware address)\n3. Lookup chaddr in configuration database\n4. If found: Construct BOOTREPLY with configured values\n5. If not found: Ignore (or log for troubleshooting)\n6. Send BOOTREPLY to client (via relay if giaddr present)
We have explored the architecture, packet format, and operation of BOOTP. Let's consolidate the key concepts:
What's Next:\n\nIn 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.