//go:build !cgo || static_build || no_libnftables package nftables import ( "context" "fmt" "io" "os/exec" "strings" "github.com/containerd/log" "go.opentelemetry.io/otel" ) type nftHandle = struct{} func (t *table) nftApply(ctx context.Context, nftCmd []byte) error { ctx, span := otel.Tracer("").Start(ctx, spanPrefix+".nftApply.exec") defer span.End() cmd := exec.Command(nftPath, "-f", "-") stdinPipe, err := cmd.StdinPipe() if err != nil { return fmt.Errorf("getting stdin pipe for nft: %w", err) } stdoutPipe, err := cmd.StdoutPipe() if err != nil { return fmt.Errorf("getting stdout pipe for nft: %w", err) } stderrPipe, err := cmd.StderrPipe() if err != nil { return fmt.Errorf("getting stderr pipe for nft: %w", err) } if err := cmd.Start(); err != nil { return fmt.Errorf("starting nft: %w", err) } if _, err := stdinPipe.Write(nftCmd); err != nil { return fmt.Errorf("sending nft commands: %w", err) } if err := stdinPipe.Close(); err != nil { return fmt.Errorf("closing nft input pipe: %w", err) } stdoutBuf := strings.Builder{} if _, err := io.Copy(&stdoutBuf, stdoutPipe); err != nil { return fmt.Errorf("reading stdout of nft: %w", err) } stdout := stdoutBuf.String() stderrBuf := strings.Builder{} if _, err := io.Copy(&stderrBuf, stderrPipe); err != nil { return fmt.Errorf("reading stderr of nft: %w", err) } stderr := stderrBuf.String() err = cmd.Wait() if err != nil { return fmt.Errorf("running nft: %s %w", stderr, err) } log.G(ctx).WithFields(log.Fields{"stdout": stdout, "stderr": stderr}).Debug("nftables: updated") return nil } func (t *table) closeNftHandle() { }