如何在 Ubuntu Headless 中使用 iptables 通过接口过滤允许 DNS

如何在 Ubuntu Headless 中使用 iptables 通过接口过滤允许 DNS

我看到过一些涉及静态 DNS、openVPN 服务器推送等的问题,但它们都不适用,或者它们需要 GUI 工具,而我正在使用通过 SSH 进入的无头 Ubuntu Core。

root@redacted:~# lsb_release -a
Distributor ID: Ubuntu
Description:    Ubuntu 14.04.3 LTS
Release:        14.04
Codename:       trusty

当机器仅通过 eth0 连接到本地网络时,一切正常。我可以直接 ping IP(8.8.8.8)并解析域名(google.com)。

wget -q -O - ipecho.net/plain #Shows my ISPs provided Public IP

当机器使用 VPN 网络通过 tun0 连接时,我可以直接 ping IP(8.8.8.8)并解析域名(google.com)。

wget -q -O - ipecho.net/plain #Shows my VPNs provided Public IP

到目前为止一切都如预期...

现在问题来了...我添加以下 iptables 规则来强制特定用户只能使用 tun0 适配器:

sudo iptables -A OUTPUT -m owner --gid-owner vpnonly -o lo -j ACCEPT
sudo iptables -A OUTPUT -m owner --gid-owner vpnonly -o eth0 -p tcp -d 192.168.x.x/24 --sport xxxx -j ACCEPT
sudo iptables -A OUTPUT -m owner --gid-owner vpnonly \! -o tun0 -j REJECT

如果你好奇的话,第二条规则允许以用户 vponly 身份运行的基于 Web 的 UI 在我的本地网络上访问。

所以现在,当我运行那些我不想通过我的公共 IP 进行通信的进程时,为了防止 VPN 出现故障/断开连接/等情况而发生泄漏,我只需在 vpnonly 下运行它们,而 vpnonly 的唯一组就是 vpnonly。然而当我以 vpnonly 身份运行进程时,我可以直接 ping IP(8.8.8.8)但是我不能解析域名(google.com)。

root@redacted:~# sudo -u vpnonly ping -c 2 google.com
ping: unknown host google.com

即使我可以让它再次解析域名,那也将令人满意,但我真正想做的是将 VPN 设置为使用单独的特定 DNS,同时让 eth0 使用 8.8.8.8、8.8.4.4。

我已经在 Google 上搜索了所有我能想到的与此相关的内容,但无法解决...我希望我已经添加了足够的细节,但很乐意根据要求添加更多内容

编辑 1:完整的 iptables

root@redacted:~# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere             owner GID match vpnonly
ACCEPT     tcp  --  anywhere             192.168.x.x/24       owner GID match vpnonly tcp spt:xxxx
REJECT     all  --  anywhere             anywhere             owner GID match vpnonly reject-with icmp-port-unreachable

-

root@redacted:~# iptables -L -v
Chain INPUT (policy ACCEPT 16407 packets, 12M bytes)
 pkts bytes target     prot opt in     out     source               destination   

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination   

Chain OUTPUT (policy ACCEPT 6230 packets, 675K bytes)
 pkts bytes target     prot opt in     out     source               destination   
 3751 2800K ACCEPT     all  --  any    lo      anywhere             anywhere             owner GID match vpnonly
 6635 3332K ACCEPT     tcp  --  any    eth0    anywhere             192.168.x.x/24       owner GID match vpnonly tcp spt:xxxx
    4   224 REJECT     all  --  any    !tun0   anywhere             anywhere             owner GID match vpnonly reject-with icmp-port-unreachable

编辑2:

在添加 iptables 规则之前,一切都运行正常,此时我遇到的唯一问题是域名解析。我的 vpn 还提供非日志 DNS。解决方案是将我的 /etc/network/interfaces 名称服务器条目从 192.168.x.1 更改为我的 VPN 提供的 DNS IP 地址,然后在拒绝之前允许所有到该 DNS IP 的连接吗?我想在尝试之前问一下,一是确保它像我认为的那样安全,二是我无论如何都会提供赏金。我想确保没有泄漏,并且不想通过 DNS 引入泄漏...

经过进一步的启发,我是否应该在拒绝之前明确允许 192.168.x.1 和 VPN DNS IP,而不是修改接口?

我真正想做的是强制这些 DNS 查询通过 tun0 适配器,尽可能使用户“vponly”与外界的任何通信都通过 VPN。

答案1

第一个问题是,您能访问您的 DNS 服务器吗?如果您阻止了除 tun0 之外的所有服务器的访问,则您很可能阻止了 DNS 访问。

如果您在本地运行某种 DNS 服务器,比如 Bind 或 dnsmasq,那么该服务也需要能够访问互联网。

我建议在拒绝之前向您的 iptables 添加一个日志条目,以查看哪些流量被拒绝。

使用端口 53 是破坏安全性的标准方法,因此打开 *:53 可能不明智,因此最好专门指定您的 DNS 服务器(本地和上游)作为可接受的流量目标。我假设 --sport xxxx 的意思是您正在为您的 Web 服务使用非标准端口而不是 :80。如果不是,您应该在 192.168 规则中指定它(对于 IP 也是如此,它应该是完整的 /32 地址)。

另外别忘了,如果您想使用 ping 进行测试,您需要为 ICMP 设置 iptable 条目。ICMP 8(echo)是 ping,ICMP 0 是 ping 回复。

还需要考虑您拥有哪些路由,因为您需要确保流量的默认路由是 tun0。如果 tun0 是唯一允许的接口,您需要确保所需的所有路由都通过该接口发送流量。

如果这不能诊断出您的问题,请使用 ethtool 进行一些网络嗅探,以查看哪些对话正在进行,哪些对话没有进行。这可能是一些奇怪的事情,例如允许 REQ,但 ACK 没有返回。

答案2

一种简单的方法是创建一个服务 .conf,它将保留您喜欢的任何 iptables 规则。

您可以安装一个包来执行此操作,但手动方式如下:

sudo vi /etc/init/persist-iptables.conf

你可以随意命名,只要确保它/etc/init/.conf

然后您要插入以下几行:

description "Persist IPTables on Boot"

start on runlevel [2345]

script
        # Accept all loopback traffic localhost or 127.0.0.1
        iptables -A INPUT -i lo -j ACCEPT
        iptables -A OUTPUT -o lo -j ACCEPT

        # Accept any DNS traffic, I use a DD-WRT router with
        # Force DNS Redirection to a non-logging DNS
        iptables -A OUTPUT -d 255.255.255.255 -j ACCEPT
        iptables -A INPUT -s 255.255.255.255 -j ACCEPT

        # Accept all local traffic from 192.168.1.1-192.168.1.255
        iptables -A INPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -j ACCEPT
        iptables -A OUTPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -j ACCEPT

        # Forward all eth0, eth1, etc through tun interfaces
        iptables -A FORWARD -i eth+ -o tun+ -j ACCEPT
        iptables -A FORWARD -i tun+ -o eth+ -j ACCEPT

        # Postroute masquerade through tun interfaces
        iptables -t nat -A POSTROUTING -o tun+ -j MASQUERADE

        # Drop any other traffic through eth adapters
        iptables -A OUTPUT -o eth+ ! -d a.b.c.d -j DROP
end script

现在,当你的系统重新启动时(这会清除你的 IP 表),它将自动运行以再次更新 iptables。你也可以自己调用它sudo service persist-iptables start

该文件将允许所有本地主机流量,允许所有 DNS 流量(您需要确保它是来自路由器的正确 DNS),允许所有本地流量,将流量从 eth 适配器转发到 tun 适配器并对其进行后路由屏蔽,最后丢弃任何其他流量。

相关内容