分类: 系统运维
2012-06-17 17:50:55
In
Chapter 5 we described how a diskless system, with no knowledge of its
IP address, can determine its IP address using RARP when it is
bootstrapped. There are two problems with RARP: (1) the only thing
returned is the IP address, and (2) since RARP uses a link-layer
broadcast, RARP requests are not
forwarded by routers (necessitating
an RARP server on every physical network). This chapter describes an
alternative method for a diskless system to bootstrap itself, called
the Bootstrap Protocol, or BOOTP.
BOOTP uses UDP and normally works in conjunction with TFTP
BOOTP Packet Format
BOOTP requests and replies are encapsulated in UDP datagrams:
IP header | UDP header | BOOT request/reply |
20 bytes | 8 bytes | 300 bytes |
0~7 | 8~15 | 16~23 | 24~31 |
Opcode (1=request, 2=reply) | hardware type (1=Ethernet) | hardware address length(6 for Ethernet) | hop count |
transaction ID | |||
number of seconds | (unused) | ||
client IP address | |||
your IP address | |||
server IP address | |||
gateway IP address | |||
client hardware address(16 bytes) | |||
server hostname(64 bytes) | |||
boot filename(128 bytes) | |||
vendor-specific information(64 bytes) |
The hop count is set to 0 by the client, but can be used by a proxy server.
The
transaction ID is a 32-bit integer set by the client and returned by
the server. This lets the client match a response with a request. The
client should set this to a random number for each request.
Number
of seconds can be set by the client to the time since it started trying
to bootstrap. The servers can look at this value, and perhaps a
secondary server for a client won't respond until the number of seconds
has exceeded some value, implying that the client's primary server is
down.
If the client already knows its IP address, it fills in the
client IP address. Otherwise, the client sets this to 0. In the latter
case the server fills in your IP address with the client's IP address.
The server IP address is filled in by the server. If a proxy server is
used (Section 16.5), that proxy server fills in its gateway IP address.
The
client must set its client hardware address. Although this is the same
value as in the Ethernet header, by placing the field in the UDP
datagram also, it is easily available to any user process (e.g., a BOOTP
server) that receives the datagram. It is normally much harder (or
impossible) for a process reading UDP
datagrams to determine the fields in the Ethernet header that carried the UDP datagram.
The
server hostname is a null terminated string that is optionally filled
in by the server. The server can also fill in the boot filename with the
fully qualified, null terminated pathname of a file to bootstrap from.
The vendor-specific area is used for various extensions to BOOTP.
When
a client is bootstrapping using BOOTP (an opcode of 1) the request is
normally a link-layer broadcast and the destination IP address in the IP
header is normally 255.255.255.255 (the limited broadcast.)
The
source IP address is often 0.0.0.0 since the client does not know its
own IP address yet. 0.0.0.0 is a valid source IP address when a system
is
bootstrapping itself.
Port Numbers
There
are two well-known ports for BOOTP: 67 for the server and 68 for the
client. This means the client does not choose an unused ephemeral port,
but uses 68 instead. The reason two port numbers were chosen, instead of
just one for the server, is that a server's reply can be (but normally
isn't) broadcast.
If the server's reply were broadcast, and if
the client were to choose an ephemeral port number, these broadcasts
would also be received by other applications on other hosts that happen
to be using the same ephemeral port number. Hence, it is considered bad
form to broadcast to a random (i.e., ephemeral) port number.
If
the client also used the server's well-known port (67) as its port,
then all servers on the network are awakened to look at each broadcast
reply. (If all the servers were awakened, they would examine the opcode,
see that it's a reply and not a request, and go back to sleep.)
Therefore the choice was made to
have all clients use a single well-known port that differs from the server's well-known port.
If
multiple clients are bootstrapping at the same time, and if the server
broadcasts the replies, each client sees the replies intended for the
other clients. The clients can use the transaction ID field in the BOOTP
header to match replies with requests, or the client can examine the
returned client hardware address.
BOOTP Server Design
The
BOOTP client is normally provided in read-only memory on the diskless
system. It is interesting to see how the server is normally implemented.
First,
the server reads UDP datagrams from its well-known port (67). Nothing
special is required. This differs from an RARP server, which we said had
to read Ethernet frames with a type field of "RARP request." The BOOTP
protocol also made it easy for the server to obtain the client's
hardware address, by placing it into the BOOTP packet.
An
interesting problem arises: how can the server send a response directly
back to the client? The response is a UDP datagram, and the server knows
the client's IP address (probably read from a configuration file on the
server). But if the client sends a UDP datagram to that IP address (the
normal way UDP output is handled), the server's host will probably
issue an ARP request for that IP address. But the client can't respond
to the ARP request since it doesn't know its IP address yet! (This is
called the "chicken and egg" issue in RFC 951.)
There are two
solutions. The first, commonly used by Unix servers, is tor the server
to issue an ioctl(2) request to the kernel, to place an entry into the
ARP cache for this client. (This is what the arp -s command does.) The
server can do this since it knows the client's hardware address and IP
address. This means that when the server sends the UDP datagram (the
BOOTP reply), the server's ARP module will find the client's IP address
in the ARP cache.
An alternative solution is tor the server to
broadcast the BOOTP reply, instead of sending it directly to the client.
Since reducing the number of broadcasts on a network is always
desirable, this solution should be used only if the server cannot make
an entry into its ARP cache. Normally it requires superuser permission
to make an entry into the ARP cache, requiring a broadcast reply if the
server is nonprivileged.
BOOTP Through a Router
One
of the drawbacks of RARP is that it uses a link-layer broadcast, which
is normally not forwarded by a router. This required an RARP server on
each physical network. BOOTP can be used through a router, if supported
by the router. (Most major router vendors do support this feature.)
This
is mainly intended for diskless routers, because if a multiuser system
with a disk is used as a router, it can probably run a BOOTP server
itself. Alternatively, the common Unix BOOTP server supports this relay
mode, but again, if you can run a BOOTP server on the physical network,
there's normally no need to forward the requests to yet another server
on another network.
What happens is that the router (also called
the "BOOTP relay agent") listens tor BOOTP requests on the server's
well-known port (67). When a request is received, the relay agent places
its IP address into the gateway IP address field in the BOOTP request,
and sends the request to the real BOOTP server. (The
address placed
by the relay agent into the gateway field is the IP address of the
interface on which the request was received.) The relay agent also
increments the hops field by one. (This is to prevent infinite loops in
case the request is reforwarded. RFC 951 mentions that the request
should probably be thrown away if the hop count reaches 3.) Since the
outgoing request is a unicast datagram (as opposed to the original
client request that was broadcast), it can follow any route to the real
BOOTP server, passing through other routers. The real server gets the
request, forms the BOOTP reply, and sends it back to the relay agent,
not the client. The real server knows that the request has been
forwarded, since the gateway field in the request is nonzero. The relay
agent receives the reply and sends it to the client.
Vendor-Specific Information
A 64-byte vendor-specific area contains optional information for the server to return to the client.
If
information is provided, the first 4 bytes of this area are set to the
IP address 99.130.83.99. This is called the magic cookie and means there
is information in the area.
The rest of this area is a list of
items. Each item begins with a 1-byte tag field. Two of the items
consist of just the tag field: a tag of 0 is a pad byte (to force
following items to preferred byte boundaries), and a tag of 255 marks
the end of the items. Any bytes remaining in this area after the first
end byte should be
set to this value (255).
Other than these
two 1-byte items, the remaining items consist of a single length byte,
followed by the information. The format of some of the items in the
vendor-specific area:
tag=0 |
1 byte |
tag=1 | len=4 | subnet mask |
1 byte | 1 byte | 4 bytes |
tag=2 | len=4 | time |
1 byte | 1 byte | 4 bytes |
tag=3 | len=N | IP address of preferred gateway | ... | IP address of gateway |
1 byte | 1 byte | N bytes |
14 other tags with tag 4~17
tag=255 |
1 byte |
The
subnet mask and time value are really fixed-length items because their
values always occupy 4 bytes. The time offset is the number of seconds
since midnight January 1,1900, UTC.
The gateway item is an example of a variable-length item. The length is always a multiple of 4, and the values are the 32-bit IP addresses of one or more gateways (routers) for the client to use. The first one returned must be the preferred gateway.
There are 14 other items defined in RFC 1533. Probably the most
important is the IP address of a DNS name server, with a tag value of 6.
Other items return the IP address of a printer server, the IP address
of a time server, and so on. Refer to the RFC for all the details.