博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一台机器配置多个ip地址时被动响应和主动发起的源ip选择
阅读量:2341 次
发布时间:2019-05-10

本文共 3810 字,大约阅读时间需要 12 分钟。

如果一个主机绑定有多个 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

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

prerouting 和postrouting 也经常用于NAT配置网关机进行网络地址转换使用,这时候有一下规律:

PREROUTING是目的地址转换(DNAT),要把别人的公网IP换成你们内部的IP,才让访问到你们内部受防火墙保护的服务器。

POSTROUTING是源地址转换(SNAT),要把你内部网络上受防火墙保护的ip地址转换成你本地的公网地址才能让它们上网。

SNAT 变换数据包的源地址。

例:更改所有来自192.168.1.0/24的数据包的源ip地址为1.2.3.4:

iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j SNAT --to-source 1.2.3.4

DNAT,用于对外部提供www,ftp等服务
例:更改所有来自192.168.1.0/24的数据包的目的ip地址为1.2.3.4:
iptables -t nat -A PREROUTING -s 192.168.1.0/24 -i eth1 --dport 65533  -j DNAT --to-destination 1.2.3.4

在nat table修改源IP:

iptables -t nat -I POSTROUTING -d 81.201.0.0/16 -p udp --sport 5060 -j SNAT --to-source 165.254.88.10

列出nat table rules:

iptables -L -t nat

Flush nat table rules:

iptables --flush -t nat

转载地址:http://ijzvb.baihongyu.com/

你可能感兴趣的文章
去面试快手,问了我很多消息队列的知识!
查看>>
图解LeetCode No.18之四数之和
查看>>
402. Remove K Digits
查看>>
75. Sort Colors
查看>>
获取数组中前K小的数字
查看>>
数组heapify变为堆结构
查看>>
二叉树的非递归遍历
查看>>
218. The Skyline Problem
查看>>
Java PAT (Basic Level) Practice 写出这个数
查看>>
Python PAT (Basic Level) Practice 1016 部分A+B
查看>>
Python PAT (Basic Level) Practice 1006 换个格式输出整数
查看>>
Python PAT (Basic Level) Practice 1009 说反话
查看>>
Python PAT (Basic Level) Practice 1011 A+B 和 C
查看>>
Python PAT (Basic Level) Practice 1017 A除以B
查看>>
Python PAT (Basic Level) Practice 1042 字符统计
查看>>
spring dubbo 2.7.3 zookeeper 项目构建
查看>>
spring dubbo 报错
查看>>
如何在非 bean 对象中注入 dubbo service
查看>>
前后端分离 ajax java跨域配置 spring boot 、 spring security
查看>>
java spring boot 拦截所有请求 显示请求路径 方法 ip 等
查看>>