1.问题

IP地址到底是属于主机的还是属于网卡的?这个问题有点太学院派了,现实中,只要懂得IP地址的概念以及IP路由,基本上没有问题。IP作为一个网络层协议,它更多的意义在于寻址而不是标识主机,因此你可以认为IP是属于网卡的。
然而不同的人对于IP地址有不同的看法,程序员看来,IP地址是属于主机的,因为他们总是用一个套接字来表示一个服务,套接字中的IP地址表示一台主机,协议和端口号表示了该主机上的一个特定进程;对于网络工程师而言,他们会认为IP地址是属于一个网段的,也就是编写于网卡上的,如果一台主机有多块网卡,那么它的每块网卡都可以有多个IP地址,IP地址在网络工程师看来,更多的是为了根据IP路由结果将数据包发往下一跳。

2.Local路由表

每一台实现了TCP/IP的主机都有一张Local路由表,虽然实现方式不一定一样。所谓的Local路由表,就是标示到达所有本机所有网卡的IP地址的路由,包括物理网卡和虚拟网卡,当然也包括咯opback网卡,这些路由的下一跳就是最后一跳,其实就是本机,也就是本地接收!后文会提到,在任意一块网卡上配置一个IP地址,内核都会自动增加一个Local表的路由项。
因此,只要是在Local表中配置一条路由,数据包就会被本地三层接收,至于能否接收成功,就看第四层以及更高层了。

3.负责寻址的IP地址

IP地址在TCP/IP网络上身兼两职,既标示主机,又负责寻址。IP是无状态无连接的,数据包是一跳一跳逐渐接近目的地的,其重要作用的是IP路由,每个中间设备都会有一张路由表,数据包到达该中间设备的时候,根据最长掩码匹配原则(不考虑有类IP寻址),找到下一跳的IP地址,然后进行“下一跳解析”(比如arp)将寻址落实在链路层,然后将数据包发往下一跳。

4.标示主机本身的IP地址

IP地址在TCP/IP网络上身兼两职,既负责寻址,又标示主机。由于二元对立,标示主机的IP地址当然就不能配置在任何物理网卡上,也不会依赖物理网卡的up和down,只要主机本身没有down掉(崩溃或者掉电等),任何一块物理网卡的down掉就不妨碍该主机继续提供服务,但是前提是数据包可以从另一块网卡到达该主机。

5.配置在物理网卡上的IP地址标示主机

配置在物理网卡上IP地址都可以标示主机,因为该物理网卡上配置IP的时候,会对路由表产生影响,第一个影响是会生成一条直连路由,另一个影响就是会生成一条Local路由,只要生成了Local路由就能标示主机,但是物理网卡IP标示主机的前提是该物理网卡是up状态,但是这合理吗?物理网卡的up状态保持依赖于很多的外部条件,甚至依赖该网卡对端设备的up状态,因此这种标示法是不合理的,正常情况下,不应该用物理网卡的IP地址来标示主机,物理网卡的IP地址应该只负责寻址!

6.IP地址规划

IP地址由主机位和网络位组成,主机位的位数描述了网络的规模,规划网络的时候,网络中可容纳的网卡地址数量为主机位容量减去2,因此只要规划一个网络就会浪费掉两个地址,避免广播地址和网络地址的方式就是使用32位前缀,由于32位前缀的IP地址不再表示一个网络,因此也就不可能拥有所谓的同网段直连路由(即链路层路由),那么使用32位前缀IP地址的代价就是手工添加一条明确的路由指向32位IP地址的目标作为最后一跳。
至此,我将IP地址分成了两种用途,第一种用途用来标示主机,我使用32位前缀的地址,第二种用途我用来寻址,执行标准的IP路由。依照前文的描述,标示主机的IP地址不能配置在物理网卡上,那么配置在哪里呢?答案就是Loopback接口。

7.Loopback接口

Loopback接口是一个特殊的虚拟网卡,很多人都认为它的地址是127.0.0.1,用于测试协议栈是否有故障,然而事情不是大多数人想当然的这么简单。
首先,我可以肯定地说,配置在Loopback接口上的IP是属于主机的,而配置在物理网卡上的IP地址在不同层面可以认为属于主机和属于网卡。另外,这种Loopback不依赖任何物理链路状态和链路层协议,永远不会down掉,只要有一块网卡是up状态并且路由可达,该Loopback接口上配置的标示该主机的IP地址就可达。

8.配置路由指定源地址很重要

到此,我将IP地址的两类用途彻底分离了,用于寻址的不用来标示主机,用于标示主机的不负责寻址,也就是说,当绑定套结字的时候,不再使用物理接口的IP地址,而是使用Loopback口的32位前缀的IP地址。然而分久必合,IP地址两类用途之间还是有关联的,这种关键体现在数据包发出时的源地址选择上,按照IP路由逻辑,在没有bind地址的情况下,源地址选择将和下一跳网关执行最长掩码匹配算法来选择。我们不能指望上层都会bind源地址,因此就需要在IP层影响源地址选择算法,否则Loopback接口的地址将永远不会被选中,因为它没有链路层路由,和任何地址都不处在“同一网段”,故而你不能在“该网段”去寻找下一跳。
因此,配置路由指定源地址很重要,幸运的是Linux系统使用iproute2可以实现,而Windows系统通过一种变通的方式也能做到(但是Windows系统需要安装额外的Loopback驱动用以导出该虚拟接口)。

9.一个实际例子

我添加一个32位掩码的IP地址到Loopback接口:
ip addr add dev lo 33.33.33.33/32
再添加两条路由
ip route add 0.0.0.0/0 via 1.1.1.2 metric 10 src 33.33.33.33
ip route add 0.0.0.0/0 via 2.2.2.2 metric 20 src 33.33.33.33

然后在其网卡1直连的机器1上配置一条路由:
route add -host 33.33.33.33 gw 1.1.1.1 (1.1.1.1是网卡1的IP地址)
然后在其网卡2直连的机器2上配置一条路由:
route add -host 33.33.33.33 gw 2.2.2.1 (2.2.2.1是网卡2的IP地址)
效果是什么?效果就是网卡1或者网卡2由于某种原因down掉了,只要另一个还up,33.33.33.33这个地址就是可达的,同时33.33.33.33也是提供服务的地址。在这个例子中,网卡上配置的1.1.1.1,2.2.2.1这两个IP地址完全是用于IP路由寻址的,而标示主机的33.33.33.33则配置在Loopback接口上。Loopback接口的IP地址被认为只能是最后一跳,因为不能将它用于寻址。

10.另一个方案

既然标示主机的IP地址可以全部配置在loopback上,那么为何不把所有的IP地址都配置在loopback上呢?即物理网卡上不再配置任何IP地址,然后配置arp,使得可以回复本应该配置在物理网卡的但是实际上却配置在loopback上的IP地址的ARP请求,另外直连路由需要从loopback删除,并重新手工添加在相应的物理网卡上。

11.续

Loopback实际上是个hole,但是如果它不是一个hole,它确实可以做一些事,类似Cisco的NVI那样...