diff --git a/.gitignore b/.gitignore index 427d11d..663a056 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ zt3 zt4 zt5 zt6 +objs *.bob *.alice diff --git a/Jenkinsfile b/Jenkinsfile index 8c5be08..d2f9b7f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -16,7 +16,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('linux static lib, no stack') { - sh 'make static_lib NO_STACK=1; make tests' + sh 'make clean; make static_lib NO_STACK=1; make tests' } } catch (err) { @@ -30,7 +30,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('linux static lib, no stack, ipv4') { - sh 'make static_lib NO_STACK=1 LIBZT_IPV4=1; make tests' + sh 'make clean; make static_lib NO_STACK=1 LIBZT_IPV4=1; make tests' } } catch (err) { @@ -44,7 +44,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('linux static lib, no stack, ipv6') { - sh 'make static_lib NO_STACK=1 LIBZT_IPV6=1; make tests' + sh 'make clean; make static_lib NO_STACK=1 LIBZT_IPV6=1; make tests' } } catch (err) { @@ -58,7 +58,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('linux static lib, no stack, ipv4, ipv6') { - sh 'make static_lib NO_STACK=1 LIBZT_IPV4=1 LIBZT_IPV6=1; make tests' + sh 'make clean; make static_lib NO_STACK=1 LIBZT_IPV4=1 LIBZT_IPV6=1; make tests' } } catch (err) { @@ -74,7 +74,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('linux static lib, picoTCP') { - sh 'make static_lib STACK_PICO=1; make tests' + sh 'make clean; make static_lib STACK_PICO=1; make tests' } } catch (err) { @@ -88,7 +88,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('linux static lib, picoTCP, ipv4') { - sh 'make static_lib STACK_PICO=1 LIBZT_IPV4=1; make tests' + sh 'make clean; make static_lib STACK_PICO=1 LIBZT_IPV4=1; make tests' } } catch (err) { @@ -102,7 +102,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('linux static lib, picoTCP, ipv6') { - sh 'make static_lib STACK_PICO=1 LIBZT_IPV6=1; make tests' + sh 'make clean; make static_lib STACK_PICO=1 LIBZT_IPV6=1; make tests' } } catch (err) { @@ -116,7 +116,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('linux static lib, picoTCP, ipv4, ipv6') { - sh 'make static_lib STACK_PICO=1 LIBZT_IPV4=1 LIBZT_IPV6=1; make tests' + sh 'make clean; make static_lib STACK_PICO=1 LIBZT_IPV4=1 LIBZT_IPV6=1; make tests' } } catch (err) { @@ -133,7 +133,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('linux static lib lwIP') { - sh 'make static_lib STACK_LWIP=1; make tests' + sh 'make clean; make static_lib STACK_LWIP=1; make tests' } } catch (err) { @@ -148,7 +148,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('linux static lib lwIP, ipv4') { - sh 'make static_lib STACK_LWIP=1 LIBZT_IPV4=1; make tests' + sh 'make clean; make static_lib STACK_LWIP=1 LIBZT_IPV4=1; make tests' } } catch (err) { @@ -163,7 +163,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('linux static lib lwIP, ipv6') { - sh 'make static_lib STACK_LWIP=1 LIBZT_IPV6=1; make tests' + sh 'make clean; make static_lib STACK_LWIP=1 LIBZT_IPV6=1; make tests' } } catch (err) { @@ -178,7 +178,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('linux static lib lwIP, ipv4, ipv6') { - sh 'make static_lib STACK_LWIP=1 LIBZT_IPV4=1 LIBZT_IPV6=1; make tests' + sh 'make clean; make clean; make static_lib STACK_LWIP=1 LIBZT_IPV4=1 LIBZT_IPV6=1; make tests' } } catch (err) { @@ -214,7 +214,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('macOS static lib, no stack') { - sh 'make static_lib NO_STACK=1; make tests' + sh 'make clean; make static_lib NO_STACK=1; make tests' } } catch (err) { @@ -228,7 +228,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('macOS static lib, no stack, ipv4') { - sh 'make static_lib NO_STACK=1 LIBZT_IPV4=1; make tests' + sh 'make clean; make static_lib NO_STACK=1 LIBZT_IPV4=1; make tests' } } catch (err) { @@ -242,7 +242,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('macOS static lib, no stack, ipv6') { - sh 'make static_lib NO_STACK=1 LIBZT_IPV6=1'; make tests + sh 'make clean; make static_lib NO_STACK=1 LIBZT_IPV6=1'; make tests } } catch (err) { @@ -256,7 +256,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('macOS static lib, no stack, ipv4, ipv6') { - sh 'make static_lib NO_STACK=1 LIBZT_IPV4=1 LIBZT_IPV6=1; make tests' + sh 'make clean; make static_lib NO_STACK=1 LIBZT_IPV4=1 LIBZT_IPV6=1; make tests' } } catch (err) { @@ -271,7 +271,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('macOS static lib, picoTCP') { - sh 'make static_lib STACK_PICO=1; make tests' + sh 'make clean; make static_lib STACK_PICO=1; make tests' } } catch (err) { @@ -285,7 +285,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('macOS static lib, picoTCP, ipv4') { - sh 'make static_lib STACK_PICO=1 LIBZT_IPV4=1; make tests' + sh 'make clean; make static_lib STACK_PICO=1 LIBZT_IPV4=1; make tests' } } catch (err) { @@ -299,7 +299,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('macOS static lib, picoTCP, ipv6') { - sh 'make static_lib STACK_PICO=1 LIBZT_IPV6=1; make tests' + sh 'make clean; make static_lib STACK_PICO=1 LIBZT_IPV6=1; make tests' } } catch (err) { @@ -313,7 +313,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('macOS static lib, picoTCP, ipv4, ipv6') { - sh 'make static_lib STACK_PICO=1 LIBZT_IPV4=1 LIBZT_IPV6=1'; make tests + sh 'make clean; make static_lib STACK_PICO=1 LIBZT_IPV4=1 LIBZT_IPV6=1'; make tests } } catch (err) { @@ -330,7 +330,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('macOS static lib, lwIP') { - sh 'make static_lib STACK_LWIP=1; make tests' + sh 'make clean; make static_lib STACK_LWIP=1; make tests' } } catch (err) { @@ -344,7 +344,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('macOS static lib, lwIP, ipv4') { - sh 'make static_lib STACK_LWIP=1 LIBZT_IPV4=1; make tests' + sh 'make clean; make static_lib STACK_LWIP=1 LIBZT_IPV4=1; make tests' } } catch (err) { @@ -358,7 +358,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('macOS static lib, lwIP, ipv6') { - sh 'make static_lib STACK_LWIP=1 LIBZT_IPV6=1; make tests' + sh 'make clean; make static_lib STACK_LWIP=1 LIBZT_IPV6=1; make tests' } } catch (err) { @@ -372,7 +372,7 @@ parallel 'centos7': { checkout scm sh 'git submodule update --init' stage('macOS static lib, lwIP, ipv4, ipv6') { - sh 'make static_lib STACK_LWIP=1 LIBZT_IPV4=1 LIBZT_IPV6=1; make tests' + sh 'make clean; make static_lib STACK_LWIP=1 LIBZT_IPV4=1 LIBZT_IPV6=1; make tests' } } catch (err) { diff --git a/ext/picotcp/modules/pico_ipv4.c b/ext/picotcp/modules/pico_ipv4.c index 2dbfe23..de870ff 100644 --- a/ext/picotcp/modules/pico_ipv4.c +++ b/ext/picotcp/modules/pico_ipv4.c @@ -1159,7 +1159,7 @@ static int pico_ipv4_frame_sock_push(struct pico_protocol *self, struct pico_fra } -int MOCKABLE pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link) +extern int MOCKABLE pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link) { struct pico_ipv4_route test, *new; test.dest.addr = address.addr; diff --git a/ext/picotcp/modules/pico_ipv4.h b/ext/picotcp/modules/pico_ipv4.h index 4c98722..9a71c3f 100644 --- a/ext/picotcp/modules/pico_ipv4.h +++ b/ext/picotcp/modules/pico_ipv4.h @@ -94,6 +94,10 @@ extern "C" { #endif int pico_ipv4_link_add(struct pico_device *dev, struct pico_ip4 address, struct pico_ip4 netmask); int pico_string_to_ipv4(const char *ipstr, uint32_t *ip); +int pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link); +int pico_ipv4_route_del(struct pico_ip4 address, struct pico_ip4 netmask, int metric); +struct pico_ip4 pico_ipv4_route_get_gateway(struct pico_ip4 *addr); +void pico_ipv4_route_set_bcast_link(struct pico_ipv4_link *link); #ifdef __cplusplus } #endif @@ -108,10 +112,6 @@ struct pico_ipv4_link *pico_ipv4_link_by_dev_next(struct pico_device *dev, struc struct pico_device *pico_ipv4_link_find(struct pico_ip4 *address); struct pico_ip4 *pico_ipv4_source_find(const struct pico_ip4 *dst); struct pico_device *pico_ipv4_source_dev_find(const struct pico_ip4 *dst); -int pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link); -int pico_ipv4_route_del(struct pico_ip4 address, struct pico_ip4 netmask, int metric); -struct pico_ip4 pico_ipv4_route_get_gateway(struct pico_ip4 *addr); -void pico_ipv4_route_set_bcast_link(struct pico_ipv4_link *link); void pico_ipv4_unreachable(struct pico_frame *f, int err); int pico_ipv4_mcast_join(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter); diff --git a/include/libzt.h b/include/libzt.h index 742ea84..9558ec6 100644 --- a/include/libzt.h +++ b/include/libzt.h @@ -32,6 +32,11 @@ #include #include #include +#include + +#include "ZeroTierOne.h" + +// See test/selftest.cpp for examples /****************************************************************************/ /* For SOCK_RAW support, it will initially be modeled after linux's API, so */ @@ -463,6 +468,11 @@ int zts_write(ZT_WRITE_SIG); */ int zts_shutdown(ZT_SHUTDOWN_SIG); +/* + * Returns a vector of network routes { target, via, metric, etc... } + */ +std::vector *zts_get_network_routes(char *nwid); + /****************************************************************************/ /* SDK Socket API Helper functions/objects --- DONT CALL THESE DIRECTLY */ /****************************************************************************/ @@ -515,6 +525,10 @@ ZeroTier::SocketTap *getTapByNWID(uint64_t nwid); ZeroTier::SocketTap *getTapByAddr(ZeroTier::InetAddress &addr); ZeroTier::SocketTap *getTapByName(char *ifname); ZeroTier::SocketTap *getTapByIndex(int index); + +/* + * Destroys all virtual tap devices + */ void dismantleTaps(); /** diff --git a/include/lwipopts.h b/include/lwipopts.h index cf4a1d3..532dff0 100644 --- a/include/lwipopts.h +++ b/include/lwipopts.h @@ -45,14 +45,12 @@ #include "lwip/debug.h" // IP Protocol version -// It seems using ipv6/ipv4 in the same stack is problematic, for this reason we -// compile for only one or the other using the SDK_IPV4=1/SDK_IPV6=1 flags for now -#if defined(SDK_IPV6) +#if defined(LIBZT_IPV6) #define LWIP_IPV6 1 #define LWIP_IPV4 0 #endif -#if defined(SDK_IPV4) +#if defined(LIBZT_IPV4) #define LWIP_IPV4 1 #define LWIP_IPV6 0 #endif diff --git a/make-liblwip.mk b/make-liblwip.mk index c3aa079..f2079d4 100644 --- a/make-liblwip.mk +++ b/make-liblwip.mk @@ -36,7 +36,6 @@ LWIPARCH=$(CONTRIBDIR)/ports/unix #default assumes it's a dir named lwip at the same level as the contrib module LWIPDIR=ext/lwip/src - CCDEP=clang++ # Automagically pick clang or gcc, with preference for clang @@ -79,14 +78,14 @@ CORE4FILES=$(LWIPDIR)/core/ipv4/autoip.c \ $(LWIPDIR)/core/ipv4/ip4.c \ $(LWIPDIR)/core/ipv4/ip4_addr.c -CORE6FILES=$(LWIPDIR)/core/ipv6/dhcp6.c \ - $(LWIPDIR)/core/ipv6/ethip6.c \ +CORE6FILES=$(LWIPDIR)/core/ipv6/ethip6.c \ $(LWIPDIR)/core/ipv6/icmp6.c \ $(LWIPDIR)/core/ipv6/inet6.c \ $(LWIPDIR)/core/ipv6/ip6.c \ $(LWIPDIR)/core/ipv6/ip6_addr.c \ $(LWIPDIR)/core/ipv6/ip6_frag.c \ $(LWIPDIR)/core/ipv6/mld6.c \ + $(LWIPDIR)/core/ipv6/dhcp6.c \ $(LWIPDIR)/core/ipv6/nd6.c # APIFILES: The files which implement the sequential and socket APIs. @@ -113,7 +112,7 @@ SIXLOWPAN=$(LWIPDIR)/netif/lowpan6.c \ ARCHFILES=$(wildcard $(LWIPARCH)/*.c $(LWIPARCH)tapif.c $(LWIPARCH)/netif/list.c $(LWIPARCH)/netif/tcpdump.c) # LWIPFILES: All the above. -LWIPFILES=$(COREFILES) $(CORE4FILES) $(APIFILES) $(NETIFFILES) $(ARCHFILES) +LWIPFILES=$(COREFILES) $(APIFILES) $(NETIFFILES) $(ARCHFILES) ifeq ($(IPV4),1) LWIPFILES+=$(CORE4FILES) @@ -127,28 +126,21 @@ endif LWIPFILESW=$(wildcard $(LWIPFILES)) LWIPOBJS=$(notdir $(LWIPFILESW:.c=.o)) -LWIPLIB=liblwip.so - %.o: - $(CXX) $(CFLAGS) -Isrc/stack_drivers/lwip -c $(<:.o=.c) + $(CXX) $(CFLAGS) -c $(<:.o=.c) -o obj/$@ -all: $(LWIPLIB) +all: .PHONY: all clean: - rm -f *.o $(LWIPLIB4) $(LWIPLIB6) *.s .depend* *.core core + rm -f *.o *.s .depend* *.core core depend dep: .depend include .depend -$(LWIPLIB): $(LWIPOBJS) - mkdir -p build - $(CXX) -Isrc/stack_drivers/lwip -g -nostartfiles -shared -o build/$@ $^ - liblwip.a: $(LWIPOBJS) - echo $(LWIPOBJS) - libtool -static -o $@ $^ + #libtool -static -o $@ $^ .depend: $(LWIPFILES) $(CCDEP) $(CFLAGS) -MM $^ > .depend || rm -f .depend \ No newline at end of file diff --git a/make-linux.mk b/make-linux.mk index cadc9e3..811229c 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -121,12 +121,15 @@ ifeq ($(STACK_PICO),1) ifeq ($(LIBZT_IPV4)$(LIBZT_IPV6),1) ifeq ($(LIBZT_IPV4),1) CXXFLAGS+=-DLIBZT_IPV4 +STACK_FLAGS+=-IPV4=1 -IPv4=1 endif ifeq ($(LIBZT_IPV6),1) CXXFLAGS+=-DLIBZT_IPV6 +STACK_FLAGS+=-IPV6=1 -IPv6=1 endif else CXXFLAGS+=-DLIBZT_IPV4 -DLIBZT_IPV6 +STACK_FLAGS+=-IPV6=1 -IPv6=1 -IPV6=1 -IPv6=1 endif endif @@ -135,12 +138,15 @@ ifeq ($(STACK_LWIP),1) ifeq ($(LIBZT_IPV4)$(LIBZT_IPV6),1) ifeq ($(LIBZT_IPV4),1) CXXFLAGS+=-DLIBZT_IPV4 +STACK_FLAGS+=IPV4=1 IPv4=1 endif ifeq ($(LIBZT_IPV6),1) CXXFLAGS+=-DLIBZT_IPV6 +STACK_FLAGS+=IPV6=1 IPv6=1 endif else CXXFLAGS+=-DLIBZT_IPV4 +STACK_FLAGS+=IPV4=1 IPv4=1 endif endif @@ -154,29 +160,14 @@ STACK_DIR:=ext/picotcp STACK_LIB:=$(STACK_DIR)/build/lib/$(STACK_LIB) STACK_DRIVER_FILES:=src/picoTCP.cpp STACK_DRIVER_OBJS+=picoTCP.o -STACK_OBJS+= ext/picotcp/build/lib/pico_device.o \ - ext/picotcp/build/lib/pico_frame.o \ - ext/picotcp/build/lib/pico_md5.o \ - ext/picotcp/build/lib/pico_protocol.o \ - ext/picotcp/build/lib/pico_socket_multicast.o \ - ext/picotcp/build/lib/pico_socket.o \ - ext/picotcp/build/lib/pico_stack.o \ - ext/picotcp/build/lib/pico_tree.o \ - ext/picotcp/build/modules/*.o INCLUDES+=-Iext/picotcp/include -Iext/picotcp/build/include endif ifeq ($(STACK_LWIP),1) -STACK_FLAGS+=-DLWIP_PREFIX_BYTEORDER_FUNCS +STACK_DRIVER_FLAGS+=-DLWIP_PREFIX_BYTEORDER_FUNCS CXXFLAGS+=-DSTACK_LWIP STACK_DRIVER_FILES:=src/lwIP.cpp STACK_DRIVER_OBJS+=lwIP.o -STACK_OBJS+= init.o def.o dns.o inet_chksum.o ip.o mem.o \ - memp.o netif.o pbuf.o raw.o stats.o sys.o tcp.o \ - tcp_in.o tcp_out.o timeouts.o udp.o autoip.o \ - dhcp.o etharp.o icmp.o igmp.o ip4_frag.o ip4.o \ - ip4_addr.o api_lib.o api_msg.o err.o netbuf.o \ - netdb.o netifapi.o sockets.o tcpip.o ethernet.o LWIPARCH=$(CONTRIBDIR)/ports/unix LWIPDIR=ext/lwip/src INCLUDES+=-Iext/lwip/src/include/lwip \ @@ -193,6 +184,14 @@ endif all: +%.o : %.cpp + @mkdir -p $(BUILD) obj + $(CXX) $(CXXFLAGS) -c $^ -o obj/$(@F) + +%.o : %.c + @mkdir -p $(BUILD) obj + $(CC) $(CFLAGS) -c $^ -o obj/$(@F) + ############################################################################## ## User-Space Stack ## ############################################################################## @@ -201,7 +200,7 @@ picotcp: cd $(STACK_DIR); make lib ARCH=shared IPV4=1 IPV6=1 lwip: - -make -f make-liblwip.mk liblwip.a IPV4=1 IPV6=1 + -make -f make-liblwip.mk liblwip.a $(STACK_FLAGS) ############################################################################## ## Static Libraries ## @@ -209,22 +208,27 @@ lwip: ifeq ($(STACK_PICO),1) static_lib: picotcp $(ZTO_OBJS) - @mkdir -p $(BUILD) + @mkdir -p $(BUILD) obj $(CXX) $(CXXFLAGS) $(LIBZT_FILES) $(STACK_DRIVER_FILES) -c - ar rcs -o $(STATIC_LIB) $(ZTO_OBJS) $(STACK_DRIVER_OBJS) $(STACK_OBJS) $(LIBZT_OBJS) $(STACK_LIB) + mv *.o obj + mv ext/picotcp/build/lib/*.o obj + mv ext/picotcp/build/modules/*.o obj + ar rcs -o $(STATIC_LIB) obj/*.o $(STACK_LIB) endif ifeq ($(STACK_LWIP),1) static_lib: lwip $(ZTO_OBJS) - @mkdir -p $(BUILD) - $(CXX) $(CXXFLAGS) $(STACK_FLAGS) $(STACK_INCLUDES) $(LIBZT_FILES) $(STACK_DRIVER_FILES) -c - ar rcs -o $(STATIC_LIB) $(ZTO_OBJS) $(STACK_DRIVER_OBJS) $(STACK_OBJS) $(LIBZT_OBJS) $(STACK_LIB) + @mkdir -p $(BUILD) obj + $(CXX) $(CXXFLAGS) $(STACK_DRIVER_FLAGS) $(STACK_INCLUDES) $(LIBZT_FILES) $(STACK_DRIVER_FILES) -c + mv *.o obj + ar rcs -o $(STATIC_LIB) obj/*.o $(STACK_LIB) endif # for layer-2 only (this will omit all userspace network stack code) ifeq ($(NO_STACK),1) static_lib: $(ZTO_OBJS) - @mkdir -p $(BUILD) + @mkdir -p $(BUILD) obj $(CXX) $(CXXFLAGS) $(LIBZT_FILES) -c - ar rcs -o $(STATIC_LIB) $(ZTO_OBJS) $(LIBZT_OBJS) + mv *.o obj + ar rcs -o $(STATIC_LIB) obj/*.o endif ############################################################################## diff --git a/make-mac.mk b/make-mac.mk index 541df48..f2cd99b 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -119,12 +119,15 @@ ifeq ($(STACK_PICO),1) ifeq ($(LIBZT_IPV4)$(LIBZT_IPV6),1) ifeq ($(LIBZT_IPV4),1) CXXFLAGS+=-DLIBZT_IPV4 +STACK_FLAGS+=-IPV4=1 -IPv4=1 endif ifeq ($(LIBZT_IPV6),1) CXXFLAGS+=-DLIBZT_IPV6 +STACK_FLAGS+=-IPV6=1 -IPv6=1 endif else CXXFLAGS+=-DLIBZT_IPV4 -DLIBZT_IPV6 +STACK_FLAGS+=-IPV6=1 -IPv6=1 -IPV6=1 -IPv6=1 endif endif @@ -133,12 +136,15 @@ ifeq ($(STACK_LWIP),1) ifeq ($(LIBZT_IPV4)$(LIBZT_IPV6),1) ifeq ($(LIBZT_IPV4),1) CXXFLAGS+=-DLIBZT_IPV4 +STACK_FLAGS+=IPV4=1 IPv4=1 endif ifeq ($(LIBZT_IPV6),1) CXXFLAGS+=-DLIBZT_IPV6 +STACK_FLAGS+=IPV6=1 IPv6=1 endif else CXXFLAGS+=-DLIBZT_IPV4 +STACK_FLAGS+=IPV4=1 IPv4=1 endif endif @@ -152,27 +158,14 @@ STACK_DIR:=ext/picotcp STACK_LIB:=$(STACK_DIR)/build/lib/$(STACK_LIB) STACK_DRIVER_FILES:=src/picoTCP.cpp STACK_DRIVER_OBJS+=picoTCP.o -STACK_OBJS+= ext/picotcp/build/lib/pico_device.o \ - ext/picotcp/build/lib/pico_frame.o \ - ext/picotcp/build/lib/pico_md5.o \ - ext/picotcp/build/lib/pico_protocol.o \ - ext/picotcp/build/lib/pico_socket_multicast.o \ - ext/picotcp/build/lib/pico_socket.o \ - ext/picotcp/build/lib/pico_stack.o \ - ext/picotcp/build/lib/pico_tree.o INCLUDES+=-Iext/picotcp/include -Iext/picotcp/build/include endif ifeq ($(STACK_LWIP),1) +STACK_DRIVER_FLAGS+=-DLWIP_PREFIX_BYTEORDER_FUNCS CXXFLAGS+=-DSTACK_LWIP STACK_DRIVER_FILES:=src/lwIP.cpp STACK_DRIVER_OBJS+=lwIP.o -STACK_OBJS+= init.o def.o dns.o inet_chksum.o ip.o mem.o \ - memp.o netif.o pbuf.o raw.o stats.o sys.o tcp.o \ - tcp_in.o tcp_out.o timeouts.o udp.o autoip.o \ - dhcp.o etharp.o icmp.o igmp.o ip4_frag.o ip4.o \ - ip4_addr.o api_lib.o api_msg.o err.o netbuf.o \ - netdb.o netifapi.o sockets.o tcpip.o ethernet.o LWIPARCH=$(CONTRIBDIR)/ports/unix LWIPDIR=ext/lwip/src INCLUDES+=-Iext/lwip/src/include/lwip \ @@ -189,6 +182,14 @@ endif all: +%.o : %.cpp + @mkdir -p $(BUILD) obj + $(CXX) $(CXXFLAGS) -c $^ -o obj/$(@F) + +%.o : %.c + @mkdir -p $(BUILD) obj + $(CC) $(CFLAGS) -c $^ -o obj/$(@F) + ############################################################################## ## User-Space Stack ## ############################################################################## @@ -203,24 +204,30 @@ lwip: ## Static Libraries ## ############################################################################## + ifeq ($(STACK_PICO),1) static_lib: picotcp $(ZTO_OBJS) - @mkdir -p $(BUILD) + @mkdir -p $(BUILD) obj $(CXX) $(CXXFLAGS) $(LIBZT_FILES) $(STACK_DRIVER_FILES) -c - libtool -static -o $(STATIC_LIB) $(ZTO_OBJS) $(STACK_DRIVER_OBJS) $(STACK_OBJS) $(LIBZT_OBJS) $(STACK_LIB) + mv *.o obj + mv ext/picotcp/build/lib/*.o obj + mv ext/picotcp/build/modules/*.o obj + libtool -static -o $(STATIC_LIB) obj/*.o $(STACK_LIB) endif ifeq ($(STACK_LWIP),1) static_lib: lwip $(ZTO_OBJS) - @mkdir -p $(BUILD) - $(CXX) $(CXXFLAGS) $(STACK_INCLUDES) $(LIBZT_FILES) $(STACK_DRIVER_FILES) -c - libtool -static -o $(STATIC_LIB) $(ZTO_OBJS) $(STACK_DRIVER_OBJS) $(STACK_OBJS) $(LIBZT_OBJS) $(STACK_LIB) + @mkdir -p $(BUILD) obj + $(CXX) $(CXXFLAGS) $(STACK_DRIVER_FLAGS) $(STACK_INCLUDES) $(LIBZT_FILES) $(STACK_DRIVER_FILES) -c + mv *.o obj + libtool -static -o $(STATIC_LIB) obj/*.o $(STACK_LIB) endif # for layer-2 only (this will omit all userspace network stack code) ifeq ($(NO_STACK),1) static_lib: $(ZTO_OBJS) - @mkdir -p $(BUILD) + @mkdir -p $(BUILD) obj $(CXX) $(CXXFLAGS) $(LIBZT_FILES) -c - libtool -static -o $(STATIC_LIB) $(ZTO_OBJS) $(LIBZT_OBJS) + mv *.o obj + libtool -static -o $(STATIC_LIB) obj/*.o endif ############################################################################## diff --git a/src/SocketTap.cpp b/src/SocketTap.cpp index 88bcd49..1370cd1 100644 --- a/src/SocketTap.cpp +++ b/src/SocketTap.cpp @@ -52,6 +52,7 @@ #include #endif +#include "OneService.hpp" #include "Utils.hpp" #include "OSUtils.hpp" #include "Constants.hpp" @@ -59,7 +60,9 @@ class SocketTap; + extern std::vector vtaps; +//extern ZeroTier::OneService *zt1Service; namespace ZeroTier { @@ -277,50 +280,79 @@ namespace ZeroTier { Read(sock,uptr,stack_invoked); } + // Adds a route to the virtual tap + bool SocketTap::routeAdd(const InetAddress &addr, const InetAddress &nm, const InetAddress &gw) + { +#if defined(STACK_PICO) + if(picostack) + return picostack->pico_route_add(this, addr, nm, gw, 0); +#endif +#if defined(STACK_LWIP) + return true; +#endif + return false; + } + + // Deletes a route from the virtual tap + bool SocketTap::routeDelete(const InetAddress &addr, const InetAddress &nm) + { +#if defined(STACK_PICO) + if(picostack) + return picostack->pico_route_del(this, addr, nm, 0); +#endif +#if defined(STACK_LWIP) + return true; +#endif + return false; + } + /****************************************************************************/ /* SDK Socket API */ /****************************************************************************/ - int SocketTap::Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen) { + // Connect + int SocketTap::Connect(Connection *conn, const struct sockaddr *addr, socklen_t addrlen) { #if defined(NO_STACK) return -1; #endif - Mutex::Lock _l(_tcpconns_m); #if defined(STACK_PICO) if(picostack) - return picostack->pico_Connect(conn, fd, addr, addrlen); + Mutex::Lock _l(_tcpconns_m); + return picostack->pico_Connect(conn, addr, addrlen); #endif #if defined(STACK_LWIP) if(lwipstack) - return lwipstack->lwip_Connect(conn, fd, addr, addrlen); + return lwipstack->lwip_Connect(conn, addr, addrlen); #endif return ZT_ERR_GENERAL_FAILURE; } - int SocketTap::Bind(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen) { + // Bind VirtualSocket to a network stack's interface + int SocketTap::Bind(Connection *conn, const struct sockaddr *addr, socklen_t addrlen) { #if defined(NO_STACK) return -1; #endif Mutex::Lock _l(_tcpconns_m); #if defined(STACK_PICO) if(picostack) - return picostack->pico_Bind(conn, fd, addr, addrlen); + return picostack->pico_Bind(conn, addr, addrlen); #endif #if defined(STACK_LWIP) if(lwipstack) - return lwipstack->lwip_Bind(this, conn, fd, addr, addrlen); + return lwipstack->lwip_Bind(this, conn, addr, addrlen); #endif return ZT_ERR_GENERAL_FAILURE; } - int SocketTap::Listen(Connection *conn, int fd, int backlog) { + // Listen for an incoming connection + int SocketTap::Listen(Connection *conn, int backlog) { #if defined(NO_STACK) return -1; #endif Mutex::Lock _l(_tcpconns_m); #if defined(STACK_PICO) if(picostack) - return picostack->pico_Listen(conn, fd, backlog); + return picostack->pico_Listen(conn, backlog); return ZT_ERR_GENERAL_FAILURE; #endif #if defined(STACK_LWIP) @@ -331,13 +363,14 @@ namespace ZeroTier { return ZT_ERR_GENERAL_FAILURE; } + // Accept a connection Connection* SocketTap::Accept(Connection *conn) { #if defined(NO_STACK) return NULL; #endif - Mutex::Lock _l(_tcpconns_m); #if defined(STACK_PICO) if(picostack) + Mutex::Lock _l(_tcpconns_m); return picostack->pico_Accept(conn); return NULL; #endif @@ -349,6 +382,7 @@ namespace ZeroTier { return NULL; } + // Read from stack/buffers into the app's socket int SocketTap::Read(PhySocket *sock,void **uptr,bool stack_invoked) { #if defined(STACK_PICO) if(picostack) @@ -361,6 +395,7 @@ namespace ZeroTier { return -1; } + // Write data from app socket to the virtual wire, either raw over VL2, or via network stack int SocketTap::Write(Connection *conn, void *data, ssize_t len) { // VL2, SOCK_RAW, no network stack if(conn->socket_type == SOCK_RAW) { @@ -372,7 +407,6 @@ namespace ZeroTier { _handler(_arg,NULL,_nwid,src_mac,dest_mac, Utils::ntoh((uint16_t)eh->ether_type),0, ((char*)data) + sizeof(struct ether_header),len - sizeof(struct ether_header)); return len; } - #if defined(STACK_PICO) if(picostack) return picostack->pico_Write(conn, data, len); @@ -384,6 +418,26 @@ namespace ZeroTier { return -1; } + // Send data to a specified host + int SocketTap::SendTo(Connection *conn, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen) + { + // TODO: flags + int err = 0; + DEBUG_INFO(); +#if defined(STACK_PICO) + if(picostack) { + err = picostack->pico_Connect(conn, addr, addrlen); // implicit + err = picostack->pico_Write(conn, (void*)buf, len); + } +#endif +#if defined(STACK_LWIP) + if(lwipstack) + err = lwipstack->lwip_Connect(conn, addr, addrlen); // implicit + err = lwipstack->lwip_Write(conn, (void*)buf, len); +#endif + return err; + } + int SocketTap::Close(Connection *conn) { #if defined(STACK_PICO) if(!conn) { @@ -427,21 +481,66 @@ namespace ZeroTier { void SocketTap::Housekeeping() { -#if defined(STACK_PICO) Mutex::Lock _l(_tcpconns_m); std::time_t current_ts = std::time(nullptr); if(current_ts > last_housekeeping_ts + ZT_HOUSEKEEPING_INTERVAL) { - // Clean up old Connection objects - for(size_t i=0;i<_Connections.size();++i) { - if(_Connections[i]->closure_ts != -1 && (current_ts > _Connections[i]->closure_ts + ZT_CONNECTION_DELETE_WAIT_TIME)) { - // DEBUG_ERROR("deleting %p object, _Connections.size() = %d", _Connections[i], _Connections.size()); - delete _Connections[i]; - _Connections.erase(_Connections.begin() + i); - } + // update managed routes (add/del from network stacks) + if(zt1ServiceRef) { + std::vector *managed_routes = ((ZeroTier::OneService *)zt1ServiceRef)->getRoutes(this->_nwid); + ZeroTier::InetAddress target_addr; + ZeroTier::InetAddress via_addr; + ZeroTier::InetAddress null_addr; + ZeroTier::InetAddress nm; + null_addr.fromString(""); + bool found; + char ipbuf[64], ipbuf2[64], ipbuf3[64]; + // TODO: Rework this when we have time + // check if pushed route exists in tap (add) + for(int i=0; iat(i).target; + via_addr = managed_routes->at(i).via; + nm = target_addr.netmask(); + for(int j=0; j", target_addr.toString(ipbuf), nm.toString(ipbuf2), via_addr.toString(ipbuf3)); + routes.push_back(std::pair(target_addr, nm)); + routeAdd(target_addr, nm, via_addr); + } + } + } + // check if route exists in tap but not in pushed routes (remove) + for(int i=0; iat(j).target; + via_addr = managed_routes->at(j).via; + nm = target_addr.netmask(); + if(routes[i].first.ipsEqual(target_addr) && routes[i].second.ipsEqual(nm)) { + found=true; + } + } + if(!found) { + DEBUG_INFO("removing route to ", routes[i].first.toString(ipbuf), routes[i].second.toString(ipbuf2)); + routes.erase(routes.begin() + i); + routeDelete(routes[i].first, routes[i].second); + } + } } + + // TODO: Clean up Connection objects + last_housekeeping_ts = std::time(nullptr); } -#endif } /****************************************************************************/ diff --git a/src/SocketTap.hpp b/src/SocketTap.hpp index b8edd69..96bfc3f 100644 --- a/src/SocketTap.hpp +++ b/src/SocketTap.hpp @@ -155,6 +155,16 @@ namespace ZeroTier { */ void phyOnUnixWritable(PhySocket *sock, void **uptr, bool lwip_invoked); + /* + * Adds a route to the virtual tap + */ + bool routeAdd(const InetAddress &addr, const InetAddress &nm, const InetAddress &gw); + + /* + * Deletes a route from the virtual tap + */ + bool routeDelete(const InetAddress &addr, const InetAddress &nm); + /****************************************************************************/ /* Vars */ /****************************************************************************/ @@ -183,6 +193,9 @@ namespace ZeroTier { netif lwipdev6; #endif + std::vector> routes; + void *zt1ServiceRef; + static int devno; int ifindex; @@ -222,17 +235,17 @@ namespace ZeroTier { /* * Connect to a remote host via the userspace stack interface associated with this SocketTap */ - int Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen); + int Connect(Connection *conn, const struct sockaddr *addr, socklen_t addrlen); /* * Bind to the userspace stack interface associated with this SocketTap */ - int Bind(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen); + int Bind(Connection *conn, const struct sockaddr *addr, socklen_t addrlen); /* * Listen for a Connection */ - int Listen(Connection *conn, int fd, int backlog); + int Listen(Connection *conn, int backlog); /* * Accepts an incoming Connection @@ -249,6 +262,11 @@ namespace ZeroTier { */ int Write(Connection *conn, void *data, ssize_t len); + /* + * Send data to specified host + */ + int SendTo(Connection *conn, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen); + /* * Closes a Connection */ diff --git a/src/Utilities.cpp b/src/Utilities.cpp index 1a0a14a..fcef79f 100644 --- a/src/Utilities.cpp +++ b/src/Utilities.cpp @@ -24,4 +24,4 @@ * of your own application. */ -// Intentionally left blank +// Intentionally left blank \ No newline at end of file diff --git a/src/Utilities.hpp b/src/Utilities.hpp index 3bc0f33..e0cc8f7 100644 --- a/src/Utilities.hpp +++ b/src/Utilities.hpp @@ -27,6 +27,30 @@ #ifndef UTILITIES_HPP #define UTILITIES_HPP +#if defined(STACK_LWIP) && defined(LIBZT_IPV6) +#define IP6_ADDR2(ipaddr, a,b,c,d,e,f,g,h) do { (ipaddr)->addr[0] = ZeroTier::Utils::hton((u32_t)((a & 0xffff) << 16) | (b & 0xffff)); \ + (ipaddr)->addr[1] = ZeroTier::Utils::hton(((c & 0xffff) << 16) | (d & 0xffff)); \ + (ipaddr)->addr[2] = ZeroTier::Utils::hton(((e & 0xffff) << 16) | (f & 0xffff)); \ + (ipaddr)->addr[3] = ZeroTier::Utils::hton(((g & 0xffff) << 16) | (h & 0xffff)); } while(0) + +// Convert from standard IPV6 address structure to an lwIP native structure +inline void in6_to_ip6(ip6_addr_t *ba, struct sockaddr_in6 *in6) +{ + uint8_t *ip = &(in6->sin6_addr).s6_addr[0]; + IP6_ADDR2(ba, + (((ip[ 0] & 0xffff) << 8) | ((ip[ 1]) & 0xffff)), + (((ip[ 2] & 0xffff) << 8) | ((ip[ 3]) & 0xffff)), + (((ip[ 4] & 0xffff) << 8) | ((ip[ 5]) & 0xffff)), + (((ip[ 6] & 0xffff) << 8) | ((ip[ 7]) & 0xffff)), + (((ip[ 8] & 0xffff) << 8) | ((ip[ 9]) & 0xffff)), + (((ip[10] & 0xffff) << 8) | ((ip[11]) & 0xffff)), + (((ip[12] & 0xffff) << 8) | ((ip[13]) & 0xffff)), + (((ip[14] & 0xffff) << 8) | ((ip[15]) & 0xffff)) + ); +} +#endif + + #if defined(STACK_LWIP) && defined(LIBZT_IPV4) #include "lwip/ip_addr.h" diff --git a/src/libzt.cpp b/src/libzt.cpp index e1bc65a..0eba847 100644 --- a/src/libzt.cpp +++ b/src/libzt.cpp @@ -74,9 +74,10 @@ for applications to use. See also: include/libzt.h */ extern "C" { #endif -static ZeroTier::OneService *zt1Service; - namespace ZeroTier { + + static ZeroTier::OneService *zt1Service; + std::string homeDir; // Platform-specific dir we *must* use internally std::string netDir; // Where network .conf files are to be written @@ -98,7 +99,7 @@ namespace ZeroTier { std::map*> fdmap; /* - * + * Virtual tap interfaces, one per virtual network */ std::vector vtaps; @@ -113,7 +114,7 @@ namespace ZeroTier { void zts_start(const char *path) { - if(zt1Service) + if(ZeroTier::zt1Service) return; #if defined(STACK_PICO) if(ZeroTier::picostack) @@ -142,15 +143,15 @@ void zts_simple_start(const char *path, const char *nwid) } void zts_stop() { - if(zt1Service) { - zt1Service->terminate(); + if(ZeroTier::zt1Service) { + ZeroTier::zt1Service->terminate(); dismantleTaps(); } } void zts_join(const char * nwid) { - if(zt1Service) { - std::string confFile = zt1Service->givenHomePath() + "/networks.d/" + nwid + ".conf"; + if(ZeroTier::zt1Service) { + std::string confFile = ZeroTier::zt1Service->givenHomePath() + "/networks.d/" + nwid + ".conf"; if(!ZeroTier::OSUtils::mkdir(ZeroTier::netDir)) { DEBUG_ERROR("unable to create: %s", ZeroTier::netDir.c_str()); handle_general_failure(); @@ -159,7 +160,13 @@ void zts_join(const char * nwid) { DEBUG_ERROR("unable to write network conf file: %s", confFile.c_str()); handle_general_failure(); } - zt1Service->join(nwid); + ZeroTier::zt1Service->join(nwid); + } + // provide ZTO service reference to virtual taps + // TODO: This might prove to be unreliable, but it works for now + for(int i=0;izt1ServiceRef=(void*)ZeroTier::zt1Service; } } @@ -179,8 +186,8 @@ void zts_join_soft(const char * filepath, const char * nwid) { } void zts_leave(const char * nwid) { - if(zt1Service) - zt1Service->leave(nwid); + if(ZeroTier::zt1Service) + ZeroTier::zt1Service->leave(nwid); } void zts_leave_soft(const char * filepath, const char * nwid) { @@ -206,9 +213,9 @@ void zts_lib_version(char *ver) { } int zts_get_device_id(char *devID) { - if(zt1Service) { + if(ZeroTier::zt1Service) { char id[ZT_ID_LEN+1]; - sprintf(id, "%lx",zt1Service->getNode()->address()); + sprintf(id, "%lx",ZeroTier::zt1Service->getNode()->address()); memcpy(devID, id, ZT_ID_LEN+1); return 0; } @@ -228,7 +235,7 @@ int zts_get_device_id(char *devID) { } int zts_running() { - return !zt1Service ? false : zt1Service->isRunning(); + return !ZeroTier::zt1Service ? false : ZeroTier::zt1Service->isRunning(); } int zts_has_ipv4_address(const char *nwid) @@ -254,7 +261,7 @@ int zts_has_address(const char *nwid) void zts_get_ipv4_address(const char *nwid, char *addrstr, const int addrlen) { - if(zt1Service) { + if(ZeroTier::zt1Service) { uint64_t nwid_int = strtoull(nwid, NULL, 16); ZeroTier::SocketTap *tap = getTapByNWID(nwid_int); if(tap && tap->_ips.size()){ @@ -276,7 +283,7 @@ void zts_get_ipv4_address(const char *nwid, char *addrstr, const int addrlen) void zts_get_ipv6_address(const char *nwid, char *addrstr, const int addrlen) { - if(zt1Service) { + if(ZeroTier::zt1Service) { uint64_t nwid_int = strtoull(nwid, NULL, 16); ZeroTier::SocketTap *tap = getTapByNWID(nwid_int); if(tap && tap->_ips.size()){ @@ -313,15 +320,15 @@ void zts_get_rfc4193_addr(char *addr, const char *nwid, const char *devID) } unsigned long zts_get_peer_count() { - if(zt1Service) - return zt1Service->getNode()->peers()->peerCount; + if(ZeroTier::zt1Service) + return ZeroTier::zt1Service->getNode()->peers()->peerCount; else return 0; } int zts_get_peer_address(char *peer, const char *devID) { - if(zt1Service) { - ZT_PeerList *pl = zt1Service->getNode()->peers(); + if(ZeroTier::zt1Service) { + ZT_PeerList *pl = ZeroTier::zt1Service->getNode()->peers(); // uint64_t addr; for(int i=0; ipeerCount; i++) { // ZT_Peer *p = &(pl->peers[i]); @@ -374,7 +381,7 @@ int zts_socket(ZT_SOCKET_SIG) { return -1; } int err = 0; - if(!zt1Service) { + if(!ZeroTier::zt1Service) { DEBUG_ERROR("cannot create socket, no service running. call zts_start() first."); errno = EMFILE; // could also be ENFILE return -1; @@ -417,7 +424,6 @@ int zts_socket(ZT_SOCKET_SIG) { #if defined(STACK_LWIP) // TODO: check for max lwIP timers/sockets - ZeroTier::Connection *conn = new ZeroTier::Connection(); void *pcb; err = ZeroTier::lwipstack->lwip_Socket(&pcb, socket_family, socket_type, protocol); if(pcb) { @@ -493,15 +499,14 @@ Linux: */ int zts_connect(ZT_CONNECT_SIG) { -#if defined(STACK_PICO) - //DEBUG_INFO("fd = %d", fd); + DEBUG_INFO("fd = %d", fd); int err = 0; if(fd < 0) { errno = EBADF; DEBUG_ERROR("EBADF"); return -1; } - if(!zt1Service) { + if(!ZeroTier::zt1Service) { DEBUG_ERROR("Service not started. Call zts_start(path) first"); errno = EBADF; return -1; @@ -539,9 +544,13 @@ int zts_connect(ZT_CONNECT_SIG) { err = -1; } else { +#if defined(STACK_PICO) // pointer to tap we use in callbacks from the stack conn->picosock->priv = new ZeroTier::ConnectionPair(tap, conn); - err = tap->Connect(conn, fd, addr, addrlen); +#endif +#if defined(STACK_LWIP) +#endif + err = tap->Connect(conn, addr, addrlen); if(err == 0) { tap->_Connections.push_back(conn); // Give this Connection to the tap we decided on conn->tap = tap; @@ -549,7 +558,6 @@ int zts_connect(ZT_CONNECT_SIG) { // Wrap the socketpair we created earlier // For I/O loop participation and referencing the PhySocket's parent Connection in callbacks conn->sock = tap->_phy.wrapSocket(conn->sdk_fd, conn); - //DEBUG_ERROR("sock->fd = %d", tap->_phy.getDescriptor(conn->sock)); } } else { @@ -575,7 +583,6 @@ int zts_connect(ZT_CONNECT_SIG) { else { blocking = !(f_err & O_NONBLOCK); } - // non-blocking if(err == 0 && !blocking) { DEBUG_EXTRA("EINPROGRESS, not a real error, assuming non-blocking mode"); @@ -596,11 +603,15 @@ int zts_connect(ZT_CONNECT_SIG) { tap->_tcpconns_m.lock(); for(int i=0; i_Connections.size(); i++) { +#if defined(STACK_PICO) if(tap->_Connections[i]->state == PICO_ERR_ECONNRESET) { errno = ECONNRESET; DEBUG_ERROR("ECONNRESET"); err = -1; } +#endif +#if defined(STACK_LWIP) +#endif if(tap->_Connections[i]->state == ZT_SOCK_STATE_UNHANDLED_CONNECTED) { tap->_Connections[i]->state = ZT_SOCK_STATE_CONNECTED; errno = 0; @@ -615,8 +626,6 @@ int zts_connect(ZT_CONNECT_SIG) { } } return err; -#endif - return 0; } /* @@ -640,7 +649,7 @@ int zts_bind(ZT_BIND_SIG) { errno = EBADF; return -1; } - if(!zt1Service) { + if(!ZeroTier::zt1Service) { DEBUG_ERROR("Service not started. Call zts_start(path) first"); errno = EBADF; return -1; @@ -677,7 +686,7 @@ int zts_bind(ZT_BIND_SIG) { else { conn->picosock->priv = new ZeroTier::ConnectionPair(tap, conn); tap->_Connections.push_back(conn); // Give this Connection to the tap we decided on - err = tap->Bind(conn, fd, addr, addrlen); + err = tap->Bind(conn, addr, addrlen); conn->tap = tap; if(err == 0) { // success ZeroTier::unmap.erase(fd); @@ -688,7 +697,7 @@ int zts_bind(ZT_BIND_SIG) { #if defined(STACK_LWIP) else { tap->_Connections.push_back(conn); - err = tap->Bind(conn, fd, addr, addrlen); + err = tap->Bind(conn, addr, addrlen); conn->tap = tap; if(err == 0) { // success ZeroTier::unmap.erase(fd); @@ -731,7 +740,7 @@ int zts_listen(ZT_LISTEN_SIG) { errno = EBADF; return -1; } - if(!zt1Service) { + if(!ZeroTier::zt1Service) { DEBUG_ERROR("service not started. call zts_start(path) first"); errno = EACCES; return -1; @@ -752,7 +761,7 @@ int zts_listen(ZT_LISTEN_SIG) { } if(!err) { backlog = backlog > 128 ? 128 : backlog; // See: /proc/sys/net/core/somaxconn - err = tap->Listen(conn, fd, backlog); + err = tap->Listen(conn, backlog); conn->state = ZT_SOCK_STATE_LISTENING; ZeroTier::_multiplexer_lock.unlock(); } @@ -998,7 +1007,7 @@ int zts_close(ZT_CLOSE_SIG) } else { - if(!zt1Service) { + if(!ZeroTier::zt1Service) { DEBUG_ERROR("cannot close socket. service not started. call zts_start(path) first"); errno = EBADF; err = -1; @@ -1221,29 +1230,64 @@ ssize_t zts_sendto(ZT_SENDTO_SIG) err = -1; } else { - struct sockaddr_ll *socket_address = (struct sockaddr_ll *)addr; - ZeroTier::SocketTap *tap = getTapByIndex(socket_address->sll_ifindex); - if(tap) - { - DEBUG_INFO("found interface of ifindex=%d", tap->ifindex); - ZeroTier::Connection *conn = ZeroTier::unmap[fd]; - if(conn) { - DEBUG_INFO("located connection object for fd=%d", fd); - err = tap->Write(conn, (void*)buf, len); + ZeroTier::Connection *conn = ZeroTier::unmap[fd]; + ZeroTier::InetAddress iaddr; + ZeroTier::SocketTap *tap; + char ipstr[INET6_ADDRSTRLEN]; + int port; + memset(ipstr, 0, INET6_ADDRSTRLEN); + + if(conn->socket_type == SOCK_DGRAM) { + if(conn->socket_family == AF_INET) { + inet_ntop(AF_INET, + (const void *)&((struct sockaddr_in *)addr)->sin_addr.s_addr, ipstr, INET_ADDRSTRLEN); + iaddr.fromString(ipstr); + port = ((struct sockaddr_in*)addr)->sin_port; + } + if(conn->socket_family == AF_INET6) { + inet_ntop(AF_INET6, + (const void *)&((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr, ipstr, INET6_ADDRSTRLEN); + // TODO: This is a hack, determine a proper way to do this + char addrstr[64]; + sprintf(addrstr, "%s%s", ipstr, std::string("/88").c_str()); + iaddr.fromString(addrstr); + port = ((struct sockaddr_in6*)addr)->sin6_port; + } + tap = getTapByAddr(iaddr); + if(tap) { + tap->SendTo(conn, buf, len, flags, addr, addrlen); } else { - DEBUG_ERROR("unable to locate connection object for fd=%d", fd); + DEBUG_INFO("SOCK_DGRAM, tap not found"); + errno = EDESTADDRREQ; // TODO: double check this is the best errno to report + return -1; + } + } + if(conn->socket_type == SOCK_RAW) + { + struct sockaddr_ll *socket_address = (struct sockaddr_ll *)addr; + ZeroTier::SocketTap *tap = getTapByIndex(socket_address->sll_ifindex); + if(tap) + { + DEBUG_INFO("found interface of ifindex=%d", tap->ifindex); + if(conn) { + DEBUG_INFO("located connection object for fd=%d", fd); + err = tap->Write(conn, (void*)buf, len); + } + else { + DEBUG_ERROR("unable to locate connection object for fd=%d", fd); + err = -1; + errno = EINVAL; + } + } + else + { + DEBUG_ERROR("unable to locate tap of ifindex=%d", socket_address->sll_ifindex); err = -1; errno = EINVAL; } + //err = sendto(fd, buf, len, flags, addr, addrlen); } - else - { - DEBUG_ERROR("unable to locate tap of ifindex=%d", socket_address->sll_ifindex); - err = -1; - errno = EINVAL; - } - //err = sendto(fd, buf, len, flags, addr, addrlen); } return err; } @@ -1319,7 +1363,7 @@ int zts_shutdown(ZT_SHUTDOWN_SIG) } else { - if(!zt1Service) { + if(!ZeroTier::zt1Service) { DEBUG_ERROR("cannot shutdown socket. service not started. call zts_start(path) first"); errno = EBADF; err = -1; @@ -1406,7 +1450,7 @@ namespace ZeroTier { } // Shuts down ZeroTier service and SOCKS5 Proxy server JNIEXPORT void JNICALL Java_zerotier_ZeroTier_ztjni_1stop(JNIEnv *env, jobject thisObj) { - if(zt1Service) + if(ZeroTier::zt1Service) zts_stop(); } @@ -1652,7 +1696,7 @@ namespace ZeroTier { int zts_get_pico_socket(int fd, struct pico_socket **s) { int err = 0; - if(!zt1Service) { + if(!ZeroTier::zt1Service) { DEBUG_ERROR("cannot locate socket. service not started. call zts_start(path) first"); errno = EBADF; err = -1; @@ -1700,6 +1744,7 @@ bool can_provision_new_socket() // TODO: Add check here (see lwipopts.h) return true; #endif + return false; } int zts_nsockets() @@ -1723,6 +1768,12 @@ int zts_maxsockets() /* ZeroTier Core helper functions for libzt - DON'T CALL THESE DIRECTLY */ /****************************************************************************/ +std::vector *zts_get_network_routes(char *nwid) +{ + uint64_t nwid_int = strtoull(nwid, NULL, 16); + return ZeroTier::zt1Service->getRoutes(nwid_int); +} + ZeroTier::SocketTap *getTapByNWID(uint64_t nwid) { ZeroTier::_vtaps_lock.lock(); @@ -1739,14 +1790,33 @@ ZeroTier::SocketTap *getTapByAddr(ZeroTier::InetAddress &addr) { ZeroTier::_vtaps_lock.lock(); ZeroTier::SocketTap *s, *tap = nullptr; + char ipbuf[64], ipbuf2[64], ipbuf3[64]; for(int i=0; i_ips.size(); j++) { if(s->_ips[j].isEqualPrefix(addr) || s->_ips[j].ipsEqual(addr) || s->_ips[j].containsAddress(addr)) { + DEBUG_INFO("chose tap ", s->_ips[j].toString(ipbuf)); tap = s; + break; + } + } + // check managed routes + if(!tap) { + std::vector *managed_routes = ZeroTier::zt1Service->getRoutes(s->_nwid); + ZeroTier::InetAddress target, nm, via; + for(int i=0; isize(); i++){ + target = managed_routes->at(i).target; + nm = target.netmask(); + via = managed_routes->at(i).via; + if(target.containsAddress(addr)) { + DEBUG_INFO("chose tap with route ", target.toString(ipbuf), nm.toString(ipbuf2), via.toString(ipbuf3)); + tap = s; + break; + } } } } @@ -1797,7 +1867,7 @@ void *zts_start_service(void *thread_id) { DEBUG_INFO("homeDir=%s", ZeroTier::homeDir.c_str()); // Where network .conf files will be stored ZeroTier::netDir = ZeroTier::homeDir + "/networks.d"; - zt1Service = (ZeroTier::OneService *)0; + ZeroTier::zt1Service = (ZeroTier::OneService *)0; // Construct path for network config and supporting service files if (ZeroTier::homeDir.length()) { @@ -1832,17 +1902,17 @@ void *zts_start_service(void *thread_id) { int servicePort = 9000 + (randp % 1000); for(;;) { - zt1Service = ZeroTier::OneService::newInstance(ZeroTier::homeDir.c_str(),servicePort); - switch(zt1Service->run()) { + ZeroTier::zt1Service = ZeroTier::OneService::newInstance(ZeroTier::homeDir.c_str(),servicePort); + switch(ZeroTier::zt1Service->run()) { case ZeroTier::OneService::ONE_STILL_RUNNING: case ZeroTier::OneService::ONE_NORMAL_TERMINATION: break; case ZeroTier::OneService::ONE_UNRECOVERABLE_ERROR: - DEBUG_ERROR("fatal error: %s",zt1Service->fatalErrorMessage().c_str()); + DEBUG_ERROR("fatal error: %s",ZeroTier::zt1Service->fatalErrorMessage().c_str()); break; case ZeroTier::OneService::ONE_IDENTITY_COLLISION: { - delete zt1Service; - zt1Service = (ZeroTier::OneService *)0; + delete ZeroTier::zt1Service; + ZeroTier::zt1Service = (ZeroTier::OneService *)0; std::string oldid; ZeroTier::OSUtils::readFile((ZeroTier::homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),oldid); @@ -1859,8 +1929,8 @@ void *zts_start_service(void *thread_id) { } break; // terminate loop -- normally we don't keep restarting } - delete zt1Service; - zt1Service = (ZeroTier::OneService *)0; + delete ZeroTier::zt1Service; + ZeroTier::zt1Service = (ZeroTier::OneService *)0; return NULL; } diff --git a/src/lwIP.cpp b/src/lwIP.cpp index cab89e3..1f30c82 100644 --- a/src/lwIP.cpp +++ b/src/lwIP.cpp @@ -36,6 +36,13 @@ #include "netif/ethernet.h" #include "lwip/etharp.h" +#if defined(LIBZT_IPV6) +#include "lwip/ethip6.h" +#include "lwip/nd6.h" +#endif + +void nd6_tmr(void); + err_t tapif_init(struct netif *netif) { DEBUG_INFO(); @@ -82,6 +89,7 @@ namespace ZeroTier if (std::find(tap->_ips.begin(),tap->_ips.end(),ip) == tap->_ips.end()) { tap->_ips.push_back(ip); std::sort(tap->_ips.begin(),tap->_ips.end()); + char ipbuf[64], nmbuf[64]; #if defined(LIBZT_IPV4) if (ip.isV4()) { // Set IP @@ -101,13 +109,11 @@ namespace ZeroTier tap->lwipdev.flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP | NETIF_FLAG_LINK_UP | NETIF_FLAG_UP; netif_set_default(&(tap->lwipdev)); netif_set_up(&(tap->lwipdev)); - char ipbuf[64]; - DEBUG_INFO("addr=%s, netmask=%s", ip.toString(ipbuf), ip.netmask().toString(ipbuf)); + DEBUG_INFO("addr=%s, netmask=%s", ip.toString(ipbuf), ip.netmask().toString(nmbuf)); } #endif #if defined(LIBZT_IPV6) if(ip.isV6()) { - DEBUG_INFO("local_addr=%s", ip.toString().c_str()); static ip6_addr_t addr6; struct sockaddr_in6 in6; memcpy(in6.sin6_addr.s6_addr,ip.rawIpData(),16); @@ -128,8 +134,7 @@ namespace ZeroTier tap->lwipdev6.output_ip6 = ethip6_output; tap->lwipdev6.state = tap; tap->lwipdev6.flags = NETIF_FLAG_LINK_UP | NETIF_FLAG_UP; - char ipbuf[64]; - DEBUG_INFO("addr=%s, netmask=%s", ip.toString(ipbuf), ip.netmask().toString(ipbuf)); + DEBUG_INFO("addr=%s, netmask=%s", ip.toString(ipbuf), ip.netmask().toString(nmbuf)); } #endif } @@ -138,13 +143,12 @@ namespace ZeroTier void lwIP::lwip_loop(SocketTap *tap) { DEBUG_INFO(); - uint64_t prev_tcp_time = 0, prev_status_time = 0, prev_discovery_time = 0; + uint64_t prev_tcp_time = 0, prev_discovery_time = 0; while(tap->_run) { uint64_t now = OSUtils::now(); uint64_t since_tcp = now - prev_tcp_time; uint64_t since_discovery = now - prev_discovery_time; - uint64_t since_status = now - prev_status_time; uint64_t tcp_remaining = LWIP_TCP_TIMER_INTERVAL; uint64_t discovery_remaining = 5000; @@ -173,6 +177,7 @@ namespace ZeroTier discovery_remaining = DISCOVERY_INTERVAL - since_discovery; } tap->_phy.poll((unsigned long)std::min(tcp_remaining,discovery_remaining)); + tap->Housekeeping(); } } @@ -244,7 +249,7 @@ namespace ZeroTier return -1; } - int lwIP::lwip_Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen) + int lwIP::lwip_Connect(Connection *conn, const struct sockaddr *addr, socklen_t addrlen) { DEBUG_INFO(); ip_addr_t ba; @@ -252,9 +257,8 @@ namespace ZeroTier int port = 0, err = 0; #if defined(LIBZT_IPV4) - struct sockaddr_in *in4; + struct sockaddr_in *in4 = (struct sockaddr_in *)addr; if(addr->sa_family == AF_INET) { - in4 = (struct sockaddr_in *)addr; inet_ntop(AF_INET, &(in4->sin_addr), addrstr, INET_ADDRSTRLEN); DEBUG_INFO("%s:%d", addrstr, lwip_ntohs(in4->sin_port)); } @@ -336,9 +340,10 @@ namespace ZeroTier return -1; } } + return err; } - int lwIP::lwip_Bind(SocketTap *tap, Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen) + int lwIP::lwip_Bind(SocketTap *tap, Connection *conn, const struct sockaddr *addr, socklen_t addrlen) { DEBUG_INFO(); ip_addr_t ba; @@ -346,9 +351,8 @@ namespace ZeroTier int port = 0, err = 0; #if defined(LIBZT_IPV4) - struct sockaddr_in *in4; + struct sockaddr_in *in4 = (struct sockaddr_in *)addr; if(addr->sa_family == AF_INET) { - in4 = (struct sockaddr_in *)addr; inet_ntop(AF_INET, &(in4->sin_addr), addrstr, INET_ADDRSTRLEN); DEBUG_INFO("%s:%d", addrstr, lwip_ntohs(in4->sin_port)); } @@ -422,7 +426,6 @@ namespace ZeroTier Connection* lwIP::lwip_Accept(Connection *conn) { - DEBUG_EXTRA("conn=%p", conn); if(!conn) { DEBUG_ERROR("invalid conn"); handle_general_failure(); @@ -430,9 +433,7 @@ namespace ZeroTier } // Retreive first of queued Connections from parent connection Connection *new_conn = NULL; - DEBUG_INFO("locking..."); Mutex::Lock _l(conn->tap->_tcpconns_m); - DEBUG_INFO("locked."); if(conn->_AcceptedConnections.size()) { new_conn = conn->_AcceptedConnections.front(); conn->_AcceptedConnections.pop(); @@ -443,6 +444,7 @@ namespace ZeroTier int lwIP::lwip_Read(Connection *conn, bool lwip_invoked) { DEBUG_EXTRA("conn=%p", conn); + int err = 0; if(!conn) { DEBUG_ERROR("no connection"); return -1; @@ -458,49 +460,39 @@ namespace ZeroTier int n = conn->tap->_phy.streamSend(conn->sock, conn->RXbuf->get_buf(), wr); char str[22]; memcpy(str, conn->RXbuf->get_buf(), 22); - DEBUG_INFO("string = %s", str); - DEBUG_INFO("n =%d", n); conn->RXbuf->consume(n); - //if(n == max) - //{ - //if(conn->socket_type == SOCK_DGRAM){ - // conn->tap->_phy.setNotifyWritable(conn->sock, false); - //} + if(conn->socket_type == SOCK_DGRAM) + { + // TODO + } if(conn->socket_type == SOCK_STREAM) { // Only acknolwedge receipt of TCP packets tcp_recved((struct tcp_pcb*)conn->pcb, n); - DEBUG_TRANS("TCP RX %ld bytes", n); + DEBUG_TRANS("TCP RX %d bytes", n); } - //} } if(conn->RXbuf->count() == 0) { DEBUG_INFO("wrote everything"); conn->tap->_phy.setNotifyWritable(conn->sock, false); // nothing else to send to the app } if(!lwip_invoked) { - DEBUG_INFO("unlocking..."); conn->tap->_tcpconns_m.unlock(); conn->_rx_m.unlock(); } - - /* - int payload_sz, addr_sz_offset = sizeof(struct sockaddr_storage); - memcpy(&payload_sz, conn->rxbuf + addr_sz_offset, sizeof(int)); // OPT: - // extract address - struct sockaddr_storage addr; - memcpy(&addr, conn->rxbuf, addr_sz_offset); - */ + return err; } int lwIP::lwip_Write(Connection *conn, void *data, ssize_t len) { - DEBUG_EXTRA("conn=%p", (void*)&conn); + DEBUG_EXTRA("conn=%p, len=%d", (void*)&conn, len); + int err = 0; if(!conn) { DEBUG_ERROR("no connection"); return -1; } if(conn->socket_type == SOCK_DGRAM) { + DEBUG_ERROR("socket_type==SOCK_DGRAM"); // TODO: Packet re-assembly hasn't yet been tested with lwIP so UDP packets are limited to MTU-sized chunks int udp_trans_len = std::min((ssize_t)conn->TXbuf->count(), (ssize_t)ZT_MAX_MTU); DEBUG_EXTRA("allocating pbuf chain of size=%d for UDP packet, txsz=%d", udp_trans_len, conn->TXbuf->count()); @@ -526,24 +518,27 @@ namespace ZeroTier } if(conn->socket_type == SOCK_STREAM) { + DEBUG_ERROR("socket_type==SOCK_STREAM"); // How much we are currently allowed to write to the connection ssize_t sndbuf = ((struct tcp_pcb*)conn->pcb)->snd_buf; - int err, sz, r; - + int err, r; if(!sndbuf) { // PCB send buffer is full, turn off readability notifications for the // corresponding PhySocket until nc_sent() is called and confirms that there is // now space on the buffer - DEBUG_ERROR(" LWIP stack is full, sndbuf == 0"); + DEBUG_ERROR("lwIP stack is full, sndbuf == 0"); conn->tap->_phy.setNotifyReadable(conn->sock, false); return -1; } - if(conn->TXbuf->count() <= 0) - return -1; // Nothing to write - - //if(!conn->listening) - // tcp_output(conn->TCP_pcb); - + int buf_w = conn->TXbuf->write((const unsigned char*)data, len); + if (buf_w != len) { + // because we checked ZT_TCP_TX_BUF_SZ above, this should not happen + DEBUG_ERROR("TX wrote only %d but expected to write %d", buf_w, len); + exit(0); + } + if(conn->TXbuf->count() <= 0) { + return -1; // nothing to write + } if(conn->sock) { r = std::min((ssize_t)conn->TXbuf->count(), sndbuf); // Writes data pulled from the client's socket buffer to LWIP. This merely sends the @@ -552,9 +547,9 @@ namespace ZeroTier err = tcp_write((struct tcp_pcb*)conn->pcb, conn->TXbuf->get_buf(), r, TCP_WRITE_FLAG_COPY); tcp_output((struct tcp_pcb*)conn->pcb); if(err != ERR_OK) { - DEBUG_ERROR(" error while writing to PCB, err=%d", err); + DEBUG_ERROR("error while writing to lwIP tcp_pcb, err=%d", err); if(err == -1) - DEBUG_ERROR("out of memory"); + DEBUG_ERROR("lwIP out of memory"); return -1; } else { conn->TXbuf->consume(r); // success @@ -563,6 +558,7 @@ namespace ZeroTier } } } + return err; } int lwIP::lwip_Close(Connection *conn) @@ -580,7 +576,6 @@ namespace ZeroTier DEBUG_EXTRA("ignoring close request. invalid PCB state for this operation. sock=%p", conn->sock); return -1; } - // DEBUG_BLANK("__tcp_close(...)"); struct tcp_pcb* tpcb = (struct tcp_pcb*)conn->pcb; if(tcp_close(tpcb) == ERR_OK) { // Unregister callbacks for this PCB @@ -614,14 +609,9 @@ namespace ZeroTier //Mutex::Lock _l(conn->tap->_tcpconns_m); //Mutex::Lock _l2(conn->_rx_m); - - DEBUG_INFO("locking..."); - conn->tap->_tcpconns_m.lock(); conn->_rx_m.lock(); - DEBUG_INFO("locked."); - struct pbuf* q = p; if(p == NULL) { if(((struct tcp_pcb*)conn->pcb)->state == CLOSE_WAIT) { @@ -725,14 +715,13 @@ namespace ZeroTier { DEBUG_ERROR("err=%d", err); Connection *conn = (Connection *)arg; - Mutex::Lock _l(conn->tap->_tcpconns_m); - if(!conn){ DEBUG_ERROR("conn==NULL"); errno = -1; // FIXME: Find more appropriate value } + Mutex::Lock _l(conn->tap->_tcpconns_m); int fd = conn->tap->_phy.getDescriptor(conn->sock); - DEBUG_ERROR("conn=%p, pcb=%p, err=%d", conn, conn->pcb, err); + DEBUG_ERROR("conn=%p, pcb=%p, fd=%d, err=%d", conn, conn->pcb, fd, err); DEBUG_ERROR("closing connection"); conn->tap->Close(conn); switch(err) @@ -781,19 +770,19 @@ namespace ZeroTier // TODO: Below are errors which don't have a standard errno correlate case ERR_RST: - //l->tap->sendReturnValue(fd, -1, -1); + // -1 break; case ERR_CLSD: - //l->tap->sendReturnValue(fd, -1, -1); + // -1 break; case ERR_CONN: - //l->tap->sendReturnValue(fd, -1, -1); + // -1 break; case ERR_ARG: - //l->tap->sendReturnValue(fd, -1, -1); + // -1 break; case ERR_IF: - //l->tap->sendReturnValue(fd, -1, -1); + // -1 break; default: break; diff --git a/src/lwIP.hpp b/src/lwIP.hpp index 8e566bb..c1d1e21 100644 --- a/src/lwIP.hpp +++ b/src/lwIP.hpp @@ -56,6 +56,7 @@ struct netif; #endif #if defined(LIBZT_IPV6) #include "lwip/ip6_addr.h" +#include "ethip6.h" #define LWIP_NETIF_ADD_SIG struct netif *netif, void *state, netif_init_fn init, netif_input_fn input #define LWIP_ETHIP6_OUTPUT_SIG struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr #define LWIP_ETHARP_OUTPUT_SIG struct netif *netif, struct pbuf *q, const ip6_addr_t *ipaddr @@ -109,9 +110,9 @@ struct netif; #endif #if defined(LIBZT_IPV6) extern "C" void nd6_tmr(void); - extern "C" void netif_ip6_addr_set_state(LWIP_NETIF_IP6_ADDR_SET_STATE_SIG); + //extern "C" void netif_ip6_addr_set_state(LWIP_NETIF_IP6_ADDR_SET_STATE_SIG); extern "C" void netif_create_ip6_linklocal_address(LWIP_NETIF_CREATE_IP6_LINKLOCAL_ADDRESS_SIG); - extern "C" err_t _ethip6_output(LWIP_ETHIP6_OUTPUT_SIG); + extern "C" err_t ethip6_output(LWIP_ETHIP6_OUTPUT_SIG); #endif extern "C" void lwip_init(); @@ -185,8 +186,8 @@ namespace ZeroTier { void lwip_rx(SocketTap *tap, const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); int lwip_Socket(void **pcb, int socket_family, int socket_type, int protocol); - int lwip_Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen); - int lwip_Bind(SocketTap *tap, Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen); + int lwip_Connect(Connection *conn, const struct sockaddr *addr, socklen_t addrlen); + int lwip_Bind(SocketTap *tap, Connection *conn, const struct sockaddr *addr, socklen_t addrlen); int lwip_Listen(Connection *conn, int backlog); Connection* lwip_Accept(Connection *conn); int lwip_Read(Connection *conn, bool lwip_invoked); diff --git a/src/picoTCP.cpp b/src/picoTCP.cpp index 0edecbe..5312a8e 100644 --- a/src/picoTCP.cpp +++ b/src/picoTCP.cpp @@ -48,12 +48,12 @@ #include "Constants.hpp" #include "Phy.hpp" - +int pico_ipv4_to_string(PICO_IPV4_TO_STRING_SIG); extern "C" int pico_stack_init(void); extern "C" void pico_stack_tick(void); - -int pico_ipv4_to_string(PICO_IPV4_TO_STRING_SIG); extern "C" int pico_ipv4_link_add(PICO_IPV4_LINK_ADD_SIG); +extern "C" int pico_ipv4_route_add(PICO_IPV4_ROUTE_ADD_SIG); +extern "C" int pico_ipv4_route_del(PICO_IPV4_ROUTE_DEL_SIG); extern "C" int pico_device_init(PICO_DEVICE_INIT_SIG); extern "C" int pico_string_to_ipv4(PICO_STRING_TO_IPV4_SIG); extern "C" int pico_string_to_ipv6(PICO_STRING_TO_IPV6_SIG); @@ -131,6 +131,39 @@ namespace ZeroTier { } return false; } + + // TODO: + // pico_ipv6_route_add + // pico_ipv6_route_del + + bool picoTCP::pico_route_add(SocketTap *tap, const InetAddress &addr, const InetAddress &nm, const InetAddress &gw, int metric) + { + struct pico_ipv4_link *link = NULL; + struct pico_ip4 address; + address.addr = *((uint32_t *)addr.rawIpData()); + struct pico_ip4 netmask; + netmask.addr = *((uint32_t *)nm.rawIpData()); + struct pico_ip4 gateway; + gateway.addr = *((uint32_t *)gw.rawIpData()); + int err = pico_ipv4_route_add(address, netmask, gateway, metric, link); + if(err) { + DEBUG_ERROR("err=%d, %s", err, beautify_pico_error(pico_err)); + } + return err; + } + + bool picoTCP::pico_route_del(SocketTap *tap, const InetAddress &addr, const InetAddress &nm, int metric) + { + struct pico_ip4 address; + address.addr = *((uint32_t *)addr.rawIpData()); + struct pico_ip4 netmask; + netmask.addr = *((uint32_t *)nm.rawIpData()); + int err = pico_ipv4_route_del(address, netmask, metric); + if(err) { + DEBUG_ERROR("err=%d, %s", err, beautify_pico_error(pico_err)); + } + return err; + } void picoTCP::pico_loop(SocketTap *tap) { @@ -138,7 +171,7 @@ namespace ZeroTier { { tap->_phy.poll(ZT_PHY_POLL_INTERVAL); pico_stack_tick(); - //tap->Housekeeping(); + tap->Housekeeping(); } } @@ -521,7 +554,7 @@ namespace ZeroTier { protocol_version = PICO_PROTO_IPV6; if(socket_type == SOCK_DGRAM) { - DEBUG_ERROR("SOCK_DGRAM"); + DEBUG_INFO("SOCK_DGRAM"); psock = pico_socket_open( protocol_version, PICO_PROTO_UDP, &ZeroTier::picoTCP::pico_cb_socket_activity); if(psock) { // configure size of UDP SND/RCV buffers @@ -555,7 +588,7 @@ namespace ZeroTier { return err; } - int picoTCP::pico_Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen) + int picoTCP::pico_Connect(Connection *conn, const struct sockaddr *addr, socklen_t addrlen) { if(!conn || !conn->picosock) { DEBUG_ERROR("invalid conn or conn->picosock"); @@ -582,6 +615,9 @@ namespace ZeroTier { pico_string_to_ipv6(ipv6_str, zaddr.addr); err = pico_socket_connect(conn->picosock, &zaddr, in6->sin6_port); } + if(err) { + DEBUG_ERROR("err=%d, %s", err, beautify_pico_error(pico_err)); + } memcpy(&(conn->peer_addr), &addr, sizeof(struct sockaddr_storage)); if(err == PICO_ERR_EPROTONOSUPPORT) @@ -593,7 +629,7 @@ namespace ZeroTier { return err; } - int picoTCP::pico_Bind(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen) + int picoTCP::pico_Bind(Connection *conn, const struct sockaddr *addr, socklen_t addrlen) { //DEBUG_INFO(); if(!conn || !conn->picosock) { @@ -647,7 +683,7 @@ namespace ZeroTier { return err; } - int picoTCP::pico_Listen(Connection *conn, int fd, int backlog) + int picoTCP::pico_Listen(Connection *conn, int backlog) { //DEBUG_INFO(); if(!conn || !conn->picosock) { @@ -776,7 +812,7 @@ namespace ZeroTier { { int err = 0; // TODO: Add RingBuffer overflow checks - //DEBUG_INFO("conn=%p, len = %d", conn, len); + DEBUG_INFO("conn=%p, len=%d", conn, len); Mutex::Lock _l(conn->_tx_m); if(len <= 0) { DEBUG_ERROR("invalid write length (len=%d)", len); @@ -793,51 +829,56 @@ namespace ZeroTier { return -1; } - int original_txsz = conn->TXbuf->count(); + if(conn->socket_type == SOCK_DGRAM) + { + int r; + if((r = pico_socket_write(conn->picosock, data, len)) < 0) { + DEBUG_ERROR("unable to write to picosock=%p, r=%d", conn->picosock, r); + err = -1; + } + else { + err = r; // successful write + } + DEBUG_TRANS("[ UDP TX -> STACK] :: conn=%p, len=%d, err=%s", conn, r, beautify_pico_error(pico_err)); + } + if(conn->socket_type == SOCK_STREAM) + { + int original_txsz = conn->TXbuf->count(); + if(original_txsz + len >= ZT_TCP_TX_BUF_SZ) { + DEBUG_ERROR("txsz=%d, len=%d", original_txsz, len); + DEBUG_ERROR("TX buffer is too small, try increasing ZT_TCP_TX_BUF_SZ in libzt.h"); + exit(0); + } + int buf_w = conn->TXbuf->write((const unsigned char*)data, len); + if (buf_w != len) { + // because we checked ZT_TCP_TX_BUF_SZ above, this should not happen + DEBUG_ERROR("TX wrote only %d but expected to write %d", buf_w, len); + exit(0); + } + //DEBUG_INFO("TXbuf->count() = %d", conn->TXbuf->count()); + int txsz = conn->TXbuf->count(); - if(original_txsz + len >= ZT_TCP_TX_BUF_SZ) { - DEBUG_ERROR("txsz = %d, len = %d", original_txsz, len); - DEBUG_ERROR("TX buffer is too small, try increasing ZT_TCP_TX_BUF_SZ in libzt.h"); - exit(0); + int r, max_write_len = std::min(std::min(txsz, ZT_SDK_MTU),ZT_STACK_SOCKET_WR_MAX); + //int buf_r = conn->TXbuf->read(conn->tmptxbuf, max_write_len); + + if((r = pico_socket_write(conn->picosock, conn->TXbuf->get_buf(), max_write_len)) < 0) { + DEBUG_ERROR("unable to write to picosock=%p, r=%d", conn->picosock, r); + err = -1; + } + else { + err = r; // successful write + } + if(r>0){ + conn->TXbuf->consume(r); + } + DEBUG_TRANS("[ TCP TX -> STACK] :: conn=%p, len=%d", conn, r); } - - int buf_w = conn->TXbuf->write((const unsigned char*)data, len); - if (buf_w != len) { - // because we checked ZT_TCP_TX_BUF_SZ above, this should not happen - DEBUG_ERROR("TX wrote only %d but expected to write %d", buf_w, len); - exit(0); - } - //DEBUG_INFO("TXbuf->count() = %d", conn->TXbuf->count()); - int txsz = conn->TXbuf->count(); - - //if(original_txsz > 0) - // return; // don't write here, we already have stuff in the queue, a callback will handle it - - int r, max_write_len = std::min(std::min(txsz, ZT_SDK_MTU),ZT_STACK_SOCKET_WR_MAX); - //int buf_r = conn->TXbuf->read(conn->tmptxbuf, max_write_len); - - if((r = pico_socket_write(conn->picosock, conn->TXbuf->get_buf(), max_write_len)) < 0) { - DEBUG_ERROR("unable to write to picosock=%p, r=%d", conn->picosock, r); - err = -1; - } - else { - err = r; // successful write - } - if(conn->socket_type == SOCK_STREAM) { - //DEBUG_TRANS("[ TCP TX -> STACK] :: conn = %p, len = %d", conn, r); - } - if(conn->socket_type == SOCK_DGRAM) { - //DEBUG_TRANS("[ UDP TX -> STACK] :: conn = %p, len = %d", conn, r); - } - if(r>0) - conn->TXbuf->consume(r); - return err; } int picoTCP::pico_Close(Connection *conn) { - DEBUG_INFO("conn = %p, picosock=%p, fd = %d", conn, conn->picosock, conn->app_fd); + DEBUG_INFO("conn=%p, picosock=%p, fd=%d", conn, conn->picosock, conn->app_fd); if(!conn || !conn->picosock) return ZT_ERR_GENERAL_FAILURE; int err = 0; diff --git a/src/picoTCP.hpp b/src/picoTCP.hpp index 1f98126..e3f5d2e 100644 --- a/src/picoTCP.hpp +++ b/src/picoTCP.hpp @@ -67,6 +67,10 @@ #define PICO_SOCKET_SHUTDOWN_SIG struct pico_socket *s, int mode #define PICO_SOCKET_ACCEPT_SIG struct pico_socket *s, void *orig, uint16_t *port #define PICO_IPV6_LINK_ADD_SIG struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask +#define PICO_IPV4_ROUTE_ADD_SIG struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link +#define PICO_IPV4_ROUTE_DEL_SIG struct pico_ip4 address, struct pico_ip4 netmask, int metric +#define PICO_IPV6_ROUTE_ADD_SIG struct pico_ip6 address, struct pico_ip6 netmask, struct pico_ip6 gateway, int metric, struct pico_ipv6_link *link +#define PICO_IPV6_ROUTE_DEL_SIG struct pico_ip6 address, struct pico_ip6 netmask, struct pico_ip6 gateway, int metric, struct pico_ipv6_link *link namespace ZeroTier { @@ -92,6 +96,16 @@ namespace ZeroTier */ bool pico_init_interface(ZeroTier::SocketTap *tap, const ZeroTier::InetAddress &ip); + /* + * Adds a route to the picoTCP device + */ + bool pico_route_add(SocketTap *tap, const InetAddress &addr, const InetAddress &nm, const InetAddress &gw, int metric); + + /* + * Deletes a route from the picoTCP device + */ + bool pico_route_del(SocketTap *tap, const InetAddress &addr, const InetAddress &nm, int metric); + /* * Main stack loop */ @@ -130,17 +144,17 @@ namespace ZeroTier /* * Connect to remote host via userspace network stack interface - Called from SocketTap */ - int pico_Connect(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen); + int pico_Connect(Connection *conn, const struct sockaddr *addr, socklen_t addrlen); /* * Bind to a userspace network stack interface - Called from SocketTap */ - int pico_Bind(Connection *conn, int fd, const struct sockaddr *addr, socklen_t addrlen); + int pico_Bind(Connection *conn, const struct sockaddr *addr, socklen_t addrlen); /* * Listen for incoming connections - Called from SocketTap */ - int pico_Listen(Connection *conn, int fd, int backlog); + int pico_Listen(Connection *conn, int backlog); /* * Accept an incoming connection - Called from SocketTap diff --git a/test/layer2.cpp b/test/layer2.cpp index 76d28f8..8bf9f21 100644 --- a/test/layer2.cpp +++ b/test/layer2.cpp @@ -57,6 +57,10 @@ int main(int argc , char *argv[]) } fprintf(stderr, "Created raw socket (%d)\n", fd); +#if defined(__APPLE__) + fprintf(stderr, "SOCK_RAW not supported on mac builds yet. exiting"); + exit(0); +#endif #if defined(__linux__) // The rest of this file isn't yet supported on non-linux platforms // get interface index to bind on struct ifreq if_idx; diff --git a/test/selftest.cpp b/test/selftest.cpp index 7c0f121..2a7986d 100644 --- a/test/selftest.cpp +++ b/test/selftest.cpp @@ -345,7 +345,7 @@ void udp_client_4(UNIT_TEST_SIG_4) if((sockfd = zts_socket(AF_INET, SOCK_DGRAM, 0)) < 0) DEBUG_ERROR("error creating ZeroTier socket"); - w = zts_sendto(sockfd, str, strlen(str), 0, (struct sockaddr *)&addr, sizeof(addr)); + w = zts_sendto(sockfd, str, strlen(str), 0, (struct sockaddr *)addr, sizeof(addr)); memset(rbuf, 0, sizeof(rbuf)); int serverlen = sizeof(addr); r = zts_recvfrom(sockfd, rbuf, STR_SIZE, 0, (struct sockaddr *)&addr, (socklen_t *)&serverlen); @@ -367,10 +367,13 @@ void udp_server_4(UNIT_TEST_SIG_4) if((sockfd = zts_socket(AF_INET, SOCK_DGRAM, 0)) < 0) DEBUG_ERROR("error creating ZeroTier socket"); + if((err = zts_bind(sockfd, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) < 0)) + DEBUG_ERROR("error binding to interface (%d)", err); + int serverlen = sizeof(addr); r = zts_recvfrom(sockfd, rbuf, STR_SIZE, 0, (struct sockaddr *)&addr, (socklen_t *)&serverlen); memset(rbuf, 0, sizeof(rbuf)); - w = zts_sendto(sockfd, str, strlen(str), 0, (struct sockaddr *)&addr, sizeof(addr)); + w = zts_sendto(sockfd, str, strlen(str), 0, (struct sockaddr *)addr, sizeof(addr)); sleep(WAIT_FOR_TRANSMISSION_TO_COMPLETE); err = zts_close(sockfd); @@ -1159,6 +1162,23 @@ int obscure_api_test() return err; } +void get_network_routes(char *nwid) +{ + // Retreive managed routes for a given ZeroTier network + std::vector *routes = zts_get_network_routes(nwid); + + for(int i=0; isize(); i++) { + struct sockaddr_in *target = (struct sockaddr_in*)&(routes->at(i).target); + struct sockaddr_in *via = (struct sockaddr_in*)&(routes->at(i).via); + char target_str[INET6_ADDRSTRLEN]; + memset(target_str, 0, INET6_ADDRSTRLEN); + inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)target)->sin_addr.s_addr, target_str, INET_ADDRSTRLEN); + char via_str[INET6_ADDRSTRLEN]; + memset(via_str, 0, INET6_ADDRSTRLEN); + inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)via)->sin_addr.s_addr, via_str, INET_ADDRSTRLEN); + DEBUG_INFO("", target_str, via_str, routes->at(i).flags); + } +} /****************************************************************************/ /* RANDOMIZED API TEST */ @@ -1433,6 +1453,7 @@ int main(int argc , char *argv[]) // ipv4 client/server + ipv = 4; if(mode == TEST_MODE_SERVER) { create_addr(local_ipstr, port, ipv, (struct sockaddr *)&addr); @@ -1459,7 +1480,7 @@ int main(int argc , char *argv[]) port++; // UDP - +/* if(mode == TEST_MODE_SERVER) { create_addr(local_ipstr, port, ipv, (struct sockaddr *)&addr); udp_server_4((struct sockaddr_in *)&addr, operation, count, delay, details, &passed); // tcp_server_4 @@ -1483,7 +1504,7 @@ int main(int argc , char *argv[]) } RECORD_RESULTS(&test_number, passed, details, &results); port++; - +*/ // ipv4 sustained transfer ipv = 4; if(mode == TEST_MODE_SERVER) {