github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/lnp2p/peermgr.go (about)

     1  package lnp2p
     2  
     3  //"crypto/ecdsa" // TODO Use ecdsa not koblitz
     4  import (
     5  	"crypto/ecdsa"
     6  	"fmt"
     7  	"net"
     8  	"sync"
     9  	"time"
    10  
    11  	"github.com/mit-dci/lit/btcutil/hdkeychain"
    12  	"github.com/mit-dci/lit/crypto/koblitz"
    13  	"github.com/mit-dci/lit/eventbus"
    14  	"github.com/mit-dci/lit/lncore"
    15  	"github.com/mit-dci/lit/lndc"
    16  	"github.com/mit-dci/lit/lnutil"
    17  	"github.com/mit-dci/lit/logging"
    18  	"github.com/mit-dci/lit/nat"
    19  	"github.com/mit-dci/lit/portxo"
    20  )
    21  
    22  type privkey *koblitz.PrivateKey
    23  type pubkey *koblitz.PublicKey
    24  
    25  // MaxNodeCount is the size of the peerIdx->LnAddr array.
    26  // TEMP This shouldn't be necessary.
    27  const MaxNodeCount = 1024
    28  
    29  // PeerManager .
    30  type PeerManager struct {
    31  
    32  	// Biographical.
    33  	idkey       privkey
    34  	peerdb      lncore.LitPeerStorage
    35  	ebus        *eventbus.EventBus
    36  	mproc       MessageProcessor
    37  	netsettings *NetSettings
    38  
    39  	// Peer tracking.
    40  	peers   []lncore.LnAddr // compatibility
    41  	peerMap map[lncore.LnAddr]*Peer
    42  
    43  	// Accepting connections.
    44  	listeningPorts map[int]*listeningthread
    45  
    46  	// Outgoing messages.
    47  	sending  bool
    48  	outqueue chan outgoingmsg
    49  
    50  	// Tracker
    51  	trackerURL string
    52  
    53  	// Sync.
    54  	mtx *sync.Mutex
    55  }
    56  
    57  const outgoingbuf = 16
    58  
    59  // NetSettings is a container struct for misc network settings like NAT
    60  // holepunching and proxies.
    61  type NetSettings struct {
    62  	NatMode *string `json:"natmode"`
    63  
    64  	ProxyAddr *string `json:"proxyserv"`
    65  	ProxyAuth *string `json:"proxyauth"`
    66  }
    67  
    68  // NewPeerManager creates a peer manager from a root key
    69  func NewPeerManager(rootkey *hdkeychain.ExtendedKey, pdb lncore.LitPeerStorage, trackerURL string, bus *eventbus.EventBus, ns *NetSettings) (*PeerManager, error) {
    70  	k, err := computeIdentKeyFromRoot(rootkey)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  
    75  	pm := &PeerManager{
    76  		idkey:          k,
    77  		peerdb:         pdb,
    78  		ebus:           bus,
    79  		mproc:          NewMessageProcessor(),
    80  		netsettings:    ns,
    81  		peers:          make([]lncore.LnAddr, MaxNodeCount),
    82  		peerMap:        map[lncore.LnAddr]*Peer{},
    83  		listeningPorts: map[int]*listeningthread{},
    84  		sending:        false,
    85  		trackerURL:     trackerURL,
    86  		outqueue:       make(chan outgoingmsg, outgoingbuf),
    87  		mtx:            &sync.Mutex{},
    88  	}
    89  
    90  	return pm, nil
    91  }
    92  
    93  // GetMessageProcessor gets the message processor for this peer manager that's passed incoming messasges from peers.
    94  func (pm *PeerManager) GetMessageProcessor() *MessageProcessor {
    95  	return &pm.mproc
    96  }
    97  
    98  // GetExternalAddress returns the human-readable LN address
    99  func (pm *PeerManager) GetExternalAddress() string {
   100  	idk := pm.idkey // lol
   101  	c := koblitz.PublicKey(ecdsa.PublicKey(idk.PublicKey))
   102  	addr := convertPubkeyToLitAddr(pubkey(&c))
   103  	return string(addr)
   104  }
   105  
   106  func computeIdentKeyFromRoot(rootkey *hdkeychain.ExtendedKey) (privkey, error) {
   107  	var kg portxo.KeyGen
   108  	kg.Depth = 5
   109  	kg.Step[0] = 44 | 1<<31  // from bip44, but not actually sensical in this context
   110  	kg.Step[1] = 513 | 1<<31 // magic
   111  	kg.Step[2] = 9 | 1<<31   // magic
   112  	kg.Step[3] = 0 | 1<<31
   113  	kg.Step[4] = 0 | 1<<31
   114  	k, err := kg.DerivePrivateKey(rootkey)
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  	return privkey(k), nil
   119  }
   120  
   121  // GetPeerIdx is a convenience function for working with older code.
   122  func (pm *PeerManager) GetPeerIdx(peer *Peer) uint32 {
   123  	if peer.idx == nil {
   124  		return 0
   125  	}
   126  	return *peer.idx
   127  }
   128  
   129  // GetPeer returns the peer with the given lnaddr.
   130  func (pm *PeerManager) GetPeer(lnaddr lncore.LnAddr) *Peer {
   131  	p, ok := pm.peerMap[lnaddr]
   132  	if !ok {
   133  		return nil
   134  	}
   135  	return p
   136  }
   137  
   138  // GetPeerByIdx is a compatibility function for getting a peer by its "peer id".
   139  func (pm *PeerManager) GetPeerByIdx(id int32) *Peer {
   140  	if id < 0 || id >= int32(len(pm.peers)) {
   141  		return nil
   142  	}
   143  	return pm.peerMap[pm.peers[id]]
   144  }
   145  
   146  // TryConnectAddress attempts to connect to the specified LN address.
   147  func (pm *PeerManager) TryConnectAddress(addr string) (*Peer, error) {
   148  
   149  	// Figure out who we're trying to connect to.
   150  	who, where := splitAdrString(addr)
   151  	if where == "" {
   152  		ipv4, _, err := lnutil.Lookup(addr, pm.trackerURL, "")
   153  		if err != nil {
   154  			return nil, err
   155  		}
   156  		where = fmt.Sprintf("%s:2448", ipv4)
   157  	}
   158  
   159  	lnwho, err := lncore.ParseLnAddr(who)
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  
   164  	x, y := pm.tryConnectPeer(where, &lnwho)
   165  	return x, y
   166  
   167  }
   168  
   169  func (pm *PeerManager) tryConnectPeer(netaddr string, lnaddr *lncore.LnAddr) (*Peer, error) {
   170  
   171  	// lnaddr check, to make sure that we do the right thing.
   172  	if lnaddr == nil {
   173  		return nil, fmt.Errorf("connection to a peer with unknown lnaddr not supported yet")
   174  	}
   175  
   176  	dialer := net.Dial
   177  
   178  	// Use a proxy server if applicable.
   179  	ns := pm.netsettings
   180  	if ns != nil && ns.ProxyAddr != nil {
   181  		d, err := connectToProxyTCP(*ns.ProxyAddr, ns.ProxyAuth)
   182  		if err != nil {
   183  			return nil, err
   184  		}
   185  		dialer = d
   186  	}
   187  
   188  	// Create the connection.
   189  	lndcconn, err := lndc.Dial(pm.idkey, netaddr, string(*lnaddr), dialer)
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  
   194  	// Try to set up the new connection.
   195  	p, err := pm.handleNewConnection(lndcconn, *lnaddr)
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  
   200  	// Now start listening for inbound traffic.
   201  	// (it *also* took me a while to realize I forgot *this*)
   202  	go processConnectionInboundTraffic(p, pm)
   203  
   204  	// Return
   205  	return p, nil
   206  
   207  }
   208  
   209  func (pm *PeerManager) handleNewConnection(conn *lndc.Conn, expectedAddr lncore.LnAddr) (*Peer, error) {
   210  
   211  	// Now that we've got the connection, actually create the peer object.
   212  	pk := pubkey(conn.RemotePub())
   213  	rlitaddr := convertPubkeyToLitAddr(pk)
   214  
   215  	if rlitaddr != expectedAddr {
   216  		conn.Close()
   217  		return nil, fmt.Errorf("peermgr: Connection init error, expected addr %s got addr %s", expectedAddr, rlitaddr)
   218  	}
   219  
   220  	p := &Peer{
   221  		lnaddr:   rlitaddr,
   222  		nickname: nil,
   223  		conn:     conn,
   224  		idpubkey: pk,
   225  
   226  		// TEMP
   227  		idx: nil,
   228  	}
   229  
   230  	pi, err := pm.peerdb.GetPeerInfo(expectedAddr)
   231  	if err != nil {
   232  		logging.Errorf("peermgr: Problem loading peer info from DB: %s\n", err.Error())
   233  		// don't kill the connection?
   234  	}
   235  
   236  	if pi == nil {
   237  		pidx, err := pm.peerdb.GetUniquePeerIdx()
   238  		if err != nil {
   239  			logging.Errorf("Problem getting unique peeridx from DB: %s\n", err.Error())
   240  		} else {
   241  			p.idx = &pidx
   242  		}
   243  		raddr := conn.RemoteAddr().String()
   244  		pi = &lncore.PeerInfo{
   245  			LnAddr:   &rlitaddr,
   246  			Nickname: nil,
   247  			NetAddr:  &raddr,
   248  			PeerIdx:  pidx,
   249  		}
   250  		err = pm.peerdb.AddPeer(p.GetLnAddr(), *pi)
   251  		if err != nil {
   252  			logging.Errorf("Error saving new peer to DB: %s\n", err.Error())
   253  		}
   254  	} else {
   255  		p.nickname = pi.Nickname
   256  		// TEMP
   257  		p.idx = &pi.PeerIdx
   258  	}
   259  
   260  	// Register the peer we just connected to!
   261  	// (it took me a while to realize I forgot this)
   262  	pm.registerPeer(p)
   263  
   264  	// Now actually return the peer.
   265  	return p, nil
   266  
   267  }
   268  
   269  func (pm *PeerManager) registerPeer(peer *Peer) {
   270  
   271  	lnaddr := peer.lnaddr
   272  
   273  	// We're making changes to the manager so keep stuff away while we set up.
   274  	pm.mtx.Lock()
   275  	defer pm.mtx.Unlock()
   276  
   277  	logging.Infof("peermgr: New peer %s\n", peer.GetLnAddr())
   278  
   279  	// Append peer to peer list and add to peermap
   280  	pm.peers[int(*peer.idx)] = lnaddr // TEMP This idx logic is a litte weird.
   281  	pm.peerMap[lnaddr] = peer
   282  	peer.pmgr = pm
   283  
   284  	// Announce the peer has been added.
   285  	e := NewPeerEvent{
   286  		Addr:            lnaddr,
   287  		Peer:            peer,
   288  		RemoteInitiated: false,
   289  
   290  		// TODO Remove these.
   291  		RemotePub: peer.idpubkey,
   292  		Conn:      peer.conn,
   293  	}
   294  	pm.ebus.Publish(e)
   295  
   296  }
   297  
   298  func (pm *PeerManager) unregisterPeer(peer *Peer) {
   299  
   300  	// Again, sensitive changes we should get a lock to do first.
   301  	pm.mtx.Lock()
   302  	defer pm.mtx.Unlock()
   303  
   304  	logging.Infof("peermgr: Unregistering peer: %s\n", peer.GetLnAddr())
   305  
   306  	// Remove the peer idx entry.
   307  	idx := pm.GetPeerIdx(peer)
   308  	pm.peers[idx] = ""
   309  
   310  	// Remove the actual peer entry.
   311  	pm.peerMap[peer.GetLnAddr()] = nil
   312  
   313  	// More cleanup.
   314  	peer.conn = nil
   315  	peer.idx = nil
   316  	peer.pmgr = nil
   317  
   318  }
   319  
   320  // DisconnectPeer disconnects a peer from ourselves and does relevant cleanup.
   321  func (pm *PeerManager) DisconnectPeer(peer *Peer) error {
   322  
   323  	err := peer.conn.Close()
   324  	if err != nil {
   325  		return err
   326  	}
   327  
   328  	// This will cause the peer disconnect event to be raised when the reader
   329  	// goroutine started to exit and run the unregistration
   330  
   331  	return nil
   332  
   333  }
   334  
   335  // ListenOnPort attempts to start a goroutine lisening on the port.
   336  func (pm *PeerManager) ListenOnPort(port int) error {
   337  
   338  	// Do NAT setup stuff.
   339  	ns := pm.netsettings
   340  	if ns != nil && ns.NatMode != nil {
   341  
   342  		// Do some type juggling.
   343  		lisPort := uint16(port)
   344  
   345  		// Actually figure out what we're going to do.
   346  		if *ns.NatMode == "upnp" {
   347  			// Universal Plug-n-Play
   348  			logging.Infof("Attempting port forwarding via UPnP...")
   349  			err := nat.SetupUpnp(lisPort)
   350  			if err != nil {
   351  				return err
   352  			}
   353  		} else if *ns.NatMode == "pmp" {
   354  			// NAT Port Mapping Protocol
   355  			timeout := time.Duration(10 * time.Second)
   356  			logging.Infof("Attempting port forwarding via PMP...")
   357  			_, err := nat.SetupPmp(timeout, lisPort)
   358  			if err != nil {
   359  				return err
   360  			}
   361  		} else {
   362  			return fmt.Errorf("invalid NAT type: %s", *ns.NatMode)
   363  		}
   364  	}
   365  
   366  	threadobj := &listeningthread{
   367  		listener: nil,
   368  	}
   369  
   370  	// Publish the new thread
   371  	res, err := pm.ebus.Publish(NewListeningPortEvent{port})
   372  	if err != nil {
   373  		return err
   374  	}
   375  
   376  	if !res {
   377  		return fmt.Errorf("listen cancelled by event handler")
   378  	}
   379  
   380  	// Try to start listening.
   381  	// TODO Listen on proxy if possible?
   382  	logging.Info("PORT: ", port)
   383  	listener, err := lndc.NewListener(pm.idkey, port)
   384  	if err != nil {
   385  		logging.Errorf("listening failed: %s\n", err.Error())
   386  		logging.Info(err)
   387  		pm.ebus.Publish(StopListeningPortEvent{
   388  			Port:   port,
   389  			Reason: "initfail",
   390  		})
   391  		return err
   392  	}
   393  
   394  	threadobj.listener = listener
   395  
   396  	// Install the thread object.
   397  	pm.mtx.Lock()
   398  	pm.listeningPorts[port] = threadobj
   399  	pm.mtx.Unlock()
   400  
   401  	// Activate the MessageProcessor if we haven't yet.
   402  	if !pm.mproc.IsActive() {
   403  		pm.mproc.Activate()
   404  	}
   405  
   406  	// Actually start it
   407  	go acceptConnections(listener, port, pm)
   408  
   409  	return nil
   410  
   411  }
   412  
   413  // GetListeningAddrs returns the listening addresses.
   414  func (pm *PeerManager) GetListeningAddrs() []string {
   415  	pm.mtx.Lock()
   416  	defer pm.mtx.Unlock()
   417  	ports := make([]string, 0)
   418  	for _, t := range pm.listeningPorts {
   419  		ports = append(ports, t.listener.Addr().String())
   420  	}
   421  	return ports
   422  }
   423  
   424  // StopListening closes the socket listened on the given address, stopping the goroutine.
   425  func (pm *PeerManager) StopListening(port int) error {
   426  
   427  	pm.mtx.Lock()
   428  	defer pm.mtx.Unlock()
   429  
   430  	// This will interrupt the .Accept() call in the other goroutine, and handle cleanup for us.
   431  	lt, ok := pm.listeningPorts[port]
   432  	if !ok {
   433  		return fmt.Errorf("not listening")
   434  	}
   435  
   436  	lt.listener.Close()
   437  	return nil
   438  
   439  }
   440  
   441  // StartSending starts a goroutine to start sending queued messages out to peers.
   442  func (pm *PeerManager) StartSending() error {
   443  	if pm.sending {
   444  		return fmt.Errorf("already sending")
   445  	}
   446  	pm.sending = true
   447  	go sendMessages(pm.outqueue)
   448  	return nil
   449  }
   450  
   451  // StopSending has us stop sending new messages to peers.
   452  func (pm *PeerManager) StopSending() error {
   453  	if !pm.sending {
   454  		return fmt.Errorf("not sending")
   455  	}
   456  	fc := make(chan error)
   457  	pm.outqueue <- outgoingmsg{nil, nil, &fc} // sends a message to stop the goroutine
   458  
   459  	<-fc // wait for the queue to flush
   460  	pm.sending = false
   461  
   462  	return nil
   463  }
   464  
   465  func (pm *PeerManager) queueMessageToPeer(peer *Peer, msg Message, ec *chan error) error {
   466  	if !pm.sending {
   467  		return fmt.Errorf("sending is disabled on this peer manager, need to start it?")
   468  	}
   469  	pm.outqueue <- outgoingmsg{peer, &msg, ec}
   470  	return nil
   471  }
   472  
   473  // TmpHintPeerIdx sets the peer idx hint for a particular peer.
   474  // TEMP This should be removed at some point in the future.
   475  func (pm *PeerManager) TmpHintPeerIdx(peer *Peer, idx uint32) error {
   476  
   477  	pi, err := pm.peerdb.GetPeerInfo(peer.GetLnAddr())
   478  	if err != nil {
   479  		return err
   480  	}
   481  
   482  	pi.PeerIdx = idx
   483  
   484  	return pm.peerdb.UpdatePeer(peer.GetLnAddr(), pi)
   485  
   486  }