如何用go操作iptables和ipset設置黑白名單
1、背景
iptables是linux中一個比較好用的防火墻工具,可以通過它對網(wǎng)絡數(shù)據(jù)包進行管理和過濾,iptables中的四表五鏈在網(wǎng)上能查到很多文章解釋,這里不做過多解釋。
ipset是一個用于管理IP地址集合的工具,能和iptables組合起來一起使用,方便維護和管理各種防火墻規(guī)則。
本文會給出一個通過go庫操作iptables中filter表的INPUT鏈和ipset來實現(xiàn)允許和拒絕進入本機ipv4網(wǎng)絡數(shù)據(jù)包的示例。
2、go庫下載
【1】iptables下載
go get -u github.com/coreos/go-iptables
【2】ipset下載
go get -u github.com/vishvananda/netlink
3、go庫和命令行對比
| 操作方式 | 優(yōu)點 | 缺點 |
|---|---|---|
| 命令行操作 | 簡單方便 | 平臺架構版本兼容性差,復雜場景靈活性差 |
| go庫操作 | 平臺兼容性強,復雜場景靈活性高 | 需要花時間驗證庫的正確性 |
4、代碼示例
【1】定義iptables規(guī)則和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規(guī)則
var iptRules = [][]string{
{"-m", "state", "--state", "ESTABLISHED,RELATED", "-j", "ACCEPT"}, //已建連接允許
{"-i", "lo", "-j", "ACCEPT"}, //本地回環(huán)包運行
{"-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網(wǎng)口的數(shù)據(jù)包放行,兩條規(guī)則分別為:
1、iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 2、iptables -A INPUT -i lo -j ACCEPT
默認在filter表上增加規(guī)則,也可以增加-t指定其它表
【2】創(chuàng)建ipset集合
//創(chuàng)建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中可以定義其它自定義參數(shù),比如:超時時間、ipv4/ipv6、最大個數(shù)、是否覆蓋已存在的集合等。
【3】創(chuàng)建iptables規(guī)則
//創(chuàng)建iptables規(guī)則
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函數(shù)是往指定鏈中追加規(guī)則,如果規(guī)則存在就不會去做操作。
【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))
}
根據(jù)不同的集合類型給netlink.IPSetEntry設置不同的參數(shù)。
【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庫的基礎用法,在真實的業(yè)務場景中是可以做出很多優(yōu)化,比如:黑白名單各自定義一條自定義鏈再追加到INPUT鏈去維護,這樣黑白名單相互之間不會互相影響。
更多功能可以根據(jù)庫里的API應用到適合的場景。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Windows+Linux系統(tǒng)下Go語言環(huán)境安裝配置過程
Go 語言被設計成一門應用于搭載 Web 服務器,存儲集群或類似用途的巨型中央服務器的系統(tǒng)編程語言。這篇文章主要介紹了Windows+Linux系統(tǒng)下Go語言環(huán)境搭建配置過程,針對每種系統(tǒng)給大家講解的非常詳細,需要的朋友可以參考下2021-06-06
Go type關鍵字(類型定義與類型別名的使用差異)用法實例探究
這篇文章主要為大家介紹了Go type關鍵字(類型定義與類型別名的使用差異)用法實例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2024-01-01

