Files
upstream-mirror e241b33f26
Some checks failed
codecov / upload (push) Failing after 13m59s
CodeQL / Analyze (push) Failing after 1s
Testing / vet-proto (push) Failing after 1s
Testing / tests (arm, latest) (push) Waiting to run
Testing / extras (latest) (push) Failing after 1s
Testing / static checks (latest-1) (push) Failing after 1s
Testing / tests (-race, latest) (push) Failing after 1s
Testing / tests (i386, latest) (push) Failing after 1s
Testing / tests (latest) (push) Failing after 1s
Testing / tests (latest-1) (push) Failing after 1s
Lock Threads / lock (push) Failing after 1s
govulncheck / govulncheck (.) (push) Failing after 1s
govulncheck / govulncheck (./cmd/protoc-gen-go-grpc) (push) Failing after 1s
govulncheck / govulncheck (./gcp/observability) (push) Failing after 1s
govulncheck / govulncheck (./security/advancedtls) (push) Failing after 1s
govulncheck / govulncheck (./stats/opencensus) (push) Failing after 1s
Stale bot / stale (push) Failing after 1s
snapshot of https://github.com/grpc/grpc-go.git (master, 2026-09-15; blobs > 131072B omitted)
2026-09-15 20:40:15 +05:00

165 lines
5.7 KiB
Go

/*
*
* Copyright 2025 gRPC authors.
*
* 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 xdsresource
import (
"fmt"
"net/netip"
"google.golang.org/grpc/internal/envconfig"
"google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version"
"google.golang.org/protobuf/types/known/anypb"
v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
v3gcpauthnpb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/gcp_authn/v3"
)
func init() {
if envconfig.XDSHTTPConnectEnabled {
registerMetadataConverter(version.V3AddressURL, proxyAddressConverter{})
}
if envconfig.GCPAuthenticationFilterEnabled {
registerMetadataConverter(version.V3AudienceURL, audienceConverter{})
}
}
var (
// metadataRegistry is a map from proto type to metadataConverter.
metadataRegistry = make(map[string]metadataConverter)
)
// metadataConverter converts xds metadata entries in
// Metadata.typed_filter_metadata into an internal form with the fields relevant
// to gRPC.
type metadataConverter interface {
// convert parses the Any proto into a concrete struct.
convert(*anypb.Any) (any, error)
}
// registerMetadataConverter registers the converter to the map keyed on a proto
// type_url. Must be called at init time. Not thread safe.
func registerMetadataConverter(protoType string, c metadataConverter) {
metadataRegistry[protoType] = c
}
// metadataConverterForType retrieves a converter based on key given.
func metadataConverterForType(typeURL string) metadataConverter {
return metadataRegistry[typeURL]
}
// RegisterMetadataConverterForTesting registers the converter for testing
// purposes and returns a cleanup function to restore the registry to its
// previous state.
func RegisterMetadataConverterForTesting(typeURL string) (func(), error) {
var conv metadataConverter
switch typeURL {
case version.V3AddressURL:
conv = proxyAddressConverter{}
case version.V3AudienceURL:
conv = audienceConverter{}
default:
return nil, fmt.Errorf("unknown typeURL for testing: %s", typeURL)
}
curConverter, found := metadataRegistry[typeURL]
registerMetadataConverter(typeURL, conv)
return func() {
if found {
metadataRegistry[typeURL] = curConverter
return
}
delete(metadataRegistry, typeURL)
}, nil
}
// UnregisterMetadataConverterForTesting unregisters the converter for testing
// purposes and returns a cleanup function to restore the registry to its
// previous state.
func UnregisterMetadataConverterForTesting(typeURL string) func() {
curConverter, found := metadataRegistry[typeURL]
delete(metadataRegistry, typeURL)
return func() {
if found {
metadataRegistry[typeURL] = curConverter
}
}
}
// StructMetadataValue stores the values in a google.protobuf.Struct from
// FilterMetadata.
type StructMetadataValue struct {
// Data stores the parsed JSON representation of a google.protobuf.Struct.
Data map[string]any
}
// ProxyAddressMetadataValue holds the address parsed from the
// envoy.config.core.v3.Address proto message, as specified in gRFC A86.
type ProxyAddressMetadataValue struct {
// Address stores the proxy address configured (A86). It will be in the form
// of host:port. It has to be either IPv6 or IPv4.
Address string
}
// proxyAddressConvertor implements the metadataConverter interface to handle
// the conversion of envoy.config.core.v3.Address protobuf messages into an
// internal representation.
type proxyAddressConverter struct{}
func (proxyAddressConverter) convert(anyProto *anypb.Any) (any, error) {
addressProto := &v3corepb.Address{}
if err := anyProto.UnmarshalTo(addressProto); err != nil {
return nil, fmt.Errorf("failed to unmarshal resource from Any proto: %v", err)
}
socketaddress := addressProto.GetSocketAddress()
if socketaddress == nil {
return nil, fmt.Errorf("no socket_address field in metadata")
}
if _, err := netip.ParseAddr(socketaddress.GetAddress()); err != nil {
return nil, fmt.Errorf("address field is not a valid IPv4 or IPv6 address: %q", socketaddress.GetAddress())
}
portvalue := socketaddress.GetPortValue()
if portvalue == 0 {
return nil, fmt.Errorf("port value not set in socket_address")
}
return ProxyAddressMetadataValue{Address: parseAddress(socketaddress)}, nil
}
// AudienceMetadataValue holds the audience parsed from the
// envoy.extensions.filters.http.gcp_authn.v3.Audience proto message, as
// specified in gRFC A83.
type AudienceMetadataValue struct {
// Audience is the URL of the receiving service that performs token
// authentication.
Audience string
}
// audienceConverter implements the metadataConverter interface to
// handle the conversion of envoy.extensions.filters.http.gcp_authn.v3.Audience
// protobuf messages into an internal representation.
type audienceConverter struct{}
func (audienceConverter) convert(anyProto *anypb.Any) (any, error) {
audienceProto := &v3gcpauthnpb.Audience{}
if err := anyProto.UnmarshalTo(audienceProto); err != nil {
return nil, fmt.Errorf("failed to unmarshal the envoy.extensions.filters.http.gcp_authn.v3.Audience resource from Any proto: %v", err)
}
if audienceProto.GetUrl() == "" {
return nil, fmt.Errorf("empty url field in audience metadata")
}
return AudienceMetadataValue{Audience: audienceProto.GetUrl()}, nil
}