Skip to content

Commit

Permalink
Portmap: append, rather than prepend, entry rules
Browse files Browse the repository at this point in the history
This means that portmapped connections can be more easily controlled /
firewalled.
  • Loading branch information
squeed committed Feb 27, 2019
1 parent 9ebe139 commit 29f9ba5
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 12 deletions.
23 changes: 15 additions & 8 deletions plugins/meta/portmap/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ type chain struct {

entryRules [][]string // the rules that "point" to this chain
rules [][]string // the rules this chain contains

prependEntry bool // whether or not the entry rules should be prepended
}

// setup idempotently creates the chain. It will not error if the chain exists.
Expand All @@ -45,19 +47,19 @@ func (c *chain) setup(ipt *iptables.IPTables) error {
}

// Add the rules to the chain
for i := len(c.rules) - 1; i >= 0; i-- {
if err := prependUnique(ipt, c.table, c.name, c.rules[i]); err != nil {
for _, rule := range c.rules {
if err := insertUnique(ipt, c.table, c.name, false, rule); err != nil {
return err
}
}

// Add the entry rules to the entry chains
for _, entryChain := range c.entryChains {
for i := len(c.entryRules) - 1; i >= 0; i-- {
for _, rule := range c.entryRules {
r := []string{}
r = append(r, c.entryRules[i]...)
r = append(r, rule...)
r = append(r, "-j", c.name)
if err := prependUnique(ipt, c.table, entryChain, r); err != nil {
if err := insertUnique(ipt, c.table, entryChain, c.prependEntry, r); err != nil {
return err
}
}
Expand Down Expand Up @@ -105,8 +107,9 @@ func (c *chain) teardown(ipt *iptables.IPTables) error {
return nil
}

// prependUnique will prepend a rule to a chain, if it does not already exist
func prependUnique(ipt *iptables.IPTables, table, chain string, rule []string) error {
// insertUnique will add a rule to a chain if it does not already exist.
// By default the rule is appended, unless prepend is true.
func insertUnique(ipt *iptables.IPTables, table, chain string, prepend bool, rule []string) error {
exists, err := ipt.Exists(table, chain, rule...)
if err != nil {
return err
Expand All @@ -115,7 +118,11 @@ func prependUnique(ipt *iptables.IPTables, table, chain string, rule []string) e
return nil
}

return ipt.Insert(table, chain, 1, rule...)
if prepend {
return ipt.Insert(table, chain, 1, rule...)
} else {
return ipt.Append(table, chain, rule...)
}
}

func chainExists(ipt *iptables.IPTables, tableName, chainName string) (bool, error) {
Expand Down
2 changes: 1 addition & 1 deletion plugins/meta/portmap/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ var _ = Describe("chain tests", func() {
Expect(err).NotTo(HaveOccurred())
Expect(haveRules).To(Equal([]string{
"-N " + tlChainName,
"-A " + tlChainName + " -d 203.0.113.1/32 -j " + testChain.name,
"-A " + tlChainName + ` -m comment --comment "canary value" -j ACCEPT`,
"-A " + tlChainName + " -d 203.0.113.1/32 -j " + testChain.name,
}))

// Check that the chain and rule was created
Expand Down
7 changes: 4 additions & 3 deletions plugins/meta/portmap/portmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,10 @@ func genMarkMasqChain(markBit int) chain {
markValue := 1 << uint(markBit)
markDef := fmt.Sprintf("%#x/%#x", markValue, markValue)
ch := chain{
table: "nat",
name: MarkMasqChainName,
entryChains: []string{"POSTROUTING"},
table: "nat",
name: MarkMasqChainName,
entryChains: []string{"POSTROUTING"},
prependEntry: true, // This conflicts with the (rather in need of a rethink) CNI plugin masquerading rules
entryRules: [][]string{{
"-m", "comment",
"--comment", "CNI portfwd requiring masquerade",
Expand Down
6 changes: 6 additions & 0 deletions plugins/meta/portmap/portmap_integ_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,12 @@ var _ = Describe("portmap integration tests", func() {
fmt.Fprintf(GinkgoWriter, "hostIP: %s:%d, contIP: %s:%d\n",
hostIP, hostPort, contIP, containerPort)

// dump iptables-save output for debugging
cmd = exec.Command("iptables-save")
cmd.Stderr = GinkgoWriter
cmd.Stdout = GinkgoWriter
Expect(cmd.Run()).To(Succeed())

// Sanity check: verify that the container is reachable directly
contOK := testEchoServer(contIP.String(), containerPort, "")

Expand Down
1 change: 1 addition & 0 deletions plugins/meta/portmap/portmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ var _ = Describe("portmapping configuration", func() {
"--mark", "0x20/0x20",
"-j", "MASQUERADE",
}},
prependEntry: true,
}))
})
})
Expand Down

0 comments on commit 29f9ba5

Please sign in to comment.