spoofcheck: Make use of go-nft's ApplyConfigEcho()

Store the relevant applied config part for later to extract the rule to
delete from there instead of having to list the ruleset. This is much
faster especially with large rulesets.

Signed-off-by: Phil Sutter <psutter@redhat.com>
This commit is contained in:
Phil Sutter
2023-06-01 14:08:27 +02:00
parent bf79945c70
commit 2ba7f1608f
7 changed files with 120 additions and 55 deletions

View File

@ -67,3 +67,10 @@ func ApplyConfig(c *Config) error {
func ApplyConfigContext(ctx context.Context, c *Config) error {
return nftexec.ApplyConfig(ctx, c)
}
// ApplyConfigEcho applies the given nftables config on the system, echoing
// back the added elements with their assigned handles
// The system is expected to have the `nft` executable deployed and nftables enabled in the kernel.
func ApplyConfigEcho(ctx context.Context, c *Config) (*Config, error) {
return nftexec.ApplyConfigEcho(ctx, c)
}

View File

@ -23,8 +23,6 @@ import (
"bytes"
"context"
"fmt"
"io/ioutil"
"os"
"os/exec"
"strings"
@ -33,22 +31,24 @@ import (
const (
cmdBin = "nft"
cmdHandle = "-a"
cmdEcho = "-e"
cmdFile = "-f"
cmdJSON = "-j"
cmdList = "list"
cmdRuleset = "ruleset"
cmdStdin = "-"
)
// ReadConfig loads the nftables configuration from the system and
// returns it as a nftables config structure.
// The system is expected to have the `nft` executable deployed and nftables enabled in the kernel.
func ReadConfig(ctx context.Context, filterCommands ...string) (*nftconfig.Config, error) {
whatToList := cmdRuleset
if len(filterCommands) > 0 {
whatToList = strings.Join(filterCommands, " ")
}
stdout, err := execCommand(ctx, cmdJSON, cmdList, whatToList)
stdout, err := execCommand(ctx, nil, cmdJSON, cmdList, whatToList)
if err != nil {
return nil, err
}
@ -69,38 +69,52 @@ func ApplyConfig(ctx context.Context, c *nftconfig.Config) error {
return err
}
tmpFile, err := ioutil.TempFile(os.TempDir(), "spoofcheck-")
if err != nil {
return fmt.Errorf("failed to create temporary file: %v", err)
}
defer os.Remove(tmpFile.Name())
if _, err = tmpFile.Write(data); err != nil {
return fmt.Errorf("failed to write to temporary file: %v", err)
}
if err := tmpFile.Close(); err != nil {
return fmt.Errorf("failed to close temporary file: %v", err)
}
if _, err := execCommand(ctx, cmdJSON, cmdFile, tmpFile.Name()); err != nil {
if _, err := execCommand(ctx, data, cmdJSON, cmdFile, cmdStdin); err != nil {
return err
}
return nil
}
func execCommand(ctx context.Context, args ...string) (*bytes.Buffer, error) {
// ApplyConfigEcho applies the given nftables config on the system, echoing
// back the added elements with their assigned handles
// The system is expected to have the `nft` executable deployed and nftables enabled in the kernel.
func ApplyConfigEcho(ctx context.Context, c *nftconfig.Config) (*nftconfig.Config, error) {
data, err := c.ToJSON()
if err != nil {
return nil, err
}
stdout, err := execCommand(ctx, data, cmdHandle, cmdEcho, cmdJSON, cmdFile, cmdStdin)
if err != nil {
return nil, err
}
config := nftconfig.New()
if err := config.FromJSON(stdout.Bytes()); err != nil {
return nil, fmt.Errorf("failed to parse echo: %v", err)
}
return config, nil
}
func execCommand(ctx context.Context, input []byte, args ...string) (*bytes.Buffer, error) {
cmd := exec.CommandContext(ctx, cmdBin, args...)
var stdout, stderr bytes.Buffer
cmd.Stderr = &stderr
cmd.Stdout = &stdout
if input != nil {
var stdin bytes.Buffer
stdin.Write(input)
cmd.Stdin = &stdin
}
if err := cmd.Run(); err != nil {
return nil, fmt.Errorf(
"failed to execute %s %s: %v stdout:'%s' stderr:'%s'",
cmd.Path, strings.Join(cmd.Args, " "), err, stdout.String(), stderr.String(),
"failed to execute %s %s: %v stdin:'%s' stdout:'%s' stderr:'%s'",
cmd.Path, strings.Join(cmd.Args, " "), err, string(input), stdout.String(), stderr.String(),
)
}