这是我的 iptables 命令:
sudo iptables -F
sudo iptables -A INPUT -p tcp -s 109.123.74.85 --dport 27000 -j ACCEPT
sudo iptables -A INPUT -p tcp -s 188.170.80.4 --dport 27000 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 27000 -j REJECT
sudo iptables -L
这给了我以下 iptables 规则:
$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- 109.123.74.85 anywhere tcp dpt:27000
ACCEPT tcp -- 188.170.80.4 anywhere tcp dpt:27000
REJECT tcp -- anywhere anywhere tcp dpt:27000 reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain DOCKER (0 references)
target prot opt source destination
Chain DOCKER-ISOLATION (0 references)
target prot opt source destination
我有一个简单的 HTTP 服务器来测试它:
python3 -m http.server 27000
当我从 VPN 客户端(ip 109.123.74.85)请求它时:curl myServerIP:27000/1.txt
它没有响应。
但是,当我关闭客户端上的 VPN 并curl myServerIP:27000/1.txt
使用客户端 IP 188.170.80.4 发出请求时,它可以正常工作。
另外,有趣的是,当我使用端口 8881 而不是 27000 时,它对于 VPN 和非 VPN 客户端都能很好地运行。
那么如何配置 iptables 来为使用 VPN 的特定 IP 地址客户端打开端口 27000,而对其他所有 IP 地址客户端进行阻止?
更新 1
为了澄清响应类型:当我从 VPN 客户端发出请求时,我收到操作超时:
curl myServerIP:27000/1.txt
curl: (7) Failed to connect to myServerIP port 27000: Operation timed out
更新 2
当我描述端口 8881 运行正常时,我的意思是在这种情况下我使用了以下 iptables:
sudo iptables -A INPUT -p tcp -s 109.123.74.85 --dport 8881 -j ACCEPT
sudo iptables -A INPUT -p tcp -s 188.170.80.4 --dport 8881 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 8881 -j REJECT
更新 3
这是我检查客户端 IP 地址的方法:curl ifconfig.me
更新 4
该死,我意识到我遇到了同样的问题,VPN 客户端请求 27000 端口,即使服务器上的 iptables 为空。所以我想我应该写信给 vpn 提供商支持,弄清楚发生了什么。虽然请求端口 8881 工作正常。
更新 5(最终版)
所以我更换了 VPN 提供商,一切都按预期运行
答案1
我猜你不是 iptables 专家,所以我会尽量快速帮助你,但你应该阅读iptables 教程(这是一份很棒的文档)以了解详细信息。
将示例规则集保存到某个文件中,然后使用命令加载它iptables-apply <path-to-file>
。默认情况下,此命令需要用户确认。如果超过等待超时时间而未得到用户确认,则规则集将回滚。
此外,您应该阅读 Linux 发行版的文档以使更改永久生效,否则系统重启后结果将丢失。使用 iptables-persistent 包或类似包是个好主意。
针对您的情况制定的规则的一般框架:
# Generated by iptables-save v1.6.2 on Thu May 16 16:17:54 2019
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:HTTP_IN - [0:0]
# allow already established and related connections
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# you can use multiple port numbers, separated with comma
# use the HTTP_IN chain for incoming packets to tcp/27000 port
-A INPUT -p tcp -m tcp -m multiport --dports 27000 -j HTTP_IN
# allow local connections
-A INPUT -i lo -j ACCEPT
# allow the icmp packets. it can be improved.
-A INPUT -p icmp -j ACCEPT
# this is the whitelist of ip addresses
-A HTTP_IN -s 109.123.74.85/32 -j ACCEPT
-A HTTP_IN -s 188.170.80.4/32 -j ACCEPT
# this rule should be last in the HTTP_IN chain
-A HTTP_IN -j REJECT --reject-with icmp-port-unreachable
COMMIT
为了更好地将新的 IP 地址添加到白名单,您可以编辑当前规则集文件并使用iptables-restore
或加载它iptables-apply
。您也可以使用iptables -I HTTP_IN --src <allowed-ip> -j ACCEPT
命令。
与您的问题相关的一些细节。
当我从 VPN 客户端(ip 109.123.74.85)请求它时:
curl myServerIP:27000/1.txt
它没有响应。
not response
和之间是有区别的connection reset
。第一种情况下,您没有任何回复;第二种情况下,您会收到特殊数据包(带有 RST 标志的 TCP 或某些 ICMP 消息)。如果您没有回复,则问题出在其他地方 - 使用tcpdump
进行故障排除。如果您有ICMP port unreachable
回复 - 检查您的客户端的 IP 地址,很可能它与您的预期不同。您还可以检查规则计数器(最好使用iptables-save -c
命令列出带有计数器的完整规则集)。
另外,有趣的是,当我使用端口 8881 而不是 27000 时,它对于 VPN 和非 VPN 客户端都能很好地运行。
这是预期的行为,因为在这种情况下数据包没有通过您的ACCEPT
/REJECT
规则并且被 INPUT 策略接受。
解决两台主机之间的连接问题最有效的方法是tcpdump
在两端使用。此外,Linux在处理tcpdump
之前netfilter
(读作iptables
)捕获传入数据包,但在防火墙之后捕获传出数据包。如果您在一端看到传出数据包,但在另一端看不到它们是传入的,那么它们在中间某处被丢弃或丢失了。您可以使用traceroute
/tcp
数据udp
包来检测问题主机。