initial sources

This commit is contained in:
Joseph Henry
2016-06-14 15:48:48 -07:00
parent e073a35b72
commit 76b7e0fef7
15 changed files with 5089 additions and 0 deletions
+227
View File
@@ -0,0 +1,227 @@
ZeroTier SDK (beta)
======
The ZeroTier SDK offers a microkernel-like networking paradigm for containerized applications and application-specific virtual networking.
The SDK couples the ZeroTier core Ethernet virtualization engine with a user-space TCP/IP stack and a library that intercepts calls to the Posix network API. This allows servers and applications to be used without modification or recompilation. It can be used to run services on virtual networks without elevated privileges, special configuration of the physical host, kernel support, or any other application specific configuration. It's ideal for use with [Docker](http://http://www.docker.com), [LXC](https://linuxcontainers.org), or [Rkt](https://coreos.com/rkt/docs/latest/) to build containerized microservices that automatically connect to a virtual network when deployed. It can also be used on a plain un-containerized Linux system to run applications on virtual networks without elevated privileges or system modification.
More discussion can be found in our [original blog announcement](https://www.zerotier.com/blog/?p=490) and [the SDK product page](https://www.zerotier.com/product-netcon.shtml).
The SDK is currently in **BETA** and is suitable for testing and experimentation. Only Linux is supported. Future updates will focus on compatibility, full stack support, and improved performance, and may also port to other OSes.
# Limitations and Compatibility
The beta version of the SDK **only supports IPv4**. There is no IPv6 support and no support for ICMP (or RAW sockets). That means network-containerizing *ping* won't work.
The virtual TCP/IP stack will respond to *incoming* ICMP ECHO requests, which means that you can ping it from another host on the same ZeroTier virtual network. This is useful for testing.
## Controlling traffic
**Network Containers are currently all or nothing.** If engaged, the intercept library intercepts all network I/O calls and redirects them through the new path. A network-containerized application cannot communicate over the regular network connection of its host or container or with anything else except other hosts on its ZeroTier virtual LAN. Support for optional "fall-through" to the host IP stack for outgoing connections outside the virtual network and for gateway routes within the virtual network is planned. (It will be optional since in some cases total network isolation might be considered a nice security feature.)
#### Compatibility Test Results
The following applications have been tested and confirmed to work for the beta release:
Fedora 23:
httpstub.c
nginx 1.8.0
http 2.4.16, 2.4.17
darkhttpd 1.11
python 2.7.10 (python -m SimpleHTTPServer)
python 3.4.3 (python -m http.server)
redis 3.0.4
node 6.0.0-pre
sshd
CentOS 7:
httpstub.c
nginx 1.6.3
httpd 2.4.6 (debug mode -X)
darkhttpd 1.11
node 4.2.2
redis 2.8.19
sshd
Ubuntu 14.04.3:
httpstub.c
nginx 1.4.6
python 2.7.6 (python -m SimpleHTTPServer)
python 3.4.0 (python -m http.server)
node 5.2.0
redis 2.8.4
sshd
It is *likely* to work with other things but there are no guarantees.
# Building the SDK
The SDK works on Linux and has been lightly tested on OSX. To build the service host, IP stack, and intercept library, from the base of the ZeroTier One tree run:
make clean
make netcon
This will build a binary called *zerotier-netcon-service* and a library called *libzerotierintercept.so*. It will also build the IP stack as *netcon/liblwip.so*.
To enable debug trace statements for Network Containers, use *-D\_NETCON\_DEBUG*
The *zerotier-netcon-service* binary is almost the same as a regular ZeroTier One build except instead of creating virtual network ports using Linux's */dev/net/tun* interface, it creates instances of a user-space TCP/IP stack for each virtual network and provides RPC access to this stack via a Unix domain socket. The latter is a library that can be loaded with the Linux *LD\_PRELOAD* environment variable or by placement into */etc/ld.so.preload* on a Linux system or container. Additional magic involving nameless Unix domain socket pairs and interprocess socket handoff is used to emulate TCP sockets with extremely low overhead and in a way that's compatible with select, poll, epoll, and other I/O event mechanisms.
The intercept library does nothing unless the *ZT\_NC\_NETWORK* environment variable is set. If on program launch (or fork) it detects the presence of this environment variable, it will attempt to connect to a running *zerotier-netcon-service* at the specified Unix domain socket path.
Unlike *zerotier-one*, *zerotier-netcon-service* does not need to be run with root privileges and will not modify the host's network configuration in any way. It can be run alongside *zerotier-one* on the same host with no ill effect, though this can be confusing since you'll have to remember the difference between "real" host interfaces (tun/tap) and network containerized endpoints. The latter are completely unknown to the kernel and will not show up in *ifconfig*.
# Linking into an application on Mac OSX
Example:
gcc myapp.c -o myapp libzerotierintercept.so
export ZT_NC_NETWORK=/tmp/netcon-test-home/nc_8056c2e21c000001
Start service
./zerotier-netcon-service -d -p8000 /tmp/netcon-test-home
Run application
./myapp
# Starting the Network Containers Service
You don't need Docker or any other container engine to try Network Containers. A simple test can be performed in user space (no root) in your own home directory.
First, build the netcon service and intercept library as described above. Then create a directory to act as a temporary ZeroTier home for your test netcon service instance. You'll need to move the *liblwip.so* binary that was built with *make netcon* into there, since the service must be able to find it there and load it.
mkdir /tmp/netcon-test-home
cp -f ./netcon/liblwip.so /tmp/netcon-test-home
Now you can run the service (no sudo needed, and *-d* tells it to run in the background):
./zerotier-netcon-service -d -p8000 /tmp/netcon-test-home
As with ZeroTier One in its normal incarnation, you'll need to join a network for anything interesting to happen:
./zerotier-cli -D/tmp/netcon-test-home join 8056c2e21c000001
If you don't want to use [Earth](https://www.zerotier.com/public.shtml) for this test, replace 8056c2e21c000001 with a different network ID. The *-D* option tells *zerotier-cli* not to look in /var/lib/zerotier-one for information about a running instance of the ZeroTier system service but instead to look in */tmp/netcon-test-home*.
Now type:
./zerotier-cli -D/tmp/netcon-test-home listnetworks
Try it a few times until you see that you've successfully joined the network and have an IP address. Instead of a *zt#* device, a path to a Unix domain socket will be listed for the network's port.
Now you will want to have ZeroTier One (the normal *zerotier-one* build, not network containers) running somewhere else, such as on another Linux system or VM. Technically you could run it on the *same* Linux system and it wouldn't matter at all, but many people find this intensely confusing until they grasp just what exactly is happening here.
On the other Linux system, join the same network if you haven't already (8056c2e21c000001 if you're using Earth) and wait until you have an IP address. Then try pinging the IP address your netcon instance received. You should see ping replies.
Back on the host that's running *zerotier-netcon-service*, type *ip addr list* or *ifconfig* (ifconfig is technically deprecated so some Linux systems might not have it). Notice that the IP address of the network containers endpoint is not listed and no network device is listed for it either. That's because as far as the Linux kernel is concerned it doesn't exist.
What are you pinging? What is happening here?
The *zerotier-netcon-service* binary has joined a *virtual* network and is running a *virtual* TCP/IP stack entirely in user space. As far as your system is concerned it's just another program exchanging UDP packets with a few other hosts on the Internet and nothing out of the ordinary is happening at all. That's why you never had to type *sudo*. It didn't change anything on the host.
Now you can run an application inside your network container.
export LD_PRELOAD=`pwd`/libzerotierintercept.so
export ZT_NC_NETWORK=/tmp/netcon-test-home/nc_8056c2e21c000001
node netcon/httpserver.js
Also note that the "pwd" in LD_PRELOAD assumes you are in the ZeroTier source root and have built netcon there. If not, substitute the full path to *libzerotierintercept.so*. If you want to remove those environment variables later, use "unset LD_PRELOAD" and "unset ZT_NC_NETWORK".
If you don't have node.js installed, an alternative test using python would be:
python -m SimpleHTTPServer 80
If you are running Python 3, use "-m http.server".
If all went well a small static HTTP server is now serving up the current directory, but only inside the network container. Going to port 80 on your machine won't work. To reach it, go to the other system where you joined the same network with a conventional ZeroTier instance and try:
curl http://NETCON.INSTANCE.IP/
Replace *NETCON.INSTANCE.IP* with the IP address that *zerotier-netcon-service* was assigned on the virtual network. (This is the same IP you pinged in your first test.) If everything works, you should get back a copy of ZeroTier One's main README.md file.
# Installing in a Docker container (or any other container engine)
If it's not immediately obvious, installation into a Docker container is easy. Just install *zerotier-netcon-service*, *libzerotierintercept.so*, and *liblwip.so* into the container at an appropriate locations. We suggest putting it all in */var/lib/zerotier-one* since this is the default ZeroTier home and will eliminate the need to supply a path to any of ZeroTier's services or utilities. Then, in your Docker container entry point script launch the service with *-d* to run it in the background, set the appropriate environment variables as described above, and launch your container's main application.
The only bit of complexity is configuring which virtual network to join. ZeroTier's service automatically joins networks that have *.conf* files in *ZTHOME/networks.d* even if the *.conf* file is empty. So one way of doing this very easily is to add the following commands to your Dockerfile or container entry point script:
mkdir -p /var/lib/zerotier-one/networks.d
touch /var/lib/zerotier-one/networks.d/8056c2e21c000001.conf
Replace 8056c2e21c000001 with the network ID of the network you want your container to automatically join. It's also a good idea in your container's entry point script to add a small loop to wait until the container's instance of ZeroTier generates an identity and comes online. This could be something like:
/var/lib/zerotier-one/zerotier-netcon-service -d
while [ ! -f /var/lib/zerotier-one/identity.secret ]; do
sleep 0.1
done
# zerotier-netcon-service is now running and has generated an identity
(Be sure you don't bundle the identity into the container, otherwise every container will try to be the same device and they will "fight" over the device's address.)
Now each new instance of your container will automatically join the specified network on startup. Authorizing the container on a private network still requires a manual authorization step either via the ZeroTier Central web UI or the API. We're working on some ideas to automate this via bearer token auth or similar since doing this manually or with scripts for large deployments is tedious.
# Docker-based Unit Tests
Each unit test will temporarily copy all required ZeroTier binaries into its local directory, then build the *netcon_dockerfile* and *monitor_dockerfile*. Once built, each container will be run and perform tests and monitoring specified in *netcon_entrypoint.sh* and *monitor_entrypoint.sh*
Results will be written to the *netcon/docker-test/_results/* directory which is a common shared volume between all containers involved in the test and will be a combination of raw and formatted dumps to files whose names reflect the test performed. In the event of failure, *FAIL.* will be prepended to the result file's name (e.g. *FAIL.my_application_1.0.2.x86_64*), likewise in the event of success, *OK.* will be prepended.
To run unit tests:
1) Disable SELinux. This is so the containers can use a shared volume to exchange MD5 sums and address information.
2) Set up your own network at [https://my.zerotier.com/](https://my.zerotier.com/). For our example we'll just use the Earth network (8056c2e21c000001). Use its network id as follows:
3) Generate two pairs of identity keys. Each public/private pair will be used by the *netcon* and *monitor* containers:
mkdir -p /tmp/netcon_first
cp -f ./netcon/liblwip.so /tmp/netcon_first
./zerotier-netcon-service -d -p8100 /tmp/netcon_first
while [ ! -f /tmp/netcon_first/identity.secret ]; do
sleep 0.1
done
./zerotier-cli -D/tmp/netcon_first join 8056c2e21c000001
kill `cat /tmp/netcon_first/zerotier-one.pid`
mkdir -p /tmp/netcon_second
cp -f ./netcon/liblwip.so /tmp/netcon_second
./zerotier-netcon-service -d -p8101 /tmp/netcon_second
while [ ! -f /tmp/netcon_second/identity.secret ]; do
sleep 0.1
done
./zerotier-cli -D/tmp/netcon_second join 8056c2e21c000001
kill `cat /tmp/netcon_second/zerotier-one.pid`
4) Copy the identity files to your *docker-test* directory. Names will be altered during copy step so the dockerfiles know which identities to use for each image/container:
cp /tmp/netcon_first/identity.public ./netcon/docker-test/netcon_identity.public
cp /tmp/netcon_first/identity.secret ./netcon/docker-test/netcon_identity.secret
cp /tmp/netcon_second/identity.public ./netcon/docker-test/monitor_identity.public
cp /tmp/netcon_second/identity.secret ./netcon/docker-test/monitor_identity.secret
5) Place a blank network config file in the *netcon/docker-test* directory (e.g. "8056c2e21c000001.conf")
- This will be used to inform test-specific scripts what network to use for testing
After you've created your network and placed its blank config file in *netcon/docker-test* run the following to perform unit tests for httpd:
./build.sh httpd
./test.sh httpd
It's useful to note that the keyword *httpd* in this example is merely a substring for a test name, this means that if we replaced it with *x86_64* or *fc23*, it would run all unit tests for *x86_64* systems or *Fedora 23* respectively.
# Mobile App Embedding
API | Hookable | Proxy-able |
----------------- | ------------- | ------------ |
iOS (NSStream) | NO | YES |
iOS (BSD socket) | YES | NO |
Android (socket) | Not reliably | NO |
Android (Socket) | Not reliably | YES |
+106
View File
@@ -0,0 +1,106 @@
/*
* 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/
*/
#ifndef _ZT_SDK_H
#define _ZT_SDK_H 1
#include <sys/socket.h>
#include "SDK_Signatures.h"
#ifdef __cplusplus
extern "C" {
#endif
#define INTERCEPT_ENABLED 111
#define INTERCEPT_DISABLED 222
void zt_init_rpc(const char *nwid);
const char *get_netpath();
void zt_init_rpc(const char *nwid);
bool check_intercept_enabled_for_thread();
#if defined(__linux__)
static int (*realaccept4)(ACCEPT4_SIG) = 0;
#if !defined(__ANDROID__)
static int (*realsyscall)(SYSCALL_SIG) = 0;
#endif
#endif
#if !defined(__ANDROID__)
static int (*realbind)(BIND_SIG) = 0;
static int (*realsendmsg)(SENDMSG_SIG) = 0;
static ssize_t (*realsendto)(SENDTO_SIG) = 0;
static int (*realrecvmsg)(RECVMSG_SIG) = 0;
static int (*realrecvfrom)(RECVFROM_SIG) = 0;
#endif
static int (*realconnect)(CONNECT_SIG) = 0;
static int (*realaccept)(ACCEPT_SIG) = 0;
static int (*reallisten)(LISTEN_SIG) = 0;
static int (*realsocket)(SOCKET_SIG) = 0;
static int (*realsetsockopt)(SETSOCKOPT_SIG) = 0;
static int (*realgetsockopt)(GETSOCKOPT_SIG) = 0;
static int (*realclose)(CLOSE_SIG) = 0;
static int (*realgetsockname)(GETSOCKNAME_SIG) = 0;
ssize_t zt_sendto(SENDTO_SIG);
ssize_t zt_sendmsg(SENDMSG_SIG);
ssize_t zt_recvfrom(RECVFROM_SIG);
ssize_t zt_recvmsg(RECVMSG_SIG);
#if defined(__UNITY_3D__)
struct UnityArrayInput
{
void *array;
int len;
};
ssize_t zt_send(int fd, struct UnityArrayInput *buf, int len);
ssize_t zt_recv(int fd, struct UnityArrayInput *buf, int len);
#endif
int zt_socket(SOCKET_SIG);
int zt_connect(CONNECT_SIG);
int zt_bind(BIND_SIG);
#if defined(__linux__)
int zt_accept(ACCEPT_SIG);
#endif
int zt_accept(ACCEPT_SIG);
int zt_listen(LISTEN_SIG);
int zt_setsockopt(SETSOCKOPT_SIG);
int zt_getsockopt(GETSOCKOPT_SIG);
int zt_getsockname(GETSOCKNAME_SIG);
int zt_close(CLOSE_SIG);
#ifdef __cplusplus
}
#endif
#endif // _ZT_SDK_H
+112
View File
@@ -0,0 +1,112 @@
/*
* 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/
*/
#ifndef _COMMON_DEBUG_
#define _COMMON_DEBUG_
#include <stdio.h>
#include <netdb.h>
#include <stdarg.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/syscall.h>
#define DEBUG_LEVEL 5 // Set this to adjust what you'd like to see in the debug traces
#define MSG_TRANSFER 1 // RX/TX specific statements
#define MSG_ERROR 2 // Errors
#define MSG_INFO 3 // Information which is generally useful to any user
#define MSG_DEBUG 4 // Information which is only useful to someone debugging
#define MSG_DEBUG_EXTRA 5 // If nothing in your world makes sense
#define DEBUG_TO_FILE 1
void dwr(int level, const char *fmt, ... );
void dwr(int level, const char *fmt, ... )
{
#if defined(_SDK_DEBUG)
if(level > DEBUG_LEVEL)
return;
int saveerr;
saveerr = errno;
va_list ap;
va_start(ap, fmt);
char timestring[20];
time_t timestamp;
timestamp = time(NULL);
strftime(timestring, sizeof(timestring), "%H:%M:%S", localtime(&timestamp));
#if defined(__ANDROID__)
pid_t tid = gettid();
#elif defined(__linux__)
pid_t tid = 5;//syscall(SYS_gettid);
#elif defined(__APPLE__)
pid_t tid = pthread_mach_thread_np(pthread_self());
#endif
if(DEBUG_TO_FILE > 0) {
FILE *file = fopen("/Users/Joseph/code/ztnc_logfile.txt","a");
fprintf(file, "%s [tid=%7d] ", timestring, tid);
}
fprintf(stderr, "%s [tid=%7d] ", timestring, tid);
vfprintf(stderr, fmt, ap);
fflush(stderr);
errno = saveerr;
va_end(ap);
#endif // NETCON_DEBUG
}
#ifdef __cplusplus
extern "C" {
#endif
#if __ANDROID__
#include <jni.h>
#include <android/log.h>
#define LOG_TAG "ZTSDK"
#define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
#else
#define LOGV(...) fprintf(stdout, __VA_ARGS__)
#define LOGI(...) fprintf(stdout, __VA_ARGS__)
#define LOGD(...) fprintf(stdout, __VA_ARGS__)
#define LOGE(...) fprintf(stdout, __VA_ARGS__)
#endif
#ifdef __cplusplus
} // extern "C"
#endif
#endif
+56
View File
@@ -0,0 +1,56 @@
/*
* 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/
*/
#define DEBUG_LEVEL 5 // Set this to adjust what you'd like to see in the debug traces
#define MSG_TRANSFER 1 // RX/TX specific statements
#define MSG_ERROR 2 // Errors
#define MSG_INFO 3 // Information which is generally useful to any user
#define MSG_DEBUG 4 // Information which is only useful to someone debugging
#define MSG_DEBUG_EXTRA 5 // If nothing in your world makes sense
#ifdef __cplusplus
extern "C" {
#endif
#if __ANDROID__
#include <jni.h>
#include <android/log.h>
#define LOG_TAG "ZTSDK"
#define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
#else
#define LOGV(...) fprintf(stdout, __VA_ARGS__)
#define LOGI(...) fprintf(stdout, __VA_ARGS__)
#define LOGD(...) fprintf(stdout, __VA_ARGS__)
#define LOGE(...) fprintf(stdout, __VA_ARGS__)
#endif
#ifdef __cplusplus
} // extern "C"
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+571
View File
File diff suppressed because it is too large Load Diff
+334
View File
@@ -0,0 +1,334 @@
/*
* 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/
*/
#ifndef SDK_LWIPSTACK_H
#define SDK_LWIPSTACK_H
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/init.h"
#include "lwip/tcp_impl.h"
#include "lwip/udp.h"
#include <stdio.h>
#include <dlfcn.h>
#ifdef D_GNU_SOURCE
#define _GNU_SOURCE
#endif
typedef ip_addr ip_addr_t;
struct tcp_pcb;
// lwip General Stack API
#define PBUF_FREE_SIG struct pbuf *p
#define PBUF_ALLOC_SIG pbuf_layer layer, u16_t length, pbuf_type type
#define LWIP_HTONS_SIG u16_t x
#define LWIP_NTOHS_SIG u16_t x
#define IPADDR_NTOA_SIG const ip_addr_t *addr
#define ETHARP_OUTPUT_SIG struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr
#define ETHERNET_INPUT_SIG struct pbuf *p, struct netif *netif
#define IP_INPUT_SIG struct pbuf *p, struct netif *inp
#define NETIF_SET_DEFAULT_SIG struct netif *netif
#define NETIF_ADD_SIG struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input
#define NETIF_SET_UP_SIG struct netif *netif
#define NETIF_POLL_SIG struct netif *netif
// lwIP UDP API
#define UDP_NEW_SIG void
#define UDP_CONNECT_SIG struct udp_pcb * pcb, struct ip_addr * ipaddr, u16_t port
#define UDP_SEND_SIG struct udp_pcb * pcb, struct pbuf * p
#define UDP_SENDTO_SIG struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port
#define UDP_RECV_SIG struct udp_pcb * pcb, void (* recv)(void * arg, struct udp_pcb * upcb, struct pbuf * p, struct ip_addr * addr, u16_t port), void * recv_arg
#define UDP_RECVED_SIG struct udp_pcb * pcb, u16_t len
#define UDP_BIND_SIG struct udp_pcb * pcb, struct ip_addr * ipaddr, u16_t port
#define UDP_REMOVE_SIG struct udp_pcb *pcb
// lwIP TCP API
#define TCP_WRITE_SIG struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags
#define TCP_SENT_SIG struct tcp_pcb * pcb, err_t (* sent)(void * arg, struct tcp_pcb * tpcb, u16_t len)
#define TCP_NEW_SIG void
#define TCP_RECV_SIG struct tcp_pcb * pcb, err_t (* recv)(void * arg, struct tcp_pcb * tpcb, struct pbuf * p, err_t err)
#define TCP_RECVED_SIG struct tcp_pcb * pcb, u16_t len
#define TCP_SNDBUF_SIG struct tcp_pcb * pcb
#define TCP_CONNECT_SIG struct tcp_pcb * pcb, struct ip_addr * ipaddr, u16_t port, err_t (* connected)(void * arg, struct tcp_pcb * tpcb, err_t err)
#define TCP_RECV_SIG struct tcp_pcb * pcb, err_t (* recv)(void * arg, struct tcp_pcb * tpcb, struct pbuf * p, err_t err)
#define TCP_ERR_SIG struct tcp_pcb * pcb, void (* err)(void * arg, err_t err)
#define TCP_POLL_SIG struct tcp_pcb * pcb, err_t (* poll)(void * arg, struct tcp_pcb * tpcb), u8_t interval
#define TCP_ARG_SIG struct tcp_pcb * pcb, void * arg
#define TCP_CLOSE_SIG struct tcp_pcb * pcb
#define TCP_ABORT_SIG struct tcp_pcb * pcb
#define TCP_OUTPUT_SIG struct tcp_pcb * pcb
#define TCP_ACCEPT_SIG struct tcp_pcb * pcb, err_t (* accept)(void * arg, struct tcp_pcb * newpcb, err_t err)
#define TCP_LISTEN_SIG struct tcp_pcb * pcb
#define TCP_LISTEN_WITH_BACKLOG_SIG struct tcp_pcb * pcb, u8_t backlog
#define TCP_BIND_SIG struct tcp_pcb * pcb, struct ip_addr * ipaddr, u16_t port
#define TCP_INPUT_SIG struct pbuf *p, struct netif *inp
void dwr(int level, const char *fmt, ... );
namespace ZeroTier {
/**
* Loads an instance of liblwip.so in a private memory arena
*
* This uses dlmopen() to load an instance of the LWIP stack into its
* own private memory space. This is done to get around the stack's
* lack of thread-safety or multi-instance support. The alternative
* would be to massively refactor the stack so everything lives in a
* state object instead of static memory space.
*/
class LWIPStack
{
public:
void *_libref;
void close() {
#if defined(__STATIC__LWIP__)
return;
#elif defined(__DYNAMIC_LWIP__)
dlclose(_libref);
#endif
}
void (*_lwip_init)();
err_t (*_tcp_write)(TCP_WRITE_SIG);
void (*_tcp_sent)(TCP_SENT_SIG);
struct tcp_pcb * (*_tcp_new)(TCP_NEW_SIG);
u16_t (*_tcp_sndbuf)(TCP_SNDBUF_SIG);
err_t (*_tcp_connect)(TCP_CONNECT_SIG);
struct udp_pcb * (*_udp_new)(UDP_NEW_SIG);
err_t (*_udp_connect)(UDP_CONNECT_SIG);
err_t (*_udp_send)(UDP_SEND_SIG);
err_t (*_udp_sendto)(UDP_SENDTO_SIG);
void (*_udp_recv)(UDP_RECV_SIG);
void (*_udp_recved)(UDP_RECVED_SIG);
err_t (*_udp_bind)(UDP_BIND_SIG);
void (*_udp_remove)(UDP_REMOVE_SIG);
void (*_tcp_recv)(TCP_RECV_SIG);
void (*_tcp_recved)(TCP_RECVED_SIG);
void (*_tcp_err)(TCP_ERR_SIG);
void (*_tcp_poll)(TCP_POLL_SIG);
void (*_tcp_arg)(TCP_ARG_SIG);
err_t (*_tcp_close)(TCP_CLOSE_SIG);
void (*_tcp_abort)(TCP_ABORT_SIG);
err_t (*_tcp_output)(TCP_OUTPUT_SIG);
void (*_tcp_accept)(TCP_ACCEPT_SIG);
struct tcp_pcb * (*_tcp_listen)(TCP_LISTEN_SIG);
struct tcp_pcb * (*_tcp_listen_with_backlog)(TCP_LISTEN_WITH_BACKLOG_SIG);
err_t (*_tcp_bind)(TCP_BIND_SIG);
void (*_etharp_tmr)(void);
void (*_tcp_tmr)(void);
u8_t (*_pbuf_free)(PBUF_FREE_SIG);
struct pbuf * (*_pbuf_alloc)(PBUF_ALLOC_SIG);
u16_t (*_lwip_htons)(LWIP_HTONS_SIG);
u16_t (*_lwip_ntohs)(LWIP_NTOHS_SIG);
char* (*_ipaddr_ntoa)(IPADDR_NTOA_SIG);
err_t (*_etharp_output)(ETHARP_OUTPUT_SIG);
err_t (*_ethernet_input)(ETHERNET_INPUT_SIG);
void (*_tcp_input)(TCP_INPUT_SIG);
err_t (*_ip_input)(IP_INPUT_SIG);
void (*_netif_set_default)(NETIF_SET_DEFAULT_SIG);
struct netif * (*_netif_add)(NETIF_ADD_SIG);
void (*_netif_set_up)(NETIF_SET_UP_SIG);
void (*_netif_poll)(NETIF_POLL_SIG);
Mutex _lock;
LWIPStack(const char* path) :
_libref(NULL)
{
#if defined(__ANDROID__) || defined(__UNITY_3D__)
#define __STATIC_LWIP__
#elif defined(__linux__)
#define __DYNAMIC_LWIP__
// Dynamically load liblwip.so
_libref = dlmopen(LM_ID_NEWLM, path, RTLD_NOW);
#elif defined(__APPLE__)
#include "TargetConditionals.h"
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
#include "node/Mutex.hpp"
#define __STATIC_LWIP__
// iOS Simulator or iOS device
// Do nothing, symbols are statically-linked
#elif TARGET_OS_MAC
#define __DYNAMIC_LWIP__
// Dynamically load liblwip.so
_libref = dlopen(path, RTLD_NOW);
#else
error "Unknown Apple platform"
#endif
#endif
#ifdef __STATIC_LWIP__ // Set static references (for use in iOS)
_ethernet_input = (err_t(*)(ETHERNET_INPUT_SIG))&ethernet_input;
_etharp_output = (err_t(*)(ETHARP_OUTPUT_SIG))&etharp_output;
_lwip_init = (void(*)(void))&lwip_init;
_tcp_write = (err_t(*)(TCP_WRITE_SIG))&tcp_write;
_tcp_sent = (void(*)(TCP_SENT_SIG))&tcp_sent;
_tcp_new = (struct tcp_pcb*(*)(TCP_NEW_SIG))&tcp_new;
_udp_new = (struct udp_pcb*(*)(UDP_NEW_SIG))&udp_new;
_udp_connect = (err_t(*)(UDP_CONNECT_SIG))&udp_connect;
_udp_send = (err_t(*)(UDP_SEND_SIG))&udp_send;
_udp_sendto = (err_t(*)(UDP_SENDTO_SIG))&udp_sendto;
_udp_recv = (void(*)(UDP_RECV_SIG))&udp_recv;
_udp_bind = (err_t(*)(UDP_BIND_SIG))&udp_bind;
_udp_remove = (void(*)(UDP_REMOVE_SIG))&udp_remove;
_tcp_connect = (err_t(*)(TCP_CONNECT_SIG))&tcp_connect;
_tcp_recv = (void(*)(TCP_RECV_SIG))&tcp_recv;
_tcp_recved = (void(*)(TCP_RECVED_SIG))&tcp_recved;
_tcp_err = (void(*)(TCP_ERR_SIG))&tcp_err;
_tcp_poll = (void(*)(TCP_POLL_SIG))&tcp_poll;
_tcp_arg = (void(*)(TCP_ARG_SIG))&tcp_arg;
_tcp_close = (err_t(*)(TCP_CLOSE_SIG))&tcp_close;
_tcp_abort = (void(*)(TCP_ABORT_SIG))&tcp_abort;
_tcp_output = (err_t(*)(TCP_OUTPUT_SIG))&tcp_output;
_tcp_accept = (void(*)(TCP_ACCEPT_SIG))&tcp_accept;
_tcp_listen_with_backlog = (struct tcp_pcb*(*)(TCP_LISTEN_WITH_BACKLOG_SIG))&tcp_listen_with_backlog;
_tcp_bind = (err_t(*)(TCP_BIND_SIG))&tcp_bind;
_etharp_tmr = (void(*)(void))&etharp_tmr;
_tcp_tmr = (void(*)(void))&tcp_tmr;
_pbuf_free = (u8_t(*)(PBUF_FREE_SIG))&pbuf_free;
_pbuf_alloc = (struct pbuf*(*)(PBUF_ALLOC_SIG))&pbuf_alloc;
_lwip_htons = (u16_t(*)(LWIP_HTONS_SIG))&lwip_htons;
_lwip_ntohs = (u16_t(*)(LWIP_NTOHS_SIG))&lwip_ntohs;
_ipaddr_ntoa = (char*(*)(IPADDR_NTOA_SIG))&ipaddr_ntoa;
_tcp_input = (void(*)(TCP_INPUT_SIG))&tcp_input;
_ip_input = (err_t(*)(IP_INPUT_SIG))&ip_input;
_netif_set_default = (void(*)(NETIF_SET_DEFAULT_SIG))&netif_set_default;
_netif_add = (struct netif*(*)(NETIF_ADD_SIG))&netif_add;
_netif_set_up = (void(*)(NETIF_SET_UP_SIG))&netif_set_up;
#endif
#ifdef __DYNAMIC_LWIP__ // Use dynamically-loaded symbols (for use in normal desktop applications)
if(_libref == NULL)
printf("dlerror(): %s\n", dlerror());
_ethernet_input = (err_t(*)(ETHERNET_INPUT_SIG))dlsym(_libref, "ethernet_input");
_etharp_output = (err_t(*)(ETHARP_OUTPUT_SIG))dlsym(_libref, "etharp_output");
_lwip_init = (void(*)(void))dlsym(_libref, "lwip_init");
_tcp_write = (err_t(*)(TCP_WRITE_SIG))dlsym(_libref, "tcp_write");
_tcp_sent = (void(*)(TCP_SENT_SIG))dlsym(_libref, "tcp_sent");
_tcp_new = (struct tcp_pcb*(*)(TCP_NEW_SIG))dlsym(_libref, "tcp_new");
_udp_new = (struct udp_pcb*(*)(UDP_NEW_SIG))dlsym(_libref, "udp_new");
_udp_connect = (err_t(*)(UDP_CONNECT_SIG))dlsym(_libref, "udp_connect");
_udp_send = (err_t(*)(UDP_SEND_SIG))dlsym(_libref, "udp_send");
_udp_sendto = (err_t(*)(UDP_SENDTO_SIG))dlsym(_libref, "udp_sendto");
_udp_recv = (void(*)(UDP_RECV_SIG))dlsym(_libref, "udp_recv");
_udp_bind = (err_t(*)(UDP_BIND_SIG))dlsym(_libref, "udp_bind");
_udp_remove = (void(*)(UDP_REMOVE_SIG))dlsym(_libref, "udp_remove");
_tcp_sndbuf = (u16_t(*)(TCP_SNDBUF_SIG))dlsym(_libref, "tcp_sndbuf");
_tcp_connect = (err_t(*)(TCP_CONNECT_SIG))dlsym(_libref, "tcp_connect");
_tcp_recv = (void(*)(TCP_RECV_SIG))dlsym(_libref, "tcp_recv");
_tcp_recved = (void(*)(TCP_RECVED_SIG))dlsym(_libref, "tcp_recved");
_tcp_err = (void(*)(TCP_ERR_SIG))dlsym(_libref, "tcp_err");
_tcp_poll = (void(*)(TCP_POLL_SIG))dlsym(_libref, "tcp_poll");
_tcp_arg = (void(*)(TCP_ARG_SIG))dlsym(_libref, "tcp_arg");
_tcp_close = (err_t(*)(TCP_CLOSE_SIG))dlsym(_libref, "tcp_close");
_tcp_abort = (void(*)(TCP_ABORT_SIG))dlsym(_libref, "tcp_abort");
_tcp_output = (err_t(*)(TCP_OUTPUT_SIG))dlsym(_libref, "tcp_output");
_tcp_accept = (void(*)(TCP_ACCEPT_SIG))dlsym(_libref, "tcp_accept");
_tcp_listen = (struct tcp_pcb*(*)(TCP_LISTEN_SIG))dlsym(_libref, "tcp_listen");
_tcp_listen_with_backlog = (struct tcp_pcb*(*)(TCP_LISTEN_WITH_BACKLOG_SIG))dlsym(_libref, "tcp_listen_with_backlog");
_tcp_bind = (err_t(*)(TCP_BIND_SIG))dlsym(_libref, "tcp_bind");
_etharp_tmr = (void(*)(void))dlsym(_libref, "etharp_tmr");
_tcp_tmr = (void(*)(void))dlsym(_libref, "tcp_tmr");
_pbuf_free = (u8_t(*)(PBUF_FREE_SIG))dlsym(_libref, "pbuf_free");
_pbuf_alloc = (struct pbuf*(*)(PBUF_ALLOC_SIG))dlsym(_libref, "pbuf_alloc");
_lwip_htons = (u16_t(*)(LWIP_HTONS_SIG))dlsym(_libref, "lwip_htons");
_lwip_ntohs = (u16_t(*)(LWIP_NTOHS_SIG))dlsym(_libref, "lwip_ntohs");
_ipaddr_ntoa = (char*(*)(IPADDR_NTOA_SIG))dlsym(_libref, "ipaddr_ntoa");
_tcp_input = (void(*)(TCP_INPUT_SIG))dlsym(_libref, "tcp_input");
_ip_input = (err_t(*)(IP_INPUT_SIG))dlsym(_libref, "ip_input");
_netif_set_default = (void(*)(NETIF_SET_DEFAULT_SIG))dlsym(_libref, "netif_set_default");
_netif_add = (struct netif*(*)(NETIF_ADD_SIG))dlsym(_libref, "netif_add");
_netif_set_up = (void(*)(NETIF_SET_UP_SIG))dlsym(_libref, "netif_set_up");
#endif
}
~LWIPStack()
{
if (_libref)
dlclose(_libref);
}
inline void __lwip_init() throw() { Mutex::Lock _l(_lock); return _lwip_init(); }
inline err_t __tcp_write(TCP_WRITE_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_write(pcb,arg,len,apiflags); }
inline void __tcp_sent(TCP_SENT_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_sent(pcb,sent); }
inline struct tcp_pcb * __tcp_new(TCP_NEW_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_new(); }
inline struct udp_pcb * __udp_new(UDP_NEW_SIG) throw() { Mutex::Lock _l(_lock); return _udp_new(); }
inline err_t __udp_connect(UDP_CONNECT_SIG) throw() { Mutex::Lock _l(_lock); return _udp_connect(pcb,ipaddr,port); }
inline err_t __udp_send(UDP_SEND_SIG) throw() { Mutex::Lock _l(_lock); return _udp_send(pcb,p); }
inline err_t __udp_sendto(UDP_SENDTO_SIG) throw() { Mutex::Lock _l(_lock); return _udp_sendto(pcb,p,dst_ip,dst_port); }
inline void __udp_recv(UDP_RECV_SIG) throw() { Mutex::Lock _l(_lock); return _udp_recv(pcb,recv,recv_arg); }
inline err_t __udp_bind(UDP_BIND_SIG) throw() { Mutex::Lock _l(_lock); return _udp_bind(pcb,ipaddr,port); }
inline void __udp_remove(UDP_REMOVE_SIG) throw() { Mutex::Lock _l(_lock); return _udp_remove(pcb); }
inline u16_t __tcp_sndbuf(TCP_SNDBUF_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_sndbuf(pcb); }
inline err_t __tcp_connect(TCP_CONNECT_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_connect(pcb,ipaddr,port,connected); }
inline void __tcp_recv(TCP_RECV_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_recv(pcb,recv); }
inline void __tcp_recved(TCP_RECVED_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_recved(pcb,len); }
inline void __tcp_err(TCP_ERR_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_err(pcb,err); }
inline void __tcp_poll(TCP_POLL_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_poll(pcb,poll,interval); }
inline void __tcp_arg(TCP_ARG_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_arg(pcb,arg); }
inline err_t __tcp_close(TCP_CLOSE_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_close(pcb); }
inline void __tcp_abort(TCP_ABORT_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_abort(pcb); }
inline err_t __tcp_output(TCP_OUTPUT_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_output(pcb); }
inline void __tcp_accept(TCP_ACCEPT_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_accept(pcb,accept); }
inline struct tcp_pcb * __tcp_listen(TCP_LISTEN_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_listen(pcb); }
inline struct tcp_pcb * __tcp_listen_with_backlog(TCP_LISTEN_WITH_BACKLOG_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_listen_with_backlog(pcb,backlog); }
inline err_t __tcp_bind(TCP_BIND_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_bind(pcb,ipaddr,port); }
inline void __etharp_tmr(void) throw() { Mutex::Lock _l(_lock); return _etharp_tmr(); }
inline void __tcp_tmr(void) throw() { Mutex::Lock _l(_lock); return _tcp_tmr(); }
inline u8_t __pbuf_free(PBUF_FREE_SIG) throw() { Mutex::Lock _l(_lock); return _pbuf_free(p); }
inline struct pbuf * __pbuf_alloc(PBUF_ALLOC_SIG) throw() { Mutex::Lock _l(_lock); return _pbuf_alloc(layer,length,type); }
inline u16_t __lwip_htons(LWIP_HTONS_SIG) throw() { Mutex::Lock _l(_lock); return _lwip_htons(x); }
inline u16_t __lwip_ntohs(LWIP_NTOHS_SIG) throw() { Mutex::Lock _l(_lock); return _lwip_ntohs(x); }
inline char* __ipaddr_ntoa(IPADDR_NTOA_SIG) throw() { Mutex::Lock _l(_lock); return _ipaddr_ntoa(addr); }
inline err_t __etharp_output(ETHARP_OUTPUT_SIG) throw() { Mutex::Lock _l(_lock); return _etharp_output(netif,q,ipaddr); }
inline err_t __ethernet_input(ETHERNET_INPUT_SIG) throw() { Mutex::Lock _l(_lock); return _ethernet_input(p,netif); }
inline void __tcp_input(TCP_INPUT_SIG) throw() { Mutex::Lock _l(_lock); return _tcp_input(p,inp); }
inline err_t __ip_input(IP_INPUT_SIG) throw() { Mutex::Lock _l(_lock); return _ip_input(p,inp); }
inline void __netif_set_default(NETIF_SET_DEFAULT_SIG) throw() { Mutex::Lock _l(_lock); return _netif_set_default(netif); }
inline struct netif * __netif_add(NETIF_ADD_SIG) throw() { Mutex::Lock _l(_lock); return _netif_add(netif,ipaddr,netmask,gw,state,init,input); }
inline void __netif_set_up(NETIF_SET_UP_SIG) throw() { Mutex::Lock _l(_lock); return _netif_set_up(netif); }
};
} // namespace ZeroTier
#endif
+411
View File
@@ -0,0 +1,411 @@
/*
* 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"
#include "osdep/Phy.hpp"
#include "node/Utils.hpp"
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#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
namespace ZeroTier
{
void NetconEthernetTap::StartProxy(const char *nwid)
{
#if defined (__ANDROID__)
LOGV("StartProxy()\n");
#else
printf("StartProxy()\n");
#endif
unsigned int randp = 0;
Utils::getSecureRandom(&randp,sizeof(randp));
proxyListenPort = 1000 + (randp % 1000);
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)proxyListenPort);
proxyListenPhySocket = _phy.tcpListen((const struct sockaddr*)&in4,(void *)this);
sockstate = SOCKS_OPEN;
printf("SOCKS5 proxy server address for <%s> is: <0.0.0.0:%d> (sock=%p)\n", nwid, proxyListenPort, (void*)&proxyListenPhySocket);
}
void ExtractAddress(int addr_type, unsigned char *buf, struct sockaddr_in * addr)
{
// TODO: Generalize extraction logic
if(addr_type == 3)
{
// 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)
{
printf("phyOnTcpData(): sock=%p, len=%lu\n", (void*)&sock, len);
unsigned char *buf;
buf = (unsigned char *)data;
// Get connection for this PhySocket
Connection *conn = getConnection(sock);
if(!conn) {
printf("phyOnTcpData(): Unable to locate Connection for sock=%p\n", (void*)&sock);
return;
}
// Write data to lwIP PCB (outgoing)
if(conn->proxy_conn_state == SOCKS_COMPLETE)
{
if(len) {
printf("len=%lu\n", len);
memcpy((&conn->txbuf)+(conn->txsz), buf, len);
conn->txsz += len;
handleWrite(conn);
}
}
if(conn->proxy_conn_state==SOCKS_UDP)
{
printf("SOCKS_UDP from client\n");
// +----+------+------+----------+----------+----------+
// |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;
}
printf(" INFO <ver=%d, meth_len=%d, supp_meth=%d>\n", version, methodsLength, supportedMethod);
// 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];
printf("SOCKS REQUEST = <ver=%d, cmd=%d, typ=%d>\n", version, cmd, addr_type);
// CONNECT request
if(cmd == 1) {
// Ipv4
if(addr_type == 1)
{
//printf("IPv4\n");
int raw_addr;
memcpy(&raw_addr, &buf[4], 4);
char newaddr[16];
inet_ntop(AF_INET, &raw_addr, (char*)newaddr, INET_ADDRSTRLEN);
printf("new addr = %s\n", newaddr);
int rawport, port;
memcpy(&rawport, &buf[5], 2);
port = Utils::ntoh(rawport);
printf("new port = %d\n", port);
// Assemble new address
struct sockaddr_in addr;
addr.sin_addr.s_addr = IPADDR_ANY;
addr.sin_family = AF_INET;
addr.sin_port = Utils::hton(proxyListenPort);
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd < 0)
perror("socket");
int err = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
if(err < 0)
perror("connect");
}
// Fully-qualified domain name
if(addr_type == 3)
{
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)
printf("Error while creating proxied-socket\n");
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 |
// +----+-----+-------+------+----------+----------+
printf("REPLY = %d\n", addr.sin_port);
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)
{
printf("BIND request\n");
//char raw_addr[15];
//int bind_port;
}
// UDP ASSOCIATION Request
if(cmd == 3)
{
// PORT supplied should be port assigned by server in previous msg
printf("UDP association request\n");
// 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);
int del = addrstr.find(":");
ip = addrstr.substr(0, del);
port = addrstr.substr(del+1, domain_len);
// Create new lwIP PCB
PhySocket * new_sock = handleSocketProxy(sock, SOCK_DGRAM);
printf("new_sock = %p\n", (void*)&sock);
printf("new_sock = %p\n", (void*)&new_sock);
if(!new_sock)
printf("Error while creating proxied-socket\n");
// 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)
{
printf("phyOnTcpAccept(): sock=%p\n", (void*)&sockN);
Connection *newConn = new Connection();
newConn->sock = sockN;
_phy.setNotifyWritable(sockN, false);
_Connections.push_back(newConn);
}
void NetconEthernetTap::phyOnTcpConnect(PhySocket *sock,void **uptr,bool success)
{
printf("phyOnTcpConnect(): sock=%p\n", (void*)&sock);
}
// 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)
{
printf("phyOnDatagram(): len = %lu\n", len);
if(len) {
Connection *conn = getConnection(sock);
if(!conn){
printf("unable to locate Connection: sock=%p\n", (void*)sock);
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)
{
printf("phyOnTcpClose(): sock=%p\n", (void*)&sock);
Mutex::Lock _l(_tcpconns_m);
closeConnection(sock);
}
void NetconEthernetTap::phyOnTcpWritable(PhySocket *sock,void **uptr, bool lwip_invoked)
{
printf(" phyOnTcpWritable(): sock=%p\n", (void*)&sock);
processReceivedData(sock,uptr,lwip_invoked);
}
// 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)
{
printf("phyOnFileDescriptorActivity(): sock=%p\n", (void*&)sock);
/*
if(readable)
{
//ProxyConn *conn = (ProxyConn*)*uptr;
//if(!conn){
// printf("\t!conn");
// return;
//}
//char buf[50];
//memset(buf, 0, sizeof(buf));
//printf("Activity(R)->socket() = %d\n", _phy.getDescriptor(sock));
//printf("Activity(W)->socket() = %d\n", conn->fd);
//int n_read = read(_phy.getDescriptor(sock), buf, sizeof(buf));
//printf(" read = %d\n", n_read);
//int n_sent = write(conn->fd, buf, n_read);
//printf("buf = %s\n", buf);
//printf(" sent = %d\n", n_sent);
}
if(writable)
{
printf(" writable\n");
}
*/
}
}
+324
View File
@@ -0,0 +1,324 @@
/*
* 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/
*/
#ifdef USE_GNU_SOURCE
#define _GNU_SOURCE
#endif
#if defined(__linux__)
#include <sys/syscall.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include <sys/un.h>
#include <pthread.h>
#include <errno.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <stdint.h>
#include <sys/socket.h>
#include <strings.h>
#include "SDK.h"
#include "SDK_RPC.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SERVICE_CONNECT_ATTEMPTS 30
static int rpc_count;
static pthread_mutex_t lock;
void rpc_mutex_init() {
if(pthread_mutex_init(&lock, NULL) != 0) {
fprintf(stderr, "error while initializing service call mutex\n");
}
}
void rpc_mutex_destroy() {
pthread_mutex_destroy(&lock);
}
/*
* Reads a new file descriptor from the service
*/
int get_new_fd(int sock)
{
char buf[BUF_SZ];
int newfd;
ssize_t size = sock_fd_read(sock, buf, sizeof(buf), &newfd);
if(size > 0)
return newfd;
return -1;
}
/*
* Reads a return value from the service and sets errno (if applicable)
*/
int get_retval(int rpc_sock)
{
if(rpc_sock >= 0) {
int retval;
int sz = sizeof(char) + sizeof(retval) + sizeof(errno);
char retbuf[BUF_SZ];
memset(&retbuf, 0, sz);
long n_read = read(rpc_sock, &retbuf, sz);
if(n_read > 0) {
memcpy(&retval, &retbuf[1], sizeof(retval));
memcpy(&errno, &retbuf[1+sizeof(retval)], sizeof(errno));
return retval;
}
}
return -1;
}
int load_symbols_rpc()
{
#if defined(NETCON_INTERCEPT) || defined(__IOS__) || defined(__UNITY_3D__)
realsocket = dlsym(RTLD_NEXT, "socket");
realconnect = dlsym(RTLD_NEXT, "connect");
if(!realconnect || !realsocket)
return -1;
#endif
return 1;
}
int rpc_join(char * sockname)
{
FILE *f = fopen("/Users/Joseph/utest2/_log.txt","a");
fprintf(f, sockname);
if(sockname == NULL) {
printf("Warning, rpc netpath is NULL\n");
}
if(!load_symbols_rpc())
return -1;
struct sockaddr_un addr;
int conn_err = -1, attempts = 0;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, sockname, sizeof(addr.sun_path)-1);
int sock;
if((sock = realsocket(AF_UNIX, SOCK_STREAM, 0)) < 0){
fprintf(stderr, "Error while creating RPC socket\n");
return -1;
}
while((conn_err != 0) && (attempts < SERVICE_CONNECT_ATTEMPTS)){
if((conn_err = realconnect(sock, (struct sockaddr*)&addr, sizeof(addr))) != 0) {
fprintf(stderr, "Error while connecting to RPC socket. Re-attempting...\n");
sleep(1);
}
else
return sock;
attempts++;
}
return -1;
}
/*
* Send a command to the service
*/
int rpc_send_command(char *path, int cmd, int forfd, void *data, int len)
{
pthread_mutex_lock(&lock);
char c, padding[] = {PADDING};
char cmdbuf[BUF_SZ], CANARY[CANARY_SZ+PADDING_SZ], metabuf[BUF_SZ];
memcpy(CANARY+CANARY_SZ, padding, sizeof(padding));
uint64_t canary_num;
// ephemeral RPC socket used only for this command
int rpc_sock = rpc_join(path);
// Generate token
int fdrand = open("/dev/urandom", O_RDONLY);
if(read(fdrand, &CANARY, CANARY_SZ) < 0) {
fprintf(stderr,"unable to read from /dev/urandom for RPC canary data\n");
return -1;
}
memcpy(&canary_num, CANARY, CANARY_SZ);
cmdbuf[CMD_ID_IDX] = cmd;
memcpy(&cmdbuf[CANARY_IDX], &canary_num, CANARY_SZ);
memcpy(&cmdbuf[STRUCT_IDX], data, len);
rpc_count++;
memset(metabuf, 0, BUF_SZ);
#if defined(__linux__)
#if !defined(__ANDROID__)
pid_t pid = 5; //syscall(SYS_getpid);
pid_t tid = 4;//syscall(SYS_gettid);
#else
// Dummy values
pid_t pid = 5;
pid_t tid = gettid();
#endif
#endif
char timestring[20];
time_t timestamp;
timestamp = time(NULL);
strftime(timestring, sizeof(timestring), "%H:%M:%S", localtime(&timestamp));
#if defined(__linux__)
memcpy(&metabuf[IDX_PID], &pid, sizeof(pid_t) ); /* pid */
memcpy(&metabuf[IDX_TID], &tid, sizeof(pid_t) ); /* tid */
#endif
memcpy(&metabuf[IDX_COUNT], &rpc_count, sizeof(rpc_count) ); /* rpc_count */
memcpy(&metabuf[IDX_TIME], &timestring, 20 ); /* timestamp */
/* Combine command flag+payload with RPC metadata */
memcpy(metabuf, RPC_PHRASE, RPC_PHRASE_SZ); // Write signal phrase
memcpy(&metabuf[IDX_PAYLOAD], cmdbuf, len + 1 + CANARY_SZ);
// Write RPC
long n_write = write(rpc_sock, &metabuf, BUF_SZ);
if(n_write < 0) {
fprintf(stderr, "Error writing command to service (CMD = %d)\n", cmdbuf[CMD_ID_IDX]);
errno = 0;
}
// Write token to corresponding data stream
if(read(rpc_sock, &c, 1) < 0) {
fprintf(stderr, "unable to read RPC ACK byte from service.\n");
return -1;
}
if(c == 'z' && n_write > 0 && forfd > -1){
if(send(forfd, &CANARY, CANARY_SZ+PADDING_SZ, 0) < 0) {
perror("send: \n");
fprintf(stderr,"unable to write canary to stream (fd=%d)\n", forfd);
return -1;
}
}
// Process response from service
int ret = ERR_OK;
if(n_write > 0) {
if(cmdbuf[CMD_ID_IDX]==RPC_SOCKET) {
pthread_mutex_unlock(&lock);
return rpc_sock; // Used as new socket
}
if(cmdbuf[CMD_ID_IDX]==RPC_CONNECT
|| cmdbuf[CMD_ID_IDX]==RPC_BIND
|| cmdbuf[CMD_ID_IDX]==RPC_LISTEN) {
ret = get_retval(rpc_sock);
}
if(cmdbuf[CMD_ID_IDX]==RPC_GETSOCKNAME) {
pthread_mutex_unlock(&lock);
return rpc_sock; // Don't close rpc here, we'll use it to read getsockopt_st
}
}
else
ret = -1;
close(rpc_sock); // We're done with this RPC socket, close it (if type-R)
pthread_mutex_unlock(&lock);
return ret;
}
/*
* Send file descriptor
*/
ssize_t sock_fd_write(int sock, int fd)
{
ssize_t size;
struct msghdr msg;
struct iovec iov;
char buf = '\0';
int buflen = 1;
union {
struct cmsghdr cmsghdr;
char control[CMSG_SPACE(sizeof (int))];
} cmsgu;
struct cmsghdr *cmsg;
iov.iov_base = &buf;
iov.iov_len = buflen;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
if (fd != -1) {
msg.msg_control = cmsgu.control;
msg.msg_controllen = sizeof(cmsgu.control);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof (int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*((int *) CMSG_DATA(cmsg)) = fd;
} else {
msg.msg_control = NULL;
msg.msg_controllen = 0;
}
size = sendmsg(sock, &msg, 0);
if (size < 0)
perror ("sendmsg");
return size;
}
/*
* Read a file descriptor
*/
ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd)
{
ssize_t size;
if (fd) {
struct msghdr msg;
struct iovec iov;
union {
struct cmsghdr cmsghdr;
char control[CMSG_SPACE(sizeof (int))];
} cmsgu;
struct cmsghdr *cmsg;
iov.iov_base = buf;
iov.iov_len = bufsize;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsgu.control;
msg.msg_controllen = sizeof(cmsgu.control);
size = recvmsg (sock, &msg, 0);
if (size < 0)
return -1;
cmsg = CMSG_FIRSTHDR(&msg);
if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
if (cmsg->cmsg_level != SOL_SOCKET) {
fprintf (stderr, "invalid cmsg_level %d\n",cmsg->cmsg_level);
return -1;
}
if (cmsg->cmsg_type != SCM_RIGHTS) {
fprintf (stderr, "invalid cmsg_type %d\n",cmsg->cmsg_type);
return -1;
}
*fd = *((int *) CMSG_DATA(cmsg));
} else *fd = -1;
} else {
size = read (sock, buf, bufsize);
if (size < 0) {
fprintf(stderr, "sock_fd_read(): read: Error\n");
return -1;
}
}
return size;
}
#ifdef __cplusplus
}
#endif
+152
View File
@@ -0,0 +1,152 @@
/*
* 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/
*/
#ifndef __RPCLIB_H_
#define __RPCLIB_H_
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/un.h>
#include <pthread.h>
#include <errno.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <sys/socket.h>
#include <strings.h>
#define CANARY_SZ sizeof(uint64_t)
#define PADDING_SZ 12
#define PADDING 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
#define RPC_PHRASE "zerotier\0"
#define RPC_PHRASE_SZ 9
#define RPC_TIMESTAMP_SZ 20
// 1st RPC section (metdata)
#define IDX_SIGNAL_PHRASE 0
#define IDX_PID IDX_SIGNAL_PHRASE + RPC_PHRASE_SZ
#define IDX_TID sizeof(pid_t) + IDX_PID
#define IDX_COUNT IDX_TID + sizeof(pid_t)
#define IDX_TIME IDX_COUNT + sizeof(int)
#define IDX_PAYLOAD IDX_TIME + RPC_TIMESTAMP_SZ
// 2nd RPC section (payload and canary)
#define CMD_ID_IDX 0
#define CANARY_IDX 1
#define STRUCT_IDX CANARY_IDX+CANARY_SZ
#define BUF_SZ 512
#define ERR_OK 0
/* RPC codes */
#define RPC_UNDEFINED 0
#define RPC_CONNECT 1
#define RPC_CONNECT_SOCKARG 2
#define RPC_CLOSE 3
#define RPC_READ 4
#define RPC_WRITE 5
#define RPC_BIND 6
#define RPC_ACCEPT 7
#define RPC_LISTEN 8
#define RPC_SOCKET 9
#define RPC_SHUTDOWN 10
#define RPC_GETSOCKNAME 11
#define RPC_RETVAL 12
#define RPC_IS_CONNECTED 13
#ifdef __cplusplus
extern "C" {
#endif
int get_retval(int);
int rpc_join( char * sockname);
int rpc_send_command(char *path, int cmd, int forfd, void *data, int len);
int get_new_fd(int sock);
ssize_t sock_fd_write(int sock, int fd);
ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd);
void rpc_mutex_destroy();
void rpc_mutex_init();
/* Structures used for sending commands via RPC mechanism */
struct bind_st {
int sockfd;
struct sockaddr_storage addr;
socklen_t addrlen;
int __tid;
};
struct connect_st {
int __fd;
struct sockaddr_storage __addr;
socklen_t __len;
int __tid;
};
struct close_st {
int fd;
};
struct listen_st {
int sockfd;
int backlog;
int __tid;
};
struct socket_st {
int socket_family;
int socket_type;
int protocol;
int __tid;
};
struct accept_st {
int sockfd;
struct sockaddr_storage addr;
socklen_t addrlen;
int __tid;
};
struct shutdown_st {
int socket;
int how;
};
struct getsockname_st {
int sockfd;
struct sockaddr_storage addr;
socklen_t addrlen;
};
#ifdef __cplusplus
}
#endif
#endif
+250
View File
@@ -0,0 +1,250 @@
/*
* 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/
*/
#if defined(__ANDROID__)
#include <jni.h>
#endif
#include <dlfcn.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <pthread.h>
#include "OneService.hpp"
#include "Utils.hpp"
#include "OSUtils.hpp"
#include "SDK.h"
#include "SDK_Debug.h"
#include "SDK_ServiceSetup.hpp"
std::string service_path;
pthread_t intercept_thread;
int * intercept_thread_id;
pthread_key_t thr_id_key;
static ZeroTier::OneService *volatile zt1Service;
static std::string homeDir;
std::string netDir;
#ifdef __cplusplus
extern "C" {
#endif
void join_network(const char * nwid)
{
std::string confFile = netDir + "/" + nwid + ".conf";
if(!ZeroTier::OSUtils::mkdir(netDir)) {
LOGV("unable to create %s\n", netDir.c_str());
}
if(!ZeroTier::OSUtils::writeFile(confFile.c_str(), "")) {
LOGV("unable to write network conf file: %s\n", nwid);
}
zt1Service->join(nwid);
}
void leave_network(const char *nwid)
{
zt1Service->leave(nwid);
}
void zt_join_network(std::string nwid) {
join_network(nwid.c_str());
}
void zt_leave_network(std::string nwid) {
leave_network(nwid.c_str());
}
bool zt_is_running() {
return zt1Service->isRunning();
}
void zt_terminate() {
zt1Service->terminate();
}
#if defined(__UNITY_3D__)
// .NET Interop-friendly debug mechanism
typedef void (*FuncPtr)( const char * );
FuncPtr Debug;
void SetDebugFunction( FuncPtr fp ) { Debug = fp; }
// Starts a service at the specified path
void unity_start_service(char * path, int len) {
Debug(path);
init_service(INTERCEPT_DISABLED, path);
}
#endif
#if !defined(__ANDROID__)
/*
* Starts a service thread and performs basic setup tasks
*/
void init_service(int key, const char * path)
{
service_path = path;
pthread_key_create(&thr_id_key, NULL);
intercept_thread_id = (int*)malloc(sizeof(int));
*intercept_thread_id = key;
pthread_create(&intercept_thread, NULL, startOneService, (void *)(intercept_thread_id));
}
/*
* Enables or disables intercept for current thread using key in thread-local storage
*/
void set_intercept_status(int mode)
{
fprintf(stderr, "set_intercept_status(mode=%d): tid = %d\n", mode, pthread_mach_thread_np(pthread_self()));
pthread_key_create(&thr_id_key, NULL);
intercept_thread_id = (int*)malloc(sizeof(int));
*intercept_thread_id = mode;
pthread_setspecific(thr_id_key, intercept_thread_id);
#if !defined(__UNITY_3D__)
check_intercept_enabled_for_thread();
#endif
}
#endif
/*
* Starts a new service instance
*/
#if defined(__ANDROID__)
JNIEXPORT void JNICALL Java_Netcon_NetconWrapper_startOneService(JNIEnv *env, jobject thisObj)
{
#else
void *startOneService(void *thread_id)
{
set_intercept_status(INTERCEPT_DISABLED);
#endif
int MAX_DIR_SZ = 256;
char current_dir[MAX_DIR_SZ];
getcwd(current_dir, MAX_DIR_SZ);
chdir(service_path.c_str());
zt1Service = (ZeroTier::OneService *)0;
#if defined(__ANDROID__)
homeDir = "/sdcard/zerotier";
#endif
#if defined(__APPLE__)
#include "TargetConditionals.h"
#if TARGET_IPHONE_SIMULATOR
// homeDir = "dont/run/this/in/the/simulator";
#elif TARGET_OS_IPHONE
homeDir = "ZeroTier/One";
#endif
#endif
#if defined(__UNITY_3D__)
homeDir = "/Users/Joseph/utest2/";
#endif
netDir = homeDir + "/networks.d";
LOGV("Starting ZT service...\n");
//Debug("Starting ZT service...");
if (!homeDir.length()) {
#if defined(__ANDROID__)
return;
#else
return NULL;
#endif
} else {
std::vector<std::string> hpsp(ZeroTier::Utils::split(homeDir.c_str(),ZT_PATH_SEPARATOR_S,"",""));
std::string ptmp;
if (homeDir[0] == ZT_PATH_SEPARATOR)
ptmp.push_back(ZT_PATH_SEPARATOR);
for(std::vector<std::string>::iterator pi(hpsp.begin());pi!=hpsp.end();++pi) {
if (ptmp.length() > 0)
ptmp.push_back(ZT_PATH_SEPARATOR);
ptmp.append(*pi);
if ((*pi != ".")&&(*pi != "..")) {
if (!ZeroTier::OSUtils::mkdir(ptmp)) {
std::string homePathErrStr = "home path does not exist, and could not create";
//Debug(homePathErrStr.c_str());
throw std::runtime_error(homePathErrStr);
}
}
}
}
chdir(current_dir); // Return to previous current working directory (at the request of Unity3D)
LOGV("homeDir = %s", homeDir.c_str());
//Debug(homeDir.c_str());
// Generate random port for new service instance
unsigned int randp = 0;
ZeroTier::Utils::getSecureRandom(&randp,sizeof(randp));
int servicePort = 9000 + (randp % 1000);
for(;;) {
zt1Service = ZeroTier::OneService::newInstance(homeDir.c_str(),servicePort);
switch(zt1Service->run()) {
case ZeroTier::OneService::ONE_STILL_RUNNING: // shouldn't happen, run() won't return until done
case ZeroTier::OneService::ONE_NORMAL_TERMINATION:
break;
case ZeroTier::OneService::ONE_UNRECOVERABLE_ERROR:
//fprintf(stderr,"%s: fatal error: %s" ZT_EOL_S,argv[0],zt1Service->fatalErrorMessage().c_str());
//returnValue = 1;
break;
case ZeroTier::OneService::ONE_IDENTITY_COLLISION: {
delete zt1Service;
zt1Service = (ZeroTier::OneService *)0;
std::string oldid;
//OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),oldid);
if (oldid.length()) {
//OSUtils::writeFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret.saved_after_collision").c_str(),oldid);
//OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str());
//OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.public").c_str());
}
} continue; // restart!
}
break; // terminate loop -- normally we don't keep restarting
}
#if defined(__ANDROID__)
return;
#else
return NULL;
#endif
}
#ifdef __cplusplus
}
#endif
+59
View File
@@ -0,0 +1,59 @@
/*
* 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/
*/
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__ANDROID__)
#include <jni.h>
#endif
#ifndef ONE_SERVICE_SETUP_HPP
#define ONE_SERVICE_SETUP_HPP
#define INTERCEPT_ENABLED 111
#define INTERCEPT_DISABLED 222
#if defined(__ANDROID__)
JNIEXPORT void JNICALL Java_SDK_SDKWrapper_startOneService(JNIEnv *env, jobject thisObj);
#else
void *startOneService(void *thread_id);
void init_service(int key, const char * path);
void init_intercept(int key);
#endif
void set_intercept_status(int mode);
void join_network(const char * nwid);
void leave_network(const char * nwid);
#endif
#ifdef __cplusplus
}
#endif
+57
View File
@@ -0,0 +1,57 @@
/*
* 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/
*/
#ifndef _SIGNATURES_H
#define _SIGNATURES_H 1
#include <sys/socket.h>
#define SETSOCKOPT_SIG int socket, int level, int option_name, const void *option_value, socklen_t option_len
#define GETSOCKOPT_SIG int sockfd, int level, int optname, void *optval, socklen_t *optlen
#define SENDMSG_SIG int socket, const struct msghdr *message, int flags
#define SENDTO_SIG int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addr_len
#define RECV_SIG int socket, void *buffer, size_t length, int flags
#define RECVFROM_SIG int socket, void * buffer, size_t length, int flags, struct sockaddr * __restrict address, socklen_t * __restrict address_len
#define RECVMSG_SIG int socket, struct msghdr *message,int flags
#define SEND_SIG int socket, const void *buffer, size_t length, int flags
#define WRITE_SIG int __fd, const void *__buf, size_t __n
#define RECV_SIG int socket, void *buffer, size_t length, int flags
#define READ_SIG int __fd, void *__buf, size_t __nbytes
#define SOCKET_SIG int socket_family, int socket_type, int protocol
#define CONNECT_SIG int __fd, const struct sockaddr * __addr, socklen_t __len
#define BIND_SIG int sockfd, const struct sockaddr *addr, socklen_t addrlen
#define LISTEN_SIG int sockfd, int backlog
#define ACCEPT4_SIG int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags
#define ACCEPT_SIG int sockfd, struct sockaddr *addr, socklen_t *addrlen
#define CLOSE_SIG int fd
#define GETSOCKNAME_SIG int sockfd, struct sockaddr *addr, socklen_t *addrlen
#define SYSCALL_SIG long number, ...
#endif // _SIGNATURES_H
+540
View File
File diff suppressed because it is too large Load Diff