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

 更新时间:2025年06月25日 10:46:15   作者:在成都搬砖的鸭鸭  
这篇文章主要介绍了如何用go操作iptables和ipset设置黑白名单问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

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       = "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_ip_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"), CIDR: 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-set 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的iptables和ipset库的基础用法,在真实的业务场景中是可以做出很多优化,比如:黑白名单各自定义一条自定义链再追加到INPUT链去维护,这样黑白名单相互之间不会互相影响。

更多功能可以根据库里的API应用到适合的场景。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 一键定位Golang线上服务内存泄露的秘籍

    一键定位Golang线上服务内存泄露的秘籍

    内存泄露?别让它拖垮你的Golang线上服务!快速掌握Go语言服务内存泄漏排查秘籍,从此问题无处遁形,一文读懂如何精准定位与有效解决Golang应用中的内存问题,立即阅读,让性能飞升!
    2024-01-01
  • Go 语言中静态类型和动态类型的使用

    Go 语言中静态类型和动态类型的使用

    本文主要介绍了Go语言中的静态类型和动态类型,静态类型在编译时确定,提供了类型安全,性能优化和代码清晰,而动态类型在运行时确定,提供了更高的灵活性,但可能引发运行时错误,下面就来介绍一下,感兴趣的可以了解一下
    2024-10-10
  • 一文带大家搞懂Go语言中的迭代器

    一文带大家搞懂Go语言中的迭代器

    迭代器是使用户可在容器对象上遍访的对象,设计人员使用此接口无需关心容器对象的内存分配的实现细节,本文主要为大家详细介绍一下Go语言中的迭代器的实现,需要的可以了解下
    2025-02-02
  • Windows+Linux系统下Go语言环境安装配置过程

    Windows+Linux系统下Go语言环境安装配置过程

    Go 语言被设计成一门应用于搭载 Web 服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。这篇文章主要介绍了Windows+Linux系统下Go语言环境搭建配置过程,针对每种系统给大家讲解的非常详细,需要的朋友可以参考下
    2021-06-06
  • Go type关键字(类型定义与类型别名的使用差异)用法实例探究

    Go type关键字(类型定义与类型别名的使用差异)用法实例探究

    这篇文章主要为大家介绍了Go type关键字(类型定义与类型别名的使用差异)用法实例探究,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • Go 防止 goroutine 泄露的方法

    Go 防止 goroutine 泄露的方法

    Go 的并发模型与其他语言不同,虽说它简化了并发程序的开发难度,但如果不了解使用方法,常常会遇到 goroutine 泄露的问题。本篇主要从如何写出正确代码的角度来介绍如何防止 goroutine 的泄露,需要的朋友可以参考下
    2019-09-09
  • 详解Golang中gcache模块的基本使用

    详解Golang中gcache模块的基本使用

    这篇文章主要通过结合商业项目的使用场景,为大家介绍了gcache的基本使用、缓存控制以及淘汰策略。使用gcache做缓存处理,简单方便易上手
    2022-11-11
  •  Go 语言实现 HTTP 文件上传和下载

     Go 语言实现 HTTP 文件上传和下载

    这篇文章主要介绍了Go语言实现HTTP文件上传和下载,文章围绕主题展开详细的内容戒杀,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • Go语言实现请求超时处理的方法总结

    Go语言实现请求超时处理的方法总结

    这篇文章主要为大家详细介绍了Go语言中实现请求的超时控制的方法,主要是通过timer和timerCtx来实现请求的超时控制,希望对大家有所帮助
    2023-05-05
  • go语言实现短信发送实例探究

    go语言实现短信发送实例探究

    这篇文章主要为大家介绍了go语言实现短信发送实例探究,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01

最新评论