`
月影无痕
  • 浏览: 1002484 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

配置多个ip地址时源ip的选择

 
阅读更多

如果一个主机绑定有多个 IP地址,那么在被动响应和主动发起连接两种方式中,源 IP 地址的选择机制肯定是有所差异的。

 

主机在接收外部数据包,并发送响应数据包时,响应源地址显然就是客户端请求的地址,这是非常容易理解的,如客户端向主机的1.1.2.3:80 发起请求,那么主机响应数据包的源 IP 地址一定是 1.1.2.3

 

那么当主机对外主动发起请求时,数据包的源IP 地址如何选择?这个问题我们可能一般很少深入了解, 为了弄清楚这个问题,我发了不少时间,广泛查阅各种资料,目前得出的结论如下:

当一个主机创建IP 数据包时,必须选择正确的源IP地址,这是至关重要的,因为只有源地址正确,才能让接收者正确响应。如果源地址错误,则无法得到对端主机的任何回应。

 

Linux 2.2 选择源 IP 地址使用以下三种机制:

 

1.  应用程序可以通过bind(2) 系统调用,应用至 sendmsg(2) 调用上,并通过辅助数据对象 IP_PKTINFO ,从而显式指定源 IP 地址。在这种情况下,操作系统内核仅仅检查其源 IP 地址是否正确,否则产生相应的错误。

2.  如果应用程序没有指定源IP 地址,包含源 IP 的路由表将决定数据包源 IP 地址,通过设置 ip route 命令的 src 参数,从而指定源 IP 地址。如果路由表没有包含 src 属性,则使用主要 IP 地址。

3.  其它情况下内核搜寻绑定定数据包路由接口上的IP 地址, IPv6 选择第一个可用的 IP 地址。 IPv4 情况下,尽量选择与目标 IP 处于同一子网的源 IP ,如果目标 IP 与自己的所有 ip 没有处于同一子网,则使用第二种算法。

 

相应的参照文章:

http://linux-ip.net/gl/ip-cref/node155.html

http://serverfault.com/questions/12285/when-ip-aliasing-how-does-the-os-determine-which-ip-address-will-be-used-as-sour

 

默认情况下,如果Linux 的网卡有多个 IP 且位于不同的子网之中,如果数据包目标地址为某个子网中的 IP,  那么对应的与目标同子网的 IP 将会被使用。如果 eth0 有两个 IP 192.168.1.12/24,  10.1.1.1/8 ,那么到 10.0.0.0 子网的数据包的源地址将使用 10.1.1.1 。 当然可以使用 ip route src 属性指定源址。

 

如果绑定的几个IP 处于同一个子网内,那么主要 IP 地址将被使用(如 eth0 接口上的 IP 也可以使用 iptables 修改数据包的源地址实现之,如:

iptables -t nat -I POSTROUTING -o eth0 -d 1.2.3.4/0 -s 192.168.100.1 -j SNAT --to-source 192.168.100.2

 

 

原理分析及处理办法我们已经分析完毕,接下来使用实际的例子展示

Linux 主机绑定有以下几个 IP (网关为 192.168.0.1
eth0 192.168.0.250/24,  eth0: 1  192.168.0.22/24,   eth0:2 192.168.0.23/24

另外,绑定多个IP 可使用 ip addr add 命令,不产生子接口。

在上述案例中192.168.0.250 将成为默认主要 IP

 

目标:当此主机对外发起新连接时,源IP 地址使用 192.168.0.22,  不使用默认的 192.168.0.250

方法:修改路由表的源IP 属性
查看系统的 ip 地址及路由表详细信息 ( 加粗字体是输入的内容 )
[root@localhost ~]#  ip addr

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue 

    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

    inet 127.0.0.1/8 scope host lo

    inet 192.168.100.250/32 scope global lo

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000

    link/ether f4:6d:04:76:ca:98 brd ff:ff:ff:ff:ff:ff

    inet 192.168.0.250/24 brd 192.168.0.255 scope global eth0

    inet 172.16.25.1/24 scope global eth0

    inet 192.168.0.22/24 scope global secondary eth0

    inet 192.168.0.23/24 scope global secondary eth0

请注意 192.168.0.250 global 状态,而其它地址是 secondary 状态。

 

[root@localhost ~]#  ip route

192.168.0.0/24 dev eth0  proto kernel  scope link  src 192.168.0.250 

172.16.25.0/24 dev eth0  proto kernel  scope link  src 172.16.25.1 

169.254.0.0/16 dev eth0  scope link 

default via 192.168.0.1 dev eth0 

注意以上输出,会发现到同一子网的路由的源IP 地址会使用主要 IP 地址。而到默认网关的路由没有指定源 IP (实际上会用与网关同一子网的主要 IP )。

 

修改路由表,让系统使用指定IP(192.168.0.22) 作为源址:
[root@localhost ~]#  ip route change default dev eth0 src 192.168.0.22

[root@localhost ~]#  ip route change to 192.168.0.0/24 dev eth0 src 192.168.0.22

[root@localhost ~]#  ip route

192.168.0.0/24 dev eth0  scope link  src 192.168.0.22 

172.16.25.0/24 dev eth0  proto kernel  scope link  src 172.16.25.1 

169.254.0.0/16 dev eth0  scope link 

default dev eth0  scope link  src 192.168.0.22 

 

通过最后的输出,我们发现修改生效,然后使用其它主机实际测试一下。如果有任何疑惑,请联系zhangxugg@163.com

另外还有一种方式,使用iptables 修改源 IP 地址:

iptables -t nat -I POSTROUTING -o eth0 -d  0.0.0.0 /0 -s 192.168.0. 250  -j SNAT --to-source 192.168. 0.22

经过实验,测试也通过,显然修改路由表的方式要更好一些。

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics