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

     1  package overlay
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net"
     7  	"sync"
     8  
     9  	"github.com/Microsoft/hcsshim"
    10  	"github.com/Microsoft/hcsshim/osversion"
    11  	"github.com/docker/libnetwork/driverapi"
    12  	"github.com/docker/libnetwork/drivers/windows"
    13  	"github.com/docker/libnetwork/netlabel"
    14  	"github.com/docker/libnetwork/types"
    15  	"github.com/sirupsen/logrus"
    16  )
    17  
    18  type endpointTable map[string]*endpoint
    19  
    20  const overlayEndpointPrefix = "overlay/endpoint"
    21  
    22  type endpoint struct {
    23  	id             string
    24  	nid            string
    25  	profileID      string
    26  	remote         bool
    27  	mac            net.HardwareAddr
    28  	addr           *net.IPNet
    29  	disablegateway bool
    30  	portMapping    []types.PortBinding // Operation port bindings
    31  }
    32  
    33  var (
    34  	//Server 2016 (RS1) does not support concurrent add/delete of endpoints.  Therefore, we need
    35  	//to use this mutex and serialize the add/delete of endpoints on RS1.
    36  	endpointMu   sync.Mutex
    37  	windowsBuild = osversion.Build()
    38  )
    39  
    40  func validateID(nid, eid string) error {
    41  	if nid == "" {
    42  		return fmt.Errorf("invalid network id")
    43  	}
    44  
    45  	if eid == "" {
    46  		return fmt.Errorf("invalid endpoint id")
    47  	}
    48  
    49  	return nil
    50  }
    51  
    52  func (n *network) endpoint(eid string) *endpoint {
    53  	n.Lock()
    54  	defer n.Unlock()
    55  
    56  	return n.endpoints[eid]
    57  }
    58  
    59  func (n *network) addEndpoint(ep *endpoint) {
    60  	n.Lock()
    61  	n.endpoints[ep.id] = ep
    62  	n.Unlock()
    63  }
    64  
    65  func (n *network) deleteEndpoint(eid string) {
    66  	n.Lock()
    67  	delete(n.endpoints, eid)
    68  	n.Unlock()
    69  }
    70  
    71  func (n *network) removeEndpointWithAddress(addr *net.IPNet) {
    72  	var networkEndpoint *endpoint
    73  	n.Lock()
    74  	for _, ep := range n.endpoints {
    75  		if ep.addr.IP.Equal(addr.IP) {
    76  			networkEndpoint = ep
    77  			break
    78  		}
    79  	}
    80  
    81  	if networkEndpoint != nil {
    82  		delete(n.endpoints, networkEndpoint.id)
    83  	}
    84  	n.Unlock()
    85  
    86  	if networkEndpoint != nil {
    87  		logrus.Debugf("Removing stale endpoint from HNS")
    88  		_, err := endpointRequest("DELETE", networkEndpoint.profileID, "")
    89  		if err != nil {
    90  			logrus.Debugf("Failed to delete stale overlay endpoint (%.7s) from hns", networkEndpoint.id)
    91  		}
    92  	}
    93  }
    94  
    95  func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
    96  	epOptions map[string]interface{}) error {
    97  	var err error
    98  	if err = validateID(nid, eid); err != nil {
    99  		return err
   100  	}
   101  
   102  	n := d.network(nid)
   103  	if n == nil {
   104  		return fmt.Errorf("network id %q not found", nid)
   105  	}
   106  
   107  	ep := n.endpoint(eid)
   108  	if ep != nil {
   109  		logrus.Debugf("Deleting stale endpoint %s", eid)
   110  		n.deleteEndpoint(eid)
   111  		_, err := endpointRequest("DELETE", ep.profileID, "")
   112  		if err != nil {
   113  			return err
   114  		}
   115  	}
   116  
   117  	ep = &endpoint{
   118  		id:   eid,
   119  		nid:  n.id,
   120  		addr: ifInfo.Address(),
   121  		mac:  ifInfo.MacAddress(),
   122  	}
   123  
   124  	if ep.addr == nil {
   125  		return fmt.Errorf("create endpoint was not passed interface IP address")
   126  	}
   127  
   128  	s := n.getSubnetforIP(ep.addr)
   129  	if s == nil {
   130  		return fmt.Errorf("no matching subnet for IP %q in network %q", ep.addr, nid)
   131  	}
   132  
   133  	// Todo: Add port bindings and qos policies here
   134  
   135  	hnsEndpoint := &hcsshim.HNSEndpoint{
   136  		Name:              eid,
   137  		VirtualNetwork:    n.hnsID,
   138  		IPAddress:         ep.addr.IP,
   139  		EnableInternalDNS: true,
   140  		GatewayAddress:    s.gwIP.String(),
   141  	}
   142  
   143  	if ep.mac != nil {
   144  		hnsEndpoint.MacAddress = ep.mac.String()
   145  	}
   146  
   147  	paPolicy, err := json.Marshal(hcsshim.PaPolicy{
   148  		Type: "PA",
   149  		PA:   n.providerAddress,
   150  	})
   151  
   152  	if err != nil {
   153  		return err
   154  	}
   155  
   156  	hnsEndpoint.Policies = append(hnsEndpoint.Policies, paPolicy)
   157  
   158  	if osversion.Build() > 16236 {
   159  		natPolicy, err := json.Marshal(hcsshim.PaPolicy{
   160  			Type: "OutBoundNAT",
   161  		})
   162  
   163  		if err != nil {
   164  			return err
   165  		}
   166  
   167  		hnsEndpoint.Policies = append(hnsEndpoint.Policies, natPolicy)
   168  
   169  		epConnectivity, err := windows.ParseEndpointConnectivity(epOptions)
   170  		if err != nil {
   171  			return err
   172  		}
   173  
   174  		ep.portMapping = epConnectivity.PortBindings
   175  		ep.portMapping, err = windows.AllocatePorts(n.portMapper, ep.portMapping, ep.addr.IP)
   176  		if err != nil {
   177  			return err
   178  		}
   179  
   180  		defer func() {
   181  			if err != nil {
   182  				windows.ReleasePorts(n.portMapper, ep.portMapping)
   183  			}
   184  		}()
   185  
   186  		pbPolicy, err := windows.ConvertPortBindings(ep.portMapping)
   187  		if err != nil {
   188  			return err
   189  		}
   190  		hnsEndpoint.Policies = append(hnsEndpoint.Policies, pbPolicy...)
   191  
   192  		ep.disablegateway = true
   193  	}
   194  
   195  	configurationb, err := json.Marshal(hnsEndpoint)
   196  	if err != nil {
   197  		return err
   198  	}
   199  
   200  	hnsresponse, err := endpointRequest("POST", "", string(configurationb))
   201  	if err != nil {
   202  		return err
   203  	}
   204  
   205  	ep.profileID = hnsresponse.Id
   206  
   207  	if ep.mac == nil {
   208  		ep.mac, err = net.ParseMAC(hnsresponse.MacAddress)
   209  		if err != nil {
   210  			return err
   211  		}
   212  
   213  		if err := ifInfo.SetMacAddress(ep.mac); err != nil {
   214  			return err
   215  		}
   216  	}
   217  
   218  	ep.portMapping, err = windows.ParsePortBindingPolicies(hnsresponse.Policies)
   219  	if err != nil {
   220  		endpointRequest("DELETE", hnsresponse.Id, "")
   221  		return err
   222  	}
   223  
   224  	n.addEndpoint(ep)
   225  
   226  	return nil
   227  }
   228  
   229  func (d *driver) DeleteEndpoint(nid, eid string) error {
   230  	if err := validateID(nid, eid); err != nil {
   231  		return err
   232  	}
   233  
   234  	n := d.network(nid)
   235  	if n == nil {
   236  		return fmt.Errorf("network id %q not found", nid)
   237  	}
   238  
   239  	ep := n.endpoint(eid)
   240  	if ep == nil {
   241  		return fmt.Errorf("endpoint id %q not found", eid)
   242  	}
   243  
   244  	windows.ReleasePorts(n.portMapper, ep.portMapping)
   245  
   246  	n.deleteEndpoint(eid)
   247  
   248  	_, err := endpointRequest("DELETE", ep.profileID, "")
   249  	if err != nil {
   250  		return err
   251  	}
   252  
   253  	return nil
   254  }
   255  
   256  func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
   257  	if err := validateID(nid, eid); err != nil {
   258  		return nil, err
   259  	}
   260  
   261  	n := d.network(nid)
   262  	if n == nil {
   263  		return nil, fmt.Errorf("network id %q not found", nid)
   264  	}
   265  
   266  	ep := n.endpoint(eid)
   267  	if ep == nil {
   268  		return nil, fmt.Errorf("endpoint id %q not found", eid)
   269  	}
   270  
   271  	data := make(map[string]interface{}, 1)
   272  	data["hnsid"] = ep.profileID
   273  	data["AllowUnqualifiedDNSQuery"] = true
   274  
   275  	if ep.portMapping != nil {
   276  		// Return a copy of the operational data
   277  		pmc := make([]types.PortBinding, 0, len(ep.portMapping))
   278  		for _, pm := range ep.portMapping {
   279  			pmc = append(pmc, pm.GetCopy())
   280  		}
   281  		data[netlabel.PortMap] = pmc
   282  	}
   283  
   284  	return data, nil
   285  }
   286  
   287  func endpointRequest(method, path, request string) (*hcsshim.HNSEndpoint, error) {
   288  	if windowsBuild == 14393 {
   289  		endpointMu.Lock()
   290  	}
   291  	hnsresponse, err := hcsshim.HNSEndpointRequest(method, path, request)
   292  	if windowsBuild == 14393 {
   293  		endpointMu.Unlock()
   294  	}
   295  	return hnsresponse, err
   296  }