使用Golang管理IPTables的最佳实践

使用Golang管理IPTables的最佳实践 我有一个bash脚本:

firewall=$(  iptables --list OUTPUT --line-number )
if ! (echo “$firewall” | grep ‘DROP       all  –  color.centos.com’ > /dev/null); then
iptables -A OUTPUT  -s color.centos.com -j DROP
fi
if ! (echo “$firewall” | grep ‘DROP       all  –  color.centos.com’ > /dev/null); then
iptables -A OUTPUT  -s color.centos.com -j DROP
fi

我想过,但根据我的经验,我无法做到这一点 -_- 有人能帮助我吗?


更多关于使用Golang管理IPTables的最佳实践的实战教程也可以访问 https://www.itying.com/category-94-b0.html

21 回复

兄弟,这可能吗?

更多关于使用Golang管理IPTables的最佳实践的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


当然,这是可能的。你到目前为止尝试了什么?

是的,在 Go 语言中也是可以实现的。

先生,您能稍微解释一下我该如何使用 grep 吗?

我已经向你介绍过 strings 包了。里面有很多字符串处理的功能。

你现在具体还需要什么?

你有一个7行、小于1KB的shell脚本,它将变成一个50多行、大于2MB的Go程序。你为什么要用Go重写这个脚本?

先生,实际上我们正在开发一个程序。但如果我们用Bash编写,用户可以通过文件或进程查看代码。 我们想要一个编译后的文件,并且我们的代码不应该被泄露。

通常,除了 iptables 之外,你不会使用 exec.* 来处理任何事情,因为你可以直接在 Go 中完成,而无需使用 bash。

如果不使用 exec,我该如何实现?是否有相关的库或文档?

// 此部分为代码示例,实际内容需根据上下文填充
// 例如:一个用于管理iptables的Go函数框架
func manageIPTables() {
    // 实现通过Go语言管理iptables的逻辑
}

我是初学者兄弟 -_- 我没有找到像下面这样的解决方案: if ! (echo “$firewall” | grep ‘DROP all – color.centos.com’ > /dev/null); 我现在不在电脑旁,但我尝试过使用 exec.Command 来做,但没有成功。

2MB 不是问题。即使是 7-10MB 也不是问题。 我们想在大学提交项目,那里什么都不重要——只要工作能完成就行—— 在 bash 脚本中我们可以轻松完成,但这项工作应该用一种编译语言来完成。我们选择了 Go,但我搜索了很多,没有找到任何解决方案。

先生,您所说的“反向迭代那些行”是什么意思?😐

NobbZ: 检查该行是否包含模式

  • 如果包含模式,则移除该规则

先生,我们如何获取规则编号?

if 在 Go 语言中同样可用。

echo "$firewall" | grep '…' > /dev/null 这个命令会在存储在 $firewall 变量中的输入字符串里搜索给定的模式 ()。

这里没有必要调用 shell 命令…

// 示例代码块,语言已指定为 go

我已经向你解释了那个shell代码片段的作用,希望你能意识到你可以在Go语言内部完成这个操作,我甚至说过,对于那个代码片段,“没有必要调用shell”。

你可以使用 strings.Contains

然后,你可以使用 exec.Cmd/exec.Command 来编排所有 iptables 的执行,或者使用你喜欢的搜索引擎来寻找一个为你抽象化此操作的库。一个粗略的搜索就给了我大量的结果。

  1. iptables --list OUTPUT --line-number 的输出获取到一个字符串中。
  2. 将该字符串按 \n 分割成一个行的切片。
  3. 反向遍历这些行。
  4. 检查行是否包含特定模式
    • 如果包含该模式,则移除规则。
    • 如果不包含该模式,则什么也不做。

你在哪一步遇到了问题?你说这是为了大学课程,我不会替你完成作业。

var1 := "iptables"
var2 := "--list"
var3 := "OUTPUT"
var4 := "--line-number"
out, _ := exec.Command(var1, var2, var3, var4).Output()
s := regexp.MustCompile("\n").Split(string(out), -1)
for i := len(s); i <= 0; i-- {
fmt.Println(s[i])
}
}

我写了这些代码,但在 fmt.Println(s[i]) 这行没有得到任何输出。

你在bash中所做的一切,在Go中同样可以实现。你不需要提供示例并询问是否可能,答案永远是“是的”。

你真正想问的问题是“如何在Golang中实现这个”。

然后我们才能给你一个真正有帮助的答案。

当然,你的做法会有所不同。

在Golang中,你会使用少得多的管道,而是在Golang本身中进行等效的字符串操作和过滤。

例如,你会完整地获取iptables的输出,逐行遍历并应用正则表达式,然后将每一行匹配的行传递给一个函数,该函数执行你目前在循环中所做的事情。一般来说,除了iptables,你不会对任何东西使用exec.*,因为你可以在Go中直接完成,而无需使用bash。

func main() {
    fmt.Println("hello world")
}

在Go中管理iptables,推荐使用github.com/coreos/go-iptables库。以下是实现你需求的示例代码:

package main

import (
    "log"
    
    "github.com/coreos/go-iptables/iptables"
)

func main() {
    // 创建iptables实例
    ipt, err := iptables.New()
    if err != nil {
        log.Fatalf("Failed to initialize iptables: %v", err)
    }
    
    // 检查规则是否存在
    exists, err := ipt.Exists("filter", "OUTPUT", "-s", "color.centos.com", "-j", "DROP")
    if err != nil {
        log.Fatalf("Failed to check rule existence: %v", err)
    }
    
    // 如果规则不存在,则添加
    if !exists {
        err = ipt.Append("filter", "OUTPUT", "-s", "color.centos.com", "-j", "DROP")
        if err != nil {
            log.Fatalf("Failed to add rule: %v", err)
        }
        log.Println("Rule added successfully")
    } else {
        log.Println("Rule already exists")
    }
}

这个库提供了更可靠的方式来管理iptables规则,避免了通过字符串解析检查规则存在的不可靠性。

先生,我明白您的意思,但鉴于您经验更丰富、知识更渊博,能否告诉我具体该怎么做?比如能否提供一个示例?

在 Bash 中,这很容易。但在 Go 语言中,这很困难。 我想做的是,找出所有包含 *.CentOS.com 的 IPTables OUTPUT 规则, 然后获取每条规则的编号,并逐一删除这些规则。

例如,如果我运行 iptables --list OUTPUT --line-number | grep -E ‘*.centos.com’ 那么我会得到如下输出: 3 DROP all – color1.centos.com anywhere 4 DROP all – color2.centos.com anywhere 5 DROP all – color3.centos.com anywhere 6 DROP all – color4.centos.com anywhere 7 DROP all – color5.centos.com anywhere 8 DROP all – color6.centos.com anywhere

这里您可以看到,3、4、5、6、7、8 是规则编号。我想删除这些规则,但假设我们删除了规则 3,那么规则 4 会变成规则 3,规则 5 会变成规则 4,依此类推。 在 Bash 中,这很容易做到,但在 Go 语言中,我有点困惑 -_- 我来自 PHP 和 Bash 背景,所以对 Go 语言经验不多,请大家帮帮我。

monsterlegend99:

先生,您说的“反向迭代那些行”是什么意思?

反向迭代,即从后往前遍历。这样你可以从末尾开始删除,而不会影响你后续将要遍历的索引。

monsterlegend99:

先生,我们如何获取规则编号?

根据你提供的所有示例来看,“规则编号”似乎是第一个空格之前的所有内容。所以,在空格处分割该行,然后取结果数组的第一个元素。

所做的事情与在bash中并无不同,只是你使用了Go的函数来实现。

你不用修改 IFS,而是使用 strings.Splitstrings.SplitN

另外,我已经多次链接了相关文档,我希望你至少能浅显地阅读一下链接的内容,并在后续提问时附上一些代码,展示你尝试了什么以及哪里不理解。

以下可能对本主题有帮助:

好的,明白了,谢谢。 现在还有一个问题 -_-

输出

ProccessID=$( iptables --list OUTPUT --line-number | grep -E '*.centos.com'  )
SAVEIFS=$IFS   # 保存当前IFS
IFS=$'\n'      # 将IFS更改为换行符
ProccessID=($ProccessID) # 分割为数组 $names
IFS=$SAVEIFS   # 恢复IFS
for (( i=0; i<${#ProccessID[@]}; i++ ))
do
    currentID=$( echo "$ProccessID[$i]" |  head -n1 | awk '{print $1;}' )
    iptables -D OUTPUT $currentID
done
## 输入
ProccessID=$( iptables --list INPUT --line-number | grep -E '*.centos.com'  )
SAVEIFS=$IFS   # 保存当前IFS
IFS=$'\n'      # 将IFS更改为换行符
ProccessID=($ProccessID) # 分割为数组 $names
IFS=$SAVEIFS   # 恢复IFS
for (( i=0; i<${#ProccessID[@]}; i++ ))
do
    currentID=$( echo "$ProccessID[$i]" |  head -n1 | awk '{print $1;}' )
    iptables -D INPUT $currentID
done

这在 Go 语言中也能实现吗?

回到顶部