1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
|
//go:build windows
package libnetwork
import (
"context"
"fmt"
"net"
"net/netip"
"runtime"
"strings"
"sync"
"time"
"github.com/Microsoft/hcsshim"
"github.com/containerd/log"
"github.com/docker/docker/libnetwork/drivers/windows"
"github.com/docker/docker/libnetwork/ipamapi"
"github.com/docker/docker/libnetwork/ipams/windowsipam"
"github.com/pkg/errors"
)
type platformNetwork struct {
resolverOnce sync.Once
dnsCompartment uint32
}
func executeInCompartment(compartmentID uint32, x func()) {
runtime.LockOSThread()
if err := hcsshim.SetCurrentThreadCompartmentId(compartmentID); err != nil {
log.G(context.TODO()).Error(err)
}
defer func() {
hcsshim.SetCurrentThreadCompartmentId(0)
runtime.UnlockOSThread()
}()
x()
}
func (n *Network) ExecFunc(f func()) error {
executeInCompartment(n.dnsCompartment, f)
return nil
}
func (n *Network) startResolver() {
if n.networkType == "ics" {
return
}
n.resolverOnce.Do(func() {
log.G(context.TODO()).Debugf("Launching DNS server for network %q", n.Name())
hnsid := n.DriverOptions()[windows.HNSID]
if hnsid == "" {
return
}
hnsresponse, err := hcsshim.HNSNetworkRequest("GET", hnsid, "")
if err != nil {
log.G(context.TODO()).Errorf("Resolver Setup/Start failed for container %s, %q", n.Name(), err)
return
}
for _, subnet := range hnsresponse.Subnets {
if subnet.GatewayAddress != "" {
for i := 0; i < 3; i++ {
resolver := NewResolver(subnet.GatewayAddress, true, n)
log.G(context.TODO()).Debugf("Binding a resolver on network %s gateway %s", n.Name(), subnet.GatewayAddress)
n.dnsCompartment = hnsresponse.DNSServerCompartment
n.ExecFunc(resolver.SetupFunc(53))
if err = resolver.Start(); err != nil {
log.G(context.TODO()).Errorf("Resolver Setup/Start failed for container %s, %q", n.Name(), err)
time.Sleep(1 * time.Second)
} else {
log.G(context.TODO()).Debugf("Resolver bound successfully for network %s", n.Name())
n.resolver = append(n.resolver, resolver)
break
}
}
}
}
})
}
// addEpToResolver configures the internal DNS resolver for an endpoint.
//
// Windows resolvers don't consistently fall back to a secondary server if they
// get a SERVFAIL from our resolver. So, our resolver needs to forward the query
// upstream.
//
// To retrieve the list of DNS Servers to use for requests originating from an
// endpoint, this method finds the HNSEndpoint represented by the endpoint. If
// HNSEndpoint's list of DNS servers includes the HNSEndpoint's gateway address,
// it's the Resolver running at that address. Other DNS servers in the
// list have either come from config ('--dns') or have been set up by HNS as
// external resolvers, these are the external servers the Resolver should
// use for DNS requests from that endpoint.
func addEpToResolver(
ctx context.Context,
netName, epName string,
config *containerConfig,
epIface *EndpointInterface,
resolvers []*Resolver,
) error {
if config.dnsNoProxy {
return nil
}
hnsEndpoints, err := hcsshim.HNSListEndpointRequest()
if err != nil {
return nil
}
return addEpToResolverImpl(ctx, netName, epName, epIface, resolvers, hnsEndpoints)
}
func addEpToResolverImpl(
ctx context.Context,
netName, epName string,
epIface *EndpointInterface,
resolvers []*Resolver,
hnsEndpoints []hcsshim.HNSEndpoint,
) error {
// Find the HNSEndpoint represented by ep, matching on endpoint address.
hnsEp := findHNSEp(epIface.addr, epIface.addrv6, hnsEndpoints)
if hnsEp == nil || !hnsEp.EnableInternalDNS {
return nil
}
// Find the resolver for that HNSEndpoint, matching on gateway address.
resolver := findResolver(resolvers, hnsEp.GatewayAddress, hnsEp.GatewayAddressV6)
if resolver == nil {
log.G(ctx).WithFields(log.Fields{
"network": netName,
"endpoint": epName,
}).Debug("No internal DNS resolver to configure")
return nil
}
// Get the list of DNS servers HNS has set up for this Endpoint.
var dnsList []extDNSEntry
dnsServers := strings.Split(hnsEp.DNSServerList, ",")
// Create an extDNSEntry for each DNS server, apart from 'resolver' itself.
var foundSelf bool
hnsGw4, _ := netip.ParseAddr(hnsEp.GatewayAddress)
hnsGw6, _ := netip.ParseAddr(hnsEp.GatewayAddressV6)
for _, dnsServer := range dnsServers {
dnsAddr, _ := netip.ParseAddr(dnsServer)
if dnsAddr.IsValid() && (dnsAddr == hnsGw4 || dnsAddr == hnsGw6) {
foundSelf = true
} else {
dnsList = append(dnsList, extDNSEntry{IPStr: dnsServer})
}
}
if !foundSelf {
log.G(ctx).WithFields(log.Fields{
"network": netName,
"endpoint": epName,
}).Debug("Endpoint is not configured to use internal DNS resolver")
return nil
}
// If the internal resolver is configured as one of this endpoint's DNS servers,
// tell it which ext servers to use for requests from this endpoint's addresses.
log.G(ctx).Infof("External DNS servers for '%s': %v", epName, dnsList)
if srcAddr, ok := netip.AddrFromSlice(hnsEp.IPAddress); ok {
if err := resolver.SetExtServersForSrc(srcAddr.Unmap(), dnsList); err != nil {
return errors.Wrapf(err, "failed to set external DNS servers for %s address %s",
epName, hnsEp.IPAddress)
}
}
if srcAddr, ok := netip.AddrFromSlice(hnsEp.IPv6Address); ok {
if err := resolver.SetExtServersForSrc(srcAddr, dnsList); err != nil {
return errors.Wrapf(err, "failed to set external DNS servers for %s address %s",
epName, hnsEp.IPv6Address)
}
}
return nil
}
func deleteEpFromResolver(epName string, epIface *EndpointInterface, resolvers []*Resolver) error {
hnsEndpoints, err := hcsshim.HNSListEndpointRequest()
if err != nil {
return nil
}
return deleteEpFromResolverImpl(epName, epIface, resolvers, hnsEndpoints)
}
func deleteEpFromResolverImpl(
epName string,
epIface *EndpointInterface,
resolvers []*Resolver,
hnsEndpoints []hcsshim.HNSEndpoint,
) error {
// Find the HNSEndpoint represented by ep, matching on endpoint address.
hnsEp := findHNSEp(epIface.addr, epIface.addrv6, hnsEndpoints)
if hnsEp == nil {
return fmt.Errorf("no HNS endpoint for %s", epName)
}
// Find the resolver for that HNSEndpoint, matching on gateway address.
resolver := findResolver(resolvers, hnsEp.GatewayAddress, hnsEp.GatewayAddressV6)
if resolver == nil {
return nil
}
// Delete external DNS servers for the endpoint's IP addresses.
if srcAddr, ok := netip.AddrFromSlice(hnsEp.IPAddress); ok {
if err := resolver.SetExtServersForSrc(srcAddr.Unmap(), nil); err != nil {
return errors.Wrapf(err, "failed to delete external DNS servers for %s address %s",
epName, hnsEp.IPv6Address)
}
}
if srcAddr, ok := netip.AddrFromSlice(hnsEp.IPv6Address); ok {
if err := resolver.SetExtServersForSrc(srcAddr, nil); err != nil {
return errors.Wrapf(err, "failed to delete external DNS servers for %s address %s",
epName, hnsEp.IPv6Address)
}
}
return nil
}
func findHNSEp(ip4, ip6 *net.IPNet, hnsEndpoints []hcsshim.HNSEndpoint) *hcsshim.HNSEndpoint {
for _, hnsEp := range hnsEndpoints {
if (hnsEp.IPAddress != nil && hnsEp.IPAddress.Equal(ip4.IP)) ||
(hnsEp.IPv6Address != nil && hnsEp.IPv6Address.Equal(ip6.IP)) {
return &hnsEp
}
}
return nil
}
func findResolver(resolvers []*Resolver, gw4, gw6 string) *Resolver {
gw4addr, _ := netip.ParseAddr(gw4)
gw6addr, _ := netip.ParseAddr(gw6)
for _, resolver := range resolvers {
ns := resolver.NameServer()
if ns.IsValid() && (ns == gw4addr || ns == gw6addr) {
return resolver
}
}
return nil
}
func defaultIpamForNetworkType(networkType string) string {
if windows.IsBuiltinLocalDriver(networkType) {
return windowsipam.DefaultIPAM
}
return ipamapi.DefaultIPAM
}
|