diff --git a/BUILD.bazel b/BUILD.bazel index 2ad44fe769..c43159ca4e 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -177,7 +177,7 @@ pkg_tar( "//control/cmd/control", "//daemon/cmd/daemon", "//dispatcher/cmd/dispatcher", - #"//gateway/cmd/gateway", + "//gateway/cmd/gateway", "//router/cmd/router", "//scion-pki/cmd/scion-pki", "//scion/cmd/scion", diff --git a/control/beaconing/connect/sender.go b/control/beaconing/connect/sender.go index 1c3d97e702..73d7f8516d 100644 --- a/control/beaconing/connect/sender.go +++ b/control/beaconing/connect/sender.go @@ -17,7 +17,7 @@ import ( ) type BeaconSenderFactory struct { - Dialer func(net.Addr, ...squic.EarlyDialerOption) squic.EarlyDialer + Dialer libconnect.Dialer } func (f *BeaconSenderFactory) NewSender( @@ -64,7 +64,7 @@ func (s BeaconSender) Close() error { // Registrar registers segments. type Registrar struct { - Dialer func(net.Addr, ...squic.EarlyDialerOption) squic.EarlyDialer + Dialer libconnect.Dialer } // RegisterSegment registers a segment with the remote. diff --git a/control/beaconing/happy/BUILD.bazel b/control/beaconing/happy/BUILD.bazel index 8607fb8404..1794168482 100644 --- a/control/beaconing/happy/BUILD.bazel +++ b/control/beaconing/happy/BUILD.bazel @@ -8,7 +8,7 @@ go_library( deps = [ "//control/beaconing:go_default_library", "//pkg/addr:go_default_library", - "//pkg/log:go_default_library", + "//pkg/connect/happy:go_default_library", "//pkg/private/serrors:go_default_library", "//pkg/segment:go_default_library", ], diff --git a/control/beaconing/happy/sender.go b/control/beaconing/happy/sender.go index e20833fda5..f3906b9820 100644 --- a/control/beaconing/happy/sender.go +++ b/control/beaconing/happy/sender.go @@ -49,12 +49,12 @@ func (s BeaconSender) Send(ctx context.Context, b *seg.PathSegment) error { happy.Call1[*seg.PathSegment, struct{}]{ Call: happy.NoReturn1[*seg.PathSegment](s.Connect.Send).Call, Input1: b, - Typ: "connect", + Typ: "control_plane.v1.SegmentCreationService.Beacon", }, happy.Call1[*seg.PathSegment, struct{}]{ Call: happy.NoReturn1[*seg.PathSegment](s.Connect.Send).Call, Input1: b, - Typ: "grpc", + Typ: "control_plane.v1.SegmentCreationService.Beacon", }, ) return err @@ -83,13 +83,13 @@ func (r *Registrar) RegisterSegment(ctx context.Context, meta seg.Meta, remote n Call: happy.NoReturn2[seg.Meta, net.Addr](r.Connect.RegisterSegment).Call, Input1: meta, Input2: remote, - Typ: "connect", + Typ: "control_plane.v1.SegmentRegistrationService.SegmentsRegistration", }, happy.Call2[seg.Meta, net.Addr, struct{}]{ Call: happy.NoReturn2[seg.Meta, net.Addr](r.Connect.RegisterSegment).Call, Input1: meta, Input2: remote, - Typ: "grpc", + Typ: "control_plane.v1.SegmentRegistrationService.SegmentsRegistration", }, ) return err diff --git a/control/cmd/control/BUILD.bazel b/control/cmd/control/BUILD.bazel index bbaa160174..cd097c7773 100644 --- a/control/cmd/control/BUILD.bazel +++ b/control/cmd/control/BUILD.bazel @@ -32,6 +32,7 @@ go_library( "//control/trust/grpc:go_default_library", "//control/trust/metrics:go_default_library", "//pkg/addr:go_default_library", + "//pkg/connect:go_default_library", "//pkg/grpc:go_default_library", "//pkg/log:go_default_library", "//pkg/metrics:go_default_library", @@ -41,6 +42,7 @@ go_library( "//pkg/proto/control_plane:go_default_library", "//pkg/proto/control_plane/v1/control_planeconnect:go_default_library", "//pkg/proto/discovery:go_default_library", + "//pkg/proto/discovery/v1/discoveryconnect:go_default_library", "//pkg/scrypto:go_default_library", "//pkg/scrypto/cppki:go_default_library", "//pkg/snet:go_default_library", @@ -55,6 +57,7 @@ go_library( "//private/ca/renewal/connect:go_default_library", "//private/ca/renewal/grpc:go_default_library", "//private/discovery:go_default_library", + "//private/discovery/connect:go_default_library", "//private/drkey/drkeyutil:go_default_library", "//private/keyconf:go_default_library", "//private/mgmtapi/cppki/api:go_default_library", @@ -89,7 +92,6 @@ go_library( "@in_gopkg_yaml_v2//:go_default_library", "@org_go4_netipx//:go_default_library", "@org_golang_google_grpc//:go_default_library", - "@org_golang_google_grpc//peer:go_default_library", "@org_golang_x_net//http2:go_default_library", "@org_golang_x_net//http2/h2c:go_default_library", "@org_golang_x_sync//errgroup:go_default_library", diff --git a/control/cmd/control/main.go b/control/cmd/control/main.go index e7ece8580a..c5b2daff57 100644 --- a/control/cmd/control/main.go +++ b/control/cmd/control/main.go @@ -21,10 +21,8 @@ import ( "encoding/json" "errors" "fmt" - "net" "net/http" _ "net/http/pprof" - "net/netip" "path/filepath" "strings" "sync" @@ -42,7 +40,6 @@ import ( "go4.org/netipx" "golang.org/x/sync/errgroup" "google.golang.org/grpc" - "google.golang.org/grpc/peer" cs "github.com/scionproto/scion/control" "github.com/scionproto/scion/control/beacon" @@ -67,6 +64,7 @@ import ( cstrustgrpc "github.com/scionproto/scion/control/trust/grpc" cstrustmetrics "github.com/scionproto/scion/control/trust/metrics" "github.com/scionproto/scion/pkg/addr" + libconnect "github.com/scionproto/scion/pkg/connect" libgrpc "github.com/scionproto/scion/pkg/grpc" "github.com/scionproto/scion/pkg/log" libmetrics "github.com/scionproto/scion/pkg/metrics" @@ -76,6 +74,7 @@ import ( cppb "github.com/scionproto/scion/pkg/proto/control_plane" cpconnect "github.com/scionproto/scion/pkg/proto/control_plane/v1/control_planeconnect" dpb "github.com/scionproto/scion/pkg/proto/discovery" + dconnect "github.com/scionproto/scion/pkg/proto/discovery/v1/discoveryconnect" "github.com/scionproto/scion/pkg/scrypto" "github.com/scionproto/scion/pkg/scrypto/cppki" "github.com/scionproto/scion/pkg/snet" @@ -90,6 +89,7 @@ import ( renewalconnect "github.com/scionproto/scion/private/ca/renewal/connect" renewalgrpc "github.com/scionproto/scion/private/ca/renewal/grpc" "github.com/scionproto/scion/private/discovery" + discoveryconnect "github.com/scionproto/scion/private/discovery/connect" "github.com/scionproto/scion/private/drkey/drkeyutil" "github.com/scionproto/scion/private/keyconf" cppkiapi "github.com/scionproto/scion/private/mgmtapi/cppki/api" @@ -117,27 +117,6 @@ import ( trustmetrics "github.com/scionproto/scion/private/trust/metrics" ) -type loggingHandler struct { - prefix string - next http.Handler -} - -func (h loggingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - fmt.Println(h.prefix, r.Method, r.URL) - - if addr, ok := r.Context().Value(http3.RemoteAddrContextKey).(net.Addr); ok { - log.Info("HTTP3 request", "remote", r.Context().Value(http3.RemoteAddrContextKey)) - ctx := peer.NewContext(r.Context(), &peer.Peer{Addr: addr}) - r = r.WithContext(ctx) - } else if addrPort, err := netip.ParseAddrPort(r.RemoteAddr); err == nil { - log.Info("HTTP request", "remote", addrPort) - tcpAddr := net.TCPAddrFromAddrPort(addrPort) - ctx := peer.NewContext(r.Context(), &peer.Peer{Addr: tcpAddr}) - r = r.WithContext(ctx) - } - h.next.ServeHTTP(w, r) -} - var globalCfg config.Config func main() { @@ -318,12 +297,8 @@ func realMain(ctx context.Context) error { IA: topo.IA(), Dialer: (&squic.EarlyDialerFactory{ Transport: quicStack.InsecureDialer.Transport, - TLSConfig: func() *tls.Config { - cfg := quicStack.InsecureDialer.TLSConfig.Clone() - cfg.NextProtos = []string{"h3", "SCION"} - return cfg - }(), - Rewriter: dialer.Rewriter, + TLSConfig: libconnect.AdaptTLS(quicStack.InsecureDialer.TLSConfig), + Rewriter: dialer.Rewriter, }).NewDialer, }, Grpc: trustgrpc.Fetcher{ @@ -390,7 +365,6 @@ func realMain(ctx context.Context) error { IA: topo.IA(), Requests: libmetrics.NewPromCounter(cstrustmetrics.Handler.Requests), } - connectInter.Handle(cpconnect.NewTrustMaterialServiceHandler(cstrustconnect.MaterialServer{MaterialServer: trustServer})) cppb.RegisterTrustMaterialServiceServer(quicServer, trustServer) connectInter.Handle(cpconnect.NewTrustMaterialServiceHandler(cstrustconnect.MaterialServer{MaterialServer: trustServer})) connectIntra.Handle(cpconnect.NewTrustMaterialServiceHandler(cstrustconnect.MaterialServer{MaterialServer: trustServer})) @@ -406,11 +380,11 @@ func realMain(ctx context.Context) error { }, } cppb.RegisterSegmentCreationServiceServer(quicServer, segmentCreationServer) - { - pattern, handler := cpconnect.NewSegmentCreationServiceHandler(beaconingconnect.SegmentCreationServer{SegmentCreationServer: segmentCreationServer}) - fmt.Println(pattern) - connectInter.Handle(pattern, handler) - } + connectInter.Handle( + cpconnect.NewSegmentCreationServiceHandler(beaconingconnect.SegmentCreationServer{ + SegmentCreationServer: segmentCreationServer, + }), + ) // Handle segment lookup authLookupServer := &segreqgrpc.LookupServer{ @@ -639,6 +613,9 @@ func realMain(ctx context.Context) error { Requests: libmetrics.NewPromCounter(metrics.DiscoveryRequestsTotal), } dpb.RegisterDiscoveryServiceServer(quicServer, ds) + connectInter.Handle( + dconnect.NewDiscoveryServiceHandler(discoveryconnect.Topology{Topology: ds}), + ) // dsHealth := health.NewServer() // dsHealth.SetServingStatus("discovery", healthpb.HealthCheckResponse_SERVING) @@ -742,7 +719,7 @@ func realMain(ctx context.Context) error { var cleanup app.Cleanup connectServer := http3.Server{ - Handler: loggingHandler{"inter", connectInter}, + Handler: libconnect.AttachPeer(connectInter), } grpcConns := make(chan quic.Connection) @@ -788,7 +765,7 @@ func realMain(ctx context.Context) error { cleanup.Add(func() error { quicServer.GracefulStop(); return nil }) intraServer := http.Server{ - Handler: h2c.NewHandler(loggingHandler{"intra", connectIntra}, &http2.Server{}), + Handler: h2c.NewHandler(libconnect.AttachPeer(connectIntra), &http2.Server{}), } g.Go(func() error { defer log.HandlePanic() diff --git a/gateway/BUILD.bazel b/gateway/BUILD.bazel index 902fb0db7b..3099daf5a8 100644 --- a/gateway/BUILD.bazel +++ b/gateway/BUILD.bazel @@ -13,7 +13,9 @@ go_library( visibility = ["//visibility:public"], deps = [ "//gateway/control:go_default_library", + "//gateway/control/connect:go_default_library", "//gateway/control/grpc:go_default_library", + "//gateway/control/happy:go_default_library", "//gateway/dataplane:go_default_library", "//gateway/pathhealth:go_default_library", "//gateway/pathhealth/policies:go_default_library", @@ -21,6 +23,7 @@ go_library( "//gateway/routing:go_default_library", "//gateway/xnet:go_default_library", "//pkg/addr:go_default_library", + "//pkg/connect:go_default_library", "//pkg/daemon:go_default_library", "//pkg/grpc:go_default_library", "//pkg/log:go_default_library", @@ -28,6 +31,7 @@ go_library( "//pkg/private/serrors:go_default_library", "//pkg/private/util:go_default_library", "//pkg/proto/gateway:go_default_library", + "//pkg/proto/gateway/v1/gatewayconnect:go_default_library", "//pkg/snet:go_default_library", "//pkg/snet/metrics:go_default_library", "//pkg/snet/squic:go_default_library", @@ -41,6 +45,7 @@ go_library( "@com_github_prometheus_client_golang//prometheus:go_default_library", "@com_github_prometheus_client_golang//prometheus/promauto:go_default_library", "@com_github_quic_go_quic_go//:go_default_library", + "@com_github_quic_go_quic_go//http3:go_default_library", "@org_golang_google_grpc//:go_default_library", ], ) diff --git a/gateway/control/connect/BUILD.bazel b/gateway/control/connect/BUILD.bazel new file mode 100644 index 0000000000..5a1aa82817 --- /dev/null +++ b/gateway/control/connect/BUILD.bazel @@ -0,0 +1,26 @@ +load("//tools/lint:go.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "discoverer.go", + "prefix_fetcher.go", + "prefix_server.go", + ], + importpath = "github.com/scionproto/scion/gateway/control/connect", + visibility = ["//visibility:public"], + deps = [ + "//gateway/control:go_default_library", + "//gateway/control/grpc:go_default_library", + "//pkg/addr:go_default_library", + "//pkg/connect:go_default_library", + "//pkg/private/serrors:go_default_library", + "//pkg/proto/discovery:go_default_library", + "//pkg/proto/discovery/v1/discoveryconnect:go_default_library", + "//pkg/proto/gateway:go_default_library", + "//pkg/proto/gateway/v1/gatewayconnect:go_default_library", + "//pkg/snet:go_default_library", + "@com_connectrpc_connect//:go_default_library", + "@com_github_quic_go_quic_go//http3:go_default_library", + ], +) diff --git a/gateway/control/connect/discoverer.go b/gateway/control/connect/discoverer.go new file mode 100644 index 0000000000..96ff1b3c54 --- /dev/null +++ b/gateway/control/connect/discoverer.go @@ -0,0 +1,55 @@ +package connect + +import ( + "context" + + "connectrpc.com/connect" + "github.com/quic-go/quic-go/http3" + "github.com/scionproto/scion/gateway/control" + "github.com/scionproto/scion/gateway/control/grpc" + "github.com/scionproto/scion/pkg/addr" + libconnect "github.com/scionproto/scion/pkg/connect" + "github.com/scionproto/scion/pkg/private/serrors" + dpb "github.com/scionproto/scion/pkg/proto/discovery" + "github.com/scionproto/scion/pkg/proto/discovery/v1/discoveryconnect" + "github.com/scionproto/scion/pkg/snet" +) + +// Discoverer discovers the gateways for a specific remote AS. +type Discoverer struct { + // Remote is the ISD-AS of the remote AS. + Remote addr.IA + // Dialer dials a new QUIC connection. + Dialer libconnect.Dialer + // Paths is a registration for the paths to the remote AS. + Paths control.PathMonitorRegistration +} + +func (d Discoverer) Gateways(ctx context.Context) ([]control.Gateway, error) { + paths := d.Paths.Get().Paths + if len(paths) == 0 { + return nil, serrors.New("no path available") + } + ds := &snet.SVCAddr{ + IA: d.Remote, + Path: paths[0].Dataplane(), + NextHop: paths[0].UnderlayNextHop(), + SVC: addr.SvcDS, + } + + dialer := d.Dialer(ds) + client := discoveryconnect.NewDiscoveryServiceClient( + libconnect.HTTPClient{ + RoundTripper: &http3.RoundTripper{ + Dial: dialer.DialEarly, + }, + }, + libconnect.BaseUrl(ds), + ) + + rep, err := client.Gateways(ctx, connect.NewRequest(&dpb.GatewaysRequest{})) + if err != nil { + return nil, serrors.WrapStr("receiving gateways", err) + } + return grpc.TransformGateways(rep.Msg.Gateways) +} diff --git a/gateway/control/connect/prefix_fetcher.go b/gateway/control/connect/prefix_fetcher.go new file mode 100644 index 0000000000..759ff6055e --- /dev/null +++ b/gateway/control/connect/prefix_fetcher.go @@ -0,0 +1,79 @@ +// Copyright 2023 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 connect + +import ( + "context" + "net" + + "connectrpc.com/connect" + "github.com/quic-go/quic-go/http3" + "github.com/scionproto/scion/gateway/control" + "github.com/scionproto/scion/pkg/addr" + libconnect "github.com/scionproto/scion/pkg/connect" + "github.com/scionproto/scion/pkg/private/serrors" + gpb "github.com/scionproto/scion/pkg/proto/gateway" + "github.com/scionproto/scion/pkg/proto/gateway/v1/gatewayconnect" + "github.com/scionproto/scion/pkg/snet" +) + +// PrefixFetcher fetches prefixes from a gateway in a specific remote AS. +type PrefixFetcher struct { + // Remote is the ISD-AS of the remote AS. + Remote addr.IA + // Dialer dials a new QUIC connection. + Dialer libconnect.Dialer + // Paths is a registration for the paths to the remote AS. + Paths control.PathMonitorRegistration +} + +func (f PrefixFetcher) Prefixes(ctx context.Context, gateway *net.UDPAddr) ([]*net.IPNet, error) { + paths := f.Paths.Get().Paths + if len(paths) == 0 { + return nil, serrors.New("no path available") + } + remote := &snet.UDPAddr{ + IA: f.Remote, + Path: paths[0].Dataplane(), + NextHop: paths[0].UnderlayNextHop(), + Host: gateway, + } + + dialer := f.Dialer(remote) + client := gatewayconnect.NewIPPrefixesServiceClient( + libconnect.HTTPClient{ + RoundTripper: &http3.RoundTripper{ + Dial: dialer.DialEarly, + }, + }, + libconnect.BaseUrl(remote), + ) + rep, err := client.Prefixes(ctx, connect.NewRequest(&gpb.PrefixesRequest{})) + if err != nil { + return nil, serrors.WrapStr("receiving IP prefixes", err) + } + prefixes := make([]*net.IPNet, 0, len(rep.Msg.Prefixes)) + for _, pb := range rep.Msg.Prefixes { + mask := net.CIDRMask(int(pb.Mask), len(pb.Prefix)*8) + if mask == nil { + continue + } + prefixes = append(prefixes, &net.IPNet{ + IP: pb.Prefix, + Mask: mask, + }) + } + return prefixes, nil +} diff --git a/gateway/control/connect/prefix_server.go b/gateway/control/connect/prefix_server.go new file mode 100644 index 0000000000..f1fe8e675c --- /dev/null +++ b/gateway/control/connect/prefix_server.go @@ -0,0 +1,41 @@ +// Copyright 2023 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 connect + +import ( + "context" + + "connectrpc.com/connect" + + "github.com/scionproto/scion/gateway/control/grpc" + "github.com/scionproto/scion/pkg/proto/gateway" +) + +// IPPrefixServer serves IP prefix requests. +type IPPrefixServer struct { + *grpc.IPPrefixServer +} + +func (s IPPrefixServer) Prefixes( + ctx context.Context, + req *connect.Request[gateway.PrefixesRequest], +) (*connect.Response[gateway.PrefixesResponse], error) { + + rep, err := s.IPPrefixServer.Prefixes(ctx, req.Msg) + if err != nil { + return nil, err + } + return connect.NewResponse(rep), nil +} diff --git a/gateway/control/grpc/discoverer.go b/gateway/control/grpc/discoverer.go index c972fb5a64..eead04b851 100644 --- a/gateway/control/grpc/discoverer.go +++ b/gateway/control/grpc/discoverer.go @@ -54,8 +54,12 @@ func (d Discoverer) Gateways(ctx context.Context) ([]control.Gateway, error) { if err != nil { return nil, serrors.WrapStr("receiving gateways", err) } - gateways := make([]control.Gateway, 0, len(rep.Gateways)) - for _, pb := range rep.Gateways { + return TransformGateways(rep.Gateways) +} + +func TransformGateways(response []*dpb.Gateway) ([]control.Gateway, error) { + gateways := make([]control.Gateway, 0, len(response)) + for _, pb := range response { ctrl, err := net.ResolveUDPAddr("udp", pb.ControlAddress) if err != nil { return nil, serrors.WrapStr("parsing control address", err) diff --git a/gateway/control/happy/BUILD.bazel b/gateway/control/happy/BUILD.bazel new file mode 100644 index 0000000000..724a3f307e --- /dev/null +++ b/gateway/control/happy/BUILD.bazel @@ -0,0 +1,15 @@ +load("//tools/lint:go.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "discoverer.go", + "prefix_fetcher.go", + ], + importpath = "github.com/scionproto/scion/gateway/control/happy", + visibility = ["//visibility:public"], + deps = [ + "//gateway/control:go_default_library", + "//pkg/connect/happy:go_default_library", + ], +) diff --git a/gateway/control/happy/discoverer.go b/gateway/control/happy/discoverer.go new file mode 100644 index 0000000000..0b557e508f --- /dev/null +++ b/gateway/control/happy/discoverer.go @@ -0,0 +1,27 @@ +package happy + +import ( + "context" + + "github.com/scionproto/scion/gateway/control" + "github.com/scionproto/scion/pkg/connect/happy" +) + +type Discoverer struct { + Connect control.Discoverer + Grpc control.Discoverer +} + +func (d Discoverer) Gateways(ctx context.Context) ([]control.Gateway, error) { + return happy.Happy( + ctx, + happy.Call0[[]control.Gateway]{ + Call: d.Connect.Gateways, + Typ: "discovery.v1.DiscoveryService.Gateways", + }, + happy.Call0[[]control.Gateway]{ + Call: d.Grpc.Gateways, + Typ: "discovery.v1.DiscoveryService.Gateways", + }, + ) +} diff --git a/gateway/control/happy/prefix_fetcher.go b/gateway/control/happy/prefix_fetcher.go new file mode 100644 index 0000000000..f7f4b62cb7 --- /dev/null +++ b/gateway/control/happy/prefix_fetcher.go @@ -0,0 +1,30 @@ +package happy + +import ( + "context" + "net" + + "github.com/scionproto/scion/gateway/control" + "github.com/scionproto/scion/pkg/connect/happy" +) + +type PrefixFetcher struct { + Connect control.SimplePrefixFetcher + Grpc control.SimplePrefixFetcher +} + +func (f PrefixFetcher) Prefixes(ctx context.Context, gateway *net.UDPAddr) ([]*net.IPNet, error) { + return happy.Happy( + ctx, + happy.Call1[*net.UDPAddr, []*net.IPNet]{ + Call: f.Connect.Prefixes, + Input1: gateway, + Typ: "gateway.v1.IPPrefixesService.Prefixes", + }, + happy.Call1[*net.UDPAddr, []*net.IPNet]{ + Call: f.Grpc.Prefixes, + Input1: gateway, + Typ: "gateway.v1.IPPrefixesService.Prefixes", + }, + ) +} diff --git a/gateway/control/watcher.go b/gateway/control/watcher.go index aaf2abac3d..be56a33f3d 100644 --- a/gateway/control/watcher.go +++ b/gateway/control/watcher.go @@ -307,10 +307,14 @@ type PrefixConsumer interface { // PrefixFetcher fetches the IP prefixes from a remote gateway. type PrefixFetcher interface { - Prefixes(ctx context.Context, gateway *net.UDPAddr) ([]*net.IPNet, error) + SimplePrefixFetcher Close() error } +type SimplePrefixFetcher interface { + Prefixes(ctx context.Context, gateway *net.UDPAddr) ([]*net.IPNet, error) +} + // PrefixFetcherFactory constructs a PrefixFetcher for a given remote gateway. type PrefixFetcherFactory interface { NewPrefixFetcher(ctx context.Context, gateway Gateway) PrefixFetcher diff --git a/gateway/gateway.go b/gateway/gateway.go index 7682e41a47..2301eefd55 100644 --- a/gateway/gateway.go +++ b/gateway/gateway.go @@ -26,9 +26,11 @@ import ( "github.com/prometheus/client_golang/prometheus" quic "github.com/quic-go/quic-go" + "github.com/quic-go/quic-go/http3" "google.golang.org/grpc" "github.com/scionproto/scion/gateway/control" + controlconnect "github.com/scionproto/scion/gateway/control/connect" controlgrpc "github.com/scionproto/scion/gateway/control/grpc" "github.com/scionproto/scion/gateway/dataplane" "github.com/scionproto/scion/gateway/pathhealth" @@ -37,6 +39,7 @@ import ( "github.com/scionproto/scion/gateway/routing" "github.com/scionproto/scion/gateway/xnet" "github.com/scionproto/scion/pkg/addr" + "github.com/scionproto/scion/pkg/connect" "github.com/scionproto/scion/pkg/daemon" libgrpc "github.com/scionproto/scion/pkg/grpc" "github.com/scionproto/scion/pkg/log" @@ -44,6 +47,7 @@ import ( "github.com/scionproto/scion/pkg/private/serrors" "github.com/scionproto/scion/pkg/private/util" gatewaypb "github.com/scionproto/scion/pkg/proto/gateway" + "github.com/scionproto/scion/pkg/proto/gateway/v1/gatewayconnect" "github.com/scionproto/scion/pkg/snet" "github.com/scionproto/scion/pkg/snet/squic" "github.com/scionproto/scion/pkg/sock/reliable" @@ -522,6 +526,23 @@ func (g *Gateway) Run(ctx context.Context) error { }, Metrics: g.Metrics.SCIONNetworkMetrics, } + + grpcDialer := &libgrpc.QUICDialer{ + Dialer: quicClientDialer, + Rewriter: &infraenv.AddressRewriter{ + // Use the local Daemon to construct paths to the target AS. + Router: pathRouter, + // We never resolve addresses in the local AS, so pass a nil here. + SVCRouter: nil, + Resolver: &svc.Resolver{ + LocalIA: localIA, + // Reuse the network with SCMP error support. + ConnFactory: scionNetwork.Dispatcher, + LocalIP: g.ServiceDiscoveryClientIP, + }, + SVCResolutionFraction: 1.337, + }, + } remoteMonitor := &control.RemoteMonitor{ IAs: remoteIAsChannel, RemotesMonitored: rmMetric, @@ -534,22 +555,12 @@ func (g *Gateway) Run(ctx context.Context) error { Policies: &policies.Policies{ PathPolicy: control.DefaultPathPolicy, }, - Dialer: &libgrpc.QUICDialer{ - Dialer: quicClientDialer, - Rewriter: &infraenv.AddressRewriter{ - // Use the local Daemon to construct paths to the target AS. - Router: pathRouter, - // We never resolve addresses in the local AS, so pass a nil here. - SVCRouter: nil, - Resolver: &svc.Resolver{ - LocalIA: localIA, - // Reuse the network with SCMP error support. - ConnFactory: scionNetwork.Dispatcher, - LocalIP: g.ServiceDiscoveryClientIP, - }, - SVCResolutionFraction: 1.337, - }, - }, + Dialer: grpcDialer, + ConnectDialer: (&squic.EarlyDialerFactory{ + Transport: quicClientDialer.Transport, + TLSConfig: connect.AdaptTLS(quicClientDialer.TLSConfig), + Rewriter: grpcDialer.Rewriter, + }).NewDialer, }, } @@ -573,35 +584,66 @@ func (g *Gateway) Run(ctx context.Context) error { logger.Info("QUIC server connection initialized", "local_addr", serverConn.LocalAddr()) - internalQUICServerListener, err := quic.Listen(serverConn, ephemeralTLSConfig, nil) + internalQUICServerListener, err := quic.Listen( + serverConn, + connect.AdaptTLS(ephemeralTLSConfig), + nil, + ) if err != nil { return serrors.WrapStr("unable to initializer server QUIC listener", err) } - // Wrap in net.Listener for use with gRPC - quicServerListener := squic.NewConnListener(internalQUICServerListener) var paMetric metrics.Gauge if g.Metrics != nil { paMetric = metrics.NewPromGauge(g.Metrics.PrefixesAdvertised) } - discoveryServer := grpc.NewServer( + + prefixConnect := http.NewServeMux() + prefixGrpc := grpc.NewServer( libgrpc.UnaryServerInterceptor(), libgrpc.DefaultMaxConcurrentStreams(), ) - gatewaypb.RegisterIPPrefixesServiceServer( - discoveryServer, - controlgrpc.IPPrefixServer{ - LocalIA: localIA, - Advertiser: &SelectAdvertisedRoutes{ - ConfigPublisher: configPublisher, - }, - PrefixesAdvertised: paMetric, + + prefixServer := controlgrpc.IPPrefixServer{ + LocalIA: localIA, + Advertiser: &SelectAdvertisedRoutes{ + ConfigPublisher: configPublisher, }, + PrefixesAdvertised: paMetric, + } + prefixConnect.Handle( + gatewayconnect.NewIPPrefixesServiceHandler(controlconnect.IPPrefixServer{ + IPPrefixServer: &prefixServer, + }), + ) + gatewaypb.RegisterIPPrefixesServiceServer( + prefixGrpc, + prefixServer, ) + grpcConns := make(chan quic.Connection) + prefixConnectionDispatcher := connect.ConnectionDispatcher{ + Listener: internalQUICServerListener, + Connect: &http3.Server{Handler: connect.AttachPeer(prefixConnect)}, + Grpc: connect.QUICConnServerFunc(func(conn quic.Connection) error { + grpcConns <- conn + return nil + }), + Error: func(err error) { + logger.Debug("Failed to handle connection", "err", err) + }, + } + + go func() { + defer log.HandlePanic() + if err := prefixConnectionDispatcher.Run(ctx); err != nil { + panic(err) + } + }() go func() { defer log.HandlePanic() - if err := discoveryServer.Serve(quicServerListener); err != nil { + grpcListener := squic.NewConnListener(grpcConns, internalQUICServerListener.Addr()) + if err := prefixGrpc.Serve(grpcListener); err != nil { panic(err) } }() diff --git a/gateway/watcher.go b/gateway/watcher.go index af30d13ae6..44130ac77c 100644 --- a/gateway/watcher.go +++ b/gateway/watcher.go @@ -20,9 +20,12 @@ import ( "sync" "github.com/scionproto/scion/gateway/control" + controlconnect "github.com/scionproto/scion/gateway/control/connect" controlgrpc "github.com/scionproto/scion/gateway/control/grpc" + "github.com/scionproto/scion/gateway/control/happy" "github.com/scionproto/scion/gateway/pathhealth/policies" "github.com/scionproto/scion/pkg/addr" + "github.com/scionproto/scion/pkg/connect" libgrpc "github.com/scionproto/scion/pkg/grpc" "github.com/scionproto/scion/pkg/private/serrors" ) @@ -35,34 +38,44 @@ type fetcherFactory struct { func (f fetcherFactory) NewPrefixFetcher(ctx context.Context, gateway control.Gateway) control.PrefixFetcher { - return &prefixFetcher{ - PrefixFetcher: &controlgrpc.PrefixFetcher{ - Remote: f.remote, - Dialer: f.wf.Dialer, - Pather: f.wf.PathMonitor.Register( - ctx, + pather := f.wf.PathMonitor.Register( + ctx, + f.remote, + &policies.Policies{ + PathPolicy: control.PathPolicyWithAllowedInterfaces( + f.wf.Policies.PathPolicy, f.remote, - &policies.Policies{ - PathPolicy: control.PathPolicyWithAllowedInterfaces( - f.wf.Policies.PathPolicy, - f.remote, - gateway.Interfaces, - ), - PerfPolicy: f.wf.Policies.PerfPolicy, - PathCount: f.wf.Policies.PathCount, - }, - // XXX(roosd): This potentially can lead to label value - // explosion. However, the gateway IPs are rather stable in - // practice. Conceptually, this is similar to using the remote - // ISD-AS as a label value, which we do as well. - fmt.Sprintf("prefix-watcher-%s", gateway.Control.IP), + gateway.Interfaces, ), + PerfPolicy: f.wf.Policies.PerfPolicy, + PathCount: f.wf.Policies.PathCount, + }, + // XXX(roosd): This potentially can lead to label value + // explosion. However, the gateway IPs are rather stable in + // practice. Conceptually, this is similar to using the remote + // ISD-AS as a label value, which we do as well. + fmt.Sprintf("prefix-watcher-%s", gateway.Control.IP), + ) + return &prefixFetcher{ + SimplePrefixFetcher: happy.PrefixFetcher{ + Connect: &controlconnect.PrefixFetcher{ + Remote: f.remote, + Dialer: f.wf.ConnectDialer, + Paths: pather, + }, + Grpc: &controlgrpc.PrefixFetcher{ + Remote: f.remote, + Dialer: f.wf.Dialer, + Pather: pather, + }, }, + pather: pather, } } type prefixFetcher struct { - *controlgrpc.PrefixFetcher + control.SimplePrefixFetcher + pather control.PathMonitorRegistration closedMtx sync.RWMutex closed bool @@ -75,15 +88,16 @@ func (f *prefixFetcher) Close() error { return serrors.New("already closed") } f.closed = true - f.PrefixFetcher.Pather.Close() + f.pather.Close() return nil } type WatcherFactory struct { - Dialer libgrpc.Dialer - PathMonitor control.PathMonitor - Aggregator control.PrefixConsumer - Policies *policies.Policies + Dialer libgrpc.Dialer + ConnectDialer connect.Dialer + PathMonitor control.PathMonitor + Aggregator control.PrefixConsumer + Policies *policies.Policies } func (wf *WatcherFactory) New( @@ -96,11 +110,19 @@ func (wf *WatcherFactory) New( return &watcherWrapper{ GatewayWatcher: control.GatewayWatcher{ Remote: remote, - Discoverer: controlgrpc.Discoverer{ - Remote: remote, - Dialer: wf.Dialer, - Paths: pather, + Discoverer: happy.Discoverer{ + Connect: controlconnect.Discoverer{ + Remote: remote, + Dialer: wf.ConnectDialer, + Paths: pather, + }, + Grpc: controlgrpc.Discoverer{ + Remote: remote, + Dialer: wf.Dialer, + Paths: pather, + }, }, + Template: control.PrefixWatcherConfig{ Consumer: wf.Aggregator, FetcherFactory: fetcherFactory{ diff --git a/pkg/connect/BUILD.bazel b/pkg/connect/BUILD.bazel index ed535f6156..6a06ca8ca5 100644 --- a/pkg/connect/BUILD.bazel +++ b/pkg/connect/BUILD.bazel @@ -2,11 +2,18 @@ load("//tools/lint:go.bzl", "go_library") go_library( name = "go_default_library", - srcs = ["dialer.go"], + srcs = [ + "dialer.go", + "server.go", + ], importpath = "github.com/scionproto/scion/pkg/connect", visibility = ["//visibility:public"], deps = [ + "//pkg/log:go_default_library", "//pkg/snet:go_default_library", + "//pkg/snet/squic:go_default_library", + "@com_github_quic_go_quic_go//:go_default_library", "@com_github_quic_go_quic_go//http3:go_default_library", + "@org_golang_google_grpc//peer:go_default_library", ], ) diff --git a/pkg/connect/dialer.go b/pkg/connect/dialer.go index 895e891aff..8c1ea688ff 100644 --- a/pkg/connect/dialer.go +++ b/pkg/connect/dialer.go @@ -1,6 +1,7 @@ -package conect +package connect import ( + "crypto/tls" "fmt" "net" "net/http" @@ -8,8 +9,11 @@ import ( "github.com/quic-go/quic-go/http3" "github.com/scionproto/scion/pkg/snet" + "github.com/scionproto/scion/pkg/snet/squic" ) +type Dialer = func(net.Addr, ...squic.EarlyDialerOption) squic.EarlyDialer + func BaseUrl(server net.Addr) string { switch s := server.(type) { case *snet.UDPAddr: @@ -29,3 +33,10 @@ type HTTPClient struct { func (c HTTPClient) Do(req *http.Request) (*http.Response, error) { return c.RoundTripper.RoundTrip(req) } + +// AdaptTLS adapts the TLS config to indicate HTTP/3 and connectgrpc support. +func AdaptTLS(cfg *tls.Config) *tls.Config { + c := cfg.Clone() + c.NextProtos = []string{"h3", "SCION"} + return c +} diff --git a/pkg/connect/happy/happy.go b/pkg/connect/happy/happy.go index c10e2dbd95..76b4f7d82d 100644 --- a/pkg/connect/happy/happy.go +++ b/pkg/connect/happy/happy.go @@ -14,10 +14,17 @@ type Caller[R any] interface { Type() string } -type NoReturn1[I1 any] func(context.Context, I1) error +type Call0[R any] struct { + Call func(context.Context) (R, error) + Typ string +} -func (d NoReturn1[I1]) Call(ctx context.Context, i1 I1) (struct{}, error) { - return struct{}{}, d(ctx, i1) +func (c Call0[R]) Invoke(ctx context.Context) (R, error) { + return c.Call(ctx) +} + +func (c Call0[R]) Type() string { + return c.Typ } type Call1[I1 any, R any] struct { @@ -34,6 +41,12 @@ func (c Call1[I1, R]) Type() string { return c.Typ } +type NoReturn1[I1 any] func(context.Context, I1) error + +func (d NoReturn1[I1]) Call(ctx context.Context, i1 I1) (struct{}, error) { + return struct{}{}, d(ctx, i1) +} + type Call2[I1 any, I2, R any] struct { Call func(context.Context, I1, I2) (R, error) Input1 I1 @@ -72,10 +85,10 @@ func Happy[R any](ctx context.Context, fast, slow Caller[R]) (R, error) { rep, err := fast.Invoke(abortCtx) if err == nil { reps[0] = rep - logger.Debug("Received response via fast path", "type", fast.Type()) + logger.Debug("Received response via connect", "type", fast.Type()) cancel() } else { - logger.Debug("Failed to receive on fast path", "type", fast.Type(), "err", err) + logger.Debug("Failed to receive via connect", "type", fast.Type(), "err", err) } errs[0] = err }() @@ -91,10 +104,10 @@ func Happy[R any](ctx context.Context, fast, slow Caller[R]) (R, error) { rep, err := slow.Invoke(abortCtx) if err == nil { reps[0] = rep - logger.Debug("Received response via slow path", "type", slow.Type()) + logger.Debug("Received response via grpc", "type", slow.Type()) cancel() } else { - logger.Debug("Failed to receive on slow path", "type", slow.Type(), "err", err) + logger.Debug("Failed to receive on grpc", "type", slow.Type(), "err", err) } errs[1] = err }() diff --git a/pkg/connect/server.go b/pkg/connect/server.go new file mode 100644 index 0000000000..e20bc34805 --- /dev/null +++ b/pkg/connect/server.go @@ -0,0 +1,81 @@ +package connect + +import ( + "context" + "net" + "net/http" + "net/netip" + + "github.com/quic-go/quic-go" + "github.com/quic-go/quic-go/http3" + "google.golang.org/grpc/peer" + + "github.com/scionproto/scion/pkg/log" +) + +// AttachPeer creates a middleware that attaches the remote address to the +// context with the grpc-go peer mechanism. +func AttachPeer(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + logger := log.FromCtx(r.Context()) + if addr, ok := r.Context().Value(http3.RemoteAddrContextKey).(net.Addr); ok { + logger.Debug("HTTP3 request", "remote", addr) + ctx := peer.NewContext(r.Context(), &peer.Peer{Addr: addr}) + r = r.WithContext(ctx) + } else if addrPort, err := netip.ParseAddrPort(r.RemoteAddr); err == nil { + logger.Debug("HTTP request", "remote", addrPort) + tcpAddr := net.TCPAddrFromAddrPort(addrPort) + ctx := peer.NewContext(r.Context(), &peer.Peer{Addr: tcpAddr}) + r = r.WithContext(ctx) + } + next.ServeHTTP(w, r) + }) + +} + +type QUICConnServer interface { + ServeQUICConn(conn quic.Connection) error +} + +type QUICConnServerFunc func(conn quic.Connection) error + +func (f QUICConnServerFunc) ServeQUICConn(conn quic.Connection) error { + return f(conn) +} + +type ConnectionDispatcher struct { + Listener *quic.Listener + Connect QUICConnServer + Grpc QUICConnServer + Error func(error) +} + +// Run accepts connections and dispatches them to the appropriate server +// handler. +func (d ConnectionDispatcher) Run(ctx context.Context) error { + for { + conn, err := d.Listener.Accept(ctx) + if err == quic.ErrServerClosed { + return http.ErrServerClosed + } + if err != nil { + // If the context has been canceled, we do not report an error. + if ctx.Err() != nil { + return nil + } + return err + } + go func() { + defer log.HandlePanic() + if conn.ConnectionState().TLS.NegotiatedProtocol == "h3" { + if err := d.Connect.ServeQUICConn(conn); err != nil { + d.Error(err) + } + } else { + if err := d.Grpc.ServeQUICConn(conn); err != nil { + d.Error(err) + } + } + }() + } +} diff --git a/private/discovery/connect/BUILD.bazel b/private/discovery/connect/BUILD.bazel new file mode 100644 index 0000000000..16e1083c26 --- /dev/null +++ b/private/discovery/connect/BUILD.bazel @@ -0,0 +1,14 @@ +load("//tools/lint:go.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["toposervice.go"], + importpath = "github.com/scionproto/scion/private/discovery/connect", + visibility = ["//visibility:public"], + deps = [ + "//pkg/proto/discovery:go_default_library", + "//pkg/proto/discovery/v1/discoveryconnect:go_default_library", + "//private/discovery:go_default_library", + "@com_connectrpc_connect//:go_default_library", + ], +) diff --git a/private/discovery/connect/toposervice.go b/private/discovery/connect/toposervice.go new file mode 100644 index 0000000000..3fd056702a --- /dev/null +++ b/private/discovery/connect/toposervice.go @@ -0,0 +1,39 @@ +package connect + +import ( + "context" + + "connectrpc.com/connect" + + dpb "github.com/scionproto/scion/pkg/proto/discovery" + "github.com/scionproto/scion/pkg/proto/discovery/v1/discoveryconnect" + "github.com/scionproto/scion/private/discovery" +) + +var _ discoveryconnect.DiscoveryServiceHandler = Topology{} + +type Topology struct { + discovery.Topology +} + +func (t Topology) Gateways( + ctx context.Context, + req *connect.Request[dpb.GatewaysRequest], +) (*connect.Response[dpb.GatewaysResponse], error) { + rep, err := t.Topology.Gateways(ctx, req.Msg) + if err != nil { + return nil, err + } + return connect.NewResponse(rep), nil +} + +func (t Topology) HiddenSegmentServices( + ctx context.Context, + req *connect.Request[dpb.HiddenSegmentServicesRequest], +) (*connect.Response[dpb.HiddenSegmentServicesResponse], error) { + rep, err := t.Topology.HiddenSegmentServices(ctx, req.Msg) + if err != nil { + return nil, err + } + return connect.NewResponse(rep), nil +} diff --git a/private/segment/segfetcher/connect/requester.go b/private/segment/segfetcher/connect/requester.go index d8ce12a698..5b9a03f1f0 100644 --- a/private/segment/segfetcher/connect/requester.go +++ b/private/segment/segfetcher/connect/requester.go @@ -33,7 +33,7 @@ import ( // Requester fetches segments from a remote using gRPC. type Requester struct { - Dialer func(net.Addr, ...squic.EarlyDialerOption) squic.EarlyDialer + Dialer libconnect.Dialer } func (f *Requester) Segments(ctx context.Context, req segfetcher.Request, diff --git a/private/segment/segfetcher/happy/BUILD.bazel b/private/segment/segfetcher/happy/BUILD.bazel index ad4aecf9f8..b783960a29 100644 --- a/private/segment/segfetcher/happy/BUILD.bazel +++ b/private/segment/segfetcher/happy/BUILD.bazel @@ -6,8 +6,7 @@ go_library( importpath = "github.com/scionproto/scion/private/segment/segfetcher/happy", visibility = ["//visibility:public"], deps = [ - "//pkg/log:go_default_library", - "//pkg/private/serrors:go_default_library", + "//pkg/connect/happy:go_default_library", "//private/segment/segfetcher:go_default_library", ], ) diff --git a/private/segment/segfetcher/happy/requester.go b/private/segment/segfetcher/happy/requester.go index 2d74ac942f..dc8ba2606a 100644 --- a/private/segment/segfetcher/happy/requester.go +++ b/private/segment/segfetcher/happy/requester.go @@ -23,13 +23,13 @@ func (f *Requester) Segments(ctx context.Context, req segfetcher.Request, Call: f.Connect.Segments, Input1: req, Input2: server, - Typ: "connect", + Typ: "control_plane.v1.SegmentLookupService.Segments", }, happy.Call2[segfetcher.Request, net.Addr, segfetcher.SegmentsReply]{ Call: f.Grpc.Segments, Input1: req, Input2: server, - Typ: "grpc", + Typ: "control_plane.v1.SegmentLookupService.Segments", }, ) } diff --git a/private/trust/connect/BUILD.bazel b/private/trust/connect/BUILD.bazel index ee37b140ba..9c056751f1 100644 --- a/private/trust/connect/BUILD.bazel +++ b/private/trust/connect/BUILD.bazel @@ -11,7 +11,6 @@ go_library( "//pkg/private/serrors:go_default_library", "//pkg/proto/control_plane/v1/control_planeconnect:go_default_library", "//pkg/scrypto/cppki:go_default_library", - "//pkg/snet/squic:go_default_library", "//private/trust:go_default_library", "//private/trust/grpc:go_default_library", "@com_connectrpc_connect//:go_default_library", diff --git a/private/trust/connect/fetcher.go b/private/trust/connect/fetcher.go index 39d40a284c..df97c060cb 100644 --- a/private/trust/connect/fetcher.go +++ b/private/trust/connect/fetcher.go @@ -12,7 +12,6 @@ import ( "github.com/scionproto/scion/pkg/private/serrors" "github.com/scionproto/scion/pkg/proto/control_plane/v1/control_planeconnect" "github.com/scionproto/scion/pkg/scrypto/cppki" - "github.com/scionproto/scion/pkg/snet/squic" "github.com/scionproto/scion/private/trust" "github.com/scionproto/scion/private/trust/grpc" ) @@ -20,8 +19,8 @@ import ( type Fetcher struct { // IA is the local ISD-AS. IA addr.IA - // Dialer dials a new gRPC connection. - Dialer func(net.Addr, ...squic.EarlyDialerOption) squic.EarlyDialer + // Dialer dials a new QUIC connection. + Dialer libconnect.Dialer } // Chains fetches certificate chains over the network diff --git a/private/trust/happy/BUILD.bazel b/private/trust/happy/BUILD.bazel index ea8d7bd598..18545d686d 100644 --- a/private/trust/happy/BUILD.bazel +++ b/private/trust/happy/BUILD.bazel @@ -6,8 +6,7 @@ go_library( importpath = "github.com/scionproto/scion/private/trust/happy", visibility = ["//visibility:public"], deps = [ - "//pkg/log:go_default_library", - "//pkg/private/serrors:go_default_library", + "//pkg/connect/happy:go_default_library", "//pkg/scrypto/cppki:go_default_library", "//private/trust:go_default_library", ], diff --git a/private/trust/happy/fetcher.go b/private/trust/happy/fetcher.go index 2758615bd9..76e0545d4a 100644 --- a/private/trust/happy/fetcher.go +++ b/private/trust/happy/fetcher.go @@ -24,13 +24,13 @@ func (f Fetcher) Chains(ctx context.Context, query trust.ChainQuery, Call: f.Connect.Chains, Input1: query, Input2: server, - Typ: "connect", + Typ: "control_plane.v1.TrustMaterialService.Chains", }, happy.Call2[trust.ChainQuery, net.Addr, [][]*x509.Certificate]{ Call: f.Grpc.Chains, Input1: query, Input2: server, - Typ: "grpc", + Typ: "control_plane.v1.TrustMaterialService.Chains", }, ) } @@ -44,13 +44,13 @@ func (f Fetcher) TRC(ctx context.Context, id cppki.TRCID, Call: f.Connect.TRC, Input1: id, Input2: server, - Typ: "connect", + Typ: "control_plane.v1.TrustMaterialService.TRC", }, happy.Call2[cppki.TRCID, net.Addr, cppki.SignedTRC]{ Call: f.Grpc.TRC, Input1: id, Input2: server, - Typ: "grpc", + Typ: "control_plane.v1.TrustMaterialService.TRC", }, ) }