95 lines
2.7 KiB
Go
95 lines
2.7 KiB
Go
/*
|
|
Copyright 2023 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package knftables
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os/exec"
|
|
"strings"
|
|
"syscall"
|
|
)
|
|
|
|
type nftablesError struct {
|
|
wrapped error
|
|
msg string
|
|
errno syscall.Errno
|
|
}
|
|
|
|
// wrapError wraps an error resulting from running nft
|
|
func wrapError(err error) error {
|
|
nerr := &nftablesError{wrapped: err, msg: err.Error()}
|
|
ee := &exec.ExitError{}
|
|
if errors.As(err, &ee) {
|
|
if len(ee.Stderr) > 0 {
|
|
nerr.msg = string(ee.Stderr)
|
|
eol := strings.Index(nerr.msg, "\n")
|
|
// The nft binary does not call setlocale() and so will return
|
|
// English error strings regardless of the locale.
|
|
enoent := strings.Index(nerr.msg, "No such file or directory")
|
|
eexist := strings.Index(nerr.msg, "File exists")
|
|
if enoent != -1 && (enoent < eol || eol == -1) {
|
|
nerr.errno = syscall.ENOENT
|
|
} else if eexist != -1 && (eexist < eol || eol == -1) {
|
|
nerr.errno = syscall.EEXIST
|
|
}
|
|
}
|
|
}
|
|
return nerr
|
|
}
|
|
|
|
// notFoundError returns an nftablesError with the given message for which IsNotFound will
|
|
// return true.
|
|
func notFoundError(format string, args ...interface{}) error {
|
|
return &nftablesError{msg: fmt.Sprintf(format, args...), errno: syscall.ENOENT}
|
|
}
|
|
|
|
// existsError returns an nftablesError with the given message for which IsAlreadyExists
|
|
// will return true.
|
|
func existsError(format string, args ...interface{}) error {
|
|
return &nftablesError{msg: fmt.Sprintf(format, args...), errno: syscall.EEXIST}
|
|
}
|
|
|
|
func (nerr *nftablesError) Error() string {
|
|
return nerr.msg
|
|
}
|
|
|
|
func (nerr *nftablesError) Unwrap() error {
|
|
return nerr.wrapped
|
|
}
|
|
|
|
// IsNotFound tests if err corresponds to an nftables "not found" error of any sort.
|
|
// (e.g., in response to a "delete rule" command, this might indicate that the rule
|
|
// doesn't exist, or the chain doesn't exist, or the table doesn't exist.)
|
|
func IsNotFound(err error) bool {
|
|
var nerr *nftablesError
|
|
if errors.As(err, &nerr) {
|
|
return nerr.errno == syscall.ENOENT
|
|
}
|
|
return false
|
|
}
|
|
|
|
// IsAlreadyExists tests if err corresponds to an nftables "already exists" error (e.g.
|
|
// when doing a "create" rather than an "add").
|
|
func IsAlreadyExists(err error) bool {
|
|
var nerr *nftablesError
|
|
if errors.As(err, &nerr) {
|
|
return nerr.errno == syscall.EEXIST
|
|
}
|
|
return false
|
|
}
|