2021-08-23 13:14:53 +00:00
|
|
|
//go:build windows
|
2016-09-19 22:48:06 +00:00
|
|
|
|
|
|
|
package libnetwork
|
|
|
|
|
|
|
|
import (
|
2023-06-23 00:33:17 +00:00
|
|
|
"context"
|
2024-03-15 17:04:41 +00:00
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"net/netip"
|
2016-09-19 22:48:06 +00:00
|
|
|
"runtime"
|
2024-03-15 17:04:41 +00:00
|
|
|
"strings"
|
|
|
|
"sync"
|
2016-10-12 23:55:20 +00:00
|
|
|
"time"
|
2016-09-19 22:48:06 +00:00
|
|
|
|
|
|
|
"github.com/Microsoft/hcsshim"
|
2023-09-13 15:41:45 +00:00
|
|
|
"github.com/containerd/log"
|
2021-04-06 00:24:47 +00:00
|
|
|
"github.com/docker/docker/libnetwork/drivers/windows"
|
|
|
|
"github.com/docker/docker/libnetwork/ipamapi"
|
|
|
|
"github.com/docker/docker/libnetwork/ipams/windowsipam"
|
2024-03-15 17:04:41 +00:00
|
|
|
"github.com/pkg/errors"
|
2016-09-19 22:48:06 +00:00
|
|
|
)
|
|
|
|
|
2024-03-15 17:04:41 +00:00
|
|
|
type platformNetwork struct {
|
|
|
|
resolverOnce sync.Once
|
|
|
|
dnsCompartment uint32
|
|
|
|
}
|
|
|
|
|
2016-09-19 22:48:06 +00:00
|
|
|
func executeInCompartment(compartmentID uint32, x func()) {
|
|
|
|
runtime.LockOSThread()
|
|
|
|
|
|
|
|
if err := hcsshim.SetCurrentThreadCompartmentId(compartmentID); err != nil {
|
2023-06-23 00:33:17 +00:00
|
|
|
log.G(context.TODO()).Error(err)
|
2016-09-19 22:48:06 +00:00
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
hcsshim.SetCurrentThreadCompartmentId(0)
|
|
|
|
runtime.UnlockOSThread()
|
|
|
|
}()
|
|
|
|
|
|
|
|
x()
|
|
|
|
}
|
|
|
|
|
2024-03-15 17:04:41 +00:00
|
|
|
func (n *Network) ExecFunc(f func()) error {
|
|
|
|
executeInCompartment(n.dnsCompartment, f)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-07-21 22:38:57 +00:00
|
|
|
func (n *Network) startResolver() {
|
2017-11-17 21:03:41 +00:00
|
|
|
if n.networkType == "ics" {
|
|
|
|
return
|
|
|
|
}
|
2016-09-19 22:48:06 +00:00
|
|
|
n.resolverOnce.Do(func() {
|
2023-06-23 00:33:17 +00:00
|
|
|
log.G(context.TODO()).Debugf("Launching DNS server for network %q", n.Name())
|
2023-07-25 15:37:19 +00:00
|
|
|
hnsid := n.DriverOptions()[windows.HNSID]
|
2016-11-01 21:51:41 +00:00
|
|
|
if hnsid == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-09-19 22:48:06 +00:00
|
|
|
hnsresponse, err := hcsshim.HNSNetworkRequest("GET", hnsid, "")
|
|
|
|
if err != nil {
|
2023-06-23 00:33:17 +00:00
|
|
|
log.G(context.TODO()).Errorf("Resolver Setup/Start failed for container %s, %q", n.Name(), err)
|
2016-09-19 22:48:06 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, subnet := range hnsresponse.Subnets {
|
|
|
|
if subnet.GatewayAddress != "" {
|
2016-10-12 23:55:20 +00:00
|
|
|
for i := 0; i < 3; i++ {
|
2024-03-15 17:04:41 +00:00
|
|
|
resolver := NewResolver(subnet.GatewayAddress, true, n)
|
2023-06-23 00:33:17 +00:00
|
|
|
log.G(context.TODO()).Debugf("Binding a resolver on network %s gateway %s", n.Name(), subnet.GatewayAddress)
|
2024-03-15 17:04:41 +00:00
|
|
|
n.dnsCompartment = hnsresponse.DNSServerCompartment
|
|
|
|
n.ExecFunc(resolver.SetupFunc(53))
|
2016-10-12 23:55:20 +00:00
|
|
|
|
|
|
|
if err = resolver.Start(); err != nil {
|
2023-06-23 00:33:17 +00:00
|
|
|
log.G(context.TODO()).Errorf("Resolver Setup/Start failed for container %s, %q", n.Name(), err)
|
2016-10-12 23:55:20 +00:00
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
} else {
|
2023-06-23 00:33:17 +00:00
|
|
|
log.G(context.TODO()).Debugf("Resolver bound successfully for network %s", n.Name())
|
2016-10-12 23:55:20 +00:00
|
|
|
n.resolver = append(n.resolver, resolver)
|
|
|
|
break
|
|
|
|
}
|
2016-09-19 22:48:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2016-10-12 23:55:20 +00:00
|
|
|
|
2024-03-15 17:04:41 +00:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2016-10-12 23:55:20 +00:00
|
|
|
func defaultIpamForNetworkType(networkType string) string {
|
|
|
|
if windows.IsBuiltinLocalDriver(networkType) {
|
|
|
|
return windowsipam.DefaultIPAM
|
|
|
|
}
|
|
|
|
return ipamapi.DefaultIPAM
|
|
|
|
}
|