diff --git a/agent/app/agent_windows.go b/agent/app/agent_windows.go index dbb8b5e9263..0626944ab77 100644 --- a/agent/app/agent_windows.go +++ b/agent/app/agent_windows.go @@ -21,8 +21,6 @@ import ( "sync" "time" - fsxfactory "github.com/aws/amazon-ecs-agent/agent/fsx/factory" - asmfactory "github.com/aws/amazon-ecs-agent/agent/asm/factory" "github.com/aws/amazon-ecs-agent/agent/credentials" "github.com/aws/amazon-ecs-agent/agent/data" @@ -30,7 +28,9 @@ import ( "github.com/aws/amazon-ecs-agent/agent/ecscni" "github.com/aws/amazon-ecs-agent/agent/engine" "github.com/aws/amazon-ecs-agent/agent/engine/dockerstate" + "github.com/aws/amazon-ecs-agent/agent/eni/networkutils" "github.com/aws/amazon-ecs-agent/agent/eni/watcher" + fsxfactory "github.com/aws/amazon-ecs-agent/agent/fsx/factory" s3factory "github.com/aws/amazon-ecs-agent/agent/s3/factory" "github.com/aws/amazon-ecs-agent/agent/sighandlers" "github.com/aws/amazon-ecs-agent/agent/sighandlers/exitcodes" @@ -76,12 +76,12 @@ func (agent *ecsAgent) initializeTaskENIDependencies(state dockerstate.TaskEngin return err, false } - // Query the VPC's primary IPv4 CIDR using IMDS - primaryIPv4VPCCIDR, err := agent.ec2MetadataClient.PrimaryIPV4VPCCIDR(agent.mac) + dnsServerList, err := agent.resourceFields.NetworkUtils.GetDNSServerAddressList(agent.mac) if err != nil { - return fmt.Errorf("unable to get primary ipv4 cidr of the vpc: %v", err), false + // An error at this point is terminal as the tasks need the access to domain controllers. + return fmt.Errorf("unable to get dns server addresses of instance eni: %v", err), true } - agent.cfg.PrimaryIPv4VPCCIDR = primaryIPv4VPCCIDR + agent.cfg.InstanceENIDNSServerList = dnsServerList return nil, false } @@ -305,6 +305,7 @@ func (agent *ecsAgent) initializeResourceFields(credentialsManager credentials.M Ctx: agent.ctx, DockerClient: agent.dockerClient, S3ClientCreator: s3factory.NewS3ClientCreator(), + NetworkUtils: networkutils.New(), } } diff --git a/agent/config/types.go b/agent/config/types.go index 1d9abc4b8d3..896dc6e8111 100644 --- a/agent/config/types.go +++ b/agent/config/types.go @@ -14,7 +14,6 @@ package config import ( - "net" "time" "github.com/aws/amazon-ecs-agent/agent/dockerclient" @@ -334,7 +333,7 @@ type Config struct { // External specifies whether agent is running on external compute capacity (i.e. outside of aws). External BooleanDefaultFalse - // PrimaryIPv4VPCCIDR stores the primary IPv4 CIDR of the VPC in which agent is running - // Currently, this field is only populated for Windows and is used during task networking setup - PrimaryIPv4VPCCIDR *net.IPNet + // InstanceENIDNSServerList stores the list of dns servers for the primary instance ENI. + // Currently, this field is only populated for Windows and is used during task networking setup. + InstanceENIDNSServerList []string } diff --git a/agent/ecscni/netconfig_windows.go b/agent/ecscni/netconfig_windows.go index 395b14695a9..44665436d97 100644 --- a/agent/ecscni/netconfig_windows.go +++ b/agent/ecscni/netconfig_windows.go @@ -16,8 +16,6 @@ package ecscni import ( - "net" - "github.com/containernetworking/cni/pkg/types" "github.com/aws/amazon-ecs-agent/agent/api/eni" @@ -31,12 +29,8 @@ func NewVPCENIPluginConfigForTaskNSSetup(eni *eni.ENI, cfg *Config) (*libcni.Net Nameservers: eni.DomainNameServers, } - if len(eni.DomainNameServers) == 0 && cfg.PrimaryIPv4VPCCIDR != nil { - constructedDNS, err := constructDNSFromVPCCIDR(cfg.PrimaryIPv4VPCCIDR) - if err != nil { - return nil, errors.Wrapf(err, "cannot create vpc-eni network config") - } - dns.Nameservers = constructedDNS + if len(eni.DomainNameSearchList) == 0 && cfg.InstanceENIDNSServerList != nil { + dns.Nameservers = cfg.InstanceENIDNSServerList } eniConf := VPCENIPluginConfig{ @@ -74,18 +68,3 @@ func NewVPCENIPluginConfigForECSBridgeSetup(cfg *Config) (*libcni.NetworkConfig, networkConfig.Network.Name = ECSBridgeNetworkName return networkConfig, nil } - -// constructDNSFromVPCCIDR is used to construct DNS server from the primary ipv4 cidr of the vpc. -func constructDNSFromVPCCIDR(vpcCIDR *net.IPNet) ([]string, error) { - // The DNS server maps to a reserved IP address at the base of the VPC IPv4 network rage plus 2 - // https://docs.aws.amazon.com/vpc/latest/userguide/VPC_DHCP_Options.html#AmazonDNS - - if vpcCIDR == nil { - return nil, errors.Errorf("unable to contruct dns from invalid vpc cidr") - } - mask := net.CIDRMask(24, 32) - maskedIPv4 := vpcCIDR.IP.Mask(mask).To4() - maskedIPv4[3] = 2 - - return []string{maskedIPv4.String()}, nil -} diff --git a/agent/ecscni/netconfig_windows_test.go b/agent/ecscni/netconfig_windows_test.go index 8554c419a30..cae09a08e49 100644 --- a/agent/ecscni/netconfig_windows_test.go +++ b/agent/ecscni/netconfig_windows_test.go @@ -17,7 +17,6 @@ package ecscni import ( "encoding/json" - "net" "testing" apieni "github.com/aws/amazon-ecs-agent/agent/api/eni" @@ -28,8 +27,6 @@ const ( linkName = "Ethernet 4" validVPCGatewayCIDR = "10.0.0.1/24" validVPCGatewayIPv4Addr = "10.0.0.1" - invalidVPCGatewayCIDR = "10.0.0.300/24" - invalidVPCGatewayAddr = "10.0.0.300" validDNSServer = "10.0.0.2" ipv4 = "10.0.0.120" ipv4CIDR = "10.0.0.120/24" @@ -55,12 +52,11 @@ func getTaskENI() *apieni.ENI { } func getCNIConfig() *Config { - _, cidr, _ := net.ParseCIDR(vpcCIDR) return &Config{ - MinSupportedCNIVersion: cniMinSupportedVersion, - ContainerID: containerID, - BlockInstanceMetadata: false, - PrimaryIPv4VPCCIDR: cidr, + MinSupportedCNIVersion: cniMinSupportedVersion, + ContainerID: containerID, + BlockInstanceMetadata: false, + InstanceENIDNSServerList: []string{validDNSServer}, } } @@ -100,20 +96,3 @@ func TestNewVPCENIPluginConfigForECSBridgeSetup(t *testing.T) { assert.True(t, netConfig.UseExistingNetwork) assert.False(t, netConfig.NoInfraContainer) } - -// TestConstructDNSFromVPCCIDRSuccess tests if the dns is constructed properly from the given vpc's primary cidr -func TestConstructDNSFromVPCCIDRSuccess(t *testing.T) { - _, cidr, _ := net.ParseCIDR(vpcCIDR) - result, err := constructDNSFromVPCCIDR(cidr) - - assert.NoError(t, err) - assert.EqualValues(t, []string{validDNSServer}, result) -} - -// TestConstructDNSFromVPCCIDRError tests if an error is thrown if the vpc cidr is invalid -func TestConstructDNSFromVPCCIDRError(t *testing.T) { - result, err := constructDNSFromVPCCIDR(nil) - - assert.Error(t, err) - assert.Nil(t, result) -} diff --git a/agent/ecscni/types.go b/agent/ecscni/types.go index dcc6cdd5560..1c1f130d2de 100644 --- a/agent/ecscni/types.go +++ b/agent/ecscni/types.go @@ -14,8 +14,6 @@ package ecscni import ( - "net" - "github.com/containernetworking/cni/libcni" cnitypes "github.com/containernetworking/cni/pkg/types" ) @@ -62,8 +60,9 @@ type Config struct { AdditionalLocalRoutes []cnitypes.IPNet // NetworkConfigs is the list of CNI network configurations to be invoked NetworkConfigs []*NetworkConfig - // PrimaryIPv4VPCCIDR is the primary ipv4 cidr of the vpc in which agent is running - PrimaryIPv4VPCCIDR *net.IPNet + // InstanceENIDNSServerList stores the list of dns servers for the primary instance ENI. + // Currently, this field is only populated for Windows and is used during task networking setup. + InstanceENIDNSServerList []string } // NetworkConfig wraps CNI library's NetworkConfig object. It tracks the interface device diff --git a/agent/engine/docker_task_engine.go b/agent/engine/docker_task_engine.go index 69f56e0053c..be9455e959b 100644 --- a/agent/engine/docker_task_engine.go +++ b/agent/engine/docker_task_engine.go @@ -1526,9 +1526,9 @@ func (engine *DockerTaskEngine) buildCNIConfigFromTaskContainer( containerInspectOutput *types.ContainerJSON, includeIPAMConfig bool) (*ecscni.Config, error) { cniConfig := &ecscni.Config{ - BlockInstanceMetadata: engine.cfg.AWSVPCBlockInstanceMetdata.Enabled(), - MinSupportedCNIVersion: config.DefaultMinSupportedCNIVersion, - PrimaryIPv4VPCCIDR: engine.cfg.PrimaryIPv4VPCCIDR, + BlockInstanceMetadata: engine.cfg.AWSVPCBlockInstanceMetdata.Enabled(), + MinSupportedCNIVersion: config.DefaultMinSupportedCNIVersion, + InstanceENIDNSServerList: engine.cfg.InstanceENIDNSServerList, } if engine.cfg.OverrideAWSVPCLocalIPv4Address != nil && len(engine.cfg.OverrideAWSVPCLocalIPv4Address.IP) != 0 && diff --git a/agent/eni/networkutils/utils_windows.go b/agent/eni/networkutils/utils_windows.go index 470d951f4ac..d1c927343e0 100644 --- a/agent/eni/networkutils/utils_windows.go +++ b/agent/eni/networkutils/utils_windows.go @@ -18,7 +18,12 @@ package networkutils import ( "context" "net" + "strings" + "syscall" "time" + "unsafe" + + "golang.org/x/sys/windows" apierrors "github.com/aws/amazon-ecs-agent/agent/api/errors" "github.com/aws/amazon-ecs-agent/agent/eni/netwrapper" @@ -27,14 +32,12 @@ import ( "github.com/pkg/errors" ) -// NetworkUtils is the interface used for accessing network utils +// NetworkUtils is the interface used for accessing network related functionality on Windows. // The methods declared in this package may or may not add any additional logic over the actual networking api calls. -// Moreover, we will use a wrapper over Golang's net package. This is done to ensure that any future change which -// requires a package different from Golang's net, can be easily implemented by changing the underlying wrapper without -// impacting watcher type NetworkUtils interface { GetInterfaceMACByIndex(int, context.Context, time.Duration) (string, error) GetAllNetworkInterfaces() ([]net.Interface, error) + GetDNSServerAddressList(macAddress string) ([]string, error) SetNetWrapper(netWrapper netwrapper.NetWrapper) } @@ -50,15 +53,15 @@ type networkUtils struct { netWrapper netwrapper.NetWrapper } -// New creates a new network utils +// New creates a new network utils. func New() NetworkUtils { return &networkUtils{ netWrapper: netwrapper.New(), } } -// This method is used for obtaining the MAC address of an interface with a given interface index -// We internally call net.InterfaceByIndex for this purpose +// GetInterfaceMACByIndex is used for obtaining the MAC address of an interface with a given interface index. +// We internally call net.InterfaceByIndex for this purpose. func (utils *networkUtils) GetInterfaceMACByIndex(index int, ctx context.Context, timeout time.Duration) (mac string, err error) { @@ -69,8 +72,8 @@ func (utils *networkUtils) GetInterfaceMACByIndex(index int, ctx context.Context return utils.retrieveMAC() } -// This method is used to retrieve MAC address using retry with backoff. -// We use retry logic in order to account for any delay in MAC Address becoming available after the interface addition notification is received +// retrieveMAC is used to retrieve MAC address using retry with backoff. +// We use retry logic in order to account for any delay in MAC Address becoming available after the interface addition notification is received. func (utils *networkUtils) retrieveMAC() (string, error) { backoff := retry.NewExponentialBackoff(macAddressBackoffMin, macAddressBackoffMax, macAddressBackoffJitter, macAddressBackoffMultiple) @@ -106,12 +109,59 @@ func (utils *networkUtils) retrieveMAC() (string, error) { return utils.macAddress, nil } -// Returns all the network interfaces +// GetAllNetworkInterfaces returns all the network interfaces. func (utils *networkUtils) GetAllNetworkInterfaces() ([]net.Interface, error) { return utils.netWrapper.GetAllNetworkInterfaces() } -// This method is used to inject netWrapper instance. This will be handy while testing to inject mocks. +// SetNetWrapper is used to inject netWrapper instance. This will be handy while testing to inject mocks. func (utils *networkUtils) SetNetWrapper(netWrapper netwrapper.NetWrapper) { utils.netWrapper = netWrapper } + +// GetDNSServerAddressList returns the DNS server addresses of the queried interface. +func (utils *networkUtils) GetDNSServerAddressList(macAddress string) ([]string, error) { + addresses, err := utils.netWrapper.GetAdapterAddresses() + if err != nil { + return nil, err + } + + var firstDnsNode *windows.IpAdapterDnsServerAdapter + // Find the adapter which has the same mac as queried. + for _, adapterAddr := range addresses { + if strings.EqualFold(utils.parseMACAddress(adapterAddr).String(), macAddress) { + firstDnsNode = adapterAddr.FirstDnsServerAddress + break + } + } + + dnsServerAddressList := make([]string, 0) + for firstDnsNode != nil { + dnsServerAddressList = append(dnsServerAddressList, utils.parseSocketAddress(firstDnsNode.Address)) + firstDnsNode = firstDnsNode.Next + } + + return dnsServerAddressList, nil +} + +// parseMACAddress parses the physical address of windows.IpAdapterAddresses into net.HardwareAddr. +func (utils *networkUtils) parseMACAddress(adapterAddress *windows.IpAdapterAddresses) net.HardwareAddr { + hardwareAddr := make(net.HardwareAddr, adapterAddress.PhysicalAddressLength) + if adapterAddress.PhysicalAddressLength > 0 { + copy(hardwareAddr, adapterAddress.PhysicalAddress[:]) + return hardwareAddr + } + return hardwareAddr +} + +// parseSocketAddress parses the SocketAddress into its string representation. +// This method needs to be deprecated in favour of IP() method of SocketAdress introduced in Go 1.13+. +// The method details have been taken from https://github.com/golang/sys/blob/release-branch.go1.13/windows/types_windows.go +func (utils *networkUtils) parseSocketAddress(addr windows.SocketAddress) string { + var ipAddr string + if uintptr(addr.SockaddrLength) >= unsafe.Sizeof(syscall.RawSockaddrInet4{}) && addr.Sockaddr.Addr.Family == syscall.AF_INET { + ip := net.IP((*syscall.RawSockaddrInet4)(unsafe.Pointer(addr.Sockaddr)).Addr[:]) + ipAddr = ip.String() + } + return ipAddr +} diff --git a/agent/eni/networkutils/utils_windows_test.go b/agent/eni/networkutils/utils_windows_test.go index 7607119c287..10c050620c0 100644 --- a/agent/eni/networkutils/utils_windows_test.go +++ b/agent/eni/networkutils/utils_windows_test.go @@ -19,8 +19,11 @@ import ( "context" "errors" "net" + "syscall" "testing" + "golang.org/x/sys/windows" + mock_netwrapper "github.com/aws/amazon-ecs-agent/agent/eni/netwrapper/mocks" "github.com/golang/mock/gomock" @@ -30,6 +33,7 @@ import ( const ( interfaceIndex = 9 macAddress = "02:22:ea:8c:81:dc" + validDnsServer = "10.0.0.2" ) // This is a success test. We receive the appropriate MAC address corresponding to the interface index. @@ -145,7 +149,7 @@ func TestGetInterfaceMACByIndexWithGolangNetError(t *testing.T) { netUtils.SetNetWrapper(mocknetwrapper) mocknetwrapper.EXPECT().FindInterfaceByIndex(interfaceIndex).Return( - nil, errors.New("Unable to retrieve interface")) + nil, errors.New("unable to retrieve interface")) mac, err := netUtils.GetInterfaceMACByIndex(interfaceIndex, ctx, macAddressBackoffMax) @@ -190,7 +194,7 @@ func TestGetAllNetworkInterfacesError(t *testing.T) { netUtils.SetNetWrapper(mocknetwrapper) mocknetwrapper.EXPECT().GetAllNetworkInterfaces().Return( - nil, errors.New("Error occured while fetching interfaces"), + nil, errors.New("error occurred while fetching interfaces"), ) inf, err := netUtils.GetAllNetworkInterfaces() @@ -198,3 +202,35 @@ func TestGetAllNetworkInterfacesError(t *testing.T) { assert.Nil(t, inf) assert.Error(t, err) } + +// TestGetDNSServerAddressList tests the success path of GetDNSServerAddressList. +func TestGetDNSServerAddressList(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + mocknetwrapper := mock_netwrapper.NewMockNetWrapper(mockCtrl) + netUtils := networkUtils{netWrapper: mocknetwrapper} + + mocknetwrapper.EXPECT().GetAdapterAddresses().Return([]*windows.IpAdapterAddresses{ + { + PhysicalAddressLength: 6, + PhysicalAddress: [8]byte{2, 34, 234, 140, 129, 220, 0, 0}, + FirstDnsServerAddress: &windows.IpAdapterDnsServerAdapter{ + Address: windows.SocketAddress{ + Sockaddr: &syscall.RawSockaddrAny{ + Addr: syscall.RawSockaddr{ + Family: syscall.AF_INET, + Data: [14]int8{0, 0, 10, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0}, + }, + }, + SockaddrLength: 16, + }, + }, + }, + }, nil) + + dnsServerList, err := netUtils.GetDNSServerAddressList(macAddress) + assert.NoError(t, err) + assert.Len(t, dnsServerList, 1) + assert.EqualValues(t, dnsServerList[0], validDnsServer) +} diff --git a/agent/eni/netwrapper/generate_mocks.go b/agent/eni/netwrapper/generate_mocks_windows.go similarity index 100% rename from agent/eni/netwrapper/generate_mocks.go rename to agent/eni/netwrapper/generate_mocks_windows.go diff --git a/agent/eni/netwrapper/mocks/mock_netwrapper.go b/agent/eni/netwrapper/mocks/mock_netwrapper_windows.go similarity index 81% rename from agent/eni/netwrapper/mocks/mock_netwrapper.go rename to agent/eni/netwrapper/mocks/mock_netwrapper_windows.go index c256230189a..197026df265 100644 --- a/agent/eni/netwrapper/mocks/mock_netwrapper.go +++ b/agent/eni/netwrapper/mocks/mock_netwrapper_windows.go @@ -23,6 +23,7 @@ import ( reflect "reflect" gomock "github.com/golang/mock/gomock" + windows "golang.org/x/sys/windows" ) // MockNetWrapper is a mock of NetWrapper interface @@ -63,6 +64,21 @@ func (mr *MockNetWrapperMockRecorder) FindInterfaceByIndex(arg0 interface{}) *go return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindInterfaceByIndex", reflect.TypeOf((*MockNetWrapper)(nil).FindInterfaceByIndex), arg0) } +// GetAdapterAddresses mocks base method +func (m *MockNetWrapper) GetAdapterAddresses() ([]*windows.IpAdapterAddresses, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAdapterAddresses") + ret0, _ := ret[0].([]*windows.IpAdapterAddresses) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAdapterAddresses indicates an expected call of GetAdapterAddresses +func (mr *MockNetWrapperMockRecorder) GetAdapterAddresses() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAdapterAddresses", reflect.TypeOf((*MockNetWrapper)(nil).GetAdapterAddresses)) +} + // GetAllNetworkInterfaces mocks base method func (m *MockNetWrapper) GetAllNetworkInterfaces() ([]net.Interface, error) { m.ctrl.T.Helper() diff --git a/agent/eni/netwrapper/netwrapper.go b/agent/eni/netwrapper/netwrapper.go deleted file mode 100644 index abcd5d39f40..00000000000 --- a/agent/eni/netwrapper/netwrapper.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"). You may -// not use this file except in compliance with the License. A copy of the -// License is located at -// -// http://aws.amazon.com/apache2.0/ -// -// or in the "license" file accompanying this file. This file is distributed -// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either -// express or implied. See the License for the specific language governing -// permissions and limitations under the License. - -package netwrapper - -import "net" - -// NetWrapper interface is created to abstract Golang's net package from its usage in the watcher -// Also, this enables us to mock this interface for unit tests -type NetWrapper interface { - FindInterfaceByIndex(int) (*net.Interface, error) - GetAllNetworkInterfaces() ([]net.Interface, error) -} - -type utils struct{} - -// New returns a wrapper over Golang's net package -func New() NetWrapper { - return &utils{} -} - -func (utils *utils) FindInterfaceByIndex(index int) (*net.Interface, error) { - return net.InterfaceByIndex(index) -} - -func (utils *utils) GetAllNetworkInterfaces() ([]net.Interface, error) { - return net.Interfaces() -} diff --git a/agent/eni/netwrapper/netwrapper_windows.go b/agent/eni/netwrapper/netwrapper_windows.go new file mode 100644 index 00000000000..587d5411748 --- /dev/null +++ b/agent/eni/netwrapper/netwrapper_windows.go @@ -0,0 +1,80 @@ +// +build windows + +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +package netwrapper + +import ( + "net" + "os" + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +// NetWrapper interface is created to abstract Golang's net package from its usage in the watcher +// Also, this enables us to mock this interface for unit tests +type NetWrapper interface { + FindInterfaceByIndex(int) (*net.Interface, error) + GetAllNetworkInterfaces() ([]net.Interface, error) + GetAdapterAddresses() ([]*windows.IpAdapterAddresses, error) +} + +type utils struct{} + +// New returns a wrapper over Golang's net package +func New() NetWrapper { + return &utils{} +} + +func (utils *utils) FindInterfaceByIndex(index int) (*net.Interface, error) { + return net.InterfaceByIndex(index) +} + +func (utils *utils) GetAllNetworkInterfaces() ([]net.Interface, error) { + return net.Interfaces() +} + +// GetAdapterAddresses returns a list of IP adapter and address +// structures. The structure contains an IP adapter and flattened +// multiple IP addresses including unicast, anycast and multicast +// addresses. +// This method is copied as it is from the official golang source code. +// https://golang.org/src/net/interface_windows.go +func (utils *utils) GetAdapterAddresses() ([]*windows.IpAdapterAddresses, error) { + var b []byte + l := uint32(15000) // recommended initial size + for { + b = make([]byte, l) + err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l) + if err == nil { + if l == 0 { + return nil, nil + } + break + } + if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW { + return nil, os.NewSyscallError("getadaptersaddresses", err) + } + if l <= uint32(len(b)) { + return nil, os.NewSyscallError("getadaptersaddresses", err) + } + } + var aas []*windows.IpAdapterAddresses + for aa := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); aa != nil; aa = aa.Next { + aas = append(aas, aa) + } + return aas, nil +} diff --git a/agent/taskresource/types_windows.go b/agent/taskresource/types_windows.go index 61f3eff0b81..e3adc0e029f 100644 --- a/agent/taskresource/types_windows.go +++ b/agent/taskresource/types_windows.go @@ -19,6 +19,7 @@ import ( "context" "github.com/aws/amazon-ecs-agent/agent/dockerclient/dockerapi" + "github.com/aws/amazon-ecs-agent/agent/eni/networkutils" s3factory "github.com/aws/amazon-ecs-agent/agent/s3/factory" ) @@ -28,4 +29,5 @@ type ResourceFields struct { Ctx context.Context DockerClient dockerapi.DockerClient S3ClientCreator s3factory.S3ClientCreator + NetworkUtils networkutils.NetworkUtils }