add initial jni stuff for lokinet android. i fucking hate android so god damn much.

pull/155/head
Jeff Becker 6 years ago
parent b323665140
commit 7e4d74cbfc
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

@ -50,7 +50,9 @@ endif(WIN32)
if(DEBIAN) if(DEBIAN)
add_definitions(-DDEBIAN) add_definitions(-DDEBIAN)
else() else()
set(CRYPTO_FLAGS -march=native) if( NOT ANDROID)
set(CRYPTO_FLAGS -march=native)
endif()
endif() endif()
set(CMAKE_THREAD_PREFER_PTHREAD TRUE) set(CMAKE_THREAD_PREFER_PTHREAD TRUE)

@ -165,6 +165,7 @@ android-gradle: android-gradle-prepare
cd $(ANDROID_DIR) && JAVA_HOME=$(JAVA_HOME) $(GRADLE) clean assemble cd $(ANDROID_DIR) && JAVA_HOME=$(JAVA_HOME) $(GRADLE) clean assemble
android: android-gradle android: android-gradle
cp -f $(ANDROID_DIR)/build/outputs/apk/*.apk $(REPO)
windows-configure: clean windows-configure: clean
mkdir -p '$(BUILD_ROOT)' mkdir -p '$(BUILD_ROOT)'

@ -13,7 +13,8 @@
<uses-permission android:name="android.permission.INTERNET" /> <!-- normal perm, per https://developer.android.com/guide/topics/permissions/normal-permissions.html --> <uses-permission android:name="android.permission.INTERNET" /> <!-- normal perm, per https://developer.android.com/guide/topics/permissions/normal-permissions.html -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- normal perm --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- normal perm -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application <application
android:allowBackup="true" android:allowBackup="true"
@ -26,9 +27,9 @@
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<activity <activity
android:name=".PermsAskerActivity" android:name=".LokiNetActivity"
android:label="@string/app_name"> android:label="@string/app_name">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
@ -36,22 +37,14 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <service android:name=".LokinetService"
android:name=".LokiNetActivity" android:enabled="true"
android:label="@string/app_name" /> android:exported="true"
android:permission="android.permission.BIND_VPN_SERVICE">
<service <intent-filter>
android:name=".ForegroundService" <action android:name="android.net.VpnService"/>
android:enabled="true" /> </intent-filter>
</service>
<activity
android:name=".PermsExplanationActivity"
android:label="@string/title_activity_perms_asker_prompt"
android:parentActivityName=".PermsAskerActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="network.loki.lokinet.PermsAskerActivity" />
</activity>
</application> </application>
</manifest> </manifest>

@ -34,6 +34,7 @@ android {
cmake { cmake {
targets "lokinetandroid" targets "lokinetandroid"
arguments "-DANDROID=ON", "-DANDROID_STL=c++_static" arguments "-DANDROID=ON", "-DANDROID_STL=c++_static"
cppFlags "-fexceptions"
} }
} }
packagingOptions{ packagingOptions{

@ -22,6 +22,6 @@
android:id="@+id/button_request_write_ext_storage_perms" android:id="@+id/button_request_write_ext_storage_perms"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Retry requesting the SD card write permissions" android:text="Retry requesting VPN"
android:visibility="gone"/> android:visibility="gone"/>
</LinearLayout> </LinearLayout>

@ -15,7 +15,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/horizontal_page_margin" android:layout_marginBottom="@dimen/horizontal_page_margin"
android:text="SD card write access is required to write the keys and other files on an SD card." android:text="VPN permissions are required for lokinet usage."
/> />
<Button <Button

@ -12,4 +12,8 @@
<string name="stopped">lokinet has stopped</string> <string name="stopped">lokinet has stopped</string>
<string name="remaining">remaining</string> <string name="remaining">remaining</string>
<string name="title_activity_perms_asker_prompt">Prompt</string> <string name="title_activity_perms_asker_prompt">Prompt</string>
<string name="bootstrap_ok">got bootstrap node info</string>
<string name="bootstrap_fail">failed to bootstrap</string>
<string name="netdb_create_fail">failed to create netdb directory</string>
<string name="vpn_setup_fail">failed to set up vpn tunnel</string>
</resources> </resources>

@ -35,6 +35,8 @@ public class LokiNetActivity extends Activity {
private TextView textView; private TextView textView;
private static final String DefaultBootstrapURL = "https://i2p.rocks/bootstrap.signed"; private static final String DefaultBootstrapURL = "https://i2p.rocks/bootstrap.signed";
private AsyncBootstrap bootstrapper;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -65,14 +67,18 @@ public class LokiNetActivity extends Activity {
} }
} }
public void startLokinet() { public void startLokinet()
{
if(bootstrapper != null)
return;
bootstrapper = new AsyncBootstrap();
bootstrapper.execute(DefaultBootstrapURL);
} }
public void runLokinetService() public void runLokinetService()
{ {
bindService(new Intent(LokiNetActivity.this, startService(new Intent(LokiNetActivity.this,
ForegroundService.class), mConnection, Context.BIND_AUTO_CREATE); LokinetService.class));
} }
@Override @Override
@ -81,29 +87,41 @@ public class LokiNetActivity extends Activity {
textView = null; textView = null;
} }
public File getRootDir()
{
return getFilesDir();
}
private class AsyncBootstrap extends AsyncTask<String, String, String> private class AsyncBootstrap extends AsyncTask<String, String, String>
{ {
public String doInBackground(String ... urls) { public String doInBackground(String ... urls) {
try try
{ {
File bootstrapFile = new File(getCacheDir(), "bootstrap.signed"); File bootstrapFile = new File(getRootDir(), "bootstrap.signed");
URL bootstrapURL = new URL(urls[0]); URL bootstrapURL = new URL(urls[0]);
InputStream instream = bootstrapURL.openStream(); InputStream instream = bootstrapURL.openStream();
writeFile(bootstrapFile, instream); writeFile(bootstrapFile, instream);
instream.close(); instream.close();
return "downloaded"; return getString(R.string.bootstrap_ok);
} }
catch(Exception thrown) catch(Exception thrown)
{ {
return thrown.getLocalizedMessage(); return getString(R.string.bootstrap_fail) + ": " + throwableToString(thrown);
} }
} }
public void onPostExecute(String val) { public void onPostExecute(String val) {
final File configFile = new File(getCacheDir(), "daemon.ini"); textView.setText(val);
runLokinetService(); if(val.equals(getString(R.string.bootstrap_ok)))
runLokinetService();
bootstrapDone();
} }
} }
private void bootstrapDone()
{
bootstrapper = null;
}
private CharSequence throwableToString(Throwable tr) { private CharSequence throwableToString(Throwable tr) {
StringWriter sw = new StringWriter(8192); StringWriter sw = new StringWriter(8192);
PrintWriter pw = new PrintWriter(sw); PrintWriter pw = new PrintWriter(sw);
@ -112,33 +130,6 @@ public class LokiNetActivity extends Activity {
return sw.toString(); return sw.toString();
} }
private ForegroundService boundService;
// private LocalService mBoundService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. Because we have bound to a explicit
// service that we know is running in our own process, we can
// cast its IBinder to a concrete class and directly access it.
boundService = ((ForegroundService.LocalBinder)service).getService();
textView.setText(R.id.loaded);
// Tell the user about this for our demo.
// Toast.makeText(Binding.this, R.string.local_service_connected,
// Toast.LENGTH_SHORT).show();
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
// Because it is running in our same process, we should never
// see this happen.
// mBoundService = null;
// Toast.makeText(Binding.this, R.string.local_service_disconnected,
// Toast.LENGTH_SHORT).show();
}
};
@Override @Override
@ -160,7 +151,6 @@ public class LokiNetActivity extends Activity {
startLokinet(); startLokinet();
return true; return true;
case R.id.action_stop: case R.id.action_stop:
Lokinet_JNI.stopLokinet();
return true; return true;
} }

@ -17,11 +17,23 @@ public class Lokinet_JNI {
*/ */
public static native void stopLokinet(); public static native void stopLokinet();
/** get interface address we want */
public static native String getIfAddr();
/** get interface address range we want */
public static native int getIfRange();
/** /**
* change network status * change network status
*/ */
public static native void onNetworkStateChanged(boolean isConnected); public static native void onNetworkStateChanged(boolean isConnected);
/**
* set vpn network interface fd
* @param fd the file descriptor of the vpn interface
*/
public static native void setVPNFileDescriptor(int fd);
/** /**
* load jni libraries * load jni libraries
*/ */

@ -15,21 +15,22 @@ import java.lang.reflect.Method;
//android.permission.WRITE_EXTERNAL_STORAGE //android.permission.WRITE_EXTERNAL_STORAGE
public class PermsAskerActivity extends Activity { public class PermsAskerActivity extends Activity {
private static final int PERMISSION_WRITE_EXTERNAL_STORAGE = 0; private static final int PERMISSION_VPN = 0;
private Button button_request_write_ext_storage_perms; private Button button_request_write_ext_storage_perms;
private TextView textview_retry; private TextView textview_retry;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
startMainActivity();
/*
//if less than Android 6, no runtime perms req system present //if less than Android 6, no runtime perms req system present
if (android.os.Build.VERSION.SDK_INT < 23) { if (android.os.Build.VERSION.SDK_INT < 23) {
startMainActivity();
return; return;
} }
setContentView(R.layout.activity_perms_asker); setContentView(R.layout.activity_perms_asker);
button_request_write_ext_storage_perms = (Button) findViewById(R.id.button_request_write_ext_storage_perms); button_request_write_ext_storage_perms = (Button) findViewById(R.id.button_request_write_ext_storage_perms);
textview_retry = (TextView) findViewById(R.id.textview_retry); textview_retry = (TextView) findViewById(R.id.textview_retry);
@ -41,6 +42,7 @@ public class PermsAskerActivity extends Activity {
} }
}); });
request_write_ext_storage_perms(); request_write_ext_storage_perms();
*/
} }
private void request_write_ext_storage_perms() { private void request_write_ext_storage_perms() {
@ -63,7 +65,7 @@ public class PermsAskerActivity extends Activity {
Integer resultObj; Integer resultObj;
try { try {
resultObj = (Integer) methodCheckPermission.invoke( resultObj = (Integer) methodCheckPermission.invoke(
this, Manifest.permission.WRITE_EXTERNAL_STORAGE); this, Manifest.permission.BIND_VPN_SERVICE);
} catch (Throwable e) { } catch (Throwable e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -74,7 +76,7 @@ public class PermsAskerActivity extends Activity {
Boolean aBoolean; Boolean aBoolean;
try { try {
aBoolean = (Boolean) method_shouldShowRequestPermissionRationale.invoke(this, aBoolean = (Boolean) method_shouldShowRequestPermissionRationale.invoke(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE); Manifest.permission.BIND_VPN_SERVICE);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -92,8 +94,8 @@ public class PermsAskerActivity extends Activity {
try { try {
method_requestPermissions.invoke(this, method_requestPermissions.invoke(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, new String[]{Manifest.permission.BIND_VPN_SERVICE},
PERMISSION_WRITE_EXTERNAL_STORAGE); PERMISSION_VPN);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -105,7 +107,7 @@ public class PermsAskerActivity extends Activity {
public void onRequestPermissionsResult(int requestCode, public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) { String permissions[], int[] grantResults) {
switch (requestCode) { switch (requestCode) {
case PERMISSION_WRITE_EXTERNAL_STORAGE: { case PERMISSION_VPN: {
// If request is cancelled, the result arrays are empty. // If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) { && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
@ -119,7 +121,7 @@ public class PermsAskerActivity extends Activity {
// permission denied, boo! Disable the // permission denied, boo! Disable the
// functionality that depends on this permission. // functionality that depends on this permission.
textview_retry.setText("SD card write permission denied, you need to allow this to continue"); textview_retry.setText("you need to allow this to continue");
textview_retry.setVisibility(TextView.VISIBLE); textview_retry.setVisibility(TextView.VISIBLE);
button_request_write_ext_storage_perms.setVisibility(Button.VISIBLE); button_request_write_ext_storage_perms.setVisibility(Button.VISIBLE);
} }
@ -158,8 +160,8 @@ public class PermsAskerActivity extends Activity {
} }
try { try {
method_requestPermissions.invoke(this, method_requestPermissions.invoke(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, new String[]{Manifest.permission.BIND_VPN_SERVICE},
PERMISSION_WRITE_EXTERNAL_STORAGE); PERMISSION_VPN);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

@ -35,6 +35,10 @@ extern "C"
void void
llarp_main_signal(struct llarp_main *ptr, int sig); llarp_main_signal(struct llarp_main *ptr, int sig);
/// give main context a vpn file descriptor (android/ios)
void
llarp_main_inject_vpn_fd(struct llarp_main * m, int fd);
/// setup main context /// setup main context
int int
llarp_main_setup(struct llarp_main *ptr); llarp_main_setup(struct llarp_main *ptr);

@ -29,7 +29,7 @@
#define PQ_CIPHERTEXTSIZE crypto_kem_CIPHERTEXTBYTES #define PQ_CIPHERTEXTSIZE crypto_kem_CIPHERTEXTBYTES
#define PQ_PUBKEYSIZE crypto_kem_PUBLICKEYBYTES #define PQ_PUBKEYSIZE crypto_kem_PUBLICKEYBYTES
#define PQ_SECRETKEYSIZE crypto_kem_SECRETKEYBYTES #define PQ_SECRETKEYSIZE crypto_kem_SECRETKEYBYTES
#define PQ_KEYPAIRSIZE (PQ_SECRETKEYSIZE + PQ_SECRETKEYSIZE) #define PQ_KEYPAIRSIZE (PQ_SECRETKEYSIZE + PQ_PUBKEYSIZE)
/// label functors /// label functors

@ -166,6 +166,14 @@ llarp_tcp_acceptor_close(struct llarp_tcp_acceptor *);
#define IFNAMSIZ (16) #define IFNAMSIZ (16)
#endif #endif
struct llarp_fd_promise;
/// wait until the fd promise is set
int
llarp_fd_promise_wait_for_value(struct llarp_fd_promise * promise);
struct llarp_tun_io struct llarp_tun_io
{ {
// TODO: more info? // TODO: more info?
@ -175,6 +183,11 @@ struct llarp_tun_io
void *user; void *user;
void *impl; void *impl;
/// functor for getting a promise that returns the vpn fd
/// dont set me if you don't know how to use this
struct llarp_fd_promise * (*get_fd_promise)(struct llarp_tun_io *);
struct llarp_ev_loop *parent; struct llarp_ev_loop *parent;
/// called when we are able to write right before we write /// called when we are able to write right before we write
/// this happens after reading packets /// this happens after reading packets
@ -189,6 +202,7 @@ struct llarp_tun_io
bool bool
llarp_ev_add_tun(struct llarp_ev_loop *ev, struct llarp_tun_io *tun); llarp_ev_add_tun(struct llarp_ev_loop *ev, struct llarp_tun_io *tun);
/// async write a packet on tun interface /// async write a packet on tun interface
/// returns true if queued, returns false on drop /// returns true if queued, returns false on drop
bool bool

@ -13,6 +13,7 @@ namespace llarp
{ {
namespace handlers namespace handlers
{ {
static const int DefaultTunNetmask = 16; static const int DefaultTunNetmask = 16;
static const char DefaultTunIfname[] = "lokinet0"; static const char DefaultTunIfname[] = "lokinet0";
static const char DefaultTunDstAddr[] = "10.10.0.1"; static const char DefaultTunDstAddr[] = "10.10.0.1";
@ -73,6 +74,7 @@ namespace llarp
#endif #endif
llarp_tun_io tunif; llarp_tun_io tunif;
std::unique_ptr<llarp_fd_promise> Promise;
/// called before writing to tun interface /// called before writing to tun interface
static void static void
@ -168,6 +170,9 @@ namespace llarp
/// up interface /// up interface
std::promise< bool > m_TunSetupResult; std::promise< bool > m_TunSetupResult;
#endif #endif
std::promise<int> m_VPNPromise;
/// DNS server per tun /// DNS server per tun
struct dnsd_context dnsd; struct dnsd_context dnsd;
/// DNS loki lookup subsystem configuration (also holds optional iptracker /// DNS loki lookup subsystem configuration (also holds optional iptracker

@ -21,7 +21,7 @@ llarp_free_router(struct llarp_router **router);
bool bool
llarp_configure_router(struct llarp_router *router, struct llarp_config *conf); llarp_configure_router(struct llarp_router *router, struct llarp_config *conf);
void bool
llarp_run_router(struct llarp_router *router, struct llarp_nodedb *nodedb); llarp_run_router(struct llarp_router *router, struct llarp_nodedb *nodedb);
void void

@ -137,6 +137,10 @@ extern "C"
struct device struct device
{ {
/** set me on ios and android to block on a promise for the fd */
int (*obtain_fd)(struct device *);
/** user data */
void * user;
t_tun tun_fd; t_tun tun_fd;
int ctrl_sock; int ctrl_sock;
int flags; /* ifr.ifr_flags on Unix */ int flags; /* ifr.ifr_flags on Unix */

@ -26,7 +26,7 @@ struct AndroidMain
bool bool
ReloadConfig() ReloadConfig()
{ {
if(!m_Impl) if(!m_impl)
return false; return false;
llarp_main_signal(m_impl, SIGHUP); llarp_main_signal(m_impl, SIGHUP);
return true; return true;
@ -41,6 +41,12 @@ struct AndroidMain
m_impl = llarp_main_init(configFile.c_str(), true); m_impl = llarp_main_init(configFile.c_str(), true);
if(m_impl == nullptr) if(m_impl == nullptr)
return false; return false;
if(llarp_main_setup(m_impl))
{
llarp_main_free(m_impl);
m_impl = nullptr;
return false;
}
m_thread = new std::thread(std::bind(&AndroidMain::Run, this)); m_thread = new std::thread(std::bind(&AndroidMain::Run, this));
return true; return true;
} }
@ -56,18 +62,57 @@ struct AndroidMain
void void
Run() Run()
{ {
llarp_main_run(m_impl); if(llarp_main_run(m_impl))
{
// on error
llarp::LogError("daemon run fail");
llarp_main * ptr = m_impl;
m_impl = nullptr;
llarp_main_signal(ptr, SIGINT);
llarp_main_free(ptr);
}
}
const char * GetIfAddr()
{
if(m_impl)
{
auto tun = main_router_getFirstTunEndpoint(m_impl);
if(tun)
return tun->tunif.ifaddr;
}
return "";
}
int GetIfRange() const
{
if(m_impl)
{
auto tun = main_router_getFirstTunEndpoint(m_impl);
if(tun)
return tun->tunif.netmask;
}
return -1;
}
void
SetVPN_FD(int fd)
{
if(m_impl)
llarp_main_inject_vpn_fd(m_impl, fd);
} }
/// stop daemon thread /// stop daemon thread
void void
Stop() Stop()
{ {
llarp_main_signal(m_impl, SIGINT); if(m_impl)
llarp_main_signal(m_impl, SIGINT);
m_thread->join(); m_thread->join();
delete m_thread; delete m_thread;
m_thread = nullptr; m_thread = nullptr;
llarp_main_free(m_impl); if(m_impl)
llarp_main_free(m_impl);
m_impl = nullptr; m_impl = nullptr;
} }
@ -86,7 +131,7 @@ extern "C"
} }
JNIEXPORT jstring JNICALL JNIEXPORT jstring JNICALL
Java_network_loki_lokinet_Lokinet_1JNI_startLokinet(JNIEnv* env, jclass jcl, Java_network_loki_lokinet_Lokinet_1JNI_startLokinet(JNIEnv* env, jclass,
jstring configfile) jstring configfile)
{ {
if(daemon->Running()) if(daemon->Running())
@ -107,17 +152,41 @@ extern "C"
return env->NewStringUTF("failed to start daemon"); return env->NewStringUTF("failed to start daemon");
} }
else else
return ev->NewStringUTF("failed to configure daemon"); return env->NewStringUTF("failed to configure daemon");
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_network_loki_lokinet_Lokinet_1JNI_stopLokinet(JNIEnv* env, jclass) Java_network_loki_lokinet_Lokinet_1JNI_stopLokinet(JNIEnv*, jclass)
{ {
if(daemon->Running()) if(daemon->Running())
{ {
daemon->Stop(); daemon->Stop();
} }
} }
JNIEXPORT void JNICALL
Java_network_loki_lokinet_Lokinet_1JNI_setVPNFileDescriptor(JNIEnv*, jclass, jint fd)
{
daemon->SetVPN_FD(fd);
}
JNIEXPORT jstring JNICALL Java_network_loki_lokinet_Lokinet_1JNI_getIfAddr
(JNIEnv * env, jclass)
{
if(daemon)
return env->NewStringUTF(daemon->GetIfAddr());
else
return env->NewStringUTF("");
}
JNIEXPORT jint JNICALL Java_network_loki_lokinet_Lokinet_1JNI_getIfRange
(JNIEnv *, jclass)
{
if(daemon)
return daemon->GetIfRange();
else
return -1;
}
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_network_loki_lokinet_Lokinet_1JNI_onNetworkStateChanged(JNIEnv*, jclass, Java_network_loki_lokinet_Lokinet_1JNI_onNetworkStateChanged(JNIEnv*, jclass,

@ -23,6 +23,12 @@ JNIEXPORT jstring JNICALL Java_network_loki_lokinet_Lokinet_1JNI_getABICompiledW
JNIEXPORT jstring JNICALL Java_network_loki_lokinet_Lokinet_1JNI_startLokinet JNIEXPORT jstring JNICALL Java_network_loki_lokinet_Lokinet_1JNI_startLokinet
(JNIEnv *, jclass, jstring); (JNIEnv *, jclass, jstring);
JNIEXPORT jstring JNICALL Java_network_loki_lokinet_Lokinet_1JNI_getIfAddr
(JNIEnv *, jclass);
JNIEXPORT jint JNICALL Java_network_loki_lokinet_Lokinet_1JNI_getIfRange
(JNIEnv *, jclass);
/* /*
* Class: network_loki_lokinet_Lokinet_JNI * Class: network_loki_lokinet_Lokinet_JNI
* Method: stopLokinet * Method: stopLokinet
@ -31,6 +37,9 @@ JNIEXPORT jstring JNICALL Java_network_loki_lokinet_Lokinet_1JNI_startLokinet
JNIEXPORT void JNICALL Java_network_loki_lokinet_Lokinet_1JNI_stopLokinet JNIEXPORT void JNICALL Java_network_loki_lokinet_Lokinet_1JNI_stopLokinet
(JNIEnv *, jclass); (JNIEnv *, jclass);
JNIEXPORT void JNICALL Java_network_loki_lokinet_Lokinet_1JNI_setVPNFileDescriptor
(JNIEnv *, jclass, jint);
/* /*
* Class: network_loki_lokinet_Lokinet_JNI * Class: network_loki_lokinet_Lokinet_JNI
* Method: onNetworkStateChanged * Method: onNetworkStateChanged

@ -327,6 +327,7 @@ interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
l_rta = RTA_NEXT(l_rta, l_rtaSize)) l_rta = RTA_NEXT(l_rta, l_rtaSize))
{ {
void *l_rtaData = RTA_DATA(l_rta); void *l_rtaData = RTA_DATA(l_rta);
(void) l_rtaData;
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch(l_rta->rta_type) switch(l_rta->rta_type)
{ {
@ -454,6 +455,7 @@ interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
l_rta = RTA_NEXT(l_rta, l_rtaSize)) l_rta = RTA_NEXT(l_rta, l_rtaSize))
{ {
void *l_rtaData = RTA_DATA(l_rta); void *l_rtaData = RTA_DATA(l_rta);
(void) l_rtaData;
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch(l_rta->rta_type) switch(l_rta->rta_type)

@ -164,7 +164,11 @@ llarp_generic_ensure_config(std::ofstream &f, std::string basepath)
// will this break reproducibility rules? // will this break reproducibility rules?
// (probably) // (probably)
#ifdef __linux__ #ifdef __linux__
#ifdef ANDROID
f << "bind=127.0.0.1:1153" << std::endl;
#else
f << "bind=127.3.2.1:53" << std::endl; f << "bind=127.3.2.1:53" << std::endl;
#endif
#else #else
f << "bind=127.0.0.1:53" << std::endl; f << "bind=127.0.0.1:53" << std::endl;
#endif #endif

@ -13,6 +13,8 @@
#include <pthread_np.h> #include <pthread_np.h>
#endif #endif
#include "ev.hpp"
namespace llarp namespace llarp
{ {
Context::~Context() Context::~Context()
@ -154,10 +156,7 @@ namespace llarp
llarp::LogError("Failed to configure router"); llarp::LogError("Failed to configure router");
return 1; return 1;
} }
// set nodedb, load our RC, establish DHT return 0;
llarp_run_router(router, nodedb);
return 0; // success
} }
int int
@ -174,7 +173,9 @@ namespace llarp
return 1; return 1;
} }
} }
// run
if(!llarp_run_router(router, nodedb))
return 1; // success
// run net io thread // run net io thread
llarp::LogInfo("running mainloop"); llarp::LogInfo("running mainloop");
llarp_ev_loop_run_single_process(mainloop, worker, logic); llarp_ev_loop_run_single_process(mainloop, worker, logic);
@ -296,6 +297,17 @@ extern "C"
ptr->ctx->HandleSignal(sig); ptr->ctx->HandleSignal(sig);
} }
void
llarp_main_inject_vpn_fd(struct llarp_main * ptr, int fd)
{
llarp::handlers::TunEndpoint * tun = ptr->ctx->router->hiddenServiceContext.getFirstTun();
if(!tun)
return;
if(!tun->Promise)
return;
tun->Promise->Set(fd);
}
int int
llarp_main_setup(struct llarp_main *ptr) llarp_main_setup(struct llarp_main *ptr)
{ {
@ -308,7 +320,7 @@ extern "C"
if(!ptr) if(!ptr)
{ {
llarp::LogError("No ptr passed in"); llarp::LogError("No ptr passed in");
return 0; return 1;
} }
return ptr->ctx->Run(); return ptr->ctx->Run();
} }
@ -448,8 +460,8 @@ extern "C"
main_router_mapAddress(struct llarp_main *ptr, main_router_mapAddress(struct llarp_main *ptr,
const llarp::service::Address &addr, uint32_t ip) const llarp::service::Address &addr, uint32_t ip)
{ {
auto *endpoint = &ptr->ctx->router->hiddenServiceContext; auto &endpoint = ptr->ctx->router->hiddenServiceContext;
return endpoint->MapAddress(addr, llarp::huint32_t{ip}); return endpoint.MapAddress(addr, llarp::huint32_t{ip});
} }
bool bool
@ -463,8 +475,9 @@ extern "C"
llarp::handlers::TunEndpoint * llarp::handlers::TunEndpoint *
main_router_getFirstTunEndpoint(struct llarp_main *ptr) main_router_getFirstTunEndpoint(struct llarp_main *ptr)
{ {
auto *context = &ptr->ctx->router->hiddenServiceContext; if(ptr && ptr->ctx && ptr->ctx->router)
return context->getFirstTun(); return ptr->ctx->router->hiddenServiceContext.getFirstTun();
return nullptr;
} }
//#include <llarp/service/context.hpp> //#include <llarp/service/context.hpp>

@ -20,6 +20,7 @@
#error No async event loop for your platform, subclass llarp_ev_loop #error No async event loop for your platform, subclass llarp_ev_loop
#endif #endif
void void
llarp_ev_loop_alloc(struct llarp_ev_loop **ev) llarp_ev_loop_alloc(struct llarp_ev_loop **ev)
{ {
@ -57,6 +58,11 @@ llarp_ev_loop_run(struct llarp_ev_loop *ev, struct llarp_logic *logic)
return 0; return 0;
} }
int llarp_fd_promise_wait_for_value(struct llarp_fd_promise * p)
{
return p->Get();
}
void void
llarp_ev_loop_run_single_process(struct llarp_ev_loop *ev, llarp_ev_loop_run_single_process(struct llarp_ev_loop *ev,
struct llarp_threadpool *tp, struct llarp_threadpool *tp,

@ -14,6 +14,8 @@
#ifdef _WIN32 #ifdef _WIN32
#include <variant> #include <variant>
#else
#include <sys/un.h>
#endif #endif
#ifndef MAX_WRITE_QUEUE_SIZE #ifndef MAX_WRITE_QUEUE_SIZE
@ -608,6 +610,24 @@ namespace llarp
}; // namespace llarp }; // namespace llarp
struct llarp_fd_promise
{
llarp_fd_promise(std::promise<int> * p) : _impl(p) {}
std::promise<int> * _impl;
void Set(int fd)
{
_impl->set_value(fd);
}
int Get()
{
auto future = _impl->get_future();
future.wait();
return future.get();
}
};
// this (nearly!) abstract base class // this (nearly!) abstract base class
// is overriden for each platform // is overriden for each platform
struct llarp_ev_loop struct llarp_ev_loop

@ -224,26 +224,46 @@ namespace llarp
return ret; return ret;
} }
static int wait_for_fd_promise(struct device * dev)
{
llarp::tun *t = static_cast<llarp::tun *>(dev->user);
if(t->t->get_fd_promise)
{
struct llarp_fd_promise * promise = t->t->get_fd_promise(t->t);
if(promise)
return llarp_fd_promise_wait_for_value(promise);
}
return -1;
}
bool bool
setup() setup()
{ {
// for android
if(t->get_fd_promise)
{
tunif->obtain_fd = &wait_for_fd_promise;
tunif->user = this;
}
llarp::LogDebug("set ifname to ", t->ifname); llarp::LogDebug("set ifname to ", t->ifname);
strncpy(tunif->if_name, t->ifname, sizeof(tunif->if_name)); strncpy(tunif->if_name, t->ifname, sizeof(tunif->if_name));
if(tuntap_start(tunif, TUNTAP_MODE_TUNNEL, 0) == -1) if(tuntap_start(tunif, TUNTAP_MODE_TUNNEL, 0) == -1)
{ {
llarp::LogWarn("failed to start interface"); llarp::LogWarn("failed to start interface");
return false; return false;
} }
if(tuntap_up(tunif) == -1) if(t->get_fd_promise == nullptr)
{ {
llarp::LogWarn("failed to put interface up: ", strerror(errno)); if(tuntap_up(tunif) == -1)
return false; {
} llarp::LogWarn("failed to put interface up: ", strerror(errno));
if(tuntap_set_ip(tunif, t->ifaddr, t->ifaddr, t->netmask) == -1) return false;
{ }
llarp::LogWarn("failed to set ip"); if(tuntap_set_ip(tunif, t->ifaddr, t->ifaddr, t->netmask) == -1)
return false; {
llarp::LogWarn("failed to set ip");
return false;
}
} }
fd = tunif->tun_fd; fd = tunif->tun_fd;
if(fd == -1) if(fd == -1)
@ -257,6 +277,8 @@ namespace llarp
~tun() ~tun()
{ {
if(tunif)
tuntap_destroy(tunif);
} }
}; };
}; // namespace llarp }; // namespace llarp
@ -485,7 +507,10 @@ struct llarp_epoll_loop : public llarp_ev_loop
create_tun(llarp_tun_io* tun) create_tun(llarp_tun_io* tun)
{ {
llarp::tun* t = new llarp::tun(tun, this); llarp::tun* t = new llarp::tun(tun, this);
if(t->setup()) if(tun->get_fd_promise)
{
} else if(t->setup())
{ {
return t; return t;
} }

@ -23,7 +23,7 @@ namespace llarp
ExitEndpoint::ExitEndpoint(const std::string &name, llarp_router *r) ExitEndpoint::ExitEndpoint(const std::string &name, llarp_router *r)
: m_Router(r) : m_Router(r)
, m_Name(name) , m_Name(name)
, m_Tun{{0}, 0, {0}, 0, 0, 0, 0, 0, 0} , m_Tun{{0}, 0, {0}, 0, 0, 0, 0, 0, 0, 0}
, m_InetToNetwork(name + "_exit_rx", r->netloop, r->netloop) , m_InetToNetwork(name + "_exit_rx", r->netloop, r->netloop)
{ {

@ -8,16 +8,29 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <netdb.h> #include <netdb.h>
#endif #endif
#include "ev.hpp"
namespace llarp namespace llarp
{ {
namespace handlers namespace handlers
{ {
static llarp_fd_promise * get_tun_fd_promise(llarp_tun_io * tun)
{
return static_cast<TunEndpoint *>(tun->user)->Promise.get();
}
TunEndpoint::TunEndpoint(const std::string &nickname, llarp_router *r) TunEndpoint::TunEndpoint(const std::string &nickname, llarp_router *r)
: service::Endpoint(nickname, r) : service::Endpoint(nickname, r)
, m_UserToNetworkPktQueue(nickname + "_sendq", r->netloop, r->netloop) , m_UserToNetworkPktQueue(nickname + "_sendq", r->netloop, r->netloop)
, m_NetworkToUserPktQueue(nickname + "_recvq", r->netloop, r->netloop) , m_NetworkToUserPktQueue(nickname + "_recvq", r->netloop, r->netloop)
{ {
#ifdef ANDROID
tunif.get_fd_promise = &get_tun_fd_promise;
Promise.reset(new llarp_fd_promise(&m_VPNPromise));
#else
tunif.get_fd_promise = nullptr;
#endif
tunif.user = this; tunif.user = this;
tunif.netmask = DefaultTunNetmask; tunif.netmask = DefaultTunNetmask;
strncpy(tunif.ifaddr, DefaultTunSrcAddr, sizeof(tunif.ifaddr) - 1); strncpy(tunif.ifaddr, DefaultTunSrcAddr, sizeof(tunif.ifaddr) - 1);

@ -703,7 +703,7 @@ llarp_router::async_verify_RC(const llarp::RouterContact &rc,
llarp_nodedb_async_verify(job); llarp_nodedb_async_verify(job);
} }
void bool
llarp_router::Run() llarp_router::Run()
{ {
if(enableRPCServer) if(enableRPCServer)
@ -807,12 +807,12 @@ llarp_router::Run()
if(!_rc.Sign(&crypto, identity)) if(!_rc.Sign(&crypto, identity))
{ {
llarp::LogError("failed to sign rc"); llarp::LogError("failed to sign rc");
return; return false;
} }
if(!SaveRC()) if(!SaveRC())
{ {
return; return false;
} }
llarp::LogInfo("have ", llarp_nodedb_num_loaded(nodedb), " routers"); llarp::LogInfo("have ", llarp_nodedb_num_loaded(nodedb), " routers");
@ -821,6 +821,7 @@ llarp_router::Run()
if(!outboundLink->Start(logic)) if(!outboundLink->Start(logic))
{ {
llarp::LogWarn("outbound link failed to start"); llarp::LogWarn("outbound link failed to start");
return false;
} }
int IBLinksStarted = 0; int IBLinksStarted = 0;
@ -844,8 +845,7 @@ llarp_router::Run()
if(!InitServiceNode()) if(!InitServiceNode())
{ {
llarp::LogError("Failed to initialize service node"); llarp::LogError("Failed to initialize service node");
Close(); return false;
return;
} }
delay = llarp_randint() % 50; delay = llarp_randint() % 50;
} }
@ -860,16 +860,14 @@ llarp_router::Run()
if(!_rc.Sign(&crypto, identity)) if(!_rc.Sign(&crypto, identity))
{ {
llarp::LogError("failed to regenerate keys and sign RC"); llarp::LogError("failed to regenerate keys and sign RC");
Close(); return false;
return;
} }
// generate default hidden service // generate default hidden service
llarp::LogInfo("setting up default network endpoint"); llarp::LogInfo("setting up default network endpoint");
if(!CreateDefaultHiddenService()) if(!CreateDefaultHiddenService())
{ {
llarp::LogError("failed to set up default network endpoint"); llarp::LogError("failed to set up default network endpoint");
Close(); return false;
return;
} }
} }
@ -877,8 +875,7 @@ llarp_router::Run()
if(!hiddenServiceContext.StartAll()) if(!hiddenServiceContext.StartAll())
{ {
llarp::LogError("Failed to start hidden service context"); llarp::LogError("Failed to start hidden service context");
Close(); return false;
return;
} }
llarp::PubKey ourPubkey = pubkey(); llarp::PubKey ourPubkey = pubkey();
llarp::LogInfo("starting dht context as ", ourPubkey); llarp::LogInfo("starting dht context as ", ourPubkey);
@ -886,6 +883,7 @@ llarp_router::Run()
ScheduleTicker(1000); ScheduleTicker(1000);
// delayed connect all // delayed connect all
llarp_logic_call_later(logic, {delay, this, &ConnectAll}); llarp_logic_call_later(logic, {delay, this, &ConnectAll});
return true;
} }
bool bool
@ -1041,11 +1039,11 @@ llarp_configure_router(struct llarp_router *router, struct llarp_config *conf)
return router->EnsureIdentity(); return router->EnsureIdentity();
} }
void bool
llarp_run_router(struct llarp_router *router, struct llarp_nodedb *nodedb) llarp_run_router(struct llarp_router *router, struct llarp_nodedb *nodedb)
{ {
router->nodedb = nodedb; router->nodedb = nodedb;
router->Run(); return router->Run();
} }
void void

@ -200,7 +200,7 @@ struct llarp_router
bool bool
Ready(); Ready();
void bool
Run(); Run();
void void

@ -45,9 +45,10 @@ namespace llarp
llarp::LogError("No endpoints found"); llarp::LogError("No endpoints found");
return nullptr; return nullptr;
} }
auto firstEndpoint = m_Endpoints.begin(); auto itr = m_Endpoints.begin();
auto *uniqueEndpoint = &firstEndpoint->second; if(itr == m_Endpoints.end())
return uniqueEndpoint->get(); return nullptr;
return itr->second.get();
} }
bool bool

@ -36,6 +36,7 @@
int int
tuntap_sys_start(struct device *dev, int mode, int tun) tuntap_sys_start(struct device *dev, int mode, int tun)
{ {
int fd; int fd;
int persist; int persist;
char *ifname; char *ifname;
@ -79,15 +80,27 @@ tuntap_sys_start(struct device *dev, int mode, int tun)
tuntap_log(TUNTAP_LOG_ERR, "Invalid parameter 'tun'"); tuntap_log(TUNTAP_LOG_ERR, "Invalid parameter 'tun'");
return -1; return -1;
} }
/* Open the clonable interface */
fd = -1; fd = -1;
if((fd = open("/dev/net/tun", O_RDWR)) == -1) if(dev->obtain_fd)
{ {
tuntap_log(TUNTAP_LOG_ERR, "Can't open /dev/net/tun"); // for android
return -1; fd = dev->obtain_fd(dev);
if(fd == -1)
{
tuntap_log(TUNTAP_LOG_ERR, "failed to get network interface");
return -1;
}
return fd;
}
else
{
/* Open the clonable interface */
if((fd = open("/dev/net/tun", O_RDWR)) == -1)
{
tuntap_log(TUNTAP_LOG_ERR, "Can't open /dev/net/tun");
return -1;
}
} }
/* Set the interface name, if any */ /* Set the interface name, if any */
if(fd > TUNTAP_ID_MAX) if(fd > TUNTAP_ID_MAX)

@ -56,7 +56,8 @@ extern "C"
if((dev = (struct device *)malloc(sizeof(*dev))) == NULL) if((dev = (struct device *)malloc(sizeof(*dev))) == NULL)
return NULL; return NULL;
dev->obtain_fd = nullptr;
dev->user = nullptr;
(void)memset(dev->if_name, '\0', sizeof(dev->if_name)); (void)memset(dev->if_name, '\0', sizeof(dev->if_name));
dev->tun_fd = TUNFD_INVALID_VALUE; dev->tun_fd = TUNFD_INVALID_VALUE;
dev->ctrl_sock = -1; dev->ctrl_sock = -1;

Loading…
Cancel
Save