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