为什么即使禁用转发,Linux 仍允许在不同接口 ip 上进行连接?

为什么即使禁用转发,Linux 仍允许在不同接口 ip 上进行连接?

该系统有两个接口1.1.1.11.1.2.1。 sysctlnet.ipv4.ip_forward要么被禁用,要么被启用,但iptables -P FORWARD DROP已设置。

现在1.1.1.1在另一台计算机上设置为默认路由1.1.1.2,我能够 ping 并连接到1.1.2.1接口 ip。如何以最优雅的方式轻松防止这种情况发生?

解决方案

我现在正在使用这个神奇的衬垫,感谢@AB:

nft add rule inet filter input fib daddr . iif type != { local, broadcast, multicast } drop

解释:

nft代表 nftables,假定的继承者iptables

input是来自 table 的链inet filter,该表是默认创建的(您可以使用nft list table inet filter命令查询它),但如果您有自定义 nft 设置,您应该相应地更改它。inet类型分类器意味着它适用于 ip4 和 ip6 协议。

fib daddr . iif type是对转发信息库的查询,你基本上是在输入界面上问type目标地址有什么daddriif

如果地址不是local也不是,broadcast也不是multicast到接口的数据包来自那么drop它。

@AB 还提出了一些如何阻止(或如何不阻止)遵循 DNAT 规则的数据包的观点,请查看他的答案以了解详细信息。

答案1

由于1.1.2.1是属于同一系统的其他IP地址,因此不涉及转发。系统接收一个数据包并自行处理它,作为本地传送的传入数据包,而不是路由到第三方的数据包。这符合 Linux 上 IP 应该被视为池的一部分而不是属于接口的一般想法。

为了防止使用这样的数据包被接受iptables,你必须在输入链而不是向前链。如果涉及的两个网络是 /24,则如下所示:

iptables -I INPUT -s 1.1.1.0/24 -d 1.1.2.0/24 -j DROP

由于在某些情况下这也会阻止系统连接到自身(因为此示例在规则中不使用接口名称),因此它可能至少应该在其前面添加此规则:

iptables -I INPUT -i lo -j ACCEPT

说明接口名称有时有助于组织规则和某些极端情况下的安全性(并不像想象的那么频繁,考虑到反向路径过滤在大多数发行版上默认激活)。

更新:正如OP所提到的,当然,-s 1.1.1.0/24 -d ! 1.1.1.0/24如果所有LAN都应该同样“隔离”,则可以通过每个LAN仅使用一个规则而不是LAN ^ 2规则来更好地编写此示例规则。


更新:根据进一步的要求,这里有一个更优雅的方法,使用nftables与一个谎言(转发信息库)表达式(甚至在手册页中记录为示例):将非本地(也不是广播也不是多播)的目标地址删除到接收它的接口。由于此表达式不需要显式声明任何 IP(也不需要任何接口),因此它甚至可以同时适用于 IPv4 和 IPv6,方法是使用内网地址家庭表而不是ip地址族表。

# nft add table inet filter
# nft add chain inet filter prerouting '{ type filter hook prerouting priority -150; policy accept; }
# nft add rule inet filter prerouting fib daddr . iif type != { local, broadcast, multicast } counter drop

仅此一项就可以处理任意数量的 LAN/接口(只要您不玩游戏并将多个 LAN 放在同一接口上,这可能会违反上述多个 LAN 之间的规则)。counter是可选的,只是为了查看使用例如 的命中nft list ruleset

然而,这条规则允许 DNAT 到另一个当地的在其他接口上定义的 IP,因为它发生在任何 DNAT 之前(使用iptables它以优先级 NF_IP_PRI_NAT_DST (=-100)) 注册,但同时阻止路由/转发(如果 OP 选择启用它)或转发 DNAT:它们要么因为不是本地的(对于正常转发)而被丢弃,要么返回数据包将在“反向 DNAT”发生之前满足此规则并将被删除。如果添加在挂钩输入相反,相反的情况将会发生:不允许本地 DNAT 到其他 IP,但路由/转发 DNAT 可以工作,因为它通过向前钩子而不是输入。这会更有用,对于其他罕见的情况,可以添加例外。所以最终应该使用这个而不是上面的:

# nft add table inet filter
# nft add chain inet filter input '{ type filter hook input priority 0; policy accept; }
# nft add rule inet filter input fib daddr . iif type != { local, broadcast, multicast } counter drop

iptablesnftables可以和平共处(除了纳特其中只有一个应该尝试注册,而不是两者)。那么这几个nftables线条可以沿着任何现有的iptables规则。

上面的规则可以写成脚本格式(主要是 的输出nft list ruleset),而不是在启动时初始化,例如:

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy accept;
        fib daddr . iif type != { local, broadcast, multicast } counter drop
    }
}

挑剔的是,唯一要检查的是何时使用较新的iptables 通过 nftables API,例如 Debian buster 上的默认值,flush ruleset也会刷新iptables规则,因为它们实际上是使用nftables,因为现在你不能“提前”只刷新不存在的链而不会出现错误。所以这个脚本应该在任何之前运行iptables如果是这种情况,请编写脚本。


另请注意,1.1.1.0/24 网络中的客户端虽然无法连接到 1.1.2.1,但仍然能够使用 ARP 推断其存在。就像是:

arping -I eth0 1.1.2.1

即使 1.1.2.1“属于”其他网络中的其他接口(具有不同的 MAC 地址),也会通过 1.1.1.0/24 网络上的系统接口从 1.1.2.1 获得回复。

这是因为,Linux 默认情况下,无论好坏,都会应答在其任何接口上收到的针对其任何 IP 的 ARP 请求。这次有详细描述:arp_过滤器

为了避免这种情况,要么混合arp_过滤器+ip rule或者arp_公告+arp_忽略,或使用arptables(或者nftablesARPfamily)来过滤 ARP 请求(无论如何可能需要前面的设置之一)。

相关内容