2016-06-14 15:48:48 -07:00
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright ( C ) 2011 - 2015 ZeroTier , Inc .
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*
* - -
*
* ZeroTier may be used and distributed under the terms of the GPLv3 , which
* are available at : http : //www.gnu.org/licenses/gpl-3.0.html
*
* If you would like to embed ZeroTier into a commercial application or
* redistribute it in a modified binary form , please contact ZeroTier Networks
* LLC . Start here : http : //www.zerotier.com/
*/
# include "SDK_Debug.h"
# include "SDK_EthernetTap.hpp"
2016-06-22 14:07:28 -07:00
# include "Phy.hpp"
# include "Utils.hpp"
2016-07-18 01:42:18 -07:00
# include "OSUtils.hpp"
2016-06-14 15:48:48 -07:00
# include <string.h>
# include <arpa/inet.h>
# include <sys/socket.h>
2016-07-18 01:42:18 -07:00
# include <sstream>
2016-06-14 15:48:48 -07:00
# define SOCKS_OPEN 0
# define SOCKS_CONNECT_INIT 1
# define SOCKS_CONNECT_IPV4 2
# define SOCKS_UDP 3 // ?
# define SOCKS_COMPLETE 4
# define CONNECTION_TIMEOUT 8
# define IDX_VERSION 0
# define IDX_COMMAND 1
# define IDX_METHOD 1
# define IDX_FRAG 1
# define IDX_ERROR_CODE 1
# define IDX_NMETHODS 1
# define IDX_METHODS 2 // Supported methods
# define IDX_ATYP 3
# define IDX_DST_ADDR 4 // L:D where L = addrlen, D = addr
# define IDX_
# define THIS_PROXY_VERSION 5
# define MAX_ADDR_LEN 32
# define PORT_LEN 2
2016-08-04 13:10:12 -07:00
void dwr ( int level , const char * fmt , . . . ) ;
2016-06-14 15:48:48 -07:00
namespace ZeroTier
{
2016-08-17 12:41:59 -07:00
int NetconEthernetTap : : getProxyServerAddress ( struct sockaddr_storage * addr ) {
if ( sockstate > = 0 ) {
addr = & proxyServerAddress ;
return 0 ;
2016-07-18 01:42:18 -07:00
}
2016-08-17 12:41:59 -07:00
return - 1 ;
}
int NetconEthernetTap : : getProxyServerPort ( ) {
struct sockaddr_in * in4 ;
in4 = ( struct sockaddr_in * ) & proxyServerAddress ;
return in4 - > sin_port ;
}
int NetconEthernetTap : : stopProxyServer ( )
{
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( ) ;
2016-08-17 12:41:59 -07:00
if ( proxyListenPhySocket ) {
_phy . close ( proxyListenPhySocket ) ;
return 0 ;
2016-07-18 01:42:18 -07:00
}
2016-09-16 11:25:52 -07:00
DEBUG_ERROR ( " invalid proxyListenPhySocket " ) ;
2016-08-17 12:41:59 -07:00
return - 1 ;
}
2016-07-18 01:42:18 -07:00
2016-08-17 12:41:59 -07:00
int NetconEthernetTap : : startProxyServer ( const char * homepath , uint64_t nwid , struct sockaddr_storage * addr )
{
// Address of proxy server is determined in the following order:
// - Provided address in param: addr
// - If no address, assume 127.0.0.1:<networks.d/nwid.port>
// - If no port assignment file, 127.0.0.1:RANDOM_PORT
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( ) ;
2016-08-17 12:41:59 -07:00
int portno = - 1 ;
if ( addr ) {
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " using provided address " ) ;
2016-08-17 12:41:59 -07:00
// This address pointer may come from a different memory space and might be de-allocated, so we keep a copy
memcpy ( & proxyServerAddress , addr , sizeof ( struct sockaddr_storage ) ) ;
struct sockaddr_in * in4 = ( struct sockaddr_in * ) & addr ;
proxyListenPhySocket = _phy . tcpListen ( ( const struct sockaddr * ) & in4 , ( void * ) this ) ;
sockstate = SOCKS_OPEN ;
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " SOCKS5 proxy server address for <%.16lx> is: <%s> (sock=%p) " , nwid , inet_ntoa ( in4 - > sin_addr ) , /*ntohs(in4->sin_port), */ ( void * ) & proxyListenPhySocket ) ;
2016-08-17 12:41:59 -07:00
return 0 ;
}
else {
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " no address provided. Checking port file. " ) ;
2016-08-17 12:41:59 -07:00
// Look for a port file for this network's proxy server instance
char portFile [ 4096 ] ;
Utils : : snprintf ( portFile , sizeof ( portFile ) , " %s/networks.d/%.16llx.port " , homepath , nwid ) ;
std : : string portStr ;
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " reading port from: %s \n " , portFile ) ;
2016-08-17 12:41:59 -07:00
if ( ZeroTier : : OSUtils : : fileExists ( portFile , true ) )
{
if ( ZeroTier : : OSUtils : : readFile ( portFile , portStr ) ) {
portno = atoi ( portStr . c_str ( ) ) ;
}
}
else {
unsigned int randp = 0 ;
Utils : : getSecureRandom ( & randp , sizeof ( randp ) ) ;
portno = 1000 + ( randp % 1000 ) ;
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " no port specified in networks.d/%.16lx.port, randomly picking port " , nwid ) ;
2016-08-17 12:41:59 -07:00
std : : stringstream ss ;
ss < < portno ;
portStr = ss . str ( ) ;
if ( ! ZeroTier : : OSUtils : : writeFile ( portFile , portStr ) ) {
2016-09-16 11:25:52 -07:00
DEBUG_ERROR ( " unable to write proxy port file: %s " , portFile ) ;
2016-08-17 12:41:59 -07:00
}
}
struct sockaddr_in in4 ;
memset ( & in4 , 0 , sizeof ( in4 ) ) ;
in4 . sin_family = AF_INET ;
in4 . sin_addr . s_addr = Utils : : hton ( ( uint32_t ) 0x00000000 ) ; // right now we just listen for TCP @0.0.0.0
in4 . sin_port = Utils : : hton ( ( uint16_t ) portno ) ;
proxyListenPhySocket = _phy . tcpListen ( ( const struct sockaddr * ) & in4 , ( void * ) this ) ;
sockstate = SOCKS_OPEN ;
2016-09-06 15:07:06 -07:00
//DEBUG_INFO("SOCKS5 proxy server address for <%.16llx> is: <%s:%d> (sock=%p)\n", nwid, , portno, (void*)&proxyListenPhySocket);
2016-08-17 12:41:59 -07:00
}
return 0 ;
2016-06-14 15:48:48 -07:00
}
void ExtractAddress ( int addr_type , unsigned char * buf , struct sockaddr_in * addr )
{
// TODO: Generalize extraction logic
2016-08-11 23:34:40 -07:00
if ( addr_type = = 144 )
2016-06-14 15:48:48 -07:00
{
// Extract address from buffer
int domain_len = buf [ IDX_DST_ADDR ] ; // (L):D
char addr_ [ MAX_ADDR_LEN ] ;
int port_ = 0 ;
memset ( addr_ , 0 , MAX_ADDR_LEN ) ;
memcpy ( addr_ , & buf [ IDX_DST_ADDR + 1 ] , domain_len ) ; // L:(D)
memcpy ( & port_ , & buf [ IDX_DST_ADDR + 1 ] + ( domain_len ) , PORT_LEN ) ;
port_ = Utils : : hton ( ( uint16_t ) port_ ) ;
std : : string addr_str ( addr_ ) ;
// Format address for Netcon/lwIP
addr - > sin_family = AF_INET ;
addr - > sin_port = port_ ;
addr - > sin_addr . s_addr = inet_addr ( addr_str . c_str ( ) ) ;
}
}
void NetconEthernetTap : : phyOnTcpData ( PhySocket * sock , void * * uptr , void * data , unsigned long len )
{
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " sock=%p, len=%lu " , ( void * ) & sock , len ) ;
2016-06-14 15:48:48 -07:00
unsigned char * buf ;
buf = ( unsigned char * ) data ;
// Get connection for this PhySocket
Connection * conn = getConnection ( sock ) ;
if ( ! conn ) {
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " unable to locate Connection for sock=%p " , ( void * ) & sock ) ;
2016-06-14 15:48:48 -07:00
return ;
}
// Write data to lwIP PCB (outgoing)
if ( conn - > proxy_conn_state = = SOCKS_COMPLETE )
{
if ( len ) {
2016-09-06 15:07:06 -07:00
DEBUG_INFO ( " len=%lu \n " , len ) ;
2016-06-14 15:48:48 -07:00
memcpy ( ( & conn - > txbuf ) + ( conn - > txsz ) , buf , len ) ;
conn - > txsz + = len ;
handleWrite ( conn ) ;
}
}
if ( conn - > proxy_conn_state = = SOCKS_UDP )
{
2016-09-06 15:07:06 -07:00
DEBUG_INFO ( " SOCKS_UDP from client \n " ) ;
2016-06-14 15:48:48 -07:00
// +----+------+------+----------+----------+----------+
// |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
// +----+------+------+----------+----------+----------+
// | 2 | 1 | 1 | Variable | 2 | Variable |
// +----+------+------+----------+----------+----------+
//int fragment_num = buf[2];
//int addr_type = buf[3];
}
// SOCKS_OPEN
// +----+----------+----------+
// |VER | NMETHODS | METHODS |
// +----+----------+----------+
// | 1 | 1 | 1 to 255 |
// +----+----------+----------+
if ( conn - > proxy_conn_state = = SOCKS_OPEN )
{
if ( len > = 3 )
{
int version = buf [ IDX_VERSION ] ;
int methodsLength = buf [ IDX_NMETHODS ] ;
int firstSupportedMethod = buf [ IDX_METHODS ] ;
int supportedMethod = 0 ;
// Password auth
if ( firstSupportedMethod = = 2 ) {
supportedMethod = firstSupportedMethod ;
}
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " INFO <ver=%d, meth_len=%d, supp_meth=%d> " , version , methodsLength , supportedMethod ) ;
2016-06-14 15:48:48 -07:00
// Send METHOD selection msg
// +----+--------+
// |VER | METHOD |
// +----+--------+
// | 1 | 1 |
// +----+--------+
char reply [ 2 ] ;
reply [ IDX_VERSION ] = THIS_PROXY_VERSION ; // version
reply [ IDX_METHOD ] = supportedMethod ;
_phy . streamSend ( sock , reply , sizeof ( reply ) ) ;
// Set state for next message
conn - > proxy_conn_state = SOCKS_CONNECT_INIT ;
}
}
// SOCKS_CONNECT
// +----+-----+-------+------+----------+----------+
// |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
// +----+-----+-------+------+----------+----------+
// | 1 | 1 | X'00' | 1 | Variable | 2 |
// +----+-----+-------+------+----------+----------+
if ( conn - > proxy_conn_state = = SOCKS_CONNECT_INIT )
{
// Ex. 4(meta) + 4(ipv4) + 2(port) = 10
if ( len > = 10 )
{
int version = buf [ IDX_VERSION ] ;
int cmd = buf [ IDX_COMMAND ] ;
int addr_type = buf [ IDX_ATYP ] ;
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " SOCKS REQUEST = <ver=%d, cmd=%d, typ=%d> " , version , cmd , addr_type ) ;
2016-06-14 15:48:48 -07:00
// CONNECT request
if ( cmd = = 1 ) {
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " CONNECT request " ) ;
2016-06-14 15:48:48 -07:00
// Ipv4
2016-08-11 23:34:40 -07:00
/*
if ( addr_type = = 144 )
2016-06-14 15:48:48 -07:00
{
2016-09-16 11:25:52 -07:00
//DEBUG_INFO("IPv4\n");
2016-06-14 15:48:48 -07:00
int raw_addr ;
memcpy ( & raw_addr , & buf [ 4 ] , 4 ) ;
char newaddr [ 16 ] ;
inet_ntop ( AF_INET , & raw_addr , ( char * ) newaddr , INET_ADDRSTRLEN ) ;
2016-09-06 15:07:06 -07:00
DEBUG_INFO ( " new addr = %s \n " , newaddr ) ;
2016-06-14 15:48:48 -07:00
int rawport , port ;
memcpy ( & rawport , & buf [ 5 ] , 2 ) ;
port = Utils : : ntoh ( rawport ) ;
2016-09-06 15:07:06 -07:00
DEBUG_INFO ( " new port = %d \n " , port ) ;
2016-06-14 15:48:48 -07:00
// Assemble new address
struct sockaddr_in addr ;
addr . sin_addr . s_addr = IPADDR_ANY ;
addr . sin_family = AF_INET ;
2016-08-11 23:34:40 -07:00
addr . sin_port = Utils : : hton ( 8080 ) ;
2016-06-14 15:48:48 -07:00
int fd = socket ( AF_INET , SOCK_STREAM , 0 ) ;
2016-09-06 15:07:06 -07:00
DEBUG_INFO ( " fd = %d \n " , fd ) ;
2016-06-14 15:48:48 -07:00
if ( fd < 0 )
perror ( " socket " ) ;
int err = connect ( fd , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
2016-09-06 15:07:06 -07:00
DEBUG_INFO ( " connect_err = %d \n " , err ) ;
2016-06-14 15:48:48 -07:00
if ( err < 0 )
perror ( " connect " ) ;
}
2016-08-11 23:34:40 -07:00
*/
2016-06-14 15:48:48 -07:00
// Fully-qualified domain name
2016-08-11 23:34:40 -07:00
if ( addr_type = = 144 )
2016-06-14 15:48:48 -07:00
{
int domain_len = buf [ IDX_DST_ADDR ] ; // (L):D
struct sockaddr_in addr ;
ExtractAddress ( addr_type , buf , & addr ) ;
PhySocket * new_sock = handleSocketProxy ( sock , SOCK_STREAM ) ;
if ( ! new_sock )
2016-09-16 11:25:52 -07:00
DEBUG_ERROR ( " error while creating proxied-socket " ) ;
2016-06-14 15:48:48 -07:00
handleConnectProxy ( sock , & addr ) ;
// Convert connection err code into SOCKS-err-code
// X'00' succeeded
// X'01' general SOCKS server failure
// X'02' connection not allowed by ruleset
// X'03' Network unreachable
// X'04' Host unreachable
// X'05' Connection refused
// X'06' TTL expired
// X'07' Command not supported
// X'08' Address type not supported
// X'09' to X'FF' unassigned
// SOCKS_CONNECT_REPLY
// +----+-----+-------+------+----------+----------+
// |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
// +----+-----+-------+------+----------+----------+
// | 1 | 1 | X'00' | 1 | Variable | 2 |
// +----+-----+-------+------+----------+----------+
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " REPLY = %d " , addr . sin_port ) ;
2016-06-14 15:48:48 -07:00
char reply [ len ] ; // TODO: determine proper length
int addr_len = domain_len ;
memset ( reply , 0 , len ) ; // Create reply buffer at least as big as incoming SOCKS request data
memcpy ( & reply [ IDX_DST_ADDR ] , & buf [ IDX_DST_ADDR ] , domain_len ) ;
reply [ IDX_VERSION ] = THIS_PROXY_VERSION ; // version
reply [ IDX_ERROR_CODE ] = 0 ; // success/err code
reply [ 2 ] = 0 ; // RSV
reply [ IDX_ATYP ] = addr_type ; // ATYP (1, 3, 4)
reply [ IDX_DST_ADDR ] = addr_len ;
memcpy ( & reply [ IDX_DST_ADDR + domain_len ] , & addr . sin_port , PORT_LEN ) ; // PORT
_phy . streamSend ( sock , reply , sizeof ( reply ) ) ;
// Any further data activity on this PhySocket will be considered data to send
conn - > proxy_conn_state = SOCKS_COMPLETE ;
}
// END CONNECT
}
// BIND Request
if ( cmd = = 2 )
{
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " BIND request " ) ;
2016-06-14 15:48:48 -07:00
//char raw_addr[15];
//int bind_port;
}
// UDP ASSOCIATION Request
if ( cmd = = 3 )
{
// PORT supplied should be port assigned by server in previous msg
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " UDP association request " ) ;
2016-06-14 15:48:48 -07:00
// SOCKS_CONNECT (Cont.)
// +----+-----+-------+------+----------+----------+
// |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
// +----+-----+-------+------+----------+----------+
// | 1 | 1 | X'00' | 1 | Variable | 2 |
// +----+-----+-------+------+----------+----------+
// NOTE: Similar to cmd==1, should consolidate logic
// NOTE: Can't separate out port with method used in IPv4 block
int domain_len = buf [ 4 ] ;
// Grab Addr:Port
char raw_addr [ domain_len ] ;
memset ( raw_addr , 0 , domain_len ) ;
memcpy ( raw_addr , & buf [ 5 ] , domain_len ) ;
std : : string ip , port , addrstr ( raw_addr ) ;
2016-08-04 13:10:12 -07:00
ssize_t del = addrstr . find ( " : " ) ;
2016-06-14 15:48:48 -07:00
ip = addrstr . substr ( 0 , del ) ;
port = addrstr . substr ( del + 1 , domain_len ) ;
// Create new lwIP PCB
PhySocket * new_sock = handleSocketProxy ( sock , SOCK_DGRAM ) ;
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " sock = %p " , ( void * ) & sock ) ;
DEBUG_INFO ( " new_sock = %p " , ( void * ) & new_sock ) ;
2016-06-14 15:48:48 -07:00
if ( ! new_sock )
2016-09-16 11:25:52 -07:00
DEBUG_ERROR ( " error while creating proxied-socket " ) ;
2016-06-14 15:48:48 -07:00
// Form address
struct sockaddr_in addr ;
memset ( & addr , ' 0 ' , sizeof ( addr ) ) ;
addr . sin_family = AF_INET ;
addr . sin_port = Utils : : hton ( ( uint16_t ) atoi ( port . c_str ( ) ) ) ;
addr . sin_addr . s_addr = inet_addr ( ip . c_str ( ) ) ;
//addr.sin_addr.s_addr = inet_addr("10.5.5.2");
handleConnectProxy ( sock , & addr ) ;
conn - > proxy_conn_state = SOCKS_UDP ;
}
//if(addr_type == 1337)
//{
// // IPv6
//}
}
}
}
void NetconEthernetTap : : phyOnTcpAccept ( PhySocket * sockL , PhySocket * sockN , void * * uptrL , void * * uptrN , const struct sockaddr * from )
{
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " sock=%p " , ( void * ) & sockN ) ;
2016-06-14 15:48:48 -07:00
Connection * newConn = new Connection ( ) ;
newConn - > sock = sockN ;
_phy . setNotifyWritable ( sockN , false ) ;
_Connections . push_back ( newConn ) ;
}
void NetconEthernetTap : : phyOnTcpConnect ( PhySocket * sock , void * * uptr , bool success )
{
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " sock=%p " , ( void * ) & sock ) ;
2016-06-14 15:48:48 -07:00
}
// Unused -- no UDP or TCP from this thread/Phy<>
void NetconEthernetTap : : phyOnDatagram ( PhySocket * sock , void * * uptr , const struct sockaddr * local_address , const struct sockaddr * from , void * data , unsigned long len )
{
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " len = %lu " , len ) ;
2016-06-14 15:48:48 -07:00
if ( len ) {
Connection * conn = getConnection ( sock ) ;
if ( ! conn ) {
2016-09-16 11:25:52 -07:00
DEBUG_ERROR ( " unable to locate Connection: sock=%p " , ( void * ) sock ) ;
2016-06-14 15:48:48 -07:00
return ;
}
unsigned char * buf = ( unsigned char * ) data ;
memcpy ( ( & conn - > txbuf ) + ( conn - > txsz ) , buf , len ) ;
conn - > txsz + = len ;
handleWrite ( conn ) ;
}
}
void NetconEthernetTap : : phyOnTcpClose ( PhySocket * sock , void * * uptr )
{
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " sock=%p " , ( void * ) & sock ) ;
2016-06-14 15:48:48 -07:00
Mutex : : Lock _l ( _tcpconns_m ) ;
closeConnection ( sock ) ;
}
2016-09-28 16:46:30 -07:00
void NetconEthernetTap : : phyOnTcpWritable ( PhySocket * sock , void * * uptr /*, bool lwip_invoked*/ )
2016-06-14 15:48:48 -07:00
{
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " sock=%p " , ( void * ) & sock ) ;
2016-09-28 16:46:30 -07:00
processReceivedData ( sock , uptr , true ) ;
2016-06-14 15:48:48 -07:00
}
// RX data on stream socks and send back over client sock's underlying fd
void NetconEthernetTap : : phyOnFileDescriptorActivity ( PhySocket * sock , void * * uptr , bool readable , bool writable )
{
2016-09-16 11:25:52 -07:00
DEBUG_INFO ( " sock=%p " , ( void * & ) sock ) ;
2016-06-14 15:48:48 -07:00
}
}