开发者

如何用go操作iptables和ipset设置黑白名单

开发者 https://www.devze.com 2025-06-28 11:19 出处:网络 作者: 在成都搬砖的鸭鸭
目录1、背景2、go库下载3、go库和命令行对比4、代码示例【1】定义iptables规则和ipset集合名称常量【2】创建ipset集合【3】创建iptables规则【4】添加条目【5】查看iptables【6】查看ipset5、总结1、背景
目录
  • 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)。

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    关注公众号