|
1 | 1 | package plugin |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "bytes" |
4 | 5 | "context" |
5 | 6 | "fmt" |
6 | 7 | "net" |
@@ -41,53 +42,65 @@ func (p *Plugin) CreateNetwork(r CreateNetworkRequest) error { |
41 | 42 | } |
42 | 43 | } |
43 | 44 |
|
44 | | - links, err := netlink.LinkList() |
| 45 | + link, err := netlink.LinkByName(opts.Bridge) |
45 | 46 | if err != nil { |
46 | | - return fmt.Errorf("failed to retrieve list of network interfaces: %w", err) |
| 47 | + return fmt.Errorf("failed to lookup interface %v: %w", opts.Bridge, err) |
47 | 48 | } |
48 | | - |
49 | | - nets, err := p.docker.NetworkList(context.Background(), dTypes.NetworkListOptions{}) |
50 | | - if err != nil { |
51 | | - return fmt.Errorf("failed to retrieve list of networks from Docker: %w", err) |
| 49 | + if link.Type() != "bridge" { |
| 50 | + return util.ErrNotBridge |
52 | 51 | } |
53 | 52 |
|
54 | | - found := false |
55 | | - for _, l := range links { |
56 | | - attrs := l.Attrs() |
57 | | - if l.Type() != "bridge" || attrs.Name != opts.Bridge { |
58 | | - continue |
| 53 | + if !opts.IgnoreConflicts { |
| 54 | + v4Addrs, err := netlink.AddrList(link, unix.AF_INET) |
| 55 | + if err != nil { |
| 56 | + return fmt.Errorf("failed to retrieve IPv4 addresses for %v: %w", opts.Bridge, err) |
59 | 57 | } |
60 | | - |
61 | | - v4Addrs, err := netlink.AddrList(l, unix.AF_INET) |
| 58 | + v6Addrs, err := netlink.AddrList(link, unix.AF_INET6) |
62 | 59 | if err != nil { |
63 | | - return fmt.Errorf("failed to retrieve IPv4 addresses for %v: %w", attrs.Name, err) |
| 60 | + return fmt.Errorf("failed to retrieve IPv6 addresses for %v: %w", opts.Bridge, err) |
64 | 61 | } |
65 | | - v6Addrs, err := netlink.AddrList(l, unix.AF_INET6) |
| 62 | + bridgeAddrs := append(v4Addrs, v6Addrs...) |
| 63 | + |
| 64 | + nets, err := p.docker.NetworkList(context.Background(), dTypes.NetworkListOptions{}) |
66 | 65 | if err != nil { |
67 | | - return fmt.Errorf("failed to retrieve IPv6 addresses for %v: %w", attrs.Name, err) |
| 66 | + return fmt.Errorf("failed to retrieve list of networks from Docker: %w", err) |
68 | 67 | } |
69 | | - addrs := append(v4Addrs, v6Addrs...) |
70 | 68 |
|
71 | 69 | // Make sure the addresses on this bridge aren't used by another network |
72 | 70 | for _, n := range nets { |
| 71 | + if IsDHCPPlugin(n.Driver) { |
| 72 | + otherOpts, err := decodeOpts(n.Options) |
| 73 | + if err != nil { |
| 74 | + log. |
| 75 | + WithField("network", n.Name). |
| 76 | + WithError(err). |
| 77 | + Warn("Failed to parse other DHCP network's options") |
| 78 | + } else if otherOpts.Bridge == opts.Bridge { |
| 79 | + return util.ErrBridgeUsed |
| 80 | + } |
| 81 | + } |
| 82 | + if n.IPAM.Driver == "null" { |
| 83 | + // Null driver networks will have 0.0.0.0/0 which covers any address range! |
| 84 | + continue |
| 85 | + } |
| 86 | + |
73 | 87 | for _, c := range n.IPAM.Config { |
74 | | - _, cidr, err := net.ParseCIDR(c.Subnet) |
| 88 | + _, dockerCIDR, err := net.ParseCIDR(c.Subnet) |
75 | 89 | if err != nil { |
76 | 90 | return fmt.Errorf("failed to parse subnet %v on Docker network %v: %w", c.Subnet, n.ID, err) |
77 | 91 | } |
| 92 | + if bytes.Equal(dockerCIDR.Mask, net.CIDRMask(0, 32)) || bytes.Equal(dockerCIDR.Mask, net.CIDRMask(0, 128)) { |
| 93 | + // Last check to make sure the network isn't 0.0.0.0/0 or ::/0 (which would always pass the check below) |
| 94 | + continue |
| 95 | + } |
78 | 96 |
|
79 | | - for _, linkAddr := range addrs { |
80 | | - if linkAddr.IPNet.Contains(cidr.IP) || cidr.Contains(linkAddr.IP) { |
| 97 | + for _, bridgeAddr := range bridgeAddrs { |
| 98 | + if bridgeAddr.IPNet.Contains(dockerCIDR.IP) || dockerCIDR.Contains(bridgeAddr.IP) { |
81 | 99 | return util.ErrBridgeUsed |
82 | 100 | } |
83 | 101 | } |
84 | 102 | } |
85 | 103 | } |
86 | | - found = true |
87 | | - break |
88 | | - } |
89 | | - if !found { |
90 | | - return util.ErrBridgeNotFound |
91 | 104 | } |
92 | 105 |
|
93 | 106 | log.WithFields(log.Fields{ |
|
0 commit comments