mirror of
https://github.com/oxen-io/lokinet
synced 2023-12-14 06:53:00 +01:00
Large collection of changes to make android work
- Previous android java and jni code updated to work, but with much love still needed to make it work nicely, e.g. handling when the VPN is turned off. - DNS handling refactored to allow android to intercept and handle DNS requests as we can't set the system DNS to use a high port (and apparently Chrome ignores system DNS settings anyway) - add packet router structure to allow separate handling of specific intercepted traffic, e.g. UDP traffic to port 53 gets handled by our DNS handler rather than being naively forwarded as exit traffic. - For now, android lokinet is exit-only and hard-coded to use exit.loki as its exit. The exit will be configurable before release, but allowing to not use exit-only mode is more of a challenge. - some old gitignore remnants which were matching to things we don't want them to (and are no longer relevant) removed - some minor changes to CI configuration
This commit is contained in:
parent
f2f0486f13
commit
4c630e0437
43 changed files with 1055 additions and 424 deletions
|
@ -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",
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -40,9 +40,6 @@ vsproject/
|
|||
.vs
|
||||
|
||||
daemon.ini
|
||||
lokinet-win32.exe
|
||||
lokinet
|
||||
lokinet.exe
|
||||
|
||||
|
||||
.gradle/
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<service android:name=".LokinetService"
|
||||
<service android:name=".LokinetDaemon"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_VPN_SERVICE">
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
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,
|
||||
LokinetService.class));
|
||||
LokinetDaemon.class));
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.d(LOG_TAG, "VpnService prepared intent NOT RESULT_OK, shit.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
39
android/src/network/loki/lokinet/LokinetConfig.java
Normal file
39
android/src/network/loki/lokinet/LokinetConfig.java
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
167
android/src/network/loki/lokinet/LokinetDaemon.java
Normal file
167
android/src/network/loki/lokinet/LokinetDaemon.java
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package network.loki.lokinet;
|
||||
|
||||
|
||||
import android.net.VpnService;
|
||||
|
||||
public class LokinetService extends VpnService
|
||||
{
|
||||
|
||||
}
|
|
@ -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"
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -99,6 +99,14 @@ namespace llarp
|
|||
virtual std::shared_ptr<llarp::vpn::Platform>
|
||||
makeVPNPlatform();
|
||||
|
||||
#ifdef ANDROID
|
||||
|
||||
int androidFD = -1;
|
||||
|
||||
int
|
||||
GetUDPSocket();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Config> config = nullptr;
|
||||
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
#include "network_loki_lokinet_LokinetConfig.h"
|
||||
#include <llarp.hpp>
|
||||
#include <config/config.hpp>
|
||||
#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<llarp::Config*>(
|
||||
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<llarp::Config>(env, self);
|
||||
if (conf == nullptr)
|
||||
return JNI_FALSE;
|
||||
return VisitStringAsStringView<jboolean>(env, fname, [conf](std::string_view val) -> jboolean {
|
||||
if (conf->Load(val, false, llarp::GetDefaultDataDir()))
|
||||
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<llarp::Config>(env, self);
|
||||
if (conf == nullptr)
|
||||
return JNI_FALSE;
|
||||
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<std::string>(env, section, convert);
|
||||
const auto k = VisitStringAsStringView<std::string>(env, key, convert);
|
||||
const auto v = VisitStringAsStringView<std::string>(env, value, convert);
|
||||
|
||||
auto conf = GetImpl<llarp::Config>(env, self);
|
||||
if (conf)
|
||||
{
|
||||
conf->AddDefault(sect, k, v);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
#include "lokinet_jni_common.hpp"
|
||||
#include "lokinet_jni_vpnio.hpp"
|
||||
#include <llarp.hpp>
|
||||
#include <config/config.hpp>
|
||||
|
||||
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<llarp::Config>(*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<llarp::Context>(env, self);
|
||||
auto impl = GetImpl<lokinet_jni_vpnio>(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<int>(env, self, "m_FD");
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_network_loki_lokinet_LokinetDaemon_GetUDPSocket(JNIEnv* env, jobject self)
|
||||
{
|
||||
auto ptr = GetImpl<llarp::Context>(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());
|
||||
}
|
||||
}
|
|
@ -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<T>(env, buffer);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
||||
|
|
|
@ -1020,6 +1020,12 @@ namespace llarp
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Config::AddDefault(std::string section, std::string key, std::string val)
|
||||
{
|
||||
m_Additional.emplace_back(std::array<std::string, 3>{section, key, val});
|
||||
}
|
||||
|
||||
bool
|
||||
Config::Load(std::optional<fs::path> 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)
|
||||
{
|
||||
|
|
|
@ -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<std::array<std::string, 3>> m_Additional;
|
||||
ConfigParser m_Parser;
|
||||
const fs::path m_DataDir;
|
||||
};
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -5,49 +5,45 @@
|
|||
#include <array>
|
||||
#include <utility>
|
||||
|
||||
namespace llarp
|
||||
namespace llarp::dns
|
||||
{
|
||||
namespace dns
|
||||
static std::vector<byte_t>
|
||||
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)
|
||||
std::array<byte_t, 1500> tmp = {{0}};
|
||||
llarp_buffer_t buf{tmp};
|
||||
if (not msg.Encode(&buf))
|
||||
throw std::runtime_error("cannot encode dns message");
|
||||
std::vector<byte_t> 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_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;
|
||||
m_Server.recvfrom = &HandleUDP;
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::Stop()
|
||||
PacketHandler::Stop()
|
||||
{
|
||||
if (m_UnboundResolver)
|
||||
m_UnboundResolver->Stop();
|
||||
}
|
||||
|
||||
bool
|
||||
Proxy::Start(const IpAddress& addr, const std::vector<IpAddress>& resolvers)
|
||||
Proxy::Start(SockAddr addr, std::vector<IpAddress> resolvers)
|
||||
{
|
||||
if (resolvers.size())
|
||||
{
|
||||
if (not SetupUnboundResolver(resolvers))
|
||||
{
|
||||
llarp::LogError("Failed to add upstream resolvers during DNS server setup.");
|
||||
if (not PacketHandler::Start(addr, std::move(resolvers)))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return (llarp_ev_add_udp(m_ServerLoop, &m_Server, addr.createSockAddr()) == 0);
|
||||
return (llarp_ev_add_udp(m_Loop, &m_Server, addr) == 0);
|
||||
}
|
||||
|
||||
static Proxy::Buffer_t
|
||||
|
@ -59,35 +55,15 @@ namespace llarp
|
|||
}
|
||||
|
||||
void
|
||||
Proxy::HandleUDPRecv_server(llarp_udp_io* u, const SockAddr& from, ManagedBuffer buf)
|
||||
Proxy::HandleUDP(llarp_udp_io* u, const SockAddr& from, ManagedBuffer buf)
|
||||
{
|
||||
Buffer_t msgbuf = CopyBuffer(buf.underlying);
|
||||
auto self = static_cast<Proxy*>(u->user);
|
||||
self->HandlePktServer(from, msgbuf);
|
||||
self->HandlePacket(from, from, std::move(msgbuf));
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::HandleUDPRecv_client(llarp_udp_io* u, const SockAddr& from, ManagedBuffer buf)
|
||||
{
|
||||
Buffer_t msgbuf = CopyBuffer(buf.underlying);
|
||||
auto self = static_cast<Proxy*>(u->user)->shared_from_this();
|
||||
LogicCall(
|
||||
self->m_ServerLogic, [self, from, msgbuf]() { self->HandlePktClient(from, msgbuf); });
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::Restart()
|
||||
PacketHandler::Restart()
|
||||
{
|
||||
if (m_UnboundResolver)
|
||||
{
|
||||
|
@ -97,26 +73,33 @@ namespace llarp
|
|||
}
|
||||
|
||||
bool
|
||||
Proxy::SetupUnboundResolver(const std::vector<IpAddress>& resolvers)
|
||||
PacketHandler::Start(SockAddr, std::vector<IpAddress> resolvers)
|
||||
{
|
||||
auto failFunc = [self = weak_from_this()](SockAddr to, Message msg) {
|
||||
return SetupUnboundResolver(std::move(resolvers));
|
||||
}
|
||||
|
||||
bool
|
||||
PacketHandler::SetupUnboundResolver(std::vector<IpAddress> resolvers)
|
||||
{
|
||||
auto failFunc = [self = weak_from_this()](SockAddr from, SockAddr to, Message msg) {
|
||||
auto this_ptr = self.lock();
|
||||
if (this_ptr)
|
||||
{
|
||||
this_ptr->SendServerMessageTo(to, std::move(msg));
|
||||
this_ptr->SendServerMessageBufferTo(from, to, MessageToBuffer(std::move(msg)));
|
||||
}
|
||||
};
|
||||
|
||||
auto replyFunc = [self = weak_from_this()](SockAddr to, std::vector<byte_t> buf) {
|
||||
auto replyFunc = [self = weak_from_this()](
|
||||
SockAddr from, SockAddr to, std::vector<byte_t> buf) {
|
||||
auto this_ptr = self.lock();
|
||||
if (this_ptr)
|
||||
{
|
||||
this_ptr->HandleUpstreamResponse(to, std::move(buf));
|
||||
this_ptr->SendServerMessageBufferTo(from, to, std::move(buf));
|
||||
}
|
||||
};
|
||||
|
||||
m_UnboundResolver = std::make_shared<UnboundResolver>(
|
||||
m_ServerLoop, std::move(replyFunc), std::move(failFunc));
|
||||
m_UnboundResolver =
|
||||
std::make_shared<UnboundResolver>(m_Logic, std::move(replyFunc), std::move(failFunc));
|
||||
if (not m_UnboundResolver->Init())
|
||||
{
|
||||
llarp::LogError("Failed to initialize upstream DNS resolver.");
|
||||
|
@ -131,125 +114,60 @@ namespace llarp
|
|||
m_UnboundResolver = nullptr;
|
||||
return false;
|
||||
}
|
||||
m_Resolvers.emplace(resolver);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::HandleTick(llarp_udp_io*)
|
||||
{}
|
||||
|
||||
void
|
||||
Proxy::SendServerMessageBufferTo(const SockAddr& to, const llarp_buffer_t& buf)
|
||||
Proxy::SendServerMessageBufferTo(SockAddr, SockAddr to, Buffer_t buf)
|
||||
{
|
||||
if (llarp_ev_udp_sendto(&m_Server, to, buf) < 0)
|
||||
llarp::LogError("dns reply failed");
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::SendServerMessageTo(const SockAddr& to, Message msg)
|
||||
bool
|
||||
PacketHandler::ShouldHandlePacket(SockAddr to, SockAddr from, Buffer_t buf) const
|
||||
{
|
||||
auto self = shared_from_this();
|
||||
LogicCall(m_ServerLogic, [to, msg = std::move(msg), self]() {
|
||||
std::array<byte_t, 1500> 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");
|
||||
});
|
||||
}
|
||||
(void)from;
|
||||
|
||||
void
|
||||
Proxy::HandleUpstreamResponse(SockAddr to, std::vector<byte_t> buf)
|
||||
{
|
||||
auto self = shared_from_this();
|
||||
LogicCall(m_ServerLogic, [to, buffer = std::move(buf), self]() {
|
||||
llarp_buffer_t buf(buffer);
|
||||
self->SendServerMessageBufferTo(to, buf);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::SendClientMessageTo(const SockAddr& to, Message msg)
|
||||
{
|
||||
auto self = shared_from_this();
|
||||
LogicCall(m_ClientLogic, [to, msg, self]() {
|
||||
std::array<byte_t, 1500> 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");
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::HandlePktClient(const SockAddr& from, Buffer_t buf)
|
||||
{
|
||||
llarp_buffer_t pkt(buf);
|
||||
MessageHeader hdr;
|
||||
if (!hdr.Decode(&pkt))
|
||||
llarp_buffer_t pkt{buf};
|
||||
if (not hdr.Decode(&pkt))
|
||||
{
|
||||
llarp::LogWarn("failed to parse dns header from ", from);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
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))
|
||||
|
||||
Message msg{hdr};
|
||||
if (not msg.Decode(&pkt))
|
||||
{
|
||||
if (m_QueryHandler && m_QueryHandler->ShouldHookDNSMessage(msg))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_QueryHandler and m_QueryHandler->ShouldHookDNSMessage(msg))
|
||||
return true;
|
||||
|
||||
if (m_Resolvers.find(to) != m_Resolvers.end())
|
||||
{
|
||||
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 false;
|
||||
}
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::HandlePktServer(const SockAddr& from, Buffer_t buf)
|
||||
PacketHandler::HandlePacket(SockAddr resolver, SockAddr from, Buffer_t buf)
|
||||
{
|
||||
MessageHeader hdr;
|
||||
llarp_buffer_t pkt(buf);
|
||||
if (!hdr.Decode(&pkt))
|
||||
llarp_buffer_t pkt{buf};
|
||||
if (not hdr.Decode(&pkt))
|
||||
{
|
||||
llarp::LogWarn("failed to parse dns header from ", from);
|
||||
return;
|
||||
}
|
||||
|
||||
Message msg(hdr);
|
||||
if (!msg.Decode(&pkt))
|
||||
if (not msg.Decode(&pkt))
|
||||
{
|
||||
llarp::LogWarn("failed to parse dns message from ", from);
|
||||
return;
|
||||
|
@ -268,17 +186,17 @@ namespace llarp
|
|||
// yea it is, let's turn off DoH because god is dead.
|
||||
msg.AddNXReply();
|
||||
// press F to pay respects
|
||||
SendServerMessageTo(from, std::move(msg));
|
||||
SendServerMessageBufferTo(resolver, from, MessageToBuffer(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)))
|
||||
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))
|
||||
{
|
||||
llarp::LogWarn("failed to handle hooked dns");
|
||||
}
|
||||
|
@ -288,14 +206,11 @@ namespace llarp
|
|||
// no upstream resolvers
|
||||
// let's serv fail it
|
||||
msg.AddServFail();
|
||||
|
||||
SendServerMessageTo(from, std::move(msg));
|
||||
SendServerMessageBufferTo(resolver, from, MessageToBuffer(std::move(msg)));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_UnboundResolver->Lookup(from, std::move(msg));
|
||||
m_UnboundResolver->Lookup(resolver, from, std::move(msg));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
||||
} // namespace llarp::dns
|
||||
|
|
|
@ -27,18 +27,17 @@ namespace llarp
|
|||
HandleHookedDNSMessage(Message query, std::function<void(Message)> sendReply) = 0;
|
||||
};
|
||||
|
||||
struct Proxy : public std::enable_shared_from_this<Proxy>
|
||||
struct PacketHandler : public std::enable_shared_from_this<PacketHandler>
|
||||
{
|
||||
using Logic_ptr = std::shared_ptr<Logic>;
|
||||
Proxy(
|
||||
llarp_ev_loop_ptr serverLoop,
|
||||
Logic_ptr serverLogic,
|
||||
llarp_ev_loop_ptr clientLoop,
|
||||
Logic_ptr clientLogic,
|
||||
IQueryHandler* handler);
|
||||
using Buffer_t = std::vector<uint8_t>;
|
||||
|
||||
bool
|
||||
Start(const IpAddress& addr, const std::vector<IpAddress>& resolvers);
|
||||
explicit PacketHandler(Logic_ptr logic, IQueryHandler* handler);
|
||||
|
||||
virtual ~PacketHandler() = default;
|
||||
|
||||
virtual bool
|
||||
Start(SockAddr localaddr, std::vector<IpAddress> upstreamResolvers);
|
||||
|
||||
void
|
||||
Stop();
|
||||
|
@ -46,80 +45,50 @@ namespace llarp
|
|||
void
|
||||
Restart();
|
||||
|
||||
using Buffer_t = std::vector<uint8_t>;
|
||||
|
||||
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);
|
||||
|
||||
/// low level ticker
|
||||
static void
|
||||
HandleTick(llarp_udp_io*);
|
||||
|
||||
void
|
||||
HandlePktClient(const SockAddr& from, Buffer_t buf);
|
||||
|
||||
void
|
||||
HandlePktServer(const SockAddr& from, Buffer_t buf);
|
||||
|
||||
void
|
||||
SendClientMessageTo(const SockAddr& to, Message msg);
|
||||
|
||||
void
|
||||
SendServerMessageBufferTo(const SockAddr& to, const llarp_buffer_t& buf);
|
||||
|
||||
void
|
||||
SendServerMessageTo(const SockAddr& to, Message msg);
|
||||
|
||||
void
|
||||
HandleUpstreamResponse(SockAddr to, std::vector<byte_t> buf);
|
||||
|
||||
void
|
||||
HandleUpstreamFailure(const SockAddr& to, Message msg);
|
||||
|
||||
IpAddress
|
||||
PickRandomResolver() const;
|
||||
HandlePacket(SockAddr resolver, SockAddr from, Buffer_t buf);
|
||||
|
||||
bool
|
||||
SetupUnboundResolver(const std::vector<IpAddress>& resolvers);
|
||||
ShouldHandlePacket(SockAddr to, SockAddr from, Buffer_t buf) const;
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
SendServerMessageBufferTo(SockAddr from, SockAddr to, Buffer_t buf) = 0;
|
||||
|
||||
private:
|
||||
void
|
||||
HandleUpstreamFailure(SockAddr from, SockAddr to, Message msg);
|
||||
|
||||
bool
|
||||
SetupUnboundResolver(std::vector<IpAddress> resolvers);
|
||||
|
||||
IQueryHandler* const m_QueryHandler;
|
||||
std::set<IpAddress> m_Resolvers;
|
||||
std::shared_ptr<UnboundResolver> m_UnboundResolver;
|
||||
Logic_ptr m_Logic;
|
||||
};
|
||||
|
||||
struct Proxy : public PacketHandler
|
||||
{
|
||||
using Logic_ptr = std::shared_ptr<Logic>;
|
||||
explicit Proxy(llarp_ev_loop_ptr loop, Logic_ptr logic, IQueryHandler* handler);
|
||||
|
||||
bool
|
||||
Start(SockAddr localaddr, std::vector<IpAddress> resolvers) override;
|
||||
|
||||
using Buffer_t = std::vector<uint8_t>;
|
||||
|
||||
protected:
|
||||
void
|
||||
SendServerMessageBufferTo(SockAddr from, SockAddr to, Buffer_t buf) override;
|
||||
|
||||
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<IpAddress> m_Resolvers;
|
||||
std::shared_ptr<UnboundResolver> 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<TX, IpAddress, TX::Hash> m_Forwarded;
|
||||
llarp_ev_loop_ptr m_Loop;
|
||||
};
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace llarp::dns
|
|||
std::weak_ptr<UnboundResolver> 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> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,9 @@
|
|||
|
||||
namespace llarp::dns
|
||||
{
|
||||
using ReplyFunction = std::function<void(SockAddr source, std::vector<byte_t> buf)>;
|
||||
using FailFunction = std::function<void(SockAddr source, Message msg)>;
|
||||
using ReplyFunction =
|
||||
std::function<void(SockAddr resolver, SockAddr source, std::vector<byte_t> buf)>;
|
||||
using FailFunction = std::function<void(SockAddr resolver, SockAddr source, Message msg)>;
|
||||
|
||||
class UnboundResolver : public std::enable_shared_from_this<UnboundResolver>
|
||||
{
|
||||
|
@ -28,7 +29,6 @@ namespace llarp::dns
|
|||
std::atomic<bool> started;
|
||||
std::unique_ptr<std::thread> 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> 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
|
||||
|
|
|
@ -15,8 +15,7 @@ namespace llarp
|
|||
{
|
||||
ExitEndpoint::ExitEndpoint(const std::string& name, AbstractRouter* r)
|
||||
: m_Router(r)
|
||||
, m_Resolver(std::make_shared<dns::Proxy>(
|
||||
r->netloop(), r->logic(), r->netloop(), r->logic(), this))
|
||||
, m_Resolver(std::make_shared<dns::Proxy>(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;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <rpc/endpoint_rpc.hpp>
|
||||
|
||||
#include <util/str.hpp>
|
||||
#include <util/endian.hpp>
|
||||
|
||||
#include <dns/srv_data.hpp>
|
||||
|
||||
|
@ -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<byte_t> 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<dns::Proxy>(
|
||||
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<DnsHandler>(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<const uint16_t*>(ptr)};
|
||||
const SockAddr laddr{dst.n, *reinterpret_cast<const uint16_t*>(ptr + 2)};
|
||||
|
||||
std::vector<byte_t> 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<dns::Proxy>(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)));
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <service/endpoint.hpp>
|
||||
#include <util/codel.hpp>
|
||||
#include <util/thread/threading.hpp>
|
||||
#include <vpn/packet_router.hpp>
|
||||
|
||||
#include <future>
|
||||
#include <queue>
|
||||
|
@ -232,7 +233,7 @@ namespace llarp
|
|||
reply(*query);
|
||||
}
|
||||
/// our dns resolver
|
||||
std::shared_ptr<dns::Proxy> m_Resolver;
|
||||
std::shared_ptr<dns::PacketHandler> m_Resolver;
|
||||
|
||||
/// maps ip address to timestamp last active
|
||||
std::unordered_map<huint128_t, llarp_time_t> m_IPActivity;
|
||||
|
@ -258,6 +259,8 @@ namespace llarp
|
|||
std::string m_IfName;
|
||||
|
||||
std::shared_ptr<vpn::NetworkInterface> m_NetIf;
|
||||
|
||||
std::unique_ptr<vpn::PacketRouter> m_PacketRouter;
|
||||
};
|
||||
|
||||
} // namespace handlers
|
||||
|
|
|
@ -235,6 +235,12 @@ namespace llarp
|
|||
return m_Pending.size();
|
||||
}
|
||||
|
||||
int
|
||||
GetUDPSocket() const
|
||||
{
|
||||
return m_udp.fd;
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
OnTick();
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -19,6 +19,14 @@
|
|||
#include <util/logging/logger.hpp>
|
||||
#include <util/str.hpp>
|
||||
|
||||
#if ANDROID
|
||||
#include <android/ifaddrs.h>
|
||||
#else
|
||||
#ifndef _WIN32
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
#include <list>
|
||||
|
||||
|
|
|
@ -26,6 +26,10 @@
|
|||
#define inet_aton(x, y) inet_pton(AF_INET, x, y)
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
bool
|
||||
operator==(const sockaddr& a, const sockaddr& b);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<bool> _stopping;
|
||||
std::atomic<bool> _running;
|
||||
|
|
84
llarp/vpn/android.hpp
Normal file
84
llarp/vpn/android.hpp
Normal file
|
@ -0,0 +1,84 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <ev/vpn.hpp>
|
||||
#include <vpn/common.hpp>
|
||||
#include <llarp.hpp>
|
||||
|
||||
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<ssize_t>(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<NetworkInterface>
|
||||
ObtainInterface(InterfaceInfo info) override
|
||||
{
|
||||
return std::make_shared<AndroidInterface>(std::move(info), fd);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace llarp::vpn
|
81
llarp/vpn/packet_router.cpp
Normal file
81
llarp/vpn/packet_router.cpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
#include <vpn/packet_router.hpp>
|
||||
|
||||
namespace llarp::vpn
|
||||
{
|
||||
struct UDPPacketHandler : public Layer4Handler
|
||||
{
|
||||
PacketHandlerFunc m_BaseHandler;
|
||||
std::unordered_map<nuint16_t, PacketHandlerFunc> 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<const uint16_t*>(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<UDPPacketHandler>(m_BaseHandler));
|
||||
}
|
||||
m_IPProtoHandler[udp_proto]->AddSubHandler(ToNet(localport), func);
|
||||
}
|
||||
|
||||
void
|
||||
PacketRouter::AddIProtoHandler(uint8_t proto, PacketHandlerFunc func)
|
||||
{
|
||||
m_IPProtoHandler[proto] = std::make_unique<GenericLayer4Handler>(std::move(func));
|
||||
}
|
||||
|
||||
} // namespace llarp::vpn
|
42
llarp/vpn/packet_router.hpp
Normal file
42
llarp/vpn/packet_router.hpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
#include <net/net_int.hpp>
|
||||
#include <net/ip_packet.hpp>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace llarp::vpn
|
||||
{
|
||||
using PacketHandlerFunc = std::function<void(llarp::net::IPPacket)>;
|
||||
|
||||
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<uint8_t, std::unique_ptr<Layer4Handler>> 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
|
|
@ -24,7 +24,7 @@ namespace llarp::vpn
|
|||
#endif
|
||||
#ifdef __linux__
|
||||
#ifdef ANDROID
|
||||
plat = std::make_shared<vpn::AndroidPlatform>();
|
||||
plat = std::make_shared<vpn::AndroidPlatform>(ctx);
|
||||
#else
|
||||
plat = std::make_shared<vpn::LinuxPlatform>();
|
||||
#endif
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include <messages/discard.hpp>
|
||||
#include <util/time.hpp>
|
||||
|
||||
#include <net/net_if.hpp>
|
||||
|
||||
#undef LOG_TAG
|
||||
#define LOG_TAG __FILE__
|
||||
|
||||
|
|
Loading…
Reference in a new issue