由于需要对iptables规则进行修改,百度了好久iptc,结果只有很少的帖子,然后到Stack Overflow上搜了iptc,在一堆IPTC数据中翻到了几个相关的帖子,并发现在github上有iptc库。
那么现在就来记录一下如何使用python语言的iptc库进行linux系统iptables防火墙规则增删查改。
安装iptc库
首先需要在linux系统中加载iptc库:
pip install --upgrade python-iptables # 或pip3
前置要求安装python3和pip3
yum install -y epel-release
yum install -y openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel zlib-devel
yum install -y python3 python3-devel
pip3 install --upgrade pip
yum install -y gcc libffi-devel python-devel
错误提示:
/usr/include/bits/errno.h:24:26: fatal error: linux/errno.h: No such file or directory
解决方法:
wget http://mirror.centos.org/centos/7/os/x86_64/Packages/kernel-headers-3.10.0-1160.el7.x86_64.rpm
rpm -ivh kernel-headers-3.10.0-957.el7.x86_64.rpm
基础配置
研究了一下github上iptc库的范例,了解到使用iptc库进行iptables基本需要新建一个rule并指定table和chain,然后通过match设置rule中各项参数的值,添加到rule中,最后将rule插入到iptables中。
重点:iptc库的所有参数都是字符串模式
简单规则之目的/源地址
我们首先来建立一个非常简单的iptables规则链:
阻止来自固定地址的链接:
iptables -A INPUT -s 192.168.0.7 -j DROP
import iptc
# 设定要操作的规则表,NAT\FILTER\RAW\MANGLE
# 设定要操作的规则链,INPUT\OUTPUT\FORWARD\PREROUTING\POSTROUTING
table = iptc.Table(iptc.Table.FILTER)
chain = iptc.Chain(table, "INPUT")
# 设定规则
rule = iptc.Rule()
rule.src = "192.168.0.7/255.255.255.0"
# 设定匹配
# match = iptc.Match(rule,"tcp")
# rule.match = match
# 设定目标
target = iptc.Target(rule, "DROP")
rule.target = target
chain.insert_rule(rule)
运行结果为:
[root@bogon python]# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP all -- 192.168.0.0/24 anywhere
# 下略
在iptc库设定中,目的地址和源地址都由rule的dst和src字段设置,甚至通过dst_range/src_range字段来设置目的地址段/源地址段,例如:
rule.dst_range = "192.168.0.200-192.168.0.233"
rule.src_range = "192.168.0.1"
简单规则之目的/源端口
允许来自固定端口或访问固定端口的链接:
iptables -A INPUT -sport 80 -dport 80 -j ACCEPT
端口配置规则是位于协议规则之下的,因此需要先配置协议
import iptc
# 设定要操作的规则表,NAT\FILTER\RAW\MANGLE
# 设定要操作的规则链,INPUT\OUTPUT\FORWARD\PREROUTING\POSTROUTING
table = iptc.Table(iptc.Table.FILTER)
chain = iptc.Chain(table, "INPUT")
# 设定规则
rule = iptc.Rule()
rule.protocol = "tcp"
# 设定匹配
match = iptc.Match(rule,"tcp")
match.sport = "80"
match.dport = "80"
rule.add_match(match)
# 设定目标
target = iptc.Target(rule, "ACCEPT")
rule.target = target
chain.insert_rule(rule)
运行结果为:
[root@bogon python]# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- anywhere anywhere tcp spt:http dpt:http
# 下略
成功配置允许发送端口和接受端口均为80端口的TCP数据包进入服务器的规则。
简单规则之TCP标记
允许来自固定端口或访问固定端口的链接:
iptables -t filter -A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j ACCEPT
等效于匹配TCP三次握手中的第一次握手报文。
PS:–tcp-flags FIN,SYN,RST,ACK SYN也可以直接等效于 -syn
import iptc
# 设定要操作的规则表,NAT\FILTER\RAW\MANGLE
# 设定要操作的规则链,INPUT\OUTPUT\FORWARD\PREROUTING\POSTROUTING
table = iptc.Table(iptc.Table.FILTER)
chain = iptc.Chain(table, "INPUT")
# 设定规则
rule = iptc.Rule()
rule.protocol = "tcp"
# 设定匹配
match = iptc.Match(rule,"tcp")
# --tcp-flags 匹配TCP标记
match.tcp_flags = ['FIN,SYN,RST,ACK', 'SYN']
rule.add_match(match)
# 设定目标
target = iptc.Target(rule, "ACCEPT")
rule.target = target
chain.insert_rule(rule)
[root@bogon python]# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- anywhere anywhere tcp flags:FIN,SYN,RST,ACK/SYN
# 下略
简单规则之TCP的state扩展
iptables -t filter -A INPUT -p tcp -m tcp --state RELATED,ESTABLISHED -j ACCEPT
import iptc
# 设定要操作的规则表,NAT\FILTER\RAW\MANGLE
# 设定要操作的规则链,INPUT\OUTPUT\FORWARD\PREROUTING\POSTROUTING
table = iptc.Table(iptc.Table.FILTER)
chain = iptc.Chain(table, "INPUT")
# 设定规则
rule = iptc.Rule()
rule.protocol = "tcp"
# 设定匹配
# --state 匹配报文状态
match = iptc.Match(rule,"state")
match.state = "RELATED,ESTABLISHED"
rule.add_match(match)
# 设定目标
target = iptc.Target(rule, "ACCEPT")
rule.target = target
chain.insert_rule(rule)
运行结果为:
[root@bogon python]# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- anywhere anywhere state RELATED,ESTABLISHED
# 下略
简单规则之新建规则链
import iptc
table = iptc.Table(iptc.Table.FILTER)
chain = table.create_chain("TEST")
运行结果
[root@bogon python]# iptables -L
# 上略
Chain TEST (0 references)
target prot opt source destination
多重规则
允许来自固定IP区域、固定端口、固定报文状态、固定时间的链接(随便配的,不考虑是否可行):
iptables -A INPUT -s 192.168.0.7 -j DROP
import iptc
# 设定要操作的规则表,NAT\FILTER\RAW\MANGLE
# 设定要操作的规则链,INPUT\OUTPUT\FORWARD\PREROUTING\POSTROUTING
table = iptc.Table(iptc.Table.FILTER)
chain = iptc.Chain(table, "INPUT")
# 设定规则
rule = iptc.Rule()
# 设定目的地址段和源地址
match_range = iptc.Match(rule, "iprange")
match_range.src_range = "192.168.1.100-192.168.1.200"
match_range.dst_range = "172.22.33.106"
rule.match = match_range
match_tcp = iptc.Match(rule, "tcp")
match_tcp.dport = '80'
match_tcp.sport = '80'
rule.match = match_tcp
match_state = iptc.Match(rule, "state")
match_state.state = "RELATED,ESTABLISHED"
rule.match = match_state
# 设定目标
target = iptc.Target(rule, "DROP")
rule.target = target
chain.insert_rule(rule)
运行结果为:
[root@bogon python]# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP all -- 192.168.0.0/24 anywhere
# 下略
写的挺乱的,后续再改。