From 2f98c526d1118b2ba8da2bab05624cc9e2d8f113 Mon Sep 17 00:00:00 2001
From: Swagat Bora <sbora@amazon.com>
Date: Wed, 9 Oct 2024 17:32:46 +0000
Subject: [PATCH] feat: implementation of enable_icc option + code refactor

Signed-off-by: Swagat Bora <sbora@amazon.com>
---
 go.mod                                        |   3 +-
 go.sum                                        |   2 +
 internal/service/network/bridge_driver.go     | 375 ++++++++++++++++++
 .../service/network/bridge_driver_test.go     | 123 ++++++
 internal/service/network/create.go            | 177 ++-------
 internal/service/network/create_test.go       | 145 ++++++-
 internal/service/network/remove.go            |  44 ++
 mocks/mocks_backend/nerdctlimagesvc.go        |   2 +-
 mocks/mocks_container/containersvc.go         |   2 +-
 mocks/mocks_network/bridge_driver.go          | 150 +++++++
 mocks/mocks_network/iptables.go               | 120 ++++++
 11 files changed, 998 insertions(+), 145 deletions(-)
 create mode 100644 internal/service/network/bridge_driver.go
 create mode 100644 internal/service/network/bridge_driver_test.go
 create mode 100644 mocks/mocks_network/bridge_driver.go
 create mode 100644 mocks/mocks_network/iptables.go

diff --git a/go.mod b/go.mod
index 207d507a..38c0cdea 100644
--- a/go.mod
+++ b/go.mod
@@ -13,6 +13,7 @@ require (
 	github.com/containerd/platforms v0.2.1
 	github.com/containerd/typeurl/v2 v2.2.0
 	github.com/containernetworking/cni v1.2.2
+	github.com/coreos/go-iptables v0.7.0
 	github.com/coreos/go-systemd/v22 v22.5.0
 	github.com/distribution/reference v0.6.0
 	github.com/docker/cli v26.0.0+incompatible
@@ -63,7 +64,6 @@ require (
 	github.com/containerd/typeurl v1.0.3-0.20220422153119-7f6e6d160d67 // indirect
 	github.com/containernetworking/plugins v1.4.1 // indirect
 	github.com/containers/ocicrypt v1.1.10 // indirect
-	github.com/coreos/go-iptables v0.7.0 // indirect
 	github.com/cyphar/filepath-securejoin v0.2.4 // indirect
 	github.com/djherbis/times v1.6.0 // indirect
 	github.com/docker/docker-credential-helpers v0.8.1 // indirect
@@ -138,6 +138,7 @@ require (
 	go.opentelemetry.io/otel/trace v1.30.0 // indirect
 	golang.org/x/crypto v0.27.0 // indirect
 	golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
+	golang.org/x/mod v0.20.0 // indirect
 	golang.org/x/sync v0.8.0 // indirect
 	golang.org/x/term v0.24.0 // indirect
 	golang.org/x/text v0.18.0 // indirect
diff --git a/go.sum b/go.sum
index 21c7f4b1..05aaf7c4 100644
--- a/go.sum
+++ b/go.sum
@@ -358,6 +358,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
+golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
diff --git a/internal/service/network/bridge_driver.go b/internal/service/network/bridge_driver.go
new file mode 100644
index 00000000..f6ae1dec
--- /dev/null
+++ b/internal/service/network/bridge_driver.go
@@ -0,0 +1,375 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package network
+
+import (
+	"encoding/json"
+	"fmt"
+	"os"
+	"path/filepath"
+	"strconv"
+
+	"github.com/containerd/nerdctl/pkg/lockutil"
+	"github.com/containerd/nerdctl/pkg/netutil"
+	"github.com/coreos/go-iptables/iptables"
+	"github.com/runfinch/finch-daemon/api/types"
+	"github.com/runfinch/finch-daemon/internal/backend"
+	"github.com/runfinch/finch-daemon/pkg/flog"
+)
+
+const (
+	FinchICCLabel = "finch.network.bridge.enable_icc"
+
+	BridgeICCOption             = "com.docker.network.bridge.enable_icc"
+	BridgeHostBindingIpv4Option = "com.docker.network.bridge.host_binding_ipv4"
+	BridgeNameOption            = "com.docker.network.bridge.name"
+)
+
+//go:generate mockgen --destination=../../../mocks/mocks_network/bridge_driver.go -package=mocks_network -mock_names BridgeDriverOperations=BridgeDriver . BridgeDriverOperations
+type BridgeDriverOperations interface {
+	HandleCreateOptions(request types.NetworkCreateRequest, options netutil.CreateOptions) (netutil.CreateOptions, error)
+	HandlePostCreate(net *netutil.NetworkConfig) (string, error)
+	SetBridgeName(net *netutil.NetworkConfig, bridge string) error
+	GetBridgeName(net *netutil.NetworkConfig) (string, error)
+	GetNetworkByBridgeName(bridge string) (*netutil.NetworkConfig, error)
+	DisableICC(bridgeIface string, insert bool) error
+	SetICCDisabled()
+	ICCDisabled() bool
+}
+
+// IPTablesWrapper is an interface that wraps the methods of iptables.IPTables
+// to help with mock
+//
+//go:generate mockgen --destination=../../../mocks/mocks_network/iptables.go -package=mocks_network  . IPTablesWrapper
+type IPTablesWrapper interface {
+	ChainExists(table, chain string) (bool, error)
+	NewChain(table, chain string) error
+	Insert(table, chain string, pos int, rulespec ...string) error
+	Append(table, chain string, rulespec ...string) error
+	DeleteIfExists(table, chain string, rulespec ...string) error
+}
+
+// IPTablesWrapperImpl implements IPTablesWrapper
+// that delegates to an actual iptables.IPTables instance.
+type IPTablesWrapperImpl struct {
+	ipt *iptables.IPTables
+}
+
+func NewIPTablesWrapper() IPTablesWrapper {
+	iptables, _ := iptables.NewWithProtocol(iptables.ProtocolIPv4)
+	return &IPTablesWrapperImpl{ipt: iptables}
+}
+
+func (i *IPTablesWrapperImpl) ChainExists(table, chain string) (bool, error) {
+	return i.ipt.ChainExists(table, chain)
+}
+
+func (i *IPTablesWrapperImpl) NewChain(table, chain string) error {
+	return i.ipt.NewChain(table, chain)
+}
+
+func (i *IPTablesWrapperImpl) Insert(table, chain string, pos int, rulespec ...string) error {
+	return i.ipt.Insert(table, chain, pos, rulespec...)
+}
+
+func (i *IPTablesWrapperImpl) Append(table, chain string, rulespec ...string) error {
+	return i.ipt.Append(table, chain, rulespec...)
+}
+
+func (i *IPTablesWrapperImpl) DeleteIfExists(table, chain string, rulespec ...string) error {
+	return i.ipt.DeleteIfExists(table, chain, rulespec...)
+}
+
+type bridgeDriver struct {
+	bridgeName string
+	disableICC bool
+	netClient  backend.NerdctlNetworkSvc
+	logger     flog.Logger
+	ipt        IPTablesWrapper
+}
+
+var _ BridgeDriverOperations = (*bridgeDriver)(nil)
+
+var NewBridgeDriver = func(netClient backend.NerdctlNetworkSvc, logger flog.Logger) BridgeDriverOperations {
+	return &bridgeDriver{
+		netClient: netClient,
+		logger:    logger,
+		ipt:       NewIPTablesWrapper(),
+	}
+}
+
+// handleBridgeDriverOptions filters unsupported options for the bridge driver.
+func (bd *bridgeDriver) HandleCreateOptions(request types.NetworkCreateRequest, options netutil.CreateOptions) (netutil.CreateOptions, error) {
+	// enable_icc, host_binding_ipv4, and bridge name network options are not supported by nerdctl.
+	// So we must filter out any unsupported options which would prevent the network from being created and accept the defaults.
+	filterUnsupportedOptions := func(original map[string]string) map[string]string {
+		opts := map[string]string{}
+		for k, v := range original {
+			switch k {
+			case BridgeHostBindingIpv4Option:
+				if v != "0.0.0.0" {
+					bd.logger.Warnf("network option com.docker.network.bridge.host_binding_ipv4 is set to %s, but it must be 0.0.0.0", v)
+				}
+			case BridgeICCOption:
+				iccOption, err := strconv.ParseBool(v) //t
+				if err != nil {
+					bd.logger.Warnf("invalid value for com.docker.network.bridge.enable_icc: %s", v)
+				}
+				if !iccOption {
+					bd.SetICCDisabled()
+				}
+
+			case BridgeNameOption:
+				bd.bridgeName = v
+			default:
+				opts[k] = v
+			}
+		}
+		return opts
+	}
+
+	options.Options = filterUnsupportedOptions(request.Options)
+
+	if bd.ICCDisabled() {
+		// Append a label when enable_icc is set to false. This is used for clean up during network removal.
+		options.Labels = append(options.Labels, FinchICCLabel+"=false")
+	}
+
+	// Return the modified options
+	return options, nil
+}
+
+func (bd *bridgeDriver) HandlePostCreate(net *netutil.NetworkConfig) (string, error) {
+	// Handle bridge driver post create actions
+	var warning string
+	var err error
+	bridgeName := bd.bridgeName
+	if bridgeName != "" {
+		// Since nerdctl currently does not support custom bridge names,
+		// we explicitly override bridge name in the conflist file for the network that was just created
+		if err = bd.SetBridgeName(net, bridgeName); err != nil {
+			warning = fmt.Sprintf("Failed to set network bridge name %s: %s", bridgeName, err)
+		}
+	}
+
+	if bd.ICCDisabled() {
+		// Handle "enable_icc=false" option if set (bd.disableICC is true)
+		// By default, CNI allows connectivity between containers attached to the same bridge.
+		// If "com.docker.network.bridge.enable_icc" option is explicitly set to false,
+		// we disable inter-container connectivity by applying iptable rules
+		// If "com.docker.network.bridge.enable_icc=true" is set, it is considered a noop
+		if bridgeName == "" {
+			bridgeName, err = bd.GetBridgeName(net)
+			if err != nil {
+				return "", fmt.Errorf("failed to get bridge name to enable inter-container connectivity: %w ", err)
+			}
+		}
+		err = bd.DisableICC(bridgeName, true)
+		if err != nil {
+			return "", fmt.Errorf("failed to disable inter-container connectivity: %w", err)
+		}
+	}
+
+	return warning, nil
+}
+
+// setBridgeName will override the bridge name in an existing CNI config file for a network.
+func (bd *bridgeDriver) SetBridgeName(net *netutil.NetworkConfig, bridge string) error {
+	return lockutil.WithDirLock(bd.netClient.NetconfPath(), func() error {
+		// first, make sure that the bridge name is not used by any of the existing bridge networks
+		bridgeNet, err := bd.GetNetworkByBridgeName(bridge)
+		if err != nil {
+			return err
+		}
+		if bridgeNet != nil {
+			return fmt.Errorf("bridge name %s already in use by network %s", bridge, bridgeNet.Name)
+		}
+
+		// load the CNI config file and set bridge name
+		configFilename := bd.getConfigPathForNetworkName(net.Name)
+		configFile, err := os.Open(configFilename)
+		if err != nil {
+			return err
+		}
+		defer configFile.Close()
+		var netJSON interface{}
+		if err = json.NewDecoder(configFile).Decode(&netJSON); err != nil {
+			return err
+		}
+		netMap, ok := netJSON.(map[string]interface{})
+		if !ok {
+			return fmt.Errorf("network config file %s is not a valid map", configFilename)
+		}
+		plugins, ok := netMap["plugins"]
+		if !ok {
+			return fmt.Errorf("could not find plugins in network config file %s", configFilename)
+		}
+		pluginsMap, ok := plugins.([]interface{})
+		if !ok {
+			return fmt.Errorf("could not parse plugins in network config file %s", configFilename)
+		}
+		for _, plugin := range pluginsMap {
+			pluginMap, ok := plugin.(map[string]interface{})
+			if !ok {
+				continue
+			}
+			if pluginMap["type"] == "bridge" {
+				pluginMap["bridge"] = bridge
+				data, err := json.MarshalIndent(netJSON, "", "  ")
+				if err != nil {
+					return err
+				}
+				return os.WriteFile(configFilename, data, 0o644)
+			}
+		}
+		return fmt.Errorf("bridge plugin not found in network config file %s", configFilename)
+	})
+}
+
+func (bd *bridgeDriver) GetBridgeName(net *netutil.NetworkConfig) (string, error) {
+	var bridgeName string
+	err := lockutil.WithDirLock(bd.netClient.NetconfPath(), func() error {
+		configFilename := bd.getConfigPathForNetworkName(net.Name)
+		configFile, err := os.Open(configFilename)
+		if err != nil {
+			return err
+		}
+		defer configFile.Close()
+
+		var netJSON interface{}
+		if err = json.NewDecoder(configFile).Decode(&netJSON); err != nil {
+			return err
+		}
+
+		netMap, ok := netJSON.(map[string]interface{})
+		if !ok {
+			return fmt.Errorf("network config file %s is not a valid map", configFilename)
+		}
+
+		plugins, ok := netMap["plugins"]
+		if !ok {
+			return fmt.Errorf("could not find plugins in network config file %s", configFilename)
+		}
+
+		pluginsMap, ok := plugins.([]interface{})
+		if !ok {
+			return fmt.Errorf("could not parse plugins in network config file %s", configFilename)
+		}
+
+		for _, plugin := range pluginsMap {
+			pluginMap, ok := plugin.(map[string]interface{})
+			if !ok {
+				continue
+			}
+			if pluginMap["type"] == "bridge" {
+				bridge, ok := pluginMap["bridge"].(string)
+				if !ok {
+					return fmt.Errorf("bridge name in config file %s is not a string", configFilename)
+				}
+				bridgeName = bridge
+				return nil
+			}
+		}
+
+		return fmt.Errorf("bridge plugin not found in network config file %s", configFilename)
+	})
+
+	if err != nil {
+		return "", err
+	}
+
+	return bridgeName, nil
+}
+
+type bridgePlugin struct {
+	Type   string `json:"type"`
+	Bridge string `json:"bridge"`
+}
+
+func (bd *bridgeDriver) GetNetworkByBridgeName(bridge string) (*netutil.NetworkConfig, error) {
+	networks, err := bd.netClient.FilterNetworks(func(*netutil.NetworkConfig) bool {
+		return true
+	})
+	if err != nil {
+		return nil, err
+	}
+	for _, network := range networks {
+		for _, plugin := range network.Plugins {
+			if plugin.Network.Type != "bridge" {
+				continue
+			}
+			var bridgeJSON bridgePlugin
+			if err = json.Unmarshal(plugin.Bytes, &bridgeJSON); err != nil {
+				continue
+			}
+			if bridgeJSON.Bridge == bridge {
+				return network, nil
+			}
+		}
+	}
+	return nil, nil
+}
+
+func (bd *bridgeDriver) SetICCDisabled() {
+	bd.disableICC = true
+}
+
+func (bd *bridgeDriver) ICCDisabled() bool {
+	return bd.disableICC
+}
+
+func (bd *bridgeDriver) DisableICC(bridgeIface string, insert bool) error {
+	filterTable := "filter"
+	isolateChain := "FINCH-ISOLATE-CHAIN"
+
+	if bd.ipt == nil {
+		return fmt.Errorf("iptables is not initialized")
+	}
+
+	// Check if the FINCH-ISOLATE-CHAIN already exists
+	exists, err := bd.ipt.ChainExists(filterTable, isolateChain)
+	if err != nil {
+		return fmt.Errorf("failed to check if %s chain exists: %v", isolateChain, err)
+	}
+
+	if !exists {
+		// Create and setup the FINCH-ISOLATE-CHAIN chain if it doesn't exist
+		err = bd.ipt.NewChain(filterTable, isolateChain)
+		if err != nil {
+			return fmt.Errorf("failed to create %s chain: %v", isolateChain, err)
+		}
+		// Add a rule to the FORWARD chain that jumps to the FINCH-ISOLATE-CHAIN for all packets
+		jumpRule := []string{"-j", isolateChain}
+		err = bd.ipt.Insert(filterTable, "FORWARD", 1, jumpRule...)
+		if err != nil {
+			return fmt.Errorf("failed to add %s jump rule to FORWARD chain: %v", isolateChain, err)
+		}
+		// In the FINCH-ISOLATE-CHAIN, add a rule to return to the FORWARD chain if no match
+		returnRule := []string{"-j", "RETURN"}
+		err = bd.ipt.Append(filterTable, isolateChain, returnRule...)
+		if err != nil {
+			return fmt.Errorf("failed to add RETURN rule to DOCKER-ISOLATE chain: %v", err)
+		}
+	}
+
+	// In the FINCH-ISOLATE-CHAIN, add or remove the DROP rule for packets from and to the same bridge
+	dropRule := []string{"-i", bridgeIface, "-o", bridgeIface, "-j", "DROP"}
+	if insert {
+		err = bd.ipt.Insert(filterTable, isolateChain, 1, dropRule...)
+		if err != nil {
+			return fmt.Errorf("failed to add DROP rule to %s chain: %v", isolateChain, err)
+		}
+	} else {
+		err = bd.ipt.DeleteIfExists(filterTable, isolateChain, dropRule...)
+		if err != nil {
+			return fmt.Errorf("failed to remove DROP rule from %s chain: %v", isolateChain, err)
+		}
+	}
+	return nil
+}
+
+// From https://github.com/containerd/nerdctl/blob/v1.5.0/pkg/netutil/netutil.go#L186-L188
+func (bd *bridgeDriver) getConfigPathForNetworkName(netName string) string {
+	return filepath.Join(bd.netClient.NetconfPath(), "nerdctl-"+netName+".conflist")
+}
diff --git a/internal/service/network/bridge_driver_test.go b/internal/service/network/bridge_driver_test.go
new file mode 100644
index 00000000..93b3e3a0
--- /dev/null
+++ b/internal/service/network/bridge_driver_test.go
@@ -0,0 +1,123 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package network
+
+import (
+	"fmt"
+
+	"github.com/golang/mock/gomock"
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
+	"github.com/runfinch/finch-daemon/mocks/mocks_network"
+)
+
+var _ = Describe("bridgeDriver DisableICC", func() {
+	var (
+		mockController *gomock.Controller
+		mockIpt        *mocks_network.MockIPTablesWrapper
+		driver         *bridgeDriver
+		bridgeIface    string
+	)
+
+	BeforeEach(func() {
+		mockController = gomock.NewController(GinkgoT())
+		mockIpt = mocks_network.NewMockIPTablesWrapper(mockController)
+		driver = &bridgeDriver{ipt: mockIpt}
+		bridgeIface = "br-mock"
+	})
+
+	Context("FINCH-ISOLATE-CHAIN chain does not exist", func() {
+		BeforeEach(func() {
+			// FINCH-ISOLATE-CHAIN does not exist initially
+			mockIpt.EXPECT().ChainExists("filter", "FINCH-ISOLATE-CHAIN").Return(false, nil)
+
+			// NewChain method should be called
+			mockIpt.EXPECT().NewChain("filter", "FINCH-ISOLATE-CHAIN").Return(nil)
+
+			// Expect a rule to be added to FORWARD chain that jumps to FINCH-ISOLATE-CHAIN
+			mockIpt.EXPECT().Insert("filter", "FORWARD", 1, "-j", "FINCH-ISOLATE-CHAIN").Return(nil)
+			// Expect a RETURN rule to be appended in FINCH-ISOLATE-CHAIN
+			mockIpt.EXPECT().Append("filter", "FINCH-ISOLATE-CHAIN", "-j", "RETURN").Return(nil)
+
+			// Expect the second Insert call to FINCH-ISOLATE-CHAIN for the DROP rule
+			mockIpt.EXPECT().Insert("filter", "FINCH-ISOLATE-CHAIN", 1, "-i", bridgeIface, "-o", bridgeIface, "-j", "DROP").Return(nil)
+		})
+
+		It("should create and set up the FINCH-ISOLATE-CHAIN", func() {
+			err := driver.DisableICC(bridgeIface, true)
+			Expect(err).ShouldNot(HaveOccurred())
+		})
+	})
+
+	Context("FINCH-ISOLATE-CHAIN exists", func() {
+		BeforeEach(func() {
+			mockIpt.EXPECT().ChainExists("filter", "FINCH-ISOLATE-CHAIN").Return(true, nil)
+		})
+
+		When("insert set to true", func() {
+			BeforeEach(func() {
+				// Expect the DROP rule to be inserted for packets from and to the same bridge
+				mockIpt.EXPECT().Insert("filter", "FINCH-ISOLATE-CHAIN", 1, "-i", bridgeIface, "-o", bridgeIface, "-j", "DROP").Return(nil)
+			})
+
+			It("should add the DROP rule to the FINCH-ISOLATE-CHAIN", func() {
+				err := driver.DisableICC(bridgeIface, true)
+				Expect(err).ShouldNot(HaveOccurred())
+			})
+		})
+
+		When("insert set to false", func() {
+			BeforeEach(func() {
+				// Expect the DROP rule to be removed for packets from and to the same bridge
+				mockIpt.EXPECT().DeleteIfExists("filter", "FINCH-ISOLATE-CHAIN", "-i", bridgeIface, "-o", bridgeIface, "-j", "DROP").Return(nil)
+			})
+
+			It("should remove the DROP rule from the FINCH-ISOLATE-CHAIN", func() {
+				err := driver.DisableICC(bridgeIface, false)
+				Expect(err).ShouldNot(HaveOccurred())
+			})
+		})
+	})
+
+	Context("when iptables returns an error", func() {
+		It("should return an error if ChainExists fails", func() {
+			mockIpt.EXPECT().ChainExists("filter", "FINCH-ISOLATE-CHAIN").Return(false, fmt.Errorf("iptables error"))
+
+			err := driver.DisableICC(bridgeIface, true)
+			Expect(err).Should(HaveOccurred())
+			Expect(err.Error()).To(ContainSubstring("failed to check if FINCH-ISOLATE-CHAIN chain exists"))
+		})
+
+		It("should return an error if NewChain fails", func() {
+			mockIpt.EXPECT().ChainExists("filter", "FINCH-ISOLATE-CHAIN").Return(false, nil)
+
+			mockIpt.EXPECT().NewChain("filter", "FINCH-ISOLATE-CHAIN").Return(fmt.Errorf("iptables error"))
+
+			err := driver.DisableICC(bridgeIface, true)
+			Expect(err).Should(HaveOccurred())
+			Expect(err.Error()).To(ContainSubstring("failed to create FINCH-ISOLATE-CHAIN chain"))
+		})
+
+		It("should return an error if Insert fails while adding DROP rule", func() {
+			mockIpt.EXPECT().ChainExists("filter", "FINCH-ISOLATE-CHAIN").Return(true, nil)
+
+			mockIpt.EXPECT().Insert("filter", "FINCH-ISOLATE-CHAIN", 1, "-i", bridgeIface, "-o", bridgeIface, "-j", "DROP").Return(fmt.Errorf("iptables error"))
+
+			err := driver.DisableICC(bridgeIface, true)
+			Expect(err).Should(HaveOccurred())
+			Expect(err.Error()).To(ContainSubstring("failed to add DROP rule"))
+		})
+
+		It("should return an error if Delete fails while removing DROP rule", func() {
+			mockIpt.EXPECT().ChainExists("filter", "FINCH-ISOLATE-CHAIN").Return(true, nil)
+
+			// Simulate an error while removing the DROP rule
+			mockIpt.EXPECT().DeleteIfExists("filter", "FINCH-ISOLATE-CHAIN", "-i", bridgeIface, "-o", bridgeIface, "-j", "DROP").Return(fmt.Errorf("iptables error"))
+
+			err := driver.DisableICC(bridgeIface, false)
+			Expect(err).Should(HaveOccurred())
+			Expect(err.Error()).To(ContainSubstring("failed to remove DROP rule"))
+		})
+	})
+})
diff --git a/internal/service/network/create.go b/internal/service/network/create.go
index 031718d3..1933acfe 100644
--- a/internal/service/network/create.go
+++ b/internal/service/network/create.go
@@ -5,13 +5,9 @@ package network
 
 import (
 	"context"
-	"encoding/json"
 	"fmt"
-	"os"
-	"path/filepath"
 	"strings"
 
-	"github.com/containerd/nerdctl/pkg/lockutil"
 	"github.com/containerd/nerdctl/pkg/netutil"
 
 	"github.com/runfinch/finch-daemon/api/types"
@@ -21,49 +17,28 @@ import (
 
 // Create implements the logic to turn a network create request to the back-end nerdctl create network calls.
 func (s *service) Create(ctx context.Context, request types.NetworkCreateRequest) (types.NetworkCreateResponse, error) {
-	// enable_ip_masquerade, host_binding_ipv4, and bridge name network options are not supported by nerdctl.
-	// So we must filter out any unsupported options which would prevent the network from being created and accept the defaults.
-	bridge := ""
-	filterUnsupportedOptions := func(original map[string]string) map[string]string {
-		options := map[string]string{}
-		for k, v := range original {
-			switch k {
-			case "com.docker.network.bridge.enable_ip_masquerade":
-				// must be true
-				if v != "true" {
-					s.logger.Warnf("network option com.docker.network.bridge.enable_ip_masquerade is set to %s, but it must be true", v)
-				}
-			case "com.docker.network.bridge.host_binding_ipv4":
-				// must be 0.0.0.0
-				if v != "0.0.0.0" {
-					s.logger.Warnf("network option com.docker.network.bridge.host_binding_ipv4 is set to %s, but it must be 0.0.0.0", v)
-				}
-			case "com.docker.network.bridge.enable_icc":
-				s.logger.Warnf("network option com.docker.network.bridge.enable_icc is not currently supported in nerdctl", v)
-			case "com.docker.network.bridge.name":
-				bridge = v
-			default:
-				options[k] = v
-			}
+	var bridgeDriver BridgeDriverOperations
+	var err error
+
+	createOptionsFrom := func(request types.NetworkCreateRequest) (netutil.CreateOptions, error) {
+		// Default to "bridge" driver if request does not specify a driver
+		driver := request.Driver
+		if driver == "" {
+			driver = "bridge"
 		}
-		return options
-	}
 
-	createOptionsFrom := func(r types.NetworkCreateRequest) netutil.CreateOptions {
 		options := netutil.CreateOptions{
-			Name:        r.Name,
-			Driver:      "bridge",
+			Name:        request.Name,
+			Driver:      driver,
 			IPAMDriver:  "default",
-			IPAMOptions: r.IPAM.Options,
-			Options:     filterUnsupportedOptions(r.Options),
-			Labels:      maputility.Flatten(r.Labels, maputility.KeyEqualsValueFormat),
+			IPAMOptions: request.IPAM.Options,
+			Labels:      maputility.Flatten(request.Labels, maputility.KeyEqualsValueFormat),
 		}
-		if r.Driver != "" {
-			options.Driver = r.Driver
-		}
-		if r.IPAM.Driver != "" {
-			options.IPAMDriver = r.IPAM.Driver
+
+		if request.IPAM.Driver != "" {
+			options.IPAMDriver = request.IPAM.Driver
 		}
+
 		if len(request.IPAM.Config) != 0 {
 			options.Subnets = []string{}
 			if subnet, ok := request.IPAM.Config[0]["Subnet"]; ok {
@@ -76,7 +51,18 @@ func (s *service) Create(ctx context.Context, request types.NetworkCreateRequest
 				options.Gateway = gateway
 			}
 		}
-		return options
+
+		// Handle driver-specific options
+		switch driver {
+		case "bridge":
+			bridgeDriver = NewBridgeDriver(s.netClient, s.logger)
+			options, err = bridgeDriver.HandleCreateOptions(request, options)
+			return options, err
+		default:
+			options.Options = request.Options
+		}
+
+		return options, nil
 	}
 
 	if config, err := s.getNetwork(request.Name); err == nil {
@@ -92,8 +78,13 @@ func (s *service) Create(ctx context.Context, request types.NetworkCreateRequest
 		return response, nil
 	}
 
-	net, err := s.netClient.CreateNetwork(createOptionsFrom(request))
-	warning := ""
+	options, err := createOptionsFrom(request)
+	if err != nil {
+		return types.NetworkCreateResponse{}, err
+	}
+
+	// Create network
+	net, err := s.netClient.CreateNetwork(options)
 	if err != nil && strings.Contains(err.Error(), "unsupported cni driver") {
 		return types.NetworkCreateResponse{}, errdefs.NewNotFound(errPluginNotFound)
 	} else if err != nil {
@@ -104,11 +95,12 @@ func (s *service) Create(ctx context.Context, request types.NetworkCreateRequest
 		return types.NetworkCreateResponse{}, errNetworkIDNotFound
 	}
 
-	// Since nerdctl currently does not support custom bridge names,
-	// we explicitly override bridge name in the conflist file for the network that was just created
-	if bridge != "" {
-		if err = s.setBridgeName(net, bridge); err != nil {
-			warning = fmt.Sprintf("Failed to set network bridge name %s: %s", bridge, err)
+	// Handle post network create actions
+	warning := ""
+	if bridgeDriver != nil {
+		warning, err = bridgeDriver.HandlePostCreate(net)
+		if err != nil {
+			return types.NetworkCreateResponse{}, err
 		}
 	}
 
@@ -117,90 +109,3 @@ func (s *service) Create(ctx context.Context, request types.NetworkCreateRequest
 		Warning: warning,
 	}, nil
 }
-
-// setBridgeName will override the bridge name in an existing CNI config file for a network.
-func (s *service) setBridgeName(net *netutil.NetworkConfig, bridge string) error {
-	return lockutil.WithDirLock(s.netClient.NetconfPath(), func() error {
-		// first, make sure that the bridge name is not used by any of the existing bridge networks
-		bridgeNet, err := s.getNetworkByBridgeName(bridge)
-		if err != nil {
-			return err
-		}
-		if bridgeNet != nil {
-			return fmt.Errorf("bridge name %s already in use by network %s", bridge, bridgeNet.Name)
-		}
-
-		// load the CNI config file and set bridge name
-		configFilename := s.getConfigPathForNetworkName(net.Name)
-		configFile, err := os.Open(configFilename)
-		if err != nil {
-			return err
-		}
-		defer configFile.Close()
-		var netJSON interface{}
-		if err = json.NewDecoder(configFile).Decode(&netJSON); err != nil {
-			return err
-		}
-		netMap, ok := netJSON.(map[string]interface{})
-		if !ok {
-			return fmt.Errorf("network config file %s is not a valid map", configFilename)
-		}
-		plugins, ok := netMap["plugins"]
-		if !ok {
-			return fmt.Errorf("could not find plugins in network config file %s", configFilename)
-		}
-		pluginsMap, ok := plugins.([]interface{})
-		if !ok {
-			return fmt.Errorf("could not parse plugins in network config file %s", configFilename)
-		}
-		for _, plugin := range pluginsMap {
-			pluginMap, ok := plugin.(map[string]interface{})
-			if !ok {
-				continue
-			}
-			if pluginMap["type"] == "bridge" {
-				pluginMap["bridge"] = bridge
-				data, err := json.MarshalIndent(netJSON, "", "  ")
-				if err != nil {
-					return err
-				}
-				return os.WriteFile(configFilename, data, 0o644)
-			}
-		}
-		return fmt.Errorf("bridge plugin not found in network config file %s", configFilename)
-	})
-}
-
-// From https://github.com/containerd/nerdctl/blob/v1.5.0/pkg/netutil/netutil.go#L186-L188
-func (s *service) getConfigPathForNetworkName(netName string) string {
-	return filepath.Join(s.netClient.NetconfPath(), "nerdctl-"+netName+".conflist")
-}
-
-type bridgePlugin struct {
-	Type   string `json:"type"`
-	Bridge string `json:"bridge"`
-}
-
-func (s *service) getNetworkByBridgeName(bridge string) (*netutil.NetworkConfig, error) {
-	networks, err := s.netClient.FilterNetworks(func(*netutil.NetworkConfig) bool {
-		return true
-	})
-	if err != nil {
-		return nil, err
-	}
-	for _, network := range networks {
-		for _, plugin := range network.Plugins {
-			if plugin.Network.Type != "bridge" {
-				continue
-			}
-			var bridgeJSON bridgePlugin
-			if err = json.Unmarshal(plugin.Bytes, &bridgeJSON); err != nil {
-				continue
-			}
-			if bridgeJSON.Bridge == bridge {
-				return network, nil
-			}
-		}
-	}
-	return nil, nil
-}
diff --git a/internal/service/network/create_test.go b/internal/service/network/create_test.go
index edcd302e..294fe6c1 100644
--- a/internal/service/network/create_test.go
+++ b/internal/service/network/create_test.go
@@ -6,6 +6,7 @@ package network
 import (
 	"context"
 	"errors"
+	"fmt"
 
 	"github.com/containerd/nerdctl/pkg/netutil"
 	"github.com/golang/mock/gomock"
@@ -14,8 +15,11 @@ import (
 
 	"github.com/runfinch/finch-daemon/api/handlers/network"
 	"github.com/runfinch/finch-daemon/api/types"
+	"github.com/runfinch/finch-daemon/internal/backend"
 	"github.com/runfinch/finch-daemon/mocks/mocks_backend"
 	"github.com/runfinch/finch-daemon/mocks/mocks_logger"
+	"github.com/runfinch/finch-daemon/mocks/mocks_network"
+	"github.com/runfinch/finch-daemon/pkg/flog"
 )
 
 var _ = Describe("Network Service Create Network Implementation", func() {
@@ -25,12 +29,13 @@ var _ = Describe("Network Service Create Network Implementation", func() {
 	)
 
 	var (
-		ctx            context.Context
-		mockController *gomock.Controller
-		cdClient       *mocks_backend.MockContainerdClient
-		ncNetClient    *mocks_backend.MockNerdctlNetworkSvc
-		logger         *mocks_logger.Logger
-		service        network.Service
+		ctx              context.Context
+		mockController   *gomock.Controller
+		cdClient         *mocks_backend.MockContainerdClient
+		ncNetClient      *mocks_backend.MockNerdctlNetworkSvc
+		logger           *mocks_logger.Logger
+		service          network.Service
+		mockBridgeDriver *mocks_network.BridgeDriver
 	)
 
 	BeforeEach(func() {
@@ -40,6 +45,7 @@ var _ = Describe("Network Service Create Network Implementation", func() {
 		ncNetClient = mocks_backend.NewMockNerdctlNetworkSvc(mockController)
 		logger = mocks_logger.NewLogger(mockController)
 		service = NewService(cdClient, ncNetClient, logger)
+		mockBridgeDriver = mocks_network.NewBridgeDriver(mockController)
 	})
 
 	When("a create network call is successful", func() {
@@ -336,4 +342,131 @@ var _ = Describe("Network Service Create Network Implementation", func() {
 			})
 		})
 	})
+
+	Context("ICC configuration", func() {
+		When("com.docker.network.bridge.enable_icc is set to true in the request", func() {
+			It("should not change default behavior", func() {
+				request := types.NewCreateNetworkRequest(
+					networkName,
+					types.WithOptions(map[string]string{
+						"com.docker.network.bridge.enable_icc": "true",
+					}),
+				)
+
+				ncNetClient.EXPECT().FilterNetworks(gomock.Any()).Return([]*netutil.NetworkConfig{}, nil)
+				logger.EXPECT().Debugf(gomock.Any(), gomock.Any())
+
+				nid := networkID
+				ncNetClient.EXPECT().CreateNetwork(gomock.Any()).DoAndReturn(func(actual netutil.CreateOptions) (*netutil.NetworkConfig, error) {
+					// Check if the label exists
+					checkLabel := "com.docker.network.bridge.enable_icc=true"
+					labelExists := false
+					for _, label := range actual.Labels {
+						if label == checkLabel {
+							labelExists = true
+							break
+						}
+					}
+
+					// Expect that DisableICC is not called
+					mockBridgeDriver.EXPECT().DisableICC(gomock.Any(), gomock.Any()).Times(0)
+
+					Expect(labelExists).To(BeFalse(), fmt.Sprintf("Label '%s' should not exist in Labels", checkLabel))
+
+					return &netutil.NetworkConfig{NerdctlID: &nid}, nil
+				})
+
+				response, err := service.Create(ctx, *request)
+				Expect(err).ShouldNot(HaveOccurred())
+				Expect(response.ID).Should(Equal(networkID))
+			})
+		})
+
+		When("ICC is not specified in the request", func() {
+			It("should use the default setting in the create options and not set any icc labels", func() {
+				request := types.NewCreateNetworkRequest(networkName)
+
+				ncNetClient.EXPECT().FilterNetworks(gomock.Any()).Return([]*netutil.NetworkConfig{}, nil)
+				logger.EXPECT().Debugf(gomock.Any(), gomock.Any())
+
+				nid := networkID
+				ncNetClient.EXPECT().CreateNetwork(gomock.Any()).DoAndReturn(func(actual netutil.CreateOptions) (*netutil.NetworkConfig, error) {
+					// Check if the label exists
+					expectedLabel := "com.docker.network.bridge.enable_icc=true"
+					labelExists := false
+					for _, label := range actual.Labels {
+						if label == expectedLabel {
+							labelExists = true
+							break
+						}
+					}
+
+					Expect(labelExists).To(BeFalse(), fmt.Sprintf("Label '%s' should not exist in Labels", expectedLabel))
+
+					return &netutil.NetworkConfig{NerdctlID: &nid}, nil
+				})
+
+				response, err := service.Create(ctx, *request)
+				Expect(err).ShouldNot(HaveOccurred())
+				Expect(response.ID).Should(Equal(networkID))
+			})
+		})
+
+		When("com.docker.network.bridge.enable_icc is set to false in the request", func() {
+			It("should set ICC to false in the create options", func() {
+				request := types.NewCreateNetworkRequest(
+					networkName,
+					types.WithOptions(map[string]string{
+						BridgeICCOption: "false",
+					}),
+				)
+
+				ncNetClient.EXPECT().FilterNetworks(gomock.Any()).Return([]*netutil.NetworkConfig{}, nil)
+				logger.EXPECT().Debugf(gomock.Any(), gomock.Any())
+
+				nid := networkID
+				ncNetClient.EXPECT().CreateNetwork(gomock.Any()).DoAndReturn(func(actual netutil.CreateOptions) (*netutil.NetworkConfig, error) {
+					// Check if the label exists
+					expectedLabel := FinchICCLabel + "=false"
+					labelExists := false
+					for _, label := range actual.Labels {
+						if label == expectedLabel {
+							labelExists = true
+							break
+						}
+					}
+
+					Expect(labelExists).To(BeTrue(), fmt.Sprintf("Label '%s' should exist in Labels", expectedLabel))
+
+					return &netutil.NetworkConfig{NerdctlID: &nid}, nil
+				})
+
+				originalDriverFunc := NewBridgeDriver
+				NewBridgeDriver = func(netClient backend.NerdctlNetworkSvc, logger flog.Logger) BridgeDriverOperations {
+					return mockBridgeDriver
+				}
+				defer func() { NewBridgeDriver = originalDriverFunc }()
+
+				// Set up expectations for mockBridgeDriver
+				mockBridgeDriver.EXPECT().HandleCreateOptions(gomock.Any(), gomock.Any()).DoAndReturn(
+					func(request types.NetworkCreateRequest, options netutil.CreateOptions) (netutil.CreateOptions, error) {
+						// Mock the behavior for BridgeICCOption set to false
+						// Remove the option from the options map
+						fmt.Println("HandleCreateOptions called with options:", options)
+						delete(options.Options, BridgeICCOption)
+						options.Labels = append(options.Labels, FinchICCLabel+"=false")
+						return options, nil
+					}).AnyTimes()
+
+				mockBridgeDriver.EXPECT().HandlePostCreate(gomock.Any()).Return("", nil).AnyTimes()
+				mockBridgeDriver.EXPECT().ICCDisabled().DoAndReturn(func() bool {
+					return true
+				}).AnyTimes()
+
+				response, err := service.Create(ctx, *request)
+				Expect(err).ShouldNot(HaveOccurred())
+				Expect(response.ID).Should(Equal(networkID))
+			})
+		})
+	})
 })
diff --git a/internal/service/network/remove.go b/internal/service/network/remove.go
index 674bb49e..e9c3a6cf 100644
--- a/internal/service/network/remove.go
+++ b/internal/service/network/remove.go
@@ -7,6 +7,7 @@ import (
 	"context"
 	"fmt"
 
+	"github.com/containerd/nerdctl/pkg/netutil"
 	"github.com/runfinch/finch-daemon/pkg/errdefs"
 )
 
@@ -25,8 +26,51 @@ func (s *service) Remove(ctx context.Context, networkId string) error {
 	if value, ok := usedNetworkInfo[net.Name]; ok {
 		return errdefs.NewForbidden(fmt.Errorf("network %q is in use by container %q", networkId, value))
 	}
+
 	if net.File == "" {
 		return errdefs.NewForbidden(fmt.Errorf("%s is a pre-defined network and cannot be removed", networkId))
 	}
+
+	// Perform additional workflow based on the assigned network labels
+	if err := s.handleNetworkLabels(net); err != nil {
+		return fmt.Errorf("failed to handle nerdctl label: %w", err)
+	}
+
 	return s.netClient.RemoveNetwork(net)
 }
+
+func (s *service) handleNetworkLabels(net *netutil.NetworkConfig) error {
+	if net.NerdctlLabels == nil {
+		return nil
+	}
+
+	for key, value := range *net.NerdctlLabels {
+		switch key {
+		case FinchICCLabel:
+			if err := s.handleEnableICCOption(net, value); err != nil {
+				return fmt.Errorf("error handling %s label: %w", BridgeICCOption, err)
+			}
+		}
+	}
+	return nil
+}
+
+func (s *service) handleEnableICCOption(net *netutil.NetworkConfig, value string) error {
+	if value != "false" {
+		// for some reason the label value got modified.
+		// we will still try to remove the iptable rules.
+		// iptable.DeleteIfExists is used to ignore non-existent errors
+		s.logger.Warnf("unexpected value for %s label: %s", BridgeICCOption, value)
+	}
+	// Remove iptable rules set for disabling ICC for the network bridge
+	bridgeDriver := NewBridgeDriver(s.netClient, s.logger)
+	bridgeName, err := bridgeDriver.GetBridgeName(net)
+	if err != nil {
+		return fmt.Errorf("unable to get bridge name: %w", err)
+	}
+	err = bridgeDriver.DisableICC(bridgeName, false)
+	if err != nil {
+		return fmt.Errorf("unable to remove ICC disable rule: %w", err)
+	}
+	return nil
+}
diff --git a/mocks/mocks_backend/nerdctlimagesvc.go b/mocks/mocks_backend/nerdctlimagesvc.go
index 018db5da..e4121ae2 100644
--- a/mocks/mocks_backend/nerdctlimagesvc.go
+++ b/mocks/mocks_backend/nerdctlimagesvc.go
@@ -10,12 +10,12 @@ import (
 	reflect "reflect"
 
 	images "github.com/containerd/containerd/images"
-	platforms "github.com/containerd/platforms"
 	remotes "github.com/containerd/containerd/remotes"
 	docker "github.com/containerd/containerd/remotes/docker"
 	imgutil "github.com/containerd/nerdctl/pkg/imgutil"
 	dockerconfigresolver "github.com/containerd/nerdctl/pkg/imgutil/dockerconfigresolver"
 	dockercompat "github.com/containerd/nerdctl/pkg/inspecttypes/dockercompat"
+	platforms "github.com/containerd/platforms"
 	gomock "github.com/golang/mock/gomock"
 	v1 "github.com/opencontainers/image-spec/specs-go/v1"
 )
diff --git a/mocks/mocks_container/containersvc.go b/mocks/mocks_container/containersvc.go
index be39abd1..7b80ef56 100644
--- a/mocks/mocks_container/containersvc.go
+++ b/mocks/mocks_container/containersvc.go
@@ -191,7 +191,7 @@ func (m *MockService) Restart(arg0 context.Context, arg1 string, arg2 time.Durat
 	ret0, _ := ret[0].(error)
 	return ret0
 }
- 
+
 // Restart indicates an expected call of Restart.
 func (mr *MockServiceMockRecorder) Restart(arg0, arg1, arg2 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
diff --git a/mocks/mocks_network/bridge_driver.go b/mocks/mocks_network/bridge_driver.go
new file mode 100644
index 00000000..ad2f551f
--- /dev/null
+++ b/mocks/mocks_network/bridge_driver.go
@@ -0,0 +1,150 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: github.com/runfinch/finch-daemon/internal/service/network (interfaces: BridgeDriverOperations)
+
+// Package mocks_network is a generated GoMock package.
+package mocks_network
+
+import (
+	reflect "reflect"
+
+	netutil "github.com/containerd/nerdctl/pkg/netutil"
+	gomock "github.com/golang/mock/gomock"
+	types "github.com/runfinch/finch-daemon/api/types"
+)
+
+// BridgeDriver is a mock of BridgeDriverOperations interface.
+type BridgeDriver struct {
+	ctrl     *gomock.Controller
+	recorder *BridgeDriverMockRecorder
+}
+
+// BridgeDriverMockRecorder is the mock recorder for BridgeDriver.
+type BridgeDriverMockRecorder struct {
+	mock *BridgeDriver
+}
+
+// NewBridgeDriver creates a new mock instance.
+func NewBridgeDriver(ctrl *gomock.Controller) *BridgeDriver {
+	mock := &BridgeDriver{ctrl: ctrl}
+	mock.recorder = &BridgeDriverMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *BridgeDriver) EXPECT() *BridgeDriverMockRecorder {
+	return m.recorder
+}
+
+// DisableICC mocks base method.
+func (m *BridgeDriver) DisableICC(arg0 string, arg1 bool) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "DisableICC", arg0, arg1)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// DisableICC indicates an expected call of DisableICC.
+func (mr *BridgeDriverMockRecorder) DisableICC(arg0, arg1 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DisableICC", reflect.TypeOf((*BridgeDriver)(nil).DisableICC), arg0, arg1)
+}
+
+// GetBridgeName mocks base method.
+func (m *BridgeDriver) GetBridgeName(arg0 *netutil.NetworkConfig) (string, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetBridgeName", arg0)
+	ret0, _ := ret[0].(string)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// GetBridgeName indicates an expected call of GetBridgeName.
+func (mr *BridgeDriverMockRecorder) GetBridgeName(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBridgeName", reflect.TypeOf((*BridgeDriver)(nil).GetBridgeName), arg0)
+}
+
+// GetNetworkByBridgeName mocks base method.
+func (m *BridgeDriver) GetNetworkByBridgeName(arg0 string) (*netutil.NetworkConfig, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetNetworkByBridgeName", arg0)
+	ret0, _ := ret[0].(*netutil.NetworkConfig)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// GetNetworkByBridgeName indicates an expected call of GetNetworkByBridgeName.
+func (mr *BridgeDriverMockRecorder) GetNetworkByBridgeName(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNetworkByBridgeName", reflect.TypeOf((*BridgeDriver)(nil).GetNetworkByBridgeName), arg0)
+}
+
+// HandleCreateOptions mocks base method.
+func (m *BridgeDriver) HandleCreateOptions(arg0 types.NetworkCreateRequest, arg1 netutil.CreateOptions) (netutil.CreateOptions, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "HandleCreateOptions", arg0, arg1)
+	ret0, _ := ret[0].(netutil.CreateOptions)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// HandleCreateOptions indicates an expected call of HandleCreateOptions.
+func (mr *BridgeDriverMockRecorder) HandleCreateOptions(arg0, arg1 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleCreateOptions", reflect.TypeOf((*BridgeDriver)(nil).HandleCreateOptions), arg0, arg1)
+}
+
+// HandlePostCreate mocks base method.
+func (m *BridgeDriver) HandlePostCreate(arg0 *netutil.NetworkConfig) (string, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "HandlePostCreate", arg0)
+	ret0, _ := ret[0].(string)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// HandlePostCreate indicates an expected call of HandlePostCreate.
+func (mr *BridgeDriverMockRecorder) HandlePostCreate(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandlePostCreate", reflect.TypeOf((*BridgeDriver)(nil).HandlePostCreate), arg0)
+}
+
+// ICCDisabled mocks base method.
+func (m *BridgeDriver) ICCDisabled() bool {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ICCDisabled")
+	ret0, _ := ret[0].(bool)
+	return ret0
+}
+
+// ICCDisabled indicates an expected call of ICCDisabled.
+func (mr *BridgeDriverMockRecorder) ICCDisabled() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ICCDisabled", reflect.TypeOf((*BridgeDriver)(nil).ICCDisabled))
+}
+
+// SetBridgeName mocks base method.
+func (m *BridgeDriver) SetBridgeName(arg0 *netutil.NetworkConfig, arg1 string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "SetBridgeName", arg0, arg1)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// SetBridgeName indicates an expected call of SetBridgeName.
+func (mr *BridgeDriverMockRecorder) SetBridgeName(arg0, arg1 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetBridgeName", reflect.TypeOf((*BridgeDriver)(nil).SetBridgeName), arg0, arg1)
+}
+
+// SetICCDisabled mocks base method.
+func (m *BridgeDriver) SetICCDisabled() {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "SetICCDisabled")
+}
+
+// SetICCDisabled indicates an expected call of SetICCDisabled.
+func (mr *BridgeDriverMockRecorder) SetICCDisabled() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetICCDisabled", reflect.TypeOf((*BridgeDriver)(nil).SetICCDisabled))
+}
diff --git a/mocks/mocks_network/iptables.go b/mocks/mocks_network/iptables.go
new file mode 100644
index 00000000..87a922da
--- /dev/null
+++ b/mocks/mocks_network/iptables.go
@@ -0,0 +1,120 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: github.com/runfinch/finch-daemon/internal/service/network (interfaces: IPTablesWrapper)
+
+// Package mocks_network is a generated GoMock package.
+package mocks_network
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+)
+
+// MockIPTablesWrapper is a mock of IPTablesWrapper interface.
+type MockIPTablesWrapper struct {
+	ctrl     *gomock.Controller
+	recorder *MockIPTablesWrapperMockRecorder
+}
+
+// MockIPTablesWrapperMockRecorder is the mock recorder for MockIPTablesWrapper.
+type MockIPTablesWrapperMockRecorder struct {
+	mock *MockIPTablesWrapper
+}
+
+// NewMockIPTablesWrapper creates a new mock instance.
+func NewMockIPTablesWrapper(ctrl *gomock.Controller) *MockIPTablesWrapper {
+	mock := &MockIPTablesWrapper{ctrl: ctrl}
+	mock.recorder = &MockIPTablesWrapperMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockIPTablesWrapper) EXPECT() *MockIPTablesWrapperMockRecorder {
+	return m.recorder
+}
+
+// Append mocks base method.
+func (m *MockIPTablesWrapper) Append(arg0, arg1 string, arg2 ...string) error {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "Append", varargs...)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Append indicates an expected call of Append.
+func (mr *MockIPTablesWrapperMockRecorder) Append(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Append", reflect.TypeOf((*MockIPTablesWrapper)(nil).Append), varargs...)
+}
+
+// ChainExists mocks base method.
+func (m *MockIPTablesWrapper) ChainExists(arg0, arg1 string) (bool, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ChainExists", arg0, arg1)
+	ret0, _ := ret[0].(bool)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ChainExists indicates an expected call of ChainExists.
+func (mr *MockIPTablesWrapperMockRecorder) ChainExists(arg0, arg1 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainExists", reflect.TypeOf((*MockIPTablesWrapper)(nil).ChainExists), arg0, arg1)
+}
+
+// DeleteIfExists mocks base method.
+func (m *MockIPTablesWrapper) DeleteIfExists(arg0, arg1 string, arg2 ...string) error {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "DeleteIfExists", varargs...)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// DeleteIfExists indicates an expected call of DeleteIfExists.
+func (mr *MockIPTablesWrapperMockRecorder) DeleteIfExists(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteIfExists", reflect.TypeOf((*MockIPTablesWrapper)(nil).DeleteIfExists), varargs...)
+}
+
+// Insert mocks base method.
+func (m *MockIPTablesWrapper) Insert(arg0, arg1 string, arg2 int, arg3 ...string) error {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1, arg2}
+	for _, a := range arg3 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "Insert", varargs...)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Insert indicates an expected call of Insert.
+func (mr *MockIPTablesWrapperMockRecorder) Insert(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1, arg2}, arg3...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockIPTablesWrapper)(nil).Insert), varargs...)
+}
+
+// NewChain mocks base method.
+func (m *MockIPTablesWrapper) NewChain(arg0, arg1 string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewChain", arg0, arg1)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// NewChain indicates an expected call of NewChain.
+func (mr *MockIPTablesWrapperMockRecorder) NewChain(arg0, arg1 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewChain", reflect.TypeOf((*MockIPTablesWrapper)(nil).NewChain), arg0, arg1)
+}