2017-12-29 07:16:20 +03:00
package yggdrasil
// This sends packets to peers using TCP as a transport
// It's generally better tested than the UDP implementation
// Using it regularly is insane, but I find TCP easier to test/debug with it
// Updating and optimizing the UDP version is a higher priority
// TODO:
// Something needs to make sure we're getting *valid* packets
// Could be used to DoS (connect, give someone else's keys, spew garbage)
// I guess the "peer" part should watch for link packets, disconnect?
2018-06-10 01:46:19 +03:00
// TCP connections start with a metadata exchange.
// It involves exchanging version numbers and crypto keys
// See version.go for version metadata format
2018-06-13 01:50:08 +03:00
import (
"errors"
"fmt"
2018-06-21 18:39:43 +03:00
"math/rand"
2018-06-13 01:50:08 +03:00
"net"
2018-06-23 09:10:18 +03:00
"sort"
2018-06-13 01:50:08 +03:00
"sync"
"sync/atomic"
"time"
"golang.org/x/net/proxy"
)
2017-12-29 07:16:20 +03:00
2018-01-05 01:37:51 +03:00
const tcp_msgSize = 2048 + 65535 // TODO figure out what makes sense
2018-06-16 23:31:25 +03:00
const tcp_timeout = 6 * time . Second
2017-12-29 07:16:20 +03:00
2018-06-11 02:03:28 +03:00
// Wrapper function for non tcp/ip connections.
2018-04-19 17:30:40 +03:00
func setNoDelay ( c net . Conn , delay bool ) {
tcp , ok := c . ( * net . TCPConn )
if ok {
tcp . SetNoDelay ( delay )
}
}
2018-06-11 02:03:28 +03:00
// The TCP listener and information about active TCP connections, to avoid duplication.
2017-12-29 07:16:20 +03:00
type tcpInterface struct {
2018-01-05 01:37:51 +03:00
core * Core
2018-04-19 17:30:40 +03:00
serv net . Listener
2018-01-05 01:37:51 +03:00
mutex sync . Mutex // Protecting the below
calls map [ string ] struct { }
2018-02-18 05:44:23 +03:00
conns map [ tcpInfo ] ( chan struct { } )
2017-12-29 07:16:20 +03:00
}
2018-06-11 02:03:28 +03:00
// This is used as the key to a map that tracks existing connections, to prevent multiple connections to the same keys and local/remote address pair from occuring.
// Different address combinations are allowed, so multi-homing is still technically possible (but not necessarily advisable).
2018-02-18 05:44:23 +03:00
type tcpInfo struct {
box boxPubKey
sig sigPubKey
2018-04-20 15:41:09 +03:00
localAddr string
remoteAddr string
2017-12-29 07:16:20 +03:00
}
2018-06-11 02:03:28 +03:00
// Returns the address of the listener.
2018-05-28 00:13:37 +03:00
func ( iface * tcpInterface ) getAddr ( ) * net . TCPAddr {
return iface . serv . Addr ( ) . ( * net . TCPAddr )
}
2018-06-11 02:03:28 +03:00
// Attempts to initiate a connection to the provided address.
2018-05-28 00:13:37 +03:00
func ( iface * tcpInterface ) connect ( addr string ) {
2018-06-14 17:11:34 +03:00
iface . call ( addr , nil )
2018-05-28 00:13:37 +03:00
}
2018-06-11 02:03:28 +03:00
// Attempst to initiate a connection to the provided address, viathe provided socks proxy address.
2018-05-28 00:13:37 +03:00
func ( iface * tcpInterface ) connectSOCKS ( socksaddr , peeraddr string ) {
2018-06-14 17:21:35 +03:00
iface . call ( peeraddr , & socksaddr )
2018-05-28 00:13:37 +03:00
}
2018-06-11 02:03:28 +03:00
// Initializes the struct.
2018-04-19 17:30:40 +03:00
func ( iface * tcpInterface ) init ( core * Core , addr string ) ( err error ) {
2018-01-05 01:37:51 +03:00
iface . core = core
2018-04-19 17:30:40 +03:00
iface . serv , err = net . Listen ( "tcp" , addr )
if err == nil {
iface . calls = make ( map [ string ] struct { } )
iface . conns = make ( map [ tcpInfo ] ( chan struct { } ) )
go iface . listener ( )
2018-01-05 01:37:51 +03:00
}
2018-05-28 00:13:37 +03:00
return err
2017-12-29 07:16:20 +03:00
}
2018-06-11 02:03:28 +03:00
// Runs the listener, which spawns off goroutines for incoming connections.
2017-12-29 07:16:20 +03:00
func ( iface * tcpInterface ) listener ( ) {
2018-01-05 01:37:51 +03:00
defer iface . serv . Close ( )
2018-03-07 12:41:04 +03:00
iface . core . log . Println ( "Listening for TCP on:" , iface . serv . Addr ( ) . String ( ) )
2018-01-05 01:37:51 +03:00
for {
2018-04-19 17:30:40 +03:00
sock , err := iface . serv . Accept ( )
2018-01-05 01:37:51 +03:00
if err != nil {
panic ( err )
}
2018-05-07 00:32:34 +03:00
go iface . handler ( sock , true )
2018-01-05 01:37:51 +03:00
}
2017-12-29 07:16:20 +03:00
}
2018-06-11 02:03:28 +03:00
// Checks if a connection already exists.
// If not, it adds it to the list of active outgoing calls (to block future attempts) and dials the address.
// If the dial is successful, it launches the handler.
// When finished, it removes the outgoing call, so reconnection attempts can be made later.
// This all happens in a separate goroutine that it spawns.
2018-06-14 17:21:35 +03:00
func ( iface * tcpInterface ) call ( saddr string , socksaddr * string ) {
2018-01-05 01:37:51 +03:00
go func ( ) {
quit := false
iface . mutex . Lock ( )
if _ , isIn := iface . calls [ saddr ] ; isIn {
quit = true
} else {
iface . calls [ saddr ] = struct { } { }
defer func ( ) {
2018-06-16 23:31:25 +03:00
// Block new calls for a little while, to mitigate livelock scenarios
time . Sleep ( tcp_timeout )
2018-06-21 18:39:43 +03:00
time . Sleep ( time . Duration ( rand . Intn ( 1000 ) ) * time . Millisecond )
2018-01-05 01:37:51 +03:00
iface . mutex . Lock ( )
delete ( iface . calls , saddr )
iface . mutex . Unlock ( )
} ( )
}
iface . mutex . Unlock ( )
2018-06-14 17:11:34 +03:00
if quit {
return
}
var conn net . Conn
var err error
2018-06-14 17:21:35 +03:00
if socksaddr != nil {
var dialer proxy . Dialer
dialer , err = proxy . SOCKS5 ( "tcp" , * socksaddr , nil , proxy . Direct )
if err != nil {
return
}
2018-06-14 17:11:34 +03:00
conn , err = dialer . Dial ( "tcp" , saddr )
if err != nil {
return
}
conn = & wrappedConn {
c : conn ,
raddr : & wrappedAddr {
network : "tcp" ,
addr : saddr ,
} ,
}
} else {
conn , err = net . Dial ( "tcp" , saddr )
2018-01-05 01:37:51 +03:00
if err != nil {
return
}
}
2018-06-14 17:11:34 +03:00
iface . handler ( conn , false )
2018-01-05 01:37:51 +03:00
} ( )
2017-12-29 07:16:20 +03:00
}
2018-06-11 02:03:28 +03:00
// This exchanges/checks connection metadata, sets up the peer struct, sets up the writer goroutine, and then runs the reader within the current goroutine.
// It defers a bunch of cleanup stuff to tear down all of these things when the reader exists (e.g. due to a closed connection or a timeout).
2018-05-07 00:32:34 +03:00
func ( iface * tcpInterface ) handler ( sock net . Conn , incoming bool ) {
2018-01-05 01:37:51 +03:00
defer sock . Close ( )
// Get our keys
2018-06-09 02:42:56 +03:00
myLinkPub , myLinkPriv := newBoxKeys ( ) // ephemeral link keys
2018-06-10 01:46:19 +03:00
meta := version_getBaseMetadata ( )
meta . box = iface . core . boxPub
meta . sig = iface . core . sigPub
meta . link = * myLinkPub
metaBytes := meta . encode ( )
_ , err := sock . Write ( metaBytes )
2018-01-05 01:37:51 +03:00
if err != nil {
return
}
2018-06-16 23:31:25 +03:00
timeout := time . Now ( ) . Add ( tcp_timeout )
2018-01-05 01:37:51 +03:00
sock . SetReadDeadline ( timeout )
2018-06-10 02:38:30 +03:00
_ , err = sock . Read ( metaBytes )
2018-01-05 01:37:51 +03:00
if err != nil {
return
}
2018-06-10 01:46:19 +03:00
meta = version_metadata { } // Reset to zero value
2018-06-10 02:38:30 +03:00
if ! meta . decode ( metaBytes ) || ! meta . check ( ) {
// Failed to decode and check the metadata
// If it's a version mismatch issue, then print an error message
2018-06-10 01:46:19 +03:00
base := version_getBaseMetadata ( )
if meta . meta == base . meta {
if meta . ver > base . ver {
iface . core . log . Println ( "Failed to connect to node:" , sock . RemoteAddr ( ) . String ( ) , "version:" , meta . ver )
} else if meta . ver == base . ver && meta . minorVer > base . minorVer {
iface . core . log . Println ( "Failed to connect to node:" , sock . RemoteAddr ( ) . String ( ) , "version:" , fmt . Sprintf ( "%d.%d" , meta . ver , meta . minorVer ) )
}
}
2018-06-10 02:38:30 +03:00
// TODO? Block forever to prevent future connection attempts? suppress future messages about the same node?
2018-01-05 01:37:51 +03:00
return
}
2018-06-10 01:46:19 +03:00
info := tcpInfo { // used as a map key, so don't include ephemeral link key
box : meta . box ,
sig : meta . sig ,
}
2018-01-05 01:37:51 +03:00
// Quit the parent call if this is a connection to ourself
equiv := func ( k1 , k2 [ ] byte ) bool {
for idx := range k1 {
if k1 [ idx ] != k2 [ idx ] {
return false
}
}
return true
}
2018-02-18 05:44:23 +03:00
if equiv ( info . box [ : ] , iface . core . boxPub [ : ] ) {
2018-01-05 01:37:51 +03:00
return
2018-06-13 01:50:08 +03:00
}
2018-02-18 05:44:23 +03:00
if equiv ( info . sig [ : ] , iface . core . sigPub [ : ] ) {
2018-01-05 01:37:51 +03:00
return
}
2018-05-07 00:32:34 +03:00
// Check if we're authorized to connect to this key / IP
2018-05-23 13:28:20 +03:00
if incoming && ! iface . core . peers . isAllowedEncryptionPublicKey ( & info . box ) {
2018-05-07 00:32:34 +03:00
// Allow unauthorized peers if they're link-local
raddrStr , _ , _ := net . SplitHostPort ( sock . RemoteAddr ( ) . String ( ) )
raddr := net . ParseIP ( raddrStr )
if ! raddr . IsLinkLocalUnicast ( ) {
return
}
}
2018-02-18 05:44:23 +03:00
// Check if we already have a connection to this node, close and block if yes
2018-04-20 15:41:09 +03:00
info . localAddr , _ , _ = net . SplitHostPort ( sock . LocalAddr ( ) . String ( ) )
info . remoteAddr , _ , _ = net . SplitHostPort ( sock . RemoteAddr ( ) . String ( ) )
2018-02-18 05:44:23 +03:00
iface . mutex . Lock ( )
if blockChan , isIn := iface . conns [ info ] ; isIn {
iface . mutex . Unlock ( )
sock . Close ( )
<- blockChan
return
}
blockChan := make ( chan struct { } )
iface . conns [ info ] = blockChan
iface . mutex . Unlock ( )
2018-02-20 08:22:36 +03:00
defer func ( ) {
iface . mutex . Lock ( )
delete ( iface . conns , info )
iface . mutex . Unlock ( )
close ( blockChan )
} ( )
2018-01-05 01:37:51 +03:00
// Note that multiple connections to the same node are allowed
// E.g. over different interfaces
2018-06-10 01:46:19 +03:00
p := iface . core . peers . newPeer ( & info . box , & info . sig , getSharedKey ( myLinkPriv , & meta . link ) )
2018-06-07 01:44:10 +03:00
p . linkOut = make ( chan [ ] byte , 1 )
2018-01-05 01:37:51 +03:00
in := func ( bs [ ] byte ) {
2018-06-07 01:44:10 +03:00
p . handlePacket ( bs )
2018-01-05 01:37:51 +03:00
}
2018-06-23 07:46:42 +03:00
out := make ( chan [ ] byte , 1024 ) // Should be effectively infinite, but gets fed into finite LIFO stack
2018-01-05 01:37:51 +03:00
defer close ( out )
go func ( ) {
2018-06-11 02:03:28 +03:00
var shadow int64
2018-01-05 01:37:51 +03:00
var stack [ ] [ ] byte
put := func ( msg [ ] byte ) {
stack = append ( stack , msg )
2018-06-23 09:10:18 +03:00
sort . SliceStable ( stack , func ( i , j int ) bool {
// Sort in reverse order, with smallest messages at the end
return len ( stack [ i ] ) >= len ( stack [ j ] )
} )
2018-02-04 03:44:28 +03:00
for len ( stack ) > 32 {
2018-01-05 01:37:51 +03:00
util_putBytes ( stack [ 0 ] )
stack = stack [ 1 : ]
2018-06-07 23:04:17 +03:00
shadow ++
2018-01-05 01:37:51 +03:00
}
}
2018-06-23 04:39:57 +03:00
send := make ( chan [ ] byte )
defer close ( send )
go func ( ) {
for msg := range send {
msgLen := wire_encode_uint64 ( uint64 ( len ( msg ) ) )
buf := net . Buffers { tcp_msg [ : ] , msgLen , msg }
buf . WriteTo ( sock )
atomic . AddUint64 ( & p . bytesSent , uint64 ( len ( tcp_msg ) + len ( msgLen ) + len ( msg ) ) )
util_putBytes ( msg )
}
} ( )
2018-06-16 23:31:25 +03:00
timerInterval := tcp_timeout * 2 / 3
2018-06-08 00:49:51 +03:00
timer := time . NewTimer ( timerInterval )
defer timer . Stop ( )
2018-06-07 01:44:10 +03:00
for {
2018-06-11 02:03:28 +03:00
if shadow != 0 {
p . updateQueueSize ( - shadow )
shadow = 0
2018-06-07 23:04:17 +03:00
}
2018-06-08 00:49:51 +03:00
timer . Stop ( )
select {
case <- timer . C :
default :
}
timer . Reset ( timerInterval )
2018-06-07 01:44:10 +03:00
select {
2018-06-08 00:49:51 +03:00
case _ = <- timer . C :
2018-06-23 04:39:57 +03:00
send <- nil // TCP keep-alive traffic
2018-06-07 01:44:10 +03:00
case msg := <- p . linkOut :
2018-06-23 04:39:57 +03:00
send <- msg
2018-06-07 01:44:10 +03:00
case msg , ok := <- out :
if ! ok {
return
}
put ( msg )
}
2018-01-05 01:37:51 +03:00
for len ( stack ) > 0 {
2018-06-23 04:39:57 +03:00
// First make sure linkOut gets sent first, if it's non-empty
select {
case msg := <- p . linkOut :
send <- msg
2018-06-23 07:46:42 +03:00
continue
2018-06-23 04:39:57 +03:00
default :
}
// Then block until we send or receive something
2018-01-05 01:37:51 +03:00
select {
2018-06-07 01:44:10 +03:00
case msg := <- p . linkOut :
2018-06-23 04:39:57 +03:00
send <- msg
2018-01-05 01:37:51 +03:00
case msg , ok := <- out :
if ! ok {
return
}
put ( msg )
2018-06-23 04:39:57 +03:00
case send <- stack [ len ( stack ) - 1 ] :
2018-02-20 04:34:51 +03:00
stack = stack [ : len ( stack ) - 1 ]
2018-06-07 01:44:10 +03:00
p . updateQueueSize ( - 1 )
2018-01-05 01:37:51 +03:00
}
}
}
} ( )
p . out = func ( msg [ ] byte ) {
2018-06-23 04:39:57 +03:00
p . updateQueueSize ( 1 )
2018-01-05 01:37:51 +03:00
defer func ( ) { recover ( ) } ( )
2018-06-23 04:39:57 +03:00
out <- msg
2018-01-05 01:37:51 +03:00
}
2018-05-06 01:14:03 +03:00
p . close = func ( ) { sock . Close ( ) }
2018-04-19 17:30:40 +03:00
setNoDelay ( sock , true )
2018-06-07 01:44:10 +03:00
go p . linkLoop ( )
2018-01-05 01:37:51 +03:00
defer func ( ) {
// Put all of our cleanup here...
2018-05-06 01:14:03 +03:00
p . core . peers . removePeer ( p . port )
2018-01-05 01:37:51 +03:00
} ( )
2018-04-20 15:41:09 +03:00
them , _ , _ := net . SplitHostPort ( sock . RemoteAddr ( ) . String ( ) )
2018-02-18 05:44:23 +03:00
themNodeID := getNodeID ( & info . box )
2018-01-05 01:37:51 +03:00
themAddr := address_addrForNodeID ( themNodeID )
themAddrString := net . IP ( themAddr [ : ] ) . String ( )
themString := fmt . Sprintf ( "%s@%s" , themAddrString , them )
iface . core . log . Println ( "Connected:" , themString )
iface . reader ( sock , in ) // In this goroutine, because of defers
iface . core . log . Println ( "Disconnected:" , themString )
return
2017-12-29 07:16:20 +03:00
}
2018-06-11 02:03:28 +03:00
// This reads from the socket into a []byte buffer for incomping messages.
// It copies completed messages out of the cache into a new slice, and passes them to the peer struct via the provided `in func([]byte)` argument.
// Then it shifts the incomplete fragments of data forward so future reads won't overwrite it.
2018-04-19 17:30:40 +03:00
func ( iface * tcpInterface ) reader ( sock net . Conn , in func ( [ ] byte ) ) {
2018-01-05 01:37:51 +03:00
bs := make ( [ ] byte , 2 * tcp_msgSize )
frag := bs [ : 0 ]
for {
2018-06-16 23:31:25 +03:00
timeout := time . Now ( ) . Add ( tcp_timeout )
2018-01-05 01:37:51 +03:00
sock . SetReadDeadline ( timeout )
n , err := sock . Read ( bs [ len ( frag ) : ] )
if err != nil || n == 0 {
break
}
frag = bs [ : len ( frag ) + n ]
for {
msg , ok , err := tcp_chop_msg ( & frag )
if err != nil {
return
}
if ! ok {
break
} // We didn't get the whole message yet
newMsg := append ( util_getBytes ( ) , msg ... )
in ( newMsg )
util_yield ( )
}
frag = append ( bs [ : 0 ] , frag ... )
}
2017-12-29 07:16:20 +03:00
}
////////////////////////////////////////////////////////////////////////////////
2018-06-11 02:03:28 +03:00
// These are 4 bytes of padding used to catch if something went horribly wrong with the tcp connection.
2017-12-29 07:16:20 +03:00
var tcp_msg = [ ... ] byte { 0xde , 0xad , 0xb1 , 0x75 } // "dead bits"
2018-06-11 02:03:28 +03:00
// This takes a pointer to a slice as an argument.
// It checks if there's a complete message and, if so, slices out those parts and returns the message, true, and nil.
// If there's no error, but also no complete message, it returns nil, false, and nil.
// If there's an error, it returns nil, false, and the error, which the reader then handles (currently, by returning from the reader, which causes the connection to close).
2017-12-29 07:16:20 +03:00
func tcp_chop_msg ( bs * [ ] byte ) ( [ ] byte , bool , error ) {
2018-01-05 01:37:51 +03:00
// Returns msg, ok, err
if len ( * bs ) < len ( tcp_msg ) {
return nil , false , nil
}
for idx := range tcp_msg {
if ( * bs ) [ idx ] != tcp_msg [ idx ] {
return nil , false , errors . New ( "Bad message!" )
}
}
msgLen , msgLenLen := wire_decode_uint64 ( ( * bs ) [ len ( tcp_msg ) : ] )
if msgLen > tcp_msgSize {
return nil , false , errors . New ( "Oversized message!" )
}
msgBegin := len ( tcp_msg ) + msgLenLen
msgEnd := msgBegin + int ( msgLen )
if msgLenLen == 0 || len ( * bs ) < msgEnd {
// We don't have the full message
// Need to buffer this and wait for the rest to come in
return nil , false , nil
}
msg := ( * bs ) [ msgBegin : msgEnd ]
( * bs ) = ( * bs ) [ msgEnd : ]
return msg , true , nil
2017-12-29 07:16:20 +03:00
}