dubbo.apache.org/dubbo-go/v3@v3.1.1/xds/server/conn_wrapper.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  /*
    19   *
    20   * Copyright 2021 gRPC authors.
    21   *
    22   */
    23  
    24  package server
    25  
    26  import (
    27  	"errors"
    28  	"fmt"
    29  	"net"
    30  	"sync"
    31  	"time"
    32  )
    33  
    34  import (
    35  	"dubbo.apache.org/dubbo-go/v3/xds/client/resource"
    36  	"dubbo.apache.org/dubbo-go/v3/xds/credentials/certprovider"
    37  	xdsinternal "dubbo.apache.org/dubbo-go/v3/xds/utils/credentials/xds"
    38  )
    39  
    40  // connWrapper is a thin wrapper around a net.Conn returned by Accept(). It
    41  // provides the following additional functionality:
    42  //  1. A way to retrieve the configured deadline. This is required by the
    43  //     ServerHandshake() method of the xdsCredentials when it attempts to read
    44  //     key material from the certificate providers.
    45  //  2. Implements the XDSHandshakeInfo() method used by the xdsCredentials to
    46  //     retrieve the configured certificate providers.
    47  //  3. xDS filter_chain matching logic to select appropriate security
    48  //     configuration for the incoming connection.
    49  type connWrapper struct {
    50  	net.Conn
    51  
    52  	// The specific filter chain picked for handling this connection.
    53  	filterChain *resource.FilterChain
    54  
    55  	// A reference fo the listenerWrapper on which this connection was accepted.
    56  	parent *listenerWrapper
    57  
    58  	// The certificate providers created for this connection.
    59  	rootProvider, identityProvider certprovider.Provider
    60  
    61  	// The connection deadline as configured by the grpc.Server on the rawConn
    62  	// that is returned by a call to Accept(). This is set to the connection
    63  	// timeout value configured by the user (or to a default value) before
    64  	// initiating the transport credential handshake, and set to zero after
    65  	// completing the HTTP2 handshake.
    66  	deadlineMu sync.Mutex
    67  	deadline   time.Time
    68  
    69  	// The virtual hosts with matchable routes and instantiated HTTP Filters per
    70  	// route.
    71  	virtualHosts []resource.VirtualHostWithInterceptors
    72  }
    73  
    74  // VirtualHosts returns the virtual hosts to be used for server side routing.
    75  func (c *connWrapper) VirtualHosts() []resource.VirtualHostWithInterceptors {
    76  	return c.virtualHosts
    77  }
    78  
    79  // SetDeadline makes a copy of the passed in deadline and forwards the call to
    80  // the underlying rawConn.
    81  func (c *connWrapper) SetDeadline(t time.Time) error {
    82  	c.deadlineMu.Lock()
    83  	c.deadline = t
    84  	c.deadlineMu.Unlock()
    85  	return c.Conn.SetDeadline(t)
    86  }
    87  
    88  // GetDeadline returns the configured deadline. This will be invoked by the
    89  // ServerHandshake() method of the XdsCredentials, which needs a deadline to
    90  // pass to the certificate provider.
    91  func (c *connWrapper) GetDeadline() time.Time {
    92  	c.deadlineMu.Lock()
    93  	t := c.deadline
    94  	c.deadlineMu.Unlock()
    95  	return t
    96  }
    97  
    98  // XDSHandshakeInfo returns a HandshakeInfo with appropriate security
    99  // configuration for this connection. This method is invoked by the
   100  // ServerHandshake() method of the XdsCredentials.
   101  func (c *connWrapper) XDSHandshakeInfo() (*xdsinternal.HandshakeInfo, error) {
   102  	// Ideally this should never happen, since xdsCredentials are the only ones
   103  	// which will invoke this method at handshake time. But to be on the safe
   104  	// side, we avoid acting on the security configuration received from the
   105  	// control plane when the user has not configured the use of xDS
   106  	// credentials, by checking the value of this flag.
   107  	if !c.parent.xdsCredsInUse {
   108  		return nil, errors.New("user has not configured xDS credentials")
   109  	}
   110  
   111  	if c.filterChain.SecurityCfg == nil {
   112  		// If the security config is empty, this means that the control plane
   113  		// did not provide any security configuration and therefore we should
   114  		// return an empty HandshakeInfo here so that the xdsCreds can use the
   115  		// configured fallback credentials.
   116  		return xdsinternal.NewHandshakeInfo(nil, nil), nil
   117  	}
   118  
   119  	cpc := c.parent.xdsC.BootstrapConfig().CertProviderConfigs
   120  	// Identity provider name is mandatory on the server-side, and this is
   121  	// enforced when the resource is received at the XDSClient layer.
   122  	secCfg := c.filterChain.SecurityCfg
   123  	ip, err := buildProviderFunc(cpc, secCfg.IdentityInstanceName, secCfg.IdentityCertName, true, false)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  	// Root provider name is optional and required only when doing mTLS.
   128  	var rp certprovider.Provider
   129  	if instance, cert := secCfg.RootInstanceName, secCfg.RootCertName; instance != "" {
   130  		rp, err = buildProviderFunc(cpc, instance, cert, false, true)
   131  		if err != nil {
   132  			return nil, err
   133  		}
   134  	}
   135  	c.identityProvider = ip
   136  	c.rootProvider = rp
   137  
   138  	xdsHI := xdsinternal.NewHandshakeInfo(c.rootProvider, c.identityProvider)
   139  	xdsHI.SetRequireClientCert(secCfg.RequireClientCert)
   140  	return xdsHI, nil
   141  }
   142  
   143  // Close closes the providers and the underlying connection.
   144  func (c *connWrapper) Close() error {
   145  	if c.identityProvider != nil {
   146  		c.identityProvider.Close()
   147  	}
   148  	if c.rootProvider != nil {
   149  		c.rootProvider.Close()
   150  	}
   151  	return c.Conn.Close()
   152  }
   153  
   154  func buildProviderFunc(configs map[string]*certprovider.BuildableConfig, instanceName, certName string, wantIdentity, wantRoot bool) (certprovider.Provider, error) {
   155  	cfg, ok := configs[instanceName]
   156  	if !ok {
   157  		return nil, fmt.Errorf("certificate provider instance %q not found in bootstrap file", instanceName)
   158  	}
   159  	provider, err := cfg.Build(certprovider.BuildOptions{
   160  		CertName:     certName,
   161  		WantIdentity: wantIdentity,
   162  		WantRoot:     wantRoot,
   163  	})
   164  	if err != nil {
   165  		// This error is not expected since the bootstrap process parses the
   166  		// config and makes sure that it is acceptable to the plugin. Still, it
   167  		// is possible that the plugin parses the config successfully, but its
   168  		// Build() method errors out.
   169  		return nil, fmt.Errorf("failed to get security plugin instance (%+v): %v", cfg, err)
   170  	}
   171  	return provider, nil
   172  }