github.com/pwn-term/docker@v0.0.0-20210616085119-6e977cce2565/libnetwork/drivers/windows/windows.go (about)

     1  // +build windows
     2  
     3  // Shim for the Host Network Service (HNS) to manage networking for
     4  // Windows Server containers and Hyper-V containers. This module
     5  // is a basic libnetwork driver that passes all the calls to HNS
     6  // It implements the 4 networking modes supported by HNS L2Bridge,
     7  // L2Tunnel, NAT and Transparent(DHCP)
     8  //
     9  // The network are stored in memory and docker daemon ensures discovering
    10  // and loading these networks on startup
    11  
    12  package windows
    13  
    14  import (
    15  	"encoding/json"
    16  	"fmt"
    17  	"net"
    18  	"strconv"
    19  	"strings"
    20  	"sync"
    21  
    22  	"github.com/Microsoft/hcsshim"
    23  	"github.com/Microsoft/hcsshim/osversion"
    24  	"github.com/docker/libnetwork/datastore"
    25  	"github.com/docker/libnetwork/discoverapi"
    26  	"github.com/docker/libnetwork/driverapi"
    27  	"github.com/docker/libnetwork/netlabel"
    28  	"github.com/docker/libnetwork/portmapper"
    29  	"github.com/docker/libnetwork/types"
    30  	"github.com/sirupsen/logrus"
    31  )
    32  
    33  // networkConfiguration for network specific configuration
    34  type networkConfiguration struct {
    35  	ID                    string
    36  	Type                  string
    37  	Name                  string
    38  	HnsID                 string
    39  	RDID                  string
    40  	VLAN                  uint
    41  	VSID                  uint
    42  	DNSServers            string
    43  	MacPools              []hcsshim.MacPool
    44  	DNSSuffix             string
    45  	SourceMac             string
    46  	NetworkAdapterName    string
    47  	dbIndex               uint64
    48  	dbExists              bool
    49  	DisableGatewayDNS     bool
    50  	EnableOutboundNat     bool
    51  	OutboundNatExceptions []string
    52  }
    53  
    54  // endpointConfiguration represents the user specified configuration for the sandbox endpoint
    55  type endpointOption struct {
    56  	MacAddress  net.HardwareAddr
    57  	QosPolicies []types.QosPolicy
    58  	DNSServers  []string
    59  	DisableDNS  bool
    60  	DisableICC  bool
    61  }
    62  
    63  // EndpointConnectivity stores the port bindings and exposed ports that the user has specified in epOptions.
    64  type EndpointConnectivity struct {
    65  	PortBindings []types.PortBinding
    66  	ExposedPorts []types.TransportPort
    67  }
    68  
    69  type hnsEndpoint struct {
    70  	id        string
    71  	nid       string
    72  	profileID string
    73  	Type      string
    74  	//Note: Currently, the sandboxID is the same as the containerID since windows does
    75  	//not expose the sandboxID.
    76  	//In the future, windows will support a proper sandboxID that is different
    77  	//than the containerID.
    78  	//Therefore, we are using sandboxID now, so that we won't have to change this code
    79  	//when windows properly supports a sandboxID.
    80  	sandboxID      string
    81  	macAddress     net.HardwareAddr
    82  	epOption       *endpointOption       // User specified parameters
    83  	epConnectivity *EndpointConnectivity // User specified parameters
    84  	portMapping    []types.PortBinding   // Operation port bindings
    85  	addr           *net.IPNet
    86  	gateway        net.IP
    87  	dbIndex        uint64
    88  	dbExists       bool
    89  }
    90  
    91  type hnsNetwork struct {
    92  	id         string
    93  	created    bool
    94  	config     *networkConfiguration
    95  	endpoints  map[string]*hnsEndpoint // key: endpoint id
    96  	driver     *driver                 // The network's driver
    97  	portMapper *portmapper.PortMapper
    98  	sync.Mutex
    99  }
   100  
   101  type driver struct {
   102  	name     string
   103  	networks map[string]*hnsNetwork
   104  	store    datastore.DataStore
   105  	sync.Mutex
   106  }
   107  
   108  const (
   109  	errNotFound = "HNS failed with error : The object identifier does not represent a valid object. "
   110  )
   111  
   112  // IsBuiltinLocalDriver validates if network-type is a builtin local-scoped driver
   113  func IsBuiltinLocalDriver(networkType string) bool {
   114  	if "l2bridge" == networkType || "l2tunnel" == networkType ||
   115  		"nat" == networkType || "ics" == networkType ||
   116  		"transparent" == networkType || "internal" == networkType ||
   117  		"private" == networkType {
   118  		return true
   119  	}
   120  
   121  	return false
   122  }
   123  
   124  // New constructs a new bridge driver
   125  func newDriver(networkType string) *driver {
   126  	return &driver{name: networkType, networks: map[string]*hnsNetwork{}}
   127  }
   128  
   129  // GetInit returns an initializer for the given network type
   130  func GetInit(networkType string) func(dc driverapi.DriverCallback, config map[string]interface{}) error {
   131  	return func(dc driverapi.DriverCallback, config map[string]interface{}) error {
   132  		if !IsBuiltinLocalDriver(networkType) {
   133  			return types.BadRequestErrorf("Network type not supported: %s", networkType)
   134  		}
   135  
   136  		d := newDriver(networkType)
   137  
   138  		err := d.initStore(config)
   139  		if err != nil {
   140  			return err
   141  		}
   142  
   143  		return dc.RegisterDriver(networkType, d, driverapi.Capability{
   144  			DataScope:         datastore.LocalScope,
   145  			ConnectivityScope: datastore.LocalScope,
   146  		})
   147  	}
   148  }
   149  
   150  func (d *driver) getNetwork(id string) (*hnsNetwork, error) {
   151  	d.Lock()
   152  	defer d.Unlock()
   153  
   154  	if nw, ok := d.networks[id]; ok {
   155  		return nw, nil
   156  	}
   157  
   158  	return nil, types.NotFoundErrorf("network not found: %s", id)
   159  }
   160  
   161  func (n *hnsNetwork) getEndpoint(eid string) (*hnsEndpoint, error) {
   162  	n.Lock()
   163  	defer n.Unlock()
   164  
   165  	if ep, ok := n.endpoints[eid]; ok {
   166  		return ep, nil
   167  	}
   168  
   169  	return nil, types.NotFoundErrorf("Endpoint not found: %s", eid)
   170  }
   171  
   172  func (d *driver) parseNetworkOptions(id string, genericOptions map[string]string) (*networkConfiguration, error) {
   173  	config := &networkConfiguration{Type: d.name}
   174  
   175  	for label, value := range genericOptions {
   176  		switch label {
   177  		case NetworkName:
   178  			config.Name = value
   179  		case HNSID:
   180  			config.HnsID = value
   181  		case RoutingDomain:
   182  			config.RDID = value
   183  		case Interface:
   184  			config.NetworkAdapterName = value
   185  		case DNSSuffix:
   186  			config.DNSSuffix = value
   187  		case DNSServers:
   188  			config.DNSServers = value
   189  		case DisableGatewayDNS:
   190  			b, err := strconv.ParseBool(value)
   191  			if err != nil {
   192  				return nil, err
   193  			}
   194  			config.DisableGatewayDNS = b
   195  		case MacPool:
   196  			config.MacPools = make([]hcsshim.MacPool, 0)
   197  			s := strings.Split(value, ",")
   198  			if len(s)%2 != 0 {
   199  				return nil, types.BadRequestErrorf("Invalid mac pool. You must specify both a start range and an end range")
   200  			}
   201  			for i := 0; i < len(s)-1; i += 2 {
   202  				config.MacPools = append(config.MacPools, hcsshim.MacPool{
   203  					StartMacAddress: s[i],
   204  					EndMacAddress:   s[i+1],
   205  				})
   206  			}
   207  		case VLAN:
   208  			vlan, err := strconv.ParseUint(value, 10, 32)
   209  			if err != nil {
   210  				return nil, err
   211  			}
   212  			config.VLAN = uint(vlan)
   213  		case VSID:
   214  			vsid, err := strconv.ParseUint(value, 10, 32)
   215  			if err != nil {
   216  				return nil, err
   217  			}
   218  			config.VSID = uint(vsid)
   219  		case EnableOutboundNat:
   220  			if osversion.Build() <= 16236 {
   221  				return nil, fmt.Errorf("Invalid network option. OutboundNat is not supported on this OS version")
   222  			}
   223  			b, err := strconv.ParseBool(value)
   224  			if err != nil {
   225  				return nil, err
   226  			}
   227  			config.EnableOutboundNat = b
   228  		case OutboundNatExceptions:
   229  			s := strings.Split(value, ",")
   230  			config.OutboundNatExceptions = s
   231  		}
   232  	}
   233  
   234  	config.ID = id
   235  	config.Type = d.name
   236  	return config, nil
   237  }
   238  
   239  func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error {
   240  	if len(ipamV6Data) > 0 {
   241  		return types.ForbiddenErrorf("windowsshim driver doesn't support v6 subnets")
   242  	}
   243  
   244  	if len(ipamV4Data) == 0 {
   245  		return types.BadRequestErrorf("network %s requires ipv4 configuration", id)
   246  	}
   247  
   248  	return nil
   249  }
   250  
   251  func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
   252  }
   253  
   254  func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
   255  	return "", nil
   256  }
   257  
   258  func (d *driver) createNetwork(config *networkConfiguration) *hnsNetwork {
   259  	network := &hnsNetwork{
   260  		id:         config.ID,
   261  		endpoints:  make(map[string]*hnsEndpoint),
   262  		config:     config,
   263  		driver:     d,
   264  		portMapper: portmapper.New(""),
   265  	}
   266  
   267  	d.Lock()
   268  	d.networks[config.ID] = network
   269  	d.Unlock()
   270  
   271  	return network
   272  }
   273  
   274  // Create a new network
   275  func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
   276  	if _, err := d.getNetwork(id); err == nil {
   277  		return types.ForbiddenErrorf("network %s exists", id)
   278  	}
   279  
   280  	genData, ok := option[netlabel.GenericData].(map[string]string)
   281  	if !ok {
   282  		return fmt.Errorf("Unknown generic data option")
   283  	}
   284  
   285  	// Parse and validate the config. It should not conflict with existing networks' config
   286  	config, err := d.parseNetworkOptions(id, genData)
   287  	if err != nil {
   288  		return err
   289  	}
   290  
   291  	err = config.processIPAM(id, ipV4Data, ipV6Data)
   292  	if err != nil {
   293  		return err
   294  	}
   295  
   296  	n := d.createNetwork(config)
   297  
   298  	// A non blank hnsid indicates that the network was discovered
   299  	// from HNS. No need to call HNS if this network was discovered
   300  	// from HNS
   301  	if config.HnsID == "" {
   302  		subnets := []hcsshim.Subnet{}
   303  
   304  		for _, ipData := range ipV4Data {
   305  			subnet := hcsshim.Subnet{
   306  				AddressPrefix: ipData.Pool.String(),
   307  			}
   308  
   309  			if ipData.Gateway != nil {
   310  				subnet.GatewayAddress = ipData.Gateway.IP.String()
   311  			}
   312  
   313  			subnets = append(subnets, subnet)
   314  		}
   315  
   316  		network := &hcsshim.HNSNetwork{
   317  			Name:               config.Name,
   318  			Type:               d.name,
   319  			Subnets:            subnets,
   320  			DNSServerList:      config.DNSServers,
   321  			DNSSuffix:          config.DNSSuffix,
   322  			MacPools:           config.MacPools,
   323  			SourceMac:          config.SourceMac,
   324  			NetworkAdapterName: config.NetworkAdapterName,
   325  		}
   326  
   327  		if config.VLAN != 0 {
   328  			vlanPolicy, err := json.Marshal(hcsshim.VlanPolicy{
   329  				Type: "VLAN",
   330  				VLAN: config.VLAN,
   331  			})
   332  
   333  			if err != nil {
   334  				return err
   335  			}
   336  			network.Policies = append(network.Policies, vlanPolicy)
   337  		}
   338  
   339  		if config.VSID != 0 {
   340  			vsidPolicy, err := json.Marshal(hcsshim.VsidPolicy{
   341  				Type: "VSID",
   342  				VSID: config.VSID,
   343  			})
   344  
   345  			if err != nil {
   346  				return err
   347  			}
   348  			network.Policies = append(network.Policies, vsidPolicy)
   349  		}
   350  
   351  		if network.Name == "" {
   352  			network.Name = id
   353  		}
   354  
   355  		configurationb, err := json.Marshal(network)
   356  		if err != nil {
   357  			return err
   358  		}
   359  
   360  		configuration := string(configurationb)
   361  		logrus.Debugf("HNSNetwork Request =%v Address Space=%v", configuration, subnets)
   362  
   363  		hnsresponse, err := hcsshim.HNSNetworkRequest("POST", "", configuration)
   364  		if err != nil {
   365  			return err
   366  		}
   367  
   368  		config.HnsID = hnsresponse.Id
   369  		genData[HNSID] = config.HnsID
   370  		n.created = true
   371  
   372  		defer func() {
   373  			if err != nil {
   374  				d.DeleteNetwork(n.id)
   375  			}
   376  		}()
   377  
   378  		hnsIPv4Data := make([]driverapi.IPAMData, len(hnsresponse.Subnets))
   379  
   380  		for i, subnet := range hnsresponse.Subnets {
   381  			var gwIP, subnetIP *net.IPNet
   382  
   383  			//The gateway returned from HNS is an IPAddress.
   384  			//We need to convert it to an IPNet to use as the Gateway of driverapi.IPAMData struct
   385  			gwCIDR := subnet.GatewayAddress + "/32"
   386  			_, gwIP, err = net.ParseCIDR(gwCIDR)
   387  			if err != nil {
   388  				return err
   389  			}
   390  
   391  			hnsIPv4Data[i].Gateway = gwIP
   392  			_, subnetIP, err = net.ParseCIDR(subnet.AddressPrefix)
   393  			if err != nil {
   394  				return err
   395  			}
   396  			hnsIPv4Data[i].Pool = subnetIP
   397  		}
   398  
   399  		nInfo.UpdateIpamConfig(hnsIPv4Data)
   400  
   401  	} else {
   402  		// Delete any stale HNS endpoints for this network.
   403  		if endpoints, err := hcsshim.HNSListEndpointRequest(); err == nil {
   404  			for _, ep := range endpoints {
   405  				if ep.VirtualNetwork == config.HnsID {
   406  					logrus.Infof("Removing stale HNS endpoint %s", ep.Id)
   407  					_, err = hcsshim.HNSEndpointRequest("DELETE", ep.Id, "")
   408  					if err != nil {
   409  						logrus.Warnf("Error removing HNS endpoint %s", ep.Id)
   410  					}
   411  				}
   412  			}
   413  		} else {
   414  			logrus.Warnf("Error listing HNS endpoints for network %s", config.HnsID)
   415  		}
   416  
   417  		n.created = true
   418  	}
   419  
   420  	return d.storeUpdate(config)
   421  }
   422  
   423  func (d *driver) DeleteNetwork(nid string) error {
   424  	n, err := d.getNetwork(nid)
   425  	if err != nil {
   426  		return types.InternalMaskableErrorf("%s", err)
   427  	}
   428  
   429  	n.Lock()
   430  	config := n.config
   431  	n.Unlock()
   432  
   433  	if n.created {
   434  		_, err = hcsshim.HNSNetworkRequest("DELETE", config.HnsID, "")
   435  		if err != nil && err.Error() != errNotFound {
   436  			return types.ForbiddenErrorf(err.Error())
   437  		}
   438  	}
   439  
   440  	d.Lock()
   441  	delete(d.networks, nid)
   442  	d.Unlock()
   443  
   444  	// delele endpoints belong to this network
   445  	for _, ep := range n.endpoints {
   446  		if err := d.storeDelete(ep); err != nil {
   447  			logrus.Warnf("Failed to remove bridge endpoint %.7s from store: %v", ep.id, err)
   448  		}
   449  	}
   450  
   451  	return d.storeDelete(config)
   452  }
   453  
   454  func convertQosPolicies(qosPolicies []types.QosPolicy) ([]json.RawMessage, error) {
   455  	var qps []json.RawMessage
   456  
   457  	// Enumerate through the qos policies specified by the user and convert
   458  	// them into the internal structure matching the JSON blob that can be
   459  	// understood by the HCS.
   460  	for _, elem := range qosPolicies {
   461  		encodedPolicy, err := json.Marshal(hcsshim.QosPolicy{
   462  			Type:                            "QOS",
   463  			MaximumOutgoingBandwidthInBytes: elem.MaxEgressBandwidth,
   464  		})
   465  
   466  		if err != nil {
   467  			return nil, err
   468  		}
   469  		qps = append(qps, encodedPolicy)
   470  	}
   471  	return qps, nil
   472  }
   473  
   474  // ConvertPortBindings converts PortBindings to JSON for HNS request
   475  func ConvertPortBindings(portBindings []types.PortBinding) ([]json.RawMessage, error) {
   476  	var pbs []json.RawMessage
   477  
   478  	// Enumerate through the port bindings specified by the user and convert
   479  	// them into the internal structure matching the JSON blob that can be
   480  	// understood by the HCS.
   481  	for _, elem := range portBindings {
   482  		proto := strings.ToUpper(elem.Proto.String())
   483  		if proto != "TCP" && proto != "UDP" {
   484  			return nil, fmt.Errorf("invalid protocol %s", elem.Proto.String())
   485  		}
   486  
   487  		if elem.HostPort != elem.HostPortEnd {
   488  			return nil, fmt.Errorf("Windows does not support more than one host port in NAT settings")
   489  		}
   490  
   491  		if len(elem.HostIP) != 0 && !elem.HostIP.IsUnspecified() {
   492  			return nil, fmt.Errorf("Windows does not support host IP addresses in NAT settings")
   493  		}
   494  
   495  		encodedPolicy, err := json.Marshal(hcsshim.NatPolicy{
   496  			Type:         "NAT",
   497  			ExternalPort: elem.HostPort,
   498  			InternalPort: elem.Port,
   499  			Protocol:     elem.Proto.String(),
   500  		})
   501  
   502  		if err != nil {
   503  			return nil, err
   504  		}
   505  		pbs = append(pbs, encodedPolicy)
   506  	}
   507  	return pbs, nil
   508  }
   509  
   510  // ParsePortBindingPolicies parses HNS endpoint response message to PortBindings
   511  func ParsePortBindingPolicies(policies []json.RawMessage) ([]types.PortBinding, error) {
   512  	var bindings []types.PortBinding
   513  	hcsPolicy := &hcsshim.NatPolicy{}
   514  
   515  	for _, elem := range policies {
   516  
   517  		if err := json.Unmarshal([]byte(elem), &hcsPolicy); err != nil || hcsPolicy.Type != "NAT" {
   518  			continue
   519  		}
   520  
   521  		binding := types.PortBinding{
   522  			HostPort:    hcsPolicy.ExternalPort,
   523  			HostPortEnd: hcsPolicy.ExternalPort,
   524  			Port:        hcsPolicy.InternalPort,
   525  			Proto:       types.ParseProtocol(hcsPolicy.Protocol),
   526  			HostIP:      net.IPv4(0, 0, 0, 0),
   527  		}
   528  
   529  		bindings = append(bindings, binding)
   530  	}
   531  
   532  	return bindings, nil
   533  }
   534  
   535  func parseEndpointOptions(epOptions map[string]interface{}) (*endpointOption, error) {
   536  	if epOptions == nil {
   537  		return nil, nil
   538  	}
   539  
   540  	ec := &endpointOption{}
   541  
   542  	if opt, ok := epOptions[netlabel.MacAddress]; ok {
   543  		if mac, ok := opt.(net.HardwareAddr); ok {
   544  			ec.MacAddress = mac
   545  		} else {
   546  			return nil, fmt.Errorf("Invalid endpoint configuration")
   547  		}
   548  	}
   549  
   550  	if opt, ok := epOptions[QosPolicies]; ok {
   551  		if policies, ok := opt.([]types.QosPolicy); ok {
   552  			ec.QosPolicies = policies
   553  		} else {
   554  			return nil, fmt.Errorf("Invalid endpoint configuration")
   555  		}
   556  	}
   557  
   558  	if opt, ok := epOptions[netlabel.DNSServers]; ok {
   559  		if dns, ok := opt.([]string); ok {
   560  			ec.DNSServers = dns
   561  		} else {
   562  			return nil, fmt.Errorf("Invalid endpoint configuration")
   563  		}
   564  	}
   565  
   566  	if opt, ok := epOptions[DisableICC]; ok {
   567  		if disableICC, ok := opt.(bool); ok {
   568  			ec.DisableICC = disableICC
   569  		} else {
   570  			return nil, fmt.Errorf("Invalid endpoint configuration")
   571  		}
   572  	}
   573  
   574  	if opt, ok := epOptions[DisableDNS]; ok {
   575  		if disableDNS, ok := opt.(bool); ok {
   576  			ec.DisableDNS = disableDNS
   577  		} else {
   578  			return nil, fmt.Errorf("Invalid endpoint configuration")
   579  		}
   580  	}
   581  
   582  	return ec, nil
   583  }
   584  
   585  // ParseEndpointConnectivity parses options passed to CreateEndpoint, specifically port bindings, and store in a endpointConnectivity object.
   586  func ParseEndpointConnectivity(epOptions map[string]interface{}) (*EndpointConnectivity, error) {
   587  	if epOptions == nil {
   588  		return nil, nil
   589  	}
   590  
   591  	ec := &EndpointConnectivity{}
   592  
   593  	if opt, ok := epOptions[netlabel.PortMap]; ok {
   594  		if bs, ok := opt.([]types.PortBinding); ok {
   595  			ec.PortBindings = bs
   596  		} else {
   597  			return nil, fmt.Errorf("Invalid endpoint configuration")
   598  		}
   599  	}
   600  
   601  	if opt, ok := epOptions[netlabel.ExposedPorts]; ok {
   602  		if ports, ok := opt.([]types.TransportPort); ok {
   603  			ec.ExposedPorts = ports
   604  		} else {
   605  			return nil, fmt.Errorf("Invalid endpoint configuration")
   606  		}
   607  	}
   608  	return ec, nil
   609  }
   610  
   611  func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
   612  	n, err := d.getNetwork(nid)
   613  	if err != nil {
   614  		return err
   615  	}
   616  
   617  	// Check if endpoint id is good and retrieve corresponding endpoint
   618  	ep, err := n.getEndpoint(eid)
   619  	if err == nil && ep != nil {
   620  		return driverapi.ErrEndpointExists(eid)
   621  	}
   622  
   623  	endpointStruct := &hcsshim.HNSEndpoint{
   624  		VirtualNetwork: n.config.HnsID,
   625  	}
   626  
   627  	epOption, err := parseEndpointOptions(epOptions)
   628  	if err != nil {
   629  		return err
   630  	}
   631  	epConnectivity, err := ParseEndpointConnectivity(epOptions)
   632  	if err != nil {
   633  		return err
   634  	}
   635  
   636  	macAddress := ifInfo.MacAddress()
   637  	// Use the macaddress if it was provided
   638  	if macAddress != nil {
   639  		endpointStruct.MacAddress = strings.Replace(macAddress.String(), ":", "-", -1)
   640  	}
   641  
   642  	portMapping := epConnectivity.PortBindings
   643  
   644  	if n.config.Type == "l2bridge" || n.config.Type == "l2tunnel" {
   645  		ip := net.IPv4(0, 0, 0, 0)
   646  		if ifInfo.Address() != nil {
   647  			ip = ifInfo.Address().IP
   648  		}
   649  
   650  		portMapping, err = AllocatePorts(n.portMapper, portMapping, ip)
   651  		if err != nil {
   652  			return err
   653  		}
   654  
   655  		defer func() {
   656  			if err != nil {
   657  				ReleasePorts(n.portMapper, portMapping)
   658  			}
   659  		}()
   660  	}
   661  
   662  	endpointStruct.Policies, err = ConvertPortBindings(portMapping)
   663  	if err != nil {
   664  		return err
   665  	}
   666  
   667  	qosPolicies, err := convertQosPolicies(epOption.QosPolicies)
   668  	if err != nil {
   669  		return err
   670  	}
   671  	endpointStruct.Policies = append(endpointStruct.Policies, qosPolicies...)
   672  
   673  	if ifInfo.Address() != nil {
   674  		endpointStruct.IPAddress = ifInfo.Address().IP
   675  	}
   676  
   677  	endpointStruct.DNSServerList = strings.Join(epOption.DNSServers, ",")
   678  
   679  	// overwrite the ep DisableDNS option if DisableGatewayDNS was set to true during the network creation option
   680  	if n.config.DisableGatewayDNS {
   681  		logrus.Debugf("n.config.DisableGatewayDNS[%v] overwrites epOption.DisableDNS[%v]", n.config.DisableGatewayDNS, epOption.DisableDNS)
   682  		epOption.DisableDNS = n.config.DisableGatewayDNS
   683  	}
   684  
   685  	if n.driver.name == "nat" && !epOption.DisableDNS {
   686  		logrus.Debugf("endpointStruct.EnableInternalDNS =[%v]", endpointStruct.EnableInternalDNS)
   687  		endpointStruct.EnableInternalDNS = true
   688  	}
   689  
   690  	endpointStruct.DisableICC = epOption.DisableICC
   691  
   692  	// Inherit OutboundNat policy from the network
   693  	if n.config.EnableOutboundNat {
   694  		outboundNatPolicy, err := json.Marshal(hcsshim.OutboundNatPolicy{
   695  			Policy:     hcsshim.Policy{Type: hcsshim.OutboundNat},
   696  			Exceptions: n.config.OutboundNatExceptions,
   697  		})
   698  
   699  		if err != nil {
   700  			return err
   701  		}
   702  		endpointStruct.Policies = append(endpointStruct.Policies, outboundNatPolicy)
   703  	}
   704  
   705  	configurationb, err := json.Marshal(endpointStruct)
   706  	if err != nil {
   707  		return err
   708  	}
   709  
   710  	hnsresponse, err := hcsshim.HNSEndpointRequest("POST", "", string(configurationb))
   711  	if err != nil {
   712  		return err
   713  	}
   714  
   715  	mac, err := net.ParseMAC(hnsresponse.MacAddress)
   716  	if err != nil {
   717  		return err
   718  	}
   719  
   720  	// TODO For now the ip mask is not in the info generated by HNS
   721  	endpoint := &hnsEndpoint{
   722  		id:         eid,
   723  		nid:        n.id,
   724  		Type:       d.name,
   725  		addr:       &net.IPNet{IP: hnsresponse.IPAddress, Mask: hnsresponse.IPAddress.DefaultMask()},
   726  		macAddress: mac,
   727  	}
   728  
   729  	if hnsresponse.GatewayAddress != "" {
   730  		endpoint.gateway = net.ParseIP(hnsresponse.GatewayAddress)
   731  	}
   732  
   733  	endpoint.profileID = hnsresponse.Id
   734  	endpoint.epConnectivity = epConnectivity
   735  	endpoint.epOption = epOption
   736  	endpoint.portMapping, err = ParsePortBindingPolicies(hnsresponse.Policies)
   737  
   738  	if err != nil {
   739  		hcsshim.HNSEndpointRequest("DELETE", hnsresponse.Id, "")
   740  		return err
   741  	}
   742  
   743  	n.Lock()
   744  	n.endpoints[eid] = endpoint
   745  	n.Unlock()
   746  
   747  	if ifInfo.Address() == nil {
   748  		ifInfo.SetIPAddress(endpoint.addr)
   749  	}
   750  
   751  	if macAddress == nil {
   752  		ifInfo.SetMacAddress(endpoint.macAddress)
   753  	}
   754  
   755  	if err = d.storeUpdate(endpoint); err != nil {
   756  		logrus.Errorf("Failed to save endpoint %.7s to store: %v", endpoint.id, err)
   757  	}
   758  
   759  	return nil
   760  }
   761  
   762  func (d *driver) DeleteEndpoint(nid, eid string) error {
   763  	n, err := d.getNetwork(nid)
   764  	if err != nil {
   765  		return types.InternalMaskableErrorf("%s", err)
   766  	}
   767  
   768  	ep, err := n.getEndpoint(eid)
   769  	if err != nil {
   770  		return err
   771  	}
   772  
   773  	if n.config.Type == "l2bridge" || n.config.Type == "l2tunnel" {
   774  		ReleasePorts(n.portMapper, ep.portMapping)
   775  	}
   776  
   777  	n.Lock()
   778  	delete(n.endpoints, eid)
   779  	n.Unlock()
   780  
   781  	_, err = hcsshim.HNSEndpointRequest("DELETE", ep.profileID, "")
   782  	if err != nil && err.Error() != errNotFound {
   783  		return err
   784  	}
   785  
   786  	if err := d.storeDelete(ep); err != nil {
   787  		logrus.Warnf("Failed to remove bridge endpoint %.7s from store: %v", ep.id, err)
   788  	}
   789  	return nil
   790  }
   791  
   792  func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
   793  	network, err := d.getNetwork(nid)
   794  	if err != nil {
   795  		return nil, err
   796  	}
   797  
   798  	ep, err := network.getEndpoint(eid)
   799  	if err != nil {
   800  		return nil, err
   801  	}
   802  
   803  	data := make(map[string]interface{}, 1)
   804  	if network.driver.name == "nat" {
   805  		data["AllowUnqualifiedDNSQuery"] = true
   806  	}
   807  
   808  	data["hnsid"] = ep.profileID
   809  	if ep.epConnectivity.ExposedPorts != nil {
   810  		// Return a copy of the config data
   811  		epc := make([]types.TransportPort, 0, len(ep.epConnectivity.ExposedPorts))
   812  		for _, tp := range ep.epConnectivity.ExposedPorts {
   813  			epc = append(epc, tp.GetCopy())
   814  		}
   815  		data[netlabel.ExposedPorts] = epc
   816  	}
   817  
   818  	if ep.portMapping != nil {
   819  		// Return a copy of the operational data
   820  		pmc := make([]types.PortBinding, 0, len(ep.portMapping))
   821  		for _, pm := range ep.portMapping {
   822  			pmc = append(pmc, pm.GetCopy())
   823  		}
   824  		data[netlabel.PortMap] = pmc
   825  	}
   826  
   827  	if len(ep.macAddress) != 0 {
   828  		data[netlabel.MacAddress] = ep.macAddress
   829  	}
   830  	return data, nil
   831  }
   832  
   833  // Join method is invoked when a Sandbox is attached to an endpoint.
   834  func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
   835  	network, err := d.getNetwork(nid)
   836  	if err != nil {
   837  		return err
   838  	}
   839  
   840  	// Ensure that the endpoint exists
   841  	endpoint, err := network.getEndpoint(eid)
   842  	if err != nil {
   843  		return err
   844  	}
   845  
   846  	err = jinfo.SetGateway(endpoint.gateway)
   847  	if err != nil {
   848  		return err
   849  	}
   850  
   851  	endpoint.sandboxID = sboxKey
   852  
   853  	err = hcsshim.HotAttachEndpoint(endpoint.sandboxID, endpoint.profileID)
   854  	if err != nil {
   855  		// If container doesn't exists in hcs, do not throw error for hot add/remove
   856  		if err != hcsshim.ErrComputeSystemDoesNotExist {
   857  			return err
   858  		}
   859  	}
   860  
   861  	jinfo.DisableGatewayService()
   862  	return nil
   863  }
   864  
   865  // Leave method is invoked when a Sandbox detaches from an endpoint.
   866  func (d *driver) Leave(nid, eid string) error {
   867  	network, err := d.getNetwork(nid)
   868  	if err != nil {
   869  		return types.InternalMaskableErrorf("%s", err)
   870  	}
   871  
   872  	// Ensure that the endpoint exists
   873  	endpoint, err := network.getEndpoint(eid)
   874  	if err != nil {
   875  		return err
   876  	}
   877  
   878  	err = hcsshim.HotDetachEndpoint(endpoint.sandboxID, endpoint.profileID)
   879  	if err != nil {
   880  		// If container doesn't exists in hcs, do not throw error for hot add/remove
   881  		if err != hcsshim.ErrComputeSystemDoesNotExist {
   882  			return err
   883  		}
   884  	}
   885  	return nil
   886  }
   887  
   888  func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
   889  	return nil
   890  }
   891  
   892  func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
   893  	return nil
   894  }
   895  
   896  func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) {
   897  	return nil, types.NotImplementedErrorf("not implemented")
   898  }
   899  
   900  func (d *driver) NetworkFree(id string) error {
   901  	return types.NotImplementedErrorf("not implemented")
   902  }
   903  
   904  func (d *driver) Type() string {
   905  	return d.name
   906  }
   907  
   908  func (d *driver) IsBuiltIn() bool {
   909  	return true
   910  }
   911  
   912  // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
   913  func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
   914  	return nil
   915  }
   916  
   917  // DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
   918  func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
   919  	return nil
   920  }