diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index ae8afef..1976392 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -5,6 +5,15 @@
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/gradle.properties b/android/gradle.properties
index 94adc3a..a673820 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,3 +1,4 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
+android.enableR8=true
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f6b961f
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..5e81935
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Mar 22 01:39:44 CET 2021
+distributionBase=GRADLE_USER_HOME
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..cccdd3d
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 075b902..26552e7 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -492,4 +492,4 @@
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
-}
\ No newline at end of file
+}
diff --git a/lib/main.dart b/lib/main.dart
index 11655b6..43fea2b 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
+import 'package:lokinet_lib/lokinet_lib.dart';
void main() {
runApp(MyApp());
@@ -52,13 +53,16 @@ class MyHomePage extends StatefulWidget {
class _MyHomePageState extends State {
int _counter = 0;
- void _incrementCounter() {
+ Future _incrementCounter() async {
+ final result = await LokinetLib.prepareConnection();
+ print(result);
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
+
_counter++;
});
}
@@ -104,6 +108,19 @@ class _MyHomePageState extends State {
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
+ TextButton(
+ child: Text('Bootstrap'),
+ onPressed: () async {
+ await LokinetLib.bootstrapLokinet();
+ },
+ ),
+ Divider(),
+ TextButton(
+ child: Text('Connect'),
+ onPressed: () {
+ LokinetLib.connectToLokinet();
+ },
+ )
],
),
),
diff --git a/local.properties b/local.properties
new file mode 100644
index 0000000..699498e
--- /dev/null
+++ b/local.properties
@@ -0,0 +1,8 @@
+## This file must *NOT* be checked into Version Control Systems,
+# as it contains information specific to your local configuration.
+#
+# Location of the SDK. This is only used by Gradle.
+# For customization when using a Version Control System, please read the
+# header note.
+#Mon Mar 22 01:39:44 CET 2021
+sdk.dir=C\:\\Users\\konst\\AppData\\Local\\Android\\Sdk
diff --git a/lokinet_lib/.gitignore b/lokinet_lib/.gitignore
new file mode 100644
index 0000000..e9dc58d
--- /dev/null
+++ b/lokinet_lib/.gitignore
@@ -0,0 +1,7 @@
+.DS_Store
+.dart_tool/
+
+.packages
+.pub/
+
+build/
diff --git a/lokinet_lib/.metadata b/lokinet_lib/.metadata
new file mode 100644
index 0000000..70a9f94
--- /dev/null
+++ b/lokinet_lib/.metadata
@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: 9b2d32b605630f28625709ebd9d78ab3016b2bf6
+ channel: stable
+
+project_type: plugin
diff --git a/lokinet_lib/CHANGELOG.md b/lokinet_lib/CHANGELOG.md
new file mode 100644
index 0000000..41cc7d8
--- /dev/null
+++ b/lokinet_lib/CHANGELOG.md
@@ -0,0 +1,3 @@
+## 0.0.1
+
+* TODO: Describe initial release.
diff --git a/lokinet_lib/LICENSE b/lokinet_lib/LICENSE
new file mode 100644
index 0000000..ba75c69
--- /dev/null
+++ b/lokinet_lib/LICENSE
@@ -0,0 +1 @@
+TODO: Add your license here.
diff --git a/lokinet_lib/README.md b/lokinet_lib/README.md
new file mode 100644
index 0000000..d19df07
--- /dev/null
+++ b/lokinet_lib/README.md
@@ -0,0 +1,15 @@
+# lokinet_lib
+
+A new Flutter project.
+
+## Getting Started
+
+This project is a starting point for a Flutter
+[plug-in package](https://flutter.dev/developing-packages/),
+a specialized package that includes platform-specific implementation code for
+Android and/or iOS.
+
+For help getting started with Flutter, view our
+[online documentation](https://flutter.dev/docs), which offers tutorials,
+samples, guidance on mobile development, and a full API reference.
+
diff --git a/lokinet_lib/android/.gitignore b/lokinet_lib/android/.gitignore
new file mode 100644
index 0000000..c6cbe56
--- /dev/null
+++ b/lokinet_lib/android/.gitignore
@@ -0,0 +1,8 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
diff --git a/lokinet_lib/android/build.gradle b/lokinet_lib/android/build.gradle
new file mode 100644
index 0000000..3de7b4e
--- /dev/null
+++ b/lokinet_lib/android/build.gradle
@@ -0,0 +1,49 @@
+group "io.oxen.lokinet_lib"
+version "1.0-SNAPSHOT"
+
+buildscript {
+ ext.kotlin_version = "1.3.50"
+ repositories {
+ google()
+ jcenter()
+ }
+
+ dependencies {
+ classpath "com.android.tools.build:gradle:3.5.0"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+rootProject.allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+apply plugin: "com.android.library"
+apply plugin: "kotlin-android"
+
+android {
+ compileSdkVersion 29
+
+ sourceSets {
+ main.java.srcDirs += "src/main/java"
+ main.java.srcDirs += "src/main/kotlin"
+ main.jniLibs.srcDirs += "src/main/jniLibs"
+ }
+ defaultConfig {
+ minSdkVersion 16
+ }
+ lintOptions {
+ disable "InvalidPackage"
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+}
diff --git a/lokinet_lib/android/gradle.properties b/lokinet_lib/android/gradle.properties
new file mode 100644
index 0000000..94adc3a
--- /dev/null
+++ b/lokinet_lib/android/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx1536M
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/lokinet_lib/android/gradle/wrapper/gradle-wrapper.properties b/lokinet_lib/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..01a286e
--- /dev/null
+++ b/lokinet_lib/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
diff --git a/lokinet_lib/android/settings.gradle b/lokinet_lib/android/settings.gradle
new file mode 100644
index 0000000..763b253
--- /dev/null
+++ b/lokinet_lib/android/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'lokinet_lib'
diff --git a/lokinet_lib/android/src/main/AndroidManifest.xml b/lokinet_lib/android/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..131c8d2
--- /dev/null
+++ b/lokinet_lib/android/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/lokinet_lib/android/src/main/java/network/loki/lokinet/LokinetConfig.java b/lokinet_lib/android/src/main/java/network/loki/lokinet/LokinetConfig.java
new file mode 100644
index 0000000..209ddfb
--- /dev/null
+++ b/lokinet_lib/android/src/main/java/network/loki/lokinet/LokinetConfig.java
@@ -0,0 +1,39 @@
+package network.loki.lokinet;
+
+import java.nio.ByteBuffer;
+
+public class LokinetConfig
+{
+ static {
+ System.loadLibrary("lokinet-android");
+ }
+
+ private static native ByteBuffer Obtain(String dataDir);
+ private static native void Free(ByteBuffer buf);
+
+ /*** load config file from disk */
+ public native boolean Load();
+ /*** save chages to disk */
+ public native boolean Save();
+
+
+ /** override default config value before loading from config file */
+ public native void AddDefaultValue(String section, String key, String value);
+
+ private final ByteBuffer impl;
+
+ public LokinetConfig(String dataDir)
+ {
+ impl = Obtain(dataDir);
+ if(impl == null)
+ throw new RuntimeException("cannot obtain config from "+dataDir);
+ }
+
+ public void finalize()
+ {
+ if (impl != null)
+ {
+ Free(impl);
+ }
+ }
+}
diff --git a/lokinet_lib/android/src/main/java/network/loki/lokinet/LokinetDaemon.java b/lokinet_lib/android/src/main/java/network/loki/lokinet/LokinetDaemon.java
new file mode 100644
index 0000000..192cfb3
--- /dev/null
+++ b/lokinet_lib/android/src/main/java/network/loki/lokinet/LokinetDaemon.java
@@ -0,0 +1,166 @@
+package network.loki.lokinet;
+
+import java.lang.Thread;
+import java.nio.ByteBuffer;
+
+import android.net.VpnService;
+import android.util.Log;
+import android.content.Intent;
+import android.os.ParcelFileDescriptor;
+
+public class LokinetDaemon extends VpnService
+{
+ static {
+ System.loadLibrary("lokinet-android");
+ }
+
+ private static native ByteBuffer Obtain();
+ private static native void Free(ByteBuffer buf);
+ public native boolean Configure(LokinetConfig config);
+ public native int Mainloop();
+ public native boolean IsRunning();
+ public native boolean Stop();
+ public native void InjectVPNFD();
+ public native int GetUDPSocket();
+
+ private static native String DetectFreeRange();
+
+ public static final String LOG_TAG = "LokinetDaemon";
+
+ ByteBuffer impl = null;
+ ParcelFileDescriptor iface;
+ int m_FD = -1;
+ int m_UDPSocket = -1;
+
+ @Override
+ public void onCreate()
+ {
+ super.onCreate();
+ }
+
+ @Override
+ public void onDestroy()
+ {
+ super.onDestroy();
+
+ if (IsRunning())
+ {
+ Stop();
+ }
+ if (impl != null)
+ {
+ Free(impl);
+ impl = null;
+ }
+ }
+
+ public int onStartCommand(Intent intent, int flags, int startID)
+ {
+ Log.d(LOG_TAG, "onStartCommand()");
+
+ if (!IsRunning())
+ {
+ if (impl != null)
+ {
+ Free(impl);
+ impl = null;
+ }
+ impl = Obtain();
+ if (impl == null)
+ {
+ Log.e(LOG_TAG, "got nullptr when creating llarp::Context in jni");
+ return START_NOT_STICKY;
+ }
+
+ String dataDir = getFilesDir().toString();
+ LokinetConfig config;
+ try
+ {
+ config = new LokinetConfig(dataDir);
+ }
+ catch(RuntimeException ex)
+ {
+ Log.e(LOG_TAG, ex.toString());
+ return START_NOT_STICKY;
+ }
+
+ // FIXME: make these configurable
+ String exitNode = "exit.loki";
+ String upstreamDNS = "1.1.1.1";
+ String ourRange = DetectFreeRange();
+
+ if(ourRange.isEmpty())
+ {
+ Log.e(LOG_TAG, "cannot detect free range");
+ return START_NOT_STICKY;
+ }
+
+
+ // set up config values
+ config.AddDefaultValue("network", "exit-node", exitNode);
+ config.AddDefaultValue("network", "ifaddr", ourRange);
+ config.AddDefaultValue("dns", "upstream", upstreamDNS);
+
+
+ if (!config.Load())
+ {
+ Log.e(LOG_TAG, "failed to load (or create) config file at: " + dataDir + "/loki.network.loki.lokinet.ini");
+ return START_NOT_STICKY;
+ }
+
+ VpnService.Builder builder = new VpnService.Builder();
+
+ builder.setMtu(1500);
+
+ String[] parts = ourRange.split("/");
+ String ourIP = parts[0];
+ int ourMask = Integer.parseInt(parts[1]);
+
+ builder.addAddress(ourIP, ourMask);
+ builder.addRoute("0.0.0.0", 0);
+ builder.addDnsServer(upstreamDNS);
+ builder.setSession("Lokinet");
+ builder.setConfigureIntent(null);
+
+ iface = builder.establish();
+ if (iface == null)
+ {
+ Log.e(LOG_TAG, "VPN Interface from builder.establish() came back null");
+ return START_NOT_STICKY;
+ }
+
+ m_FD = iface.detachFd();
+
+ InjectVPNFD();
+
+ if (!Configure(config))
+ {
+ //TODO: close vpn FD if this fails, either on native side, or here if possible
+ Log.e(LOG_TAG, "failed to configure daemon");
+ return START_NOT_STICKY;
+ }
+
+ m_UDPSocket = GetUDPSocket();
+
+ if (m_UDPSocket <= 0)
+ {
+ Log.e(LOG_TAG, "failed to get proper UDP handle from daemon, aborting.");
+ return START_NOT_STICKY;
+ }
+
+ protect(m_UDPSocket);
+
+ new Thread(() -> {
+ Mainloop();
+ }).start();
+
+ Log.d(LOG_TAG, "started successfully!");
+ }
+ else
+ {
+ Log.d(LOG_TAG, "already running");
+ }
+
+ return START_STICKY;
+ }
+}
diff --git a/lokinet_lib/android/src/main/kotlin/io/oxen/lokinet_lib/LokinetLibPlugin.kt b/lokinet_lib/android/src/main/kotlin/io/oxen/lokinet_lib/LokinetLibPlugin.kt
new file mode 100644
index 0000000..7bc95c3
--- /dev/null
+++ b/lokinet_lib/android/src/main/kotlin/io/oxen/lokinet_lib/LokinetLibPlugin.kt
@@ -0,0 +1,96 @@
+package io.oxen.lokinet_lib
+
+import android.app.Activity.RESULT_OK
+import android.content.Intent
+import android.net.VpnService
+import androidx.annotation.NonNull
+import io.flutter.embedding.engine.plugins.FlutterPlugin
+import io.flutter.embedding.engine.plugins.activity.ActivityAware
+import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
+import io.flutter.plugin.common.MethodCall
+import io.flutter.plugin.common.MethodChannel
+import io.flutter.plugin.common.MethodChannel.MethodCallHandler
+import io.flutter.plugin.common.PluginRegistry
+import network.loki.lokinet.LokinetDaemon
+
+/** LokinetLibPlugin */
+class LokinetLibPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
+ private lateinit var activityBinding: ActivityPluginBinding
+
+ /// The MethodChannel that will the communication between Flutter and native Android
+ ///
+ /// This local reference serves to register the plugin with the Flutter Engine and unregister it
+ /// when the Flutter Engine is detached from the Activity
+ private lateinit var channel: MethodChannel
+
+ override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
+ System.loadLibrary("lokinet-android")
+
+ channel = MethodChannel(flutterPluginBinding.binaryMessenger, "lokinet_lib")
+ channel.setMethodCallHandler(this)
+ }
+
+ override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
+ channel.setMethodCallHandler(null)
+ }
+
+ override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: MethodChannel.Result) {
+
+ when (call.method) {
+ "prepare" -> {
+ val intent = VpnService.prepare(activityBinding.activity.applicationContext)
+ if (intent != null) {
+ var listener: PluginRegistry.ActivityResultListener? = null
+ listener = PluginRegistry.ActivityResultListener { req, res, _ ->
+ if (req == 0 && res == RESULT_OK) {
+ result.success(true)
+ } else {
+ result.success(false)
+ }
+ listener?.let { activityBinding.removeActivityResultListener(it) };
+ true
+ }
+ activityBinding.addActivityResultListener(listener)
+ activityBinding.activity.startActivityForResult(intent, 0)
+ } else {
+ // If intent is null, already prepared
+ result.success(true)
+ }
+ }
+ "prepared" -> {
+ val intent = VpnService.prepare(activityBinding.activity.applicationContext)
+ result.success(intent == null)
+ }
+ "connect" -> {
+ val intent = VpnService.prepare(activityBinding.activity.applicationContext)
+ if (intent != null) {
+ // Not prepared yet
+ result.success(false)
+ return
+ }
+
+ activityBinding.activity.applicationContext.startService(
+ Intent(
+ activityBinding.activity.applicationContext,
+ LokinetDaemon::class.java
+ )
+ )
+
+ result.success(true);
+ }
+ else -> result.notImplemented()
+ }
+ }
+
+ override fun onAttachedToActivity(binding: ActivityPluginBinding) {
+ activityBinding = binding
+ }
+
+ override fun onDetachedFromActivity() {}
+
+ override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
+ activityBinding = binding
+ }
+
+ override fun onDetachedFromActivityForConfigChanges() {}
+}
diff --git a/lokinet_lib/ios/.gitignore b/lokinet_lib/ios/.gitignore
new file mode 100644
index 0000000..aa479fd
--- /dev/null
+++ b/lokinet_lib/ios/.gitignore
@@ -0,0 +1,37 @@
+.idea/
+.vagrant/
+.sconsign.dblite
+.svn/
+
+.DS_Store
+*.swp
+profile
+
+DerivedData/
+build/
+GeneratedPluginRegistrant.h
+GeneratedPluginRegistrant.m
+
+.generated/
+
+*.pbxuser
+*.mode1v3
+*.mode2v3
+*.perspectivev3
+
+!default.pbxuser
+!default.mode1v3
+!default.mode2v3
+!default.perspectivev3
+
+xcuserdata
+
+*.moved-aside
+
+*.pyc
+*sync/
+Icon?
+.tags*
+
+/Flutter/Generated.xcconfig
+/Flutter/flutter_export_environment.sh
\ No newline at end of file
diff --git a/lokinet_lib/ios/Assets/.gitkeep b/lokinet_lib/ios/Assets/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/lokinet_lib/ios/Classes/LokinetLibPlugin.h b/lokinet_lib/ios/Classes/LokinetLibPlugin.h
new file mode 100644
index 0000000..5d75c5b
--- /dev/null
+++ b/lokinet_lib/ios/Classes/LokinetLibPlugin.h
@@ -0,0 +1,4 @@
+#import
+
+@interface LokinetLibPlugin : NSObject
+@end
diff --git a/lokinet_lib/ios/Classes/LokinetLibPlugin.m b/lokinet_lib/ios/Classes/LokinetLibPlugin.m
new file mode 100644
index 0000000..ae8daab
--- /dev/null
+++ b/lokinet_lib/ios/Classes/LokinetLibPlugin.m
@@ -0,0 +1,15 @@
+#import "LokinetLibPlugin.h"
+#if __has_include()
+#import
+#else
+// Support project import fallback if the generated compatibility header
+// is not copied when this plugin is created as a library.
+// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816
+#import "lokinet_lib-Swift.h"
+#endif
+
+@implementation LokinetLibPlugin
++ (void)registerWithRegistrar:(NSObject*)registrar {
+ [SwiftLokinetLibPlugin registerWithRegistrar:registrar];
+}
+@end
diff --git a/lokinet_lib/ios/Classes/SwiftLokinetLibPlugin.swift b/lokinet_lib/ios/Classes/SwiftLokinetLibPlugin.swift
new file mode 100644
index 0000000..a3a9c66
--- /dev/null
+++ b/lokinet_lib/ios/Classes/SwiftLokinetLibPlugin.swift
@@ -0,0 +1,14 @@
+import Flutter
+import UIKit
+
+public class SwiftLokinetLibPlugin: NSObject, FlutterPlugin {
+ public static func register(with registrar: FlutterPluginRegistrar) {
+ let channel = FlutterMethodChannel(name: "lokinet_lib", binaryMessenger: registrar.messenger())
+ let instance = SwiftLokinetLibPlugin()
+ registrar.addMethodCallDelegate(instance, channel: channel)
+ }
+
+ public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+ result("iOS " + UIDevice.current.systemVersion)
+ }
+}
diff --git a/lokinet_lib/ios/lokinet_lib.podspec b/lokinet_lib/ios/lokinet_lib.podspec
new file mode 100644
index 0000000..6b3009f
--- /dev/null
+++ b/lokinet_lib/ios/lokinet_lib.podspec
@@ -0,0 +1,23 @@
+#
+# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
+# Run `pod lib lint lokinet_lib.podspec' to validate before publishing.
+#
+Pod::Spec.new do |s|
+ s.name = 'lokinet_lib'
+ s.version = '0.0.1'
+ s.summary = 'A new Flutter project.'
+ s.description = <<-DESC
+A new Flutter project.
+ DESC
+ s.homepage = 'http://example.com'
+ s.license = { :file => '../LICENSE' }
+ s.author = { 'Your Company' => 'email@example.com' }
+ s.source = { :path => '.' }
+ s.source_files = 'Classes/**/*'
+ s.dependency 'Flutter'
+ s.platform = :ios, '8.0'
+
+ # Flutter.framework does not contain a i386 slice.
+ s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
+ s.swift_version = '5.0'
+end
diff --git a/lokinet_lib/lib/lokinet_lib.dart b/lokinet_lib/lib/lokinet_lib.dart
new file mode 100644
index 0000000..aa32719
--- /dev/null
+++ b/lokinet_lib/lib/lokinet_lib.dart
@@ -0,0 +1,34 @@
+import 'dart:async';
+import 'dart:io';
+
+import 'package:flutter/services.dart';
+import 'package:path_provider/path_provider.dart';
+
+class LokinetLib {
+ static const MethodChannel _channel =
+ const MethodChannel('lokinet_lib');
+
+ static Future bootstrapLokinet() async {
+ final request = await HttpClient().getUrl(Uri.parse('https://seed.lokinet.org/lokinet.signed'));
+ final response = await request.close();
+ var path = await getApplicationDocumentsDirectory();
+ await response.pipe(File('${path.parent.path}/files/bootstrap.signed').openWrite());
+ print('${path.parent.path}/files/lokinet.signed');
+ print(Directory('${path.parent.path}/files/').listSync().toString());
+ }
+
+ static Future prepareConnection() async {
+ final bool prepare = await _channel.invokeMethod('prepare');
+ return prepare;
+ }
+
+ static Future get isPrepare async {
+ final bool prepared = await _channel.invokeMethod('prepared');
+ return prepared;
+ }
+
+ static Future connectToLokinet() async {
+ final bool connect = await _channel.invokeMethod('connect');
+ return connect;
+ }
+}
diff --git a/lokinet_lib/pubspec.lock b/lokinet_lib/pubspec.lock
new file mode 100644
index 0000000..b5f08ae
--- /dev/null
+++ b/lokinet_lib/pubspec.lock
@@ -0,0 +1,238 @@
+# Generated by pub
+# See https://dart.dev/tools/pub/glossary#lockfile
+packages:
+ async:
+ dependency: transitive
+ description:
+ name: async
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.5.0-nullsafety.1"
+ boolean_selector:
+ dependency: transitive
+ description:
+ name: boolean_selector
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.1.0-nullsafety.1"
+ characters:
+ dependency: transitive
+ description:
+ name: characters
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.1.0-nullsafety.3"
+ charcode:
+ dependency: transitive
+ description:
+ name: charcode
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.2.0-nullsafety.1"
+ clock:
+ dependency: transitive
+ description:
+ name: clock
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.1.0-nullsafety.1"
+ collection:
+ dependency: transitive
+ description:
+ name: collection
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.15.0-nullsafety.3"
+ fake_async:
+ dependency: transitive
+ description:
+ name: fake_async
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.2.0-nullsafety.1"
+ ffi:
+ dependency: transitive
+ description:
+ name: ffi
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.1.3"
+ file:
+ dependency: transitive
+ description:
+ name: file
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "5.2.1"
+ flutter:
+ dependency: "direct main"
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ flutter_test:
+ dependency: "direct dev"
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ intl:
+ dependency: transitive
+ description:
+ name: intl
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.16.1"
+ matcher:
+ dependency: transitive
+ description:
+ name: matcher
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.12.10-nullsafety.1"
+ meta:
+ dependency: transitive
+ description:
+ name: meta
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.3.0-nullsafety.3"
+ path:
+ dependency: transitive
+ description:
+ name: path
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.8.0-nullsafety.1"
+ path_provider:
+ dependency: "direct main"
+ description:
+ name: path_provider
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.6.28"
+ path_provider_linux:
+ dependency: transitive
+ description:
+ name: path_provider_linux
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.0.1+2"
+ path_provider_macos:
+ dependency: transitive
+ description:
+ name: path_provider_macos
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.0.4+8"
+ path_provider_platform_interface:
+ dependency: transitive
+ description:
+ name: path_provider_platform_interface
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.4"
+ path_provider_windows:
+ dependency: transitive
+ description:
+ name: path_provider_windows
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.0.4+3"
+ platform:
+ dependency: transitive
+ description:
+ name: platform
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.2.1"
+ plugin_platform_interface:
+ dependency: transitive
+ description:
+ name: plugin_platform_interface
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.3"
+ process:
+ dependency: transitive
+ description:
+ name: process
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "3.0.13"
+ sky_engine:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.99"
+ source_span:
+ dependency: transitive
+ description:
+ name: source_span
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.8.0-nullsafety.2"
+ stack_trace:
+ dependency: transitive
+ description:
+ name: stack_trace
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.10.0-nullsafety.1"
+ stream_channel:
+ dependency: transitive
+ description:
+ name: stream_channel
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.1.0-nullsafety.1"
+ string_scanner:
+ dependency: transitive
+ description:
+ name: string_scanner
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.1.0-nullsafety.1"
+ term_glyph:
+ dependency: transitive
+ description:
+ name: term_glyph
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.2.0-nullsafety.1"
+ test_api:
+ dependency: transitive
+ description:
+ name: test_api
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.2.19-nullsafety.2"
+ typed_data:
+ dependency: transitive
+ description:
+ name: typed_data
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.3.0-nullsafety.3"
+ vector_math:
+ dependency: transitive
+ description:
+ name: vector_math
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.1.0-nullsafety.3"
+ win32:
+ dependency: transitive
+ description:
+ name: win32
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.7.4+1"
+ xdg_directories:
+ dependency: transitive
+ description:
+ name: xdg_directories
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.1.2"
+sdks:
+ dart: ">=2.10.0-110 <2.11.0"
+ flutter: ">=1.20.0 <2.0.0"
diff --git a/lokinet_lib/pubspec.yaml b/lokinet_lib/pubspec.yaml
new file mode 100644
index 0000000..5dfdf91
--- /dev/null
+++ b/lokinet_lib/pubspec.yaml
@@ -0,0 +1,66 @@
+name: lokinet_lib
+description: A Lib for Lokinet
+version: 0.0.1
+author:
+homepage:
+
+environment:
+ sdk: ">=2.7.0 <3.0.0"
+ flutter: ">=1.20.0"
+
+dependencies:
+ flutter:
+ sdk: flutter
+ path_provider: ^1.6.28
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+# The following section is specific to Flutter.
+flutter:
+ # This section identifies this Flutter project as a plugin project.
+ # The 'pluginClass' and Android 'package' identifiers should not ordinarily
+ # be modified. They are used by the tooling to maintain consistency when
+ # adding or updating assets for this project.
+ plugin:
+ platforms:
+ android:
+ package: io.oxen.lokinet_lib
+ pluginClass: LokinetLibPlugin
+# ios:
+# pluginClass: LokinetLibPlugin
+
+ # To add assets to your plugin package, add an assets section, like this:
+ # assets:
+ # - images/a_dot_burr.jpeg
+ # - images/a_dot_ham.jpeg
+ #
+ # For details regarding assets in packages, see
+ # https://flutter.dev/assets-and-images/#from-packages
+ #
+ # An image asset can refer to one or more resolution-specific "variants", see
+ # https://flutter.dev/assets-and-images/#resolution-aware.
+
+ # To add custom fonts to your plugin package, add a fonts section here,
+ # in this "flutter" section. Each entry in this list should have a
+ # "family" key with the font family name, and a "fonts" key with a
+ # list giving the asset and other descriptors for the font. For
+ # example:
+ # fonts:
+ # - family: Schyler
+ # fonts:
+ # - asset: fonts/Schyler-Regular.ttf
+ # - asset: fonts/Schyler-Italic.ttf
+ # style: italic
+ # - family: Trajan Pro
+ # fonts:
+ # - asset: fonts/TrajanPro.ttf
+ # - asset: fonts/TrajanPro_Bold.ttf
+ # weight: 700
+ #
+ # For details regarding fonts in packages, see
+ # https://flutter.dev/custom-fonts/#from-packages
diff --git a/pubspec.lock b/pubspec.lock
index f4f6866..dc2b599 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -85,6 +85,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0-nullsafety.1"
+ ffi:
+ dependency: transitive
+ description:
+ name: ffi
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.1.3"
+ file:
+ dependency: transitive
+ description:
+ name: file
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "5.2.1"
flutter:
dependency: "direct main"
description: flutter
@@ -109,6 +123,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.19"
+ intl:
+ dependency: transitive
+ description:
+ name: intl
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.16.1"
+ lokinet_lib:
+ dependency: "direct main"
+ description:
+ path: lokinet_lib
+ relative: true
+ source: path
+ version: "0.0.1"
matcher:
dependency: transitive
description:
@@ -130,6 +158,41 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0-nullsafety.1"
+ path_provider:
+ dependency: transitive
+ description:
+ name: path_provider
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.6.28"
+ path_provider_linux:
+ dependency: transitive
+ description:
+ name: path_provider_linux
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.0.1+2"
+ path_provider_macos:
+ dependency: transitive
+ description:
+ name: path_provider_macos
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.0.4+8"
+ path_provider_platform_interface:
+ dependency: transitive
+ description:
+ name: path_provider_platform_interface
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.4"
+ path_provider_windows:
+ dependency: transitive
+ description:
+ name: path_provider_windows
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.0.4+3"
petitparser:
dependency: transitive
description:
@@ -137,6 +200,27 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
+ platform:
+ dependency: transitive
+ description:
+ name: platform
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.2.1"
+ plugin_platform_interface:
+ dependency: transitive
+ description:
+ name: plugin_platform_interface
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.3"
+ process:
+ dependency: transitive
+ description:
+ name: process
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "3.0.13"
sky_engine:
dependency: transitive
description: flutter
@@ -198,6 +282,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0-nullsafety.3"
+ win32:
+ dependency: transitive
+ description:
+ name: win32
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.7.4+1"
+ xdg_directories:
+ dependency: transitive
+ description:
+ name: xdg_directories
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.1.2"
xml:
dependency: transitive
description:
@@ -214,3 +312,4 @@ packages:
version: "2.2.1"
sdks:
dart: ">=2.10.0-110 <2.11.0"
+ flutter: ">=1.20.0 <2.0.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index b4b6bb7..4c7dbfc 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -23,7 +23,8 @@ environment:
dependencies:
flutter:
sdk: flutter
-
+ lokinet_lib:
+ path: ./lokinet_lib
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.