github.com/TeaOSLab/EdgeNode@v1.3.8/internal/iplibrary/action_firewalld.go (about)

     1  package iplibrary
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
     7  	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
     8  	executils "github.com/TeaOSLab/EdgeNode/internal/utils/exec"
     9  	"runtime"
    10  	"time"
    11  )
    12  
    13  // FirewalldAction Firewalld动作管理
    14  // 常用命令:
    15  //   - 查询列表: firewall-cmd --list-all
    16  //   - 添加IP:firewall-cmd --add-rich-rule="rule family='ipv4' source address='192.168.2.32' reject" --timeout=30s
    17  //   - 删除IP:firewall-cmd --remove-rich-rule="rule family='ipv4' source address='192.168.2.32' reject" --timeout=30s
    18  type FirewalldAction struct {
    19  	BaseAction
    20  
    21  	config *firewallconfigs.FirewallActionFirewalldConfig
    22  
    23  	firewalldNotFound bool
    24  }
    25  
    26  func NewFirewalldAction() *FirewalldAction {
    27  	return &FirewalldAction{}
    28  }
    29  
    30  func (this *FirewalldAction) Init(config *firewallconfigs.FirewallActionConfig) error {
    31  	this.config = &firewallconfigs.FirewallActionFirewalldConfig{}
    32  	err := this.convertParams(config.Params, this.config)
    33  	if err != nil {
    34  		return err
    35  	}
    36  	return nil
    37  }
    38  
    39  func (this *FirewalldAction) AddItem(listType IPListType, item *pb.IPItem) error {
    40  	return this.runAction("addItem", listType, item)
    41  }
    42  
    43  func (this *FirewalldAction) DeleteItem(listType IPListType, item *pb.IPItem) error {
    44  	return this.runAction("deleteItem", listType, item)
    45  }
    46  
    47  func (this *FirewalldAction) runAction(action string, listType IPListType, item *pb.IPItem) error {
    48  	if item.Type == "all" {
    49  		return nil
    50  	}
    51  
    52  	if len(item.IpTo) == 0 {
    53  		return this.runActionSingleIP(action, listType, item)
    54  	}
    55  	cidrList, err := iPv4RangeToCIDRRange(item.IpFrom, item.IpTo)
    56  	if err != nil {
    57  		// 不合法的范围不予处理即可
    58  		return nil
    59  	}
    60  	if len(cidrList) == 0 {
    61  		return nil
    62  	}
    63  	for _, cidr := range cidrList {
    64  		item.IpFrom = cidr
    65  		item.IpTo = ""
    66  		err := this.runActionSingleIP(action, listType, item)
    67  		if err != nil {
    68  			return err
    69  		}
    70  	}
    71  	return nil
    72  }
    73  
    74  func (this *FirewalldAction) runActionSingleIP(action string, listType IPListType, item *pb.IPItem) error {
    75  	timestamp := time.Now().Unix()
    76  
    77  	if item.ExpiredAt > 0 && timestamp > item.ExpiredAt {
    78  		return nil
    79  	}
    80  
    81  	path := this.config.Path
    82  	var err error
    83  	if len(path) == 0 {
    84  		path, err = executils.LookPath("firewall-cmd")
    85  		if err != nil {
    86  			if this.firewalldNotFound {
    87  				return nil
    88  			}
    89  			this.firewalldNotFound = true
    90  			return err
    91  		}
    92  	}
    93  	if len(path) == 0 {
    94  		return errors.New("can not find 'firewall-cmd'")
    95  	}
    96  
    97  	opt := ""
    98  	switch action {
    99  	case "addItem":
   100  		opt = "--add-rich-rule"
   101  	case "deleteItem":
   102  		opt = "--remove-rich-rule"
   103  	default:
   104  		return errors.New("invalid action '" + action + "'")
   105  	}
   106  	opt += "=rule family='"
   107  	switch item.Type {
   108  	case "ipv4":
   109  		opt += "ipv4"
   110  	case "ipv6":
   111  		opt += "ipv6"
   112  	default:
   113  		// 我们忽略不能识别的Family
   114  		return nil
   115  	}
   116  
   117  	opt += "' source address='"
   118  	if len(item.IpFrom) == 0 {
   119  		return errors.New("invalid ip from")
   120  	}
   121  	opt += item.IpFrom + "' "
   122  
   123  	switch listType {
   124  	case IPListTypeWhite:
   125  		opt += " accept"
   126  	case IPListTypeBlack:
   127  		opt += " reject"
   128  	default:
   129  		// 我们忽略不能识别的列表类型
   130  		return nil
   131  	}
   132  
   133  	args := []string{opt}
   134  	if action == "addItem" {
   135  		if item.ExpiredAt > timestamp {
   136  			args = append(args, "--timeout="+fmt.Sprintf("%d", item.ExpiredAt-timestamp)+"s")
   137  		} else {
   138  			// TODO 思考是否需要permanent,不然--reload之后会丢失
   139  		}
   140  	}
   141  
   142  	if runtime.GOOS == "darwin" {
   143  		// MAC OS直接返回
   144  		return nil
   145  	}
   146  	cmd := executils.NewTimeoutCmd(30*time.Second, path, args...)
   147  	cmd.WithStderr()
   148  	err = cmd.Run()
   149  	if err != nil {
   150  		return fmt.Errorf("%w, output: %s", err, cmd.Stderr())
   151  	}
   152  	return nil
   153  }