github.com/rawahars/moby@v24.0.4+incompatible/libnetwork/drivers/bridge/setup_bridgenetfiltering.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  package bridge
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"os"
    10  	"syscall"
    11  
    12  	"github.com/sirupsen/logrus"
    13  )
    14  
    15  // Enumeration type saying which versions of IP protocol to process.
    16  type ipVersion int
    17  
    18  const (
    19  	ipvnone ipVersion = iota
    20  	ipv4
    21  	ipv6
    22  	ipvboth
    23  )
    24  
    25  // getIPVersion gets the IP version in use ( [ipv4], [ipv6] or [ipv4 and ipv6] )
    26  func getIPVersion(config *networkConfiguration) ipVersion {
    27  	ipVersion := ipv4
    28  	if config.AddressIPv6 != nil || config.EnableIPv6 {
    29  		ipVersion |= ipv6
    30  	}
    31  	return ipVersion
    32  }
    33  
    34  func setupBridgeNetFiltering(config *networkConfiguration, i *bridgeInterface) error {
    35  	err := checkBridgeNetFiltering(config, i)
    36  	if err != nil {
    37  		if ptherr, ok := err.(*os.PathError); ok {
    38  			if errno, ok := ptherr.Err.(syscall.Errno); ok && errno == syscall.ENOENT {
    39  				if isRunningInContainer() {
    40  					logrus.Warnf("running inside docker container, ignoring missing kernel params: %v", err)
    41  					err = nil
    42  				} else {
    43  					err = errors.New("please ensure that br_netfilter kernel module is loaded")
    44  				}
    45  			}
    46  		}
    47  		if err != nil {
    48  			return fmt.Errorf("cannot restrict inter-container communication: %v", err)
    49  		}
    50  	}
    51  	return nil
    52  }
    53  
    54  // Enable bridge net filtering if ip forwarding is enabled. See github issue #11404
    55  func checkBridgeNetFiltering(config *networkConfiguration, i *bridgeInterface) error {
    56  	ipVer := getIPVersion(config)
    57  	iface := config.BridgeName
    58  	doEnable := func(ipVer ipVersion) error {
    59  		var ipVerName string
    60  		if ipVer == ipv4 {
    61  			ipVerName = "IPv4"
    62  		} else {
    63  			ipVerName = "IPv6"
    64  		}
    65  		enabled, err := isPacketForwardingEnabled(ipVer, iface)
    66  		if err != nil {
    67  			logrus.Warnf("failed to check %s forwarding: %v", ipVerName, err)
    68  		} else if enabled {
    69  			enabled, err := getKernelBoolParam(getBridgeNFKernelParam(ipVer))
    70  			if err != nil || enabled {
    71  				return err
    72  			}
    73  			return setKernelBoolParam(getBridgeNFKernelParam(ipVer), true)
    74  		}
    75  		return nil
    76  	}
    77  
    78  	switch ipVer {
    79  	case ipv4, ipv6:
    80  		return doEnable(ipVer)
    81  	case ipvboth:
    82  		v4err := doEnable(ipv4)
    83  		v6err := doEnable(ipv6)
    84  		if v4err == nil {
    85  			return v6err
    86  		}
    87  		return v4err
    88  	default:
    89  		return nil
    90  	}
    91  }
    92  
    93  // Get kernel param path saying whether IPv${ipVer} traffic is being forwarded
    94  // on particular interface. Interface may be specified for IPv6 only. If
    95  // `iface` is empty, `default` will be assumed, which represents default value
    96  // for new interfaces.
    97  func getForwardingKernelParam(ipVer ipVersion, iface string) string {
    98  	switch ipVer {
    99  	case ipv4:
   100  		return "/proc/sys/net/ipv4/ip_forward"
   101  	case ipv6:
   102  		if iface == "" {
   103  			iface = "default"
   104  		}
   105  		return fmt.Sprintf("/proc/sys/net/ipv6/conf/%s/forwarding", iface)
   106  	default:
   107  		return ""
   108  	}
   109  }
   110  
   111  // Get kernel param path saying whether bridged IPv${ipVer} traffic shall be
   112  // passed to ip${ipVer}tables' chains.
   113  func getBridgeNFKernelParam(ipVer ipVersion) string {
   114  	switch ipVer {
   115  	case ipv4:
   116  		return "/proc/sys/net/bridge/bridge-nf-call-iptables"
   117  	case ipv6:
   118  		return "/proc/sys/net/bridge/bridge-nf-call-ip6tables"
   119  	default:
   120  		return ""
   121  	}
   122  }
   123  
   124  // Gets the value of the kernel parameters located at the given path
   125  func getKernelBoolParam(path string) (bool, error) {
   126  	enabled := false
   127  	line, err := os.ReadFile(path)
   128  	if err != nil {
   129  		return false, err
   130  	}
   131  	if len(line) > 0 {
   132  		enabled = line[0] == '1'
   133  	}
   134  	return enabled, err
   135  }
   136  
   137  // Sets the value of the kernel parameter located at the given path
   138  func setKernelBoolParam(path string, on bool) error {
   139  	value := byte('0')
   140  	if on {
   141  		value = byte('1')
   142  	}
   143  	return os.WriteFile(path, []byte{value, '\n'}, 0644)
   144  }
   145  
   146  // Checks to see if packet forwarding is enabled
   147  func isPacketForwardingEnabled(ipVer ipVersion, iface string) (bool, error) {
   148  	switch ipVer {
   149  	case ipv4, ipv6:
   150  		return getKernelBoolParam(getForwardingKernelParam(ipVer, iface))
   151  	case ipvboth:
   152  		enabled, err := getKernelBoolParam(getForwardingKernelParam(ipv4, ""))
   153  		if err != nil || !enabled {
   154  			return enabled, err
   155  		}
   156  		return getKernelBoolParam(getForwardingKernelParam(ipv6, iface))
   157  	default:
   158  		return true, nil
   159  	}
   160  }
   161  
   162  func isRunningInContainer() bool {
   163  	_, err := os.Stat("/.dockerenv")
   164  	return !os.IsNotExist(err)
   165  }