github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/gossip/comm/comm_impl.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package comm 18 19 import ( 20 "bytes" 21 "crypto/tls" 22 "errors" 23 "fmt" 24 "net" 25 "reflect" 26 "sync" 27 "sync/atomic" 28 "time" 29 30 "github.com/hyperledger/fabric/gossip/api" 31 "github.com/hyperledger/fabric/gossip/common" 32 "github.com/hyperledger/fabric/gossip/identity" 33 "github.com/hyperledger/fabric/gossip/util" 34 proto "github.com/hyperledger/fabric/protos/gossip" 35 "github.com/op/go-logging" 36 "github.com/spf13/viper" 37 "golang.org/x/net/context" 38 "google.golang.org/grpc" 39 "google.golang.org/grpc/credentials" 40 "google.golang.org/grpc/peer" 41 ) 42 43 const ( 44 defDialTimeout = time.Second * time.Duration(3) 45 defConnTimeout = time.Second * time.Duration(2) 46 defRecvBuffSize = 20 47 defSendBuffSize = 20 48 ) 49 50 // SetDialTimeout sets the dial timeout 51 func SetDialTimeout(timeout time.Duration) { 52 viper.Set("peer.gossip.dialTimeout", timeout) 53 } 54 55 func (c *commImpl) SetDialOpts(opts ...grpc.DialOption) { 56 if len(opts) == 0 { 57 c.logger.Warning("Given an empty set of grpc.DialOption, aborting") 58 return 59 } 60 c.opts = opts 61 } 62 63 // NewCommInstanceWithServer creates a comm instance that creates an underlying gRPC server 64 func NewCommInstanceWithServer(port int, idMapper identity.Mapper, peerIdentity api.PeerIdentityType, 65 secureDialOpts api.PeerSecureDialOpts, dialOpts ...grpc.DialOption) (Comm, error) { 66 67 var ll net.Listener 68 var s *grpc.Server 69 var certHash []byte 70 71 if len(dialOpts) == 0 { 72 dialOpts = []grpc.DialOption{grpc.WithTimeout(util.GetDurationOrDefault("peer.gossip.dialTimeout", defDialTimeout))} 73 } 74 75 if port > 0 { 76 s, ll, secureDialOpts, certHash = createGRPCLayer(port) 77 } 78 79 commInst := &commImpl{ 80 selfCertHash: certHash, 81 PKIID: idMapper.GetPKIidOfCert(peerIdentity), 82 idMapper: idMapper, 83 logger: util.GetLogger(util.LoggingCommModule, fmt.Sprintf("%d", port)), 84 peerIdentity: peerIdentity, 85 opts: dialOpts, 86 secureDialOpts: secureDialOpts, 87 port: port, 88 lsnr: ll, 89 gSrv: s, 90 msgPublisher: NewChannelDemultiplexer(), 91 lock: &sync.RWMutex{}, 92 deadEndpoints: make(chan common.PKIidType, 100), 93 stopping: int32(0), 94 exitChan: make(chan struct{}, 1), 95 subscriptions: make([]chan proto.ReceivedMessage, 0), 96 } 97 commInst.connStore = newConnStore(commInst, commInst.logger) 98 99 if port > 0 { 100 commInst.stopWG.Add(1) 101 go func() { 102 defer commInst.stopWG.Done() 103 s.Serve(ll) 104 }() 105 proto.RegisterGossipServer(s, commInst) 106 } 107 108 return commInst, nil 109 } 110 111 // NewCommInstance creates a new comm instance that binds itself to the given gRPC server 112 func NewCommInstance(s *grpc.Server, cert *tls.Certificate, idStore identity.Mapper, 113 peerIdentity api.PeerIdentityType, secureDialOpts api.PeerSecureDialOpts, 114 dialOpts ...grpc.DialOption) (Comm, error) { 115 116 dialOpts = append(dialOpts, grpc.WithTimeout(util.GetDurationOrDefault("peer.gossip.dialTimeout", defDialTimeout))) 117 commInst, err := NewCommInstanceWithServer(-1, idStore, peerIdentity, secureDialOpts, dialOpts...) 118 if err != nil { 119 return nil, err 120 } 121 122 if cert != nil { 123 inst := commInst.(*commImpl) 124 if len(cert.Certificate) == 0 { 125 inst.logger.Panic("Certificate supplied but certificate chain is empty") 126 } else { 127 inst.selfCertHash = certHashFromRawCert(cert.Certificate[0]) 128 } 129 } 130 131 proto.RegisterGossipServer(s, commInst.(*commImpl)) 132 133 return commInst, nil 134 } 135 136 type commImpl struct { 137 selfCertHash []byte 138 peerIdentity api.PeerIdentityType 139 idMapper identity.Mapper 140 logger *logging.Logger 141 opts []grpc.DialOption 142 secureDialOpts func() []grpc.DialOption 143 connStore *connectionStore 144 PKIID []byte 145 deadEndpoints chan common.PKIidType 146 msgPublisher *ChannelDeMultiplexer 147 lock *sync.RWMutex 148 lsnr net.Listener 149 gSrv *grpc.Server 150 exitChan chan struct{} 151 stopWG sync.WaitGroup 152 subscriptions []chan proto.ReceivedMessage 153 port int 154 stopping int32 155 } 156 157 func (c *commImpl) createConnection(endpoint string, expectedPKIID common.PKIidType) (*connection, error) { 158 var err error 159 var cc *grpc.ClientConn 160 var stream proto.Gossip_GossipStreamClient 161 var pkiID common.PKIidType 162 var connInfo *proto.ConnectionInfo 163 var dialOpts []grpc.DialOption 164 165 c.logger.Debug("Entering", endpoint, expectedPKIID) 166 defer c.logger.Debug("Exiting") 167 168 if c.isStopping() { 169 return nil, errors.New("Stopping") 170 } 171 dialOpts = append(dialOpts, c.secureDialOpts()...) 172 dialOpts = append(dialOpts, grpc.WithBlock()) 173 dialOpts = append(dialOpts, c.opts...) 174 cc, err = grpc.Dial(endpoint, dialOpts...) 175 if err != nil { 176 return nil, err 177 } 178 179 cl := proto.NewGossipClient(cc) 180 181 if _, err = cl.Ping(context.Background(), &proto.Empty{}); err != nil { 182 cc.Close() 183 return nil, err 184 } 185 186 ctx, cf := context.WithCancel(context.Background()) 187 if stream, err = cl.GossipStream(ctx); err == nil { 188 connInfo, err = c.authenticateRemotePeer(stream) 189 if err == nil { 190 pkiID = connInfo.ID 191 if expectedPKIID != nil && !bytes.Equal(pkiID, expectedPKIID) { 192 // PKIID is nil when we don't know the remote PKI id's 193 c.logger.Warning("Remote endpoint claims to be a different peer, expected", expectedPKIID, "but got", pkiID) 194 cc.Close() 195 return nil, errors.New("Authentication failure") 196 } 197 conn := newConnection(cl, cc, stream, nil) 198 conn.pkiID = pkiID 199 conn.info = connInfo 200 conn.logger = c.logger 201 conn.cancel = cf 202 203 h := func(m *proto.SignedGossipMessage) { 204 c.logger.Debug("Got message:", m) 205 c.msgPublisher.DeMultiplex(&ReceivedMessageImpl{ 206 conn: conn, 207 lock: conn, 208 SignedGossipMessage: m, 209 connInfo: connInfo, 210 }) 211 } 212 conn.handler = h 213 return conn, nil 214 } 215 c.logger.Warning("Authentication failed:", err) 216 } 217 cc.Close() 218 return nil, err 219 } 220 221 func (c *commImpl) Send(msg *proto.SignedGossipMessage, peers ...*RemotePeer) { 222 if c.isStopping() || len(peers) == 0 { 223 return 224 } 225 226 c.logger.Debug("Entering, sending", msg, "to ", len(peers), "peers") 227 228 for _, peer := range peers { 229 go func(peer *RemotePeer, msg *proto.SignedGossipMessage) { 230 c.sendToEndpoint(peer, msg) 231 }(peer, msg) 232 } 233 } 234 235 func (c *commImpl) sendToEndpoint(peer *RemotePeer, msg *proto.SignedGossipMessage) { 236 if c.isStopping() { 237 return 238 } 239 c.logger.Debug("Entering, Sending to", peer.Endpoint, ", msg:", msg) 240 defer c.logger.Debug("Exiting") 241 var err error 242 243 conn, err := c.connStore.getConnection(peer) 244 if err == nil { 245 disConnectOnErr := func(err error) { 246 c.logger.Warning(peer, "isn't responsive:", err) 247 c.disconnect(peer.PKIID) 248 } 249 conn.send(msg, disConnectOnErr) 250 return 251 } 252 c.logger.Warning("Failed obtaining connection for", peer, "reason:", err) 253 c.disconnect(peer.PKIID) 254 } 255 256 func (c *commImpl) isStopping() bool { 257 return atomic.LoadInt32(&c.stopping) == int32(1) 258 } 259 260 func (c *commImpl) Probe(remotePeer *RemotePeer) error { 261 var dialOpts []grpc.DialOption 262 endpoint := remotePeer.Endpoint 263 pkiID := remotePeer.PKIID 264 if c.isStopping() { 265 return errors.New("Stopping") 266 } 267 c.logger.Debug("Entering, endpoint:", endpoint, "PKIID:", pkiID) 268 dialOpts = append(dialOpts, c.secureDialOpts()...) 269 dialOpts = append(dialOpts, grpc.WithBlock()) 270 dialOpts = append(dialOpts, c.opts...) 271 272 cc, err := grpc.Dial(remotePeer.Endpoint, dialOpts...) 273 if err != nil { 274 c.logger.Debug("Returning", err) 275 return err 276 } 277 defer cc.Close() 278 cl := proto.NewGossipClient(cc) 279 _, err = cl.Ping(context.Background(), &proto.Empty{}) 280 c.logger.Debug("Returning", err) 281 return err 282 } 283 284 func (c *commImpl) Handshake(remotePeer *RemotePeer) (api.PeerIdentityType, error) { 285 var dialOpts []grpc.DialOption 286 dialOpts = append(dialOpts, c.secureDialOpts()...) 287 dialOpts = append(dialOpts, grpc.WithBlock()) 288 dialOpts = append(dialOpts, c.opts...) 289 290 cc, err := grpc.Dial(remotePeer.Endpoint, dialOpts...) 291 if err != nil { 292 return nil, err 293 } 294 defer cc.Close() 295 296 cl := proto.NewGossipClient(cc) 297 if _, err = cl.Ping(context.Background(), &proto.Empty{}); err != nil { 298 return nil, err 299 } 300 301 stream, err := cl.GossipStream(context.Background()) 302 if err != nil { 303 return nil, err 304 } 305 connInfo, err := c.authenticateRemotePeer(stream) 306 if err != nil { 307 c.logger.Warning("Authentication failed:", err) 308 return nil, err 309 } 310 if len(remotePeer.PKIID) > 0 && !bytes.Equal(connInfo.ID, remotePeer.PKIID) { 311 return nil, errors.New("PKI-ID of remote peer doesn't match expected PKI-ID") 312 } 313 return connInfo.Identity, nil 314 } 315 316 func (c *commImpl) Accept(acceptor common.MessageAcceptor) <-chan proto.ReceivedMessage { 317 genericChan := c.msgPublisher.AddChannel(acceptor) 318 specificChan := make(chan proto.ReceivedMessage, 10) 319 320 if c.isStopping() { 321 c.logger.Warning("Accept() called but comm module is stopping, returning empty channel") 322 return specificChan 323 } 324 325 c.lock.Lock() 326 c.subscriptions = append(c.subscriptions, specificChan) 327 c.lock.Unlock() 328 329 go func() { 330 defer c.logger.Debug("Exiting Accept() loop") 331 defer func() { 332 recover() 333 }() 334 335 c.stopWG.Add(1) 336 defer c.stopWG.Done() 337 338 for { 339 select { 340 case msg := <-genericChan: 341 specificChan <- msg.(*ReceivedMessageImpl) 342 case s := <-c.exitChan: 343 c.exitChan <- s 344 return 345 } 346 } 347 }() 348 return specificChan 349 } 350 351 func (c *commImpl) PresumedDead() <-chan common.PKIidType { 352 return c.deadEndpoints 353 } 354 355 func (c *commImpl) CloseConn(peer *RemotePeer) { 356 c.logger.Debug("Closing connection for", peer) 357 c.connStore.closeConn(peer) 358 } 359 360 func (c *commImpl) emptySubscriptions() { 361 c.lock.Lock() 362 defer c.lock.Unlock() 363 for _, ch := range c.subscriptions { 364 close(ch) 365 } 366 } 367 368 func (c *commImpl) Stop() { 369 if c.isStopping() { 370 return 371 } 372 atomic.StoreInt32(&c.stopping, int32(1)) 373 c.logger.Info("Stopping") 374 defer c.logger.Info("Stopped") 375 if c.gSrv != nil { 376 c.gSrv.Stop() 377 } 378 if c.lsnr != nil { 379 c.lsnr.Close() 380 } 381 c.connStore.shutdown() 382 c.logger.Debug("Shut down connection store, connection count:", c.connStore.connNum()) 383 c.exitChan <- struct{}{} 384 c.msgPublisher.Close() 385 c.logger.Debug("Shut down publisher") 386 c.emptySubscriptions() 387 c.logger.Debug("Closed subscriptions, waiting for goroutines to stop...") 388 c.stopWG.Wait() 389 } 390 391 func (c *commImpl) GetPKIid() common.PKIidType { 392 return c.PKIID 393 } 394 395 func extractRemoteAddress(stream stream) string { 396 var remoteAddress string 397 p, ok := peer.FromContext(stream.Context()) 398 if ok { 399 if address := p.Addr; address != nil { 400 remoteAddress = address.String() 401 } 402 } 403 return remoteAddress 404 } 405 406 func (c *commImpl) authenticateRemotePeer(stream stream) (*proto.ConnectionInfo, error) { 407 ctx := stream.Context() 408 remoteAddress := extractRemoteAddress(stream) 409 remoteCertHash := extractCertificateHashFromContext(ctx) 410 var err error 411 var cMsg *proto.SignedGossipMessage 412 var signer proto.Signer 413 useTLS := c.selfCertHash != nil 414 415 // If TLS is enabled, sign the connection message in order to bind 416 // the TLS session to the peer's identity 417 if useTLS { 418 signer = func(msg []byte) ([]byte, error) { 419 return c.idMapper.Sign(msg) 420 } 421 } else { // If we don't use TLS, we have no unique text to sign, 422 // so don't sign anything 423 signer = func(msg []byte) ([]byte, error) { 424 return msg, nil 425 } 426 } 427 428 // TLS enabled but not detected on other side 429 if useTLS && len(remoteCertHash) == 0 { 430 c.logger.Warningf("%s didn't send TLS certificate", remoteAddress) 431 return nil, errors.New("No TLS certificate") 432 } 433 434 cMsg, err = c.createConnectionMsg(c.PKIID, c.selfCertHash, c.peerIdentity, signer) 435 if err != nil { 436 return nil, err 437 } 438 439 c.logger.Debug("Sending", cMsg, "to", remoteAddress) 440 stream.Send(cMsg.Envelope) 441 m, err := readWithTimeout(stream, util.GetDurationOrDefault("peer.gossip.connTimeout", defConnTimeout), remoteAddress) 442 if err != nil { 443 c.logger.Warningf("Failed reading messge from %s, reason: %v", remoteAddress, err) 444 return nil, err 445 } 446 receivedMsg := m.GetConn() 447 if receivedMsg == nil { 448 c.logger.Warning("Expected connection message from", remoteAddress, "but got", receivedMsg) 449 return nil, errors.New("Wrong type") 450 } 451 452 if receivedMsg.PkiId == nil { 453 c.logger.Warning("%s didn't send a pkiID", remoteAddress) 454 return nil, errors.New("No PKI-ID") 455 } 456 457 c.logger.Debug("Received", receivedMsg, "from", remoteAddress) 458 err = c.idMapper.Put(receivedMsg.PkiId, receivedMsg.Identity) 459 if err != nil { 460 c.logger.Warning("Identity store rejected", remoteAddress, ":", err) 461 return nil, err 462 } 463 464 connInfo := &proto.ConnectionInfo{ 465 ID: receivedMsg.PkiId, 466 Identity: receivedMsg.Identity, 467 Endpoint: remoteAddress, 468 } 469 470 // if TLS is enabled and detected, verify remote peer 471 if useTLS { 472 // If the remote peer sent its TLS certificate, make sure it actually matches the TLS cert 473 // that the peer used. 474 if !bytes.Equal(remoteCertHash, receivedMsg.TlsCertHash) { 475 return nil, fmt.Errorf("Expected %v in remote hash of TLS cert, but got %v", remoteCertHash, receivedMsg.TlsCertHash) 476 } 477 verifier := func(peerIdentity []byte, signature, message []byte) error { 478 pkiID := c.idMapper.GetPKIidOfCert(api.PeerIdentityType(peerIdentity)) 479 return c.idMapper.Verify(pkiID, signature, message) 480 } 481 err = m.Verify(receivedMsg.Identity, verifier) 482 if err != nil { 483 c.logger.Error("Failed verifying signature from", remoteAddress, ":", err) 484 return nil, err 485 } 486 connInfo.Auth = &proto.AuthInfo{ 487 Signature: m.Signature, 488 SignedData: m.Payload, 489 } 490 } 491 492 c.logger.Debug("Authenticated", remoteAddress) 493 494 return connInfo, nil 495 } 496 497 func (c *commImpl) GossipStream(stream proto.Gossip_GossipStreamServer) error { 498 if c.isStopping() { 499 return errors.New("Shutting down") 500 } 501 connInfo, err := c.authenticateRemotePeer(stream) 502 if err != nil { 503 c.logger.Error("Authentication failed:", err) 504 return err 505 } 506 c.logger.Debug("Servicing", extractRemoteAddress(stream)) 507 508 conn := c.connStore.onConnected(stream, connInfo) 509 510 // if connStore denied the connection, it means we already have a connection to that peer 511 // so close this stream 512 if conn == nil { 513 return nil 514 } 515 516 h := func(m *proto.SignedGossipMessage) { 517 c.msgPublisher.DeMultiplex(&ReceivedMessageImpl{ 518 conn: conn, 519 lock: conn, 520 SignedGossipMessage: m, 521 connInfo: connInfo, 522 }) 523 } 524 525 conn.handler = h 526 527 defer func() { 528 c.logger.Debug("Client", extractRemoteAddress(stream), " disconnected") 529 c.connStore.closeByPKIid(connInfo.ID) 530 conn.close() 531 }() 532 533 return conn.serviceConnection() 534 } 535 536 func (c *commImpl) Ping(context.Context, *proto.Empty) (*proto.Empty, error) { 537 return &proto.Empty{}, nil 538 } 539 540 func (c *commImpl) disconnect(pkiID common.PKIidType) { 541 if c.isStopping() { 542 return 543 } 544 c.deadEndpoints <- pkiID 545 c.connStore.closeByPKIid(pkiID) 546 } 547 548 func readWithTimeout(stream interface{}, timeout time.Duration, address string) (*proto.SignedGossipMessage, error) { 549 incChan := make(chan *proto.SignedGossipMessage, 1) 550 errChan := make(chan error, 1) 551 go func() { 552 if srvStr, isServerStr := stream.(proto.Gossip_GossipStreamServer); isServerStr { 553 if m, err := srvStr.Recv(); err == nil { 554 msg, err := m.ToGossipMessage() 555 if err != nil { 556 errChan <- err 557 return 558 } 559 incChan <- msg 560 } 561 } else if clStr, isClientStr := stream.(proto.Gossip_GossipStreamClient); isClientStr { 562 if m, err := clStr.Recv(); err == nil { 563 msg, err := m.ToGossipMessage() 564 if err != nil { 565 errChan <- err 566 return 567 } 568 incChan <- msg 569 } 570 } else { 571 panic(fmt.Errorf("Stream isn't a GossipStreamServer or a GossipStreamClient, but %v. Aborting", reflect.TypeOf(stream))) 572 } 573 }() 574 select { 575 case <-time.NewTicker(timeout).C: 576 return nil, fmt.Errorf("Timed out waiting for connection message from %s", address) 577 case m := <-incChan: 578 return m, nil 579 case err := <-errChan: 580 return nil, err 581 } 582 } 583 584 func (c *commImpl) createConnectionMsg(pkiID common.PKIidType, certHash []byte, cert api.PeerIdentityType, signer proto.Signer) (*proto.SignedGossipMessage, error) { 585 m := &proto.GossipMessage{ 586 Tag: proto.GossipMessage_EMPTY, 587 Nonce: 0, 588 Content: &proto.GossipMessage_Conn{ 589 Conn: &proto.ConnEstablish{ 590 TlsCertHash: certHash, 591 Identity: cert, 592 PkiId: pkiID, 593 }, 594 }, 595 } 596 sMsg := &proto.SignedGossipMessage{ 597 GossipMessage: m, 598 } 599 _, err := sMsg.Sign(signer) 600 return sMsg, err 601 } 602 603 type stream interface { 604 Send(envelope *proto.Envelope) error 605 Recv() (*proto.Envelope, error) 606 grpc.Stream 607 } 608 609 func createGRPCLayer(port int) (*grpc.Server, net.Listener, api.PeerSecureDialOpts, []byte) { 610 var returnedCertHash []byte 611 var s *grpc.Server 612 var ll net.Listener 613 var err error 614 var serverOpts []grpc.ServerOption 615 var dialOpts []grpc.DialOption 616 617 cert := GenerateCertificatesOrPanic() 618 returnedCertHash = certHashFromRawCert(cert.Certificate[0]) 619 620 tlsConf := &tls.Config{ 621 Certificates: []tls.Certificate{cert}, 622 ClientAuth: tls.RequestClientCert, 623 InsecureSkipVerify: true, 624 } 625 serverOpts = append(serverOpts, grpc.Creds(credentials.NewTLS(tlsConf))) 626 ta := credentials.NewTLS(&tls.Config{ 627 Certificates: []tls.Certificate{cert}, 628 InsecureSkipVerify: true, 629 }) 630 dialOpts = append(dialOpts, grpc.WithTransportCredentials(ta)) 631 632 listenAddress := fmt.Sprintf("%s:%d", "", port) 633 ll, err = net.Listen("tcp", listenAddress) 634 if err != nil { 635 panic(err) 636 } 637 secureDialOpts := func() []grpc.DialOption { 638 return dialOpts 639 } 640 s = grpc.NewServer(serverOpts...) 641 return s, ll, secureDialOpts, returnedCertHash 642 }