Skip to content

Commit

Permalink
modify HP and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
JordiSubira committed Sep 28, 2023
1 parent 102e8a4 commit 1c82e9c
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 54 deletions.
46 changes: 36 additions & 10 deletions control/cmd/control/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -566,16 +566,22 @@ func realMain(ctx context.Context) error {
healthpb.RegisterHealthServer(tcpServer, dsHealth)

hpCfg := cs.HiddenPathConfigurator{
LocalIA: topo.IA(),
Verifier: verifier,
Signer: signer,
PathDB: pathDB,
Dialer: dialer,
FetcherConfig: fetcherCfg,
IntraASTCPServer: tcpServer,
InterASQUICServer: quicServer,
}
hpWriterCfg, err := hpCfg.Setup(globalCfg.PS.HiddenPathsCfg)
LocalIA: topo.IA(),
Verifier: verifier,
Signer: signer,
PathDB: pathDB,
Dialer: dialer,
FetcherConfig: fetcherCfg,
IntraASTCPServer: tcpServer,
}
// (XXX)JordiSubira: We should revisit how we want to handle HP service,
// right now it only seems to be used within the CS. So perhaps we should treat
// it as a part of the CS (same as BS, CertServ, DRKey, etc). For the moment, we
// create a different grpc.Server endpoint that will be located behind a different
// quic socket using the IP:port in the topology.json file. This is required
// because the client side, uses the DS to discover the address of the remote
// HP server, thus it should use whatever is written in the topology file.
hpInterASServer, hpWriterCfg, err := hpCfg.Setup(globalCfg.PS.HiddenPathsCfg)
if err != nil {
return err
}
Expand Down Expand Up @@ -677,6 +683,26 @@ func realMain(ctx context.Context) error {
return nil
})
cleanup.Add(func() error { tcpServer.GracefulStop(); return nil })
if hpInterASServer != nil {
a, err := topo.HiddenSegmentRegistrationAddresses()
if err != nil {
return err
}
if len(a) == 0 {
return serrors.New("Hidden path registration address expected and not found")
}
// XXX(JordiSubira): Just take the first address, we only use topology.json with
// information for one unique AS.
hpListener, err := nc.OpenListener(a[0].String())
g.Go(func() error {
defer log.HandlePanic()
if err := hpInterASServer.Serve(hpListener); err != nil {
return serrors.WrapStr("serving Hidden Path API", err)
}
return nil
})
cleanup.Add(func() error { hpInterASServer.GracefulStop(); return nil })
}

if globalCfg.API.Addr != "" {
r := chi.NewRouter()
Expand Down
68 changes: 38 additions & 30 deletions control/hiddenpaths.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,31 +31,31 @@ import (

// HiddenPathConfigurator can be used to configure the hidden path servers.
type HiddenPathConfigurator struct {
LocalIA addr.IA
Verifier infra.Verifier
Signer hpgrpc.Signer
PathDB pathdb.DB
Dialer libgrpc.Dialer
FetcherConfig segreq.FetcherConfig
IntraASTCPServer *grpc.Server
InterASQUICServer *grpc.Server
LocalIA addr.IA
Verifier infra.Verifier
Signer hpgrpc.Signer
PathDB pathdb.DB
Rewriter libgrpc.AddressRewriter
Dialer libgrpc.Dialer
FetcherConfig segreq.FetcherConfig
IntraASTCPServer *grpc.Server
}

// Setup sets up the hidden paths servers using the configuration at the given
// location. An empty location will not enable any hidden path behavior. It
// returns the configuration for the hidden segment writer. The return value can
// be nil if this AS isn't a writer.
func (c HiddenPathConfigurator) Setup(location string) (*HiddenPathRegistrationCfg, error) {
func (c HiddenPathConfigurator) Setup(location string) (*grpc.Server, *HiddenPathRegistrationCfg, error) {
if location == "" {
return nil, nil
return nil, nil, nil
}
groups, regPolicy, err := hiddenpath.LoadConfiguration(location)
if err != nil {
return nil, err
return nil, nil, err
}
roles := groups.Roles(c.LocalIA)
if roles.None() {
return nil, nil
return nil, nil, nil
}
log.Info("Starting hidden path forward server")
hspb.RegisterHiddenSegmentLookupServiceServer(c.IntraASTCPServer, &hpgrpc.SegmentServer{
Expand All @@ -67,26 +67,33 @@ func (c HiddenPathConfigurator) Setup(location string) (*HiddenPathRegistrationC
Dialer: c.Dialer,
Signer: c.Signer,
},
Resolver: hiddenpath.LookupResolver{
HPResolver: hiddenpath.LookupResolver{
Router: segreq.NewRouter(c.FetcherConfig),
Discoverer: &hpgrpc.Discoverer{
Dialer: c.Dialer,
},
},
CSResolver: hiddenpath.CSResolver{
Router: segreq.NewRouter(c.FetcherConfig),
Rewriter: c.Rewriter,
},
Verifier: hiddenpath.VerifierAdapter{
Verifier: c.Verifier,
},
},
})
var interASServer *grpc.Server
if roles.Registry {
interASServer = grpc.NewServer(
libgrpc.UnaryServerInterceptor(),
)
log.Info("Starting hidden path authoritative and registration server")
hspb.RegisterAuthoritativeHiddenSegmentLookupServiceServer(c.InterASQUICServer,
hspb.RegisterAuthoritativeHiddenSegmentLookupServiceServer(interASServer,
&hpgrpc.AuthoritativeSegmentServer{
Lookup: c.localAuthServer(groups),
Verifier: c.Verifier,
},
)
hspb.RegisterHiddenSegmentRegistrationServiceServer(c.InterASQUICServer,
})
hspb.RegisterHiddenSegmentRegistrationServiceServer(interASServer,
&hpgrpc.RegistrationServer{
Registry: hiddenpath.RegistryServer{
Groups: groups,
Expand All @@ -103,21 +110,22 @@ func (c HiddenPathConfigurator) Setup(location string) (*HiddenPathRegistrationC
)
}
if !roles.Writer {
return nil, nil
return interASServer, nil, nil
}
log.Info("Using hidden path beacon writer")
return &HiddenPathRegistrationCfg{
Policy: regPolicy,
Router: segreq.NewRouter(c.FetcherConfig),
Discoverer: &hpgrpc.Discoverer{
Dialer: c.Dialer,
},
RPC: &hpgrpc.Registerer{
Dialer: c.Dialer,
RegularRegistration: beaconinggrpc.Registrar{Dialer: c.Dialer},
Signer: c.Signer,
},
}, nil
return interASServer,
&HiddenPathRegistrationCfg{
Policy: regPolicy,
Router: segreq.NewRouter(c.FetcherConfig),
Discoverer: &hpgrpc.Discoverer{
Dialer: c.Dialer,
},
RPC: &hpgrpc.Registerer{
Dialer: c.Dialer,
RegularRegistration: beaconinggrpc.Registrar{Dialer: c.Dialer},
Signer: c.Signer,
},
}, nil
}

func (c HiddenPathConfigurator) localAuthServer(groups hiddenpath.Groups) hiddenpath.Lookuper {
Expand Down
1 change: 1 addition & 0 deletions pkg/experimental/hiddenpath/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ go_library(
"//control/beaconing:go_default_library",
"//control/ifstate:go_default_library",
"//pkg/addr:go_default_library",
"//pkg/grpc:go_default_library",
"//pkg/log:go_default_library",
"//pkg/metrics:go_default_library",
"//pkg/private/prom:go_default_library",
Expand Down
27 changes: 27 additions & 0 deletions pkg/experimental/hiddenpath/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"net"

"github.com/scionproto/scion/pkg/addr"
"github.com/scionproto/scion/pkg/grpc"
"github.com/scionproto/scion/pkg/private/serrors"
"github.com/scionproto/scion/pkg/snet"
"github.com/scionproto/scion/pkg/snet/path"
Expand Down Expand Up @@ -61,6 +62,32 @@ func (r RegistrationResolver) Resolve(ctx context.Context, ia addr.IA) (net.Addr
})
}

// CSResolver resolves the address of a Control Service
// server in an IA. This is needed to get the needed
// certificates from the Register to verify the segments.
type CSResolver struct {
Router snet.Router
Rewriter grpc.AddressRewriter
}

// Resolve resolves the CS server in the remote IA.
func (r CSResolver) Resolve(ctx context.Context, ia addr.IA) (net.Addr, error) {
// TODO(JordiSubira): Put path failover mechanism in-place
path, err := r.Router.Route(ctx, ia)
if err != nil {
return nil, serrors.WrapStr("looking up path", err)
}
if path == nil {
return nil, serrors.WrapStr("no path found to remote", err)
}
return &snet.SVCAddr{
IA: ia,
NextHop: path.UnderlayNextHop(),
Path: path.Dataplane(),
SVC: addr.SvcCS,
}, nil
}

// LookupResolver resolves the address of a hidden segment lookup
// server in an IA.
type LookupResolver struct {
Expand Down
22 changes: 14 additions & 8 deletions pkg/experimental/hiddenpath/forwarder.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,13 @@ type Verifier interface {
// For each group id of the request, it requests the segments at the the
// respective autoritative registry.
type ForwardServer struct {
Groups map[GroupID]*Group
LocalAuth Lookuper
LocalIA addr.IA
RPC RPC
Resolver AddressResolver
Verifier Verifier
Groups map[GroupID]*Group
LocalAuth Lookuper
LocalIA addr.IA
RPC RPC
HPResolver AddressResolver
CSResolver AddressResolver
Verifier Verifier
}

// Segments serves segments for the given request. It finds per group ID
Expand Down Expand Up @@ -104,7 +105,7 @@ func (s ForwardServer) Segments(ctx context.Context,
replies <- segsOrErr{segs: reply, err: err}
return
}
a, err := s.Resolver.Resolve(ctx, r)
a, err := s.HPResolver.Resolve(ctx, r)
if err != nil {
replies <- segsOrErr{err: err}
return
Expand All @@ -114,9 +115,14 @@ func (s ForwardServer) Segments(ctx context.Context,
replies <- segsOrErr{err: err}
return
}
a, err = s.CSResolver.Resolve(ctx, r)
if err != nil {
replies <- segsOrErr{err: err}
return
}
if err := s.Verifier.Verify(ctx, reply, a); err != nil {
replies <- segsOrErr{
err: serrors.New("can not verify segments", "crypto-source", r,
err: serrors.WrapStr("verifying segment", err, "crypto-source", r,
"server", a),
}
return
Expand Down
13 changes: 7 additions & 6 deletions pkg/experimental/hiddenpath/forwarder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,13 @@ func TestForwardServerSegments(t *testing.T) {
AnyTimes()

server := hiddenpath.ForwardServer{
Groups: tc.groups(),
RPC: tc.rpc(ctrl),
LocalAuth: tc.lookuper(ctrl),
LocalIA: local,
Verifier: tc.verifier(ctrl),
Resolver: resolver,
Groups: tc.groups(),
RPC: tc.rpc(ctrl),
LocalAuth: tc.lookuper(ctrl),
LocalIA: local,
Verifier: tc.verifier(ctrl),
HPResolver: resolver,
CSResolver: resolver,
}
got, err := server.Segments(context.Background(), tc.request)
tc.assertErr(t, err)
Expand Down
31 changes: 31 additions & 0 deletions private/app/appnet/infraenv.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,37 @@ func (nc *NetworkConfig) AddressRewriter(
}
}

func (nc *NetworkConfig) OpenListener(a string) (*squic.ConnListener, error) {
scionNet := &snet.SCIONNetwork{
LocalIA: nc.IA,
Connector: &snet.DefaultConnector{
// XXX(roosd): This is essential, the server must not read SCMP
// errors. Otherwise, the accept loop will always return that error
// on every subsequent call to accept.
SCMPHandler: ignoreSCMP{},
Metrics: nc.SCIONPacketConnMetrics,
},
Metrics: nc.SCIONNetworkMetrics,
}
udpAddr, err := net.ResolveUDPAddr("udp", a)
if err != nil {
return nil, serrors.WrapStr("parsing server QUIC address", err)
}
server, err := scionNet.Listen(context.Background(), "udp", udpAddr, addr.SvcNone)
if err != nil {
return nil, serrors.WrapStr("creating server connection", err)
}
serverTLSConfig, err := GenerateTLSConfig()
if err != nil {
return nil, err
}
listener, err := quic.Listen(server, serverTLSConfig, nil)
if err != nil {
return nil, err
}
return squic.NewConnListener(listener), nil
}

// initSvcRedirect creates the main control-plane UDP socket. SVC anycasts will be
// delivered to this socket, which replies to SVC resolution requests. The
// address will be included as the QUIC address in SVC resolution replies.
Expand Down

0 comments on commit 1c82e9c

Please sign in to comment.