From 0a5f12bf0670caee4582f2aa6f809a323a50642f Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Thu, 10 Aug 2023 11:55:23 +0200 Subject: [PATCH 01/33] hidden_paths: Enable registration of hiddenpaths locally. Fixes #4364 --- control/tasks.go | 5 +++ doc/hidden-paths.rst | 47 ++---------------------- pkg/experimental/hiddenpath/BUILD.bazel | 1 + pkg/experimental/hiddenpath/discovery.go | 27 +++++--------- pkg/snet/path.go | 5 +++ pkg/snet/path/path.go | 4 ++ private/app/appnet/addr.go | 3 +- 7 files changed, 30 insertions(+), 62 deletions(-) diff --git a/control/tasks.go b/control/tasks.go index 4b8a8ab755..fedae5e905 100644 --- a/control/tasks.go +++ b/control/tasks.go @@ -196,6 +196,11 @@ func (t *TasksConfig) segmentWriter(segType seg.Type, Writer: writer, Tick: beaconing.NewTick(t.RegistrationInterval), } + // The period of the task is short because we want to retry quickly + // if we fail fast. So during one interval we'll make as many attempts + // as we can until we succeed. After succeeding, the task does nothing + // until the end of the interval. The interval itself is used as a + // timeout. If we fail slow we give up at the end of the cycle. return periodic.Start(r, 500*time.Millisecond, t.RegistrationInterval) } diff --git a/doc/hidden-paths.rst b/doc/hidden-paths.rst index 4a24fd1aa4..2df2951a00 100644 --- a/doc/hidden-paths.rst +++ b/doc/hidden-paths.rst @@ -325,57 +325,18 @@ Everything combined the path lookup looks as follows: Hidden segment service discovery -------------------------------- -Hidden segment services in remote ASes can be discovered via a hidden segment -service discovery. Similar to the gateway discovery an initial UDP roundtrip is -done to find the discovery service. The discovery service can then be queried -for hidden segment services. The reply of the discovery contains a list of +Hidden segment services in remote ASes can be queried for hidden segment +services. The hidden segment services are build into the control service +and share the same address, so they can be connected to by dialing the +'CS' service address directly. The reply of the discovery contains a list of hidden segment lookup services and a list of hidden segment registration services. -To make the information of what hidden segment services exist in an AS available -to the discovery service, the servers that run hidden segment services must -register in the topology file: - -- Servers that run the hidden segment lookup service must be listed as - ``hidden_segment_lookup_service``. - -- Servers that run the hidden segment registration service must be listed as - ``hidden_segment_registration_service``. - Note that having access control on the hidden segment discovery service is not strictly required, since even if someone can get access to the endpoints, which service hidden segment infrastructure, the services themselves must verify that only authorized parties read or write hidden segment data. -Discovery service gRPC definition -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. code-block:: protobuf - - service DiscoveryService { - // Return the remote hidden segment services. - rpc HiddenSegmentServices(HiddenSegmentServicesRequest) returns (HiddenSegmentServicesResponse) {} - } - - message HiddenSegmentServicesRequest {} - - message HiddenSegmentServicesResponse { - // The list of lookup service instances. - repeated HiddenSegmentLookupServer lookup = 1; - // The list of registration service instances. - repeated HiddenSegmentRegistrationServer registration = 2; - } - - message HiddenSegmentLookupServer { - // The address of a hidden segment lookup service instance. - string address = 1; - } - - message HiddenSegmentRegistrationServer { - // The address of a hidden segment registration service instance. - string address = 1; - } - Security -------- diff --git a/pkg/experimental/hiddenpath/BUILD.bazel b/pkg/experimental/hiddenpath/BUILD.bazel index ee33cdb962..3962a4665e 100644 --- a/pkg/experimental/hiddenpath/BUILD.bazel +++ b/pkg/experimental/hiddenpath/BUILD.bazel @@ -25,6 +25,7 @@ go_library( "//pkg/private/serrors:go_default_library", "//pkg/segment:go_default_library", "//pkg/snet:go_default_library", + "//pkg/snet/path:go_default_library", "//private/config:go_default_library", "//private/pathdb:go_default_library", "//private/pathdb/query:go_default_library", diff --git a/pkg/experimental/hiddenpath/discovery.go b/pkg/experimental/hiddenpath/discovery.go index 8418debb9c..2e129f15d3 100644 --- a/pkg/experimental/hiddenpath/discovery.go +++ b/pkg/experimental/hiddenpath/discovery.go @@ -21,6 +21,7 @@ import ( "github.com/scionproto/scion/pkg/addr" "github.com/scionproto/scion/pkg/private/serrors" "github.com/scionproto/scion/pkg/snet" + "github.com/scionproto/scion/pkg/snet/path" ) // Servers is a list of discovered remote hidden segment server. @@ -80,31 +81,21 @@ func (r LookupResolver) Resolve(ctx context.Context, ia addr.IA) (net.Addr, erro func resolve(ctx context.Context, ia addr.IA, discoverer Discoverer, router snet.Router, extractAddr func(Servers) (*net.UDPAddr, error)) (net.Addr, error) { - path, err := router.Route(ctx, ia) + p, err := router.Route(ctx, ia) if err != nil { return nil, serrors.WrapStr("looking up path", err) } - if path == nil { + if p == nil { return nil, serrors.WrapStr("no path found to remote", err) } dsAddr := &snet.SVCAddr{ IA: ia, - NextHop: path.UnderlayNextHop(), - Path: path.Dataplane(), - SVC: addr.SvcDS, + NextHop: p.UnderlayNextHop(), + Path: p.Dataplane(), + SVC: addr.SvcCS, } - hps, err := discoverer.Discover(ctx, dsAddr) - if err != nil { - return nil, serrors.WrapStr("discovering hidden path server", err) - } - a, err := extractAddr(hps) - if err != nil { - return nil, serrors.WithCtx(err, "isd_as", ia) + if dsAddr.Path == nil { + dsAddr.Path = path.Empty{} } - return &snet.UDPAddr{ - IA: ia, - Host: a, - NextHop: path.UnderlayNextHop(), - Path: path.Dataplane(), - }, nil + return dsAddr, nil } diff --git a/pkg/snet/path.go b/pkg/snet/path.go index 8fa12fc036..60084df487 100644 --- a/pkg/snet/path.go +++ b/pkg/snet/path.go @@ -65,6 +65,11 @@ type Path interface { // Metadata returns supplementary information about this path. // Returns nil if the metadata is not available. Metadata() *PathMetadata + // Interfaces returns Metada().Interfaces() if the underlying implementation supports it + // Else returns nil. The difference between calling this and accessing Metadata().Interfaces is + // that there is no need to check if Metadata() is nil. An alternative could be to have an + // Interfaces() method to PathMetadata that accepts nil, and to call that instead. + Interfaces() []PathInterface } // PathInterface is an interface of the path. diff --git a/pkg/snet/path/path.go b/pkg/snet/path/path.go index 08748964d9..afb25b073d 100644 --- a/pkg/snet/path/path.go +++ b/pkg/snet/path/path.go @@ -65,6 +65,10 @@ func (p Path) Metadata() *snet.PathMetadata { return p.Meta.Copy() } +func (p Path) Interfaces() []snet.PathInterface { + return p.Meta.Interfaces +} + func (p Path) String() string { hops := fmtInterfaces(p.Meta.Interfaces) return fmt.Sprintf("Hops: [%s] MTU: %d NextHop: %s", diff --git a/private/app/appnet/addr.go b/private/app/appnet/addr.go index 4bbd733037..67f60d0bed 100644 --- a/private/app/appnet/addr.go +++ b/private/app/appnet/addr.go @@ -155,12 +155,13 @@ func (r AddressRewriter) buildFullAddress(ctx context.Context, ret.NextHop = p.UnderlayNextHop() // SVC addresses in the local AS get resolved via topology lookup - if len(p.Metadata().Interfaces) == 0 { //when local AS + if len(p.Interfaces()) == 0 { //when local AS ov, err := r.SVCRouter.GetUnderlay(s.SVC) if err != nil { return nil, serrors.WrapStr("Unable to resolve underlay", err) } ret.NextHop = ov + ret.Path = path.Empty{} } return ret, nil From 5fb135bfcad6ee51cc74447663048272da4f5476 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Thu, 10 Aug 2023 17:13:53 +0200 Subject: [PATCH 02/33] hidden_paths: fix mock for path. New method Interfaces() is missing. --- pkg/snet/mock_snet/mock.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pkg/snet/mock_snet/mock.go b/pkg/snet/mock_snet/mock.go index 181ac9a929..c72f2b7089 100644 --- a/pkg/snet/mock_snet/mock.go +++ b/pkg/snet/mock_snet/mock.go @@ -280,6 +280,20 @@ func (mr *MockPathMockRecorder) Metadata() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Metadata", reflect.TypeOf((*MockPath)(nil).Metadata)) } +// Metadata mocks base method. +func (m *MockPath) Interaces() []snet.Interface { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Interfaces") + ret0, _ := ret[0].([]snet.Interfaces) + return ret0 +} + +// Metadata indicates an expected call of Interfaces. +func (mr *MockPathMockRecorder) Interfaces() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Interfaces", reflect.TypeOf((*MockPath)(nil).Interfaces)) +} + // Source mocks base method. func (m *MockPath) Source() addr.IA { m.ctrl.T.Helper() From 9cd4df81dbb99464cf48168dcae7ecfec8457fa4 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Thu, 10 Aug 2023 17:37:27 +0200 Subject: [PATCH 03/33] hidden_paths: fix wrong signature of Interfaces() method in mocks. --- pkg/snet/mock_snet/mock.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/snet/mock_snet/mock.go b/pkg/snet/mock_snet/mock.go index c72f2b7089..91c25ecdf7 100644 --- a/pkg/snet/mock_snet/mock.go +++ b/pkg/snet/mock_snet/mock.go @@ -281,10 +281,10 @@ func (mr *MockPathMockRecorder) Metadata() *gomock.Call { } // Metadata mocks base method. -func (m *MockPath) Interaces() []snet.Interface { +func (m *MockPath) Interaces() []snet.PathInterface { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Interfaces") - ret0, _ := ret[0].([]snet.Interfaces) + ret0, _ := ret[0].([]snet.PathInterface) return ret0 } From e2b8f7be8e5f75d44281f24a8d40e27f5ebf2165 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Thu, 10 Aug 2023 17:51:13 +0200 Subject: [PATCH 04/33] hidden_paths: fix mocks, take two. --- pkg/snet/mock_snet/mock.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/snet/mock_snet/mock.go b/pkg/snet/mock_snet/mock.go index 91c25ecdf7..dd37c0e56b 100644 --- a/pkg/snet/mock_snet/mock.go +++ b/pkg/snet/mock_snet/mock.go @@ -281,7 +281,7 @@ func (mr *MockPathMockRecorder) Metadata() *gomock.Call { } // Metadata mocks base method. -func (m *MockPath) Interaces() []snet.PathInterface { +func (m *MockPath) Interfaces() []snet.PathInterface { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Interfaces") ret0, _ := ret[0].([]snet.PathInterface) From ecfb97cb9967251bd31c5e106457faa220d41724 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Thu, 10 Aug 2023 17:57:38 +0200 Subject: [PATCH 05/33] hidden_paths: yet another test Path implementation that lacked the Interfaces() method. --- private/app/appnet/addr_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/private/app/appnet/addr_test.go b/private/app/appnet/addr_test.go index 27bba692cc..df81943a42 100644 --- a/private/app/appnet/addr_test.go +++ b/private/app/appnet/addr_test.go @@ -481,6 +481,10 @@ func (t *testPath) Metadata() *snet.PathMetadata { panic("not implemented") } +func (t *testPath) Interfaces() []snet.PathInterface { + panic("not implemented") +} + func (t *testPath) Copy() snet.Path { panic("not implemented") } From 21e1da6bf976b0e72cc8beccd92480ba808f4d00 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Thu, 10 Aug 2023 18:06:30 +0200 Subject: [PATCH 06/33] hidden_paths: must commit generated go mocks. --- pkg/snet/mock_snet/mock.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/pkg/snet/mock_snet/mock.go b/pkg/snet/mock_snet/mock.go index dd37c0e56b..d230c0930c 100644 --- a/pkg/snet/mock_snet/mock.go +++ b/pkg/snet/mock_snet/mock.go @@ -266,32 +266,32 @@ func (mr *MockPathMockRecorder) Destination() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Destination", reflect.TypeOf((*MockPath)(nil).Destination)) } -// Metadata mocks base method. -func (m *MockPath) Metadata() *snet.PathMetadata { +// Interfaces mocks base method. +func (m *MockPath) Interfaces() []snet.PathInterface { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Metadata") - ret0, _ := ret[0].(*snet.PathMetadata) + ret := m.ctrl.Call(m, "Interfaces") + ret0, _ := ret[0].([]snet.PathInterface) return ret0 } -// Metadata indicates an expected call of Metadata. -func (mr *MockPathMockRecorder) Metadata() *gomock.Call { +// Interfaces indicates an expected call of Interfaces. +func (mr *MockPathMockRecorder) Interfaces() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Metadata", reflect.TypeOf((*MockPath)(nil).Metadata)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Interfaces", reflect.TypeOf((*MockPath)(nil).Interfaces)) } // Metadata mocks base method. -func (m *MockPath) Interfaces() []snet.PathInterface { +func (m *MockPath) Metadata() *snet.PathMetadata { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Interfaces") - ret0, _ := ret[0].([]snet.PathInterface) + ret := m.ctrl.Call(m, "Metadata") + ret0, _ := ret[0].(*snet.PathMetadata) return ret0 } -// Metadata indicates an expected call of Interfaces. -func (mr *MockPathMockRecorder) Interfaces() *gomock.Call { +// Metadata indicates an expected call of Metadata. +func (mr *MockPathMockRecorder) Metadata() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Interfaces", reflect.TypeOf((*MockPath)(nil).Interfaces)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Metadata", reflect.TypeOf((*MockPath)(nil).Metadata)) } // Source mocks base method. From ed60241fe35904e740e597f2d41e34e33971bb47 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Wed, 16 Aug 2023 12:52:33 +0200 Subject: [PATCH 07/33] hidden_paths: A less disruptive solution to the registry addressing. * give the control service a static port. * use that in the topo config as the hidden_path service address for use by the discovery service. * This change does not yet include the associated changes to the config generators. --- acceptance/hidden_paths/test.py | 9 +++++---- pkg/experimental/hiddenpath/discovery.go | 17 +++++++++++++++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/acceptance/hidden_paths/test.py b/acceptance/hidden_paths/test.py index c3144c9e41..693bfab6de 100755 --- a/acceptance/hidden_paths/test.py +++ b/acceptance/hidden_paths/test.py @@ -66,10 +66,10 @@ def setup_prepare(self): # can use them. Optimally we would define a static server port inside # the CS and use that one instead. control_addresses = { - "2": "172.20.0.51:32768", - "3": "172.20.0.59:32768", - "4": "172.20.0.67:32768", - "5": "172.20.0.75:32768", + "2": "172.20.0.51:42768", + "3": "172.20.0.59:42768", + "4": "172.20.0.67:42768", + "5": "172.20.0.75:42768", } # Each AS participating in hidden paths has their own hidden paths configuration file. hp_configs = { @@ -93,6 +93,7 @@ def setup_prepare(self): control_path = self.artifacts / "gen" / ("ASff00_0_%s" % as_number) \ / ("%s.toml" % control_id) scion.update_toml({"path.hidden_paths_cfg": hp_config_url}, [control_path]) + scion.update_toml({"quic.address": control_addresses[as_number]}, [control_path]) # For simplicity, expose the services in all hidden paths ASes, # even though some don't need the registration service. diff --git a/pkg/experimental/hiddenpath/discovery.go b/pkg/experimental/hiddenpath/discovery.go index 2e129f15d3..f336a152c0 100644 --- a/pkg/experimental/hiddenpath/discovery.go +++ b/pkg/experimental/hiddenpath/discovery.go @@ -92,10 +92,23 @@ func resolve(ctx context.Context, ia addr.IA, discoverer Discoverer, router snet IA: ia, NextHop: p.UnderlayNextHop(), Path: p.Dataplane(), - SVC: addr.SvcCS, + SVC: addr.SvcDS, } if dsAddr.Path == nil { dsAddr.Path = path.Empty{} } - return dsAddr, nil + hps, err := discoverer.Discover(ctx, dsAddr) + if err != nil { + return nil, serrors.WrapStr("discovering hidden path server", err) + } + a, err := extractAddr(hps) + if err != nil { + return nil, serrors.WithCtx(err, "isd_as", ia) + } + return &snet.UDPAddr{ + IA: ia, + Host: a, + NextHop: dsAddr.NextHop, + Path: dsAddr.Path, + }, nil } From ac6a9cd3a4e610aa840e4a2d641dd1eaefce5a51 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Thu, 17 Aug 2023 17:20:37 +0200 Subject: [PATCH 08/33] hidden_paths: Slight change of approach to address configuration. The CS public address and the CS scion address can now be the same, while the service resolver explicitly gets a different port. I am experimenting with the possibility of configuring the service resolver address as the regular address field of a new service named "service_resolution". (oncilla@ thinks it's a bad idea. I do not understand why yet but I guess I'll find out). Also updated tests to match the intended changes, and to call assert.Equal() with arguments in the correct order. --- control/cmd/control/main.go | 7 ++++++ control/hiddenpaths.go | 33 ++++++++++++++------------- private/app/appnet/addr_test.go | 40 ++++++++++++++------------------- private/app/appnet/infraenv.go | 4 +++- private/topology/interface.go | 16 ++++++++++++- private/topology/json/json.go | 1 + private/topology/reload.go | 7 ++++++ private/topology/servicetype.go | 3 +++ private/topology/topology.go | 11 ++++++++- 9 files changed, 80 insertions(+), 42 deletions(-) diff --git a/control/cmd/control/main.go b/control/cmd/control/main.go index d481cd607c..926bfd45b5 100644 --- a/control/cmd/control/main.go +++ b/control/cmd/control/main.go @@ -202,9 +202,16 @@ func realMain(ctx context.Context) error { nc := infraenv.NetworkConfig{ IA: topo.IA(), + // Public: (Historical name) The TCP/IP:port address for this (control) service. Public: topo.ControlServiceAddress(globalCfg.General.ID), + // ServiceResolution: The UDP/SCION address of the service "redirector". It is hosted by this + // (control service) process but as a separate service. + ServiceResolution: topo.ServiceResolutionAddress(globalCfg.General.ID), ReconnectToDispatcher: globalCfg.General.ReconnectToDispatcher, QUIC: infraenv.QUIC{ + // Address: the QUIC/SCION address of this service. See QUICStack() for how address + // assigned. This can be configured statically and can be identical to the Public address. + // If not configured: a dynamic port is assigned. Address: globalCfg.QUIC.Address, TLSVerifier: trust.NewTLSCryptoVerifier(trustDB), GetCertificate: cs.NewTLSCertificateLoader( diff --git a/control/hiddenpaths.go b/control/hiddenpaths.go index f0036c1f10..2d5372d431 100644 --- a/control/hiddenpaths.go +++ b/control/hiddenpaths.go @@ -80,26 +80,27 @@ func (c HiddenPathConfigurator) Setup(location string) (*HiddenPathRegistrationC }) if roles.Registry { log.Info("Starting hidden path authoritative and registration server") - hspb.RegisterAuthoritativeHiddenSegmentLookupServiceServer(c.InterASQUICServer, - &hpgrpc.AuthoritativeSegmentServer{ + hsSegmentService := &hpgrpc.AuthoritativeSegmentServer{ Lookup: c.localAuthServer(groups), Verifier: c.Verifier, - }) - hspb.RegisterHiddenSegmentRegistrationServiceServer(c.InterASQUICServer, - &hpgrpc.RegistrationServer{ - Registry: hiddenpath.RegistryServer{ - Groups: groups, - DB: &hiddenpath.Storer{ - DB: c.PathDB, - }, - Verifier: hiddenpath.VerifierAdapter{ - Verifier: c.Verifier, - }, - LocalIA: c.LocalIA, + } + hspb.RegisterAuthoritativeHiddenSegmentLookupServiceServer(c.InterASQUICServer, hsSegmentService) + hspb.RegisterAuthoritativeHiddenSegmentLookupServiceServer(c.IntraASTCPServer, hsSegmentService) + hsRegistrationService := &hpgrpc.RegistrationServer{ + Registry: hiddenpath.RegistryServer{ + Groups: groups, + DB: &hiddenpath.Storer{ + DB: c.PathDB, }, - Verifier: c.Verifier, + Verifier: hiddenpath.VerifierAdapter{ + Verifier: c.Verifier, + }, + LocalIA: c.LocalIA, }, - ) + Verifier: c.Verifier, + } + hspb.RegisterHiddenSegmentRegistrationServiceServer(c.InterASQUICServer, hsRegistrationService) + hspb.RegisterHiddenSegmentRegistrationServiceServer(c.IntraASTCPServer, hsRegistrationService) } if !roles.Writer { return nil, nil diff --git a/private/app/appnet/addr_test.go b/private/app/appnet/addr_test.go index df81943a42..408a1abca3 100644 --- a/private/app/appnet/addr_test.go +++ b/private/app/appnet/addr_test.go @@ -80,8 +80,8 @@ func TestRedirectQUIC(t *testing.T) { a, r, err := aw.RedirectToQUIC(context.Background(), tc.input) tc.assertErr(t, err) - assert.Equal(t, a, tc.wantAddr) - assert.Equal(t, r, tc.wantRedirect) + assert.Equal(t, tc.wantAddr, a) + assert.Equal(t, tc.wantRedirect, r) }) } @@ -97,9 +97,7 @@ func TestRedirectQUIC(t *testing.T) { router.EXPECT().Route(gomock.Any(), gomock.Any()).Return(path, nil) path.EXPECT().Dataplane().Return(snetpath.SCION{}) path.EXPECT().UnderlayNextHop().Return(&net.UDPAddr{IP: net.ParseIP("10.1.1.1")}) - path.EXPECT().Metadata().Return(&snet.PathMetadata{ - Interfaces: make([]snet.PathInterface, 1), // just non-empty - }) + path.EXPECT().Interfaces().Return(make([]snet.PathInterface, 1)) // just non-empty aw := infraenv.AddressRewriter{ Router: router, @@ -134,9 +132,7 @@ func TestRedirectQUIC(t *testing.T) { router.EXPECT().Route(gomock.Any(), gomock.Any()).Return(path, nil) path.EXPECT().Dataplane().Return(snetpath.SCION{}) path.EXPECT().UnderlayNextHop().Return(&net.UDPAddr{IP: net.ParseIP("10.1.1.1")}) - path.EXPECT().Metadata().Return(&snet.PathMetadata{ - Interfaces: make([]snet.PathInterface, 1), // just non-empty - }) + path.EXPECT().Interfaces().Return(make([]snet.PathInterface, 1)) // just non-empty aw := infraenv.AddressRewriter{ Router: router, @@ -166,7 +162,7 @@ func TestRedirectQUIC(t *testing.T) { router.EXPECT().Route(gomock.Any(), gomock.Any()).Return(path, nil) path.EXPECT().Dataplane().Return(snetpath.SCION{}) path.EXPECT().UnderlayNextHop().Return(&net.UDPAddr{IP: net.ParseIP("10.1.1.1")}) - path.EXPECT().Metadata().Return(&snet.PathMetadata{}) + path.EXPECT().Interfaces().Return([]snet.PathInterface{}) svcRouter := mock_infraenv.NewMockSVCResolver(ctrl) svcRouter.EXPECT().GetUnderlay(addr.SvcCS).Return( &net.UDPAddr{IP: net.ParseIP("10.1.1.1")}, nil, @@ -182,7 +178,7 @@ func TestRedirectQUIC(t *testing.T) { want := &snet.SVCAddr{ SVC: addr.SvcCS, NextHop: &net.UDPAddr{IP: net.ParseIP("10.1.1.1")}, - Path: snetpath.SCION{}, + Path: snetpath.Empty{}, } a, r, err := aw.RedirectToQUIC(context.Background(), input) assert.NoError(t, err) @@ -225,7 +221,7 @@ func TestBuildFullAddress(t *testing.T) { SVC: addr.SvcCS, } a, err := aw.BuildFullAddress(context.Background(), input) - assert.Equal(t, a, input) + assert.Equal(t, input, a) assert.NoError(t, err) }) @@ -243,9 +239,7 @@ func TestBuildFullAddress(t *testing.T) { path := mock_snet.NewMockPath(ctrl) path.EXPECT().Dataplane().Return(snetpath.SCION{}) path.EXPECT().UnderlayNextHop().Return(&net.UDPAddr{}) - path.EXPECT().Metadata().Return(&snet.PathMetadata{ - Interfaces: make([]snet.PathInterface, 1), // just non-empty - }) + path.EXPECT().Interfaces().Return(make([]snet.PathInterface, 1)) // just non-empty router.EXPECT().Route(gomock.Any(), gomock.Any()).Return(path, nil) input := &snet.SVCAddr{IA: remoteIA, SVC: addr.SvcCS, Path: snetpath.Empty{}} a, err := aw.BuildFullAddress(context.Background(), input) @@ -255,7 +249,7 @@ func TestBuildFullAddress(t *testing.T) { NextHop: &net.UDPAddr{}, SVC: addr.SvcCS, } - assert.Equal(t, a, want) + assert.Equal(t, want, a) assert.NoError(t, err) }) @@ -277,7 +271,7 @@ func TestBuildFullAddress(t *testing.T) { svcRouter.EXPECT().GetUnderlay(addr.SvcCS).Return(underlayAddr, nil) path := mock_snet.NewMockPath(ctrl) - path.EXPECT().Metadata().Return(&snet.PathMetadata{}) + path.EXPECT().Interfaces().Return([]snet.PathInterface{}) path.EXPECT().Dataplane() path.EXPECT().UnderlayNextHop() router.EXPECT().Route(gomock.Any(), gomock.Any()).Return(path, nil) @@ -285,8 +279,8 @@ func TestBuildFullAddress(t *testing.T) { input := &snet.SVCAddr{IA: localIA, SVC: addr.SvcCS, Path: snetpath.Empty{}} a, err := aw.BuildFullAddress(context.Background(), input) - want := &snet.SVCAddr{IA: localIA, NextHop: underlayAddr, SVC: addr.SvcCS} - assert.Equal(t, a, want) + want := &snet.SVCAddr{IA: localIA, NextHop: underlayAddr, SVC: addr.SvcCS, Path: snetpath.Empty{}} + assert.Equal(t, want, a) assert.NoError(t, err) }) @@ -304,7 +298,7 @@ func TestBuildFullAddress(t *testing.T) { svcRouter.EXPECT().GetUnderlay(addr.SvcCS).Return(nil, errors.New("err")) path := mock_snet.NewMockPath(ctrl) - path.EXPECT().Metadata().Return(&snet.PathMetadata{}) + path.EXPECT().Interfaces().Return([]snet.PathInterface{}) path.EXPECT().Dataplane() path.EXPECT().UnderlayNextHop() router.EXPECT().Route(gomock.Any(), gomock.Any()).Return(path, nil) @@ -388,9 +382,9 @@ func TestResolve(t *testing.T) { } initResolver(resolver, tc.ResolverSetup) p, a, redirect, err := aw.ResolveSVC(context.Background(), path, tc.input) - assert.Equal(t, p, tc.wantPath) - assert.Equal(t, a.String(), tc.want.String()) - assert.Equal(t, redirect, tc.wantQUICRedirect) + assert.Equal(t, tc.wantPath, p) + assert.Equal(t, tc.want.String(), a.String()) + assert.Equal(t, tc.wantQUICRedirect, redirect) tc.assertErr(t, err) }) } @@ -448,7 +442,7 @@ func TestParseReply(t *testing.T) { if err != nil { return } - assert.Equal(t, a.String(), tc.want.String()) + assert.Equal(t, tc.want.String(), a.String()) }) } } diff --git a/private/app/appnet/infraenv.go b/private/app/appnet/infraenv.go index 595cd1cc01..4cfb3d9c10 100644 --- a/private/app/appnet/infraenv.go +++ b/private/app/appnet/infraenv.go @@ -64,6 +64,8 @@ type NetworkConfig struct { // Public is the Internet-reachable address in the case where the service // is behind NAT. Public *net.UDPAddr + // ServiceResolution is the address of the service resolver. + ServiceResolution *net.UDPAddr // ReconnectToDispatcher sets up sockets that automatically reconnect if // the dispatcher closes the connection (e.g., if the dispatcher goes // down). @@ -266,7 +268,7 @@ func (nc *NetworkConfig) initSvcRedirect(quicAddress string) (func(), error) { Dispatcher: packetDispatcher, Metrics: nc.SCIONNetworkMetrics, } - conn, err := network.Listen(context.Background(), "udp", nc.Public, addr.SvcWildcard) + conn, err := network.Listen(context.Background(), "udp", nc.ServiceResolution, addr.SvcWildcard) if err != nil { return nil, serrors.WrapStr("listening on SCION", err, "addr", nc.Public) } diff --git a/private/topology/interface.go b/private/topology/interface.go index f6440c1770..f72cfcaa94 100644 --- a/private/topology/interface.go +++ b/private/topology/interface.go @@ -42,9 +42,15 @@ type Topology interface { InterfaceIDs() []common.IFIDType // PublicAddress gets the public address of a server with the requested type and name, and nil - // if no such server exists. + // if no such server exists. The service type is specified as a addr.SVC and retricted to + // addr.SvcDS and addr.SvcCS. PublicAddress(svc addr.SVC, name string) *net.UDPAddr + // PublicAddressByType gets the public address of a server with the requested type and name, and nil + // if no such server exists. This support more types than PublicAddress. That is, all the types + // specified by topology.ServiceType. + PublicAddressByType(svc ServiceType, name string) *net.UDPAddr + // Anycast returns the address for an arbitrary server of the requested type. Anycast(svc addr.SVC) (*net.UDPAddr, error) // Multicast returns all addresses for the requested type. @@ -203,6 +209,14 @@ func (t *topologyS) BR(name string) (BRInfo, bool) { return br, ok } +func (t *topologyS) PublicAddressByType(svc ServiceType, name string) *net.UDPAddr { + topoAddr, err := t.Topology.GetTopoAddr(name, svc) + if err != nil { + return nil + } + return topoAddr.SCIONAddress +} + func (t *topologyS) PublicAddress(svc addr.SVC, name string) *net.UDPAddr { topoAddr := t.topoAddress(svc, name) if topoAddr == nil { diff --git a/private/topology/json/json.go b/private/topology/json/json.go index 08e7cf333d..1f231b53cb 100644 --- a/private/topology/json/json.go +++ b/private/topology/json/json.go @@ -83,6 +83,7 @@ type Topology struct { HiddenSegmentLookup map[string]*ServerInfo `json:"hidden_segment_lookup_service,omitempty"` HiddenSegmentReg map[string]*ServerInfo `json:"hidden_segment_registration_service,omitempty"` SIG map[string]*GatewayInfo `json:"sigs,omitempty"` + ServiceResolution map[string]*ServerInfo `json:"service_resolution,omitempty"` } // ServerInfo contains the information for a SCION application running in the local AS. diff --git a/private/topology/reload.go b/private/topology/reload.go index 74f974681f..1436704d22 100644 --- a/private/topology/reload.go +++ b/private/topology/reload.go @@ -167,6 +167,13 @@ func (l *Loader) ControlServiceAddress(id string) *net.UDPAddr { return l.topo.PublicAddress(addr.SvcCS, id) } +func (l *Loader) ServiceResolutionAddress(id string) *net.UDPAddr { + l.mtx.Lock() + defer l.mtx.Unlock() + + return l.topo.PublicAddressByType(ServiceResolution, id) +} + // TODO(lukedirtwalker): remove error and simplify struct in the return type. func (l *Loader) Gateways() ([]GatewayInfo, error) { l.mtx.Lock() diff --git a/private/topology/servicetype.go b/private/topology/servicetype.go index bdfa9b21c6..acf80ccf60 100644 --- a/private/topology/servicetype.go +++ b/private/topology/servicetype.go @@ -28,6 +28,7 @@ const ( Gateway HiddenSegmentLookup HiddenSegmentRegistration + ServiceResolution ) func (t ServiceType) String() string { @@ -64,6 +65,8 @@ func ServiceTypeFromString(s string) ServiceType { return HiddenSegmentLookup case "hiddensegmentregistration": return HiddenSegmentRegistration + case "serviceresolution": + return ServiceResolution default: return Unknown } diff --git a/private/topology/topology.go b/private/topology/topology.go index 56bc023210..81372a9e78 100644 --- a/private/topology/topology.go +++ b/private/topology/topology.go @@ -72,6 +72,7 @@ type ( HiddenSegmentLookup IDAddrMap HiddenSegmentRegistration IDAddrMap SIG map[string]GatewayInfo + ServiceResolution IDAddrMap } // GatewayInfo describes a scion gateway. @@ -146,6 +147,7 @@ func NewRWTopology() *RWTopology { HiddenSegmentRegistration: make(IDAddrMap), SIG: make(map[string]GatewayInfo), IFInfoMap: make(IfInfoMap), + ServiceResolution: make(IDAddrMap), } } @@ -309,6 +311,10 @@ func (t *RWTopology) populateServices(raw *jsontopo.Topology) error { if err != nil { return serrors.WrapStr("unable to extract hidden segment registration address", err) } + t.ServiceResolution, err = svcMapFromRaw(raw.ServiceResolution) + if err != nil { + return serrors.WrapStr("unable to extract service resolution address", err) + } return nil } @@ -363,6 +369,8 @@ func (t *RWTopology) getSvcInfo(svc ServiceType) (*svcInfo, error) { m[k] = *v.CtrlAddr } return &svcInfo{idTopoAddrMap: m}, nil + case ServiceResolution: + return &svcInfo{idTopoAddrMap: t.ServiceResolution}, nil default: return nil, serrors.New("unsupported service type", "type", svc) } @@ -385,9 +393,10 @@ func (t *RWTopology) Copy() *RWTopology { CS: t.CS.copy(), DS: t.DS.copy(), - SIG: copySIGMap(t.SIG), HiddenSegmentLookup: t.HiddenSegmentLookup.copy(), HiddenSegmentRegistration: t.HiddenSegmentRegistration.copy(), + SIG: copySIGMap(t.SIG), + ServiceResolution: t.ServiceResolution.copy(), } } From 13f2f76bfd0f9854e75bfc7e331b42425c130549 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Fri, 18 Aug 2023 10:32:15 +0200 Subject: [PATCH 09/33] Comply with lint's admonitions --- control/cmd/control/main.go | 15 ++++++++------- control/hiddenpaths.go | 16 ++++++++++------ private/app/appnet/addr_test.go | 7 ++++++- private/topology/interface.go | 15 ++++++++------- 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/control/cmd/control/main.go b/control/cmd/control/main.go index 926bfd45b5..8873c653d5 100644 --- a/control/cmd/control/main.go +++ b/control/cmd/control/main.go @@ -201,16 +201,17 @@ func realMain(ctx context.Context) error { } nc := infraenv.NetworkConfig{ - IA: topo.IA(), - // Public: (Historical name) The TCP/IP:port address for this (control) service. - Public: topo.ControlServiceAddress(globalCfg.General.ID), - // ServiceResolution: The UDP/SCION address of the service "redirector". It is hosted by this - // (control service) process but as a separate service. + IA: topo.IA(), + // Public: (Historical name) The TCP/IP:port address for the control service. + Public: topo.ControlServiceAddress(globalCfg.General.ID), + // ServiceResolution: The UDP/SCION address of the service "redirector". + // It is hosted as a separate service. ServiceResolution: topo.ServiceResolutionAddress(globalCfg.General.ID), ReconnectToDispatcher: globalCfg.General.ReconnectToDispatcher, QUIC: infraenv.QUIC{ - // Address: the QUIC/SCION address of this service. See QUICStack() for how address - // assigned. This can be configured statically and can be identical to the Public address. + // Address: the QUIC/SCION address of this service. See QUICStack() + // for how the address is assigned. This can be configured + // statically and can be identical to the Public address. // If not configured: a dynamic port is assigned. Address: globalCfg.QUIC.Address, TLSVerifier: trust.NewTLSCryptoVerifier(trustDB), diff --git a/control/hiddenpaths.go b/control/hiddenpaths.go index 2d5372d431..b885cafc52 100644 --- a/control/hiddenpaths.go +++ b/control/hiddenpaths.go @@ -81,11 +81,13 @@ func (c HiddenPathConfigurator) Setup(location string) (*HiddenPathRegistrationC if roles.Registry { log.Info("Starting hidden path authoritative and registration server") hsSegmentService := &hpgrpc.AuthoritativeSegmentServer{ - Lookup: c.localAuthServer(groups), - Verifier: c.Verifier, + Lookup: c.localAuthServer(groups), + Verifier: c.Verifier, } - hspb.RegisterAuthoritativeHiddenSegmentLookupServiceServer(c.InterASQUICServer, hsSegmentService) - hspb.RegisterAuthoritativeHiddenSegmentLookupServiceServer(c.IntraASTCPServer, hsSegmentService) + hspb.RegisterAuthoritativeHiddenSegmentLookupServiceServer( + c.InterASQUICServer, hsSegmentService) + hspb.RegisterAuthoritativeHiddenSegmentLookupServiceServer( + c.IntraASTCPServer, hsSegmentService) hsRegistrationService := &hpgrpc.RegistrationServer{ Registry: hiddenpath.RegistryServer{ Groups: groups, @@ -99,8 +101,10 @@ func (c HiddenPathConfigurator) Setup(location string) (*HiddenPathRegistrationC }, Verifier: c.Verifier, } - hspb.RegisterHiddenSegmentRegistrationServiceServer(c.InterASQUICServer, hsRegistrationService) - hspb.RegisterHiddenSegmentRegistrationServiceServer(c.IntraASTCPServer, hsRegistrationService) + hspb.RegisterHiddenSegmentRegistrationServiceServer( + c.InterASQUICServer, hsRegistrationService) + hspb.RegisterHiddenSegmentRegistrationServiceServer( + c.IntraASTCPServer, hsRegistrationService) } if !roles.Writer { return nil, nil diff --git a/private/app/appnet/addr_test.go b/private/app/appnet/addr_test.go index 408a1abca3..3872efe10d 100644 --- a/private/app/appnet/addr_test.go +++ b/private/app/appnet/addr_test.go @@ -279,7 +279,12 @@ func TestBuildFullAddress(t *testing.T) { input := &snet.SVCAddr{IA: localIA, SVC: addr.SvcCS, Path: snetpath.Empty{}} a, err := aw.BuildFullAddress(context.Background(), input) - want := &snet.SVCAddr{IA: localIA, NextHop: underlayAddr, SVC: addr.SvcCS, Path: snetpath.Empty{}} + want := &snet.SVCAddr{ + IA: localIA, + NextHop: underlayAddr, + SVC: addr.SvcCS, + Path: snetpath.Empty{}, + } assert.Equal(t, want, a) assert.NoError(t, err) }) diff --git a/private/topology/interface.go b/private/topology/interface.go index f72cfcaa94..c375696bbe 100644 --- a/private/topology/interface.go +++ b/private/topology/interface.go @@ -41,14 +41,14 @@ type Topology interface { // InterfaceIDs returns all interface IDS from the local AS. InterfaceIDs() []common.IFIDType - // PublicAddress gets the public address of a server with the requested type and name, and nil - // if no such server exists. The service type is specified as a addr.SVC and retricted to - // addr.SvcDS and addr.SvcCS. + // PublicAddress gets the public address of a server with the requested type and + // name, and nil if no such server exists. The service type is specified as a + // addr.SVC and retricted to addr.SvcDS and addr.SvcCS. PublicAddress(svc addr.SVC, name string) *net.UDPAddr - // PublicAddressByType gets the public address of a server with the requested type and name, and nil - // if no such server exists. This support more types than PublicAddress. That is, all the types - // specified by topology.ServiceType. + // PublicAddressByType gets the public address of a server with the requested type + // and name, and nil if no such server exists. This support more types than + // PublicAddress. That is, all the types specified by topology.ServiceType. PublicAddressByType(svc ServiceType, name string) *net.UDPAddr // Anycast returns the address for an arbitrary server of the requested type. @@ -56,7 +56,8 @@ type Topology interface { // Multicast returns all addresses for the requested type. Multicast(svc addr.SVC) ([]*net.UDPAddr, error) - // UnderlayAnycast returns the underlay address for an arbitrary server of the requested type. + // UnderlayAnycast returns the underlay address for an arbitrary server of the + // requested type. UnderlayAnycast(svc addr.SVC) (*net.UDPAddr, error) // UnderlayMulticast returns all underlay addresses for the requested type. UnderlayMulticast(svc addr.SVC) ([]*net.UDPAddr, error) From 3ca68f6694fb1ce47f4a35fb002abdc7d5277e1f Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Fri, 18 Aug 2023 10:35:10 +0200 Subject: [PATCH 10/33] update mocks --- private/topology/mock_topology/mock.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/private/topology/mock_topology/mock.go b/private/topology/mock_topology/mock.go index 2c33bb48b2..6fdadf2281 100644 --- a/private/topology/mock_topology/mock.go +++ b/private/topology/mock_topology/mock.go @@ -210,6 +210,20 @@ func (mr *MockTopologyMockRecorder) PublicAddress(arg0, arg1 interface{}) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublicAddress", reflect.TypeOf((*MockTopology)(nil).PublicAddress), arg0, arg1) } +// PublicAddressByType mocks base method. +func (m *MockTopology) PublicAddressByType(arg0 topology.ServiceType, arg1 string) *net.UDPAddr { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PublicAddressByType", arg0, arg1) + ret0, _ := ret[0].(*net.UDPAddr) + return ret0 +} + +// PublicAddressByType indicates an expected call of PublicAddressByType. +func (mr *MockTopologyMockRecorder) PublicAddressByType(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublicAddressByType", reflect.TypeOf((*MockTopology)(nil).PublicAddressByType), arg0, arg1) +} + // SVCNames mocks base method. func (m *MockTopology) SVCNames(arg0 addr.SVC) topology.ServiceNames { m.ctrl.T.Helper() From 0c24724bd534d9351418a74b89b80531b9a488f7 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Fri, 18 Aug 2023 17:30:53 +0200 Subject: [PATCH 11/33] resolver_service: Make the service resolution port dynamic by default. If the service resolution address isn't configured, let it have a random port. The dispatcher dynamically assigns a port and also registers it as the recipient of resolution requests. It appears that no knowledge of the port is required outside of that. --- control/cmd/control/main.go | 2 ++ private/app/appnet/infraenv.go | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/control/cmd/control/main.go b/control/cmd/control/main.go index 8873c653d5..3a589fa21e 100644 --- a/control/cmd/control/main.go +++ b/control/cmd/control/main.go @@ -200,6 +200,8 @@ func realMain(ctx context.Context) error { return err } + // FIXME: readability would be improved if we could be consistent with address + // representations in NetworkConfig (string or cooked, chose one). nc := infraenv.NetworkConfig{ IA: topo.IA(), // Public: (Historical name) The TCP/IP:port address for the control service. diff --git a/private/app/appnet/infraenv.go b/private/app/appnet/infraenv.go index 4cfb3d9c10..bb3eebeab9 100644 --- a/private/app/appnet/infraenv.go +++ b/private/app/appnet/infraenv.go @@ -107,6 +107,14 @@ func (nc *NetworkConfig) QUICStack() (*QUICStack, error) { if nc.QUIC.Address == "" { nc.QUIC.Address = net.JoinHostPort(nc.Public.IP.String(), "0") } + if nc.ServiceResolution == nil { + srAddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(nc.Public.IP.String(), "0")) + if err != nil { + return nil, serrors.WrapStr("parsing service_resolution QUIC address", err) + } + nc.ServiceResolution = srAddr + } + client, server, err := nc.initQUICSockets() if err != nil { return nil, err @@ -268,9 +276,11 @@ func (nc *NetworkConfig) initSvcRedirect(quicAddress string) (func(), error) { Dispatcher: packetDispatcher, Metrics: nc.SCIONNetworkMetrics, } + conn, err := network.Listen(context.Background(), "udp", nc.ServiceResolution, addr.SvcWildcard) if err != nil { - return nil, serrors.WrapStr("listening on SCION", err, "addr", nc.Public) + log.Info("Listen failed", "err", err) + return nil, serrors.WrapStr("listening on SCION", err, "addr", nc.ServiceResolution) } ctx, cancel := context.WithCancel(context.Background()) From b0983d836fb02e58b274020404f60a106b4a4267 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Mon, 21 Aug 2023 11:25:42 +0200 Subject: [PATCH 12/33] hidden_paths: satisfy lint's formatting preferences. --- private/app/appnet/addr_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/private/app/appnet/addr_test.go b/private/app/appnet/addr_test.go index 3872efe10d..ac913ba0ad 100644 --- a/private/app/appnet/addr_test.go +++ b/private/app/appnet/addr_test.go @@ -280,10 +280,10 @@ func TestBuildFullAddress(t *testing.T) { a, err := aw.BuildFullAddress(context.Background(), input) want := &snet.SVCAddr{ - IA: localIA, + IA: localIA, NextHop: underlayAddr, - SVC: addr.SvcCS, - Path: snetpath.Empty{}, + SVC: addr.SvcCS, + Path: snetpath.Empty{}, } assert.Equal(t, want, a) assert.NoError(t, err) From 814522f1a25a5925742eac29276ea524e21206e4 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Tue, 22 Aug 2023 14:50:56 +0200 Subject: [PATCH 13/33] hidden_paths: Simplifications - the Resolver address now always has a dynamic port. Doing this allows the CS's SCION address to have the same host/port as the CS's public address (by default) instead of being dynamic. This in turn makes it discoverable, which allows the hidden path registry to be reachable. This approach allows the topology file to declare the hidden_path registry address to be obviously identical to the address configured for the CS... much less confusing. --- control/cmd/control/main.go | 8 +++--- doc/hidden-paths.rst | 47 ++++++++++++++++++++++++++++++--- private/app/appnet/infraenv.go | 17 ++++++------ private/topology/interface.go | 21 +++------------ private/topology/json/json.go | 1 - private/topology/reload.go | 7 ----- private/topology/servicetype.go | 3 --- private/topology/topology.go | 11 +------- 8 files changed, 58 insertions(+), 57 deletions(-) diff --git a/control/cmd/control/main.go b/control/cmd/control/main.go index 3a589fa21e..146bedc52f 100644 --- a/control/cmd/control/main.go +++ b/control/cmd/control/main.go @@ -208,13 +208,11 @@ func realMain(ctx context.Context) error { Public: topo.ControlServiceAddress(globalCfg.General.ID), // ServiceResolution: The UDP/SCION address of the service "redirector". // It is hosted as a separate service. - ServiceResolution: topo.ServiceResolutionAddress(globalCfg.General.ID), ReconnectToDispatcher: globalCfg.General.ReconnectToDispatcher, QUIC: infraenv.QUIC{ - // Address: the QUIC/SCION address of this service. See QUICStack() - // for how the address is assigned. This can be configured - // statically and can be identical to the Public address. - // If not configured: a dynamic port is assigned. + // Address: the QUIC/SCION address of this service. If not + // configured, QUICStack() uses the same IP and port as + // for the public address. Address: globalCfg.QUIC.Address, TLSVerifier: trust.NewTLSCryptoVerifier(trustDB), GetCertificate: cs.NewTLSCertificateLoader( diff --git a/doc/hidden-paths.rst b/doc/hidden-paths.rst index 2df2951a00..4a24fd1aa4 100644 --- a/doc/hidden-paths.rst +++ b/doc/hidden-paths.rst @@ -325,18 +325,57 @@ Everything combined the path lookup looks as follows: Hidden segment service discovery -------------------------------- -Hidden segment services in remote ASes can be queried for hidden segment -services. The hidden segment services are build into the control service -and share the same address, so they can be connected to by dialing the -'CS' service address directly. The reply of the discovery contains a list of +Hidden segment services in remote ASes can be discovered via a hidden segment +service discovery. Similar to the gateway discovery an initial UDP roundtrip is +done to find the discovery service. The discovery service can then be queried +for hidden segment services. The reply of the discovery contains a list of hidden segment lookup services and a list of hidden segment registration services. +To make the information of what hidden segment services exist in an AS available +to the discovery service, the servers that run hidden segment services must +register in the topology file: + +- Servers that run the hidden segment lookup service must be listed as + ``hidden_segment_lookup_service``. + +- Servers that run the hidden segment registration service must be listed as + ``hidden_segment_registration_service``. + Note that having access control on the hidden segment discovery service is not strictly required, since even if someone can get access to the endpoints, which service hidden segment infrastructure, the services themselves must verify that only authorized parties read or write hidden segment data. +Discovery service gRPC definition +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: protobuf + + service DiscoveryService { + // Return the remote hidden segment services. + rpc HiddenSegmentServices(HiddenSegmentServicesRequest) returns (HiddenSegmentServicesResponse) {} + } + + message HiddenSegmentServicesRequest {} + + message HiddenSegmentServicesResponse { + // The list of lookup service instances. + repeated HiddenSegmentLookupServer lookup = 1; + // The list of registration service instances. + repeated HiddenSegmentRegistrationServer registration = 2; + } + + message HiddenSegmentLookupServer { + // The address of a hidden segment lookup service instance. + string address = 1; + } + + message HiddenSegmentRegistrationServer { + // The address of a hidden segment registration service instance. + string address = 1; + } + Security -------- diff --git a/private/app/appnet/infraenv.go b/private/app/appnet/infraenv.go index bb3eebeab9..852a7663b9 100644 --- a/private/app/appnet/infraenv.go +++ b/private/app/appnet/infraenv.go @@ -105,14 +105,7 @@ func (nc *NetworkConfig) TCPStack() (net.Listener, error) { func (nc *NetworkConfig) QUICStack() (*QUICStack, error) { if nc.QUIC.Address == "" { - nc.QUIC.Address = net.JoinHostPort(nc.Public.IP.String(), "0") - } - if nc.ServiceResolution == nil { - srAddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(nc.Public.IP.String(), "0")) - if err != nil { - return nil, serrors.WrapStr("parsing service_resolution QUIC address", err) - } - nc.ServiceResolution = srAddr + nc.QUIC.Address = nc.Public.String() } client, server, err := nc.initQUICSockets() @@ -277,7 +270,13 @@ func (nc *NetworkConfig) initSvcRedirect(quicAddress string) (func(), error) { Metrics: nc.SCIONNetworkMetrics, } - conn, err := network.Listen(context.Background(), "udp", nc.ServiceResolution, addr.SvcWildcard) + // The service resolution address has a dynamic port. The port isn't used but for + // some reason the dispatcher wants one (and it must be unique too). + srAddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(nc.Public.IP.String(), "0")) + if err != nil { + return nil, serrors.WrapStr("parsing service_resolution QUIC address", err) + } + conn, err := network.Listen(context.Background(), "udp", srAddr, addr.SvcWildcard) if err != nil { log.Info("Listen failed", "err", err) return nil, serrors.WrapStr("listening on SCION", err, "addr", nc.ServiceResolution) diff --git a/private/topology/interface.go b/private/topology/interface.go index c375696bbe..f6440c1770 100644 --- a/private/topology/interface.go +++ b/private/topology/interface.go @@ -41,23 +41,16 @@ type Topology interface { // InterfaceIDs returns all interface IDS from the local AS. InterfaceIDs() []common.IFIDType - // PublicAddress gets the public address of a server with the requested type and - // name, and nil if no such server exists. The service type is specified as a - // addr.SVC and retricted to addr.SvcDS and addr.SvcCS. + // PublicAddress gets the public address of a server with the requested type and name, and nil + // if no such server exists. PublicAddress(svc addr.SVC, name string) *net.UDPAddr - // PublicAddressByType gets the public address of a server with the requested type - // and name, and nil if no such server exists. This support more types than - // PublicAddress. That is, all the types specified by topology.ServiceType. - PublicAddressByType(svc ServiceType, name string) *net.UDPAddr - // Anycast returns the address for an arbitrary server of the requested type. Anycast(svc addr.SVC) (*net.UDPAddr, error) // Multicast returns all addresses for the requested type. Multicast(svc addr.SVC) ([]*net.UDPAddr, error) - // UnderlayAnycast returns the underlay address for an arbitrary server of the - // requested type. + // UnderlayAnycast returns the underlay address for an arbitrary server of the requested type. UnderlayAnycast(svc addr.SVC) (*net.UDPAddr, error) // UnderlayMulticast returns all underlay addresses for the requested type. UnderlayMulticast(svc addr.SVC) ([]*net.UDPAddr, error) @@ -210,14 +203,6 @@ func (t *topologyS) BR(name string) (BRInfo, bool) { return br, ok } -func (t *topologyS) PublicAddressByType(svc ServiceType, name string) *net.UDPAddr { - topoAddr, err := t.Topology.GetTopoAddr(name, svc) - if err != nil { - return nil - } - return topoAddr.SCIONAddress -} - func (t *topologyS) PublicAddress(svc addr.SVC, name string) *net.UDPAddr { topoAddr := t.topoAddress(svc, name) if topoAddr == nil { diff --git a/private/topology/json/json.go b/private/topology/json/json.go index 1f231b53cb..08e7cf333d 100644 --- a/private/topology/json/json.go +++ b/private/topology/json/json.go @@ -83,7 +83,6 @@ type Topology struct { HiddenSegmentLookup map[string]*ServerInfo `json:"hidden_segment_lookup_service,omitempty"` HiddenSegmentReg map[string]*ServerInfo `json:"hidden_segment_registration_service,omitempty"` SIG map[string]*GatewayInfo `json:"sigs,omitempty"` - ServiceResolution map[string]*ServerInfo `json:"service_resolution,omitempty"` } // ServerInfo contains the information for a SCION application running in the local AS. diff --git a/private/topology/reload.go b/private/topology/reload.go index 1436704d22..74f974681f 100644 --- a/private/topology/reload.go +++ b/private/topology/reload.go @@ -167,13 +167,6 @@ func (l *Loader) ControlServiceAddress(id string) *net.UDPAddr { return l.topo.PublicAddress(addr.SvcCS, id) } -func (l *Loader) ServiceResolutionAddress(id string) *net.UDPAddr { - l.mtx.Lock() - defer l.mtx.Unlock() - - return l.topo.PublicAddressByType(ServiceResolution, id) -} - // TODO(lukedirtwalker): remove error and simplify struct in the return type. func (l *Loader) Gateways() ([]GatewayInfo, error) { l.mtx.Lock() diff --git a/private/topology/servicetype.go b/private/topology/servicetype.go index acf80ccf60..bdfa9b21c6 100644 --- a/private/topology/servicetype.go +++ b/private/topology/servicetype.go @@ -28,7 +28,6 @@ const ( Gateway HiddenSegmentLookup HiddenSegmentRegistration - ServiceResolution ) func (t ServiceType) String() string { @@ -65,8 +64,6 @@ func ServiceTypeFromString(s string) ServiceType { return HiddenSegmentLookup case "hiddensegmentregistration": return HiddenSegmentRegistration - case "serviceresolution": - return ServiceResolution default: return Unknown } diff --git a/private/topology/topology.go b/private/topology/topology.go index 81372a9e78..56bc023210 100644 --- a/private/topology/topology.go +++ b/private/topology/topology.go @@ -72,7 +72,6 @@ type ( HiddenSegmentLookup IDAddrMap HiddenSegmentRegistration IDAddrMap SIG map[string]GatewayInfo - ServiceResolution IDAddrMap } // GatewayInfo describes a scion gateway. @@ -147,7 +146,6 @@ func NewRWTopology() *RWTopology { HiddenSegmentRegistration: make(IDAddrMap), SIG: make(map[string]GatewayInfo), IFInfoMap: make(IfInfoMap), - ServiceResolution: make(IDAddrMap), } } @@ -311,10 +309,6 @@ func (t *RWTopology) populateServices(raw *jsontopo.Topology) error { if err != nil { return serrors.WrapStr("unable to extract hidden segment registration address", err) } - t.ServiceResolution, err = svcMapFromRaw(raw.ServiceResolution) - if err != nil { - return serrors.WrapStr("unable to extract service resolution address", err) - } return nil } @@ -369,8 +363,6 @@ func (t *RWTopology) getSvcInfo(svc ServiceType) (*svcInfo, error) { m[k] = *v.CtrlAddr } return &svcInfo{idTopoAddrMap: m}, nil - case ServiceResolution: - return &svcInfo{idTopoAddrMap: t.ServiceResolution}, nil default: return nil, serrors.New("unsupported service type", "type", svc) } @@ -393,10 +385,9 @@ func (t *RWTopology) Copy() *RWTopology { CS: t.CS.copy(), DS: t.DS.copy(), + SIG: copySIGMap(t.SIG), HiddenSegmentLookup: t.HiddenSegmentLookup.copy(), HiddenSegmentRegistration: t.HiddenSegmentRegistration.copy(), - SIG: copySIGMap(t.SIG), - ServiceResolution: t.ServiceResolution.copy(), } } From 189b687a0be46a90dd0f73953f3babc0c9aa8ae5 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Tue, 22 Aug 2023 14:58:58 +0200 Subject: [PATCH 14/33] hidden_paths: removed abadonned change. The ServiceResolution address doesn't need to be configurable. --- private/app/appnet/infraenv.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/private/app/appnet/infraenv.go b/private/app/appnet/infraenv.go index 852a7663b9..72483b49f4 100644 --- a/private/app/appnet/infraenv.go +++ b/private/app/appnet/infraenv.go @@ -64,8 +64,6 @@ type NetworkConfig struct { // Public is the Internet-reachable address in the case where the service // is behind NAT. Public *net.UDPAddr - // ServiceResolution is the address of the service resolver. - ServiceResolution *net.UDPAddr // ReconnectToDispatcher sets up sockets that automatically reconnect if // the dispatcher closes the connection (e.g., if the dispatcher goes // down). From 5b70948eb3ecfd10d4c6546c919680cf7b03a883 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Tue, 22 Aug 2023 15:12:36 +0200 Subject: [PATCH 15/33] hidden_paths: cleanup another leftover reference to teh service resolution addr. --- private/app/appnet/infraenv.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/private/app/appnet/infraenv.go b/private/app/appnet/infraenv.go index 72483b49f4..a73589f061 100644 --- a/private/app/appnet/infraenv.go +++ b/private/app/appnet/infraenv.go @@ -277,7 +277,7 @@ func (nc *NetworkConfig) initSvcRedirect(quicAddress string) (func(), error) { conn, err := network.Listen(context.Background(), "udp", srAddr, addr.SvcWildcard) if err != nil { log.Info("Listen failed", "err", err) - return nil, serrors.WrapStr("listening on SCION", err, "addr", nc.ServiceResolution) + return nil, serrors.WrapStr("listening on SCION", err, "addr", srAddr) } ctx, cancel := context.WithCancel(context.Background()) From da7ab4fb8f7cfdc664edf02a8fe5996c8e6df3d0 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Tue, 22 Aug 2023 15:25:35 +0200 Subject: [PATCH 16/33] hidden_paths: revert mocks for abandonned code. --- private/topology/mock_topology/mock.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/private/topology/mock_topology/mock.go b/private/topology/mock_topology/mock.go index 6fdadf2281..2c33bb48b2 100644 --- a/private/topology/mock_topology/mock.go +++ b/private/topology/mock_topology/mock.go @@ -210,20 +210,6 @@ func (mr *MockTopologyMockRecorder) PublicAddress(arg0, arg1 interface{}) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublicAddress", reflect.TypeOf((*MockTopology)(nil).PublicAddress), arg0, arg1) } -// PublicAddressByType mocks base method. -func (m *MockTopology) PublicAddressByType(arg0 topology.ServiceType, arg1 string) *net.UDPAddr { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PublicAddressByType", arg0, arg1) - ret0, _ := ret[0].(*net.UDPAddr) - return ret0 -} - -// PublicAddressByType indicates an expected call of PublicAddressByType. -func (mr *MockTopologyMockRecorder) PublicAddressByType(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublicAddressByType", reflect.TypeOf((*MockTopology)(nil).PublicAddressByType), arg0, arg1) -} - // SVCNames mocks base method. func (m *MockTopology) SVCNames(arg0 addr.SVC) topology.ServiceNames { m.ctrl.T.Helper() From eb032fa553afea5371b532e5c1737049c313ea75 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Tue, 22 Aug 2023 16:54:06 +0200 Subject: [PATCH 17/33] hidden_paths: removed another remnant of ResolutionServiceAddress. --- control/cmd/control/main.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/control/cmd/control/main.go b/control/cmd/control/main.go index 146bedc52f..f1c44d6ac9 100644 --- a/control/cmd/control/main.go +++ b/control/cmd/control/main.go @@ -206,8 +206,6 @@ func realMain(ctx context.Context) error { IA: topo.IA(), // Public: (Historical name) The TCP/IP:port address for the control service. Public: topo.ControlServiceAddress(globalCfg.General.ID), - // ServiceResolution: The UDP/SCION address of the service "redirector". - // It is hosted as a separate service. ReconnectToDispatcher: globalCfg.General.ReconnectToDispatcher, QUIC: infraenv.QUIC{ // Address: the QUIC/SCION address of this service. If not From cdd27dcc91645c6bd39a2f4ad52c484c9af4cb75 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Tue, 22 Aug 2023 18:35:27 +0200 Subject: [PATCH 18/33] hidden_paths: use the new config appraoch in tests - hs services have the same address as cs. --- acceptance/common/scion.py | 18 ++++++++++++++++++ acceptance/hidden_paths/test.py | 19 +++++-------------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/acceptance/common/scion.py b/acceptance/common/scion.py index 9ad00ae034..b6577fadd6 100644 --- a/acceptance/common/scion.py +++ b/acceptance/common/scion.py @@ -69,6 +69,24 @@ def update_json(change_dict: Dict[str, Any], files: LocalPath): json.dump(t, f, indent=2) +def load_from_json(key: str, files: LocalPath) -> Any: + """ Reads the value associated with the given key from the given json files. + + The first value found is returned. + + Args: + key: dot separated path of the JSON key. + files: names of file or files to update. + + Raises: + IOError / FileNotFoundError: File path is not valid + """ + for file in files: + with open(file, "r") as f: + t = json.load(f) + for path, val in t.items(): + return val + class ASList: """ ASList is a list of AS separated by core and non-core ASes. It can be loaded diff --git a/acceptance/hidden_paths/test.py b/acceptance/hidden_paths/test.py index 693bfab6de..14ab86217a 100755 --- a/acceptance/hidden_paths/test.py +++ b/acceptance/hidden_paths/test.py @@ -61,16 +61,6 @@ def setup_prepare(self): "4": "172.20.0.65", "5": "172.20.0.73", } - # XXX(lukedirtwalker): The ports below are the dynamic QUIC server - # ports. Thanks to the docker setup they are setup consistently so we - # can use them. Optimally we would define a static server port inside - # the CS and use that one instead. - control_addresses = { - "2": "172.20.0.51:42768", - "3": "172.20.0.59:42768", - "4": "172.20.0.67:42768", - "5": "172.20.0.75:42768", - } # Each AS participating in hidden paths has their own hidden paths configuration file. hp_configs = { "2": "hp_groups_as2_as5.yml", @@ -93,19 +83,20 @@ def setup_prepare(self): control_path = self.artifacts / "gen" / ("ASff00_0_%s" % as_number) \ / ("%s.toml" % control_id) scion.update_toml({"path.hidden_paths_cfg": hp_config_url}, [control_path]) - scion.update_toml({"quic.address": control_addresses[as_number]}, [control_path]) # For simplicity, expose the services in all hidden paths ASes, # even though some don't need the registration service. as_dir_path = self.artifacts / "gen" / ("ASff00_0_%s" % as_number) + # The hidden_segment services are behind the same server as the control_service. + topology_file = as_dir_path / "topology.json" + control_service_addr = scion.load_from_json('control_service.%s.addr' % control_id, [topology_file]) topology_update = { "hidden_segment_lookup_service.%s.addr" % control_id: - control_addresses[as_number], + control_service_addr, "hidden_segment_registration_service.%s.addr" % control_id: - control_addresses[as_number], + control_service_addr, } - topology_file = as_dir_path / "topology.json" scion.update_json(topology_update, [topology_file]) def setup_start(self): From 4d69965ed31a6600aa16667d22b32e9cfb095086 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Wed, 23 Aug 2023 12:13:37 +0200 Subject: [PATCH 19/33] hidden_paths: fixed the helper that fetches public addresses from topo. --- acceptance/common/scion.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/acceptance/common/scion.py b/acceptance/common/scion.py index b6577fadd6..0e9c8ee9e6 100644 --- a/acceptance/common/scion.py +++ b/acceptance/common/scion.py @@ -14,7 +14,7 @@ import logging import json -from typing import Any, Dict, List, MutableMapping +from typing import Any, Dict, List, MutableMapping, Mapping import toml import yaml @@ -72,20 +72,24 @@ def update_json(change_dict: Dict[str, Any], files: LocalPath): def load_from_json(key: str, files: LocalPath) -> Any: """ Reads the value associated with the given key from the given json files. - The first value found is returned. + The first value found is returned. If not found, None is returned. Args: key: dot separated path of the JSON key. files: names of file or files to update. + Returns: + The value. None if the path doesn't exist in the dictionary tree. + Raises: IOError / FileNotFoundError: File path is not valid """ for file in files: with open(file, "r") as f: t = json.load(f) - for path, val in t.items(): - return val + v = val_at_path(t, key) + if v != None: + return v class ASList: """ @@ -134,7 +138,17 @@ def path_to_dict(path: str, val: Any) -> Dict: d = {k: d} return d - +def val_at_path(d: Mapping[str, Any], path: str) -> Any: + """ + Walks nested dictionaries by following the given path and returns the value + associated with the leaf key. + """ + v = d + for k in path.split('.'): + v = v.get(k, None) + if not isinstance(v, Mapping): + return v + def merge_dict(change_dict: Dict[str, Any], orig_dict: MutableMapping[str, Any]): """ Merge changes into the original dictionary. Leaf values in the change dict From b79c8d4d2e60af043facbbee9576c308ef768c51 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Wed, 23 Aug 2023 13:20:44 +0200 Subject: [PATCH 20/33] hidden_paths: better comment and remove unnecessary string conversions. --- private/app/appnet/infraenv.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/private/app/appnet/infraenv.go b/private/app/appnet/infraenv.go index a73589f061..6c366c2d11 100644 --- a/private/app/appnet/infraenv.go +++ b/private/app/appnet/infraenv.go @@ -268,12 +268,10 @@ func (nc *NetworkConfig) initSvcRedirect(quicAddress string) (func(), error) { Metrics: nc.SCIONNetworkMetrics, } - // The service resolution address has a dynamic port. The port isn't used but for - // some reason the dispatcher wants one (and it must be unique too). - srAddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(nc.Public.IP.String(), "0")) - if err != nil { - return nil, serrors.WrapStr("parsing service_resolution QUIC address", err) - } + // The service resolution address gets a dynamic port. In reality, neither the + // address nor the port are needed to address the resolver, but the dispatcher still + // requires them and checks unicity. At least a dynamic port is allowed. + srAddr := &net.UDPAddr{IP: nc.Public.IP, Port: 0} conn, err := network.Listen(context.Background(), "udp", srAddr, addr.SvcWildcard) if err != nil { log.Info("Listen failed", "err", err) From 925e9242676314fcccf7be5ac9d5bd9837279ed1 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Wed, 23 Aug 2023 13:22:43 +0200 Subject: [PATCH 21/33] hidden_paths: code formatting. --- acceptance/common/scion.py | 7 +++++-- acceptance/hidden_paths/test.py | 3 ++- control/cmd/control/main.go | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/acceptance/common/scion.py b/acceptance/common/scion.py index 0e9c8ee9e6..b22fabbd84 100644 --- a/acceptance/common/scion.py +++ b/acceptance/common/scion.py @@ -88,9 +88,10 @@ def load_from_json(key: str, files: LocalPath) -> Any: with open(file, "r") as f: t = json.load(f) v = val_at_path(t, key) - if v != None: + if v is not None: return v + class ASList: """ ASList is a list of AS separated by core and non-core ASes. It can be loaded @@ -138,6 +139,7 @@ def path_to_dict(path: str, val: Any) -> Dict: d = {k: d} return d + def val_at_path(d: Mapping[str, Any], path: str) -> Any: """ Walks nested dictionaries by following the given path and returns the value @@ -148,7 +150,8 @@ def val_at_path(d: Mapping[str, Any], path: str) -> Any: v = v.get(k, None) if not isinstance(v, Mapping): return v - + + def merge_dict(change_dict: Dict[str, Any], orig_dict: MutableMapping[str, Any]): """ Merge changes into the original dictionary. Leaf values in the change dict diff --git a/acceptance/hidden_paths/test.py b/acceptance/hidden_paths/test.py index 14ab86217a..3a9f1af7f9 100755 --- a/acceptance/hidden_paths/test.py +++ b/acceptance/hidden_paths/test.py @@ -90,7 +90,8 @@ def setup_prepare(self): # The hidden_segment services are behind the same server as the control_service. topology_file = as_dir_path / "topology.json" - control_service_addr = scion.load_from_json('control_service.%s.addr' % control_id, [topology_file]) + control_service_addr = scion.load_from_json( + 'control_service.%s.addr' % control_id, [topology_file]) topology_update = { "hidden_segment_lookup_service.%s.addr" % control_id: control_service_addr, diff --git a/control/cmd/control/main.go b/control/cmd/control/main.go index f1c44d6ac9..9fb6e332d1 100644 --- a/control/cmd/control/main.go +++ b/control/cmd/control/main.go @@ -205,7 +205,7 @@ func realMain(ctx context.Context) error { nc := infraenv.NetworkConfig{ IA: topo.IA(), // Public: (Historical name) The TCP/IP:port address for the control service. - Public: topo.ControlServiceAddress(globalCfg.General.ID), + Public: topo.ControlServiceAddress(globalCfg.General.ID), ReconnectToDispatcher: globalCfg.General.ReconnectToDispatcher, QUIC: infraenv.QUIC{ // Address: the QUIC/SCION address of this service. If not From 8fbea8955009a2f64c3e04e11cd7982cb9b316af Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Wed, 23 Aug 2023 15:34:07 +0200 Subject: [PATCH 22/33] hidden_paths: Simplified some more. Got rid of the IntraASTCPServer for the hidden segment service. It's not needed. The local optimization has low value and won't be done at this time if ever. --- control/hiddenpaths.go | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/control/hiddenpaths.go b/control/hiddenpaths.go index b885cafc52..299d265871 100644 --- a/control/hiddenpaths.go +++ b/control/hiddenpaths.go @@ -80,31 +80,27 @@ func (c HiddenPathConfigurator) Setup(location string) (*HiddenPathRegistrationC }) if roles.Registry { log.Info("Starting hidden path authoritative and registration server") - hsSegmentService := &hpgrpc.AuthoritativeSegmentServer{ - Lookup: c.localAuthServer(groups), - Verifier: c.Verifier, - } - hspb.RegisterAuthoritativeHiddenSegmentLookupServiceServer( - c.InterASQUICServer, hsSegmentService) - hspb.RegisterAuthoritativeHiddenSegmentLookupServiceServer( - c.IntraASTCPServer, hsSegmentService) - hsRegistrationService := &hpgrpc.RegistrationServer{ - Registry: hiddenpath.RegistryServer{ - Groups: groups, - DB: &hiddenpath.Storer{ - DB: c.PathDB, - }, - Verifier: hiddenpath.VerifierAdapter{ - Verifier: c.Verifier, + hspb.RegisterAuthoritativeHiddenSegmentLookupServiceServer(c.InterASQUICServer, + &hpgrpc.AuthoritativeSegmentServer{ + Lookup: c.localAuthServer(groups), + Verifier: c.Verifier, + }, + ) + hspb.RegisterHiddenSegmentRegistrationServiceServer(c.InterASQUICServer, + &hpgrpc.RegistrationServer{ + Registry: hiddenpath.RegistryServer{ + Groups: groups, + DB: &hiddenpath.Storer{ + DB: c.PathDB, + }, + Verifier: hiddenpath.VerifierAdapter{ + Verifier: c.Verifier, + }, + LocalIA: c.LocalIA, }, - LocalIA: c.LocalIA, + Verifier: c.Verifier, }, - Verifier: c.Verifier, - } - hspb.RegisterHiddenSegmentRegistrationServiceServer( - c.InterASQUICServer, hsRegistrationService) - hspb.RegisterHiddenSegmentRegistrationServiceServer( - c.IntraASTCPServer, hsRegistrationService) + ) } if !roles.Writer { return nil, nil From 5376bc4b66b5d5c9ee86a9612ec62c1fe08d3868 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Thu, 24 Aug 2023 16:40:01 +0200 Subject: [PATCH 23/33] hidden_paths: Ensure that intraAS paths have metadata. This avoids the need for special behavior to handle nil metadata in a few places. --- control/cmd/control/main.go | 1 + pkg/snet/path/BUILD.bazel | 1 + pkg/snet/path/intraAS.go | 55 ++++++++++++++++++++++++++++++++++ pkg/snet/router.go | 13 -------- private/app/appnet/infraenv.go | 5 +++- 5 files changed, 61 insertions(+), 14 deletions(-) create mode 100644 pkg/snet/path/intraAS.go diff --git a/control/cmd/control/main.go b/control/cmd/control/main.go index 9fb6e332d1..24418ea0d1 100644 --- a/control/cmd/control/main.go +++ b/control/cmd/control/main.go @@ -227,6 +227,7 @@ func realMain(ctx context.Context) error { }, SCIONNetworkMetrics: metrics.SCIONNetworkMetrics, SCIONPacketConnMetrics: metrics.SCIONPacketConnMetrics, + MTU: topo.MTU(), } quicStack, err := nc.QUICStack() if err != nil { diff --git a/pkg/snet/path/BUILD.bazel b/pkg/snet/path/BUILD.bazel index 351e08c2e3..1ce7121424 100644 --- a/pkg/snet/path/BUILD.bazel +++ b/pkg/snet/path/BUILD.bazel @@ -5,6 +5,7 @@ go_library( srcs = [ "empty.go", "epic.go", + "intraAS.go", "onehop.go", "path.go", "scion.go", diff --git a/pkg/snet/path/intraAS.go b/pkg/snet/path/intraAS.go new file mode 100644 index 0000000000..eb344f202b --- /dev/null +++ b/pkg/snet/path/intraAS.go @@ -0,0 +1,55 @@ +// Copyright 2020 ETH Zurich +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License 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 path implements snet.Path with full metadata +// This is used by libraries that provide paths for applications to use, such +// as the path combinator and the SCION Daemon API. Applications using snet will not +// usually make use of this package directly. +// +// This component implements a path querier that returns only paths +// within the local AS in the form of a standard Path with metadata +// but zero hops. + +package path + +import ( + "context" + "time" + + "github.com/scionproto/scion/pkg/addr" + rawpath "github.com/scionproto/scion/pkg/slayers/path" + "github.com/scionproto/scion/pkg/snet" +) + + +// IntraASPathQuerier implements the PathQuerier interface. It will only provide +// AS internal paths, i.e., empty paths with only the IA as destination. This +// should only be used in places where you know that you only need to +// communicate inside the AS. +type IntraASPathQuerier struct { + IA addr.IA + MTU uint16 +} + +// Query implements PathQuerier. +func (q IntraASPathQuerier) Query(_ context.Context, _ addr.IA) ([]snet.Path, error) { + return []snet.Path{Path{ + Src: q.IA, + Dst: q.IA, + Meta: snet.PathMetadata{ + MTU: q.MTU, + Expiry: time.Now().Add(rawpath.MaxTTL * time.Second), + }, + }}, nil +} diff --git a/pkg/snet/router.go b/pkg/snet/router.go index f763a529ba..a11f78c1a7 100644 --- a/pkg/snet/router.go +++ b/pkg/snet/router.go @@ -55,16 +55,3 @@ func (r *BaseRouter) Route(ctx context.Context, dst addr.IA) (Path, error) { func (r *BaseRouter) AllRoutes(ctx context.Context, dst addr.IA) ([]Path, error) { return r.Querier.Query(ctx, dst) } - -// IntraASPathQuerier implements the PathQuerier interface. It will only provide -// AS internal paths, i.e., empty paths with only the IA as destination. This -// should only be used in places where you know that you only need to -// communicate inside the AS. -type IntraASPathQuerier struct { - IA addr.IA -} - -// Query implements PathQuerier. -func (q IntraASPathQuerier) Query(_ context.Context, _ addr.IA) ([]Path, error) { - return []Path{&partialPath{source: q.IA, destination: q.IA}}, nil -} diff --git a/private/app/appnet/infraenv.go b/private/app/appnet/infraenv.go index 6c366c2d11..659e9816ae 100644 --- a/private/app/appnet/infraenv.go +++ b/private/app/appnet/infraenv.go @@ -38,6 +38,7 @@ import ( "github.com/scionproto/scion/pkg/log" "github.com/scionproto/scion/pkg/private/serrors" "github.com/scionproto/scion/pkg/snet" + "github.com/scionproto/scion/pkg/snet/path" "github.com/scionproto/scion/pkg/snet/squic" "github.com/scionproto/scion/pkg/sock/reliable" "github.com/scionproto/scion/pkg/sock/reliable/reconnect" @@ -83,6 +84,8 @@ type NetworkConfig struct { SCIONNetworkMetrics snet.SCIONNetworkMetrics // Metrics injected into DefaultPacketDispatcherService. SCIONPacketConnMetrics snet.SCIONPacketConnMetrics + // MTU of the local AS + MTU uint16 } // QUICStack contains everything to run a QUIC based RPC stack. @@ -222,7 +225,7 @@ func (nc *NetworkConfig) AddressRewriter( } } return &AddressRewriter{ - Router: &snet.BaseRouter{Querier: snet.IntraASPathQuerier{IA: nc.IA}}, + Router: &snet.BaseRouter{Querier: path.IntraASPathQuerier{IA: nc.IA, MTU: nc.MTU}}, SVCRouter: nc.SVCResolver, Resolver: &svc.Resolver{ LocalIA: nc.IA, From 59e9b6c3412cd1dcfc8fa872e3b43376758f1a50 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Thu, 24 Aug 2023 17:00:19 +0200 Subject: [PATCH 24/33] hidden_paths: remove the Interfaces method from the Path interface. This method isn't useful anymore. All paths which metadata gets used now have real metadata. --- pkg/snet/path.go | 9 --------- pkg/snet/path/path.go | 4 ---- private/app/appnet/addr.go | 2 +- private/app/appnet/addr_test.go | 20 +++++++++----------- 4 files changed, 10 insertions(+), 25 deletions(-) diff --git a/pkg/snet/path.go b/pkg/snet/path.go index 60084df487..1a19ad5760 100644 --- a/pkg/snet/path.go +++ b/pkg/snet/path.go @@ -65,11 +65,6 @@ type Path interface { // Metadata returns supplementary information about this path. // Returns nil if the metadata is not available. Metadata() *PathMetadata - // Interfaces returns Metada().Interfaces() if the underlying implementation supports it - // Else returns nil. The difference between calling this and accessing Metadata().Interfaces is - // that there is no need to check if Metadata() is nil. An alternative could be to have an - // Interfaces() method to PathMetadata that accepts nil, and to call that instead. - Interfaces() []PathInterface } // PathInterface is an interface of the path. @@ -254,10 +249,6 @@ func (p *partialPath) Dataplane() DataplanePath { return p.dataplane } -func (p *partialPath) Interfaces() []PathInterface { - return nil -} - func (p *partialPath) Source() addr.IA { return p.source } diff --git a/pkg/snet/path/path.go b/pkg/snet/path/path.go index afb25b073d..08748964d9 100644 --- a/pkg/snet/path/path.go +++ b/pkg/snet/path/path.go @@ -65,10 +65,6 @@ func (p Path) Metadata() *snet.PathMetadata { return p.Meta.Copy() } -func (p Path) Interfaces() []snet.PathInterface { - return p.Meta.Interfaces -} - func (p Path) String() string { hops := fmtInterfaces(p.Meta.Interfaces) return fmt.Sprintf("Hops: [%s] MTU: %d NextHop: %s", diff --git a/private/app/appnet/addr.go b/private/app/appnet/addr.go index 67f60d0bed..2d5514c40b 100644 --- a/private/app/appnet/addr.go +++ b/private/app/appnet/addr.go @@ -155,7 +155,7 @@ func (r AddressRewriter) buildFullAddress(ctx context.Context, ret.NextHop = p.UnderlayNextHop() // SVC addresses in the local AS get resolved via topology lookup - if len(p.Interfaces()) == 0 { //when local AS + if len(p.Metadata().Interfaces) == 0 { //when local AS ov, err := r.SVCRouter.GetUnderlay(s.SVC) if err != nil { return nil, serrors.WrapStr("Unable to resolve underlay", err) diff --git a/private/app/appnet/addr_test.go b/private/app/appnet/addr_test.go index ac913ba0ad..66dadebb63 100644 --- a/private/app/appnet/addr_test.go +++ b/private/app/appnet/addr_test.go @@ -97,8 +97,9 @@ func TestRedirectQUIC(t *testing.T) { router.EXPECT().Route(gomock.Any(), gomock.Any()).Return(path, nil) path.EXPECT().Dataplane().Return(snetpath.SCION{}) path.EXPECT().UnderlayNextHop().Return(&net.UDPAddr{IP: net.ParseIP("10.1.1.1")}) - path.EXPECT().Interfaces().Return(make([]snet.PathInterface, 1)) // just non-empty - + path.EXPECT().Metadata().Return(&snet.PathMetadata{ + Interfaces: make([]snet.PathInterface, 1), // just non-empty + }) aw := infraenv.AddressRewriter{ Router: router, Resolver: resolver, @@ -132,8 +133,9 @@ func TestRedirectQUIC(t *testing.T) { router.EXPECT().Route(gomock.Any(), gomock.Any()).Return(path, nil) path.EXPECT().Dataplane().Return(snetpath.SCION{}) path.EXPECT().UnderlayNextHop().Return(&net.UDPAddr{IP: net.ParseIP("10.1.1.1")}) - path.EXPECT().Interfaces().Return(make([]snet.PathInterface, 1)) // just non-empty - + path.EXPECT().Metadata().Return(&snet.PathMetadata{ + Interfaces: make([]snet.PathInterface, 1), // just non-empty + }) aw := infraenv.AddressRewriter{ Router: router, Resolver: resolver, @@ -162,7 +164,7 @@ func TestRedirectQUIC(t *testing.T) { router.EXPECT().Route(gomock.Any(), gomock.Any()).Return(path, nil) path.EXPECT().Dataplane().Return(snetpath.SCION{}) path.EXPECT().UnderlayNextHop().Return(&net.UDPAddr{IP: net.ParseIP("10.1.1.1")}) - path.EXPECT().Interfaces().Return([]snet.PathInterface{}) + path.EXPECT().Metadata().Return(&snet.PathMetadata{}) svcRouter := mock_infraenv.NewMockSVCResolver(ctrl) svcRouter.EXPECT().GetUnderlay(addr.SvcCS).Return( &net.UDPAddr{IP: net.ParseIP("10.1.1.1")}, nil, @@ -271,7 +273,7 @@ func TestBuildFullAddress(t *testing.T) { svcRouter.EXPECT().GetUnderlay(addr.SvcCS).Return(underlayAddr, nil) path := mock_snet.NewMockPath(ctrl) - path.EXPECT().Interfaces().Return([]snet.PathInterface{}) + path.EXPECT().Metadata().Return(&snet.PathMetadata{}) path.EXPECT().Dataplane() path.EXPECT().UnderlayNextHop() router.EXPECT().Route(gomock.Any(), gomock.Any()).Return(path, nil) @@ -303,7 +305,7 @@ func TestBuildFullAddress(t *testing.T) { svcRouter.EXPECT().GetUnderlay(addr.SvcCS).Return(nil, errors.New("err")) path := mock_snet.NewMockPath(ctrl) - path.EXPECT().Interfaces().Return([]snet.PathInterface{}) + path.EXPECT().Metadata().Return(&snet.PathMetadata{}) path.EXPECT().Dataplane() path.EXPECT().UnderlayNextHop() router.EXPECT().Route(gomock.Any(), gomock.Any()).Return(path, nil) @@ -480,10 +482,6 @@ func (t *testPath) Metadata() *snet.PathMetadata { panic("not implemented") } -func (t *testPath) Interfaces() []snet.PathInterface { - panic("not implemented") -} - func (t *testPath) Copy() snet.Path { panic("not implemented") } From 9f9d418af5b1f6268ec4da32dad1d5a5386a5b46 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Thu, 24 Aug 2023 17:15:30 +0200 Subject: [PATCH 25/33] hidden_paths: fix docstring. --- acceptance/common/scion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acceptance/common/scion.py b/acceptance/common/scion.py index b22fabbd84..c330fb20c3 100644 --- a/acceptance/common/scion.py +++ b/acceptance/common/scion.py @@ -76,7 +76,7 @@ def load_from_json(key: str, files: LocalPath) -> Any: Args: key: dot separated path of the JSON key. - files: names of file or files to update. + files: names of file or files to read. Returns: The value. None if the path doesn't exist in the dictionary tree. From 625def5dc539b73566c613edcfb7e5c64a15bdb0 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Thu, 24 Aug 2023 17:16:00 +0200 Subject: [PATCH 26/33] hidden_paths: removed leftover reference to Interfaces(). --- private/app/appnet/addr_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/private/app/appnet/addr_test.go b/private/app/appnet/addr_test.go index 66dadebb63..df0ea79466 100644 --- a/private/app/appnet/addr_test.go +++ b/private/app/appnet/addr_test.go @@ -241,7 +241,9 @@ func TestBuildFullAddress(t *testing.T) { path := mock_snet.NewMockPath(ctrl) path.EXPECT().Dataplane().Return(snetpath.SCION{}) path.EXPECT().UnderlayNextHop().Return(&net.UDPAddr{}) - path.EXPECT().Interfaces().Return(make([]snet.PathInterface, 1)) // just non-empty + path.EXPECT().Metadata().Return(&snet.PathMetadata{ + Interfaces: make([]snet.PathInterface, 1), // just non-empty + }) router.EXPECT().Route(gomock.Any(), gomock.Any()).Return(path, nil) input := &snet.SVCAddr{IA: remoteIA, SVC: addr.SvcCS, Path: snetpath.Empty{}} a, err := aw.BuildFullAddress(context.Background(), input) From 4fda540fa575abf6693e8908f3b668ef21825dbd Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Thu, 24 Aug 2023 17:33:08 +0200 Subject: [PATCH 27/33] hidden_paths: update mocks. --- pkg/snet/mock_snet/mock.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/pkg/snet/mock_snet/mock.go b/pkg/snet/mock_snet/mock.go index d230c0930c..181ac9a929 100644 --- a/pkg/snet/mock_snet/mock.go +++ b/pkg/snet/mock_snet/mock.go @@ -266,20 +266,6 @@ func (mr *MockPathMockRecorder) Destination() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Destination", reflect.TypeOf((*MockPath)(nil).Destination)) } -// Interfaces mocks base method. -func (m *MockPath) Interfaces() []snet.PathInterface { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Interfaces") - ret0, _ := ret[0].([]snet.PathInterface) - return ret0 -} - -// Interfaces indicates an expected call of Interfaces. -func (mr *MockPathMockRecorder) Interfaces() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Interfaces", reflect.TypeOf((*MockPath)(nil).Interfaces)) -} - // Metadata mocks base method. func (m *MockPath) Metadata() *snet.PathMetadata { m.ctrl.T.Helper() From ac87cde8b83479e70d9bbb1edfa8e45f6d5ee275 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Thu, 24 Aug 2023 17:43:39 +0200 Subject: [PATCH 28/33] hidden_paths: fix formatting. --- pkg/snet/path/intraAS.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/snet/path/intraAS.go b/pkg/snet/path/intraAS.go index eb344f202b..61c77c402f 100644 --- a/pkg/snet/path/intraAS.go +++ b/pkg/snet/path/intraAS.go @@ -32,7 +32,6 @@ import ( "github.com/scionproto/scion/pkg/snet" ) - // IntraASPathQuerier implements the PathQuerier interface. It will only provide // AS internal paths, i.e., empty paths with only the IA as destination. This // should only be used in places where you know that you only need to From d1e9dbd5bbb1a65c1f635af686442297edab3120 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Thu, 24 Aug 2023 18:21:03 +0200 Subject: [PATCH 29/33] hidden_paths: fix more formatting --- control/cmd/control/main.go | 2 +- private/app/appnet/addr_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/control/cmd/control/main.go b/control/cmd/control/main.go index 24418ea0d1..d5de9e08fb 100644 --- a/control/cmd/control/main.go +++ b/control/cmd/control/main.go @@ -227,7 +227,7 @@ func realMain(ctx context.Context) error { }, SCIONNetworkMetrics: metrics.SCIONNetworkMetrics, SCIONPacketConnMetrics: metrics.SCIONPacketConnMetrics, - MTU: topo.MTU(), + MTU: topo.MTU(), } quicStack, err := nc.QUICStack() if err != nil { diff --git a/private/app/appnet/addr_test.go b/private/app/appnet/addr_test.go index df0ea79466..dd6a009d3d 100644 --- a/private/app/appnet/addr_test.go +++ b/private/app/appnet/addr_test.go @@ -99,7 +99,7 @@ func TestRedirectQUIC(t *testing.T) { path.EXPECT().UnderlayNextHop().Return(&net.UDPAddr{IP: net.ParseIP("10.1.1.1")}) path.EXPECT().Metadata().Return(&snet.PathMetadata{ Interfaces: make([]snet.PathInterface, 1), // just non-empty - }) + }) aw := infraenv.AddressRewriter{ Router: router, Resolver: resolver, @@ -243,7 +243,7 @@ func TestBuildFullAddress(t *testing.T) { path.EXPECT().UnderlayNextHop().Return(&net.UDPAddr{}) path.EXPECT().Metadata().Return(&snet.PathMetadata{ Interfaces: make([]snet.PathInterface, 1), // just non-empty - }) + }) router.EXPECT().Route(gomock.Any(), gomock.Any()).Return(path, nil) input := &snet.SVCAddr{IA: remoteIA, SVC: addr.SvcCS, Path: snetpath.Empty{}} a, err := aw.BuildFullAddress(context.Background(), input) From d7c8d15addd2cbe830b33c876a3a699bbd577c61 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Fri, 25 Aug 2023 10:42:56 +0200 Subject: [PATCH 30/33] hidden_paths: moved intraAS.go to teh appnet pkg. --- pkg/snet/path/BUILD.bazel | 1 - private/app/appnet/BUILD.bazel | 2 ++ private/app/appnet/infraenv.go | 3 +-- .../path => private/app/appnet}/intraAS.go | 19 ++++++------------- 4 files changed, 9 insertions(+), 16 deletions(-) rename {pkg/snet/path => private/app/appnet}/intraAS.go (68%) diff --git a/pkg/snet/path/BUILD.bazel b/pkg/snet/path/BUILD.bazel index 1ce7121424..351e08c2e3 100644 --- a/pkg/snet/path/BUILD.bazel +++ b/pkg/snet/path/BUILD.bazel @@ -5,7 +5,6 @@ go_library( srcs = [ "empty.go", "epic.go", - "intraAS.go", "onehop.go", "path.go", "scion.go", diff --git a/private/app/appnet/BUILD.bazel b/private/app/appnet/BUILD.bazel index a65d75e38d..43a2f28919 100644 --- a/private/app/appnet/BUILD.bazel +++ b/private/app/appnet/BUILD.bazel @@ -5,6 +5,7 @@ go_library( srcs = [ "addr.go", "infraenv.go", + "intraAS.go", ], importpath = "github.com/scionproto/scion/private/app/appnet", visibility = ["//visibility:public"], @@ -13,6 +14,7 @@ go_library( "//pkg/daemon:go_default_library", "//pkg/log:go_default_library", "//pkg/private/serrors:go_default_library", + "//pkg/slayers/path:go_default_library", "//pkg/snet:go_default_library", "//pkg/snet/path:go_default_library", "//pkg/snet/squic:go_default_library", diff --git a/private/app/appnet/infraenv.go b/private/app/appnet/infraenv.go index 659e9816ae..c9fdd7646c 100644 --- a/private/app/appnet/infraenv.go +++ b/private/app/appnet/infraenv.go @@ -38,7 +38,6 @@ import ( "github.com/scionproto/scion/pkg/log" "github.com/scionproto/scion/pkg/private/serrors" "github.com/scionproto/scion/pkg/snet" - "github.com/scionproto/scion/pkg/snet/path" "github.com/scionproto/scion/pkg/snet/squic" "github.com/scionproto/scion/pkg/sock/reliable" "github.com/scionproto/scion/pkg/sock/reliable/reconnect" @@ -225,7 +224,7 @@ func (nc *NetworkConfig) AddressRewriter( } } return &AddressRewriter{ - Router: &snet.BaseRouter{Querier: path.IntraASPathQuerier{IA: nc.IA, MTU: nc.MTU}}, + Router: &snet.BaseRouter{Querier: IntraASPathQuerier{IA: nc.IA, MTU: nc.MTU}}, SVCRouter: nc.SVCResolver, Resolver: &svc.Resolver{ LocalIA: nc.IA, diff --git a/pkg/snet/path/intraAS.go b/private/app/appnet/intraAS.go similarity index 68% rename from pkg/snet/path/intraAS.go rename to private/app/appnet/intraAS.go index 61c77c402f..e126f9c561 100644 --- a/pkg/snet/path/intraAS.go +++ b/private/app/appnet/intraAS.go @@ -12,16 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package path implements snet.Path with full metadata -// This is used by libraries that provide paths for applications to use, such -// as the path combinator and the SCION Daemon API. Applications using snet will not -// usually make use of this package directly. -// -// This component implements a path querier that returns only paths -// within the local AS in the form of a standard Path with metadata -// but zero hops. - -package path +package appnet import ( "context" @@ -30,12 +21,14 @@ import ( "github.com/scionproto/scion/pkg/addr" rawpath "github.com/scionproto/scion/pkg/slayers/path" "github.com/scionproto/scion/pkg/snet" + "github.com/scionproto/scion/pkg/snet/path" ) // IntraASPathQuerier implements the PathQuerier interface. It will only provide -// AS internal paths, i.e., empty paths with only the IA as destination. This +// AS-internal paths, i.e., zero-hops paths with only the IA as destination. This // should only be used in places where you know that you only need to -// communicate inside the AS. +// communicate inside the AS. The type of Path returned is a complete +// implementation with proper metadata. type IntraASPathQuerier struct { IA addr.IA MTU uint16 @@ -43,7 +36,7 @@ type IntraASPathQuerier struct { // Query implements PathQuerier. func (q IntraASPathQuerier) Query(_ context.Context, _ addr.IA) ([]snet.Path, error) { - return []snet.Path{Path{ + return []snet.Path{path.Path{ Src: q.IA, Dst: q.IA, Meta: snet.PathMetadata{ From deed43559a25e3285ff5be41c0bd9157c6256526 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Fri, 25 Aug 2023 11:17:21 +0200 Subject: [PATCH 31/33] hidden_paths: add an empty dataplanePath to intraAS paths so they are truly complete and safe to use. --- private/app/appnet/intraAS.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/private/app/appnet/intraAS.go b/private/app/appnet/intraAS.go index e126f9c561..6735dce534 100644 --- a/private/app/appnet/intraAS.go +++ b/private/app/appnet/intraAS.go @@ -37,8 +37,9 @@ type IntraASPathQuerier struct { // Query implements PathQuerier. func (q IntraASPathQuerier) Query(_ context.Context, _ addr.IA) ([]snet.Path, error) { return []snet.Path{path.Path{ - Src: q.IA, - Dst: q.IA, + Src: q.IA, + Dst: q.IA, + DataplanePath: path.Empty{}, Meta: snet.PathMetadata{ MTU: q.MTU, Expiry: time.Now().Add(rawpath.MaxTTL * time.Second), From 2373845d3620a6dada6e5867a5e40c17dcb32225 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Fri, 25 Aug 2023 11:44:41 +0200 Subject: [PATCH 32/33] hidden_paths: renamed intraAS.go as intra_as.go. --- private/app/appnet/{intraAS.go => intra_as.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename private/app/appnet/{intraAS.go => intra_as.go} (100%) diff --git a/private/app/appnet/intraAS.go b/private/app/appnet/intra_as.go similarity index 100% rename from private/app/appnet/intraAS.go rename to private/app/appnet/intra_as.go From 3e92748c44196a35deb3baa9e9ee0fdb23574739 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Hugly Date: Fri, 25 Aug 2023 12:16:28 +0200 Subject: [PATCH 33/33] hidden_paths: renamed intraAS.go to intra_as.go --- private/app/appnet/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/private/app/appnet/BUILD.bazel b/private/app/appnet/BUILD.bazel index 43a2f28919..68f7650183 100644 --- a/private/app/appnet/BUILD.bazel +++ b/private/app/appnet/BUILD.bazel @@ -5,7 +5,7 @@ go_library( srcs = [ "addr.go", "infraenv.go", - "intraAS.go", + "intra_as.go", ], importpath = "github.com/scionproto/scion/private/app/appnet", visibility = ["//visibility:public"],