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"
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.
2017-12-28 22:16:20 -06:00
type tcpInterface struct {
2018-07-29 14:30:13 +00:00
core * Core
2018-12-30 15:21:09 +00:00
reconfigure chan chan error
2018-07-29 14:30:13 +00:00
serv net . Listener
2019-01-19 00:14:10 +00:00
stop chan bool
addr string
2018-07-29 14:30:13 +00:00
mutex sync . Mutex // Protecting the below
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.
func ( iface * tcpInterface ) setExtraOptions ( c net . Conn ) {
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.
2018-05-27 22:13:37 +01:00
func ( iface * tcpInterface ) getAddr ( ) * net . TCPAddr {
return iface . serv . Addr ( ) . ( * net . TCPAddr )
}
2018-06-10 18:03:28 -05:00
// Attempts to initiate a connection to the provided address.
2018-09-25 15:32:45 +01:00
func ( iface * tcpInterface ) connect ( addr string , intf string ) {
iface . 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.
2018-05-27 22:13:37 +01:00
func ( iface * tcpInterface ) connectSOCKS ( socksaddr , peeraddr string ) {
2018-09-25 15:32:45 +01:00
iface . call ( peeraddr , & socksaddr , "" )
2018-05-27 22:13:37 +01:00
}
2018-06-10 18:03:28 -05:00
// Initializes the struct.
2018-12-29 19:14:26 +00:00
func ( iface * tcpInterface ) init ( core * Core ) ( err error ) {
2018-01-04 22:37:51 +00:00
iface . core = core
2019-01-19 00:14:10 +00:00
iface . stop = make ( chan bool , 1 )
2018-12-30 15:21:09 +00:00
iface . reconfigure = make ( chan chan error , 1 )
go func ( ) {
for {
2019-01-15 08:51:19 +00:00
e := <- iface . reconfigure
iface . core . configMutex . RLock ( )
updated := iface . core . config . Listen != iface . core . configOld . Listen
iface . core . configMutex . RUnlock ( )
if updated {
2019-01-19 00:14:10 +00:00
iface . stop <- true
2019-01-15 08:51:19 +00:00
iface . serv . Close ( )
e <- iface . listen ( )
} else {
e <- nil
2018-12-30 15:21:09 +00:00
}
}
} ( )
return iface . listen ( )
}
func ( iface * tcpInterface ) listen ( ) error {
var err error
2018-12-29 19:53:31 +00:00
iface . core . configMutex . RLock ( )
2019-01-19 00:14:10 +00:00
iface . addr = iface . core . config . Listen
2018-12-29 19:53:31 +00:00
iface . core . configMutex . RUnlock ( )
2018-12-30 15:21:09 +00:00
2019-01-13 18:08:41 +00:00
ctx := context . Background ( )
lc := net . ListenConfig {
Control : iface . tcpContext ,
}
2019-01-19 00:14:10 +00:00
iface . serv , err = lc . Listen ( ctx , "tcp" , iface . addr )
2018-04-19 10:30:40 -04:00
if err == nil {
2019-01-16 13:20:12 +00:00
iface . mutex . Lock ( )
2018-04-19 10:30:40 -04:00
iface . calls = make ( map [ string ] struct { } )
iface . conns = make ( map [ tcpInfo ] ( chan struct { } ) )
2019-01-16 13:20:12 +00:00
iface . mutex . Unlock ( )
2018-04-19 10:30:40 -04:00
go iface . listener ( )
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.
2017-12-28 22:16:20 -06:00
func ( iface * tcpInterface ) listener ( ) {
2018-01-04 22:37:51 +00:00
defer iface . serv . Close ( )
2019-01-27 13:31:43 +00:00
iface . core . log . Infoln ( "Listening for TCP on:" , iface . serv . Addr ( ) . String ( ) )
2018-01-04 22:37:51 +00:00
for {
2018-04-19 10:30:40 -04:00
sock , err := iface . serv . Accept ( )
2019-01-15 08:53:57 +00:00
if err != nil {
2019-01-27 13:31:43 +00:00
iface . core . log . Errorln ( "Failed to accept connection:" , err )
2019-01-15 08:53:57 +00:00
return
}
2018-12-30 15:21:09 +00:00
select {
2019-01-19 00:14:10 +00:00
case <- iface . stop :
2019-01-27 13:31:43 +00:00
iface . core . log . Errorln ( "Stopping listener" )
2018-12-30 15:21:09 +00:00
return
default :
if err != nil {
panic ( err )
}
go iface . 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
func ( iface * tcpInterface ) isAlreadyConnected ( info tcpInfo ) bool {
iface . mutex . Lock ( )
defer iface . mutex . Unlock ( )
_ , isIn := iface . conns [ info ]
return isIn
}
// Checks if we already are calling this address
func ( iface * tcpInterface ) isAlreadyCalling ( saddr string ) bool {
iface . mutex . Lock ( )
defer iface . mutex . Unlock ( )
_ , isIn := iface . calls [ saddr ]
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.
2018-09-25 15:32:45 +01:00
func ( iface * tcpInterface ) 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-01-22 21:23:57 -06:00
if iface . isAlreadyCalling ( callname ) {
2018-06-14 09:11:34 -05:00
return
}
2019-01-16 13:20:12 +00:00
iface . mutex . Lock ( )
2018-12-30 21:11:16 +00:00
iface . calls [ callname ] = struct { } { }
2019-01-16 13:20:12 +00:00
iface . 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 )
iface . mutex . Lock ( )
delete ( iface . calls , callname )
iface . mutex . Unlock ( )
} ( )
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 {
Control : iface . tcpContext ,
}
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
}
}
2018-06-14 09:11:34 -05:00
iface . handler ( conn , false )
2018-01-04 22:37:51 +00:00
} ( )
2017-12-28 22:16:20 -06:00
}
2019-01-21 23:08:50 -06:00
func ( iface * tcpInterface ) handler ( sock net . Conn , incoming bool ) {
defer sock . Close ( )
iface . setExtraOptions ( sock )
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-02-01 00:02:17 +00:00
link , err := iface . core . link . create ( & stream , name , "tcp" , local , remote , incoming , remotelinklocal )
2019-01-21 23:08:50 -06:00
if err != nil {
iface . core . log . Println ( err )
panic ( err )
}
2019-01-27 20:54:21 +00:00
iface . core . log . Debugln ( "DEBUG: starting handler for" , name )
2019-01-22 21:48:43 -06:00
err = link . handler ( )
2019-01-27 20:54:21 +00:00
iface . core . log . Debugln ( "DEBUG: stopped handler for" , name , err )
2019-01-21 23:08:50 -06:00
}