0x01 前言

我之前写了一个python脚本,利用阿里云的DNS解析服务做了DDNS服务(通过python将阿里云DNS解析作为DDNS使用)。

现在有一个安全问题,我用家里的网络去访问公网的服务器的时候,因为家里使用PPPoE,所以IP会不断变化,所以公网服务器需要开放端口的话就只能开放全部IP。

虽然端口都是使用数字证书加密和验证的,但依然很难让人放心,要是能动态更新iptables就好了。

0x02 脚本

来一个简单的脚本,首先是获取域名的IP地址:

ping -c 1 -t 1 ngx.hk | grep 'PING' | awk '{print $3}' | sed 's/[(,)]//g'

#运行结果如下
[root@web ~]# ping -c 1 -t 1 ngx.hk | grep 'PING' | awk '{print $3}' | sed 's/[(,)]//g'
10.1.1.1

然后是放行的iptables:

iptables -A INPUT -p tcp --dport 8081 -s 10.1.1.1 -j ACCEPT

还有删除iptables的命令:

iptables -D INPUT -p tcp --dport 8081 -s $get_ip -j ACCEPT

我们需要怎样取得就IP呢?通过iptables去获取是可以的,但是这样的话,在第一次运行之前必须手动运行一次放行的命令。如果有多个IP对应一个端口的情况,也很难编写脚本。

所以我选择将IP写入到一个临时文件:

`iptables -A INPUT -p tcp --dport 8081 -s $get_ip -j ACCEPT`
echo $get_ip >> ./dyn_ip.txt

这样的话,第一次运行时会自动将放行命令添加到iptables并写入到临时文件。

为此还需要一个判断,如果该临时文件存在的话,就直接从文件中获取临时文件的最后一行:

tail ./dyn_ip.txt -n 1

取得旧IP,就可以和get_ip的值做比较:

if ! [ "$old_ip" = "$get_ip"  ]; then
 `iptables -D INPUT -p tcp --dport 8081 -s $old_ip -j ACCEPT`
 `iptables -A INPUT -p tcp --dport 8081 -s $get_ip -j ACCEPT`
 echo $get_ip >> ./dyn_ip.txt
fi

上面这段脚本的意思是:如果旧IP和新IP不一致,则先删除旧IP的iptables,然后添加新IP到iptables中,最后将新IP写入临时文件。

因为将IP写入了文件,所以还需要判断该文件是否存在,如果不存在则直接运行添加iptables命令并写入文件,如果存在则输出最后一行并比对:

if [ -e './dyn_ip.txt' ]; then
 old_ip=`tail ./dyn_ip.txt -n 1`
 if ! [ "$old_ip" = "$get_ip"  ]; then
  `iptables -D INPUT -p tcp --dport 8081 -s $old_ip -j ACCEPT`
  `iptables -A INPUT -p tcp --dport 8081 -s $get_ip -j ACCEPT`
  echo $get_ip >> ./dyn_ip.txt
 fi
else
 `iptables -A INPUT -p tcp --dport 8081 -s $get_ip -j ACCEPT`
 echo $get_ip >> ./dyn_ip.txt
fi

0x03 最终

为了使临时文件保存的路径和脚本的路径一致,还需要添加以下命令:

cd `dirname $0`

先获取脚本路径,然后使用cd进入到该路径。

最终的脚本如下:

#!/bin/sh

get_ip=`ping -c 1 -t 1 ngx.hk | grep 'PING' | awk '{print $3}' | sed 's/[(,)]//g'`

cd `dirname $0`

if [ -e './dyn_ip.txt' ]; then
 old_ip=`tail ./dyn_ip.txt -n 1`
 if ! [ "$old_ip" = "$get_ip"  ]; then
  `iptables -D INPUT -p tcp --dport 8081 -s $old_ip -j ACCEPT`
  `iptables -A INPUT -p tcp --dport 8081 -s $get_ip -j ACCEPT`
  echo $get_ip >> ./dyn_ip.txt
 fi
else
 `iptables -A INPUT -p tcp --dport 8081 -s $get_ip -j ACCEPT`
 echo $get_ip >> ./dyn_ip.txt
fi

一共17行,简单明了。

0x04 运行

手动运行:

sh /usr/local/shell/dyn_iptables.sh

既然写了脚本,肯定不希望手动运行啦。那么使用crond建立定时任务:

#打开文件
[root@web ~]# vim /etc/crontab

#添加以下一行后保存并退出
*/1 * * * * root sh /usr/local/shell/dyn_iptables.sh >> /dev/null 2>&1

#重启crond服务
[root@web ~]# systemctl restart crond.service

以上crond任务为每分钟执行一次,而后面的尾巴:

>> /dev/null 2>&1

是为了避免不必要的root mail产生。

0x05 结语

这样就可以很安心地使用开放的端口了。