github.com/yous1230/fabric@v2.0.0-beta.0.20191224111736-74345bee6ac2+incompatible/gossip/comm/comm_impl.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package comm 8 9 import ( 10 "bytes" 11 "context" 12 "crypto/tls" 13 "encoding/hex" 14 "fmt" 15 "reflect" 16 "sync" 17 "sync/atomic" 18 "time" 19 20 proto "github.com/hyperledger/fabric-protos-go/gossip" 21 "github.com/hyperledger/fabric/gossip/api" 22 "github.com/hyperledger/fabric/gossip/common" 23 "github.com/hyperledger/fabric/gossip/identity" 24 "github.com/hyperledger/fabric/gossip/metrics" 25 "github.com/hyperledger/fabric/gossip/protoext" 26 "github.com/hyperledger/fabric/gossip/util" 27 "github.com/pkg/errors" 28 "google.golang.org/grpc" 29 "google.golang.org/grpc/peer" 30 ) 31 32 const ( 33 handshakeTimeout = time.Second * 10 34 DefDialTimeout = time.Second * 3 35 DefConnTimeout = time.Second * 2 36 DefRecvBuffSize = 20 37 DefSendBuffSize = 20 38 ) 39 40 // SecurityAdvisor defines an external auxiliary object 41 // that provides security and identity related capabilities 42 type SecurityAdvisor interface { 43 // OrgByPeerIdentity returns the organization identity of the given PeerIdentityType 44 OrgByPeerIdentity(api.PeerIdentityType) api.OrgIdentityType 45 } 46 47 func (c *commImpl) SetDialOpts(opts ...grpc.DialOption) { 48 if len(opts) == 0 { 49 c.logger.Warning("Given an empty set of grpc.DialOption, aborting") 50 return 51 } 52 c.opts = opts 53 } 54 55 // NewCommInstance creates a new comm instance that binds itself to the given gRPC server 56 func NewCommInstance(s *grpc.Server, certs *common.TLSCertificates, idStore identity.Mapper, 57 peerIdentity api.PeerIdentityType, secureDialOpts api.PeerSecureDialOpts, sa api.SecurityAdvisor, 58 commMetrics *metrics.CommMetrics, config CommConfig, dialOpts ...grpc.DialOption) (Comm, error) { 59 60 commInst := &commImpl{ 61 sa: sa, 62 pubSub: util.NewPubSub(), 63 PKIID: idStore.GetPKIidOfCert(peerIdentity), 64 idMapper: idStore, 65 logger: util.GetLogger(util.CommLogger, ""), 66 peerIdentity: peerIdentity, 67 opts: dialOpts, 68 secureDialOpts: secureDialOpts, 69 msgPublisher: NewChannelDemultiplexer(), 70 lock: &sync.Mutex{}, 71 deadEndpoints: make(chan common.PKIidType, 100), 72 identityChanges: make(chan common.PKIidType, 1), 73 stopping: int32(0), 74 exitChan: make(chan struct{}), 75 subscriptions: make([]chan protoext.ReceivedMessage, 0), 76 tlsCerts: certs, 77 metrics: commMetrics, 78 dialTimeout: config.DialTimeout, 79 connTimeout: config.ConnTimeout, 80 recvBuffSize: config.RecvBuffSize, 81 sendBuffSize: config.SendBuffSize, 82 } 83 84 connConfig := ConnConfig{ 85 RecvBuffSize: config.RecvBuffSize, 86 SendBuffSize: config.SendBuffSize, 87 } 88 89 commInst.connStore = newConnStore(commInst, commInst.logger, connConfig) 90 91 proto.RegisterGossipServer(s, commInst) 92 93 return commInst, nil 94 } 95 96 // CommConfig is the configuration required to initialize a new comm 97 type CommConfig struct { 98 DialTimeout time.Duration // Dial timeout 99 ConnTimeout time.Duration // Connection timeout 100 RecvBuffSize int // Buffer size of received messages 101 SendBuffSize int // Buffer size of sending messages 102 } 103 104 type commImpl struct { 105 sa api.SecurityAdvisor 106 tlsCerts *common.TLSCertificates 107 pubSub *util.PubSub 108 peerIdentity api.PeerIdentityType 109 idMapper identity.Mapper 110 logger util.Logger 111 opts []grpc.DialOption 112 secureDialOpts func() []grpc.DialOption 113 connStore *connectionStore 114 PKIID []byte 115 deadEndpoints chan common.PKIidType 116 identityChanges chan common.PKIidType 117 msgPublisher *ChannelDeMultiplexer 118 lock *sync.Mutex 119 exitChan chan struct{} 120 stopWG sync.WaitGroup 121 subscriptions []chan protoext.ReceivedMessage 122 stopping int32 123 metrics *metrics.CommMetrics 124 dialTimeout time.Duration 125 connTimeout time.Duration 126 recvBuffSize int 127 sendBuffSize int 128 } 129 130 func (c *commImpl) createConnection(endpoint string, expectedPKIID common.PKIidType) (*connection, error) { 131 var err error 132 var cc *grpc.ClientConn 133 var stream proto.Gossip_GossipStreamClient 134 var pkiID common.PKIidType 135 var connInfo *protoext.ConnectionInfo 136 var dialOpts []grpc.DialOption 137 138 c.logger.Debug("Entering", endpoint, expectedPKIID) 139 defer c.logger.Debug("Exiting") 140 141 if c.isStopping() { 142 return nil, errors.New("Stopping") 143 } 144 dialOpts = append(dialOpts, c.secureDialOpts()...) 145 dialOpts = append(dialOpts, grpc.WithBlock()) 146 dialOpts = append(dialOpts, c.opts...) 147 ctx := context.Background() 148 ctx, cancel := context.WithTimeout(ctx, c.dialTimeout) 149 defer cancel() 150 cc, err = grpc.DialContext(ctx, endpoint, dialOpts...) 151 if err != nil { 152 return nil, errors.WithStack(err) 153 } 154 155 cl := proto.NewGossipClient(cc) 156 157 ctx, cancel = context.WithTimeout(context.Background(), DefConnTimeout) 158 defer cancel() 159 if _, err = cl.Ping(ctx, &proto.Empty{}); err != nil { 160 cc.Close() 161 return nil, errors.WithStack(err) 162 } 163 164 ctx, cancel = context.WithCancel(context.Background()) 165 if stream, err = cl.GossipStream(ctx); err == nil { 166 connInfo, err = c.authenticateRemotePeer(stream, true) 167 if err == nil { 168 pkiID = connInfo.ID 169 // PKIID is nil when we don't know the remote PKI id's 170 if expectedPKIID != nil && !bytes.Equal(pkiID, expectedPKIID) { 171 actualOrg := c.sa.OrgByPeerIdentity(connInfo.Identity) 172 // If the identity isn't present, it's nil - therefore OrgByPeerIdentity would 173 // return nil too and thus would be different than the actual organization 174 identity, _ := c.idMapper.Get(expectedPKIID) 175 oldOrg := c.sa.OrgByPeerIdentity(identity) 176 if !bytes.Equal(actualOrg, oldOrg) { 177 c.logger.Warning("Remote endpoint claims to be a different peer, expected", expectedPKIID, "but got", pkiID) 178 cc.Close() 179 cancel() 180 return nil, errors.New("authentication failure") 181 } else { 182 c.logger.Infof("Peer %s changed its PKI-ID from %s to %s", endpoint, expectedPKIID, pkiID) 183 c.identityChanges <- expectedPKIID 184 } 185 } 186 connConfig := ConnConfig{ 187 RecvBuffSize: c.recvBuffSize, 188 SendBuffSize: c.sendBuffSize, 189 } 190 conn := newConnection(cl, cc, stream, c.metrics, connConfig) 191 conn.pkiID = pkiID 192 conn.info = connInfo 193 conn.logger = c.logger 194 conn.cancel = cancel 195 196 h := func(m *protoext.SignedGossipMessage) { 197 c.logger.Debug("Got message:", m) 198 c.msgPublisher.DeMultiplex(&ReceivedMessageImpl{ 199 conn: conn, 200 SignedGossipMessage: m, 201 connInfo: connInfo, 202 }) 203 } 204 conn.handler = interceptAcks(h, connInfo.ID, c.pubSub) 205 return conn, nil 206 } 207 c.logger.Warningf("Authentication failed: %+v", err) 208 } 209 cc.Close() 210 cancel() 211 return nil, errors.WithStack(err) 212 } 213 214 func (c *commImpl) Send(msg *protoext.SignedGossipMessage, peers ...*RemotePeer) { 215 if c.isStopping() || len(peers) == 0 { 216 return 217 } 218 c.logger.Debug("Entering, sending", msg, "to ", len(peers), "peers") 219 220 for _, peer := range peers { 221 go func(peer *RemotePeer, msg *protoext.SignedGossipMessage) { 222 c.sendToEndpoint(peer, msg, nonBlockingSend) 223 }(peer, msg) 224 } 225 } 226 227 func (c *commImpl) sendToEndpoint(peer *RemotePeer, msg *protoext.SignedGossipMessage, shouldBlock blockingBehavior) { 228 if c.isStopping() { 229 return 230 } 231 c.logger.Debug("Entering, Sending to", peer.Endpoint, ", msg:", msg) 232 defer c.logger.Debug("Exiting") 233 var err error 234 235 conn, err := c.connStore.getConnection(peer) 236 if err == nil { 237 disConnectOnErr := func(err error) { 238 c.logger.Warningf("%v isn't responsive: %v", peer, err) 239 c.disconnect(peer.PKIID) 240 conn.close() 241 } 242 conn.send(msg, disConnectOnErr, shouldBlock) 243 return 244 } 245 c.logger.Warningf("Failed obtaining connection for %v reason: %v", peer, err) 246 c.disconnect(peer.PKIID) 247 } 248 249 func (c *commImpl) isStopping() bool { 250 return atomic.LoadInt32(&c.stopping) == int32(1) 251 } 252 253 func (c *commImpl) Probe(remotePeer *RemotePeer) error { 254 var dialOpts []grpc.DialOption 255 endpoint := remotePeer.Endpoint 256 pkiID := remotePeer.PKIID 257 if c.isStopping() { 258 return fmt.Errorf("Stopping") 259 } 260 c.logger.Debug("Entering, endpoint:", endpoint, "PKIID:", pkiID) 261 dialOpts = append(dialOpts, c.secureDialOpts()...) 262 dialOpts = append(dialOpts, grpc.WithBlock()) 263 dialOpts = append(dialOpts, c.opts...) 264 ctx := context.Background() 265 ctx, cancel := context.WithTimeout(ctx, c.dialTimeout) 266 defer cancel() 267 cc, err := grpc.DialContext(ctx, remotePeer.Endpoint, dialOpts...) 268 if err != nil { 269 c.logger.Debugf("Returning %v", err) 270 return err 271 } 272 defer cc.Close() 273 cl := proto.NewGossipClient(cc) 274 ctx, cancel = context.WithTimeout(context.Background(), DefConnTimeout) 275 defer cancel() 276 _, err = cl.Ping(ctx, &proto.Empty{}) 277 c.logger.Debugf("Returning %v", err) 278 return err 279 } 280 281 func (c *commImpl) Handshake(remotePeer *RemotePeer) (api.PeerIdentityType, error) { 282 var dialOpts []grpc.DialOption 283 dialOpts = append(dialOpts, c.secureDialOpts()...) 284 dialOpts = append(dialOpts, grpc.WithBlock()) 285 dialOpts = append(dialOpts, c.opts...) 286 ctx := context.Background() 287 ctx, cancel := context.WithTimeout(ctx, c.dialTimeout) 288 defer cancel() 289 cc, err := grpc.DialContext(ctx, remotePeer.Endpoint, dialOpts...) 290 if err != nil { 291 return nil, err 292 } 293 defer cc.Close() 294 295 cl := proto.NewGossipClient(cc) 296 ctx, cancel = context.WithTimeout(context.Background(), DefConnTimeout) 297 defer cancel() 298 if _, err = cl.Ping(ctx, &proto.Empty{}); err != nil { 299 return nil, err 300 } 301 302 ctx, cancel = context.WithTimeout(context.Background(), handshakeTimeout) 303 defer cancel() 304 stream, err := cl.GossipStream(ctx) 305 if err != nil { 306 return nil, err 307 } 308 connInfo, err := c.authenticateRemotePeer(stream, true) 309 if err != nil { 310 c.logger.Warningf("Authentication failed: %v", err) 311 return nil, err 312 } 313 if len(remotePeer.PKIID) > 0 && !bytes.Equal(connInfo.ID, remotePeer.PKIID) { 314 return nil, fmt.Errorf("PKI-ID of remote peer doesn't match expected PKI-ID") 315 } 316 return connInfo.Identity, nil 317 } 318 319 func (c *commImpl) Accept(acceptor common.MessageAcceptor) <-chan protoext.ReceivedMessage { 320 genericChan := c.msgPublisher.AddChannel(acceptor) 321 specificChan := make(chan protoext.ReceivedMessage, 10) 322 323 if c.isStopping() { 324 c.logger.Warning("Accept() called but comm module is stopping, returning empty channel") 325 return specificChan 326 } 327 328 c.lock.Lock() 329 c.subscriptions = append(c.subscriptions, specificChan) 330 c.lock.Unlock() 331 332 c.stopWG.Add(1) 333 go func() { 334 defer c.logger.Debug("Exiting Accept() loop") 335 336 defer c.stopWG.Done() 337 338 for { 339 select { 340 case msg, channelOpen := <-genericChan: 341 if !channelOpen { 342 return 343 } 344 select { 345 case specificChan <- msg.(*ReceivedMessageImpl): 346 case <-c.exitChan: 347 return 348 } 349 case <-c.exitChan: 350 return 351 } 352 } 353 }() 354 return specificChan 355 } 356 357 func (c *commImpl) PresumedDead() <-chan common.PKIidType { 358 return c.deadEndpoints 359 } 360 361 func (c *commImpl) IdentitySwitch() <-chan common.PKIidType { 362 return c.identityChanges 363 } 364 365 func (c *commImpl) CloseConn(peer *RemotePeer) { 366 c.logger.Debug("Closing connection for", peer) 367 c.connStore.closeConnByPKIid(peer.PKIID) 368 } 369 370 func (c *commImpl) closeSubscriptions() { 371 c.lock.Lock() 372 defer c.lock.Unlock() 373 for _, ch := range c.subscriptions { 374 close(ch) 375 } 376 } 377 378 func (c *commImpl) Stop() { 379 if !atomic.CompareAndSwapInt32(&c.stopping, 0, int32(1)) { 380 return 381 } 382 c.logger.Info("Stopping") 383 defer c.logger.Info("Stopped") 384 c.connStore.shutdown() 385 c.logger.Debug("Shut down connection store, connection count:", c.connStore.connNum()) 386 c.msgPublisher.Close() 387 close(c.exitChan) 388 c.stopWG.Wait() 389 c.closeSubscriptions() 390 } 391 392 func (c *commImpl) GetPKIid() common.PKIidType { 393 return c.PKIID 394 } 395 396 func extractRemoteAddress(stream stream) string { 397 var remoteAddress string 398 p, ok := peer.FromContext(stream.Context()) 399 if ok { 400 if address := p.Addr; address != nil { 401 remoteAddress = address.String() 402 } 403 } 404 return remoteAddress 405 } 406 407 func (c *commImpl) authenticateRemotePeer(stream stream, initiator bool) (*protoext.ConnectionInfo, error) { 408 ctx := stream.Context() 409 remoteAddress := extractRemoteAddress(stream) 410 remoteCertHash := extractCertificateHashFromContext(ctx) 411 var err error 412 var cMsg *protoext.SignedGossipMessage 413 useTLS := c.tlsCerts != nil 414 var selfCertHash []byte 415 416 if useTLS { 417 certReference := c.tlsCerts.TLSServerCert 418 if initiator { 419 certReference = c.tlsCerts.TLSClientCert 420 } 421 selfCertHash = certHashFromRawCert(certReference.Load().(*tls.Certificate).Certificate[0]) 422 } 423 424 signer := func(msg []byte) ([]byte, error) { 425 return c.idMapper.Sign(msg) 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, fmt.Errorf("No TLS certificate") 432 } 433 434 cMsg, err = c.createConnectionMsg(c.PKIID, 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, c.connTimeout, 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, fmt.Errorf("Wrong type") 450 } 451 452 if receivedMsg.PkiId == nil { 453 c.logger.Warningf("%s didn't send a pkiID", remoteAddress) 454 return nil, fmt.Errorf("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.Warningf("Identity store rejected %s : %v", remoteAddress, err) 461 return nil, err 462 } 463 464 connInfo := &protoext.ConnectionInfo{ 465 ID: receivedMsg.PkiId, 466 Identity: receivedMsg.Identity, 467 Endpoint: remoteAddress, 468 Auth: &protoext.AuthInfo{ 469 Signature: m.Signature, 470 SignedData: m.Payload, 471 }, 472 } 473 474 // if TLS is enabled and detected, verify remote peer 475 if useTLS { 476 // If the remote peer sent its TLS certificate, make sure it actually matches the TLS cert 477 // that the peer used. 478 if !bytes.Equal(remoteCertHash, receivedMsg.TlsCertHash) { 479 return nil, errors.Errorf("Expected %v in remote hash of TLS cert, but got %v", remoteCertHash, receivedMsg.TlsCertHash) 480 } 481 } 482 // Final step - verify the signature on the connection message itself 483 verifier := func(peerIdentity []byte, signature, message []byte) error { 484 pkiID := c.idMapper.GetPKIidOfCert(api.PeerIdentityType(peerIdentity)) 485 return c.idMapper.Verify(pkiID, signature, message) 486 } 487 err = m.Verify(receivedMsg.Identity, verifier) 488 if err != nil { 489 c.logger.Errorf("Failed verifying signature from %s : %v", remoteAddress, err) 490 return nil, err 491 } 492 493 c.logger.Debug("Authenticated", remoteAddress) 494 495 return connInfo, nil 496 } 497 498 // SendWithAck sends a message to remote peers, waiting for acknowledgement from minAck of them, or until a certain timeout expires 499 func (c *commImpl) SendWithAck(msg *protoext.SignedGossipMessage, timeout time.Duration, minAck int, peers ...*RemotePeer) AggregatedSendResult { 500 if len(peers) == 0 { 501 return nil 502 } 503 var err error 504 505 // Roll a random NONCE to be used as a send ID to differentiate 506 // between different invocations 507 msg.Nonce = util.RandomUInt64() 508 // Replace the envelope in the message to update the NONCE 509 msg, err = protoext.NoopSign(msg.GossipMessage) 510 511 if c.isStopping() || err != nil { 512 if err == nil { 513 err = errors.New("comm is stopping") 514 } 515 results := []SendResult{} 516 for _, p := range peers { 517 results = append(results, SendResult{ 518 error: err, 519 RemotePeer: *p, 520 }) 521 } 522 return results 523 } 524 c.logger.Debug("Entering, sending", msg, "to ", len(peers), "peers") 525 sndFunc := func(peer *RemotePeer, msg *protoext.SignedGossipMessage) { 526 c.sendToEndpoint(peer, msg, blockingSend) 527 } 528 // Subscribe to acks 529 subscriptions := make(map[string]func() error) 530 for _, p := range peers { 531 topic := topicForAck(msg.Nonce, p.PKIID) 532 sub := c.pubSub.Subscribe(topic, timeout) 533 subscriptions[string(p.PKIID)] = func() error { 534 msg, err := sub.Listen() 535 if err != nil { 536 return err 537 } 538 if msg, isAck := msg.(*proto.Acknowledgement); !isAck { 539 return fmt.Errorf("Received a message of type %s, expected *proto.Acknowledgement", reflect.TypeOf(msg)) 540 } else { 541 if msg.Error != "" { 542 return errors.New(msg.Error) 543 } 544 } 545 return nil 546 } 547 } 548 waitForAck := func(p *RemotePeer) error { 549 return subscriptions[string(p.PKIID)]() 550 } 551 ackOperation := newAckSendOperation(sndFunc, waitForAck) 552 return ackOperation.send(msg, minAck, peers...) 553 } 554 555 func (c *commImpl) GossipStream(stream proto.Gossip_GossipStreamServer) error { 556 if c.isStopping() { 557 return fmt.Errorf("Shutting down") 558 } 559 connInfo, err := c.authenticateRemotePeer(stream, false) 560 if err != nil { 561 c.logger.Errorf("Authentication failed: %v", err) 562 return err 563 } 564 c.logger.Debug("Servicing", extractRemoteAddress(stream)) 565 566 conn := c.connStore.onConnected(stream, connInfo, c.metrics) 567 568 h := func(m *protoext.SignedGossipMessage) { 569 c.msgPublisher.DeMultiplex(&ReceivedMessageImpl{ 570 conn: conn, 571 SignedGossipMessage: m, 572 connInfo: connInfo, 573 }) 574 } 575 576 conn.handler = interceptAcks(h, connInfo.ID, c.pubSub) 577 578 defer func() { 579 c.logger.Debug("Client", extractRemoteAddress(stream), " disconnected") 580 c.connStore.closeConnByPKIid(connInfo.ID) 581 }() 582 583 return conn.serviceConnection() 584 } 585 586 func (c *commImpl) Ping(context.Context, *proto.Empty) (*proto.Empty, error) { 587 return &proto.Empty{}, nil 588 } 589 590 func (c *commImpl) disconnect(pkiID common.PKIidType) { 591 if c.isStopping() { 592 return 593 } 594 c.deadEndpoints <- pkiID 595 c.connStore.closeConnByPKIid(pkiID) 596 } 597 598 func readWithTimeout(stream stream, timeout time.Duration, address string) (*protoext.SignedGossipMessage, error) { 599 incChan := make(chan *protoext.SignedGossipMessage, 1) 600 errChan := make(chan error, 1) 601 go func() { 602 if m, err := stream.Recv(); err == nil { 603 msg, err := protoext.EnvelopeToGossipMessage(m) 604 if err != nil { 605 errChan <- err 606 return 607 } 608 incChan <- msg 609 } 610 }() 611 select { 612 case <-time.After(timeout): 613 return nil, errors.Errorf("timed out waiting for connection message from %s", address) 614 case m := <-incChan: 615 return m, nil 616 case err := <-errChan: 617 return nil, errors.WithStack(err) 618 } 619 } 620 621 func (c *commImpl) createConnectionMsg(pkiID common.PKIidType, certHash []byte, cert api.PeerIdentityType, signer protoext.Signer) (*protoext.SignedGossipMessage, error) { 622 m := &proto.GossipMessage{ 623 Tag: proto.GossipMessage_EMPTY, 624 Nonce: 0, 625 Content: &proto.GossipMessage_Conn{ 626 Conn: &proto.ConnEstablish{ 627 TlsCertHash: certHash, 628 Identity: cert, 629 PkiId: pkiID, 630 }, 631 }, 632 } 633 sMsg := &protoext.SignedGossipMessage{ 634 GossipMessage: m, 635 } 636 _, err := sMsg.Sign(signer) 637 return sMsg, errors.WithStack(err) 638 } 639 640 type stream interface { 641 Send(envelope *proto.Envelope) error 642 Recv() (*proto.Envelope, error) 643 Context() context.Context 644 } 645 646 func topicForAck(nonce uint64, pkiID common.PKIidType) string { 647 return fmt.Sprintf("%d %s", nonce, hex.EncodeToString(pkiID)) 648 }