Add Check support to firewall meta plugin, test cases

This commit is contained in:
Michael Cambria
2019-04-08 17:45:44 -04:00
parent 95be5da5e2
commit d47387c6fe
7 changed files with 450 additions and 57 deletions

View File

@ -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.

View File

@ -4,7 +4,7 @@
This plugin creates firewall rules to allow traffic to/from container IP address via the host network .
It does not create any network interfaces and therefore does not set up connectivity by itself.
It is only useful when used in addition to other plugins.
It is intended to be used as a chained plugins.
## Operation
The following network configuration file
@ -45,7 +45,91 @@ Available backends include `iptables` and `firewalld` and may be selected with t
If no `backend` key is given, the plugin will use firewalld if the service exists on the D-Bus system bus.
If no firewalld service is found, it will fall back to iptables.
## firewalld backend rule structure
When the `firewalld` backend is used, this example will place the IPAM allocated address for the container (e.g. 10.88.0.2) into firewalld's `trusted` zone, allowing it to send/receive traffic.
A sample standalone config list (with the file extension .conflist) using firewalld backend might
look like:
```json
{
"cniVersion": "0.3.1",
"name": "bridge-firewalld",
"plugins": [
{
"type": "bridge",
"bridge": "cni0",
"isGateway": true,
"ipMasq": true,
"ipam": {
"type": "host-local",
"subnet": "10.88.0.0/16",
"routes": [
{ "dst": "0.0.0.0/0" }
]
}
},
{
"type": "firewall",
"backend": "firewalld"
}
]
}
```
`FORWARD_IN_ZONES_SOURCE` chain:
- `-d 10.88.0.2 -j FWDI_trusted`
`CNI_FORWARD_OUT_ZONES_SOURCE` chain:
- `-s 10.88.0.2 -j FWDO_trusted`
## iptables backend rule structure
A sample standalone config list (with the file extension .conflist) using iptables backend might
look like:
```json
{
"cniVersion": "0.3.1",
"name": "bridge-firewalld",
"plugins": [
{
"type": "bridge",
"bridge": "cni0",
"isGateway": true,
"ipMasq": true,
"ipam": {
"type": "host-local",
"subnet": "10.88.0.0/16",
"routes": [
{ "dst": "0.0.0.0/0" }
]
}
},
{
"type": "firewall",
"backend": "iptables"
}
]
}
```
When the `iptables` backend is used, the above example will create two new iptables chains in the `filter` table and add rules that allow the given interface to send/receive traffic.
When the `firewalld` backend is used, the above example will place the `cni0` interface into firewalld's `trusted` zone, allowing it to send/receive traffic.
### FORWARD
A new chain, CNI-FORWARD is added to the FORWARD chain. CNI-FORWARD is the chain where rules will be added
when containers are created and from where rules will be removed when containers terminate.
`FORWARD` chain:
- `-j CNI-FORWARD`
CNI-FORWARD will have a pair of rules added, one for each direction, using the IPAM assigned IP address
of the container as shown:
`CNI_FORWARD` chain:
- `-s 10.88.0.2 -m conntrack --ctstate RELATED,ESTABLISHED -j CNI-FORWARD`
- `-d 10.88.0.2 -j CNI-FORWARD`

View File

@ -45,14 +45,12 @@ type FirewallNetConf struct {
// the firewalld backend is used but the zone is not given, it defaults
// to 'trusted'
FirewalldZone string `json:"firewalldZone,omitempty"`
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 {
@ -62,10 +60,27 @@ 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)
return nil, nil, fmt.Errorf("failed to load netconf: %v", err)
}
// Parse previous result.
if conf.RawPrevResult == nil {
return nil, nil, fmt.Errorf("missing prevResult from earlier plugin")
}
// 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)
}
result, err = current.NewResultFromResult(conf.PrevResult)
if err != nil {
return nil, nil, fmt.Errorf("could not convert result to current version: %v", err)
}
// Default the firewalld zone to trusted
@ -73,26 +88,7 @@ func parseConf(data []byte) (*FirewallNetConf, error) {
conf.FirewalldZone = "trusted"
}
// Parse previous result.
if conf.RawPrevResult == nil {
return 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)
}
res, err := version.NewResult(conf.CNIVersion, resultBytes)
if err != nil {
return nil, fmt.Errorf("could not parse prevResult: %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)
}
return &conf, nil
return &conf, result, nil
}
func getBackend(conf *FirewallNetConf) (FirewallBackend, error) {
@ -113,7 +109,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
}
@ -123,11 +119,10 @@ 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{}
}
@ -135,7 +130,7 @@ func cmdAdd(args *skel.CmdArgs) error {
}
func cmdDel(args *skel.CmdArgs) error {
conf, err := parseConf(args.StdinData)
conf, result, err := parseConf(args.StdinData)
if err != nil {
return err
}
@ -152,7 +147,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
}
@ -160,5 +155,28 @@ func cmdDel(args *skel.CmdArgs) error {
}
func main() {
skel.PluginMain(cmdAdd, cmdDel, version.All)
skel.PluginMain(cmdAdd, cmdCheck, cmdDel, version.PluginSupports("0.4.0"), "TODO")
}
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
}

View File

@ -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{
@ -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)
@ -178,7 +189,7 @@ var _ = Describe("firewalld test", func() {
IfName: ifname,
StdinData: []byte(conf),
}
_, _, err := testutils.CmdAddWithResult(targetNs.Path(), ifname, []byte(conf), func() error {
_, _, err := testutils.CmdAdd(targetNs.Path(), args.ContainerID, ifname, []byte(conf), func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())
@ -186,7 +197,7 @@ var _ = Describe("firewalld test", func() {
Expect(fwd.source).To(Equal("10.0.0.2/32"))
fwd.clear()
err = testutils.CmdDelWithResult(targetNs.Path(), ifname, func() error {
err = testutils.CmdDel(targetNs.Path(), args.ContainerID, ifname, func() error {
return cmdDel(args)
})
Expect(err).NotTo(HaveOccurred())
@ -224,7 +235,7 @@ var _ = Describe("firewalld test", func() {
IfName: ifname,
StdinData: []byte(conf),
}
_, _, err := testutils.CmdAddWithResult(targetNs.Path(), ifname, []byte(conf), func() error {
_, _, err := testutils.CmdAdd(targetNs.Path(), args.ContainerID, ifname, []byte(conf), func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())
@ -262,7 +273,7 @@ var _ = Describe("firewalld test", func() {
IfName: ifname,
StdinData: []byte(conf),
}
r, _, err := testutils.CmdAddWithResult(targetNs.Path(), ifname, []byte(conf), func() error {
r, _, err := testutils.CmdAdd(targetNs.Path(), args.ContainerID, ifname, []byte(conf), func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())
@ -275,4 +286,58 @@ 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())
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"))
})
})

View File

@ -235,7 +235,7 @@ var _ = Describe("firewall plugin iptables backend", func() {
err := originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
r, _, err := testutils.CmdAddWithResult(targetNS.Path(), IFNAME, fullConf, func() error {
r, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())
@ -264,7 +264,7 @@ var _ = Describe("firewall plugin iptables backend", func() {
err := originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
_, _, err := testutils.CmdAddWithResult(targetNS.Path(), IFNAME, fullConf, func() error {
_, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())
@ -312,7 +312,7 @@ var _ = Describe("firewall plugin iptables backend", func() {
err := originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
_, _, err := testutils.CmdAddWithResult(targetNS.Path(), IFNAME, conf, func() error {
_, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, conf, func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())
@ -350,13 +350,157 @@ var _ = Describe("firewall plugin iptables backend", func() {
err := originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
_, _, err := testutils.CmdAddWithResult(targetNS.Path(), IFNAME, fullConf, func() error {
_, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())
validateFullRuleset(fullConf)
err = testutils.CmdDelWithResult(targetNS.Path(), IFNAME, func() error {
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())
})
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())

View File

@ -18,6 +18,7 @@ import (
"fmt"
"strings"
"github.com/containernetworking/cni/pkg/types/current"
"github.com/godbus/dbus"
)
@ -31,6 +32,7 @@ const (
firewalldZoneInterface = "org.fedoraproject.FirewallD1.zone"
firewalldAddSourceMethod = "addSource"
firewalldRemoveSourceMethod = "removeSource"
firewalldQuerySourceMethod = "querySource"
errZoneAlreadySet = "ZONE_ALREADY_SET"
)
@ -80,8 +82,8 @@ func newFirewalldBackend(conf *FirewallNetConf) (FirewallBackend, error) {
return backend, nil
}
func (fb *fwdBackend) Add(conf *FirewallNetConf) error {
for _, ip := range conf.PrevResult.IPs {
func (fb *fwdBackend) Add(conf *FirewallNetConf, result *current.Result) error {
for _, ip := range result.IPs {
ipStr := ipString(ip.Address)
// Add a firewalld rule which assigns the given source IP to the given zone
firewalldObj := fb.conn.Object(firewalldName, firewalldPath)
@ -95,8 +97,8 @@ func (fb *fwdBackend) Add(conf *FirewallNetConf) error {
return nil
}
func (fb *fwdBackend) Del(conf *FirewallNetConf) error {
for _, ip := range conf.PrevResult.IPs {
func (fb *fwdBackend) Del(conf *FirewallNetConf, result *current.Result) error {
for _, ip := range result.IPs {
ipStr := ipString(ip.Address)
// Remove firewalld rules which assigned the given source IP to the given zone
firewalldObj := fb.conn.Object(firewalldName, firewalldPath)
@ -105,3 +107,16 @@ func (fb *fwdBackend) Del(conf *FirewallNetConf) error {
}
return nil
}
func (fb *fwdBackend) Check(conf *FirewallNetConf, result *current.Result) error {
for _, ip := range result.IPs {
ipStr := ipString(ip.Address)
// Check for a firewalld rule for the given source IP to the given zone
firewalldObj := fb.conn.Object(firewalldName, firewalldPath)
var res bool
if err := firewalldObj.Call(firewalldZoneInterface+"."+firewalldQuerySourceMethod, 0, conf.FirewalldZone, ipStr).Store(&res); err != nil {
return fmt.Errorf("failed to find the address %v in %v zone", ipStr, conf.FirewalldZone)
}
}
return nil
}

View File

@ -21,6 +21,7 @@ import (
"fmt"
"net"
"github.com/containernetworking/cni/pkg/types/current"
"github.com/coreos/go-iptables/iptables"
)
@ -99,9 +100,9 @@ func protoForIP(ip net.IPNet) iptables.Protocol {
return iptables.ProtocolIPv6
}
func (ib *iptablesBackend) addRules(conf *FirewallNetConf, ipt *iptables.IPTables, proto iptables.Protocol) error {
func (ib *iptablesBackend) addRules(conf *FirewallNetConf, result *current.Result, ipt *iptables.IPTables, proto iptables.Protocol) error {
rules := make([][]string, 0)
for _, ip := range conf.PrevResult.IPs {
for _, ip := range result.IPs {
if protoForIP(ip.Address) == proto {
rules = append(rules, getPrivChainRules(ipString(ip.Address))...)
}
@ -131,9 +132,9 @@ func (ib *iptablesBackend) addRules(conf *FirewallNetConf, ipt *iptables.IPTable
return nil
}
func (ib *iptablesBackend) delRules(conf *FirewallNetConf, ipt *iptables.IPTables, proto iptables.Protocol) error {
func (ib *iptablesBackend) delRules(conf *FirewallNetConf, result *current.Result, ipt *iptables.IPTables, proto iptables.Protocol) error {
rules := make([][]string, 0)
for _, ip := range conf.PrevResult.IPs {
for _, ip := range result.IPs {
if protoForIP(ip.Address) == proto {
rules = append(rules, getPrivChainRules(ipString(ip.Address))...)
}
@ -146,13 +147,69 @@ func (ib *iptablesBackend) delRules(conf *FirewallNetConf, ipt *iptables.IPTable
return nil
}
func (ib *iptablesBackend) checkRules(conf *FirewallNetConf, result *current.Result, ipt *iptables.IPTables, proto iptables.Protocol) error {
rules := make([][]string, 0)
for _, ip := range result.IPs {
if protoForIP(ip.Address) == proto {
rules = append(rules, getPrivChainRules(ipString(ip.Address))...)
}
}
if len(rules) <= 0 {
return nil
}
// Ensure our private chains exist
if err := ensureChain(ipt, "filter", ib.privChainName); err != nil {
return err
}
if err := ensureChain(ipt, "filter", ib.adminChainName); err != nil {
return err
}
// Ensure our filter rule exists in the forward chain
privRule := generateFilterRule(ib.privChainName)
privExists, err := ipt.Exists("filter", "FORWARD", privRule...)
if err != nil {
return err
}
if !privExists {
return fmt.Errorf("expected %v rule %v not found", "FORWARD", privRule)
}
// Ensure our admin override chain rule exists in our private chain
adminRule := generateFilterRule(ib.adminChainName)
adminExists, err := ipt.Exists("filter", ib.privChainName, adminRule...)
if err != nil {
return err
}
if !adminExists {
return fmt.Errorf("expected %v rule %v not found", ib.privChainName, adminRule)
}
// ensure rules for this IP address exist
for _, rule := range rules {
// Ensure our rule exists in our private chain
exists, err := ipt.Exists("filter", ib.privChainName, rule...)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("expected rule %v not found", rule)
}
}
return nil
}
func findProtos(conf *FirewallNetConf) []iptables.Protocol {
protos := []iptables.Protocol{iptables.ProtocolIPv4, iptables.ProtocolIPv6}
if conf.PrevResult != nil {
// If PrevResult is given, scan all IP addresses to figure out
// which IP versions to use
protos = []iptables.Protocol{}
for _, addr := range conf.PrevResult.IPs {
result, _ := current.NewResultFromResult(conf.PrevResult)
for _, addr := range result.IPs {
if addr.Address.IP.To4() != nil {
protos = append(protos, iptables.ProtocolIPv4)
} else {
@ -196,18 +253,27 @@ func newIptablesBackend(conf *FirewallNetConf) (FirewallBackend, error) {
return backend, nil
}
func (ib *iptablesBackend) Add(conf *FirewallNetConf) error {
func (ib *iptablesBackend) Add(conf *FirewallNetConf, result *current.Result) error {
for proto, ipt := range ib.protos {
if err := ib.addRules(conf, ipt, proto); err != nil {
if err := ib.addRules(conf, result, ipt, proto); err != nil {
return err
}
}
return nil
}
func (ib *iptablesBackend) Del(conf *FirewallNetConf) error {
func (ib *iptablesBackend) Del(conf *FirewallNetConf, result *current.Result) error {
for proto, ipt := range ib.protos {
ib.delRules(conf, ipt, proto)
ib.delRules(conf, result, ipt, proto)
}
return nil
}
func (ib *iptablesBackend) Check(conf *FirewallNetConf, result *current.Result) error {
for proto, ipt := range ib.protos {
if err := ib.checkRules(conf, result, ipt, proto); err != nil {
return err
}
}
return nil
}