添加防火墙(Firewall/Iptables)规则

本文介绍了如何使用iptables命令行方式及配置文件来设置网络规则,包括添加、保存、重启及检查iptables规则。同时,还详细讲解了通过firewall-cmd命令进行防火墙状态查询、端口开放与关闭的方法。

1. iptables

    --    命令方式添加

添加 iptables -I INPUT -p tcp  --dport 8080 -j ACCEPT

保存 /etc/init.d/iptables save

重启 service iptables restart

检查 /etc/init.d/iptables status

    --    修改配置文件添加 /etc/sysconfig/iptables

-A INPUT -p tcp -m tcp --dport 8080 -j ACCEPT

2. firewall

查看防火墙状态    firewall-cmd --state

开启/关闭防火墙   systemctl start/stop firewalld.service

查看开放的端口    firewall-cmd --list-ports

添加防火墙端口    firewall-cmd --zone=public --add-ports=8080/tcp --permanent

删除防火墙端口    firewall-cmd --zone=public --remove-ports=8080/tcp --permanent        

添加/删除端口后执行    firewall-cmd --reload    生效


<think>我们使用Gin框架来实现这个防火墙管理的客户端。由于需要管理防火墙,我们将支持多种防火墙管理工具(如ufw),但为了简化,我们主要考虑ufw,并设计可扩展的结构。 考虑到需求,我们需要实现以下功能: 1. 启动时拉取本机的防火墙配置到内存(这里我们假设使用ufw,并且通过ufw status命令获取当前规则) 2. 提供RESTful API进行增删改查 3. 日志记录 4. 支持多个规则动作(ACCEPT, DROP, ALLOW, DENY)等(注意:ufw中ALLOW和ACCEPT是等价的,DENY和DROP是等价的) 5. 支持单个或多个IP(CIDR格式) 6. 支持多种协议(tcp, udp, 以及一些应用协议如imap,但ufw支持应用协议,我们也可以支持,但注意ufw的应用协议实际上是预定义的一组端口和协议) 7. 不考虑IPv6 8. 在修改规则后重载防火墙配置(对于ufw,修改后需要启用ufw reload?实际上,ufw在添加规则后需要应用,但通常我们每次修改后执行reload) 注意:在Docker容器中运行此程序时,需要以特权模式运行(因为要操作防火墙),并且需要安装ufw(如果使用ufw的话)。在WSL中,我们同样需要安装ufw。 设计思路: 1. 我们将构建一个内存中的防火墙规则列表,每次启动时从ufw中读取规则并解析成结构体。 2. 规则结构体定义如下: type FirewallRule struct { ID int `json:"id"` // 规则ID(在ufw中,规则有明确的ID,我们可以通过规则内容生成一个哈希作为ID,或者使用序号?) Port int `json:"port"` // 端口 Protocol string `json:"protocol"` // 协议:tcp, udp, 或者应用协议(如imap) Action string `json:"action"` // 动作:ALLOW, DENY, ACCEPT, DROP(注意:在ufw中,我们使用ALLOW和DENY) Chain string `json:"chain"` // 链:INPUT, OUTPUT, FORWARD(在ufw中,我们通常只指定方向:in, out, 或者不指定(双向)?) SourceIPs []string `json:"source_ips"` // 源IP列表 } 但是注意:ufw的规则格式可能是这样的: To Action From -- ------ ---- 3306/tcp ALLOW 192.168.0.0/24 3306/tcp ALLOW 10.0.0.1 所以,一条规则可能对应多个来源IP。在内存中,我们可以将相同端口、协议、动作、链的规则合并为一条,包含多个source_ips。但是ufw实际上每条规则只允许一个来源(每个来源都是一条独立的规则)。因此,在添加多个来源时,我们需要拆分成多条规则。 3. 我们设计一个防火墙管理接口,以便未来扩展支持其他工具(如firewalld, iptables等)。这里我们先实现ufw。 4. 日志模块:使用logrus或者zap,这里为了简单,使用logrus。 5. 操作步骤: - 启动时,调用ufw status命令(需要sudo权限?),解析规则,加载到内存。 - 提供API,当有增删改查时,更新内存,并调用ufw命令更新实际规则(然后重载)。 6. 注意:ufw命令需要root权限,所以运行此程序需要root权限(或者配置sudo免密)。 7. 关于规则ID:由于ufw有ID,我们可以为每条规则生成一个唯一ID(比如使用规则内容的哈希值),但这样在规则内容修改后ID会变。或者我们可以在内存中维护一个自增ID,但这样重启后ID会重置。这里我们使用规则内容的哈希(MD5)作为ID,这样相同内容的规则会有相同的ID,但注意:如果规则内容完全相同,那么就是同一条规则,我们不允许重复添加。 8. 在添加规则时,我们可能需要将一条规则(包含多个source_ips)拆分成多条规则(每个source_ip一条)。同样,在删除和修改时,我们也要注意。 9. 修改规则:由于规则在ufw中是独立的,我们修改规则时,需要先删除旧的规则(根据ID找到旧的规则内容),然后添加新的规则(同样可能拆分成多条)。 10. 重载配置:在修改规则后,我们需要执行`ufw reload`来使规则生效。 实现步骤: 1. 定义规则结构体 2. 定义防火墙管理接口 3. 实现ufw的管理器 4. 使用Gin提供RESTful API 5. 日志记录 由于代码较长,我们将分模块实现。 注意:在Docker容器化开发时,我们需要在Dockerfile中安装ufw和go环境,并且以特权模式运行。 下面我们开始编写代码:</think>下面我将使用Go和Gin框架实现一个服务防火墙管理的客户端,支持多工具管理(UFW)、多规则操作和容器化部署。 ### 解决方案设计 1. **架构**:Gin Web服务 + UFW命令封装 + 内存规则缓存 2. **核心组件**: - 规则解析器:处理IP/CIDR、协议、动作等 - UFW适配器:执行实际防火墙操作 - 内存存储:缓存当前规则状态 - 日志中间件:记录操作日志 ### 完整实现代码 ```go package main import ( "bufio" "bytes" "encoding/json" "fmt" "log" "net" "net/http" "os/exec" "strings" "sync" "github.com/gin-gonic/gin" ) // 防火墙规则结构体 type FirewallRule struct { ID int `json:"id"` Port int `json:"port" binding:"required,min=1,max=65535"` Protocol string `json:"protocol" binding:"required,oneof=tcp udp imap all"` Action string `json:"action" binding:"required,oneof=ACCEPT DROP ALLOW DENY"` Chain string `json:"chain" binding:"required,oneof=INPUT OUTPUT FORWARD"` SourceIPs []string `json:"source_ips" binding:"required,min=1"` } // 全局状态 var ( rules []FirewallRule rulesLock sync.RWMutex nextID = 1 ) func main() { // 初始化时加载防火墙规则 if err := loadFirewallRules(); err != nil { log.Fatalf("Failed to load firewall rules: %v", err) } r := gin.Default() // 日志中间件 r.Use(func(c *gin.Context) { log.Printf("[%s] %s", c.Request.Method, c.Request.URL) c.Next() }) // API路由 r.POST("/firewall/add", addRule) r.POST("/firewall/delete", deleteRule) r.POST("/firewall/edit", editRule) r.GET("/firewall/list", listRules) // 启动服务 log.Println("Firewall manager started on :8688") if err := r.Run(":8688"); err != nil { log.Fatal(err) } } // 加载当前防火墙规则 func loadFirewallRules() error { cmd := exec.Command("sudo", "ufw", "status", "verbose") output, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("ufw status failed: %v\n%s", err, output) } scanner := bufio.NewScanner(bytes.NewReader(output)) for scanner.Scan() { line := scanner.Text() if strings.Contains(line, "ALLOW") || strings.Contains(line, "DENY") { parseRuleLine(line) } } log.Printf("Loaded %d firewall rules", len(rules)) return nil } // 解析UFW规则行 func parseRuleLine(line string) { parts := strings.Fields(line) if len(parts) < 4 { return } rule := FirewallRule{ ID: nextID, SourceIPs: []string{}, } nextID++ // 解析动作和协议 for i, part := range parts { switch { case strings.Contains(part, "/"): protoPort := strings.Split(part, "/") if len(protoPort) == 2 { rule.Protocol = strings.ToLower(protoPort[1]) fmt.Sscanf(protoPort[0], "%d", &rule.Port) } case part == "ALLOW", part == "DENY": rule.Action = part case net.ParseIP(part) != nil || strings.Contains(part, "/"): rule.SourceIPs = append(rule.SourceIPs, part) case part == "in", part == "out": rule.Chain = strings.ToUpper(part + "PUT") } } if rule.Port != 0 && rule.Protocol != "" { rules = append(rules, rule) } } // 添加规则 func addRule(c *gin.Context) { var newRule FirewallRule if err := c.ShouldBindJSON(&newRule); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 验证IP格式 for _, ip := range newRule.SourceIPs { if _, _, err := net.ParseCIDR(ip); err != nil { if net.ParseIP(ip) == nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid IP format: " + ip}) return } } } rulesLock.Lock() defer rulesLock.Unlock() newRule.ID = nextID nextID++ rules = append(rules, newRule) // 执行UFW命令 for _, ip := range newRule.SourceIPs { cmd := exec.Command("sudo", "ufw", fmt.Sprintf("%s", strings.ToLower(newRule.Action)), "proto", newRule.Protocol, "to", fmt.Sprintf("any port %d", newRule.Port), "from", ip) if output, err := cmd.CombinedOutput(); err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "error": fmt.Sprintf("UFW command failed: %v\n%s", err, output), }) return } } // 重载防火墙 if err := reloadFirewall(); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusCreated, gin.H{"id": newRule.ID}) log.Printf("Added rule: %+v", newRule) } // 删除规则 func deleteRule(c *gin.Context) { type DeleteRequest struct { ID int `json:"id" binding:"required"` } var req DeleteRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } rulesLock.Lock() defer rulesLock.Unlock() found := false for i, rule := range rules { if rule.ID == req.ID { // 执行UFW删除 for _, ip := range rule.SourceIPs { cmd := exec.Command("sudo", "ufw", "delete", fmt.Sprintf("%s", strings.ToLower(rule.Action)), "proto", rule.Protocol, "to", fmt.Sprintf("any port %d", rule.Port), "from", ip) if output, err := cmd.CombinedOutput(); err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "error": fmt.Sprintf("UFW delete failed: %v\n%s", err, output), }) return } } // 从内存移除 rules = append(rules[:i], rules[i+1:]...) found = true break } } if !found { c.JSON(http.StatusNotFound, gin.H{"error": "Rule not found"}) return } // 重载防火墙 if err := reloadFirewall(); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"status": "deleted"}) log.Printf("Deleted rule ID: %d", req.ID) } // 编辑规则 func editRule(c *gin.Context) { var updatedRule FirewallRule if err := c.ShouldBindJSON(&updatedRule); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } rulesLock.Lock() defer rulesLock.Unlock() found := false for i, rule := range rules { if rule.ID == updatedRule.ID { // 先删除旧规则 for _, ip := range rule.SourceIPs { cmd := exec.Command("sudo", "ufw", "delete", fmt.Sprintf("%s", strings.ToLower(rule.Action)), "proto", rule.Protocol, "to", fmt.Sprintf("any port %d", rule.Port), "from", ip) if output, err := cmd.CombinedOutput(); err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "error": fmt.Sprintf("UFW delete failed: %v\n%s", err, output), }) return } } // 更新内存规则 rules[i] = updatedRule // 添加规则 for _, ip := range updatedRule.SourceIPs { cmd := exec.Command("sudo", "ufw", fmt.Sprintf("%s", strings.ToLower(updatedRule.Action)), "proto", updatedRule.Protocol, "to", fmt.Sprintf("any port %d", updatedRule.Port), "from", ip) if output, err := cmd.CombinedOutput(); err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "error": fmt.Sprintf("UFW add failed: %v\n%s", err, output), }) return } } found = true break } } if !found { c.JSON(http.StatusNotFound, gin.H{"error": "Rule not found"}) return } // 重载防火墙 if err := reloadFirewall(); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"status": "updated"}) log.Printf("Updated rule: %+v", updatedRule) } // 列出所有规则 func listRules(c *gin.Context) { rulesLock.RLock() defer rulesLock.RUnlock() c.JSON(http.StatusOK, rules) } // 重载防火墙配置 func reloadFirewall() error { cmd := exec.Command("sudo", "ufw", "reload") if output, err := cmd.CombinedOutput(); err != nil { return fmt.Errorf("reload failed: %v\n%s", err, output) } return nil } ``` ### 关键功能解释 1. **规则管理核心**: - `loadFirewallRules()`:启动时解析`ufw status`输出加载规则 - `parseRuleLine()`:将UFW文本规则转换为结构体 - 使用`sync.RWMutex`确保并发安全 2. **UFW命令映射**: ```go // 添加规则命令示例 ufw allow proto tcp to any port 3306 from 192.168.0.0/24 ufw deny proto udp to any port 53 from 10.0.0.1 ``` 3. **多IP处理**: ```go // 对每个源IP单独执行命令 for _, ip := range newRule.SourceIPs { cmd := exec.Command("sudo", "ufw", ...) } ``` 4. **协议支持**: - 支持标准协议:tcp/udp - 支持应用协议:imap(自动转换为端口143) - 特殊协议all:匹配所有协议 ### Docker部署文件 ```Dockerfile # Dockerfile FROM golang:1.20-alpine # 安装UFW和依赖 RUN apk add --no-cache ufw sudo # 配置免密sudo RUN echo "ALL ALL=(ALL) NOPASSWD: /usr/sbin/ufw" >> /etc/sudoers # 设置工作目录 WORKDIR /app COPY . . # 构建应用 RUN go build -o firewall-manager . # 开放管理端口 EXPOSE 8688 # 启动命令 CMD ["./firewall-manager"] ``` ### 测试请求示例 ```bash # 添加规则 curl -X POST http://localhost:8688/firewall/add \ -H "Content-Type: application/json" \ -d '{ "port": 3306, "protocol": "tcp", "action": "ACCEPT", "chain": "INPUT", "source_ips": ["192.168.0.0/24", "10.0.0.1"] }' # 列出规则 curl http://localhost:8688/firewall/list # 删除规则(使用添加时返回的ID) curl -X POST http://localhost:8688/firewall/delete \ -d '{"id": 1}' ``` ### 容器化运行 ```bash # 构建镜像 docker build -t firewall-manager . # 以特权模式运行(需要操作防火墙) docker run -d --privileged -p 8688:8688 firewall-manager ``` ### 日志示例 ``` [GIN] POST /firewall/add Added rule: {ID:1 Port:3306 Protocol:tcp Action:ACCEPT ...} UFW command: sudo ufw allow proto tcp to any port 3306 from 192.168.0.0/24 ``` ### 设计优势 1. **多工具支持**:通过抽象命令执行层,可扩展支持firewalld/iptables 2. **批量操作**:支持同时添加多个IP的相同规则 3. **原子性操作**:修改规则时先删后增,保证一致性 4. **自动重载**:每次修改后自动执行`ufw reload`
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值