예제 #1
0
파일: links.go 프로젝트: pbx0/docker
func (l *Link) Disable() {
	// We do not care about errors here because the link may not
	// exist in iptables
	// -D == iptables delete flag
	l.toggle("-D", true)
	// call this on Firewalld reload
	iptables.OnReloaded(func() { l.toggle("-D", true) })
	l.IsEnabled = false
}
예제 #2
0
파일: links.go 프로젝트: pbx0/docker
func (l *Link) Enable() error {
	// -A == iptables append flag
	if err := l.toggle("-A", false); err != nil {
		return err
	}
	// call this on Firewalld reload
	iptables.OnReloaded(func() { l.toggle("-I", false) })
	l.IsEnabled = true
	return nil
}
예제 #3
0
func InitDriver(config *Config) error {
	var (
		networkv4  *net.IPNet
		networkv6  *net.IPNet
		addrv4     net.Addr
		addrsv6    []net.Addr
		bridgeIPv6 = "fe80::1/64"
	)

	// try to modprobe bridge first
	// see gh#12177
	if out, err := exec.Command("modprobe", "-va", "bridge", "nf_nat", "br_netfilter").Output(); err != nil {
		logrus.Warnf("Running modprobe bridge nf_nat failed with message: %s, error: %v", out, err)
	}

	initPortMapper()

	if config.DefaultIp != nil {
		defaultBindingIP = config.DefaultIp
	}

	hairpinMode = !config.EnableUserlandProxy

	bridgeIface = config.Iface
	usingDefaultBridge := false
	if bridgeIface == "" {
		usingDefaultBridge = true
		bridgeIface = DefaultNetworkBridge
	}

	addrv4, addrsv6, err := networkdriver.GetIfaceAddr(bridgeIface)

	if err != nil {
		// No Bridge existent, create one
		// If we're not using the default bridge, fail without trying to create it
		if !usingDefaultBridge {
			return err
		}

		logrus.Info("Bridge interface not found, trying to create it")

		// If the iface is not found, try to create it
		if err := configureBridge(config.IP, bridgeIPv6, config.EnableIPv6); err != nil {
			logrus.Errorf("Could not configure Bridge: %s", err)
			return err
		}

		addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface)
		if err != nil {
			return err
		}

		if config.FixedCIDRv6 != "" {
			// Setting route to global IPv6 subnet
			logrus.Infof("Adding route to IPv6 network %q via device %q", config.FixedCIDRv6, bridgeIface)
			if err := netlink.AddRoute(config.FixedCIDRv6, "", "", bridgeIface); err != nil {
				logrus.Fatalf("Could not add route to IPv6 network %q via device %q", config.FixedCIDRv6, bridgeIface)
			}
		}
	} else {
		// Bridge exists already, getting info...
		// Validate that the bridge ip matches the ip specified by BridgeIP
		if config.IP != "" {
			networkv4 = addrv4.(*net.IPNet)
			bip, _, err := net.ParseCIDR(config.IP)
			if err != nil {
				return err
			}
			if !networkv4.IP.Equal(bip) {
				return fmt.Errorf("Bridge ip (%s) does not match existing bridge configuration %s", networkv4.IP, bip)
			}
		}

		// A bridge might exist but not have any IPv6 addr associated with it yet
		// (for example, an existing Docker installation that has only been used
		// with IPv4 and docker0 already is set up) In that case, we can perform
		// the bridge init for IPv6 here, else we will error out below if --ipv6=true
		if len(addrsv6) == 0 && config.EnableIPv6 {
			if err := setupIPv6Bridge(bridgeIPv6); err != nil {
				return err
			}
			// Recheck addresses now that IPv6 is setup on the bridge
			addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface)
			if err != nil {
				return err
			}
		}

		// TODO: Check if route to config.FixedCIDRv6 is set
	}

	if config.EnableIPv6 {
		bip6, _, err := net.ParseCIDR(bridgeIPv6)
		if err != nil {
			return err
		}
		found := false
		for _, addrv6 := range addrsv6 {
			networkv6 = addrv6.(*net.IPNet)
			if networkv6.IP.Equal(bip6) {
				found = true
				break
			}
		}
		if !found {
			return fmt.Errorf("Bridge IPv6 does not match existing bridge configuration %s", bip6)
		}
	}

	networkv4 = addrv4.(*net.IPNet)

	if config.EnableIPv6 {
		if len(addrsv6) == 0 {
			return errors.New("IPv6 enabled but no IPv6 detected")
		}
		bridgeIPv6Addr = networkv6.IP
	}

	if config.EnableIptables {
		if err := iptables.FirewalldInit(); err != nil {
			logrus.Debugf("Error initializing firewalld: %v", err)
		}
	}

	// Configure iptables for link support
	if config.EnableIptables {
		if err := setupIPTables(addrv4, config.InterContainerCommunication, config.EnableIpMasq); err != nil {
			logrus.Errorf("Error configuring iptables: %s", err)
			return err
		}
		// call this on Firewalld reload
		iptables.OnReloaded(func() { setupIPTables(addrv4, config.InterContainerCommunication, config.EnableIpMasq) })
	}

	if config.EnableIpForward {
		// Enable IPv4 forwarding
		if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte{'1', '\n'}, 0644); err != nil {
			logrus.Warnf("Unable to enable IPv4 forwarding: %v", err)
		}

		if config.FixedCIDRv6 != "" {
			// Enable IPv6 forwarding
			if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/default/forwarding", []byte{'1', '\n'}, 0644); err != nil {
				logrus.Warnf("Unable to enable IPv6 default forwarding: %v", err)
			}
			if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/all/forwarding", []byte{'1', '\n'}, 0644); err != nil {
				logrus.Warnf("Unable to enable IPv6 all forwarding: %v", err)
			}
		}
	}

	if hairpinMode {
		// Enable loopback adresses routing
		sysPath := filepath.Join("/proc/sys/net/ipv4/conf", bridgeIface, "route_localnet")
		if err := ioutil.WriteFile(sysPath, []byte{'1', '\n'}, 0644); err != nil {
			logrus.Warnf("Unable to enable local routing for hairpin mode: %v", err)
		}
	}

	// We can always try removing the iptables
	if err := iptables.RemoveExistingChain("DOCKER", iptables.Nat); err != nil {
		return err
	}

	if config.EnableIptables {
		_, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Nat, hairpinMode)
		if err != nil {
			return err
		}
		// call this on Firewalld reload
		iptables.OnReloaded(func() { iptables.NewChain("DOCKER", bridgeIface, iptables.Nat, hairpinMode) })
		chain, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter, hairpinMode)
		if err != nil {
			return err
		}
		// call this on Firewalld reload
		iptables.OnReloaded(func() { iptables.NewChain("DOCKER", bridgeIface, iptables.Filter, hairpinMode) })

		portMapper.SetIptablesChain(chain)
	}

	bridgeIPv4Network = networkv4
	if config.FixedCIDR != "" {
		_, subnet, err := net.ParseCIDR(config.FixedCIDR)
		if err != nil {
			return err
		}
		logrus.Debugf("Subnet: %v", subnet)
		if err := ipAllocator.RegisterSubnet(bridgeIPv4Network, subnet); err != nil {
			logrus.Errorf("Error registering subnet for IPv4 bridge network: %s", err)
			return err
		}
	}

	if gateway, err := requestDefaultGateway(config.DefaultGatewayIPv4, bridgeIPv4Network); err != nil {
		return err
	} else {
		gatewayIPv4 = gateway
	}

	if config.FixedCIDRv6 != "" {
		_, subnet, err := net.ParseCIDR(config.FixedCIDRv6)
		if err != nil {
			return err
		}
		logrus.Debugf("Subnet: %v", subnet)
		if err := ipAllocator.RegisterSubnet(subnet, subnet); err != nil {
			logrus.Errorf("Error registering subnet for IPv6 bridge network: %s", err)
			return err
		}
		globalIPv6Network = subnet

		if gateway, err := requestDefaultGateway(config.DefaultGatewayIPv6, globalIPv6Network); err != nil {
			return err
		} else {
			gatewayIPv6 = gateway
		}
	}

	// Block BridgeIP in IP allocator
	ipAllocator.RequestIP(bridgeIPv4Network, bridgeIPv4Network.IP)

	if config.EnableIptables {
		iptables.OnReloaded(portMapper.ReMapAll) // call this on Firewalld reload
	}

	return nil
}