diff --git a/channeldb/channel.go b/channeldb/channel.go index 2e053680..9aa2bebc 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -21,6 +21,8 @@ var ( closedChannelBucket = []byte("c") activeChanKey = []byte("a") + identityKey = []byte("idkey") + // TODO(roasbeef): replace w/ tesnet-L also revisit dependancy... ActiveNetParams = &chaincfg.TestNet3Params ) @@ -95,6 +97,35 @@ type OpenChannel struct { CreationTime time.Time } +// These don't really belong here but not sure which other file to put them yet. +// PutIdKey saves the private key used for +func (c *DB) PutIdKey(priv *btcec.PrivateKey) error { + return c.namespace.Update(func(tx walletdb.Tx) error { + // Get the bucket dedicated to storing the meta-data for open + // channels. + rootBucket := tx.RootBucket() + return rootBucket.Put(identityKey, priv.Serialize()) + }) +} + +// GetIdKey returns the IdKey +func (c *DB) GetIdKey() (*btcec.PrivateKey, error) { + var privbytes []byte + err := c.namespace.View(func(tx walletdb.Tx) error { + // Get the bucket dedicated to storing the meta-data for open + // channels. + rootBucket := tx.RootBucket() + privbytes = rootBucket.Get(identityKey) + return nil + }) + if err != nil { + return nil, err + } + + priv, _ := btcec.PrivKeyFromBytes(btcec.S256(), privbytes) + return priv, nil +} + // PutOpenChannel... func (c *DB) PutOpenChannel(channel *OpenChannel) error { return c.namespace.Update(func(tx walletdb.Tx) error { diff --git a/cmd/lnshell/commands.go b/cmd/lnshell/commands.go index 2f9e4298..cec85ea5 100644 --- a/cmd/lnshell/commands.go +++ b/cmd/lnshell/commands.go @@ -57,7 +57,14 @@ func LnConnect(args []string) error { // LnListen listens on the default port for incoming connections func LnListen(args []string) error { - fmt.Printf("will start TCP port listener\n") + req := new(lnrpc.TCPListenRequest) + req.Hostport = "0.0.0.0:2448" + _, err := z.TCPListen(stub, req) + if err != nil { + return err + } + + fmt.Printf("started TCP port listener\n") return nil } diff --git a/lndc/netio.go b/lndc/netio.go new file mode 100644 index 00000000..bb8649fd --- /dev/null +++ b/lndc/netio.go @@ -0,0 +1,633 @@ +package lndc + +import ( + "bytes" + "crypto/cipher" + "encoding/binary" + "fmt" + "io" + "net" + "time" + + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/fastsha256" + "github.com/codahale/chacha20poly1305" + "golang.org/x/crypto/ripemd160" + "li.lan/labs/strux/lnwire" +) + +/* good ol' OP_HASH160, which is just ripemd160(sha256(input)) */ +func H160(input []byte) []byte { + rp := ripemd160.New() + shaout := fastsha256.Sum256(input) + _, _ = rp.Write(shaout[:]) + return rp.Sum(nil) +} + +// Lightning Network Data Conection. Encrypted. +type LNDConn struct { + Version uint8 + Cn net.Conn + RemotePub *btcec.PublicKey + RemoteLNId [16]byte + MyNonceInt uint64 + RemoteNonceInt uint64 + // if Authed == false, the RemotePub is the EPHEMERAL key. + // once authed == true, RemotePub is who you're actually talking to. + Authed bool + // chachaStream saves some time as you don't have to init it with + // the session key every time. Make SessionKey redundant; remove later + chachaStream cipher.AEAD + + // ViaPbx specifies whether this is a direct TCP connection or an + // encapsulated PBX connection. + // if going ViaPbx, Cn isn't used + // channels are used for Read() and Write(), + // which are filled by the PBXhandler. + ViaPbx bool + PbxIncoming chan []byte + PbxOutgoing chan []byte +} + +/* new & improved tcp open session. +There's connector A and listener B. Once the connection is set up there's no +difference, but there can be during the setup. +Setup: +1 -> A sends B ephemeral secp256k1 pubkey (33 bytes) +2 <- B sends A ephemeral secp256k1 pubkey (33 bytes) +A and B do DH, get a shared secret. +========== +Seesion is open! Done! Well not quite. Session is confidential but not +yet authenticated. From here on, can use the Send() and Recv() functions with +chacha20poly1305. +========== +The DH proof is h160(remote eph pubkey, IDDH secret) +A initiates auth. + +If A does not know B's pubkey but only B's pubkey hash: + +1 -> A sends [PubKeyA, PubKeyHashB] (53 bytes) +B computes ID pubkey DH +2 <- B sends [PubkeyB, DH proof] (53 bytes) +3 -> A sends DH proof (20 bytes) +done. + +This exchange can be sped up if A already knows B's pubkey: + +A already knows who they're talking to, or trying to talk to +1 -> A sends [PubKeyA, PubkeyHashB, DH proof] (73 bytes) +2 <- B sends DH proof (20 bytes) + +A and B both verify those H160 hashes, and if matching consider their +session counterparty authenticated. + +A possible weakness of the DH proof is if B re-uses eph keys. That potentially +makes *A*'s proof weaker though. A gets to choose the proof B creates. As +long as your software makes new eph keys each time, you should be +*/ + +// Open creates and auths an lndc connections, +// after the TCP or pbx connection is already assigned / dialed. +func (lndc *LNDConn) Open( + me *btcec.PrivateKey, remote []byte) error { + // make TCP connection to listening host + var err error + + if len(remote) != 33 && len(remote) != 20 { + return fmt.Errorf("must supply either remote pubkey or pubkey hash") + } + // calc remote LNId; need this for creating pbx connections + // just because LNid is in the struct does not mean it's authed! + if len(remote) == 20 { + copy(lndc.RemoteLNId[:], remote[:16]) + } else { + theirAdr := H160(remote) + copy(lndc.RemoteLNId[:], theirAdr[:16]) + } + + // make up an ephtemeral keypair. Doesn't exit this function. + myEph, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + return nil + } + + // Sned 1. Send my ephemeral pubkey. Can add version bits. + err = lndc.writeClear(myEph.PubKey().SerializeCompressed()) + if err != nil { + return err + } + + // read their ephemeral pubkey + TheirEphPubBytes, err := lndc.readClear() + if err != nil { + return err + } + + // deserialize their ephemeral pubkey + TheirEphPub, err := btcec.ParsePubKey(TheirEphPubBytes, btcec.S256()) + if err != nil { + return err + } + // do non-interactive diffie with ephemeral pubkeys + // sha256 for good luck + sessionKey := + fastsha256.Sum256(btcec.GenerateSharedSecret(myEph, TheirEphPub)) + + lndc.chachaStream, err = chacha20poly1305.New(sessionKey[:]) + if err != nil { + return err + } + // display private key for debug only + fmt.Printf("made session key %x\n", sessionKey) + + lndc.MyNonceInt = 1 << 63 + lndc.RemoteNonceInt = 0 + + lndc.RemotePub = TheirEphPub + lndc.Authed = false + + // session is now open and confidential but not yet authenticated. + // So auth! + if len(remote) == 20 { // only know pubkey hash (20 bytes) + return lndc.AuthPKH(me, remote, myEph.PubKey().SerializeCompressed()) + } else { // must be 33 byte pubkey + return lndc.AuthPubKey(me, remote, myEph.PubKey().SerializeCompressed()) + } +} + +// TcpListen takes a lndc that's just connected, and sets it up. +// Call this just after a connection comes in. +// calls AuthListen, waiting for the auth step before returning. +// in the case of a pbx connection, there is no lndc.Cn +func (lndc *LNDConn) Setup(me *btcec.PrivateKey) error { + var err error + var TheirEphPubBytes []byte + + TheirEphPubBytes, err = lndc.readClear() + if err != nil { + return err + } + + if len(TheirEphPubBytes) != 33 { + return fmt.Errorf("Got invalid %d byte eph pubkey %x\n", + len(TheirEphPubBytes), TheirEphPubBytes) + } + // deserialize their ephemeral pubkey + TheirEphPub, err := btcec.ParsePubKey(TheirEphPubBytes, btcec.S256()) + if err != nil { + return err + } + + // their key looks OK, make our own + myEph, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + return nil + } + + // and send out our eph key + err = lndc.writeClear(myEph.PubKey().SerializeCompressed()) + if err != nil { + return err + } + + // do non-interactive diffie with ephemeral pubkeys + // sha256 for good luck + sessionKey := + fastsha256.Sum256(btcec.GenerateSharedSecret(myEph, TheirEphPub)) + + lndc.chachaStream, err = chacha20poly1305.New(sessionKey[:]) + + // display private key for debug only + fmt.Printf("made session key %x\n", sessionKey) + + lndc.RemoteNonceInt = 1 << 63 + lndc.MyNonceInt = 0 + + lndc.RemotePub = TheirEphPub + lndc.Authed = false + + // session is open and confidential but not yet authenticated. + // Listen for auth message + return lndc.AuthListen(me, myEph.PubKey().SerializeCompressed()) +} + +func (lndc *LNDConn) AuthListen( + myId *btcec.PrivateKey, localEphPubBytes []byte) error { + + var err error + slice := make([]byte, 65535) + n, err := lndc.Read(slice) + if err != nil { + return err + } + fmt.Printf("read %d bytes\n", n) + slice = slice[:n] + if err != nil { + fmt.Printf("Read error: %s\n", err.Error()) + err2 := lndc.Close() + if err2 != nil { + return err2 + } + return err + } + + authmsg := slice + if len(authmsg) != 53 && len(authmsg) != 73 { + err = lndc.Close() + if err != nil { + return err + } + return fmt.Errorf( + "Got auth message of %d bytes, expect 53 or 73", len(authmsg)) + } + theirPub, err := btcec.ParsePubKey(authmsg[:33], btcec.S256()) + if err != nil { + return err + } + myPKH := H160(myId.PubKey().SerializeCompressed()) + if bytes.Equal(myPKH, authmsg[33:53]) == false { + err = lndc.Close() + if err != nil { + return err + } + return fmt.Errorf( + "remote host asking for PKH %x, that's not me", authmsg[33:53]) + } + + // do DH with id keys + idDH := fastsha256.Sum256(btcec.GenerateSharedSecret(myId, theirPub)) + myDHproof := H160(append(lndc.RemotePub.SerializeCompressed(), idDH[:]...)) + theirDHproof := H160(append(localEphPubBytes, idDH[:]...)) + if len(authmsg) == 73 { // quick mode + // verify their DH proof + if bytes.Equal(authmsg[53:], theirDHproof) == false { + err = lndc.Close() + if err != nil { + return err + } + return fmt.Errorf( + "Invalid DH proof from %s", lndc.Cn.RemoteAddr().String()) + } + // looks good, send my own + _, err = lndc.Write(myDHproof) + if err != nil { + err2 := lndc.Close() + if err2 != nil { + return err2 + } + return err + } + // and we're authed + } else { // 53 byte, they don't know my pubkey + msg := append(myId.PubKey().SerializeCompressed(), myDHproof...) + _, err = lndc.Write(msg) + if err != nil { + err2 := lndc.Close() + if err2 != nil { + return err2 + } + return err + } + resp := make([]byte, 65535) + n, err := lndc.Read(resp) + if err != nil { + return err + } + resp = resp[:n] + + if n != 20 { + err2 := lndc.Close() + if err2 != nil { + return err2 + } + fmt.Errorf("expected 20 byte DH proof, got %d", n) + } + + // verify their DH proof + if bytes.Equal(resp, theirDHproof) == false { + err = lndc.Close() + if err != nil { + return err + } + return fmt.Errorf("Invalid DH proof %x", theirDHproof) + } + //proof looks good, auth + } + lndc.RemotePub = theirPub + theirAdr := H160(theirPub.SerializeCompressed()) + copy(lndc.RemoteLNId[:], theirAdr[:16]) + lndc.Authed = true + return nil +} + +func (lndc *LNDConn) AuthPKH( + myId *btcec.PrivateKey, theirPKH, localEphPubBytes []byte) error { + var err error + + if myId == nil { + return fmt.Errorf("can't auth: supplied privkey is nil") + } + if lndc.Authed { + return fmt.Errorf("%s already authed", lndc.RemotePub) + } + if len(theirPKH) != 20 { + return fmt.Errorf("remote PKH must be 20 bytes, got %d", len(theirPKH)) + } + + // send 53 bytes; my pubkey, and remote pubkey hash + msg := myId.PubKey().SerializeCompressed() + msg = append(msg, theirPKH...) + + _, err = lndc.Write(msg) + if err != nil { + return err + } + // wait for their response. + // TODO add timeout here + resp := make([]byte, 65535) + n, err := lndc.Read(resp) + if err != nil { + return err + } + resp = resp[:n] + // response should be 53 bytes, their pubkey and DH proof + if n != 53 { + return fmt.Errorf( + "PKH auth response should be 53 bytes, got %d", len(resp)) + } + theirPub, err := btcec.ParsePubKey(resp[:33], btcec.S256()) + if err != nil { + return err + } + idDH := fastsha256.Sum256(btcec.GenerateSharedSecret(myId, theirPub)) + fmt.Printf("made idDH %x\n", idDH) + + theirDHproof := H160(append(localEphPubBytes, idDH[:]...)) + // verify their DH proof + if bytes.Equal(resp[33:], theirDHproof) == false { + return fmt.Errorf("Invalid DH proof %x", theirDHproof) + } + // their DH proof checks out, send our own + myDHproof := H160(append(lndc.RemotePub.SerializeCompressed(), idDH[:]...)) + _, err = lndc.Write(myDHproof) + if err != nil { + return err + } + // proof sent, auth complete + lndc.RemotePub = theirPub + theirAdr := H160(theirPub.SerializeCompressed()) + copy(lndc.RemoteLNId[:], theirAdr[:16]) + lndc.Authed = true + return nil +} + +func (lndc *LNDConn) AuthPubKey( + myId *btcec.PrivateKey, remotePubBytes, localEphPubBytes []byte) error { + + var err error + if myId == nil { + return fmt.Errorf("can't auth: supplied privkey is nil") + } + if lndc.Authed { + return fmt.Errorf("%s already authed", lndc.RemotePub) + } + theirPub, err := btcec.ParsePubKey(remotePubBytes, btcec.S256()) + if err != nil { + return err + } + theirPKH := H160(remotePubBytes) + // I know enough to generate DH, do so + idDH := fastsha256.Sum256(btcec.GenerateSharedSecret(myId, theirPub)) + myDHproof := H160(append(lndc.RemotePub.SerializeCompressed(), idDH[:]...)) + // message is 73 bytes; my pubkey, their pubkey hash, DH proof + msg := myId.PubKey().SerializeCompressed() + msg = append(msg, theirPKH...) + msg = append(msg, myDHproof...) + + _, err = lndc.Write(msg) + if err != nil { + return err + } + resp := make([]byte, 65535) + n, err := lndc.Read(resp) + if err != nil { + return err + } + resp = resp[:n] + if n != 20 { + fmt.Errorf("expected 20 byte DH proof, got %d", len(resp)) + } + + theirDHproof := H160(append(localEphPubBytes, idDH[:]...)) + // verify their DH proof + if bytes.Equal(resp, theirDHproof) == false { + return fmt.Errorf("Invalid DH proof %x", theirDHproof) + } + // proof checks out, auth complete + lndc.RemotePub = theirPub + theirAdr := H160(theirPub.SerializeCompressed()) + copy(lndc.RemoteLNId[:], theirAdr[:16]) + lndc.Authed = true + return nil +} + +func (lndc *LNDConn) WhoAreYou(host string) (*btcec.PublicKey, error) { + var err error + if lndc.Cn == nil { + return nil, fmt.Errorf("no connection to ask on") + } + fmt.Printf("connecting to address %s\n", host) + // make TCP connection to listening host + lndc.Cn, err = net.Dial("tcp", host) + if err != nil { + return nil, err + } + err = lndc.writeClear([]byte("WHOAREYOU")) + if err != nil { + return nil, err + } + var b bytes.Buffer + lndc.Read(b.Bytes()) + + IamResp, err := lndc.readClear() + if err != nil { + return nil, err + } + return btcec.ParsePubKey(IamResp[:33], btcec.S256()) +} + +/* +Make ETcpCons adhere to Conn interface. +need: +Read(b []byte) (n int, err error) +Write(b []byte) (n int, err error) +Close() error +LocalAddr() Addr +RemoteAddr() Addr +SetDeadline(t time.Time) error +SetReadDeadline(t time.Time) error +SetWriteDeadline(t time.Time) error + +ETcpCons can be either regular TCP connections, which is good, or PBX-routed +connections, which is worse, but there are levels of connectivity we are +prepared to accept. + +When it's PBX, don't try to use Cn +*/ + +func (lndc *LNDConn) Read(b []byte) (n int, err error) { + // first get message length from first 2 bytes + var ctext []byte + ctext, err = lndc.readClear() + if err != nil { + return 0, err + } + + // now decrypt + nonceBuf := new(bytes.Buffer) + err = binary.Write(nonceBuf, binary.BigEndian, lndc.RemoteNonceInt) + fmt.Printf("decrypt %d byte from %x nonce %d\n", + len(ctext), lndc.RemoteLNId, lndc.RemoteNonceInt) + lndc.RemoteNonceInt++ // increment remote nonce, no matter what... + + msg, err := lndc.chachaStream.Open(nil, nonceBuf.Bytes(), ctext, nil) + if err != nil { + fmt.Printf("decrypt %d byte ciphertext failed\n", len(ctext)) + return 0, err + } + + n = copy(b, msg) + if n < len(msg) { + return 0, fmt.Errorf( + "Can't read from %x: Slice provided too small. %d bytes, need %d", + lndc.RemoteLNId, len(b), len(msg)) + } + + return n, nil +} + +func (lndc *LNDConn) Write(b []byte) (n int, err error) { + if b == nil { + return 0, fmt.Errorf("Write to %x nil", lndc.RemoteLNId) + } + fmt.Printf("Encrypt %d byte plaintext to %x nonce %d\n", + len(b), lndc.RemoteLNId, lndc.MyNonceInt) + // first encrypt message with shared key + nonceBuf := new(bytes.Buffer) + err = binary.Write(nonceBuf, binary.BigEndian, lndc.MyNonceInt) + if err != nil { + return 0, err + } + lndc.MyNonceInt++ // increment mine + + ctext := lndc.chachaStream.Seal(nil, nonceBuf.Bytes(), b, nil) + if err != nil { + return 0, err + } + if len(ctext) > 65530 { + return 0, fmt.Errorf("Write to %x too long, %d bytes", + lndc.RemoteLNId, len(ctext)) + } + + // use writeClear to prepend length / destination header + err = lndc.writeClear(ctext) + // returns len of how much you put in, not how much written on the wire + return len(b), err +} + +func (lndc *LNDConn) Close() error { + // return lndc.Cn.Close() + // return nil + lndc.MyNonceInt = 0 + lndc.RemoteNonceInt = 0 + lndc.RemotePub = nil + + // if lndc.ViaPbx { + // return nil // don't close pbx connection + // } + err := lndc.Cn.Close() + + return err +} + +// network address; if PBX reports address of pbx host +func (lndc *LNDConn) LocalAddr() net.Addr { + return lndc.Cn.LocalAddr() +} +func (lndc *LNDConn) RemoteAddr() net.Addr { + return lndc.Cn.RemoteAddr() +} + +// timing stuff for net.conn compatibility +func (lndc *LNDConn) SetDeadline(t time.Time) error { + return lndc.Cn.SetDeadline(t) +} +func (lndc *LNDConn) SetReadDeadline(t time.Time) error { + + return lndc.Cn.SetReadDeadline(t) +} +func (lndc *LNDConn) SetWriteDeadline(t time.Time) error { + return lndc.Cn.SetWriteDeadline(t) +} + +/* ReadClear and WriteClear don't encrypt but directly read and write to the +underlying data link, only adding or subtracting a 2 byte length header. +All Read() and Write() calls for lndc's use these functions internally +(they aren't exported). They're also used in the key agreement phase. +*/ + +// encapsulation for sending to Pbx host. +// put FWDMSG, then 16 byte destination ID, then message (with msgtype) +func (lndc *LNDConn) PbxEncapsulate(b *[]byte) { + fmt.Printf("PbxEncapsulate %d byte message, dest ID %x\n", + len(*b), lndc.RemoteLNId) + *b = append(lndc.RemoteLNId[:], *b...) + *b = append([]byte{lnwire.MSGID_FWDMSG}, *b...) +} + +func (lndc *LNDConn) readClear() ([]byte, error) { + var msgLen uint16 + // needs to be pointer or will silently not do anything. + var msg []byte + + if lndc.ViaPbx { //pbx mode + msg = <-lndc.PbxIncoming + } else { // normal tcp mode + err := binary.Read(lndc.Cn, binary.BigEndian, &msgLen) + if err != nil { + return nil, err + } + // fmt.Printf("%d byte LMsg incoming\n", msgLen) + msg = make([]byte, msgLen) + _, err = io.ReadFull(lndc.Cn, msg) + if err != nil { + return nil, err + } + } + return msg, nil +} + +func (lndc *LNDConn) writeClear(msg []byte) error { + var err error + if len(msg) > 65530 { + return fmt.Errorf("LMsg too long, %d bytes", len(msg)) + } + if msg == nil { + return fmt.Errorf("LMsg nil") + } + if lndc.ViaPbx { + lndc.PbxEncapsulate(&msg) + lndc.PbxOutgoing <- msg + } else { + // add 2 byte length header (pbx doesn't need it) and send over TCP + hdr := new(bytes.Buffer) + err = binary.Write(hdr, binary.BigEndian, uint16(len(msg))) + if err != nil { + return err + } + msg = append(hdr.Bytes(), msg...) + _, err = lndc.Cn.Write(msg) + return err + } + return nil +} diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index 24a71830..0548f18f 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -269,6 +269,36 @@ func NewLightningWallet(config *Config) (*LightningWallet, error) { fmt.Fprintln(os.Stderr, err) return nil, err } + + // open wallet to initialize and create id key + wallet, db, err := openWallet(pubPass, netDir) + if err != nil { + return nil, err + } + + err = wallet.Manager.Unlock(config.PrivatePass) + if err != nil { + return nil, err + } + + adrs, err := wallet.Manager.NextInternalAddresses(0, 1) + if err != nil { + return nil, err + } + priv, err := adrs[0].(waddrmgr.ManagedPubKeyAddress).PrivKey() + if err != nil { + return nil, err + } + lnNamespace, err := db.Namespace(lightningNamespaceKey) + if err != nil { + return nil, err + } + cdb := channeldb.New(wallet.Manager, lnNamespace) + err = cdb.PutIdKey(priv) + if err != nil { + return nil, err + } + fmt.Printf("stored private identity key in channeldb\n") } // Wallet has been created and been initialized at this point, open it diff --git a/plasma.go b/plasma.go index e91b4803..7d1a77a6 100644 --- a/plasma.go +++ b/plasma.go @@ -5,6 +5,7 @@ import ( "fmt" "net" "os" + "time" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" @@ -36,7 +37,7 @@ func main() { fmt.Printf("unable to start wallet: %v\n", err) os.Exit(1) } - + lnwallet.Unlock(cf.PrivatePass, time.Duration(0)) fmt.Println("wallet open") // Initialize, and register our implementation of the gRPC server. diff --git a/rpcserver.go b/rpcserver.go index 2d037344..295b6dd3 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -2,11 +2,14 @@ package main import ( "encoding/hex" + "fmt" "log" + "net" "github.com/btcsuite/btcutil" "github.com/btcsuite/btcwallet/waddrmgr" "golang.org/x/net/context" + "li.lan/labs/plasma/lndc" "li.lan/labs/plasma/lnrpc" "li.lan/labs/plasma/lnwallet" ) @@ -70,6 +73,17 @@ func (r *rpcServer) LNConnect(ctx context.Context, // TCPListen func (r *rpcServer) TCPListen(ctx context.Context, in *lnrpc.TCPListenRequest) (*lnrpc.TCPListenResponse, error) { + // LnListen listens on the default port for incoming connections + //ignore args and launch listener goroutine + + priv, err := r.lnwallet.ChannelDB.GetIdKey() + if err != nil { + return nil, err + } + + fmt.Printf("got a private key. %x\n", priv.Serialize()) + + // go TCPListener() resp := new(lnrpc.TCPListenResponse) return resp, nil @@ -82,3 +96,44 @@ func (r *rpcServer) LNChat(ctx context.Context, resp := new(lnrpc.LnChatResponse) return resp, nil } + +func TCPListener() { + listener, err := net.Listen("tcp", ":"+"2448") + if err != nil { + fmt.Printf("TCP listen error: %s\n", err.Error()) + return + } + + fmt.Printf("Listening on %s\n", listener.Addr().String()) + for { + con, err := listener.Accept() // this blocks + if err != nil { + log.Printf("Listener error: %s\n", err.Error()) + continue + } + newConn, err := InitIncomingConn(con) + if err != nil { + fmt.Printf("InitConn error: %s\n", err.Error()) + continue + } + idslice := lndc.H160(newConn.RemotePub.SerializeCompressed()) + var newId [16]byte + copy(newId[:], idslice[:16]) + // CnMap[newId] = newConn + fmt.Printf("added %x to map\n", newId) + // go LNDCReceiver(newConn, newId) + } +} + +func InitIncomingConn(con net.Conn) (*lndc.LNDConn, error) { + LNcon := new(lndc.LNDConn) + LNcon.Cn = con + err := LNcon.Setup(nil) + if err != nil { + return LNcon, err + } + fmt.Printf("Got connection from %s authed with pubkey %x", + LNcon.Cn.RemoteAddr().String(), LNcon.RemotePub.SerializeCompressed()) + return LNcon, nil + +}