|
@@ -0,0 +1,135 @@
|
|
|
+package bridge
|
|
|
+
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+ "net"
|
|
|
+
|
|
|
+ log "github.com/Sirupsen/logrus"
|
|
|
+ "github.com/docker/docker/pkg/networkfs/resolvconf"
|
|
|
+ "github.com/vishvananda/netlink"
|
|
|
+)
|
|
|
+
|
|
|
+var bridgeNetworks []*net.IPNet
|
|
|
+
|
|
|
+func init() {
|
|
|
+ // Here we don't follow the convention of using the 1st IP of the range for the gateway.
|
|
|
+ // This is to use the same gateway IPs as the /24 ranges, which predate the /16 ranges.
|
|
|
+ // In theory this shouldn't matter - in practice there's bound to be a few scripts relying
|
|
|
+ // on the internal addressing or other stupid things like that.
|
|
|
+ // They shouldn't, but hey, let's not break them unless we really have to.
|
|
|
+ for _, addr := range []string{
|
|
|
+ "172.17.42.1/16", // Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23
|
|
|
+ "10.0.42.1/16", // Don't even try using the entire /8, that's too intrusive
|
|
|
+ "10.1.42.1/16",
|
|
|
+ "10.42.42.1/16",
|
|
|
+ "172.16.42.1/24",
|
|
|
+ "172.16.43.1/24",
|
|
|
+ "172.16.44.1/24",
|
|
|
+ "10.0.42.1/24",
|
|
|
+ "10.0.43.1/24",
|
|
|
+ "192.168.42.1/24",
|
|
|
+ "192.168.43.1/24",
|
|
|
+ "192.168.44.1/24",
|
|
|
+ } {
|
|
|
+ ip, net, err := net.ParseCIDR(addr)
|
|
|
+ if err != nil {
|
|
|
+ log.Errorf("Failed to parse address %s", addr)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ net.IP = ip
|
|
|
+ bridgeNetworks = append(bridgeNetworks, net)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func SetupBridgeIPv4(i *Interface) error {
|
|
|
+ bridgeIPv4, err := electBridgeIPv4(i.Config)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ log.Debugf("Creating bridge interface %q with network %s", i.Config.BridgeName, bridgeIPv4)
|
|
|
+ return netlink.AddrAdd(i.Link, &netlink.Addr{bridgeIPv4, ""})
|
|
|
+}
|
|
|
+
|
|
|
+func electBridgeIPv4(config *Configuration) (*net.IPNet, error) {
|
|
|
+ // Use the requested IPv4 CIDR when available.
|
|
|
+ if config.AddressIPv4 != nil {
|
|
|
+ return config.AddressIPv4, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ // We don't check for an error here, because we don't really care if we
|
|
|
+ // can't read /etc/resolv.conf. So instead we skip the append if resolvConf
|
|
|
+ // is nil. It either doesn't exist, or we can't read it for some reason.
|
|
|
+ nameservers := []string{}
|
|
|
+ if resolvConf, _ := resolvconf.Get(); resolvConf != nil {
|
|
|
+ nameservers = append(nameservers, resolvconf.GetNameserversAsCIDR(resolvConf)...)
|
|
|
+ }
|
|
|
+
|
|
|
+ // Try to automatically elect appropriate brige IPv4 settings.
|
|
|
+ for _, n := range bridgeNetworks {
|
|
|
+ if err := checkNameserverOverlaps(nameservers, n); err == nil {
|
|
|
+ if err := checkRouteOverlaps(n); err == nil {
|
|
|
+ return n, nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil, fmt.Errorf("Couldn't find an address range for interface %q", config.BridgeName)
|
|
|
+}
|
|
|
+
|
|
|
+func checkNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error {
|
|
|
+ for _, ns := range nameservers {
|
|
|
+ _, nsNetwork, err := net.ParseCIDR(ns)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if networkOverlaps(toCheck, nsNetwork) {
|
|
|
+ return fmt.Errorf("Requested network %s overlaps with name server")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func checkRouteOverlaps(toCheck *net.IPNet) error {
|
|
|
+ networks, err := netlink.RouteList(nil, netlink.FAMILY_V4)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, network := range networks {
|
|
|
+ // TODO Is that right?
|
|
|
+ if network.Dst != nil && networkOverlaps(toCheck, network.Dst) {
|
|
|
+ return fmt.Errorf("Requested network %s overlaps with an existing network")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func networkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
|
|
|
+ if len(netX.IP) == len(netY.IP) {
|
|
|
+ if firstIP, _ := networkRange(netX); netY.Contains(firstIP) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ if firstIP, _ := networkRange(netY); netX.Contains(firstIP) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false
|
|
|
+}
|
|
|
+
|
|
|
+func networkRange(network *net.IPNet) (net.IP, net.IP) {
|
|
|
+ var netIP net.IP
|
|
|
+ if network.IP.To4() != nil {
|
|
|
+ netIP = network.IP.To4()
|
|
|
+ } else if network.IP.To16() != nil {
|
|
|
+ netIP = network.IP.To16()
|
|
|
+ } else {
|
|
|
+ return nil, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ lastIP := make([]byte, len(netIP), len(netIP))
|
|
|
+ for i := 0; i < len(netIP); i++ {
|
|
|
+ lastIP[i] = netIP[i] | ^network.Mask[i]
|
|
|
+ }
|
|
|
+ return netIP.Mask(network.Mask), net.IP(lastIP)
|
|
|
+}
|