DNS support
Signed-off-by: msabansal <sabansal@microsoft.com>
This commit is contained in:
parent
ae98412893
commit
7f43fd30f3
|
@ -804,6 +804,8 @@ func (c *controller) addNetwork(n *network) error {
|
|||
return err
|
||||
}
|
||||
|
||||
n.startResolver()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -15,4 +15,19 @@ const (
|
|||
|
||||
// QosPolicies of the endpoint
|
||||
QosPolicies = "com.docker.endpoint.windowsshim.qospolicies"
|
||||
|
||||
// VLAN of the network
|
||||
VLAN = "com.docker.network.windowsshim.vlanid"
|
||||
|
||||
// VSID of the network
|
||||
VSID = "com.docker.network.windowsshim.vsid"
|
||||
|
||||
// DNSSuffix of the network
|
||||
DNSSuffix = "com.docker.network.windowsshim.dnssuffix"
|
||||
|
||||
// DNSServers of the network
|
||||
DNSServers = "com.docker.network.windowsshim.dnsservers"
|
||||
|
||||
// SourceMac of the network
|
||||
SourceMac = "com.docker.network.windowsshim.sourcemac"
|
||||
)
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
|
@ -34,6 +35,11 @@ type networkConfiguration struct {
|
|||
Name string
|
||||
HnsID string
|
||||
RDID string
|
||||
VLAN uint
|
||||
VSID uint
|
||||
DNSServers string
|
||||
DNSSuffix string
|
||||
SourceMac string
|
||||
NetworkAdapterName string
|
||||
}
|
||||
|
||||
|
@ -43,6 +49,7 @@ type endpointConfiguration struct {
|
|||
PortBindings []types.PortBinding
|
||||
ExposedPorts []types.TransportPort
|
||||
QosPolicies []types.QosPolicy
|
||||
DNSServers []string
|
||||
}
|
||||
|
||||
type hnsEndpoint struct {
|
||||
|
@ -69,7 +76,7 @@ type driver struct {
|
|||
}
|
||||
|
||||
func isValidNetworkType(networkType string) bool {
|
||||
if "l2bridge" == networkType || "l2tunnel" == networkType || "nat" == networkType || "transparent" == networkType {
|
||||
if "l2bridge" == networkType || "l2tunnel" == networkType || "nat" == networkType || "ics" == networkType || "transparent" == networkType {
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -129,6 +136,22 @@ func (d *driver) parseNetworkOptions(id string, genericOptions map[string]string
|
|||
config.RDID = value
|
||||
case Interface:
|
||||
config.NetworkAdapterName = value
|
||||
case DNSSuffix:
|
||||
config.DNSSuffix = value
|
||||
case DNSServers:
|
||||
config.DNSServers = value
|
||||
case VLAN:
|
||||
vlan, err := strconv.ParseUint(value, 10, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.VLAN = uint(vlan)
|
||||
case VSID:
|
||||
vsid, err := strconv.ParseUint(value, 10, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.VSID = uint(vsid)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,9 +230,36 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
|
|||
Name: config.Name,
|
||||
Type: d.name,
|
||||
Subnets: subnets,
|
||||
DNSServerList: config.DNSServers,
|
||||
DNSSuffix: config.DNSSuffix,
|
||||
SourceMac: config.SourceMac,
|
||||
NetworkAdapterName: config.NetworkAdapterName,
|
||||
}
|
||||
|
||||
if config.VLAN != 0 {
|
||||
vlanPolicy, err := json.Marshal(hcsshim.VlanPolicy{
|
||||
Type: "VLAN",
|
||||
VLAN: config.VLAN,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
network.Policies = append(network.Policies, vlanPolicy)
|
||||
}
|
||||
|
||||
if config.VSID != 0 {
|
||||
vsidPolicy, err := json.Marshal(hcsshim.VsidPolicy{
|
||||
Type: "VSID",
|
||||
VSID: config.VSID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
network.Policies = append(network.Policies, vsidPolicy)
|
||||
}
|
||||
|
||||
if network.Name == "" {
|
||||
network.Name = id
|
||||
}
|
||||
|
@ -379,6 +429,14 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfigurat
|
|||
}
|
||||
}
|
||||
|
||||
if opt, ok := epOptions[netlabel.DNSServers]; ok {
|
||||
if dns, ok := opt.([]string); ok {
|
||||
ec.DNSServers = dns
|
||||
} else {
|
||||
return nil, fmt.Errorf("Invalid endpoint configuration")
|
||||
}
|
||||
}
|
||||
|
||||
return ec, nil
|
||||
}
|
||||
|
||||
|
@ -421,6 +479,12 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
|
|||
endpointStruct.IPAddress = ifInfo.Address().IP
|
||||
}
|
||||
|
||||
endpointStruct.DNSServerList = strings.Join(ec.DNSServers, ",")
|
||||
|
||||
if n.driver.name == "nat" {
|
||||
endpointStruct.EnableInternalDNS = true
|
||||
}
|
||||
|
||||
configurationb, err := json.Marshal(endpointStruct)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -502,6 +566,10 @@ func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, erro
|
|||
}
|
||||
|
||||
data := make(map[string]interface{}, 1)
|
||||
if network.driver.name == "nat" {
|
||||
data["AllowUnqualifiedDNSQuery"] = true
|
||||
}
|
||||
|
||||
data["hnsid"] = ep.profileID
|
||||
if ep.config.ExposedPorts != nil {
|
||||
// Return a copy of the config data
|
||||
|
|
|
@ -29,7 +29,7 @@ func testNetwork(networkType string, t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
err := d.CreateNetwork("dummy", netOption, ipdList, nil)
|
||||
err := d.CreateNetwork("dummy", netOption, nil, ipdList, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
|
|
@ -883,6 +883,14 @@ func CreateOptionPortMapping(portBindings []types.PortBinding) EndpointOption {
|
|||
}
|
||||
}
|
||||
|
||||
// CreateOptionDNS function returns an option setter for dns entry option to
|
||||
// be passed to container Create method.
|
||||
func CreateOptionDNS(dns []string) EndpointOption {
|
||||
return func(ep *endpoint) {
|
||||
ep.generic[netlabel.DNSServers] = dns
|
||||
}
|
||||
}
|
||||
|
||||
// CreateOptionAnonymous function returns an option setter for setting
|
||||
// this endpoint as anonymous
|
||||
func CreateOptionAnonymous() EndpointOption {
|
||||
|
|
|
@ -389,10 +389,8 @@ func TestSRVServiceQuery(t *testing.T) {
|
|||
|
||||
c.(*controller).svcRecords[n.ID()] = sr
|
||||
|
||||
_, ip, err := ep.Info().Sandbox().ResolveService("_http._tcp.web.swarm")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, ip := ep.Info().Sandbox().ResolveService("_http._tcp.web.swarm")
|
||||
|
||||
if len(ip) == 0 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -400,10 +398,8 @@ func TestSRVServiceQuery(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, ip, err = ep.Info().Sandbox().ResolveService("_host_http._tcp.web.swarm")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, ip = ep.Info().Sandbox().ResolveService("_host_http._tcp.web.swarm")
|
||||
|
||||
if len(ip) == 0 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -412,7 +408,7 @@ func TestSRVServiceQuery(t *testing.T) {
|
|||
}
|
||||
|
||||
// Service name with invalid protocol name. Should fail without error
|
||||
_, ip, err = ep.Info().Sandbox().ResolveService("_http._icmp.web.swarm")
|
||||
_, ip = ep.Info().Sandbox().ResolveService("_http._icmp.web.swarm")
|
||||
if len(ip) != 0 {
|
||||
t.Fatal("Valid response for invalid service name")
|
||||
}
|
||||
|
|
|
@ -1208,8 +1208,8 @@ func (f *fakeSandbox) ResolveIP(ip string) string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (f *fakeSandbox) ResolveService(name string) ([]*net.SRV, []net.IP, error) {
|
||||
return nil, nil, nil
|
||||
func (f *fakeSandbox) ResolveService(name string) ([]*net.SRV, []net.IP) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (f *fakeSandbox) Endpoints() []libnetwork.Endpoint {
|
||||
|
|
|
@ -27,6 +27,9 @@ const (
|
|||
// ExposedPorts constant represents the container's Exposed Ports
|
||||
ExposedPorts = Prefix + ".endpoint.exposedports"
|
||||
|
||||
// DNSServers A list of DNS servers associated with the endpoint
|
||||
DNSServers = Prefix + ".endpoint.dnsservers"
|
||||
|
||||
//EnableIPv6 constant represents enabling IPV6 at network level
|
||||
EnableIPv6 = Prefix + ".enable_ipv6"
|
||||
|
||||
|
|
|
@ -184,6 +184,8 @@ type network struct {
|
|||
persist bool
|
||||
stopWatchCh chan struct{}
|
||||
drvOnce *sync.Once
|
||||
resolverOnce sync.Once
|
||||
resolver []Resolver
|
||||
internal bool
|
||||
inDelete bool
|
||||
ingress bool
|
||||
|
@ -803,6 +805,9 @@ func (n *network) deleteNetwork() error {
|
|||
}
|
||||
}
|
||||
|
||||
for _, resolver := range n.resolver {
|
||||
resolver.Stop()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1528,3 +1533,126 @@ func (n *network) TableEventRegister(tableName string) error {
|
|||
func (n *network) hasSpecialDriver() bool {
|
||||
return n.Type() == "host" || n.Type() == "null"
|
||||
}
|
||||
|
||||
func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) {
|
||||
var ipv6Miss bool
|
||||
|
||||
c := n.getController()
|
||||
c.Lock()
|
||||
sr, ok := c.svcRecords[n.ID()]
|
||||
c.Unlock()
|
||||
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
req = strings.TrimSuffix(req, ".")
|
||||
var ip []net.IP
|
||||
n.Lock()
|
||||
ip, ok = sr.svcMap[req]
|
||||
|
||||
if ipType == types.IPv6 {
|
||||
// If the name resolved to v4 address then its a valid name in
|
||||
// the docker network domain. If the network is not v6 enabled
|
||||
// set ipv6Miss to filter the DNS query from going to external
|
||||
// resolvers.
|
||||
if ok && n.enableIPv6 == false {
|
||||
ipv6Miss = true
|
||||
}
|
||||
ip = sr.svcIPv6Map[req]
|
||||
}
|
||||
n.Unlock()
|
||||
|
||||
if ip != nil {
|
||||
return ip, false
|
||||
}
|
||||
|
||||
return nil, ipv6Miss
|
||||
}
|
||||
|
||||
func (n *network) ResolveIP(ip string) string {
|
||||
var svc string
|
||||
|
||||
c := n.getController()
|
||||
c.Lock()
|
||||
sr, ok := c.svcRecords[n.ID()]
|
||||
c.Unlock()
|
||||
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
nwName := n.Name()
|
||||
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
svc, ok = sr.ipMap[ip]
|
||||
|
||||
if ok {
|
||||
return svc + "." + nwName
|
||||
}
|
||||
|
||||
return svc
|
||||
}
|
||||
|
||||
func (n *network) ResolveService(name string) ([]*net.SRV, []net.IP) {
|
||||
c := n.getController()
|
||||
|
||||
srv := []*net.SRV{}
|
||||
ip := []net.IP{}
|
||||
|
||||
log.Debugf("Service name To resolve: %v", name)
|
||||
|
||||
// There are DNS implementaions that allow SRV queries for names not in
|
||||
// the format defined by RFC 2782. Hence specific validations checks are
|
||||
// not done
|
||||
parts := strings.Split(name, ".")
|
||||
if len(parts) < 3 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
portName := parts[0]
|
||||
proto := parts[1]
|
||||
svcName := strings.Join(parts[2:], ".")
|
||||
|
||||
c.Lock()
|
||||
sr, ok := c.svcRecords[n.ID()]
|
||||
c.Unlock()
|
||||
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
svcs, ok := sr.service[svcName]
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
for _, svc := range svcs {
|
||||
if svc.portName != portName {
|
||||
continue
|
||||
}
|
||||
if svc.proto != proto {
|
||||
continue
|
||||
}
|
||||
for _, t := range svc.target {
|
||||
srv = append(srv,
|
||||
&net.SRV{
|
||||
Target: t.name,
|
||||
Port: t.port,
|
||||
})
|
||||
|
||||
ip = append(ip, t.ip)
|
||||
}
|
||||
}
|
||||
|
||||
return srv, ip
|
||||
}
|
||||
|
||||
func (n *network) ExecFunc(f func()) error {
|
||||
return types.NotImplementedErrorf("ExecFunc not supported by network")
|
||||
}
|
||||
|
||||
func (n *network) NdotsSet() bool {
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
// +build !windows
|
||||
|
||||
package libnetwork
|
||||
|
||||
// Stub implementations for DNS related functions
|
||||
|
||||
func (n *network) startResolver() {
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
// +build windows
|
||||
|
||||
package libnetwork
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/Microsoft/hcsshim"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork/drivers/windows"
|
||||
)
|
||||
|
||||
func executeInCompartment(compartmentID uint32, x func()) {
|
||||
runtime.LockOSThread()
|
||||
|
||||
if err := hcsshim.SetCurrentThreadCompartmentId(compartmentID); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
defer func() {
|
||||
hcsshim.SetCurrentThreadCompartmentId(0)
|
||||
runtime.UnlockOSThread()
|
||||
}()
|
||||
|
||||
x()
|
||||
}
|
||||
|
||||
func (n *network) startResolver() {
|
||||
n.resolverOnce.Do(func() {
|
||||
log.Debugf("Launching DNS server for network", n.Name())
|
||||
options := n.Info().DriverOptions()
|
||||
hnsid := options[windows.HNSID]
|
||||
|
||||
hnsresponse, err := hcsshim.HNSNetworkRequest("GET", hnsid, "")
|
||||
if err != nil {
|
||||
log.Errorf("Resolver Setup/Start failed for container %s, %q", n.Name(), err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, subnet := range hnsresponse.Subnets {
|
||||
if subnet.GatewayAddress != "" {
|
||||
resolver := NewResolver(subnet.GatewayAddress, false, "", n)
|
||||
log.Debugf("Binding a resolver on network %s gateway %s", n.Name(), subnet.GatewayAddress)
|
||||
executeInCompartment(hnsresponse.DNSServerCompartment, resolver.SetupFunc(53))
|
||||
if err = resolver.Start(); err != nil {
|
||||
log.Errorf("Resolver Setup/Start failed for container %s, %q", n.Name(), err)
|
||||
} else {
|
||||
n.resolver = append(n.resolver, resolver)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -23,7 +23,7 @@ type Resolver interface {
|
|||
Stop()
|
||||
// SetupFunc() provides the setup function that should be run
|
||||
// in the container's network namespace.
|
||||
SetupFunc() func()
|
||||
SetupFunc(int) func()
|
||||
// NameServer() returns the IP of the DNS resolver for the
|
||||
// containers.
|
||||
NameServer() string
|
||||
|
@ -34,8 +34,29 @@ type Resolver interface {
|
|||
ResolverOptions() []string
|
||||
}
|
||||
|
||||
// DNSBackend represents a backend DNS resolver used for DNS name
|
||||
// resolution. All the queries to the resolver are forwared to the
|
||||
// backend resolver.
|
||||
type DNSBackend interface {
|
||||
// ResolveName resolves a service name to an IPv4 or IPv6 address by searching
|
||||
// the networks the sandbox is connected to. For IPv6 queries, second return
|
||||
// value will be true if the name exists in docker domain but doesn't have an
|
||||
// IPv6 address. Such queries shouldn't be forwarded to external nameservers.
|
||||
ResolveName(name string, iplen int) ([]net.IP, bool)
|
||||
// ResolveIP returns the service name for the passed in IP. IP is in reverse dotted
|
||||
// notation; the format used for DNS PTR records
|
||||
ResolveIP(name string) string
|
||||
// ResolveService returns all the backend details about the containers or hosts
|
||||
// backing a service. Its purpose is to satisfy an SRV query
|
||||
ResolveService(name string) ([]*net.SRV, []net.IP)
|
||||
// ExecFunc allows a function to be executed in the context of the backend
|
||||
// on behalf of the resolver.
|
||||
ExecFunc(f func()) error
|
||||
//NdotsSet queries the backends ndots dns option settings
|
||||
NdotsSet() bool
|
||||
}
|
||||
|
||||
const (
|
||||
resolverIP = "127.0.0.11"
|
||||
dnsPort = "53"
|
||||
ptrIPv4domain = ".in-addr.arpa."
|
||||
ptrIPv6domain = ".ip6.arpa."
|
||||
|
@ -53,16 +74,19 @@ type extDNSEntry struct {
|
|||
|
||||
// resolver implements the Resolver interface
|
||||
type resolver struct {
|
||||
sb *sandbox
|
||||
extDNSList [maxExtDNS]extDNSEntry
|
||||
server *dns.Server
|
||||
conn *net.UDPConn
|
||||
tcpServer *dns.Server
|
||||
tcpListen *net.TCPListener
|
||||
err error
|
||||
count int32
|
||||
tStamp time.Time
|
||||
queryLock sync.Mutex
|
||||
backend DNSBackend
|
||||
extDNSList [maxExtDNS]extDNSEntry
|
||||
server *dns.Server
|
||||
conn *net.UDPConn
|
||||
tcpServer *dns.Server
|
||||
tcpListen *net.TCPListener
|
||||
err error
|
||||
count int32
|
||||
tStamp time.Time
|
||||
queryLock sync.Mutex
|
||||
listenAddress string
|
||||
proxyDNS bool
|
||||
resolverKey string
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -70,20 +94,24 @@ func init() {
|
|||
}
|
||||
|
||||
// NewResolver creates a new instance of the Resolver
|
||||
func NewResolver(sb *sandbox) Resolver {
|
||||
func NewResolver(address string, proxyDNS bool, resolverKey string, backend DNSBackend) Resolver {
|
||||
return &resolver{
|
||||
sb: sb,
|
||||
err: fmt.Errorf("setup not done yet"),
|
||||
backend: backend,
|
||||
proxyDNS: proxyDNS,
|
||||
listenAddress: address,
|
||||
resolverKey: resolverKey,
|
||||
err: fmt.Errorf("setup not done yet"),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *resolver) SetupFunc() func() {
|
||||
func (r *resolver) SetupFunc(port int) func() {
|
||||
return (func() {
|
||||
var err error
|
||||
|
||||
// DNS operates primarily on UDP
|
||||
addr := &net.UDPAddr{
|
||||
IP: net.ParseIP(resolverIP),
|
||||
IP: net.ParseIP(r.listenAddress),
|
||||
Port: port,
|
||||
}
|
||||
|
||||
r.conn, err = net.ListenUDP("udp", addr)
|
||||
|
@ -94,7 +122,8 @@ func (r *resolver) SetupFunc() func() {
|
|||
|
||||
// Listen on a TCP as well
|
||||
tcpaddr := &net.TCPAddr{
|
||||
IP: net.ParseIP(resolverIP),
|
||||
IP: net.ParseIP(r.listenAddress),
|
||||
Port: port,
|
||||
}
|
||||
|
||||
r.tcpListen, err = net.ListenTCP("tcp", tcpaddr)
|
||||
|
@ -156,7 +185,7 @@ func (r *resolver) SetExtServers(dns []string) {
|
|||
}
|
||||
|
||||
func (r *resolver) NameServer() string {
|
||||
return resolverIP
|
||||
return r.listenAddress
|
||||
}
|
||||
|
||||
func (r *resolver) ResolverOptions() []string {
|
||||
|
@ -184,7 +213,10 @@ func createRespMsg(query *dns.Msg) *dns.Msg {
|
|||
}
|
||||
|
||||
func (r *resolver) handleIPQuery(name string, query *dns.Msg, ipType int) (*dns.Msg, error) {
|
||||
addr, ipv6Miss := r.sb.ResolveName(name, ipType)
|
||||
var addr []net.IP
|
||||
var ipv6Miss bool
|
||||
addr, ipv6Miss = r.backend.ResolveName(name, ipType)
|
||||
|
||||
if addr == nil && ipv6Miss {
|
||||
// Send a reply without any Answer sections
|
||||
log.Debugf("Lookup name %s present without IPv6 address", name)
|
||||
|
@ -230,7 +262,8 @@ func (r *resolver) handlePTRQuery(ptr string, query *dns.Msg) (*dns.Msg, error)
|
|||
return nil, fmt.Errorf("invalid PTR query, %v", ptr)
|
||||
}
|
||||
|
||||
host := r.sb.ResolveIP(parts[0])
|
||||
host := r.backend.ResolveIP(parts[0])
|
||||
|
||||
if len(host) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -250,11 +283,9 @@ func (r *resolver) handlePTRQuery(ptr string, query *dns.Msg) (*dns.Msg, error)
|
|||
}
|
||||
|
||||
func (r *resolver) handleSRVQuery(svc string, query *dns.Msg) (*dns.Msg, error) {
|
||||
srv, ip, err := r.sb.ResolveService(svc)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
srv, ip := r.backend.ResolveService(svc)
|
||||
|
||||
if len(srv) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -325,16 +356,25 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
|
|||
return
|
||||
}
|
||||
|
||||
// If the user sets ndots > 0 explicitly and the query is
|
||||
// in the root domain don't forward it out. We will return
|
||||
// failure and let the client retry with the search domain
|
||||
// attached
|
||||
if resp == nil {
|
||||
// If the backend doesn't support proxying dns request
|
||||
// fail the response
|
||||
if !r.proxyDNS {
|
||||
resp = new(dns.Msg)
|
||||
resp.SetRcode(query, dns.RcodeServerFailure)
|
||||
w.WriteMsg(resp)
|
||||
return
|
||||
}
|
||||
|
||||
// If the user sets ndots > 0 explicitly and the query is
|
||||
// in the root domain don't forward it out. We will return
|
||||
// failure and let the client retry with the search domain
|
||||
// attached
|
||||
switch query.Question[0].Qtype {
|
||||
case dns.TypeA:
|
||||
fallthrough
|
||||
case dns.TypeAAAA:
|
||||
if r.sb.ndotsSet && !strings.Contains(strings.TrimSuffix(name, "."), ".") {
|
||||
if r.backend.NdotsSet() && !strings.Contains(strings.TrimSuffix(name, "."), ".") {
|
||||
resp = createRespMsg(query)
|
||||
}
|
||||
}
|
||||
|
@ -369,8 +409,8 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
|
|||
extConn, err = net.DialTimeout(proto, addr, extIOTimeout)
|
||||
}
|
||||
|
||||
r.sb.execFunc(extConnect)
|
||||
if err != nil {
|
||||
execErr := r.backend.ExecFunc(extConnect)
|
||||
if execErr != nil || err != nil {
|
||||
log.Debugf("Connect failed, %s", err)
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ func reexecSetupResolver() {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
_, ipPort, _ := net.SplitHostPort(os.Args[2])
|
||||
resolverIP, ipPort, _ := net.SplitHostPort(os.Args[2])
|
||||
_, tcpPort, _ := net.SplitHostPort(os.Args[3])
|
||||
rules := [][]string{
|
||||
{"-t", "nat", "-I", outputChain, "-d", resolverIP, "-p", "udp", "--dport", dnsPort, "-j", "DNAT", "--to-destination", os.Args[2]},
|
||||
|
@ -90,7 +90,7 @@ func (r *resolver) setupIPTable() error {
|
|||
|
||||
cmd := &exec.Cmd{
|
||||
Path: reexec.Self(),
|
||||
Args: append([]string{"setup-resolver"}, r.sb.Key(), laddr, ltcpaddr),
|
||||
Args: append([]string{"setup-resolver"}, r.resolverKey, laddr, ltcpaddr),
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
}
|
||||
|
|
|
@ -37,19 +37,11 @@ type Sandbox interface {
|
|||
Rename(name string) error
|
||||
// Delete destroys this container after detaching it from all connected endpoints.
|
||||
Delete() error
|
||||
// ResolveName resolves a service name to an IPv4 or IPv6 address by searching
|
||||
// the networks the sandbox is connected to. For IPv6 queries, second return
|
||||
// value will be true if the name exists in docker domain but doesn't have an
|
||||
// IPv6 address. Such queries shouldn't be forwarded to external nameservers.
|
||||
ResolveName(name string, iplen int) ([]net.IP, bool)
|
||||
// ResolveIP returns the service name for the passed in IP. IP is in reverse dotted
|
||||
// notation; the format used for DNS PTR records
|
||||
ResolveIP(name string) string
|
||||
// ResolveService returns all the backend details about the containers or hosts
|
||||
// backing a service. Its purpose is to satisfy an SRV query
|
||||
ResolveService(name string) ([]*net.SRV, []net.IP, error)
|
||||
// Endpoints returns all the endpoints connected to the sandbox
|
||||
Endpoints() []Endpoint
|
||||
// ResolveService returns all the backend details about the containers or hosts
|
||||
// backing a service. Its purpose is to satisfy an SRV query
|
||||
ResolveService(name string) ([]*net.SRV, []net.IP)
|
||||
}
|
||||
|
||||
// SandboxOption is an option setter function type used to pass various options to
|
||||
|
@ -131,6 +123,10 @@ type containerConfig struct {
|
|||
exposedPorts []types.TransportPort
|
||||
}
|
||||
|
||||
const (
|
||||
resolverIPSandbox = "127.0.0.11"
|
||||
)
|
||||
|
||||
func (sb *sandbox) ID() string {
|
||||
return sb.id
|
||||
}
|
||||
|
@ -415,33 +411,21 @@ func (sb *sandbox) ResolveIP(ip string) string {
|
|||
|
||||
for _, ep := range sb.getConnectedEndpoints() {
|
||||
n := ep.getNetwork()
|
||||
|
||||
c := n.getController()
|
||||
|
||||
c.Lock()
|
||||
sr, ok := c.svcRecords[n.ID()]
|
||||
c.Unlock()
|
||||
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
nwName := n.Name()
|
||||
n.Lock()
|
||||
svc, ok = sr.ipMap[ip]
|
||||
n.Unlock()
|
||||
if ok {
|
||||
return svc + "." + nwName
|
||||
svc = n.ResolveIP(ip)
|
||||
if len(svc) != 0 {
|
||||
return svc
|
||||
}
|
||||
}
|
||||
|
||||
return svc
|
||||
}
|
||||
|
||||
func (sb *sandbox) execFunc(f func()) {
|
||||
func (sb *sandbox) ExecFunc(f func()) error {
|
||||
sb.osSbox.InvokeFunc(f)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sb *sandbox) ResolveService(name string) ([]*net.SRV, []net.IP, error) {
|
||||
func (sb *sandbox) ResolveService(name string) ([]*net.SRV, []net.IP) {
|
||||
srv := []*net.SRV{}
|
||||
ip := []net.IP{}
|
||||
|
||||
|
@ -452,53 +436,18 @@ func (sb *sandbox) ResolveService(name string) ([]*net.SRV, []net.IP, error) {
|
|||
// not done
|
||||
parts := strings.Split(name, ".")
|
||||
if len(parts) < 3 {
|
||||
return nil, nil, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
portName := parts[0]
|
||||
proto := parts[1]
|
||||
svcName := strings.Join(parts[2:], ".")
|
||||
|
||||
for _, ep := range sb.getConnectedEndpoints() {
|
||||
n := ep.getNetwork()
|
||||
|
||||
c := n.getController()
|
||||
|
||||
c.Lock()
|
||||
sr, ok := c.svcRecords[n.ID()]
|
||||
c.Unlock()
|
||||
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
svcs, ok := sr.service[svcName]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, svc := range svcs {
|
||||
if svc.portName != portName {
|
||||
continue
|
||||
}
|
||||
if svc.proto != proto {
|
||||
continue
|
||||
}
|
||||
for _, t := range svc.target {
|
||||
srv = append(srv,
|
||||
&net.SRV{
|
||||
Target: t.name,
|
||||
Port: t.port,
|
||||
})
|
||||
|
||||
ip = append(ip, t.ip)
|
||||
}
|
||||
}
|
||||
srv, ip = n.ResolveService(name)
|
||||
if len(srv) > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return srv, ip, nil
|
||||
return srv, ip
|
||||
}
|
||||
|
||||
func getDynamicNwEndpoints(epList []*endpoint) []*endpoint {
|
||||
|
@ -635,33 +584,15 @@ func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoin
|
|||
ep.Unlock()
|
||||
}
|
||||
|
||||
c := n.getController()
|
||||
c.Lock()
|
||||
sr, ok := c.svcRecords[n.ID()]
|
||||
c.Unlock()
|
||||
ip, miss := n.ResolveName(name, ipType)
|
||||
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
var ip []net.IP
|
||||
n.Lock()
|
||||
ip, ok = sr.svcMap[name]
|
||||
|
||||
if ipType == types.IPv6 {
|
||||
// If the name resolved to v4 address then its a valid name in
|
||||
// the docker network domain. If the network is not v6 enabled
|
||||
// set ipv6Miss to filter the DNS query from going to external
|
||||
// resolvers.
|
||||
if ok && n.enableIPv6 == false {
|
||||
ipv6Miss = true
|
||||
}
|
||||
ip = sr.svcIPv6Map[name]
|
||||
}
|
||||
n.Unlock()
|
||||
if ip != nil {
|
||||
return ip, false
|
||||
}
|
||||
|
||||
if miss {
|
||||
ipv6Miss = miss
|
||||
}
|
||||
}
|
||||
return nil, ipv6Miss
|
||||
}
|
||||
|
@ -708,7 +639,7 @@ func (sb *sandbox) SetKey(basePath string) error {
|
|||
if oldosSbox != nil && sb.resolver != nil {
|
||||
sb.resolver.Stop()
|
||||
|
||||
sb.osSbox.InvokeFunc(sb.resolver.SetupFunc())
|
||||
sb.osSbox.InvokeFunc(sb.resolver.SetupFunc(0))
|
||||
if err := sb.resolver.Start(); err != nil {
|
||||
log.Errorf("Resolver Setup/Start failed for container %s, %q", sb.ContainerID(), err)
|
||||
}
|
||||
|
@ -1231,3 +1162,7 @@ func (eh *epHeap) Pop() interface{} {
|
|||
*eh = old[0 : n-1]
|
||||
return x
|
||||
}
|
||||
|
||||
func (sb *sandbox) NdotsSet() bool {
|
||||
return sb.ndotsSet
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ const (
|
|||
func (sb *sandbox) startResolver(restore bool) {
|
||||
sb.resolverOnce.Do(func() {
|
||||
var err error
|
||||
sb.resolver = NewResolver(sb)
|
||||
sb.resolver = NewResolver(resolverIPSandbox, true, sb.Key(), sb)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
sb.resolver = nil
|
||||
|
@ -46,7 +46,7 @@ func (sb *sandbox) startResolver(restore bool) {
|
|||
}
|
||||
sb.resolver.SetExtServers(sb.extDNS)
|
||||
|
||||
sb.osSbox.InvokeFunc(sb.resolver.SetupFunc())
|
||||
sb.osSbox.InvokeFunc(sb.resolver.SetupFunc(0))
|
||||
if err = sb.resolver.Start(); err != nil {
|
||||
log.Errorf("Resolver Setup/Start failed for container %s, %q", sb.ContainerID(), err)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue