TCP/IP协议 — TFTP 与 BOOTP 协议

风尘

文章目录

  1. 1. TFTP 协议
    1. 1.1. 协议
    2. 1.2. 安全性
  2. 2. BOOTP 协议
    1. 2.1. 分组格式
    2. 2.2. 端口号
    3. 2.3. BOOTP 服务器设计
    4. 2.4. BOOTP 穿越路由

[TOC]

TFTP 协议

简单文件传送协议(Trivial File Transfer Protocol,TFTP),最初用于无盘系统(通常是无盘系统或者X终端)。与FTP协议不同,为了更简单、小巧,TFTP被设计使用UDPTFTP(及其所需的UDPIP和设备驱动程序)可以装入只读存储器。

协议

客户和服务器之间的每次交换开始时,客户请求服务器读取或写入一个文件。请求报文格式如下:

5种TFTP报文格式5种TFTP报文格式

操作码 字段,读请求RRQ,操作码为1;写请求WRQ,操作码为2

文件名 字段,表示客户要读取或写入的位于服务器上的文件。文件字段以0字节作为结束。

模式 字段,一个ASCII码串,同样以0字节结束。netascii表示数据以成行的ASCII码字符组成,以两个字节—回车符跟换行符(CR/LF)作为结束符,默认使用该模式;octet表示将数据看作8bit一组的字节流而不作任何解释。

块编号 字段,每个数据分组包含一个块编号字段,它以后要在确认分组中使用。

TFTP客户需要发送一个读请求说明要读的文件名和文件模式 (mode)。如果这个文件能被这个客户读取,TFTP服务器就返回一个块编号为1的数据分组。TFTP客户又发送一个块编号为1ACKTFTP服务器随后发送块编号为2的数据。TFTP客户发回块编号为2ACK。重复这个过程直到这个文件传送完。除了最后一个数据分组可含有不足512字节的数据,其他每个数据分组均含有512字节的数据。当TFTP客户收到一个不足512字节的数据分组,就知道它收到最后一个数据分组。

在写请求的情况下, TFTP 客户发送WRQ指明文件名和模式。如果该文件能被 该客户写,TFTP服务器就返回块编号为0ACK包。该客户就将文件的头512字节以块编号为1发出。服务器则返回块编号为1ACK

这种类型的数据传输称为停止等待协议。它只用在一些简单的协议,(如TFTP,在任一时刻外部网络中只有一个数据包处于传输中,并且任一方每接收到一个包,就要又发送一个新的包来作为回复,一直到文件传输完毕)。TCP提供了不同形式的确,能提供更高的系统吞吐量。TFTP的优点在于实现的简单而不是高的系统吞吐量。

最后一种TFTP报文类型是差错报文,它的操作码为5。它用于服务器不能处理读请求或写请求的情况。在文件传输过程中的读和写差错也会导致传送这种报文,接着停止传输。差错编号 字段给出一个数字的差错码,跟着是一个ASCII表示的 差错报文 字段,可能包含额外的操作系统说明的信息。

既然TFTP使用不可靠的UDPTFTP就必须处理分组丢失和分组重复。分组丢失可通过发送方的超时与重传机制解决,在原先的TFTPRFC 783)版本里这会引起一个叫 魔术新手综合症(Sorcerer’s Apprentice Syndrome,SAS) 问题,在第二版的TFTP(RFC 1350)被修正,说明里指出只有第一个ACK会被承认并引发下一个资料区块的传送,同一份资料的ACK将被直接忽略。

安全性

TFTP分组中并不提供用户名和口令,这是它的一个特征(即,“安全漏洞”)。由于TFTP是设计用于系统引导过程进程,它不可能提供用户名和口令。

这一特性被许多解密高手用于获取Unix口令文件的复制,然后来猜测用户口令。为防止这种类型的访问,目前大多数TFTP服务器提供了一个选项来限制只能访问特定目录下的文件(Unix系统中通常是 /tftpboo )。这个目录中只包含无盘系统进行系统引导时所需的文件。

对其他的安全性, Unix系统下的TFTP服务器通常将它的用户ID和组ID设置为不会赋给任何真正用户的值。这只允许访问具有读或写属性的文件。

BOOTP 协议

引导程序协议(Bootstrap Protocol,BOOTP) ,基于IP/UDP协议,也称自举协议,是DHCP协议的前身。用于无盘工作站的局域网中,可以让无盘工作站从一个中心服务器上获得IP地址。

在进行系统引导时,能够通过RARP来获取它的IP地址,但是会有两个问题:

  • IP地址是返回的唯一结果。
  • RARP使用链路层广播,所以它的请求不会被路由器转发,迫使每个网络都要设置一个RARP服务器。

BOOTP使用UDP,且通常需与TFTP协同工作,用于无盘系统进行系统引导的替代方法。

分组格式

BOOTP请求和应答均被封装在UDP数据报中,如下:

BOOTP 分组格式BOOTP 分组格式

下图是一个长度为300字节的BOOTP请求和应答格式:

BOOTP 请求和应答的格式BOOTP 请求和应答的格式

操作码 字段,请求为1;应答为2

硬件类型 字段,1表示10Mb/s的以太网,与ARP请求或应答含义相同。

硬件地址长度 字段,同样地与ARP一样为6字节。

跳数 字段,由客户设置为0,也可以被一个代理服务器设置。

事务标识 字段,由客户设置,并由服务器返回的32bit整数。客户用对请求和应答进行匹配。对每个请求客户应该将该字段设置为一个随机数。 0表示该客户忽略这个字段。

秒数 字段,客户开始进行引导时,将该字段设置一个时间值。服务器能够看到这个时间值,备用服务器在等待时间超过这个时间值后才会响应客户请求,这意味着主服务器没有启动。

客户 IP 地址 字段,如果客户已经知道了自身的IP地址,它将写入该字段。否则,将该字段置为0

你的 IP 地址 字段,如果客户不知道自身的IP地址时,服务器将该客户的IP地址写入该字段。

服务器 IP 地址 字段,由服务器填写。

网关 IP 地址 字段,如果使用了某个代理服务器,则该代理服务器填写该字段。

客户主机硬件地址 字段,客户必须在该设置它的硬件地址,尽管这个值与以太网数据帧头的值相同。UDP数据报中也设置了这个字段,使任何接收这个数据报的用户进程(如:BOOTP服务器)很容易使用它。

服务器主机名 字段,是一个以空值终止的字符串,由服务器选则性地填写。

引导文件名 字段,由服务器填写的,用于系统引导的文件名及其所在位置的路径全名。

特定厂商信息 字段,用于对BOOTP进行不同的扩展。

RFC 1533 [Alexander and Droms 1993] 定义了这个区域的格式,这个区域含有服务器返回客户的可选信息。如果有信息要提供,这个区域的前4个字节被设置为IP地址99.130.83.99。这可称作 魔术甜饼 (magic cookie),表示该区域内包含信息。其余部分是一个条目表,格式如下:

特定厂商格式特定厂商格式

每个条目开始是一个1字节的标志字段,其中的两个条目仅有标志字段:标志为0的条目作为填充字节(为使后面的条目有更好的字节边界),标志为255的条目表示结尾条目。第一个结尾条目后剩余的字节都应设置为这个数值(255)。除了这两个1字节的条目,其他的条目还包含一个单字节的长度字段,后面是相应的信息。

子网掩码 条目和 时间值 条目都是定长条目,因为它们的值总是占4个字节。时间偏移值是从1900年1月1日0时以来的秒数(UTC)。

网关 条目是变长条目。长度通常是4的倍数,这个值是一个或多个供客户使用的网关(路由器)的IP地址。返回的第一个必须是首选的网关。

RFC 1533 还定义了其他14个条目。其中最重要的可能是DNS名字服务器的IP地址条目,条目的值为 6。其他的条目包括打印服务器、时间服务器等的IP地址。详细情况可参考RFC文档。

厂商说明区域的大小被限制为64字节。这对某些应用是个约束。一个新的称为 **动态主机配置协议(Dynamic Host Configuration Protocol,DHCP)**已经出现,但它不是替代BOOTP的。DHCP将这个区域的长度扩展到312字节,它在RFC 1541 [Droms 1993] 中定义。

端口号

BOOTP有两个熟知的端口,服务器67,客户68。这意味着BOOTP 客户不会选择未用的临时端口,而只用端口68。选择两个端口而不是仅选择一个端口因为BOOTP务器的应答可以进行广播(但通常是不用广播的)。

如果服务器的应答是通过广播传送的,同时客户又选择未用的临时端口,那么这些广播也能被其他的主机中碰巧使用相同临时端口的应用进程接收到。因此,采用随机端口(即临时端口)对广播来说是一个不好的选择。

如果客户也使用服务器的知名端口(67)作为它的端口,那么网络内的所有服务器会被唤醒来查看每个广播应答(如果所有的服务器都被唤醒,它们将检查操作码,如果是一个应答而不是请求,就不作处理)。因此可以让所有的客户使用与服务器知名端口不同的同一知名端口。

如果多个客户同时进行系统引导,并且服务器广播所有应答,这样每个客户都会收到其他客户的应答。客户可以通过BOOTP首部中的事务标识字段来确认应答是否与请求匹配,或者可以通过检查返回的客户硬件地址加以区分。

BOOTP 服务器设计

BOOTP客户通常固化在无盘系统只读存储器中,因此了解BOOTP服务器的实现将更有意义。

BOOTP服务器将从它的熟知端口号67读取UDP数据报,没有特别的需要。这与必须要读取以太网帧类型字段RARP请求的RARP服务器不同。BOOTP协议通过将客户的硬件地址放入BOOTP分组中,使得服务器很容易获取客户硬件地址。

这里出现了一个有趣的问题: TFTP服务器如何能将一个响应直接送回BOOTP 客户?这个响应是一个UDP数据报,而服务器知道该客户的IP地址(可能通过读取服务器上的配置文件)。由于客户端不知道自己的IP地址,因此无法应答ARP请求,因此服务器上的ARP无法找到客户的硬件地址。(这就是RFC951中被称作 "chicken and egg"的问题)

对于上面问题,有两种解决方案:

第一种是服务器发送一个IOCTL(2)请求给内核,为该客户在ARP高速缓存中设置一个条目(这就是命令arp -s的工作),所以当服务器发送UDP数据报时,服务器ARP模块将会在ARP高速缓存中发现客户IP地址。服务器一直这么做直到它知道客户的硬件地址和IP地址。

第二种是服务器广播这个BOOTP应答而不是直接将应答发回该客户,通常期望网络广播越少越好,因此这种解决方案应该只在服务器无法在它的ARP高速缓存设置一个条目的情况下使用。通常只有拥有超级用户权限才能在ARP高速缓存设置一个条目,如果没有这种权限就只能广播BOOTP应答。

当一个客户使用BOOTP(操作码为1)进行系统引导时,引导请求通常是采用链路层广播, IP首部中的目的IP地址为255.255.255.255(受限的广播)。源IP地址通常是0.0.0.0,因为此时客户还不知道它本身的IP地址。

BOOTP 穿越路由

绝大多数路由器厂商的产品都支持BOOTP协议,所以能够被路由器转发。这个功能主要用于无盘路由器,因为如果一个带磁盘的多用户系统被用作路由器,它就能够自己运行BOOTP服务器。

常用的Unix BOOTP服务器支持这种中继模式(relay mode)。

如果在这个物理网络内运行一个BOOTP服务器,通常没有必要将BOOTP请求转发到在另外网络中的另一个服务器。

当路由器(也称作“BOOTP 中继代理”)在服务器的熟知端口(67)接收到BOOTP请求时,中继代理将IP地址填入收到BOOTP请求中的“ 网关IP地址 字段”,然后将该请求发送到真正的BOOTP服务器(由中继代
理填入网关字段的地址是收到的BOOTP请求接口的IP地址)。中继代理还将跳数字段值加1(这是为防止请求被无限地在网络内转发。 RFC951认为如果跳数值到达3就可以丢弃该请求)。

发出的请求是一个单播的数据报(与发起的客户的请求是广播的相反),它能按照一定的路由通过其他的路由器到达真正的BOOTP服务器。真正的BOOTP服务器收到这个请求后,产生BOOTP应答,并将它发回中继代理,而不是请求的客户。既然请求网关字段不为零,真正的BOOTP服务器知道这个请求是经过转发的。中继代理收到应答后将它发给请求的客户。