Linux的主机防火墙通过netfilter实现,netfilter则为linux的一段内核代码,它实现了对出入主机的数据包做相应的规则检查,匹配到规则则按规则定义的动作执行相应操作,没有匹配到的则按默认动作处理,iptables就是这样一个工作在用户空间的可以对netfilter的规则进行增、删、查、改的这么一个工具。


在linux内核2.0以前用的是ipfw, 到2.2开始用ipchain, 2.4以后用的就是iptables了。

iptables检查规则类似于cisco检查ACL规则,逐条依次往下检查,匹配到则退出检查。


iptables/netfilter工作原理:

五条链,也叫checkpoint检查点,hook function(勾子函数)就是把进来的包先勾住检查一番,对有良民证的就按规则放行,否则嘿嘿。

    PREROUTING:包刚进来还没路由之前的关卡

    POSTROUTING:包路由完要离开时

    INPUT:路由后发现包是发往本机

    OUTPUT:本机发往外面要出去

    FORWARD:通过本机转发

wKiom1PofL7gwA1XAAEpE51r7qY005.jpg

之所以叫tables是因为他在内核维护了4张表

    filter:包过滤

    nat:网络地址转

    mangle:包重构,把包拆开来打上某些标记再送走,在LVS中会用到

    raw:刚从外面进来或者刚从本机要出去要处理的规则,很少用到

wKiom1PoZmbSLSwRAAK7vfvP5xw810.jpg

上图取自百度百科,要想知道哪个表可以工作在哪些链上可以用命令 iptables -L -n -t TABLE_NAME查看。

如:

[root@console ~]# iptables -L -n -t mangle
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

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         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination

iptables常用用法

    查看已有规则

        -L | --list 列出规则

        -n | --numeric 以数字形式显示,不解析IP地址及端口号

        -v | --verbose 显示详细信息

        -t | --table 指定要操作的表

        --line-numbers 显示规则的行号

        -S | --list-ruls 显示某个表的某个链的规则,不指定链则这个表的所有链

    管理链

        -F | --flush 清空链: 

            iptables -t filtesr -F INPUT 清空filter表INPUT链的所有规则,如果没有指定链则会清空所有链的所有规则对于filter表可以不指定-t(table),默认就是filter表。

        -P | --policy 设置默认规则

            iptables -t filter -P INPUT DROP 

        -Z | --zero 清空计数器

        -N | --new-chain 新建一条自定义链,自定义链需要被调用,调用后再返回原链继续检查。

        -X | --delete-chain 删除自定义的空链

        -E | --rename-chain 重命名自定义链

    管理规则

        -A | --append 添加规则

        -R | --replace 修改规则

        -I | --insert 插入一条规则

        -D | --delete 删除规则

        -s | --source 源IP地址

        -d | --destination 目标IP地址

        -p | --protocol 协议

        --sport | --source-port 源端口

        --dport | --destination-port 目标端口

        -j | --jump 跳转,目标可以是:DROP, REJECT, ACCEPT, DNAT, SNAT, LOG, MARK,RETURN 返回主链, REDIRECT 端口重定向,自定义链


保存已经写好的规则

  1. service iptables save --> 把规则保存至/etc/sysconfig/iptables 对!iptables在/etc/rc.d/init.d/下是有服务脚本的

  2. 其实上面的命令是调用了iptables-save命令的,当你写了一些规则觉得很好但是又不需要应用到当前主机上时就可以通过这个命令重定向保存到其他位置:iptables-save > ~/iptables.rules

  3. 然后哪一天又需要用到这些规则了:iptables-restore < ~/iptables.rules

    

例子

  1. 允许172.16.0.0网段ssh到本机(172.16.100.10),设置INPUT,OUTPUT默认策略均为DROP。

  • iptables -A INPUT -s 172.16.0.0/16 -p tcp --dport 22 -d 172.16.100.10 -j ACCEPT

  • iptables -A OUTPUT -s 172.16.100.10 -p tcp --sport 22 -d 172.16.0.0/16 -j ACCEPT

  • iptables -P INPUT DROP

  • iptables -P OUTPUT DROP

    如果本来是ssh连到远程主机的,则一定要先设置放行规则后再设置默认策略为DROP,否则把自己关在门外的感觉那可不是盖的。为了避免杯具发生,可以在做规则之前先设置个计划任务,每隔一段时间重启一下iptables服务,起码喝杯咖啡的时间还可以回到解放前。

2. 但是不允许172.16.100.12这台主机ssh到本机

  • iptables -I INPUT 1 -s 172.16.100.12 -p tcp --dport 22 -j DROP

要把这条规则放到之前放行的前面,因为如果上面放行匹配到了就直接处理跳出检查了。

3. 允许172.16.0.0/16网段ping本机(--icmp-type 8 为echo request请求进来,0 为echo reply回应请求)

  • iptables -A INPUT -p icmp --icmp-type 8 -d 172.16.100.10 -j ACCEPT

  • iptables -A OUTPUT -p icmp --icmp-type 0 -s 172.16.100.10 -j ACCEPT


显式扩展模块:上面的-p tcp其实是调用了/lib64/xtables-1.4.7/libxt_tcp.sop这个模块,但是我们写规则的时候并不用特别指出,这称之为隐式扩展,下面两种方法可以看到

wKioL1Poibez6hmjAAPK8hbubwc846.jpg

下面是几种常用的显示扩展

4. multiport扩展:可以一次指定最多15个端口

  • 放行ftp,ssh及web请求

    • iptables -A INPUT -d 172.16.100.10 -p tcp -m multiport --destination-ports 21,22,80 -j ACCEPT

    • iptables -A OUTPUT -s 172.16.100.10 -p tcp -m multiport --source-ports 21,22,80 -j ACCEPT


5. iprange扩展:放行一段IP地址192.168.100.100-192.168.100.180访问本机web服务

  • iptables -A INPUT -d 172.16.100.10 -p tcp --dport 80 -m iprange --src-range 192.168.100.100-192.168.100.180 -j ACCEPT

  • iptables -A OUTPUT -s 172.16.100.10 -p tcp --sport 80 -m iprange --dst-range 192.168.100.100-192.168.100.180 -j ACCEPT


6. time扩展:可指定放行的时间段 --datestart    --datestop    --timestart    --timestop    --weekdays    --monthdays

  • 只允许192.168.0.0/24网段周一到周五中午9:30到17:00访问本机web服务

    • iptables -A INPUT -s 192.168.0.0/24 -d 172.16.100.10 -p tcp --dport 80 -m time --weekdays Mon,Tue,Wed,Thu,Fri --time-start 09:30 --time-stop 17:00 -j ACCEPT

    • iptables -A OUTPUT -d 192.168.0.0/24 -s 172.16.100.10 -p tcp --sport 80 -m time --weekdays Mon,Tue,Wed,Thu,Fri --timestart 09:30 --timestop 17:00 -j ACCEPT   

    

7. state扩展:内核模块会为每一个连接维持一个数据结构保存连接的状态信息,状态主要有NEW,ESTABLISHED,RELEATED,INVALID几种。

  • 允许172.16.10.0/24网段访问本机ssh,web服务

    •  iptables -I INPUT 3 -s 172.16.10.0/24 -d 172.16.100.10  -p tcp -m multiport --destination-ports 22,80 -m state --state NEW,ESTABLISHED -j ACCEPT

    • iptables -I OUTPUT 1 -m state --state ESTABLISHED  # 对于所有established状态的包全部旅行,那么OUTPUT链上的其他的放行的规则都可以删除了

  • 放行工作在被动(passive)模式下的ftp服务

    • 对于passive的ftp,由于数据端口是随机的,所以要放行RELATED状态包,而对于ftp的包状态追踪需要加载nf_conntrack_ftp模块,可以modprobe nf_conntrack_ftp 也可以写入/etc/sysconfig/iptables-config配置文件

[root@console ~]# vim /etc/sysconfig/iptables-config 

# Load additional iptables modules (nat helpers)
#   Default: -none-
# Space separated list of nat helpers (e.g. 'ip_nat_ftp ip_nat_irc'), which
# are loaded after the firewall rules are applied. Options for the helpers are
# stored in /etc/modprobe.conf.
IPTABLES_MODULES="nf_conntrack_ftp"

# 编辑配置文件后需要重启iptables

[root@console ~]# modprobe nf_conntrack_ftp
[root@console ~]# lsmod | grep nf_conntrack_ftp
nf_conntrack_ftp       12913  0 
nf_conntrack           79357  6 nf_conntrack_ftp,iptable_nat,nf_nat,nf_conntrack_ipv4,nf_conntrack_ipv6,xt_state

[root@console ~]# iptables -I INPUT 1 -d 172.16.100.10 -s 172.16.0.0 -m state --state ESTABLISHED,RELATED -j ACCEPT
[root@console ~]# iptables -R INPUT 2 -d 172.16.100.10 -s 172.16.0.0 -p tcp -m multiport --destination-ports 21,22,80 -m state --state NEW -j ACCEPT
[root@console ~]# iptables -R  OUTPUT 1 -m state --state ESTABLISHED,RELATED -j ACCEPT
# 切到另一台机器,测试一哈
[root@node1 ~]# lftp 172.16.100.10
lftp 172.16.100.10:~> ls
drwxr-xr-x    2 0        0            4096 Aug 12 02:50 pub
lftp 172.16.100.10:/> cd pub
lftp 172.16.100.10:/pub> ls
-rw-r--r--    1 0        0             787 Aug 12 02:50 fstab
lftp 172.16.100.10:/pub> get fstab 
787 bytes transferred
lftp 172.16.100.10:/pub> bye

--tcp-flags 匹配指定的 TCP 标记,有两个参数,都为列表,列表内部用半角逗号分隔,这两个列表之间用空格分隔。后面的为1,其他的为0,后面的是前面的子集。

--tcp-flags SYN,ACK,RST,FIN SYN,ACK 表示SYN,ACK位为1,RST,FIN位为0


8. string扩展:可以简单过滤字符串 --algo 指定算法,常用的的为bm和kmp --string | --hex-string 把要过滤的字串先转成十六进制,匹配效率要高

# 没加string过滤前
[root@node1 ~]# curl 172.16.100.10
<h2>console</h2>
[root@node1 ~]# curl 172.16.100.10/test.html
admin console
# 加上字串过滤,再请求test.html由于含有‘admin’字串,所以被拒绝,没响应
[root@console ~]# iptables -I OUTPUT 1 -s 172.16.100.10 -p tcp --sport 80 -m string --algo bm --string 'admin' -j DROP
[root@node1 ~]# curl 172.16.100.10
<h2>console</h2>
[root@node1 ~]# curl 172.16.100.10/test.html






^C


9. limit扩展模块:做连接数限制 --limit-burst 一次可以同时进来的连接数

  • iptables -I INPUT 2 -p tcp --dport 22 -m state --state NEW -m limit --limit 10/min --limit-burst 2 -j ACCEPT

  • 限制每分钟只可以发起10个新的ssh连接,并且同时只可以有2个进来



10. 自定义链:

  • iptables -N chain_in

  • iptables -A chain_in -p tcp --tcp-flags ALL ALL -j DROP

  • iptables -A chain_in -p tcp --tcp-flags ALL NONE -j DROP

  • iptables -A chian_in -d 172.16.100.10 -j RETURN  # 检查完事要返回原链

  • iptables -A INPUT -d 172.16.100.10 -j chain_in


11. 放行ntpd时间服务 

  • iptables -A INPUT -d 172.16.100.10 -p udp --dport 123 -m state --state NEW -j ACCEPT


12.recent 模块:可以实现简单防御DOS***,原理就是为进来的连接维持一个列表并计数,当达到设定的阀值时就按设定的规则处理

  • iptables -I INPUT 2 -d 172.16.100.10 -i eth0 -p tcp --dport 22 -m state --state NEW -m recent --set --name ssh_defend

    # 对新进的ssh连接请求设定规则,--set 记录此IP到列表,如果已有则更新计数 --name 为这个规则起个名字叫ssh_defend以便下面调用,这条规则生效后在/proc/net/xt_recent/ (rhel6)下生成同名文件,用来保存被其匹配到的连接信息,对rhel5的话目录是 /proc/net/ipt_recent/


  • [root@console net]# ls /proc/net/xt_recent/
    ssh_defend
    [root@console net]# cat /proc/net/xt_recent/ssh_defend 
    src=172.16.100.1 ttl: 128 last_seen: 4300580195 oldest_pkt: 14 4300507152, 4300518639, 4300535257, 4300535257, 4300538260, 4300538260, 4300544261, 4300544261, 4300571189, 4300571189, 4300574189, 4300574189, 4300580195, 4300580195
  • iptables -I INPUT 3 -d 172.16.100.10 -i eth0 -p tcp --dport 22 -m state --state NEW -m recent --update --name ssh_defend --seconds 300 --hitcount 3 -j DROP

    # --name 指定要和谁做匹配, 300秒内超过3个连接则 DROP


13. hashlimit模块:对源、目标IP地址、端口做hash,以实现单独统计计数,用令牌桶的算法控制,令牌桶能容纳的令牌数是自己设置定值,来一个请求就发一个令牌,桶不满就会生成新的令牌放进来,但是不能超过桶容量,支持--hashlimit-mode 指定基于源地址srcip、目标地址dstip、源端口srcport和目标端口dstport做规则匹配 

  •  iptables -R INPUT 2 -d 172.16.100.10 -s 172.16.0.0/16 -p tcp --dport 22 -m state --state NEW -m hashlimit --hashlimit-name ssh_protect --hashlimit-mode srcip --hashlimit 5/m --hashlimit-burst 10 -j DROP