Skip to content

Commit

Permalink
Merge pull request #19 from danwinship/more-fields
Browse files Browse the repository at this point in the history
Add flags to Table and policy to Chain
  • Loading branch information
k8s-ci-robot authored Nov 25, 2024
2 parents 007fc6b + 7c2e05b commit 2ce86d5
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 8 deletions.
7 changes: 7 additions & 0 deletions fake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,13 @@ func TestFakeParseDump(t *testing.T) {
add element ip kube-proxy map1 { 192.168.0.2 . tcp . 443 comment "with a comment" : goto anotherchain }
`,
},
{
ipFamily: IPv4Family,
dump: `
add table ip kube-proxy { flags dormant ; }
add chain ip kube-proxy filter-prerouting { type filter hook prerouting priority -100 ; policy drop ; }
`,
},
{
ipFamily: IPv4Family,
dump: `
Expand Down
49 changes: 42 additions & 7 deletions objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,22 +76,48 @@ func (table *Table) writeOperation(verb verb, ctx *nftContext, writer io.Writer)
// All other cases refer to the table by name
fmt.Fprintf(writer, "%s table %s %s", verb, ctx.family, ctx.table)
if verb == addVerb || verb == createVerb {
if table.Comment != nil && !ctx.noObjectComments {
fmt.Fprintf(writer, " { comment %q ; }", *table.Comment)
hasComment := table.Comment != nil && !ctx.noObjectComments
if hasComment || len(table.Flags) != 0 {
fmt.Fprintf(writer, " {")
if hasComment {
fmt.Fprintf(writer, " comment %q ;", *table.Comment)
}
if len(table.Flags) != 0 {
fmt.Fprintf(writer, " flags ")
for i := range table.Flags {
if i > 0 {
fmt.Fprintf(writer, ",")
}
fmt.Fprintf(writer, "%s", table.Flags[i])
}
fmt.Fprintf(writer, " ;")
}
fmt.Fprintf(writer, " }")
}
}
fmt.Fprintf(writer, "\n")
}

var tableRegexp = regexp.MustCompile(fmt.Sprintf(
`(?:{ comment %s ; })?`, commentGroup))
`(?:{ (?:comment %s ; )?(?:flags %s ; )?})?`, commentGroup, noSpaceGroup))

func parseTableFlags(s string) []TableFlag {
var res []TableFlag
for _, flag := range strings.Split(s, ",") {
res = append(res, TableFlag(flag))
}
return res
}

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])
if match[2] != "" {
table.Flags = parseTableFlags(match[2])
}
return nil
}

Expand All @@ -101,6 +127,9 @@ func (chain *Chain) validate(verb verb) error {
if chain.Type != nil || chain.Priority != nil {
return fmt.Errorf("regular chain %q must not specify Type or Priority", chain.Name)
}
if chain.Policy != nil {
return fmt.Errorf("regular chain %q must not specify Policy", chain.Name)
}
if chain.Device != nil {
return fmt.Errorf("regular chain %q must not specify Device", chain.Name)
}
Expand Down Expand Up @@ -156,6 +185,9 @@ func (chain *Chain) writeOperation(verb verb, ctx *nftContext, writer io.Writer)
} else {
fmt.Fprintf(writer, " priority %s ;", *chain.Priority)
}
if chain.Policy != nil {
fmt.Fprintf(writer, " policy %s ;", *chain.Policy)
}
}
if chain.Comment != nil && !ctx.noObjectComments {
fmt.Fprintf(writer, " comment %q ;", *chain.Comment)
Expand All @@ -168,18 +200,18 @@ 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 ;) })
// groups in []: [1]%s(?: {(?: type [2]%s hook [3]%s(?: device "[4]%s")(?: priority [5]%s ;)(?: policy [6]%s ;)?)(?: comment [7]%s ;) })
var chainRegexp = regexp.MustCompile(fmt.Sprintf(
`%s(?: {(?: type %s hook %s(?: device "%s")?(?: priority %s ;))?(?: comment %s ;)? })?`,
noSpaceGroup, noSpaceGroup, noSpaceGroup, noSpaceGroup, noSpaceGroup, commentGroup))
`%s(?: {(?: type %s hook %s(?: device "%s")?(?: priority %s ;)(?: policy %s ;)?)?(?: comment %s ;)? })?`,
noSpaceGroup, 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])
chain.Comment = getComment(match[7])
if match[2] != "" {
chain.Type = (*BaseChainType)(&match[2])
}
Expand All @@ -192,6 +224,9 @@ func (chain *Chain) parse(line string) error {
if match[5] != "" {
chain.Priority = (*BaseChainPriority)(&match[5])
}
if match[6] != "" {
chain.Policy = (*BaseChainPolicy)(&match[6])
}
return nil
}

Expand Down
29 changes: 28 additions & 1 deletion objects_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,21 @@ func TestObjects(t *testing.T) {
object: &Table{Comment: PtrTo("foo")},
out: `add table ip mytable { comment "foo" ; }`,
},
{
name: "add table with flags",
verb: addVerb,
object: &Table{Flags: []TableFlag{DormantFlag}},
out: `add table ip mytable { flags dormant ; }`,
},
{
name: "add table with comment and flags",
verb: addVerb,
object: &Table{
Comment: PtrTo("foo"),
Flags: []TableFlag{DormantFlag},
},
out: `add table ip mytable { comment "foo" ; flags dormant ; }`,
},
{
name: "create table",
verb: createVerb,
Expand Down Expand Up @@ -227,6 +242,12 @@ func TestObjects(t *testing.T) {
object: &Chain{Name: "mychain", Type: PtrTo(NATType), Hook: PtrTo(PostroutingHook), Priority: PtrTo(SNATPriority), Comment: PtrTo("foo")},
out: `add chain ip mytable mychain { type nat hook postrouting priority 100 ; comment "foo" ; }`,
},
{
name: "add base chain with policy",
verb: addVerb,
object: &Chain{Name: "mychain", Type: PtrTo(NATType), Hook: PtrTo(PostroutingHook), Priority: PtrTo(SNATPriority), Policy: PtrTo(DropPolicy)},
out: `add chain ip mytable mychain { type nat hook postrouting priority 100 ; policy drop ; }`,
},
{
name: "add base chain with device",
verb: addVerb,
Expand Down Expand Up @@ -324,7 +345,13 @@ func TestObjects(t *testing.T) {
err: "must not specify Type or Priority",
},
{
name: "invalid add non-base chain with device",
name: "invalid add non-base chain with Policy",
verb: addVerb,
object: &Chain{Name: "mychain", Policy: PtrTo(AcceptPolicy)},
err: "must not specify Policy",
},
{
name: "invalid add non-base chain with Device",
verb: addVerb,
object: &Chain{Name: "mychain", Device: PtrTo("eth0")},
err: "must not specify Device",
Expand Down
29 changes: 29 additions & 0 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,25 @@ const (
NetDevFamily Family = "netdev"
)

// TableFlag represents a table flag
type TableFlag string

const (
// DormantFlag indicates that a table is not currently evaluated. (Its base chains
// are unregistered.)
DormantFlag TableFlag = "dormant"
)

// Table represents an nftables table.
type Table struct {
// Comment is an optional comment for the table. (Requires kernel >= 5.10 and
// nft >= 0.9.7; otherwise this field will be silently ignored. Requires
// nft >= 1.0.8 to include comments in List() results.)
Comment *string

// Flags are the table flags
Flags []TableFlag

// Handle is an identifier that can be used to uniquely identify an object when
// deleting it. When adding a new object, this must be nil.
Handle *int
Expand Down Expand Up @@ -185,6 +197,19 @@ const (
SNATPriority BaseChainPriority = "srcnat"
)

// BaseChainPolicy sets what happens to packets not explicitly accepted or refused by a
// base chain.
type BaseChainPolicy string

const (
// AcceptPolicy, which is the default, accepts any unmatched packets (though,
// as with any other nftables chain, a later chain can drop or reject it).
AcceptPolicy BaseChainPolicy = "accept"

// DropPolicy drops any unmatched packets.
DropPolicy BaseChainPolicy = "drop"
)

// Chain represents an nftables chain; either a "base chain" (if Type, Hook, and Priority
// are specified), or a "regular chain" (if they are not).
type Chain struct {
Expand All @@ -201,6 +226,10 @@ type Chain struct {
// a regular chain. You can call ParsePriority() to convert this to a number.
Priority *BaseChainPriority

// Policy is the policy for packets not explicitly accepted or refused by a base
// chain.
Policy *BaseChainPolicy

// Device is the network interface that the chain is attached to; this must be set
// for a base chain connected to the "ingress" or "egress" hooks, and unset for
// all other chains.
Expand Down

0 comments on commit 2ce86d5

Please sign in to comment.