diff --git a/daemon/BUILD.bazel b/daemon/BUILD.bazel index 09a0f7efd1..112b98f9a6 100644 --- a/daemon/BUILD.bazel +++ b/daemon/BUILD.bazel @@ -7,21 +7,18 @@ go_library( importpath = "github.com/scionproto/scion/daemon", visibility = ["//visibility:public"], deps = [ - "//daemon/drkey:go_default_library", - "//daemon/fetcher:go_default_library", - "//daemon/internal/servers:go_default_library", + "//daemon/grpc:go_default_library", "//pkg/addr:go_default_library", "//pkg/daemon:go_default_library", - "//pkg/grpc:go_default_library", - "//pkg/log:go_default_library", + "//pkg/daemon/asinfo:go_default_library", + "//pkg/daemon/fetcher:go_default_library", + "//pkg/daemon/private/engine:go_default_library", "//pkg/metrics:go_default_library", "//pkg/private/prom:go_default_library", - "//pkg/private/serrors:go_default_library", + "//private/drkey:go_default_library", "//private/env:go_default_library", "//private/revcache:go_default_library", "//private/trust:go_default_library", - "//private/trust/grpc:go_default_library", - "//private/trust/metrics:go_default_library", "@com_github_opentracing_opentracing_go//:go_default_library", "@com_github_prometheus_client_golang//prometheus:go_default_library", ], diff --git a/daemon/cmd/daemon/BUILD.bazel b/daemon/cmd/daemon/BUILD.bazel index 765db00e78..74cf160699 100644 --- a/daemon/cmd/daemon/BUILD.bazel +++ b/daemon/cmd/daemon/BUILD.bazel @@ -15,11 +15,10 @@ go_library( deps = [ "//daemon:go_default_library", "//daemon/config:go_default_library", - "//daemon/drkey:go_default_library", - "//daemon/drkey/grpc:go_default_library", - "//daemon/fetcher:go_default_library", "//daemon/mgmtapi:go_default_library", "//pkg/addr:go_default_library", + "//pkg/daemon/fetcher:go_default_library", + "//pkg/daemon/private/trust:go_default_library", "//pkg/experimental/hiddenpath:go_default_library", "//pkg/experimental/hiddenpath/grpc:go_default_library", "//pkg/grpc:go_default_library", @@ -27,12 +26,11 @@ go_library( "//pkg/metrics:go_default_library", "//pkg/private/prom:go_default_library", "//pkg/private/serrors:go_default_library", - "//pkg/proto/crypto:go_default_library", "//pkg/proto/daemon:go_default_library", - "//pkg/scrypto/cppki:go_default_library", - "//pkg/scrypto/signed:go_default_library", "//private/app:go_default_library", "//private/app/launcher:go_default_library", + "//private/drkey:go_default_library", + "//private/drkey/grpc:go_default_library", "//private/mgmtapi/cppki/api:go_default_library", "//private/mgmtapi/segments/api:go_default_library", "//private/pathdb:go_default_library", diff --git a/daemon/cmd/daemon/main.go b/daemon/cmd/daemon/main.go index f926377dee..cb4e8c93c2 100644 --- a/daemon/cmd/daemon/main.go +++ b/daemon/cmd/daemon/main.go @@ -35,11 +35,10 @@ import ( "github.com/scionproto/scion/daemon" "github.com/scionproto/scion/daemon/config" - sd_drkey "github.com/scionproto/scion/daemon/drkey" - sd_grpc "github.com/scionproto/scion/daemon/drkey/grpc" - "github.com/scionproto/scion/daemon/fetcher" api "github.com/scionproto/scion/daemon/mgmtapi" "github.com/scionproto/scion/pkg/addr" + "github.com/scionproto/scion/pkg/daemon/fetcher" + daemontrust "github.com/scionproto/scion/pkg/daemon/private/trust" "github.com/scionproto/scion/pkg/experimental/hiddenpath" hpgrpc "github.com/scionproto/scion/pkg/experimental/hiddenpath/grpc" libgrpc "github.com/scionproto/scion/pkg/grpc" @@ -47,12 +46,11 @@ import ( "github.com/scionproto/scion/pkg/metrics" "github.com/scionproto/scion/pkg/private/prom" "github.com/scionproto/scion/pkg/private/serrors" - cryptopb "github.com/scionproto/scion/pkg/proto/crypto" sdpb "github.com/scionproto/scion/pkg/proto/daemon" - "github.com/scionproto/scion/pkg/scrypto/cppki" - "github.com/scionproto/scion/pkg/scrypto/signed" "github.com/scionproto/scion/private/app" "github.com/scionproto/scion/private/app/launcher" + sddrkey "github.com/scionproto/scion/private/drkey" + sdgrpc "github.com/scionproto/scion/private/drkey/grpc" cppkiapi "github.com/scionproto/scion/private/mgmtapi/cppki/api" segapi "github.com/scionproto/scion/private/mgmtapi/segments/api" "github.com/scionproto/scion/private/pathdb" @@ -60,7 +58,7 @@ import ( "github.com/scionproto/scion/private/revcache" "github.com/scionproto/scion/private/segment/segfetcher" segfetchergrpc "github.com/scionproto/scion/private/segment/segfetcher/grpc" - infra "github.com/scionproto/scion/private/segment/verifier" + segverifier "github.com/scionproto/scion/private/segment/verifier" "github.com/scionproto/scion/private/service" "github.com/scionproto/scion/private/storage" "github.com/scionproto/scion/private/storage/drkey/level2" @@ -155,8 +153,9 @@ func realMain(ctx context.Context) error { []string{"driver", "operation", prom.LabelResult}, ), }) - engine, err := daemon.TrustEngine( - errCtx, globalCfg.General.ConfigDir, topo.IA(), trustDB, dialer, + certsDir := filepath.Join(globalCfg.General.ConfigDir, "certs") + engine, err := daemontrust.NewEngine( + errCtx, certsDir, topo.IA(), trustDB, dialer, ) if err != nil { return serrors.Wrap("creating trust engine", err) @@ -168,7 +167,7 @@ func realMain(ctx context.Context) error { MaxCacheExpiration: globalCfg.TrustEngine.Cache.Expiration.Duration, } trcLoader := trust.TRCLoader{ - Dir: filepath.Join(globalCfg.General.ConfigDir, "certs"), + Dir: certsDir, DB: trustDB, } //nolint:staticcheck // SA1019: fix later (https://github.com/scionproto/scion/issues/4776). @@ -186,7 +185,7 @@ func realMain(ctx context.Context) error { }, 10*time.Second, 10*time.Second) defer trcLoaderTask.Stop() - var drkeyClientEngine *sd_drkey.ClientEngine + var drkeyClientEngine *sddrkey.ClientEngine if globalCfg.DRKeyLevel2DB.Connection != "" { backend, err := storage.NewDRKeyLevel2Storage(globalCfg.DRKeyLevel2DB) if err != nil { @@ -215,10 +214,10 @@ func realMain(ctx context.Context) error { } defer level2DB.Close() - drkeyFetcher := &sd_grpc.Fetcher{ + drkeyFetcher := &sdgrpc.Fetcher{ Dialer: dialer, } - drkeyClientEngine = &sd_drkey.ClientEngine{ + drkeyClientEngine = &sddrkey.ClientEngine{ IA: topo.IA(), DB: level2DB, Fetcher: drkeyFetcher, @@ -254,9 +253,9 @@ func realMain(ctx context.Context) error { } } - createVerifier := func() infra.Verifier { + createVerifier := func() segverifier.Verifier { if globalCfg.SD.DisableSegVerification { - return acceptAllVerifier{} + return segverifier.AcceptAllVerifier{} } return compat.Verifier{Verifier: trust.Verifier{ Engine: engine, @@ -272,21 +271,21 @@ func realMain(ctx context.Context) error { ) sdpb.RegisterDaemonServiceServer(server, daemon.NewServer( daemon.ServerConfig{ - IA: topo.IA(), - MTU: topo.MTU(), - Topology: topo, + IA: topo.IA(), + MTU: topo.MTU(), + LocalASInfo: topo, Fetcher: fetcher.NewFetcher( fetcher.FetcherConfig{ - IA: topo.IA(), - MTU: topo.MTU(), - Core: topo.Core(), - NextHopper: topo, - RPC: requester, - PathDB: pathDB, - Inspector: engine, - Verifier: createVerifier(), - RevCache: revCache, - Cfg: globalCfg.SD, + IA: topo.IA(), + MTU: topo.MTU(), + Core: topo.Core(), + NextHopper: topo, + RPC: requester, + PathDB: pathDB, + Inspector: engine, + Verifier: createVerifier(), + RevCache: revCache, + QueryInterval: globalCfg.SD.QueryInterval.Duration, }, ), Engine: engine, @@ -367,26 +366,6 @@ func realMain(ctx context.Context) error { return g.Wait() } -type acceptAllVerifier struct{} - -func (acceptAllVerifier) Verify(ctx context.Context, signedMsg *cryptopb.SignedMessage, - associatedData ...[]byte, -) (*signed.Message, error) { - return nil, nil -} - -func (v acceptAllVerifier) WithServer(net.Addr) infra.Verifier { - return v -} - -func (v acceptAllVerifier) WithIA(addr.IA) infra.Verifier { - return v -} - -func (v acceptAllVerifier) WithValidity(cppki.Validity) infra.Verifier { - return v -} - func loaderMetrics() topology.LoaderMetrics { updates := prom.NewCounterVec("", "", "topology_updates_total", diff --git a/daemon/daemon.go b/daemon/daemon.go index 37bbe95b3e..d30e1ec9f0 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -16,31 +16,25 @@ package daemon import ( - "context" - "errors" "io" "net" - "path/filepath" "strconv" - opentracing "github.com/opentracing/opentracing-go" + "github.com/opentracing/opentracing-go" "github.com/prometheus/client_golang/prometheus" - "github.com/scionproto/scion/daemon/drkey" - "github.com/scionproto/scion/daemon/fetcher" - "github.com/scionproto/scion/daemon/internal/servers" + "github.com/scionproto/scion/daemon/grpc" "github.com/scionproto/scion/pkg/addr" "github.com/scionproto/scion/pkg/daemon" - libgrpc "github.com/scionproto/scion/pkg/grpc" - "github.com/scionproto/scion/pkg/log" + "github.com/scionproto/scion/pkg/daemon/asinfo" + "github.com/scionproto/scion/pkg/daemon/fetcher" + "github.com/scionproto/scion/pkg/daemon/private/engine" "github.com/scionproto/scion/pkg/metrics" "github.com/scionproto/scion/pkg/private/prom" - "github.com/scionproto/scion/pkg/private/serrors" + "github.com/scionproto/scion/private/drkey" "github.com/scionproto/scion/private/env" "github.com/scionproto/scion/private/revcache" "github.com/scionproto/scion/private/trust" - trustgrpc "github.com/scionproto/scion/private/trust/grpc" - trustmetrics "github.com/scionproto/scion/private/trust/metrics" ) // InitTracer initializes the global tracer. @@ -53,60 +47,6 @@ func InitTracer(tracing env.Tracing, id string) (io.Closer, error) { return trCloser, nil } -// TrustEngine builds the trust engine backed by the trust database. -func TrustEngine( - ctx context.Context, - cfgDir string, - ia addr.IA, - db trust.DB, - dialer libgrpc.Dialer, -) (trust.Engine, error) { - certsDir := filepath.Join(cfgDir, "certs") - loaded, err := trust.LoadTRCs(ctx, certsDir, db) - if err != nil { - return trust.Engine{}, serrors.Wrap("loading TRCs", err) - } - log.Info("TRCs loaded", "files", loaded.Loaded) - for f, r := range loaded.Ignored { - if errors.Is(r, trust.ErrAlreadyExists) { - log.Debug("Ignoring existing TRC", "file", f) - continue - } - log.Info("Ignoring non-TRC", "file", f, "reason", r) - } - loaded, err = trust.LoadChains(ctx, certsDir, db) - if err != nil { - return trust.Engine{}, serrors.Wrap("loading certificate chains", - err) - } - log.Info("Certificate chains loaded", "files", loaded.Loaded) - for f, r := range loaded.Ignored { - if errors.Is(r, trust.ErrAlreadyExists) { - log.Debug("Ignoring existing certificate chain", "file", f) - continue - } - if errors.Is(r, trust.ErrOutsideValidity) { - log.Debug("Ignoring certificate chain outside validity", "file", f) - continue - } - log.Info("Ignoring non-certificate chain", "file", f, "reason", r) - } - return trust.Engine{ - Inspector: trust.DBInspector{DB: db}, - Provider: trust.FetchingProvider{ - DB: db, - Fetcher: trustgrpc.Fetcher{ - IA: ia, - Dialer: dialer, - Requests: metrics.NewPromCounter(trustmetrics.RPC.Fetches), - }, - Recurser: trust.LocalOnlyRecurser{}, - Router: trust.LocalRouter{IA: ia}, - }, - DB: db, - }, nil -} - // ServerConfig is the configuration for the daemon API server. type ServerConfig struct { IA addr.IA @@ -114,91 +54,93 @@ type ServerConfig struct { Fetcher fetcher.Fetcher RevCache revcache.RevCache Engine trust.Engine - Topology servers.Topology + LocalASInfo asinfo.LocalASInfo DRKeyClient *drkey.ClientEngine } // NewServer constructs a daemon API server. -func NewServer(cfg ServerConfig) *servers.DaemonServer { - return &servers.DaemonServer{ - IA: cfg.IA, - MTU: cfg.MTU, - // TODO(JordiSubira): This will be changed in the future to fetch - // the information from the CS instead of feeding the configuration - // file into. - Topology: cfg.Topology, - Fetcher: cfg.Fetcher, - ASInspector: cfg.Engine.Inspector, - RevCache: cfg.RevCache, - DRKeyClient: cfg.DRKeyClient, - Metrics: servers.Metrics{ - PathsRequests: servers.RequestMetrics{ +func NewServer(cfg ServerConfig) *grpc.DaemonServer { + return &grpc.DaemonServer{ + Engine: &engine.DaemonEngine{ + IA: cfg.IA, + MTU: cfg.MTU, + // TODO(JordiSubira): This will be changed in the future to fetch + // the information from the CS instead of feeding the configuration + // file into. + LocalASInfo: cfg.LocalASInfo, + Fetcher: cfg.Fetcher, + ASInspector: cfg.Engine.Inspector, + RevCache: cfg.RevCache, + DRKeyClient: cfg.DRKeyClient, + }, + Metrics: grpc.Metrics{ + PathsRequests: grpc.RequestMetrics{ Requests: metrics.NewPromCounterFrom(prometheus.CounterOpts{ Namespace: "sd", Subsystem: "path", Name: "requests_total", Help: "The amount of path requests received.", - }, servers.PathsRequestsLabels), + }, grpc.PathsRequestsLabels), Latency: metrics.NewPromHistogramFrom(prometheus.HistogramOpts{ Namespace: "sd", Subsystem: "path", Name: "request_duration_seconds", Help: "Time to handle path requests.", Buckets: prom.DefaultLatencyBuckets, - }, servers.LatencyLabels), + }, grpc.LatencyLabels), }, - ASRequests: servers.RequestMetrics{ + ASRequests: grpc.RequestMetrics{ Requests: metrics.NewPromCounterFrom(prometheus.CounterOpts{ Namespace: "sd", Subsystem: "as_info", Name: "requests_total", Help: "The amount of AS requests received.", - }, servers.ASRequestsLabels), + }, grpc.ASRequestsLabels), Latency: metrics.NewPromHistogramFrom(prometheus.HistogramOpts{ Namespace: "sd", Subsystem: "as_info", Name: "request_duration_seconds", Help: "Time to handle AS requests.", Buckets: prom.DefaultLatencyBuckets, - }, servers.LatencyLabels), + }, grpc.LatencyLabels), }, - InterfacesRequests: servers.RequestMetrics{ + InterfacesRequests: grpc.RequestMetrics{ Requests: metrics.NewPromCounterFrom(prometheus.CounterOpts{ Namespace: "sd", Subsystem: "if_info", Name: "requests_total", Help: "The amount of interfaces requests received.", - }, servers.InterfacesRequestsLabels), + }, grpc.InterfacesRequestsLabels), Latency: metrics.NewPromHistogramFrom(prometheus.HistogramOpts{ Namespace: "sd", Subsystem: "if_info", Name: "request_duration_seconds", Help: "Time to handle interfaces requests.", Buckets: prom.DefaultLatencyBuckets, - }, servers.LatencyLabels), + }, grpc.LatencyLabels), }, - ServicesRequests: servers.RequestMetrics{ + ServicesRequests: grpc.RequestMetrics{ Requests: metrics.NewPromCounterFrom(prometheus.CounterOpts{ Namespace: "sd", Subsystem: "service_info", Name: "requests_total", Help: "The amount of services requests received.", - }, servers.ServicesRequestsLabels), + }, grpc.ServicesRequestsLabels), Latency: metrics.NewPromHistogramFrom(prometheus.HistogramOpts{ Namespace: "sd", Subsystem: "service_info", Name: "request_duration_seconds", Help: "Time to handle services requests.", Buckets: prom.DefaultLatencyBuckets, - }, servers.LatencyLabels), + }, grpc.LatencyLabels), }, - InterfaceDownNotifications: servers.RequestMetrics{ + InterfaceDownNotifications: grpc.RequestMetrics{ Requests: metrics.NewPromCounter(prom.SafeRegister( prometheus.NewCounterVec(prometheus.CounterOpts{ Namespace: "sd", Name: "received_revocations_total", Help: "The amount of revocations received.", - }, servers.InterfaceDownNotificationsLabels)).(*prometheus.CounterVec), + }, grpc.InterfaceDownNotificationsLabels)).(*prometheus.CounterVec), ), Latency: metrics.NewPromHistogramFrom(prometheus.HistogramOpts{ Namespace: "sd", @@ -206,7 +148,7 @@ func NewServer(cfg ServerConfig) *servers.DaemonServer { Name: "notification_duration_seconds", Help: "Time to handle interface down notifications.", Buckets: prom.DefaultLatencyBuckets, - }, servers.LatencyLabels), + }, grpc.LatencyLabels), }, }, } diff --git a/daemon/internal/servers/BUILD.bazel b/daemon/grpc/BUILD.bazel similarity index 63% rename from daemon/internal/servers/BUILD.bazel rename to daemon/grpc/BUILD.bazel index ec1ae2a4ec..072871a751 100644 --- a/daemon/internal/servers/BUILD.bazel +++ b/daemon/grpc/BUILD.bazel @@ -3,35 +3,31 @@ load("@rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = [ - "grpc.go", "metrics.go", + "server.go", ], - importpath = "github.com/scionproto/scion/daemon/internal/servers", + importpath = "github.com/scionproto/scion/daemon/grpc", visibility = ["//daemon:__subpackages__"], deps = [ - "//daemon/drkey:go_default_library", - "//daemon/fetcher:go_default_library", "//pkg/addr:go_default_library", + "//pkg/daemon/asinfo:go_default_library", + "//pkg/daemon/fetcher:go_default_library", + "//pkg/daemon/private/engine:go_default_library", + "//pkg/daemon/types:go_default_library", "//pkg/drkey:go_default_library", - "//pkg/log:go_default_library", "//pkg/metrics:go_default_library", - "//pkg/private/ctrl/path_mgmt:go_default_library", - "//pkg/private/ctrl/path_mgmt/proto:go_default_library", "//pkg/private/prom:go_default_library", "//pkg/private/serrors:go_default_library", - "//pkg/private/util:go_default_library", "//pkg/proto/daemon:go_default_library", - "//pkg/segment/iface:go_default_library", "//pkg/slices:go_default_library", "//pkg/snet:go_default_library", "//pkg/snet/path:go_default_library", + "//private/drkey:go_default_library", "//private/revcache:go_default_library", "//private/topology:go_default_library", "//private/trust:go_default_library", - "@com_github_opentracing_opentracing_go//:go_default_library", "@org_golang_google_protobuf//types/known/durationpb:go_default_library", "@org_golang_google_protobuf//types/known/emptypb:go_default_library", "@org_golang_google_protobuf//types/known/timestamppb:go_default_library", - "@org_golang_x_sync//singleflight:go_default_library", ], ) diff --git a/daemon/internal/servers/metrics.go b/daemon/grpc/metrics.go similarity index 99% rename from daemon/internal/servers/metrics.go rename to daemon/grpc/metrics.go index c69d565e42..38e1db2261 100644 --- a/daemon/internal/servers/metrics.go +++ b/daemon/grpc/metrics.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package servers +package grpc import ( "github.com/scionproto/scion/pkg/addr" diff --git a/daemon/grpc/server.go b/daemon/grpc/server.go new file mode 100644 index 0000000000..97445228cf --- /dev/null +++ b/daemon/grpc/server.go @@ -0,0 +1,454 @@ +// Copyright 2020 Anapaya Systems +// +// 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 grpc + +import ( + "bytes" + "context" + "net" + "net/netip" + "time" + + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/emptypb" + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/scionproto/scion/pkg/addr" + "github.com/scionproto/scion/pkg/daemon/asinfo" + "github.com/scionproto/scion/pkg/daemon/fetcher" + "github.com/scionproto/scion/pkg/daemon/private/engine" + daemontypes "github.com/scionproto/scion/pkg/daemon/types" + "github.com/scionproto/scion/pkg/drkey" + "github.com/scionproto/scion/pkg/private/serrors" + sdpb "github.com/scionproto/scion/pkg/proto/daemon" + "github.com/scionproto/scion/pkg/slices" + "github.com/scionproto/scion/pkg/snet" + snetpath "github.com/scionproto/scion/pkg/snet/path" + drkeyengine "github.com/scionproto/scion/private/drkey" + "github.com/scionproto/scion/private/revcache" + "github.com/scionproto/scion/private/topology" + "github.com/scionproto/scion/private/trust" +) + +// Topology is the interface for accessing topology information. +type Topology interface { + IfIDs() []uint16 + UnderlayNextHop(uint16) *net.UDPAddr + ControlServiceAddresses() []*net.UDPAddr + PortRange() (uint16, uint16) +} + +// DaemonServer handles gRPC requests to the SCION daemon. +// It delegates business logic to the embedded DaemonEngine. +type DaemonServer struct { + Engine *engine.DaemonEngine + Metrics Metrics +} + +// NewDaemonServer creates a new DaemonServer with the given configuration. +func NewDaemonServer( + ia addr.IA, + mtu uint16, + localASInfo asinfo.LocalASInfo, + fetcher fetcher.Fetcher, + revCache revcache.RevCache, + asInspector trust.Inspector, + drkeyClient *drkeyengine.ClientEngine, + metrics Metrics, +) *DaemonServer { + return &DaemonServer{ + Engine: &engine.DaemonEngine{ + IA: ia, + MTU: mtu, + LocalASInfo: localASInfo, + Fetcher: fetcher, + RevCache: revCache, + ASInspector: asInspector, + DRKeyClient: drkeyClient, + }, + Metrics: metrics, + } +} + +// Paths serves the paths request. +func (s *DaemonServer) Paths( + ctx context.Context, + req *sdpb.PathsRequest, +) (*sdpb.PathsResponse, error) { + start := time.Now() + dstI := addr.IA(req.DestinationIsdAs).ISD() + response, err := s.paths(ctx, req) + s.Metrics.PathsRequests.inc( + pathReqLabels{Result: errToMetricResult(err), Dst: dstI}, + time.Since(start).Seconds(), + ) + return response, unwrapMetricsError(err) +} + +func (s *DaemonServer) paths( + ctx context.Context, + req *sdpb.PathsRequest, +) (*sdpb.PathsResponse, error) { + srcIA, dstIA := addr.IA(req.SourceIsdAs), addr.IA(req.DestinationIsdAs) + flags := daemontypes.PathReqFlags{ + Refresh: req.Refresh, + Hidden: req.Hidden, + } + paths, err := s.Engine.Paths(ctx, dstIA, srcIA, flags) + if err != nil { + return nil, err + } + reply := &sdpb.PathsResponse{} + for _, p := range paths { + reply.Paths = append(reply.Paths, pathToPB(p)) + } + return reply, nil +} + +// AS serves the AS request. +func (s *DaemonServer) AS(ctx context.Context, req *sdpb.ASRequest) (*sdpb.ASResponse, error) { + start := time.Now() + response, err := s.as(ctx, req) + s.Metrics.ASRequests.inc( + reqLabels{Result: errToMetricResult(err)}, + time.Since(start).Seconds(), + ) + return response, unwrapMetricsError(err) +} + +func (s *DaemonServer) as(ctx context.Context, req *sdpb.ASRequest) (*sdpb.ASResponse, error) { + asInfo, err := s.Engine.ASInfo(ctx, addr.IA(req.IsdAs)) + if err != nil { + return nil, err + } + // Note: We don't have the 'core' attribute in daemon.ASInfo, + // so we need to query it directly here. + reqIA := addr.IA(req.IsdAs) + if reqIA.IsZero() { + reqIA = s.Engine.IA + } + core, err := s.Engine.ASInspector.HasAttributes(ctx, reqIA, trust.Core) + if err != nil { + return nil, serrors.Wrap("inspecting ISD-AS", err, "isd_as", reqIA) + } + return &sdpb.ASResponse{ + IsdAs: uint64(asInfo.IA), + Core: core, + Mtu: uint32(asInfo.MTU), + }, nil +} + +// Interfaces serves the interfaces request. +func (s *DaemonServer) Interfaces( + ctx context.Context, + req *sdpb.InterfacesRequest, +) (*sdpb.InterfacesResponse, error) { + start := time.Now() + response, err := s.interfaces(ctx, req) + s.Metrics.InterfacesRequests.inc( + reqLabels{Result: errToMetricResult(err)}, + time.Since(start).Seconds(), + ) + return response, unwrapMetricsError(err) +} + +func (s *DaemonServer) interfaces( + ctx context.Context, + _ *sdpb.InterfacesRequest, +) (*sdpb.InterfacesResponse, error) { + intfs, err := s.Engine.Interfaces(ctx) + if err != nil { + return nil, err + } + reply := &sdpb.InterfacesResponse{ + Interfaces: make(map[uint64]*sdpb.Interface), + } + for ifID, addr := range intfs { + reply.Interfaces[uint64(ifID)] = &sdpb.Interface{ + Address: &sdpb.Underlay{ + Address: addr.String(), + }, + } + } + return reply, nil +} + +// Services serves the services request. +func (s *DaemonServer) Services( + ctx context.Context, + req *sdpb.ServicesRequest, +) (*sdpb.ServicesResponse, error) { + start := time.Now() + response, err := s.services(ctx, req) + s.Metrics.ServicesRequests.inc( + reqLabels{Result: errToMetricResult(err)}, + time.Since(start).Seconds(), + ) + return response, unwrapMetricsError(err) +} + +func (s *DaemonServer) services( + ctx context.Context, + _ *sdpb.ServicesRequest, +) (*sdpb.ServicesResponse, error) { + uris, err := s.Engine.SVCInfo(ctx) + if err != nil { + return nil, err + } + reply := &sdpb.ServicesResponse{ + Services: make(map[string]*sdpb.ListService), + } + list := &sdpb.ListService{} + for _, uri := range uris { + list.Services = append(list.Services, &sdpb.Service{Uri: uri}) + } + reply.Services[topology.Control.String()] = list + return reply, nil +} + +// NotifyInterfaceDown notifies the server about an interface that is down. +func (s *DaemonServer) NotifyInterfaceDown( + ctx context.Context, + req *sdpb.NotifyInterfaceDownRequest, +) (*sdpb.NotifyInterfaceDownResponse, error) { + start := time.Now() + response, err := s.notifyInterfaceDown(ctx, req) + s.Metrics.InterfaceDownNotifications.inc( + ifDownLabels{Result: errToMetricResult(err), Src: "notification"}, + time.Since(start).Seconds(), + ) + return response, unwrapMetricsError(err) +} + +func (s *DaemonServer) notifyInterfaceDown( + ctx context.Context, + req *sdpb.NotifyInterfaceDownRequest, +) (*sdpb.NotifyInterfaceDownResponse, error) { + err := s.Engine.NotifyInterfaceDown(ctx, addr.IA(req.IsdAs), req.Id) + if err != nil { + return nil, err + } + return &sdpb.NotifyInterfaceDownResponse{}, nil +} + +// PortRange returns the port range for the dispatched ports. +func (s *DaemonServer) PortRange( + ctx context.Context, + _ *emptypb.Empty, +) (*sdpb.PortRangeResponse, error) { + startPort, endPort, err := s.Engine.PortRange(ctx) + if err != nil { + return nil, err + } + return &sdpb.PortRangeResponse{ + DispatchedPortStart: uint32(startPort), + DispatchedPortEnd: uint32(endPort), + }, nil +} + +func (s *DaemonServer) DRKeyASHost( + ctx context.Context, + req *sdpb.DRKeyASHostRequest, +) (*sdpb.DRKeyASHostResponse, error) { + meta, err := requestToASHostMeta(req) + if err != nil { + return nil, serrors.Wrap("parsing protobuf ASHostReq", err) + } + lvl2Key, err := s.Engine.DRKeyGetASHostKey(ctx, meta) + if err != nil { + return nil, serrors.Wrap("getting AS-Host from client store", err) + } + return &sdpb.DRKeyASHostResponse{ + EpochBegin: ×tamppb.Timestamp{Seconds: lvl2Key.Epoch.NotBefore.Unix()}, + EpochEnd: ×tamppb.Timestamp{Seconds: lvl2Key.Epoch.NotAfter.Unix()}, + Key: lvl2Key.Key[:], + }, nil +} + +func (s *DaemonServer) DRKeyHostAS( + ctx context.Context, + req *sdpb.DRKeyHostASRequest, +) (*sdpb.DRKeyHostASResponse, error) { + meta, err := requestToHostASMeta(req) + if err != nil { + return nil, serrors.Wrap("parsing protobuf HostASReq", err) + } + lvl2Key, err := s.Engine.DRKeyGetHostASKey(ctx, meta) + if err != nil { + return nil, serrors.Wrap("getting Host-AS from client store", err) + } + return &sdpb.DRKeyHostASResponse{ + EpochBegin: ×tamppb.Timestamp{Seconds: lvl2Key.Epoch.NotBefore.Unix()}, + EpochEnd: ×tamppb.Timestamp{Seconds: lvl2Key.Epoch.NotAfter.Unix()}, + Key: lvl2Key.Key[:], + }, nil +} + +func (s *DaemonServer) DRKeyHostHost( + ctx context.Context, + req *sdpb.DRKeyHostHostRequest, +) (*sdpb.DRKeyHostHostResponse, error) { + meta, err := requestToHostHostMeta(req) + if err != nil { + return nil, serrors.Wrap("parsing protobuf HostHostReq", err) + } + lvl2Key, err := s.Engine.DRKeyGetHostHostKey(ctx, meta) + if err != nil { + return nil, serrors.Wrap("getting Host-Host from client store", err) + } + return &sdpb.DRKeyHostHostResponse{ + EpochBegin: ×tamppb.Timestamp{Seconds: lvl2Key.Epoch.NotBefore.Unix()}, + EpochEnd: ×tamppb.Timestamp{Seconds: lvl2Key.Epoch.NotAfter.Unix()}, + Key: lvl2Key.Key[:], + }, nil +} + +// Protobuf conversion helpers + +func pathToPB(path snet.Path) *sdpb.Path { + meta := path.Metadata() + interfaces := make([]*sdpb.PathInterface, len(meta.Interfaces)) + for i, intf := range meta.Interfaces { + interfaces[i] = &sdpb.PathInterface{ + Id: uint64(intf.ID), + IsdAs: uint64(intf.IA), + } + } + + latency := make([]*durationpb.Duration, len(meta.Latency)) + for i, v := range meta.Latency { + seconds := int64(v / time.Second) + nanos := int32(v - time.Duration(seconds)*time.Second) + latency[i] = &durationpb.Duration{Seconds: seconds, Nanos: nanos} + } + geo := make([]*sdpb.GeoCoordinates, len(meta.Geo)) + for i, v := range meta.Geo { + geo[i] = &sdpb.GeoCoordinates{ + Latitude: v.Latitude, + Longitude: v.Longitude, + Address: v.Address, + } + } + linkType := make([]sdpb.LinkType, len(meta.LinkType)) + for i, v := range meta.LinkType { + linkType[i] = linkTypeToPB(v) + } + + var raw []byte + scionPath, ok := path.Dataplane().(snetpath.SCION) + if ok { + raw = scionPath.Raw + } + nextHopStr := "" + if nextHop := path.UnderlayNextHop(); nextHop != nil { + nextHopStr = nextHop.String() + } + + epicAuths := &sdpb.EpicAuths{ + AuthPhvf: bytes.Clone(meta.EpicAuths.AuthPHVF), + AuthLhvf: bytes.Clone(meta.EpicAuths.AuthLHVF), + } + + var discovery map[uint64]*sdpb.DiscoveryInformation + if di := meta.DiscoveryInformation; di != nil { + discovery = make(map[uint64]*sdpb.DiscoveryInformation, len(di)) + for ia, info := range di { + discovery[uint64(ia)] = &sdpb.DiscoveryInformation{ + ControlServiceAddresses: slices.Transform( + info.ControlServices, + netip.AddrPort.String, + ), + DiscoveryServiceAddresses: slices.Transform( + info.DiscoveryServices, + netip.AddrPort.String, + ), + } + } + } + + return &sdpb.Path{ + Raw: raw, + Interface: &sdpb.Interface{ + Address: &sdpb.Underlay{Address: nextHopStr}, + }, + Interfaces: interfaces, + Mtu: uint32(meta.MTU), + Expiration: ×tamppb.Timestamp{Seconds: meta.Expiry.Unix()}, + Latency: latency, + Bandwidth: meta.Bandwidth, + Geo: geo, + LinkType: linkType, + InternalHops: meta.InternalHops, + Notes: meta.Notes, + EpicAuths: epicAuths, + DiscoveryInformation: discovery, + } +} + +func linkTypeToPB(lt snet.LinkType) sdpb.LinkType { + switch lt { + case snet.LinkTypeDirect: + return sdpb.LinkType_LINK_TYPE_DIRECT + case snet.LinkTypeMultihop: + return sdpb.LinkType_LINK_TYPE_MULTI_HOP + case snet.LinkTypeOpennet: + return sdpb.LinkType_LINK_TYPE_OPEN_NET + default: + return sdpb.LinkType_LINK_TYPE_UNSPECIFIED + } +} + +func requestToASHostMeta(req *sdpb.DRKeyASHostRequest) (drkey.ASHostMeta, error) { + err := req.ValTime.CheckValid() + if err != nil { + return drkey.ASHostMeta{}, serrors.Wrap("invalid valTime from pb request", err) + } + return drkey.ASHostMeta{ + ProtoId: drkey.Protocol(req.ProtocolId), + Validity: req.ValTime.AsTime(), + SrcIA: addr.IA(req.SrcIa), + DstIA: addr.IA(req.DstIa), + DstHost: req.DstHost, + }, nil +} + +func requestToHostASMeta(req *sdpb.DRKeyHostASRequest) (drkey.HostASMeta, error) { + err := req.ValTime.CheckValid() + if err != nil { + return drkey.HostASMeta{}, serrors.Wrap("invalid valTime from pb request", err) + } + return drkey.HostASMeta{ + ProtoId: drkey.Protocol(req.ProtocolId), + Validity: req.ValTime.AsTime(), + SrcIA: addr.IA(req.SrcIa), + DstIA: addr.IA(req.DstIa), + SrcHost: req.SrcHost, + }, nil +} + +func requestToHostHostMeta(req *sdpb.DRKeyHostHostRequest) (drkey.HostHostMeta, error) { + err := req.ValTime.CheckValid() + if err != nil { + return drkey.HostHostMeta{}, serrors.Wrap("invalid valTime from pb request", err) + } + return drkey.HostHostMeta{ + ProtoId: drkey.Protocol(req.ProtocolId), + Validity: req.ValTime.AsTime(), + SrcIA: addr.IA(req.SrcIa), + DstIA: addr.IA(req.DstIa), + SrcHost: req.SrcHost, + DstHost: req.DstHost, + }, nil +} diff --git a/daemon/internal/servers/grpc.go b/daemon/internal/servers/grpc.go deleted file mode 100644 index 06edc3b736..0000000000 --- a/daemon/internal/servers/grpc.go +++ /dev/null @@ -1,500 +0,0 @@ -// Copyright 2020 Anapaya Systems -// -// 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 servers - -import ( - "context" - "fmt" - "net" - "net/netip" - "time" - - "github.com/opentracing/opentracing-go" - "golang.org/x/sync/singleflight" - "google.golang.org/protobuf/types/known/durationpb" - "google.golang.org/protobuf/types/known/emptypb" - "google.golang.org/protobuf/types/known/timestamppb" - - drkey_daemon "github.com/scionproto/scion/daemon/drkey" - "github.com/scionproto/scion/daemon/fetcher" - "github.com/scionproto/scion/pkg/addr" - "github.com/scionproto/scion/pkg/drkey" - "github.com/scionproto/scion/pkg/log" - "github.com/scionproto/scion/pkg/private/ctrl/path_mgmt" - "github.com/scionproto/scion/pkg/private/ctrl/path_mgmt/proto" - "github.com/scionproto/scion/pkg/private/prom" - "github.com/scionproto/scion/pkg/private/serrors" - "github.com/scionproto/scion/pkg/private/util" - "github.com/scionproto/scion/pkg/proto/daemon" - "github.com/scionproto/scion/pkg/segment/iface" - "github.com/scionproto/scion/pkg/slices" - "github.com/scionproto/scion/pkg/snet" - snetpath "github.com/scionproto/scion/pkg/snet/path" - "github.com/scionproto/scion/private/revcache" - "github.com/scionproto/scion/private/topology" - "github.com/scionproto/scion/private/trust" -) - -type Topology interface { - IfIDs() []uint16 - UnderlayNextHop(uint16) *net.UDPAddr - ControlServiceAddresses() []*net.UDPAddr - PortRange() (uint16, uint16) -} - -// DaemonServer handles gRPC requests to the SCION daemon. -type DaemonServer struct { - IA addr.IA - MTU uint16 - Topology Topology - Fetcher fetcher.Fetcher - RevCache revcache.RevCache - ASInspector trust.Inspector - DRKeyClient *drkey_daemon.ClientEngine - - Metrics Metrics - - foregroundPathDedupe singleflight.Group - backgroundPathDedupe singleflight.Group -} - -// Paths serves the paths request. -func (s *DaemonServer) Paths(ctx context.Context, - req *daemon.PathsRequest, -) (*daemon.PathsResponse, error) { - start := time.Now() - dstI := addr.IA(req.DestinationIsdAs).ISD() - response, err := s.paths(ctx, req) - s.Metrics.PathsRequests.inc( - pathReqLabels{Result: errToMetricResult(err), Dst: dstI}, - time.Since(start).Seconds(), - ) - return response, unwrapMetricsError(err) -} - -func (s *DaemonServer) paths(ctx context.Context, - req *daemon.PathsRequest, -) (*daemon.PathsResponse, error) { - if _, ok := ctx.Deadline(); !ok { - var cancelF context.CancelFunc - ctx, cancelF = context.WithTimeout(ctx, 10*time.Second) - defer cancelF() - } - srcIA, dstIA := addr.IA(req.SourceIsdAs), addr.IA(req.DestinationIsdAs) - go func() { - defer log.HandlePanic() - s.backgroundPaths(ctx, srcIA, dstIA, req.Refresh) - }() - paths, err := s.fetchPaths(ctx, &s.foregroundPathDedupe, srcIA, dstIA, req.Refresh) - if err != nil { - log.FromCtx(ctx).Debug("Fetching paths", "err", err, - "src", srcIA, "dst", dstIA, "refresh", req.Refresh) - return nil, err - } - reply := &daemon.PathsResponse{} - for _, p := range paths { - reply.Paths = append(reply.Paths, pathToPB(p)) - } - return reply, nil -} - -func (s *DaemonServer) fetchPaths( - ctx context.Context, - group *singleflight.Group, - src, dst addr.IA, - refresh bool, -) ([]snet.Path, error) { - r, err, _ := group.Do(fmt.Sprintf("%s%s%t", src, dst, refresh), - func() (any, error) { - return s.Fetcher.GetPaths(ctx, src, dst, refresh) - }, - ) - // just cast to the correct type, ignore the "ok", since that can only be - // false in case of a nil result. - paths, _ := r.([]snet.Path) - return paths, err -} - -func pathToPB(path snet.Path) *daemon.Path { - meta := path.Metadata() - interfaces := make([]*daemon.PathInterface, len(meta.Interfaces)) - for i, intf := range meta.Interfaces { - interfaces[i] = &daemon.PathInterface{ - Id: uint64(intf.ID), - IsdAs: uint64(intf.IA), - } - } - - latency := make([]*durationpb.Duration, len(meta.Latency)) - for i, v := range meta.Latency { - seconds := int64(v / time.Second) - nanos := int32(v - time.Duration(seconds)*time.Second) - latency[i] = &durationpb.Duration{Seconds: seconds, Nanos: nanos} - } - geo := make([]*daemon.GeoCoordinates, len(meta.Geo)) - for i, v := range meta.Geo { - geo[i] = &daemon.GeoCoordinates{ - Latitude: v.Latitude, - Longitude: v.Longitude, - Address: v.Address, - } - } - linkType := make([]daemon.LinkType, len(meta.LinkType)) - for i, v := range meta.LinkType { - linkType[i] = linkTypeToPB(v) - } - - var raw []byte - scionPath, ok := path.Dataplane().(snetpath.SCION) - if ok { - raw = scionPath.Raw - } - nextHopStr := "" - if nextHop := path.UnderlayNextHop(); nextHop != nil { - nextHopStr = nextHop.String() - } - - epicAuths := &daemon.EpicAuths{ - AuthPhvf: append([]byte(nil), meta.EpicAuths.AuthPHVF...), - AuthLhvf: append([]byte(nil), meta.EpicAuths.AuthLHVF...), - } - - var discovery map[uint64]*daemon.DiscoveryInformation - if di := meta.DiscoveryInformation; di != nil { - discovery = make(map[uint64]*daemon.DiscoveryInformation, len(di)) - for ia, info := range di { - discovery[uint64(ia)] = &daemon.DiscoveryInformation{ - ControlServiceAddresses: slices.Transform( - info.ControlServices, - netip.AddrPort.String, - ), - DiscoveryServiceAddresses: slices.Transform( - info.DiscoveryServices, - netip.AddrPort.String, - ), - } - } - } - - return &daemon.Path{ - Raw: raw, - Interface: &daemon.Interface{ - Address: &daemon.Underlay{Address: nextHopStr}, - }, - Interfaces: interfaces, - Mtu: uint32(meta.MTU), - Expiration: ×tamppb.Timestamp{Seconds: meta.Expiry.Unix()}, - Latency: latency, - Bandwidth: meta.Bandwidth, - Geo: geo, - LinkType: linkType, - InternalHops: meta.InternalHops, - Notes: meta.Notes, - EpicAuths: epicAuths, - DiscoveryInformation: discovery, - } -} - -func linkTypeToPB(lt snet.LinkType) daemon.LinkType { - switch lt { - case snet.LinkTypeDirect: - return daemon.LinkType_LINK_TYPE_DIRECT - case snet.LinkTypeMultihop: - return daemon.LinkType_LINK_TYPE_MULTI_HOP - case snet.LinkTypeOpennet: - return daemon.LinkType_LINK_TYPE_OPEN_NET - default: - return daemon.LinkType_LINK_TYPE_UNSPECIFIED - } -} - -func (s *DaemonServer) backgroundPaths(origCtx context.Context, src, dst addr.IA, refresh bool) { - backgroundTimeout := 5 * time.Second - deadline, ok := origCtx.Deadline() - if !ok || time.Until(deadline) > backgroundTimeout { - // the original context is large enough no need to spin a background fetch. - return - } - // We're not passing origCtx because this is a background fetch that - // should continue even in case origCtx is cancelled. - ctx, cancelF := context.WithTimeout(context.Background(), backgroundTimeout) - defer cancelF() - var spanOpts []opentracing.StartSpanOption - if span := opentracing.SpanFromContext(origCtx); span != nil { - spanOpts = append(spanOpts, opentracing.FollowsFrom(span.Context())) - } - span, ctx := opentracing.StartSpanFromContext(ctx, "fetch.paths.background", spanOpts...) - defer span.Finish() - //nolint:contextcheck // false positive. - if _, err := s.fetchPaths(ctx, &s.backgroundPathDedupe, src, dst, refresh); err != nil { - log.FromCtx(ctx).Debug("Error fetching paths (background)", "err", err, - "src", src, "dst", dst, "refresh", refresh) - } -} - -// AS serves the AS request. -func (s *DaemonServer) AS(ctx context.Context, req *daemon.ASRequest) (*daemon.ASResponse, error) { - start := time.Now() - response, err := s.as(ctx, req) - s.Metrics.ASRequests.inc( - reqLabels{Result: errToMetricResult(err)}, - time.Since(start).Seconds(), - ) - return response, unwrapMetricsError(err) -} - -func (s *DaemonServer) as(ctx context.Context, req *daemon.ASRequest) (*daemon.ASResponse, error) { - reqIA := addr.IA(req.IsdAs) - if reqIA.IsZero() { - reqIA = s.IA - } - mtu := uint32(0) - if reqIA.Equal(s.IA) { - mtu = uint32(s.MTU) - } - core, err := s.ASInspector.HasAttributes(ctx, reqIA, trust.Core) - if err != nil { - log.FromCtx(ctx).Error("Inspecting ISD-AS", "err", err, "isd_as", reqIA) - return nil, serrors.Wrap("inspecting ISD-AS", err, "isd_as", reqIA) - } - reply := &daemon.ASResponse{ - IsdAs: uint64(reqIA), - Core: core, - Mtu: mtu, - } - return reply, nil -} - -// Interfaces serves the interfaces request. -func (s *DaemonServer) Interfaces(ctx context.Context, - req *daemon.InterfacesRequest, -) (*daemon.InterfacesResponse, error) { - start := time.Now() - response, err := s.interfaces(ctx, req) - s.Metrics.InterfacesRequests.inc( - reqLabels{Result: errToMetricResult(err)}, - time.Since(start).Seconds(), - ) - return response, unwrapMetricsError(err) -} - -func (s *DaemonServer) interfaces(ctx context.Context, - _ *daemon.InterfacesRequest, -) (*daemon.InterfacesResponse, error) { - reply := &daemon.InterfacesResponse{ - Interfaces: make(map[uint64]*daemon.Interface), - } - topo := s.Topology - for _, ifID := range topo.IfIDs() { - nextHop := topo.UnderlayNextHop(ifID) - if nextHop == nil { - continue - } - reply.Interfaces[uint64(ifID)] = &daemon.Interface{ - Address: &daemon.Underlay{ - Address: nextHop.String(), - }, - } - } - return reply, nil -} - -// Services serves the services request. -func (s *DaemonServer) Services(ctx context.Context, - req *daemon.ServicesRequest, -) (*daemon.ServicesResponse, error) { - start := time.Now() - respsonse, err := s.services(ctx, req) - s.Metrics.ServicesRequests.inc( - reqLabels{Result: errToMetricResult(err)}, - time.Since(start).Seconds(), - ) - return respsonse, unwrapMetricsError(err) -} - -func (s *DaemonServer) services(ctx context.Context, - _ *daemon.ServicesRequest, -) (*daemon.ServicesResponse, error) { - reply := &daemon.ServicesResponse{ - Services: make(map[string]*daemon.ListService), - } - list := &daemon.ListService{} - for _, h := range s.Topology.ControlServiceAddresses() { - // TODO(lukedirtwalker): build actual URI after it's defined (anapapaya/scion#3587) - list.Services = append(list.Services, &daemon.Service{Uri: h.String()}) - } - reply.Services[topology.Control.String()] = list - return reply, nil -} - -// NotifyInterfaceDown notifies the server about an interface that is down. -func (s *DaemonServer) NotifyInterfaceDown(ctx context.Context, - req *daemon.NotifyInterfaceDownRequest, -) (*daemon.NotifyInterfaceDownResponse, error) { - start := time.Now() - response, err := s.notifyInterfaceDown(ctx, req) - s.Metrics.InterfaceDownNotifications.inc( - ifDownLabels{Result: errToMetricResult(err), Src: "notification"}, - time.Since(start).Seconds(), - ) - return response, unwrapMetricsError(err) -} - -func (s *DaemonServer) notifyInterfaceDown(ctx context.Context, - req *daemon.NotifyInterfaceDownRequest, -) (*daemon.NotifyInterfaceDownResponse, error) { - revInfo := &path_mgmt.RevInfo{ - RawIsdas: addr.IA(req.IsdAs), - IfID: iface.ID(req.Id), - LinkType: proto.LinkType_core, - RawTTL: 10, - RawTimestamp: util.TimeToSecs(time.Now()), - } - _, err := s.RevCache.Insert(ctx, revInfo) - if err != nil { - log.FromCtx(ctx).Error("Inserting revocation", "err", err, "req", req) - return nil, metricsError{ - err: serrors.Wrap("inserting revocation", err), - result: prom.ErrDB, - } - } - return &daemon.NotifyInterfaceDownResponse{}, nil -} - -// PortRange returns the port range for the dispatched ports. -func (s *DaemonServer) PortRange( - _ context.Context, - _ *emptypb.Empty, -) (*daemon.PortRangeResponse, error) { - startPort, endPort := s.Topology.PortRange() - return &daemon.PortRangeResponse{ - DispatchedPortStart: uint32(startPort), - DispatchedPortEnd: uint32(endPort), - }, nil -} - -func (s *DaemonServer) DRKeyASHost( - ctx context.Context, - req *daemon.DRKeyASHostRequest, -) (*daemon.DRKeyASHostResponse, error) { - if s.DRKeyClient == nil { - return nil, serrors.New("DRKey is not available") - } - meta, err := requestToASHostMeta(req) - if err != nil { - return nil, serrors.Wrap("parsing protobuf ASHostReq", err) - } - - lvl2Key, err := s.DRKeyClient.GetASHostKey(ctx, meta) - if err != nil { - return nil, serrors.Wrap("getting AS-Host from client store", err) - } - - return &daemon.DRKeyASHostResponse{ - EpochBegin: ×tamppb.Timestamp{Seconds: lvl2Key.Epoch.NotBefore.Unix()}, - EpochEnd: ×tamppb.Timestamp{Seconds: lvl2Key.Epoch.NotAfter.Unix()}, - Key: lvl2Key.Key[:], - }, nil -} - -func (s *DaemonServer) DRKeyHostAS( - ctx context.Context, - req *daemon.DRKeyHostASRequest, -) (*daemon.DRKeyHostASResponse, error) { - if s.DRKeyClient == nil { - return nil, serrors.New("DRKey is not available") - } - meta, err := requestToHostASMeta(req) - if err != nil { - return nil, serrors.Wrap("parsing protobuf HostASReq", err) - } - - lvl2Key, err := s.DRKeyClient.GetHostASKey(ctx, meta) - if err != nil { - return nil, serrors.Wrap("getting Host-AS from client store", err) - } - - return &daemon.DRKeyHostASResponse{ - EpochBegin: ×tamppb.Timestamp{Seconds: lvl2Key.Epoch.NotBefore.Unix()}, - EpochEnd: ×tamppb.Timestamp{Seconds: lvl2Key.Epoch.NotAfter.Unix()}, - Key: lvl2Key.Key[:], - }, nil -} - -func (s *DaemonServer) DRKeyHostHost( - ctx context.Context, - req *daemon.DRKeyHostHostRequest, -) (*daemon.DRKeyHostHostResponse, error) { - if s.DRKeyClient == nil { - return nil, serrors.New("DRKey is not available") - } - meta, err := requestToHostHostMeta(req) - if err != nil { - return nil, serrors.Wrap("parsing protobuf HostHostReq", err) - } - lvl2Key, err := s.DRKeyClient.GetHostHostKey(ctx, meta) - if err != nil { - return nil, serrors.Wrap("getting Host-Host from client store", err) - } - - return &daemon.DRKeyHostHostResponse{ - EpochBegin: ×tamppb.Timestamp{Seconds: lvl2Key.Epoch.NotBefore.Unix()}, - EpochEnd: ×tamppb.Timestamp{Seconds: lvl2Key.Epoch.NotAfter.Unix()}, - Key: lvl2Key.Key[:], - }, nil -} - -func requestToASHostMeta(req *daemon.DRKeyASHostRequest) (drkey.ASHostMeta, error) { - err := req.ValTime.CheckValid() - if err != nil { - return drkey.ASHostMeta{}, serrors.Wrap("invalid valTime from pb request", err) - } - return drkey.ASHostMeta{ - ProtoId: drkey.Protocol(req.ProtocolId), - Validity: req.ValTime.AsTime(), - SrcIA: addr.IA(req.SrcIa), - DstIA: addr.IA(req.DstIa), - DstHost: req.DstHost, - }, nil -} - -func requestToHostASMeta(req *daemon.DRKeyHostASRequest) (drkey.HostASMeta, error) { - err := req.ValTime.CheckValid() - if err != nil { - return drkey.HostASMeta{}, serrors.Wrap("invalid valTime from pb request", err) - } - return drkey.HostASMeta{ - ProtoId: drkey.Protocol(req.ProtocolId), - Validity: req.ValTime.AsTime(), - SrcIA: addr.IA(req.SrcIa), - DstIA: addr.IA(req.DstIa), - SrcHost: req.SrcHost, - }, nil -} - -func requestToHostHostMeta(req *daemon.DRKeyHostHostRequest) (drkey.HostHostMeta, error) { - err := req.ValTime.CheckValid() - if err != nil { - return drkey.HostHostMeta{}, serrors.Wrap("invalid valTime from pb request", err) - } - return drkey.HostHostMeta{ - ProtoId: drkey.Protocol(req.ProtocolId), - Validity: req.ValTime.AsTime(), - SrcIA: addr.IA(req.SrcIa), - DstIA: addr.IA(req.DstIa), - SrcHost: req.SrcHost, - DstHost: req.DstHost, - }, nil -} diff --git a/demo/stun/test-client/BUILD.bazel b/demo/stun/test-client/BUILD.bazel index ecf9e06c6f..5a8b109565 100644 --- a/demo/stun/test-client/BUILD.bazel +++ b/demo/stun/test-client/BUILD.bazel @@ -8,6 +8,7 @@ go_library( deps = [ "//pkg/addr:go_default_library", "//pkg/daemon:go_default_library", + "//pkg/daemon/types:go_default_library", "//pkg/snet:go_default_library", "@com_tailscale//net/stun:go_default_library", ], diff --git a/demo/stun/test-client/main.go b/demo/stun/test-client/main.go index f5ed0fea68..44ceadaac2 100644 --- a/demo/stun/test-client/main.go +++ b/demo/stun/test-client/main.go @@ -24,6 +24,7 @@ import ( "github.com/scionproto/scion/pkg/addr" "github.com/scionproto/scion/pkg/daemon" + daemontypes "github.com/scionproto/scion/pkg/daemon/types" "github.com/scionproto/scion/pkg/snet" "tailscale.com/net/stun" @@ -53,7 +54,7 @@ func main() { log.Fatalf("Failed to create SCION daemon connector: %v", err) } - ps, err := dc.Paths(ctx, remoteAddr.IA, localAddr.IA, daemon.PathReqFlags{Refresh: true}) + ps, err := dc.Paths(ctx, remoteAddr.IA, localAddr.IA, daemontypes.PathReqFlags{Refresh: true}) if err != nil { log.Fatalf("Failed to lookup paths: %v", err) } diff --git a/pkg/daemon/BUILD.bazel b/pkg/daemon/BUILD.bazel index 3377fca1b9..7c5eb3ad72 100644 --- a/pkg/daemon/BUILD.bazel +++ b/pkg/daemon/BUILD.bazel @@ -5,16 +5,16 @@ go_library( name = "go_default_library", srcs = [ "apitypes.go", - "daemon.go", + "connector.go", "grpc.go", - "metrics.go", + "grpc_metrics.go", "topology.go", ], importpath = "github.com/scionproto/scion/pkg/daemon", visibility = ["//visibility:public"], deps = [ "//pkg/addr:go_default_library", - "//pkg/daemon/internal/metrics:go_default_library", + "//pkg/daemon/types:go_default_library", "//pkg/drkey:go_default_library", "//pkg/grpc:go_default_library", "//pkg/log:go_default_library", diff --git a/pkg/daemon/apitypes.go b/pkg/daemon/apitypes.go index c3c66a005c..3299afb16b 100644 --- a/pkg/daemon/apitypes.go +++ b/pkg/daemon/apitypes.go @@ -20,30 +20,20 @@ import ( "net" "github.com/scionproto/scion/pkg/addr" + "github.com/scionproto/scion/pkg/daemon/types" "github.com/scionproto/scion/pkg/private/ctrl/path_mgmt" "github.com/scionproto/scion/pkg/private/serrors" "github.com/scionproto/scion/pkg/snet" "github.com/scionproto/scion/private/topology" ) -type PathReqFlags struct { - Refresh bool - Hidden bool -} - -// ASInfo provides information about the local AS. -type ASInfo struct { - IA addr.IA - MTU uint16 -} - type Querier struct { Connector Connector IA addr.IA } func (q Querier) Query(ctx context.Context, dst addr.IA) ([]snet.Path, error) { - paths, err := q.Connector.Paths(ctx, dst, q.IA, PathReqFlags{}) + paths, err := q.Connector.Paths(ctx, dst, q.IA, types.PathReqFlags{}) if err != nil { return paths, serrors.Wrap("querying paths", err, "local_isd_as", q.IA) } diff --git a/pkg/daemon/asinfo/BUILD.bazel b/pkg/daemon/asinfo/BUILD.bazel new file mode 100644 index 0000000000..b93736c3c9 --- /dev/null +++ b/pkg/daemon/asinfo/BUILD.bazel @@ -0,0 +1,15 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["asinfo.go"], + importpath = "github.com/scionproto/scion/pkg/daemon/asinfo", + visibility = ["//visibility:public"], + deps = [ + "//pkg/addr:go_default_library", + "//pkg/metrics:go_default_library", + "//pkg/private/prom:go_default_library", + "//pkg/private/serrors:go_default_library", + "//private/topology:go_default_library", + ], +) diff --git a/pkg/daemon/asinfo/asinfo.go b/pkg/daemon/asinfo/asinfo.go new file mode 100644 index 0000000000..cdfd8fa274 --- /dev/null +++ b/pkg/daemon/asinfo/asinfo.go @@ -0,0 +1,85 @@ +// Copyright 2019 Anapaya Systems +// +// 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 asinfo + +import ( + "net" + + "github.com/scionproto/scion/pkg/addr" + "github.com/scionproto/scion/pkg/metrics" + "github.com/scionproto/scion/pkg/private/prom" + "github.com/scionproto/scion/pkg/private/serrors" + "github.com/scionproto/scion/private/topology" +) + +// LocalASInfo provides control plane information for the daemon engine. +type LocalASInfo interface { + // IA returns the local ISD-AS number. + IA() addr.IA + // MTU returns the MTU of the local AS. + MTU() uint16 + // Core returns whether the local AS is core. + Core() bool + // IfIDs InterfaceIDs returns all interface IDS from the local AS. + IfIDs() []uint16 + // UnderlayNextHop returns the internal underlay address of the router + // containing the interface ID. + UnderlayNextHop(uint16) *net.UDPAddr + // ControlServiceAddresses returns the addresses of the control services + ControlServiceAddresses() []*net.UDPAddr + // PortRange returns the first and last ports of the port range (both included), + // in which endhost listen for SCION/UDP application using the UDP/IP underlay. + PortRange() (uint16, uint16) +} + +// LoadFromTopoFile loads a control plane info from a file. +// The returned LocalASInfo can be passed to NewStandaloneConnector. +func LoadFromTopoFile(topoFile string) (LocalASInfo, error) { + loader, err := topology.NewLoader( + topology.LoaderCfg{ + File: topoFile, + Reload: nil, + Validator: &topology.DefaultValidator{}, + Metrics: newLoaderMetrics(), + }, + ) + if err != nil { + return nil, serrors.Wrap("creating topology loader", err) + } + return loader, nil +} + +// newLoaderMetrics creates metrics for the topology loader. +func newLoaderMetrics() topology.LoaderMetrics { + updates := prom.NewCounterVec( + "", "", + "topology_updates_total", + "The total number of updates.", + []string{prom.LabelResult}, + ) + return topology.LoaderMetrics{ + ValidationErrors: metrics.NewPromCounter(updates).With(prom.LabelResult, "err_validate"), + ReadErrors: metrics.NewPromCounter(updates).With(prom.LabelResult, "err_read"), + LastUpdate: metrics.NewPromGauge( + prom.NewGaugeVec( + "", "", + "topology_last_update_time", + "Timestamp of the last successful update.", + []string{}, + ), + ), + Updates: metrics.NewPromCounter(updates).With(prom.LabelResult, prom.Success), + } +} diff --git a/pkg/daemon/daemon.go b/pkg/daemon/connector.go similarity index 66% rename from pkg/daemon/daemon.go rename to pkg/daemon/connector.go index c6d41eda4b..a54543a218 100644 --- a/pkg/daemon/daemon.go +++ b/pkg/daemon/connector.go @@ -13,7 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package daemon provides APIs for querying SCION Daemons. package daemon import ( @@ -21,43 +20,12 @@ import ( "net/netip" "github.com/scionproto/scion/pkg/addr" - "github.com/scionproto/scion/pkg/daemon/internal/metrics" + "github.com/scionproto/scion/pkg/daemon/types" "github.com/scionproto/scion/pkg/drkey" - libmetrics "github.com/scionproto/scion/pkg/metrics" "github.com/scionproto/scion/pkg/private/ctrl/path_mgmt" - "github.com/scionproto/scion/pkg/private/serrors" "github.com/scionproto/scion/pkg/snet" ) -// Errors for SCION Daemon API requests -var ( - ErrUnableToConnect = serrors.New("unable to connect to the SCION Daemon") -) - -const ( - // DefaultAPIAddress contains the system default for a daemon API socket. - DefaultAPIAddress = "127.0.0.1:30255" - // DefaultAPIPort contains the default port for a daemon client API socket. - DefaultAPIPort = 30255 -) - -// NewService returns a SCION Daemon API connection factory. -// Deprecated: Use Service struct directly instead. -func NewService(name string) Service { - return Service{ - Address: name, - Metrics: Metrics{ - Connects: libmetrics.NewPromCounter(metrics.Conns.CounterVec()), - PathsRequests: libmetrics.NewPromCounter( - metrics.PathRequests.CounterVec()), - ASRequests: libmetrics.NewPromCounter(metrics.ASInfos.CounterVec()), - InterfacesRequests: libmetrics.NewPromCounter(metrics.IFInfos.CounterVec()), - ServicesRequests: libmetrics.NewPromCounter(metrics.SVCInfos.CounterVec()), - InterfaceDownNotifications: libmetrics.NewPromCounter(metrics.Revocations.CounterVec()), - }, - } -} - // A Connector is used to query the SCION daemon. All connector methods block until // either an error occurs, or the method successfully returns. type Connector interface { @@ -70,10 +38,10 @@ type Connector interface { // Interfaces returns the map of interface identifiers to the underlay internal address. Interfaces(ctx context.Context) (map[uint16]netip.AddrPort, error) // Paths requests from the daemon a set of end to end paths between the source and destination. - Paths(ctx context.Context, dst, src addr.IA, f PathReqFlags) ([]snet.Path, error) + Paths(ctx context.Context, dst, src addr.IA, f types.PathReqFlags) ([]snet.Path, error) // ASInfo requests from the daemon information about AS ia, the zero IA can be // used to detect the local IA. - ASInfo(ctx context.Context, ia addr.IA) (ASInfo, error) + ASInfo(ctx context.Context, ia addr.IA) (types.ASInfo, error) // SVCInfo requests from the daemon information about addresses and ports of // infrastructure services. Slice svcTypes contains a list of desired // service types. If unset, a fresh (i.e., uncached) answer containing all diff --git a/daemon/fetcher/BUILD.bazel b/pkg/daemon/fetcher/BUILD.bazel similarity index 85% rename from daemon/fetcher/BUILD.bazel rename to pkg/daemon/fetcher/BUILD.bazel index ff080f4d6a..62e86ef8eb 100644 --- a/daemon/fetcher/BUILD.bazel +++ b/pkg/daemon/fetcher/BUILD.bazel @@ -3,10 +3,9 @@ load("@rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["fetcher.go"], - importpath = "github.com/scionproto/scion/daemon/fetcher", + importpath = "github.com/scionproto/scion/pkg/daemon/fetcher", visibility = ["//visibility:public"], deps = [ - "//daemon/config:go_default_library", "//pkg/addr:go_default_library", "//pkg/private/serrors:go_default_library", "//pkg/snet:go_default_library", diff --git a/daemon/fetcher/fetcher.go b/pkg/daemon/fetcher/fetcher.go similarity index 92% rename from daemon/fetcher/fetcher.go rename to pkg/daemon/fetcher/fetcher.go index 63206b0995..d558517177 100644 --- a/daemon/fetcher/fetcher.go +++ b/pkg/daemon/fetcher/fetcher.go @@ -21,7 +21,6 @@ import ( "net" "time" - "github.com/scionproto/scion/daemon/config" "github.com/scionproto/scion/pkg/addr" "github.com/scionproto/scion/pkg/private/serrors" "github.com/scionproto/scion/pkg/snet" @@ -33,10 +32,6 @@ import ( "github.com/scionproto/scion/private/trust" ) -const ( - DefaultMinWorkerLifetime = 10 * time.Second -) - type TrustStore interface { trust.Inspector } @@ -47,7 +42,6 @@ type Fetcher interface { type fetcher struct { pather segfetcher.Pather - config config.SDConfig } type FetcherConfig struct { @@ -62,9 +56,9 @@ type FetcherConfig struct { PathDB pathdb.DB Inspector trust.Inspector - Verifier infra.Verifier - RevCache revcache.RevCache - Cfg config.SDConfig + Verifier infra.Verifier + RevCache revcache.RevCache + QueryInterval time.Duration } func NewFetcher(cfg FetcherConfig) Fetcher { @@ -75,7 +69,7 @@ func NewFetcher(cfg FetcherConfig) Fetcher { NextHopper: cfg.NextHopper, RevCache: cfg.RevCache, Fetcher: &segfetcher.Fetcher{ - QueryInterval: cfg.Cfg.QueryInterval.Duration, + QueryInterval: cfg.QueryInterval, PathDB: cfg.PathDB, Resolver: segfetcher.NewResolver( cfg.PathDB, @@ -101,7 +95,6 @@ func NewFetcher(cfg FetcherConfig) Fetcher { Inspector: cfg.Inspector, }, }, - config: cfg.Cfg, } } diff --git a/daemon/fetcher/mock_fetcher/BUILD.bazel b/pkg/daemon/fetcher/mock_fetcher/BUILD.bazel similarity index 76% rename from daemon/fetcher/mock_fetcher/BUILD.bazel rename to pkg/daemon/fetcher/mock_fetcher/BUILD.bazel index f87ba9414e..ea2bf02cb5 100644 --- a/daemon/fetcher/mock_fetcher/BUILD.bazel +++ b/pkg/daemon/fetcher/mock_fetcher/BUILD.bazel @@ -4,14 +4,14 @@ gomock( name = "go_default_mock", out = "mock.go", interfaces = ["Fetcher"], - library = "//daemon/fetcher:go_default_library", + library = "//pkg/daemon/fetcher:go_default_library", package = "mock_fetcher", ) go_library( name = "go_default_library", srcs = ["mock.go"], - importpath = "github.com/scionproto/scion/daemon/fetcher/mock_fetcher", + importpath = "github.com/scionproto/scion/pkg/daemon/fetcher/mock_fetcher", visibility = ["//visibility:public"], deps = [ "//pkg/addr:go_default_library", diff --git a/daemon/fetcher/mock_fetcher/mock.go b/pkg/daemon/fetcher/mock_fetcher/mock.go similarity index 95% rename from daemon/fetcher/mock_fetcher/mock.go rename to pkg/daemon/fetcher/mock_fetcher/mock.go index 6ef59091ee..999d583b57 100644 --- a/daemon/fetcher/mock_fetcher/mock.go +++ b/pkg/daemon/fetcher/mock_fetcher/mock.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/scionproto/scion/daemon/fetcher (interfaces: Fetcher) +// Source: github.com/scionproto/scion/pkg/daemon/fetcher (interfaces: Fetcher) // Package mock_fetcher is a generated GoMock package. package mock_fetcher diff --git a/pkg/daemon/grpc.go b/pkg/daemon/grpc.go index ce28397d41..a43d7aa742 100644 --- a/pkg/daemon/grpc.go +++ b/pkg/daemon/grpc.go @@ -26,9 +26,12 @@ import ( "google.golang.org/protobuf/types/known/timestamppb" "github.com/scionproto/scion/pkg/addr" + daemontypes "github.com/scionproto/scion/pkg/daemon/types" "github.com/scionproto/scion/pkg/drkey" libgrpc "github.com/scionproto/scion/pkg/grpc" + libmetrics "github.com/scionproto/scion/pkg/metrics" "github.com/scionproto/scion/pkg/private/ctrl/path_mgmt" + "github.com/scionproto/scion/pkg/private/prom" "github.com/scionproto/scion/pkg/private/serrors" sdpb "github.com/scionproto/scion/pkg/proto/daemon" dkpb "github.com/scionproto/scion/pkg/proto/drkey" @@ -38,6 +41,66 @@ import ( "github.com/scionproto/scion/private/topology" ) +const ( + // DefaultAPIAddress contains the system default for a daemon API socket. + DefaultAPIAddress = "127.0.0.1:30255" + // DefaultAPIPort contains the default port for a daemon client API socket. + DefaultAPIPort = 30255 + // defaultConnectionTimeout contains the default timeout for a daemon connection. + defaultConnectionTimeout = time.Second +) + +// NewService returns a SCION Daemon API connection factory. +func NewService(name string) Service { + return Service{ + Address: name, + Metrics: Metrics{ + Connects: libmetrics.NewPromCounter( + prom.NewCounterVecWithLabels( + "lib_sciond", "conn", "connections_total", + "The amount of SCIOND connection attempts.", promLabels{}, + ), + ), + PathsRequests: libmetrics.NewPromCounter( + prom.NewCounterVecWithLabels( + "lib_sciond", "path", "requests_total", + "The amount of Path requests sent.", promLabels{}, + ), + ), + ASRequests: libmetrics.NewPromCounter( + prom.NewCounterVecWithLabels( + "lib_sciond", "as_info", "requests_total", + "The amount of AS info requests sent.", promLabels{}, + ), + ), + InterfacesRequests: libmetrics.NewPromCounter( + prom.NewCounterVecWithLabels( + "lib_sciond", "if_info", "requests_total", + "The amount of IF info requests sent.", promLabels{}, + ), + ), + ServicesRequests: libmetrics.NewPromCounter( + prom.NewCounterVecWithLabels( + "lib_sciond", "service_info", "requests_total", + "The amount of SVC info requests sent.", promLabels{}, + ), + ), + InterfaceDownNotifications: libmetrics.NewPromCounter( + prom.NewCounterVecWithLabels( + "lib_sciond", "revocation", "requests_total", + "The amount of Revocation requests sent.", promLabels{}, + ), + ), + }, + } +} + +// promLabels implements prom.Labels for result label. +type promLabels struct{} + +func (promLabels) Labels() []string { return []string{prom.LabelResult} } +func (promLabels) Values() []string { return []string{""} } + // Service exposes the API to connect to a SCION daemon service. type Service struct { // Address is the address of the SCION daemon to connect to. @@ -47,7 +110,7 @@ type Service struct { Metrics Metrics } -func (s Service) Connect(ctx context.Context) (Connector, error) { +func (s Service) Connect(_ context.Context) (Connector, error) { conn, err := grpc.NewClient(s.Address, grpc.WithTransportCredentials(insecure.NewCredentials()), libgrpc.UnaryClientInterceptor(), @@ -105,7 +168,7 @@ func (c grpcConn) Interfaces(ctx context.Context) (map[uint16]netip.AddrPort, er } func (c grpcConn) Paths(ctx context.Context, dst, src addr.IA, - f PathReqFlags) ([]snet.Path, error) { + f daemontypes.PathReqFlags) ([]snet.Path, error) { client := sdpb.NewDaemonServiceClient(c.conn) response, err := client.Paths(ctx, &sdpb.PathsRequest{ @@ -123,15 +186,15 @@ func (c grpcConn) Paths(ctx context.Context, dst, src addr.IA, return paths, err } -func (c grpcConn) ASInfo(ctx context.Context, ia addr.IA) (ASInfo, error) { +func (c grpcConn) ASInfo(ctx context.Context, ia addr.IA) (daemontypes.ASInfo, error) { client := sdpb.NewDaemonServiceClient(c.conn) response, err := client.AS(ctx, &sdpb.ASRequest{IsdAs: uint64(ia)}) if err != nil { c.metrics.incAS(err) - return ASInfo{}, err + return daemontypes.ASInfo{}, err } c.metrics.incAS(nil) - return ASInfo{ + return daemontypes.ASInfo{ IA: addr.IA(response.IsdAs), MTU: uint16(response.Mtu), }, nil diff --git a/pkg/daemon/metrics.go b/pkg/daemon/grpc_metrics.go similarity index 100% rename from pkg/daemon/metrics.go rename to pkg/daemon/grpc_metrics.go diff --git a/pkg/daemon/internal/metrics/BUILD.bazel b/pkg/daemon/internal/metrics/BUILD.bazel deleted file mode 100644 index 40203989fa..0000000000 --- a/pkg/daemon/internal/metrics/BUILD.bazel +++ /dev/null @@ -1,12 +0,0 @@ -load("@rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = ["metrics.go"], - importpath = "github.com/scionproto/scion/pkg/daemon/internal/metrics", - visibility = ["//pkg/daemon:__subpackages__"], - deps = [ - "//pkg/private/prom:go_default_library", - "@com_github_prometheus_client_golang//prometheus:go_default_library", - ], -) diff --git a/pkg/daemon/internal/metrics/metrics.go b/pkg/daemon/internal/metrics/metrics.go deleted file mode 100644 index 5f28d475df..0000000000 --- a/pkg/daemon/internal/metrics/metrics.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2019 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 metrics - -import ( - "github.com/prometheus/client_golang/prometheus" - - "github.com/scionproto/scion/pkg/private/prom" -) - -const ( - // Namespace is the metrics namespace for the SCIOND client API. - Namespace = "lib_sciond" - - subsystemConn = "conn" - subsystemPath = "path" - subsystemASInfo = "as_info" - subsystemIFInfo = "if_info" - subsystemSVCInfo = "service_info" - subsystemRevocation = "revocation" -) - -// Result values -const ( - OkSuccess = prom.Success - ErrTimeout = prom.ErrTimeout - ErrNotClassified = prom.ErrNotClassified -) - -type resultLabel struct { - Result string -} - -// Labels returns the labels. -func (l resultLabel) Labels() []string { - return []string{prom.LabelResult} -} - -// Values returns the values for the labels. -func (l resultLabel) Values() []string { - return []string{l.Result} -} - -// Metric accessors. -var ( - // PathRequests contains metrics for path requests. - PathRequests = newPathRequest() - // Revocations contains metrics for revocations. - Revocations = newRevocation() - // ASInfos contains metrics for AS info requests. - ASInfos = newASInfoRequest() - // IFInfos contains metrics for IF info requests. - IFInfos = newIFInfo() - // SVCInfos contains metrics for SVC info requests. - SVCInfos = newSVCInfo() - // Conns contains metrics for connections to SCIOND. - Conns = newConn() -) - -// Request is the generic metric for requests. -type Request struct { - count *prometheus.CounterVec -} - -func (r *Request) CounterVec() *prometheus.CounterVec { - return r.count -} - -// Inc increases the metric count. The result parameter is used to label the increment. -func (r Request) Inc(result string) { - r.count.WithLabelValues(result).Inc() -} - -func newConn() Request { - return Request{ - count: prom.NewCounterVecWithLabels(Namespace, subsystemConn, "connections_total", - "The amount of SCIOND connection attempts.", resultLabel{}), - } -} - -func newPathRequest() Request { - return Request{ - count: prom.NewCounterVecWithLabels(Namespace, subsystemPath, "requests_total", - "The amount of Path requests sent.", resultLabel{}), - } -} - -func newRevocation() Request { - return Request{ - count: prom.NewCounterVecWithLabels(Namespace, subsystemRevocation, "requests_total", - "The amount of Revocation requests sent.", resultLabel{}), - } -} - -func newASInfoRequest() Request { - return Request{ - count: prom.NewCounterVecWithLabels(Namespace, subsystemASInfo, "requests_total", - "The amount of AS info requests sent.", resultLabel{}), - } -} - -func newSVCInfo() Request { - return Request{ - count: prom.NewCounterVecWithLabels(Namespace, subsystemSVCInfo, "requests_total", - "The amount of SVC info requests sent.", resultLabel{}), - } -} - -func newIFInfo() Request { - return Request{ - count: prom.NewCounterVecWithLabels(Namespace, subsystemIFInfo, "requests_total", - "The amount of IF info requests sent.", resultLabel{}), - } -} diff --git a/pkg/daemon/mock_daemon/BUILD.bazel b/pkg/daemon/mock_daemon/BUILD.bazel index d28cdfe2f2..1a7669964b 100644 --- a/pkg/daemon/mock_daemon/BUILD.bazel +++ b/pkg/daemon/mock_daemon/BUILD.bazel @@ -15,7 +15,7 @@ go_library( visibility = ["//visibility:public"], deps = [ "//pkg/addr:go_default_library", - "//pkg/daemon:go_default_library", + "//pkg/daemon/types:go_default_library", "//pkg/drkey:go_default_library", "//pkg/private/ctrl/path_mgmt:go_default_library", "//pkg/snet:go_default_library", diff --git a/pkg/daemon/mock_daemon/mock.go b/pkg/daemon/mock_daemon/mock.go index 05a868518c..4ae9db9e38 100644 --- a/pkg/daemon/mock_daemon/mock.go +++ b/pkg/daemon/mock_daemon/mock.go @@ -11,7 +11,7 @@ import ( gomock "github.com/golang/mock/gomock" addr "github.com/scionproto/scion/pkg/addr" - daemon "github.com/scionproto/scion/pkg/daemon" + types "github.com/scionproto/scion/pkg/daemon/types" drkey "github.com/scionproto/scion/pkg/drkey" path_mgmt "github.com/scionproto/scion/pkg/private/ctrl/path_mgmt" snet "github.com/scionproto/scion/pkg/snet" @@ -41,10 +41,10 @@ func (m *MockConnector) EXPECT() *MockConnectorMockRecorder { } // ASInfo mocks base method. -func (m *MockConnector) ASInfo(arg0 context.Context, arg1 addr.IA) (daemon.ASInfo, error) { +func (m *MockConnector) ASInfo(arg0 context.Context, arg1 addr.IA) (types.ASInfo, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ASInfo", arg0, arg1) - ret0, _ := ret[0].(daemon.ASInfo) + ret0, _ := ret[0].(types.ASInfo) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -145,7 +145,7 @@ func (mr *MockConnectorMockRecorder) LocalIA(arg0 interface{}) *gomock.Call { } // Paths mocks base method. -func (m *MockConnector) Paths(arg0 context.Context, arg1, arg2 addr.IA, arg3 daemon.PathReqFlags) ([]snet.Path, error) { +func (m *MockConnector) Paths(arg0 context.Context, arg1, arg2 addr.IA, arg3 types.PathReqFlags) ([]snet.Path, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Paths", arg0, arg1, arg2, arg3) ret0, _ := ret[0].([]snet.Path) diff --git a/pkg/daemon/private/engine/BUILD.bazel b/pkg/daemon/private/engine/BUILD.bazel new file mode 100644 index 0000000000..d72174d529 --- /dev/null +++ b/pkg/daemon/private/engine/BUILD.bazel @@ -0,0 +1,28 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["engine.go"], + importpath = "github.com/scionproto/scion/pkg/daemon/private/engine", + visibility = ["//visibility:public"], + deps = [ + "//pkg/addr:go_default_library", + "//pkg/daemon/asinfo:go_default_library", + "//pkg/daemon/fetcher:go_default_library", + "//pkg/daemon/types:go_default_library", + "//pkg/drkey:go_default_library", + "//pkg/log:go_default_library", + "//pkg/private/ctrl/path_mgmt:go_default_library", + "//pkg/private/ctrl/path_mgmt/proto:go_default_library", + "//pkg/private/prom:go_default_library", + "//pkg/private/serrors:go_default_library", + "//pkg/private/util:go_default_library", + "//pkg/segment/iface:go_default_library", + "//pkg/snet:go_default_library", + "//private/drkey:go_default_library", + "//private/revcache:go_default_library", + "//private/trust:go_default_library", + "@com_github_opentracing_opentracing_go//:go_default_library", + "@org_golang_x_sync//singleflight:go_default_library", + ], +) diff --git a/pkg/daemon/private/engine/engine.go b/pkg/daemon/private/engine/engine.go new file mode 100644 index 0000000000..dc6f329c26 --- /dev/null +++ b/pkg/daemon/private/engine/engine.go @@ -0,0 +1,237 @@ +// Copyright 2020 Anapaya Systems +// +// 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 engine + +import ( + "context" + "fmt" + "net/netip" + "time" + + "github.com/opentracing/opentracing-go" + "golang.org/x/sync/singleflight" + + "github.com/scionproto/scion/pkg/addr" + "github.com/scionproto/scion/pkg/daemon/asinfo" + "github.com/scionproto/scion/pkg/daemon/fetcher" + "github.com/scionproto/scion/pkg/daemon/types" + "github.com/scionproto/scion/pkg/drkey" + "github.com/scionproto/scion/pkg/log" + "github.com/scionproto/scion/pkg/private/ctrl/path_mgmt" + "github.com/scionproto/scion/pkg/private/ctrl/path_mgmt/proto" + "github.com/scionproto/scion/pkg/private/prom" + "github.com/scionproto/scion/pkg/private/serrors" + "github.com/scionproto/scion/pkg/private/util" + "github.com/scionproto/scion/pkg/segment/iface" + "github.com/scionproto/scion/pkg/snet" + drkey_daemon "github.com/scionproto/scion/private/drkey" + "github.com/scionproto/scion/private/revcache" + "github.com/scionproto/scion/private/trust" +) + +// DaemonEngine contains the core daemon logic, independent of the transport layer. +// It can be used directly by in-process clients or wrapped by the gRPC server. +type DaemonEngine struct { + IA addr.IA + MTU uint16 + LocalASInfo asinfo.LocalASInfo + Fetcher fetcher.Fetcher + RevCache revcache.RevCache + ASInspector trust.Inspector + DRKeyClient *drkey_daemon.ClientEngine + + foregroundPathDedupe singleflight.Group + backgroundPathDedupe singleflight.Group +} + +// LocalIA returns the local ISD-AS number. +func (e *DaemonEngine) LocalIA(_ context.Context) (addr.IA, error) { + return e.IA, nil +} + +// PortRange returns the dispatched port range. +func (e *DaemonEngine) PortRange(_ context.Context) (uint16, uint16, error) { + start, end := e.LocalASInfo.PortRange() + return start, end, nil +} + +// Interfaces returns the map of interface identifiers to the underlay internal address. +func (e *DaemonEngine) Interfaces(_ context.Context) (map[uint16]netip.AddrPort, error) { + result := make(map[uint16]netip.AddrPort) + topo := e.LocalASInfo + for _, ifID := range topo.IfIDs() { + nextHop := topo.UnderlayNextHop(ifID) + if nextHop == nil { + continue + } + result[ifID] = nextHop.AddrPort() + } + return result, nil +} + +// Paths requests a set of end to end paths between the source and destination. +func (e *DaemonEngine) Paths( + ctx context.Context, + dst, src addr.IA, + flags types.PathReqFlags, +) ([]snet.Path, error) { + if _, ok := ctx.Deadline(); !ok { + var cancelF context.CancelFunc + ctx, cancelF = context.WithTimeout(ctx, 10*time.Second) + defer cancelF() + } + go func() { + defer log.HandlePanic() + e.backgroundPaths(ctx, src, dst, flags.Refresh) + }() + paths, err := e.fetchPaths(ctx, &e.foregroundPathDedupe, src, dst, flags.Refresh) + if err != nil { + log.FromCtx(ctx).Debug( + "Fetching paths", "err", err, + "src", src, "dst", dst, "refresh", flags.Refresh, + ) + return nil, err + } + return paths, nil +} + +func (e *DaemonEngine) fetchPaths( + ctx context.Context, + group *singleflight.Group, + src, dst addr.IA, + refresh bool, +) ([]snet.Path, error) { + r, err, _ := group.Do( + fmt.Sprintf("%s%s%t", src, dst, refresh), + func() (any, error) { + return e.Fetcher.GetPaths(ctx, src, dst, refresh) + }, + ) + paths, _ := r.([]snet.Path) + return paths, err +} + +func (e *DaemonEngine) backgroundPaths(origCtx context.Context, src, dst addr.IA, refresh bool) { + backgroundTimeout := 5 * time.Second + deadline, ok := origCtx.Deadline() + if !ok || time.Until(deadline) > backgroundTimeout { + return + } + ctx, cancelF := context.WithTimeout(context.Background(), backgroundTimeout) + defer cancelF() + var spanOpts []opentracing.StartSpanOption + if span := opentracing.SpanFromContext(origCtx); span != nil { + spanOpts = append(spanOpts, opentracing.FollowsFrom(span.Context())) + } + span, ctx := opentracing.StartSpanFromContext(ctx, "fetch.paths.background", spanOpts...) + defer span.Finish() + //nolint:contextcheck + if _, err := e.fetchPaths(ctx, &e.backgroundPathDedupe, src, dst, refresh); err != nil { + log.FromCtx(ctx).Debug( + "Error fetching paths (background)", "err", err, + "src", src, "dst", dst, "refresh", refresh, + ) + } +} + +// ASInfo requests information about an AS. The zero IA returns local AS info. +func (e *DaemonEngine) ASInfo(_ context.Context, ia addr.IA) (types.ASInfo, error) { + reqIA := ia + if reqIA.IsZero() { + reqIA = e.IA + } + mtu := uint16(0) + if reqIA.Equal(e.IA) { + mtu = e.MTU + } + return types.ASInfo{ + IA: reqIA, + MTU: mtu, + }, nil +} + +// SVCInfo requests information about addresses and ports of infrastructure services. +func (e *DaemonEngine) SVCInfo(_ context.Context) ([]string, error) { + var uris []string + for _, h := range e.LocalASInfo.ControlServiceAddresses() { + uris = append(uris, h.String()) + } + return uris, nil +} + +// NotifyInterfaceDown notifies about an interface that is down. +func (e *DaemonEngine) NotifyInterfaceDown(ctx context.Context, ia addr.IA, ifID uint64) error { + revInfo := &path_mgmt.RevInfo{ + RawIsdas: ia, + IfID: iface.ID(ifID), + LinkType: proto.LinkType_core, + RawTTL: 10, + RawTimestamp: util.TimeToSecs(time.Now()), + } + _, err := e.RevCache.Insert(ctx, revInfo) + if err != nil { + log.FromCtx(ctx).Error( + "Inserting revocation", "err", err, + "isd_as", ia, "if_id", ifID, + ) + return metricsError{ + err: serrors.Wrap("inserting revocation", err), + result: prom.ErrDB, + } + } + return nil +} + +// DRKeyGetASHostKey requests an AS-Host Key. +func (e *DaemonEngine) DRKeyGetASHostKey( + ctx context.Context, + meta drkey.ASHostMeta, +) (drkey.ASHostKey, error) { + if e.DRKeyClient == nil { + return drkey.ASHostKey{}, serrors.New("DRKey is not available") + } + return e.DRKeyClient.GetASHostKey(ctx, meta) +} + +// DRKeyGetHostASKey requests a Host-AS Key. +func (e *DaemonEngine) DRKeyGetHostASKey( + ctx context.Context, + meta drkey.HostASMeta, +) (drkey.HostASKey, error) { + if e.DRKeyClient == nil { + return drkey.HostASKey{}, serrors.New("DRKey is not available") + } + return e.DRKeyClient.GetHostASKey(ctx, meta) +} + +// DRKeyGetHostHostKey requests a Host-Host Key. +func (e *DaemonEngine) DRKeyGetHostHostKey( + ctx context.Context, + meta drkey.HostHostMeta, +) (drkey.HostHostKey, error) { + if e.DRKeyClient == nil { + return drkey.HostHostKey{}, serrors.New("DRKey is not available") + } + return e.DRKeyClient.GetHostHostKey(ctx, meta) +} + +type metricsError struct { + err error + result string +} + +func (e metricsError) Error() string { + return e.err.Error() +} diff --git a/pkg/daemon/private/trust/BUILD.bazel b/pkg/daemon/private/trust/BUILD.bazel new file mode 100644 index 0000000000..144251894b --- /dev/null +++ b/pkg/daemon/private/trust/BUILD.bazel @@ -0,0 +1,18 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["trust.go"], + importpath = "github.com/scionproto/scion/pkg/daemon/private/trust", + visibility = ["//visibility:public"], + deps = [ + "//pkg/addr:go_default_library", + "//pkg/grpc:go_default_library", + "//pkg/log:go_default_library", + "//pkg/metrics:go_default_library", + "//pkg/private/serrors:go_default_library", + "//private/trust:go_default_library", + "//private/trust/grpc:go_default_library", + "//private/trust/metrics:go_default_library", + ], +) diff --git a/pkg/daemon/private/trust/trust.go b/pkg/daemon/private/trust/trust.go new file mode 100644 index 0000000000..36417b04a2 --- /dev/null +++ b/pkg/daemon/private/trust/trust.go @@ -0,0 +1,82 @@ +// Copyright 2025 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 trust + +import ( + "context" + "errors" + + "github.com/scionproto/scion/pkg/addr" + "github.com/scionproto/scion/pkg/grpc" + "github.com/scionproto/scion/pkg/log" + "github.com/scionproto/scion/pkg/metrics" + "github.com/scionproto/scion/pkg/private/serrors" + "github.com/scionproto/scion/private/trust" + trustgrpc "github.com/scionproto/scion/private/trust/grpc" + trustmetrics "github.com/scionproto/scion/private/trust/metrics" +) + +// NewEngine builds the trust engine backed by the trust database. +func NewEngine( + ctx context.Context, + certsDir string, + ia addr.IA, + db trust.DB, + dialer grpc.Dialer, +) (trust.Engine, error) { + loaded, err := trust.LoadTRCs(ctx, certsDir, db) + if err != nil { + return trust.Engine{}, serrors.Wrap("loading TRCs", err) + } + log.Info("TRCs loaded", "files", loaded.Loaded) + for f, r := range loaded.Ignored { + if errors.Is(r, trust.ErrAlreadyExists) { + log.Debug("Ignoring existing TRC", "file", f) + continue + } + log.Info("Ignoring non-TRC", "file", f, "reason", r) + } + loaded, err = trust.LoadChains(ctx, certsDir, db) + if err != nil { + return trust.Engine{}, serrors.Wrap("loading certificate chains", + err) + } + log.Info("Certificate chains loaded", "files", loaded.Loaded) + for f, r := range loaded.Ignored { + if errors.Is(r, trust.ErrAlreadyExists) { + log.Debug("Ignoring existing certificate chain", "file", f) + continue + } + if errors.Is(r, trust.ErrOutsideValidity) { + log.Debug("Ignoring certificate chain outside validity", "file", f) + continue + } + log.Info("Ignoring non-certificate chain", "file", f, "reason", r) + } + return trust.Engine{ + Inspector: trust.DBInspector{DB: db}, + Provider: trust.FetchingProvider{ + DB: db, + Fetcher: trustgrpc.Fetcher{ + IA: ia, + Dialer: dialer, + Requests: metrics.NewPromCounter(trustmetrics.RPC.Fetches), + }, + Recurser: trust.LocalOnlyRecurser{}, + Router: trust.LocalRouter{IA: ia}, + }, + DB: db, + }, nil +} diff --git a/pkg/daemon/topology.go b/pkg/daemon/topology.go index b1a76b6e96..bb47b2cd2a 100644 --- a/pkg/daemon/topology.go +++ b/pkg/daemon/topology.go @@ -108,7 +108,7 @@ func (t *ReloadingTopology) Run(ctx context.Context, period time.Duration) { defer ticker.Stop() reload := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + ctx, cancel := context.WithTimeout(ctx, defaultConnectionTimeout) defer cancel() if err := t.loadInterfaces(ctx); err != nil { log.FromCtx(ctx).Error("Failed to reload interfaces", "err", err) diff --git a/pkg/daemon/types/BUILD.bazel b/pkg/daemon/types/BUILD.bazel new file mode 100644 index 0000000000..4e4e3d2541 --- /dev/null +++ b/pkg/daemon/types/BUILD.bazel @@ -0,0 +1,9 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["types.go"], + importpath = "github.com/scionproto/scion/pkg/daemon/types", + visibility = ["//visibility:public"], + deps = ["//pkg/addr:go_default_library"], +) diff --git a/pkg/daemon/types/types.go b/pkg/daemon/types/types.go new file mode 100644 index 0000000000..e0284a8603 --- /dev/null +++ b/pkg/daemon/types/types.go @@ -0,0 +1,31 @@ +// Copyright 2019 Anapaya Systems +// +// 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 types + +import ( + "github.com/scionproto/scion/pkg/addr" +) + +// PathReqFlags contains flags for path requests. +type PathReqFlags struct { + Refresh bool + Hidden bool +} + +// ASInfo provides information about the local AS. +type ASInfo struct { + IA addr.IA + MTU uint16 +} diff --git a/private/app/path/BUILD.bazel b/private/app/path/BUILD.bazel index bd4d560f45..fa6e9ae6cd 100644 --- a/private/app/path/BUILD.bazel +++ b/private/app/path/BUILD.bazel @@ -9,6 +9,7 @@ go_library( deps = [ "//pkg/addr:go_default_library", "//pkg/daemon:go_default_library", + "//pkg/daemon/types:go_default_library", "//pkg/private/serrors:go_default_library", "//pkg/snet:go_default_library", "//pkg/snet/path:go_default_library", diff --git a/private/app/path/path.go b/private/app/path/path.go index b003a4bbfe..126e12a64d 100644 --- a/private/app/path/path.go +++ b/private/app/path/path.go @@ -30,6 +30,7 @@ import ( "github.com/scionproto/scion/pkg/addr" "github.com/scionproto/scion/pkg/daemon" + daemontypes "github.com/scionproto/scion/pkg/daemon/types" "github.com/scionproto/scion/pkg/private/serrors" "github.com/scionproto/scion/pkg/snet" snetpath "github.com/scionproto/scion/pkg/snet/path" @@ -173,7 +174,7 @@ func fetchPaths( refresh bool, seq string, ) ([]snet.Path, error) { - allPaths, err := conn.Paths(ctx, remote, 0, daemon.PathReqFlags{Refresh: refresh}) + allPaths, err := conn.Paths(ctx, remote, 0, daemontypes.PathReqFlags{Refresh: refresh}) if err != nil { return nil, serrors.Wrap("retrieving paths", err) } diff --git a/daemon/drkey/BUILD.bazel b/private/drkey/BUILD.bazel similarity index 85% rename from daemon/drkey/BUILD.bazel rename to private/drkey/BUILD.bazel index a32adb9e83..734c0feae5 100644 --- a/daemon/drkey/BUILD.bazel +++ b/private/drkey/BUILD.bazel @@ -3,7 +3,7 @@ load("@rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["client_engine.go"], - importpath = "github.com/scionproto/scion/daemon/drkey", + importpath = "github.com/scionproto/scion/private/drkey", visibility = ["//visibility:public"], deps = [ "//pkg/addr:go_default_library", diff --git a/daemon/drkey/client_engine.go b/private/drkey/client_engine.go similarity index 100% rename from daemon/drkey/client_engine.go rename to private/drkey/client_engine.go diff --git a/daemon/drkey/grpc/BUILD.bazel b/private/drkey/grpc/BUILD.bazel similarity index 91% rename from daemon/drkey/grpc/BUILD.bazel rename to private/drkey/grpc/BUILD.bazel index 65b1a706c4..d165842555 100644 --- a/daemon/drkey/grpc/BUILD.bazel +++ b/private/drkey/grpc/BUILD.bazel @@ -7,7 +7,7 @@ go_library( "fetcher.go", "protobuf.go", ], - importpath = "github.com/scionproto/scion/daemon/drkey/grpc", + importpath = "github.com/scionproto/scion/private/drkey/grpc", visibility = ["//visibility:public"], deps = [ "//pkg/addr:go_default_library", @@ -26,11 +26,11 @@ go_test( srcs = ["fetching_test.go"], deps = [ ":go_default_library", - "//daemon/drkey:go_default_library", "//pkg/drkey:go_default_library", "//pkg/private/xtest:go_default_library", "//pkg/proto/control_plane:go_default_library", "//pkg/proto/control_plane/mock_control_plane:go_default_library", + "//private/drkey:go_default_library", "@com_github_golang_mock//gomock:go_default_library", "@com_github_stretchr_testify//require:go_default_library", "@org_golang_google_protobuf//types/known/timestamppb:go_default_library", diff --git a/daemon/drkey/grpc/fetcher.go b/private/drkey/grpc/fetcher.go similarity index 100% rename from daemon/drkey/grpc/fetcher.go rename to private/drkey/grpc/fetcher.go diff --git a/daemon/drkey/grpc/fetching_test.go b/private/drkey/grpc/fetching_test.go similarity index 89% rename from daemon/drkey/grpc/fetching_test.go rename to private/drkey/grpc/fetching_test.go index 25edceeab5..a5dc3f8af2 100644 --- a/daemon/drkey/grpc/fetching_test.go +++ b/private/drkey/grpc/fetching_test.go @@ -23,15 +23,15 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/protobuf/types/known/timestamppb" - sd_drkey "github.com/scionproto/scion/daemon/drkey" - sd_grpc "github.com/scionproto/scion/daemon/drkey/grpc" "github.com/scionproto/scion/pkg/drkey" "github.com/scionproto/scion/pkg/private/xtest" cppb "github.com/scionproto/scion/pkg/proto/control_plane" mock_cppb "github.com/scionproto/scion/pkg/proto/control_plane/mock_control_plane" + drkeyengine "github.com/scionproto/scion/private/drkey" + drkeygrpc "github.com/scionproto/scion/private/drkey/grpc" ) -var _ sd_drkey.Fetcher = (*sd_grpc.Fetcher)(nil) +var _ drkeyengine.Fetcher = (*drkeygrpc.Fetcher)(nil) func TestGetHostHost(t *testing.T) { ctrl := gomock.NewController(t) @@ -57,7 +57,7 @@ func TestGetHostHost(t *testing.T) { cppb.RegisterDRKeyIntraServiceServer(server.Server(), daemonSrv) server.Start(t) - fetcher := sd_grpc.Fetcher{ + fetcher := drkeygrpc.Fetcher{ Dialer: server, } diff --git a/daemon/drkey/grpc/protobuf.go b/private/drkey/grpc/protobuf.go similarity index 100% rename from daemon/drkey/grpc/protobuf.go rename to private/drkey/grpc/protobuf.go diff --git a/private/segment/verifier/BUILD.bazel b/private/segment/verifier/BUILD.bazel index 86d68f7125..90c24718df 100644 --- a/private/segment/verifier/BUILD.bazel +++ b/private/segment/verifier/BUILD.bazel @@ -2,12 +2,17 @@ load("@rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", - srcs = ["verifier.go"], + srcs = [ + "acceptall.go", + "verifier.go", + ], importpath = "github.com/scionproto/scion/private/segment/verifier", visibility = ["//visibility:public"], deps = [ "//pkg/addr:go_default_library", + "//pkg/proto/crypto:go_default_library", "//pkg/scrypto/cppki:go_default_library", + "//pkg/scrypto/signed:go_default_library", "//pkg/segment:go_default_library", ], ) diff --git a/private/segment/verifier/acceptall.go b/private/segment/verifier/acceptall.go new file mode 100644 index 0000000000..d888e4e92d --- /dev/null +++ b/private/segment/verifier/acceptall.go @@ -0,0 +1,48 @@ +// Copyright 2025 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 verifier + +import ( + "context" + "net" + + "github.com/scionproto/scion/pkg/addr" + "github.com/scionproto/scion/pkg/proto/crypto" + "github.com/scionproto/scion/pkg/scrypto/cppki" + "github.com/scionproto/scion/pkg/scrypto/signed" +) + +// AcceptAllVerifier accepts all path segments without verification. +// It is only intended for testing purposes. +type AcceptAllVerifier struct{} + +func (AcceptAllVerifier) Verify( + ctx context.Context, signedMsg *crypto.SignedMessage, + associatedData ...[]byte, +) (*signed.Message, error) { + return nil, nil +} + +func (v AcceptAllVerifier) WithServer(net.Addr) Verifier { + return v +} + +func (v AcceptAllVerifier) WithIA(addr.IA) Verifier { + return v +} + +func (v AcceptAllVerifier) WithValidity(cppki.Validity) Verifier { + return v +} diff --git a/scion/showpaths/BUILD.bazel b/scion/showpaths/BUILD.bazel index 892930288c..94d564eab8 100644 --- a/scion/showpaths/BUILD.bazel +++ b/scion/showpaths/BUILD.bazel @@ -11,6 +11,7 @@ go_library( deps = [ "//pkg/addr:go_default_library", "//pkg/daemon:go_default_library", + "//pkg/daemon/types:go_default_library", "//pkg/private/serrors:go_default_library", "//pkg/segment/iface:go_default_library", "//pkg/slices:go_default_library", diff --git a/scion/showpaths/showpaths.go b/scion/showpaths/showpaths.go index 2bdc397374..72c5abbcfb 100644 --- a/scion/showpaths/showpaths.go +++ b/scion/showpaths/showpaths.go @@ -26,6 +26,7 @@ import ( "github.com/scionproto/scion/pkg/addr" "github.com/scionproto/scion/pkg/daemon" + daemontypes "github.com/scionproto/scion/pkg/daemon/types" "github.com/scionproto/scion/pkg/private/serrors" "github.com/scionproto/scion/pkg/segment/iface" "github.com/scionproto/scion/pkg/slices" @@ -351,7 +352,7 @@ func Run(ctx context.Context, dst addr.IA, cfg Config) (*Result, error) { // possibility to have the same functionality, i.e. refresh, fetch all paths. // https://github.com/scionproto/scion/issues/3348 allPaths, err := sdConn.Paths(ctx, dst, 0, - daemon.PathReqFlags{Refresh: cfg.Refresh}) + daemontypes.PathReqFlags{Refresh: cfg.Refresh}) if err != nil { return nil, serrors.Wrap("retrieving paths from the SCION Daemon", err) } diff --git a/tools/end2end/BUILD.bazel b/tools/end2end/BUILD.bazel index cdad18e433..fdefde1cba 100644 --- a/tools/end2end/BUILD.bazel +++ b/tools/end2end/BUILD.bazel @@ -9,6 +9,7 @@ go_library( deps = [ "//pkg/addr:go_default_library", "//pkg/daemon:go_default_library", + "//pkg/daemon/types:go_default_library", "//pkg/log:go_default_library", "//pkg/private/common:go_default_library", "//pkg/private/serrors:go_default_library", diff --git a/tools/end2end/main.go b/tools/end2end/main.go index 7c15964678..9f9e31931c 100644 --- a/tools/end2end/main.go +++ b/tools/end2end/main.go @@ -37,6 +37,7 @@ import ( "github.com/scionproto/scion/pkg/addr" "github.com/scionproto/scion/pkg/daemon" + daemontypes "github.com/scionproto/scion/pkg/daemon/types" "github.com/scionproto/scion/pkg/log" "github.com/scionproto/scion/pkg/private/common" "github.com/scionproto/scion/pkg/private/serrors" @@ -349,7 +350,7 @@ func (c *client) getRemote(ctx context.Context, n int) (snet.Path, error) { } paths, err := c.sdConn.Paths(ctx, remote.IA, integration.Local.IA, - daemon.PathReqFlags{Refresh: n != 0}) + daemontypes.PathReqFlags{Refresh: n != 0}) if err != nil { return nil, withTag(serrors.Wrap("requesting paths", err)) }