diff --git a/.air.linux.toml b/.air.linux.toml deleted file mode 100644 index 9488443..0000000 --- a/.air.linux.toml +++ /dev/null @@ -1,42 +0,0 @@ -root = "." -testdata_dir = "testdata" -tmp_dir = "tmp" - -[build] - args_bin = [] - bin = "tmp\\main.exe" - cmd = "go build -o ./tmp/main ." - delay = 1500 - exclude_dir = ["assets", "tmp", "vendor", "testdata"] - exclude_file = [] - exclude_regex = ["_test.go"] - exclude_unchanged = false - follow_symlink = false - full_bin = "" - include_dir = [] - include_ext = ["go", "tpl", "tmpl", "html"] - include_file = [] - kill_delay = "0s" - log = "build-errors.log" - rerun = false - rerun_delay = 500 - send_interrupt = true - stop_on_error = false - -[color] - app = "" - build = "yellow" - main = "magenta" - runner = "green" - watcher = "cyan" - -[log] - main_only = false - time = false - -[misc] - clean_on_exit = false - -[screen] - clear_on_rebuild = false - keep_scroll = true diff --git a/.air.toml b/.air.toml index 31e2bb1..77d714f 100644 --- a/.air.toml +++ b/.air.toml @@ -4,8 +4,8 @@ tmp_dir = "tmp" [build] args_bin = [] - bin = "tmp\\main.exe" - cmd = "go build -o ./tmp/main.exe ." + bin = "tmp/main" + cmd = "go build -o ./tmp/main ." delay = 1500 exclude_dir = ["assets", "tmp", "vendor", "testdata"] exclude_file = [] diff --git a/.idea/misc.xml b/.idea/misc.xml index 639900d..6e86672 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - diff --git a/go.mod b/go.mod index df127f9..ba571af 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,12 @@ module iptables-helper go 1.18 require ( + github.com/fsnotify/fsnotify v1.6.0 github.com/gofiber/fiber/v2 v2.50.0 github.com/gofiber/swagger v0.1.14 github.com/pelletier/go-toml/v2 v2.1.0 github.com/spf13/viper v1.17.0 + github.com/swaggo/swag v1.16.2 go.uber.org/atomic v1.11.0 go.uber.org/zap v1.26.0 ) @@ -16,7 +18,6 @@ require ( github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/andybalholm/brotli v1.0.5 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.19.6 // indirect github.com/go-openapi/spec v0.20.4 // indirect @@ -40,7 +41,6 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/swaggo/files/v2 v2.0.0 // indirect - github.com/swaggo/swag v1.16.2 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.50.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect diff --git a/pkg/utils/command/command.go b/pkg/utils/command/command.go new file mode 100644 index 0000000..0d77294 --- /dev/null +++ b/pkg/utils/command/command.go @@ -0,0 +1,84 @@ +package command + +import ( + "iptables-helper/pkg/logger" + "os" + "os/exec" + "regexp" + "strings" +) + +var log = logger.Log() + +type Command interface { + execute(command string) (string, error) +} + +type Commander struct { +} + +func (c *Commander) Execute(command string) { + command = strings.TrimSpace(command) + commands := strings.SplitN(command, " ", 2) + order := commands[0] + + var args []string + if len(commands) > 1 { + argStr := commands[1] + + reg, _ := regexp.Compile("[^\\s\"']+|\"[^\"]*\"|'[^']*'") + tmp := reg.FindAllString(argStr, -1) + + for _, arg := range tmp { + // 双引号 则 去除 以用于 cmd /c 或 /bin/sh -c 传入字符串命令/参数使用 + // 单引号 则 不去除 按普通参数处理 + if strings.HasPrefix(arg, "\"") && strings.HasSuffix(arg, "\"") { + args = append(args, arg[1:len(arg)-1]) + } else { + args = append(args, arg) + } + } + } + + log.Infof("[+] 执行命令 %s %v\n", order, args) + cmd := exec.Command(order, args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err := cmd.Run() + if err != nil { + panic(err) + } +} + +func (c *Commander) ExecuteWithResult(command string) string { + command = strings.TrimSpace(command) + commands := strings.SplitN(command, " ", 2) + order := commands[0] + + var args []string + if len(commands) > 1 { + argStr := commands[1] + + reg, _ := regexp.Compile("[^\\s\"']+|\"[^\"]*\"|'[^']*'") + tmp := reg.FindAllString(argStr, -1) + + for _, arg := range tmp { + // 双引号 则 去除 以用于 cmd /c 或 /bin/sh -c 传入字符串命令/参数使用 + // 单引号 则 不去除 按普通参数处理 + if strings.HasPrefix(arg, "\"") && strings.HasSuffix(arg, "\"") { + args = append(args, arg[1:len(arg)-1]) + } else { + args = append(args, arg) + } + } + } + + log.Infof("[+] 执行命令 %s %v\n", order, args) + cmd := exec.Command(order, args...) + + out, err := cmd.Output() + if err != nil { + panic(err) + } + return string(out) +} diff --git a/pkg/utils/iptables/flag_test.go b/pkg/utils/iptables/flag_test.go new file mode 100644 index 0000000..e6513b0 --- /dev/null +++ b/pkg/utils/iptables/flag_test.go @@ -0,0 +1,77 @@ +package iptables + +import ( + "fmt" + flag "github.com/spf13/pflag" + "iptables-helper/pkg/logger" + "iptables-helper/pkg/utils/command" + "strings" + "testing" +) + +func TestFlag(t *testing.T) { + cmder := command.Commander{} + result := cmder.ExecuteWithResult("sudo iptables -S") + results := strings.Split(result, "\n") + + policyList := make([]Policy, 0) + chainList := make([]Chain, 0) + + for _, rule := range results { + logger.Log().Debug("解析规则: ", rule) + + //rule := "-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER" + // 转化以便解析 + rule = strings.ReplaceAll(rule, " ! ", " -! ") + + flagSet := flag.FlagSet{} + flagSet.ParseErrorsWhitelist = flag.ParseErrorsWhitelist{UnknownFlags: true} + + var reverse bool + var dst string + + // 优先解析/判断 P N A 三个基本类型 + var policy string + // 策略 + flagSet.StringVarP(&policy, "policy", "P", "", "") + var appendRule string + // 追加规则 + flagSet.StringVarP(&appendRule, "append", "A", "", "") + var newChain string + // 创建自定义规则链 + flagSet.StringVarP(&newChain, "new-chain", "N", "", "") + + flagSet.BoolVarP(&reverse, "!", "!", false, "") + flagSet.StringVarP(&dst, "destination", "d", "", "") + + _ = flagSet.Parse(strings.Split(rule, " ")) + + if len(policy) > 0 { + target := flagSet.Arg(0) + logger.Log().Infof("默认策略 %+v %+v", policy, target) + chain := Chain(policy) + chainList = append(chainList, chain) + policyList = append(policyList, Policy{chain, PolicyTarget(target)}) + continue + } + + if len(newChain) > 0 { + chainList = append(chainList, Chain(newChain)) + continue + } + + //logger.Log().Debugf("appendRule %+v", appendRule) + //logger.Log().Debugf("reverse %+v", reverse) + } + + for i := 0; i < 50; i++ { + fmt.Print("=") + } + fmt.Println() + for _, policy := range policyList { + logger.Log().Infof("默认策略: %s => %s", policy.Name, policy.Target) + } + for _, chain := range chainList { + logger.Log().Infof("自定义规则链: %s", chain) + } +} diff --git a/pkg/utils/iptables/iptables.go b/pkg/utils/iptables/iptables.go new file mode 100644 index 0000000..47d1833 --- /dev/null +++ b/pkg/utils/iptables/iptables.go @@ -0,0 +1,23 @@ +package iptables + +var ( + ACCEPT Action = "ACCEPT" + DROP Action = "DROP" +) + +type Action string +type PolicyTarget string + +type Table string + +type Policy struct { + Name Chain `json:"name"` + Target PolicyTarget `json:"target"` +} + +type Chain string + +type Rule struct { + Chain Chain `json:"chain"` + Jump Chain `json:"jump"` +} diff --git a/pkg/utils/iptables/policy/policy.go b/pkg/utils/iptables/policy/policy.go new file mode 100644 index 0000000..e9a38f3 --- /dev/null +++ b/pkg/utils/iptables/policy/policy.go @@ -0,0 +1,6 @@ +package policy + +import "iptables-helper/pkg/utils/iptables" + +var ACCEPT iptables.PolicyTarget = iptables.PolicyTarget(iptables.ACCEPT) +var DROP iptables.PolicyTarget = iptables.PolicyTarget(iptables.DROP) diff --git a/pkg/utils/iptables/table/table.go b/pkg/utils/iptables/table/table.go new file mode 100644 index 0000000..3d4b3ed --- /dev/null +++ b/pkg/utils/iptables/table/table.go @@ -0,0 +1,14 @@ +package table + +import "iptables-helper/pkg/utils/iptables" + +const DEFAULT iptables.Table = FILTER +const FILTER iptables.Table = "filter" + +const NAT iptables.Table = "nat" + +const MANGLE iptables.Table = "mangle" + +const RAW iptables.Table = "raw" + +const SECURITY iptables.Table = "security"