严格来说,TCP/IP 协定家族并没有定义 “TCP/IP 专属的” 网路硬件规格。硬件的范围实在太过广泛了﹐标准非常多﹐当今大部份的低层网路硬件标准都是由 IEEE 制定的,但也有许多标准是厂商专属的。要让 TCP/IP 协定能够顺利与不同类型的硬件进行沟通﹐那么就需要建立起一些标准协议来让大家共同参考。以我们最常用的以太网(Ethernet)为例﹐我们无需理会厂商如何设计网络界面(网络接口)的驱动程序﹐一旦它能够被系统接纳﹐网路储存层(Datalink)就能使用网路界面(网络接口)在实体网路上传送和接收资料了。
IP 位址和实体位址对应之困扰
在「网路基础」课程中﹐我们知道以太网上面使用的传送方式叫 CSMA/CD (Carrier-Sensing Multiple Access with Collision Detection)﹕虽然讯框会在整个网段(segment)中用广播的方式传递﹐而且所有节点都会收到讯框﹐然而﹐只有目的位址符合自己实体位址的讯框才会被接收下来。因此,不管上层协定是哪一种(可以是 TCP/IP 也可以是其它),在底层的传送若是使用 Ethernet 的话,就得使用 MAC (Media Access Control) 实体位址。若要查询到当前系统目前所有界面(网络接口)的实体位址,我们可在 Linux 系统里面输入 ifconfig 命令﹕
eth0 Link encap:Ethernet HWaddr 00:A0:0C:11:EA:11 inet addr:203.30.35.134 Bcast:203.30.35.159 Mask:255.255.255.224 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:100 Interrupt:3 Base address:0x300 eth1 Link encap:Ethernet HWaddr 00:80:C7:47:8C:9A inet addr:192.168.0.17 Bcast:192.168.0.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:12303 errors:0 dropped:0 overruns:0 frame:0 TX packets:12694 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:100 Interrupt:10 Base address:0x2e0
从上面的命令结果中可发现:关于每一个界面的第一行资讯﹐最后的部份就是该界面的实体位址。讯框在实体网路上面传送的过程中﹐IP 位址(或曰罗辑位址)一点都派不上用场。但问题是:当我们使用 TCP/IP 的时侯,上层的协定都是以 IP 位址为传送依据的。那么﹐这时候我们就必须有一套方法来对应 IP 位址和实体位址了。
在此一过程中﹐关键点是如何将 IP 位址对与实体位址做对应。有些使用简单实体位址的网路(如 proNET-10 )﹐其实体位址只占一个 byte 的长度﹐而且允许使用者在配置网路卡的是选择自己的实体位址。在这样的网路上进行 IP 位址和实体位址的对应﹐是比较简单的﹐我们可以把实体位址设为和 IP 位址设为一样。例如﹐假设某一个节点的 IP 位址为 192.168.1.17﹐那么我们可以将该实体位址设为 17。 这样﹐在 proNET 就可以轻易的根据 IP 位址来得到实体位址。这样的对应非常简单﹐而且要维护起来也很容易﹐在新机器加入网路的时候﹐并不需要修改或重编已存的资料。
然而﹐我们知道在以太网上﹐每一个实体界面都有一个 48bit(6byte) 的 MAC 位址﹐而 IP (v4)使用的位址则为 32bit(4byte)﹔每个位址格式都只提供相应的层级协定使用﹐彼此是不能互换使用的。这时候我们就无法用简单的数学关系来做 IP 位址和实体位址的对应了。
IP 位址和实体位址的对应方法
建立表格
首先﹐我们想到的最简单方法是在每一台机器上建立一个 IP 位址和实体位址的对应表格( table )。不过这个方法还是没办法解决如下的情形﹕
- 网路上的节点数量多如恒河沙数﹐要想将全部节点的对应关系列入表格之中几近不可能任务。
- 如果某一个节点产生异动情形(例如更换网卡)﹐那麽如果让所有表格正确做出相应修改﹐也是个头痛的问题。
- 对某无磁碟工作站来说﹐因为没有本机的储存设备﹐将无法建立表格。
写入高阶程式
除了建立表格﹐我们还可以将实际的网路位址写死在高阶网路程式里面。不过﹐和前一个方法一样﹐如果遇到硬体位址变更等异动动情形﹐那么﹐程式也需要重新编译过才行。
显然﹐上述两个方法都不怎么高明。
ARP 协议
这里我们要介绍的是 Address Resolution Protocol (ARP)。 ARP 是 TCP/IP 设计者利用以太网的广播性质﹐设计出来的位址解释协议。它的主要特性和优点是它的位址对应关系是动态的﹐它以查询的方式来获得 IP 位址和实体位址的对应。它的工作原理非常简单﹕
- 首先﹐每一台主机都会在 ARP 快取缓冲区 (ARP Cache)中建立一个 ARP 表格﹐用来记录 IP 位址和实体位址的对应关系。这个 Table 的每一笔资料会根据自身的存活时间递减而最终消失﹐以确保资料的真实性。
- 当发送主机有一个封包要传送给目的主机的时候﹐并且获得目的主机的 IP 位址﹔那发送主机会先检查自己的 ARP 表格中有没有该 IP 位址的实体位址对应。如果有﹐就直接使用此位址来传送框包﹔如果没有﹐则向网路发出一个 ARP Request 广播封包﹐查询目的主机的实体位址。这个封包会包含发送端的 IP 位址和实体位址资料。
- 这时﹐网路上所有的主机都会收到这个广播封包﹐会检查封包的 IP 栏位是否和自己的 IP 位址一致。如果不是则忽略﹔如果是则会先将发送端的实体位址和 IP 资料更新到自己的 ARP 表格去﹐如果已经有该 IP 的对应﹐则用新资料覆盖原来的﹔然后再回应一个 ARP Reply 封包给对方﹐告知发送主机关于自己的实体位址﹔
- 当发送端接到 ARP Reply 之后﹐也会更新自己的 ARP 表格﹔然后就可以用此记录进行传送了。
- 如果发送端没有得到 ARP Reply ﹐则宣告查询失败。
ARP 的查询过程可参考下图﹕
ARP 的查询过程
前面说的 ARP 表格﹐只有在 TCP/IP 协议被载入核心(kernel)之后才会建立﹐如果 TCP/IP 协定被卸载或关闭机器﹐那麽表格就会被清空﹔到下次协议载入或开机的时候再重新建立﹐而同时会向网路发出一个 ARP 广播﹐告诉其它机器它的目前位址是什么﹐以便所有机器都能保持最正确的资料。
然而﹐ARP cache 的大小是有所限制的﹐如果超过了界限﹐那么越长时间没被使用过渡资料就必须清理掉﹐以腾出空间来储存更新的资料。所以﹐当机器收到 ARP request 封包时﹐如果查询对象不是自己﹐则不会根据发送端位址资料来更新自己的 ARP 表格﹐而是完全忽略该封包。同时﹐每笔存在 cache 中的资料﹐都不是永久保存的﹕每笔资料再更新的时候﹐都会被赋予一个存活倒数计时值﹐如果在倒数时间到达的时候﹐该资料就会被清掉。然而﹐如果该资料在倒数时间到达之前被使用过﹐则计时值会被重新赋予。
当然了﹐ARP 尚有一套机制来处理当 ARP 表格资料不符合实际位址资料的状况(例如﹐在当前连线尚未结束前﹐收到目的端的位址资料更新讯息)﹔或是目的主机太忙碌而未能回答 ARP 请求等状况。
RARP 协议
刚才介绍的 ARP 协议是透过向网路查询而找出实体位址﹐那我们接下来探讨的 RARP 协定则相反﹕它是籍由查询网路上其它主机而得到自己的 IP 位址。
通常﹐我们使用的以太网卡﹐在出厂的时候就有生产厂家把网卡的实体位址烧在 ROM 里面﹐这个位址是不能改变的(某些型号的网路卡﹐或是透过其它技术手段﹐是允许您修改实体位址的)。不管系统是否起来﹐这个位址都会存在﹐而且要让系统获得它也很容易。然而,在一些无磁碟(diskless)工作站上面﹐系统档案都存放在远端的伺服器﹐当它在启动的时候﹐因为本身没有 IP 位址﹐也就无法和伺服器沟通﹐更不能将系统档案载入。那么﹐我们就必须要有一个办法﹐让这样的无磁碟工作站在和伺服器沟通之前获得自己的 IP 位址。RAPR 协定就是为解决此问题而设计出来的。
和 ARP 协议一样﹐RARP 也是用广播的形式来进行查询﹐只不过这时候问的 IP 位址不是别人﹐而是自己的 IP 位址而已。我们可以从下图看出 RARP 的运作﹐其实和 ARP 是极其相似的﹕
RARP 的查询过程
首先是查询主机向网路送出一个 RARP Request 广播封包﹐向别的主机查询自己的 IP。在时候﹐网路上的 RARP 伺服器就会将发送端的 IP 位址用 RARP Reply 封包回应给查询者。这样查询主机就获得自己的 IP 位址了。
然而不像 ARP﹐查询主机将 RARP Request 封包丢出去之后﹐可能得到的 RARP Reply 会不止一个 (在 ARP 查询中﹐我们可以确定只会获得一个回应而已)。因为网路上可能存在不止一台 RARP 伺服器(基于备份和分担考量﹐极有可能如此设计)﹐那么﹐所有收到 RARP 请求的伺服器都会尝试向查询主机作出 RARP Reply 回应。如果这样的话﹐网路上将充斥这种 RARP 回应﹐做成额外的负荷。这时候﹐我们有两种方法来解决RARP 的回应问题。
第一种方法﹐为每一个做 RARP 请求的主机分配一主伺服器﹐正常来说﹐只有主伺服器才回做出 RARP 回应﹐其它主机只是记录下接收到 RARP 请求的时间而已。假如主伺服器不能顺利作出回应﹐那么查询主机在等待逾时再次用广播方式发送 RARP 请求﹐其它非主伺服器假如在接到第一个请求后很短时间内再收到相同请求的话﹐才会作出回应动作。
第二种方法也很类似﹕正常来说﹐主伺服器当收到 RARP 请求之后﹐会直接作出回应﹔为避免所有非主伺服器同时传回 RARP 回应﹐每台非主伺服器都会随机等待一段时间再作出回应。如果主伺服器未能作出回应的话﹐查询主机会延迟一段时间才会进行第二次请求﹐以确保这段时间内获得非主伺服器的回应。当然﹐设计者可以精心的设计延迟时间至一个合理的间隔。
PROXY ARP
代理 (Proxy) ARP 通常用来在路由器上代为回答在它后面的某个网路主机的 ARP 请求。这是一种欺骗手法﹐因为查询端会以为目标主机就是路由器本身﹐但事实上﹐机器是在另一个网路里面。
Proxy ARP 常使用于远端连接网路(如拨接)环境中。例如在本地网路中有一台拨接主机﹐提供其他主机拨接上来连接本地网。当本地主机要查询远端拨接主机的 ARP 请求的时候﹐因为它的广播封包是无法到达远端的﹔此时拨接伺服器就可以代替远端主机回答这个 ARP 请求﹐然后本地主机就将封包送给拨接伺服器﹐伺服器再将封包传给远端主机。
Proxy ARP 还有另一个功能﹕就是将路由器所连接的两端实体网路相互「隐藏」起来。这样﹐两边的网路就能够使用同一个网路识别码(我们会在后面的章节中说明这个概念)﹐只要中间的路由器被配置 Proxy ARP﹐便能替任何一端网路回应另一端网路的 ARP 请求。这样的配置﹐除了能够解决现代主机与古老的机器之间的沟通(前者使用全部 0 代表主机﹐而后者则使用全部 1 代表主机﹔这个我们在后面的章节中再说明这个概念)。
Proxy ARP 另一个很有用的场合﹐是解决 IP 不足下的子网路切割情况。例如现在台湾的商业性 ADSL 网路只能分配到 5 个可用 IP﹐如果要在这么小的范围下做子网的切割﹐那么﹐除路由器所占用的两个 IP 之外﹐剩下的就只有一个 IP 可以使用。这是毫无意义的﹐但使用 Proxy ARP 之后﹐我们可以使用的 IP 将不会被浪费掉。
ARP 和 RARP 之封包格式
让我们温习前面讨论 OSI 层级时提到的以太网路框包格式﹕
序言 (Preamble) |
目的地位址 (Destination) |
來源位址 (Source) |
信息类型 (Message Type) |
数据 (Data) |
封包监测资料 (Frame check sequence) |
8 bytes | 6 bytes | 6 bytes | 2 bytes | 46-1500 bytes | 4 bytes |
以太网的框包格式
我们可以发现标准的以太网框包其中有一段 46 到 1500 byte 长度的数据空间﹐假如这是一个 ARP 封包的话﹐那么该段数据空间就用来包装整个 ARP 封包。ARP 和 RARP 的封包格式是一模一样的﹕
0 |
8 |
16 |
31 |
Hardware Type |
Protocol Type |
|
HLEN |
PLEN |
Operation |
Sender HA (Byte 0~3) |
||
Sender HA (Byte 4~5) |
Sender IP (Byte 0~1) |
|
Sender IP (Byte 2~3) |
Target HA (Byte 0~1) |
|
Target HA (Byte 2~5) |
||
Target IP (Byte 0~3) |
ARP / ARAP 封包格式
下面我们就封包中每一栏位做一个简单的说明﹕
HARDWARE TYPE
这是指网路界面卡的种类﹐如果该值为 1﹐则表示为乙太网 ( Ethernet )。
PROTOCOL TYPE
这是指高阶网路协议位址种类﹐如果该值为 0x0800﹐则表示为 IP 位址格式。
HLEN
这是指硬件位址长度(单位为 byte)﹐以太网的位址长度为 6 。
PLEN
这是指网路协议址的长度(单位为 byte)﹐IP 协议址长度为 4。
OPERATION
这是指封包类别﹐一共有四种﹕
-
ARP Request
-
ARP Reply
-
RARP Request
-
RARP Reply
SENDER HA
这是指发送端的实体位址﹐如果是以太网的话﹐将会是一个 6 byte 长度的以太网位址。
SENDER IP
这是指发送端的 IP 位址﹐会是一个 4 byte 长度的 IP 位址。
TARGET HA
这是指目的端的实体位址﹐如果是以太网的话﹐将会是一个 6 byte 长度的以太网位址。
TARGET IP
这是指目的端的 IP 位址﹐会是一个 4 byte 长度的 IP 位址。
ARP 指令
假如您要在 Linux 系统上验证一下前面所学的理论﹐只要您的网路功能已经设好﹐您可以用 arp 命令来检查当前的 ARP 表格内容﹕
# arp -n Address HWtype HWaddress Flags Mask Iface 192.168.20.88 ether 00:10:5A:74:19:A7 C eth1 192.168.20.16 ether 00:D0:B7:74:77:74 C eth1 192.168.20.140 ether 00:D0:B7:74:77:85 C eth1 192.168.20.176 ether 00:02:B3:0B:5A:60 C eth1 192.168.16.254 ether 00:D0:B7:85:40:FE C eth1 192.168.22.1 ether 00:50:8B:92:C3:AB C eth1 |
在 Linux 系统中﹐输入 arp 带一个 -n 的参数﹐是将资料用数字(number)的形式显示﹐否则它将尝试用 DNS 或其他主机对应方式来显示 IP 所对应的主机名称。大家可以很轻易在每一行资料中找到 IP 位址和实体位址的对应﹐同时还有硬体类型等信息。
假如此时您下一个 ping 命令﹐连接一台没有在 ARP 表格中出现的 IP ﹕
# ping 1211.20.240.113 PING 211.20.240.113 (211.20.240.113): 56 data bytes 64 bytes from 211.20.240.113: icmp_seq=0 ttl=128 time=0.6 ms 64 bytes from 211.20.240.113: icmp_seq=1 ttl=128 time=0.6 ms 64 bytes from 211.20.240.113: icmp_seq=2 ttl=128 time=0.6 ms 64 bytes from 211.20.240.113: icmp_seq=3 ttl=128 time=0.6 ms |
此时您再次输入 arp 命令的话﹐您将发现新主机的 ARP 资料﹕
# arp -n Address HWtype HWaddress Flags Mask Iface 192.168.20.88 ether 00:10:5A:74:19:A7 C eth1 192.168.20.16 ether 00:D0:B7:74:77:74 C eth1 192.168.20.140 ether 00:D0:B7:74:77:85 C eth1 192.168.20.176 ether 00:02:B3:0B:5A:60 C eth1 192.168.16.254 ether 00:D0:B7:85:40:FE C eth1 192.168.22.1 ether 00:50:8B:92:C3:AB C eth1 211.20.240.113 ether 00:60:6C:08:2A:24 C eth0 |
如果您把这台主机从网路上断开﹐确定它不会再发送 ARP 请求或作出 ARP 回应﹐那么过大约 20 分钟后再输入 arp 命令﹐您很可能发现许多 ARP 记录都已经消失了﹐这就是资料存活倒数计时的后果。
假如您的 Linux 系统还装有封包撷取软件﹐如 tcpdump ﹐您可以在此期间抓些封包看看﹐细心点就能看出 ARP Request 和 ARP Reply 的过程﹕
09:17:33.803030 0:0:e8:68:98:b3 ff:ff:ff:ff:ff:ff 0806 42: arp who-has 211.20.240. 113 tell 211.20.240.117 09:17:33.803777 0:60:6c:8:2a:24 0:0:e8:68:98:b3 0806 60: arp reply 211.20.240.11 3 is-at 0:60:6c:8:2a:24 |
您如果还有兴趣的话﹐还可以找些更强劲的封包撷取工具(如﹕snifit)﹐把 ARP 封包的所有细节都抓出来看看。不过这里暂时不做这样的动作了。至于如何检查封包的每一个细节﹐我们将在后面介绍 IP 和 TCP 封包的时候再介绍。
我们用 arp 不仅能查看当前的 ARP 记录﹐而且我们还可以用 arp 命令来建立 ARP 记录﹐例如﹐我们前面提到过的 Proxy ARP 功能﹐我们可以用中间的路由器来「隐藏」两端的网路﹕
# arp -s 211.20.240.115 00:10:B5:3A:8E:00 pub # arp -n Address HWtype HWaddress Flags Mask Iface 192.168.20.88 ether 00:10:5A:74:19:A7 C eth1 192.168.16.254 ether 00:D0:B7:85:40:FE C eth1 192.168.22.1 ether 00:50:8B:92:C3:AB C eth1 211.20.240.115 * * MP eth |
上面 arp 命令中的 -s 参数就是用来设定 (set) 一个 ARP 记录的。接著在输入 arp 命令﹐就会发现刚才设定的资料旗标为 MP 。这样﹐当另一端网路要查询 211.20.240.115 的时候﹐这个 Linux 路由器就能够代为回应了。
ARP 之 RFC 文件
ARP 的详细资料可以查询 RFC-826﹑RFC-814﹑以及 RFC-1166 等文件。而 RARP 的资料则可以参考 RFC-903﹑RFC-906﹑还有 RFC-1293 等文件。
习题﹕
- 请在 Linux 系统上面找出界面的实体位址。
- 分别解释 ARP﹑RARP﹑Proxy ARP 的功能与实现过程。
- 请描述 ARP / RARP 的封包格式的各栏位说明。
- 用 Linux 系统实作检查一下 ARP 表格内容﹐并尝试连接新主机以观测表格资料的变化。
- 有条件的话﹐用封包撷取软体来撷取 ARP 封包来观测一下它们是如何工作的。