2017-12-28 22:16:20 -06: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-09 17:46:19 -05: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-12 17:50:08 -05:00
import (
2019-01-13 18:08:41 +00:00
"context"
2018-06-12 17:50:08 -05:00
"fmt"
2018-06-21 10:39:43 -05:00
"math/rand"
2018-06-12 17:50:08 -05:00
"net"
"sync"
"time"
"golang.org/x/net/proxy"
2018-12-14 20:49:18 -06:00
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
2019-03-04 18:41:32 +00:00
"github.com/yggdrasil-network/yggdrasil-go/src/util"
2018-06-12 17:50:08 -05:00
)
2017-12-28 22:16:20 -06:00
2019-01-19 00:14:10 +00:00
const default_timeout = 6 * time . Second
const tcp_ping_interval = ( default_timeout * 2 / 3 )
2017-12-28 22:16:20 -06:00
2018-06-10 18:03:28 -05:00
// The TCP listener and information about active TCP connections, to avoid duplication.
2019-03-04 17:52:57 +00:00
type tcp struct {
2019-03-04 18:41:32 +00:00
link * link
reconfigure chan chan error
mutex sync . Mutex // Protecting the below
listeners map [ string ] net . Listener
listenerstops map [ string ] chan bool
calls map [ string ] struct { }
conns map [ tcpInfo ] ( chan struct { } )
2017-12-28 22:16:20 -06:00
}
2018-06-10 18:03:28 -05: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-17 20:44:23 -06:00
type tcpInfo struct {
2018-12-14 20:49:18 -06:00
box crypto . BoxPubKey
sig crypto . SigPubKey
2018-12-30 21:11:16 +00:00
localAddr string
2018-04-20 08:41:09 -04:00
remoteAddr string
2017-12-28 22:16:20 -06:00
}
2018-12-14 18:15:35 -06:00
// Wrapper function to set additional options for specific connection types.
2019-03-04 17:52:57 +00:00
func ( t * tcp ) setExtraOptions ( c net . Conn ) {
2018-12-14 18:15:35 -06:00
switch sock := c . ( type ) {
case * net . TCPConn :
sock . SetNoDelay ( true )
// TODO something for socks5
default :
}
}
2018-06-10 18:03:28 -05:00
// Returns the address of the listener.
2019-03-04 17:52:57 +00:00
func ( t * tcp ) getAddr ( ) * net . TCPAddr {
for _ , listener := range t . listeners {
return listener . Addr ( ) . ( * net . TCPAddr )
}
return nil
2018-05-27 22:13:37 +01:00
}
2018-06-10 18:03:28 -05:00
// Attempts to initiate a connection to the provided address.
2019-03-04 17:52:57 +00:00
func ( t * tcp ) connect ( addr string , intf string ) {
t . call ( addr , nil , intf )
2018-05-27 22:13:37 +01:00
}
2018-06-10 18:03:28 -05:00
// Attempst to initiate a connection to the provided address, viathe provided socks proxy address.
2019-03-04 17:52:57 +00:00
func ( t * tcp ) connectSOCKS ( socksaddr , peeraddr string ) {
t . call ( peeraddr , & socksaddr , "" )
2018-05-27 22:13:37 +01:00
}
2018-06-10 18:03:28 -05:00
// Initializes the struct.
2019-03-04 17:52:57 +00:00
func ( t * tcp ) init ( l * link ) error {
t . link = l
t . reconfigure = make ( chan chan error , 1 )
2018-12-30 15:21:09 +00:00
go func ( ) {
for {
2019-03-04 17:52:57 +00:00
e := <- t . reconfigure
t . link . core . configMutex . RLock ( )
2019-03-04 18:41:32 +00:00
added := util . Difference ( t . link . core . config . Listen , t . link . core . configOld . Listen )
deleted := util . Difference ( t . link . core . configOld . Listen , t . link . core . config . Listen )
updated := len ( added ) > 0 || len ( deleted ) > 0
2019-03-04 17:52:57 +00:00
t . link . core . configMutex . RUnlock ( )
2019-01-15 08:51:19 +00:00
if updated {
2019-03-04 18:41:32 +00:00
for _ , add := range added {
if add [ : 6 ] != "tcp://" {
continue
}
if err := t . listen ( add [ 6 : ] ) ; err != nil {
e <- err
continue
}
}
for _ , delete := range deleted {
t . link . core . log . Warnln ( "Removing listener" , delete , "not currently implemented" )
/ * t . mutex . Lock ( )
if listener , ok := t . listeners [ delete ] ; ok {
2019-03-04 17:52:57 +00:00
listener . Close ( )
}
2019-03-04 18:41:32 +00:00
if listener , ok := t . listenerstops [ delete ] ; ok {
listener <- true
}
t . mutex . Unlock ( ) * /
}
e <- nil
2019-01-15 08:51:19 +00:00
} else {
e <- nil
2018-12-30 15:21:09 +00:00
}
}
} ( )
2019-03-04 17:52:57 +00:00
t . mutex . Lock ( )
t . calls = make ( map [ string ] struct { } )
t . conns = make ( map [ tcpInfo ] ( chan struct { } ) )
t . listeners = make ( map [ string ] net . Listener )
2019-03-04 18:41:32 +00:00
t . listenerstops = make ( map [ string ] chan bool )
2019-03-04 17:52:57 +00:00
t . mutex . Unlock ( )
t . link . core . configMutex . RLock ( )
defer t . link . core . configMutex . RUnlock ( )
for _ , listenaddr := range t . link . core . config . Listen {
if listenaddr [ : 6 ] != "tcp://" {
continue
}
if err := t . listen ( listenaddr [ 6 : ] ) ; err != nil {
return err
}
}
return nil
2018-12-30 15:21:09 +00:00
}
2019-03-04 17:52:57 +00:00
func ( t * tcp ) listen ( listenaddr string ) error {
2018-12-30 15:21:09 +00:00
var err error
2019-01-13 18:08:41 +00:00
ctx := context . Background ( )
lc := net . ListenConfig {
2019-03-04 17:52:57 +00:00
Control : t . tcpContext ,
2019-01-13 18:08:41 +00:00
}
2019-03-04 17:52:57 +00:00
listener , err := lc . Listen ( ctx , "tcp" , listenaddr )
2018-04-19 10:30:40 -04:00
if err == nil {
2019-03-04 17:52:57 +00:00
t . mutex . Lock ( )
t . listeners [ listenaddr ] = listener
2019-03-04 18:41:32 +00:00
t . listenerstops [ listenaddr ] = make ( chan bool , 1 )
2019-03-04 17:52:57 +00:00
t . mutex . Unlock ( )
go t . listener ( listenaddr )
2018-12-30 15:21:09 +00:00
return nil
2018-01-04 22:37:51 +00:00
}
2018-05-27 22:13:37 +01:00
return err
2017-12-28 22:16:20 -06:00
}
2018-06-10 18:03:28 -05:00
// Runs the listener, which spawns off goroutines for incoming connections.
2019-03-04 17:52:57 +00:00
func ( t * tcp ) listener ( listenaddr string ) {
listener , ok := t . listeners [ listenaddr ]
if ! ok {
t . link . core . log . Errorln ( "Tried to start TCP listener for" , listenaddr , "which doesn't exist" )
return
}
2019-03-04 18:41:32 +00:00
reallistenaddr := listener . Addr ( ) . String ( )
2019-03-04 17:52:57 +00:00
defer listener . Close ( )
2019-03-04 18:41:32 +00:00
t . link . core . log . Infoln ( "Listening for TCP on:" , reallistenaddr )
2018-01-04 22:37:51 +00:00
for {
2019-03-04 18:41:32 +00:00
var sock net . Conn
var err error
accepted := make ( chan bool )
go func ( ) {
sock , err = listener . Accept ( )
accepted <- true
} ( )
2018-12-30 15:21:09 +00:00
select {
2019-03-04 18:41:32 +00:00
case <- accepted :
if err != nil {
t . link . core . log . Errorln ( "Failed to accept connection:" , err )
return
}
case <- t . listenerstops [ listenaddr ] :
t . link . core . log . Errorln ( "Stopping TCP listener on:" , reallistenaddr )
2018-12-30 15:21:09 +00:00
return
default :
if err != nil {
panic ( err )
}
2019-03-04 17:52:57 +00:00
go t . handler ( sock , true )
2018-01-04 22:37:51 +00:00
}
}
2017-12-28 22:16:20 -06:00
}
2018-12-30 21:11:16 +00:00
// Checks if we already have a connection to this node
2019-03-04 17:52:57 +00:00
func ( t * tcp ) isAlreadyConnected ( info tcpInfo ) bool {
t . mutex . Lock ( )
defer t . mutex . Unlock ( )
_ , isIn := t . conns [ info ]
2018-12-30 21:11:16 +00:00
return isIn
}
// Checks if we already are calling this address
2019-03-04 17:52:57 +00:00
func ( t * tcp ) isAlreadyCalling ( saddr string ) bool {
t . mutex . Lock ( )
defer t . mutex . Unlock ( )
_ , isIn := t . calls [ saddr ]
2018-12-30 21:11:16 +00:00
return isIn
}
2018-06-10 18:03:28 -05: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.
2019-03-04 17:52:57 +00:00
func ( t * tcp ) call ( saddr string , socksaddr * string , sintf string ) {
2018-01-04 22:37:51 +00:00
go func ( ) {
2018-09-25 18:05:57 +01:00
callname := saddr
if sintf != "" {
callname = fmt . Sprintf ( "%s/%s" , saddr , sintf )
}
2019-03-04 17:52:57 +00:00
if t . isAlreadyCalling ( callname ) {
2018-06-14 09:11:34 -05:00
return
}
2019-03-04 17:52:57 +00:00
t . mutex . Lock ( )
t . calls [ callname ] = struct { } { }
t . mutex . Unlock ( )
2018-12-30 21:11:16 +00:00
defer func ( ) {
// Block new calls for a little while, to mitigate livelock scenarios
2019-01-19 00:14:10 +00:00
time . Sleep ( default_timeout )
2018-12-30 21:11:16 +00:00
time . Sleep ( time . Duration ( rand . Intn ( 1000 ) ) * time . Millisecond )
2019-03-04 17:52:57 +00:00
t . mutex . Lock ( )
delete ( t . calls , callname )
t . mutex . Unlock ( )
2018-12-30 21:11:16 +00:00
} ( )
2018-06-14 09:11:34 -05:00
var conn net . Conn
var err error
2018-06-14 09:21:35 -05:00
if socksaddr != nil {
2018-09-25 19:46:06 +01:00
if sintf != "" {
return
}
2018-06-14 09:21:35 -05:00
var dialer proxy . Dialer
dialer , err = proxy . SOCKS5 ( "tcp" , * socksaddr , nil , proxy . Direct )
if err != nil {
return
}
2018-06-14 09:11:34 -05:00
conn , err = dialer . Dial ( "tcp" , saddr )
if err != nil {
return
}
conn = & wrappedConn {
c : conn ,
raddr : & wrappedAddr {
network : "tcp" ,
addr : saddr ,
} ,
}
} else {
2019-01-13 18:08:41 +00:00
dialer := net . Dialer {
2019-03-04 17:52:57 +00:00
Control : t . tcpContext ,
2019-01-13 18:08:41 +00:00
}
2018-09-25 15:32:45 +01:00
if sintf != "" {
ief , err := net . InterfaceByName ( sintf )
2018-10-04 12:26:08 +01:00
if err != nil {
return
2019-01-16 14:52:27 +00:00
}
if ief . Flags & net . FlagUp == 0 {
return
}
addrs , err := ief . Addrs ( )
if err == nil {
dst , err := net . ResolveTCPAddr ( "tcp" , saddr )
if err != nil {
2018-09-27 12:14:55 +01:00
return
2018-09-25 19:46:06 +01:00
}
2019-01-16 14:52:27 +00:00
for addrindex , addr := range addrs {
src , _ , err := net . ParseCIDR ( addr . String ( ) )
2018-09-25 15:32:45 +01:00
if err != nil {
2019-01-16 14:52:27 +00:00
continue
2018-09-25 15:32:45 +01:00
}
2019-01-17 23:06:59 +00:00
if src . Equal ( dst . IP ) {
continue
}
if ! src . IsGlobalUnicast ( ) && ! src . IsLinkLocalUnicast ( ) {
continue
}
bothglobal := src . IsGlobalUnicast ( ) == dst . IP . IsGlobalUnicast ( )
bothlinklocal := src . IsLinkLocalUnicast ( ) == dst . IP . IsLinkLocalUnicast ( )
if ! bothglobal && ! bothlinklocal {
continue
}
if ( src . To4 ( ) != nil ) != ( dst . IP . To4 ( ) != nil ) {
continue
}
if bothglobal || bothlinklocal || addrindex == len ( addrs ) - 1 {
dialer . LocalAddr = & net . TCPAddr {
IP : src ,
Port : 0 ,
Zone : sintf ,
2018-09-25 15:32:45 +01:00
}
2019-01-17 23:06:59 +00:00
break
2018-09-25 15:32:45 +01:00
}
2019-01-16 14:52:27 +00:00
}
if dialer . LocalAddr == nil {
return
2018-09-25 15:32:45 +01:00
}
}
}
2019-01-16 14:52:27 +00:00
2018-09-25 15:32:45 +01:00
conn , err = dialer . Dial ( "tcp" , saddr )
2018-01-04 22:37:51 +00:00
if err != nil {
return
}
}
2019-03-04 17:52:57 +00:00
t . handler ( conn , false )
2018-01-04 22:37:51 +00:00
} ( )
2017-12-28 22:16:20 -06:00
}
2019-03-04 17:52:57 +00:00
func ( t * tcp ) handler ( sock net . Conn , incoming bool ) {
2019-01-21 23:08:50 -06:00
defer sock . Close ( )
2019-03-04 17:52:57 +00:00
t . setExtraOptions ( sock )
2019-01-21 23:08:50 -06:00
stream := stream { }
2019-01-23 15:16:22 +00:00
stream . init ( sock )
2019-01-22 21:16:41 -06:00
local , _ , _ := net . SplitHostPort ( sock . LocalAddr ( ) . String ( ) )
remote , _ , _ := net . SplitHostPort ( sock . RemoteAddr ( ) . String ( ) )
2019-02-01 00:02:17 +00:00
remotelinklocal := net . ParseIP ( remote ) . IsLinkLocalUnicast ( )
2019-01-22 21:16:41 -06:00
name := "tcp://" + sock . RemoteAddr ( ) . String ( )
2019-03-04 17:52:57 +00:00
link , err := t . link . core . link . create ( & stream , name , "tcp" , local , remote , incoming , remotelinklocal )
2019-01-21 23:08:50 -06:00
if err != nil {
2019-03-04 17:52:57 +00:00
t . link . core . log . Println ( err )
2019-01-21 23:08:50 -06:00
panic ( err )
}
2019-03-04 17:52:57 +00:00
t . link . core . log . Debugln ( "DEBUG: starting handler for" , name )
2019-01-22 21:48:43 -06:00
err = link . handler ( )
2019-03-04 17:52:57 +00:00
t . link . core . log . Debugln ( "DEBUG: stopped handler for" , name , err )
2019-01-21 23:08:50 -06:00
}