Skip to content

Commit

Permalink
Add Check support to firewall meta plugin, test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
mccv1r0 committed Apr 8, 2019
1 parent 5413c27 commit 4d7722a
Show file tree
Hide file tree
Showing 6 changed files with 350 additions and 40 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Read [CONTRIBUTING](CONTRIBUTING.md) for build and test instructions.
* `portmap`: An iptables-based portmapping plugin. Maps ports from the host's address space to the container.
* `bandwidth`: Allows bandwidth-limiting through use of traffic control tbf (ingress/egress).
* `sbr`: A plugin that configures source based routing for an interface (from which it is chained).
* `firewall`: A firewall plugin which uses iptables or firewalld to add rules to allow traffic to/from the container.

### Sample
The sample plugin provides an example for building your own plugin.
71 changes: 44 additions & 27 deletions plugins/meta/firewall/firewall.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,14 @@ type FirewallNetConf struct {
// to 'trusted'
FirewalldZone string `json:"firewalldZone,omitempty"`

RawPrevResult map[string]interface{} `json:"prevResult,omitempty"`
PrevResult *current.Result `json:"-"`
//RawPrevResult map[string]interface{} `json:"prevResult,omitempty"`
//PrevResult *current.Result `json:"-"`
}

type FirewallBackend interface {
Add(*FirewallNetConf) error
Del(*FirewallNetConf) error
Add(*FirewallNetConf, *current.Result) error
Del(*FirewallNetConf, *current.Result) error
Check(*FirewallNetConf, *current.Result) error
}

func ipString(ip net.IPNet) string {
Expand All @@ -62,37 +63,35 @@ func ipString(ip net.IPNet) string {
return ip.IP.String() + "/32"
}

func parseConf(data []byte) (*FirewallNetConf, error) {
func parseConf(data []byte) (*FirewallNetConf, *current.Result, error) {
conf := FirewallNetConf{}
if err := json.Unmarshal(data, &conf); err != nil {
return nil, fmt.Errorf("failed to load netconf: %v", err)
}

// Default the firewalld zone to trusted
if conf.FirewalldZone == "" {
conf.FirewalldZone = "trusted"
return nil, nil, fmt.Errorf("failed to load netconf: %v", err)
}

// Parse previous result.
if conf.RawPrevResult == nil {
return nil, fmt.Errorf("missing prevResult from earlier plugin")
return nil, nil, fmt.Errorf("missing prevResult from earlier plugin")
}

resultBytes, err := json.Marshal(conf.RawPrevResult)
if err != nil {
return nil, fmt.Errorf("could not serialize prevResult: %v", err)
// Parse previous result.
var result *current.Result
var err error
if err = version.ParsePrevResult(&conf.NetConf); err != nil {
return nil, nil, fmt.Errorf("could not parse prevResult: %v", err)
}
res, err := version.NewResult(conf.CNIVersion, resultBytes)

result, err = current.NewResultFromResult(conf.PrevResult)
if err != nil {
return nil, fmt.Errorf("could not parse prevResult: %v", err)
return nil, nil, fmt.Errorf("could not convert result to current version: %v", err)
}
conf.RawPrevResult = nil
conf.PrevResult, err = current.NewResultFromResult(res)
if err != nil {
return nil, fmt.Errorf("could not convert result to current version: %v", err)

// Default the firewalld zone to trusted
if conf.FirewalldZone == "" {
conf.FirewalldZone = "trusted"
}

return &conf, nil
return &conf, result, nil
}

func getBackend(conf *FirewallNetConf) (FirewallBackend, error) {
Expand All @@ -113,7 +112,7 @@ func getBackend(conf *FirewallNetConf) (FirewallBackend, error) {
}

func cmdAdd(args *skel.CmdArgs) error {
conf, err := parseConf(args.StdinData)
conf, result, err := parseConf(args.StdinData)
if err != nil {
return err
}
Expand All @@ -123,19 +122,18 @@ func cmdAdd(args *skel.CmdArgs) error {
return err
}

if err := backend.Add(conf); err != nil {
if err := backend.Add(conf, result); err != nil {
return err
}

result := conf.PrevResult
if result == nil {
result = &current.Result{}
}
return types.PrintResult(result, conf.CNIVersion)
}

func cmdDel(args *skel.CmdArgs) error {
conf, err := parseConf(args.StdinData)
conf, result, err := parseConf(args.StdinData)
if err != nil {
return err
}
Expand All @@ -152,7 +150,7 @@ func cmdDel(args *skel.CmdArgs) error {
}

// Runtime errors are ignored
if err := backend.Del(conf); err != nil {
if err := backend.Del(conf, result); err != nil {
return err
}

Expand All @@ -164,5 +162,24 @@ func main() {
}

func cmdCheck(args *skel.CmdArgs) error {
conf, result, err := parseConf(args.StdinData)
if err != nil {
return err
}

// Ensure we have previous result.
if result == nil {
return fmt.Errorf("Required prevResult missing")
}

backend, err := getBackend(conf)
if err != nil {
return err
}

if err := backend.Check(conf, result); err != nil {
return err
}

return nil
}
67 changes: 67 additions & 0 deletions plugins/meta/firewall/firewall_firewalld_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ func (f *fakeFirewalld) RemoveSource(zone, source string) (string, *dbus.Error)
return "", nil
}

func (f *fakeFirewalld) QuerySource(zone, source string) (bool, *dbus.Error) {
if f.zone != zone {
return false, nil
}
if f.source != source {
return false, nil
}
return true, nil
}

func spawnSessionDbus(wg *sync.WaitGroup) (string, *exec.Cmd) {
// Start a private D-Bus session bus
path, err := invoke.FindInPath("dbus-daemon", []string{
Expand Down Expand Up @@ -150,6 +160,7 @@ var _ = Describe("firewalld test", func() {
// Go public methods to the D-Bus name
methods := map[string]string{
"AddSource": firewalldAddSourceMethod,
"QuerySource": firewalldQuerySourceMethod,
"RemoveSource": firewalldRemoveSourceMethod,
}
conn.ExportWithMap(fwd, methods, firewalldPath, firewalldZoneInterface)
Expand Down Expand Up @@ -275,4 +286,60 @@ var _ = Describe("firewalld test", func() {
Expect(len(result.IPs)).To(Equal(1))
Expect(result.IPs[0].Address.String()).To(Equal("10.0.0.2/24"))
})

It("works with a 0.4.0 config, including Check", func() {
Expect(isFirewalldRunning()).To(BeTrue())

conf := `{
"cniVersion": "0.4.0",
"name": "firewalld-test",
"type": "firewall",
"backend": "firewalld",
"zone": "trusted",
"prevResult": {
"cniVersion": "0.4.0",
"interfaces": [
{"name": "eth0", "sandbox": "/foobar"}
],
"ips": [
{
"version": "4",
"address": "10.0.0.2/24",
"gateway": "10.0.0.1",
"interface": 0
}
]
}
}`

args := &skel.CmdArgs{
ContainerID: "dummy",
Netns: targetNs.Path(),
IfName: ifname,
StdinData: []byte(conf),
}
r, _, err := testutils.CmdAddWithArgs(args, func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())
Expect(fwd.zone).To(Equal("trusted"))
Expect(fwd.source).To(Equal("10.0.0.2/32"))

_, err = current.GetResult(r)
Expect(err).NotTo(HaveOccurred())

err = testutils.CmdCheckWithArgs(args, func() error {
return cmdCheck(args)
})
Expect(err).NotTo(HaveOccurred())

//fwd.clear()

err = testutils.CmdDelWithArgs(args, func() error {
return cmdDel(args)
})
Expect(err).NotTo(HaveOccurred())
Expect(fwd.zone).To(Equal("trusted"))
Expect(fwd.source).To(Equal("10.0.0.2/32"))
})
})
144 changes: 144 additions & 0 deletions plugins/meta/firewall/firewall_iptables_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,4 +365,148 @@ var _ = Describe("firewall plugin iptables backend", func() {
})
Expect(err).NotTo(HaveOccurred())
})

It("installs the right iptables rules on the host v4.0.x and check is successful", func() {
args := &skel.CmdArgs{
ContainerID: "dummy",
Netns: targetNS.Path(),
IfName: IFNAME,
StdinData: fullConf,
}

err := originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()

_, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())

validateFullRuleset(fullConf)
return nil
})
Expect(err).NotTo(HaveOccurred())
})

It("cleans up on delete v4.0.x", func() {
args := &skel.CmdArgs{
ContainerID: "dummy",
Netns: targetNS.Path(),
IfName: IFNAME,
StdinData: fullConf,
}

err := originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()

_, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())
validateFullRuleset(fullConf)

err = testutils.CmdDel(targetNS.Path(), args.ContainerID, IFNAME, func() error {
return cmdDel(args)
})
Expect(err).NotTo(HaveOccurred())
validateCleanedUp(fullConf)
return nil
})
Expect(err).NotTo(HaveOccurred())
})
})

var _ = Describe("firewall plugin iptables backend v0.4.x", func() {
var originalNS, targetNS ns.NetNS
const IFNAME string = "dummy0"

fullConf := []byte(`{
"name": "test",
"type": "firewall",
"backend": "iptables",
"ifName": "dummy0",
"cniVersion": "0.4.0",
"prevResult": {
"interfaces": [
{"name": "dummy0"}
],
"ips": [
{
"version": "4",
"address": "10.0.0.2/24",
"interface": 0
},
{
"version": "6",
"address": "2001:db8:1:2::1/64",
"interface": 0
}
]
}
}`)

BeforeEach(func() {
// Create a new NetNS so we don't modify the host
var err error
originalNS, err = testutils.NewNS()
Expect(err).NotTo(HaveOccurred())

err = originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()

err = netlink.LinkAdd(&netlink.Dummy{
LinkAttrs: netlink.LinkAttrs{
Name: IFNAME,
},
})
Expect(err).NotTo(HaveOccurred())
_, err = netlink.LinkByName(IFNAME)
Expect(err).NotTo(HaveOccurred())
return nil
})
Expect(err).NotTo(HaveOccurred())

targetNS, err = testutils.NewNS()
Expect(err).NotTo(HaveOccurred())
})

AfterEach(func() {
Expect(originalNS.Close()).To(Succeed())
Expect(targetNS.Close()).To(Succeed())
})

It("installs iptables rules, Check rules then cleans up on delete using v4.0.x", func() {
args := &skel.CmdArgs{
ContainerID: "dummy",
Netns: targetNS.Path(),
IfName: IFNAME,
StdinData: fullConf,
}

err := originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()

r, _, err := testutils.CmdAddWithArgs(args, func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())

_, err = current.GetResult(r)
Expect(err).NotTo(HaveOccurred())

err = testutils.CmdCheckWithArgs(args, func() error {
return cmdCheck(args)
})
Expect(err).NotTo(HaveOccurred())
validateFullRuleset(fullConf)

err = testutils.CmdDelWithArgs(args, func() error {
return cmdDel(args)
})
Expect(err).NotTo(HaveOccurred())
validateCleanedUp(fullConf)
return nil
})
Expect(err).NotTo(HaveOccurred())
})
})
Loading

0 comments on commit 4d7722a

Please sign in to comment.