Przeglądaj źródła

Merge branch 'dev' of http://10.6.6.2/zerotier/ZeroTierOne into dev

Adam Ierymenko 8 lat temu
rodzic
commit
b3298a8f57

+ 226 - 0
java/jni/com_zerotierone_sdk_Node.cpp

@@ -56,6 +56,7 @@ namespace {
             , eventListener(NULL)
             , frameListener(NULL)
             , configListener(NULL)
+            , pathChecker(NULL)
             , callbacks(NULL)
         {
             callbacks = (ZT_Node_Callbacks*)malloc(sizeof(ZT_Node_Callbacks));
@@ -73,6 +74,7 @@ namespace {
             env->DeleteGlobalRef(eventListener);
             env->DeleteGlobalRef(frameListener);
             env->DeleteGlobalRef(configListener);
+            env->DeleteGlobalRef(pathChecker);
 
             free(callbacks);
             callbacks = NULL;
@@ -90,6 +92,7 @@ namespace {
         jobject eventListener;
         jobject frameListener;
         jobject configListener;
+        jobject pathChecker;
 
         ZT_Node_Callbacks *callbacks;
     };
@@ -487,6 +490,165 @@ namespace {
         return retval;
     }
 
+    int PathCheckFunction(ZT_Node *node,
+        void *userPtr,
+        void *threadPtr,
+        uint64_t address,
+        const struct sockaddr_storage *localAddress,
+        const struct sockaddr_storage *remoteAddress)
+    {
+        JniRef *ref = (JniRef*)userPtr;
+        assert(ref->node == node);
+
+        if(ref->pathChecker == NULL) {
+            return true;
+        }
+
+        JNIEnv *env = NULL;
+        ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
+
+        jclass pathCheckerClass = env->GetObjectClass(ref->pathChecker);
+        if(pathCheckerClass == NULL)
+        {
+            LOGE("Couldn't find class for PathChecker instance");
+            return true;
+        }
+
+        jmethodID pathCheckCallbackMethod = lookup.findMethod(pathCheckerClass,
+            "onPathCheck", "(JLjava/net/InetSocketAddress;Ljava/net/InetSocketAddress;)Z");
+        if(pathCheckCallbackMethod == NULL)
+        {
+            LOGE("Couldn't find onPathCheck method implementation");
+            return true;
+        }
+
+        jobject localAddressObj = NULL;
+        jobject remoteAddressObj = NULL;
+
+        if(memcmp(localAddress, &ZT_SOCKADDR_NULL, sizeof(sockaddr_storage)) != 0)
+        {
+            localAddressObj = newInetSocketAddress(env, *localAddress);
+        }
+        if(memcmp(remoteAddress, &ZT_SOCKADDR_NULL, sizeof(sockaddr_storage)) != 0)
+        {
+            remoteAddressObj = newInetSocketAddress(env, *remoteAddress);
+        }
+
+        return env->CallBooleanMethod(ref->pathChecker, pathCheckCallbackMethod, address, localAddressObj, remoteAddressObj);
+    }
+
+    int PathLookupFunction(ZT_Node *node,
+        void *userPtr,
+        void *threadPtr,
+        uint64_t address,
+        int ss_family,
+        struct sockaddr_storage *result)
+    {
+        JniRef *ref = (JniRef*)userPtr;
+        assert(ref->node == node);
+
+        if(ref->pathChecker == NULL) {
+            return false;
+        }
+
+        JNIEnv *env = NULL;
+        ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
+
+        jclass pathCheckerClass = env->GetObjectClass(ref->pathChecker);
+        if(pathCheckerClass == NULL)
+        {
+            LOGE("Couldn't find class for PathChecker instance");
+            return false;
+        }
+
+        jmethodID pathLookupMethod = lookup.findMethod(pathCheckerClass,
+            "onPathLookup", "(JI)Ljava/net/InetSocketAddress;");
+        if(pathLookupMethod == NULL) {
+            return false;
+        }
+
+        jobject sockAddressObject = env->CallObjectMethod(ref->pathChecker, pathLookupMethod, address, ss_family);
+        if(sockAddressObject == NULL)
+        {
+            LOGE("Unable to call onPathLookup implementation");
+            return false;
+        }
+
+        jclass inetSockAddressClass = env->GetObjectClass(sockAddressObject);
+        if(inetSockAddressClass == NULL)
+        {
+            LOGE("Unable to find InetSocketAddress class");
+            return false;
+        }
+
+        jmethodID getAddressMethod = lookup.findMethod(inetSockAddressClass, "getAddress", "()Ljava/net/InetAddress;");
+        if(getAddressMethod == NULL)
+        {
+            LOGE("Unable to find InetSocketAddress.getAddress() method");
+            return false;
+        }
+
+        jmethodID getPortMethod = lookup.findMethod(inetSockAddressClass, "getPort", "()I");
+        if(getPortMethod == NULL)
+        {
+            LOGE("Unable to find InetSocketAddress.getPort() method");
+            return false;
+        }
+
+        jint port = env->CallIntMethod(sockAddressObject, getPortMethod);
+        jobject addressObject = env->CallObjectMethod(sockAddressObject, getAddressMethod);
+        
+        jclass inetAddressClass = lookup.findClass("java/net/InetAddress");
+        if(inetAddressClass == NULL)
+        {
+            LOGE("Unable to find InetAddress class");
+            return false;
+        }
+
+        getAddressMethod = lookup.findMethod(inetAddressClass, "getAddress", "()[B");
+        if(getAddressMethod == NULL)
+        {
+            LOGE("Unable to find InetAddress.getAddress() method");
+            return false;
+        }
+
+        jbyteArray addressBytes = (jbyteArray)env->CallObjectMethod(addressObject, getAddressMethod);
+        if(addressBytes == NULL)
+        {
+            LOGE("Unable to call InetAddress.getBytes()");
+            return false;
+        }
+
+        int addressSize = env->GetArrayLength(addressBytes);
+        if(addressSize == 4)
+        {
+            // IPV4
+            sockaddr_in *addr = (sockaddr_in*)result;
+            addr->sin_family = AF_INET;
+            addr->sin_port = htons(port);
+            
+            void *data = env->GetPrimitiveArrayCritical(addressBytes, NULL);
+            memcpy(&addr->sin_addr, data, 4);
+            env->ReleasePrimitiveArrayCritical(addressBytes, data, 0);
+        }
+        else if (addressSize == 16)
+        {
+            // IPV6
+            sockaddr_in6 *addr = (sockaddr_in6*)result;
+            addr->sin6_family = AF_INET6;
+            addr->sin6_port = htons(port);
+            void *data = env->GetPrimitiveArrayCritical(addressBytes, NULL);
+            memcpy(&addr->sin6_addr, data, 16);
+            env->ReleasePrimitiveArrayCritical(addressBytes, data, 0);
+        }
+        else
+        {
+            return false;
+        }
+
+        return true;
+    }
+
     typedef std::map<uint64_t, JniRef*> NodeMap;
     static NodeMap nodeMap;
     ZeroTier::Mutex nodeMapMutex;
@@ -619,12 +781,28 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_node_1init(
     }
     ref->eventListener = env->NewGlobalRef(tmp);
 
+    fid = lookup.findField(
+        cls, "pathChecker", "Lcom/zerotier/sdk/PathChecker;");
+    if(fid == NULL)
+    {
+        LOGE("no path checker?");
+        return NULL;
+    }
+
+    tmp = env->GetObjectField(obj, fid);
+    if(tmp != NULL)
+    {
+        ref->pathChecker = env->NewGlobalRef(tmp);
+    }
+
     ref->callbacks->dataStoreGetFunction = &DataStoreGetFunction;
     ref->callbacks->dataStorePutFunction = &DataStorePutFunction;
     ref->callbacks->wirePacketSendFunction = &WirePacketSendFunction;
     ref->callbacks->virtualNetworkFrameFunction = &VirtualNetworkFrameFunctionCallback;
     ref->callbacks->virtualNetworkConfigFunction = &VirtualNetworkConfigFunctionCallback;
     ref->callbacks->eventCallback = &EventCallback;
+    ref->callbacks->pathCheckFunction = &PathCheckFunction;
+    ref->callbacks->pathLookupFunction = &PathLookupFunction;
 
     ZT_ResultCode rc = ZT_Node_new(
         &node,
@@ -1107,6 +1285,54 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_multicastUnsubscribe(
     return createResultObject(env, rc);
 }
 
+/*
+ * Class:   com_zerotier_sdk_Node
+ * Method:  orbit
+ * Signature: (JJJ)Lcom/zerotier/sdk/ResultCode;
+ */
+JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_orbit(
+    JNIEnv *env, jobject obj,
+    jlong id,
+    jlong in_moonWorldId,
+    jlong in_moonSeed)
+{
+    uint64_t nodeId = (uint64_t)id;
+    ZT_Node *node = findNode(nodeId);
+    if(node == NULL)
+    {
+        return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
+    }
+
+    uint64_t moonWorldId = (uint64_t)in_moonWorldId;
+    uint64_t moonSeed = (uint64_t)in_moonSeed;
+
+    ZT_ResultCode rc = ZT_Node_orbit(node, NULL, moonWorldId, moonSeed);
+    return createResultObject(env, rc);
+}
+
+/*
+ * Class:   com_zerotier_sdk_Node
+ * Method:  deorbit
+ * Signature: (JJ)L/com/zerotier/sdk/ResultCode;
+ */
+JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_deorbit(
+    JNIEnv *env, jobject obj,
+    jlong id,
+    jlong in_moonWorldId)
+{
+    uint64_t nodeId = (uint64_t)id;
+    ZT_Node *node = findNode(nodeId);
+    if(node == NULL)
+    {
+        return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
+    }
+
+    uint64_t moonWorldId = (uint64_t)in_moonWorldId;
+
+    ZT_ResultCode rc = ZT_Node_deorbit(node, NULL, moonWorldId);
+    return createResultObject(env, rc);
+}
+
 /*
  * Class:     com_zerotier_sdk_Node
  * Method:    address

+ 42 - 1
java/src/com/zerotier/sdk/Node.java

@@ -74,6 +74,7 @@ public class Node {
     private final EventListener eventListener;
     private final VirtualNetworkFrameListener frameListener;
     private final VirtualNetworkConfigListener configListener;
+    private final PathChecker pathChecker;
     
     /**
      * Create a new ZeroTier One node
@@ -88,6 +89,7 @@ public class Node {
      * @param eventListener User written instance of the {@link EventListener} interface to receive status updates and non-fatal error notices.  This instance must be unique per Node object.
      * @param frameListener 
      * @param configListener User written instance of the {@link VirtualNetworkConfigListener} interface to be called when virtual LANs are created, deleted, or their config parameters change.  This instance must be unique per Node object.
+     * @param pathChecker User written instance of the {@link PathChecker} interface. Not required and can be null.
      */
 	public Node(long now,
                 DataStoreGetListener getListener,
@@ -95,7 +97,8 @@ public class Node {
                 PacketSender sender,
                 EventListener eventListener,
                 VirtualNetworkFrameListener frameListener,
-                VirtualNetworkConfigListener configListener) throws NodeException
+                VirtualNetworkConfigListener configListener,
+                PathChecker pathChecker) throws NodeException
 	{
         this.nodeId = now;
 
@@ -105,6 +108,7 @@ public class Node {
         this.eventListener = eventListener;
         this.frameListener = frameListener;
         this.configListener = configListener;
+        this.pathChecker = pathChecker;
 
         ResultCode rc = node_init(now);
         if(rc != ResultCode.RESULT_OK)
@@ -318,6 +322,34 @@ public class Node {
         return multicastUnsubscribe(nodeId, nwid, multicastGroup, multicastAdi);
     }
 
+    /**
+     * Add or update a moon
+     *
+     * Moons are persisted in the data store in moons.d/, so this can persist
+     * across invocations if the contents of moon.d are scanned and orbit is
+     * called for each on startup.
+     *
+     * @param moonWorldId Moon's world ID
+     * @param moonSeed If non-zero, the ZeroTier address of any member of the moon to query for moon definition
+     * @return Error if moon was invalid or failed to be added
+     */
+    public ResultCode orbit(
+            long moonWorldId,
+            long moonSeed) {
+        return orbit(nodeId, moonWorldId, moonSeed);
+    }
+
+    /**
+     * Remove a moon (does nothing if not present)
+     *
+     * @param moonWorldId World ID of moon to remove
+     * @return Error if anything bad happened
+     */
+    public ResultCode deorbit(
+            long moonWorldId) {
+        return deorbit(nodeId, moonWorldId);
+    }
+
     /**
      * Get this node's 40-bit ZeroTier address
      *
@@ -420,6 +452,15 @@ public class Node {
         long multicastGroup,
         long multicastAdi);
 
+    private native ResultCode orbit(
+            long nodeId,
+            long moonWorldId,
+            long moonSeed);
+
+    private native ResultCode deorbit(
+            long nodeId,
+            long moonWorldId);
+
     private native long address(long nodeId);
 
     private native NodeStatus status(long nodeId);

+ 45 - 0
java/src/com/zerotier/sdk/PathChecker.java

@@ -0,0 +1,45 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2017  ZeroTier, Inc.  https://www.zerotier.com/
+ */
+
+package com.zerotier.sdk;
+
+import java.net.InetSocketAddress;
+
+public interface PathChecker {
+    /**
+     * Callback to check whether a path should be used for ZeroTier traffic
+     *
+     * This function must return true if the path should be used.
+     *
+     * If no path check function is specified, ZeroTier will still exclude paths
+     * that overlap with ZeroTier-assigned and managed IP address blocks. But the
+     * use of a path check function is recommended to ensure that recursion does
+     * not occur in cases where addresses are assigned by the OS or managed by
+     * an out of band mechanism like DHCP. The path check function should examine
+     * all configured ZeroTier interfaces and check to ensure that the supplied
+     * addresses will not result in ZeroTier traffic being sent over a ZeroTier
+     * interface (recursion).
+     *
+     * Obviously this is not required in configurations where this can't happen,
+     * such as network containers or embedded.
+     *
+     * @param ztAddress ZeroTier address or 0 for none/any
+     * @param localAddress Local interface address
+     * @param remoteAddress remote address
+     */
+    boolean onPathCheck(long ztAddress, InetSocketAddress localAddress, InetSocketAddress remoteAddress);
+
+    /**
+     * Function to get physical addresses for ZeroTier peers
+     *
+     * If provided this function will be occasionally called to get physical
+     * addresses that might be tried to reach a ZeroTier address.
+     *
+     * @param ztAddress ZeroTier address (least significant 40 bits)
+     * @param ss_family desired address family or -1 for any
+     * @return address and port of ztAddress or null
+     */
+    InetSocketAddress onPathLookup(long ztAddress, int ss_family);
+}