天天看点

实用防火墙(Iptables)脚本分析

实用防火墙(iptables)脚本分析

——redhat,centos,ubuntu等常见linux发行版中都会预装iptables防火墙,大多数初学者设置起来由于对这款软件比较陌生,设置起来比较困难,下面这段脚本实现了修改变量的值就能轻松移植到自己的网络,同时对各段内容做了介绍。首先在/usr/bin下建立一个脚本名为firewall,设定可执行权限

#chmod +x /usr/bin/firewall

下面我最这个脚本的关键部分做一些说明:

——首先设定假设你想限制某ip(例如10.10.10.20),你只需将他们填入到badips变量中,可以设定多个ip或网端,每个用空格分开.

badips="10.10.10.20 10.1.14.0/24"

——接下来开始设定impossible_ips变量,例如设定三个私有ip的网段,前提是你的主机ip 不能在三个设定的网段范围之内,如果在设定范围内就要删除.

impossible_ips="10.0.0.0/8 172.16.0.0/12 192.168.0.0/16"

如果你的系统只是家用,单独上网,以下6行代码就无需设置。

1).in_tcp_portallowed=""

2).in_icmp_allowed=""

3).egress="0"

4).out_tcp_portallowed=""

5).out_udp_portallowed=""

6).out_icmp_allowed=""

<a></a>

——如果你架设了服务器就需要下面的设定,这里强调一下in_tcp_porallowed,in_udp_portallowed是变量,他的值设定常见网络服务的端口号;如果需要开放连续端口就需要使用“:”号,例如需要开放38000-38090之间的所有端口,只要进行如下设定:

in_tcp_portallowed=”38000:38090”

下面看个复杂的例子,

例1:

——假定ssh服务只允许200.100.10.10访问,而ftp服务之开放给192.168.20.0/24网段使用;smtp则是出了10.10.10.20以外其余都可以访问:

in_tcp_portallowed=”ssh,200.100.10.10ftp,192.168.20.0/24smtp,!10.10.10.20”

例2:

——架设需要开放smtp,domain服务给所有ip使用,然后仅允许来自200.100.10.10和192.168.20.0/24的使用者使用ssh登陆服务器:

in_tcp_portallowed=”ssh,200.100.10.10 ssh,192.168.20.0/24 smtp domain”

案3:一个错误的案例

——有人想允许192.168.150.30对内网ssh服务器访问,但是除了192.168.20.10以外其他所有ip都可以访问22端口,其余都阻断。他是这样写的:

in_tcp_portallowed=”ssh,192.168.150.30ssh,!192.168.20.10”

——我们可以看到虽然规则1限制了只有192.168.150.30可以访问 ssh服务器,但是规则2却反而将其开放给所有人,第一个规则等于摆设。

实用防火墙(Iptables)脚本分析

更多详细的信息您可以在/etc/service文件中找到。

# 允许内网的tcp链接

in_tcp_portallowed="ssh,192.14.0.3 smtp domain http https"

# 允许内网的udp链接

in_udp_portallowed="domain"

如果你想让ping包通过那么需要如下设定

in_icmp_allowed=”8”

当然也可以设定只有某个ip能ping,例如:

in_icmp_allowed=”8,61.63.33.172”

表示只有61.63.33.172可以ping 主机。

# 允许内网ICMP的类型

in_icmp_allowed="0 3 8 11"

实用防火墙(Iptables)脚本分析

下面看个例子帮助我们理解这张表,在ping时,如果这个 echo-request 不能到达对方的机器﹐或是对方回应的 echo-reply 不能顺利送回来﹐那 ping 就失败。在许多有防火墙的环境中都会碰到﹐如果防火墙将 request 和 reply 拦下来就会导致 ping 失败。另外﹐就算不是防火墙设置的问题﹐对方也可以将机器设定为不回应任何 echo-request 封包﹐若在 linux 上,只要用下面命令就可以了﹕

echo "1" &gt; /proc/sys/net/ipv4/icmp_echo_ignore_all

再举一个例子,在使用traceroute命令式,我们要知道当封包被一个路由节点处理之后﹐它原来的 ttl 值就会被扣掉 1 ﹐这样﹐如果封包的 ttl 降到 0 的时候﹐路由器就会丢弃这个封包﹐并且同时向来源地送出一个 time_exceeded( type 11 ) 的 icmp 封包﹐以告知其封包的命运。

egress这个设置表示是否限制对外的链接,值为0代表不限制,1代表限制对外链接。

egress="0"

# 允许对外链接的通讯端口

out_tcp_portallowed="ssh smtp,root http https pop3"

# 允许对外链接的udp通讯端口

out_udp_portallowed=""

out_icmp_allowed="0 3 8 11"

#如果你希望记录所有被放火墙阻止的数据包,就需要将droplog的值设定为1,不过这样会使/var/log/messages日志容量上升

droplog="0"

#

dshield="0"

#装载iptables核心模块

modprobe ip_tables 2&gt;/dev/null

modprobe ip_conntrack 2&gt;/dev/null

modprobe ip_conntrack_ftp 2&gt;/dev/null

modprobe ip_conntrack_irc 2&gt;/dev/null

#清除当前iptables所有表的规则

echo -n "initiating iptables..."

iptables -p input accept

iptables -p output accept

iptables -p forward accept

iptables -t filter -f

iptables -t nat -f

iptables -t filter -x

iptables -t nat -x

echo "ok"

if [ "$dshield" = "1" ]; then

echo -n "getting the dshield block list..."

badips="$badips

`lynx --dump http://feeds.dshield.org/block.txt | \

awk '/^[1-9]/ {print $1 "/" $3}'`"

fi

block.txt的部分内容如下:

开始ip 结束ip 网络号 攻击数量 name country email

222.189.239.0222.189.239.255242054

195.178.109.0195.178.109.255241601providerru[no email]

216.145.110.0216.145.110.255241355

[email protected]

[email protected]

# 若你加上start参数,则将$skiptest变量置1,那么就会跳过测试模式,设定所有规则后不再清除。

[ "$1" = "start" ] &amp;&amp; skiptest="1"

##设置iptables核心的安全相关参数

echo 1 &gt; /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts

echo 1 &gt; /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses

echo 0 &gt; /proc/sys/net/ipv4/conf/all/accept_source_route

echo 0 &gt; /proc/sys/net/ipv4/conf/all/accept_redirects

echo 0 &gt; /proc/sys/net/ipv4/conf/all/send_redirects

echo 1 &gt; /proc/sys/net/ipv4/conf/all/rp_filter

echo 1 &gt; /proc/sys/net/ipv4/tcp_syncookies

echo 3 &gt; /proc/sys/net/ipv4/tcp_retries1

echo 30 &gt; /proc/sys/net/ipv4/tcp_fin_timeout

echo 1400 &gt; /proc/sys/net/ipv4/tcp_keepalive_time

echo 0 &gt; /proc/sys/net/ipv4/tcp_window_scaling

echo 0 &gt; /proc/sys/net/ipv4/tcp_sack

echo 0 &gt; /proc/sys/net/ipv4/tcp_timestamps

## 下面开始设定防火墙规则

echo -n "setting rules..." 

#设定input,output,forward的过滤规则,不符合规则的就会丢弃。

iptables -p input drop 

iptables -p output drop

iptables -p forward drop

# 允许流经环路地址(loopback)的包通过,lo代表环路接口。

iptables -a input -i lo -j accept

iptables -a output -o lo -j accept

iptables -a input -i ! lo -s 127.0.0.0/8 -j drop

iptables -a output -o ! lo -d 127.0.0.0/8 -j drop

# 增加新链badpkt

iptables -n badpkt

# 若droplog数值为1则记录所有badpkt链的数据包

if [ "$droplog" = "1" ]; then

iptables -a badpkt -j log --log-prefix "** firewall badpkt **"

# 丢弃所有进入badpkt链的封包

iptables -a badpkt -j drop

# 将可疑封包交给badpkt链处理。

iptables -a input -m state --state invalid -j badpkt

iptables -a input -p tcp ! --syn -m state --state new -j badpkt

iptables -a input -p tcp --tcp-flags all none -j badpkt

iptables -a input -p tcp --tcp-flags syn,fin syn,fin -j badpkt

iptables -a input -p tcp --tcp-flags syn,rst syn,rst -j badpkt

iptables -a input -p tcp --tcp-flags fin,rst fin,rst -j badpkt

iptables -a input -p tcp --tcp-flags ack,fin fin -j badpkt

iptables -a input -p tcp --tcp-flags ack,urg urg -j badpkt

iptables -a input -p tcp --tcp-flags ack,psh psh -j badpkt

iptables -a input -p tcp --tcp-flags all fin,urg,psh -j badpkt

iptables -a input -p tcp --tcp-flags all syn,rst,ack,fin,urg -j badpkt

iptables -a input -p tcp --tcp-flags all all -j badpkt

iptables -a input -p tcp --tcp-flags all fin -j badpkt

# 允许目的端口为53的udp包通过,这样才能使用dns查询。

iptables -a output -p udp -m state --state new --dport 53 -j accept

# 允许已建立连线和回应的数据包通过

iptables -a input -m state --state established,related -j accept

iptables -a output -m state --state established,related -j accept

# 增加一个阻止ip的新链

iptables -n badip

# 若droplog变量为1,则记录所有进入badip链的封包

iptables -a badip -j log --log-prefix "** firewall badip **"

# 丢弃所有进入badip链的封包

iptables -a badip -j drop

# 阻止特定ip

for ip in $badips $impossible_ips ; do

iptables -a input -s $ip -j badip

done

# 允许特定tcp号对内新连接

for i in $in_tcp_portallowed ; do

ifs=','

set $i

unset ifs ipt_option

port="$1"

[ -n "$2" ] &amp;&amp; ipt_option="-s `echo $2 | sed 's/^!/! /'`"

iptables -a input -p tcp $ipt_option --dport $port \

--syn -m state --state new -j accept

# 允许特定udp端口的对内新链接

for i in $in_udp_portallowed ; do

iptables -a input -p udp $ipt_option --dport $port \

-m state --state new -j accept

# 允许特定icmp类型数据包进入

for i in $in_icmp_allowed ; do

type="$1"

iptables -a input -p icmp $ipt_option --icmp-type $type \

# 前面讲过egress数值为1标志管制对外链接

if [ $egress = "1" ]; then

# 允许特定tcp对外链接

for i in $out_tcp_portallowed ; do

[ -n "$2" ] &amp;&amp; ipt_option="-d `echo $2 | sed 's/^!/! /'`"

[ -n "$3" ] &amp;&amp; ipt_option="$ipt_option -m owner \

`echo $3 | sed 's/\([^!]\)/ --uid-owner \1/'`"

iptables -a output -p tcp $ipt_option --dport $port \

for i in $out_udp_portallowed ; do

iptables -a output -p udp $ipt_option --dport $port \

for i in $out_icmp_allowed ; do

iptables -a output -p icmp $ipt_option --icmp-type $type \

if [ ! "$egress" = "1" ]; then

iptables -a output -m state --state new -j accept

iptables -a input -j log --log-prefix "** firewall drop **"

iptables -a output -j log --log-prefix "** firewall drop **"

iptables -a forward -j log --log-prefix "** firewall drop **"

echo "done"

# 5秒后自动清除iptables规则,这样可以避免锁住自己。

if [ "$skiptest" = "1" ]; then exit ;fi

echo -e "\ntest mode"

echo -n "all chains will be cleaned after 5 sec."

i=1; while [ "$i" -le "5" ]; do

echo -n "."

i=`expr $i + 1`

sleep 1

echo -en "\nflushing ruleset..."

这样一个200多行脚本就能实现基本功能的防火墙,大家可以去上机试试,附件中带完整脚本。

继续阅读