为什么 netcat 不使用与 IP 关联的正确接口?

为什么 netcat 不使用与 IP 关联的正确接口?
  • 我有两个网络接口 A1.2.3.4和 B 1.2.3.99。 (在ifconfig
  • 我跑去nc -l 1.2.3.99 20101 -v监听B接口。
  • 我运行是nc -v 1.2.3.99 20101 -s 1.2.3.4 -4因为我想使用该界面A

它已连接,但当我检查时wireshark,没有来自A或 的数据包B,仅在lo...

为什么它不使用具有关联 IP 的接口?我应该怎么做才能强制他们使用关联的接口?

编辑:

遵循帕特里克的建议后:

ip route add local 1.2.3.99 dev B table main
ip route del local 1.2.3.99 dev B table local
ip route add 1.2.3.99 dev B table local

我运行nc -l 1.2.3.99 20101但创建 tcp 服务器时出现错误Ncat: bind to 1.2.3.99:20101: Cannot assign requested address. QUITTING.

17:10:38 alexis:~  $ ip route list table local
1.2.3.99 dev B  scope link 
...

17:10:40 alexis:~  $ ip route list table main
default via 10.133.0.1 dev eth0 
local 1.2.3.99 dev B  scope host
...

答案1

当您告诉应用程序使用特定的 IP 地址时,该应用程序使用IP地址,而不是接口。有些应用程序确实允许您使用特定的界面,但这是一个单独的行为(SO_BINDTODEVICE)。

由于应用程序绑定到 IP 地址,而不是接口,因此内核可以自由使用它想要的任何接口。为了确定使用哪个接口,它使用路由表(是的,有多个)。

如果您只是想要一种快速方法来确定流量将采用哪个接口/路由,您可以使用ip route get 1.2.3.99 from 1.2.3.4,它将输出类似以下内容:

# ip route get 1.2.3.99 from 1.2.3.4
local 1.2.3.99 from 1.2.3.4 dev lo 
    cache <local>

这表明内核将通过lo接口发送流量。

要了解原因,让我们从命令开始ip rule

# ip rule
0:  from all lookup local 
32766:  from all lookup main 
32767:  from all lookup default 

这显示了内核将用来查找流量路由的所有路由表。它从顶部开始,到第一个匹配处停止。表示from all该规则匹配任意源地址。所以首先要查表local。然后我们可以查看这个表:

# ip route show table local
broadcast 127.0.0.0 dev lo  proto kernel  scope link  src 127.0.0.1 
local 127.0.0.0/8 dev lo  proto kernel  scope host  src 127.0.0.1 
local 127.0.0.1 dev lo  proto kernel  scope host  src 127.0.0.1 
broadcast 127.255.255.255 dev lo  proto kernel  scope link  src 127.0.0.1 
broadcast 1.2.3.0 dev eth0  proto kernel  scope link  src 1.2.3.4 
local 1.2.3.4 dev eth0  proto kernel  scope host  src 1.2.3.4 
broadcast 1.2.3.255 dev eth0  proto kernel  scope link  src 1.2.3.4 
local 1.2.3.99 dev eth1  proto kernel  scope host  src 1.2.3.99

(你的可能看起来会有所不同)

然后,我们通过查看目的地是否与第二个字段匹配来查看是否有任何路由与目的地地址 (1.2.3.99) 匹配。在上面的输出中,最后一个匹配。在此行中,第一个字段是local,其man ip-route含义是:

本地 - 目的地被分配给该主机。数据包被环回并在本地传送。

这意味着流量将流过该lo接口。


至于如何让它使用A/B接口,你有 2 个选择:

1) 应用程序需要为您提供一个参数,您可以在其中指定接口。 netcat 有十几种风格,但我系统上的版本没有这样的选项。socat但确实如此(我个人推荐socat使用 netcat,因为 netcat 的不一致和可移植性是噩梦。它的功能也更强大)。

2) 创建一条local与之前匹配的非路由local

ip route add local 1.2.3.99 dev B table main
ip route del local 1.2.3.99 dev B table local
ip route add 1.2.3.99 dev B table local

在这些规则中,前 2 条规则将local路由移至表中mainmain必须首先将路由添加到表中,因为主机必须local在某个地方有一条路由,以便内核接受该地址的流量。将路由放在 2 个表中就可以了。之后,我们向local表中添加一条没有local指定的新路由,这将导致流量不通过该lo接口。

答案2

netcat-openbsddebian 和 opensd 上,您可以选择要使用的路由表。

选项是-V.

对于常规netcat我相信这是不可能的。

使用 socat,您可以使用在调用时声明它的特定接口。

答案3

对本地地址的访问始终使用环回接口,因为网络接口设计用于将数据包发送到线路上的其他节点,而不是您自己。

答案4

简单回答

Linux内核中有两个数据包队列,一个用于发送数据包,一个用于接收数据包。

内核决定(根据路由表和目标地址,NIC数据包将物理到达哪个)

但是,如果内核发现目标 IP 地址与源 IP 位于同一主机上,则在一个 NIC 上物理发送此数据包并在另一 NIC 上接收它是没有意义的。这将是矫枉过正,浪费时间和资源。因此,内核只是将数据包从发送队列中放置/删除,然后将其放入接收队列中。这一切都发生在使用伪网卡的内核中, 环回界面lo

简单的原理图,让我们假设还有另一个用于接收数据包的队列:

在此输入图像描述

相关内容