Update knftables to v0.0.16

Signed-off-by: Nadia Pinaeva <n.m.pinaeva@gmail.com>
This commit is contained in:
Nadia Pinaeva
2024-04-02 10:36:29 +02:00
parent f4e246bc93
commit 20bd3dd774
14 changed files with 366 additions and 33 deletions

View File

@@ -19,9 +19,37 @@ package knftables
import (
"fmt"
"io"
"regexp"
"strconv"
"strings"
"time"
)
func parseInt(numbersOnly string) *int {
i64, _ := strconv.ParseInt(numbersOnly, 10, 64)
i := int(i64)
return &i
}
func parseUint(numbersOnly string) *uint64 {
ui64, _ := strconv.ParseUint(numbersOnly, 10, 64)
return &ui64
}
// getComment parses a match for the commentGroup regexp (below). To distinguish between empty comment and no comment,
// we capture comment with double quotes.
func getComment(commentGroup string) *string {
if commentGroup == "" {
return nil
}
noQuotes := strings.Trim(commentGroup, "\"")
return &noQuotes
}
var commentGroup = `(".*")`
var noSpaceGroup = `([^ ]*)`
var numberGroup = `([0-9]*)`
// Object implementation for Table
func (table *Table) validate(verb verb) error {
switch verb {
@@ -55,6 +83,18 @@ func (table *Table) writeOperation(verb verb, ctx *nftContext, writer io.Writer)
fmt.Fprintf(writer, "\n")
}
var tableRegexp = regexp.MustCompile(fmt.Sprintf(
`(?:{ comment %s ; })?`, commentGroup))
func (table *Table) parse(line string) error {
match := tableRegexp.FindStringSubmatch(line)
if match == nil {
return fmt.Errorf("failed parsing table add command")
}
table.Comment = getComment(match[1])
return nil
}
// Object implementation for Chain
func (chain *Chain) validate(verb verb) error {
if chain.Hook == nil {
@@ -128,6 +168,33 @@ func (chain *Chain) writeOperation(verb verb, ctx *nftContext, writer io.Writer)
fmt.Fprintf(writer, "\n")
}
// groups in []: [1]%s(?: {(?: type [2]%s hook [3]%s(?: device "[4]%s")(?: priority [5]%s ;))(?: comment [6]%s ;) })
var chainRegexp = regexp.MustCompile(fmt.Sprintf(
`%s(?: {(?: type %s hook %s(?: device "%s")?(?: priority %s ;))?(?: comment %s ;)? })?`,
noSpaceGroup, noSpaceGroup, noSpaceGroup, noSpaceGroup, noSpaceGroup, commentGroup))
func (chain *Chain) parse(line string) error {
match := chainRegexp.FindStringSubmatch(line)
if match == nil {
return fmt.Errorf("failed parsing chain add command")
}
chain.Name = match[1]
chain.Comment = getComment(match[6])
if match[2] != "" {
chain.Type = (*BaseChainType)(&match[2])
}
if match[3] != "" {
chain.Hook = (*BaseChainHook)(&match[3])
}
if match[4] != "" {
chain.Device = &match[4]
}
if match[5] != "" {
chain.Priority = (*BaseChainPriority)(&match[5])
}
return nil
}
// Object implementation for Rule
func (rule *Rule) validate(verb verb) error {
if rule.Chain == "" {
@@ -181,6 +248,28 @@ func (rule *Rule) writeOperation(verb verb, ctx *nftContext, writer io.Writer) {
fmt.Fprintf(writer, "\n")
}
// groups in []: [1]%s(?: index [2]%s)?(?: handle [3]%s)? [4]([^"]*)(?: comment [5]%s)?$
var ruleRegexp = regexp.MustCompile(fmt.Sprintf(
`%s(?: index %s)?(?: handle %s)? ([^"]*)(?: comment %s)?$`,
noSpaceGroup, numberGroup, numberGroup, commentGroup))
func (rule *Rule) parse(line string) error {
match := ruleRegexp.FindStringSubmatch(line)
if match == nil {
return fmt.Errorf("failed parsing rule add command")
}
rule.Chain = match[1]
rule.Rule = match[4]
rule.Comment = getComment(match[5])
if match[2] != "" {
rule.Index = parseInt(match[2])
}
if match[3] != "" {
rule.Handle = parseInt(match[3])
}
return nil
}
// Object implementation for Set
func (set *Set) validate(verb verb) error {
switch verb {
@@ -261,6 +350,16 @@ func (set *Set) writeOperation(verb verb, ctx *nftContext, writer io.Writer) {
fmt.Fprintf(writer, "\n")
}
func (set *Set) parse(line string) error {
match := setRegexp.FindStringSubmatch(line)
if match == nil {
return fmt.Errorf("failed parsing set add command")
}
set.Name, set.Type, set.TypeOf, set.Flags, set.Timeout, set.GCInterval,
set.Size, set.Policy, set.Comment, set.AutoMerge = parseMapAndSetProps(match)
return nil
}
// Object implementation for Map
func (mapObj *Map) validate(verb verb) error {
switch verb {
@@ -338,6 +437,68 @@ func (mapObj *Map) writeOperation(verb verb, ctx *nftContext, writer io.Writer)
fmt.Fprintf(writer, "\n")
}
func (mapObj *Map) parse(line string) error {
match := mapRegexp.FindStringSubmatch(line)
if match == nil {
return fmt.Errorf("failed parsing map add command")
}
mapObj.Name, mapObj.Type, mapObj.TypeOf, mapObj.Flags, mapObj.Timeout, mapObj.GCInterval,
mapObj.Size, mapObj.Policy, mapObj.Comment, _ = parseMapAndSetProps(match)
return nil
}
var autoMergeProp = `( auto-merge ;)?`
// groups in []: [1]%s {(?: [2](type|typeof) [3]([^;]*)) ;(?: flags [4]([^;]*) ;)?(?: timeout [5]%ss ;)?(?: gc-interval [6]%ss ;)?(?: size [7]%s ;)?(?: policy [8]%s ;)?[9]%s(?: comment [10]%s ;)? }
var mapOrSet = `%s {(?: (type|typeof) ([^;]*)) ;(?: flags ([^;]*) ;)?(?: timeout %ss ;)?(?: gc-interval %ss ;)?(?: size %s ;)?(?: policy %s ;)?%s(?: comment %s ;)? }`
var mapRegexp = regexp.MustCompile(fmt.Sprintf(mapOrSet, noSpaceGroup, numberGroup, numberGroup, noSpaceGroup, noSpaceGroup, "", commentGroup))
var setRegexp = regexp.MustCompile(fmt.Sprintf(mapOrSet, noSpaceGroup, numberGroup, numberGroup, noSpaceGroup, noSpaceGroup, autoMergeProp, commentGroup))
func parseMapAndSetProps(match []string) (name string, typeProp string, typeOf string, flags []SetFlag,
timeout *time.Duration, gcInterval *time.Duration, size *uint64, policy *SetPolicy, comment *string, autoMerge *bool) {
name = match[1]
// set and map have different number of match groups, but comment is always the last
comment = getComment(match[len(match)-1])
if match[2] == "type" {
typeProp = match[3]
} else {
typeOf = match[3]
}
if match[4] != "" {
flags = parseSetFlags(match[4])
}
if match[5] != "" {
timeoutObj, _ := time.ParseDuration(match[5] + "s")
timeout = &timeoutObj
}
if match[6] != "" {
gcIntervalObj, _ := time.ParseDuration(match[6] + "s")
gcInterval = &gcIntervalObj
}
if match[7] != "" {
size = parseUint(match[7])
}
if match[8] != "" {
policy = (*SetPolicy)(&match[8])
}
if len(match) > 10 {
// set
if match[9] != "" {
autoMergeObj := true
autoMerge = &autoMergeObj
}
}
return
}
func parseSetFlags(s string) []SetFlag {
var res []SetFlag
for _, flag := range strings.Split(s, ",") {
res = append(res, SetFlag(flag))
}
return res
}
// Object implementation for Element
func (element *Element) validate(verb verb) error {
if element.Map == "" && element.Set == "" {
@@ -387,3 +548,34 @@ func (element *Element) writeOperation(verb verb, ctx *nftContext, writer io.Wri
fmt.Fprintf(writer, " }\n")
}
// groups in []: [1]%s { [2]([^:"]*)(?: comment [3]%s)? : [4](.*) }
var mapElementRegexp = regexp.MustCompile(fmt.Sprintf(
`%s { ([^"]*)(?: comment %s)? : (.*) }`, noSpaceGroup, commentGroup))
// groups in []: [1]%s { [2]([^:"]*)(?: comment [3]%s)? }
var setElementRegexp = regexp.MustCompile(fmt.Sprintf(
`%s { ([^"]*)(?: comment %s)? }`, noSpaceGroup, commentGroup))
func (element *Element) parse(line string) error {
// try to match map element first, since it has more groups, and if it matches, then we can be sure
// this is map element.
match := mapElementRegexp.FindStringSubmatch(line)
if match == nil {
match = setElementRegexp.FindStringSubmatch(line)
if match == nil {
return fmt.Errorf("failed parsing element add command")
}
}
element.Comment = getComment(match[3])
mapOrSetName := match[1]
element.Key = append(element.Key, strings.Split(match[2], " . ")...)
if len(match) == 5 {
// map regex matched
element.Map = mapOrSetName
element.Value = append(element.Value, strings.Split(match[4], " . ")...)
} else {
element.Set = mapOrSetName
}
return nil
}