github.com/ergo-services/ergo@v1.999.224/node/network.go (about) 1 package node 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/binary" 7 "io" 8 "sync" 9 "time" 10 11 "crypto/aes" 12 "crypto/md5" 13 "crypto/rand" 14 "crypto/rsa" 15 "crypto/sha256" 16 "crypto/tls" 17 "crypto/x509" 18 "fmt" 19 20 "github.com/ergo-services/ergo/etf" 21 "github.com/ergo-services/ergo/gen" 22 "github.com/ergo-services/ergo/lib" 23 24 "net" 25 26 "strconv" 27 "strings" 28 ) 29 30 type networkInternal interface { 31 // add/remove static route 32 AddStaticRoute(node string, host string, port uint16, options RouteOptions) error 33 AddStaticRoutePort(node string, port uint16, options RouteOptions) error 34 AddStaticRouteOptions(node string, options RouteOptions) error 35 RemoveStaticRoute(node string) bool 36 StaticRoutes() []Route 37 StaticRoute(name string) (Route, bool) 38 39 // add/remove proxy route 40 AddProxyRoute(route ProxyRoute) error 41 RemoveProxyRoute(name string) bool 42 ProxyRoutes() []ProxyRoute 43 ProxyRoute(name string) (ProxyRoute, bool) 44 45 Registrar() Registrar 46 Resolve(peername string) (Route, error) 47 ResolveProxy(peername string) (ProxyRoute, error) 48 49 Connect(peername string) error 50 Disconnect(peername string) error 51 Nodes() []string 52 NodesIndirect() []string 53 54 // stats 55 NetworkStats(name string) (NetworkStats, error) 56 57 // core router methods 58 RouteProxyConnectRequest(from ConnectionInterface, request ProxyConnectRequest) error 59 RouteProxyConnectReply(from ConnectionInterface, reply ProxyConnectReply) error 60 RouteProxyConnectCancel(from ConnectionInterface, cancel ProxyConnectCancel) error 61 RouteProxyDisconnect(from ConnectionInterface, disconnect ProxyDisconnect) error 62 RouteProxy(from ConnectionInterface, sessionID string, packet *lib.Buffer) error 63 64 getConnection(peername string) (ConnectionInterface, error) 65 stopNetwork() 66 67 networkStats() internalNetworkStats 68 } 69 70 type internalNetworkStats struct { 71 transitConnections int 72 proxyConnections int 73 connections int 74 } 75 76 type connectionInternal struct { 77 // conn. has nil value for the proxy connection 78 conn net.Conn 79 // connection interface of the network connection 80 connection ConnectionInterface 81 // 82 proxySessionID string 83 // 84 proxyTransitTo map[string]bool 85 } 86 87 type network struct { 88 nodename string 89 cookie string 90 ctx context.Context 91 listeners []net.Listener 92 93 registrar Registrar 94 staticOnly bool 95 staticRoutes map[string]Route 96 staticRoutesMutex sync.RWMutex 97 98 proxyRoutes map[string]ProxyRoute 99 proxyRoutesMutex sync.RWMutex 100 101 connections map[string]connectionInternal 102 connectionsProxy map[ConnectionInterface][]string // peers via proxy 103 connectionsTransit map[ConnectionInterface][]string // transit session IDs 104 connectionsMutex sync.RWMutex 105 106 proxyTransitSessions map[string]proxyTransitSession 107 proxyTransitSessionsMutex sync.RWMutex 108 109 proxyConnectRequest map[etf.Ref]proxyConnectRequest 110 proxyConnectRequestMutex sync.RWMutex 111 112 tls *tls.Config 113 proxy Proxy 114 version Version 115 creation uint32 116 flags Flags 117 118 router coreRouterInternal 119 handshake HandshakeInterface 120 proto ProtoInterface 121 122 remoteSpawn map[string]gen.ProcessBehavior 123 remoteSpawnMutex sync.Mutex 124 } 125 126 func newNetwork(ctx context.Context, nodename string, cookie string, options Options, router coreRouterInternal) (networkInternal, error) { 127 n := &network{ 128 nodename: nodename, 129 cookie: cookie, 130 ctx: ctx, 131 tls: options.TLS, 132 staticOnly: options.StaticRoutesOnly, 133 staticRoutes: make(map[string]Route), 134 proxyRoutes: make(map[string]ProxyRoute), 135 connections: make(map[string]connectionInternal), 136 connectionsProxy: make(map[ConnectionInterface][]string), 137 connectionsTransit: make(map[ConnectionInterface][]string), 138 proxyTransitSessions: make(map[string]proxyTransitSession), 139 proxyConnectRequest: make(map[etf.Ref]proxyConnectRequest), 140 remoteSpawn: make(map[string]gen.ProcessBehavior), 141 flags: options.Flags, 142 proxy: options.Proxy, 143 registrar: options.Registrar, 144 handshake: options.Handshake, 145 proto: options.Proto, 146 router: router, 147 creation: options.Creation, 148 } 149 150 splitNodeHost := strings.Split(nodename, "@") 151 if len(splitNodeHost) != 2 || splitNodeHost[0] == "" || splitNodeHost[1] == "" { 152 return nil, fmt.Errorf("FQDN for node name is required (example: node@hostname)") 153 } 154 155 if n.proxy.Flags.Enable == false { 156 n.proxy.Flags = DefaultProxyFlags() 157 } 158 159 n.version, _ = options.Env[EnvKeyVersion].(Version) 160 161 if len(options.Listeners) == 0 { 162 return nil, fmt.Errorf("no listeners defined") 163 } 164 for i, lo := range options.Listeners { 165 if lo.TLS == nil { 166 lo.TLS = options.TLS 167 } 168 if lo.Handshake == nil { 169 lo.Handshake = options.Handshake 170 } 171 if lo.Proto == nil { 172 lo.Proto = options.Proto 173 } 174 if lo.Flags.Enable == false { 175 lo.Flags = options.Flags 176 } 177 if lo.Cookie == "" { 178 lo.Cookie = cookie 179 } 180 181 if err := lo.Handshake.Init(n.nodename, n.creation, lo.Flags); err != nil { 182 return nil, err 183 } 184 185 if lo.Listen > 0 { 186 lo.ListenBegin = lo.Listen 187 lo.ListenEnd = lo.Listen 188 lib.Log("Node listener[%d] port: %d", i, lo.Listen) 189 } else { 190 if lo.ListenBegin == 0 { 191 lo.ListenBegin = defaultListenBegin 192 } 193 if lo.ListenEnd == 0 { 194 lo.ListenEnd = defaultListenEnd 195 } 196 lib.Log("Node listener[%d] port range: %d...%d", i, lo.ListenBegin, lo.ListenEnd) 197 } 198 register := i == 0 199 listener, err := n.listen(ctx, splitNodeHost[1], lo, register) 200 if err != nil { 201 // close all listening sockets 202 n.stopNetwork() 203 return nil, err 204 } 205 n.listeners = append(n.listeners, listener) 206 } 207 208 return n, nil 209 } 210 211 func (n *network) stopNetwork() { 212 for _, l := range n.listeners { 213 l.Close() 214 } 215 n.connectionsMutex.RLock() 216 defer n.connectionsMutex.RUnlock() 217 for _, ci := range n.connections { 218 if ci.conn == nil { 219 continue 220 } 221 ci.conn.Close() 222 } 223 } 224 225 // AddStaticRouteOptions adds static options for the given node. 226 func (n *network) AddStaticRouteOptions(node string, options RouteOptions) error { 227 if n.staticOnly { 228 return fmt.Errorf("can't be used if enabled StaticRoutesOnly") 229 } 230 return n.AddStaticRoute(node, "", 0, options) 231 } 232 233 // AddStaticRoutePort adds a static route to the node with the given name 234 func (n *network) AddStaticRoutePort(node string, port uint16, options RouteOptions) error { 235 ns := strings.Split(node, "@") 236 if port < 1 { 237 return fmt.Errorf("port must be greater 0") 238 } 239 if len(ns) != 2 { 240 return fmt.Errorf("wrong FQDN") 241 } 242 return n.AddStaticRoute(node, ns[1], port, options) 243 244 } 245 246 // AddStaticRoute adds a static route to the node with the given name 247 func (n *network) AddStaticRoute(node string, host string, port uint16, options RouteOptions) error { 248 if len(strings.Split(node, "@")) != 2 { 249 return fmt.Errorf("wrong FQDN") 250 } 251 252 if port > 0 { 253 if _, err := net.LookupHost(host); err != nil { 254 return err 255 } 256 } 257 258 route := Route{ 259 Node: node, 260 Host: host, 261 Port: port, 262 Options: options, 263 } 264 265 n.staticRoutesMutex.Lock() 266 defer n.staticRoutesMutex.Unlock() 267 268 _, exist := n.staticRoutes[node] 269 if exist { 270 return lib.ErrTaken 271 } 272 273 if options.Handshake != nil { 274 if err := options.Handshake.Init(n.nodename, n.creation, n.flags); err != nil { 275 return err 276 } 277 } 278 n.staticRoutes[node] = route 279 280 return nil 281 } 282 283 // RemoveStaticRoute removes static route record. Returns false if it doesn't exist. 284 func (n *network) RemoveStaticRoute(node string) bool { 285 n.staticRoutesMutex.Lock() 286 defer n.staticRoutesMutex.Unlock() 287 _, exist := n.staticRoutes[node] 288 if exist { 289 delete(n.staticRoutes, node) 290 return true 291 } 292 return false 293 } 294 295 // StaticRoutes returns list of static routes added with AddStaticRoute 296 func (n *network) StaticRoutes() []Route { 297 var routes []Route 298 299 n.staticRoutesMutex.RLock() 300 defer n.staticRoutesMutex.RUnlock() 301 for _, v := range n.staticRoutes { 302 routes = append(routes, v) 303 } 304 305 return routes 306 } 307 308 func (n *network) StaticRoute(name string) (Route, bool) { 309 n.staticRoutesMutex.RLock() 310 defer n.staticRoutesMutex.RUnlock() 311 route, exist := n.staticRoutes[name] 312 return route, exist 313 } 314 315 func (n *network) getConnectionDirect(peername string, connect bool) (ConnectionInterface, error) { 316 n.connectionsMutex.RLock() 317 ci, ok := n.connections[peername] 318 n.connectionsMutex.RUnlock() 319 if ok { 320 return ci.connection, nil 321 } 322 323 if connect == false { 324 return nil, lib.ErrNoRoute 325 } 326 327 connection, err := n.connect(peername) 328 if err != nil { 329 lib.Log("[%s] CORE no route to node %q: %s", n.nodename, peername, err) 330 return nil, lib.ErrNoRoute 331 } 332 return connection, nil 333 334 } 335 336 // getConnection 337 func (n *network) getConnection(peername string) (ConnectionInterface, error) { 338 if peername == n.nodename { 339 // can't connect to itself 340 return nil, lib.ErrNoRoute 341 } 342 n.connectionsMutex.RLock() 343 ci, ok := n.connections[peername] 344 n.connectionsMutex.RUnlock() 345 if ok { 346 lib.Log("[%s] NETWORK found active connection with %s", n.nodename, peername) 347 return ci.connection, nil 348 } 349 350 // try to connect via proxy if there ProxyRoute was presented for this peer 351 request := ProxyConnectRequest{ 352 ID: n.router.MakeRef(), 353 To: peername, 354 Creation: n.creation, 355 } 356 357 if err := n.RouteProxyConnectRequest(nil, request); err != nil { 358 if err != lib.ErrProxyNoRoute { 359 return nil, err 360 } 361 362 // there wasn't proxy presented. try to connect directly. 363 connection, err := n.getConnectionDirect(peername, true) 364 return connection, err 365 } 366 367 connection, err := n.waitProxyConnection(request.ID, 5) 368 if err != nil { 369 return nil, err 370 } 371 372 return connection, nil 373 } 374 375 // Resolve 376 func (n *network) Resolve(node string) (Route, error) { 377 n.staticRoutesMutex.RLock() 378 defer n.staticRoutesMutex.RUnlock() 379 380 if r, ok := n.staticRoutes[node]; ok { 381 if r.Port == 0 { 382 // use static option for this route 383 route, err := n.registrar.Resolve(node) 384 route.Options = r.Options 385 return route, err 386 } 387 return r, nil 388 } 389 390 if n.staticOnly { 391 return Route{}, lib.ErrNoRoute 392 } 393 394 return n.registrar.Resolve(node) 395 } 396 397 // ResolveProxy 398 func (n *network) ResolveProxy(name string) (ProxyRoute, error) { 399 n.proxyRoutesMutex.RLock() 400 defer n.proxyRoutesMutex.RUnlock() 401 route, found := n.proxyRoutes[name] 402 if found == false { 403 sn := strings.Split(name, "@") 404 if len(sn) != 2 { 405 return route, lib.ErrUnknown 406 } 407 domain := "@" + sn[1] 408 route, found = n.proxyRoutes[domain] 409 } 410 if found == false { 411 return n.registrar.ResolveProxy(name) 412 } 413 if route.Proxy == "" { 414 r, err := n.registrar.ResolveProxy(name) 415 if err != nil { 416 return route, err 417 } 418 route.Proxy = r.Proxy 419 } 420 return route, nil 421 } 422 423 // Registrar 424 func (n *network) Registrar() Registrar { 425 return n.registrar 426 } 427 428 // Connect 429 func (n *network) Connect(node string) error { 430 _, err := n.getConnection(node) 431 return err 432 } 433 434 // Disconnect 435 func (n *network) Disconnect(node string) error { 436 n.connectionsMutex.RLock() 437 ci, ok := n.connections[node] 438 n.connectionsMutex.RUnlock() 439 if !ok { 440 return lib.ErrNoRoute 441 } 442 443 if ci.conn == nil { 444 // this is proxy connection 445 disconnect := ProxyDisconnect{ 446 Node: n.nodename, 447 Proxy: n.nodename, 448 SessionID: ci.proxySessionID, 449 Reason: "normal", 450 } 451 n.unregisterConnection(node, &disconnect) 452 return ci.connection.ProxyDisconnect(disconnect) 453 } 454 455 ci.conn.Close() 456 return nil 457 } 458 459 // Nodes 460 func (n *network) Nodes() []string { 461 list := []string{} 462 n.connectionsMutex.RLock() 463 defer n.connectionsMutex.RUnlock() 464 465 for node := range n.connections { 466 list = append(list, node) 467 } 468 return list 469 } 470 471 func (n *network) NodesIndirect() []string { 472 list := []string{} 473 n.connectionsMutex.RLock() 474 defer n.connectionsMutex.RUnlock() 475 476 for node, ci := range n.connections { 477 if ci.conn == nil { 478 list = append(list, node) 479 } 480 } 481 return list 482 } 483 484 func (n *network) NetworkStats(name string) (NetworkStats, error) { 485 var stats NetworkStats 486 n.connectionsMutex.RLock() 487 ci, found := n.connections[name] 488 n.connectionsMutex.RUnlock() 489 490 if found == false { 491 return stats, lib.ErrUnknown 492 } 493 494 stats = ci.connection.Stats() 495 return stats, nil 496 } 497 498 // RouteProxyConnectRequest 499 func (n *network) RouteProxyConnectRequest(from ConnectionInterface, request ProxyConnectRequest) error { 500 if request.To != n.nodename { 501 var err error 502 var connection ConnectionInterface 503 var proxyTransitTo map[string]bool 504 // 505 // outgoing proxy request 506 // 507 508 // check if we already have 509 n.connectionsMutex.RLock() 510 if ci, exist := n.connections[request.To]; exist { 511 connection = ci.connection 512 proxyTransitTo = ci.proxyTransitTo 513 } 514 n.connectionsMutex.RUnlock() 515 516 if from != nil { 517 // 518 // transit request 519 // 520 if from == connection { 521 lib.Log("[%s] NETWORK proxy. Error: proxy route points to the connection this request came from", n.nodename) 522 return lib.ErrProxyLoopDetected 523 } 524 lib.Log("[%s] NETWORK transit proxy connection to %q", n.nodename, request.To) 525 526 // proxy feature must be enabled explicitly for the transitional requests 527 if n.proxy.Transit == false { 528 lib.Log("[%s] NETWORK proxy. Proxy feature is disabled on this node", n.nodename) 529 return lib.ErrProxyTransitDisabled 530 } 531 532 if proxyTransitTo != nil { 533 if proxyTransitTo[request.To] == false { 534 nodeHost := strings.Split(request.To, "@") 535 if len(nodeHost) != 2 || proxyTransitTo[nodeHost[1]] == false { 536 lib.Log("[%s] NETWORK proxy. Proxy connection is restricted (to: %s)", n.nodename, request.To) 537 return lib.ErrProxyTransitRestricted 538 } 539 } 540 } 541 542 if request.Hop < 1 { 543 lib.Log("[%s] NETWORK proxy. Error: exceeded hop limit", n.nodename) 544 return lib.ErrProxyHopExceeded 545 } 546 request.Hop-- 547 548 if len(request.Path) > defaultProxyPathLimit { 549 return lib.ErrProxyPathTooLong 550 } 551 552 for i := range request.Path { 553 if n.nodename != request.Path[i] { 554 continue 555 } 556 lib.Log("[%s] NETWORK proxy. Error: loop detected in proxy path %#v", n.nodename, request.Path) 557 return lib.ErrProxyLoopDetected 558 } 559 560 if connection == nil { 561 // check if we have proxy route 562 route, err_route := n.ResolveProxy(request.To) 563 if err_route == nil && route.Proxy != n.nodename { 564 // proxy request goes to the next hop 565 connection, err = n.getConnectionDirect(route.Proxy, true) 566 } else { 567 connection, err = n.getConnectionDirect(request.To, true) 568 } 569 570 if err != nil { 571 return err 572 } 573 } 574 575 request.Path = append([]string{n.nodename}, request.Path...) 576 err = connection.ProxyConnectRequest(request) 577 return err 578 } 579 580 if connection == nil { 581 route, err_route := n.ResolveProxy(request.To) 582 if err_route != nil { 583 // if it was invoked from getConnection ('from' == nil) there will 584 // be attempt to make direct connection using getConnectionDirect 585 return lib.ErrProxyNoRoute 586 } 587 588 // initiating proxy connection 589 lib.Log("[%s] NETWORK initiate proxy connection to %q via %q", n.nodename, request.To, route.Proxy) 590 connection, err = n.getConnectionDirect(route.Proxy, true) 591 if err != nil { 592 return err 593 } 594 595 } 596 597 cookie := n.proxy.Cookie 598 flags := n.proxy.Flags 599 if route, err_route := n.ResolveProxy(request.To); err_route == nil { 600 cookie = route.Cookie 601 if request.Flags.Enable == false { 602 flags = route.Flags 603 } 604 } 605 privKey, _ := rsa.GenerateKey(rand.Reader, 2048) 606 pubKey := x509.MarshalPKCS1PublicKey(&privKey.PublicKey) 607 request.PublicKey = pubKey 608 request.Flags = flags 609 610 // create digest using creation, cookie and pubKey. 611 // we can't use neither n.nodename or request.To, or request.ID - 612 // - anything that contains nodename or peername, because of etf.AtomMapping. 613 request.Digest = generateProxyDigest(n.creation, cookie, pubKey) 614 615 if request.Hop < 1 { 616 request.Hop = DefaultProxyMaxHop 617 } 618 request.Creation = n.creation 619 connectRequest := proxyConnectRequest{ 620 privateKey: privKey, 621 request: request, 622 connection: make(chan ConnectionInterface), 623 cancel: make(chan ProxyConnectCancel), 624 } 625 request.Path = []string{n.nodename} 626 if err := connection.ProxyConnectRequest(request); err != nil { 627 return err 628 } 629 n.putProxyConnectRequest(connectRequest) 630 return nil 631 } 632 633 // 634 // handle proxy connect request 635 // 636 637 // check digest 638 // use the last item in the request.Path as a peername 639 if len(request.Path) < 2 { 640 // reply error. there must be atleast 2 nodes - initiating and transit nodes 641 lib.Log("[%s] NETWORK proxy. Proxy connect request has wrong path (too short)", n.nodename) 642 return lib.ErrProxyConnect 643 } 644 peername := request.Path[len(request.Path)-1] 645 646 if n.proxy.Accept == false { 647 lib.Warning("[%s] Got proxy connect request from %q. Not allowed.", n.nodename, peername) 648 return lib.ErrProxyConnect 649 } 650 651 cookie := n.proxy.Cookie 652 flags := n.proxy.Flags 653 if route, err_route := n.ResolveProxy(peername); err_route == nil { 654 cookie = route.Cookie 655 if request.Flags.Enable == false { 656 flags = route.Flags 657 } 658 } 659 checkDigest := generateProxyDigest(request.Creation, cookie, request.PublicKey) 660 if bytes.Equal(request.Digest, checkDigest) == false { 661 // reply error. digest mismatch 662 lib.Log("[%s] NETWORK proxy. Proxy connect request has wrong digest", n.nodename) 663 return lib.ErrProxyConnect 664 } 665 666 // do some encryption magic 667 pk, err := x509.ParsePKCS1PublicKey(request.PublicKey) 668 if err != nil { 669 lib.Log("[%s] NETWORK proxy. Proxy connect request has wrong public key", n.nodename) 670 return lib.ErrProxyConnect 671 } 672 hash := sha256.New() 673 key := make([]byte, 32) 674 rand.Read(key) 675 cipherkey, err := rsa.EncryptOAEP(hash, rand.Reader, pk, key, nil) 676 if err != nil { 677 lib.Log("[%s] NETWORK proxy. Proxy connect request. Can't encrypt: %s ", n.nodename, err) 678 return lib.ErrProxyConnect 679 } 680 block, err := aes.NewCipher(key) 681 if err != nil { 682 return err 683 } 684 685 sessionID := lib.RandomString(32) 686 digest := generateProxyDigest(n.creation, n.proxy.Cookie, key) 687 if flags.Enable == false { 688 flags = DefaultProxyFlags() 689 } 690 691 // if one of the nodes want to use encryption then it must be used by both nodes 692 if request.Flags.EnableEncryption || flags.EnableEncryption { 693 request.Flags.EnableEncryption = true 694 flags.EnableEncryption = true 695 } 696 697 cInternal := connectionInternal{ 698 connection: from, 699 proxySessionID: sessionID, 700 } 701 if _, err := n.registerConnection(peername, cInternal); err != nil { 702 return lib.ErrProxySessionDuplicate 703 } 704 705 reply := ProxyConnectReply{ 706 ID: request.ID, 707 To: peername, 708 Digest: digest, 709 Cipher: cipherkey, 710 Flags: flags, 711 Creation: n.creation, 712 SessionID: sessionID, 713 Path: request.Path[1:], 714 } 715 716 if err := from.ProxyConnectReply(reply); err != nil { 717 // can't send reply. ignore this connection request 718 lib.Log("[%s] NETWORK proxy. Proxy connect request. Can't send reply: %s ", n.nodename, err) 719 n.unregisterConnection(peername, nil) 720 return lib.ErrProxyConnect 721 } 722 723 session := ProxySession{ 724 ID: sessionID, 725 NodeFlags: reply.Flags, 726 PeerFlags: request.Flags, 727 PeerName: peername, 728 Creation: request.Creation, 729 Block: block, 730 } 731 732 // register proxy session 733 from.ProxyRegisterSession(session) 734 return nil 735 } 736 737 func (n *network) RouteProxyConnectReply(from ConnectionInterface, reply ProxyConnectReply) error { 738 739 n.proxyTransitSessionsMutex.RLock() 740 _, duplicate := n.proxyTransitSessions[reply.SessionID] 741 n.proxyTransitSessionsMutex.RUnlock() 742 743 if duplicate { 744 return lib.ErrProxySessionDuplicate 745 } 746 747 if from == nil { 748 // from value can't be nil 749 return lib.ErrProxyUnknownRequest 750 } 751 752 if reply.To != n.nodename { 753 // send this reply further and register this session 754 if n.proxy.Transit == false { 755 return lib.ErrProxyTransitDisabled 756 } 757 758 if len(reply.Path) == 0 { 759 return lib.ErrProxyUnknownRequest 760 } 761 if len(reply.Path) > defaultProxyPathLimit { 762 return lib.ErrProxyPathTooLong 763 } 764 765 next := reply.Path[0] 766 connection, err := n.getConnectionDirect(next, false) 767 if err != nil { 768 return err 769 } 770 if connection == from { 771 return lib.ErrProxyLoopDetected 772 } 773 774 reply.Path = reply.Path[1:] 775 // check for the looping 776 for i := range reply.Path { 777 if reply.Path[i] == next { 778 return lib.ErrProxyLoopDetected 779 } 780 } 781 782 if err := connection.ProxyConnectReply(reply); err != nil { 783 return err 784 } 785 786 // register transit proxy session 787 n.proxyTransitSessionsMutex.Lock() 788 session := proxyTransitSession{ 789 a: from, 790 b: connection, 791 } 792 n.proxyTransitSessions[reply.SessionID] = session 793 n.proxyTransitSessionsMutex.Unlock() 794 795 // keep session id for both connections in order 796 // to handle connection closing (we should 797 // send ProxyDisconnect if one of the connection 798 // was closed) 799 n.connectionsMutex.Lock() 800 sessions, _ := n.connectionsTransit[session.a] 801 sessions = append(sessions, reply.SessionID) 802 n.connectionsTransit[session.a] = sessions 803 sessions, _ = n.connectionsTransit[session.b] 804 sessions = append(sessions, reply.SessionID) 805 n.connectionsTransit[session.b] = sessions 806 n.connectionsMutex.Unlock() 807 return nil 808 } 809 810 // look up for the request we made earlier 811 r, found := n.getProxyConnectRequest(reply.ID) 812 if found == false { 813 return lib.ErrProxyUnknownRequest 814 } 815 816 // decrypt cipher key using private key 817 hash := sha256.New() 818 key, err := rsa.DecryptOAEP(hash, rand.Reader, r.privateKey, reply.Cipher, nil) 819 if err != nil { 820 lib.Log("[%s] CORE route proxy. Proxy connect reply has invalid cipher", n.nodename) 821 return lib.ErrProxyConnect 822 } 823 824 cookie := n.proxy.Cookie 825 // check if we should use proxy route cookie 826 n.proxyRoutesMutex.RLock() 827 route, has_route := n.proxyRoutes[r.request.To] 828 n.proxyRoutesMutex.RUnlock() 829 if has_route { 830 cookie = route.Cookie 831 } 832 // check digest 833 checkDigest := generateProxyDigest(reply.Creation, cookie, key) 834 if bytes.Equal(checkDigest, reply.Digest) == false { 835 lib.Log("[%s] CORE route proxy. Proxy connect reply has wrong digest", n.nodename) 836 return lib.ErrProxyConnect 837 } 838 839 block, err := aes.NewCipher(key) 840 if err != nil { 841 return err 842 } 843 cInternal := connectionInternal{ 844 connection: from, 845 proxySessionID: reply.SessionID, 846 } 847 if registered, err := n.registerConnection(r.request.To, cInternal); err != nil { 848 select { 849 case r.connection <- registered: 850 } 851 return lib.ErrProxySessionDuplicate 852 } 853 // if one of the nodes want to use encryption then it must be used by both nodes 854 if r.request.Flags.EnableEncryption || reply.Flags.EnableEncryption { 855 r.request.Flags.EnableEncryption = true 856 reply.Flags.EnableEncryption = true 857 } 858 859 session := ProxySession{ 860 ID: reply.SessionID, 861 NodeFlags: r.request.Flags, 862 PeerFlags: reply.Flags, 863 PeerName: r.request.To, 864 Creation: reply.Creation, 865 Block: block, 866 } 867 868 // register proxy session 869 from.ProxyRegisterSession(session) 870 871 select { 872 case r.connection <- from: 873 } 874 875 return nil 876 } 877 878 func (n *network) RouteProxyConnectCancel(from ConnectionInterface, cancel ProxyConnectCancel) error { 879 if from == nil { 880 // from value can not be nil 881 return lib.ErrProxyConnect 882 } 883 if len(cancel.Path) == 0 { 884 n.cancelProxyConnectRequest(cancel) 885 return nil 886 } 887 888 next := cancel.Path[0] 889 if next != n.nodename { 890 if len(cancel.Path) > defaultProxyPathLimit { 891 return lib.ErrProxyPathTooLong 892 } 893 connection, err := n.getConnectionDirect(next, false) 894 if err != nil { 895 return err 896 } 897 898 if connection == from { 899 return lib.ErrProxyLoopDetected 900 } 901 902 cancel.Path = cancel.Path[1:] 903 // check for the looping 904 for i := range cancel.Path { 905 if cancel.Path[i] == next { 906 return lib.ErrProxyLoopDetected 907 } 908 } 909 910 if err := connection.ProxyConnectCancel(cancel); err != nil { 911 return err 912 } 913 return nil 914 } 915 916 return lib.ErrProxyUnknownRequest 917 } 918 919 func (n *network) RouteProxyDisconnect(from ConnectionInterface, disconnect ProxyDisconnect) error { 920 921 n.proxyTransitSessionsMutex.RLock() 922 session, isTransitSession := n.proxyTransitSessions[disconnect.SessionID] 923 n.proxyTransitSessionsMutex.RUnlock() 924 if isTransitSession == false { 925 // check for the proxy connection endpoint 926 var peername string 927 var found bool 928 var ci connectionInternal 929 930 // get peername by session id 931 n.connectionsMutex.RLock() 932 for p, c := range n.connections { 933 if c.proxySessionID != disconnect.SessionID { 934 continue 935 } 936 found = true 937 peername = p 938 ci = c 939 break 940 } 941 if found == false { 942 n.connectionsMutex.RUnlock() 943 return lib.ErrProxySessionUnknown 944 } 945 n.connectionsMutex.RUnlock() 946 947 if ci.proxySessionID != disconnect.SessionID || ci.connection != from { 948 return lib.ErrProxySessionUnknown 949 } 950 951 n.unregisterConnection(peername, &disconnect) 952 return nil 953 } 954 955 n.proxyTransitSessionsMutex.Lock() 956 delete(n.proxyTransitSessions, disconnect.SessionID) 957 n.proxyTransitSessionsMutex.Unlock() 958 959 // remove this session from the connections 960 n.connectionsMutex.Lock() 961 sessions, ok := n.connectionsTransit[session.a] 962 if ok { 963 for i := range sessions { 964 if sessions[i] == disconnect.SessionID { 965 sessions[i] = sessions[0] 966 sessions = sessions[1:] 967 n.connectionsTransit[session.a] = sessions 968 break 969 } 970 } 971 } 972 sessions, ok = n.connectionsTransit[session.b] 973 if ok { 974 for i := range sessions { 975 if sessions[i] == disconnect.SessionID { 976 sessions[i] = sessions[0] 977 sessions = sessions[1:] 978 n.connectionsTransit[session.b] = sessions 979 break 980 } 981 } 982 } 983 n.connectionsMutex.Unlock() 984 985 // send this message further 986 switch from { 987 case session.b: 988 return session.a.ProxyDisconnect(disconnect) 989 case session.a: 990 return session.b.ProxyDisconnect(disconnect) 991 default: 992 // shouldn't happen 993 panic("internal error") 994 } 995 } 996 997 func (n *network) RouteProxy(from ConnectionInterface, sessionID string, packet *lib.Buffer) error { 998 // check if this session is present on this node 999 n.proxyTransitSessionsMutex.RLock() 1000 session, ok := n.proxyTransitSessions[sessionID] 1001 n.proxyTransitSessionsMutex.RUnlock() 1002 1003 if !ok { 1004 return lib.ErrProxySessionUnknown 1005 } 1006 1007 switch from { 1008 case session.b: 1009 return session.a.ProxyPacket(packet) 1010 case session.a: 1011 return session.b.ProxyPacket(packet) 1012 default: 1013 // shouldn't happen 1014 panic("internal error") 1015 } 1016 } 1017 1018 func (n *network) AddProxyRoute(route ProxyRoute) error { 1019 n.proxyRoutesMutex.Lock() 1020 defer n.proxyRoutesMutex.Unlock() 1021 if route.MaxHop > defaultProxyPathLimit { 1022 return lib.ErrProxyPathTooLong 1023 } 1024 if route.MaxHop < 1 { 1025 route.MaxHop = DefaultProxyMaxHop 1026 } 1027 1028 if route.Flags.Enable == false { 1029 route.Flags = n.proxy.Flags 1030 } 1031 1032 if s := strings.Split(route.Name, "@"); len(s) == 2 { 1033 if s[0] == "" { 1034 // must be domain name 1035 if strings.HasPrefix(route.Name, "@") == false { 1036 return lib.ErrRouteName 1037 } 1038 } 1039 } else { 1040 return lib.ErrRouteName 1041 } 1042 1043 if _, exist := n.proxyRoutes[route.Name]; exist { 1044 return lib.ErrTaken 1045 } 1046 1047 n.proxyRoutes[route.Name] = route 1048 return nil 1049 } 1050 1051 func (n *network) RemoveProxyRoute(name string) bool { 1052 n.proxyRoutesMutex.Lock() 1053 defer n.proxyRoutesMutex.Unlock() 1054 if _, exist := n.proxyRoutes[name]; exist == false { 1055 return false 1056 } 1057 delete(n.proxyRoutes, name) 1058 return true 1059 } 1060 1061 func (n *network) ProxyRoutes() []ProxyRoute { 1062 var routes []ProxyRoute 1063 n.proxyRoutesMutex.RLock() 1064 defer n.proxyRoutesMutex.RUnlock() 1065 for _, v := range n.proxyRoutes { 1066 routes = append(routes, v) 1067 } 1068 return routes 1069 } 1070 1071 func (n *network) ProxyRoute(name string) (ProxyRoute, bool) { 1072 n.proxyRoutesMutex.RLock() 1073 defer n.proxyRoutesMutex.RUnlock() 1074 route, exist := n.proxyRoutes[name] 1075 return route, exist 1076 } 1077 1078 func (n *network) listen(ctx context.Context, hostname string, options Listener, register bool) (net.Listener, error) { 1079 1080 lc := net.ListenConfig{ 1081 KeepAlive: defaultKeepAlivePeriod * time.Second, 1082 } 1083 tlsEnabled := false 1084 if options.TLS != nil { 1085 if options.TLS.Certificates != nil || options.TLS.GetCertificate != nil { 1086 tlsEnabled = true 1087 } 1088 } 1089 1090 for port := options.ListenBegin; port <= options.ListenEnd; port++ { 1091 if options.Hostname != "" { 1092 hostname = options.Hostname 1093 } 1094 1095 hostPort := net.JoinHostPort(hostname, strconv.Itoa(int(port))) 1096 lib.Log("[%s] NETWORK trying to start listener on %q", n.nodename, hostPort) 1097 listener, err := lc.Listen(ctx, "tcp", hostPort) 1098 if err != nil { 1099 continue 1100 } 1101 1102 if register && n.registrar != nil { 1103 registerOptions := RegisterOptions{ 1104 Port: port, 1105 Creation: n.creation, 1106 NodeVersion: n.version, 1107 HandshakeVersion: options.Handshake.Version(), 1108 EnableTLS: tlsEnabled, 1109 EnableProxy: options.Flags.EnableProxy, 1110 EnableCompression: options.Flags.EnableCompression, 1111 } 1112 1113 if err := n.registrar.Register(n.ctx, n.nodename, registerOptions); err != nil { 1114 listener.Close() 1115 return nil, fmt.Errorf("can not register this node: %s", err) 1116 } 1117 } 1118 1119 if tlsEnabled { 1120 listener = tls.NewListener(listener, options.TLS) 1121 } 1122 1123 go func() { 1124 for { 1125 c, err := listener.Accept() 1126 if err != nil { 1127 if err == io.EOF { 1128 return 1129 } 1130 if ctx.Err() == nil { 1131 continue 1132 } 1133 lib.Log(err.Error()) 1134 return 1135 } 1136 lib.Log("[%s] NETWORK accepted new connection from %s", n.nodename, c.RemoteAddr().String()) 1137 1138 details, err := options.Handshake.Accept(c.RemoteAddr(), c, tlsEnabled, options.Cookie) 1139 if err != nil { 1140 if err != io.EOF { 1141 lib.Warning("[%s] Can't handshake with %s: %s", n.nodename, c.RemoteAddr().String(), err) 1142 } 1143 c.Close() 1144 continue 1145 } 1146 if details.Name == "" { 1147 err := fmt.Errorf("remote node introduced itself as %q", details.Name) 1148 lib.Warning("Handshake error: %s", err) 1149 c.Close() 1150 continue 1151 } 1152 connection, err := options.Proto.Init(n.ctx, c, n.nodename, details) 1153 if err != nil { 1154 lib.Warning("Proto error: %s", err) 1155 c.Close() 1156 continue 1157 } 1158 1159 cInternal := connectionInternal{ 1160 conn: c, 1161 connection: connection, 1162 } 1163 1164 if len(details.ProxyTransit.AllowTo) > 0 { 1165 cInternal.proxyTransitTo = make(map[string]bool) 1166 for _, to := range details.ProxyTransit.AllowTo { 1167 cInternal.proxyTransitTo[to] = true 1168 } 1169 } 1170 1171 if _, err := n.registerConnection(details.Name, cInternal); err != nil { 1172 // Race condition: 1173 // There must be another goroutine which already created and registered 1174 // connection to this node. 1175 // Close this connection and use the already registered connection 1176 c.Close() 1177 continue 1178 } 1179 1180 // run serving connection 1181 go func(ctx context.Context, ci connectionInternal) { 1182 options.Proto.Serve(ci.connection, n.router) 1183 n.unregisterConnection(details.Name, nil) 1184 options.Proto.Terminate(ci.connection) 1185 ci.conn.Close() 1186 }(ctx, cInternal) 1187 1188 } 1189 }() 1190 1191 return listener, nil 1192 } 1193 1194 // all ports within a given range are taken 1195 return nil, fmt.Errorf("can not start listener (port range is taken)") 1196 } 1197 1198 func (n *network) connect(node string) (ConnectionInterface, error) { 1199 var c net.Conn 1200 lib.Log("[%s] NETWORK trying to connect to %#v", n.nodename, node) 1201 1202 // resolve the route 1203 route, err := n.Resolve(node) 1204 if err != nil { 1205 return nil, err 1206 } 1207 customHandshake := route.Options.Handshake != nil 1208 lib.Log("[%s] NETWORK resolved %#v to %s:%d (custom handshake: %t)", n.nodename, node, route.Host, route.Port, customHandshake) 1209 1210 HostPort := net.JoinHostPort(route.Host, strconv.Itoa(int(route.Port))) 1211 dialer := net.Dialer{ 1212 KeepAlive: defaultKeepAlivePeriod * time.Second, 1213 Timeout: 3 * time.Second, // timeout to establish TCP-connection 1214 } 1215 1216 tlsEnabled := route.Options.TLS != nil 1217 1218 if route.Options.IsErgo == true { 1219 // use the route TLS settings if they were defined 1220 if tlsEnabled { 1221 if n.tls != nil { 1222 route.Options.TLS.InsecureSkipVerify = n.tls.InsecureSkipVerify 1223 } 1224 // use the local TLS settings 1225 tlsdialer := tls.Dialer{ 1226 NetDialer: &dialer, 1227 Config: route.Options.TLS, 1228 } 1229 c, err = tlsdialer.DialContext(n.ctx, "tcp", HostPort) 1230 } else { 1231 // TLS disabled on a remote node 1232 c, err = dialer.DialContext(n.ctx, "tcp", HostPort) 1233 } 1234 } else { 1235 // this is an Erlang/Elixir node. use the local TLS settings 1236 tlsEnabled = n.tls != nil 1237 if tlsEnabled { 1238 tlsdialer := tls.Dialer{ 1239 NetDialer: &dialer, 1240 Config: n.tls, 1241 } 1242 c, err = tlsdialer.DialContext(n.ctx, "tcp", HostPort) 1243 1244 } else { 1245 c, err = dialer.DialContext(n.ctx, "tcp", HostPort) 1246 } 1247 } 1248 1249 // check if we couldn't establish a connection with the node 1250 if err != nil { 1251 lib.Warning("Could not connect to %q (%s): %s", node, HostPort, err) 1252 return nil, err 1253 } 1254 1255 // handshake 1256 handshake := route.Options.Handshake 1257 if handshake == nil { 1258 // use default handshake 1259 handshake = n.handshake 1260 } 1261 1262 cookie := n.cookie 1263 if route.Options.Cookie != "" { 1264 cookie = route.Options.Cookie 1265 } 1266 1267 details, err := handshake.Start(c.RemoteAddr(), c, tlsEnabled, cookie) 1268 if err != nil { 1269 lib.Warning("Handshake error: %s", err) 1270 c.Close() 1271 return nil, err 1272 } 1273 if details.Name != node { 1274 err := fmt.Errorf("Handshake error: node %q introduced itself as %q", node, details.Name) 1275 lib.Warning("%s", err) 1276 return nil, err 1277 } 1278 1279 // proto 1280 proto := route.Options.Proto 1281 if proto == nil { 1282 // use default proto 1283 proto = n.proto 1284 } 1285 1286 connection, err := proto.Init(n.ctx, c, n.nodename, details) 1287 if err != nil { 1288 c.Close() 1289 lib.Warning("Proto error: %s", err) 1290 return nil, err 1291 } 1292 cInternal := connectionInternal{ 1293 conn: c, 1294 connection: connection, 1295 } 1296 1297 if registered, err := n.registerConnection(details.Name, cInternal); err != nil { 1298 // Race condition: 1299 // There must be another goroutine which already created and registered 1300 // connection to this node. 1301 // Close this connection and use the already registered one 1302 c.Close() 1303 if err == lib.ErrTaken { 1304 return registered, nil 1305 } 1306 return nil, err 1307 } 1308 1309 // enable keep alive on this connection 1310 if tcp, ok := c.(*net.TCPConn); ok { 1311 tcp.SetKeepAlive(true) 1312 tcp.SetKeepAlivePeriod(5 * time.Second) 1313 tcp.SetNoDelay(true) 1314 } 1315 1316 // run serving connection 1317 go func(ctx context.Context, ci connectionInternal) { 1318 proto.Serve(ci.connection, n.router) 1319 n.unregisterConnection(details.Name, nil) 1320 proto.Terminate(ci.connection) 1321 ci.conn.Close() 1322 }(n.ctx, cInternal) 1323 1324 return connection, nil 1325 } 1326 1327 func (n *network) registerConnection(peername string, ci connectionInternal) (ConnectionInterface, error) { 1328 lib.Log("[%s] NETWORK registering peer %#v", n.nodename, peername) 1329 n.connectionsMutex.Lock() 1330 defer n.connectionsMutex.Unlock() 1331 1332 if registered, exist := n.connections[peername]; exist { 1333 // already registered 1334 return registered.connection, lib.ErrTaken 1335 } 1336 n.connections[peername] = ci 1337 1338 event := MessageEventNetwork{ 1339 PeerName: peername, 1340 Online: true, 1341 } 1342 if ci.conn == nil { 1343 // this is proxy connection 1344 p, _ := n.connectionsProxy[ci.connection] 1345 p = append(p, peername) 1346 n.connectionsProxy[ci.connection] = p 1347 event.Proxy = true 1348 } 1349 n.router.sendEvent(corePID, EventNetwork, event) 1350 return ci.connection, nil 1351 } 1352 1353 func (n *network) unregisterConnection(peername string, disconnect *ProxyDisconnect) { 1354 lib.Log("[%s] NETWORK unregistering peer %v", n.nodename, peername) 1355 1356 n.connectionsMutex.Lock() 1357 ci, exist := n.connections[peername] 1358 if exist == false { 1359 n.connectionsMutex.Unlock() 1360 return 1361 } 1362 delete(n.connections, peername) 1363 n.connectionsMutex.Unlock() 1364 1365 n.router.RouteNodeDown(peername, disconnect) 1366 event := MessageEventNetwork{ 1367 PeerName: peername, 1368 Online: false, 1369 } 1370 1371 if ci.conn == nil { 1372 // it was proxy connection 1373 ci.connection.ProxyUnregisterSession(ci.proxySessionID) 1374 event.Proxy = true 1375 n.router.sendEvent(corePID, EventNetwork, event) 1376 return 1377 } 1378 n.router.sendEvent(corePID, EventNetwork, event) 1379 1380 n.connectionsMutex.Lock() 1381 cp, _ := n.connectionsProxy[ci.connection] 1382 for _, p := range cp { 1383 lib.Log("[%s] NETWORK unregistering peer (via proxy) %v", n.nodename, p) 1384 delete(n.connections, p) 1385 event.PeerName = p 1386 event.Proxy = true 1387 n.router.sendEvent(corePID, EventNetwork, event) 1388 } 1389 1390 ct, _ := n.connectionsTransit[ci.connection] 1391 delete(n.connectionsTransit, ci.connection) 1392 n.connectionsMutex.Unlock() 1393 1394 // send disconnect for the proxy sessions 1395 for _, p := range cp { 1396 disconnect := ProxyDisconnect{ 1397 Node: peername, 1398 Proxy: n.nodename, 1399 Reason: "noconnection", 1400 } 1401 n.router.RouteNodeDown(p, &disconnect) 1402 } 1403 1404 // disconnect for the transit proxy sessions 1405 for i := range ct { 1406 disconnect := ProxyDisconnect{ 1407 Node: peername, 1408 Proxy: n.nodename, 1409 SessionID: ct[i], 1410 Reason: "noconnection", 1411 } 1412 n.RouteProxyDisconnect(ci.connection, disconnect) 1413 } 1414 1415 } 1416 1417 // Connection interface default callbacks 1418 func (c *Connection) Send(from gen.Process, to etf.Pid, message etf.Term) error { 1419 return lib.ErrUnsupported 1420 } 1421 func (c *Connection) SendReg(from gen.Process, to gen.ProcessID, message etf.Term) error { 1422 return lib.ErrUnsupported 1423 } 1424 func (c *Connection) SendAlias(from gen.Process, to etf.Alias, message etf.Term) error { 1425 return lib.ErrUnsupported 1426 } 1427 func (c *Connection) Link(local gen.Process, remote etf.Pid) error { 1428 return lib.ErrUnsupported 1429 } 1430 func (c *Connection) Unlink(local gen.Process, remote etf.Pid) error { 1431 return lib.ErrUnsupported 1432 } 1433 func (c *Connection) LinkExit(local etf.Pid, remote etf.Pid, reason string) error { 1434 return lib.ErrUnsupported 1435 } 1436 func (c *Connection) Monitor(local gen.Process, remote etf.Pid, ref etf.Ref) error { 1437 return lib.ErrUnsupported 1438 } 1439 func (c *Connection) MonitorReg(local gen.Process, remote gen.ProcessID, ref etf.Ref) error { 1440 return lib.ErrUnsupported 1441 } 1442 func (c *Connection) Demonitor(by etf.Pid, process etf.Pid, ref etf.Ref) error { 1443 return lib.ErrUnsupported 1444 } 1445 func (c *Connection) DemonitorReg(by etf.Pid, process gen.ProcessID, ref etf.Ref) error { 1446 return lib.ErrUnsupported 1447 } 1448 func (c *Connection) MonitorExitReg(process gen.Process, reason string, ref etf.Ref) error { 1449 return lib.ErrUnsupported 1450 } 1451 func (c *Connection) MonitorExit(to etf.Pid, terminated etf.Pid, reason string, ref etf.Ref) error { 1452 return lib.ErrUnsupported 1453 } 1454 func (c *Connection) SpawnRequest(nodeName string, behaviorName string, request gen.RemoteSpawnRequest, args ...etf.Term) error { 1455 return lib.ErrUnsupported 1456 } 1457 func (c *Connection) SpawnReply(to etf.Pid, ref etf.Ref, pid etf.Pid) error { 1458 return lib.ErrUnsupported 1459 } 1460 func (c *Connection) SpawnReplyError(to etf.Pid, ref etf.Ref, err error) error { 1461 return lib.ErrUnsupported 1462 } 1463 func (c *Connection) ProxyConnectRequest(connect ProxyConnectRequest) error { 1464 return lib.ErrUnsupported 1465 } 1466 func (c *Connection) ProxyConnectReply(reply ProxyConnectReply) error { 1467 return lib.ErrUnsupported 1468 } 1469 func (c *Connection) ProxyDisconnect(disconnect ProxyDisconnect) error { 1470 return lib.ErrUnsupported 1471 } 1472 func (c *Connection) ProxyRegisterSession(session ProxySession) error { 1473 return lib.ErrUnsupported 1474 } 1475 func (c *Connection) ProxyUnregisterSession(id string) error { 1476 return lib.ErrUnsupported 1477 } 1478 func (c *Connection) ProxyPacket(packet *lib.Buffer) error { 1479 return lib.ErrUnsupported 1480 } 1481 func (c *Connection) Stats() NetworkStats { 1482 return NetworkStats{} 1483 } 1484 1485 // Handshake interface default callbacks 1486 func (h *Handshake) Start(remote net.Addr, conn lib.NetReadWriter, tls bool, cookie string) (HandshakeDetails, error) { 1487 return HandshakeDetails{}, lib.ErrUnsupported 1488 } 1489 func (h *Handshake) Accept(remote net.Addr, conn lib.NetReadWriter, tls bool, cookie string) (HandshakeDetails, error) { 1490 return HandshakeDetails{}, lib.ErrUnsupported 1491 } 1492 func (h *Handshake) Version() HandshakeVersion { 1493 var v HandshakeVersion 1494 return v 1495 } 1496 1497 // internals 1498 1499 func (n *network) putProxyConnectRequest(r proxyConnectRequest) { 1500 n.proxyConnectRequestMutex.Lock() 1501 defer n.proxyConnectRequestMutex.Unlock() 1502 n.proxyConnectRequest[r.request.ID] = r 1503 } 1504 1505 func (n *network) cancelProxyConnectRequest(cancel ProxyConnectCancel) { 1506 n.proxyConnectRequestMutex.Lock() 1507 defer n.proxyConnectRequestMutex.Unlock() 1508 1509 r, found := n.proxyConnectRequest[cancel.ID] 1510 if found == false { 1511 return 1512 } 1513 1514 delete(n.proxyConnectRequest, cancel.ID) 1515 select { 1516 case r.cancel <- cancel: 1517 default: 1518 } 1519 return 1520 } 1521 1522 func (n *network) waitProxyConnection(id etf.Ref, timeout int) (ConnectionInterface, error) { 1523 n.proxyConnectRequestMutex.RLock() 1524 r, found := n.proxyConnectRequest[id] 1525 n.proxyConnectRequestMutex.RUnlock() 1526 1527 if found == false { 1528 return nil, lib.ErrProxyUnknownRequest 1529 } 1530 1531 defer func(id etf.Ref) { 1532 n.proxyConnectRequestMutex.Lock() 1533 delete(n.proxyConnectRequest, id) 1534 n.proxyConnectRequestMutex.Unlock() 1535 }(id) 1536 1537 timer := lib.TakeTimer() 1538 defer lib.ReleaseTimer(timer) 1539 timer.Reset(time.Second * time.Duration(timeout)) 1540 1541 for { 1542 select { 1543 case connection := <-r.connection: 1544 return connection, nil 1545 case err := <-r.cancel: 1546 return nil, fmt.Errorf("[%s] %s", err.From, err.Reason) 1547 case <-timer.C: 1548 return nil, lib.ErrTimeout 1549 case <-n.ctx.Done(): 1550 // node is on the way to terminate, it means connection is closed 1551 // so it doesn't matter what kind of error will be returned 1552 return nil, lib.ErrProxyUnknownRequest 1553 } 1554 } 1555 } 1556 1557 func (n *network) getProxyConnectRequest(id etf.Ref) (proxyConnectRequest, bool) { 1558 n.proxyConnectRequestMutex.RLock() 1559 defer n.proxyConnectRequestMutex.RUnlock() 1560 r, found := n.proxyConnectRequest[id] 1561 return r, found 1562 } 1563 1564 func (n *network) networkStats() internalNetworkStats { 1565 stats := internalNetworkStats{} 1566 n.proxyTransitSessionsMutex.RLock() 1567 stats.transitConnections = len(n.proxyTransitSessions) 1568 n.proxyTransitSessionsMutex.RUnlock() 1569 1570 n.connectionsMutex.RLock() 1571 stats.proxyConnections = len(n.connectionsProxy) 1572 stats.connections = len(n.connections) 1573 n.connectionsMutex.RUnlock() 1574 return stats 1575 } 1576 1577 // 1578 // internals 1579 // 1580 1581 func generateProxyDigest(creation uint32, cookie string, pubkey []byte) []byte { 1582 // md5(md5(md5(md5(node)+cookie)+peer)+pubkey) 1583 c := [4]byte{} 1584 binary.BigEndian.PutUint32(c[:], creation) 1585 digest1 := md5.Sum([]byte(c[:])) 1586 digest2 := md5.Sum(append(digest1[:], []byte(cookie)...)) 1587 digest3 := md5.Sum(append(digest2[:], pubkey...)) 1588 return digest3[:] 1589 }