RFC 951

Bootstrap Protocol

๐Ÿ“… published September 1985, from ietf

RFC 951: BOOTSTRAP PROTOCOL (BOOTP) ๐ŸŽ€

Part 1 of 3 ๐Ÿ’–

Okay bestie, the title block is giving old-school ARPANET ๐Ÿฆ‹. It was written by Bill Croft at Stanford University and John Gilmore at Sun Microsystems, and it's dated September 1985 ๐Ÿ“…. It's a proposed protocol (more on that in Section 1), and this copy doesn't list anything it obsoletes or updates. Let's get into it ๐Ÿ’…

1. Status of this Memo ๐ŸŒธ

So this RFC puts a proposed protocol out there for the ARPA-Internet community and asks people to talk about it and suggest improvements ๐Ÿ’ฌ. Distribution of this memo is unlimited, so you can share it with literally anyone ๐Ÿซถ

2. Overview โœจ

Okay so this RFC describes an IP/UDP bootstrap protocol (BOOTP) that lets a diskless client machine figure out three things: its own IP address, the address of a server host, and the name of a file to load into memory and run ๐Ÿง . The whole bootstrap is basically TWO PHASES ๐Ÿ‘‘. This RFC covers the first one, which you could call 'address determination and bootfile selection'. Once the client has its address and filename info, control moves to phase two, where the file transfer happens. That transfer will usually use TFTP [9], since both phases are meant to live in PROM on the client ๐Ÿ’œ. BOOTP could also work with other protocols like SFTP [3] or FTP [6], just saying ๐Ÿ™ˆ

We suggest that the client's PROM software give you a way to do a complete bootstrap with no 'user' interaction at all. That's the kind of boot you get on an unattended power-up ๐Ÿ”Œ. There should also be a mechanism so the user can manually supply the address and filename info, which skips BOOTP and jumps straight into the file transfer phase ๐Ÿงš. If there's non-volatile storage, we suggest keeping default settings there and bypassing BOOTP, unless those settings make the file transfer phase fail. If the cached info fails, the bootstrap should fall back to phase 1 and use BOOTP ๐Ÿ”

Here's a quick outline of the protocol, bestie ๐Ÿ“:

  1. A single packet exchange is performed. Timeouts are used to retransmit until a reply is received. The same packet field layout is used in both directions. Fixed length fields of maximum reasonable length are used to simplify structure definition and parsing ๐Ÿงฉ
  2. An 'opcode' field exists with two values. The client broadcasts a 'bootrequest' packet, and then the server answers with a 'bootreply' packet. The bootrequest contains the client's hardware address and its IP address, if it knows it ๐Ÿ“ฃ
  3. The request can optionally contain the name of the server the client wants to respond. This lets the client force the boot to happen from a specific host, which is handy if multiple versions of the same bootfile exist or if the server is in a far distant net/domain ๐ŸŒ. The client doesn't have to deal with name or domain services, because that job gets pushed off to the BOOTP server ๐Ÿ™Œ
  4. The request can optionally contain the 'generic' filename to be booted, like 'unix' or 'ethertip'. When the server sends the bootreply, it swaps this field for the fully qualified path name of the right boot file ๐Ÿ“‚. To figure out that name, the server may check its own database that correlates the client's address and filename request with a boot file customized for that client ๐Ÿ—‚๏ธ. If the bootrequest filename is a null string, the server returns a filename field naming the 'default' file to load for that client ๐Ÿซง
  5. For clients that don't know their IP addresses, the server also needs a database that relates hardware address to IP address. That client IP address then goes into a field in the bootreply ๐Ÿชช
  6. Some network topologies (Stanford's is one) might have a physical cable with no TFTP server directly attached. For example, all the gateways and hosts on a certain cable could be diskless ๐Ÿ˜ญ. With help from neighboring gateways, BOOTP can let clients boot off servers several hops away, through those gateways. See the section 'Booting Through Gateways' below. This part of the protocol needs no special action from the client. Implementing it is optional, and it takes a small amount of extra code in gateways and servers ๐Ÿ› ๏ธ

3. Packet Format ๐Ÿ“ฆ

All numbers shown are decimal, unless it says otherwise ๐Ÿ”ข. The BOOTP packet gets wrapped in a standard IP [8] UDP [7] datagram. To keep things simple, it's assumed the BOOTP packet is never fragmented. Numeric fields are packed in 'standard network byte order', which means high order bits go first ๐Ÿ’…

In the IP header of a bootrequest, the client fills in its own IP source address if it knows it, and zero if it doesn't. When the server address is unknown, the IP destination address will be the 'broadcast address' 255.255.255.255. That address basically means 'broadcast on the local cable, (I don't know my net number)' [4] ๐Ÿ“ก

The UDP header has source and destination port numbers. BOOTP uses two reserved port numbers: 'BOOTP client' (68) and 'BOOTP server' (67) ๐ŸŽŸ๏ธ. The client sends requests with 'BOOTP server' as the destination port, and this is usually a broadcast ๐Ÿ“ข. The server sends replies with 'BOOTP client' as the destination port. Depending on the kernel or driver facilities in the server, that may or may not be a broadcast. This gets explained more in the section titled 'Chicken/Egg issues' below ๐Ÿฃ. Why two reserved ports? It's so the BOOTP server daemons don't get 'woken up' and scheduled when a bootreply has to be broadcast to a client ๐Ÿ˜ด. The server and other hosts won't be listening on the 'BOOTP client' port, so any incoming broadcasts get filtered out at the kernel level ๐Ÿ›ก๏ธ. We couldn't just let the client pick a 'random' port number for the UDP source field, either. Since the server reply may be broadcast, a random port number could confuse other hosts that happen to be listening on that port ๐Ÿ™ˆ

The UDP length field gets set to the length of the UDP plus BOOTP portions of the packet ๐Ÿ“. The client (or server) can set the UDP checksum field to zero if it wants, which skips that extra overhead in a PROM implementation โšก. In the 'Packet Processing' section below, the phrase '[UDP checksum.]' shows up whenever the checksum might be verified or computed ๐Ÿงฎ

Here's the field table, verbatim, because implementers need every single byte ๐Ÿ“:

      FIELD   BYTES   DESCRIPTION
      -----   -----   -----------

         op      1       packet op code / message type.
                         1 = BOOTREQUEST, 2 = BOOTREPLY

         htype   1       hardware address type,
                         see ARP section in "Assigned Numbers" RFC.
                         '1' = 10mb ethernet

         hlen    1       hardware address length
                         (eg '6' for 10mb ethernet).

         hops    1       client sets to zero,
                         optionally used by gateways
                         in cross-gateway booting.

         xid     4       transaction ID, a random number,
                         used to match this boot request with the
                         responses it generates.

         secs    2       filled in by client, seconds elapsed since
                         client started trying to boot.

         --      2       unused

         ciaddr  4       client IP address;
                         filled in by client in bootrequest if known.

         yiaddr  4       'your' (client) IP address;
                         filled by server if client doesn't
                         know its own address (ciaddr was 0).

         siaddr  4       server IP address;
                         returned in bootreply by server.

         giaddr  4       gateway IP address,
                         used in optional cross-gateway booting.

         chaddr  16      client hardware address,
                         filled in by client.

         sname   64      optional server host name,
                         null terminated string.

         file    128     boot file name, null terminated string;
                         'generic' name or null in bootrequest,
                         fully qualified directory-path
                         name in bootreply.

         vend    64      optional vendor-specific area,
                         e.g. could be hardware type/serial on request,
                         or 'capability' / remote file system handle
                         on reply.  This info may be set aside for use
                         by a third phase bootstrap or kernel.

4. Chicken / Egg Issues ๐Ÿฃ

Okay, the big question: how can the server send an IP datagram to the client if the client doesn't know its own IP address (yet)? ๐Ÿค” Whenever a bootreply is being sent, the transmitting machine does the following:

  1. If the client knows its own IP address ('ciaddr' field is nonzero), the IP can be sent 'as normal', since the client will respond to ARPs [5] โœ…
  2. If the client doesn't know its IP address yet (ciaddr is zero), then the client can't respond to ARPs sent by the transmitter of the bootreply. So there are two options ๐Ÿ˜ฌ:
    • a. If the transmitter has the kernel or driver hooks needed to 'manually' construct an ARP address cache entry, it can fill in an entry using the 'chaddr' and 'yiaddr' fields. Of course, this entry should have a timeout on it, just like any other entry made by the normal ARP code itself โณ. The transmitter can then simply send the bootreply to the client's IP address. UNIX (4.2 BSD) has this capability ๐Ÿก
    • b. If the transmitter lacks those kernel hooks, it can simply send the bootreply to the IP broadcast address on the appropriate interface. That's only one additional broadcast over the previous case ๐Ÿ“ฃ

5. Client Use of ARP ๐Ÿค

The client PROM must contain a simple implementation of ARP, and the address cache could be just one entry in size ๐Ÿงธ. This lets a second-phase-only boot (TFTP) happen when the client already knows the IP addresses and bootfile name ๐ŸŽฏ

Any time the client is expecting to receive a TFTP or BOOTP reply, it should be prepared to answer an ARP request for its own IP to hardware address mapping, if it knows that mapping ๐Ÿ’Œ

Since the bootreply will contain the hardware source address of the server/gateway in the hardware encapsulation, the client MAY be able to skip sending an ARP request for the server/gateway IP address, which would be used in the following TFTP phase. But this should only be treated as a special case, because it's still desirable to allow a second-phase-only boot like we talked about above ๐Ÿซถ

6. Comparison to RARP ๐Ÿ•ต๏ธ

An earlier protocol, Reverse Address Resolution Protocol (RARP) [1], was proposed to let a client figure out its IP address, given that it knew its hardware address. The catch is that RARP was a hardware link level protocol (not IP/UDP based) ๐Ÿ™ƒ. That meant RARP could only be implemented on hosts with special kernel or driver modifications to access these 'raw' packets ๐Ÿ”ง. There are a lot of network kernels out there now, and each one is maintained by different organizations. So a boot protocol that doesn't require kernel modifications is a decided advantage ๐Ÿ‘‘

BOOTP provides this hardware-to-IP-address lookup function, along with the other useful features described in the sections above ๐Ÿ’–

7. Packet Processing โœจ

7.1. Client Transmission ๐Ÿ’–

Okay bestie, before you build the packet for the very first time, it is a good idea to clear the entire packet buffer to all zeros ๐Ÿงน. That way every field starts in its default state ๐Ÿซถ. Then the client creates a packet with the following fields.

The IP destination address is set to 255.255.255.255. (the broadcast address) or to the server's IP address (if known). The IP source address and ciaddr are set to the client's IP address if known, else 0. The UDP header gets the proper length, with the source port set to BOOTP client and the destination port set to BOOTP server โœจ.

op is set to 1, BOOTREQUEST. htype is set to the hardware address type as assigned in the ARP section of the "Assigned Numbers" RFC. hlen is set to the length of the hardware address, e.g. 6 for 10mb ethernet ๐Ÿ”Œ.

xid is set to a "random" transaction id ๐ŸŽฒ. secs is the number of seconds that have passed since the client started booting, so servers know how long the client has been trying โฐ. As the number gets bigger, certain servers may feel more "sympathetic" toward a client they don't normally serve ๐Ÿฅบ. If a client doesn't have a suitable clock, it could build a rough estimate using a loop timer. Or it could just always send a fixed value, say 100 seconds ๐Ÿ’….

If the client knows its IP address, ciaddr (and the IP source address) are set to that value. chaddr is filled in with the client's hardware address ๐Ÿชช.

If the client wants to restrict booting to a particular server name, it may place a null-terminated string in sname. The name should be any of the allowable names or nicknames of the desired host ๐ŸŽฏ.

The client has a few options for the file field. If it's left null, it means "I want to boot the default file for my machine." A null file name can also mean "I'm only interested in finding out client/server/gateway IP addresses, I don't care about file names" ๐Ÿ™ˆ. The field can also be a generic name such as "unix" or "gateway," which means "boot the named program configured for my machine." Finally, it can be a fully directory-qualified path name ๐Ÿ—‚๏ธ.

The vend field can be filled in by the client with vendor-specific strings or structures. For example, the machine hardware type or serial number may go here. However, the operation of the BOOTP server should not DEPEND on this information existing ๐Ÿšซ.

If the vend field is used, it is recommended that a 4 byte "magic number" be the first item within vend. This lets a server figure out what kind of information it's looking at in this field ๐Ÿ”ฎ. Numbers can be assigned by the usual "magic number" process: you pick one and it's magic โœจ. A different magic number could be used for bootreplies than for bootrequests, so the client can take special action with the reply information ๐ŸŽ€.

[UDP checksum.]

7.2. Client Retransmission Strategy ๐Ÿ”

If no reply comes back for a certain length of time, the client should retransmit the request. The time interval must be chosen carefully so it doesn't flood the network ๐ŸŒŠ. Picture a cable with 100 machines that are all just coming up after a power failure. Retransmitting the request every four seconds will inundate the net ๐Ÿ’€.

As a possible strategy, you might consider backing off exponentially, similar to how ethernet backs off after a collision ๐Ÿ“‰. So for example, if the first packet goes out at 0:00, the second would be at :04, then :08, then :16, then :32, then :64. You should also randomize each time ๐ŸŽฐ. This is done similar to the ethernet specification: start with a mask, and it with a random number to get the first backoff, and on each succeeding backoff, make the mask one bit longer. This doubles the average delay on each backoff ๐Ÿงฎ.

After the "average" backoff reaches about 60 seconds, it should not be increased any further, but it should still be randomized ๐Ÿซถ.

Before each retransmission, the client should update the secs field. [UDP checksum.]

7.3. Server Receives BOOTREQUEST ๐Ÿ–ฅ๏ธ

[UDP checksum.] If the UDP destination port does not match the BOOTP server port, discard the packet ๐Ÿ—‘๏ธ.

If the server name field (sname) is null (no particular server specified), or sname is specified and matches our name or nickname, then keep going with packet processing โœ….

If sname is specified but doesn't match "us," there are several options:

  1. You may choose to simply discard this packet.
  2. If a name lookup on sname shows it's on this same cable, discard the packet.
  3. If sname is on a different net, you may choose to forward the packet to that address. If you do, check the giaddr (gateway address) field. If giaddr is zero, fill it in with my address or the address of a gateway that can be used to reach that net. Then forward the packet ๐Ÿ“ฆ.

If the client IP address (ciaddr) is zero, then the client doesn't know its own IP address yet. Try to look up the client hardware address (chaddr, hlen, htype) in our database. If no match is found, discard the packet. Otherwise, we now have an IP address for this client, so fill it into the yiaddr (your IP address) field ๐Ÿท๏ธ.

Next, we check the boot file name field (file). The field will be null if the client isn't interested in filenames or wants the default bootfile. If the field is non-null, it's used as a lookup key in a database, along with the client's IP address. If there's a default file, a generic file (possibly indexed by the client address), or a fully-specified path name that matches, replace the file field with the fully-specified path name of the selected boot file ๐Ÿ“. If the field is non-null and no match is found, then the client is asking for a file we don't have. Discard the packet, because maybe some other BOOTP server will have it ๐Ÿคทโ€โ™€๏ธ.

The vend vendor-specific data field should be checked next. If a recognized type of data is provided, client-specific actions should be taken, and a response should be placed in the vend data field of the reply packet ๐ŸŽ. For example, a workstation client could provide an authentication key and get back a capability for remote file access, or a set of configuration options that can be passed to the operating system that's about to boot ๐Ÿ’ป.

Place my (server) IP address in the siaddr field. Set the op field to BOOTREPLY. The UDP destination port is set to BOOTP client. If the client address ciaddr is nonzero, send the packet there. Else, if the gateway address giaddr is nonzero, set the UDP destination port to BOOTP server and send the packet to giaddr ๐Ÿ›ฃ๏ธ. Else, the client is on one of our cables but doesn't know its own IP address yet, so use a method described in the 'Egg' section above to send it to the client ๐Ÿฅš. If 'Egg' is used and we have multiple interfaces on this host, use the yiaddr (your IP address) field to figure out which net (cable/interface) to send the packet to ๐Ÿงญ. [UDP checksum.]

7.4. Server/Gateway Receives BOOTREPLY ๐Ÿ“ฌ

[UDP checksum.] If yiaddr (your [the client's] IP address) refers to one of our cables, use one of the 'Egg' methods above to forward it to the client. Be sure to send it to the BOOTP client UDP destination port ๐ŸŽฏ.

7.5. Client Reception ๐Ÿ“ก

Don't forget to process ARP requests for my own IP address (if I know it) ๐Ÿ™‹โ€โ™€๏ธ. [UDP checksum.] The client should discard incoming packets that: are not IP/UDPs addressed to the boot port; are not BOOTREPLYs; do not match my IP address (if I know it) or my hardware address; or do not match my transaction id. Otherwise, we have received a successful reply ๐ŸŽ‰. yiaddr will contain my IP address, if I didn't know it before. file is the file name to TFTP "read request" ๐Ÿ“‚. The server address is in siaddr. If giaddr (gateway address) is nonzero, then the packets should be forwarded there first, in order to get to the server ๐Ÿ›ค๏ธ.

8. Booting Through Gateways ๐ŸŒ‰

This part of the protocol is optional and needs some extra code in cooperating gateways and servers, but it allows cross-gateway booting ๐ŸŒˆ. This is mainly useful when gateways are diskless machines. Gateways with disks (e.g. a UNIX machine acting as a gateway) might as well run their own BOOTP/TFTP servers ๐Ÿ’พ.

Gateways listening to broadcast BOOTREQUESTs may decide to forward or rebroadcast these requests "when appropriate." For example, the gateway could have, as part of its configuration tables, a list of other networks or hosts to receive a copy of any broadcast BOOTREQUESTs ๐Ÿ“‹. Even though a hops field exists, it's a poor idea to simply rebroadcast the requests globally, since broadcast loops will almost certainly happen ๐Ÿ”„.

The forwarding could begin right away, or it could wait until the secs (seconds client has been trying) field passes a certain threshold โณ.

If a gateway does decide to forward the request, it should look at the giaddr (gateway IP address) field. If it's zero, the gateway should plug its own IP address (on the receiving cable) into this field. It may also use the hops field to optionally control how far the packet gets reforwarded. Hops should be incremented on each forwarding. For example, if hops passes 3, the packet should probably be discarded ๐Ÿšฎ. [UDP checksum.]

Here we recommended placing this special forwarding function in the gateways. But that doesn't have to be the case! As long as some 'BOOTP forwarding agent' exists on the net with the booting client, the agent can do the forwarding when appropriate. So this service may or may not be co-located with the gateway ๐Ÿซถ.

In the case of a forwarding agent that isn't located in the gateway, the agent could save itself some work by plugging the broadcast address of the interface that received the bootrequest into the giaddr field ๐Ÿง . That way the reply gets forwarded using normal gateways, without involving the forwarding agent. The downside, of course, is that you lose the ability to use the 'Egg' non-broadcast method of sending the reply, which causes extra overhead for every host on the client cable ๐Ÿ˜ญ.

9. Sample BOOTP Server Database โœจ

okay bestie, the RFC gives us a sample text file that the BOOTP server program might use ๐Ÿ“„๐Ÿ’– it's not required, just a suggestion, but it's so clean. The file has two sections, split by a line with a % in column 1 ๐ŸŽ€. The first section holds a 'default directory' plus mappings from generic names to directory/pathnames. The first generic name listed there is the 'default file' you get when the bootrequest has a null 'file' string ๐Ÿงš

The second section maps a hardware addresstype/address to an ipaddress ๐Ÿฆ‹ You can also optionally override the default generic name by giving an ipaddress-specific genericname. There's a 'suffix' item too, which is optional ๐Ÿ’… If you supply one, any generic names the client asks for get accessed by first appending 'suffix' to the 'pathname' for that generic name. If that file doesn't exist, the plain 'pathname' gets tried instead. Honestly the suffix is a whole main character move, because you can set up a full set of custom generics without much effort ๐ŸŒˆ

Here's the general format. Fields are separated by one or more spaces or tabs, trailing empty fields can be left out, and blank lines and lines starting with '#' get ignored ๐ŸŒธ

# comment line

homedirectory
genericname1    pathname1
genericname2    pathname2
...

% end of generic names, start of address mappings

hostname1 hardwaretype hardwareaddr1 ipaddr1 genericname suffix
hostname2 hardwaretype hardwareaddr2 ipaddr2 genericname suffix
...

Now a specific example ๐Ÿ˜ญ๐Ÿซถ The 'hardwaretype' number matches the one in the ARP section of the 'Assigned Numbers' RFC, so that's the lookup key. The 'hardwaretype' and 'ipaddr' numbers are in decimal, and 'hardwareaddr' is in hex ๐Ÿ”ฅ

# last updated by smith

/usr/boot
vmunix          vmunix
tip             ethertip
watch           /usr/diag/etherwatch
gate            gate.

% end of generic names, start of address mappings

hamilton        1 02.60.8c.06.34.98     36.19.0.5
burr            1 02.60.8c.34.11.78     36.44.0.12
101-gateway     1 02.60.8c.23.ab.35     36.44.0.32      gate 101
mjh-gateway     1 02.60.8c.12.32.bc     36.42.0.64      gate mjh
welch-tipa      1 02.60.8c.22.65.32     36.47.0.14      tip
welch-tipb      1 02.60.8c.12.15.c8     36.46.0.12      tip
So in this example, if 'mjh-gateway' does a default boot, it gets the file '/usr/boot/gate.mjh'. Suffix + pathname lookup in action, periodt ๐Ÿ’…

10. Acknowledgements ๐Ÿซถ

Ross Finlayson (et. al.) wrote two earlier RFCs about TFTP bootstrapping [2] using RARP [1], and they deserve a whole crown ๐Ÿ‘‘

We also want to shout out Noel Chiappa, Bob Lyon, Jeff Mogul, Mark Lewis, and David Plummer for their earlier work and comments ๐ŸŒŸ iconic group of legends.

References ๐Ÿ“š

  1. Ross Finlayson, Timothy Mann, Jeffrey Mogul, Marvin Theimer. A Reverse Address Resolution Protocol. RFC 903, NIC, June, 1984.
  2. Ross Finlayson. Bootstrap Loading using TFTP. RFC 906, NIC, June, 1984.
  3. Mark Lottor. Simple File Transfer Protocol. RFC 913, NIC, September, 1984.
  4. Jeffrey Mogul. Broadcasting Internet Packets. RFC 919, NIC, October, 1984.
  5. David Plummer. An Ethernet Address Resolution Protocol. RFC 826, NIC, September, 1982.
  6. Jon Postel. File Transfer Protocol. RFC 765, NIC, June, 1980.
  7. Jon Postel. User Datagram Protocol. RFC 768, NIC, August, 1980.
  8. Jon Postel. Internet Protocol. RFC 791, NIC, September, 1981.
  9. K. R. Sollins, Noel Chiappa. The TFTP Protocol. RFC 783, NIC, June, 1981.
๐Ÿ“ฆ where this page comes from