From 1a3f513741013571e2487337bae8db5fd8e25e03 Mon Sep 17 00:00:00 2001 From: zxb <919411476@qq.com> Date: Fri, 3 Nov 2023 10:31:11 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=84=E5=88=99=E6=B7=BB=E5=8A=A0=E4=B8=8E?= =?UTF-8?q?=E5=88=A0=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docs.go | 107 +++++++++++++++++++++++++++++- docs/swagger.json | 107 +++++++++++++++++++++++++++++- docs/swagger.yaml | 65 +++++++++++++++++- internel/controller/controller.go | 48 +++++++++++++- pkg/utils/command/command.go | 7 +- pkg/utils/iptables/flag_test.go | 2 +- pkg/utils/iptables/handler.go | 74 +++++++++++++++++++++ pkg/utils/iptables/iptables.go | 4 +- pkg/utils/iptables/parser.go | 1 + 9 files changed, 404 insertions(+), 11 deletions(-) create mode 100644 pkg/utils/iptables/handler.go diff --git a/docs/docs.go b/docs/docs.go index 96bb43f..8124a44 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -107,6 +107,108 @@ const docTemplate = `{ } } } + }, + "/rule/add": { + "post": { + "description": "添加 iptables 规则", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Info" + ], + "summary": "添加 iptables 规则", + "parameters": [ + { + "description": "规则", + "name": "vo", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/iptables.Rule" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/resp.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "string" + } + } + } + ] + } + }, + "default": { + "description": "", + "schema": { + "$ref": "#/definitions/errorx.CodeErrorResponse" + } + } + } + } + }, + "/rule/del/cmd": { + "delete": { + "description": "删除 iptables 规则", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Info" + ], + "summary": "删除 iptables 规则", + "parameters": [ + { + "type": "string", + "description": "根据 cmd 命令参数 删除指定规则", + "name": "cmd", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/resp.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "string" + } + } + } + ] + } + }, + "default": { + "description": "", + "schema": { + "$ref": "#/definitions/errorx.CodeErrorResponse" + } + } + } + } } }, "definitions": { @@ -168,6 +270,9 @@ const docTemplate = `{ "chain": { "type": "string" }, + "cmd": { + "type": "string" + }, "destination": { "description": "-d [dest] example: 192.168.1.1, 192.168.1.0/24", "type": "string" @@ -181,7 +286,7 @@ const docTemplate = `{ "type": "string" }, "excludeDestination": { - "description": "! -s [source] example: 192.168.1.1, 192.168.1.0/24", + "description": "! -d [source] example: 192.168.1.1, 192.168.1.0/24", "type": "string" }, "excludeInputInterface": { diff --git a/docs/swagger.json b/docs/swagger.json index 8469e56..3b4e6a9 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -100,6 +100,108 @@ } } } + }, + "/rule/add": { + "post": { + "description": "添加 iptables 规则", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Info" + ], + "summary": "添加 iptables 规则", + "parameters": [ + { + "description": "规则", + "name": "vo", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/iptables.Rule" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/resp.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "string" + } + } + } + ] + } + }, + "default": { + "description": "", + "schema": { + "$ref": "#/definitions/errorx.CodeErrorResponse" + } + } + } + } + }, + "/rule/del/cmd": { + "delete": { + "description": "删除 iptables 规则", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Info" + ], + "summary": "删除 iptables 规则", + "parameters": [ + { + "type": "string", + "description": "根据 cmd 命令参数 删除指定规则", + "name": "cmd", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/resp.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "string" + } + } + } + ] + } + }, + "default": { + "description": "", + "schema": { + "$ref": "#/definitions/errorx.CodeErrorResponse" + } + } + } + } } }, "definitions": { @@ -161,6 +263,9 @@ "chain": { "type": "string" }, + "cmd": { + "type": "string" + }, "destination": { "description": "-d [dest] example: 192.168.1.1, 192.168.1.0/24", "type": "string" @@ -174,7 +279,7 @@ "type": "string" }, "excludeDestination": { - "description": "! -s [source] example: 192.168.1.1, 192.168.1.0/24", + "description": "! -d [source] example: 192.168.1.1, 192.168.1.0/24", "type": "string" }, "excludeInputInterface": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index b8a9dab..2977f71 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -39,6 +39,8 @@ definitions: properties: chain: type: string + cmd: + type: string destination: description: '-d [dest] example: 192.168.1.1, 192.168.1.0/24' type: string @@ -49,7 +51,7 @@ definitions: description: '--dports example: 45000:46000' type: string excludeDestination: - description: '! -s [source] example: 192.168.1.1, 192.168.1.0/24' + description: '! -d [source] example: 192.168.1.1, 192.168.1.0/24' type: string excludeInputInterface: description: '! -i [interface]' @@ -197,4 +199,65 @@ paths: summary: 获取 iptables 规则 信息 tags: - Info + /rule/add: + post: + consumes: + - application/json + description: 添加 iptables 规则 + parameters: + - description: 规则 + in: body + name: vo + required: true + schema: + $ref: '#/definitions/iptables.Rule' + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/resp.Response' + - properties: + data: + type: string + type: object + default: + description: "" + schema: + $ref: '#/definitions/errorx.CodeErrorResponse' + summary: 添加 iptables 规则 + tags: + - Info + /rule/del/cmd: + delete: + consumes: + - application/json + description: 删除 iptables 规则 + parameters: + - description: 根据 cmd 命令参数 删除指定规则 + in: query + name: cmd + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/resp.Response' + - properties: + data: + type: string + type: object + default: + description: "" + schema: + $ref: '#/definitions/errorx.CodeErrorResponse' + summary: 删除 iptables 规则 + tags: + - Info swagger: "2.0" diff --git a/internel/controller/controller.go b/internel/controller/controller.go index 1f77e20..79461d5 100644 --- a/internel/controller/controller.go +++ b/internel/controller/controller.go @@ -4,6 +4,7 @@ import ( "github.com/gofiber/fiber/v2" "github.com/shirou/gopsutil/net" response "iptables-helper/pkg/resp" + "iptables-helper/pkg/resp/errorx" "iptables-helper/pkg/utils/command" "iptables-helper/pkg/utils/iptables" ) @@ -11,6 +12,8 @@ import ( func SetupController(r fiber.Router) { api := r.Group("/") getRuleInfo(api) + addRule(api) + delRule(api) getIfInfo(api) } @@ -26,11 +29,54 @@ func SetupController(r fiber.Router) { func getRuleInfo(api fiber.Router) { api.Get("/info", func(ctx *fiber.Ctx) error { cmder := command.Commander{} - result := cmder.ExecuteWithResult("sudo iptables -S") + result, _ := cmder.ExecuteWithResult("sudo iptables -S") return ctx.JSON(response.NewResponse(iptables.Parse(result))) }) } +// addRule +// @Summary 添加 iptables 规则 +// @Description 添加 iptables 规则 +// @Tags Info +// @Accept json +// @Produce json +// @Param vo body iptables.Rule true "规则" +// @Success 200 {object} response.Response{data=string} +// @Failure default {object} errorx.CodeErrorResponse +// @Router /rule/add [post] +func addRule(api fiber.Router) { + api.Post("/rule/add", func(ctx *fiber.Ctx) error { + rule := &iptables.Rule{} + _ = ctx.BodyParser(rule) + if err := errorx.ParseError(iptables.AddRule(*rule)); err != nil { + return ctx.JSON(err) + } else { + return ctx.JSON(response.NewResponse("")) + } + }) +} + +// delRule +// @Summary 删除 iptables 规则 +// @Description 删除 iptables 规则 +// @Tags Info +// @Accept json +// @Produce json +// @Param cmd query string true "根据 cmd 命令参数 删除指定规则" +// @Success 200 {object} response.Response{data=string} +// @Failure default {object} errorx.CodeErrorResponse +// @Router /rule/del/cmd [delete] +func delRule(api fiber.Router) { + api.Delete("/rule/del/cmd", func(ctx *fiber.Ctx) error { + cmd := ctx.Query("cmd") + if err := errorx.ParseError(iptables.DelRuleByCmd(cmd)); err != nil { + return ctx.JSON(err) + } else { + return ctx.JSON(response.NewResponse("")) + } + }) +} + // getIfInfo // @Summary 获取 网卡 信息 // @Description 获取 网卡 信息 diff --git a/pkg/utils/command/command.go b/pkg/utils/command/command.go index 0d77294..1137b84 100644 --- a/pkg/utils/command/command.go +++ b/pkg/utils/command/command.go @@ -50,7 +50,7 @@ func (c *Commander) Execute(command string) { } } -func (c *Commander) ExecuteWithResult(command string) string { +func (c *Commander) ExecuteWithResult(command string) (string, error) { command = strings.TrimSpace(command) commands := strings.SplitN(command, " ", 2) order := commands[0] @@ -77,8 +77,5 @@ func (c *Commander) ExecuteWithResult(command string) string { cmd := exec.Command(order, args...) out, err := cmd.Output() - if err != nil { - panic(err) - } - return string(out) + return string(out), err } diff --git a/pkg/utils/iptables/flag_test.go b/pkg/utils/iptables/flag_test.go index a944c15..459581a 100644 --- a/pkg/utils/iptables/flag_test.go +++ b/pkg/utils/iptables/flag_test.go @@ -9,7 +9,7 @@ import ( func TestFlag(t *testing.T) { cmder := command.Commander{} - result := cmder.ExecuteWithResult("sudo iptables -S") + result, _ := cmder.ExecuteWithResult("sudo iptables -S") Parse(result) } diff --git a/pkg/utils/iptables/handler.go b/pkg/utils/iptables/handler.go new file mode 100644 index 0000000..89c5c96 --- /dev/null +++ b/pkg/utils/iptables/handler.go @@ -0,0 +1,74 @@ +package iptables + +import ( + "iptables-helper/pkg/resp/errorx" + "iptables-helper/pkg/utils/command" + "strings" +) + +func appendArgs[T string | Chain | PolicyTarget | Action](args []string, argField string, argValue T) []string { + value := strings.TrimSpace(string(argValue)) + if len(value) <= 0 { + return args + } + args = append(args, argField, value) + return args +} + +func appendArgsWithError[T string | Chain | PolicyTarget | Action](args []string, argField string, argValue T, err error) ([]string, error) { + value := strings.TrimSpace(string(argValue)) + if len(value) <= 0 && err != nil { + return args, err + } + args = append(args, argField, value) + return args, nil +} + +func AddRule(rule Rule) error { + var err error + args := make([]string, 0) + + if args, err = appendArgsWithError(args, "-A", rule.Chain, errorx.NewDefaultError("规则链 Chain 不能为空")); err != nil { + return err + } + + args = appendArgs(args, "-j", rule.Jump) + args = appendArgs(args, "-g", rule.Goto) + + args = appendArgs(args, "-i", rule.InputInterface) + args = appendArgs(args, "! -i", rule.ExcludeInputInterface) + + args = appendArgs(args, "-o", rule.OutputInterface) + args = appendArgs(args, "! -o", rule.ExcludeOutputInterface) + + args = appendArgs(args, "-s", rule.Source) + args = appendArgs(args, "! -s", rule.ExcludeSource) + + args = appendArgs(args, "-d", rule.Destination) + args = appendArgs(args, "! -d", rule.ExcludeDestination) + + args = appendArgs(args, "-p", rule.Protocol) + args = appendArgs(args, "! -p", rule.ExcludeProtocol) + + args = appendArgs(args, "-m", rule.Match) + + args = appendArgs(args, "--sport", rule.SrcPort) + args = appendArgs(args, "--sports", rule.SrcPorts) + + args = appendArgs(args, "--dport", rule.DstPort) + args = appendArgs(args, "--dports", rule.DstPorts) + + args = appendArgs(args, "--limit", rule.Limit) + + cmd := command.Commander{} + _, err = cmd.ExecuteWithResult("sudo iptables " + strings.Join(args, " ")) + return err +} + +func DelRuleByCmd(cmd string) error { + cmd = strings.Split(cmd, ";")[0] + cmd = strings.Split(cmd, "&")[0] + commander := command.Commander{} + _, err := commander.ExecuteWithResult("sudo iptables -D " + cmd) + return err +} diff --git a/pkg/utils/iptables/iptables.go b/pkg/utils/iptables/iptables.go index 48ed59b..ad7676e 100644 --- a/pkg/utils/iptables/iptables.go +++ b/pkg/utils/iptables/iptables.go @@ -44,7 +44,7 @@ type Rule struct { // -d [dest] example: 192.168.1.1, 192.168.1.0/24 Destination string `json:"destination"` - // ! -s [source] example: 192.168.1.1, 192.168.1.0/24 + // ! -d [source] example: 192.168.1.1, 192.168.1.0/24 ExcludeDestination string `json:"excludeDestination"` // -p [proto] example: all, tcp, udp, icmp @@ -66,6 +66,8 @@ type Rule struct { // --limit example: 3/min Limit string `json:"limit"` + + Cmd string `json:"cmd"` } type Info struct { diff --git a/pkg/utils/iptables/parser.go b/pkg/utils/iptables/parser.go index d00988c..980216b 100644 --- a/pkg/utils/iptables/parser.go +++ b/pkg/utils/iptables/parser.go @@ -117,6 +117,7 @@ func Parse(rules string) Info { DstPorts: *dstPorts, Limit: *limit, + Cmd: strings.Replace(rule, "-A ", "", 1), } ruleList = append(ruleList, r) } else {