目录
- 1、背景
- 2、go库下载
- 3、go库和命令行对比
- 4、代码示例
- 【1】定义iptables规则和ipset集合名称常量
- 【2】创建ipset集合
- 【3】创建iptables规则
- 【4】添加条目
- 【5】查看iptables
- 【6】查看ipset
- 5、总结
1、背景
iptables是linux中一个比较好用的防火墙工具,可以通过它对网络数据包进行管理和过滤,iptables中的四表五链在网上能查到很多文章解释,这里不做过多解释。
ipset是一个用于管理IP地址集合的工具,能和iptables组合起来一起使用,方便维护和管理各种防火墙规则。
本文会给出一个通过go库操作iptables中filter表的INPUT链和ipset来实现允许和拒绝进入本机ipv4网络数据包的示例。
2、go库下载
【1】iptables下载
go get -u github.com/coreos/go-iptables
【2】ipset下载
go get -u github.com/vishvananda/netlink
3、go库和命令行对比
操作方式 | 优点 | 缺点 |
---|---|---|
命令行操作 | 简单方便 | 平台架构版本兼容性差,复杂场景灵活性差 |
go库操作 | 平台兼容性强,复杂场景灵活性高 | 需要花时间验证库的正确性 |
4、代码示例
【1】定义iptables规则和ipset集合名称常量
// ipset类型 const ( HASH_IP = "hash:ip" HASH_IP_PORT = "hash:ip,port" HASH_NET = "hash:net" HASH_NET_PORT = "hash:net,port" ) // ipset名称 const ( WL_IP python= "wl_ip" WL_IP_PORT = "wl_ip_port" WL_NET = "wl_net" WL_NET_PORT = "wl_net_port" BL_IP = "bl_ip" BL_IP_PORT = "bl_ipjs_port" BL_NET = "bl_net" BL_NET_PORT = "bl_net_port" ) var ipSetNameToTypeMp = map[string]string{ WL_IP: HASH_IP, WL_IP_PORT: HASH_IP_PORT, WL_NET: HASH_NET, WL_NET_PORT: HASH_NET_PORT, BL_IP: HASH_IP, BL_IP_PORT: HASH_IP_PORT, BL_NET: HASH_NET, BL_NET_PORT: HASH_NET_PORT, } // iptables规则 var iptRules = [][]string{ {"-m", "state", "--state", "ESTABLISHED,RELATED", "-j", "ACCEPT"}, //已建连接允许 {"-i", "lo", "-j", "ACCEPT"}, //本地回环包运行 {"-m", "set", "--match-set", WL_IP, "src", "-j", "ACCEPT"}, //对集合条目里的源ip允许 {"-m", "set", "--match-set", WL_IP_PORT, "src,dst", "-j", "ACCEPT"}, //对集合条目里的源ip和目的port允许 {"-m", "set", "--match-set", WL_NET, "src", "-j", "ACCEPT"}, //对集合条目里的源ip允许 {"-m", "set", "--match-set", WL_NET_PORT, "src,dst", "-j", "ACCEPT"}, //对集合条目里的源ip和目的port允许 {"-m", "set", "--match-set", BL_IP, "src", "-j", "ACCEPT"}, //对集合条目里的源ip拒绝 {"-m", "set", "--match-set", BL_IP_PORT, "src,dst", "-j", "ACCEPT"}, //对集合条目里的源ip和目的port拒绝 {"-m", "set", "--match-set", BL_NET, "src", "-j", "ACCEPT"}, //对集合条目里的源ip拒绝 {"-m", "set", "--match-set", BL_NET_PORT, "src,dst", "-j", "ACCEPT"}, //对集合条目里的源ip和目的port拒绝 }
一般都会对本机的已建连接和lo网口的数据包放行,两条规则分别为:
1、iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 2、iptables -A INPUT -i lo -j ACCEPT
默认在filter表上增加规则,也可以增加-t指定其它表
【2】创建ipset集合
//创建ipset集合 for setName, setType := range ipSetNameToTypeMp { if err := netlink.IpsetCreate(setName, setType, netlink.IpsetCreateOptions{Replace: true}); err != nil { logger.Error("ipset create error", zap.String("set_name", setName), zap.Error(err)) continue } }
netlink.IpsetCreateOptions中可以定义其它自定义参数,比如:超时时间、ipv4/ipv6、最大个数、是否覆盖已存在的集合等。
【3】创建iptables规则
//创建iptables规则 ipt, err := iptables.New() if err != nil { logger.Error("iptables new error", zap.Error(err)) return } for _, iptRule := range iptRules { if err = ipt.AppendUnique("filter", "INPUT", iptRule...); err != nil { logger.Error("iptables append unique error", zap.Error(err)) continue } }
AppendUnique函数是往指定链中追加规则,如果规则存在就不会去做操作。
【4】添加条目
//增加ipset条目 var port = uint16(100) if err = netlink.IpsetAdd(WL_IP, &netlink.IPSetEntry{IP: net.ParseIP("1.1.1.1")}); err != nil { //对源ip为1.1.1.1的包加白 logger.Error("ipset add error", zap.Error(err)) } if err = netlink.IpsetAdd(WL_IP_PORT, &netlink.IPSetEntry{IP: net.ParseIP("2.2.2.2"), Port: &port}); err != nil { //对源ip为2.2.2.2,目的端口为100的包加白 logger.Error("ipset add error", zap.Error(err)) } if err = netlink.IpsetAdd(WL_NET, &netlink.IPSetEntry{IP: net.ParseIP("3.3.3.3"), CIDR: 24}); err != nil { //对源ip在3.3.3.3/24范围内的包加白 logger.Error("ipset add error", zap.Error(err)) } if err = netlink.IpsetAdd(WL_NET_PORT, &netlink.IPSetEntry{IP: net.ParseIP("4.4.4.4"), Chttp://www.devze.comIDR: 24, Port: &port}); err != nil { //对源在4.4.4.4/24范围内,目的端口为100的包加白 logger.Error("ipset add error", zap.Error(err)) } if err = netlink.IpsetAdd(BL_IP, &netlink.IPSetEntry{IP: net.ParseIP("5.5.5.5")}); err != nil { //对源ip为1.1.1.1的包加黑 logger.Error("ipset add error", zap.Error(err)) } if err = netlink.IpsetAdd(BL_IP_PORT, &netlink.IPSetEntry{IP: net.ParseIP("6.6.6.6"), Port: &port}); err != nil { //对源ip为2.2.2.2,目的端口为100的包加黑 logger.Error("ipset add error", zap.Error(err)) } if err = netlink.IpsetAdd(BL_NET, &netlink.IPSetEntry{IP: net.ParseIP("7.7.7.7"), CIDR: 24}); err != nil { //对源ip在3.3.3.3/24范围内的包加黑 logger.Error("ipset add error", zap.Error(err)) } if err = netlink.IpsetAdd(BL_NET_PORT, &netlink.IPSetEntry{IP: net.ParseIP("8.8.8.8"), CIDR: 24, Port: &port}); err != nil { //对源在4.4.4.4/24范围内,目的端口为100的包加黑 logger.Error("ipset add error", zap.Error(err)) }
根据不同的集合类型给netlink.IPSetEntry设置不同的参数。
【5】查看iptables
[root@xxx ~]# iptables -nL INPUT Chain INPUT (policy ACCEPT) target prot opt source destination ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 match-set wl_ip src ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 match-set wl_ip_port src,dst ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 match-set wl_net src ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 match-set wl_net_port src,dst ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 match-set bl_ip src ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 match-set bl_ip_port src,dst ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 match-set bl_net src ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 match-set bl_net_port src,dst [root@xxx ~]# iptables -S | grep INPUT -P INPUT ACCEPT -N SPA_HIDE_INPUT -N SPA_WL_INPUT -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -m set --match-set wl_ip src -j ACCEPT -A INPUT -m set --match-set wl_ip_port src,dst -j ACCEPT -A INPUT -m set --match-javascriptset wl_net src -j ACCEPT -A INPUT -m set --match-set wl_net_port src,dst -j ACCEPT -A INPUT -m set --match-set bl_ip src -j ACCEPT -A INPUT -m set --match-set bl_ip_port src,dst -j ACCEPT -A INPUT -m set --match-set bl_net src -j ACCEPT -A INPUT -m set --match-set bl_net_port src,dst -j ACCEPT
【6】查看ipset
[root@xxx ~]# ipset list Name: bl_ip Type: hash:ip Revision: 0 Header: family inet hashsize 1024 maxelem 65536 Size in memory: 16544 References: 1 Members: 5.5.5.5 Name: bl_ip_port Type: hash:ip,port Revision: 1 Header: family inet hashsize 1024 maxelem 65536 Size in memory: 16560 References: 1 Members: 6.6.6.6,tcp:100 Name: bl_net Type: hash:net Revision: 0 Header: family inet hashsize 1024 maxelem 65536 Size in memory: 16816 References: 1 Members: 7.7.7.0/24 Name: bl_net_port Type: hash:net,port Revision: 1 Header: family inet hashsize 1024 maxelem 65536 Size in memory: 16816 References: 1 Members: 8.8.8.0/24,tcp:100 Name: wl_ip Type: hash:ip Revision: 0 Header: family inet hashsize 1024 maxelem 65536 Size in memory: 16544 References: 1 Members: 1.1.1.1 Name: wl_ip_port Type: hash:ip,port Revision: 1 Header: family inet hashsize 1024 maxelem 65536 Size in memory: 16560 References: 1 Members: 2.2.2.2,tcp:100 Name: wl_net Type: hash:net Revision: 0 Header: family inet hashsize 1024 maxelem 65536 Size in memory: 16816 References: 1 Members: 3.3.3.0/24 Name: wl_net_port Type: hash:net,port Revision: 1 Header: family inet hashsize 1024 maxelem 65536 Size in memory: 16816 References: 1 Members: 4.4.4.0/24,tcp:100
5、总结
上面给出了一部分go的iptab编程les和ipset库的基础用法,在真实的业务场景中是可以做出很多优化,比如:黑白名单各自定义一条自定义链再追加到INPUT链去维护,这样黑白名单相互之间不会互相影响。
更多功能可以根据库里的API应用到适合的场景。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。
精彩评论