Linux iptables防火墙原理与常用配置

Linux系统中,防火墙(Firewall),网址转换(NAT),数据包(package)记录,流量统计,这些功能是由Netfilter子系统所提供的,而iptables是控制Netfilter的工具。iptables将许多复杂的规则组织成成容易控制的方式,以便管理员可以进行分组测试,或关闭、启动某组规则。iptable只读取数据包头,不会给信息流增加负担,也无需进行验证。

iptables结构

  
iptables由4表、5链和用户在链内写入的各种规则所组成。

1、表:容纳各种规则链;

表是按照功能分的类,具体功能如下:

(1)raw表:用来决定是否对数据包进行状态跟踪。(不常用)

(2)mangle表:为数据包设置标记,有ACK、SYN、FIN、RST、PSH、URG等标记。(不常用)

(3)nat表:修改数据包的IP地址、端口等信息。(网关型防火墙常用)

(4)filter表:确定是否放行数据包。(常用)

2、链:容纳各种防火墙规则;

链是按照时机分的类。

(1)input:处理入站请求包

(2)output:处理出站包(就是响应、应答包)

(3)forward:处理转发数据包,实现不同网段间的通信

(4)prerouting:在包做路由选择之前应用此链的规则

(5)postrouting:在数据包做路由选择之后应用此链的规则

表的处理优先级:raw > mangle > nat > filter

详细的数据包流程:

未分类

iptable应用场景

未分类

上图是应用场景的简单拓扑描述,下面的应用场景举例,都以上图为参考.

系统启动的时候所有的默认策略都是ACCEPT,在下面的场景举例中,我们都是在这种前提下设定iptable的。下面每个场景举例都是独立的,没有相关联性的。

网关服务器安全策略

目标 : 网关服务器系统自生安全策略,只对内网用户开放22端口(sshd服务)

#清空 filter table
[root@localhost]# iptables -F -t filter
[root@localhost]# iptables -X -t filter
[root@localhost]# iptables -Z -t filter

#清空 nat table
[root@localhost]# iptables -F -t nat
[root@localhost]# iptables -X -t nat
[root@localhost]# iptables -Z -t nat

#设置默认策略(INPUT链默认为DROP)
[root@localhost]# iptables -t filter -P INPUT DROP
[root@localhost]# iptables -t filter -P OUTPUT ACCEPT
[root@localhost]# iptables -t filter -P FORWARD ACCEPT

#回环接口(lo),默认accept
[root@localhost]# iptables -A INPUT -p ALL -i lo -j ACCEPT

#只对内网用户开放sshd服务
[root@localhost]# iptables -A INPUT -p tcp -s 192.168.138.0/24 --dport 22 -j ACCEPT

说明: 防火墙的策略顺序一般都是 从 非信任 ==> 信任,默认关闭所有访问权限,然后按照需要逐条开放访问权限.

共享上网(nat)

目标:使局域网的用户都可以访问外网的服务器

[root@localhost]# echo 1 > /proc/sys/net/ipv4/ip_forward
[root@localhost]# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

说明: SNAT 和 MASQUERADE 区别

SNAT : 不管是几个地址,必须明确的指定要SNAT的ip,适合网关服务器有固定地址或者是固定地址范围. MASQUERADE : 是针对ADSL动态拨号这种场景而设计,从服务器的网络接口上,自动获取当前ip地址来做NAT,这样就实现了动态SNAT地址转换

内网的服务器对外服务(端口映射)

目标:使外网用户可以访问到局域网192.168.138.21这台HTTP服务

[root@localhost]# echo 1 > /proc/sys/net/ipv4/ip_forward
[root@localhost]# iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.138.21
[root@localhost]# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

在网关服务器进行透明代理

目标: 使局域网用户,访问外网web服务时,自动使用squid作web透明代理服务器。

[root@localhost]# echo 1 > /proc/sys/net/ipv4/ip_forward
[root@localhost]# iptables -t nat -A PREROUTING -s 192.168.138.0/24 -p tcp --dport 80 -i eth0 -j DNAT --to 192.168.138.1
[root@localhost]# iptables -t nat -A PREROUTING -s 192.168.138.0/24 -p tcp --dport 80 -i eth0 -j REDIRECT --to 3128 
[root@localhost]# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE 

注意:iptables写入的规则重启会自动失效,需要使用/etc/rc.d/init.d/iptables save 保存到文件,重启才会自动读取文件上的配置,且使用iptables save保存之后,重启iptables服务:service iptables restart

iptables命令详解

iptables(选项)(参数)

-t<表>:指定要操纵的表; 
-A:向规则链中添加条目; 
-D:从规则链中删除条目; 
-i:向规则链中插入条目; 
-R:替换规则链中的条目; 
-L:显示规则链中已有的条目; 
-F:清楚规则链中已有的条目; 
-Z:清空规则链中的数据包计算器和字节计数器; 
-N:创建新的用户自定义规则链;
-X:用于删除用户自定义的空链,使用方法跟-N相同,但是在删除之前必须要将里面的链给清空; 
-P:定义规则链中的默认目标; 
-h:显示帮助信息; 
-p:指定要匹配的数据包协议类型; 
-s:指定要匹配的数据包源ip地址; 
-j<目标>:指定要跳转的目标; 
-i<网络接口>:指定数据包进入本机的网络接口; 
-o<网络接口>:指定数据包要离开本机所使用的网络接口。

iptables命令选项输入顺序:

iptables -t 表名 <-A/I/D/R> 规则链名 [规则号] <-i/o 网卡名> -p 协议名 <-s 源IP/源子网> 
             --sport 源端口 <-d 目标IP/目标子网> --dport 目标端口 -j 动作

表名包括:

  • raw:高级功能,如:网址过滤。

  • mangle:数据包修改(QOS),用于实现服务质量。

  • nat:地址转换,用于网关路由器。

  • filter:包过滤,用于防火墙规则。

规则链名包括:

  • INPUT链:处理输入数据包。

  • OUTPUT链:处理输出数据包。

  • PORWARD链:处理转发数据包。

  • PREROUTING链:用于目标地址转换(DNAT)。

  • POSTOUTING链:用于源地址转换(SNAT)。

动作包括:

  • ACCEPT:接收数据包。

  • DROP:丢弃数据包。

  • REDIRECT:重定向、映射、透明代理。

  • SNAT:源地址转换。

  • DNAT:目标地址转换。

  • MASQUERADE:IP伪装(NAT),用于ADSL。

  • LOG:日志记录。

centos7下安装iptables防火墙(关闭firewalld)

说明:centos7默认使用的firewalld防火墙,由于习惯使用iptables做防火墙,所以在安装好centos7系统后,会将默认的firewall关闭,并另安装iptables进行防火墙规则设定

系统操作环境centos7

[root@serve1 ~]# cat /etc/redhat-release    
CentOS Linux release 7.4.1708 (Core)

关闭firewalld防火墙

systemctl stop firewalld    #关闭firewalld防火墙
systemctl disable firewalld    #禁止开机自启

安装iptables防火墙并开启

yum install iptables-services    #安装iptables防火墙
systemctl start iptables    #启动
systemctl enable iptables    #开机自启

关闭SELinux

vim /etc/selinux/config
SELINUX=disabled    #把enforcing改为disabled
setenforce 0     #即时生效

基于iptables下OpenVPN访问权限控制

最近有博友咨询关于OpenVPN的用户访问权限控制的问题,即当用户连接进来以后,怎么去控制他的权限,我这里采用了一个脚本的方式自动添加,其它就是采用iptables的三层功能做路由与端口的访问控制,这里将这个shell分享出来,希望对有需要的朋友可以提供帮忙。

权限控制:

read -p "请选择您要做的操作:" caozuo
case $caozuo in
1) read -p "请输入您需要添加ERP访问权限的用户:" vpnuser
   while [ ! `more /etc/openvpn/staticip.txt | grep -w $vpnuser` ]
   doread -p "您需要添加权限的用户$vpnuser还未进行过首次登录,请让其登录一次再进行设置,请重新输入要添加权限的用户,退出请按Ctrl+C:" vpnuser
   done
     vpnuserip=`more /etc/openvpn/staticip.txt | grep $vpnuser | awk -F ‘,‘ ‘{print $2}‘`
        vpnuseripold=`more /etc/sysconfig/iptables | grep "$vpnuserip/32 -d 192.168.1.111/32 -p tcp -m tcp --dport 23 -j ACCEPT" | wc -l`if [ "$vpnuseripold" -ge "1" ]; thenread -p "您要添加权限的用户$vpnuser已经具有访问ERP的权限,不需要重复添加,按回车键退出"exitfi
     service iptables restart > nul
     iptables -I FORWARD 2 -p tcp -s $vpnuserip -d 192.168.1.111 --dport 23 -j ACCEPT
     echo " 您已经成功添加用户$vpnuser具有ERP访问权限"
     service iptables save > nul
;;

权限查看:

4) read -p "请输入要查询权限的用户名:" vpnuser
   while [ ! `more /etc/openvpn/staticip.txt | grep -w $vpnuser` ]
   doread -p "您输入用户名不存在,请重新输入用户名,退出请按Ctrl+C:" vpnuser
   done
   vpnuserip=`more /etc/openvpn/staticip.txt | grep $vpnuser | awk -F ‘,‘ ‘{print $2}‘`
   echo "您查询的用户$vpnuser具有以下访问权限:"
   more /etc/sysconfig/iptables | grep $vpnuserip | awk -F "" ‘{print $6,$12}‘ | sed -e ‘s/32端口号:g‘
;;

操作界面:

未分类

操作演示:

未分类

Debian配置iptables

Debian默认已经安装iptables,查看规则iptables -L默认允许所有出入,这是非常不安全的,因此需要对规则进行调整。

编辑配置文件:

/etc/iptables.test.rules

添加下面的规则,请根据实际情况调整:

*filter

# Allows all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT

# Accepts all established inbound connections
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allows all outbound traffic
# You could modify this to only allow certain traffic
-A OUTPUT -j ACCEPT

# Allows HTTP and HTTPS connections from anywhere (the normal ports for websites)
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT

# Allows SSH connections 
# The --dport number is the same as in /etc/ssh/sshd_config
-A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT

# Now you should read up on iptables rules and consider whether ssh access 
# for everyone is really desired. Most likely you will only allow access from certain IPs.

# Allow ping
#  note that blocking other types of icmp packets is considered a bad idea by some
#  remove -m icmp --icmp-type 8 from this line to allow all kinds of icmp:
#  https://security.stackexchange.com/questions/22711
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT

# log iptables denied calls (access via 'dmesg' command)
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7

# Reject all other inbound - default deny unless explicitly allowed policy:
-A INPUT -j REJECT
-A FORWARD -j REJECT

COMMIT

激活规则:

iptables-restore < /etc/iptables.test.rules

保存规则到主配置文件:

iptables-save > /etc/iptables.up.rules

开机自动加载规则

#编辑配置
/etc/network/if-pre-up.d/iptables

添加如下内容

#!/bin/sh
 /sbin/iptables-restore < /etc/iptables.up.rules

添加执行权限

chmod +x /etc/network/if-pre-up.d/iptables

OK,一切皆已搞定,感觉比CentOS的iptables要麻烦一点。

CentOS 6 通过iptables进行流量转发

受限于国内网络环境以及国际出口的成天炸炸炸,当然这一切都可以通过加钱来解决,加钱世界可及 — 中国奠信

有些服务器的网络面向大陆比较友好,例如阿里云香港B/C区、腾讯云香港,这时可以通过使用iptables进行流量转发来让那些面向大陆网络情况不是很友好的服务器,也能跑满100Mbps甚至更高。

流量转发的方案很多,iptables算是其中一种,还有HaProxy和SoCat,不过都有比较大的局限,例如HaProxy无法转发UDP,SoCat无法批量转发多个端口,但是单端口转发SoCat是个不错的选择。

既然要进行流量转发,那么首先要开启服务器的转发功能,打开控制台输入 vi /etc/sysctl.conf 然后找到 net.ipv4.ip_forward = 0 修改为 net.ipv4.ip_forward = 1 随后保存。

执行 sysctl -p 来使更改生效。

然后执行以下命令来添加iptables转发规则

单端口转发

iptables -t nat -A PREROUTING -p tcp --dport [要转发的端口号] -j DNAT --to-destination [要转发的服务器IP]
iptables -t nat -A PREROUTING -p udp --dport [要转发的端口号] -j DNAT --to-destination [要转发的服务器IP]
iptables -t nat -A POSTROUTING -p tcp -d [要转发的服务器IP] --dport [要转发的端口号] -j SNAT --to-source [本机IP]
iptables -t nat -A POSTROUTING -p udp -d [要转发的服务器IP] --dport [要转发的端口号] -j SNAT --to-source [本机IP]

端口段转发,栗子:转发10000到20000这个端口段,则填10000:20000

iptables -t nat -A PREROUTING -p tcp --dport [要转发的端口段] -j DNAT --to-destination [要转发的服务器IP]
iptables -t nat -A PREROUTING -p udp --dport [要转发的端口段] -j DNAT --to-destination [要转发的服务器IP]
iptables -t nat -A POSTROUTING -p tcp -d [要转发的服务器IP] --dport [要转发的端口段] -j SNAT --to-source [本机IP]
iptables -t nat -A POSTROUTING -p udp -d [要转发的服务器IP] --dport [要转发的端口段] -j SNAT --to-source [本机IP]

最后保存规则和重启iptables服务

service iptables save

service iptables restart

现在可以去试试看流量转发后速度效果如何了。

解决 iptables: Firewall modules are not loaded.

今天配置主机的时候 启动 重启防火墙都没有反应 查看防火墙状态

报错

[root@host ~]# service iptables status
iptables: Firewall modules are not loaded.

防火墙报: iptables: Firewall modules are not loaded. 百度搜到了解决方法

一. 有博客说模块没有加载,我试了这种方法没成功

加载模块

modprobe  ip_tables  #加载ip_tables模块
modprobe  iptable_filter  #加载iptable_filter模块
lsmod | grep iptable  #查看模块,有模块即解决了
iptable_filter          2173  0 
ip_tables               9567  1 iptable_filter

二. 清理iptables规则.测试成功

清理iptables规则

iptables -F #清理iptables规则
service iptables save #保存
service iptables restart #重启防火墙
service iptables status #查看状态

linux 开启独立iptables日志

iptables的日志(log)由syslogd纪录和管理。初始存放在 /var/log/messages里面。自动采取循环纪录(rotation)的方式记录。但是由于混在 messages中,对于管理和监视产生了不便。

由于iptables是linux的内核本身的功能,由dmesg或syslogd的facility结合内核管理。iptables的日志的初始值是[warn(=4)], 需要修改 rsyslog.conf。

注:系统日志配置在CentOS5上叫syslog,而在CentOS6上叫rsyslog,叫增强版的syslog,CentOS5上的配置文件在/etc/syslog.conf下,而CentOS6在/etc/rsyslog.conf下。

1、修改/etc/rsyslog.conf

*.info;mail.none;authpriv.none;cron.none                /var/log/messages

修改为

*.info;*.!notice;mail.none;authpriv.none;cron.none                /var/log/messages

同时添加

kern.=notice                                            /var/log/iptables.log

建议改为notice,将iptables产生的日志放在 /var/log/iptables.log

2、iptablse添加日志选项

iptables -t nat -I POSTROUTING -o eth0 -j LOG --log-level notice --log-prefix "iptables "

–log-level 为日志级别
–log-prefix 添加日志前缀便于分析处理

3、让日志滚动

在/etc/logrotate.d/syslog中 添加
/var/log/iptables.log,默认使用的是系统的轮替规则,当然也可以根据自己的需要去修改

4、用自己的轮替规则

(1)在目录/etc/logrotate.d/下创建一个日志转储的配置文件(名字可以自己定义,只要在该目录下就会被执行),比如iptables

(2)配置文件iptables的内容如下

/var/log/iptables.log {
daily
dateext
copytruncate
nocompress
rotate 15
}

第一行的左大括号之前的/var/log/iptables.log 指出了要转储的日志文件的具体位置和文件名;
daily:按天去转储;
dateext:表示转储后的日志文件会附加上日期信息
copytruncate 用于还在打开中的日志文件,把当前日志备份并截断;
nocompress 不要对转储的日志压缩
rotate 15 保留多少个转储之后的日志文件;

(3)确保iptables的权限为:-rw-r–r–

A 七种信息等级

1)info
2)notice
3)warning或warn
4)err或error
5)crit
6)alert
7)emerg或panic:导致系统几乎要死机

B 信息等级的指定方式

1). xxx: 表示大于xxx级别的信息
2).=xxx:表示等于xxx级别的信息
3).!xxx:表示在xxx之外的等级的信息

附加:

更改linux rsyslog 日期格式
默认时间格式:Dec 16 09:52:01,看起来不习惯,修改成 2014-12-16 09:52:01

vim /etc/rsyslog.conf
# 定义自己的本土化的时间格式
$template myformat,"%$NOW% %TIMESTAMP:8:15% %hostname% %syslogtag% %msg%n"
# Use default timestamp format
#$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
# 使用自定义的格式
$ActionFileDefaultTemplate myformat

利用iptables防止syn flood攻击

未分类

命令:

iptables -N syn-flood
iptables -A syn-flood -m limit --limit 50/s --limit-burst 10 -j RETURN
iptables -A syn-flood -j DROP
iptables -I INPUT -j syn-flood

解释:

-N 创建一个条新的链
--limit 50/s 表示每秒50次;1/m 则为每分钟一次
--limit-burst 表示允许触发 limit 限制的最大包个数 (预设5),它就像是一个容器,最多装10个,超过10个就装不下了,这些包就给后面的规则了
-I INPUT -j syn-flood  把INPUT的包交给syn-flood链处理
这里的--limit-burst=10相当于说最开始有10个可以匹配的包去转发,然后匹配的包的个数是根据--limit=50/s进行限制的,也就是每秒限制转发50个数据包,多余的会被下面符合要求的DROP规则去处理,进行丢弃,这样就实现了对数据包的限速问题。

iptables转发端口配置方法

默认的 NAT 网络模式里的虚拟机可以访问外网,但不能从外界访问虚拟机,但是可以通过 KVM 服务器配置 iptables 端口转发来访问虚拟机。

端口转发就是基于 nat 表的 PREROUTING 和 POSTROUTING 链, 所有的数据报文都要先经过 nat 的 PREROUTING 链进行处理, 再根据路由规则选择是进入 filter 的 INPUT 链还是 filter 的 FORWARD 链, 不管进入哪个链, 之后都会进去 nat 表的 POSTROUTING 链, 最后数据报文再转发出去。

开启 KVM 服务器的 ip_forward 内核转发功能

# 打开 ip_forward 转发:
echo "1"> /proc/sys/net/ipv4/ip_forward

这种方法是暂时的,系统重启后会还原。要永久生效可修改 /etc/stsctl.conf 文件。

# 编辑 /etc/stsctl.conf 文件
vim /etc/stsctl.conf
# 添加 net.ipv4.ip_forward = 1
net.ipv4.ip_forward = 1
# 保存退出后执行 sysctl –p 使其生效
sysctl –p

设置 PREROUTING 路由规则

iptables -t nat -A PREROUTING -d 1.1.1.1/32 -p tcp -m tcp --dport 9556 -j DNAT --to-destination 192.168.122.8:22

这里是把访问 KVM 服务器公网 IP 1.1.1.1(假设的 IP) 的 9556 端口数据通过 DNAT 的方式将数据报文中的目的 ip 信息改为后端的 192.168.122.8:22

设置 filter 表的 FORWARD 规则

iptables -I FORWARD -d 192.168.122.8/32 -j ACCEPT

如果当前 FORWARD 链的默认规则为 REJECT 则需要添加, 如果是 ACCEPT 则不需要执行上面的操作。

设置 POSTROUTING 路由规则

iptables -t nat -A POSTROUTING -d 192.168.122.8/32 -p tcp -m tcp --dport 22 -j SNAT --to-source 192.168.122.1

这里是把访问 192.168.122.8 端口 22 的返回数据再通过 SNAT 的方式将数据报文的源地址改为 192.168.122.1 (即 KVM 服务器的内网地址) 发送出去。

保存和查看 NAT 规则

/etc/rc.d/init.d/iptables save

# 保存 iptables 配置
service iptables save
# 重启 iptables
service iptables restart
# 查看 NAT 规则
iptables -t nat -nvL

其它

KVM 服务器启动时也会创建一些 NAT 规则,在上面 “查看 NAT 规则” 可以看到,正是那些规则才使我们创建的 NAT 网络模式的虚拟机默认即可访问外网。但它没并有写入 iptables 规则保存文件,所以我们在添加、修改 NAT 规则时重启 iptables 后最好也相应重启 KVM 服务。(如果我们使用 service iptables save 保存 iptables 配置时 KVM 服务在运行状态,那么就会把它的规则一起保存到 iptables 规则保存文件 /etc/sysconfig/iptables 里。)

iptables 是在内核层面实现端口转发功能的,相比其它应用层转发工具更高效、更灵活,但也相对更加复杂,请谨慎使用。

使用路由和iptables配置不同主机上的docker容器互相通信

docker启动时,会在宿主主机上创建一个名为docker0的虚拟网络接口,默认选择172.17.42.1/16,一个16位的子网掩码给容器提供了65534个IP地址。docker0只是一个在绑定到这上面的其他网卡间自动转发数据包的虚拟以太网桥,它可以使容器和主机相互通信,容器与容器间通信。

问题是,如何让位于不同主机上的docker容器可以通信?

最简单的思路,修改一台主机docker默认的虚拟网段,然后在各自主机上分别把对方的docker网段加入到路由表中,即可实现docker容器夸主机通信。

现有两台虚拟机

  • v1:192.168.124.51
  • v2:192.168.124.52

更改虚拟机docker0网段,修改为

  • v1:172.17.1.1/24
  • v2:172.17.2.1/24

命令如下:

#v1
sudo ifconfig docker0 172.17.1.1 netmask 255.255.255.0
sudo service docker restart

#v2
sudo ifconfig docker0 172.17.2.1 netmask 255.255.255.0
sudo service docker restart

然后在v1,v2上把对方的docker0网段加入到自己的路由表中

#v1
sudo route add -net 172.17.2.0 netmask 255.255.255.0 gw 192.168.124.52
sudo iptables -t nat -F POSTROUTING
sudo iptables -t nat -A POSTROUTING -s 172.17.1.0/24 ! -d 172.17.0.0/16 -j MASQUERADE

#v2
sudo route add -net 172.17.1.0  netmask 255.255.255.0  gw 192.168.124.51
sudo iptables -t nat -F POSTROUTING
sudo iptables -t nat -A POSTROUTING -s 172.17.2.0/24 ! -d 172.17.0.0/16 -j MASQUERADE

测试,v1,v2创建容器test1,test2

#v1
docker run --rm --name test1 -i -t base:latest bin/bash
docker inspect --format '{{.NetworkSettings.IPAddress}}' test1
#172.17.1.1

v2
docker run --rm --name test2 -i -t base:latest bin/bash
docker inspect --format '{{.NetworkSettings.IPAddress}}' test2
#172.17.2.1

主机上可以ping通对方容器ip,至此也就ok了。