From 4b5db21f89dc73036d3aa31c4c87358572909378 Mon Sep 17 00:00:00 2001 From: piccione99 Date: Fri, 2 Aug 2024 16:04:52 -0400 Subject: [PATCH] populate interface-used with default route --- go.mod | 11 ++++++ go.sum | 14 +++++++ internal/metadata/metadata.go | 6 ++- internal/metadata/metadata_test.go | 57 ++++++++++++++++++++++++++++ internal/net/network_service.go | 5 +++ internal/net/network_service_test.go | 13 +++++++ internal/net/network_wrapper.go | 6 +++ internal/net/network_wrapper_test.go | 29 ++++++++++++++ internal/websocket/ws.go | 4 ++ 9 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 internal/net/network_wrapper_test.go diff --git a/go.mod b/go.mod index 1816770..d9c0c0a 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,16 @@ require ( gopkg.in/dealancer/validate.v2 v2.1.0 ) +require ( + github.com/google/go-cmp v0.6.0 // indirect + github.com/josharian/native v1.1.0 // indirect + github.com/jsimonetti/rtnetlink v1.3.5 // indirect + github.com/mdlayher/netlink v1.7.2 // indirect + github.com/mdlayher/socket v0.4.1 // indirect + go4.org/mem v0.0.0-20220726221520-4f986261bf13 // indirect + golang.zx2c4.com/wireguard/windows v0.5.3 // indirect +) + require ( github.com/Microsoft/go-winio v0.6.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -33,6 +43,7 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/miekg/dns v1.1.59 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/nixigaj/go-default-route v0.0.0-20231019115740-0722aff7ebf3 github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/xmidt-org/httpaux v0.4.0 // indirect diff --git a/go.sum b/go.sum index 015fc06..33ceff1 100644 --- a/go.sum +++ b/go.sum @@ -34,6 +34,10 @@ github.com/goschtalt/yaml-encoder v0.0.3 h1:vfQ3vXZNvoEFPa3NzOWNtweYVa+2qMh8eqhX github.com/goschtalt/yaml-encoder v0.0.3/go.mod h1:E9ANM2mgRmoqP+JTFFv03fVWcnn+QrIDfVu5shDvX3A= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= +github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/jsimonetti/rtnetlink v1.3.5 h1:hVlNQNRlLDGZz31gBPicsG7Q53rnlsz1l1Ix/9XlpVA= +github.com/jsimonetti/rtnetlink v1.3.5/go.mod h1:0LFedyiTkebnd43tE4YAkWGIq9jQphow4CcwxaT2Y00= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -43,11 +47,17 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= +github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= +github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= +github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/nixigaj/go-default-route v0.0.0-20231019115740-0722aff7ebf3 h1:e1Veji4bHvp7Is8KIq00qYizLHmmIVDpWfSCqRT5HO4= +github.com/nixigaj/go-default-route v0.0.0-20231019115740-0722aff7ebf3/go.mod h1:fvHmLvG5wkvd4TmD6Vs1DckR8lU9z/bmYoTop7KGZu4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/psanford/memfs v0.0.0-20210214183328-a001468d78ef h1:NKxTG6GVGbfMXc2mIk+KphcH6hagbVXhcFkbTgYleTI= @@ -89,6 +99,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go4.org/mem v0.0.0-20220726221520-4f986261bf13 h1:CbZeCBZ0aZj8EfVgnqQcYZgf0lpZ3H9rmp5nkDTAst8= +go4.org/mem v0.0.0-20220726221520-4f986261bf13/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= @@ -155,6 +167,8 @@ golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= +golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ= gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/metadata/metadata.go b/internal/metadata/metadata.go index 5d8ec4b..b6a99a5 100644 --- a/internal/metadata/metadata.go +++ b/internal/metadata/metadata.go @@ -91,7 +91,11 @@ func (c *MetadataProvider) GetMetadata() map[string]interface{} { case BootTimeRetryDelay: header[field] = c.bootTimeRetryDelay case InterfaceUsed: - header[field] = c.interfaceUsed.GetInterfaceUsed() + // for now, let's just use the default router interface from the OS. We will eventually have websocket pass this value in + i, err := c.networkService.GetDefaultInterface() + if i != nil && err == nil { + header[field] = i.Name + } case InterfacesAvailable: // what if we can't get interfaces available? names, err := c.networkService.GetInterfaceNames() if err != nil { diff --git a/internal/metadata/metadata_test.go b/internal/metadata/metadata_test.go index c7ed5d0..e06e5f4 100644 --- a/internal/metadata/metadata_test.go +++ b/internal/metadata/metadata_test.go @@ -4,6 +4,7 @@ package metadata import ( + "errors" "net" "net/http" "testing" @@ -30,6 +31,15 @@ func (m *mockNetworkService) GetInterfaceNames() ([]string, error) { return args.Get(0).([]string), args.Error(1) } +func (m *mockNetworkService) GetDefaultInterface() (*net.Interface, error) { + args := m.Called() + var arg0 *net.Interface = nil + if args.Get(0) != nil { + arg0 = args.Get(0).(*net.Interface) + } + return arg0, args.Error(1) +} + type ConveySuite struct { suite.Suite conveyHeaderProvider *MetadataProvider @@ -68,6 +78,11 @@ func TestConveySuite(t *testing.T) { func (suite *ConveySuite) TestGetConveyHeader() { suite.mockNetworkService.On("GetInterfaceNames").Return([]string{"erouter0", "eth0"}, nil) + i := &net.Interface{ + Name: "erouter0", + } + suite.mockNetworkService.On("GetDefaultInterface").Return(i, nil) + header := suite.conveyHeaderProvider.GetMetadata() suite.Equal("1.1", header["fw-name"]) @@ -82,7 +97,41 @@ func (suite *ConveySuite) TestGetConveyHeader() { suite.Equal("erouter0", header["webpa-interface-used"]) } +func (suite *ConveySuite) TestDefaultRouteInterfaceUsedHeader() { + suite.mockNetworkService.On("GetInterfaceNames").Return([]string{"erouter0", "eth0"}, nil) + i := &net.Interface{ + Name: "default-interface", + } + + suite.mockNetworkService.On("GetDefaultInterface").Return(i, nil) + header := suite.conveyHeaderProvider.GetMetadata() + suite.Equal("default-interface", header["webpa-interface-used"]) +} + +func (suite *ConveySuite) TestDefaultRouteInterfaceUsedHeaderNil() { + suite.mockNetworkService.On("GetInterfaceNames").Return([]string{"erouter0", "eth0"}, nil) + + suite.mockNetworkService.On("GetDefaultInterface").Return(nil, nil) + header := suite.conveyHeaderProvider.GetMetadata() + suite.Equal(nil, header["webpa-interface-used"]) +} + +func (suite *ConveySuite) TestDefaultRouteInterfaceUsedHeaderError() { + suite.mockNetworkService.On("GetInterfaceNames").Return([]string{"erouter0", "eth0"}, nil) + + i := &net.Interface{ + Name: "default-interface", + } + suite.mockNetworkService.On("GetDefaultInterface").Return(i, errors.New("some os error")) + header := suite.conveyHeaderProvider.GetMetadata() + suite.Equal(nil, header["webpa-interface-used"]) +} + func (suite *ConveySuite) TestGetConveyHeaderSubsetFields() { + i := &net.Interface{ + Name: "erouter0", + } + suite.mockNetworkService.On("GetDefaultInterface").Return(i, nil) suite.mockNetworkService.On("GetInterfaceNames").Return([]string{"docsis"}, nil) suite.conveyHeaderProvider.fields = []string{"fw-name", "hw-model"} @@ -101,6 +150,10 @@ func (suite *ConveySuite) TestGetConveyHeaderSubsetFields() { } func (suite *ConveySuite) TestDecorate() { + i := &net.Interface{ + Name: "erouter0", + } + suite.mockNetworkService.On("GetDefaultInterface").Return(i, nil) suite.mockNetworkService.On("GetInterfaceNames").Return([]string{"docsis"}, nil) req, err := http.NewRequest(http.MethodGet, "https://example.com", nil) @@ -114,6 +167,10 @@ func (suite *ConveySuite) TestDecorate() { } func (suite *ConveySuite) TestDecorateMsg() { + i := &net.Interface{ + Name: "erouter0", + } + suite.mockNetworkService.On("GetDefaultInterface").Return(i, nil) suite.mockNetworkService.On("GetInterfaceNames").Return([]string{"erouter0"}, nil) msg := new(wrp.Message) diff --git a/internal/net/network_service.go b/internal/net/network_service.go index 5191853..91116c5 100644 --- a/internal/net/network_service.go +++ b/internal/net/network_service.go @@ -12,6 +12,7 @@ import ( type NetworkServicer interface { GetInterfaces() ([]net.Interface, error) GetInterfaceNames() ([]string, error) + GetDefaultInterface() (*net.Interface, error) } type NetworkService struct { @@ -66,6 +67,10 @@ func (ns *NetworkService) GetInterfaceNames() ([]string, error) { return names, nil } +func (ns *NetworkService) GetDefaultInterface() (*net.Interface, error) { + return ns.N.DefaultInterface() +} + func (ns *NetworkService) isAllowed(name string) bool { for k, v := range ns.AllowedInterfaces { if strings.EqualFold(name, k) { diff --git a/internal/net/network_service_test.go b/internal/net/network_service_test.go index e49b277..d4e9e16 100644 --- a/internal/net/network_service_test.go +++ b/internal/net/network_service_test.go @@ -23,6 +23,11 @@ func (m *mockNetworkWrapper) Interfaces() ([]net.Interface, error) { return args.Get(0).([]net.Interface), args.Error(1) } +func (m *mockNetworkWrapper) DefaultInterface() (*net.Interface, error) { + args := m.Called() + return args.Get(0).(*net.Interface), args.Error(1) +} + type NetworkServiceSuite struct { suite.Suite networkService NetworkServicer @@ -107,3 +112,11 @@ func (suite *NetworkServiceSuite) TestGetInterfaceNamesError() { suite.Error(err) suite.Equal(0, len(names)) } + +func (suite *NetworkServiceSuite) TestGetDefaulInterface() { + i := &net.Interface{} + suite.mockNetworkWrapper.On("DefaultInterface").Return(i, nil) + result, err := suite.networkService.GetDefaultInterface() + suite.NoError(err) + suite.Equal(i, result) +} diff --git a/internal/net/network_wrapper.go b/internal/net/network_wrapper.go index bb2ad4c..545ef3e 100644 --- a/internal/net/network_wrapper.go +++ b/internal/net/network_wrapper.go @@ -4,6 +4,7 @@ package net import ( + "github.com/nixigaj/go-default-route" "net" ) @@ -11,6 +12,7 @@ type NetworkWrap struct{} type NetworkWrapper interface { Interfaces() ([]net.Interface, error) + DefaultInterface() (*net.Interface, error) } func NewNetworkWrapper() NetworkWrapper { @@ -20,3 +22,7 @@ func NewNetworkWrapper() NetworkWrapper { func (n *NetworkWrap) Interfaces() ([]net.Interface, error) { return net.Interfaces() } + +func (n *NetworkWrap) DefaultInterface() (*net.Interface, error) { + return defaultroute.DefaultRouteInterface() +} diff --git a/internal/net/network_wrapper_test.go b/internal/net/network_wrapper_test.go new file mode 100644 index 0000000..e5ff636 --- /dev/null +++ b/internal/net/network_wrapper_test.go @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2024 Comcast Cable Communications Management, LLC +// SPDX-License-Identifier: Apache-2.0 + +package net + +import ( + "fmt" + "github.com/stretchr/testify/suite" + "testing" +) + +type NetworkWrapperSuite struct { + suite.Suite + networkWrapper NetworkWrapper +} + +func TestNetworkWrapperSuite(t *testing.T) { + suite.Run(t, new(NetworkWrapperSuite)) +} + +func (suite *NetworkWrapperSuite) SetupTest() { + suite.networkWrapper = NewNetworkWrapper() +} + +func (suite *NetworkWrapperSuite) TestDefaultInterface() { + result, err := suite.networkWrapper.DefaultInterface() + fmt.Println(result) + suite.NoError(err) +} diff --git a/internal/websocket/ws.go b/internal/websocket/ws.go index de4af8d..3d5afa9 100644 --- a/internal/websocket/ws.go +++ b/internal/websocket/ws.go @@ -244,6 +244,7 @@ func (ws *Websocket) run(ctx context.Context) { ws.conveyDecorator(ws.additionalHeaders) conn, _, dialErr := ws.dial(ctx, mode) //nolint:bodyclose + cEvent.At = ws.nowFunc() if dialErr == nil { @@ -398,6 +399,7 @@ func (ws *Websocket) dial(ctx context.Context, mode ipMode) (*nhws.Conn, *http.R HTTPClient: client, }, ) + if err != nil { return nil, resp, err } @@ -444,9 +446,11 @@ func (ws *Websocket) newHTTPClient(mode ipMode) (*http.Client, error) { KeepAlive: ws.keepAliveInterval, DualStack: false, } + transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { return dialer.DialContext(ctx, string(mode), addr) } + client.Transport = &custRT{transport: transport} return client, nil