Ubuntu(Debian) ufw not blocking port 不生效

1. 背景

  1. 为了给梯子加速,尝试开启 BBR,所以尝鲜的用上了 Debian 9.

新的 TCP 拥塞控制算法 BBR (Bottleneck Bandwidth and RTT) 可以让服务器的带宽尽量跑慢,并且尽量不要有排队的情况,让网络服务更佳稳定和高效。

Linux Kernel 内核升级到 4.9 及以上版本实现 BBR 加速的,由于 Debian9 默认的内核就是 4.9 的内核而且编译了 TCP BBR 的内容,所以可以直接通过参数开启。

  1. CentOS 6.x 因为内核的原因,所以装 Docker 比较麻烦;CentOS 7 新的防火墙 FirewallD 虽然已经会初步的使用了;但是还要习惯从 server xxxx start[restart|stop] 转到 systemctl ;还有一个 journalctl -xe 查看错误日志的东西。
  2. 看到网上好多的 Docker 镜像都是基于 Debian/Ubuntu 的,很少基于 CentOS,所以也为了学习一下 Debian

综合一下,所以 VPS 装了 Debian 9 的系统。

2. 安装梯子

2.1. 脚本安装(支持 Open-VZ)

然后用一键脚本装了 v2ray,放上作者的一键式安装命令

1
bash <(curl -s -L https://git.io/v2ray.sh)

确实相当好用,nice。具体链接请点击这里

2.2. Docker 一键安装

我使用的配置方式是 Docker + Caddy + v2ray,走的是 WS + TLS。

传送门:https://github.com/yuanmomo/docker-caddy-v2ray

3. 需求

安装 v2ray 后,需要防火墙禁用一些端口,像用 WS + TLS 时,v2ray 的监听端口只需要 Caddy 能访问就 OK 了,外面是不需要访问的。

如果使用一键脚本安装,又安装了 ss 服务,如果需要手动关闭和打开 ss 的端口,那就要用到防火墙。

在之前的 CentOS 6.x 之前,用 iptables,那是相当的没有问题,但是就是命令太长,所以 Debian(Ubuntu)基于 iptables 封装了一个 ufw,来简化 iptables 的操作。

4. ufw 使用

官方操作文档:https://help.ubuntu.com/lts/serverguide/firewall.html

大概使用如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
## 启用 ufw,设置默认 incoming 为 deny
sudo ufw enable
sudo ufw default deny

## 允许所有的外部IP访问本机的25/tcp (smtp)端口
sudo ufw allow smtp
## 允许访问 ssh 服务,也就是 22 端口。
sudo ufw allow ssh
## 允许所有的外部IP访问本机的22/tcp (ssh)端口
sudo ufw allow 22/tcp
## 允许外部访问53端口(tcp/udp)
sudo ufw allow 53
## 允许此 IP 访问所有的本机端口
sudo ufw allow from 192.168.1.100
## 禁止外部访问 80 http 服务
sudo ufw deny http
## 删除 smtp 的规则
sudo ufw delete allow smtp
## 删除 通过 ufw status numbered 看到的编号为 1 的规则
sudo ufw delete 1

## ufw status numbered 看到的编号为 1 的规则前面添加允许访问80端口
sudo ufw insert 1 allow 80

## 使用数字显示防火墙的规则
ufw status numbered

5. 事实?

当我一顿猛如虎的操作了过后,然后看了一下当前 ufw 的状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
## 启用 ufw,设置默认 incoming 为 deny
[email protected]:/etc/ufw# ufw enable
[email protected]:/etc/ufw# ufw default deny

## 允许访问 22
[email protected]:/etc/ufw# ufw allow ssh
## 允许访问 80
[email protected]:/etc/ufw# ufw allow http

## 查看端口监听信息
[email protected]:~# netstat -anp | grep -i listen | grep tcp
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 21723/sshd
tcp6 0 0 :::80 :::* LISTEN 1755/v2ray
tcp6 0 0 :::443 :::* LISTEN 1755/v2ray

## 查看 ufw 防火墙的详细信息
[email protected]:/etc/ufw# ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
80/tcp ALLOW IN Anywhere
22/tcp (v6) ALLOW IN Anywhere (v6)
80/tcp (v6) ALLOW IN Anywhere (v6)

默认 deny,只允许访问两个端口: 80 和 22。443 是 ss 端口,不想开放出来,也没有配置在规则里面,简直毫无破绽。

然后美滋滋的在本地执行了一下 nmap 和 telnet( 真实 ip 被我替换掉了):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
» telnet 1.1.1.1  443
Trying 1.1.1.1...
Connected to 1.1.1.1.
Escape character is '^]'.
Connection closed by foreign host.

» telnet 1.1.1.1 22
Trying 1.1.1.1...
Connected to 1.1.1.1.
Escape character is '^]'.

» nmap 1.1.1.1

Starting Nmap 7.60 ( https://nmap.org ) at 2019-08-14 01:11 CST
Nmap scan report for 1.1.1.1
Host is up (0.0082s latency).
Not shown: 997 filtered ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
443/tcp open https

Nmap done: 1 IP address (1 host up) scanned in 5.07 seconds

什么鬼???443 怎么可能访问到???我不是没有配置 443 端口吗?默认应该是 deny 的啊???

6. 排查

然后我重新试了好几次,还重装了一次 debian,网上各种谷歌 ufw not blocking port 的关键字,看了官方文档。确认,我的 ufw 操作肯定没有问题。

发工单给 VPS HOST,然后陆陆续续的交流,没有什么进展。

自己也在不停的找问题,最后用 iptables-save 命令检查一下当前iptables 的规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[email protected]:~# iptables-save
# Generated by iptables-save v1.6.0 on Mon Aug 12 10:50:51 2019
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
.............
## iptables 操作修改的部分
-A INPUT -p udp -m state --state NEW -m udp --dport 80 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A INPUT -p udp -m state --state NEW -m udp --dport 443 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
.............
## ufw 操作修改的部分
-A ufw-user-input -p tcp -m tcp --dport 80 -j ACCEPT
-A ufw-user-input -p udp -m udp --dport 80 -j ACCEPT
-A ufw-user-input -p tcp -m tcp --dport 22 -j DROP
-A ufw-user-input -p udp -m udp --dport 22 -j DROP
.............
COMMIT
# Completed on Mon Aug 12 10:50:51 2019

中间的不重要信息已经省略了。发现有两个地方定义了 80 端口,而且格式还不一样。果断怀疑是一键安装脚本直接使用 iptables 命令操作了防火墙,而不是 ufw,而且,插入的顺序还在 ufw 控制的前面,所以就不受 ufw 控制了。

一看脚本的内容:
v2ray-sh-iptables-command

真的是就是这个原因。

7. 解决

7.1. 脚本直接用 iptables 修改 防火墙配置

这种情况,注释掉脚本使用 iptables 操作防火墙的部分即可。

7.2. Docker 修 iptables 的配置

这个是我搜出来的,之前也遇到过,只是没有仔细深入去思考,为什么 ufw 不能 deny docker 容器中的端口。

参考:https://askubuntu.com/questions/652556/uncomplicated-firewall-ufw-is-not-blocking-anything-when-using-docker

解决办法有三个:

  1. docker run 不使用 -p 参数. 使用 docker linking or docker networks 替代.
  2. 监听容器的端口在回环网卡 lo 上,也就是 127.0.0.1:
    docker run -p 127.0.0.1:8080:8080 …
  3. 配置 Docker 不要修改防火墙。修改 /etc/docker/daemon.json 文件: { “iptables” : false },然后重启。

建议使用第 1,2 两种方法。第 3 种方法回使容器不能访问外网。

Just for my love !!