package nft import ( "errors" "regexp" "strings" "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/chain" "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/command" "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/rule" "git.kor-elf.net/kor-elf-shield/go-nftables-client/internal/table" ) // NFT A client for working with nftables type NFT interface { // Command returns the command used to execute nft. // You can execute your raw request. Command() command.NFT // Clear clears all rules. // // This command is equivalent to: // nft flush ruleset Clear() error // Version returns the version of nftables. // // This command is equivalent to: // nft -V Version() (Version, error) // Table returns an API for working with tables. Table() table.API // Chain returns an API for working with chains. Chain() chain.API // Rule returns an API for working with rules. Rule() rule.API } type nft struct { command command.NFT table table.API chain chain.API rule rule.API } // New Returns a client for working with nftables. // Searches for nft in paths: nft, /usr/sbin/nft, /sbin/nft func New() (NFT, error) { paths := []string{"nft", "/usr/sbin/nft", "/sbin/nft"} for _, path := range paths { nftClient, err := NewWithPath(path) if err == nil { return nftClient, nil } } return nil, errors.New("nft not found") } // NewWithPath Returns the client for working with nftables with its path specified. func NewWithPath(path string) (NFT, error) { nftCommand, err := command.New(path) if err != nil { return nil, err } return &nft{ command: nftCommand, table: table.New(nftCommand), chain: chain.New(nftCommand), rule: rule.New(nftCommand), }, nil } func (n *nft) Clear() error { args := []string{"flush", "ruleset"} return n.command.Run(args...) } func (n *nft) Version() (Version, error) { args := []string{"-V"} out, err := n.command.RunWithOutput(args...) if err != nil { return nil, err } vers := "" opts := make(map[string]string) lines := regexp.MustCompile("\r?\n").Split(strings.TrimSpace(string(out)), -1) for index, line := range lines { line = strings.TrimSpace(line) if index == 0 { vers = line continue } values := strings.Split(line, ":") if len(values) != 2 { continue } name := strings.TrimSpace(values[0]) value := strings.TrimSpace(values[1]) opts[name] = value } return &version{ version: vers, opts: opts, }, nil } func (n *nft) Table() table.API { return n.table } func (n *nft) Chain() chain.API { return n.chain } func (n *nft) Rule() rule.API { return n.rule } func (n *nft) Command() command.NFT { return n.command }