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  }