diff --git a/app/src/main/java/com/zerotier/sdk/DataStoreGetListener.java b/app/src/main/java/com/zerotier/sdk/DataStoreGetListener.java
index 317511e..105b14c 100644
--- a/app/src/main/java/com/zerotier/sdk/DataStoreGetListener.java
+++ b/app/src/main/java/com/zerotier/sdk/DataStoreGetListener.java
@@ -24,6 +24,7 @@
* redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/
*/
+
package com.zerotier.sdk;
public interface DataStoreGetListener {
@@ -48,7 +49,7 @@ public interface DataStoreGetListener {
* @param out_buffer buffer to put the object in
* @return size of the object
*/
- public long onDataStoreGet(
+ long onDataStoreGet(
String name,
byte[] out_buffer);
}
diff --git a/app/src/main/java/com/zerotier/sdk/DataStorePutListener.java b/app/src/main/java/com/zerotier/sdk/DataStorePutListener.java
index 77e5502..0fa8e19 100644
--- a/app/src/main/java/com/zerotier/sdk/DataStorePutListener.java
+++ b/app/src/main/java/com/zerotier/sdk/DataStorePutListener.java
@@ -24,6 +24,7 @@
* redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/
*/
+
package com.zerotier.sdk;
public interface DataStorePutListener {
@@ -43,7 +44,7 @@ public interface DataStorePutListener {
* @param secure set to user read/write only.
* @return 0 on success.
*/
- public int onDataStorePut(
+ int onDataStorePut(
String name,
byte[] buffer,
boolean secure);
@@ -54,6 +55,6 @@ public int onDataStorePut(
* @param name Object name
* @return 0 on success.
*/
- public int onDelete(
+ int onDelete(
String name);
}
diff --git a/app/src/main/java/com/zerotier/sdk/Event.java b/app/src/main/java/com/zerotier/sdk/Event.java
index 22d350e..fbc016c 100644
--- a/app/src/main/java/com/zerotier/sdk/Event.java
+++ b/app/src/main/java/com/zerotier/sdk/Event.java
@@ -27,26 +27,32 @@
package com.zerotier.sdk;
+/**
+ * Status codes sent to status update callback when things happen
+ *
+ * Defined in ZeroTierOne.h as ZT_Event
+ */
public enum Event {
+
/**
* Node has been initialized
*
* This is the first event generated, and is always sent. It may occur
* before Node's constructor returns.
*/
- EVENT_UP,
+ EVENT_UP(0),
/**
* Node is offline -- network does not seem to be reachable by any available strategy
*/
- EVENT_OFFLINE,
+ EVENT_OFFLINE(1),
/**
* Node is online -- at least one upstream node appears reachable
*
* Meta-data: none
*/
- EVENT_ONLINE,
+ EVENT_ONLINE(2),
/**
* Node is shutting down
@@ -55,7 +61,7 @@ public enum Event {
* It's done for convenience, since cleaning up other state in the event
* handler may appear more idiomatic.
*/
- EVENT_DOWN,
+ EVENT_DOWN(3),
/**
* Your identity has collided with another node's ZeroTier address
@@ -85,7 +91,7 @@ public enum Event {
* condition is a good way to make sure it never arises. It's like how
* umbrellas prevent rain and smoke detectors prevent fires. They do, right?
*/
- EVENT_FATAL_ERROR_IDENTITY_COLLISION,
+ EVENT_FATAL_ERROR_IDENTITY_COLLISION(4),
/**
* Trace (debugging) message
@@ -94,5 +100,55 @@ public enum Event {
*
* Meta-data: {@link String}, TRACE message
*/
- EVENT_TRACE
-}
\ No newline at end of file
+ EVENT_TRACE(5),
+
+ /**
+ * VERB_USER_MESSAGE received
+ *
+ * These are generated when a VERB_USER_MESSAGE packet is received via
+ * ZeroTier VL1.
+ */
+ EVENT_USER_MESSAGE(6),
+
+ /**
+ * Remote trace received
+ *
+ * These are generated when a VERB_REMOTE_TRACE is received. Note
+ * that any node can fling one of these at us. It is your responsibility
+ * to filter and determine if it's worth paying attention to. If it's
+ * not just drop it. Most nodes that are not active controllers ignore
+ * these, and controllers only save them if they pertain to networks
+ * with remote tracing enabled.
+ */
+ EVENT_REMOTE_TRACE(7);
+
+ @SuppressWarnings({"FieldCanBeLocal", "unused"})
+ private final int id;
+
+ Event(int id) {
+ this.id = id;
+ }
+
+ public static Event fromInt(int id) {
+ switch (id) {
+ case 0:
+ return EVENT_UP;
+ case 1:
+ return EVENT_OFFLINE;
+ case 2:
+ return EVENT_ONLINE;
+ case 3:
+ return EVENT_DOWN;
+ case 4:
+ return EVENT_FATAL_ERROR_IDENTITY_COLLISION;
+ case 5:
+ return EVENT_TRACE;
+ case 6:
+ return EVENT_USER_MESSAGE;
+ case 7:
+ return EVENT_REMOTE_TRACE;
+ default:
+ throw new RuntimeException("Unhandled value: " + id);
+ }
+ }
+}
diff --git a/app/src/main/java/com/zerotier/sdk/EventListener.java b/app/src/main/java/com/zerotier/sdk/EventListener.java
index 91050aa..88fb8af 100644
--- a/app/src/main/java/com/zerotier/sdk/EventListener.java
+++ b/app/src/main/java/com/zerotier/sdk/EventListener.java
@@ -27,19 +27,17 @@
package com.zerotier.sdk;
-import java.net.InetSocketAddress;
-import java.lang.String;
-
/**
* Interface to handle callbacks for ZeroTier One events.
*/
public interface EventListener {
+
/**
* Callback for events with no other associated metadata
*
* @param event {@link Event} enum
*/
- public void onEvent(Event event);
+ void onEvent(Event event);
/**
* Trace messages
@@ -48,5 +46,5 @@ public interface EventListener {
*
* @param message the trace message
*/
- public void onTrace(String message);
+ void onTrace(String message);
}
diff --git a/app/src/main/java/com/zerotier/sdk/NativeUtils.java b/app/src/main/java/com/zerotier/sdk/NativeUtils.java
deleted file mode 100644
index 07e1ef5..0000000
--- a/app/src/main/java/com/zerotier/sdk/NativeUtils.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.zerotier.sdk;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * Simple library class for working with JNI (Java Native Interface)
- *
- * @see http://adamheinrich.com/2012/how-to-load-native-jni-library-from-jar
- *
- * @author Adam Heirnich , http://www.adamh.cz
- */
-public class NativeUtils {
-
- /**
- * Private constructor - this class will never be instanced
- */
- private NativeUtils() {
- }
-
- /**
- * Loads library from current JAR archive
- *
- * The file from JAR is copied into system temporary directory and then loaded. The temporary file is deleted after exiting.
- * Method uses String as filename because the pathname is "abstract", not system-dependent.
- *
- * @param filename The filename inside JAR as absolute path (beginning with '/'), e.g. /package/File.ext
- * @throws IOException If temporary file creation or read/write operation fails
- * @throws IllegalArgumentException If source file (param path) does not exist
- * @throws IllegalArgumentException If the path is not absolute or if the filename is shorter than three characters (restriction of {@see File#createTempFile(java.lang.String, java.lang.String)}).
- */
- public static void loadLibraryFromJar(String path) throws IOException {
-
- if (!path.startsWith("/")) {
- throw new IllegalArgumentException("The path has to be absolute (start with '/').");
- }
-
- // Obtain filename from path
- String[] parts = path.split("/");
- String filename = (parts.length > 1) ? parts[parts.length - 1] : null;
-
- // Split filename to prexif and suffix (extension)
- String prefix = "";
- String suffix = null;
- if (filename != null) {
- parts = filename.split("\\.", 2);
- prefix = parts[0];
- suffix = (parts.length > 1) ? "."+parts[parts.length - 1] : null; // Thanks, davs! :-)
- }
-
- // Check if the filename is okay
- if (filename == null || prefix.length() < 3) {
- throw new IllegalArgumentException("The filename has to be at least 3 characters long.");
- }
-
- // Prepare temporary file
- File temp = File.createTempFile(prefix, suffix);
- temp.deleteOnExit();
-
- if (!temp.exists()) {
- throw new FileNotFoundException("File " + temp.getAbsolutePath() + " does not exist.");
- }
-
- // Prepare buffer for data copying
- byte[] buffer = new byte[1024];
- int readBytes;
-
- // Open and check input stream
- InputStream is = NativeUtils.class.getResourceAsStream(path);
- if (is == null) {
- throw new FileNotFoundException("File " + path + " was not found inside JAR.");
- }
-
- // Open output stream and copy data between source file in JAR and the temporary file
- OutputStream os = new FileOutputStream(temp);
- try {
- while ((readBytes = is.read(buffer)) != -1) {
- os.write(buffer, 0, readBytes);
- }
- } finally {
- // If read/write fails, close streams safely before throwing an exception
- os.close();
- is.close();
- }
-
- // Finally, load the library
- System.load(temp.getAbsolutePath());
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/zerotier/sdk/Node.java b/app/src/main/java/com/zerotier/sdk/Node.java
index ef6ac9d..a3f3ab4 100644
--- a/app/src/main/java/com/zerotier/sdk/Node.java
+++ b/app/src/main/java/com/zerotier/sdk/Node.java
@@ -28,95 +28,72 @@
package com.zerotier.sdk;
import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.io.IOException;
/**
* A ZeroTier One node
*/
public class Node {
- static {
- try {
- System.loadLibrary("ZeroTierOneJNI");
- } catch (UnsatisfiedLinkError e) {
- try {
- if(System.getProperty("os.name").startsWith("Windows")) {
- System.out.println("Arch: " + System.getProperty("sun.arch.data.model"));
- if(System.getProperty("sun.arch.data.model").equals("64")) {
- NativeUtils.loadLibraryFromJar("/lib/ZeroTierOneJNI_win64.dll");
- } else {
- NativeUtils.loadLibraryFromJar("/lib/ZeroTierOneJNI_win32.dll");
- }
- } else if(System.getProperty("os.name").startsWith("Mac")) {
- NativeUtils.loadLibraryFromJar("/lib/libZeroTierOneJNI.jnilib");
- } else {
- // TODO: Linux
- }
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- }
- }
+ static {
+ System.loadLibrary("ZeroTierOneJNI");
+ }
private static final String TAG = "NODE";
/**
* Node ID for JNI purposes.
* Currently set to the now value passed in at the constructor
- *
- * -1 if the node has already been closed
*/
- private long nodeId;
-
- private final DataStoreGetListener getListener;
- private final DataStorePutListener putListener;
- private final PacketSender sender;
- private final EventListener eventListener;
- private final VirtualNetworkFrameListener frameListener;
- private final VirtualNetworkConfigListener configListener;
- private final PathChecker pathChecker;
+ private final long nodeId;
/**
* Create a new ZeroTier One node
*
+ * @param now Current clock in milliseconds
+ */
+ public Node(long now) {
+ this.nodeId = now;
+ }
+
+ /**
+ * Init a new ZeroTier One node
+ *
* Note that this can take a few seconds the first time it's called, as it
* will generate an identity.
*
- * @param now Current clock in milliseconds
* @param getListener User written instance of the {@link DataStoreGetListener} interface called to get objects from persistent storage. This instance must be unique per Node object.
- * @param putListener User written intstance of the {@link DataStorePutListener} interface called to put objects in persistent storage. This instance must be unique per Node object.
- * @param sender
+ * @param putListener User written instance of the {@link DataStorePutListener} interface called to put objects in persistent storage. This instance must be unique per Node object.
+ * @param sender User written instance of the {@link PacketSender} interface to send ZeroTier packets out over the wire.
* @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 frameListener User written instance of the {@link VirtualNetworkFrameListener} interface to send a frame out to a virtual network port.
* @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,
- DataStorePutListener putListener,
- PacketSender sender,
- EventListener eventListener,
- VirtualNetworkFrameListener frameListener,
- VirtualNetworkConfigListener configListener,
- PathChecker pathChecker) throws NodeException
- {
- this.nodeId = now;
-
- this.getListener = getListener;
- this.putListener = putListener;
- this.sender = sender;
- this.eventListener = eventListener;
- this.frameListener = frameListener;
- this.configListener = configListener;
- this.pathChecker = pathChecker;
-
- ResultCode rc = node_init(now);
- if(rc != ResultCode.RESULT_OK)
- {
- // TODO: Throw Exception
+ public ResultCode init(
+ DataStoreGetListener getListener,
+ DataStorePutListener putListener,
+ PacketSender sender,
+ EventListener eventListener,
+ VirtualNetworkFrameListener frameListener,
+ VirtualNetworkConfigListener configListener,
+ PathChecker pathChecker) throws NodeException {
+ ResultCode rc = node_init(
+ nodeId,
+ getListener,
+ putListener,
+ sender,
+ eventListener,
+ frameListener,
+ configListener,
+ pathChecker);
+ if(rc != ResultCode.RESULT_OK) {
throw new NodeException(rc.toString());
}
- }
+ return rc;
+ }
+
+ public boolean isInited() {
+ return node_isInited(nodeId);
+ }
/**
* Close this Node.
@@ -124,15 +101,12 @@ public Node(long now,
* The Node object can no longer be used once this method is called.
*/
public void close() {
- if(nodeId != -1) {
- node_delete(nodeId);
- nodeId = -1;
- }
+ node_delete(nodeId);
}
@Override
- protected void finalize() {
- close();
+ public String toString() {
+ return "Node(" + nodeId + ")";
}
/**
@@ -166,6 +140,7 @@ public ResultCode processVirtualNetworkFrame(
* Process a packet received from the physical wire
*
* @param now Current clock in milliseconds
+ * @param localSocket Local socket or -1
* @param remoteAddress Origin of packet
* @param packetData Packet data
* @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks()
@@ -197,7 +172,7 @@ public ResultCode processBackgroundTasks(long now, long[] nextBackgroundTaskDead
* Join a network
*
* This may generate calls to the port config callback before it returns,
- * or these may be deffered if a netconf is not available yet.
+ * or these may be deferred if a netconf is not available yet.
*
* If we are already a member of the network, nothing is done and OK is
* returned.
@@ -392,8 +367,8 @@ public VirtualNetworkConfig networkConfig(long nwid) {
*
* @return List of networks or NULL on failure
*/
- public VirtualNetworkConfig[] networks() {
- return networks(nodeId);
+ public VirtualNetworkConfig[] networkConfigs() {
+ return networkConfigs(nodeId);
}
/**
@@ -408,7 +383,17 @@ public Version getVersion() {
//
// function declarations for JNI
//
- private native ResultCode node_init(long now);
+ private native ResultCode node_init(
+ long nodeId,
+ DataStoreGetListener dataStoreGetListener,
+ DataStorePutListener dataStorePutListener,
+ PacketSender packetSender,
+ EventListener eventListener,
+ VirtualNetworkFrameListener virtualNetworkFrameListener,
+ VirtualNetworkConfigListener virtualNetworkConfigListener,
+ PathChecker pathChecker);
+
+ private native boolean node_isInited(long nodeId);
private native void node_delete(long nodeId);
@@ -471,5 +456,5 @@ private native ResultCode deorbit(
private native Peer[] peers(long nodeId);
- private native VirtualNetworkConfig[] networks(long nodeId);
-}
\ No newline at end of file
+ private native VirtualNetworkConfig[] networkConfigs(long nodeId);
+}
diff --git a/app/src/main/java/com/zerotier/sdk/NodeException.java b/app/src/main/java/com/zerotier/sdk/NodeException.java
index 1fdef72..beeb060 100644
--- a/app/src/main/java/com/zerotier/sdk/NodeException.java
+++ b/app/src/main/java/com/zerotier/sdk/NodeException.java
@@ -27,10 +27,11 @@
package com.zerotier.sdk;
-import java.lang.RuntimeException;
+public class NodeException extends Exception {
-public class NodeException extends RuntimeException {
+ private static final long serialVersionUID = 6268040509883125819L;
+
public NodeException(String message) {
super(message);
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/zerotier/sdk/NodeStatus.java b/app/src/main/java/com/zerotier/sdk/NodeStatus.java
index 94376d8..1172650 100644
--- a/app/src/main/java/com/zerotier/sdk/NodeStatus.java
+++ b/app/src/main/java/com/zerotier/sdk/NodeStatus.java
@@ -27,43 +27,64 @@
package com.zerotier.sdk;
-public final class NodeStatus {
- private long address;
- private String publicIdentity;
- private String secretIdentity;
- private boolean online;
+import com.zerotier.sdk.util.StringUtils;
- private NodeStatus() {}
+/**
+ * Current node status
+ *
+ * Defined in ZeroTierOne.h as ZT_NodeStatus
+ */
+public class NodeStatus {
+
+ private final long address;
+
+ private final String publicIdentity;
+
+ private final String secretIdentity;
+
+ private final boolean online;
+
+ public NodeStatus(long address, String publicIdentity, String secretIdentity, boolean online) {
+ this.address = address;
+ this.publicIdentity = publicIdentity;
+ this.secretIdentity = secretIdentity;
+ this.online = online;
+ }
+
+ @Override
+ public String toString() {
+ return "NodeStatus(" + StringUtils.addressToString(address) + ", " + publicIdentity + ", " + secretIdentity + ", " + online + ")";
+ }
/**
* 40-bit ZeroTier address of this node
*/
- public final long getAddres() {
- return address;
- }
+ public long getAddress() {
+ return address;
+ }
/**
* Public identity in string-serialized form (safe to send to others)
*
* This identity will remain valid as long as the node exists.
*/
- public final String getPublicIdentity() {
- return publicIdentity;
- }
+ public String getPublicIdentity() {
+ return publicIdentity;
+ }
/**
* Full identity including secret key in string-serialized form
*
* This identity will remain valid as long as the node exists.
*/
- public final String getSecretIdentity() {
- return secretIdentity;
- }
+ public String getSecretIdentity() {
+ return secretIdentity;
+ }
/**
* True if some kind of connectivity appears available
*/
- public final boolean isOnline() {
- return online;
- }
-}
\ No newline at end of file
+ public boolean isOnline() {
+ return online;
+ }
+}
diff --git a/app/src/main/java/com/zerotier/sdk/PacketSender.java b/app/src/main/java/com/zerotier/sdk/PacketSender.java
index 06ec01b..893824a 100644
--- a/app/src/main/java/com/zerotier/sdk/PacketSender.java
+++ b/app/src/main/java/com/zerotier/sdk/PacketSender.java
@@ -24,12 +24,14 @@
* redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/
*/
+
package com.zerotier.sdk;
import java.net.InetSocketAddress;
public interface PacketSender {
+
/**
* Function to send a ZeroTier packet out over the wire
*
@@ -40,9 +42,10 @@ public interface PacketSender {
* @param localSocket socket file descriptor to send from. Set to -1 if not specified.
* @param remoteAddr {@link InetSocketAddress} to send to
* @param packetData data to send
+ * @param ttl TTL is ignored
* @return 0 on success, any error code on failure.
*/
- public int onSendPacketRequested(
+ int onSendPacketRequested(
long localSocket,
InetSocketAddress remoteAddr,
byte[] packetData,
diff --git a/app/src/main/java/com/zerotier/sdk/PathChecker.java b/app/src/main/java/com/zerotier/sdk/PathChecker.java
index 6bf31df..cfc97d6 100644
--- a/app/src/main/java/com/zerotier/sdk/PathChecker.java
+++ b/app/src/main/java/com/zerotier/sdk/PathChecker.java
@@ -8,6 +8,7 @@
import java.net.InetSocketAddress;
public interface PathChecker {
+
/**
* Callback to check whether a path should be used for ZeroTier traffic
*
@@ -28,6 +29,7 @@ public interface PathChecker {
* @param ztAddress ZeroTier address or 0 for none/any
* @param localSocket Local interface socket. -1 if unspecified
* @param remoteAddress remote address
+ * @return true if the path should be used
*/
boolean onPathCheck(long ztAddress, long localSocket, InetSocketAddress remoteAddress);
diff --git a/app/src/main/java/com/zerotier/sdk/Peer.java b/app/src/main/java/com/zerotier/sdk/Peer.java
index eb3d713..e3d5443 100644
--- a/app/src/main/java/com/zerotier/sdk/Peer.java
+++ b/app/src/main/java/com/zerotier/sdk/Peer.java
@@ -27,68 +27,92 @@
package com.zerotier.sdk;
-import java.util.ArrayList;
+import com.zerotier.sdk.util.StringUtils;
+
+import java.util.Arrays;
/**
- * Peer status result
+ * Peer status result buffer
+ *
+ * Defined in ZeroTierOne.h as ZT_Peer
*/
-public final class Peer {
- private long address;
- private int versionMajor;
- private int versionMinor;
- private int versionRev;
- private int latency;
- private PeerRole role;
- private PeerPhysicalPath[] paths;
+public class Peer {
+
+ private final long address;
+
+ private final int versionMajor;
+
+ private final int versionMinor;
+
+ private final int versionRev;
- private Peer() {}
+ private final int latency;
+
+ private final PeerRole role;
+
+ private final PeerPhysicalPath[] paths;
+
+ public Peer(long address, int versionMajor, int versionMinor, int versionRev, int latency, PeerRole role, PeerPhysicalPath[] paths) {
+ this.address = address;
+ this.versionMajor = versionMajor;
+ this.versionMinor = versionMinor;
+ this.versionRev = versionRev;
+ this.latency = latency;
+ this.role = role;
+ this.paths = paths;
+ }
+
+ @Override
+ public String toString() {
+ return "Peer(" + StringUtils.addressToString(address) + ", " + versionMajor + ", " + versionMinor + ", " + versionRev + ", " + latency + ", " + role + ", " + Arrays.toString(paths) + ")";
+ }
/**
* ZeroTier address (40 bits)
*/
- public final long address() {
+ public long getAddress() {
return address;
}
/**
* Remote major version or -1 if not known
*/
- public final int versionMajor() {
+ public int getVersionMajor() {
return versionMajor;
}
/**
* Remote minor version or -1 if not known
*/
- public final int versionMinor() {
+ public int getVersionMinor() {
return versionMinor;
}
/**
* Remote revision or -1 if not known
*/
- public final int versionRev() {
+ public int getVersionRev() {
return versionRev;
}
/**
* Last measured latency in milliseconds or zero if unknown
*/
- public final int latency() {
+ public int getLatency() {
return latency;
}
/**
* What trust hierarchy role does this device have?
*/
- public final PeerRole role() {
+ public PeerRole getRole() {
return role;
}
/**
* Known network paths to peer
*/
- public final PeerPhysicalPath[] paths() {
+ public PeerPhysicalPath[] getPaths() {
return paths;
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/zerotier/sdk/PeerPhysicalPath.java b/app/src/main/java/com/zerotier/sdk/PeerPhysicalPath.java
index 3f9a861..f6d3264 100644
--- a/app/src/main/java/com/zerotier/sdk/PeerPhysicalPath.java
+++ b/app/src/main/java/com/zerotier/sdk/PeerPhysicalPath.java
@@ -31,48 +31,62 @@
/**
* Physical network path to a peer
+ *
+ * Defined in ZeroTierOne.h as ZT_PeerPhysicalPath
*/
-public final class PeerPhysicalPath {
- private InetSocketAddress address;
- private long lastSend;
- private long lastReceive;
- private boolean fixed;
- private boolean preferred;
+public class PeerPhysicalPath {
+
+ private final InetSocketAddress address;
+
+ private final long lastSend;
+
+ private final long lastReceive;
+
+ private final boolean preferred;
+
+ public PeerPhysicalPath(InetSocketAddress address, long lastSend, long lastReceive, boolean preferred) {
+ this.address = address;
+ if (lastSend < 0) {
+ throw new RuntimeException("lastSend < 0: " + lastSend);
+ }
+ this.lastSend = lastSend;
+ if (lastReceive < 0) {
+ throw new RuntimeException("lastReceive < 0: " + lastReceive);
+ }
+ this.lastReceive = lastReceive;
+ this.preferred = preferred;
+ }
- private PeerPhysicalPath() {}
+ @Override
+ public String toString() {
+ return "PeerPhysicalPath(" + address + ", " + lastSend + ", " + lastReceive + ", " + preferred + ")";
+ }
/**
* Address of endpoint
*/
- public final InetSocketAddress address() {
+ public InetSocketAddress getAddress() {
return address;
}
/**
* Time of last send in milliseconds or 0 for never
*/
- public final long lastSend() {
+ public long getLastSend() {
return lastSend;
}
/**
* Time of last receive in milliseconds or 0 for never
*/
- public final long lastReceive() {
+ public long getLastReceive() {
return lastReceive;
}
- /**
- * Is path fixed? (i.e. not learned, static)
- */
- public final boolean isFixed() {
- return fixed;
- }
-
/**
* Is path preferred?
*/
- public final boolean isPreferred() {
+ public boolean isPreferred() {
return preferred;
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/zerotier/sdk/PeerRole.java b/app/src/main/java/com/zerotier/sdk/PeerRole.java
index fce183d..d69a1f1 100644
--- a/app/src/main/java/com/zerotier/sdk/PeerRole.java
+++ b/app/src/main/java/com/zerotier/sdk/PeerRole.java
@@ -27,19 +27,45 @@
package com.zerotier.sdk;
+/**
+ * What trust hierarchy role does this peer have?
+ *
+ * Defined in ZeroTierOne.h as ZT_PeerRole
+ */
public enum PeerRole {
+
/**
* An ordinary node
*/
- PEER_ROLE_LEAF,
+ PEER_ROLE_LEAF(0),
/**
* moon root
*/
- PEER_ROLE_MOON,
+ PEER_ROLE_MOON(1),
/**
* planetary root
*/
- PEER_ROLE_PLANET
-}
\ No newline at end of file
+ PEER_ROLE_PLANET(2);
+
+ @SuppressWarnings({"FieldCanBeLocal", "unused"})
+ private final int id;
+
+ PeerRole(int id) {
+ this.id = id;
+ }
+
+ public static PeerRole fromInt(int id) {
+ switch (id) {
+ case 0:
+ return PEER_ROLE_LEAF;
+ case 1:
+ return PEER_ROLE_MOON;
+ case 2:
+ return PEER_ROLE_PLANET;
+ default:
+ throw new RuntimeException("Unhandled value: " + id);
+ }
+ }
+}
diff --git a/app/src/main/java/com/zerotier/sdk/ResultCode.java b/app/src/main/java/com/zerotier/sdk/ResultCode.java
index 66f5756..dc8a901 100644
--- a/app/src/main/java/com/zerotier/sdk/ResultCode.java
+++ b/app/src/main/java/com/zerotier/sdk/ResultCode.java
@@ -34,14 +34,22 @@
* occurs, the node should be considered to not be working correctly. These
* indicate serious problems like an inaccessible data store or a compile
* problem.
+ *
+ * Defined in ZeroTierOne.h as ZT_ResultCode
*/
public enum ResultCode {
+
/**
* Operation completed normally
*/
- RESULT_OK(0),
+ RESULT_OK(0),
+
+ /**
+ * Call produced no error but no action was taken
+ */
+ RESULT_OK_IGNORED(1),
- // Fatal errors (> 0, < 1000)
+ // Fatal errors (>=100, <1000)
/**
* Ran out of memory
*/
@@ -68,12 +76,36 @@ public enum ResultCode {
RESULT_ERROR_BAD_PARAMETER(1002);
-
- private final int id;
- ResultCode(int id) { this.id = id; }
- public int getValue() { return id; }
+ private final int id;
+
+ ResultCode(int id) {
+ this.id = id;
+ }
+
+ public static ResultCode fromInt(int id) {
+ switch (id) {
+ case 0:
+ return RESULT_OK;
+ case 1:
+ return RESULT_OK_IGNORED;
+ case 100:
+ return RESULT_FATAL_ERROR_OUT_OF_MEMORY;
+ case 101:
+ return RESULT_FATAL_ERROR_DATA_STORE_FAILED;
+ case 102:
+ return RESULT_FATAL_ERROR_INTERNAL;
+ case 1000:
+ return RESULT_ERROR_NETWORK_NOT_FOUND;
+ case 1001:
+ return RESULT_ERROR_UNSUPPORTED_OPERATION;
+ case 1002:
+ return RESULT_ERROR_BAD_PARAMETER;
+ default:
+ throw new RuntimeException("Unhandled value: " + id);
+ }
+ }
- public boolean isFatal(int id) {
- return (id > 100 && id < 1000);
+ public boolean isFatal() {
+ return (id >= 100 && id < 1000);
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/zerotier/sdk/Version.java b/app/src/main/java/com/zerotier/sdk/Version.java
index c93c259..0dbe1d2 100644
--- a/app/src/main/java/com/zerotier/sdk/Version.java
+++ b/app/src/main/java/com/zerotier/sdk/Version.java
@@ -27,10 +27,27 @@
package com.zerotier.sdk;
-public final class Version {
- private Version() {}
-
- public int major = 0;
- public int minor = 0;
- public int revision = 0;
-}
\ No newline at end of file
+public class Version {
+
+ private final int major;
+ private final int minor;
+ private final int revision;
+
+ public Version(int major, int minor, int revision) {
+ this.major = major;
+ this.minor = minor;
+ this.revision = revision;
+ }
+
+ public int getMajor() {
+ return major;
+ }
+
+ public int getMinor() {
+ return minor;
+ }
+
+ public int getRevision() {
+ return revision;
+ }
+}
diff --git a/app/src/main/java/com/zerotier/sdk/VirtualNetworkConfig.java b/app/src/main/java/com/zerotier/sdk/VirtualNetworkConfig.java
index c7b48d5..bcf6485 100644
--- a/app/src/main/java/com/zerotier/sdk/VirtualNetworkConfig.java
+++ b/app/src/main/java/com/zerotier/sdk/VirtualNetworkConfig.java
@@ -29,197 +29,302 @@
import android.util.Log;
-import java.lang.Comparable;
-import java.lang.Override;
-import java.lang.String;
-import java.util.ArrayList;
+import com.zerotier.sdk.util.StringUtils;
+
import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
-public final class VirtualNetworkConfig implements Comparable {
+/**
+ * Virtual network configuration
+ *
+ * Defined in ZeroTierOne.h as ZT_VirtualNetworkConfig
+ */
+public class VirtualNetworkConfig implements Comparable {
+
private final static String TAG = "VirtualNetworkConfig";
public static final int MAX_MULTICAST_SUBSCRIPTIONS = 4096;
public static final int ZT_MAX_ZT_ASSIGNED_ADDRESSES = 16;
- private long nwid;
- private long mac;
- private String name;
- private VirtualNetworkStatus status;
- private VirtualNetworkType type;
- private int mtu;
- private boolean dhcp;
- private boolean bridge;
- private boolean broadcastEnabled;
- private int portError;
- private boolean enabled;
- private long netconfRevision;
- private InetSocketAddress[] assignedAddresses;
- private VirtualNetworkRoute[] routes;
- private VirtualNetworkDNS dns;
-
- private VirtualNetworkConfig() {
+ private final long nwid;
- }
+ private final long mac;
- public boolean equals(VirtualNetworkConfig cfg) {
- ArrayList aaCurrent = new ArrayList<>();
- ArrayList aaNew = new ArrayList<>();
- for (InetSocketAddress s : assignedAddresses) {
- aaCurrent.add(s.toString());
- }
- for (InetSocketAddress s : cfg.assignedAddresses) {
- aaNew.add(s.toString());
+ private final String name;
+
+ private final VirtualNetworkStatus status;
+
+ private final VirtualNetworkType type;
+
+ private final int mtu;
+
+ private final boolean dhcp;
+
+ private final boolean bridge;
+
+ private final boolean broadcastEnabled;
+
+ private final int portError;
+
+ private final long netconfRevision;
+
+ private final InetSocketAddress[] assignedAddresses;
+
+ private final VirtualNetworkRoute[] routes;
+
+ private final VirtualNetworkDNS dns;
+
+ public VirtualNetworkConfig(long nwid, long mac, String name, VirtualNetworkStatus status, VirtualNetworkType type, int mtu, boolean dhcp, boolean bridge, boolean broadcastEnabled, int portError, long netconfRevision, InetSocketAddress[] assignedAddresses, VirtualNetworkRoute[] routes, VirtualNetworkDNS dns) {
+ this.nwid = nwid;
+ this.mac = mac;
+ this.name = name;
+ this.status = status;
+ this.type = type;
+ if (mtu < 0) {
+ throw new RuntimeException("mtu < 0: " + mtu);
}
- Collections.sort(aaCurrent);
- Collections.sort(aaNew);
- boolean aaEqual = aaCurrent.equals(aaNew);
-
- ArrayList rCurrent = new ArrayList<>();
- ArrayList rNew = new ArrayList<>();
- for (VirtualNetworkRoute r : routes) {
- rCurrent.add(r.toString());
+ this.mtu = mtu;
+ this.dhcp = dhcp;
+ this.bridge = bridge;
+ this.broadcastEnabled = broadcastEnabled;
+ this.portError = portError;
+ if (netconfRevision < 0) {
+ throw new RuntimeException("netconfRevision < 0: " + netconfRevision);
}
- for (VirtualNetworkRoute r : cfg.routes) {
- rNew.add(r.toString());
+ this.netconfRevision = netconfRevision;
+ this.assignedAddresses = assignedAddresses;
+ this.routes = routes;
+ this.dns = dns;
+ }
+
+ @Override
+ public String toString() {
+ return "VirtualNetworkConfig(" + StringUtils.networkIdToString(nwid) + ", " + StringUtils.macAddressToString(mac) + ", " + name + ", " + status + ", " + type + ", " + mtu + ", " + dhcp + ", " + bridge + ", " + broadcastEnabled + ", " + portError + ", " + netconfRevision + ", " + Arrays.toString(assignedAddresses) + ", " + Arrays.toString(routes) + ", " + dns + ")";
+ }
+
+ @Override
+ public boolean equals(Object o) {
+
+ if (!(o instanceof VirtualNetworkConfig)) {
+ return false;
}
- Collections.sort(rCurrent);
- Collections.sort(rNew);
- boolean routesEqual = rCurrent.equals(rNew);
+
+ VirtualNetworkConfig cfg = (VirtualNetworkConfig) o;
if (this.nwid != cfg.nwid) {
- Log.i(TAG, "nwid Changed. Old: " + Long.toHexString(this.nwid) + " (" + Long.toString(this.nwid) + "), " +
- "New: " + Long.toHexString(cfg.nwid) + " (" + Long.toString(cfg.nwid) + ")");
+ Log.i(TAG, "NetworkID Changed. Old: " + StringUtils.networkIdToString(this.nwid) + " (" + this.nwid + "), " +
+ "New: " + StringUtils.networkIdToString(cfg.nwid) + " (" + cfg.nwid + ")");
+
+ return false;
}
+
if (this.mac != cfg.mac) {
- Log.i(TAG, "MAC Changed. Old: " + Long.toHexString(this.mac) + ", New: " + Long.toHexString(cfg.mac));
+ Log.i(TAG, "MAC Changed. Old: " + StringUtils.macAddressToString(this.mac) + ", New: " + StringUtils.macAddressToString(cfg.mac));
+
+ return false;
}
if (!this.name.equals(cfg.name)) {
- Log.i(TAG, "Name Changed. Old: " + this.name + " New: "+ cfg.name);
+ Log.i(TAG, "Name Changed. Old: " + this.name + ", New: " + cfg.name);
+
+ return false;
+ }
+
+ if (this.status != cfg.status) {
+ Log.i(TAG, "Status Changed. Old: " + this.status + ", New: " + cfg.status);
+
+ return false;
}
- if (!this.type.equals(cfg.type)) {
- Log.i(TAG, "TYPE changed. Old " + this.type + ", New: " + cfg.type);
+ if (this.type != cfg.type) {
+ Log.i(TAG, "Type changed. Old " + this.type + ", New: " + cfg.type);
+
+ return false;
}
if (this.mtu != cfg.mtu) {
- Log.i(TAG, "MTU Changed. Old: " + this.mtu + ", New: " + cfg.mtu);
+ Log.i(TAG, "MTU Changed. Old: " + this.mtu + ", New: " + cfg.mtu);
+
+ return false;
}
if (this.dhcp != cfg.dhcp) {
Log.i(TAG, "DHCP Flag Changed. Old: " + this.dhcp + ", New: " + cfg.dhcp);
+
+ return false;
}
if (this.bridge != cfg.bridge) {
Log.i(TAG, "Bridge Flag Changed. Old: " + this.bridge + ", New: " + cfg.bridge);
+
+ return false;
}
if (this.broadcastEnabled != cfg.broadcastEnabled) {
- Log.i(TAG, "Broadcast Flag Changed. Old: "+ this.broadcastEnabled +", New: " + this.broadcastEnabled);
+ Log.i(TAG, "Broadcast Flag Changed. Old: "+ this.broadcastEnabled + ", New: " + cfg.broadcastEnabled);
+
+ return false;
}
if (this.portError != cfg.portError) {
- Log.i(TAG, "Port Error Changed. Old: " + this.portError + ", New: " + this.portError);
+ Log.i(TAG, "Port Error Changed. Old: " + this.portError + ", New: " + cfg.portError);
+
+ return false;
}
- if (this.enabled != cfg.enabled) {
- Log.i(TAG, "Enabled Changed. Old: " + this.enabled + ", New: " + this.enabled);
+ if (this.netconfRevision != cfg.netconfRevision) {
+ Log.i(TAG, "NetConfRevision Changed. Old: " + this.netconfRevision + ", New: " + cfg.netconfRevision);
+
+ return false;
}
- if (!aaEqual) {
+ if (!Arrays.equals(assignedAddresses, cfg.assignedAddresses)) {
+
+ ArrayList aaCurrent = new ArrayList<>();
+ ArrayList aaNew = new ArrayList<>();
+ for (InetSocketAddress s : assignedAddresses) {
+ aaCurrent.add(s.toString());
+ }
+ for (InetSocketAddress s : cfg.assignedAddresses) {
+ aaNew.add(s.toString());
+ }
+ Collections.sort(aaCurrent);
+ Collections.sort(aaNew);
+
Log.i(TAG, "Assigned Addresses Changed");
Log.i(TAG, "Old:");
for (String s : aaCurrent) {
Log.i(TAG, " " + s);
}
+ Log.i(TAG, "");
Log.i(TAG, "New:");
for (String s : aaNew) {
Log.i(TAG, " " +s);
}
+ Log.i(TAG, "");
+
+ return false;
}
- if (!routesEqual) {
+ if (!Arrays.equals(routes, cfg.routes)) {
+
+ ArrayList rCurrent = new ArrayList<>();
+ ArrayList rNew = new ArrayList<>();
+ for (VirtualNetworkRoute r : routes) {
+ rCurrent.add(r.toString());
+ }
+ for (VirtualNetworkRoute r : cfg.routes) {
+ rNew.add(r.toString());
+ }
+ Collections.sort(rCurrent);
+ Collections.sort(rNew);
+
Log.i(TAG, "Managed Routes Changed");
Log.i(TAG, "Old:");
for (String s : rCurrent) {
Log.i(TAG, " " + s);
}
+ Log.i(TAG, "");
Log.i(TAG, "New:");
for (String s : rNew) {
Log.i(TAG, " " + s);
}
+ Log.i(TAG, "");
+
+ return false;
+ }
+
+ boolean dnsEquals;
+ if (this.dns == null) {
+ //noinspection RedundantIfStatement
+ if (cfg.dns == null) {
+ dnsEquals = true;
+ } else {
+ dnsEquals = false;
+ }
+ } else {
+ if (cfg.dns == null) {
+ dnsEquals = false;
+ } else {
+ dnsEquals = this.dns.equals(cfg.dns);
+ }
}
- boolean dnsEquals = false;
- if (this.dns == null || cfg.dns == null) {
- dnsEquals = true;
- } else if (this.dns != null) {
- dnsEquals = this.dns.equals(cfg.dns);
+ if (!dnsEquals) {
+ return false;
}
- return this.nwid == cfg.nwid &&
- this.mac == cfg.mac &&
- this.name.equals(cfg.name) &&
- this.status.equals(cfg.status) &&
- this.type.equals(cfg.type) &&
- this.mtu == cfg.mtu &&
- this.dhcp == cfg.dhcp &&
- this.bridge == cfg.bridge &&
- this.broadcastEnabled == cfg.broadcastEnabled &&
- this.portError == cfg.portError &&
- this.enabled == cfg.enabled &&
- dnsEquals &&
- aaEqual && routesEqual;
+ return true;
}
+ @Override
public int compareTo(VirtualNetworkConfig cfg) {
- if(cfg.nwid == this.nwid) {
- return 0;
- } else {
- return this.nwid > cfg.nwid ? 1 : -1;
- }
+ return Long.compare(this.nwid, cfg.nwid);
+ }
+
+ @Override
+ public int hashCode() {
+
+ int result = 17;
+ result = 37 * result + (int) (nwid ^ (nwid >>> 32));
+ result = 37 * result + (int) (mac ^ (mac >>> 32));
+ result = 37 * result + name.hashCode();
+ result = 37 * result + status.hashCode();
+ result = 37 * result + type.hashCode();
+ result = 37 * result + mtu;
+ result = 37 * result + (dhcp ? 1 : 0);
+ result = 37 * result + (bridge ? 1 : 0);
+ result = 37 * result + (broadcastEnabled ? 1 : 0);
+ result = 37 * result + portError;
+ result = 37 * result + (int) (netconfRevision ^ (netconfRevision >>> 32));
+ result = 37 * result + Arrays.hashCode(assignedAddresses);
+ result = 37 * result + Arrays.hashCode(routes);
+ result = 37 * result + (dns == null ? 0 : dns.hashCode());
+
+ return result;
}
/**
* 64-bit ZeroTier network ID
*/
- public final long networkId() {
+ public long getNwid() {
return nwid;
}
/**
- * Ethernet MAC (40 bits) that should be assigned to port
+ * Ethernet MAC (48 bits) that should be assigned to port
*/
- public final long macAddress() {
+ public long getMac() {
return mac;
}
/**
* Network name (from network configuration master)
*/
- public final String name() {
+ public String getName() {
return name;
}
/**
* Network configuration request status
*/
- public final VirtualNetworkStatus networkStatus() {
+ public VirtualNetworkStatus getStatus() {
return status;
}
/**
* Network type
*/
- public final VirtualNetworkType networkType() {
+ public VirtualNetworkType getType() {
return type;
}
/**
* Maximum interface MTU
*/
- public final int mtu() {
+ public int getMtu() {
return mtu;
}
@@ -230,7 +335,7 @@ public final int mtu() {
* for security or other reasons. This is simply a netconf parameter that
* means 'DHCP is available on this network.'
*/
- public final boolean isDhcpAvailable() {
+ public boolean isDhcp() {
return dhcp;
}
@@ -240,21 +345,21 @@ public final boolean isDhcpAvailable() {
* This is informational. If this is false, bridged packets will simply
* be dropped and bridging won't work.
*/
- public final boolean isBridgeEnabled() {
+ public boolean isBridge() {
return bridge;
}
/**
* If true, this network supports and allows broadcast (ff:ff:ff:ff:ff:ff) traffic
*/
- public final boolean broadcastEnabled() {
+ public boolean isBroadcastEnabled() {
return broadcastEnabled;
}
/**
* If the network is in PORT_ERROR state, this is the error most recently returned by the port config callback
*/
- public final int portError() {
+ public int getPortError() {
return portError;
}
@@ -263,12 +368,12 @@ public final int portError() {
*
* If this is zero, it means we're still waiting for our netconf.
*/
- public final long netconfRevision() {
+ public long getNetconfRevision() {
return netconfRevision;
}
/**
- * ZeroTier-assigned addresses (in {@link java.net.InetSocketAddress} objects)
+ * ZeroTier-assigned addresses (in {@link InetSocketAddress} objects)
*
* For IP, the port number of the sockaddr_XX structure contains the number
* of bits in the address netmask. Only the IP address and port are used.
@@ -277,16 +382,21 @@ public final long netconfRevision() {
* This is only used for ZeroTier-managed address assignments sent by the
* virtual network's configuration master.
*/
- public final InetSocketAddress[] assignedAddresses() {
+ public InetSocketAddress[] getAssignedAddresses() {
return assignedAddresses;
}
/**
- * ZeroTier-assigned routes (in {@link com.zerotier.sdk.VirtualNetworkRoute} objects)
- *
- * @return
+ * ZeroTier-assigned routes (in {@link VirtualNetworkRoute} objects)
*/
- public final VirtualNetworkRoute[] routes() { return routes; }
+ public VirtualNetworkRoute[] getRoutes() {
+ return routes;
+ }
- public final VirtualNetworkDNS dns() { return dns; }
+ /**
+ * Network specific DNS configuration
+ */
+ public VirtualNetworkDNS getDns() {
+ return dns;
+ }
}
diff --git a/app/src/main/java/com/zerotier/sdk/VirtualNetworkConfigListener.java b/app/src/main/java/com/zerotier/sdk/VirtualNetworkConfigListener.java
index 15ae301..ce91e79 100644
--- a/app/src/main/java/com/zerotier/sdk/VirtualNetworkConfigListener.java
+++ b/app/src/main/java/com/zerotier/sdk/VirtualNetworkConfigListener.java
@@ -25,11 +25,11 @@
* LLC. Start here: http://www.zerotier.com/
*/
-
package com.zerotier.sdk;
public interface VirtualNetworkConfigListener {
+
/**
* Callback called to update virtual network port configuration
*
@@ -40,7 +40,7 @@ public interface VirtualNetworkConfigListener {
* This in turn should be used by the underlying implementation to create
* and configure tap devices at the OS (or virtual network stack) layer.
*
- * This should not call {@link Node#multicastSubscribe} or other network-modifying
+ * This should not call {@link Node#multicastSubscribe(long, long)} or other network-modifying
* methods, as this could cause a deadlock in multithreaded or interrupt
* driven environments.
*
@@ -53,8 +53,8 @@ public interface VirtualNetworkConfigListener {
* @param config {@link VirtualNetworkConfig} object with the new configuration
* @return 0 on success
*/
- public int onNetworkConfigurationUpdated(
+ int onNetworkConfigurationUpdated(
long nwid,
VirtualNetworkConfigOperation op,
VirtualNetworkConfig config);
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/zerotier/sdk/VirtualNetworkConfigOperation.java b/app/src/main/java/com/zerotier/sdk/VirtualNetworkConfigOperation.java
index b70eb47..a1981bd 100644
--- a/app/src/main/java/com/zerotier/sdk/VirtualNetworkConfigOperation.java
+++ b/app/src/main/java/com/zerotier/sdk/VirtualNetworkConfigOperation.java
@@ -24,26 +24,55 @@
* redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/
*/
+
package com.zerotier.sdk;
+/**
+ * Virtual network configuration update type
+ *
+ * Defined in ZeroTierOne.h as ZT_VirtualNetworkConfigOperation
+ */
public enum VirtualNetworkConfigOperation {
+
/**
* Network is coming up (either for the first time or after service restart)
*/
- VIRTUAL_NETWORK_CONFIG_OPERATION_UP,
+ VIRTUAL_NETWORK_CONFIG_OPERATION_UP(1),
/**
* Network configuration has been updated
*/
- VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE,
+ VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE(2),
/**
* Network is going down (not permanently)
*/
- VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN,
+ VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN(3),
/**
* Network is going down permanently (leave/delete)
*/
- VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY
+ VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY(4);
+
+ @SuppressWarnings({"FieldCanBeLocal", "unused"})
+ private final int id;
+
+ VirtualNetworkConfigOperation(int id) {
+ this.id = id;
+ }
+
+ public static VirtualNetworkConfigOperation fromInt(int id) {
+ switch (id) {
+ case 1:
+ return VIRTUAL_NETWORK_CONFIG_OPERATION_UP;
+ case 2:
+ return VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE;
+ case 3:
+ return VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN;
+ case 4:
+ return VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY;
+ default:
+ throw new RuntimeException("Unhandled value: " + id);
+ }
+ }
}
diff --git a/app/src/main/java/com/zerotier/sdk/VirtualNetworkDNS.java b/app/src/main/java/com/zerotier/sdk/VirtualNetworkDNS.java
index 7046fd4..6e4bb3d 100644
--- a/app/src/main/java/com/zerotier/sdk/VirtualNetworkDNS.java
+++ b/app/src/main/java/com/zerotier/sdk/VirtualNetworkDNS.java
@@ -8,15 +8,48 @@
import java.net.InetSocketAddress;
import java.util.ArrayList;
+/**
+ * DNS configuration to be pushed on a virtual network
+ *
+ * Defined in ZeroTierOne.h as ZT_VirtualNetworkDNS
+ */
public class VirtualNetworkDNS implements Comparable {
- private String domain;
- private ArrayList servers;
- public VirtualNetworkDNS() {}
+ private final String domain;
+ private final ArrayList servers;
+
+ public VirtualNetworkDNS(String domain, ArrayList servers) {
+ this.domain = domain;
+ this.servers = servers;
+ }
+
+ @Override
+ public String toString() {
+ return "VirtualNetworkDNS(" + domain + ", " + servers + ")";
+ }
+
+ @Override
+ public boolean equals(Object o) {
+
+ if (o == null) {
+ return false;
+ }
+
+ if (!(o instanceof VirtualNetworkDNS)) {
+ return false;
+ }
- public boolean equals(VirtualNetworkDNS o) {
- if (o == null) return false;
- return domain.equals(o.domain) && servers.equals(o.servers);
+ VirtualNetworkDNS d = (VirtualNetworkDNS) o;
+
+ if (!domain.equals(d.domain)) {
+ return false;
+ }
+
+ if (!servers.equals(d.servers)) {
+ return false;
+ }
+
+ return true;
}
@Override
@@ -24,7 +57,21 @@ public int compareTo(VirtualNetworkDNS o) {
return domain.compareTo(o.domain);
}
- public String getSearchDomain() { return domain; }
+ @Override
+ public int hashCode() {
+
+ int result = 17;
+ result = 37 * result + domain.hashCode();
+ result = 37 * result + servers.hashCode();
+
+ return result;
+ }
+
+ public String getDomain() {
+ return domain;
+ }
- public ArrayList getServers() { return servers; }
+ public ArrayList getServers() {
+ return servers;
+ }
}
diff --git a/app/src/main/java/com/zerotier/sdk/VirtualNetworkFrameListener.java b/app/src/main/java/com/zerotier/sdk/VirtualNetworkFrameListener.java
index 9ad3228..650c9ce 100644
--- a/app/src/main/java/com/zerotier/sdk/VirtualNetworkFrameListener.java
+++ b/app/src/main/java/com/zerotier/sdk/VirtualNetworkFrameListener.java
@@ -28,17 +28,18 @@
package com.zerotier.sdk;
public interface VirtualNetworkFrameListener {
+
/**
* Function to send a frame out to a virtual network port
*
* @param nwid ZeroTier One network ID
* @param srcMac source MAC address
* @param destMac destination MAC address
- * @param ethertype
- * @param vlanId
+ * @param etherType EtherType
+ * @param vlanId VLAN ID
* @param frameData data to send
*/
- public void onVirtualNetworkFrame(
+ void onVirtualNetworkFrame(
long nwid,
long srcMac,
long destMac,
diff --git a/app/src/main/java/com/zerotier/sdk/VirtualNetworkRoute.java b/app/src/main/java/com/zerotier/sdk/VirtualNetworkRoute.java
index 8dd700c..afd9ee4 100644
--- a/app/src/main/java/com/zerotier/sdk/VirtualNetworkRoute.java
+++ b/app/src/main/java/com/zerotier/sdk/VirtualNetworkRoute.java
@@ -29,80 +29,135 @@
import java.net.InetSocketAddress;
-public final class VirtualNetworkRoute implements Comparable
+/**
+ * A route to be pushed on a virtual network
+ *
+ * Defined in ZeroTierOne.h as ZT_VirtualNetworkRoute
+ */
+public class VirtualNetworkRoute implements Comparable
{
- private VirtualNetworkRoute() {
- target = null;
- via = null;
- flags = 0;
- metric = 0;
- }
-
/**
* Target network / netmask bits (in port field) or NULL or 0.0.0.0/0 for default
*/
- public InetSocketAddress target;
-
+ private final InetSocketAddress target;
+
/**
* Gateway IP address (port ignored) or NULL (family == 0) for LAN-local (no gateway)
*/
- public InetSocketAddress via;
+ private final InetSocketAddress via;
/**
* Route flags
*/
- public int flags;
+ private final int flags;
/**
* Route metric (not currently used)
*/
- public int metric;
+ private final int metric;
- @Override
+ public VirtualNetworkRoute(InetSocketAddress target, InetSocketAddress via, int flags, int metric) {
+ this.target = target;
+ this.via = via;
+ this.flags = flags;
+ this.metric = metric;
+ }
+
+ @Override
public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append(target.toString());
- if (via != null) {
- sb.append(via.toString());
- }
- return sb.toString();
+ return "VirtualNetworkRoute(" + target + ", " + via + ", " + flags + ", " + metric + ")";
}
@Override
- public int compareTo(VirtualNetworkRoute other) {
- return this.toString().compareTo(other.toString());
- }
-
- public boolean equals(VirtualNetworkRoute other) {
- boolean targetEquals = false;
- if (target == null && other.target == null) {
- targetEquals = true;
- }
- else if (target == null && other.target != null) {
- targetEquals = false;
- }
- else if (target != null && other.target == null) {
- targetEquals = false;
+ public int compareTo(VirtualNetworkRoute other) {
+ throw new RuntimeException("Unimplemented");
+ }
+
+ @Override
+ public boolean equals(Object o) {
+
+ if (!(o instanceof VirtualNetworkRoute)) {
+ return false;
}
- else {
- targetEquals = target.toString().equals(other.target.toString());
+
+ VirtualNetworkRoute other = (VirtualNetworkRoute) o;
+
+ boolean targetEquals;
+ if (target == null) {
+ //noinspection RedundantIfStatement
+ if (other.target == null) {
+ targetEquals = true;
+ } else {
+ targetEquals = false;
+ }
+ } else {
+ if (other.target == null) {
+ targetEquals = false;
+ } else {
+ targetEquals = target.equals(other.target);
+ }
}
+ if (!targetEquals) {
+ return false;
+ }
boolean viaEquals;
- if (via == null && other.via == null) {
- viaEquals = true;
+ if (via == null) {
+ //noinspection RedundantIfStatement
+ if (other.via == null) {
+ viaEquals = true;
+ } else {
+ viaEquals = false;
+ }
+ } else {
+ if (other.via == null) {
+ viaEquals = false;
+ } else {
+ viaEquals = via.equals(other.via);
+ }
}
- else if (via == null && other.via != null) {
- viaEquals = false;
+
+ if (!viaEquals) {
+ return false;
}
- else if (via != null && other.via == null) {
- viaEquals = false;
+
+ if (flags != other.flags) {
+ return false;
}
- else {
- viaEquals = via.toString().equals(other.via.toString());
+
+ if (metric != other.metric) {
+ return false;
}
- return viaEquals && targetEquals;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+
+ int result = 17;
+ result = 37 * result + (target == null ? 0 : target.hashCode());
+ result = 37 * result + (via == null ? 0 : via.hashCode());
+ result = 37 * result + flags;
+ result = 37 * result + metric;
+
+ return result;
+ }
+
+ public InetSocketAddress getTarget() {
+ return target;
+ }
+
+ public InetSocketAddress getVia() {
+ return via;
+ }
+
+ public int getFlags() {
+ return flags;
+ }
+
+ public int getMetric() {
+ return metric;
}
}
diff --git a/app/src/main/java/com/zerotier/sdk/VirtualNetworkStatus.java b/app/src/main/java/com/zerotier/sdk/VirtualNetworkStatus.java
index 2d00561..8a32ba6 100644
--- a/app/src/main/java/com/zerotier/sdk/VirtualNetworkStatus.java
+++ b/app/src/main/java/com/zerotier/sdk/VirtualNetworkStatus.java
@@ -24,36 +24,76 @@
* redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/
*/
+
package com.zerotier.sdk;
+/**
+ * Virtual network status codes
+ *
+ * Defined in ZeroTierOne.h as ZT_VirtualNetworkStatus
+ */
public enum VirtualNetworkStatus {
+
/**
* Waiting for network configuration (also means revision == 0)
*/
- NETWORK_STATUS_REQUESTING_CONFIGURATION,
+ NETWORK_STATUS_REQUESTING_CONFIGURATION(0),
/**
* Configuration received and we are authorized
*/
- NETWORK_STATUS_OK,
+ NETWORK_STATUS_OK(1),
/**
* Netconf master told us 'nope'
*/
- NETWORK_STATUS_ACCESS_DENIED,
+ NETWORK_STATUS_ACCESS_DENIED(2),
/**
* Netconf master exists, but this virtual network does not
*/
- NETWORK_STATUS_NOT_FOUND,
+ NETWORK_STATUS_NOT_FOUND(3),
/**
* Initialization of network failed or other internal error
*/
- NETWORK_STATUS_PORT_ERROR,
+ NETWORK_STATUS_PORT_ERROR(4),
/**
* ZeroTier One version too old
*/
- NETWORK_STATUS_CLIENT_TOO_OLD
+ NETWORK_STATUS_CLIENT_TOO_OLD(5),
+
+ /**
+ * External authentication is required (e.g. SSO)
+ */
+ NETWORK_STATUS_AUTHENTICATION_REQUIRED(6);
+
+ @SuppressWarnings({"FieldCanBeLocal", "unused"})
+ private final int id;
+
+ VirtualNetworkStatus(int id) {
+ this.id = id;
+ }
+
+ public static VirtualNetworkStatus fromInt(int id) {
+ switch (id) {
+ case 0:
+ return NETWORK_STATUS_REQUESTING_CONFIGURATION;
+ case 1:
+ return NETWORK_STATUS_OK;
+ case 2:
+ return NETWORK_STATUS_ACCESS_DENIED;
+ case 3:
+ return NETWORK_STATUS_NOT_FOUND;
+ case 4:
+ return NETWORK_STATUS_PORT_ERROR;
+ case 5:
+ return NETWORK_STATUS_CLIENT_TOO_OLD;
+ case 6:
+ return NETWORK_STATUS_AUTHENTICATION_REQUIRED;
+ default:
+ throw new RuntimeException("Unhandled value: " + id);
+ }
+ }
}
diff --git a/app/src/main/java/com/zerotier/sdk/VirtualNetworkType.java b/app/src/main/java/com/zerotier/sdk/VirtualNetworkType.java
index ab1f4e0..44be886 100644
--- a/app/src/main/java/com/zerotier/sdk/VirtualNetworkType.java
+++ b/app/src/main/java/com/zerotier/sdk/VirtualNetworkType.java
@@ -24,16 +24,41 @@
* redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/
*/
+
package com.zerotier.sdk;
+/**
+ * Virtual network type codes
+ *
+ * Defined in ZeroTierOne.h as ZT_VirtualNetworkType
+ */
public enum VirtualNetworkType {
+
/**
* Private networks are authorized via certificates of membership
*/
- NETWORK_TYPE_PRIVATE,
+ NETWORK_TYPE_PRIVATE(0),
/**
* Public networks have no access control -- they'll always be AUTHORIZED
*/
- NETWORK_TYPE_PUBLIC
+ NETWORK_TYPE_PUBLIC(1);
+
+ @SuppressWarnings({"FieldCanBeLocal", "unused"})
+ private final int id;
+
+ VirtualNetworkType(int id) {
+ this.id = id;
+ }
+
+ public static VirtualNetworkType fromInt(int id) {
+ switch (id) {
+ case 0:
+ return NETWORK_TYPE_PRIVATE;
+ case 1:
+ return NETWORK_TYPE_PUBLIC;
+ default:
+ throw new RuntimeException("Unhandled value: " + id);
+ }
+ }
}
diff --git a/app/src/main/java/com/zerotier/sdk/util/StringUtils.java b/app/src/main/java/com/zerotier/sdk/util/StringUtils.java
new file mode 100644
index 0000000..c7bcc5d
--- /dev/null
+++ b/app/src/main/java/com/zerotier/sdk/util/StringUtils.java
@@ -0,0 +1,52 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2023 ZeroTier, Inc. https://www.zerotier.com/
+ */
+
+package com.zerotier.sdk.util;
+
+public class StringUtils {
+
+ /**
+ * Convert mac address to string.
+ *
+ * @param mac MAC address
+ * @return string in XX:XX:XX:XX:XX:XX format
+ */
+ public static String macAddressToString(long mac) {
+
+ int[] macChars = new int[6];
+ for (int i = 0; i < 6; i++) {
+ macChars[i] = (int) (mac % 256);
+ mac >>= 8;
+ }
+
+ return String.format("%02x:%02x:%02x:%02x:%02x:%02x", macChars[5], macChars[4], macChars[3], macChars[2], macChars[1], macChars[0]);
+ }
+
+ /**
+ * Convert long to hex string.
+ *
+ * @param networkId long
+ * @return string with 0 padding
+ */
+ public static String networkIdToString(long networkId) {
+ return String.format("%016x", networkId);
+ }
+
+ /**
+ * Convert node address to string.
+ *
+ * Node addresses are 40 bits, so print 10 hex characters.
+ *
+ * @param address Node address
+ * @return formatted string
+ */
+ public static String addressToString(long address) {
+ return String.format("%010x", address);
+ }
+
+ public static String etherTypeToString(long etherType) {
+ return String.format("%04x", etherType);
+ }
+}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/events/IsServiceRunningEvent.java b/app/src/main/java/net/kaaass/zerotierfix/events/IsServiceRunningEvent.java
deleted file mode 100644
index cdd171f..0000000
--- a/app/src/main/java/net/kaaass/zerotierfix/events/IsServiceRunningEvent.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package net.kaaass.zerotierfix.events;
-
-public class IsServiceRunningEvent {
- public boolean isRunning = false;
- public Type type = Type.REQUEST;
-
- private IsServiceRunningEvent() {
- }
-
- public static IsServiceRunningEvent NewRequest() {
- return new IsServiceRunningEvent();
- }
-
- public static IsServiceRunningEvent NewReply(boolean z) {
- IsServiceRunningEvent isServiceRunningEvent = new IsServiceRunningEvent();
- isServiceRunningEvent.isRunning = z;
- isServiceRunningEvent.type = Type.REPLY;
- return isServiceRunningEvent;
- }
-
- public enum Type {
- REQUEST,
- REPLY
- }
-}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/events/IsServiceRunningReplyEvent.java b/app/src/main/java/net/kaaass/zerotierfix/events/IsServiceRunningReplyEvent.java
new file mode 100644
index 0000000..8bdf39d
--- /dev/null
+++ b/app/src/main/java/net/kaaass/zerotierfix/events/IsServiceRunningReplyEvent.java
@@ -0,0 +1,11 @@
+package net.kaaass.zerotierfix.events;
+
+import lombok.Data;
+
+/**
+ * 应答服务是否运行事件
+ */
+@Data
+public class IsServiceRunningReplyEvent {
+ private final boolean isRunning;
+}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/events/IsServiceRunningRequestEvent.java b/app/src/main/java/net/kaaass/zerotierfix/events/IsServiceRunningRequestEvent.java
new file mode 100644
index 0000000..d92b237
--- /dev/null
+++ b/app/src/main/java/net/kaaass/zerotierfix/events/IsServiceRunningRequestEvent.java
@@ -0,0 +1,10 @@
+package net.kaaass.zerotierfix.events;
+
+import lombok.Data;
+
+/**
+ * 请求服务是否运行事件
+ */
+@Data
+public class IsServiceRunningRequestEvent {
+}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/events/NetworkConfigChangedByUserEvent.java b/app/src/main/java/net/kaaass/zerotierfix/events/NetworkConfigChangedByUserEvent.java
new file mode 100644
index 0000000..91e8cc7
--- /dev/null
+++ b/app/src/main/java/net/kaaass/zerotierfix/events/NetworkConfigChangedByUserEvent.java
@@ -0,0 +1,15 @@
+package net.kaaass.zerotierfix.events;
+
+import net.kaaass.zerotierfix.model.Network;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ * 用户更改 ZT 网络配置事件
+ */
+@Data
+@AllArgsConstructor
+public class NetworkConfigChangedByUserEvent {
+ private final Network network;
+}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/events/RequestNetworkInfoEvent.java b/app/src/main/java/net/kaaass/zerotierfix/events/NetworkInfoRequestEvent.java
similarity index 68%
rename from app/src/main/java/net/kaaass/zerotierfix/events/RequestNetworkInfoEvent.java
rename to app/src/main/java/net/kaaass/zerotierfix/events/NetworkInfoRequestEvent.java
index 252c68f..d3a925a 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/events/RequestNetworkInfoEvent.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/events/NetworkInfoRequestEvent.java
@@ -1,9 +1,9 @@
package net.kaaass.zerotierfix.events;
-public class RequestNetworkInfoEvent {
+public class NetworkInfoRequestEvent {
private final long networkId;
- public RequestNetworkInfoEvent(long j) {
+ public NetworkInfoRequestEvent(long j) {
this.networkId = j;
}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/events/NetworkListCheckedChangeEvent.java b/app/src/main/java/net/kaaass/zerotierfix/events/NetworkListCheckedChangeEvent.java
new file mode 100644
index 0000000..3f39264
--- /dev/null
+++ b/app/src/main/java/net/kaaass/zerotierfix/events/NetworkListCheckedChangeEvent.java
@@ -0,0 +1,17 @@
+package net.kaaass.zerotierfix.events;
+
+import androidx.appcompat.widget.SwitchCompat;
+
+import net.kaaass.zerotierfix.model.Network;
+
+import lombok.Data;
+
+/**
+ * 网络列表点击按钮事件。用于在后台进程控制 ZT 服务的启停
+ */
+@Data
+public class NetworkListCheckedChangeEvent {
+ private final SwitchCompat switchHandle;
+ private final boolean checked;
+ private final Network selectedNetwork;
+}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/events/RequestNetworkListEvent.java b/app/src/main/java/net/kaaass/zerotierfix/events/NetworkListRequestEvent.java
similarity index 51%
rename from app/src/main/java/net/kaaass/zerotierfix/events/RequestNetworkListEvent.java
rename to app/src/main/java/net/kaaass/zerotierfix/events/NetworkListRequestEvent.java
index 8b143c5..7267839 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/events/RequestNetworkListEvent.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/events/NetworkListRequestEvent.java
@@ -1,4 +1,4 @@
package net.kaaass.zerotierfix.events;
-public class RequestNetworkListEvent {
+public class NetworkListRequestEvent {
}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/events/NetworkReconfigureEvent.java b/app/src/main/java/net/kaaass/zerotierfix/events/NetworkReconfigureEvent.java
index 13e6d4e..c38850c 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/events/NetworkReconfigureEvent.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/events/NetworkReconfigureEvent.java
@@ -1,4 +1,19 @@
package net.kaaass.zerotierfix.events;
+import com.zerotier.sdk.VirtualNetworkConfig;
+
+import net.kaaass.zerotierfix.model.Network;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ * 更新网络配置的结果事件
+ */
+@Data
+@AllArgsConstructor
public class NetworkReconfigureEvent {
+ private final boolean changed;
+ private final Network network;
+ private final VirtualNetworkConfig virtualNetworkConfig;
}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/events/NodeStatusEvent.java b/app/src/main/java/net/kaaass/zerotierfix/events/NodeStatusEvent.java
index 680f9c0..37863f1 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/events/NodeStatusEvent.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/events/NodeStatusEvent.java
@@ -9,7 +9,7 @@
/**
* 节点状态事件
*
- * 在遇到 {@link RequestNodeStatusEvent} 或 Zerotier 事件时触发
+ * 在遇到 {@link NodeStatusRequestEvent} 或 Zerotier 事件时触发
*/
@Data
@AllArgsConstructor
diff --git a/app/src/main/java/net/kaaass/zerotierfix/events/RequestNodeStatusEvent.java b/app/src/main/java/net/kaaass/zerotierfix/events/NodeStatusRequestEvent.java
similarity index 73%
rename from app/src/main/java/net/kaaass/zerotierfix/events/RequestNodeStatusEvent.java
rename to app/src/main/java/net/kaaass/zerotierfix/events/NodeStatusRequestEvent.java
index 1f549bc..b4f36ee 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/events/RequestNodeStatusEvent.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/events/NodeStatusRequestEvent.java
@@ -6,5 +6,5 @@
* 请求节点状态事件
*/
@Data
-public class RequestNodeStatusEvent {
+public class NodeStatusRequestEvent {
}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/events/RequestPeerInfoEvent.java b/app/src/main/java/net/kaaass/zerotierfix/events/PeerInfoRequestEvent.java
similarity index 77%
rename from app/src/main/java/net/kaaass/zerotierfix/events/RequestPeerInfoEvent.java
rename to app/src/main/java/net/kaaass/zerotierfix/events/PeerInfoRequestEvent.java
index 8bdba56..1ddf984 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/events/RequestPeerInfoEvent.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/events/PeerInfoRequestEvent.java
@@ -8,5 +8,5 @@
* @author kaaass
*/
@Data
-public class RequestPeerInfoEvent {
+public class PeerInfoRequestEvent {
}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/events/VPNErrorEvent.java b/app/src/main/java/net/kaaass/zerotierfix/events/VPNErrorEvent.java
new file mode 100644
index 0000000..a33de5d
--- /dev/null
+++ b/app/src/main/java/net/kaaass/zerotierfix/events/VPNErrorEvent.java
@@ -0,0 +1,13 @@
+package net.kaaass.zerotierfix.events;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ * VPN 错误事件
+ */
+@Data
+@AllArgsConstructor
+public class VPNErrorEvent {
+ private final String message;
+}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/events/VirtualNetworkConfigChangedEvent.java b/app/src/main/java/net/kaaass/zerotierfix/events/VirtualNetworkConfigChangedEvent.java
new file mode 100644
index 0000000..f4d547d
--- /dev/null
+++ b/app/src/main/java/net/kaaass/zerotierfix/events/VirtualNetworkConfigChangedEvent.java
@@ -0,0 +1,15 @@
+package net.kaaass.zerotierfix.events;
+
+import com.zerotier.sdk.VirtualNetworkConfig;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ * ZT 网络配置成功更改事件
+ */
+@Data
+@AllArgsConstructor
+public class VirtualNetworkConfigChangedEvent {
+ private final VirtualNetworkConfig virtualNetworkConfig;
+}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/model/Network.java b/app/src/main/java/net/kaaass/zerotierfix/model/Network.java
index f264aa3..6690551 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/model/Network.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/model/Network.java
@@ -19,6 +19,7 @@ public class Network {
private String networkName;
+ @Deprecated
private boolean useDefaultRoute;
private boolean lastActivated;
diff --git a/app/src/main/java/net/kaaass/zerotierfix/model/NetworkConfig.java b/app/src/main/java/net/kaaass/zerotierfix/model/NetworkConfig.java
index e88616f..28bf3c0 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/model/NetworkConfig.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/model/NetworkConfig.java
@@ -1,6 +1,8 @@
package net.kaaass.zerotierfix.model;
import net.kaaass.zerotierfix.R;
+import net.kaaass.zerotierfix.model.type.NetworkStatus;
+import net.kaaass.zerotierfix.model.type.NetworkType;
import org.greenrobot.greendao.DaoException;
import org.greenrobot.greendao.annotation.Convert;
@@ -10,6 +12,7 @@
import org.greenrobot.greendao.converter.PropertyConverter;
import java.util.List;
+
import org.greenrobot.greendao.annotation.Generated;
@Entity
@@ -43,18 +46,22 @@ public class NetworkConfig {
@ToMany(referencedJoinProperty = "networkId")
private List dnsServers;
- /** Used to resolve relations */
+ /**
+ * Used to resolve relations
+ */
@Generated(hash = 2040040024)
private transient DaoSession daoSession;
- /** Used for active entity operations. */
+ /**
+ * Used for active entity operations.
+ */
@Generated(hash = 1627972760)
private transient NetworkConfigDao myDao;
@Generated(hash = 1535887363)
public NetworkConfig(Long id, NetworkType type, NetworkStatus status, String mac, String mtu,
- boolean broadcast, boolean bridging, boolean routeViaZeroTier, boolean useCustomDNS,
- int dnsMode) {
+ boolean broadcast, boolean bridging, boolean routeViaZeroTier, boolean useCustomDNS,
+ int dnsMode) {
this.id = id;
this.type = type;
this.status = status;
@@ -174,7 +181,9 @@ public List getAssignedAddresses() {
return assignedAddresses;
}
- /** Resets a to-many relationship, making the next get call to query for a fresh result. */
+ /**
+ * Resets a to-many relationship, making the next get call to query for a fresh result.
+ */
@Generated(hash = 1705851723)
public synchronized void resetAssignedAddresses() {
assignedAddresses = null;
@@ -202,7 +211,9 @@ public List getDnsServers() {
return dnsServers;
}
- /** Resets a to-many relationship, making the next get call to query for a fresh result. */
+ /**
+ * Resets a to-many relationship, making the next get call to query for a fresh result.
+ */
@Generated(hash = 980018091)
public synchronized void resetDnsServers() {
dnsServers = null;
@@ -251,130 +262,19 @@ public void __setDaoSession(DaoSession daoSession) {
myDao = daoSession != null ? daoSession.getNetworkConfigDao() : null;
}
- public enum NetworkType {
- UNKNOWN(0),
- PRIVATE(1),
- PUBLIC(2);
-
- final int id;
-
- NetworkType(int i) {
- this.id = i;
- }
-
- public String toString() {
- int i = this.id;
- if (i != 1) {
- return i != 2 ? "Unknown" : "Public";
- }
- return "Private";
- }
-
- public int toStringId() {
- int i = this.id;
- if (i != 1) {
- return i != 2 ? R.string.network_type_unknown : R.string.network_type_public;
- }
- return R.string.network_type_private;
- }
- }
-
- public enum DNSMode {
- NO_DNS(0),
- NETWORK_DNS(1),
- CUSTOM_DNS(2);
-
- final int id;
-
- DNSMode(int i) {
- this.id = i;
- }
-
- public String toString() {
- int i = this.id;
- if (i == 0) {
- return "No DNS";
- }
- if (i != 1) {
- return i != 2 ? "Unknown" : "Custom DNS";
- }
- return "Network DNS";
- }
- }
-
- public enum NetworkStatus {
- UNKNOWN(0),
- OK(1),
- ACCESS_DENIED(2),
- CLIENT_TOO_OLD(3),
- NOT_FOUND(4),
- PORT_ERROR(5),
- REQUESTING_CONFIGURATION(6);
-
- final int id;
-
- NetworkStatus(int i) {
- this.id = i;
- }
-
- public String toString() {
- switch (this.id) {
- case 1:
- return "OK";
- case 2:
- return "ACCESS DENIED";
- case 3:
- return "CLIENT TOO OLD";
- case 4:
- return "NETWORK NOT FOUND";
- case 5:
- return "PORT ERROR";
- case 6:
- return "REQUESTING CONFIGURATION";
- default:
- return "UNKNOWN";
- }
- }
-
- public int toStringId() {
- switch (this.id) {
- case 1:
- return R.string.network_status_ok;
- case 2:
- return R.string.network_status_access_denied;
- case 3:
- return R.string.network_status_client_too_old;
- case 4:
- return R.string.network_status_not_found;
- case 5:
- return R.string.network_status_port_error;
- case 6:
- return R.string.network_status_requesting_configuration;
- default:
- return R.string.network_status_unknown;
- }
- }
- }
-
public static class NetworkTypeConverter implements PropertyConverter {
public NetworkType convertToEntityProperty(Integer num) {
if (num == null) {
return null;
}
- NetworkType[] values = NetworkType.values();
- for (NetworkType networkType : values) {
- if (networkType.id == num) {
- return networkType;
- }
- }
- return NetworkType.PRIVATE;
+ return NetworkType.fromInt(num);
}
public Integer convertToDatabaseValue(NetworkType networkType) {
if (networkType == null) {
return null;
}
- return networkType.id;
+ return networkType.toInt();
}
}
@@ -383,20 +283,14 @@ public NetworkStatus convertToEntityProperty(Integer num) {
if (num == null) {
return null;
}
- NetworkStatus[] values = NetworkStatus.values();
- for (NetworkStatus networkStatus : values) {
- if (networkStatus.id == num) {
- return networkStatus;
- }
- }
- return NetworkStatus.UNKNOWN;
+ return NetworkStatus.fromInt(num);
}
public Integer convertToDatabaseValue(NetworkStatus networkStatus) {
if (networkStatus == null) {
return null;
}
- return networkStatus.id;
+ return networkStatus.toInt();
}
}
}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/model/type/DNSMode.java b/app/src/main/java/net/kaaass/zerotierfix/model/type/DNSMode.java
new file mode 100644
index 0000000..9d30337
--- /dev/null
+++ b/app/src/main/java/net/kaaass/zerotierfix/model/type/DNSMode.java
@@ -0,0 +1,30 @@
+package net.kaaass.zerotierfix.model.type;
+
+public enum DNSMode {
+ NO_DNS(0),
+ NETWORK_DNS(1),
+ CUSTOM_DNS(2);
+
+ private final int id;
+
+ DNSMode(int i) {
+ this.id = i;
+ }
+
+ public static DNSMode fromInt(int i) {
+ if (i != 0) {
+ if (i == 1) {
+ return NETWORK_DNS;
+ }
+ if (i == 2) {
+ return CUSTOM_DNS;
+ }
+ throw new RuntimeException("Unhandled value: " + i);
+ }
+ return NO_DNS;
+ }
+
+ public int toInt() {
+ return this.id;
+ }
+}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/model/type/NetworkStatus.java b/app/src/main/java/net/kaaass/zerotierfix/model/type/NetworkStatus.java
new file mode 100644
index 0000000..cb532fa
--- /dev/null
+++ b/app/src/main/java/net/kaaass/zerotierfix/model/type/NetworkStatus.java
@@ -0,0 +1,82 @@
+package net.kaaass.zerotierfix.model.type;
+
+import com.zerotier.sdk.VirtualNetworkStatus;
+
+import net.kaaass.zerotierfix.R;
+
+public enum NetworkStatus {
+ REQUESTING_CONFIGURATION(0), OK(1), ACCESS_DENIED(2), NOT_FOUND(3), PORT_ERROR(4), CLIENT_TOO_OLD(5), AUTHENTICATION_REQUIRED(6);
+
+ private final int id;
+
+ NetworkStatus(int i) {
+ this.id = i;
+ }
+
+ public static NetworkStatus fromInt(int i) {
+ switch (i) {
+ case 0:
+ return REQUESTING_CONFIGURATION;
+ case 1:
+ return OK;
+ case 2:
+ return ACCESS_DENIED;
+ case 3:
+ return NOT_FOUND;
+ case 4:
+ return PORT_ERROR;
+ case 5:
+ return CLIENT_TOO_OLD;
+ case 6:
+ return AUTHENTICATION_REQUIRED;
+ default:
+ throw new RuntimeException("Unhandled value: " + i);
+ }
+ }
+
+ public static NetworkStatus fromVirtualNetworkStatus(VirtualNetworkStatus virtualNetworkStatus) {
+ switch (virtualNetworkStatus) {
+ case NETWORK_STATUS_REQUESTING_CONFIGURATION:
+ return REQUESTING_CONFIGURATION;
+ case NETWORK_STATUS_OK:
+ return OK;
+ case NETWORK_STATUS_ACCESS_DENIED:
+ return ACCESS_DENIED;
+ case NETWORK_STATUS_NOT_FOUND:
+ return NOT_FOUND;
+ case NETWORK_STATUS_PORT_ERROR:
+ return PORT_ERROR;
+ case NETWORK_STATUS_CLIENT_TOO_OLD:
+ return CLIENT_TOO_OLD;
+ case NETWORK_STATUS_AUTHENTICATION_REQUIRED:
+ return AUTHENTICATION_REQUIRED;
+ default:
+ throw new RuntimeException("Unhandled status: " + virtualNetworkStatus);
+ }
+ }
+
+ public int toStringId() {
+ switch (this) {
+ case REQUESTING_CONFIGURATION:
+ return R.string.network_status_requesting_configuration;
+ case OK:
+ return R.string.network_status_ok;
+ case ACCESS_DENIED:
+ return R.string.network_status_access_denied;
+ case NOT_FOUND:
+ return R.string.network_status_not_found;
+ case PORT_ERROR:
+ return R.string.network_status_port_error;
+ case CLIENT_TOO_OLD:
+ return R.string.network_status_client_too_old;
+ case AUTHENTICATION_REQUIRED:
+ return R.string.network_status_authentication_required;
+ default:
+ return R.string.network_status_unknown;
+ }
+ }
+
+ public int toInt() {
+ return this.id;
+ }
+}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/model/type/NetworkType.java b/app/src/main/java/net/kaaass/zerotierfix/model/type/NetworkType.java
new file mode 100644
index 0000000..9bf5cb7
--- /dev/null
+++ b/app/src/main/java/net/kaaass/zerotierfix/model/type/NetworkType.java
@@ -0,0 +1,53 @@
+package net.kaaass.zerotierfix.model.type;
+
+import com.zerotier.sdk.VirtualNetworkType;
+
+import net.kaaass.zerotierfix.R;
+
+public enum NetworkType {
+ UNKNOWN(0),
+ PRIVATE(1),
+ PUBLIC(2);
+
+ private final int id;
+
+ NetworkType(int i) {
+ this.id = i;
+ }
+
+ public static NetworkType fromInt(int i) {
+ if (i != 0) {
+ if (i == 1) {
+ return PUBLIC;
+ }
+ if (i == 2) {
+ return PUBLIC;
+ }
+ throw new RuntimeException("Unhandled value: " + i);
+ }
+ return PRIVATE;
+ }
+
+ public static NetworkType fromVirtualNetworkType(VirtualNetworkType virtualNetworkType) {
+ switch (virtualNetworkType) {
+ case NETWORK_TYPE_PRIVATE:
+ return PRIVATE;
+ case NETWORK_TYPE_PUBLIC:
+ return PUBLIC;
+ default:
+ throw new RuntimeException("Unhandled type: " + virtualNetworkType);
+ }
+ }
+
+ public int toStringId() {
+ int i = this.id;
+ if (i != 1) {
+ return i != 2 ? R.string.network_type_unknown : R.string.network_type_public;
+ }
+ return R.string.network_type_private;
+ }
+
+ public int toInt() {
+ return this.id;
+ }
+}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/service/ARPEntry.java b/app/src/main/java/net/kaaass/zerotierfix/service/ARPEntry.java
new file mode 100644
index 0000000..a0f63e7
--- /dev/null
+++ b/app/src/main/java/net/kaaass/zerotierfix/service/ARPEntry.java
@@ -0,0 +1,28 @@
+package net.kaaass.zerotierfix.service;
+
+import java.net.InetAddress;
+
+import lombok.AccessLevel;
+import lombok.Data;
+import lombok.Setter;
+
+/**
+ * ARP 表项。记录 MAC 与 IPv4 地址的对应关系及记录时间
+ */
+@Data
+public class ARPEntry {
+ private final long mac;
+ private final InetAddress address;
+ @Setter(AccessLevel.NONE)
+ private long time;
+
+ ARPEntry(long mac, InetAddress inetAddress) {
+ this.mac = mac;
+ this.address = inetAddress;
+ updateTime();
+ }
+
+ public void updateTime() {
+ this.time = System.currentTimeMillis();
+ }
+}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/service/ARPReplyData.java b/app/src/main/java/net/kaaass/zerotierfix/service/ARPReplyData.java
new file mode 100644
index 0000000..9de3b33
--- /dev/null
+++ b/app/src/main/java/net/kaaass/zerotierfix/service/ARPReplyData.java
@@ -0,0 +1,14 @@
+package net.kaaass.zerotierfix.service;
+
+import java.net.InetAddress;
+
+import lombok.Data;
+
+/**
+ * ARP 应答报文的所需数据。由于报文内容总是当前节点的 IP 与 MAC,因此仅记录应答报文目标的信息。
+ */
+@Data
+public class ARPReplyData {
+ private final long destMac;
+ private final InetAddress destAddress;
+}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/service/ARPTable.java b/app/src/main/java/net/kaaass/zerotierfix/service/ARPTable.java
index b95ebf1..d048f40 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/service/ARPTable.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/service/ARPTable.java
@@ -12,9 +12,9 @@ public class ARPTable {
private static final long ENTRY_TIMEOUT = 120000;
private static final int REPLY = 2;
private static final int REQUEST = 1;
- private final HashMap entriesMap = new HashMap<>();
+ private final HashMap entriesMap = new HashMap<>();
private final HashMap inetAddressToMacAddress = new HashMap<>();
- private final HashMap ipEntriesMap = new HashMap<>();
+ private final HashMap ipEntriesMap = new HashMap<>();
private final HashMap macAddressToInetAdddress = new HashMap<>();
private final Thread timeoutThread = new Thread("ARP Timeout Thread") {
/* class com.zerotier.one.service.ARPTable.AnonymousClass1 */
@@ -22,14 +22,14 @@ public class ARPTable {
public void run() {
while (!isInterrupted()) {
try {
- for (ArpEntry arpEntry : new HashMap<>(ARPTable.this.entriesMap).values()) {
- if (arpEntry.time + ARPTable.ENTRY_TIMEOUT < System.currentTimeMillis()) {
+ for (ARPEntry arpEntry : new HashMap<>(ARPTable.this.entriesMap).values()) {
+ if (arpEntry.getTime() + ARPTable.ENTRY_TIMEOUT < System.currentTimeMillis()) {
Log.d(ARPTable.TAG, "Removing " + arpEntry.getAddress().toString() + " from ARP cache");
synchronized (ARPTable.this.macAddressToInetAdddress) {
- ARPTable.this.macAddressToInetAdddress.remove(arpEntry.mac);
+ ARPTable.this.macAddressToInetAdddress.remove(arpEntry.getMac());
}
synchronized (ARPTable.this.inetAddressToMacAddress) {
- ARPTable.this.inetAddressToMacAddress.remove(arpEntry.address);
+ ARPTable.this.inetAddressToMacAddress.remove(arpEntry.getAddress());
}
synchronized (ARPTable.this.entriesMap) {
ARPTable.this.entriesMap.remove(arpEntry.getMac());
@@ -61,13 +61,6 @@ public static byte[] longToBytes(long j) {
return allocate.array();
}
- /* access modifiers changed from: protected */
- public void finalize() throws Throwable {
- stop();
- super.finalize();
- }
-
- /* access modifiers changed from: protected */
public void stop() {
try {
this.timeoutThread.interrupt();
@@ -84,7 +77,7 @@ public void setAddress(InetAddress inetAddress, long j) {
synchronized (this.macAddressToInetAdddress) {
this.macAddressToInetAdddress.put(j, inetAddress);
}
- ArpEntry arpEntry = new ArpEntry(j, inetAddress);
+ ARPEntry arpEntry = new ARPEntry(j, inetAddress);
synchronized (this.entriesMap) {
this.entriesMap.put(j, arpEntry);
}
@@ -95,7 +88,7 @@ public void setAddress(InetAddress inetAddress, long j) {
private void updateArpEntryTime(long j) {
synchronized (this.entriesMap) {
- ArpEntry arpEntry = this.entriesMap.get(j);
+ ARPEntry arpEntry = this.entriesMap.get(j);
if (arpEntry != null) {
arpEntry.updateTime();
}
@@ -104,7 +97,7 @@ private void updateArpEntryTime(long j) {
private void updateArpEntryTime(InetAddress inetAddress) {
synchronized (this.ipEntriesMap) {
- ArpEntry arpEntry = this.ipEntriesMap.get(inetAddress);
+ ARPEntry arpEntry = this.ipEntriesMap.get(inetAddress);
if (arpEntry != null) {
arpEntry.updateTime();
}
@@ -118,10 +111,13 @@ public long getMacForAddress(InetAddress inetAddress) {
return -1;
}
Log.d(TAG, "Returning MAC for " + inetAddress.toString());
- long longValue = this.inetAddressToMacAddress.get(inetAddress);
- updateArpEntryTime(longValue);
- return longValue;
+ var longValue = this.inetAddressToMacAddress.get(inetAddress);
+ if (longValue != null) {
+ updateArpEntryTime(longValue);
+ return longValue;
+ }
}
+ return -1;
}
/* access modifiers changed from: package-private */
@@ -177,82 +173,49 @@ public byte[] getARPPacket(int i, long j, long j2, InetAddress inetAddress, Inet
return bArr;
}
- public ARPReplyData processARPPacket(byte[] bArr) {
- InetAddress inetAddress;
- InetAddress inetAddress2;
+ public ARPReplyData processARPPacket(byte[] packetData) {
+ InetAddress srcAddress;
+ InetAddress dstAddress;
Log.d(TAG, "Processing ARP packet");
- byte[] bArr2 = new byte[8];
- System.arraycopy(bArr, 8, bArr2, 2, 6);
- byte[] bArr3 = new byte[4];
- System.arraycopy(bArr, 14, bArr3, 0, 4);
- byte[] bArr4 = new byte[8];
- System.arraycopy(bArr, 18, bArr4, 2, 6);
- byte[] bArr5 = new byte[4];
- System.arraycopy(bArr, 24, bArr5, 0, 4);
+
+ // 解析包内 IP、MAC 地址
+ byte[] rawSrcMac = new byte[8];
+ System.arraycopy(packetData, 8, rawSrcMac, 2, 6);
+ byte[] rawSrcAddress = new byte[4];
+ System.arraycopy(packetData, 14, rawSrcAddress, 0, 4);
+ byte[] rawDstMac = new byte[8];
+ System.arraycopy(packetData, 18, rawDstMac, 2, 6);
+ byte[] rawDstAddress = new byte[4];
+ System.arraycopy(packetData, 24, rawDstAddress, 0, 4);
try {
- inetAddress = InetAddress.getByAddress(bArr3);
+ srcAddress = InetAddress.getByAddress(rawSrcAddress);
} catch (Exception unused) {
- inetAddress = null;
+ srcAddress = null;
}
try {
- inetAddress2 = InetAddress.getByAddress(bArr5);
- } catch (Exception unused2) {
- inetAddress2 = null;
- }
- long j = ByteBuffer.wrap(bArr2).getLong();
- long j2 = ByteBuffer.wrap(bArr4).getLong();
- if (!(j == 0 || inetAddress == null)) {
- setAddress(inetAddress, j);
- }
- if (!(j2 == 0 || inetAddress2 == null)) {
- setAddress(inetAddress2, j2);
- }
- if (bArr[7] != 1) {
- return null;
- }
- Log.d(TAG, "Reply needed");
- ARPReplyData aRPReplyData = new ARPReplyData();
- aRPReplyData.destMac = j;
- aRPReplyData.destAddress = inetAddress;
- return aRPReplyData;
- }
-
- public static class ARPReplyData {
- public InetAddress destAddress;
- public long destMac;
- public InetAddress senderAddress;
- public long senderMac;
-
- public ARPReplyData() {
- }
- }
-
- /* access modifiers changed from: private */
- public static class ArpEntry {
- private final InetAddress address;
- private final long mac;
- private long time;
-
- ArpEntry(long j, InetAddress inetAddress) {
- this.mac = j;
- this.address = inetAddress;
- updateTime();
+ dstAddress = InetAddress.getByAddress(rawDstAddress);
+ } catch (Exception unused) {
+ dstAddress = null;
}
+ long srcMac = ByteBuffer.wrap(rawSrcMac).getLong();
+ long dstMac = ByteBuffer.wrap(rawDstMac).getLong();
- public long getMac() {
- return this.mac;
+ // 更新 ARP 表项
+ if (srcMac != 0 && srcAddress != null) {
+ setAddress(srcAddress, srcMac);
}
-
- public InetAddress getAddress() {
- return this.address;
+ if (dstMac != 0 && dstAddress != null) {
+ setAddress(dstAddress, dstMac);
}
- public void updateTime() {
- this.time = System.currentTimeMillis();
- }
-
- public boolean equals(ArpEntry arpEntry) {
- return this.mac == arpEntry.mac && this.address.equals(arpEntry.address);
+ // 处理响应行为
+ var packetType = packetData[7];
+ if (packetType == REQUEST) {
+ // ARP 请求,返回应答数据
+ Log.d(TAG, "Reply needed");
+ return new ARPReplyData(srcMac, srcAddress);
+ } else {
+ return null;
}
}
}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/service/NDPEntry.java b/app/src/main/java/net/kaaass/zerotierfix/service/NDPEntry.java
new file mode 100644
index 0000000..868473e
--- /dev/null
+++ b/app/src/main/java/net/kaaass/zerotierfix/service/NDPEntry.java
@@ -0,0 +1,28 @@
+package net.kaaass.zerotierfix.service;
+
+import java.net.InetAddress;
+
+import lombok.AccessLevel;
+import lombok.Data;
+import lombok.Setter;
+
+/**
+ * NDP 表项。记录 MAC 与 IPv6 地址的对应关系及记录时间
+ */
+@Data
+public class NDPEntry {
+ private final long mac;
+ private final InetAddress address;
+ @Setter(AccessLevel.NONE)
+ private long time;
+
+ NDPEntry(long j, InetAddress inetAddress) {
+ this.mac = j;
+ this.address = inetAddress;
+ updateTime();
+ }
+
+ public void updateTime() {
+ this.time = System.currentTimeMillis();
+ }
+}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/service/NDPTable.java b/app/src/main/java/net/kaaass/zerotierfix/service/NDPTable.java
index 6605190..f5daf92 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/service/NDPTable.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/service/NDPTable.java
@@ -19,16 +19,17 @@ public class NDPTable {
private final Thread timeoutThread = new Thread("NDP Timeout Thread") {
/* class com.zerotier.one.service.NDPTable.AnonymousClass1 */
+ @Override
public void run() {
while (!isInterrupted()) {
try {
for (NDPEntry nDPEntry : new HashMap<>(NDPTable.this.entriesMap).values()) {
- if (nDPEntry.time + NDPTable.ENTRY_TIMEOUT < System.currentTimeMillis()) {
+ if (nDPEntry.getTime() + NDPTable.ENTRY_TIMEOUT < System.currentTimeMillis()) {
synchronized (NDPTable.this.macAddressToInetAddress) {
- NDPTable.this.macAddressToInetAddress.remove(nDPEntry.mac);
+ NDPTable.this.macAddressToInetAddress.remove(nDPEntry.getMac());
}
synchronized (NDPTable.this.inetAddressToMacAddress) {
- NDPTable.this.inetAddressToMacAddress.remove(nDPEntry.address);
+ NDPTable.this.inetAddressToMacAddress.remove(nDPEntry.getAddress());
}
synchronized (NDPTable.this.entriesMap) {
NDPTable.this.entriesMap.remove(nDPEntry.getMac());
@@ -51,12 +52,6 @@ public NDPTable() {
this.timeoutThread.start();
}
- /* access modifiers changed from: protected */
- public void finalize() throws Throwable {
- stop();
- super.finalize();
- }
-
/* access modifiers changed from: protected */
public void stop() {
try {
@@ -169,33 +164,4 @@ public byte[] getNeighborSolicitationPacket(InetAddress inetAddress, InetAddress
return bArr;
}
- /* access modifiers changed from: private */
- public class NDPEntry {
- private final InetAddress address;
- private final long mac;
- private long time;
-
- NDPEntry(long j, InetAddress inetAddress) {
- this.mac = j;
- this.address = inetAddress;
- updateTime();
- }
-
- public long getMac() {
- return this.mac;
- }
-
- public InetAddress getAddress() {
- return this.address;
- }
-
- /* access modifiers changed from: package-private */
- public void updateTime() {
- this.time = System.currentTimeMillis();
- }
-
- public boolean equals(NDPEntry nDPEntry) {
- return this.mac == nDPEntry.mac && this.address.equals(nDPEntry.address);
- }
- }
}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/service/NetworkStateReceiver.java b/app/src/main/java/net/kaaass/zerotierfix/service/NetworkStateReceiver.java
deleted file mode 100644
index 877dd19..0000000
--- a/app/src/main/java/net/kaaass/zerotierfix/service/NetworkStateReceiver.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package net.kaaass.zerotierfix.service;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-
-// TODO: clear up
-public class NetworkStateReceiver extends BroadcastReceiver {
- private static final String TAG = "NetworkStateReceiver";
-
- public void onReceive(Context context, Intent intent) {
- NetworkInfo activeNetworkInfo = ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
- if (activeNetworkInfo != null) {
- activeNetworkInfo.isConnectedOrConnecting();
- }
- }
-}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/service/Route.java b/app/src/main/java/net/kaaass/zerotierfix/service/Route.java
index 448f1c6..f4e8f62 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/service/Route.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/service/Route.java
@@ -4,32 +4,18 @@
import java.net.InetAddress;
-// TODO: clear up
-public class Route {
- InetAddress address;
- InetAddress gateway = null;
- int prefix;
-
- public Route(InetAddress inetAddress, int i) {
- this.address = inetAddress;
- this.prefix = i;
- }
-
- /* access modifiers changed from: package-private */
- public InetAddress getGateway() {
- return this.gateway;
- }
+import lombok.Data;
- /* access modifiers changed from: package-private */
- public void setGateway(InetAddress inetAddress) {
- this.gateway = inetAddress;
- }
+/**
+ * 路由记录数据类
+ */
+@Data
+public class Route {
+ private final InetAddress address;
+ private final int prefix;
+ private InetAddress gateway = null;
public boolean belongsToRoute(InetAddress inetAddress) {
return this.address.equals(InetAddressUtils.addressToRoute(inetAddress, this.prefix));
}
-
- public boolean equals(Route route) {
- return this.address.equals(route.address) && this.prefix == route.prefix && this.gateway.equals(route.gateway);
- }
}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/service/StartupReceiver.java b/app/src/main/java/net/kaaass/zerotierfix/service/StartupReceiver.java
index d2095a9..798686b 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/service/StartupReceiver.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/service/StartupReceiver.java
@@ -6,13 +6,16 @@
import android.preference.PreferenceManager;
import android.util.Log;
+import net.kaaass.zerotierfix.util.Constants;
+
// TODO: clear up
public class StartupReceiver extends BroadcastReceiver {
private static final String TAG = "StartupReceiver";
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "Received: " + intent.getAction() + ". Starting ZeroTier One service.");
- if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean("general_start_zerotier_on_boot", true)) {
+ var pref = PreferenceManager.getDefaultSharedPreferences(context);
+ if (pref.getBoolean(Constants.PREF_GENERAL_START_ZEROTIER_ON_BOOT, true)) {
Log.i(TAG, "Preferences set to start ZeroTier on boot");
} else {
Log.i(TAG, "Preferences set to not start ZeroTier on boot");
diff --git a/app/src/main/java/net/kaaass/zerotierfix/service/TunTapAdapter.java b/app/src/main/java/net/kaaass/zerotierfix/service/TunTapAdapter.java
index b819b52..20c3861 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/service/TunTapAdapter.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/service/TunTapAdapter.java
@@ -8,6 +8,7 @@
import com.zerotier.sdk.ResultCode;
import com.zerotier.sdk.VirtualNetworkConfig;
import com.zerotier.sdk.VirtualNetworkFrameListener;
+import com.zerotier.sdk.util.StringUtils;
import net.kaaass.zerotierfix.util.IPPacketUtils;
import net.kaaass.zerotierfix.util.InetAddressUtils;
@@ -23,25 +24,24 @@
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashMap;
+import java.util.Objects;
// TODO: clear up
public class TunTapAdapter implements VirtualNetworkFrameListener {
- public static final long BROADCAST_MAC = 281474976710655L;
public static final String TAG = "TunTapAdapter";
private static final int ARP_PACKET = 2054;
private static final int IPV4_PACKET = 2048;
private static final int IPV6_PACKET = 34525;
private final HashMap routeMap = new HashMap<>();
+ private final long networkId;
+ private final ZeroTierOneService ztService;
private ARPTable arpTable = new ARPTable();
- private VirtualNetworkConfig cfg;
private FileInputStream in;
private NDPTable ndpTable = new NDPTable();
- private final long networkId;
private Node node;
private FileOutputStream out;
private Thread receiveThread;
private ParcelFileDescriptor vpnSocket;
- private final ZeroTierOneService ztService;
public TunTapAdapter(ZeroTierOneService zeroTierOneService, long j) {
this.ztService = zeroTierOneService;
@@ -63,21 +63,22 @@ public static long multicastAddressToMAC(InetAddress inetAddress) {
private void addMulticastRoutes() {
}
- public void setNetworkConfig(VirtualNetworkConfig virtualNetworkConfig) {
- this.cfg = virtualNetworkConfig;
- }
-
- public void setNode(Node node2) {
- this.node = node2;
+ public void setNode(Node node) {
+ this.node = node;
try {
- node2.multicastSubscribe(this.networkId, multicastAddressToMAC(InetAddress.getByName("224.224.224.224")));
+ var multicastAddress = InetAddress.getByName("224.224.224.224");
+ var result = node
+ .multicastSubscribe(this.networkId, multicastAddressToMAC(multicastAddress));
+ if (result != ResultCode.RESULT_OK) {
+ Log.e(TAG, "Error when calling multicastSubscribe: " + result);
+ }
} catch (UnknownHostException e) {
- Log.e(TAG, "", e);
+ Log.e(TAG, e.toString(), e);
}
}
- public void setVpnSocket(ParcelFileDescriptor parcelFileDescriptor) {
- this.vpnSocket = parcelFileDescriptor;
+ public void setVpnSocket(ParcelFileDescriptor vpnSocket) {
+ this.vpnSocket = vpnSocket;
}
public void setFileStreams(FileInputStream fileInputStream, FileOutputStream fileOutputStream) {
@@ -85,9 +86,9 @@ public void setFileStreams(FileInputStream fileInputStream, FileOutputStream fil
this.out = fileOutputStream;
}
- public void addRouteAndNetwork(Route route, long j) {
+ public void addRouteAndNetwork(Route route, long networkId) {
synchronized (this.routeMap) {
- this.routeMap.put(route, Long.valueOf(j));
+ this.routeMap.put(route, networkId);
}
}
@@ -99,63 +100,60 @@ public void clearRouteMap() {
}
private boolean isIPv4Multicast(InetAddress inetAddress) {
- byte[] address = inetAddress.getAddress();
- return address[0] >= -32 && address[0] <= -17;
+ return (inetAddress.getAddress()[0] & 0xF0) == 224;
}
private boolean isIPv6Multicast(InetAddress inetAddress) {
- byte[] address = inetAddress.getAddress();
- return address[0] == -1 && address[1] >= 0 && address[1] <= -2;
+ return (inetAddress.getAddress()[0] & 0xFF) == 0xFF;
}
public void startThreads() {
this.receiveThread = new Thread("Tunnel Receive Thread") {
- /* class com.zerotier.one.service.TunTapAdapter.AnonymousClass1 */
+ @Override
public void run() {
+ // 创建 ARP、NDP 表
if (TunTapAdapter.this.ndpTable == null) {
TunTapAdapter.this.ndpTable = new NDPTable();
}
if (TunTapAdapter.this.arpTable == null) {
TunTapAdapter.this.arpTable = new ARPTable();
}
+ // 转发 TUN 消息至 Zerotier
try {
Log.d(TunTapAdapter.TAG, "TUN Receive Thread Started");
- ByteBuffer allocate = ByteBuffer.allocate(32767);
- allocate.order(ByteOrder.LITTLE_ENDIAN);
+ var buffer = ByteBuffer.allocate(32767);
+ buffer.order(ByteOrder.LITTLE_ENDIAN);
while (!isInterrupted()) {
try {
- boolean z = true;
- int read = TunTapAdapter.this.in.read(allocate.array());
- if (read > 0) {
- Log.d(TunTapAdapter.TAG, "Sending packet to ZeroTier. " + read + " bytes.");
- byte[] bArr = new byte[read];
- System.arraycopy(allocate.array(), 0, bArr, 0, read);
- byte iPVersion = IPPacketUtils.getIPVersion(bArr);
+ boolean noDataBeenRead = true;
+ int readCount = TunTapAdapter.this.in.read(buffer.array());
+ if (readCount > 0) {
+ Log.d(TunTapAdapter.TAG, "Sending packet to ZeroTier. " + readCount + " bytes.");
+ var readData = new byte[readCount];
+ System.arraycopy(buffer.array(), 0, readData, 0, readCount);
+ byte iPVersion = IPPacketUtils.getIPVersion(readData);
if (iPVersion == 4) {
- TunTapAdapter.this.handleIPv4Packet(bArr);
+ TunTapAdapter.this.handleIPv4Packet(readData);
} else if (iPVersion == 6) {
- TunTapAdapter.this.handleIPv6Packet(bArr);
+ TunTapAdapter.this.handleIPv6Packet(readData);
} else {
Log.e(TunTapAdapter.TAG, "Unknown IP version");
}
- allocate.clear();
- z = false;
+ buffer.clear();
+ noDataBeenRead = false;
}
- if (z) {
+ if (noDataBeenRead) {
Thread.sleep(10);
}
- } catch (InterruptedException e) {
- Log.e(TunTapAdapter.TAG, "Tun/Tap Interrupted", e);
- throw e;
- } catch (Exception e2) {
- Log.e(TunTapAdapter.TAG, "Error in TUN Receive", e2);
+ } catch (IOException e) {
+ Log.e(TunTapAdapter.TAG, "Error in TUN Receive: " + e.getMessage(), e);
}
}
- } catch (Exception e3) {
- Log.e(TunTapAdapter.TAG, "Exception ending Tun/Tap", e3);
+ } catch (InterruptedException ignored) {
}
Log.d(TunTapAdapter.TAG, "TUN Receive Thread ended");
+ // 关闭 ARP、NDP 表
TunTapAdapter.this.ndpTable.stop();
TunTapAdapter.this.ndpTable = null;
TunTapAdapter.this.arpTable.stop();
@@ -165,209 +163,193 @@ public void run() {
this.receiveThread.start();
}
- /* access modifiers changed from: private */
- /* access modifiers changed from: public */
- private void handleIPv4Packet(byte[] bArr) {
- boolean z;
- InetAddress inetAddress;
- int i;
- long j;
- InetAddress destIP = IPPacketUtils.getDestIP(bArr);
- InetAddress sourceIP = IPPacketUtils.getSourceIP(bArr);
- if (this.cfg == null) {
+ private void handleIPv4Packet(byte[] packetData) {
+ boolean isMulticast;
+ long destMac;
+ var destIP = IPPacketUtils.getDestIP(packetData);
+ var sourceIP = IPPacketUtils.getSourceIP(packetData);
+ var virtualNetworkConfig = this.ztService.getVirtualNetworkConfig(this.networkId);
+
+ if (virtualNetworkConfig == null) {
Log.e(TAG, "TunTapAdapter has no network config yet");
return;
+ } else if (destIP == null) {
+ Log.e(TAG, "destAddress is null");
+ return;
+ } else if (sourceIP == null) {
+ Log.e(TAG, "sourceAddress is null");
+ return;
}
if (isIPv4Multicast(destIP)) {
- this.node.multicastSubscribe(this.networkId, multicastAddressToMAC(destIP));
- z = true;
+ var result = this.node.multicastSubscribe(this.networkId, multicastAddressToMAC(destIP));
+ if (result != ResultCode.RESULT_OK) {
+ Log.e(TAG, "Error when calling multicastSubscribe: " + result);
+ }
+ isMulticast = true;
} else {
- z = false;
+ isMulticast = false;
}
- Route routeForDestination = routeForDestination(destIP);
- InetAddress gateway = routeForDestination != null ? routeForDestination.getGateway() : null;
- InetSocketAddress[] assignedAddresses = this.cfg.assignedAddresses();
- int length = assignedAddresses.length;
- int i2 = 0;
- while (true) {
- if (i2 >= length) {
- inetAddress = null;
- i = 0;
+ var route = routeForDestination(destIP);
+ var gateway = route != null ? route.getGateway() : null;
+
+ // 查找当前节点的 v4 地址
+ var ztAddresses = virtualNetworkConfig.getAssignedAddresses();
+ InetAddress localV4Address = null;
+ int cidr = 0;
+
+ for (var address : ztAddresses) {
+ if (address.getAddress() instanceof Inet4Address) {
+ localV4Address = address.getAddress();
+ cidr = address.getPort();
break;
}
- InetSocketAddress inetSocketAddress = assignedAddresses[i2];
- if (inetSocketAddress.getAddress() instanceof Inet4Address) {
- i = inetSocketAddress.getPort();
- inetAddress = inetSocketAddress.getAddress();
- break;
- }
- i2++;
}
- if (gateway != null && !InetAddressUtils.addressToRouteNo0Route(destIP, i).equals(InetAddressUtils.addressToRouteNo0Route(sourceIP, i))) {
+
+ var destRoute = InetAddressUtils.addressToRouteNo0Route(destIP, cidr);
+ var sourceRoute = InetAddressUtils.addressToRouteNo0Route(sourceIP, cidr);
+ if (gateway != null && !Objects.equals(destRoute, sourceRoute)) {
destIP = gateway;
}
- if (inetAddress == null) {
+ if (localV4Address == null) {
Log.e(TAG, "Couldn't determine local address");
return;
}
- long macAddress = this.cfg.macAddress();
- long[] jArr = new long[1];
- if (z || this.arpTable.hasMacForAddress(destIP)) {
+
+ long localMac = virtualNetworkConfig.getMac();
+ long[] nextDeadline = new long[1];
+ if (isMulticast || this.arpTable.hasMacForAddress(destIP)) {
+ // 已确定目标 MAC,直接发送
if (isIPv4Multicast(destIP)) {
- j = multicastAddressToMAC(destIP);
+ destMac = multicastAddressToMAC(destIP);
} else {
- j = this.arpTable.getMacForAddress(destIP);
+ destMac = this.arpTable.getMacForAddress(destIP);
}
- ResultCode processVirtualNetworkFrame = this.node.processVirtualNetworkFrame(System.currentTimeMillis(), this.networkId, macAddress, j, 2048, 0, bArr, jArr);
- if (processVirtualNetworkFrame != ResultCode.RESULT_OK) {
- Log.e(TAG, "Error calling processVirtualNetworkFrame: " + processVirtualNetworkFrame.toString());
+ var result = this.node.processVirtualNetworkFrame(System.currentTimeMillis(), this.networkId, localMac, destMac, IPV4_PACKET, 0, packetData, nextDeadline);
+ if (result != ResultCode.RESULT_OK) {
+ Log.e(TAG, "Error calling processVirtualNetworkFrame: " + result.toString());
return;
}
Log.d(TAG, "Packet sent to ZT");
- this.ztService.setNextBackgroundTaskDeadline(jArr[0]);
- return;
- }
- Log.d(TAG, "Unknown dest MAC address. Need to look it up. " + destIP);
- ResultCode processVirtualNetworkFrame2 = this.node.processVirtualNetworkFrame(System.currentTimeMillis(), this.networkId, macAddress, BROADCAST_MAC, ARP_PACKET, 0, this.arpTable.getRequestPacket(macAddress, inetAddress, destIP), jArr);
- if (processVirtualNetworkFrame2 != ResultCode.RESULT_OK) {
- Log.e(TAG, "Error sending ARP packet: " + processVirtualNetworkFrame2.toString());
- return;
+ this.ztService.setNextBackgroundTaskDeadline(nextDeadline[0]);
+ } else {
+ // 目标 MAC 未知,进行 ARP 查询
+ Log.d(TAG, "Unknown dest MAC address. Need to look it up. " + destIP);
+ destMac = InetAddressUtils.BROADCAST_MAC_ADDRESS;
+ packetData = this.arpTable.getRequestPacket(localMac, localV4Address, destIP);
+ var result = this.node.processVirtualNetworkFrame(System.currentTimeMillis(), this.networkId, localMac, destMac, ARP_PACKET, 0, packetData, nextDeadline);
+ if (result != ResultCode.RESULT_OK) {
+ Log.e(TAG, "Error sending ARP packet: " + result.toString());
+ return;
+ }
+ Log.d(TAG, "ARP Request Sent!");
+ this.ztService.setNextBackgroundTaskDeadline(nextDeadline[0]);
}
- Log.d(TAG, "ARP Request Sent!");
- this.ztService.setNextBackgroundTaskDeadline(jArr[0]);
}
- /* access modifiers changed from: private */
- /* access modifiers changed from: public */
- /* JADX WARNING: Removed duplicated region for block: B:49:0x00d7 */
- /* JADX WARNING: Removed duplicated region for block: B:55:0x011e */
- /* JADX WARNING: Removed duplicated region for block: B:65:? A[RETURN, SYNTHETIC] */
- /* Code decompiled incorrectly, please refer to instructions dump. */
- // Decomp by fernflower
- private void handleIPv6Packet(byte[] var1) {
- InetAddress var2 = IPPacketUtils.getDestIP(var1);
- InetAddress var3 = IPPacketUtils.getSourceIP(var1);
- if (this.cfg == null) {
- Log.e("TunTapAdapter", "TunTapAdapter has no network config yet");
- } else {
- if (this.isIPv6Multicast(var2)) {
- this.node.multicastSubscribe(this.networkId, multicastAddressToMAC(var2));
- }
+ private void handleIPv6Packet(byte[] packetData) {
+ var destIP = IPPacketUtils.getDestIP(packetData);
+ var sourceIP = IPPacketUtils.getSourceIP(packetData);
+ var virtualNetworkConfig = this.ztService.getVirtualNetworkConfig(this.networkId);
- Route var4 = this.routeForDestination(var2);
- InetAddress var15;
- if (var4 != null) {
- var15 = var4.getGateway();
- } else {
- var15 = null;
+ if (virtualNetworkConfig == null) {
+ Log.e(TAG, "TunTapAdapter has no network config yet");
+ return;
+ } else if (destIP == null) {
+ Log.e(TAG, "destAddress is null");
+ return;
+ } else if (sourceIP == null) {
+ Log.e(TAG, "sourceAddress is null");
+ return;
+ }
+ if (this.isIPv6Multicast(destIP)) {
+ var result = this.node.multicastSubscribe(this.networkId, multicastAddressToMAC(destIP));
+ if (result != ResultCode.RESULT_OK) {
+ Log.e(TAG, "Error when calling multicastSubscribe: " + result);
}
+ }
+ var route = routeForDestination(destIP);
+ var gateway = route != null ? route.getGateway() : null;
+
+ // 查找当前节点的 v6 地址
+ var ztAddresses = virtualNetworkConfig.getAssignedAddresses();
+ InetAddress localV4Address = null;
+ int cidr = 0;
+
+ for (var address : ztAddresses) {
+ if (address.getAddress() instanceof Inet6Address) {
+ localV4Address = address.getAddress();
+ cidr = address.getPort();
+ break;
+ }
+ }
- InetSocketAddress[] var5 = this.cfg.assignedAddresses();
- int var6 = var5.length;
- int var7 = 0;
-
- InetAddress var19;
- while (true) {
- if (var7 >= var6) {
- var19 = null;
- var7 = 0;
- break;
- }
+ var destRoute = InetAddressUtils.addressToRouteNo0Route(destIP, cidr);
+ var sourceRoute = InetAddressUtils.addressToRouteNo0Route(sourceIP, cidr);
+ if (gateway != null && !Objects.equals(destRoute, sourceRoute)) {
+ destIP = gateway;
+ }
+ if (localV4Address == null) {
+ Log.e(TAG, "Couldn't determine local address");
+ return;
+ }
- InetSocketAddress var8 = var5[var7];
- if (var8.getAddress() instanceof Inet6Address) {
- var7 = var8.getPort();
- var19 = var8.getAddress();
- break;
- }
+ long localMac = virtualNetworkConfig.getMac();
+ long[] nextDeadline = new long[1];
- ++var7;
+ // 确定目标 MAC 地址
+ long destMac;
+ boolean sendNSPacket = false;
+ if (this.isNeighborSolicitation(packetData)) {
+ // 收到本地 NS 报文,根据 NDP 表记录确定是否广播查询
+ if (this.ndpTable.hasMacForAddress(destIP)) {
+ destMac = this.ndpTable.getMacForAddress(destIP);
+ } else {
+ destMac = InetAddressUtils.ipv6ToMulticastAddress(destIP);
}
-
- InetAddress var16 = var2;
- if (var15 != null) {
- var16 = var2;
- if (!InetAddressUtils.addressToRouteNo0Route(var2, var7).equals(InetAddressUtils.addressToRouteNo0Route(var3, var7))) {
- var16 = var15;
- }
+ } else if (this.isIPv6Multicast(destIP)) {
+ // 多播报文
+ destMac = multicastAddressToMAC(destIP);
+ } else if (this.isNeighborAdvertisement(packetData)) {
+ // 收到本地 NA 报文
+ if (this.ndpTable.hasMacForAddress(destIP)) {
+ destMac = this.ndpTable.getMacForAddress(destIP);
+ } else {
+ // 目标 MAC 未知,不发送数据包
+ destMac = 0L;
}
-
- if (var19 == null) {
- Log.e("TunTapAdapter", "Couldn't determine local address");
+ sendNSPacket = true;
+ } else if (this.ndpTable.hasMacForAddress(destIP)) {
+ // 目标地址 MAC 已知
+ destMac = this.ndpTable.getMacForAddress(destIP);
+ } else {
+ destMac = 0L;
+ }
+ // 发送数据包
+ if (destMac != 0L) {
+ var result = this.node.processVirtualNetworkFrame(System.currentTimeMillis(), this.networkId, localMac, destMac, IPV6_PACKET, 0, packetData, nextDeadline);
+ if (result != ResultCode.RESULT_OK) {
+ Log.e(TAG, "Error calling processVirtualNetworkFrame: " + result.toString());
} else {
- long var9;
- long var11;
- long[] var17;
- boolean var18;
- boolean var20;
- label75:
- {
- var9 = this.cfg.macAddress();
- var18 = true;
- var17 = new long[1];
- if (this.isNeighborSolicitation(var1)) {
- if (this.ndpTable.hasMacForAddress(var16)) {
- var11 = this.ndpTable.getMacForAddress(var16);
- } else {
- var11 = InetAddressUtils.ipv6ToMulticastAddress(var16);
- }
- } else if (this.isIPv6Multicast(var16)) {
- var11 = multicastAddressToMAC(var16);
- } else {
- if (this.isNeighborAdvertisement(var1)) {
- if (this.ndpTable.hasMacForAddress(var16)) {
- var11 = this.ndpTable.getMacForAddress(var16);
- } else {
- var11 = 0L;
- }
-
- var20 = true;
- break label75;
- }
-
- if (this.ndpTable.hasMacForAddress(var16)) {
- var11 = this.ndpTable.getMacForAddress(var16);
- } else {
- var11 = 0L;
- }
- }
-
- var20 = false;
- }
-
- long var21;
- int var13 = (var21 = var11) == 0L ? 0 : (var21 < 0L ? -1 : 1);
- ResultCode var14;
- if (var13 != 0) {
- var14 = this.node.processVirtualNetworkFrame(System.currentTimeMillis(), this.networkId, var9, var11, '\u86dd', 0, var1, var17);
- if (var14 != ResultCode.RESULT_OK) {
- Log.e("TunTapAdapter", "Error calling processVirtualNetworkFrame: " + var14.toString());
- } else {
- Log.d("TunTapAdapter", "Packet sent to ZT");
- this.ztService.setNextBackgroundTaskDeadline(var17[0]);
- }
-
- var18 = var20;
- }
-
- if (var18) {
- if (var13 == 0) {
- var11 = InetAddressUtils.ipv6ToMulticastAddress(var16);
- }
-
- Log.d("TunTapAdapter", "Sending Neighbor Solicitation");
- var1 = this.ndpTable.getNeighborSolicitationPacket(var3, var16, var9);
- var14 = this.node.processVirtualNetworkFrame(System.currentTimeMillis(), this.networkId, var9, var11, '\u86dd', 0, var1, var17);
- if (var14 != ResultCode.RESULT_OK) {
- Log.e("TunTapAdapter", "Error calling processVirtualNetworkFrame: " + var14.toString());
- } else {
- Log.d("TunTapAdapter", "Neighbor Solicitation sent to ZT");
- this.ztService.setNextBackgroundTaskDeadline(var17[0]);
- }
- }
-
+ Log.d(TAG, "Packet sent to ZT");
+ this.ztService.setNextBackgroundTaskDeadline(nextDeadline[0]);
+ }
+ }
+ // 发送 NS 请求
+ if (sendNSPacket) {
+ if (destMac == 0L) {
+ destMac = InetAddressUtils.ipv6ToMulticastAddress(destIP);
+ }
+ Log.d(TAG, "Sending Neighbor Solicitation");
+ packetData = this.ndpTable.getNeighborSolicitationPacket(sourceIP, destIP, localMac);
+ var result = this.node.processVirtualNetworkFrame(System.currentTimeMillis(), this.networkId, localMac, destMac, IPV6_PACKET, 0, packetData, nextDeadline);
+ if (result != ResultCode.RESULT_OK) {
+ Log.e(TAG, "Error calling processVirtualNetworkFrame: " + result.toString());
+ } else {
+ Log.d(TAG, "Neighbor Solicitation sent to ZT");
+ this.ztService.setNextBackgroundTaskDeadline(nextDeadline[0]);
}
}
+
}
public void interrupt() {
@@ -376,111 +358,132 @@ public void interrupt() {
this.in.close();
this.out.close();
} catch (IOException e) {
- Log.e(TAG, "Error stopping in/out", e);
+ Log.e(TAG, "Error stopping in/out: " + e.getMessage(), e);
}
this.receiveThread.interrupt();
try {
this.receiveThread.join();
- } catch (InterruptedException unused) {
+ } catch (InterruptedException ignored) {
}
}
}
- private boolean isNeighborSolicitation(byte[] bArr) {
- return bArr[6] == 58 && bArr[40] == -121;
+ public void join() throws InterruptedException {
+ this.receiveThread.join();
}
- private boolean isNeighborAdvertisement(byte[] bArr) {
- return bArr[6] == 58 && bArr[40] == -120;
+ private boolean isNeighborSolicitation(byte[] packetData) {
+ return packetData[6] == 58 && packetData[40] == -121;
+ }
+
+ private boolean isNeighborAdvertisement(byte[] packetData) {
+ return packetData[6] == 58 && packetData[40] == -120;
}
public boolean isRunning() {
- Thread thread = this.receiveThread;
+ var thread = this.receiveThread;
if (thread == null) {
return false;
}
return thread.isAlive();
}
- @Override // com.zerotier.sdk.VirtualNetworkFrameListener
- public void onVirtualNetworkFrame(long j, long j2, long j3, long j4, long j5, byte[] bArr) {
- Log.d(TAG, "Got Virtual Network Frame. Network ID: " + Long.toHexString(j) + " Source MAC: " + Long.toHexString(j2) + " Dest MAC: " + Long.toHexString(j3) + " Ether type: " + j4 + " VLAN ID: " + j5 + " Frame Length: " + bArr.length);
+ /**
+ * 响应并处理 ZT 网络发送至本节点的以太网帧
+ */
+ @Override
+ public void onVirtualNetworkFrame(long networkId, long srcMac, long destMac, long etherType,
+ long vlanId, byte[] frameData) {
+ Log.d(TAG, "Got Virtual Network Frame. " +
+ " Network ID: " + StringUtils.networkIdToString(networkId) +
+ " Source MAC: " + StringUtils.macAddressToString(srcMac) +
+ " Dest MAC: " + StringUtils.macAddressToString(destMac) +
+ " Ether type: " + StringUtils.etherTypeToString(etherType) +
+ " VLAN ID: " + vlanId + " Frame Length: " + frameData.length);
if (this.vpnSocket == null) {
Log.e(TAG, "vpnSocket is null!");
} else if (this.in == null || this.out == null) {
Log.e(TAG, "no in/out streams");
- } else if (j4 == 2054) {
+ } else if (etherType == ARP_PACKET) {
+ // 收到 ARP 包。更新 ARP 表,若需要则进行应答
Log.d(TAG, "Got ARP Packet");
- ARPTable.ARPReplyData processARPPacket = this.arpTable.processARPPacket(bArr);
- if (processARPPacket != null && processARPPacket.destMac != 0 && processARPPacket.destAddress != null) {
- long[] jArr = new long[1];
- VirtualNetworkConfig networkConfig = this.node.networkConfig(j);
- InetAddress inetAddress = null;
- InetSocketAddress[] assignedAddresses = networkConfig.assignedAddresses();
- int length = assignedAddresses.length;
- int i = 0;
- while (true) {
- if (i >= length) {
- break;
- }
- InetSocketAddress inetSocketAddress = assignedAddresses[i];
- if (inetSocketAddress.getAddress() instanceof Inet4Address) {
- inetAddress = inetSocketAddress.getAddress();
+ var arpReply = this.arpTable.processARPPacket(frameData);
+ if (arpReply != null && arpReply.getDestMac() != 0 && arpReply.getDestAddress() != null) {
+ // 获取本地 V4 地址
+ var networkConfig = this.node.networkConfig(networkId);
+ InetAddress localV4Address = null;
+ for (var address : networkConfig.getAssignedAddresses()) {
+ if (address.getAddress() instanceof Inet4Address) {
+ localV4Address = address.getAddress();
break;
}
- i++;
}
- if (inetAddress != null) {
- ResultCode processVirtualNetworkFrame = this.node.processVirtualNetworkFrame(System.currentTimeMillis(), j, networkConfig.macAddress(), j2, ARP_PACKET, 0, this.arpTable.getReplyPacket(networkConfig.macAddress(), inetAddress, processARPPacket.destMac, processARPPacket.destAddress), jArr);
- if (processVirtualNetworkFrame != ResultCode.RESULT_OK) {
- Log.e(TAG, "Error sending ARP packet: " + processVirtualNetworkFrame.toString());
+ // 构造并返回 ARP 应答
+ if (localV4Address != null) {
+ var nextDeadline = new long[1];
+ var packetData = this.arpTable.getReplyPacket(networkConfig.getMac(),
+ localV4Address, arpReply.getDestMac(), arpReply.getDestAddress());
+ var result = this.node
+ .processVirtualNetworkFrame(System.currentTimeMillis(), networkId,
+ networkConfig.getMac(), srcMac, ARP_PACKET, 0,
+ packetData, nextDeadline);
+ if (result != ResultCode.RESULT_OK) {
+ Log.e(TAG, "Error sending ARP packet: " + result.toString());
return;
}
Log.d(TAG, "ARP Reply Sent!");
- this.ztService.setNextBackgroundTaskDeadline(jArr[0]);
+ this.ztService.setNextBackgroundTaskDeadline(nextDeadline[0]);
}
}
- } else if (j4 == PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH) {
- Log.d(TAG, "Got IPv4 packet. Length: " + bArr.length + " Bytes");
+ } else if (etherType == IPV4_PACKET) {
+ // 收到 IPv4 包。根据需要发送至 TUN
+ Log.d(TAG, "Got IPv4 packet. Length: " + frameData.length + " Bytes");
try {
- InetAddress sourceIP = IPPacketUtils.getSourceIP(bArr);
+ var sourceIP = IPPacketUtils.getSourceIP(frameData);
if (sourceIP != null) {
if (isIPv4Multicast(sourceIP)) {
- this.node.multicastSubscribe(this.networkId, multicastAddressToMAC(sourceIP));
+ var result = this.node.multicastSubscribe(this.networkId, multicastAddressToMAC(sourceIP));
+ if (result != ResultCode.RESULT_OK) {
+ Log.e(TAG, "Error when calling multicastSubscribe: " + result);
+ }
} else {
- this.arpTable.setAddress(sourceIP, j2);
+ this.arpTable.setAddress(sourceIP, srcMac);
}
}
- this.out.write(bArr);
+ this.out.write(frameData);
} catch (Exception e) {
- Log.e(TAG, "Error writing data to vpn socket", e);
+ Log.e(TAG, "Error writing data to vpn socket: " + e.getMessage(), e);
}
- } else if (j4 == 34525) {
- Log.d(TAG, "Got IPv6 packet. Length: " + bArr.length + " Bytes");
+ } else if (etherType == IPV6_PACKET) {
+ // 收到 IPv6 包。根据需要发送至 TUN,并更新 NDP 表
+ Log.d(TAG, "Got IPv6 packet. Length: " + frameData.length + " Bytes");
try {
- InetAddress sourceIP2 = IPPacketUtils.getSourceIP(bArr);
- if (sourceIP2 != null) {
- if (isIPv6Multicast(sourceIP2)) {
- this.node.multicastSubscribe(this.networkId, multicastAddressToMAC(sourceIP2));
+ var sourceIP = IPPacketUtils.getSourceIP(frameData);
+ if (sourceIP != null) {
+ if (isIPv6Multicast(sourceIP)) {
+ var result = this.node.multicastSubscribe(this.networkId, multicastAddressToMAC(sourceIP));
+ if (result != ResultCode.RESULT_OK) {
+ Log.e(TAG, "Error when calling multicastSubscribe: " + result);
+ }
} else {
- this.ndpTable.setAddress(sourceIP2, j2);
+ this.ndpTable.setAddress(sourceIP, srcMac);
}
}
- this.out.write(bArr);
+ this.out.write(frameData);
} catch (Exception e) {
- Log.e(TAG, "Error writing data to vpn socket", e);
+ Log.e(TAG, "Error writing data to vpn socket: " + e.getMessage(), e);
}
- } else if (bArr.length >= 14) {
- Log.d(TAG, "Unknown Packet Type Received: 0x" + String.format("%02X%02X", bArr[12], bArr[13]));
+ } else if (frameData.length >= 14) {
+ Log.d(TAG, "Unknown Packet Type Received: 0x" + String.format("%02X%02X", frameData[12], frameData[13]));
} else {
- Log.d(TAG, "Unknown Packet Received. Packet Length: " + bArr.length);
+ Log.d(TAG, "Unknown Packet Received. Packet Length: " + frameData.length);
}
}
- private Route routeForDestination(InetAddress inetAddress) {
+ private Route routeForDestination(InetAddress destAddress) {
synchronized (this.routeMap) {
- for (Route route : this.routeMap.keySet()) {
- if (route.belongsToRoute(inetAddress)) {
+ for (var route : this.routeMap.keySet()) {
+ if (route.belongsToRoute(destAddress)) {
return route;
}
}
@@ -488,10 +491,10 @@ private Route routeForDestination(InetAddress inetAddress) {
}
}
- private long networkIdForDestination(InetAddress inetAddress) {
+ private long networkIdForDestination(InetAddress destAddress) {
synchronized (this.routeMap) {
for (Route route : this.routeMap.keySet()) {
- if (route.belongsToRoute(inetAddress)) {
+ if (route.belongsToRoute(destAddress)) {
return this.routeMap.get(route);
}
}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/service/UdpCom.java b/app/src/main/java/net/kaaass/zerotierfix/service/UdpCom.java
index 2af486c..2919f1c 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/service/UdpCom.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/service/UdpCom.java
@@ -9,14 +9,15 @@
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
+import java.net.SocketException;
import java.net.SocketTimeoutException;
// TODO: clear up
public class UdpCom implements PacketSender, Runnable {
private static final String TAG = "UdpCom";
- Node node;
- DatagramSocket svrSocket;
- ZeroTierOneService ztService;
+ private Node node;
+ private final DatagramSocket svrSocket;
+ private final ZeroTierOneService ztService;
UdpCom(ZeroTierOneService zeroTierOneService, DatagramSocket datagramSocket) {
this.svrSocket = datagramSocket;
@@ -59,7 +60,7 @@ public void run() {
Log.d(TAG, "Got " + datagramPacket.getLength() + " Bytes From: " + datagramPacket.getAddress().toString() + ":" + datagramPacket.getPort());
ResultCode processWirePacket = this.node.processWirePacket(System.currentTimeMillis(), -1, new InetSocketAddress(datagramPacket.getAddress(), datagramPacket.getPort()), bArr2, jArr);
if (processWirePacket != ResultCode.RESULT_OK) {
- Log.e(TAG, "procesWirePacket returned: " + processWirePacket.toString());
+ Log.e(TAG, "processWirePacket returned: " + processWirePacket.toString());
this.ztService.shutdown();
}
this.ztService.setNextBackgroundTaskDeadline(jArr[0]);
diff --git a/app/src/main/java/net/kaaass/zerotierfix/service/ZeroTierOneService.java b/app/src/main/java/net/kaaass/zerotierfix/service/ZeroTierOneService.java
index 8692251..cf0856b 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/service/ZeroTierOneService.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/service/ZeroTierOneService.java
@@ -1,14 +1,10 @@
package net.kaaass.zerotierfix.service;
-import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
import android.net.VpnService;
import android.os.Binder;
import android.os.Build;
@@ -19,25 +15,26 @@
import android.widget.Toast;
import androidx.core.app.NotificationCompat;
+import androidx.core.content.ContextCompat;
import com.zerotier.sdk.Event;
import com.zerotier.sdk.EventListener;
import com.zerotier.sdk.Node;
import com.zerotier.sdk.NodeException;
-import com.zerotier.sdk.NodeStatus;
import com.zerotier.sdk.ResultCode;
import com.zerotier.sdk.VirtualNetworkConfig;
import com.zerotier.sdk.VirtualNetworkConfigListener;
import com.zerotier.sdk.VirtualNetworkConfigOperation;
-import com.zerotier.sdk.VirtualNetworkRoute;
+import com.zerotier.sdk.VirtualNetworkStatus;
import net.kaaass.zerotierfix.ZerotierFixApplication;
import net.kaaass.zerotierfix.R;
import net.kaaass.zerotierfix.events.AfterJoinNetworkEvent;
-import net.kaaass.zerotierfix.events.DefaultRouteChangedEvent;
import net.kaaass.zerotierfix.events.ErrorEvent;
-import net.kaaass.zerotierfix.events.IsServiceRunningEvent;
+import net.kaaass.zerotierfix.events.IsServiceRunningReplyEvent;
+import net.kaaass.zerotierfix.events.IsServiceRunningRequestEvent;
import net.kaaass.zerotierfix.events.ManualDisconnectEvent;
+import net.kaaass.zerotierfix.events.NetworkConfigChangedByUserEvent;
import net.kaaass.zerotierfix.events.NetworkInfoReplyEvent;
import net.kaaass.zerotierfix.events.NetworkListReplyEvent;
import net.kaaass.zerotierfix.events.NetworkReconfigureEvent;
@@ -46,29 +43,28 @@
import net.kaaass.zerotierfix.events.NodeStatusEvent;
import net.kaaass.zerotierfix.events.OrbitMoonEvent;
import net.kaaass.zerotierfix.events.PeerInfoReplyEvent;
-import net.kaaass.zerotierfix.events.RequestNetworkInfoEvent;
-import net.kaaass.zerotierfix.events.RequestNetworkListEvent;
-import net.kaaass.zerotierfix.events.RequestNodeStatusEvent;
-import net.kaaass.zerotierfix.events.RequestPeerInfoEvent;
+import net.kaaass.zerotierfix.events.NetworkInfoRequestEvent;
+import net.kaaass.zerotierfix.events.NetworkListRequestEvent;
+import net.kaaass.zerotierfix.events.NodeStatusRequestEvent;
+import net.kaaass.zerotierfix.events.PeerInfoRequestEvent;
import net.kaaass.zerotierfix.events.StopEvent;
+import net.kaaass.zerotierfix.events.VPNErrorEvent;
+import net.kaaass.zerotierfix.events.VirtualNetworkConfigChangedEvent;
import net.kaaass.zerotierfix.model.AppNode;
-import net.kaaass.zerotierfix.model.AppNodeDao;
-import net.kaaass.zerotierfix.model.DaoSession;
-import net.kaaass.zerotierfix.model.DnsServer;
-import net.kaaass.zerotierfix.model.DnsServerDao;
import net.kaaass.zerotierfix.model.MoonOrbit;
import net.kaaass.zerotierfix.model.Network;
-import net.kaaass.zerotierfix.model.NetworkConfig;
-import net.kaaass.zerotierfix.model.NetworkConfigDao;
import net.kaaass.zerotierfix.model.NetworkDao;
+import net.kaaass.zerotierfix.model.type.DNSMode;
import net.kaaass.zerotierfix.ui.NetworkListActivity;
import net.kaaass.zerotierfix.util.Constants;
+import net.kaaass.zerotierfix.util.DatabaseUtils;
import net.kaaass.zerotierfix.util.InetAddressUtils;
+import net.kaaass.zerotierfix.util.NetworkInfoUtils;
+import net.kaaass.zerotierfix.util.StringUtils;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
-import org.greenrobot.greendao.query.WhereCondition;
import java.io.BufferedReader;
import java.io.FileInputStream;
@@ -77,11 +73,15 @@
import java.io.FileReader;
import java.io.IOException;
import java.net.DatagramSocket;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.ArrayList;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
// TODO: clear up
public class ZeroTierOneService extends VpnService implements Runnable, EventListener, VirtualNetworkConfigListener {
@@ -92,11 +92,10 @@ public class ZeroTierOneService extends VpnService implements Runnable, EventLis
private static final String[] DISALLOWED_APPS = {"com.android.vending"};
private static final String TAG = "ZT1_Service";
private static final int ZT_NOTIFICATION_TAG = 5919812;
- private final Object configLock = new Object();
private final IBinder mBinder = new ZeroTierBinder();
private final DataStore dataStore = new DataStore(this);
private final EventBus eventBus = EventBus.getDefault();
- private final long lastMulticastGroupCheck = 0;
+ private final Map virtualNetworkConfigMap = new HashMap();
FileInputStream in;
FileOutputStream out;
DatagramSocket svrSocket;
@@ -104,7 +103,6 @@ public class ZeroTierOneService extends VpnService implements Runnable, EventLis
private int bindCount = 0;
private boolean disableIPv6 = false;
private int mStartID = -1;
- private VirtualNetworkConfig networkConfigs;
private long networkId = 0;
private long nextBackgroundTaskDeadline = 0;
private Node node;
@@ -112,12 +110,13 @@ public class ZeroTierOneService extends VpnService implements Runnable, EventLis
private TunTapAdapter tunTapAdapter;
private UdpCom udpCom;
private Thread udpThread;
- private boolean useDefaultRoute = false;
- private Thread v4multicastScanner = new Thread() {
+ private Thread v4MulticastScanner = new Thread() {
/* class com.zerotier.one.service.ZeroTierOneService.AnonymousClass1 */
ArrayList subscriptions = new ArrayList<>();
+ @Override
public void run() {
+ Log.d(ZeroTierOneService.TAG, "IPv4 Multicast Scanner Thread Started.");
while (!isInterrupted()) {
try {
ArrayList arrayList = new ArrayList<>();
@@ -138,53 +137,64 @@ public void run() {
}
}
}
- } catch (FileNotFoundException unused) {
- Log.e(ZeroTierOneService.TAG, "File Not Found: /proc/net/igmp");
- } catch (IOException unused2) {
- Log.e(ZeroTierOneService.TAG, "Error parsing /proc/net/igmp");
+ } catch (FileNotFoundException e) {
+ Log.e(ZeroTierOneService.TAG, "File Not Found: /proc/net/igmp", e);
+ } catch (IOException e) {
+ Log.e(ZeroTierOneService.TAG, "Error parsing /proc/net/igmp", e);
}
+
ArrayList arrayList2 = new ArrayList<>(this.subscriptions);
ArrayList arrayList3 = new ArrayList<>(arrayList);
arrayList3.removeAll(arrayList2);
for (String str : arrayList3) {
try {
- byte[] hexStringToByteArray = ZeroTierOneService.this.hexStringToByteArray(str);
+ byte[] hexStringToByteArray = StringUtils.hexStringToBytes(str);
for (int i = 0; i < hexStringToByteArray.length / 2; i++) {
byte b = hexStringToByteArray[i];
hexStringToByteArray[i] = hexStringToByteArray[(hexStringToByteArray.length - i) - 1];
hexStringToByteArray[(hexStringToByteArray.length - i) - 1] = b;
}
- ZeroTierOneService.this.node.multicastSubscribe(ZeroTierOneService.this.networkId, TunTapAdapter.multicastAddressToMAC(InetAddress.getByAddress(hexStringToByteArray)));
- } catch (Exception ignored) {
+ ResultCode multicastSubscribe = ZeroTierOneService.this.node.multicastSubscribe(ZeroTierOneService.this.networkId, TunTapAdapter.multicastAddressToMAC(InetAddress.getByAddress(hexStringToByteArray)));
+ if (multicastSubscribe != ResultCode.RESULT_OK) {
+ Log.e(ZeroTierOneService.TAG, "Error when calling multicastSubscribe: " + multicastSubscribe);
+ }
+ } catch (Exception e) {
+ Log.e(ZeroTierOneService.TAG, e.toString(), e);
}
}
arrayList2.removeAll(new ArrayList<>(arrayList));
for (String str2 : arrayList2) {
try {
- byte[] hexStringToByteArray2 = ZeroTierOneService.this.hexStringToByteArray(str2);
+ byte[] hexStringToByteArray2 = StringUtils.hexStringToBytes(str2);
for (int i2 = 0; i2 < hexStringToByteArray2.length / 2; i2++) {
byte b2 = hexStringToByteArray2[i2];
hexStringToByteArray2[i2] = hexStringToByteArray2[(hexStringToByteArray2.length - i2) - 1];
hexStringToByteArray2[(hexStringToByteArray2.length - i2) - 1] = b2;
}
- ZeroTierOneService.this.node.multicastUnsubscribe(ZeroTierOneService.this.networkId, TunTapAdapter.multicastAddressToMAC(InetAddress.getByAddress(hexStringToByteArray2)));
- } catch (Exception ignored) {
+ ResultCode multicastUnsubscribe = ZeroTierOneService.this.node.multicastUnsubscribe(ZeroTierOneService.this.networkId, TunTapAdapter.multicastAddressToMAC(InetAddress.getByAddress(hexStringToByteArray2)));
+ if (multicastUnsubscribe != ResultCode.RESULT_OK) {
+ Log.e(ZeroTierOneService.TAG, "Error when calling multicastUnsubscribe: " + multicastUnsubscribe);
+ }
+ } catch (Exception e) {
+ Log.e(ZeroTierOneService.TAG, e.toString(), e);
}
}
this.subscriptions = arrayList;
Thread.sleep(1000);
- } catch (InterruptedException unused5) {
- Log.d(ZeroTierOneService.TAG, "V4 Multicast Scanner Thread Interrupted");
- return;
+ } catch (InterruptedException e) {
+ Log.d(ZeroTierOneService.TAG, "V4 Multicast Scanner Thread Interrupted", e);
}
}
+ Log.d(ZeroTierOneService.TAG, "IPv4 Multicast Scanner Thread Ended.");
}
};
private Thread v6MulticastScanner = new Thread() {
/* class com.zerotier.one.service.ZeroTierOneService.AnonymousClass2 */
ArrayList subscriptions = new ArrayList<>();
+ @Override
public void run() {
+ Log.d(ZeroTierOneService.TAG, "IPv6 Multicast Scanner Thread Started.");
while (!isInterrupted()) {
try {
ArrayList arrayList = new ArrayList<>();
@@ -200,38 +210,70 @@ public void run() {
arrayList.add(split[2]);
}
}
- } catch (FileNotFoundException unused) {
- Log.e(ZeroTierOneService.TAG, "File not found: /proc/net/igmp6");
- } catch (IOException unused2) {
- Log.e(ZeroTierOneService.TAG, "Error parsing /proc/net/igmp6");
+ } catch (FileNotFoundException e) {
+ Log.e(ZeroTierOneService.TAG, "File not found: /proc/net/igmp6", e);
+ } catch (IOException e) {
+ Log.e(ZeroTierOneService.TAG, "Error parsing /proc/net/igmp6", e);
}
- ArrayList arrayList2 = new ArrayList(this.subscriptions);
- ArrayList arrayList3 = new ArrayList(arrayList);
+ ArrayList arrayList2 = new ArrayList<>(this.subscriptions);
+ ArrayList arrayList3 = new ArrayList<>(arrayList);
arrayList3.removeAll(arrayList2);
for (String str : arrayList3) {
try {
- ZeroTierOneService.this.node.multicastSubscribe(ZeroTierOneService.this.networkId, TunTapAdapter.multicastAddressToMAC(InetAddress.getByAddress(ZeroTierOneService.this.hexStringToByteArray(str))));
- } catch (Exception unused3) {
+ ResultCode multicastSubscribe = ZeroTierOneService.this.node.multicastSubscribe(ZeroTierOneService.this.networkId, TunTapAdapter.multicastAddressToMAC(InetAddress.getByAddress(StringUtils.hexStringToBytes(str))));
+ if (multicastSubscribe != ResultCode.RESULT_OK) {
+ Log.e(ZeroTierOneService.TAG, "Error when calling multicastSubscribe: " + multicastSubscribe);
+ }
+ } catch (Exception e) {
+ Log.e(ZeroTierOneService.TAG, e.toString(), e);
}
}
- arrayList2.removeAll(new ArrayList(arrayList));
+ arrayList2.removeAll(new ArrayList<>(arrayList));
for (String str2 : arrayList2) {
try {
- ZeroTierOneService.this.node.multicastUnsubscribe(ZeroTierOneService.this.networkId, TunTapAdapter.multicastAddressToMAC(InetAddress.getByAddress(ZeroTierOneService.this.hexStringToByteArray(str2))));
- } catch (Exception unused4) {
+ ResultCode multicastUnsubscribe = ZeroTierOneService.this.node.multicastUnsubscribe(ZeroTierOneService.this.networkId, TunTapAdapter.multicastAddressToMAC(InetAddress.getByAddress(StringUtils.hexStringToBytes(str2))));
+ if (multicastUnsubscribe != ResultCode.RESULT_OK) {
+ Log.e(ZeroTierOneService.TAG, "Error when calling multicastUnsubscribe: " + multicastUnsubscribe);
+ }
+ } catch (Exception e) {
+ Log.e(ZeroTierOneService.TAG, e.toString(), e);
}
}
this.subscriptions = arrayList;
Thread.sleep(1000);
- } catch (InterruptedException unused5) {
- Log.d(ZeroTierOneService.TAG, "V6 Multicast Scanner Thread Interrupted");
- return;
+ } catch (InterruptedException e) {
+ Log.d(ZeroTierOneService.TAG, "V6 Multicast Scanner Thread Interrupted", e);
}
}
+ Log.d(ZeroTierOneService.TAG, "IPv6 Multicast Scanner Thread Ended.");
}
};
private Thread vpnThread;
+ public VirtualNetworkConfig getVirtualNetworkConfig(long j) {
+ VirtualNetworkConfig virtualNetworkConfig;
+ synchronized (this.virtualNetworkConfigMap) {
+ virtualNetworkConfig = this.virtualNetworkConfigMap.get(Long.valueOf(j));
+ }
+ return virtualNetworkConfig;
+ }
+
+ public VirtualNetworkConfig setVirtualNetworkConfig(long j, VirtualNetworkConfig virtualNetworkConfig) {
+ VirtualNetworkConfig put;
+ synchronized (this.virtualNetworkConfigMap) {
+ put = this.virtualNetworkConfigMap.put(Long.valueOf(j), virtualNetworkConfig);
+ }
+ return put;
+ }
+
+ public VirtualNetworkConfig clearVirtualNetworkConfig(long j) {
+ VirtualNetworkConfig remove;
+ synchronized (this.virtualNetworkConfigMap) {
+ remove = this.virtualNetworkConfigMap.remove(Long.valueOf(j));
+ }
+ return remove;
+ }
+
private void logBindCount() {
Log.i(TAG, "Bind Count: " + this.bindCount);
}
@@ -257,14 +299,12 @@ public void setNextBackgroundTaskDeadline(long j) {
}
}
- public void onCreate() {
- super.onCreate();
- }
-
+ /**
+ * 启动 ZT 服务,连接至给定网络或最近连接的网络
+ */
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
long networkId;
- long j;
Log.d(TAG, "onStartCommand");
if (startId == 3) {
Log.i(TAG, "Authorizing VPN");
@@ -272,170 +312,203 @@ public int onStartCommand(Intent intent, int flags, int startId) {
} else if (intent == null) {
Log.e(TAG, "NULL intent. Cannot start");
return START_NOT_STICKY;
+ }
+ this.mStartID = startId;
+
+ // 注册事件总线监听器
+ if (!this.eventBus.isRegistered(this)) {
+ this.eventBus.register(this);
+ }
+
+ // 确定待启动的网络 ID
+ if (intent.hasExtra(ZT1_NETWORK_ID)) {
+ // Intent 中指定了目标网络,直接使用此 ID
+ networkId = intent.getLongExtra(ZT1_NETWORK_ID, 0);
} else {
- this.mStartID = startId;
- if (!this.eventBus.isRegistered(this)) {
- this.eventBus.register(this);
- }
- if (intent.hasExtra(ZT1_NETWORK_ID)) {
- networkId = intent.getLongExtra(ZT1_NETWORK_ID, 0);
- this.useDefaultRoute = intent.getBooleanExtra(ZT1_USE_DEFAULT_ROUTE, false);
- } else {
- DaoSession daoSession = ((ZerotierFixApplication) getApplication()).getDaoSession();
+ // 默认启用最近一次启动的网络
+ DatabaseUtils.readLock.lock();
+ try {
+ var daoSession = ((ZerotierFixApplication) getApplication()).getDaoSession();
daoSession.clear();
- List list = daoSession.getNetworkDao().queryBuilder().where(NetworkDao.Properties.LastActivated.eq(true), new WhereCondition[0]).list();
- if (list == null || list.isEmpty()) {
+ var lastActivatedNetworks = daoSession.getNetworkDao().queryBuilder()
+ .where(NetworkDao.Properties.LastActivated.eq(true))
+ .list();
+ if (lastActivatedNetworks == null || lastActivatedNetworks.isEmpty()) {
Log.e(TAG, "Couldn't find last activated connection");
return START_NOT_STICKY;
- } else if (list.size() > 1) {
- Log.e(TAG, "Multiple networks marked as last connected: " + list.size());
- for (Network network : list) {
+ } else if (lastActivatedNetworks.size() > 1) {
+ Log.e(TAG, "Multiple networks marked as last connected: " + lastActivatedNetworks.size());
+ for (Network network : lastActivatedNetworks) {
Log.e(TAG, "ID: " + Long.toHexString(network.getNetworkId()));
}
- return START_NOT_STICKY;
+ throw new IllegalStateException("Database is inconsistent");
} else {
- networkId = list.get(0).getNetworkId();
- this.useDefaultRoute = list.get(0).getUseDefaultRoute();
+ networkId = lastActivatedNetworks.get(0).getNetworkId();
Log.i(TAG, "Got Always On request for ZeroTier");
}
+ } finally {
+ DatabaseUtils.readLock.unlock();
}
- if (networkId == 0) {
- Log.e(TAG, "Network ID not provided to service");
- stopSelf(startId);
- return START_NOT_STICKY;
- }
- this.networkId = networkId;
- SharedPreferences defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
- boolean useCellularData = defaultSharedPreferences.getBoolean(Constants.PREF_NETWORK_USE_CELLULAR_DATA, false);
- this.disableIPv6 = defaultSharedPreferences.getBoolean("network_disable_ipv6", false);
- ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
- int i3 = 0;
- while (activeNetworkInfo == null && i3 < 30) {
- try {
- Log.i(TAG, "Waiting for network connectivity");
- Thread.sleep(1000);
- } catch (InterruptedException ignored) {
+ }
+ if (networkId == 0) {
+ Log.e(TAG, "Network ID not provided to service");
+ stopSelf(startId);
+ return START_NOT_STICKY;
+ }
+ this.networkId = networkId;
+
+ // 检查当前的网络环境
+ var preferences = PreferenceManager.getDefaultSharedPreferences(this);
+ boolean useCellularData = preferences.getBoolean(Constants.PREF_NETWORK_USE_CELLULAR_DATA, false);
+ this.disableIPv6 = preferences.getBoolean(Constants.PREF_NETWORK_DISABLE_IPV6, false);
+ var currentNetworkInfo = NetworkInfoUtils.getNetworkInfoCurrentConnection(this);
+
+ if (currentNetworkInfo == NetworkInfoUtils.CurrentConnection.CONNECTION_NONE) {
+ // 未连接网络
+ Toast.makeText(this, R.string.toast_no_network, Toast.LENGTH_SHORT).show();
+ stopSelf(this.mStartID);
+ return START_NOT_STICKY;
+ } else if (currentNetworkInfo == NetworkInfoUtils.CurrentConnection.CONNECTION_MOBILE &&
+ !useCellularData) {
+ // 使用移动网络,但未在设置中允许移动网络访问
+ Toast.makeText(this, R.string.toast_mobile_data, Toast.LENGTH_LONG).show();
+ stopSelf(this.mStartID);
+ return START_NOT_STICKY;
+ }
+
+ // 启动 ZT 服务
+ synchronized (this) {
+ try {
+ // 创建本地 ZT 服务 Socket,监听本地端口
+ if (this.svrSocket == null) {
+ this.svrSocket = new DatagramSocket(null);
+ this.svrSocket.setReuseAddress(true);
+ this.svrSocket.setSoTimeout(1000);
+ this.svrSocket.bind(new InetSocketAddress(9994));
}
- activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
- i3++;
- }
- if (activeNetworkInfo == null || !activeNetworkInfo.isConnectedOrConnecting()) {
- Toast.makeText(this, R.string.toast_no_network, Toast.LENGTH_SHORT).show();
- return START_NOT_STICKY;
- } else if (useCellularData || !(activeNetworkInfo == null || activeNetworkInfo.getType() == 0)) {
- synchronized (this) {
+ if (!protect(this.svrSocket)) {
+ Log.e(TAG, "Error protecting UDP socket from feedback loop.");
+ }
+
+ // 创建本地节点
+ if (this.node == null) {
try {
- if (this.svrSocket == null) {
- DatagramSocket datagramSocket = new DatagramSocket(null);
- this.svrSocket = datagramSocket;
- datagramSocket.setReuseAddress(true);
- this.svrSocket.setSoTimeout(1000);
- this.svrSocket.bind(new InetSocketAddress(9994));
- }
- if (!protect(this.svrSocket)) {
- Log.e(TAG, "Error protecting UDP socket from feedback loop.");
- }
- if (this.node == null) {
- try {
- this.udpCom = new UdpCom(this, this.svrSocket);
- this.tunTapAdapter = new TunTapAdapter(this, networkId);
- long currentTimeMillis = System.currentTimeMillis();
- DataStore dataStore2 = this.dataStore;
- // 创建 ZT 节点
- this.node = new Node(currentTimeMillis, dataStore2, dataStore2, this.udpCom, this, this.tunTapAdapter, this, null);
- this.onNodeStatusRequest(null);
- // 持久化节点信息
- NodeStatus status = this.node.status();
- long address = status.getAddres();
- AppNodeDao appNodeDao = ((ZerotierFixApplication) getApplication()).getDaoSession().getAppNodeDao();
- List list2 = appNodeDao.queryBuilder().build().forCurrentThread().list();
- if (list2.isEmpty()) {
- AppNode appNode = new AppNode();
- appNode.setNodeId(address);
- appNode.setNodeIdStr(String.format("%10x", address));
- appNodeDao.insert(appNode);
- } else {
- AppNode appNode2 = list2.get(0);
- appNode2.setNodeId(address);
- appNode2.setNodeIdStr(String.format("%10x", address));
- appNodeDao.save(appNode2);
- }
- this.eventBus.post(new NodeIDEvent(status.getAddres()));
- this.udpCom.setNode(this.node);
- this.tunTapAdapter.setNode(this.node);
- Thread thread = new Thread(this.udpCom, "UDP Communication Thread");
- this.udpThread = thread;
- thread.start();
- } catch (NodeException e) {
- Log.e(TAG, "Error starting ZT1 Node", e);
- return START_NOT_STICKY;
+ this.udpCom = new UdpCom(this, this.svrSocket);
+ this.tunTapAdapter = new TunTapAdapter(this, networkId);
+
+ // 创建节点对象并初始化
+ var dataStore = this.dataStore;
+ this.node = new Node(System.currentTimeMillis());
+ this.node.init(dataStore, dataStore, this.udpCom, this, this.tunTapAdapter, this, null);
+ this.onNodeStatusRequest(null);
+
+ // 持久化当前节点信息
+ long address = this.node.address();
+ DatabaseUtils.writeLock.lock();
+ try {
+ var appNodeDao = ((ZerotierFixApplication) getApplication())
+ .getDaoSession().getAppNodeDao();
+ var nodesList = appNodeDao.queryBuilder().build()
+ .forCurrentThread().list();
+ if (nodesList.isEmpty()) {
+ var appNode = new AppNode();
+ appNode.setNodeId(address);
+ appNode.setNodeIdStr(String.format("%10x", address));
+ appNodeDao.insert(appNode);
+ } else {
+ var appNode = nodesList.get(0);
+ appNode.setNodeId(address);
+ appNode.setNodeIdStr(String.format("%10x", address));
+ appNodeDao.save(appNode);
}
+ } finally {
+ DatabaseUtils.writeLock.unlock();
}
- if (this.vpnThread == null) {
- Thread thread2 = new Thread(this, "ZeroTier Service Thread");
- this.vpnThread = thread2;
- thread2.start();
- }
- if (!this.udpThread.isAlive()) {
- this.udpThread.start();
- }
- } catch (Exception e2) {
- Log.e(TAG, e2.toString());
+
+ this.eventBus.post(new NodeIDEvent(address));
+ this.udpCom.setNode(this.node);
+ this.tunTapAdapter.setNode(this.node);
+
+ // 启动 UDP 消息处理线程
+ var thread = new Thread(this.udpCom, "UDP Communication Thread");
+ this.udpThread = thread;
+ thread.start();
+ } catch (NodeException e) {
+ Log.e(TAG, "Error starting ZT1 Node: " + e.getMessage(), e);
return START_NOT_STICKY;
}
}
- joinNetwork(networkId, this.useDefaultRoute);
- return START_STICKY;
- } else {
- Toast.makeText(this, R.string.toast_mobile_data, Toast.LENGTH_SHORT).show();
- stopSelf(this.mStartID);
- Node node3 = this.node;
- if (node3 != null) {
- node3.close();
+
+ // 创建并启动 VPN 服务线程
+ if (this.vpnThread == null) {
+ var thread = new Thread(this, "ZeroTier Service Thread");
+ this.vpnThread = thread;
+ thread.start();
+ }
+
+ // 启动 UDP 消息处理线程
+ if (!this.udpThread.isAlive()) {
+ this.udpThread.start();
}
+ } catch (Exception e) {
+ Log.e(TAG, e.toString(), e);
return START_NOT_STICKY;
}
}
+ joinNetwork(networkId);
+ return START_STICKY;
}
public void stopZeroTier() {
- Thread udpThread = this.udpThread;
- if (udpThread != null && udpThread.isAlive()) {
+ if (this.svrSocket != null) {
+ this.svrSocket.close();
+ this.svrSocket = null;
+ }
+ if (this.udpThread != null && this.udpThread.isAlive()) {
this.udpThread.interrupt();
+ try {
+ this.udpThread.join();
+ } catch (InterruptedException ignored) {
+ }
this.udpThread = null;
}
- TunTapAdapter tunTapAdapter = this.tunTapAdapter;
- if (tunTapAdapter != null && tunTapAdapter.isRunning()) {
+ if (this.tunTapAdapter != null && this.tunTapAdapter.isRunning()) {
this.tunTapAdapter.interrupt();
+ try {
+ this.tunTapAdapter.join();
+ } catch (InterruptedException ignored) {
+ }
this.tunTapAdapter = null;
}
- Thread vpnThread = this.vpnThread;
- if (vpnThread != null && vpnThread.isAlive()) {
+ if (this.vpnThread != null && this.vpnThread.isAlive()) {
this.vpnThread.interrupt();
+ try {
+ this.vpnThread.join();
+ } catch (InterruptedException ignored) {
+ }
this.vpnThread = null;
}
- DatagramSocket svrSocket = this.svrSocket;
- if (svrSocket != null) {
- svrSocket.close();
- this.svrSocket = null;
- }
- Thread v4multicastScanner = this.v4multicastScanner;
- if (v4multicastScanner != null) {
- v4multicastScanner.interrupt();
- this.v4multicastScanner = null;
+ if (this.v4MulticastScanner != null) {
+ this.v4MulticastScanner.interrupt();
+ try {
+ this.v4MulticastScanner.join();
+ } catch (InterruptedException ignored) {
+ }
+ this.v4MulticastScanner = null;
}
- Thread v6MulticastScanner = this.v6MulticastScanner;
- if (v6MulticastScanner != null) {
- v6MulticastScanner.interrupt();
+ if (this.v6MulticastScanner != null) {
+ this.v6MulticastScanner.interrupt();
+ try {
+ this.v6MulticastScanner.join();
+ } catch (InterruptedException ignored) {
+ }
this.v6MulticastScanner = null;
}
- ParcelFileDescriptor vpnSocket = this.vpnSocket;
- if (vpnSocket != null) {
+ if (this.vpnSocket != null) {
try {
- vpnSocket.close();
+ this.vpnSocket.close();
} catch (Exception e) {
- Log.e(TAG, "Error closing VPN socket", e);
+ Log.e(TAG, "Error closing VPN socket: " + e, e);
}
this.vpnSocket = null;
}
@@ -447,9 +520,8 @@ public void stopZeroTier() {
if (this.eventBus.isRegistered(this)) {
this.eventBus.unregister(this);
}
- NotificationManager notificationManager = this.notificationManager;
- if (notificationManager != null) {
- notificationManager.cancel(ZT_NOTIFICATION_TAG);
+ if (this.notificationManager != null) {
+ this.notificationManager.cancel(ZT_NOTIFICATION_TAG);
}
if (!stopSelfResult(this.mStartID)) {
Log.e(TAG, "stopSelfResult() failed!");
@@ -459,12 +531,11 @@ public void stopZeroTier() {
public void onDestroy() {
try {
stopZeroTier();
- ParcelFileDescriptor parcelFileDescriptor = this.vpnSocket;
- if (parcelFileDescriptor != null) {
+ if (this.vpnSocket != null) {
try {
- parcelFileDescriptor.close();
+ this.vpnSocket.close();
} catch (Exception e) {
- Log.e(TAG, "Error closing VPN socket", e);
+ Log.e(TAG, "Error closing VPN socket: " + e, e);
}
this.vpnSocket = null;
}
@@ -473,22 +544,19 @@ public void onDestroy() {
this.eventBus.unregister(this);
}
} catch (Exception e) {
- Log.e(TAG, "", e);
- } catch (Throwable th) {
+ Log.e(TAG, e.toString(), e);
+ } finally {
super.onDestroy();
- throw th;
}
- super.onDestroy();
}
public void onRevoke() {
stopZeroTier();
- ParcelFileDescriptor parcelFileDescriptor = this.vpnSocket;
- if (parcelFileDescriptor != null) {
+ if (this.vpnSocket != null) {
try {
- parcelFileDescriptor.close();
+ this.vpnSocket.close();
} catch (Exception e) {
- Log.e(TAG, "Error closing VPN socket", e);
+ Log.e(TAG, "Error closing VPN socket: " + e, e);
}
this.vpnSocket = null;
}
@@ -501,29 +569,29 @@ public void onRevoke() {
public void run() {
Log.d(TAG, "ZeroTierOne Service Started");
- Log.d(TAG, "This Node Address: " + Long.toHexString(this.node.address()));
+ Log.d(TAG, "This Node Address: " + com.zerotier.sdk.util.StringUtils.addressToString(this.node.address()));
while (!Thread.interrupted()) {
try {
- long j = this.nextBackgroundTaskDeadline;
- long currentTimeMillis = System.currentTimeMillis();
- int i = (Long.compare(j, currentTimeMillis));
- if (i <= 0) {
- long[] jArr = {0};
- ResultCode processBackgroundTasks = this.node.processBackgroundTasks(currentTimeMillis, jArr);
+ // 在后台任务截止期前循环进行后台任务
+ var taskDeadline = this.nextBackgroundTaskDeadline;
+ long currentTime = System.currentTimeMillis();
+ int cmp = Long.compare(taskDeadline, currentTime);
+ if (cmp <= 0) {
+ long[] newDeadline = {0};
+ var taskResult = this.node.processBackgroundTasks(currentTime, newDeadline);
synchronized (this) {
- this.nextBackgroundTaskDeadline = jArr[0];
+ this.nextBackgroundTaskDeadline = newDeadline[0];
}
- if (processBackgroundTasks != ResultCode.RESULT_OK) {
- Log.e(TAG, "Error on processBackgroundTasks: " + processBackgroundTasks.toString());
+ if (taskResult != ResultCode.RESULT_OK) {
+ Log.e(TAG, "Error on processBackgroundTasks: " + taskResult.toString());
shutdown();
}
}
- Thread.sleep(i > 0 ? j - currentTimeMillis : 100);
- } catch (InterruptedException e) {
- Log.e(TAG, "ZeroTierOne Thread Interrupted", e);
+ Thread.sleep(cmp > 0 ? taskDeadline - currentTime : 100);
+ } catch (InterruptedException ignored) {
break;
} catch (Exception e) {
- Log.e(TAG, "", e);
+ Log.e(TAG, e.toString(), e);
}
}
Log.d(TAG, "ZeroTierOne Service Ended");
@@ -540,31 +608,20 @@ public void onManualDisconnect(ManualDisconnectEvent manualDisconnectEvent) {
}
@Subscribe(threadMode = ThreadMode.POSTING)
- public void onIsServiceRunning(IsServiceRunningEvent isServiceRunningEvent) {
- if (isServiceRunningEvent.type == IsServiceRunningEvent.Type.REQUEST) {
- this.eventBus.post(IsServiceRunningEvent.NewReply(true));
- }
+ public void onIsServiceRunningRequest(IsServiceRunningRequestEvent event) {
+ this.eventBus.post(new IsServiceRunningReplyEvent(true));
}
/**
- * 加入网络
- * @param networkId
- * @param useDefaultRoute
+ * 加入 ZT 网络
*/
- public void joinNetwork(long networkId, boolean useDefaultRoute) {
+ public void joinNetwork(long networkId) {
if (this.node == null) {
Log.e(TAG, "Can't join network if ZeroTier isn't running");
return;
}
- // 如果已经加入网络,则退出
- VirtualNetworkConfig virtualNetworkConfig = this.networkConfigs;
- if (virtualNetworkConfig != null) {
- leaveNetwork(virtualNetworkConfig.networkId());
- }
// 连接到新网络
- this.networkConfigs = null;
- this.useDefaultRoute = useDefaultRoute;
- ResultCode result = this.node.join(networkId);
+ var result = this.node.join(networkId);
if (result != ResultCode.RESULT_OK) {
this.eventBus.post(new ErrorEvent(result));
return;
@@ -573,57 +630,60 @@ public void joinNetwork(long networkId, boolean useDefaultRoute) {
this.eventBus.post(new AfterJoinNetworkEvent());
}
- public void leaveNetwork(long j) {
- Node node2 = this.node;
- if (node2 == null) {
+ /**
+ * 离开 ZT 网络
+ */
+ public void leaveNetwork(long networkId) {
+ if (this.node == null) {
Log.e(TAG, "Can't leave network if ZeroTier isn't running");
return;
}
- ResultCode leave = node2.leave(j);
- if (leave != ResultCode.RESULT_OK) {
- this.eventBus.post(new ErrorEvent(leave));
+ var result = this.node.leave(networkId);
+ if (result != ResultCode.RESULT_OK) {
+ this.eventBus.post(new ErrorEvent(result));
return;
}
- VirtualNetworkConfig[] networks = this.node.networks();
- if (networks == null || (networks != null && networks.length == 0)) {
- stopZeroTier();
- ParcelFileDescriptor parcelFileDescriptor = this.vpnSocket;
- if (parcelFileDescriptor != null) {
- try {
- parcelFileDescriptor.close();
- } catch (Exception e) {
- Log.e(TAG, "Error closing VPN socket", e);
- }
- this.vpnSocket = null;
+ var networkConfigs = this.node.networkConfigs();
+ if (networkConfigs != null && networkConfigs.length != 0) {
+ return;
+ }
+ stopZeroTier();
+ if (this.vpnSocket != null) {
+ try {
+ this.vpnSocket.close();
+ } catch (Exception e) {
+ Log.e(TAG, "Error closing VPN socket", e);
}
- stopSelf(this.mStartID);
+ this.vpnSocket = null;
}
+ stopSelf(this.mStartID);
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
- public void onNetworkInfoRequest(RequestNetworkInfoEvent requestNetworkInfoEvent) {
+ public void onNetworkInfoRequest(NetworkInfoRequestEvent networkInfoRequestEvent) {
VirtualNetworkConfig networkConfig;
Node node2 = this.node;
- if (node2 != null && (networkConfig = node2.networkConfig(requestNetworkInfoEvent.getNetworkId())) != null) {
+ if (node2 != null && (networkConfig = node2.networkConfig(networkInfoRequestEvent.getNetworkId())) != null) {
this.eventBus.post(new NetworkInfoReplyEvent(networkConfig));
}
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
- public void onNetworkListRequest(RequestNetworkListEvent requestNetworkListEvent) {
+ public void onNetworkListRequest(NetworkListRequestEvent requestNetworkListEvent) {
VirtualNetworkConfig[] networks;
Node node2 = this.node;
- if (node2 != null && (networks = node2.networks()) != null && networks.length > 0) {
+ if (node2 != null && (networks = node2.networkConfigs()) != null && networks.length > 0) {
this.eventBus.post(new NetworkListReplyEvent(networks));
}
}
/**
* 请求节点状态事件回调
+ *
* @param event 事件
*/
@Subscribe(threadMode = ThreadMode.BACKGROUND)
- public void onNodeStatusRequest(RequestNodeStatusEvent event) {
+ public void onNodeStatusRequest(NodeStatusRequestEvent event) {
// 返回节点状态
if (this.node != null) {
this.eventBus.post(new NodeStatusEvent(this.node.status(), this.node.getVersion()));
@@ -631,7 +691,7 @@ public void onNodeStatusRequest(RequestNodeStatusEvent event) {
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
- public void onRequestPeerInfo(RequestPeerInfoEvent event) {
+ public void onRequestPeerInfo(PeerInfoRequestEvent event) {
if (this.node == null) {
this.eventBus.post(new PeerInfoReplyEvent(null));
return;
@@ -640,25 +700,37 @@ public void onRequestPeerInfo(RequestPeerInfoEvent event) {
}
@Subscribe(threadMode = ThreadMode.ASYNC)
- public void onNetworkReconfigure(NetworkReconfigureEvent networkReconfigureEvent) {
- updateTunnelConfig();
+ public void onNetworkReconfigure(NetworkReconfigureEvent event) {
+ boolean isChanged = event.isChanged();
+ var network = event.getNetwork();
+ var networkConfig = event.getVirtualNetworkConfig();
+ boolean configUpdated = isChanged && updateTunnelConfig(network);
+ boolean networkIsOk = networkConfig.getStatus() == VirtualNetworkStatus.NETWORK_STATUS_OK;
+
+ if (configUpdated || !networkIsOk) {
+ this.eventBus.post(new VirtualNetworkConfigChangedEvent(networkConfig));
+ }
}
@Subscribe(threadMode = ThreadMode.ASYNC)
- public void onDefaultrouteChanged(DefaultRouteChangedEvent defaultRouteChangedEvent) {
- this.useDefaultRoute = defaultRouteChangedEvent.isDefaultRoute();
- updateTunnelConfig();
+ public void onNetworkConfigChangedByUser(NetworkConfigChangedByUserEvent event) {
+ Network network = event.getNetwork();
+ if (network.getNetworkId() != this.networkId) {
+ return;
+ }
+ updateTunnelConfig(network);
}
/**
* Zerotier 事件回调
+ *
* @param event {@link Event} enum
*/
@Override
public void onEvent(Event event) {
Log.d(TAG, "Event: " + event.toString());
// 更新节点状态
- if (this.node != null) {
+ if (this.node.isInited()) {
this.eventBus.post(new NodeStatusEvent(this.node.status(), this.node.getVersion()));
}
}
@@ -668,75 +740,68 @@ public void onTrace(String str) {
Log.d(TAG, "Trace: " + str);
}
- @Override // com.zerotier.sdk.VirtualNetworkConfigListener
- public int onNetworkConfigurationUpdated(long j, VirtualNetworkConfigOperation virtualNetworkConfigOperation, VirtualNetworkConfig virtualNetworkConfig) {
- Log.i(TAG, "Virtual Network Config Operation: " + virtualNetworkConfigOperation.toString());
- int i = AnonymousClass3.$SwitchMap$com$zerotier$sdk$VirtualNetworkConfigOperation[virtualNetworkConfigOperation.ordinal()];
- if (i == 1) {
- Log.d(TAG, "Network Type:" + virtualNetworkConfig.networkType().toString() + " Network Status: " + virtualNetworkConfig.networkStatus().toString() + " Network Name: " + virtualNetworkConfig.name() + " ");
- this.eventBus.post(new NetworkInfoReplyEvent(virtualNetworkConfig));
- TunTapAdapter tunTapAdapter2 = this.tunTapAdapter;
- if (tunTapAdapter2 == null) {
- return 0;
- }
- tunTapAdapter2.setNetworkConfig(virtualNetworkConfig);
- return 0;
- } else if (i == 2) {
- Log.i(TAG, "Network Config Update!");
- VirtualNetworkConfig virtualNetworkConfig2 = this.networkConfigs;
- if (virtualNetworkConfig2 == null) {
- Log.d(TAG, "Adding new network.");
- synchronized (this.configLock) {
- this.networkConfigs = virtualNetworkConfig;
- }
- this.eventBus.post(new NetworkReconfigureEvent());
- this.eventBus.post(new NetworkInfoReplyEvent(virtualNetworkConfig));
- TunTapAdapter tunTapAdapter3 = this.tunTapAdapter;
- if (tunTapAdapter3 == null) {
- return 0;
- }
- tunTapAdapter3.setNetworkConfig(virtualNetworkConfig);
- return 0;
- }
- if (!virtualNetworkConfig2.equals(virtualNetworkConfig)) {
- Log.i(TAG, "Network Config Changed. Reconfiguring.");
- synchronized (this.configLock) {
- this.networkConfigs = virtualNetworkConfig;
- }
- this.eventBus.post(new NetworkReconfigureEvent());
- }
- this.eventBus.post(new NetworkInfoReplyEvent(virtualNetworkConfig));
- TunTapAdapter tunTapAdapter4 = this.tunTapAdapter;
- if (tunTapAdapter4 == null) {
- return 0;
- }
- tunTapAdapter4.setNetworkConfig(virtualNetworkConfig);
- return 0;
- } else if (i == 3 || i == 4) {
- Log.d(TAG, "Network Down!");
- synchronized (this.configLock) {
- this.networkConfigs = null;
+ /**
+ * 当 ZT 网络配置发生更新
+ */
+ @Override
+ public int onNetworkConfigurationUpdated(long networkId, VirtualNetworkConfigOperation op, VirtualNetworkConfig config) {
+ Log.i(TAG, "Virtual Network Config Operation: " + op);
+ DatabaseUtils.writeLock.lock();
+ try {
+ // 查找网络 ID 对应的配置
+ var networkDao = ((ZerotierFixApplication) getApplication())
+ .getDaoSession()
+ .getNetworkDao();
+ var matchedNetwork = networkDao.queryBuilder()
+ .where(NetworkDao.Properties.NetworkId.eq(networkId))
+ .list();
+ if (matchedNetwork.size() != 1) {
+ throw new IllegalStateException("Database is inconsistent");
}
- this.eventBus.post(new NetworkReconfigureEvent());
- TunTapAdapter tunTapAdapter5 = this.tunTapAdapter;
- if (tunTapAdapter5 == null) {
- return 0;
+ var network = matchedNetwork.get(0);
+ // 根据当前网络状态确定更改配置的行为
+ switch (op) {
+ case VIRTUAL_NETWORK_CONFIG_OPERATION_UP:
+ Log.d(TAG, "Network Type: " + config.getType() + " Network Status: " + config.getStatus() + " Network Name: " + config.getName() + " ");
+ setVirtualNetworkConfigAndUpdateDatabase(network, config);
+ this.eventBus.post(new VirtualNetworkConfigChangedEvent(config));
+ break;
+ case VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE:
+ Log.i(TAG, "Network Config Update!");
+ boolean isChanged = setVirtualNetworkConfigAndUpdateDatabase(network, config);
+ this.eventBus.post(new NetworkReconfigureEvent(isChanged, network, config));
+ break;
+ case VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN:
+ case VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY:
+ Log.d(TAG, "Network Down!");
+ clearVirtualNetworkConfig(networkId);
+ break;
}
- tunTapAdapter5.setNetworkConfig(null);
- return 0;
- } else {
- Log.e(TAG, "Unknown Network Config Operation!");
return 0;
+ } finally {
+ DatabaseUtils.writeLock.unlock();
}
}
- /* access modifiers changed from: protected */
- public void shutdown() {
+ private boolean setVirtualNetworkConfigAndUpdateDatabase(Network network, VirtualNetworkConfig virtualNetworkConfig) {
+ if ((DatabaseUtils.writeLock instanceof ReentrantReadWriteLock.WriteLock) && !((ReentrantReadWriteLock.WriteLock) DatabaseUtils.writeLock).isHeldByCurrentThread()) {
+ throw new IllegalStateException("DatabaseUtils.writeLock not held");
+ }
+ VirtualNetworkConfig virtualNetworkConfig2 = getVirtualNetworkConfig(network.getNetworkId());
+ setVirtualNetworkConfig(network.getNetworkId(), virtualNetworkConfig);
+ var networkName = virtualNetworkConfig.getName();
+ if (networkName != null && !networkName.isEmpty()) {
+ network.setNetworkName(networkName);
+ }
+ network.update();
+ return !virtualNetworkConfig.equals(virtualNetworkConfig2);
+ }
+
+ protected void shutdown() {
stopZeroTier();
- ParcelFileDescriptor parcelFileDescriptor = this.vpnSocket;
- if (parcelFileDescriptor != null) {
+ if (this.vpnSocket != null) {
try {
- parcelFileDescriptor.close();
+ this.vpnSocket.close();
} catch (Exception e) {
Log.e(TAG, "Error closing VPN socket", e);
}
@@ -745,207 +810,239 @@ public void shutdown() {
stopSelf(this.mStartID);
}
- /* JADX WARNING: Code restructure failed: missing block: B:45:0x0175, code lost:
- if (r9 > r6) goto L_0x0179;
- */
- /* Code decompiled incorrectly, please refer to instructions dump. */
- // Decomp by jd-gui
- private void updateTunnelConfig() {
- try {
- synchronized (this.configLock) {
- if (this.networkConfigs == null)
- return;
- if (this.tunTapAdapter.isRunning())
- this.tunTapAdapter.interrupt();
- this.tunTapAdapter.clearRouteMap();
- ParcelFileDescriptor parcelFileDescriptor2 = this.vpnSocket;
- if (parcelFileDescriptor2 != null) {
- try {
- parcelFileDescriptor2.close();
- this.in.close();
- this.out.close();
- } catch (Exception e) {
- Log.e("ZT1_Service", "Error closing VPN socket", e);
- }
- this.vpnSocket = null;
- this.in = null;
- this.out = null;
- }
- Log.i("ZT1_Service", "Configuring VpnService.Builder");
- VpnService.Builder builder1 = new VpnService.Builder();
- long networkId = this.networkConfigs.networkId();
- InetSocketAddress[] assignedAddresses = this.networkConfigs.assignedAddresses();
- long l2 = 0L;
- int i = 0;
- int j;
- for (j = 0; j < assignedAddresses.length; j++) {
- InetSocketAddress curAddress = assignedAddresses[j];
- boolean bool = curAddress.getAddress() instanceof java.net.Inet6Address;
- Log.d("ZT1_Service", "Adding VPN Address: " + curAddress.getAddress() + " Mac: " + Long.toHexString(this.networkConfigs.macAddress()));
- byte[] rawAddress = curAddress.getAddress().getAddress();
- long numAddress = l2;
- try {
- if (rawAddress.length == 4) {
- numAddress = ByteBuffer.wrap(rawAddress).getInt();
- }
- int port = curAddress.getPort();
- InetAddress curInetAddress = curAddress.getAddress();
- if (!this.disableIPv6 || !(curInetAddress instanceof java.net.Inet6Address)) {
- InetAddress curRouteAddress = InetAddressUtils.addressToRoute(curInetAddress, port);
- if (curRouteAddress == null) {
- Log.e("ZT1_Service", "NULL route calculated!");
- } else {
- ResultCode resultCode = null;
- if (rawAddress.length == 4) {
- resultCode = this.node.multicastSubscribe(networkId, 0xffffffffffffL, numAddress);
- } else {
- l2 = ByteBuffer.wrap(new byte[]{0, 0, 51, 51, -1, rawAddress[13], rawAddress[14], rawAddress[15]}).getLong();
- resultCode = this.node.multicastSubscribe(networkId, l2, numAddress);
- }
- if (resultCode != ResultCode.RESULT_OK) {
- Log.e("ZT1_Service", "Error joining multicast group");
- } else {
- Log.d("ZT1_Service", "Joined multicast group");
- }
- builder1.addAddress(curInetAddress, port);
- builder1.addRoute(curRouteAddress, port);
- Route route = new Route(curRouteAddress, port);
- this.tunTapAdapter.addRouteAndNetwork(route, networkId);
- int m = this.networkConfigs.mtu();
- port = i;
- i = Math.max(m, port);
- }
- }
- l2 = numAddress;
- } catch (Exception e) {
- Log.e("ZT1_Service", "Exception calculating multicast ADI", e);
- }
+ private boolean updateTunnelConfig(Network network) {
+ long networkId = network.getNetworkId();
+ var networkConfig = network.getNetworkConfig();
+ var virtualNetworkConfig = getVirtualNetworkConfig(networkId);
+ if (virtualNetworkConfig == null) {
+ return false;
+ }
+
+ // 重启 TUN TAP
+ if (this.tunTapAdapter.isRunning()) {
+ this.tunTapAdapter.interrupt();
+ try {
+ this.tunTapAdapter.join();
+ } catch (InterruptedException ignored) {
+ }
+ }
+ this.tunTapAdapter.clearRouteMap();
+
+ // 重启 VPN Socket
+ if (this.vpnSocket != null) {
+ try {
+ this.vpnSocket.close();
+ this.in.close();
+ this.out.close();
+ } catch (Exception e) {
+ Log.e(TAG, "Error closing VPN socket: " + e, e);
+ }
+ this.vpnSocket = null;
+ this.in = null;
+ this.out = null;
+ }
+
+ // 配置 VPN
+ Log.i(TAG, "Configuring VpnService.Builder");
+ var builder = new VpnService.Builder();
+ var assignedAddresses = virtualNetworkConfig.getAssignedAddresses();
+ Log.i(TAG, "address length: " + assignedAddresses.length);
+ boolean isRouteViaZeroTier = networkConfig.getRouteViaZeroTier();
+
+ // 遍历 ZT 网络中当前设备的 IP 地址,组播配置
+ for (var vpnAddress : assignedAddresses) {
+ Log.d(TAG, "Adding VPN Address: " + vpnAddress.getAddress()
+ + " Mac: " + com.zerotier.sdk.util.StringUtils.macAddressToString(virtualNetworkConfig.getMac()));
+ byte[] rawAddress = vpnAddress.getAddress().getAddress();
+
+ if (!this.disableIPv6 || !(vpnAddress.getAddress() instanceof Inet6Address)) {
+ var address = vpnAddress.getAddress();
+ var port = vpnAddress.getPort();
+ var route = InetAddressUtils.addressToRoute(address, port);
+ if (route == null) {
+ Log.e(TAG, "NULL route calculated!");
+ continue;
}
- InetAddress inetAddress1 = InetAddress.getByName("0.0.0.0");
- InetAddress inetAddress2 = InetAddress.getByName("::");
- if ((this.networkConfigs.routes()).length > 0) {
- VirtualNetworkRoute[] arrayOfVirtualNetworkRoute = this.networkConfigs.routes();
- for (j = 0; j < arrayOfVirtualNetworkRoute.length; j++) {
- InetSocketAddress inetSocketAddress2 = (arrayOfVirtualNetworkRoute[j]).target;
- InetSocketAddress inetSocketAddress1 = (arrayOfVirtualNetworkRoute[j]).via;
- int k = inetSocketAddress2.getPort();
- InetAddress inetAddress4 = inetSocketAddress2.getAddress();
- InetAddress inetAddress3 = InetAddressUtils.addressToRoute(inetAddress4, k);
- if ((!this.disableIPv6 || (!(inetAddress4 instanceof java.net.Inet6Address) && !(inetAddress3 instanceof java.net.Inet6Address))) && inetAddress3 != null && (this.useDefaultRoute || (!inetAddress3.equals(inetAddress1) && !inetAddress3.equals(inetAddress2)))) {
- builder1.addRoute(inetAddress3, k);
- Route route = new Route(inetAddress3, k);
- if (inetSocketAddress1 != null)
- route.setGateway(inetSocketAddress1.getAddress());
- this.tunTapAdapter.addRouteAndNetwork(route, networkId);
- }
- }
+
+ // 计算 VPN 地址相关的组播 MAC 与 ADI
+ long multicastGroup;
+ long multicastAdi;
+ if (rawAddress.length == 4) {
+ // IPv4
+ multicastGroup = InetAddressUtils.BROADCAST_MAC_ADDRESS;
+ multicastAdi = ByteBuffer.wrap(rawAddress).getInt();
+ } else {
+ // IPv6
+ multicastGroup = ByteBuffer.wrap(new byte[]{
+ 0, 0, 0x33, 0x33, (byte) 0xFF, rawAddress[13], rawAddress[14], rawAddress[15]})
+ .getLong();
+ multicastAdi = 0;
}
- builder1.addRoute(InetAddress.getByName("224.0.0.0"), 4);
- List list = ((ZerotierFixApplication) getApplication()).getDaoSession()
- .getNetworkConfigDao().queryBuilder()
- .where(NetworkConfigDao.Properties.Id.eq(networkId), new WhereCondition[0])
- .build().forCurrentThread().list();
- if (list.isEmpty()) {
- Log.e("ZT1_Service", "network config list empty?!?");
- } else if (list.size() > 1) {
- Log.e("ZT1_Service", "network config list has more than 1?!?");
+
+ // 订阅组播并添加至 TUN TAP 路由
+ var result = this.node.multicastSubscribe(networkId, multicastGroup, multicastAdi);
+ if (result != ResultCode.RESULT_OK) {
+ Log.e(TAG, "Error joining multicast group");
} else {
- j = list.get(0).getDnsMode();
- if (j != 1) {
- if (j == 2) {
- for (DnsServer dnsServer : ((ZerotierFixApplication) getApplication()).getDaoSession().getDnsServerDao().queryBuilder().where(DnsServerDao.Properties.NetworkId.eq(Long.valueOf(networkId)), new WhereCondition[0]).build().forCurrentThread().list()) {
- String str = dnsServer.getNameserver();
- try {
- InetAddress inetAddress = InetAddress.getByName(str);
- if (inetAddress instanceof java.net.Inet4Address) {
- builder1.addDnsServer(inetAddress);
- continue;
- }
- if (inetAddress instanceof java.net.Inet6Address && !this.disableIPv6)
- builder1.addDnsServer(inetAddress);
- } catch (Exception e) {
- Log.e("ZT1_Service", "Exception parsing DNS server", e);
- }
- }
- }
- } else if (this.networkConfigs.dns() != null) {
- builder1.addSearchDomain(this.networkConfigs.dns().getSearchDomain());
- for (InetSocketAddress inetSocketAddress : this.networkConfigs.dns().getServers()) {
- inetAddress1 = inetSocketAddress.getAddress();
- if (inetAddress1 instanceof java.net.Inet4Address) {
- builder1.addDnsServer(inetAddress1);
- continue;
- }
- if (inetAddress1 instanceof java.net.Inet6Address && !this.disableIPv6)
- builder1.addDnsServer(inetAddress1);
- }
- }
+ Log.d(TAG, "Joined multicast group");
}
- builder1.setMtu(i);
- builder1.setSession("ZeroTier One");
- if (Build.VERSION.SDK_INT >= 21 && !this.useDefaultRoute)
- for (String str : DISALLOWED_APPS) {
- try {
- builder1.addDisallowedApplication(str);
- } catch (Exception exception) {
- Log.e("ZT1_Service", "Cannot disallow app", exception);
+ builder.addAddress(address, port);
+ builder.addRoute(route, port);
+ this.tunTapAdapter.addRouteAndNetwork(new Route(route, port), networkId);
+ }
+ }
+
+ // 遍历网络的路由规则,将网络负责路由的地址路由至 VPN
+ try {
+ var v4Loopback = InetAddress.getByName("0.0.0.0");
+ var v6Loopback = InetAddress.getByName("::");
+ if (virtualNetworkConfig.getRoutes().length > 0) {
+ for (var routeConfig : virtualNetworkConfig.getRoutes()) {
+ var target = routeConfig.getTarget();
+ var via = routeConfig.getVia();
+ var targetAddress = target.getAddress();
+ var targetPort = target.getPort();
+ var viaAddress = InetAddressUtils.addressToRoute(targetAddress, targetPort);
+
+ boolean isIPv6Route = (targetAddress instanceof Inet6Address) || (viaAddress instanceof Inet6Address);
+ boolean isDisabledV6Route = this.disableIPv6 && isIPv6Route;
+ boolean shouldRouteToZerotier = viaAddress != null && (
+ isRouteViaZeroTier
+ || (!viaAddress.equals(v4Loopback) && !viaAddress.equals(v6Loopback))
+ );
+ if (!isDisabledV6Route && shouldRouteToZerotier) {
+ builder.addRoute(viaAddress, targetPort);
+ Route route = new Route(viaAddress, targetPort);
+ if (via != null) {
+ route.setGateway(via.getAddress());
}
+ this.tunTapAdapter.addRouteAndNetwork(route, networkId);
}
- ParcelFileDescriptor parcelFileDescriptor1 = builder1.establish();
- this.vpnSocket = parcelFileDescriptor1;
- if (parcelFileDescriptor1 == null) {
- Log.e("ZT1_Service", "vpnSocket is NULL after builder.establish()!!!!");
- stopZeroTier();
- return;
}
- this.in = new FileInputStream(this.vpnSocket.getFileDescriptor());
- this.out = new FileOutputStream(this.vpnSocket.getFileDescriptor());
- this.tunTapAdapter.setVpnSocket(this.vpnSocket);
- this.tunTapAdapter.setFileStreams(this.in, this.out);
- this.tunTapAdapter.startThreads();
- // 状态栏提示
- if (this.notificationManager == null)
- this.notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- if (Build.VERSION.SDK_INT >= 26) {
- NotificationChannel notificationChannel = new NotificationChannel("ZeroTierOne", "ZeroTier One", NotificationManager.IMPORTANCE_MIN);
- notificationChannel.setDescription(getString(R.string.network_connected));
- this.notificationManager.createNotificationChannel(notificationChannel);
- }
- Intent intent = new Intent(this, NetworkListActivity.class);
- PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
- NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "ZeroTierOne");
- String contentText = String.format(getString(R.string.connected_to_network), Long.toHexString(this.networkConfigs.networkId()));
- Notification notification = builder.setOngoing(true)
- .setSmallIcon(R.mipmap.ic_launcher)
- .setContentTitle(getString(R.string.network_connected))
- .setContentText(contentText)
- .setSubText("")
- .setContentIntent(pendingIntent).build();
- this.notificationManager.notify(ZT_NOTIFICATION_TAG, notification);
- Log.i("ZT1_Service", "ZeroTier One Connected");
- // 多播处理进程
- Thread thread = this.v4multicastScanner;
- if (!((thread != null) && !thread.isAlive()) && Build.VERSION.SDK_INT < 29)
- this.v4multicastScanner.start();
- if (!this.disableIPv6) {
- thread = this.v6MulticastScanner;
- if (thread != null && !thread.isAlive() && Build.VERSION.SDK_INT < 29)
- this.v6MulticastScanner.start();
+ }
+ builder.addRoute(InetAddress.getByName("224.0.0.0"), 4);
+ } catch (Exception e) {
+ this.eventBus.post(new VPNErrorEvent(e.getLocalizedMessage()));
+ return false;
+ }
+
+ if (Build.VERSION.SDK_INT >= 29) {
+ builder.setMetered(false);
+ }
+ addDNSServers(builder, network);
+
+ // 配置 MTU
+ int mtu = virtualNetworkConfig.getMtu();
+ Log.i(TAG, "MTU from Network Config: " + mtu);
+ if (mtu == 0) {
+ mtu = 2800;
+ }
+ Log.i(TAG, "MTU Set: " + mtu);
+ builder.setMtu(mtu);
+
+ builder.setSession(Constants.VPN_SESSION_NAME);
+
+ // 设置部分 APP 不经过 VPN
+ if (!isRouteViaZeroTier && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ for (var app : DISALLOWED_APPS) {
+ try {
+ builder.addDisallowedApplication(app);
+ } catch (Exception e3) {
+ Log.e(TAG, "Cannot disallow app", e3);
}
}
- } catch (Exception exception) {
- Log.e("ZT1_Service", "Exception setting up VPN port", exception);
}
+
+ // 建立 VPN 连接
+ this.vpnSocket = builder.establish();
+ if (this.vpnSocket == null) {
+ this.eventBus.post(new VPNErrorEvent(getString(R.string.toast_vpn_application_not_prepared)));
+ return false;
+ }
+ this.in = new FileInputStream(this.vpnSocket.getFileDescriptor());
+ this.out = new FileOutputStream(this.vpnSocket.getFileDescriptor());
+ this.tunTapAdapter.setVpnSocket(this.vpnSocket);
+ this.tunTapAdapter.setFileStreams(this.in, this.out);
+ this.tunTapAdapter.startThreads();
+
+ // 状态栏提示
+ if (this.notificationManager == null) {
+ this.notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ }
+ if (Build.VERSION.SDK_INT >= 26) {
+ String channelName = getString(R.string.channel_name);
+ String description = getString(R.string.channel_description);
+ var channel = new NotificationChannel(
+ Constants.CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_HIGH);
+ channel.setDescription(description);
+ this.notificationManager.createNotificationChannel(channel);
+ }
+ var pendingIntent =
+ PendingIntent.getActivity(this, 0,
+ new Intent(this, NetworkListActivity.class),
+ Build.VERSION.SDK_INT >= 23
+ ? PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT
+ : PendingIntent.FLAG_UPDATE_CURRENT);
+ var notification = new NotificationCompat.Builder(this, Constants.CHANNEL_ID)
+ .setPriority(1)
+ .setOngoing(true)
+ .setSmallIcon(R.mipmap.ic_launcher)
+ .setContentTitle(getString(R.string.notification_title_connected))
+ .setContentText(getString(R.string.notification_text_connected, network.getNetworkIdStr()))
+ .setColor(ContextCompat.getColor(getApplicationContext(), R.color.zerotier_orange))
+ .setContentIntent(pendingIntent).build();
+ this.notificationManager.notify(ZT_NOTIFICATION_TAG, notification);
+ Log.i(TAG, "ZeroTier One Connected");
+
+ // 旧版本 Android 多播处理
+ if (Build.VERSION.SDK_INT < 29) {
+ if (this.v4MulticastScanner != null && !this.v4MulticastScanner.isAlive()) {
+ this.v4MulticastScanner.start();
+ }
+ if (!this.disableIPv6 && this.v6MulticastScanner != null && !this.v6MulticastScanner.isAlive()) {
+ this.v6MulticastScanner.start();
+ }
+ }
+ return true;
}
- /* access modifiers changed from: package-private */
- public byte[] hexStringToByteArray(String str) {
- int length = str.length();
- byte[] bArr = new byte[(length / 2)];
- for (int i = 0; i < length; i += 2) {
- bArr[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16));
+ private void addDNSServers(VpnService.Builder builder, Network network) {
+ var networkConfig = network.getNetworkConfig();
+ var virtualNetworkConfig = getVirtualNetworkConfig(network.getNetworkId());
+ var dnsMode = DNSMode.fromInt(networkConfig.getDnsMode());
+
+ switch (dnsMode) {
+ case NETWORK_DNS:
+ if (virtualNetworkConfig.getDns() == null) {
+ return;
+ }
+ builder.addSearchDomain(virtualNetworkConfig.getDns().getDomain());
+ for (var inetSocketAddress : virtualNetworkConfig.getDns().getServers()) {
+ InetAddress address = inetSocketAddress.getAddress();
+ if (address instanceof Inet4Address) {
+ builder.addDnsServer(address);
+ } else if ((address instanceof Inet6Address) && !this.disableIPv6) {
+ builder.addDnsServer(address);
+ }
+ }
+ break;
+ case CUSTOM_DNS:
+ for (var dnsServer : networkConfig.getDnsServers()) {
+ try {
+ InetAddress byName = InetAddress.getByName(dnsServer.getNameserver());
+ if (byName instanceof Inet4Address) {
+ builder.addDnsServer(byName);
+ } else if ((byName instanceof Inet6Address) && !this.disableIPv6) {
+ builder.addDnsServer(byName);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Exception parsing DNS server: " + e, e);
+ }
+ }
+ break;
+ default:
+ break;
}
- return bArr;
}
/**
@@ -966,8 +1063,9 @@ public void onOrbitMoonEvent(OrbitMoonEvent event) {
/**
* 当前网络入轨 Moon
- * @param moonWorldId
- * @param moonSeed
+ *
+ * @param moonWorldId Moon 节点地址
+ * @param moonSeed Moon 种子节点地址
*/
public void orbitNetwork(Long moonWorldId, Long moonSeed) {
if (this.node == null) {
@@ -982,19 +1080,6 @@ public void orbitNetwork(Long moonWorldId, Long moonSeed) {
}
}
- /* renamed from: com.zerotier.one.service.ZeroTierOneService$3 reason: invalid class name */
- static /* synthetic */ class AnonymousClass3 {
- static final /* synthetic */ int[] $SwitchMap$com$zerotier$sdk$VirtualNetworkConfigOperation;
-
- static {
- $SwitchMap$com$zerotier$sdk$VirtualNetworkConfigOperation = new int[VirtualNetworkConfigOperation.values().length];
- $SwitchMap$com$zerotier$sdk$VirtualNetworkConfigOperation[VirtualNetworkConfigOperation.VIRTUAL_NETWORK_CONFIG_OPERATION_UP.ordinal()] = 1;
- $SwitchMap$com$zerotier$sdk$VirtualNetworkConfigOperation[VirtualNetworkConfigOperation.VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE.ordinal()] = 2;
- $SwitchMap$com$zerotier$sdk$VirtualNetworkConfigOperation[VirtualNetworkConfigOperation.VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN.ordinal()] = 3;
- $SwitchMap$com$zerotier$sdk$VirtualNetworkConfigOperation[VirtualNetworkConfigOperation.VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY.ordinal()] = 4;
- }
- }
-
public class ZeroTierBinder extends Binder {
public ZeroTierBinder() {
}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/ui/NetworkDetailFragment.java b/app/src/main/java/net/kaaass/zerotierfix/ui/NetworkDetailFragment.java
index f6ebc99..34e3445 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/ui/NetworkDetailFragment.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/ui/NetworkDetailFragment.java
@@ -66,10 +66,10 @@ public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bun
if (network != null) {
((TextView) inflate.findViewById(R.id.network_detail_network_id)).setText(network.getNetworkIdStr());
TextView textView = inflate.findViewById(R.id.network_detail_network_name);
- if (network.getNetworkName() != null) {
+ if (network.getNetworkName() != null && !network.getNetworkName().isEmpty()) {
textView.setText(network.getNetworkName());
} else {
- textView.setText(EnvironmentCompat.MEDIA_UNKNOWN);
+ textView.setText(getString(R.string.empty_network_name));
}
NetworkConfig networkConfig = network.getNetworkConfig();
CheckBox checkBox = inflate.findViewById(R.id.network_default_route);
diff --git a/app/src/main/java/net/kaaass/zerotierfix/ui/NetworkListFragment.java b/app/src/main/java/net/kaaass/zerotierfix/ui/NetworkListFragment.java
index 05fd8c5..cefc1fa 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/ui/NetworkListFragment.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/ui/NetworkListFragment.java
@@ -24,6 +24,7 @@
import android.widget.TextView;
import android.widget.Toast;
+import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.SwitchCompat;
import androidx.fragment.app.Fragment;
@@ -33,22 +34,25 @@
import com.zerotier.sdk.NodeStatus;
import com.zerotier.sdk.Version;
import com.zerotier.sdk.VirtualNetworkConfig;
-import com.zerotier.sdk.VirtualNetworkStatus;
import com.zerotier.sdk.VirtualNetworkType;
-import net.kaaass.zerotierfix.ZerotierFixApplication;
import net.kaaass.zerotierfix.R;
+import net.kaaass.zerotierfix.ZerotierFixApplication;
import net.kaaass.zerotierfix.events.AfterJoinNetworkEvent;
-import net.kaaass.zerotierfix.events.IsServiceRunningEvent;
+import net.kaaass.zerotierfix.events.IsServiceRunningReplyEvent;
+import net.kaaass.zerotierfix.events.IsServiceRunningRequestEvent;
import net.kaaass.zerotierfix.events.NetworkInfoReplyEvent;
+import net.kaaass.zerotierfix.events.NetworkListCheckedChangeEvent;
import net.kaaass.zerotierfix.events.NetworkListReplyEvent;
import net.kaaass.zerotierfix.events.NodeDestroyedEvent;
import net.kaaass.zerotierfix.events.NodeIDEvent;
import net.kaaass.zerotierfix.events.NodeStatusEvent;
+import net.kaaass.zerotierfix.events.NodeStatusRequestEvent;
import net.kaaass.zerotierfix.events.OrbitMoonEvent;
-import net.kaaass.zerotierfix.events.RequestNetworkListEvent;
-import net.kaaass.zerotierfix.events.RequestNodeStatusEvent;
+import net.kaaass.zerotierfix.events.NetworkListRequestEvent;
import net.kaaass.zerotierfix.events.StopEvent;
+import net.kaaass.zerotierfix.events.VPNErrorEvent;
+import net.kaaass.zerotierfix.events.VirtualNetworkConfigChangedEvent;
import net.kaaass.zerotierfix.model.AppNode;
import net.kaaass.zerotierfix.model.AssignedAddress;
import net.kaaass.zerotierfix.model.AssignedAddressDao;
@@ -58,6 +62,8 @@
import net.kaaass.zerotierfix.model.NetworkConfig;
import net.kaaass.zerotierfix.model.NetworkConfigDao;
import net.kaaass.zerotierfix.model.NetworkDao;
+import net.kaaass.zerotierfix.model.type.NetworkStatus;
+import net.kaaass.zerotierfix.model.type.NetworkType;
import net.kaaass.zerotierfix.service.ZeroTierOneService;
import net.kaaass.zerotierfix.util.Constants;
import net.kaaass.zerotierfix.util.StringUtils;
@@ -67,6 +73,7 @@
import org.greenrobot.eventbus.ThreadMode;
import org.greenrobot.greendao.query.WhereCondition;
+import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@@ -77,14 +84,11 @@
// TODO: clear up
public class NetworkListFragment extends Fragment {
- public static final int AUTH_VPN = 3;
public static final String NETWORK_ID_MESSAGE = "com.zerotier.one.network-id";
- public static final int START_VPN = 2;
public static final String TAG = "NetworkListFragment";
private final EventBus eventBus;
private final List mNetworks = new ArrayList<>();
boolean mIsBound = false;
- private JoinAfterAuth joinAfterAuth;
private RecyclerViewAdapter recyclerViewAdapter;
private RecyclerView recyclerView;
private ZeroTierOneService mBoundService;
@@ -106,7 +110,6 @@ public void onServiceDisconnected(ComponentName componentName) {
private TextView nodeClientVersionView;
private View emptyView = null;
-
final private RecyclerView.AdapterDataObserver checkIfEmptyObserver = new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
@@ -153,7 +156,7 @@ public synchronized boolean isBound() {
/* access modifiers changed from: package-private */
public void doBindService() {
if (!isBound()) {
- if (getActivity().bindService(new Intent(getActivity(), ZeroTierOneService.class), this.mConnection, Context.BIND_NOT_FOREGROUND | Context.BIND_DEBUG_UNBIND)) {
+ if (requireActivity().bindService(new Intent(getActivity(), ZeroTierOneService.class), this.mConnection, Context.BIND_NOT_FOREGROUND | Context.BIND_DEBUG_UNBIND)) {
setIsBound(true);
}
}
@@ -163,7 +166,7 @@ public void doBindService() {
public void doUnbindService() {
if (isBound()) {
try {
- getActivity().unbindService(this.mConnection);
+ requireActivity().unbindService(this.mConnection);
} catch (Exception e) {
Log.e(TAG, "", e);
} catch (Throwable th) {
@@ -174,33 +177,27 @@ public void doUnbindService() {
}
}
- @Override // androidx.fragment.app.Fragment
+ @Override
public void onStart() {
super.onStart();
- this.eventBus.register(this);
- this.eventBus.post(new RequestNetworkListEvent());
- this.eventBus.post(new RequestNodeStatusEvent());
- this.eventBus.post(IsServiceRunningEvent.NewRequest());
+ this.eventBus.post(new NetworkListRequestEvent());
+ // 初始化节点及服务状态
+ this.eventBus.post(new NodeStatusRequestEvent());
+ this.eventBus.post(new IsServiceRunningRequestEvent());
}
- @Override // androidx.fragment.app.Fragment
+ @Override
public void onStop() {
super.onStop();
doUnbindService();
- this.eventBus.unregister(this);
}
- @Override // androidx.fragment.app.Fragment
+ @Override
public void onPause() {
super.onPause();
this.eventBus.unregister(this);
}
- @Override // androidx.fragment.app.Fragment
- public void onActivityCreated(Bundle bundle) {
- super.onActivityCreated(bundle);
- }
-
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_network_list, container, false);
@@ -235,20 +232,33 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
return view;
}
- /* access modifiers changed from: private */
- /* access modifiers changed from: public */
- private void sendStartServiceIntent(long networkId, boolean useDefaultRoute) {
- Intent prepare = VpnService.prepare(getActivity());
+ /**
+ * 发送连接至指定网络的 Intent。将请求 VPN 权限后启动 ZT 服务
+ *
+ * @param networkId 网络号
+ */
+ private void sendStartServiceIntent(long networkId) {
+ var prepare = VpnService.prepare(getActivity());
if (prepare != null) {
- this.joinAfterAuth = new JoinAfterAuth(networkId, useDefaultRoute);
- startActivityForResult(prepare, 3);
+ // 等待 VPN 授权后连接网络
+ registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), (activityResult) -> {
+ var result = activityResult.getResultCode();
+ Log.d(TAG, "Returned from AUTH_VPN");
+ if (result == -1) {
+ // 授权
+ startService(networkId);
+ } else if (result == 0) {
+ // 未授权
+ updateNetworkListAndNotify();
+ }
+ }).launch(prepare);
return;
}
Log.d(TAG, "Intent is NULL. Already approved.");
- startService(networkId, useDefaultRoute);
+ startService(networkId);
}
- @Override // androidx.fragment.app.Fragment
+ @Override
public void onCreate(Bundle bundle) {
Log.d(TAG, "NetworkListFragment.onCreate");
super.onCreate(bundle);
@@ -256,25 +266,26 @@ public void onCreate(Bundle bundle) {
setHasOptionsMenu(true);
}
- @Override // androidx.fragment.app.Fragment
+ @Override
public void onResume() {
super.onResume();
this.nodeStatusView.setText(R.string.status_offline);
- this.eventBus.post(IsServiceRunningEvent.NewRequest());
+ this.eventBus.register(this);
+ this.eventBus.post(new IsServiceRunningRequestEvent());
updateNetworkListAndNotify();
- this.eventBus.post(new RequestNetworkListEvent());
- this.eventBus.post(new RequestNodeStatusEvent());
+ this.eventBus.post(new NetworkListRequestEvent());
+ this.eventBus.post(new NodeStatusRequestEvent());
}
- @Override // androidx.fragment.app.Fragment
- public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
+ @Override
+ public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater menuInflater) {
Log.d(TAG, "NetworkListFragment.onCreateOptionsMenu");
menuInflater.inflate(R.menu.menu_network_list, menu);
super.onCreateOptionsMenu(menu, menuInflater);
- this.eventBus.post(new RequestNodeStatusEvent());
+ this.eventBus.post(new NodeStatusRequestEvent());
}
- @Override // androidx.fragment.app.Fragment
+ @Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
int menuId = menuItem.getItemId();
if (menuId == R.id.menu_item_settings) {
@@ -293,48 +304,28 @@ public boolean onOptionsItemSelected(MenuItem menuItem) {
return super.onOptionsItemSelected(menuItem);
}
- @Override // androidx.fragment.app.Fragment
- public void onActivityResult(int i, int i2, Intent intent) {
- JoinAfterAuth joinAfterAuth2;
- if (i == 2) {
- long longExtra = intent.getLongExtra(ZeroTierOneService.ZT1_NETWORK_ID, 0);
- boolean booleanExtra = intent.getBooleanExtra(ZeroTierOneService.ZT1_USE_DEFAULT_ROUTE, false);
- if (longExtra != 0) {
- startService(longExtra, booleanExtra);
- } else {
- Log.e(TAG, "Network ID not provided. Cannot start network without an ID");
- }
- } else if (i == 3) {
- Log.d(TAG, "Returned from AUTH_VPN");
- if (i2 == -1 && (joinAfterAuth2 = this.joinAfterAuth) != null) {
- startService(joinAfterAuth2.networkId, this.joinAfterAuth.useDefaultRoute);
- }
- this.joinAfterAuth = null;
- }
- }
-
- @Override // androidx.fragment.app.Fragment
+ @Override
public void onDestroy() {
super.onDestroy();
doUnbindService();
}
private List getNetworkList() {
- DaoSession daoSession = ((ZerotierFixApplication) getActivity().getApplication()).getDaoSession();
+ DaoSession daoSession = ((ZerotierFixApplication) requireActivity().getApplication()).getDaoSession();
daoSession.clear();
return daoSession.getNetworkDao().queryBuilder().orderAsc(NetworkDao.Properties.NetworkId).build().forCurrentThread().list();
}
private void setNodeIdText() {
- List list = ((ZerotierFixApplication) getActivity().getApplication()).getDaoSession().getAppNodeDao().queryBuilder().build().forCurrentThread().list();
+ List list = ((ZerotierFixApplication) requireActivity().getApplication()).getDaoSession().getAppNodeDao().queryBuilder().build().forCurrentThread().list();
if (!list.isEmpty()) {
this.nodeIdView.setText(list.get(0).getNodeIdStr());
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
- public void onIsServicerunning(IsServiceRunningEvent isServiceRunningEvent) {
- if (isServiceRunningEvent.type == IsServiceRunningEvent.Type.REPLY && isServiceRunningEvent.isRunning) {
+ public void onIsServiceRunningReply(IsServiceRunningReplyEvent event) {
+ if (event.isRunning()) {
doBindService();
}
}
@@ -348,17 +339,17 @@ public void onNetworkListReply(NetworkListReplyEvent networkListReplyEvent) {
@Subscribe(threadMode = ThreadMode.MAIN)
public void onNetworkInfoReply(NetworkInfoReplyEvent networkInfoReplyEvent) {
- NetworkConfig.NetworkStatus networkStatus;
+ NetworkStatus networkStatus;
Log.d(TAG, "Got Network Info");
VirtualNetworkConfig networkInfo = networkInfoReplyEvent.getNetworkInfo();
for (Network network : getNetworkList()) {
- if (network.getNetworkId() == networkInfo.networkId()) {
+ if (network.getNetworkId() == networkInfo.getNwid()) {
network.setConnected(true);
- if (!networkInfo.name().isEmpty()) {
- network.setNetworkName(networkInfo.name());
+ if (!networkInfo.getName().isEmpty()) {
+ network.setNetworkName(networkInfo.getName());
}
- NetworkDao networkDao = ((ZerotierFixApplication) getActivity().getApplication()).getDaoSession().getNetworkDao();
- NetworkConfigDao networkConfigDao = ((ZerotierFixApplication) getActivity().getApplication()).getDaoSession().getNetworkConfigDao();
+ NetworkDao networkDao = ((ZerotierFixApplication) requireActivity().getApplication()).getDaoSession().getNetworkDao();
+ NetworkConfigDao networkConfigDao = ((ZerotierFixApplication) requireActivity().getApplication()).getDaoSession().getNetworkConfigDao();
NetworkConfig networkConfig = network.getNetworkConfig();
if (networkConfig == null) {
networkConfig = new NetworkConfig();
@@ -368,40 +359,40 @@ public void onNetworkInfoReply(NetworkInfoReplyEvent networkInfoReplyEvent) {
network.setNetworkConfig(networkConfig);
network.setNetworkConfigId(network.getNetworkId());
networkDao.save(network);
- networkConfig.setBridging(networkInfo.isBridgeEnabled());
- if (networkInfo.networkType() == VirtualNetworkType.NETWORK_TYPE_PRIVATE) {
- networkConfig.setType(NetworkConfig.NetworkType.PRIVATE);
- } else if (networkInfo.networkType() == VirtualNetworkType.NETWORK_TYPE_PUBLIC) {
- networkConfig.setType(NetworkConfig.NetworkType.PUBLIC);
+ networkConfig.setBridging(networkInfo.isBridge());
+ if (networkInfo.getType() == VirtualNetworkType.NETWORK_TYPE_PRIVATE) {
+ networkConfig.setType(NetworkType.PRIVATE);
+ } else if (networkInfo.getType() == VirtualNetworkType.NETWORK_TYPE_PUBLIC) {
+ networkConfig.setType(NetworkType.PUBLIC);
}
- switch (AnonymousClass2.$SwitchMap$com$zerotier$sdk$VirtualNetworkStatus[networkInfo.networkStatus().ordinal()]) {
- case 1:
- networkStatus = NetworkConfig.NetworkStatus.OK;
+ switch (networkInfo.getStatus()) {
+ case NETWORK_STATUS_OK:
+ networkStatus = NetworkStatus.OK;
break;
- case 2:
- networkStatus = NetworkConfig.NetworkStatus.ACCESS_DENIED;
- Toast.makeText(getActivity(), R.string.toast_not_authorized, Toast.LENGTH_SHORT).show();
+ case NETWORK_STATUS_ACCESS_DENIED:
+ networkStatus = NetworkStatus.ACCESS_DENIED;
break;
- case 3:
- networkStatus = NetworkConfig.NetworkStatus.CLIENT_TOO_OLD;
+ case NETWORK_STATUS_NOT_FOUND:
+ networkStatus = NetworkStatus.NOT_FOUND;
break;
- case 4:
- networkStatus = NetworkConfig.NetworkStatus.NOT_FOUND;
+ case NETWORK_STATUS_PORT_ERROR:
+ networkStatus = NetworkStatus.PORT_ERROR;
break;
- case 5:
- networkStatus = NetworkConfig.NetworkStatus.PORT_ERROR;
+ case NETWORK_STATUS_CLIENT_TOO_OLD:
+ networkStatus = NetworkStatus.CLIENT_TOO_OLD;
break;
- case 6:
- networkStatus = NetworkConfig.NetworkStatus.REQUESTING_CONFIGURATION;
+ case NETWORK_STATUS_AUTHENTICATION_REQUIRED:
+ networkStatus = NetworkStatus.AUTHENTICATION_REQUIRED;
break;
default:
- networkStatus = NetworkConfig.NetworkStatus.UNKNOWN;
+ case NETWORK_STATUS_REQUESTING_CONFIGURATION:
+ networkStatus = NetworkStatus.REQUESTING_CONFIGURATION;
break;
}
networkConfig.setStatus(networkStatus);
- String macAddress = Long.toHexString(networkInfo.macAddress());
+ StringBuilder macAddress = new StringBuilder(Long.toHexString(networkInfo.getMac()));
while (macAddress.length() < 12) {
- macAddress = "0" + macAddress;
+ macAddress.insert(0, "0");
}
String sb = String.valueOf(macAddress.charAt(0)) +
macAddress.charAt(1) +
@@ -421,16 +412,16 @@ public void onNetworkInfoReply(NetworkInfoReplyEvent networkInfoReplyEvent) {
macAddress.charAt(10) +
macAddress.charAt(11);
networkConfig.setMac(sb);
- networkConfig.setMtu(Integer.toString(networkInfo.mtu()));
- networkConfig.setBroadcast(networkInfo.broadcastEnabled());
- network.setNetworkConfigId(networkInfo.networkId());
+ networkConfig.setMtu(Integer.toString(networkInfo.getMtu()));
+ networkConfig.setBroadcast(networkInfo.isBroadcastEnabled());
+ network.setNetworkConfigId(networkInfo.getNwid());
network.setNetworkConfig(networkConfig);
networkDao.save(network);
networkConfigDao.save(networkConfig);
- ((ZerotierFixApplication) getActivity().getApplication()).getDaoSession().getAssignedAddressDao().queryBuilder().where(AssignedAddressDao.Properties.NetworkId.eq(networkInfo.networkId()), new WhereCondition[0]).buildDelete().forCurrentThread().forCurrentThread().executeDeleteWithoutDetachingEntities();
- ((ZerotierFixApplication) getActivity().getApplication()).getDaoSession().clear();
- AssignedAddressDao assignedAddressDao = ((ZerotierFixApplication) getActivity().getApplication()).getDaoSession().getAssignedAddressDao();
- InetSocketAddress[] assignedAddresses = networkInfo.assignedAddresses();
+ ((ZerotierFixApplication) requireActivity().getApplication()).getDaoSession().getAssignedAddressDao().queryBuilder().where(AssignedAddressDao.Properties.NetworkId.eq(networkInfo.getNwid()), new WhereCondition[0]).buildDelete().forCurrentThread().forCurrentThread().executeDeleteWithoutDetachingEntities();
+ ((ZerotierFixApplication) requireActivity().getApplication()).getDaoSession().clear();
+ AssignedAddressDao assignedAddressDao = ((ZerotierFixApplication) requireActivity().getApplication()).getDaoSession().getAssignedAddressDao();
+ InetSocketAddress[] assignedAddresses = networkInfo.getAssignedAddresses();
for (InetSocketAddress inetSocketAddress : assignedAddresses) {
InetAddress address = inetSocketAddress.getAddress();
short port = (short) inetSocketAddress.getPort();
@@ -441,8 +432,8 @@ public void onNetworkInfoReply(NetworkInfoReplyEvent networkInfoReplyEvent) {
}
if (address instanceof Inet6Address) {
assignedAddress.setType(AssignedAddress.AddressType.IPV6);
- } else if (address instanceof InetAddress) {
- assignedAddress.setType(AssignedAddress.AddressType.IPV6);
+ } else if (address instanceof Inet4Address) {
+ assignedAddress.setType(AssignedAddress.AddressType.IPV4);
}
assignedAddress.setAddressBytes(address.getAddress());
assignedAddress.setAddressString(inetAddress);
@@ -455,10 +446,50 @@ public void onNetworkInfoReply(NetworkInfoReplyEvent networkInfoReplyEvent) {
network.update();
}
}
- ((ZerotierFixApplication) getActivity().getApplication()).getDaoSession().clear();
+ ((ZerotierFixApplication) requireActivity().getApplication()).getDaoSession().clear();
updateNetworkListAndNotify();
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onVirtualNetworkConfigChanged(VirtualNetworkConfigChangedEvent event) {
+ Log.d(TAG, "Got Network Info");
+ var config = event.getVirtualNetworkConfig();
+
+ // Toast 提示网络状态
+ var status = NetworkStatus.fromVirtualNetworkStatus(config.getStatus());
+ var networkId = com.zerotier.sdk.util.StringUtils.networkIdToString(config.getNwid());
+ String message = null;
+ switch (status) {
+ case OK:
+ message = getString(R.string.toast_network_status_ok, networkId);
+ break;
+ case ACCESS_DENIED:
+ message = getString(R.string.toast_network_status_access_denied, networkId);
+ break;
+ case NOT_FOUND:
+ message = getString(R.string.toast_network_status_not_found, networkId);
+ break;
+ case PORT_ERROR:
+ message = getString(R.string.toast_network_status_port_error, networkId);
+ break;
+ case CLIENT_TOO_OLD:
+ message = getString(R.string.toast_network_status_client_too_old, networkId);
+ break;
+ case AUTHENTICATION_REQUIRED:
+ message = getString(R.string.toast_network_status_authentication_required, networkId);
+ break;
+ case REQUESTING_CONFIGURATION:
+ default:
+ break;
+ }
+ if (message != null) {
+ Toast.makeText(requireActivity(), message, Toast.LENGTH_SHORT).show();
+ }
+
+ // 触发网络信息更新
+ this.onNetworkInfoReply(new NetworkInfoReplyEvent(config));
+ }
+
@Subscribe(threadMode = ThreadMode.MAIN)
public void onNodeID(NodeIDEvent nodeIDEvent) {
setNodeIdText();
@@ -466,6 +497,7 @@ public void onNodeID(NodeIDEvent nodeIDEvent) {
/**
* 节点状态事件回调
+ *
* @param event 事件
*/
@Subscribe(threadMode = ThreadMode.MAIN)
@@ -476,7 +508,7 @@ public void onNodeStatus(NodeStatusEvent event) {
if (status.isOnline()) {
this.nodeStatusView.setText(R.string.status_online);
if (this.nodeIdView != null) {
- this.nodeIdView.setText(Long.toHexString(status.getAddres()));
+ this.nodeIdView.setText(Long.toHexString(status.getAddress()));
}
} else {
setOfflineState();
@@ -488,10 +520,18 @@ public void onNodeStatus(NodeStatusEvent event) {
}
@Subscribe(threadMode = ThreadMode.MAIN)
- public void onNodeDestroyed(NodeDestroyedEvent nodeDestroyedEvent) {
+ public void onNodeDestroyed(NodeDestroyedEvent event) {
setOfflineState();
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onVPNError(VPNErrorEvent event) {
+ var errorMessage = event.getMessage();
+ var message = getString(R.string.toast_vpn_error, errorMessage);
+ Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
+ updateNetworkListAndNotify();
+ }
+
private void setOfflineState() {
TextView textView = this.nodeStatusView;
if (textView != null) {
@@ -516,7 +556,7 @@ private void updateNetworkList() {
if (this.mVNC != null) {
for (Network network : networkList) {
for (VirtualNetworkConfig virtualNetworkConfig : this.mVNC) {
- network.setConnected(network.getNetworkId() == virtualNetworkConfig.networkId());
+ network.setConnected(network.getNetworkId() == virtualNetworkConfig.getNwid());
}
}
}
@@ -538,24 +578,28 @@ public void updateNetworkListAndNotify() {
}
}
- private void startService(long networkId, boolean useDefaultRoute) {
- Intent intent = new Intent(getActivity(), ZeroTierOneService.class);
+ /**
+ * 启动 ZT 服务连接至指定网络
+ *
+ * @param networkId 网络号
+ */
+ private void startService(long networkId) {
+ var intent = new Intent(getActivity(), ZeroTierOneService.class);
intent.putExtra(ZeroTierOneService.ZT1_NETWORK_ID, networkId);
- intent.putExtra(ZeroTierOneService.ZT1_USE_DEFAULT_ROUTE, useDefaultRoute);
doBindService();
- getActivity().startService(intent);
+ requireActivity().startService(intent);
}
- /* access modifiers changed from: private */
- /* access modifiers changed from: public */
+ /**
+ * 停止 ZT 服务
+ */
private void stopService() {
- ZeroTierOneService zeroTierOneService = this.mBoundService;
- if (zeroTierOneService != null) {
- zeroTierOneService.stopZeroTier();
+ if (this.mBoundService != null) {
+ this.mBoundService.stopZeroTier();
}
- Intent intent = new Intent(getActivity(), ZeroTierOneService.class);
+ var intent = new Intent(requireActivity(), ZeroTierOneService.class);
this.eventBus.post(new StopEvent());
- if (!getActivity().stopService(intent)) {
+ if (!requireActivity().stopService(intent)) {
Log.e(TAG, "stopService() returned false");
}
doUnbindService();
@@ -566,12 +610,13 @@ private void stopService() {
* 获得 Moon 入轨配置列表
*/
private List getMoonOrbitList() {
- DaoSession daoSession = ((ZerotierFixApplication) getActivity().getApplication()).getDaoSession();
+ DaoSession daoSession = ((ZerotierFixApplication) requireActivity().getApplication()).getDaoSession();
return daoSession.getMoonOrbitDao().loadAll();
}
/**
* 加入网络后事件回调
+ *
* @param event 事件
*/
@Subscribe
@@ -582,29 +627,67 @@ public void onAfterJoinNetworkEvent(AfterJoinNetworkEvent event) {
this.eventBus.post(new OrbitMoonEvent(moonOrbits));
}
- /* renamed from: com.zerotier.one.ui.NetworkListFragment$2 reason: invalid class name */
- static /* synthetic */ class AnonymousClass2 {
- static final /* synthetic */ int[] $SwitchMap$com$zerotier$sdk$VirtualNetworkStatus;
-
- static {
- $SwitchMap$com$zerotier$sdk$VirtualNetworkStatus = new int[VirtualNetworkStatus.values().length];
- $SwitchMap$com$zerotier$sdk$VirtualNetworkStatus[com.zerotier.sdk.VirtualNetworkStatus.NETWORK_STATUS_OK.ordinal()] = 1;
- $SwitchMap$com$zerotier$sdk$VirtualNetworkStatus[com.zerotier.sdk.VirtualNetworkStatus.NETWORK_STATUS_ACCESS_DENIED.ordinal()] = 2;
- $SwitchMap$com$zerotier$sdk$VirtualNetworkStatus[com.zerotier.sdk.VirtualNetworkStatus.NETWORK_STATUS_CLIENT_TOO_OLD.ordinal()] = 3;
- $SwitchMap$com$zerotier$sdk$VirtualNetworkStatus[com.zerotier.sdk.VirtualNetworkStatus.NETWORK_STATUS_NOT_FOUND.ordinal()] = 4;
- $SwitchMap$com$zerotier$sdk$VirtualNetworkStatus[com.zerotier.sdk.VirtualNetworkStatus.NETWORK_STATUS_PORT_ERROR.ordinal()] = 5;
- $SwitchMap$com$zerotier$sdk$VirtualNetworkStatus[com.zerotier.sdk.VirtualNetworkStatus.NETWORK_STATUS_REQUESTING_CONFIGURATION.ordinal()] = 6;
- }
- }
-
- /* access modifiers changed from: private */
- public static class JoinAfterAuth {
- long networkId;
- boolean useDefaultRoute;
-
- JoinAfterAuth(long j, boolean z) {
- this.networkId = j;
- this.useDefaultRoute = z;
+ @Subscribe(threadMode = ThreadMode.BACKGROUND)
+ public void onNetworkListCheckedChangeEvent(NetworkListCheckedChangeEvent event) {
+ var switchHandle = event.getSwitchHandle();
+ var checked = event.isChecked();
+ var selectedNetwork = event.getSelectedNetwork();
+ var networkDao = ((ZerotierFixApplication) requireActivity().getApplication())
+ .getDaoSession().getNetworkDao();
+ if (checked) {
+ // 启动网络
+ var context = requireContext();
+ boolean useCellularData = PreferenceManager
+ .getDefaultSharedPreferences(context)
+ .getBoolean(Constants.PREF_NETWORK_USE_CELLULAR_DATA, false);
+ var activeNetworkInfo = ((ConnectivityManager) context
+ .getSystemService(Context.CONNECTIVITY_SERVICE))
+ .getActiveNetworkInfo();
+ if (activeNetworkInfo == null || !activeNetworkInfo.isConnectedOrConnecting()) {
+ // 设备无网络
+ requireActivity().runOnUiThread(() -> {
+ Toast.makeText(NetworkListFragment.this.getContext(), R.string.toast_no_network, Toast.LENGTH_SHORT).show();
+ switchHandle.setChecked(false);
+ });
+ } else if (useCellularData || !(activeNetworkInfo.getType() == 0)) {
+ // 可以连接至网络
+ // 先关闭所有现有网络连接
+ for (var network : this.mNetworks) {
+ if (network.getConnected()) {
+ network.setConnected(false);
+ }
+ network.setLastActivated(false);
+ network.update();
+ }
+ this.stopService();
+ // 连接目标网络
+ if (!this.isBound()) {
+ this.sendStartServiceIntent(selectedNetwork.getNetworkId());
+ } else {
+ this.mBoundService.joinNetwork(selectedNetwork.getNetworkId());
+ }
+ Log.d(TAG, "Joining Network: " + selectedNetwork.getNetworkIdStr());
+ selectedNetwork.setConnected(true);
+ selectedNetwork.setLastActivated(true);
+ networkDao.save(selectedNetwork);
+ } else {
+ // 移动数据且未确认
+ requireActivity().runOnUiThread(() -> {
+ Toast.makeText(this.getContext(), R.string.toast_mobile_data, Toast.LENGTH_SHORT).show();
+ switchHandle.setChecked(false);
+ });
+ }
+ } else {
+ // 关闭网络
+ Log.d(TAG, "Leaving Leaving Network: " + selectedNetwork.getNetworkIdStr());
+ if (this.isBound() && this.mBoundService != null) {
+ this.mBoundService.leaveNetwork(selectedNetwork.getNetworkId());
+ this.doUnbindService();
+ }
+ this.stopService();
+ selectedNetwork.setConnected(false);
+ networkDao.save(selectedNetwork);
+ this.mVNC = null;
}
}
@@ -635,10 +718,10 @@ public void onBindViewHolder(final RecyclerViewAdapter.ViewHolder holder, int po
// 设置文本信息
holder.mNetworkId.setText(network.getNetworkIdStr());
String networkName = network.getNetworkName();
- if (networkName != null) {
+ if (networkName != null && !networkName.isEmpty()) {
holder.mNetworkName.setText(networkName);
} else {
- holder.mNetworkName.setText(R.string.network_status_unknown);
+ holder.mNetworkName.setText(R.string.empty_network_name);
}
// 设置点击事件
holder.mView.setOnClickListener(holder::onClick);
@@ -666,20 +749,19 @@ public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View view) {
super(view);
mView = view;
- mNetworkId = (TextView) view.findViewById(R.id.network_list_network_id);
- mNetworkName = (TextView) view.findViewById(R.id.network_list_network_name);
- mSwitch = (SwitchCompat) view.findViewById(R.id.network_start_network_switch);
+ mNetworkId = view.findViewById(R.id.network_list_network_id);
+ mNetworkName = view.findViewById(R.id.network_list_network_name);
+ mSwitch = view.findViewById(R.id.network_start_network_switch);
}
/**
* 单击列表项打开网络详细页面
*/
- public boolean onClick(View view) {
+ public void onClick(View view) {
Log.d(NetworkListFragment.TAG, "ConvertView OnClickListener");
Intent intent = new Intent(NetworkListFragment.this.getActivity(), NetworkDetailActivity.class);
intent.putExtra(NetworkListFragment.NETWORK_ID_MESSAGE, this.mItem.getNetworkId());
NetworkListFragment.this.startActivity(intent);
- return true;
}
/**
@@ -693,7 +775,7 @@ public boolean onLongClick(View view) {
popupMenu.setOnMenuItemClickListener(menuItem -> {
if (menuItem.getItemId() == R.id.menu_item_delete_network) {
// 删除对应网络
- DaoSession daoSession = ((ZerotierFixApplication) NetworkListFragment.this.getActivity().getApplication()).getDaoSession();
+ DaoSession daoSession = ((ZerotierFixApplication) NetworkListFragment.this.requireActivity().getApplication()).getDaoSession();
AssignedAddressDao assignedAddressDao = daoSession.getAssignedAddressDao();
NetworkConfigDao networkConfigDao = daoSession.getNetworkConfigDao();
NetworkDao networkDao = daoSession.getNetworkDao();
@@ -719,7 +801,7 @@ public boolean onLongClick(View view) {
return true;
} else if (menuItem.getItemId() == R.id.menu_item_copy_network_id) {
// 复制网络 ID
- ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipboardManager clipboard = (ClipboardManager) requireContext().getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText(getString(R.string.network_id), this.mItem.getNetworkIdStr());
clipboard.setPrimaryClip(clip);
Toast.makeText(getContext(), R.string.text_copied, Toast.LENGTH_SHORT).show();
@@ -734,58 +816,11 @@ public boolean onLongClick(View view) {
* 点击开启网络开关
*/
public void onSwitchCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- NetworkDao networkDao = ((ZerotierFixApplication) NetworkListFragment.this.getActivity().getApplication()).getDaoSession().getNetworkDao();
- if (isChecked) {
- // 启动网络
- Context context = NetworkListFragment.this.getContext();
- boolean useCellularData = PreferenceManager
- .getDefaultSharedPreferences(context)
- .getBoolean(Constants.PREF_NETWORK_USE_CELLULAR_DATA, false);
- NetworkInfo activeNetworkInfo = ((ConnectivityManager) context
- .getSystemService(Context.CONNECTIVITY_SERVICE))
- .getActiveNetworkInfo();
- if (activeNetworkInfo == null || !activeNetworkInfo.isConnectedOrConnecting()) {
- // 设备无网络
- Toast.makeText(NetworkListFragment.this.getContext(), R.string.toast_no_network, Toast.LENGTH_SHORT).show();
- this.mSwitch.setChecked(false);
- } else if (useCellularData || !(activeNetworkInfo == null || activeNetworkInfo.getType() == 0)) {
- // 可以连接至网络
- // 先关闭所有现有网络连接
- for (Network network : NetworkListFragment.this.mNetworks) {
- if (network.getConnected()) {
- network.setConnected(false);
- }
- network.setLastActivated(false);
- network.update();
- }
- NetworkListFragment.this.stopService();
- // 连接目标网络
- if (!NetworkListFragment.this.isBound()) {
- NetworkListFragment.this.sendStartServiceIntent(this.mItem.getNetworkId(), this.mItem.getUseDefaultRoute());
- } else {
- NetworkListFragment.this.mBoundService.joinNetwork(this.mItem.getNetworkId(), this.mItem.getUseDefaultRoute());
- }
- Log.d(NetworkListFragment.TAG, "Joining Network: " + this.mItem.getNetworkIdStr());
- this.mItem.setConnected(true);
- this.mItem.setLastActivated(true);
- networkDao.save(this.mItem);
- } else {
- // 移动数据且未确认
- Toast.makeText(NetworkListFragment.this.getContext(), R.string.toast_mobile_data, Toast.LENGTH_SHORT).show();
- this.mSwitch.setChecked(false);
- }
- } else {
- // 关闭网络
- Log.d(NetworkListFragment.TAG, "Leaving Leaving Network: " + this.mItem.getNetworkIdStr());
- if (!(!NetworkListFragment.this.isBound() || NetworkListFragment.this.mBoundService == null || this.mItem == null)) {
- NetworkListFragment.this.mBoundService.leaveNetwork(this.mItem.getNetworkId());
- NetworkListFragment.this.doUnbindService();
- }
- NetworkListFragment.this.stopService();
- this.mItem.setConnected(false);
- networkDao.save(this.mItem);
- NetworkListFragment.this.mVNC = null;
- }
+ NetworkListFragment.this.eventBus.post(new NetworkListCheckedChangeEvent(
+ this.mSwitch,
+ isChecked,
+ this.mItem
+ ));
}
}
}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/ui/PeerListFragment.java b/app/src/main/java/net/kaaass/zerotierfix/ui/PeerListFragment.java
index e8109a6..6dd1619 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/ui/PeerListFragment.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/ui/PeerListFragment.java
@@ -22,7 +22,7 @@
import net.kaaass.zerotierfix.R;
import net.kaaass.zerotierfix.events.PeerInfoReplyEvent;
-import net.kaaass.zerotierfix.events.RequestPeerInfoEvent;
+import net.kaaass.zerotierfix.events.PeerInfoRequestEvent;
import net.kaaass.zerotierfix.util.StringUtils;
import org.greenrobot.eventbus.EventBus;
@@ -130,7 +130,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container,
this.swipeRefreshLayout.setOnRefreshListener(this::onRefresh);
// 更新入轨数据
- this.eventBus.post(new RequestPeerInfoEvent());
+ this.eventBus.post(new PeerInfoRequestEvent());
return view;
}
@@ -139,7 +139,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container,
* 刷新列表
*/
public void onRefresh() {
- this.eventBus.post(new RequestPeerInfoEvent());
+ this.eventBus.post(new PeerInfoRequestEvent());
// 超时自动重置刷新状态
new Thread(() -> {
try {
@@ -193,20 +193,20 @@ public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int v
public void onBindViewHolder(final RecyclerViewAdapter.ViewHolder holder, int position) {
Peer peer = mValues.get(position);
holder.mItem = peer;
- holder.mAddress.setText(Long.toHexString(peer.address()));
- holder.mRole.setText(peerRoleToString(peer.role()));
+ holder.mAddress.setText(Long.toHexString(peer.getAddress()));
+ holder.mRole.setText(peerRoleToString(peer.getRole()));
// 客户端版本
String clientVersion = getString(R.string.unknown_version);
- if (peer.versionMajor() > 0) {
+ if (peer.getVersionMajor() > 0) {
clientVersion = StringUtils.peerVersionString(peer);
}
holder.mVersion.setText(clientVersion);
// 延迟
- holder.mLatency.setText(String.format(getString(R.string.peer_lat), peer.latency()));
+ holder.mLatency.setText(String.format(getString(R.string.peer_lat), peer.getLatency()));
// 当前路径
PeerPhysicalPath preferred = null;
- if (peer.paths() != null) {
- for (PeerPhysicalPath path : peer.paths()) {
+ if (peer.getPaths() != null) {
+ for (PeerPhysicalPath path : peer.getPaths()) {
if (path.isPreferred()) {
preferred = path;
break;
@@ -215,7 +215,7 @@ public void onBindViewHolder(final RecyclerViewAdapter.ViewHolder holder, int po
}
String strPreferred = getString(R.string.peer_relay);
if (preferred != null) {
- strPreferred = preferred.address().toString();
+ strPreferred = preferred.getAddress().toString();
}
holder.mPath.setText(strPreferred);
}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/util/Constants.java b/app/src/main/java/net/kaaass/zerotierfix/util/Constants.java
index 5242995..f1d353b 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/util/Constants.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/util/Constants.java
@@ -13,9 +13,17 @@ public class Constants {
public static final String PREF_SET_PLANET_FILE = "set_planet_file";
+ public static final String PREF_NETWORK_DISABLE_IPV6 = "network_disable_ipv6";
+
+ public static final String PREF_GENERAL_START_ZEROTIER_ON_BOOT = "general_start_zerotier_on_boot";
+
public static final String FILE_CUSTOM_PLANET = "planet.custom";
public static final String FILE_TEMP = "temp";
public static final String FILE_PLANET = "planet";
+
+ public static final String CHANNEL_ID = "ZerotierFix";
+
+ public static final String VPN_SESSION_NAME = "ZerotierFix";
}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/util/DatabaseUtils.java b/app/src/main/java/net/kaaass/zerotierfix/util/DatabaseUtils.java
new file mode 100644
index 0000000..0f630ec
--- /dev/null
+++ b/app/src/main/java/net/kaaass/zerotierfix/util/DatabaseUtils.java
@@ -0,0 +1,21 @@
+package net.kaaass.zerotierfix.util;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * 数据库访问工具类
+ */
+public class DatabaseUtils {
+ public static final Lock readLock;
+ public static final ReadWriteLock readWriteLock;
+ public static final Lock writeLock;
+
+ static {
+ var reentrantReadWriteLock = new ReentrantReadWriteLock();
+ readWriteLock = reentrantReadWriteLock;
+ writeLock = reentrantReadWriteLock.writeLock();
+ readLock = reentrantReadWriteLock.readLock();
+ }
+}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/util/InetAddressUtils.java b/app/src/main/java/net/kaaass/zerotierfix/util/InetAddressUtils.java
index f7d5226..cf687a1 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/util/InetAddressUtils.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/util/InetAddressUtils.java
@@ -12,29 +12,45 @@
public class InetAddressUtils {
public static final String TAG = "InetAddressUtils";
- public static byte[] addressToNetmask(InetAddress inetAddress, int i) {
- int length = inetAddress.getAddress().length;
- int i2 = length * 8;
- byte[] bArr = new byte[length];
- for (int i3 = 0; i3 < length; i3++) {
- bArr[i3] = -1;
+ public static final long BROADCAST_MAC_ADDRESS = 0xffffffffffffL;
+
+ /**
+ * 获得地址指定 CIDR 的子网掩码
+ */
+ public static byte[] addressToNetmask(InetAddress address, int cidr) {
+ int length = address.getAddress().length;
+ int subnetLength = length * 8 - cidr;
+ byte[] fullMasked = new byte[length];
+ for (int i = 0; i < length; i++) {
+ fullMasked[i] = -1;
}
if (length == 4) {
- int i4 = i2 - i;
- return ByteBuffer.allocate(4).putInt((ByteBuffer.wrap(bArr).getInt() >> i4) << i4).array();
- }
- int i5 = i2 - i;
- byte[] byteArray = new BigInteger(bArr).shiftRight(i5).shiftLeft(i5).toByteArray();
- if (byteArray.length == length) {
- return byteArray;
- }
- byte[] bArr2 = new byte[length];
- int abs = Math.abs(length - byteArray.length);
- for (int i6 = 0; i6 < abs; i6++) {
- bArr2[i6] = byteArray[0];
+ // IPv4 地址
+ return ByteBuffer.allocate(4)
+ .putInt((ByteBuffer.wrap(fullMasked).getInt() >> subnetLength) << subnetLength)
+ .array();
+ } else {
+ // IPv6 地址
+ if (cidr == 0) {
+ // 若 CIDR 为 0 则返回空子网掩码
+ return new byte[length];
+ }
+ byte[] shiftedAddress = new BigInteger(fullMasked)
+ .shiftRight(subnetLength)
+ .shiftLeft(subnetLength)
+ .toByteArray();
+ if (shiftedAddress.length == length) {
+ return shiftedAddress;
+ }
+ // 高位为 0 时需要在前补 0
+ byte[] netmask = new byte[length];
+ int offset = Math.abs(length - shiftedAddress.length);
+ for (int i = 0; i < offset; i++) {
+ netmask[i] = shiftedAddress[0];
+ }
+ System.arraycopy(shiftedAddress, 0, netmask, offset, shiftedAddress.length);
+ return netmask;
}
- System.arraycopy(byteArray, 0, bArr2, abs, byteArray.length);
- return bArr2;
}
public static InetAddress addressToRoute(InetAddress inetAddress, int i) {
@@ -60,16 +76,19 @@ public static InetAddress addressToRoute(InetAddress inetAddress, int i) {
return addressToRouteNo0Route(inetAddress, i);
}
- public static InetAddress addressToRouteNo0Route(InetAddress inetAddress, int i) {
- byte[] addressToNetmask = addressToNetmask(inetAddress, i);
- byte[] bArr = new byte[addressToNetmask.length];
- for (int i2 = 0; i2 < addressToNetmask.length; i2++) {
- bArr[i2] = (byte) (inetAddress.getAddress()[i2] & addressToNetmask[i2]);
+ /**
+ * 获得地址对应的网络前缀
+ */
+ public static InetAddress addressToRouteNo0Route(InetAddress address, int cidr) {
+ byte[] netmask = addressToNetmask(address, cidr);
+ byte[] rawAddress = new byte[netmask.length];
+ for (int i = 0; i < netmask.length; i++) {
+ rawAddress[i] = (byte) (address.getAddress()[i] & netmask[i]);
}
try {
- return InetAddress.getByAddress(bArr);
+ return InetAddress.getByAddress(rawAddress);
} catch (UnknownHostException unused) {
- Log.e(TAG, "Uknown Host Exception calculating route");
+ Log.e(TAG, "Unknown Host Exception calculating route");
return null;
}
}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/util/NetworkInfoUtils.java b/app/src/main/java/net/kaaass/zerotierfix/util/NetworkInfoUtils.java
new file mode 100644
index 0000000..ba1e56e
--- /dev/null
+++ b/app/src/main/java/net/kaaass/zerotierfix/util/NetworkInfoUtils.java
@@ -0,0 +1,48 @@
+package net.kaaass.zerotierfix.util;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
+import android.os.Build;
+
+/**
+ * 网络连接信息处理工具类
+ */
+public class NetworkInfoUtils {
+ public enum CurrentConnection {
+ CONNECTION_NONE,
+ CONNECTION_MOBILE,
+ CONNECTION_OTHER
+ }
+
+ public static CurrentConnection getNetworkInfoCurrentConnection(Context context) {
+ var connectivityManager = (ConnectivityManager) context
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (connectivityManager == null) {
+ return CurrentConnection.CONNECTION_NONE;
+ }
+ if (Build.VERSION.SDK_INT >= 23) {
+ var networkCapabilities = connectivityManager
+ .getNetworkCapabilities(connectivityManager.getActiveNetwork());
+ if (networkCapabilities == null) {
+ return CurrentConnection.CONNECTION_NONE;
+ }
+ if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ return CurrentConnection.CONNECTION_MOBILE;
+ }
+ return CurrentConnection.CONNECTION_OTHER;
+ } else {
+ var activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
+ if (activeNetworkInfo == null) {
+ return CurrentConnection.CONNECTION_NONE;
+ }
+ if (!activeNetworkInfo.isConnectedOrConnecting()) {
+ return CurrentConnection.CONNECTION_NONE;
+ }
+ if (activeNetworkInfo.getType() == 0) {
+ return CurrentConnection.CONNECTION_MOBILE;
+ }
+ return CurrentConnection.CONNECTION_OTHER;
+ }
+ }
+}
diff --git a/app/src/main/java/net/kaaass/zerotierfix/util/StringUtils.java b/app/src/main/java/net/kaaass/zerotierfix/util/StringUtils.java
index 4cb673c..6f96060 100644
--- a/app/src/main/java/net/kaaass/zerotierfix/util/StringUtils.java
+++ b/app/src/main/java/net/kaaass/zerotierfix/util/StringUtils.java
@@ -22,7 +22,7 @@ public class StringUtils {
*/
public static String toString(Version version) {
return String.format(Locale.ROOT, VERSION_FORMAT,
- version.major, version.minor, version.revision);
+ version.getMajor(), version.getMinor(), version.getRevision());
}
/**
@@ -33,6 +33,26 @@ public static String toString(Version version) {
*/
public static String peerVersionString(Peer peer) {
return String.format(Locale.ROOT, VERSION_FORMAT,
- peer.versionMajor(), peer.versionMinor(), peer.versionRev());
+ peer.getVersionMajor(), peer.getVersionMinor(), peer.getVersionRev());
+ }
+
+ /**
+ * 将 16 进制字符串转换为字符数组
+ *
+ * @param hex 16 进制字符串
+ * @return 字符数组
+ */
+ public static byte[] hexStringToBytes(String hex) {
+ int length = hex.length();
+ if (length % 2 != 0) {
+ throw new RuntimeException("String length must be even");
+ }
+ var result = new byte[length / 2];
+ for (int i = 0; i < length; i += 2) {
+ var highDigit = Character.digit(hex.charAt(i), 16);
+ var lowDigit = Character.digit(hex.charAt(i + 1), 16);
+ result[i / 2] = (byte) ((highDigit << 4) + lowDigit);
+ }
+ return result;
}
}
diff --git a/app/src/main/jniLibs/arm64-v8a/libZeroTierOneJNI.so b/app/src/main/jniLibs/arm64-v8a/libZeroTierOneJNI.so
index cca0043..7f696ce 100644
Binary files a/app/src/main/jniLibs/arm64-v8a/libZeroTierOneJNI.so and b/app/src/main/jniLibs/arm64-v8a/libZeroTierOneJNI.so differ
diff --git a/app/src/main/jniLibs/armeabi-v7a/libZeroTierOneJNI.so b/app/src/main/jniLibs/armeabi-v7a/libZeroTierOneJNI.so
index e5a09ce..294f93f 100644
Binary files a/app/src/main/jniLibs/armeabi-v7a/libZeroTierOneJNI.so and b/app/src/main/jniLibs/armeabi-v7a/libZeroTierOneJNI.so differ
diff --git a/app/src/main/jniLibs/x86/libZeroTierOneJNI.so b/app/src/main/jniLibs/x86/libZeroTierOneJNI.so
index 7f3054b..fb7fbab 100644
Binary files a/app/src/main/jniLibs/x86/libZeroTierOneJNI.so and b/app/src/main/jniLibs/x86/libZeroTierOneJNI.so differ
diff --git a/app/src/main/jniLibs/x86_64/libZeroTierOneJNI.so b/app/src/main/jniLibs/x86_64/libZeroTierOneJNI.so
index 1aa122a..ed3f568 100644
Binary files a/app/src/main/jniLibs/x86_64/libZeroTierOneJNI.so and b/app/src/main/jniLibs/x86_64/libZeroTierOneJNI.so differ
diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml
index 7b77381..2bae6f4 100644
--- a/app/src/main/res/values-zh/strings.xml
+++ b/app/src/main/res/values-zh/strings.xml
@@ -37,6 +37,7 @@
端口错误
正在请求配置
未知
+ 需要授权
网络类型
网络类型:
私有
@@ -61,7 +62,6 @@
已连接
没有网络连接,无法启动 ZeroTier
设备正在使用移动网络,必须开启“允许移动网络下使用”选项以启动 ZeroTier
- 无权使用该网络
结点列表
入轨
启用
@@ -127,4 +127,17 @@
Moon 文件格式错误
Moon 结点的 Zerotier 地址。即 Moon 文件的文件名(不包含扩展名)。
已删除缓存的 Moon 文件。需手动重连使配置生效。
+ ZeroTier Fix
+ 连接状态
+ 已连接
+ 已连接至网络: %1$s
+ VPN 服务还未准备好或已经失效。
+ 成功连接至网络 %1$s
+ 无法连接至网络 %1$s: 访问被拒绝
+ 无法连接至网络 %1$s: 网络不存在
+ 无法连接至网络 %1$s: 端口错误
+ 无法连接至网络 %1$s: 客户端版本过低
+ 无法连接至网络 %1$s: 需要授权
+ VPN 服务发生错误!%1$s
+ 未知
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index b62fcd4..6cc5c01 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -22,4 +22,6 @@
#555555
#FAC073
+
+ #fac073
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 86c22ba..3adf24b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -38,6 +38,7 @@
Port Error
Requesting Configuration
Unknown
+ Authentication Required
Type
Type:
Private
@@ -62,7 +63,6 @@
ONLINE
No Network Connectivity. ZeroTier cannot start.
Currently using mobile data. Enable \"Use Cellular Data\" in order to start ZeroTier.
- Not Authorized for network
Peers
Orbit
Enabled
@@ -129,4 +129,17 @@
Wrong moon file format
Zerotier address of Moon node. Also filename of its moon file.
Cached moon file deleted. Reconnect for this setting to take effect.
+ ZeroTier Fix
+ Connection Status
+ Connected
+ Connected to: %1$s
+ VPN application is not prepared or is revoked.
+ Successfully connected to network %1$s
+ Cannot connect to network %1$s: Access denied
+ Cannot connect to network %1$s: Network does not exist
+ Cannot connect to network %1$s: Port error
+ Cannot connect to network %1$s: Client version too low
+ Cannot connect to network %1$s: Authorization required
+ A VPN service error has occurred! %1$s
+ Unknown