diff --git a/.drone.jsonnet b/.drone.jsonnet
index 5657a8aa2..6a8099167 100644
--- a/.drone.jsonnet
+++ b/.drone.jsonnet
@@ -62,8 +62,30 @@ local debian_pipeline(name, image,
}
],
};
-
-// windows cross compile on alpine linux
+local apk_builder(name, image, extra_cmds=[], allow_fail=true) = {
+ kind: 'pipeline',
+ type: 'docker',
+ name: name,
+ platform: {arch: "amd64"},
+ trigger: { branch: { exclude: ['debian/*', 'ubuntu/*'] } },
+ steps: [
+ submodules,
+ {
+ name: 'build',
+ image: image,
+ [if allow_fail then "failure"]: "ignore",
+ environment: { SSH_KEY: { from_secret: "SSH_KEY" }, ANDROID: "android" },
+ commands: [
+ "cd android",
+ "rm -f local.properties",
+ "echo 'sdk.dir=/usr/lib/android-sdk' >> local.properties",
+ "echo 'ndk.dir=/usr/lib/android-ndk' >> local.properties",
+ "GRADLE_USER_HOME=/cache/gradle gradle --no-daemon assembleDebug",
+ ] + extra_cmds
+ }
+ ]
+};
+// windows cross compile on debian
local windows_cross_pipeline(name, image,
arch='amd64',
build_type='Release',
@@ -156,6 +178,7 @@ local deb_builder(image, distro, distro_branch, arch='amd64', loki_repo=true) =
]
};
+
// Macos build
local mac_builder(name, build_type='Release', werror=true, cmake_extra='', extra_cmds=[], allow_fail=false) = {
kind: 'pipeline',
@@ -224,6 +247,8 @@ local mac_builder(name, build_type='Release', werror=true, cmake_extra='', extra
'../contrib/ci/drone-check-static-libs.sh',
'UPLOAD_OS=linux-armhf ../contrib/ci/drone-static-upload.sh'
]),
+ // android apk builder
+ apk_builder("android apk", "registry.oxen.rocks/lokinet-ci-android", extra_cmds=['UPLOAD_OS=anrdoid ../contrib/ci/drone-static-upload.sh']),
// Windows builds (x64)
windows_cross_pipeline("Windows (amd64)", "debian:testing",
diff --git a/.gitignore b/.gitignore
index b688b6ad3..2a1d2239a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,9 +40,6 @@ vsproject/
.vs
daemon.ini
-lokinet-win32.exe
-lokinet
-lokinet.exe
.gradle/
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index 33d5bc1e9..a60e01730 100755
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -33,7 +33,7 @@
-
diff --git a/android/build.gradle b/android/build.gradle
index d867fc811..eb9d8cd9b 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -27,11 +27,11 @@ android {
targetSdkVersion 28
minSdkVersion 23
versionCode 1
- versionName '0.8.0'
+ versionName '0.8.3'
externalNativeBuild {
cmake {
// targets "lokinet-android"
- arguments "-DWITH_LTO=OFF", "-DCXXOPTS_BUILD_TESTS=OFF","-DWITH_TESTS=OFF", "-DCMAKE_CROSSCOMPILING=ON", "-DNATIVE_BUILD=OFF", "-DANDROID=ON", "-DANDROID_STL=c++_static", "-DBUILD_STATIC_DEPS=ON", "-DBUILD_SHARED_LIBS=OFF", "-DSTATIC_LINK=ON", "-DDOWNLOAD_UV=FORCE", "-DANDROID_ARM_MODE=arm"
+ arguments "-DWITH_LTO=OFF", "-DCXXOPTS_BUILD_TESTS=OFF","-DWITH_TESTS=OFF", "-DCMAKE_CROSSCOMPILING=ON", "-DNATIVE_BUILD=OFF", "-DANDROID=ON", "-DANDROID_STL=c++_static", "-DBUILD_STATIC_DEPS=ON", "-DBUILD_SHARED_LIBS=OFF", "-DSTATIC_LINK=ON", "-DANDROID_ARM_MODE=arm", "-DFORCE_OXENMQ_SUBMODULE=ON"
cppFlags "-std=c++17"
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
// abiFilters 'armeabi-v7a'
diff --git a/android/src/network/loki/lokinet/LokiNetActivity.java b/android/src/network/loki/lokinet/LokiNetActivity.java
index c36fdc7f6..cbe836465 100755
--- a/android/src/network/loki/lokinet/LokiNetActivity.java
+++ b/android/src/network/loki/lokinet/LokiNetActivity.java
@@ -19,7 +19,9 @@ import android.content.Context;
import android.content.ComponentName;
import android.content.ServiceConnection;
+import android.Manifest;
+import android.net.VpnService;
import android.os.AsyncTask;
import android.content.Intent;
import android.os.Bundle;
@@ -29,14 +31,18 @@ import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
+import android.util.Log;
+
public class LokiNetActivity extends Activity {
private static final String TAG = "lokinet-activity";
private TextView textView;
- private static final String DefaultBootstrapURL = "https://seed.lokinet.org/bootstrap.signed";
+ private static final String DefaultBootstrapURL = "https://seed.lokinet.org/lokinet.signed";
private AsyncBootstrap bootstrapper;
+ public static final String LOG_TAG = "LokinetDaemon";
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -71,11 +77,33 @@ public class LokiNetActivity extends Activity {
bootstrapper.execute(DefaultBootstrapURL);
}
-
public void runLokinetService()
{
- startService(new Intent(LokiNetActivity.this,
- LokinetService.class));
+ Intent intent = VpnService.prepare(getApplicationContext());
+ if (intent != null)
+ {
+ Log.d(LOG_TAG, "VpnService.prepare() returned an Intent, so launch that intent.");
+ startActivityForResult(intent, 0);
+ }
+ else
+ {
+ Log.w(LOG_TAG, "VpnService.prepare() returned null, not running.");
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data)
+ {
+ if (resultCode == RESULT_OK)
+ {
+ Log.d(LOG_TAG, "VpnService prepared intent RESULT_OK, launching LokinetDaemon Service");
+ startService(new Intent(LokiNetActivity.this,
+ LokinetDaemon.class));
+ }
+ else
+ {
+ Log.d(LOG_TAG, "VpnService prepared intent NOT RESULT_OK, shit.");
+ }
}
@Override
diff --git a/android/src/network/loki/lokinet/LokinetConfig.java b/android/src/network/loki/lokinet/LokinetConfig.java
new file mode 100644
index 000000000..209ddfb12
--- /dev/null
+++ b/android/src/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/android/src/network/loki/lokinet/LokinetDaemon.java b/android/src/network/loki/lokinet/LokinetDaemon.java
new file mode 100644
index 000000000..ed808d7a5
--- /dev/null
+++ b/android/src/network/loki/lokinet/LokinetDaemon.java
@@ -0,0 +1,167 @@
+package network.loki.lokinet;
+
+import java.lang.Thread;
+import java.nio.ByteBuffer;
+import java.io.File;
+
+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 + "/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/android/src/network/loki/lokinet/LokinetService.java b/android/src/network/loki/lokinet/LokinetService.java
deleted file mode 100644
index 7dbae6236..000000000
--- a/android/src/network/loki/lokinet/LokinetService.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package network.loki.lokinet;
-
-
-import android.net.VpnService;
-
-public class LokinetService extends VpnService
-{
-
-}
diff --git a/cmake/StaticBuild.cmake b/cmake/StaticBuild.cmake
index 285c679f6..ebac3a402 100644
--- a/cmake/StaticBuild.cmake
+++ b/cmake/StaticBuild.cmake
@@ -291,7 +291,7 @@ build_external(zmq
${zmq_patch}
CONFIGURE_COMMAND ./configure ${cross_host} --prefix=${DEPS_DESTDIR} --enable-static --disable-shared
--disable-curve-keygen --enable-curve --disable-drafts --disable-libunwind --with-libsodium
- --without-pgm --without-norm --without-vmci --without-docs --with-pic --disable-Werror ${zmq_extra}
+ --without-pgm --without-norm --without-vmci --without-docs --with-pic --disable-Werror --disable-libbsd ${zmq_extra}
"CC=${deps_cc}" "CXX=${deps_cxx}" "CFLAGS=${deps_CFLAGS} -fstack-protector" "CXXFLAGS=${deps_CXXFLAGS} -fstack-protector"
"sodium_CFLAGS=-I${DEPS_DESTDIR}/include" "sodium_LIBS=-L${DEPS_DESTDIR}/lib -lsodium"
)
diff --git a/contrib/ci/drone-static-upload.sh b/contrib/ci/drone-static-upload.sh
index 6f6647606..12ba90c78 100755
--- a/contrib/ci/drone-static-upload.sh
+++ b/contrib/ci/drone-static-upload.sh
@@ -39,6 +39,11 @@ if [ -e daemon/lokinet.exe ]; then
# zipit up yo
archive="$base.zip"
zip -r "$archive" "$base"
+elif [ -e build/outputs/apk/debug/lokinet-debug.apk ] ; then
+ # android af ngl
+ cp -av build/outputs/apk/debug/lokinet-debug.apk "$base"
+ archive="$base.tar.xz"
+ tar cJvf "$archive" "$base"
else
cp -av daemon/lokinet daemon/lokinet-vpn ../lokinet-bootstrap "$base"
# tar dat shiz up yo
diff --git a/include/llarp.hpp b/include/llarp.hpp
index 5944f7fcc..0e1e01ebd 100644
--- a/include/llarp.hpp
+++ b/include/llarp.hpp
@@ -99,6 +99,14 @@ namespace llarp
virtual std::shared_ptr
makeVPNPlatform();
+#ifdef ANDROID
+
+ int androidFD = -1;
+
+ int
+ GetUDPSocket();
+#endif
+
protected:
std::shared_ptr config = nullptr;
diff --git a/jni/lokinet_config.cpp b/jni/lokinet_config.cpp
index cc735e740..34fae0fab 100644
--- a/jni/lokinet_config.cpp
+++ b/jni/lokinet_config.cpp
@@ -1,13 +1,18 @@
#include "network_loki_lokinet_LokinetConfig.h"
#include
+#include
#include "lokinet_jni_common.hpp"
extern "C"
{
JNIEXPORT jobject JNICALL
- Java_network_loki_lokinet_LokinetConfig_Obtain(JNIEnv* env, jclass)
+ Java_network_loki_lokinet_LokinetConfig_Obtain(JNIEnv* env, jclass, jstring dataDir)
{
- auto conf = new llarp::Config();
+ auto conf = VisitStringAsStringView(
+ env, dataDir, [](std::string_view val) -> llarp::Config* {
+ return new llarp::Config{val};
+ });
+
if (conf == nullptr)
return nullptr;
return env->NewDirectByteBuffer(conf, sizeof(llarp::Config));
@@ -21,15 +26,49 @@ extern "C"
}
JNIEXPORT jboolean JNICALL
- Java_network_loki_lokinet_LokinetConfig_Load(JNIEnv* env, jobject self, jstring fname)
+ Java_network_loki_lokinet_LokinetConfig_Load(JNIEnv* env, jobject self)
+ {
+ auto conf = GetImpl(env, self);
+ if (conf == nullptr)
+ return JNI_FALSE;
+ if (conf->Load())
+ {
+ return JNI_TRUE;
+ }
+ return JNI_FALSE;
+ }
+
+ JNIEXPORT jboolean JNICALL
+ Java_network_loki_lokinet_LokinetConfig_Save(JNIEnv* env, jobject self)
{
auto conf = GetImpl(env, self);
if (conf == nullptr)
return JNI_FALSE;
- return VisitStringAsStringView(env, fname, [conf](std::string_view val) -> jboolean {
- if (conf->Load(val, false, llarp::GetDefaultDataDir()))
- return JNI_TRUE;
+ try
+ {
+ conf->Save();
+ }
+ catch (...)
+ {
return JNI_FALSE;
- });
+ }
+ return JNI_TRUE;
+ }
+
+ JNIEXPORT void JNICALL
+ Java_network_loki_lokinet_LokinetConfig_AddDefaultValue(
+ JNIEnv* env, jobject self, jstring section, jstring key, jstring value)
+ {
+ auto convert = [](std::string_view str) -> std::string { return std::string{str}; };
+
+ const auto sect = VisitStringAsStringView(env, section, convert);
+ const auto k = VisitStringAsStringView(env, key, convert);
+ const auto v = VisitStringAsStringView(env, value, convert);
+
+ auto conf = GetImpl(env, self);
+ if (conf)
+ {
+ conf->AddDefault(sect, k, v);
+ }
}
-}
\ No newline at end of file
+}
diff --git a/jni/lokinet_daemon.cpp b/jni/lokinet_daemon.cpp
index f38e5579e..a13cd638f 100644
--- a/jni/lokinet_daemon.cpp
+++ b/jni/lokinet_daemon.cpp
@@ -2,6 +2,7 @@
#include "lokinet_jni_common.hpp"
#include "lokinet_jni_vpnio.hpp"
#include
+#include
extern "C"
{
@@ -31,7 +32,9 @@ extern "C"
try
{
llarp::RuntimeOptions opts{};
- ptr->Configure(*config);
+
+ // janky make_shared deep copy because jni + shared pointer = scary
+ ptr->Configure(std::make_shared(*config));
ptr->Setup(opts);
}
catch (...)
@@ -71,17 +74,30 @@ extern "C"
return ptr->IsUp() ? JNI_FALSE : JNI_TRUE;
}
- JNIEXPORT jboolean JNICALL
- Java_network_loki_lokinet_LokinetDaemon_InjectVPN(JNIEnv* env, jobject self, jobject vpn)
+ JNIEXPORT void JNICALL
+ Java_network_loki_lokinet_LokinetDaemon_InjectVPNFD(JNIEnv* env, jobject self)
{
auto ptr = GetImpl(env, self);
- auto impl = GetImpl(env, vpn);
- if (ptr == nullptr || impl == nullptr)
- return JNI_FALSE;
- if (impl->info.netmask == 0)
- return JNI_FALSE;
- if (not impl->Init(ptr))
- return JNI_FALSE;
- return llarp_main_inject_default_vpn(ptr, &impl->io, impl->info) ? JNI_TRUE : JNI_FALSE;
+
+ ptr->androidFD = GetObjectMemberAsInt(env, self, "m_FD");
+ }
+
+ JNIEXPORT jint JNICALL
+ Java_network_loki_lokinet_LokinetDaemon_GetUDPSocket(JNIEnv* env, jobject self)
+ {
+ auto ptr = GetImpl(env, self);
+
+ return ptr->GetUDPSocket();
+ }
+
+ JNIEXPORT jstring JNICALL
+ Java_network_loki_lokinet_LokinetDaemon_DetectFreeRange(JNIEnv* env, jclass)
+ {
+ std::string rangestr{};
+ if (auto maybe = llarp::FindFreeRange())
+ {
+ rangestr = maybe->ToString();
+ }
+ return env->NewStringUTF(rangestr.c_str());
}
-}
\ No newline at end of file
+}
diff --git a/jni/lokinet_jni_common.hpp b/jni/lokinet_jni_common.hpp
index 0b162e54a..76f1e977b 100644
--- a/jni/lokinet_jni_common.hpp
+++ b/jni/lokinet_jni_common.hpp
@@ -26,7 +26,7 @@ VisitStringAsStringView(JNIEnv* env, jobject str, V visit)
env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT);
env->DeleteLocalRef(stringJbytes);
- return std::move(result);
+ return result;
}
/// cast jni buffer to T *
@@ -45,7 +45,7 @@ static T*
FromObjectMember(JNIEnv* env, jobject self, const char* membername)
{
jclass cl = env->GetObjectClass(self);
- jfieldID name = env->GetFieldID(cl, membername, "Ljava/nio/Buffer;");
+ jfieldID name = env->GetFieldID(cl, membername, "Ljava/nio/ByteBuffer;");
jobject buffer = env->GetObjectField(self, name);
return FromBuffer(env, buffer);
}
@@ -79,4 +79,4 @@ GetImpl(JNIEnv* env, jobject self)
return FromObjectMember(env, self, "impl");
}
-#endif
\ No newline at end of file
+#endif
diff --git a/jni/network_loki_lokinet_LokinetConfig.h b/jni/network_loki_lokinet_LokinetConfig.h
index 7496155d3..341a64fdd 100644
--- a/jni/network_loki_lokinet_LokinetConfig.h
+++ b/jni/network_loki_lokinet_LokinetConfig.h
@@ -11,15 +11,15 @@ extern "C"
/*
* Class: network_loki_lokinet_LokinetConfig
* Method: Obtain
- * Signature: ()Ljava/nio/Buffer;
+ * Signature: (Ljava/lang/String;)Ljava/nio/ByteBuffer;
*/
JNIEXPORT jobject JNICALL
- Java_network_loki_lokinet_LokinetConfig_Obtain(JNIEnv*, jclass);
+ Java_network_loki_lokinet_LokinetConfig_Obtain(JNIEnv*, jclass, jstring);
/*
* Class: network_loki_lokinet_LokinetConfig
* Method: Free
- * Signature: (Ljava/nio/Buffer;)V
+ * Signature: (Ljava/nio/ByteBuffer;)V
*/
JNIEXPORT void JNICALL
Java_network_loki_lokinet_LokinetConfig_Free(JNIEnv*, jclass, jobject);
@@ -27,10 +27,27 @@ extern "C"
/*
* Class: network_loki_lokinet_LokinetConfig
* Method: Load
- * Signature: (Ljava/lang/String;)Z
+ * Signature: ()Z
*/
JNIEXPORT jboolean JNICALL
- Java_network_loki_lokinet_LokinetConfig_Load(JNIEnv*, jobject, jstring);
+ Java_network_loki_lokinet_LokinetConfig_Load(JNIEnv*, jobject);
+
+ /*
+ * Class: network_loki_lokinet_LokinetConfig
+ * Method: Save
+ * Signature: ()Z
+ */
+ JNIEXPORT jboolean JNICALL
+ Java_network_loki_lokinet_LokinetConfig_Save(JNIEnv*, jobject);
+
+ /*
+ * Class: network_loki_lokinet_LokinetConfig
+ * Method: AddDefaultValue
+ * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ */
+ JNIEXPORT void JNICALL
+ Java_network_loki_lokinet_LokinetConfig_AddDefaultValue(
+ JNIEnv*, jobject, jstring, jstring, jstring);
#ifdef __cplusplus
}
diff --git a/jni/network_loki_lokinet_LokinetDaemon.h b/jni/network_loki_lokinet_LokinetDaemon.h
index 3b23a9f70..78966b989 100644
--- a/jni/network_loki_lokinet_LokinetDaemon.h
+++ b/jni/network_loki_lokinet_LokinetDaemon.h
@@ -11,7 +11,7 @@ extern "C"
/*
* Class: network_loki_lokinet_LokinetDaemon
* Method: Obtain
- * Signature: ()Ljava/nio/Buffer;
+ * Signature: ()Ljava/nio/ByteBuffer;
*/
JNIEXPORT jobject JNICALL
Java_network_loki_lokinet_LokinetDaemon_Obtain(JNIEnv*, jclass);
@@ -19,7 +19,7 @@ extern "C"
/*
* Class: network_loki_lokinet_LokinetDaemon
* Method: Free
- * Signature: (Ljava/nio/Buffer;)V
+ * Signature: (Ljava/nio/ByteBuffer;)V
*/
JNIEXPORT void JNICALL
Java_network_loki_lokinet_LokinetDaemon_Free(JNIEnv*, jclass, jobject);
@@ -58,11 +58,27 @@ extern "C"
/*
* Class: network_loki_lokinet_LokinetDaemon
- * Method: InjectVPN
- * Signature: (Lnetwork/loki/lokinet/LokinetVPN;)Z
+ * Method: InjectVPNFD
+ * Signature: ()V
*/
- JNIEXPORT jboolean JNICALL
- Java_network_loki_lokinet_LokinetDaemon_InjectVPN(JNIEnv*, jobject, jobject);
+ JNIEXPORT void JNICALL
+ Java_network_loki_lokinet_LokinetDaemon_InjectVPNFD(JNIEnv*, jobject);
+
+ /*
+ * Class: network_loki_lokinet_LokinetDaemon
+ * Method: GetUDPSocket
+ * Signature: ()I
+ */
+ JNIEXPORT jint JNICALL
+ Java_network_loki_lokinet_LokinetDaemon_GetUDPSocket(JNIEnv*, jobject);
+
+ /*
+ * Class: network_loki_lokinet_LokinetDaemon
+ * Method: DetectFreeRange
+ * Signature: ()Ljava/lang/String;
+ */
+ JNIEXPORT jstring JNICALL
+ Java_network_loki_lokinet_LokinetDaemon_DetectFreeRange(JNIEnv*, jclass);
#ifdef __cplusplus
}
diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt
index 1a7ea79d6..c4d4f0627 100644
--- a/llarp/CMakeLists.txt
+++ b/llarp/CMakeLists.txt
@@ -59,6 +59,7 @@ add_library(lokinet-platform
net/net_int.cpp
net/route.cpp
net/sock_addr.cpp
+ vpn/packet_router.cpp
vpn/platform.cpp
)
diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp
index 35285ba3f..928f73d10 100644
--- a/llarp/config/config.cpp
+++ b/llarp/config/config.cpp
@@ -1020,6 +1020,12 @@ namespace llarp
}
}
+ void
+ Config::AddDefault(std::string section, std::string key, std::string val)
+ {
+ m_Additional.emplace_back(std::array{section, key, val});
+ }
+
bool
Config::Load(std::optional fname, bool isRelay)
{
@@ -1073,6 +1079,12 @@ namespace llarp
m_Parser.Clear();
LoadOverrides();
+ /// load additional config options added
+ for (const auto& [sect, key, val] : m_Additional)
+ {
+ conf.addConfigValue(sect, key, val);
+ }
+
m_Parser.IterAll([&](std::string_view section, const SectionValues_t& values) {
for (const auto& pair : values)
{
diff --git a/llarp/config/config.hpp b/llarp/config/config.hpp
index 5f561e2cd..86c4b9257 100644
--- a/llarp/config/config.hpp
+++ b/llarp/config/config.hpp
@@ -224,6 +224,9 @@ namespace llarp
void
Override(std::string section, std::string key, std::string value);
+ void
+ AddDefault(std::string section, std::string key, std::string value);
+
private:
/// Load (initialize) a default config.
///
@@ -242,6 +245,7 @@ namespace llarp
void
LoadOverrides();
+ std::vector> m_Additional;
ConfigParser m_Parser;
const fs::path m_DataDir;
};
diff --git a/llarp/context.cpp b/llarp/context.cpp
index a34d67e9c..b70df293c 100644
--- a/llarp/context.cpp
+++ b/llarp/context.cpp
@@ -190,6 +190,15 @@ namespace llarp
llarp::LogDebug("free logic");
logic.reset();
}
+
+#if defined(ANDROID)
+ int
+ Context::GetUDPSocket()
+ {
+ return router->GetOutboundUDPSocket();
+ }
+#endif
+
} // namespace llarp
extern "C"
diff --git a/llarp/dns/server.cpp b/llarp/dns/server.cpp
index 1451a9766..52f25ddd3 100644
--- a/llarp/dns/server.cpp
+++ b/llarp/dns/server.cpp
@@ -5,297 +5,212 @@
#include
#include
-namespace llarp
+namespace llarp::dns
{
- namespace dns
+ static std::vector
+ MessageToBuffer(Message msg)
{
- Proxy::Proxy(
- llarp_ev_loop_ptr serverLoop,
- Logic_ptr serverLogic,
- llarp_ev_loop_ptr clientLoop,
- Logic_ptr clientLogic,
- IQueryHandler* h)
- : m_ServerLoop(std::move(serverLoop))
- , m_ClientLoop(std::move(clientLoop))
- , m_ServerLogic(std::move(serverLogic))
- , m_ClientLogic(std::move(clientLogic))
- , m_QueryHandler(h)
- {
- m_Client.user = this;
- m_Server.user = this;
- m_Client.tick = nullptr;
- m_Server.tick = nullptr;
- m_Client.recvfrom = &HandleUDPRecv_client;
- m_Server.recvfrom = &HandleUDPRecv_server;
- }
+ std::array tmp = {{0}};
+ llarp_buffer_t buf{tmp};
+ if (not msg.Encode(&buf))
+ throw std::runtime_error("cannot encode dns message");
+ std::vector pkt;
+ pkt.resize(buf.cur - buf.base);
+ std::copy_n(tmp.data(), pkt.size(), pkt.data());
+ return pkt;
+ }
+ PacketHandler::PacketHandler(Logic_ptr logic, IQueryHandler* h)
+ : m_QueryHandler{h}, m_Logic{logic}
+ {}
+
+ Proxy::Proxy(llarp_ev_loop_ptr loop, Logic_ptr logic, IQueryHandler* h)
+ : PacketHandler{logic, h}, m_Loop(std::move(loop))
+ {
+ m_Server.user = this;
+ m_Server.tick = nullptr;
+ m_Server.recvfrom = &HandleUDP;
+ }
- void
- Proxy::Stop()
- {
- if (m_UnboundResolver)
- m_UnboundResolver->Stop();
- }
+ void
+ PacketHandler::Stop()
+ {
+ if (m_UnboundResolver)
+ m_UnboundResolver->Stop();
+ }
- bool
- Proxy::Start(const IpAddress& addr, const std::vector& resolvers)
- {
- if (resolvers.size())
- {
- if (not SetupUnboundResolver(resolvers))
- {
- llarp::LogError("Failed to add upstream resolvers during DNS server setup.");
- return false;
- }
- }
- return (llarp_ev_add_udp(m_ServerLoop, &m_Server, addr.createSockAddr()) == 0);
- }
+ bool
+ Proxy::Start(SockAddr addr, std::vector resolvers)
+ {
+ if (not PacketHandler::Start(addr, std::move(resolvers)))
+ return false;
+ return (llarp_ev_add_udp(m_Loop, &m_Server, addr) == 0);
+ }
- static Proxy::Buffer_t
- CopyBuffer(const llarp_buffer_t& buf)
- {
- std::vector msgbuf(buf.sz);
- std::copy_n(buf.base, buf.sz, msgbuf.data());
- return msgbuf;
- }
+ static Proxy::Buffer_t
+ CopyBuffer(const llarp_buffer_t& buf)
+ {
+ std::vector msgbuf(buf.sz);
+ std::copy_n(buf.base, buf.sz, msgbuf.data());
+ return msgbuf;
+ }
- void
- Proxy::HandleUDPRecv_server(llarp_udp_io* u, const SockAddr& from, ManagedBuffer buf)
- {
- Buffer_t msgbuf = CopyBuffer(buf.underlying);
- auto self = static_cast(u->user);
- self->HandlePktServer(from, msgbuf);
- }
+ void
+ Proxy::HandleUDP(llarp_udp_io* u, const SockAddr& from, ManagedBuffer buf)
+ {
+ Buffer_t msgbuf = CopyBuffer(buf.underlying);
+ auto self = static_cast(u->user);
+ self->HandlePacket(from, from, std::move(msgbuf));
+ }
- void
- Proxy::HandleUDPRecv_client(llarp_udp_io* u, const SockAddr& from, ManagedBuffer buf)
+ void
+ PacketHandler::Restart()
+ {
+ if (m_UnboundResolver)
{
- Buffer_t msgbuf = CopyBuffer(buf.underlying);
- auto self = static_cast(u->user)->shared_from_this();
- LogicCall(
- self->m_ServerLogic, [self, from, msgbuf]() { self->HandlePktClient(from, msgbuf); });
+ LogInfo("reset libunbound's internal stuff");
+ m_UnboundResolver->Init();
}
+ }
- IpAddress
- Proxy::PickRandomResolver() const
- {
- const size_t sz = m_Resolvers.size();
- if (sz <= 1)
- return m_Resolvers[0];
- auto itr = m_Resolvers.begin();
- std::advance(itr, llarp::randint() % sz);
- return *itr;
- }
+ bool
+ PacketHandler::Start(SockAddr, std::vector resolvers)
+ {
+ return SetupUnboundResolver(std::move(resolvers));
+ }
- void
- Proxy::Restart()
- {
- if (m_UnboundResolver)
+ bool
+ PacketHandler::SetupUnboundResolver(std::vector resolvers)
+ {
+ auto failFunc = [self = weak_from_this()](SockAddr from, SockAddr to, Message msg) {
+ auto this_ptr = self.lock();
+ if (this_ptr)
{
- LogInfo("reset libunbound's internal stuff");
- m_UnboundResolver->Init();
+ this_ptr->SendServerMessageBufferTo(from, to, MessageToBuffer(std::move(msg)));
}
- }
-
- bool
- Proxy::SetupUnboundResolver(const std::vector& resolvers)
- {
- auto failFunc = [self = weak_from_this()](SockAddr to, Message msg) {
- auto this_ptr = self.lock();
- if (this_ptr)
- {
- this_ptr->SendServerMessageTo(to, std::move(msg));
- }
- };
+ };
- auto replyFunc = [self = weak_from_this()](SockAddr to, std::vector buf) {
- auto this_ptr = self.lock();
- if (this_ptr)
- {
- this_ptr->HandleUpstreamResponse(to, std::move(buf));
- }
- };
+ auto replyFunc = [self = weak_from_this()](
+ SockAddr from, SockAddr to, std::vector buf) {
+ auto this_ptr = self.lock();
+ if (this_ptr)
+ {
+ this_ptr->SendServerMessageBufferTo(from, to, std::move(buf));
+ }
+ };
- m_UnboundResolver = std::make_shared(
- m_ServerLoop, std::move(replyFunc), std::move(failFunc));
- if (not m_UnboundResolver->Init())
+ m_UnboundResolver =
+ std::make_shared(m_Logic, std::move(replyFunc), std::move(failFunc));
+ if (not m_UnboundResolver->Init())
+ {
+ llarp::LogError("Failed to initialize upstream DNS resolver.");
+ m_UnboundResolver = nullptr;
+ return false;
+ }
+ for (const auto& resolver : resolvers)
+ {
+ if (not m_UnboundResolver->AddUpstreamResolver(resolver.toHost()))
{
- llarp::LogError("Failed to initialize upstream DNS resolver.");
+ llarp::LogError("Failed to add upstream DNS server: ", resolver.toHost());
m_UnboundResolver = nullptr;
return false;
}
- for (const auto& resolver : resolvers)
- {
- if (not m_UnboundResolver->AddUpstreamResolver(resolver.toHost()))
- {
- llarp::LogError("Failed to add upstream DNS server: ", resolver.toHost());
- m_UnboundResolver = nullptr;
- return false;
- }
- }
-
- return true;
+ m_Resolvers.emplace(resolver);
}
- void
- Proxy::HandleTick(llarp_udp_io*)
- {}
+ return true;
+ }
- void
- Proxy::SendServerMessageBufferTo(const SockAddr& to, const llarp_buffer_t& buf)
+ void
+ Proxy::SendServerMessageBufferTo(SockAddr, SockAddr to, Buffer_t buf)
+ {
+ if (llarp_ev_udp_sendto(&m_Server, to, buf) < 0)
+ llarp::LogError("dns reply failed");
+ }
+
+ bool
+ PacketHandler::ShouldHandlePacket(SockAddr to, SockAddr from, Buffer_t buf) const
+ {
+ (void)from;
+
+ MessageHeader hdr;
+ llarp_buffer_t pkt{buf};
+ if (not hdr.Decode(&pkt))
{
- if (llarp_ev_udp_sendto(&m_Server, to, buf) < 0)
- llarp::LogError("dns reply failed");
+ return false;
}
- void
- Proxy::SendServerMessageTo(const SockAddr& to, Message msg)
+ Message msg{hdr};
+ if (not msg.Decode(&pkt))
{
- auto self = shared_from_this();
- LogicCall(m_ServerLogic, [to, msg = std::move(msg), self]() {
- std::array tmp = {{0}};
- llarp_buffer_t buf(tmp);
- if (msg.Encode(&buf))
- {
- buf.sz = buf.cur - buf.base;
- buf.cur = buf.base;
- self->SendServerMessageBufferTo(to, buf);
- }
- else
- llarp::LogWarn("failed to encode dns message when sending");
- });
+ return false;
}
- void
- Proxy::HandleUpstreamResponse(SockAddr to, std::vector buf)
+ if (m_QueryHandler and m_QueryHandler->ShouldHookDNSMessage(msg))
+ return true;
+
+ if (m_Resolvers.find(to) != m_Resolvers.end())
{
- auto self = shared_from_this();
- LogicCall(m_ServerLogic, [to, buffer = std::move(buf), self]() {
- llarp_buffer_t buf(buffer);
- self->SendServerMessageBufferTo(to, buf);
- });
+ return false;
}
+ return true;
+ }
- void
- Proxy::SendClientMessageTo(const SockAddr& to, Message msg)
+ void
+ PacketHandler::HandlePacket(SockAddr resolver, SockAddr from, Buffer_t buf)
+ {
+ MessageHeader hdr;
+ llarp_buffer_t pkt{buf};
+ if (not hdr.Decode(&pkt))
{
- auto self = shared_from_this();
- LogicCall(m_ClientLogic, [to, msg, self]() {
- std::array tmp = {{0}};
- llarp_buffer_t buf(tmp);
- if (msg.Encode(&buf))
- {
- buf.sz = buf.cur - buf.base;
- buf.cur = buf.base;
- llarp_ev_udp_sendto(&self->m_Client, to, buf);
- }
- else
- llarp::LogWarn("failed to encode dns message when sending");
- });
+ llarp::LogWarn("failed to parse dns header from ", from);
+ return;
}
- void
- Proxy::HandlePktClient(const SockAddr& from, Buffer_t buf)
+ Message msg(hdr);
+ if (not msg.Decode(&pkt))
{
- llarp_buffer_t pkt(buf);
- MessageHeader hdr;
- if (!hdr.Decode(&pkt))
- {
- llarp::LogWarn("failed to parse dns header from ", from);
- return;
- }
- TX tx = {hdr.id, from};
- auto itr = m_Forwarded.find(tx);
- if (itr == m_Forwarded.end())
- return;
- const auto& requester = itr->second;
- auto self = shared_from_this();
- Message msg(hdr);
- if (msg.Decode(&pkt))
- {
- if (m_QueryHandler && m_QueryHandler->ShouldHookDNSMessage(msg))
- {
- msg.hdr_id = itr->first.txid;
- if (!m_QueryHandler->HandleHookedDNSMessage(
- std::move(msg),
- std::bind(
- &Proxy::SendServerMessageTo,
- self,
- requester.createSockAddr(),
- std::placeholders::_1)))
- {
- llarp::LogWarn("failed to handle hooked dns");
- }
- return;
- }
- }
- LogicCall(m_ServerLogic, [=]() {
- // forward reply to requester via server
- const llarp_buffer_t tmpbuf(buf);
- llarp_ev_udp_sendto(&self->m_Server, requester.createSockAddr(), tmpbuf);
- });
- // remove pending
- m_Forwarded.erase(itr);
+ llarp::LogWarn("failed to parse dns message from ", from);
+ return;
}
- void
- Proxy::HandlePktServer(const SockAddr& from, Buffer_t buf)
+ // we don't provide a DoH resolver because it requires verified TLS
+ // TLS needs X509/ASN.1-DER and opting into the Root CA Cabal
+ // thankfully mozilla added a backdoor that allows ISPs to turn it off
+ // so we disable DoH for firefox using mozilla's ISP backdoor
+ // see: https://github.com/loki-project/loki-network/issues/832
+ for (const auto& q : msg.questions)
{
- MessageHeader hdr;
- llarp_buffer_t pkt(buf);
- if (!hdr.Decode(&pkt))
+ // is this firefox looking for their backdoor record?
+ if (q.IsName("use-application-dns.net"))
{
- llarp::LogWarn("failed to parse dns header from ", from);
+ // yea it is, let's turn off DoH because god is dead.
+ msg.AddNXReply();
+ // press F to pay respects
+ SendServerMessageBufferTo(resolver, from, MessageToBuffer(std::move(msg)));
return;
}
+ }
- Message msg(hdr);
- if (!msg.Decode(&pkt))
- {
- llarp::LogWarn("failed to parse dns message from ", from);
- return;
- }
-
- // we don't provide a DoH resolver because it requires verified TLS
- // TLS needs X509/ASN.1-DER and opting into the Root CA Cabal
- // thankfully mozilla added a backdoor that allows ISPs to turn it off
- // so we disable DoH for firefox using mozilla's ISP backdoor
- // see: https://github.com/loki-project/loki-network/issues/832
- for (const auto& q : msg.questions)
- {
- // is this firefox looking for their backdoor record?
- if (q.IsName("use-application-dns.net"))
- {
- // yea it is, let's turn off DoH because god is dead.
- msg.AddNXReply();
- // press F to pay respects
- SendServerMessageTo(from, std::move(msg));
- return;
- }
- }
-
- auto self = shared_from_this();
- if (m_QueryHandler && m_QueryHandler->ShouldHookDNSMessage(msg))
- {
- if (!m_QueryHandler->HandleHookedDNSMessage(
- std::move(msg),
- std::bind(&Proxy::SendServerMessageTo, self, from, std::placeholders::_1)))
- {
- llarp::LogWarn("failed to handle hooked dns");
- }
- }
- else if (not m_UnboundResolver)
- {
- // no upstream resolvers
- // let's serv fail it
- msg.AddServFail();
-
- SendServerMessageTo(from, std::move(msg));
- }
- else
+ if (m_QueryHandler && m_QueryHandler->ShouldHookDNSMessage(msg))
+ {
+ auto reply = [self = shared_from_this(), to = from, resolver](dns::Message msg) {
+ self->SendServerMessageBufferTo(resolver, to, MessageToBuffer(std::move(msg)));
+ };
+ if (!m_QueryHandler->HandleHookedDNSMessage(std::move(msg), reply))
{
- m_UnboundResolver->Lookup(from, std::move(msg));
+ llarp::LogWarn("failed to handle hooked dns");
}
}
-
- } // namespace dns
-} // namespace llarp
+ else if (not m_UnboundResolver)
+ {
+ // no upstream resolvers
+ // let's serv fail it
+ msg.AddServFail();
+ SendServerMessageBufferTo(resolver, from, MessageToBuffer(std::move(msg)));
+ }
+ else
+ {
+ m_UnboundResolver->Lookup(resolver, from, std::move(msg));
+ }
+ }
+} // namespace llarp::dns
diff --git a/llarp/dns/server.hpp b/llarp/dns/server.hpp
index a303283ca..9d0a8cc16 100644
--- a/llarp/dns/server.hpp
+++ b/llarp/dns/server.hpp
@@ -27,18 +27,17 @@ namespace llarp
HandleHookedDNSMessage(Message query, std::function sendReply) = 0;
};
- struct Proxy : public std::enable_shared_from_this
+ struct PacketHandler : public std::enable_shared_from_this
{
using Logic_ptr = std::shared_ptr;
- Proxy(
- llarp_ev_loop_ptr serverLoop,
- Logic_ptr serverLogic,
- llarp_ev_loop_ptr clientLoop,
- Logic_ptr clientLogic,
- IQueryHandler* handler);
+ using Buffer_t = std::vector;
- bool
- Start(const IpAddress& addr, const std::vector& resolvers);
+ explicit PacketHandler(Logic_ptr logic, IQueryHandler* handler);
+
+ virtual ~PacketHandler() = default;
+
+ virtual bool
+ Start(SockAddr localaddr, std::vector upstreamResolvers);
void
Stop();
@@ -46,80 +45,50 @@ namespace llarp
void
Restart();
- using Buffer_t = std::vector;
+ void
+ HandlePacket(SockAddr resolver, SockAddr from, Buffer_t buf);
- private:
- /// low level packet handler
- static void
- HandleUDPRecv_client(llarp_udp_io*, const SockAddr&, ManagedBuffer);
- static void
- HandleUDPRecv_server(llarp_udp_io*, const SockAddr&, ManagedBuffer);
+ bool
+ ShouldHandlePacket(SockAddr to, SockAddr from, Buffer_t buf) const;
- /// low level ticker
- static void
- HandleTick(llarp_udp_io*);
+ protected:
+ virtual void
+ SendServerMessageBufferTo(SockAddr from, SockAddr to, Buffer_t buf) = 0;
+ private:
void
- HandlePktClient(const SockAddr& from, Buffer_t buf);
+ HandleUpstreamFailure(SockAddr from, SockAddr to, Message msg);
- void
- HandlePktServer(const SockAddr& from, Buffer_t buf);
+ bool
+ SetupUnboundResolver(std::vector resolvers);
- void
- SendClientMessageTo(const SockAddr& to, Message msg);
+ IQueryHandler* const m_QueryHandler;
+ std::set m_Resolvers;
+ std::shared_ptr m_UnboundResolver;
+ Logic_ptr m_Logic;
+ };
- void
- SendServerMessageBufferTo(const SockAddr& to, const llarp_buffer_t& buf);
+ struct Proxy : public PacketHandler
+ {
+ using Logic_ptr = std::shared_ptr;
+ explicit Proxy(llarp_ev_loop_ptr loop, Logic_ptr logic, IQueryHandler* handler);
- void
- SendServerMessageTo(const SockAddr& to, Message msg);
+ bool
+ Start(SockAddr localaddr, std::vector resolvers) override;
- void
- HandleUpstreamResponse(SockAddr to, std::vector buf);
+ using Buffer_t = std::vector;
+ protected:
void
- HandleUpstreamFailure(const SockAddr& to, Message msg);
-
- IpAddress
- PickRandomResolver() const;
+ SendServerMessageBufferTo(SockAddr from, SockAddr to, Buffer_t buf) override;
- bool
- SetupUnboundResolver(const std::vector& resolvers);
+ private:
+ static void
+ HandleUDP(llarp_udp_io*, const SockAddr&, ManagedBuffer);
private:
llarp_udp_io m_Server;
- llarp_udp_io m_Client;
- llarp_ev_loop_ptr m_ServerLoop;
- llarp_ev_loop_ptr m_ClientLoop;
- Logic_ptr m_ServerLogic;
- Logic_ptr m_ClientLogic;
- IQueryHandler* m_QueryHandler;
- std::vector m_Resolvers;
- std::shared_ptr m_UnboundResolver;
-
- struct TX
- {
- MsgID_t txid;
- IpAddress from;
-
- bool
- operator==(const TX& other) const
- {
- return txid == other.txid && from == other.from;
- }
-
- struct Hash
- {
- size_t
- operator()(const TX& t) const noexcept
- {
- return t.txid ^ IpAddress::Hash()(t.from);
- }
- };
- };
-
- // maps tx to who to send reply to
- std::unordered_map m_Forwarded;
+ llarp_ev_loop_ptr m_Loop;
};
} // namespace dns
} // namespace llarp
diff --git a/llarp/dns/unbound_resolver.cpp b/llarp/dns/unbound_resolver.cpp
index 9257eaffe..52fa1a335 100644
--- a/llarp/dns/unbound_resolver.cpp
+++ b/llarp/dns/unbound_resolver.cpp
@@ -10,6 +10,7 @@ namespace llarp::dns
std::weak_ptr resolver;
Message msg;
SockAddr source;
+ SockAddr replyFrom;
};
void
@@ -34,15 +35,15 @@ namespace llarp::dns
unboundContext = nullptr;
}
- UnboundResolver::UnboundResolver(llarp_ev_loop_ptr loop, ReplyFunction reply, FailFunction fail)
+ UnboundResolver::UnboundResolver(
+ std::shared_ptr logic, ReplyFunction reply, FailFunction fail)
: unboundContext(nullptr)
, started(false)
- , eventLoop(loop)
- , replyFunc([loop, reply](auto source, auto buf) {
- loop->call_soon([source, buf, reply]() { reply(source, buf); });
+ , replyFunc([logic, reply](auto res, auto source, auto buf) {
+ LogicCall(logic, [source, buf, reply, res]() { reply(res, source, buf); });
})
- , failFunc([loop, fail](auto source, auto message) {
- loop->call_soon([source, message, fail]() { fail(source, message); });
+ , failFunc([logic, fail](auto res, auto source, auto message) {
+ LogicCall(logic, [source, message, res, fail]() { fail(res, source, message); });
})
{}
@@ -60,7 +61,7 @@ namespace llarp::dns
{
Message& msg = lookup->msg;
msg.AddServFail();
- this_ptr->failFunc(lookup->source, msg);
+ this_ptr->failFunc(lookup->replyFrom, lookup->source, msg);
ub_resolve_free(result);
return;
}
@@ -75,7 +76,7 @@ namespace llarp::dns
buf.cur = buf.base;
hdr.Encode(&buf);
- this_ptr->replyFunc(lookup->source, std::move(pkt));
+ this_ptr->replyFunc(lookup->replyFrom, lookup->source, std::move(pkt));
ub_resolve_free(result);
}
@@ -120,17 +121,17 @@ namespace llarp::dns
}
void
- UnboundResolver::Lookup(const SockAddr& source, Message msg)
+ UnboundResolver::Lookup(SockAddr to, SockAddr from, Message msg)
{
if (not unboundContext)
{
msg.AddServFail();
- failFunc(source, std::move(msg));
+ failFunc(to, from, std::move(msg));
return;
}
const auto& q = msg.questions[0];
- auto* lookup = new PendingUnboundLookup{weak_from_this(), msg, source};
+ auto* lookup = new PendingUnboundLookup{weak_from_this(), msg, from, to};
int err = ub_resolve_async(
unboundContext,
q.Name().c_str(),
@@ -143,7 +144,7 @@ namespace llarp::dns
if (err != 0)
{
msg.AddServFail();
- failFunc(source, std::move(msg));
+ failFunc(to, from, std::move(msg));
return;
}
}
diff --git a/llarp/dns/unbound_resolver.hpp b/llarp/dns/unbound_resolver.hpp
index cf0dbc1de..a4fb8c055 100644
--- a/llarp/dns/unbound_resolver.hpp
+++ b/llarp/dns/unbound_resolver.hpp
@@ -17,8 +17,9 @@
namespace llarp::dns
{
- using ReplyFunction = std::function buf)>;
- using FailFunction = std::function;
+ using ReplyFunction =
+ std::function buf)>;
+ using FailFunction = std::function;
class UnboundResolver : public std::enable_shared_from_this
{
@@ -28,7 +29,6 @@ namespace llarp::dns
std::atomic started;
std::unique_ptr runner;
- llarp_ev_loop_ptr eventLoop;
ReplyFunction replyFunc;
FailFunction failFunc;
@@ -36,7 +36,7 @@ namespace llarp::dns
Reset();
public:
- UnboundResolver(llarp_ev_loop_ptr eventLoop, ReplyFunction replyFunc, FailFunction failFunc);
+ UnboundResolver(std::shared_ptr logic, ReplyFunction replyFunc, FailFunction failFunc);
static void
Callback(void* data, int err, ub_result* result);
@@ -53,7 +53,7 @@ namespace llarp::dns
AddUpstreamResolver(const std::string& upstreamResolverIP);
void
- Lookup(const SockAddr& source, Message msg);
+ Lookup(SockAddr to, SockAddr from, Message msg);
};
} // namespace llarp::dns
diff --git a/llarp/handlers/exit.cpp b/llarp/handlers/exit.cpp
index a6001373a..a610d2978 100644
--- a/llarp/handlers/exit.cpp
+++ b/llarp/handlers/exit.cpp
@@ -15,8 +15,7 @@ namespace llarp
{
ExitEndpoint::ExitEndpoint(const std::string& name, AbstractRouter* r)
: m_Router(r)
- , m_Resolver(std::make_shared(
- r->netloop(), r->logic(), r->netloop(), r->logic(), this))
+ , m_Resolver(std::make_shared(r->netloop(), r->logic(), this))
, m_Name(name)
, m_LocalResolverAddr("127.0.0.1", 53)
, m_InetToNetwork(name + "_exit_rx", r->netloop(), r->netloop())
@@ -324,7 +323,7 @@ namespace llarp
loop->add_ticker([&]() { Flush(); });
llarp::LogInfo("Trying to start resolver ", m_LocalResolverAddr.toString());
- return m_Resolver->Start(m_LocalResolverAddr, m_UpstreamResolvers);
+ return m_Resolver->Start(m_LocalResolverAddr.createSockAddr(), m_UpstreamResolvers);
}
return true;
}
diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp
index 5de4cfb81..3c3ce2a30 100644
--- a/llarp/handlers/tun.cpp
+++ b/llarp/handlers/tun.cpp
@@ -23,6 +23,7 @@
#include
#include
+#include
#include
@@ -36,13 +37,88 @@ namespace llarp
static constexpr auto FlushInterval = 25ms;
return now >= m_LastFlushAt + FlushInterval;
}
+ constexpr size_t udp_header_size = 8;
+
+ struct DnsHandler : public dns::PacketHandler
+ {
+ TunEndpoint* const m_Endpoint;
+
+ explicit DnsHandler(AbstractRouter* router, TunEndpoint* ep)
+ : dns::PacketHandler{router->logic(), ep}, m_Endpoint{ep} {};
+
+ void
+ SendServerMessageBufferTo(SockAddr from, SockAddr to, std::vector buf) override
+ {
+ net::IPPacket pkt;
+
+ if (buf.size() + 28 > sizeof(pkt.buf))
+ return;
+
+ auto* hdr = pkt.Header();
+ pkt.buf[1] = 0;
+ hdr->version = 4;
+ hdr->ihl = 5;
+ hdr->tot_len = htons(buf.size() + 28);
+ hdr->protocol = 0x11; // udp
+ hdr->ttl = 64;
+ hdr->frag_off = htons(0b0100000000000000);
+
+ hdr->saddr = from.getIPv4();
+ hdr->daddr = to.getIPv4();
+
+ // make udp packet
+ uint8_t* ptr = pkt.buf + 20;
+ htobe16buf(ptr, from.getPort());
+ ptr += 2;
+ htobe16buf(ptr, to.getPort());
+ ptr += 2;
+ htobe16buf(ptr, buf.size() + udp_header_size);
+ ptr += 2;
+ htobe16buf(ptr, uint16_t{0}); // checksum
+ ptr += 2;
+ std::copy_n(buf.data(), buf.size(), ptr);
+
+ /// queue ip packet write
+ const IpAddress remoteIP{from};
+ const IpAddress localIP{to};
+
+ hdr->check = 0;
+ hdr->check = net::ipchksum(pkt.buf, 20);
+ pkt.sz = 28 + buf.size();
+ m_Endpoint->HandleWriteIPPacket(
+ pkt.ConstBuffer(), net::ExpandV4(remoteIP.toIP()), net::ExpandV4(localIP.toIP()), 0);
+ }
+ };
TunEndpoint::TunEndpoint(AbstractRouter* r, service::Context* parent)
: service::Endpoint(r, parent)
, m_UserToNetworkPktQueue("endpoint_sendq", r->netloop(), r->netloop())
- , m_Resolver(std::make_shared(
- r->netloop(), r->logic(), r->netloop(), r->logic(), this))
- {}
+ {
+ m_PacketRouter.reset(
+ new vpn::PacketRouter{[&](net::IPPacket pkt) { HandleGotUserPacket(std::move(pkt)); }});
+#if ANDROID
+ m_Resolver = std::make_shared(r, this);
+ m_PacketRouter->AddUDPHandler(huint16_t{53}, [&](net::IPPacket pkt) {
+ const size_t ip_header_size = (pkt.Header()->ihl * 4);
+
+ const uint8_t* ptr = pkt.buf + ip_header_size;
+ const auto dst = ToNet(pkt.dstv4());
+ const auto src = ToNet(pkt.srcv4());
+ const SockAddr raddr{src.n, *reinterpret_cast(ptr)};
+ const SockAddr laddr{dst.n, *reinterpret_cast(ptr + 2)};
+
+ std::vector buf;
+ buf.resize(pkt.sz - (udp_header_size + ip_header_size));
+ std::copy_n(ptr + udp_header_size, buf.size(), buf.data());
+ if (m_Resolver->ShouldHandlePacket(laddr, raddr, buf))
+ m_Resolver->HandlePacket(laddr, raddr, std::move(buf));
+ else
+ HandleGotUserPacket(std::move(pkt));
+ });
+#else
+ m_Resolver = std::make_shared(r->netloop(), r->logic(), this);
+#endif
+ }
util::StatusObject
TunEndpoint::ExtractStatus() const
@@ -743,7 +819,7 @@ namespace llarp
auto netloop = Router()->netloop();
if (not netloop->add_network_interface(
- m_NetIf, [&](net::IPPacket pkt) { HandleGotUserPacket(std::move(pkt)); }))
+ m_NetIf, [&](net::IPPacket pkt) { m_PacketRouter->HandleIPPacket(std::move(pkt)); }))
{
LogError(Name(), " failed to add network interface");
return false;
@@ -788,7 +864,7 @@ namespace llarp
llarp::LogError(Name(), " failed to set up network interface");
return false;
}
- if (!m_Resolver->Start(m_LocalResolverAddr, m_UpstreamResolvers))
+ if (!m_Resolver->Start(m_LocalResolverAddr.createSockAddr(), m_UpstreamResolvers))
{
llarp::LogError(Name(), " failed to start DNS server");
return false;
@@ -1008,7 +1084,9 @@ namespace llarp
auto& pkt = write.pkt;
// load
if (!pkt.Load(buf))
+ {
return false;
+ }
if (pkt.IsV4())
{
pkt.UpdateIPv4Address(xhtonl(net::TruncateV6(src)), xhtonl(net::TruncateV6(dst)));
diff --git a/llarp/handlers/tun.hpp b/llarp/handlers/tun.hpp
index eb66097a7..78755c5b8 100644
--- a/llarp/handlers/tun.hpp
+++ b/llarp/handlers/tun.hpp
@@ -10,6 +10,7 @@
#include
#include
#include
+#include
#include
#include
@@ -232,7 +233,7 @@ namespace llarp
reply(*query);
}
/// our dns resolver
- std::shared_ptr m_Resolver;
+ std::shared_ptr m_Resolver;
/// maps ip address to timestamp last active
std::unordered_map m_IPActivity;
@@ -258,6 +259,8 @@ namespace llarp
std::string m_IfName;
std::shared_ptr m_NetIf;
+
+ std::unique_ptr m_PacketRouter;
};
} // namespace handlers
diff --git a/llarp/link/server.hpp b/llarp/link/server.hpp
index a428df0fa..a43d107ca 100644
--- a/llarp/link/server.hpp
+++ b/llarp/link/server.hpp
@@ -235,6 +235,12 @@ namespace llarp
return m_Pending.size();
}
+ int
+ GetUDPSocket() const
+ {
+ return m_udp.fd;
+ }
+
private:
void
OnTick();
diff --git a/llarp/net/ip_packet.cpp b/llarp/net/ip_packet.cpp
index c9bf89f17..c3cb1f239 100644
--- a/llarp/net/ip_packet.cpp
+++ b/llarp/net/ip_packet.cpp
@@ -124,8 +124,8 @@ namespace llarp
return ExpandV4Lan(srcv4());
}
- static uint16_t
- ipchksum(const byte_t* buf, size_t sz, uint32_t sum = 0)
+ uint16_t
+ ipchksum(const byte_t* buf, size_t sz, uint32_t sum)
{
while (sz > 1)
{
diff --git a/llarp/net/ip_packet.hpp b/llarp/net/ip_packet.hpp
index ec0faaa0f..b65df40cd 100644
--- a/llarp/net/ip_packet.hpp
+++ b/llarp/net/ip_packet.hpp
@@ -280,6 +280,9 @@ namespace llarp
MakeICMPUnreachable() const;
};
+ /// generate ip checksum
+ uint16_t
+ ipchksum(const byte_t* buf, size_t sz, uint32_t sum = 0);
} // namespace net
} // namespace llarp
diff --git a/llarp/net/net.cpp b/llarp/net/net.cpp
index d795e4d93..aeeeb08a4 100644
--- a/llarp/net/net.cpp
+++ b/llarp/net/net.cpp
@@ -19,6 +19,14 @@
#include
#include
+#if ANDROID
+#include
+#else
+#ifndef _WIN32
+#include
+#endif
+#endif
+
#include
#include
diff --git a/llarp/net/net.hpp b/llarp/net/net.hpp
index c65243a1e..4cd593fa6 100644
--- a/llarp/net/net.hpp
+++ b/llarp/net/net.hpp
@@ -26,6 +26,10 @@
#define inet_aton(x, y) inet_pton(AF_INET, x, y)
#endif
+#ifndef _WIN32
+#include
+#endif
+
bool
operator==(const sockaddr& a, const sockaddr& b);
diff --git a/llarp/net/net_int.cpp b/llarp/net/net_int.cpp
index 5642201ba..72de8ca37 100644
--- a/llarp/net/net_int.cpp
+++ b/llarp/net/net_int.cpp
@@ -11,6 +11,13 @@ namespace llarp
return xntohl(n);
}
+ template <>
+ nuint16_t
+ ToNet(huint16_t h)
+ {
+ return xhtons(h);
+ }
+
template <>
nuint32_t
ToNet(huint32_t h)
diff --git a/llarp/net/sock_addr.cpp b/llarp/net/sock_addr.cpp
index 416af3fdb..cb09d6506 100644
--- a/llarp/net/sock_addr.cpp
+++ b/llarp/net/sock_addr.cpp
@@ -48,6 +48,14 @@ namespace llarp
{
setPort(port);
}
+
+ SockAddr::SockAddr(uint32_t ip, uint16_t port)
+ {
+ init();
+ setIPv4(ip);
+ setPort(ntohs(port));
+ }
+
SockAddr::SockAddr(std::string_view addr)
{
init();
@@ -292,6 +300,28 @@ namespace llarp
return m_empty;
}
+ uint32_t
+ SockAddr::getIPv4() const
+ {
+ return m_addr4.sin_addr.s_addr;
+ }
+
+ void
+ SockAddr::setIPv4(uint32_t ip)
+ {
+ m_addr.sin6_family = AF_INET;
+
+ uint8_t* ip6 = m_addr.sin6_addr.s6_addr;
+ llarp::Zero(ip6, sizeof(m_addr.sin6_addr.s6_addr));
+
+ applyIPv4MapBytes();
+
+ std::memcpy(ip6 + 12, &ip, 4);
+ m_addr4.sin_addr.s_addr = ip;
+ m_addr4.sin_family = AF_INET;
+ m_empty = false;
+ }
+
void
SockAddr::setIPv4(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
{
diff --git a/llarp/net/sock_addr.hpp b/llarp/net/sock_addr.hpp
index 15696ae30..6e0be7e69 100644
--- a/llarp/net/sock_addr.hpp
+++ b/llarp/net/sock_addr.hpp
@@ -31,6 +31,7 @@ namespace llarp
SockAddr(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint16_t port);
SockAddr(std::string_view addr);
SockAddr(std::string_view addr, uint16_t port);
+ SockAddr(uint32_t ip, uint16_t port);
SockAddr(const AddressInfo&);
@@ -81,6 +82,9 @@ namespace llarp
setIPv4(uint8_t a, uint8_t b, uint8_t c, uint8_t d);
/// port is in host order
+ void
+ setIPv4(uint32_t ip);
+
void
setPort(uint16_t port);
@@ -90,6 +94,9 @@ namespace llarp
huint128_t
asIPv6() const;
+ /// in network order
+ uint32_t
+ getIPv4() const;
huint32_t
asIPv4() const;
diff --git a/llarp/router/abstractrouter.hpp b/llarp/router/abstractrouter.hpp
index 193d541e7..26625de25 100644
--- a/llarp/router/abstractrouter.hpp
+++ b/llarp/router/abstractrouter.hpp
@@ -318,6 +318,11 @@ namespace llarp
HandleRouterEvent(std::move(event));
}
+#if defined(ANDROID)
+ virtual int
+ GetOutboundUDPSocket() const = 0;
+#endif
+
protected:
/// Virtual function to handle RouterEvent. HiveRouter overrides this in
/// order to inject the event. The default implementation in Router simply
diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp
index 6e4c237bc..e0641f12b 100644
--- a/llarp/router/router.cpp
+++ b/llarp/router/router.cpp
@@ -1345,6 +1345,9 @@ namespace llarp
if (not link->Configure(netloop(), "*", af, m_OutboundPort))
continue;
+#if defined(ANDROID)
+ m_OutboundUDPSocket = link->GetUDPSocket();
+#endif
_linkManager.AddLink(std::move(link), false);
return true;
}
diff --git a/llarp/router/router.hpp b/llarp/router/router.hpp
index 5fe527c57..d5070649a 100644
--- a/llarp/router/router.hpp
+++ b/llarp/router/router.hpp
@@ -519,6 +519,16 @@ namespace llarp
return m_Config;
}
+#if defined(ANDROID)
+ int m_OutboundUDPSocket = -1;
+
+ int
+ GetOutboundUDPSocket() const override
+ {
+ return m_OutboundUDPSocket;
+ }
+#endif
+
private:
std::atomic _stopping;
std::atomic _running;
diff --git a/llarp/vpn/android.hpp b/llarp/vpn/android.hpp
new file mode 100644
index 000000000..e7917011a
--- /dev/null
+++ b/llarp/vpn/android.hpp
@@ -0,0 +1,84 @@
+#pragma once
+
+#include
+#include
+
+#include
+#include
+#include
+
+namespace llarp::vpn
+{
+ class AndroidInterface : public NetworkInterface
+ {
+ const int m_fd;
+ const InterfaceInfo m_Info; // likely 100% ignored on android, at least for now
+
+ public:
+ AndroidInterface(InterfaceInfo info, int fd) : m_fd(fd), m_Info(info)
+ {
+ if (m_fd == -1)
+ throw std::runtime_error(
+ "Error opening AndroidVPN layer FD: " + std::string{strerror(errno)});
+ }
+
+ virtual ~AndroidInterface()
+ {
+ if (m_fd != -1)
+ ::close(m_fd);
+ }
+
+ int
+ PollFD() const override
+ {
+ return m_fd;
+ }
+
+ net::IPPacket
+ ReadNextPacket() override
+ {
+ net::IPPacket pkt;
+ const auto sz = read(m_fd, pkt.buf, sizeof(pkt.buf));
+ if (sz >= 0)
+ pkt.sz = std::min(sz, ssize_t{sizeof(pkt.buf)});
+ return pkt;
+ }
+
+ bool
+ WritePacket(net::IPPacket pkt) override
+ {
+ const auto sz = write(m_fd, pkt.buf, pkt.sz);
+ if (sz <= 0)
+ return false;
+ return sz == static_cast(pkt.sz);
+ }
+
+ bool
+ HasNextPacket() override
+ {
+ return false;
+ }
+
+ std::string
+ IfName() const override
+ {
+ return m_Info.ifname;
+ }
+ };
+
+ class AndroidPlatform : public Platform
+ {
+ const int fd;
+
+ public:
+ AndroidPlatform(llarp::Context* ctx) : fd(ctx->androidFD)
+ {}
+
+ std::shared_ptr
+ ObtainInterface(InterfaceInfo info) override
+ {
+ return std::make_shared(std::move(info), fd);
+ }
+ };
+
+} // namespace llarp::vpn
diff --git a/llarp/vpn/packet_router.cpp b/llarp/vpn/packet_router.cpp
new file mode 100644
index 000000000..aca5a5060
--- /dev/null
+++ b/llarp/vpn/packet_router.cpp
@@ -0,0 +1,81 @@
+#include
+
+namespace llarp::vpn
+{
+ struct UDPPacketHandler : public Layer4Handler
+ {
+ PacketHandlerFunc m_BaseHandler;
+ std::unordered_map m_LocalPorts;
+
+ explicit UDPPacketHandler(PacketHandlerFunc baseHandler) : m_BaseHandler{std::move(baseHandler)}
+ {}
+
+ void
+ AddSubHandler(nuint16_t localport, PacketHandlerFunc handler) override
+ {
+ m_LocalPorts.emplace(localport, std::move(handler));
+ }
+
+ void
+ HandleIPPacket(llarp::net::IPPacket pkt) override
+ {
+ const uint8_t* ptr = pkt.buf + (pkt.Header()->ihl * 4) + 2;
+ const nuint16_t dstPort{*reinterpret_cast(ptr)};
+ if (auto itr = m_LocalPorts.find(dstPort); itr != m_LocalPorts.end())
+ {
+ itr->second(std::move(pkt));
+ }
+ else
+ m_BaseHandler(std::move(pkt));
+ }
+ };
+
+ struct GenericLayer4Handler : public Layer4Handler
+ {
+ PacketHandlerFunc m_BaseHandler;
+
+ explicit GenericLayer4Handler(PacketHandlerFunc baseHandler)
+ : m_BaseHandler{std::move(baseHandler)}
+ {}
+
+ void
+ HandleIPPacket(llarp::net::IPPacket pkt) override
+ {
+ m_BaseHandler(std::move(pkt));
+ }
+ };
+
+ PacketRouter::PacketRouter(PacketHandlerFunc baseHandler) : m_BaseHandler{std::move(baseHandler)}
+ {}
+
+ void
+ PacketRouter::HandleIPPacket(llarp::net::IPPacket pkt)
+ {
+ const auto proto = pkt.Header()->protocol;
+ if (const auto itr = m_IPProtoHandler.find(proto); itr != m_IPProtoHandler.end())
+ {
+ itr->second->HandleIPPacket(std::move(pkt));
+ }
+ else
+ m_BaseHandler(std::move(pkt));
+ }
+
+ void
+ PacketRouter::AddUDPHandler(huint16_t localport, PacketHandlerFunc func)
+ {
+ constexpr byte_t udp_proto = 0x11;
+
+ if (m_IPProtoHandler.find(udp_proto) == m_IPProtoHandler.end())
+ {
+ m_IPProtoHandler.emplace(udp_proto, std::make_unique(m_BaseHandler));
+ }
+ m_IPProtoHandler[udp_proto]->AddSubHandler(ToNet(localport), func);
+ }
+
+ void
+ PacketRouter::AddIProtoHandler(uint8_t proto, PacketHandlerFunc func)
+ {
+ m_IPProtoHandler[proto] = std::make_unique(std::move(func));
+ }
+
+} // namespace llarp::vpn
diff --git a/llarp/vpn/packet_router.hpp b/llarp/vpn/packet_router.hpp
new file mode 100644
index 000000000..6d5bdf9a1
--- /dev/null
+++ b/llarp/vpn/packet_router.hpp
@@ -0,0 +1,42 @@
+#pragma once
+#include
+#include
+#include
+#include
+
+namespace llarp::vpn
+{
+ using PacketHandlerFunc = std::function;
+
+ struct Layer4Handler
+ {
+ virtual ~Layer4Handler() = default;
+
+ virtual void
+ HandleIPPacket(llarp::net::IPPacket pkt) = 0;
+
+ virtual void AddSubHandler(nuint16_t, PacketHandlerFunc){};
+ };
+
+ class PacketRouter
+ {
+ PacketHandlerFunc m_BaseHandler;
+ std::unordered_map> m_IPProtoHandler;
+
+ public:
+ /// baseHandler will be called if no other handlers matches a packet
+ explicit PacketRouter(PacketHandlerFunc baseHandler);
+
+ /// feed in an ip packet for handling
+ void
+ HandleIPPacket(llarp::net::IPPacket pkt);
+
+ /// add a non udp packet handler using ip protocol proto
+ void
+ AddIProtoHandler(uint8_t proto, PacketHandlerFunc func);
+
+ /// helper that adds a udp packet handler for UDP destinted for localport
+ void
+ AddUDPHandler(huint16_t localport, PacketHandlerFunc func);
+ };
+} // namespace llarp::vpn
diff --git a/llarp/vpn/platform.cpp b/llarp/vpn/platform.cpp
index 74cfe8840..f4759f92b 100644
--- a/llarp/vpn/platform.cpp
+++ b/llarp/vpn/platform.cpp
@@ -24,7 +24,7 @@ namespace llarp::vpn
#endif
#ifdef __linux__
#ifdef ANDROID
- plat = std::make_shared();
+ plat = std::make_shared(ctx);
#else
plat = std::make_shared();
#endif
diff --git a/test/iwp/test_iwp_session.cpp b/test/iwp/test_iwp_session.cpp
index e31113bdf..a4c355aec 100644
--- a/test/iwp/test_iwp_session.cpp
+++ b/test/iwp/test_iwp_session.cpp
@@ -10,6 +10,8 @@
#include
#include
+#include
+
#undef LOG_TAG
#define LOG_TAG __FILE__