iptables( < deb ufw)

iptables其实不是真正的防火墙,可以把它理解成一个客户端代理,用户通过iptables这个代理,将用户的安全设定执行到对应的netfilter安全框架"中,netfilter位于内核空间。

一、四表五链理论

iptables 其实是多个表(table)的容器,每个表里包含不同的链(chain),链里边定义了不同的规则(policy),我们通过定义不同的规则,来控制数据包在防火墙的进出。

1、四表

  • raw表:关闭nat表上启用的连接追踪机制(决定数据包是否被状态跟踪机制处理);内核模块:iptable_raw
  • mangle表:拆解报文,做出修改,并重新封装的功能(如修改数据包的服务类型、TTL、并且可以配置路由实现QOS内核模块);内核模块:iptable_mangle
  • nat表:网络地址转换功能;内核模块:iptable_nat
  • filter表:负责包过滤功能,防火墙;内核模块:iptables_filter

2、五链

  • PREROUTING:在进行路由选择前处理数据包(做目标地址转换)
  • INPUT:处理入站数据包
  • FORWARD:处理转发数据包
  • OUTPUT:处理出站数据包
  • POSTROUTING:在进行路由选择后处理数据包(对数据链进行源地址修改转换)

报文到达链后匹配表的优先顺序

Raw ==> mangle ==> nat ==> filter

每一条链其实就是众多规则中的一个检查清单,每一条链中可以有一条或数条规则。当一个数据包到达一个链时,iptables就会从链中第一条规则开始检查,看该数据包是否满足规则所定义的条件。如果满足,系统就会根据 该条规则所定义的方法处理该数据包;否则iptables将继续检查下一条规则,如果该数据包不符合链中任一条规则,iptables就会根据该链预先定义的默认策略来处理数据包。

3、表包含的链路

Filter 是默认的主机防火墙,过滤流入流出主机的数据包。里边包含INPUT,OUTPUT,FOWARD三个链

INPUT 过滤进入主机的数据包

OUTPUT 处理从本机发出去的数据包

FOWARD 处理流经本主机的数据包,与NAT有关系

Filter表是企业实现防火墙功能的重要手段

NAT  负责网络地址转换(来源于目的地址的IP与端口的转换),一般用于局域网的共享上网,与网络交换机acl类似,包含OUTPUT,PREROUTING,POSTROUTING三条链

OUTPUT 改变主机发出去的数据包的目标地址

PREROUTING 数据包到达防火墙时进行分路由判断之前执行的规则,改变数据包的目的地址,目的端口

POSTROUTING 数据包离开防火墙时进行分路由判断之前执行的规则,改变数据包的源的地址,源的端口

mangle 表的系统 chain: PREROUTING,OUTPUT

iptables传输数据包的过程

① 当一个数据包进入网卡时,它首先进入PREROUTING链,内核根据数据包目的IP判断是否是发往本机的。

② 如果数据包就是进入本机的,它就会沿着图向下移动,到达INPUT链。数据包到了INPUT链后,任何进程都会收到它。本机上运行的程序可以发送数据包,这些数据包会经过OUTPUT链,然后到达POSTROUTING链输出。

③ 如果数据包是要转发出去的,且内核允许转发,数据包就会流向FORWARD链进行处理(是否转发或拦截),然后到达POSTROUTING链(是否修改数据包的地 址等)进行处理。

报文的链流向:

  • 到本机某进程的报文:PREROUTING --> INPUT
  • 由本机转发的报文:PREROUTING --> FORWARD --> POSTROUTING
  • 由本机的某进程发出报文(通常为响应报文):OUTPUT --> POSTROUTING

二、iptables规则

1、写法

iptables  [ -t 表名 ] 命令选项 [链名][匹配规则][-j 处理动作]

# 表名 必须是 raw, nat,filter,mangle 中的一个。默认指filter表
# 不指定链名时,默认指表内的所有链
# 除非设置链的默认策略,否则必须指定匹配条件
# 命令选项、链名、处理动作使用大写字母,其余均为小写

①命令选项

规则管理命令选项:

  • -A:在指定链的末尾添加(append)一条新的规则
  • -D:删除(delete)指定链中的某一条规则,可以按规则序号和内容删除
  • -I : 在指定链中插入(insert)一条新的规则,默认在第一行添加
  • -R:修改、替换(replace)指定链中的某一条规则,可以按规则序号和内容替换

查看命令选项:

  • -L :列出(list)指定链中所有的规则进行查看
  • --line-numbers:查看规则时,显示规则的序号
  • -n :使用数字形式(numeric)显示输出结果
  • -v:以更详细的方式显示规则信息
  • -S:--list-rules  列出规则 

链管理命令(这都是立即生效的):

  • -E :重命名用户定义的链,不改变链本身
  • -F :清空(flush)
  • -N:新建(new-chain)一条用户自己定义的规则链
  • -X :删除指定表中用户自定义的规则链(delete-chain)
  • -P :设置指定链的默认策略(policy)
  • -Z :将所有表的所有链的字节和数据包计数器清零

②匹配规则

1) 通用匹配

###反向匹配

# 只需在选项前面使用 ! 即可,如: ! -s 192.168.0.0/16 表示除 192.168/16 外的源 IP

  • 协议匹配: -p [协议名]
  • 地址匹配
    • -s [源地址]
    • -d [目标地址]
  • 接口匹配
    • -i [入站网卡]
    • -o [出站网卡]

2) 隐含匹配

  • 端口匹配

    • -sport [源端口]
    • -dport [目标端口]
  • TCP连接标记匹配:--tcp-flags [列表1:检查范围] [列表2:被设置的标记]

    • 有两个参数列表,列表内部用逗号为分隔符,两个列表之间用空格分开
    • LIST1用作参数检查,LIST2用作参数匹配。
    • 可用标志有:

      • SYN( 同步; 表示开始会话请求 ),
      • ACK(应答),
      • FIN(结束; 结束会话),
      • RST(复位;中断一个连接)
      • PSH(推送; 数据包立即发送),
      • URG(紧急 ),
      • ALL(指选定所有的标记),
      • NONE(指未选定任何标记)
iptables -A INPUT -p tcp –tcp-flags SYN,FIN,ACK SYN
# 表示SYN、ACK、FIN的标志都检查,但是只有SYN匹配
iptables -A FROWARD -p tcp –tcp-flags ALL SYN,ACK
# 表示ALL(SYN,ACK,FIN,RST,URG,PSH)的标志都检查,但是只有设置了SYN和ACK的匹配。
  • ICMP类型匹配:--icmp-type [ICMP类型]

③处理动作

动作也可以分为基本动作和扩展动作

ACCEPT:允许数据包通过。

DROP:直接丢弃数据包,不给任何回应信息,这时候客户端会感觉自己的请求泥牛入海了,过了超时时间才会有反应。

REJECT:拒绝数据包通过,必要时会给数据发送端一个响应的信息,客户端刚请求就会收到拒绝的信息。

iptables -A FORWARD -p TCP --dport 22 -j REJECT --reject-with tcp-reset

SNAT:源地址转换,解决内网用户用同一个公网地址上网的问题。

iptables -t nat -A POSTROUTING -p tcp-o eth0 -j SNAT --to-source 194.236.50.155-194.236.50.160:1024-32000

MASQUERADE:地址伪装。是SNAT的一种特殊形式,适用于动态的、临时会变的ip上。

iptables -t nat -A POSTROUTING -p TCP -j MASQUERADE --to-ports 1024-31000

DNAT:目标地址转换。

iptables -t nat -A PREROUTING -p tcp -d 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.1-192.168.1.10:80-100

REDIRECT:在本机做端口映射。将包重新导向到另一个端口(PNAT),进行完此处理动作后,将会继续比对其它规则。 这个功能可以用来实作通透式porxy 或用来保护 web 服务器。

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080

MASK : 做防火墙标记

RETURN : 返回调用链

LOG:在/var/log/messages文件中记录日志信息,然后将数据包传递给下一条规则,也就是说除了记录以外不对数据包做任何其他操作,仍然让下一条规则去匹配。

--log-level LEVEL : 日志的等级

--log-prefix FREFIX : 日志的提示语句的前缀

2、规则管理

①查看规则

--line-numbers  在规则链前加上行号

# -S: 列出选定链的规则,
# -t : 对指定的table进行操作。raw,nat,filter,mangle中的一个。默认是filter

#查看所有的规则
iptables -L -v  -n

# 查看表中的规则
iptables -L -t filter

-L参数用于列出IPtables规则
-v参数用于显示详细信息
-n参数用于显示IP地址和端口号,而不是显示对应的服务名称
iptables -t filter -L INPUT -v -n

# 查看链中的规则
iptables -L INPUT
iptables -L FORWARD --line-numbers 

#列出nat表的规则链
iptables -S -t nat
iptables -t nat -nvL --line-numbe

# 查看POSTROUTING链nat表中的规则
iptables -L POSTROUTING -t nat
iptables -L PREROUTING -t nat --line-numbers

删除一条nat表中含POSTROUTIN的第一条规则
iptables -t nat  -D POSTROUTING  1

#删除多余的规则(规则混乱,可能互相影响)
# 删除input分组里边的第二条
iptables -L -n --line-number
iptables -D INPUT 2

②删除规则

#清除原有的filter有中的规则
iptables -F 

#清除原有的nat表中的规则
iptables -t nat  -F 

# 删除链中指定的规则
iptables -D FORWARD 1

# 删除链中指定表的规则
iptables -D POSTROUTING -t nat 1

#缺省允许IP转发
iptables -P FORWARDACCEPT

#利用iptables 实现nat MASQUERADE 共享上网
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

③添加规则

# 在指定链的末尾添加(append)一条新的规则
iptables -A FORWARD -s 10.8.0.10 -d 192.168.1.5 -j DROP
# 在指定链中插入(insert)一条新的规则,默认在第一行添加
iptables -I FORWARD -s 10.8.0.10 -d 192.168.1.5 -j DROP

3、规则的匹配顺序

①按自上而下的顺序依次匹配,匹配即停止(LOG策略例外)

②若找不到相匹配的规则,则按该链的默认策略处理

补充:保存现有规则到文件和恢复

iptables-save > /path/to/iptables.rules
iptables-restore < /path/to/iptables.rules

三、iptables的显示扩展模块

官方文档:https://ipset.netfilter.org/iptables-extensions.man.html

必须使用-m选项手动加载模块, 其扩展模块路径为:/lib64/xtables,其中大写的为目标扩展,小写的为规则扩展

1、模块管理

①查看Iptables已加载的模块

cat /proc/net/ip_tables_matches
# 查看内核已编译的模块

②查看内核支持的模块

ls /lib/modules/$(uname -r)/kernel/net/netfilter/*
#  或者
ls /lib/modules/nf_*
#  或者
ls /usr/lib/iptables/

③加载模块

modprobe 模块名

CentOS/Redhat

编辑/etc/sysconfig/iptables-config

IPTABLES_MODULES="模块1 模块2"

然后重启iptables

systemctl restart iptables

2、模块语法

-m 扩展模块 --模块参数

查看模块的支持的参数:

iptables -m <match/module name> --help
# 如果不显示模块的详细参数,则说明该模块没有加载,无法使用

3、常见条件匹配模块示例

①multiport:多端口匹配模块

-m multiport --sport | --dport [端口列表]

iptables -A INPUT -p tcp -m multiport --dport 22,25,80,443 -j ACCEPT

②iprange:IP范围匹配模块

-m iprange --src-range [IP范围]

iptables -A FORWARD -p tcp -m iprange --src-range 192.168.1.10-192.168.1.20 -j ACCEPT

③mac:MAC地址匹配模块

-m mac --mac-range [MAC地址]

iptables -A INPUT -m mac --mac-source 00:01:02:03:04:cc -j DROP

④state:报文状态匹配模块

--state [报文状态]:多个state可以使用,号分隔

支持配置的报文状态:

  • ESTABLISHED:第一个成功穿越防火墙的报文之后所有的报文;
  • NEW:一个连接的第一个报文,例如TCP连接中的SYN报文;
  • RELATED:伴随连接的报文,即某个已经处于ESTABLISHED的连接所产生的报文,这些报文不属于第一条连接,但是的确是由第一条连接产生的;
  • INVALID:如果一个包没有办法被识别,或者这个包没有任何状态,那么这个包的状态就是INVALID,我们可以主动屏蔽状态为INVALID的报文
  • UNTRACKED:报文的状态为untracked时,表示报文未被追踪,当报文的状态为Untracked时通常表示无法找到相关的连接。
iptables -A INPUT -d 172.168.100.67 -p tcp -m multiport --dport 22,80 -m state --state NEW,ESTABLISHED -j ACCEPT

⑤string:字符串匹配模块

--algo {匹配算法: bm|kmp}

--string "字符串"

iptables -I OUTPUT -s 192.168.1.0/24 -m string --algo kmp --string "qq" -j REJECT     
#使用kmp算法限制拒绝源地址192.168.1.0/24带有"qq"字符串的请求
iptables -I INPUT -m string --string "export/*" --algo bm -j DROP

⑥limit:连接数匹配模块

—limit: 平均速率,单位:个数/second ,个数/minute,个数/hour

--limit-burst: 峰值数量,默认5个

iptables -I INPUT -d 172.16.100.7 -p tcp --dport 22 -m limit --limit 25/minute --limit-burst 100 -j ACCEPT
# 当达到100个连接后,才启用上述25/minute限制

⑦connlimit:连接数匹配模块

--connlimit-upto n : 当现在的连接数量低于或等于这个数量(n),就匹配 --connlimit-above n : 当现有的连接数量大于这个数量, 就匹配

iptables -A INPUT -d 172.16.36.61 -p tcp --dport 22 -m connlimit --connlimit-above 2 -j REJECT

⑧time:时间限制匹配模块

-m time --datestart --datestop --timestart --timestop

iptables -A INPUT -p tcp --dport 21 -s 192.168.1.0/24 -m time ! --weekdays 6,7 -m time --timestart 8:30 --timestop 18:00 -m connlimit --connlimit-above 5 -j ACCET
# 在工作时间,即周一到周五的8:30-18:00,开放本机的ftp服务给 192.168.1.0网络中的主机访问;并且数据下载请求的次数每分钟不得超过 5 个;

⑨set: 地址集合模块

  • 普通的iptables链是线性的存储和过滤,在进行规则匹配时,是从规则列表中从头到尾一条一条进行匹配。这像是在链表中搜索指定节点费力
  • ipset 提供了把这个 O(n) 的操作变成 O(1) 的方法:就是把要处理的 IP 放进一个集合,对这个集合设置一条 iptables 规则。存储在带索引的数据结构中,这种结构即使集合比较大也可以进行高效的查找

  • ipset是iptables的扩展,允许创建管理匹配整个地址集合的规则。命令详解参考附录第2章节

-m set –match-set 地址集合名称

iptables -I INPUT -m set –match-set 集合名称 src -p tcp -j DROP

⑩Owner:用户模块

  • –uid-owner 和 –gid-owner 这两个选项用来匹配数据包由哪个用户和哪个用户组所产生,它们的功能由 xt_owner.ko 模块提供,且仅适用在 OUTPUT 链 POSROUTING 链中。
    • –uid-owner userid | username 该选项用来匹配数据包由哪个用户产生,因此可以利用这来限制该用户只能访问某些特定的网络服务,
    • –gid-owner groupid | groupname 该选项和 –uid-owner 类似,它用来匹配某个用户组所产生的数据包。
groupadd no-internet
iptables -I OUTPUT 1 -m owner --gid-owner no-internet -j DROP
useradd -g no-internet username

https://serverfault.com/questions/550276/how-to-block-internet-access-to-certain-programs-on-linux

四、iptables的内核调优

1、iptables的conntrack连接追踪优化

  • conntrack是netfilter的核心。有许多增强的功能,例如,地址转换(NAT),基于内容的业务识别(l7, layer-7 module)都是基于连接跟踪。

  • nf_conntrack模块在kernel 2.6.15(2006-01-03发布) 被引入,支持ipv4和ipv6,取代只支持ipv4的ip_connktrack,用于跟踪连接的状态,供其他模块使用。

  • iptables的连接追踪表最大容量是/proc/sys/ipv4/ip_conntrack_max设置的, 链接达到各种状态的超时后,会从表中删除,当模板满载时, 后续的链接可能会超时

  • 跟踪的连接用哈希表存储,每个桶(bucket)里都是1个链表,默认长度为4KB。netfilter的哈希表存储在内核空间,这部分内存不能swap

  • 哈希表大小 :64位的最大连接数/8; 32位的最大连接数/4

  • 在64位下,当CONNTRACK_MAX为 1048576,HASHSIZE 为 262144 时,最多占350多MB

  • 连接跟踪调优计算公式

    • CONNTRACK_MAX(最大几率的连接条数) = 内存个数*1024*1024*1024/16384/2 = ***

    • Buckets(哈希表大小) = CONNTRACK_MAX / 4 = ***(Byte字节)

    • 跟踪数暂用最内存大小 = CONNTRACK_MAX * 300(Byte字节)= ***(Byte字节)
  • 异常现象:

    • 丢包
  • 可调优参数

    • 哈希表桶大小

      注:net.netfilter.nf_conntrack_buckets 不能直接改(报错)

    • # 临时生效
      echo 262144 > /sys/module/nf_conntrack/parameters/hashsize
      
      # 重启永久生效
      新建文件:/etc/modprobe.d/iptables.conf
      options nf_conntrack hashsize = 32768
    • 最大追踪连接数

    • 注:加大max值, 也会加大内存的压力
    • # 临时生效
      sysctl -w net.nf_conntrack_max = 393216
      sysctl -w net.netfilter.nf_conntrack_max = 393216
      
      # 永久生效
      echo "net.nf_conntrack_ma=393216" >> /etc/sysctl.conf
      echo "net.netfilter.nf_conntrack_max=393216" >> /etc/sysctl.conf
      sysctl -p
      

      响应时间

    • net.netfilter.nf_conntrack_tcp_timeout_close_wait: 
        # CLOSE_WAIT是被动方收到FIN发ACK,然后会转到LAST_ACK发FIN,除非程序写得有问题,正常来说这状态持续时间很短。默认 60 秒
      
      # 临时生效
      sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=300
      sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=120
      sysctl -w net.netfilter.nf_conntrack_tcp_timeout_close_wait=60
      sysctl -w net.netfilter.nf_conntrack_tcp_timeout_fin_wait=120
      
      # 永久生效
      echo "net.netfilter.nf_conntrack_tcp_timeout_established=300" >> /etc/sysctl.conf
      echo "net.netfilter.nf_conntrack_tcp_timeout_time_wait=120" >> /etc/sysctl.conf
      echo "net.netfilter.nf_conntrack_tcp_timeout_close_wait=60" >> /etc/sysctl.conf
      echo "net.netfilter.nf_conntrack_tcp_timeout_fin_wait=120" >> /etc/sysctl.conf
      sysctl -p

五、iptables应用

1、防火墙

①防止ACK欺骗

拒绝TCP标记为SYN/ACK但连接状态为NEW的数据包,

iptables -A INPUT -p tcp --tcp-flags SYN,ACK SYN,ACK -m state --state NEW -j DROP

②防止TCP Null扫描

iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP

③防止Xmas扫描

iptables -A INPUT -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP

④限流/防止端口DoS攻击

iptables -A INPUT -p tcp --dport 80 -m limit --limit 25/minute --limit-burst 100 -j ACCEPT
# -m limit: 启用limit扩展,限制速度。
# --limit 25/minute: 允许最多每分钟25个连接
# --limit-burst 100: 当达到100个连接后,才启用上述25/minute限制

⑤限制主机服务时间

在工作时间,即周一到周五的8:30-18:00,开放本机的ftp服务给 192.168.1.0网络中的主机访问;并且数据下载请求的次数每分钟不得超过 5 个;

iptables -A INPUT -p tcp --dport 21 -s 192.168.1.0/24 -m time ! --weekdays 6,7 -m time --timestart 8:30 --timestop 18:00 -m connlimit --connlimit-above 5 -j ACCET

⑥丢弃无效数据包

iptables -A INPUT -m conntrack --ctstate INVALID -j DROP

⑦关键词屏蔽

iptables -I FORWARD -p udp --dport 53 -m string --string "tencent" -m time --timestart 8:15 --timestop 20:30 --days Mon,Tue,Wed,Thu,Fri,Sat -j DROP
iptables -I FORWARD -p udp --dport 53 -m string --string "TENCENT" -m time --timestart 8:15 --timestop 20:30 --days Mon,Tue,Wed,Thu,Fri,Sat -j DROP
iptables -I FORWARD -p udp --dport 53 -m string --string "qq.com" -m time --timestart 8:15 --timestop 20:30 --days Mon,Tue,Wed,Thu,Fri,Sat -j DROP

iptables -I FORWARD -s 10.113.0.0/24 -m string --string "ay2000.net" -j DROP    # 关键词屏蔽
iptables -I FORWARD -s 10.113.0.0/24 -m string --string "eroticism" -j DROP

⑧防止外网使用内网IP欺骗

iptables -t nat -A PREROUTING -i eth0 -s 10.0.0.0/8 -j DROP
iptables -t nat -A PREROUTING -i eth0 -s 172.16.0.0/12 -j DROP
iptables -t nat -A PREROUTING -i eth0 -s 192.168.0.0/16 -j DROP

⑨禁Ping

# 允许本机ping别的主机;但不开放别的主机ping本机;
iptables -A OUTPUT -p icmp --icmp-type 8 -j ACCEPT
iptables -A INPUT -p icmp --icmp-type 0 -j ACCEPT

2、NAT网络地址转换

iptable上中包含一个NAT表,其中有两条缺省的PREROUTING和 POSTROUTING 链,在这两条链上配置规则可以实现NAT功能。

①SNAT源地址目标转换

概念

SNAT(Source Network Address Translation)是指在数据包从网卡发送出去的时候,把数据包中的源地址部分替换为指定的IP。

适用于由局域网中的主机发起连接的情况。报文在经过NAT路由器时,将IP报文中的源IP地址转换为一个有效的广域网地址;在服务器给一个在私有网络中的主机返回响应报文时,目的IP地址就是这个局域网对外的广域网地址。报文到达NAT路由器的时候,路由器要将该报文分发给对应的主机,将IP报文的目的IP地址转换为私有网络地址

涉及到iptables中的链表

POSTROUTING链中的nat表

应用场景

局域网主机共享单个公网IP地址接入Internet

做法:

设置能上外网的那一台主机(192.168.1.2)的iptables,一旦接收到来自局域网(192.168.1.0/24)的数据,修改数据包的源IP地址为本机IP地址,然后就转发出去。

前提

  • 有公网IP地址绑定

  • 内核设置net.ipv4.ip_forward=1,开起路由转发功能

  • # 查看内核是否启用路由转发功能
    sysctl -a | grep "ip_forward" 或者 sysctl net.ipv4.ip_forward 
    # “net.ipv4.ip_forward=1”即可表示成功开启
    
    # 临时设置内核启用路由转发功能。重启失效
    sysctl -w net.ipv4.ip_forward=1  或者 echo 1 >/proc/sys/net/ipv4/ip_forward
    
    # 永久设置内核启用路由转发功能。
    echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf && sysctl -p

Iptables 设置

iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j SNAT --to 192.168.1.2

局域网内想上外网的主机或者路由器想添加自定义路由策略

route add 0.0.0.0 gw 192.168.1.2

②DNAT目标网络地址转换

DNAT(Destination Network Address Translation)是又称为“端口转发”,适用于由广域网上的主机发起连接的情况。当广域网的主机访问NAT路由器的广域网端口时,可以将NAT路由器的广域网的端口映射到局域网内的某个IP地址的某个端口,这样就可以实现广域网主机访问局域网内的资源。

iptables -t nat -I PREROUTING  -d 公网IP -p tcp  -m tcp  --dport 公网port  -j DNAT  --to-destination  10.10.223.12-10.10.223.20:8080(内网)

# 对于在云上绑定公网IP地址的ECS主机做DNAT,公网IP地址要写成ECS的内网地址。因为云厂商的公网IP也是使用SNAT实现的,通过公网IP访问ECS的所有流量请求,已经将目标地址改成ECS的内网地址啦。
# 例如阿里云上一台ECS绑定弹性公网IP地址123.11.12.13,内网地址为192.168.1.8,还有一台ECS,内网地址为192.168.1.9,上面部署了MYSQL。想通过弹性公网IP地址访问MySQL。则在192.168.1.8这台ECS中做DNAT的时候,可以这样配置
# iptables -t nat -I PREROUTING  -d 192.168.1.8 -p tcp --dport 33306  -j DNAT  --to-destination 192.168.1.9:3306

3、使用SystemD管理iptables规则

bash -c 'cat > /etc/systemd/system/iptables-nat.service << EOF
[Unit]
Before=network.target

[Service]
Type=oneshot

# DNAT iterms
ExecStart=/sbin/iptables -t nat -A PREROUTING -d 192.168.1.2 -p tcp --dport 3308  -j DNAT  --to-destination 192.168.1.6:3306
# SNAT iterms
ExecStart=/sbin/iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j SNAT --to 192.168.1.2

# Delete DNAT and SNAT iterms
ExecStop=/sbin/iptables -t nat -D PREROUTING -d 192.168.1.2 -p tcp --dport 3306  -j DNAT  --to-destination 192.168.1.6:3306
ExecStop=/sbin/iptables -t nat -D POSTROUTING -s 192.168.1.0/24 -j SNAT --to 192.168.1.2

[Install]
WantedBy=multi-user.target
EOF' && \
systemctl daemon-reload && \
systemctl start iptables-nat.service && \
iptables -L PREROUTING -t nat --line-numbers && \
iptables -L POSTROUTING -t nat --line-numbers && \
systemctl enable iptables-nat.service

4、ipset命令(ipset是通过IP集合的方式管理itables,提高iptables的控制效率)

六、常用设置

1、放行ssh端口:

  1 iptables -A INPUT -p tcpdport 22 -j ACCEPT
  2 iptables -A OUTPUT -p tcpsport 22 -j ACCEPT

注:/etc/rc.d/init.d/iptables save,否则直接执行service iptables restart命令后, 刚才添加的将丢失.

2、解决iptables导致的脑裂问题

  1 iptables -A INPUT -i lo -j ACCEPT  允许来自于lo接口的数据包
  2 iptables -A OUTPUT -o lo -j ACCEPT  允许向lo接口发送数据包
  3 iptables  -A INPUT -s 192.168.1.0/24 -d 224.0.0.18 -j ACCEPT       #允许组播地址通信
  4 iptables  -A INPUT -s 192.168.1.0/24 -p vrrp -j ACCEPT       #允许VRRP虚拟路由器冗余协通信

lo 是 loopback 的缩写,也就是环回地址网卡,linux主机向自身发送数据包时,实际上的数据包是通过虚拟的lo接口来发送接受的,而不会通过你的物理网卡 eth0/eth1。

3、将目的地址为gongan网10.11.1.18的8090端口的流量转到内网地址的192.168.1.100,目的端口为80。

需求:从windos终端(gonganwang主机)访问一个内网地址的服务

前提条件:

1、10.11.1.18所在服务器有个内网ip地址与192.168.1.100同网段,从10.11.1.18可以ping通192.168.1.100

2、远程windos终端可以ping通10.11.1.18

##开启路由转发

##临时
sysctl -w net.ipv4.ip_forward=1
echo "1" > /proc/sys/net/ipv4/ip_forward

##永久
vim  /etc/sysctl.conf
net.ipv4.ip_forward=1

##目标地址转换

sudo iptables -t nat -A PREROUTING -p tcp -m tcp --dport 8090 -j DNAT --to-destination 192.168.1.100:80

##源地址转换(192.168.1.100/32:80网段的数据包SNAT成10.196.11.57的ip然后发出去

sudo iptables -t nat -A POSTROUTING -d 192.168.1.100/32 -p tcp -m tcp --sport 80 -j SNAT --to-source 10.196.11.57

##MASQUERADE,地址伪装,算是snat中的一种特例,可以实现自动化的snat。

作用:从服务器的网卡上,自动获取当前ip地址来做NAT

sudo iptables -t nat -A POSTROUTING -j MASQUERADE
iptables -t nat -A PREROUTING -d 192.168.1.189 -p tcp --dport 80 -j DNAT --to-destination 1.1.1.2:80

iptables -t nat -A PREROUTING -d 192.168.1.189 -j DNAT --to-destination 1.1.1.2   将所有流量转发到内网主机

最终结果

(-A POSTROUTING -j MASQUERADE要放在最后)

 sudo  iptables  -S  -t nat 
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P POSTROUTING ACCEPT
-P OUTPUT ACCEPT
-A PREROUTING -p tcp -m tcp --dport 8090 -j DNAT --to-destination 192.168.1.100:80
-A PREROUTING -p tcp -m tcp --dport 8500 -j DNAT --to-destination 192.168.1.100:8500
-A PREROUTING -p tcp -m tcp --dport 172 -j DNAT --to-destination 192.168.1.100:172
-A POSTROUTING -d 192.168.1.100/32 -p tcp -m tcp --sport 172 -j SNAT --to-source 10.196.12.56
-A POSTROUTING -d 192.168.1.100/32 -p tcp -m tcp --sport 80 -j SNAT --to-source 10.196.12.56
-A POSTROUTING -j MASQUERADE

xshell 隧道映射访问内网服务器也可实现相同的效果

 

4、禁止、放行ip

要封停一个IP(-I :插入规则)

iptables  -I  INPUT  -s  192.168.21.3  -j  DROP

要解封一个IP(-D :删除规则)

iptables  -D  INPUT  -s  IP地址  -j  DROP

七、iptables脚本

脚本1

# vim iptables.sh
#!/bin/bash

#清空 filter 表和 nat 表
iptables -F
iptables -t nat -F

#关掉 firewalld
systemctl stop firewalld &>/dev/null
systemctl disable firewalld &>/dev/null

#以下两行允许某些调用 localhost 的应用访问
iptables -A INPUT -i lo -j ACCEPT #规则1
iptables -A INPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT #规则2

#以下一行允许从其他地方 ping
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT #规则3

#以下一行允许从其他主机、网络设备发送 MTU 调整的报文
#在一些情况下,例如通过 IPSec VPN 隧道时,主机的 MTU 需要动态减小
iptables -A INPUT -p icmp --icmp-type fragmentation-needed -j ACCEPT #规则4

#以下两行分别允许所有来源访问 TCP 80,443 端口
iptables -A INPUT -p tcp --dport 80 -j ACCEPT #规则5
iptables -A INPUT -p tcp --dport 443 -j ACCEPT #规则6

#以下一行允许所有来源访问 UDP 80,443 端口
iptables -A INPUT -p udp -m multiport --dports 80,443 -j ACCEPT #规则7

#以下一行允许 192.168.1.63 来源的 IP 访问 TCP 22 端口(OpenSSH)
iptables -A INPUT -p tcp -s 192.168.1.63 --dport 22 -j ACCEPT #规则8

#以下一行允许 192.168.1.3(发起SSH连接的系统对应网卡的IP) 来源的 IP 访问 TCP 22 端口(OpenSSH)
#如果是在远程终端跑本脚本,最好开启以下一行以防被踢掉
#另一种更加简便的方式:iptables -I INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp -s 192.168.1.3 --dport 22 -j ACCEPT #规则9

#以下一行允许 192.168.1.26 来源的 IP 访问 UDP 161 端口(SNMP)
iptables -A INPUT -p udp -s 192.168.1.26 --dport 161 -j ACCEPT #规则10

#配置 NAT
#启用内核路由转发功能
echo 1 > /proc/sys/net/ipv4/ip_forward
echo "net.ipv4.ip_forward = 1" > /etc/sysctl.conf
sysctl -p &>/dev/null

#配置源地址转换 SNAT
#将 192.168.2.0/24 转换成 192.168.1.63
iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -j SNAT --to 192.168.1.63 #规则11

#配置目的地址转换 DNAT
#将 192.168.1.63 的 80 端口请求转发到 192.168.2.2 的 80 端口
iptables -t nat -A PREROUTING -d 192.168.1.63 -p tcp --dport 80 -j DNAT --to 192.168.2.2:80 #规则12

我们期望10.0.10.62为用户访问目标,而不是web服务192.168.0.110,但62上是没有web服务的,所以有人访问62的web服务必须将其转换到110上
iptables -t nat -A PREROUTING -d 10.0.10.62 -p tcp --dport 80 -j DNAT --to-destination 192.168.0.110

#以下一行禁止所有其他的进入流量
iptables -A INPUT -j DROP #规则13

#以下一行允许本机响应规则编号为 1-12 的数据包发出
iptables -A OUTPUT -m state --state ESTABLISHED -j ACCEPT #规则14

#以下一行禁止本机主动发出外部连接
iptables -A OUTPUT -j DROP #规则15

#以下一行禁止本机转发数据包
iptables -A FORWARD -j DROP #规则16

#固化 iptables
iptables-save > /etc/sysconfig/iptables

脚本2

#!/bin/bash
#先允许
iptables -P INPUT ACCEPT

#清除规则
iptables -F
#清除用户自定义规则

iptables -X
#清除链的计数器

iptables -Z
#开启回环网络
iptables -A INPUT -i lo -j ACCEPT && iptables -A OUTPUT -o lo -j ACCEPT

#允许ping
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT 
iptables -A OUTPUT -p icmp --icmp-type  echo-reply  -j  ACCEPT

#允许2-7访问
iptables -A INPUT -p tcp -m iprange --src-range 192.168.202.2-192.168.202.7  -j ACCEPT

#允许163-168访问22端口(ssh连接)
iptables -A INPUT -p tcp -m iprange --src-range 137.64.70.163-137.64.70.168 --dport 22 -j ACCEPT

#4A地址
iptables -A INPUT -p tcp -m iprange --src-range 137.64.35.151-137.64.35.156 -j ACCEPT

#只允许主机共享rpc服务
iptables -A INPUT -p tcp -m iprange --src-range 192.168.202.2-192.168.202.7 --dport 111 -j
 ACCEPT

#只允许主机访问es
iptables -A INPUT -p tcp -m iprange --src-range 192.168.202.2-192.168.202.7 --dport 9200 -j ACCEPT

#允许主机访问2375端口
iptables -A INPUT -p tcp -m iprange --src-range 192.168.202.2-192.168.202.7 --dport 2375 -j ACCEPT

#只在164执行
iptables -A INPUT -p tcp -m iprange --src-range 137.64.76.179 --dport 28081 -j ACCEPT

#开发8080端口(只在164执行)
iptables -A INPUT -p tcp  --dport 8080 -j ACCEPT

#在屏蔽
iptables -P INPUT DROP

#所有出站一律绿灯
iptables -P OUTPUT ACCEPT

#所有转发一律丢弃
iptables -P FORWARD ACCEPT

#保存
iptables-save

脚本3、iptables自动封查IP、解禁ip
iptables是采用数据包过滤机制工作的,所以它会对请求的数据包的包头数据进行分析,并根据我们预先设定的规则进行匹配来决定是否可以进入主机。

# more nginx_ip.sh 
#!/bin/bash
. /etc/init.d/functions
conut=100 
Path=/usr/local/nginx/logs/access.log

function ipt(){ 
    awk  '{print $1}'$Path|sort|uniq -c|sort -rn >/tmp/tmp.log 
    exec < /tmp/tmp.log
    while read line
    do
        ip=echo $line|awk '{print $2}'
        if [ echo $line|awk '{print $1}' -ge $conut -a iptables -L -n|grep "$ip"|wc -l -lt 1 ]
        then
            iptables -I INPUT -s $ip -j DROP
            RETVAL=$?
            if [ $RETVAL -eq 0 ]
            then
                action "iptables -I INPUT -s $ip -j DROP" /bin/true
                echo "$ip" >>/tmp/ip_$(date +%F).log
            else
                action "iptables -I INPUT -s $ip -j DROP" /bin/false
            fi
        fi
    done
}
function del(){
[ -f /tmp/ip_$(date +%F -d '-1 day').log ]||{
    echo "log is not exist"
    exit 1} 
    exec </tmp/ip_$(date +%F -d '-1 day').log
    while read line
    do
        if [ iptables -L -n|grep "$line"|wc -l -ge 1 ]
        then
            iptables -D INPUT -s $line -j DROP
        fi
    done
}
function main(){
    flag=0
    while true
    do
        sleep 180
        ((falg++))
        ipt
        [ $flag -ge 480 ] && del && flag=0
    done
}
main

更好的方法:nginx+lua拦截IP,或者搭建软件防火强的方法。

脚本4:iptables自动屏蔽访问网站频繁的IP

场景:恶意访问,安全防范

1)屏蔽每分钟访问超过200的IP
方法1:根据访问日志(Nginx为例)
#!/bin/bash
DATE=$(date +%d/%b/%Y:%H:%M)
ABNORMAL_IP=$(tail -n5000 access.log |grep $DATE |awk '{a[$1]++}END{for(i in a)if(a[i]>100)print i}')
#先tail防止文件过大,读取慢,数字可调整每分钟最大的访问量。awk不能直接过滤日志,因为包含特殊字符。
for IP in $ABNORMAL_IP; do
    if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then
        iptables -I INPUT -s $IP -j DROP
    fi
done

方法2:通过TCP建立的连接
#!/bin/bash
ABNORMAL_IP=$(netstat -an |awk '$4~/:80$/ && $6~/ESTABLISHED/{gsub(/:[0-9]+/,"",$5);{a[$5]++}}END{for(i in a)if(a[i]>100)print i}')
#gsub是将第五列(客户端IP)的冒号和端口去掉
for IP in $ABNORMAL_IP; do
    if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then
        iptables -I INPUT -s $IP -j DROP
    fi
done

2)屏蔽每分钟SSH尝试登录超过10次的IP
方法1:通过lastb获取登录状态:
#!/bin/bash
DATE=$(date +"%a %b %e %H:%M") #星期月天时分  %e单数字时显示7,而%d显示07
ABNORMAL_IP=$(lastb |grep "$DATE" |awk '{a[$3]++}END{for(i in a)if(a[i]>10)print i}')
for IP in $ABNORMAL_IP; do
    if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then
        iptables -I INPUT -s $IP -j DROP
    fi
done

方法2:通过日志获取登录状态
#!/bin/bash
DATE=$(date +"%b %d %H")
ABNORMAL_IP="$(tail -n10000 /var/log/auth.log |grep "$DATE" |awk '/Failed/{a[$(NF-3)]++}END{for(i in a)if(a[i]>5)print i}')"
for IP in $ABNORMAL_IP; do
    if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then
        iptables -A INPUT -s $IP -j DROP
        echo "$(date +"%F %T") - iptables -A INPUT -s $IP -j DROP" >>~/ssh-login-limit.log
    fi
done

脚本5:根据web访问日志,封禁请求量异常的IP,如IP在半小时后恢复正常,则解除封禁

#!/bin/bash
####################################################################################
#根据web访问日志,封禁请求量异常的IP,如IP在半小时后恢复正常,则解除封禁
####################################################################################
logfile=/data/log/access.log
#显示一分钟前的小时和分钟
d1=`date -d "-1 minute" +%H%M`
d2=`date +%M`
ipt=/sbin/iptables
ips=/tmp/ips.txt
block()
{
 #将一分钟前的日志全部过滤出来并提取IP以及统计访问次数
 grep '$d1:' $logfile|awk '{print $1}'|sort -n|uniq -c|sort -n > $ips
 #利用for循环将次数超过100的IP依次遍历出来并予以封禁
 for i in `awk '$1>100 {print $2}' $ips`
 do
 $ipt -I INPUT -p tcp --dport 80 -s $i -j REJECT
 echo "`date +%F-%T` $i" >> /tmp/badip.log
 done
}
unblock()
{
 #将封禁后所产生的pkts数量小于10的IP依次遍历予以解封
 for a in `$ipt -nvL INPUT --line-numbers |grep '0.0.0.0/0'|awk '$2<10 {print $1}'|sort -nr`
 do 
 $ipt -D INPUT $a
 done
 $ipt -Z
}
#当时间在00分以及30分时执行解封函数
if [ $d2 -eq "00" ] || [ $d2 -eq "30" ]
 then
 #要先解再封,因为刚刚封禁时产生的pkts数量很少
 unblock
 block
 else
 block
fi

上文用到的while读取文件的方法做一点补充

1、管道的方式

cat /tmp/a.log |while read LINE
do
    echo $LINE
done

2、重定向的方式(速度较快)

while read LINE
do
     echo $LINE
done < /tmp/a.log

3、文件描述符法

exec </tmp/a.log
 
while read line
do
    echo $line
done

 

 

 

 

iptables详解 · Devops Roadmap (curiouser.top)    很全面

https://devopstack.cn/linux/871.html   Iptables 限制连接数(如SFTP) 以及 谨防CC/DDOS攻击的配置 ( connlimit模块)

 
posted @ 2019-11-23 15:43  凡人半睁眼  阅读(526)  评论(0编辑  收藏  举报