Linux 服务器 存在多网卡多IP UDP 监听 INADDR ANY(0.0.0.0)出现收包源IP不一致问题解决方案!
- Get link
- X
- Other Apps
在多IP服务器上,通过策略路由如何保证 回复给客户端的数据不从从原来的网卡出去导致访问不通的问题?
比如在一台双线上,电信 IP 是182.x.x.119 ,网通 IP 是 119.x.x.107
可以通过以下策略路由保证:
ip route flush table ct
ip route add default via 182.x.x.97 dev eth0 src 182.x.x.119 table ct
ip rule add from 182.x.x.119 table ct
ip route flush table cu
ip route add default via 119.x.x.97 dev eth1 src 119.x.x.107 table cu
ip rule add from 119.x.x.107 table cu
对这段策略路由简单解释下。
ip rule add from 182.x.x.119 table ct
表示源地址是 182.x.x.119 的包,通过ct路由表选路,
ip route add default via 182.x.x.97 dev eth0 src 182.x.x.119 table ct
表示ct路由表的默认路由是从 eth0 的 182.x.x.97 这个网关路由,源地址设置为 182.x.x.119 。
有了这层保证后,我们在实现Server 的时候,监听 socket 依然 bind 到 0.0.0.0 ,在回 数据 包的时候,只要设置该数据包从本机发出去的 源地址 配合策略路由,就可以保证 数据包 正确返回。
现在的关键问题是: 如何获取 数据 包的目的地址?
对于无连接状态的 UDP socket 获取目的地址就很难了,木有现成的系统调用,获取方法还是有点点麻烦的。通过 man ip
可以获取详细的步骤和原理:
IP_PKTINFO (since Linux 2.2)
Pass an IP_PKTINFO ancillary message that contains a pktinfo
structure that supplies some information about the incoming packet.
This only works for datagram oriented sockets.
The argument is a flag that tells the socket
whether the IP_PKTINFO message should be passed or not.
The message itself can only be sent/retrieved as control message
with a packet using recvmsg(2) or sendmsg(2).
struct in_pktinfo {
unsigned int ipi_ifindex; /* Interface index */
struct in_addr ipi_spec_dst; /* Local address */
struct in_addr ipi_addr; /* Header Destination
address */
};
ipi_ifindex is the unique index of the interface the packet was received on.
ipi_spec_dst is the local address of the packet and
ipi_addr is the destination address in the packet header.
If IP_PKTINFO is passed to sendmsg(2) and ipi_spec_dst is not zero,
then it is used as the local source address for the routing table lookup
and for setting up IP source route options. When ipi_ifindex is not zero,
the primary local address of the interface specified
by the index overwrites ipi_spec_dst for the routing table lookup.
这里的说明说的相当清楚
先决条件就是要 setsockopt
设置 IP_PKTINFO
,通过系统调用 recvmsg
便可获取 in_pktinfo
结构数据,其中 ipi_spec_dst
便是我们想要的目的地址,
然后 sendmsg
的时候传入 ipi_spec_dst
,这样就会使用这个地址来做策略路由。
有了这个做指导,编码起来就很简单的啦,有 C版本 的实现,这里的 python 版本 通熟易懂些。
上面的方法固然好,但是很多语言目前稳定版本,socket 都不支持 sendmsg,recvmsg,更不要说 setsockopt 设置 IP_PKTINFO 了。在 java 中没有,在 python 2.7 版本也没有,只有 python 3.3 版本支持。所以这种方法还不具有普适性,但是如果用的是 C 或者 Go 语言,实现起来倒是很方便的。
- Get link
- X
- Other Apps
Comments
Post a Comment