mirror of
https://github.com/zerotier/libzt.git
synced 2026-09-22 15:29:08 -07:00
initial sources
This commit is contained in:
+227
@@ -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 |
|
||||
@@ -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
@@ -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(×tamp));
|
||||
#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
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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))ðernet_input;
|
||||
_etharp_output = (err_t(*)(ETHARP_OUTPUT_SIG))ðarp_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))ðarp_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
|
||||
@@ -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
@@ -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(×tamp));
|
||||
#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], ×tring, 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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user