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