Compare commits

..

68 Commits

Author SHA1 Message Date
Jason A. Donenfeld 04689d37b7 version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-02-06 22:01:03 +01:00
Jason A. Donenfeld e041cacf4b wg: bump to latest snapshot
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-02-06 22:01:03 +01:00
Alexey f54fc92b14 Add Russian translation
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-02-06 22:01:03 +01:00
Jason A. Donenfeld 6e7b6bcc35 wg-go: bump go requirement
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-02-03 17:21:34 +01:00
Jason A. Donenfeld e70d5be535 wg: remove mnl dependency and bump dep
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-02-03 17:09:45 +01:00
Jason A. Donenfeld 2ce51c8c2e version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-01-24 15:36:50 +01:00
Jason A. Donenfeld c621ec0c50 GoBackend: restrict APIs to proper version
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-01-24 15:36:27 +01:00
Harsh Shandilya 2ed2a1431d Upgrade to Gradle 6.1
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-01-24 09:57:25 +05:30
Harsh Shandilya 3a425394ca GoBackend: Ensure we're unmetered on API 29 as well
VPN apps targetting Android 10 are treated as metered by default.

Source: https://developer.android.com/reference/android/net/VpnService.Builder.html#setMetered(boolean)

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-01-24 09:51:48 +05:30
Jason A. Donenfeld d98ba463ad version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-01-23 16:12:26 +01:00
Jason A. Donenfeld c3d97acb31 Rework timer in tunnel detail
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-01-23 16:12:26 +01:00
Jason A. Donenfeld 8dbd464fa4 Match lowercase asus phones for fab hack
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-01-23 16:10:34 +01:00
Jason A. Donenfeld 63a5bb1bbf manifest: reorder
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-01-23 16:10:34 +01:00
Jason A. Donenfeld 8c03878808 tools: update deps
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-01-23 13:46:29 +01:00
Jason A. Donenfeld d29e50e50b GoBackend: set empty underlying networks
https://lists.zx2c4.com/pipermail/wireguard/2020-January/004859.html
https://issuetracker.google.com/issues/114309459
https://developer.android.com/about/versions/pie/android-9.0-changes-all#network-capabilities-vpn

Apparently we need to call this at least once.

Reported-by: Andrey Kupreychik <foxel@quickfox.ru>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-01-23 13:45:08 +01:00
Revath S Kumar 687bf8b208 Manifest: make wireguard compatible with android TV
As of now wireguard is not listed in Android TV play store
due to the lack of CATEGORY_LEANBACK_LAUNCHER [1].
Even the app is not listed when we sideload into TV device[2].

[1]: https://developer.android.com/reference/android/content/Intent.html#CATEGORY_LEANBACK_LAUNCHER
[2]: https://developer.android.com/training/tv/start/start.html#tv-activity

Signed-off-by: Revath S Kumar <rsk@revathskumar.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-01-22 20:56:49 +01:00
xalloc 10d0807395 Add Italian translation
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-01-22 20:56:06 +01:00
Jason A. Donenfeld 0a89c87190 tools: bump to new wireguard-tools repo
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-12-27 16:49:30 +01:00
Jason A. Donenfeld a7df92a64c Version bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-12-20 11:31:58 +01:00
Harsh Shandilya 4d3043c041 Introduce TunnelToggleActivity
On Android 10, apps cannot start services when they're in the
background. This means that starting VpnService from within
QuickTileService when the app is not active ends badly. To mitigate this
situation, we introduce a proxy activity of sorts that will handle
starting VpnService for us. The activity is completely transparent and
invisible, and does only four things:

- Toggle the tunnel state
- Request the Tile bound by QuickTileService to refresh its state
- Handle any error that might have been thrown during toggle
- Call finishAffinity() and go away

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2019-12-20 11:26:33 +01:00
Jason A. Donenfeld 8261a18472 Use RequiresApi instead of TargetApi
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-12-20 11:14:38 +01:00
Harsh Shandilya a9f04c0bf4 Update AGP to 3.5.3
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2019-12-15 11:08:00 +05:30
Harsh Shandilya 84334a6bc9 Update Gradle to 6.0.1
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2019-12-15 11:07:59 +05:30
Jason A. Donenfeld 1e5596f977 QuickTileService: require phone be unlocked
Reported-by: Simon <simon@laro.se>
Reported-by: Harsh Shandilya <me@msfjarvis.dev>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-11-27 13:12:12 +01:00
Jason A. Donenfeld b67fa3a38c Version bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-11-20 12:44:54 +01:00
Jason A. Donenfeld 8b0123042f Implement statistics
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-11-20 12:44:54 +01:00
Jason A. Donenfeld 16890a659e ModuleLoader: sync file before renaming
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-22 15:05:22 +02:00
Jason A. Donenfeld d40ac7f89d ToolsInstaller: write to temporary file, fsync, rename
Reported-by: Andre Christanto <christantoandre@gmail.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-21 18:56:28 +02:00
Jason A. Donenfeld 2694f48b87 libwg-go: version bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-18 14:57:12 +02:00
Jason A. Donenfeld 0f91aeb2d3 Version bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-18 13:37:59 +02:00
Jason A. Donenfeld bc0111f895 InetAddresses: cleanup and implement final fallback
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-18 13:37:07 +02:00
Jason A. Donenfeld f8a3e9b332 libwg-go: version bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-18 13:10:08 +02:00
Jason A. Donenfeld db9397fd3e Application: put user agent in log to help debugging
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-18 13:06:54 +02:00
Jason A. Donenfeld 20717ff128 Suppress depreciation warnings
We know what we're doing here, and it's not nice.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-18 13:06:54 +02:00
Jason A. Donenfeld a532a88585 Version bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-16 14:46:23 +02:00
Jason A. Donenfeld 0b077bd523 tools: bump wg-quick
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-16 14:46:10 +02:00
Jason A. Donenfeld e008efcf97 Version bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-16 10:03:47 +02:00
Jason A. Donenfeld 7cf676f9bd Google doesn't want to enable others to support free open source software
Revert "preferences: add donation link"

This reverts commit e5455f579aec48abb30ba68b0248b02d79303126.

The app was removed from the Play Store for violating their payments
policy. Upon filing an appeal, I was told that they do not allow
donations to projects like WireGuard.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-16 10:01:01 +02:00
Jason A. Donenfeld b83538d08d Version bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-14 00:24:47 +02:00
Jason A. Donenfeld 3c31c340d8 Download modules after verifying signify signature
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-14 00:03:39 +02:00
Jason A. Donenfeld 59620456ee Revert "Fix activity leak on Android Q"
This reverts commit 489518000971914b2608da43e2146690dcc02cb9.

October has arrived.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-13 14:10:11 +02:00
Jason A. Donenfeld e42bd29382 Version bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-13 14:10:11 +02:00
Jason A. Donenfeld 18dbc21f96 libwg-go: overwrite socket directory correctly
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-13 14:09:40 +02:00
Jason A. Donenfeld 68d871c47c Version bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-13 11:53:17 +02:00
Jason A. Donenfeld a45a219e5f proguard: reenable obfuscation
Android bundles let us keep everything together.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-13 11:53:17 +02:00
Jason A. Donenfeld 49788240aa libwg-go: version bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-13 11:46:41 +02:00
Jason A. Donenfeld 52166500fd ToolsInstaller: extract from apk instead of relying on native extraction
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-13 11:46:41 +02:00
Jason A. Donenfeld 3c8fef2655 SharedLibraryLoader: separate out extraction
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-13 11:46:41 +02:00
Jason A. Donenfeld 21af2f2f62 libwg-go: overwrite socket directory correctly
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-13 11:46:41 +02:00
Jason A. Donenfeld 6d01296e8b SharedLibraryLoader: prioritize ABI ordering
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-13 11:46:41 +02:00
Jason A. Donenfeld 749efcde21 SharedLibraryLoader: iterate through all apks for bundles
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-13 11:46:41 +02:00
Jason A. Donenfeld 3af2420da9 Version bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-12 18:55:28 +02:00
Nicolas Douma d0d24f4554 tools: prepare for binder usage in wg-quick
Signed-off-by: Nicolas Douma <nicolas@serveur.io>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-12 18:55:28 +02:00
Jason A. Donenfeld 96b44c1771 Activity: make dark/night theme follow system on Q
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-12 18:55:28 +02:00
Jason A. Donenfeld 4a1d07b364 Application: use preferences from compat libs
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-12 18:55:28 +02:00
Jason A. Donenfeld 7fbe5349a2 export: use content resolver on android Q+
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-12 18:55:28 +02:00
Jason A. Donenfeld d8bad72fd6 preferences: add donation link
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-12 18:55:28 +02:00
Jason A. Donenfeld 927b32c99f libwg-go: update to go 1.13
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-12 18:55:21 +02:00
Jason A. Donenfeld 27b691bef6 idea: update settings for 3.5
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-12 16:51:15 +02:00
Harsh Shandilya d2b9de740d Migrate to Android 10
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2019-09-30 19:45:11 +02:00
Jason A. Donenfeld eb45b4b1bd InetAddresses: prepare for Android 10's real method support
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-09-30 19:42:02 +02:00
Harsh Shandilya c545b5e65f FragmentUtils: Directly cast context as SettingsActivity
ContextThemeWrapper#getContext seems to be an instance of ContextImpl now which
is not public API and also not what we want. Directly cast context as SettingsActivity
which seems to work exactly how we need this to.

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2019-09-27 17:26:56 +05:30
Harsh Shandilya 992b6486a1 Update runtime dependencies
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2019-09-27 13:27:51 +05:30
Harsh Shandilya 421b1f889b Add LeakCanary to debug builds
LeakCanary is an advanced memory leak detection library for Android designed by the fine folks
at Square.

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2019-09-27 13:18:27 +05:30
Harsh Shandilya 1ee1368e18 Fix activity leak on Android Q
This workaround was discussed at https://twitter.com/Piwai/status/1169274622614704129 after
Google had closed the issuetracker with a WONTFIX at https://issuetracker.google.com/issues/139738913.

The situation has since changed with Google promising a fix on October's ASB but since we can't really
know, patch this ourselves for the timebeing.

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2019-09-27 13:18:27 +05:30
Harsh Shandilya 1a6a8789c1 Update to Golang 1.12.10
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2019-09-27 13:15:06 +05:30
Harsh Shandilya b5c155db1b Update AGP to 3.5.0
Also update the gitignore to ignore the '.cxx' directory AGP 3.5.0
uses for native build artifacts.

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2019-09-27 13:15:06 +05:30
Harsh Shandilya 6c5b46eadd Uprev to Gradle 5.6.2
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2019-09-27 12:59:53 +05:30
50 changed files with 1444 additions and 372 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
/captures/
/local.properties
.DS_Store
.externalNativeBuild/
.cxx/
Thumbs.db
build/
*.apk
+3 -6
View File
@@ -1,6 +1,3 @@
[submodule "app/tools/libmnl"]
path = app/tools/libmnl
url = https://git.netfilter.org/libmnl/
[submodule "app/tools/wireguard"]
path = app/tools/wireguard
url = https://git.zx2c4.com/WireGuard
[submodule "app/tools/wireguard-tools"]
path = app/tools/wireguard-tools
url = https://git.zx2c4.com/wireguard-tools
+12 -91
View File
@@ -29,19 +29,13 @@
<emptyLine />
</value>
</option>
<option name="RIGHT_MARGIN" value="100" />
<AndroidXmlCodeStyleSettings>
<option name="USE_CUSTOM_SETTINGS" value="true" />
<option name="ARRANGEMENT_SETTINGS_MIGRATED_TO_191" value="true" />
</AndroidXmlCodeStyleSettings>
<JavaCodeStyleSettings>
<option name="GENERATE_FINAL_LOCALS" value="true" />
<option name="GENERATE_FINAL_PARAMETERS" value="true" />
<option name="INSERT_INNER_CLASS_IMPORTS" value="true" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="false" />
@@ -65,35 +59,7 @@
</value>
</option>
</JavaCodeStyleSettings>
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
</extensions>
</Objective-C-extensions>
<XML>
<option name="XML_KEEP_LINE_BREAKS" value="false" />
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
<option name="XML_SPACE_INSIDE_EMPTY_TAG" value="true" />
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
<codeStyleSettings language="JAVA">
@@ -385,7 +351,6 @@
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
@@ -396,6 +361,7 @@
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
@@ -406,6 +372,7 @@
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
@@ -417,6 +384,7 @@
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
@@ -427,6 +395,7 @@
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
@@ -437,6 +406,7 @@
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
@@ -447,6 +417,7 @@
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
@@ -457,6 +428,7 @@
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
@@ -467,64 +439,12 @@
<rule>
<match>
<AND>
<NAME>.*:layout_width</NAME>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
@@ -532,6 +452,7 @@
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
+1 -3
View File
@@ -7,9 +7,7 @@ This is an Android GUI for [WireGuard](https://www.wireguard.com/). It [opportun
## Building
```
$ git clone https://git.zx2c4.com/wireguard-android
$ git clone --recurse-submodules https://git.zx2c4.com/wireguard-android
$ cd wireguard-android
$ git submodule init
$ git submodule update
$ ./gradlew assembleRelease
```
+16 -11
View File
@@ -6,19 +6,19 @@ apply from: 'nonnull.gradle'
final def keystorePropertiesFile = rootProject.file("keystore.properties")
android {
buildToolsVersion '28.0.3'
buildToolsVersion '29.0.2'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
compileSdkVersion 28
compileSdkVersion 29
dataBinding.enabled true
defaultConfig {
applicationId 'com.wireguard.android'
minSdkVersion 21
targetSdkVersion 28
versionCode 451
versionName '0.0.20190708'
targetSdkVersion 29
versionCode 464
versionName '0.0.20200206'
buildConfigField 'int', 'MIN_SDK_VERSION', "$minSdkVersion.apiLevel"
}
// If the keystore file exists
@@ -67,16 +67,20 @@ android {
}
ext {
annotationsVersion = '1.0.1'
appcompatVersion = '1.0.2'
annotationsVersion = '1.1.0'
appcompatVersion = '1.1.0'
cardviewVersion = '1.0.0'
databindingVersion = '3.3.1'
databindingVersion = '3.5.3'
materialComponentsVersion = '1.0.0'
jsr305Version = '3.0.2'
preferenceVersion = '1.0.0'
streamsupportVersion = '1.7.0'
threetenabpVersion = '1.1.1'
preferenceVersion = '1.1.0'
streamsupportVersion = '1.7.1'
threetenabpVersion = '1.2.1'
// ZXING switched minSdk to 24 so we cannot upgrade to 4.0.2 without following suit.
// If you choose to upgrade to minSDK 24 then you should also disable Jetifier from
// gradle.properties.
zxingEmbeddedVersion = '3.6.0'
eddsaVersion = '0.3.0'
}
dependencies {
@@ -91,6 +95,7 @@ dependencies {
implementation "com.journeyapps:zxing-android-embedded:$zxingEmbeddedVersion"
implementation "net.sourceforge.streamsupport:android-retrofuture:$streamsupportVersion"
implementation "net.sourceforge.streamsupport:android-retrostreams:$streamsupportVersion"
implementation "net.i2p.crypto:eddsa:$eddsaVersion"
}
tasks.withType(JavaCompile) {
-2
View File
@@ -1,5 +1,3 @@
# Squelch all warnings, they're harmless but ProGuard
# escalates them as errors.
-dontwarn sun.misc.Unsafe
# We're OSS anyway and who doesn't love a readable log
-dontobfuscate
+4 -3
View File
@@ -9,6 +9,8 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
<permission
android:name="${applicationId}.permission.CONTROL_TUNNELS"
android:description="@string/permission_description"
@@ -19,7 +21,6 @@
<application
android:name=".Application"
android:allowBackup="false"
android:extractNativeLibs="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
@@ -27,12 +28,12 @@
android:theme="@style/AppTheme"
tools:ignore="UnusedAttribute">
<activity android:name=".activity.TunnelToggleActivity" android:theme="@style/NoBackgroundTheme"/>
<activity android:name=".activity.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
<intent-filter>
@@ -12,7 +12,9 @@ import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.util.Log;
import androidx.preference.PreferenceManager;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatDelegate;
@@ -22,15 +24,26 @@ import com.wireguard.android.backend.WgQuickBackend;
import com.wireguard.android.configStore.FileConfigStore;
import com.wireguard.android.model.TunnelManager;
import com.wireguard.android.util.AsyncWorker;
import com.wireguard.android.util.ModuleLoader;
import com.wireguard.android.util.RootShell;
import com.wireguard.android.util.ToolsInstaller;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.Locale;
import java9.util.concurrent.CompletableFuture;
public class Application extends android.app.Application {
private static final String TAG = "WireGuard/" + Application.class.getSimpleName();
public static final String USER_AGENT;
static {
String preferredAbi = "unknown ABI";
if (Build.SUPPORTED_ABIS.length > 0)
preferredAbi = Build.SUPPORTED_ABIS[0];
USER_AGENT = String.format(Locale.ENGLISH, "WireGuard/%s (Android %d; %s; %s; %s %s; %s)", BuildConfig.VERSION_NAME, Build.VERSION.SDK_INT, preferredAbi, Build.BOARD, Build.MANUFACTURER, Build.MODEL, Build.FINGERPRINT);
}
@SuppressWarnings("NullableProblems") private static WeakReference<Application> weakSelf;
private final CompletableFuture<Backend> futureBackend = new CompletableFuture<>();
@SuppressWarnings("NullableProblems") private AsyncWorker asyncWorker;
@@ -38,6 +51,7 @@ public class Application extends android.app.Application {
@SuppressWarnings("NullableProblems") private RootShell rootShell;
@SuppressWarnings("NullableProblems") private SharedPreferences sharedPreferences;
@SuppressWarnings("NullableProblems") private ToolsInstaller toolsInstaller;
@SuppressWarnings("NullableProblems") private ModuleLoader moduleLoader;
@SuppressWarnings("NullableProblems") private TunnelManager tunnelManager;
public Application() {
@@ -57,9 +71,19 @@ public class Application extends android.app.Application {
synchronized (app.futureBackend) {
if (app.backend == null) {
Backend backend = null;
if (new File("/sys/module/wireguard").exists()) {
boolean didStartRootShell = false;
if (!app.moduleLoader.isModuleLoaded() && app.moduleLoader.moduleMightExist()) {
try {
app.rootShell.start();
didStartRootShell = true;
app.moduleLoader.loadModule();
} catch (final Exception ignored) {
}
}
if (app.moduleLoader.isModuleLoaded()) {
try {
if (!didStartRootShell)
app.rootShell.start();
backend = new WgQuickBackend(app.getApplicationContext());
} catch (final Exception ignored) {
}
@@ -87,6 +111,9 @@ public class Application extends android.app.Application {
public static ToolsInstaller getToolsInstaller() {
return get().toolsInstaller;
}
public static ModuleLoader getModuleLoader() {
return get().moduleLoader;
}
public static TunnelManager getTunnelManager() {
return get().tunnelManager;
@@ -108,16 +135,22 @@ public class Application extends android.app.Application {
@Override
public void onCreate() {
Log.i(TAG, USER_AGENT);
super.onCreate();
asyncWorker = new AsyncWorker(AsyncTask.SERIAL_EXECUTOR, new Handler(Looper.getMainLooper()));
rootShell = new RootShell(getApplicationContext());
toolsInstaller = new ToolsInstaller(getApplicationContext());
moduleLoader = new ModuleLoader(getApplicationContext());
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
AppCompatDelegate.setDefaultNightMode(
sharedPreferences.getBoolean("dark_theme", false) ?
AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
AppCompatDelegate.setDefaultNightMode(
sharedPreferences.getBoolean("dark_theme", false) ?
AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO);
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
}
tunnelManager = new TunnelManager(new FileConfigStore(getApplicationContext()));
tunnelManager.onCreate();
@@ -5,7 +5,6 @@
package com.wireguard.android;
import android.annotation.TargetApi;
import android.content.Intent;
import androidx.databinding.Observable;
import androidx.databinding.Observable.OnPropertyChangedCallback;
@@ -17,13 +16,13 @@ import android.os.IBinder;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import android.util.Log;
import android.widget.Toast;
import com.wireguard.android.activity.MainActivity;
import com.wireguard.android.activity.TunnelToggleActivity;
import com.wireguard.android.model.Tunnel;
import com.wireguard.android.model.Tunnel.State;
import com.wireguard.android.util.ErrorMessages;
import com.wireguard.android.widget.SlashDrawable;
import java.util.Objects;
@@ -34,7 +33,7 @@ import java.util.Objects;
* forward click events to the application.
*/
@TargetApi(Build.VERSION_CODES.N)
@RequiresApi(Build.VERSION_CODES.N)
public class QuickTileService extends TileService {
private static final String TAG = "WireGuard/" + QuickTileService.class.getSimpleName();
@@ -60,12 +59,22 @@ public class QuickTileService extends TileService {
@Override
public void onClick() {
if (tunnel != null) {
final Tile tile = getQsTile();
if (tile != null) {
tile.setIcon(tile.getIcon() == iconOn ? iconOff : iconOn);
tile.updateTile();
}
tunnel.setState(State.TOGGLE).whenComplete(this::onToggleFinished);
unlockAndRun(() -> {
final Tile tile = getQsTile();
if (tile != null) {
tile.setIcon(tile.getIcon() == iconOn ? iconOff : iconOn);
tile.updateTile();
}
tunnel.setState(State.TOGGLE).whenComplete((v, t) -> {
if (t == null) {
updateTile();
} else {
final Intent toggleIntent = new Intent(this, TunnelToggleActivity.class);
toggleIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(toggleIntent);
}
});
});
} else {
final Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -110,16 +119,6 @@ public class QuickTileService extends TileService {
Application.getTunnelManager().removeOnPropertyChangedCallback(onTunnelChangedCallback);
}
private void onToggleFinished(@SuppressWarnings("unused") final State state,
@Nullable final Throwable throwable) {
if (throwable == null)
return;
final String error = ErrorMessages.get(throwable);
final String message = getString(R.string.toggle_error, error);
Log.e(TAG, message, throwable);
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
private void updateTile() {
// Update the tunnel.
final Tunnel newTunnel = Application.getTunnelManager().getLastUsedTunnel();
@@ -6,6 +6,7 @@
package com.wireguard.android.activity;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
@@ -91,13 +92,16 @@ public class SettingsActivity extends ThemeChangeAwareActivity {
@Override
public void onCreatePreferences(final Bundle savedInstanceState, final String key) {
addPreferencesFromResource(R.xml.preferences);
final PreferenceScreen screen = getPreferenceScreen();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
screen.removePreference(getPreferenceManager().findPreference("dark_theme"));
final Preference wgQuickOnlyPrefs[] = {
getPreferenceManager().findPreference("tools_installer"),
getPreferenceManager().findPreference("restore_on_boot")
};
for (final Preference pref : wgQuickOnlyPrefs)
pref.setVisible(false);
final PreferenceScreen screen = getPreferenceScreen();
Application.getBackendAsync().thenAccept(backend -> {
for (final Preference pref : wgQuickOnlyPrefs) {
if (backend instanceof WgQuickBackend)
@@ -106,6 +110,19 @@ public class SettingsActivity extends ThemeChangeAwareActivity {
screen.removePreference(pref);
}
});
final Preference moduleInstaller = getPreferenceManager().findPreference("module_downloader");
moduleInstaller.setVisible(false);
if (Application.getModuleLoader().isModuleLoaded()) {
screen.removePreference(moduleInstaller);
} else {
Application.getAsyncWorker().runAsync(Application.getRootShell()::start).whenComplete((v, e) -> {
if (e == null)
moduleInstaller.setVisible(true);
else
screen.removePreference(moduleInstaller);
});
}
}
}
}
@@ -7,6 +7,7 @@ package com.wireguard.android.activity;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
@@ -55,12 +56,14 @@ public abstract class ThemeChangeAwareActivity extends AppCompatActivity impleme
@Override
protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Application.getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
Application.getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
protected void onDestroy() {
Application.getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
Application.getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
super.onDestroy();
}
@@ -0,0 +1,51 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.os.Bundle;
import android.os.Build;
import android.service.quicksettings.TileService;
import android.util.Log;
import android.widget.Toast;
import com.wireguard.android.Application;
import com.wireguard.android.QuickTileService;
import com.wireguard.android.R;
import com.wireguard.android.model.Tunnel;
import com.wireguard.android.model.Tunnel.State;
import com.wireguard.android.util.ErrorMessages;
@RequiresApi(Build.VERSION_CODES.N)
public class TunnelToggleActivity extends AppCompatActivity {
private static final String TAG = "WireGuard/" + TunnelToggleActivity.class.getSimpleName();
@Override
protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Tunnel tunnel = Application.getTunnelManager().getLastUsedTunnel();
if (tunnel == null)
return;
tunnel.setState(State.TOGGLE).whenComplete((v, t) -> {
TileService.requestListeningState(this, new ComponentName(this, QuickTileService.class));
onToggleFinished(t);
finishAffinity();
});
}
private void onToggleFinished(@Nullable final Throwable throwable) {
if (throwable == null)
return;
final String error = ErrorMessages.get(throwable);
final String message = getString(R.string.toggle_error, error);
Log.e(TAG, message, throwable);
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
}
@@ -8,6 +8,7 @@ package com.wireguard.android.backend;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import androidx.annotation.Nullable;
import androidx.collection.ArraySet;
@@ -24,6 +25,8 @@ import com.wireguard.android.util.SharedLibraryLoader;
import com.wireguard.config.Config;
import com.wireguard.config.InetNetwork;
import com.wireguard.config.Peer;
import com.wireguard.crypto.Key;
import com.wireguard.crypto.KeyFormatException;
import java.net.InetAddress;
import java.util.Collections;
@@ -47,6 +50,8 @@ public final class GoBackend implements Backend {
this.context = context;
}
private static native String wgGetConfig(int handle);
private static native int wgGetSocketV4(int handle);
private static native int wgGetSocketV6(int handle);
@@ -90,7 +95,45 @@ public final class GoBackend implements Backend {
@Override
public Statistics getStatistics(final Tunnel tunnel) {
return new Statistics();
final Statistics stats = new Statistics();
if (tunnel != currentTunnel) {
return stats;
}
final String config = wgGetConfig(currentTunnelHandle);
Key key = null;
long rx = 0, tx = 0;
for (final String line : config.split("\\n")) {
if (line.startsWith("public_key=")) {
if (key != null)
stats.add(key, rx, tx);
rx = 0;
tx = 0;
try {
key = Key.fromHex(line.substring(11));
} catch (final KeyFormatException ignored) {
key = null;
}
} else if (line.startsWith("rx_bytes=")) {
if (key == null)
continue;
try {
rx = Long.parseLong(line.substring(9));
} catch (final NumberFormatException ignored) {
rx = 0;
}
} else if (line.startsWith("tx_bytes=")) {
if (key == null)
continue;
try {
tx = Long.parseLong(line.substring(9));
} catch (final NumberFormatException ignored) {
tx = 0;
}
}
}
if (key != null)
stats.add(key, rx, tx);
return stats;
}
@Override
@@ -170,6 +213,11 @@ public final class GoBackend implements Backend {
builder.setMtu(config.getInterface().getMtu().orElse(1280));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
builder.setMetered(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
service.setUnderlyingNetworks(null);
builder.setBlocking(true);
try (final ParcelFileDescriptor tun = builder.establish()) {
if (tun == null)
@@ -15,11 +15,13 @@ import com.wireguard.android.model.Tunnel;
import com.wireguard.android.model.Tunnel.State;
import com.wireguard.android.model.Tunnel.Statistics;
import com.wireguard.config.Config;
import com.wireguard.crypto.Key;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
@@ -83,7 +85,24 @@ public final class WgQuickBackend implements Backend {
@Override
public Statistics getStatistics(final Tunnel tunnel) {
return new Statistics();
final Statistics stats = new Statistics();
final Collection<String> output = new ArrayList<>();
try {
if (Application.getRootShell().run(output, String.format("wg show '%s' transfer", tunnel.getName())) != 0)
return stats;
} catch (final Exception ignored) {
return stats;
}
for (final String line : output) {
final String[] parts = line.split("\\t");
if (parts.length != 3)
continue;
try {
stats.add(Key.fromBase64(parts[0]), Long.parseLong(parts[1]), Long.parseLong(parts[2]));
} catch (final Exception ignored) {
}
}
return stats;
}
@Override
@@ -7,6 +7,8 @@ package com.wireguard.android.fragment;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -15,7 +17,13 @@ import android.view.ViewGroup;
import com.wireguard.android.R;
import com.wireguard.android.databinding.TunnelDetailFragmentBinding;
import com.wireguard.android.databinding.TunnelDetailPeerBinding;
import com.wireguard.android.model.Tunnel;
import com.wireguard.android.model.Tunnel.State;
import com.wireguard.crypto.Key;
import java.util.Timer;
import java.util.TimerTask;
/**
* Fragment that shows details about a specific tunnel.
@@ -23,6 +31,8 @@ import com.wireguard.android.model.Tunnel;
public class TunnelDetailFragment extends BaseFragment {
@Nullable private TunnelDetailFragmentBinding binding;
@Nullable private Timer timer;
@Nullable private State lastState = State.TOGGLE;
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
@@ -35,6 +45,27 @@ public class TunnelDetailFragment extends BaseFragment {
inflater.inflate(R.menu.tunnel_detail, menu);
}
@Override
public void onStop() {
super.onStop();
if (timer != null) {
timer.cancel();
timer = null;
}
}
@Override
public void onResume() {
super.onResume();
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
updateStats();
}
}, 0, 1000);
}
@Override
public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container,
@Nullable final Bundle savedInstanceState) {
@@ -59,6 +90,8 @@ public class TunnelDetailFragment extends BaseFragment {
binding.setConfig(null);
else
newTunnel.getConfigAsync().thenAccept(binding::setConfig);
lastState = State.TOGGLE;
updateStats();
}
@Override
@@ -72,4 +105,55 @@ public class TunnelDetailFragment extends BaseFragment {
super.onViewStateRestored(savedInstanceState);
}
private String formatBytes(final long bytes) {
if (bytes < 1024)
return getContext().getString(R.string.transfer_bytes, bytes);
else if (bytes < 1024*1024)
return getContext().getString(R.string.transfer_kibibytes, bytes/1024.0);
else if (bytes < 1024*1024*1024)
return getContext().getString(R.string.transfer_mibibytes, bytes/(1024.0*1024.0));
else if (bytes < 1024*1024*1024*1024)
return getContext().getString(R.string.transfer_gibibytes, bytes/(1024.0*1024.0*1024.0));
return getContext().getString(R.string.transfer_tibibytes, bytes/(1024.0*1024.0*1024.0)/1024.0);
}
private void updateStats() {
if (binding == null || !isResumed())
return;
final Tunnel tunnel = binding.getTunnel();
if (tunnel == null)
return;
final State state = tunnel.getState();
if (state != State.UP && lastState == state)
return;
lastState = state;
tunnel.getStatisticsAsync().whenComplete((statistics, throwable) -> {
if (throwable != null) {
for (int i = 0; i < binding.peersLayout.getChildCount(); ++i) {
final TunnelDetailPeerBinding peer = DataBindingUtil.getBinding(binding.peersLayout.getChildAt(i));
if (peer == null)
continue;
peer.transferLabel.setVisibility(View.GONE);
peer.transferText.setVisibility(View.GONE);
}
return;
}
for (int i = 0; i < binding.peersLayout.getChildCount(); ++i) {
final TunnelDetailPeerBinding peer = DataBindingUtil.getBinding(binding.peersLayout.getChildAt(i));
if (peer == null)
continue;
final Key publicKey = peer.getItem().getPublicKey();
final long rx = statistics.peerRx(publicKey);
final long tx = statistics.peerTx(publicKey);
if (rx == 0 && tx == 0) {
peer.transferLabel.setVisibility(View.GONE);
peer.transferText.setVisibility(View.GONE);
continue;
}
peer.transferText.setText(getContext().getString(R.string.transfer_rx_tx, formatBytes(rx), formatBytes(tx)));
peer.transferLabel.setVisibility(View.VISIBLE);
peer.transferText.setVisibility(View.VISIBLE);
}
});
}
}
@@ -5,6 +5,9 @@
package com.wireguard.android.model;
import android.os.SystemClock;
import android.util.Pair;
import androidx.databinding.BaseObservable;
import androidx.databinding.Bindable;
import androidx.annotation.Nullable;
@@ -12,8 +15,11 @@ import androidx.annotation.Nullable;
import com.wireguard.android.BR;
import com.wireguard.android.util.ExceptionLoggers;
import com.wireguard.config.Config;
import com.wireguard.crypto.Key;
import com.wireguard.util.Keyed;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import java9.util.concurrent.CompletableFuture;
@@ -85,15 +91,13 @@ public class Tunnel extends BaseObservable implements Keyed<String> {
@Bindable
@Nullable
public Statistics getStatistics() {
// FIXME: Check age of statistics.
if (statistics == null)
if (statistics == null || statistics.isStale())
TunnelManager.getTunnelStatistics(this).whenComplete(ExceptionLoggers.E);
return statistics;
}
public CompletionStage<Statistics> getStatisticsAsync() {
// FIXME: Check age of statistics.
if (statistics == null)
if (statistics == null || statistics.isStale())
return TunnelManager.getTunnelStatistics(this);
return CompletableFuture.completedFuture(statistics);
}
@@ -154,5 +158,48 @@ public class Tunnel extends BaseObservable implements Keyed<String> {
}
public static class Statistics extends BaseObservable {
private long lastTouched = SystemClock.elapsedRealtime();
private final Map<Key, Pair<Long, Long>> peerBytes = new HashMap<>();
public void add(final Key key, final long rx, final long tx) {
peerBytes.put(key, Pair.create(rx, tx));
lastTouched = SystemClock.elapsedRealtime();
}
private boolean isStale() {
return SystemClock.elapsedRealtime() - lastTouched > 900;
}
public Key[] peers() {
return peerBytes.keySet().toArray(new Key[0]);
}
public long peerRx(final Key peer) {
if (!peerBytes.containsKey(peer))
return 0;
return peerBytes.get(peer).first;
}
public long peerTx(final Key peer) {
if (!peerBytes.containsKey(peer))
return 0;
return peerBytes.get(peer).second;
}
public long totalRx() {
long rx = 0;
for (final Pair<Long, Long> val : peerBytes.values()) {
rx += val.first;
}
return rx;
}
public long totalTx() {
long tx = 0;
for (final Pair<Long, Long> val : peerBytes.values()) {
tx += val.second;
}
return tx;
}
}
}
@@ -8,22 +8,21 @@ package com.wireguard.android.preference;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Environment;
import androidx.annotation.Nullable;
import com.google.android.material.snackbar.Snackbar;
import androidx.preference.Preference;
import android.util.AttributeSet;
import android.util.Log;
import com.wireguard.android.Application;
import com.wireguard.android.R;
import com.wireguard.android.util.DownloadsFileSaver;
import com.wireguard.android.util.DownloadsFileSaver.DownloadsFile;
import com.wireguard.android.util.ErrorMessages;
import com.wireguard.android.util.FragmentUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
/**
@@ -41,36 +40,33 @@ public class LogExporterPreference extends Preference {
private void exportLog() {
Application.getAsyncWorker().supplyAsync(() -> {
final File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
final File file = new File(path, "wireguard-log.txt");
if (!path.isDirectory() && !path.mkdirs())
throw new IOException(
getContext().getString(R.string.create_output_dir_error));
/* We would like to simply run `builder.redirectOutput(file);`, but this is API 26.
* Instead we have to do this dance, since logcat appends.
*/
new FileOutputStream(file).close();
DownloadsFile outputFile = DownloadsFileSaver.save(getContext(), "wireguard-log.txt", "text/plain", true);
try {
final Process process = Runtime.getRuntime().exec(new String[]{
"logcat", "-b", "all", "-d", "-v", "threadtime", "-f", file.getAbsolutePath(), "*:V"});
if (process.waitFor() != 0) {
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
"logcat", "-b", "all", "-d", "-v", "threadtime", "*:V"});
try (final BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
final BufferedReader stderr = new BufferedReader(new InputStreamReader(process.getErrorStream())))
{
String line;
while ((line = stdout.readLine()) != null) {
outputFile.getOutputStream().write(line.getBytes());
outputFile.getOutputStream().write('\n');
}
outputFile.getOutputStream().close();
stdout.close();
if (process.waitFor() != 0) {
final StringBuilder errors = new StringBuilder();
errors.append("Unable to run logcat: ");
String line;
while ((line = reader.readLine()) != null)
errors.append(R.string.logcat_error);
while ((line = stderr.readLine()) != null)
errors.append(line);
throw new Exception(errors.toString());
}
}
} catch (final Exception e) {
// noinspection ResultOfMethodCallIgnored
file.delete();
outputFile.delete();
throw e;
}
return file.getAbsolutePath();
return outputFile.getFileName();
}).whenComplete(this::exportLogComplete);
}
@@ -0,0 +1,91 @@
/*
* Copyright © 2019 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.preference;
import android.content.Context;
import android.content.Intent;
import android.system.OsConstants;
import android.util.AttributeSet;
import android.widget.Toast;
import com.wireguard.android.Application;
import com.wireguard.android.R;
import com.wireguard.android.util.ModuleLoader;
import com.wireguard.android.util.ToolsInstaller;
import androidx.annotation.Nullable;
import androidx.preference.Preference;
public class ModuleDownloaderPreference extends Preference {
private State state = State.INITIAL;
public ModuleDownloaderPreference(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
@Override
public CharSequence getSummary() {
return getContext().getString(state.messageResourceId);
}
@Override
public CharSequence getTitle() {
return getContext().getString(R.string.module_installer_title);
}
@Override
protected void onClick() {
setState(State.WORKING);
Application.getAsyncWorker().supplyAsync(Application.getModuleLoader()::download).whenComplete(this::onDownloadResult);
}
private void onDownloadResult(final Integer result, @Nullable final Throwable throwable) {
if (throwable != null) {
setState(State.FAILURE);
Toast.makeText(getContext(), throwable.getMessage(), Toast.LENGTH_LONG).show();
} else if (result == OsConstants.ENOENT)
setState(State.NOTFOUND);
else if (result == OsConstants.EXIT_SUCCESS) {
setState(State.SUCCESS);
Application.getAsyncWorker().runAsync(() -> {
Thread.sleep(1000 * 5);
Intent i = getContext().getPackageManager().getLaunchIntentForPackage(getContext().getPackageName());
if (i == null)
return;
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Application.get().startActivity(i);
System.exit(0);
});
} else
setState(State.FAILURE);
}
private void setState(final State state) {
if (this.state == state)
return;
this.state = state;
if (isEnabled() != state.shouldEnableView)
setEnabled(state.shouldEnableView);
notifyChanged();
}
private enum State {
INITIAL(R.string.module_installer_initial, true),
FAILURE(R.string.module_installer_error, true),
WORKING(R.string.module_installer_working, false),
SUCCESS(R.string.module_installer_success, false),
NOTFOUND(R.string.module_installer_not_found, false);
private final int messageResourceId;
private final boolean shouldEnableView;
State(final int messageResourceId, final boolean shouldEnableView) {
this.messageResourceId = messageResourceId;
this.shouldEnableView = shouldEnableView;
}
}
}
@@ -8,7 +8,6 @@ package com.wireguard.android.preference;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Environment;
import androidx.annotation.Nullable;
import com.google.android.material.snackbar.Snackbar;
import androidx.preference.Preference;
@@ -18,13 +17,12 @@ import android.util.Log;
import com.wireguard.android.Application;
import com.wireguard.android.R;
import com.wireguard.android.model.Tunnel;
import com.wireguard.android.util.DownloadsFileSaver;
import com.wireguard.android.util.DownloadsFileSaver.DownloadsFile;
import com.wireguard.android.util.ErrorMessages;
import com.wireguard.android.util.FragmentUtils;
import com.wireguard.config.Config;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@@ -63,12 +61,8 @@ public class ZipExporterPreference extends Preference {
.whenComplete((ignored1, exception) -> Application.getAsyncWorker().supplyAsync(() -> {
if (exception != null)
throw exception;
final File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
final File file = new File(path, "wireguard-export.zip");
if (!path.isDirectory() && !path.mkdirs())
throw new IOException(
getContext().getString(R.string.create_output_dir_error));
try (ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(file))) {
DownloadsFile outputFile = DownloadsFileSaver.save(getContext(), "wireguard-export.zip", "application/zip", true);
try (ZipOutputStream zip = new ZipOutputStream(outputFile.getOutputStream())) {
for (int i = 0; i < futureConfigs.size(); ++i) {
zip.putNextEntry(new ZipEntry(tunnels.get(i).getName() + ".conf"));
zip.write(futureConfigs.get(i).getNow(null).
@@ -76,11 +70,10 @@ public class ZipExporterPreference extends Preference {
}
zip.closeEntry();
} catch (final Exception e) {
// noinspection ResultOfMethodCallIgnored
file.delete();
outputFile.delete();
throw e;
}
return file.getAbsolutePath();
return outputFile.getFileName();
}).whenComplete(this::exportZipComplete));
}
@@ -0,0 +1,98 @@
/*
* Copyright © 2019 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.util;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.provider.MediaStore.MediaColumns;
import com.wireguard.android.R;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class DownloadsFileSaver {
public static class DownloadsFile {
private Context context;
private OutputStream outputStream;
private String fileName;
private Uri uri;
private DownloadsFile(final Context context, final OutputStream outputStream, final String fileName, final Uri uri) {
this.context = context;
this.outputStream = outputStream;
this.fileName = fileName;
this.uri = uri;
}
public OutputStream getOutputStream() { return outputStream; }
public String getFileName() { return fileName; }
public void delete() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
context.getContentResolver().delete(uri, null, null);
else
new File(fileName).delete();
}
}
public static DownloadsFile save(final Context context, final String name, final String mimeType, final boolean overwriteExisting) throws Exception {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
final ContentResolver contentResolver = context.getContentResolver();
if (overwriteExisting)
contentResolver.delete(MediaStore.Downloads.EXTERNAL_CONTENT_URI, String.format("%s = ?", MediaColumns.DISPLAY_NAME), new String[]{name});
final ContentValues contentValues = new ContentValues();
contentValues.put(MediaColumns.DISPLAY_NAME, name);
contentValues.put(MediaColumns.MIME_TYPE, mimeType);
final Uri contentUri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues);
if (contentUri == null)
throw new IOException(context.getString(R.string.create_downloads_file_error));
final OutputStream contentStream = contentResolver.openOutputStream(contentUri);
if (contentStream == null)
throw new IOException(context.getString(R.string.create_downloads_file_error));
@SuppressWarnings("deprecation")
Cursor cursor = contentResolver.query(contentUri, new String[]{MediaColumns.DATA}, null, null, null);
String path = null;
if (cursor != null) {
try {
if (cursor.moveToFirst())
path = cursor.getString(0);
} finally {
cursor.close();
}
}
if (path == null) {
path = "Download/";
cursor = contentResolver.query(contentUri, new String[]{MediaColumns.DISPLAY_NAME}, null, null, null);
if (cursor != null) {
try {
if (cursor.moveToFirst())
path += cursor.getString(0);
} finally {
cursor.close();
}
}
}
return new DownloadsFile(context, contentStream, path, contentUri);
} else {
@SuppressWarnings("deprecation")
final File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
final File file = new File(path, name);
if (!path.isDirectory() && !path.mkdirs())
throw new IOException(context.getString(R.string.create_output_dir_error));
return new DownloadsFile(context, new FileOutputStream(file), file.getAbsolutePath(), null);
}
}
}
@@ -18,8 +18,8 @@ public final class FragmentUtils {
public static SettingsActivity getPrefActivity(final Preference preference) {
final Context context = preference.getContext();
if (context instanceof ContextThemeWrapper) {
if (((ContextThemeWrapper) context).getBaseContext() instanceof SettingsActivity) {
return ((SettingsActivity) ((ContextThemeWrapper) context).getBaseContext());
if (context instanceof SettingsActivity) {
return ((SettingsActivity) context);
}
}
return null;
@@ -0,0 +1,183 @@
/*
* Copyright © 2019 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.util;
import android.content.Context;
import android.system.OsConstants;
import android.util.Base64;
import com.wireguard.android.Application;
import com.wireguard.android.util.RootShell.NoRootException;
import net.i2p.crypto.eddsa.EdDSAEngine;
import net.i2p.crypto.eddsa.EdDSAPublicKey;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec;
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.InvalidParameterException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
public class ModuleLoader {
private static final String MODULE_PUBLIC_KEY_BASE64 = "RWRmHuT9PSqtwfsLtEx+QS06BJtLgFYteL9WCNjH7yuyu5Y1DieSN7If";
private static final String MODULE_LIST_URL = "https://download.wireguard.com/android-module/modules.txt.sig";
private static final String MODULE_URL = "https://download.wireguard.com/android-module/%s";
private static final String MODULE_NAME = "wireguard-%s.ko";
private final File moduleDir;
private final File tmpDir;
public ModuleLoader(final Context context) {
moduleDir = new File(context.getCacheDir(), "kmod");
tmpDir = new File(context.getCacheDir(), "tmp");
}
public boolean moduleMightExist() {
return moduleDir.exists() && moduleDir.isDirectory();
}
public void loadModule() throws IOException, NoRootException {
Application.getRootShell().run(null, String.format("insmod \"%s/wireguard-$(sha256sum /proc/version|cut -d ' ' -f 1).ko\"", moduleDir.getAbsolutePath()));
}
public boolean isModuleLoaded() {
return new File("/sys/module/wireguard").exists();
}
private static final class Sha256Digest {
private byte[] bytes;
private Sha256Digest(final String hex) {
if (hex.length() != 64)
throw new InvalidParameterException("SHA256 hashes must be 32 bytes long");
bytes = new byte[32];
for (int i = 0; i < 32; ++i)
bytes[i] = (byte)Integer.parseInt(hex.substring(i * 2, i * 2 + 2), 16);
}
}
@Nullable
private Map<String, Sha256Digest> verifySignedHashes(final String signifyDigest) {
final byte[] publicKeyBytes = Base64.decode(MODULE_PUBLIC_KEY_BASE64, Base64.DEFAULT);
if (publicKeyBytes == null || publicKeyBytes.length != 32 + 10 || publicKeyBytes[0] != 'E' || publicKeyBytes[1] != 'd')
return null;
final String[] lines = signifyDigest.split("\n", 3);
if (lines.length != 3)
return null;
if (!lines[0].startsWith("untrusted comment: "))
return null;
final byte[] signatureBytes = Base64.decode(lines[1], Base64.DEFAULT);
if (signatureBytes == null || signatureBytes.length != 64 + 10)
return null;
for (int i = 0; i < 10; ++i) {
if (signatureBytes[i] != publicKeyBytes[i])
return null;
}
try {
EdDSAParameterSpec parameterSpec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
Signature signature = new EdDSAEngine(MessageDigest.getInstance(parameterSpec.getHashAlgorithm()));
byte[] rawPublicKeyBytes = new byte[32];
System.arraycopy(publicKeyBytes, 10, rawPublicKeyBytes, 0, 32);
signature.initVerify(new EdDSAPublicKey(new EdDSAPublicKeySpec(rawPublicKeyBytes, parameterSpec)));
signature.update(lines[2].getBytes(StandardCharsets.UTF_8));
if (!signature.verify(signatureBytes, 10, 64))
return null;
} catch (final Exception ignored) {
return null;
}
Map<String, Sha256Digest> hashes = new HashMap<>();
for (final String line : lines[2].split("\n")) {
final String[] components = line.split(" ", 2);
if (components.length != 2)
return null;
try {
hashes.put(components[1], new Sha256Digest(components[0]));
} catch (final Exception ignored) {
return null;
}
}
return hashes;
}
public Integer download() throws IOException, NoRootException, NoSuchAlgorithmException {
final List<String> output = new ArrayList<>();
Application.getRootShell().run(output, "sha256sum /proc/version|cut -d ' ' -f 1");
if (output.size() != 1 || output.get(0).length() != 64)
throw new InvalidParameterException("Invalid sha256 of /proc/version");
final String moduleName = String.format(MODULE_NAME, output.get(0));
HttpURLConnection connection = (HttpURLConnection)new URL(MODULE_LIST_URL).openConnection();
connection.setRequestProperty("User-Agent", Application.USER_AGENT);
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK)
throw new IOException("Hash list could not be found");
byte[] input = new byte[1024 * 1024 * 3 /* 3MiB */];
int len;
try (final InputStream inputStream = connection.getInputStream()) {
len = inputStream.read(input);
}
if (len <= 0)
throw new IOException("Hash list was empty");
final Map<String, Sha256Digest> modules = verifySignedHashes(new String(input, 0, len, StandardCharsets.UTF_8));
if (modules == null)
throw new InvalidParameterException("The signature did not verify or invalid hash list format");
if (!modules.containsKey(moduleName))
return OsConstants.ENOENT;
connection = (HttpURLConnection)new URL(String.format(MODULE_URL, moduleName)).openConnection();
connection.setRequestProperty("User-Agent", Application.USER_AGENT);
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK)
throw new IOException("Module file could not be found, despite being on hash list");
tmpDir.mkdirs();
moduleDir.mkdir();
File tempFile = null;
try {
tempFile = File.createTempFile("UNVERIFIED-", null, tmpDir);
MessageDigest digest = MessageDigest.getInstance("SHA-256");
try (final InputStream inputStream = connection.getInputStream();
final FileOutputStream outputStream = new FileOutputStream(tempFile)) {
int total = 0;
while ((len = inputStream.read(input)) > 0) {
total += len;
if (total > 1024 * 1024 * 15 /* 15 MiB */)
throw new IOException("File too big");
outputStream.write(input, 0, len);
digest.update(input, 0, len);
}
outputStream.getFD().sync();
}
if (!Arrays.equals(digest.digest(), modules.get(moduleName).bytes))
throw new IOException("Incorrect file hash");
if (!tempFile.renameTo(new File(moduleDir, moduleName)))
throw new IOException("Unable to rename to final destination");
} finally {
if (tempFile != null)
tempFile.delete();
}
return OsConstants.EXIT_SUCCESS;
}
}
@@ -43,9 +43,8 @@ public class RootShell {
public RootShell(final Context context) {
deviceNotRootedMessage = context.getString(R.string.error_root);
final File cacheDir = context.getCacheDir();
localBinaryDir = new File(cacheDir, "bin");
localTemporaryDir = new File(cacheDir, "tmp");
localBinaryDir = new File(context.getCodeCacheDir(), "bin");
localTemporaryDir = new File(context.getCacheDir(), "tmp");
preamble = String.format("export CALLING_PACKAGE=%s PATH=\"%s:$PATH\" TMPDIR='%s'; id -u\n",
BuildConfig.APPLICATION_ID, localBinaryDir, localTemporaryDir);
this.context = context;
@@ -13,6 +13,9 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -22,6 +25,43 @@ public final class SharedLibraryLoader {
private SharedLibraryLoader() {
}
public static boolean extractLibrary(final Context context, final String libName, final File destination) throws IOException {
final Collection<String> apks = new HashSet<>();
if (context.getApplicationInfo().sourceDir != null)
apks.add(context.getApplicationInfo().sourceDir);
if (context.getApplicationInfo().splitSourceDirs != null)
apks.addAll(Arrays.asList(context.getApplicationInfo().splitSourceDirs));
for (final String abi : Build.SUPPORTED_ABIS) {
for (final String apk : apks) {
final ZipFile zipFile;
try {
zipFile = new ZipFile(new File(apk), ZipFile.OPEN_READ);
} catch (final IOException e) {
throw new RuntimeException(e);
}
final String mappedLibName = System.mapLibraryName(libName);
final byte[] buffer = new byte[1024 * 32];
final String libZipPath = "lib" + File.separatorChar + abi + File.separatorChar + mappedLibName;
final ZipEntry zipEntry = zipFile.getEntry(libZipPath);
if (zipEntry == null)
continue;
Log.d(TAG, "Extracting apk:/" + libZipPath + " to " + destination.getAbsolutePath());
try (final FileOutputStream out = new FileOutputStream(destination);
final InputStream in = zipFile.getInputStream(zipEntry)) {
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
out.getFD().sync();
}
return true;
}
}
return false;
}
public static void loadSharedLibrary(final Context context, final String libName) {
Throwable noAbiException;
try {
@@ -31,42 +71,20 @@ public final class SharedLibraryLoader {
Log.d(TAG, "Failed to load library normally, so attempting to extract from apk", e);
noAbiException = e;
}
final ZipFile zipFile;
File f = null;
try {
zipFile = new ZipFile(new File(context.getApplicationInfo().sourceDir), ZipFile.OPEN_READ);
} catch (final IOException e) {
throw new RuntimeException(e);
}
final String mappedLibName = System.mapLibraryName(libName);
final byte[] buffer = new byte[1024 * 32];
for (final String abi : Build.SUPPORTED_ABIS) {
final String libZipPath = "lib" + File.separatorChar + abi + File.separatorChar + mappedLibName;
final ZipEntry zipEntry = zipFile.getEntry(libZipPath);
if (zipEntry == null)
continue;
File f = null;
try {
f = File.createTempFile("lib", ".so", context.getCacheDir());
Log.d(TAG, "Extracting apk:/" + libZipPath + " to " + f.getAbsolutePath() + " and loading");
try (final FileOutputStream out = new FileOutputStream(f);
final InputStream in = zipFile.getInputStream(zipEntry)) {
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
}
f = File.createTempFile("lib", ".so", context.getCodeCacheDir());
if (extractLibrary(context, libName, f)) {
System.load(f.getAbsolutePath());
return;
} catch (final Exception e) {
Log.d(TAG, "Failed to load library apk:/" + libZipPath, e);
noAbiException = e;
} finally {
if (f != null)
// noinspection ResultOfMethodCallIgnored
f.delete();
}
} catch (final Exception e) {
Log.d(TAG, "Failed to load library apk:/" + libName, e);
noAbiException = e;
} finally {
if (f != null)
// noinspection ResultOfMethodCallIgnored
f.delete();
}
if (noAbiException instanceof RuntimeException)
throw (RuntimeException) noAbiException;
@@ -31,10 +31,7 @@ public final class ToolsInstaller {
public static final int NO = 0x2;
public static final int SYSTEM = 0x8;
public static final int YES = 0x1;
private static final String[][] EXECUTABLES = {
{"libwg.so", "wg"},
{"libwg-quick.so", "wg-quick"},
};
private static final String[] EXECUTABLES = {"wg", "wg-quick"};
private static final File[] INSTALL_DIRS = {
new File("/system/xbin"),
new File("/system/bin"),
@@ -45,13 +42,11 @@ public final class ToolsInstaller {
private final Context context;
private final File localBinaryDir;
private final Object lock = new Object();
private final File nativeLibraryDir;
@Nullable private Boolean areToolsAvailable;
@Nullable private Boolean installAsMagiskModule;
public ToolsInstaller(final Context context) {
localBinaryDir = new File(context.getCacheDir(), "bin");
nativeLibraryDir = new File(context.getApplicationInfo().nativeLibraryDir);
localBinaryDir = new File(context.getCodeCacheDir(), "bin");
this.context = context;
}
@@ -72,10 +67,10 @@ public final class ToolsInstaller {
if (INSTALL_DIR == null)
return ERROR;
final StringBuilder script = new StringBuilder();
for (final String[] names : EXECUTABLES) {
for (final String name : EXECUTABLES) {
script.append(String.format("cmp -s '%s' '%s' && ",
new File(nativeLibraryDir, names[0]),
new File(INSTALL_DIR, names[1])));
new File(localBinaryDir, name).getAbsolutePath(),
new File(INSTALL_DIR, name).getAbsolutePath()));
}
script.append("exit ").append(OsConstants.EALREADY).append(';');
try {
@@ -89,18 +84,15 @@ public final class ToolsInstaller {
}
}
public void ensureToolsAvailable() throws FileNotFoundException, NoRootException {
public void ensureToolsAvailable() throws FileNotFoundException {
synchronized (lock) {
if (areToolsAvailable == null) {
final int ret = symlink();
if (ret == OsConstants.EALREADY) {
Log.d(TAG, "Tools were already symlinked into our private binary dir");
try {
Log.d(TAG, extract() ? "Tools are now extracted into our private binary dir" :
"Tools were already extracted into our private binary dir");
areToolsAvailable = true;
} else if (ret == OsConstants.EXIT_SUCCESS) {
Log.d(TAG, "Tools are now symlinked into our private binary dir");
areToolsAvailable = true;
} else {
Log.e(TAG, "For some reason, wg and wg-quick are not available at all");
} catch (final IOException e) {
Log.e(TAG, "The wg and wg-quick tools are not available", e);
areToolsAvailable = false;
}
}
@@ -110,21 +102,22 @@ public final class ToolsInstaller {
}
}
public int install() throws NoRootException {
public int install() throws NoRootException, IOException {
return willInstallAsMagiskModule() ? installMagisk() : installSystem();
}
private int installMagisk() throws NoRootException {
private int installMagisk() throws NoRootException, IOException {
extract();
final StringBuilder script = new StringBuilder("set -ex; ");
script.append("trap 'rm -rf /sbin/.magisk/img/wireguard' INT TERM EXIT; ");
script.append(String.format("rm -rf /sbin/.magisk/img/wireguard/; mkdir -p /sbin/.magisk/img/wireguard%s; ", INSTALL_DIR));
script.append(String.format("printf 'name=WireGuard Command Line Tools\nversion=%s\nversionCode=%s\nauthor=zx2c4\ndescription=Command line tools for WireGuard\nminMagisk=1500\n' > /sbin/.magisk/img/wireguard/module.prop; ", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));
script.append("touch /sbin/.magisk/img/wireguard/auto_mount; ");
for (final String[] names : EXECUTABLES) {
final File destination = new File("/sbin/.magisk/img/wireguard" + INSTALL_DIR, names[1]);
for (final String name : EXECUTABLES) {
final File destination = new File("/sbin/.magisk/img/wireguard" + INSTALL_DIR, name);
script.append(String.format("cp '%s' '%s'; chmod 755 '%s'; chcon 'u:object_r:system_file:s0' '%s' || true; ",
new File(nativeLibraryDir, names[0]), destination, destination, destination));
new File(localBinaryDir, name), destination, destination, destination));
}
script.append("trap - INT TERM EXIT;");
@@ -135,15 +128,16 @@ public final class ToolsInstaller {
}
}
private int installSystem() throws NoRootException {
private int installSystem() throws NoRootException, IOException {
if (INSTALL_DIR == null)
return OsConstants.ENOENT;
extract();
final StringBuilder script = new StringBuilder("set -ex; ");
script.append("trap 'mount -o ro,remount /system' EXIT; mount -o rw,remount /system; ");
for (final String[] names : EXECUTABLES) {
final File destination = new File(INSTALL_DIR, names[1]);
for (final String name : EXECUTABLES) {
final File destination = new File(INSTALL_DIR, name);
script.append(String.format("cp '%s' '%s'; chmod 755 '%s'; restorecon '%s' || true; ",
new File(nativeLibraryDir, names[0]), destination, destination, destination));
new File(localBinaryDir, name), destination, destination, destination));
}
try {
return Application.getRootShell().run(null, script.toString()) == 0 ? YES | SYSTEM : ERROR;
@@ -152,27 +146,27 @@ public final class ToolsInstaller {
}
}
public int symlink() throws NoRootException {
final StringBuilder script = new StringBuilder("set -x; ");
for (final String[] names : EXECUTABLES) {
script.append(String.format("test '%s' -ef '%s' && ",
new File(nativeLibraryDir, names[0]),
new File(localBinaryDir, names[1])));
public boolean extract() throws IOException {
localBinaryDir.mkdirs();
final File files[] = new File[EXECUTABLES.length];
final File tempFiles[] = new File[EXECUTABLES.length];
boolean allExist = true;
for (int i = 0; i < files.length; ++i) {
files[i] = new File(localBinaryDir, EXECUTABLES[i]);
tempFiles[i] = new File(localBinaryDir, EXECUTABLES[i] + ".tmp");
allExist &= files[i].exists();
}
script.append("exit ").append(OsConstants.EALREADY).append("; set -e; ");
for (final String[] names : EXECUTABLES) {
script.append(String.format("ln -fns '%s' '%s'; ",
new File(nativeLibraryDir, names[0]),
new File(localBinaryDir, names[1])));
}
script.append("exit ").append(OsConstants.EXIT_SUCCESS).append(';');
try {
return Application.getRootShell().run(null, script.toString());
} catch (final IOException ignored) {
return OsConstants.EXIT_FAILURE;
if (allExist)
return false;
for (int i = 0; i < files.length; ++i) {
if (!SharedLibraryLoader.extractLibrary(context, EXECUTABLES[i], tempFiles[i]))
throw new FileNotFoundException("Unable to find " + EXECUTABLES[i]);
if (!tempFiles[i].setExecutable(true, false))
throw new IOException("Unable to mark " + tempFiles[i].getAbsolutePath() + " as executable");
if (!tempFiles[i].renameTo(files[i]))
throw new IOException("Unable to rename " + tempFiles[i].getAbsolutePath() + " to " + files[i].getAbsolutePath());
}
return true;
}
private boolean willInstallAsMagiskModule() {
@@ -8,7 +8,6 @@ package com.wireguard.android.widget;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
@@ -26,9 +25,10 @@ import android.os.Build;
import androidx.annotation.ColorInt;
import androidx.annotation.IntRange;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import android.util.FloatProperty;
@TargetApi(Build.VERSION_CODES.N)
@RequiresApi(Build.VERSION_CODES.N)
public class SlashDrawable extends Drawable {
private static final float CENTER_X = 10.65f;
@@ -124,6 +124,7 @@ public class SlashDrawable extends Drawable {
return mDrawable.getIntrinsicWidth();
}
@SuppressWarnings("deprecation")
@Override
public int getOpacity() {
return PixelFormat.OPAQUE;
@@ -45,7 +45,7 @@ public class FloatingActionsMenu extends ViewGroup {
public static final int LABELS_ON_RIGHT_SIDE = 1;
private static final TimeInterpolator ALPHA_EXPAND_INTERPOLATOR = new DecelerateInterpolator();
private static final int ANIMATION_DURATION = 300;
private static final boolean BROKEN_LABEL_STYLE = Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1 && Build.BRAND.equals("ASUS");
private static final boolean BROKEN_LABEL_STYLE = Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1 && Build.BRAND.equalsIgnoreCase("ASUS");
private static final float COLLAPSED_PLUS_ROTATION = 0f;
private static final TimeInterpolator COLLAPSE_INTERPOLATOR = new DecelerateInterpolator(3f);
private static final float EXPANDED_PLUS_ROTATION = 90f + 45f;
@@ -5,31 +5,35 @@
package com.wireguard.config;
import java.lang.reflect.InvocationTargetException;
import android.os.Build;
import java.lang.reflect.Method;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
/**
* Utility methods for creating instances of {@link InetAddress}.
*/
public final class InetAddresses {
private static final Method PARSER_METHOD;
@Nullable private static final Method PARSER_METHOD;
private static final Pattern WONT_TOUCH_RESOLVER = Pattern.compile("^(((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?)|((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))$");
static {
Method m = null;
try {
// This method is only present on Android.
// noinspection JavaReflectionMemberAccess
PARSER_METHOD = InetAddress.class.getMethod("parseNumericAddress", String.class);
} catch (final NoSuchMethodException e) {
throw new RuntimeException(e);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
// noinspection JavaReflectionMemberAccess
m = InetAddress.class.getMethod("parseNumericAddress", String.class);
} catch (final Exception ignored) {
}
PARSER_METHOD = m;
}
private InetAddresses() {
// Prevent instantiation.
}
private InetAddresses() { }
/**
* Parses a numeric IPv4 or IPv6 address without performing any DNS lookups.
@@ -41,14 +45,28 @@ public final class InetAddresses {
if (address.isEmpty())
throw new ParseException(InetAddress.class, address, "Empty address");
try {
return (InetAddress) PARSER_METHOD.invoke(null, address);
} catch (final IllegalAccessException | InvocationTargetException e) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
return android.net.InetAddresses.parseNumericAddress(address);
else if (PARSER_METHOD != null)
return (InetAddress) PARSER_METHOD.invoke(null, address);
else
throw new NoSuchMethodException("parseNumericAddress");
} catch (final IllegalArgumentException e) {
throw new ParseException(InetAddress.class, address, e);
} catch (final Exception e) {
final Throwable cause = e.getCause();
// Re-throw parsing exceptions with the original type, as callers might try to catch
// them. On the other hand, callers cannot be expected to handle reflection failures.
if (cause instanceof IllegalArgumentException)
throw new ParseException(InetAddress.class, address, cause);
throw new RuntimeException(e);
try {
if (WONT_TOUCH_RESOLVER.matcher(address).matches())
return InetAddress.getByName(address);
else
throw new ParseException(InetAddress.class, address, "Not an IP address");
} catch (final UnknownHostException f) {
throw new ParseException(InetAddress.class, address, f);
}
}
}
}
@@ -7,6 +7,7 @@ package com.wireguard.crypto;
import com.wireguard.crypto.KeyFormatException.Type;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Arrays;
@@ -247,6 +248,24 @@ public final class Key {
return new String(output);
}
@Override
public int hashCode() {
int ret = 0;
for (int i = 0; i < key.length / 4; ++i)
ret ^= (key[i * 4 + 0] >> 0) + (key[i * 4 + 1] >> 8) + (key[i * 4 + 2] >> 16) + (key[i * 4 + 3] >> 24);
return ret;
}
@Override
public boolean equals(final Object obj) {
if (obj == this)
return true;
if (obj == null || obj.getClass() != getClass())
return false;
final Key other = (Key) obj;
return MessageDigest.isEqual(key, other.key);
}
/**
* The supported formats for encoding a WireGuard key.
*/
@@ -125,6 +125,7 @@
</androidx.cardview.widget.CardView>
<LinearLayout
android:id="@+id/peers_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
@@ -89,6 +89,24 @@
android:layout_height="wrap_content"
android:layout_below="@+id/endpoint_label"
android:text="@{item.endpoint}" />
<TextView
android:id="@+id/transfer_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/endpoint_text"
android:layout_marginTop="8dp"
android:labelFor="@+id/transfer_text"
android:text="@string/transfer"
android:visibility="gone" />
<TextView
android:id="@+id/transfer_text"
style="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/transfer_label"
android:visibility="gone" />
</RelativeLayout>
</androidx.cardview.widget.CardView>
</layout>
+180
View File
@@ -0,0 +1,180 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<plurals name="delete_error">
<item quantity="one">Impossibile eliminare %d tunnel: %s</item>
<item quantity="other">Impossibile eliminare %d tunnel: %s</item>
</plurals>
<plurals name="delete_success">
<item quantity="one">%d tunnel eliminato correttamente</item>
<item quantity="other">%d tunnel eliminati correttamente</item>
</plurals>
<plurals name="delete_title">
<item quantity="one">%d tunnel selezionato</item>
<item quantity="other">%d tunnel selezionati</item>
</plurals>
<plurals name="import_partial_success">
<item quantity="one">Importato %d di %d tunnel</item>
<item quantity="other">Importati %d di %d tunnel</item>
</plurals>
<plurals name="import_total_success">
<item quantity="one">Importato %d tunnel</item>
<item quantity="other">Importati %d tunnel</item>
</plurals>
<plurals name="set_excluded_applications">
<item quantity="one">%d applicazione esclusa</item>
<item quantity="other">%d applicazioni escluse</item>
</plurals>
<string name="add_peer">Aggiungi peer</string>
<string name="addresses">Indirizzi</string>
<string name="allowed_ips">IP consentiti</string>
<string name="app_name">WireGuard</string>
<string name="bad_config_context">%2$s di %1$s</string>
<string name="bad_config_context_top_level">%s</string>
<string name="bad_config_error">%1$s in %2$s</string>
<string name="bad_config_explanation_pka">: deve essere positivo e non maggiore di 65535</string>
<string name="bad_config_explanation_positive_number">: deve essere positivo</string>
<string name="bad_config_explanation_udp_port">: deve essere un numero di porta UDP valido</string>
<string name="bad_config_reason_invalid_key">Chiave non valida</string>
<string name="bad_config_reason_invalid_number">Numero non valido</string>
<string name="bad_config_reason_invalid_value">Valore non valido</string>
<string name="bad_config_reason_missing_attribute">Attributo mancante</string>
<string name="bad_config_reason_missing_section">Sezione mancante</string>
<string name="bad_config_reason_missing_value">Valore mancante</string>
<string name="bad_config_reason_syntax_error">Errore di sintassi</string>
<string name="bad_config_reason_unknown_attribute">Attributo sconosciuto</string>
<string name="bad_config_reason_unknown_section">Sezione sconosciuta</string>
<string name="bad_config_reason_value_out_of_range">Valore fuori scala</string>
<string name="bad_extension_error">Il file deve essere .conf o .zip</string>
<string name="cancel">Annulla</string>
<string name="config_delete_error">Impossibile eliminare il file di configurazione %s</string>
<string name="config_exists_error">La configurazione per “%s” esiste già</string>
<string name="config_file_exists_error">Il file di configurazione “%s” esiste già</string>
<string name="config_not_found_error">File di configurazione “%s” non trovato</string>
<string name="config_rename_error">Impossibile rinominare il file di configurazione “%s”</string>
<string name="config_save_error">Impossibile salvare la configurazione per “%1$s”: %2$s</string>
<string name="config_save_success">Configurazione per “%s” salvata correttamente</string>
<string name="create_activity_title">Crea un tunnel WireGuard</string>
<string name="create_bin_dir_error">Impossibile creare cartella locale binari</string>
<string name="create_empty">Crea da zero</string>
<string name="create_from_file">Crea da un file o archivio</string>
<string name="create_from_qr_code">Crea da un codice QR</string>
<string name="create_output_dir_error">Impossibile creare la cartella di output</string>
<string name="create_downloads_file_error">Impossibile creare il file nella cartella di download</string>
<string name="create_temp_dir_error">Impossibile creare la cartella locale temporanea</string>
<string name="create_tunnel">Crea tunnel</string>
<string name="dark_theme_summary_off">Stai usando il tema chiaro (giorno)</string>
<string name="dark_theme_summary_on">Stai usando il tema scuro (notte)</string>
<string name="dark_theme_title">Usa tema scuro</string>
<string name="delete">Elimina</string>
<string name="deselect_all">Deseleziona tutto</string>
<string name="dns_servers">Server DNS</string>
<string name="edit">Modifica</string>
<string name="endpoint">Endpoint</string>
<string name="error_down">Errore di disattivazione del tunnel: %s</string>
<string name="error_fetching_apps">Errore di recupero della lista app: %s</string>
<string name="error_root">Si prega di ottenere l\'accesso root e riprovare</string>
<string name="error_up">Errore di attivazione del tunnel: %s</string>
<string name="exclude_private_ips">Escludi IP privati</string>
<string name="excluded_applications">Applicazioni escluse</string>
<string name="generate">Genera</string>
<string name="generic_error">Errore “%s” sconosciuto</string>
<string name="hint_automatic">(auto)</string>
<string name="hint_generated">(generato)</string>
<string name="hint_optional">(facoltativo)</string>
<string name="hint_random">(casuale)</string>
<string name="illegal_filename_error">Nome file “%s” non valido</string>
<string name="import_error">Impossibile importare il tunnel: %s</string>
<string name="import_from_qr_code">Importa tunnel da codice QR</string>
<string name="import_success">Importato “%s”</string>
<string name="interface_title">Interfaccia</string>
<string name="key_length_explanation_base64">: le chiavi base64 di WireGuard devono essere di 44 caratteri (32 byte)</string>
<string name="key_length_explanation_binary">: le chiavi di WireGuard devono essere di 32 byte</string>
<string name="key_length_explanation_hex">: le chiavi hex di WireGuard devono essere di 64 caratteri (32 byte)</string>
<string name="listen_port">Porta in ascolto</string>
<string name="log_export_error">Impossibile esportare il registro: %s</string>
<string name="log_export_success">Salvato in “%s”</string>
<string name="log_export_summary">Il file del registro verrà salvato nella cartella di download</string>
<string name="log_export_title">Esporta file registro</string>
<string name="logcat_error">Impossibile eseguire logcat: </string>
<string name="module_version_error">Impossibile determinare la versione modulo del kernel</string>
<string name="module_installer_not_found">Nessun modulo disponibile per il tuo dispositivo</string>
<string name="module_installer_initial">Il modulo del kernel sperimentale può migliorare le prestazioni</string>
<string name="module_installer_success">Fatto. L\'applicazione si riavvierà in 5 secondi</string>
<string name="module_installer_title">Scarica e installa il modulo del kernel</string>
<string name="module_installer_working">Scaricamento e installazione…</string>
<string name="module_installer_error">Qualcosa è andato storto. Riprova</string>
<string name="mtu">MTU</string>
<string name="multiple_tunnels_error">Può essere attivo solo un tunnel su spazio utente alla volta</string>
<string name="name">Nome</string>
<string name="no_config_error">Tentativo di attivare un tunnel senza configurazione</string>
<string name="no_configs_error">Nessuna configurazione trovata</string>
<string name="no_tunnels_error">Non esistono tunnel</string>
<string name="parse_error_generic">stringa</string>
<string name="parse_error_inet_address">indirizzo IP</string>
<string name="parse_error_inet_endpoint">endpoint</string>
<string name="parse_error_inet_network">rete IP</string>
<string name="parse_error_integer">numero</string>
<string name="parse_error_reason">Impossibile analizzare %1$s “%2$s”</string>
<string name="peer">Peer</string>
<string name="permission_description">Permette ad un\'app di controllare i tunnel WireGuard. Le app con questa autorizzazione possono attivare e disattivare i tunnel WireGuard a piacimento, potenzialmente deviando il traffico internet.</string>
<string name="permission_label">controlla tunnel WireGuard</string>
<string name="persistent_keepalive">Tieni sempre attivo</string>
<string name="pre_shared_key">Chiave condivisa (PSK)</string>
<string name="private_key">Chiave privata</string>
<string name="public_key">Chiave pubblica</string>
<string name="public_key_description">La chiave pubblica</string>
<string name="qr_code_hint">Suggerimento: genera con `qrencode -t ansiutf8 &lt; tunnel.conf`.</string>
<string name="restore_on_boot_summary">Attiva tunnel attivati in precedenza all\'avvio</string>
<string name="restore_on_boot_title">Ripristina all\'avvio</string>
<string name="save">Salva</string>
<string name="select_all">Seleziona tutto</string>
<string name="set_exclusions">Imposta esclusioni</string>
<string name="settings">Impostazioni</string>
<string name="shell_exit_status_read_error">La shell non riesce a leggere l\'exit status</string>
<string name="shell_marker_count_error">La shell si aspettava 4 marker, ne ha ricevuti %d</string>
<string name="shell_start_error">Avvio della shell fallito: %d</string>
<string name="toggle_error">Errore di commutazione tunnel WireGuard: %s</string>
<string name="tools_installer_already">wg e wg-quick sono già installati</string>
<string name="tools_installer_failure">Impossibile installare strumenti di riga di comando (non root?)</string>
<string name="tools_installer_initial">Installa strumenti facoltativi per script</string>
<string name="tools_installer_initial_magisk">Installa strumenti facoltativi per script come moduli Magisk</string>
<string name="tools_installer_initial_system">Installa strumenti facoltativi per script nella partizione di sistema</string>
<string name="tools_installer_success_magisk">wg e wg-quick installati come moduli Magisk (riavvio necessario)</string>
<string name="tools_installer_success_system">wg e wg-quick installati nella partizione di sistema</string>
<string name="tools_installer_title">Installa strumenti di riga di comando</string>
<string name="tools_installer_working">Installazione di wg e wg-quick</string>
<string name="tools_unavailable_error">Strumenti necessari non disponibili</string>
<string name="transfer">Trasferisci</string>
<string name="transfer_rx_tx">rx: %s, tx: %s</string>
<string name="transfer_bytes">%d B</string>
<string name="transfer_kibibytes">%.2f KiB</string>
<string name="transfer_mibibytes">%.2f MiB</string>
<string name="transfer_gibibytes">%.2f GiB</string>
<string name="transfer_tibibytes">%.2f TiB</string>
<string name="tun_create_error">Impossibile creare il dispositivo tun</string>
<string name="tunnel_config_error">Impossibile configurare il tunnel (wg-quick ha risposto %d)</string>
<string name="tunnel_create_error">Impossibile creare il tunnel: %s</string>
<string name="tunnel_create_success">Tunnel “%s” creato correttamente</string>
<string name="tunnel_error_already_exists">Il tunnel “%s” esiste già</string>
<string name="tunnel_error_invalid_name">Nome non valido</string>
<string name="tunnel_list_placeholder">Aggiungi un tunnel usando il pulsante blu</string>
<string name="tunnel_name">Nome tunnel</string>
<string name="tunnel_on_error">Impossibile attivare il tunnel (wgTurnOn ha risposto %d)</string>
<string name="tunnel_rename_error">Impossibile rinominare il tunnel: %s</string>
<string name="tunnel_rename_success">Tunnel rinominato correttamente in “%s”</string>
<string name="type_name_go_userspace">Spazio utente Go</string>
<string name="type_name_kernel_module">Modulo kernel</string>
<string name="unknown_error">Errore sconosciuto</string>
<string name="version_summary">%1$s backend v%2$s</string>
<string name="version_summary_checking">Controllo versione backend %s</string>
<string name="version_summary_unknown">Versione %s sconosciuta</string>
<string name="version_title">WireGuard per Android v%s</string>
<string name="vpn_not_authorized_error">Servizio VPN non autorizzato dall\'utente</string>
<string name="vpn_start_error">Impossibile avviare il servizio VPN di Android</string>
<string name="zip_export_error">Impossibile esportare i tunnel: %s</string>
<string name="zip_export_success">Salvato in “%s”</string>
<string name="zip_export_summary">Il file zip verrà salvato nella cartella di download</string>
<string name="zip_export_title">Esporta i tunnel in un file zip</string>
<string name="key_length_error">Lunghezza chiave non valida</string>
<string name="key_contents_error">Caratteri errati nella chiave</string>
</resources>
+180
View File
@@ -0,0 +1,180 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<plurals name="delete_error">
<item quantity="one">Не удалось удалить %d туннель: %s</item>
<item quantity="other">Не удалось удалить %d туннелей: %s</item>
</plurals>
<plurals name="delete_success">
<item quantity="one">Успешно удален %d туннель</item>
<item quantity="other">Успешно удалено %d туннелей</item>
</plurals>
<plurals name="delete_title">
<item quantity="one">%d туннель выбран</item>
<item quantity="other">%d туннелей выбрано</item>
</plurals>
<plurals name="import_partial_success">
<item quantity="one">Импортирован %d из %d туннелей</item>
<item quantity="other">Импортировано %d из %d туннелей</item>
</plurals>
<plurals name="import_total_success">
<item quantity="one">Импортированный %d туннель</item>
<item quantity="other">Импортировано %d туннелей</item>
</plurals>
<plurals name="set_excluded_applications">
<item quantity="one">%d Исключенное приложение</item>
<item quantity="other">%d Исключенных приложений</item>
</plurals>
<string name="add_peer">Добавить узел</string>
<string name="addresses">Адреса</string>
<string name="allowed_ips">Разрешенные IP-адреса</string>
<string name="app_name">WireGuard</string>
<string name="bad_config_context">%1$s из %2$s</string>
<string name="bad_config_context_top_level">%s</string>
<string name="bad_config_error">%1$s в %2$s</string>
<string name="bad_config_explanation_pka">: Должен быть положительный и не больше 65535</string>
<string name="bad_config_explanation_positive_number">: Должен быть положительный</string>
<string name="bad_config_explanation_udp_port">: Должен быть действительный номер порта UDP</string>
<string name="bad_config_reason_invalid_key">Неправильный ключ</string>
<string name="bad_config_reason_invalid_number">Неправильный номер</string>
<string name="bad_config_reason_invalid_value">Неправильное значение</string>
<string name="bad_config_reason_missing_attribute">Несуществующий атрибут</string>
<string name="bad_config_reason_missing_section">Несуществующий раздел</string>
<string name="bad_config_reason_missing_value">Несуществющее значение</string>
<string name="bad_config_reason_syntax_error">Синтаксическая ошибка</string>
<string name="bad_config_reason_unknown_attribute">Неизвестный атрибут</string>
<string name="bad_config_reason_unknown_section">Неизвестный раздел</string>
<string name="bad_config_reason_value_out_of_range">Значение вне диапазона</string>
<string name="bad_extension_error">Файл должен быть .conf или .zip</string>
<string name="cancel">Отмена</string>
<string name="config_delete_error">Не удалось удалить файл конфигурации %s</string>
<string name="config_exists_error">Конфигурация для “%s” уже существует</string>
<string name="config_file_exists_error">Файл конфигурации “%s” уже существует</string>
<string name="config_not_found_error">Файл конфигурации “%s” не найден</string>
<string name="config_rename_error">Не удалось переименовать файл конфигурации “%s”</string>
<string name="config_save_error">Не удается сохранить конфигурацию для “%1$s”: %2$s</string>
<string name="config_save_success">Конфигурация успешно сохранения для “%s”</string>
<string name="create_activity_title">Создать WireGuard туннель</string>
<string name="create_bin_dir_error">Не удалось создать локальный двоичный каталог</string>
<string name="create_empty">Создать вручную</string>
<string name="create_from_file">Создать из файла или архива</string>
<string name="create_from_qr_code">Создать из QR-кода</string>
<string name="create_output_dir_error">Не удалось создать выходной каталог</string>
<string name="create_downloads_file_error">Не удалось создать файл в каталоге загрузок</string>
<string name="create_temp_dir_error">Не удалось создать временный локальный каталог</string>
<string name="create_tunnel">Создать туннель</string>
<string name="dark_theme_summary_off">В данный момент используется светлая (дневная) тема</string>
<string name="dark_theme_summary_on">В данный момент используется темная (ночная) тема</string>
<string name="dark_theme_title">Использовать темную тему</string>
<string name="delete">Удалить</string>
<string name="deselect_all">Снять выделенное</string>
<string name="dns_servers">DNS-серверы</string>
<string name="edit">Редактировать</string>
<string name="endpoint">Конечная точка</string>
<string name="error_down">Ошибка при выходе из туннеля: %s</string>
<string name="error_fetching_apps">Ошибка при получении списка приложений: %s</string>
<string name="error_root">Пожалуйста, получите root-доступ и попробуйте снова</string>
<string name="error_up">Ошибка при запуске туннеля: %s</string>
<string name="exclude_private_ips">Исключить частные IP-адреса</string>
<string name="excluded_applications">Исключенные приложения</string>
<string name="generate">Создать</string>
<string name="generic_error">Неизвестная “%s” ошибка</string>
<string name="hint_automatic">(авто)</string>
<string name="hint_generated">(авто)</string>
<string name="hint_optional">(авто)</string>
<string name="hint_random">(авто)</string>
<string name="illegal_filename_error">Неверное имя файла “%s”</string>
<string name="import_error">Не удалось импортировать туннель: %s</string>
<string name="import_from_qr_code">Импортировать туннель из QR-кода</string>
<string name="import_success">Импортировано “%s”</string>
<string name="interface_title">Интерфейс</string>
<string name="key_length_explanation_base64">: Ключи WireGuard base64 должны содержать 44 символа (32 байта)</string>
<string name="key_length_explanation_binary">: Ключи WireGuard должны быть 32 байта</string>
<string name="key_length_explanation_hex">: Hex ключи WireGuard должны содержать 64 символа (32 байта)</string>
<string name="listen_port">Порт</string>
<string name="log_export_error">Не удалось экспортировать логи: %s</string>
<string name="log_export_success">Сохранено в “%s”</string>
<string name="log_export_summary">Файл логов будет сохранен в папке загрузок</string>
<string name="log_export_title">Экспорт логов в файл</string>
<string name="logcat_error">Не удалось запустить logcat: </string>
<string name="module_version_error">Не удалось определить версию модуля ядра</string>
<string name="module_installer_not_found">Для вашего устройства нет доступных модулей</string>
<string name="module_installer_initial">Экспериментальный модуль ядра может улучшить производительность</string>
<string name="module_installer_success">Успех. Приложение перезапустится через 5 секунд</string>
<string name="module_installer_title">Скачать и установить модуль ядра</string>
<string name="module_installer_working">Скачивание и установка…</string>
<string name="module_installer_error">Что-то пошло не так. Пожалуйста, попробуйте еще раз</string>
<string name="mtu">MTU</string>
<string name="multiple_tunnels_error">Только один пользовательский туннель может работать одновременно</string>
<string name="name">Имя</string>
<string name="no_config_error">Попытка поднять туннель без конфигурации</string>
<string name="no_configs_error">Конфигурации не найдены</string>
<string name="no_tunnels_error">Туннелей не существует</string>
<string name="parse_error_generic">строка</string>
<string name="parse_error_inet_address">IP-адрес</string>
<string name="parse_error_inet_endpoint">конечная точка</string>
<string name="parse_error_inet_network">IP-сеть</string>
<string name="parse_error_integer">число</string>
<string name="parse_error_reason">Не могу разобрать %1$s “%2$s”</string>
<string name="peer">Узел</string>
<string name="permission_description">Приложение сможет управлять туннелями WireGuard. Приложения с таким разрешением могут по желанию включать и отключать туннели WireGuard, что может привести к неправильному перенаправлению интернет-трафика.</string>
<string name="permission_label">управлять туннелями WireGuard</string>
<string name="persistent_keepalive">Постоянное соединение</string>
<string name="pre_shared_key">Предварительный общий ключ</string>
<string name="private_key">Закрытый ключ</string>
<string name="public_key">Открытый ключ</string>
<string name="public_key_description">Открытый ключ</string>
<string name="qr_code_hint">Совет: генерировать с `qrencode -t ansiutf8 &lt; tunnel.conf`.</string>
<string name="restore_on_boot_summary">Поднимать ранее выбранные туннели при загрузке</string>
<string name="restore_on_boot_title">Восстанавливать при загрузке</string>
<string name="save">Сохранить</string>
<string name="select_all">Выбрать все</string>
<string name="set_exclusions">ОК</string>
<string name="settings">Настройки</string>
<string name="shell_exit_status_read_error">Shell не может прочитать статус выхода</string>
<string name="shell_marker_count_error">Shell ожидает 4 маркера, получено %d</string>
<string name="shell_start_error">Не удалось запустить Shell: %d</string>
<string name="toggle_error">Ошибка переключения туннеля WireGuard: %s</string>
<string name="tools_installer_already">wg и wg-quick уже установлены</string>
<string name="tools_installer_failure">Не удалось установить инструменты командной строки (нет root?)</string>
<string name="tools_installer_initial">Установите дополнительные инструменты для сценариев</string>
<string name="tools_installer_initial_magisk">Установите дополнительные инструменты для сценариев в качестве модуля Magisk</string>
<string name="tools_installer_initial_system">Установите дополнительные инструменты для сценариев в системный раздел</string>
<string name="tools_installer_success_magisk">wg и wg-quick установлены как модуль Magisk (требуется перезагрузка)</string>
<string name="tools_installer_success_system">wg и wg-quick установлены в системный раздел</string>
<string name="tools_installer_title">Установить инструменты командной строки</string>
<string name="tools_installer_working">Установка wg и wg-quick</string>
<string name="tools_unavailable_error">Необходимые инструменты недоступны</string>
<string name="transfer">Статистика</string>
<string name="transfer_rx_tx">Принято: %s, Отдано: %s</string>
<string name="transfer_bytes">%d Б</string>
<string name="transfer_kibibytes">%.2f Кб</string>
<string name="transfer_mibibytes">%.2f Мб</string>
<string name="transfer_gibibytes">%.2f Гб</string>
<string name="transfer_tibibytes">%.2f Тб</string>
<string name="tun_create_error">Не удалось создать устройство tun</string>
<string name="tunnel_config_error">Не удалось настроить туннель (wg-quick вернул %d)</string>
<string name="tunnel_create_error">Не удалось создать туннель: %s</string>
<string name="tunnel_create_success">Успешно созданный туннель “%s”</string>
<string name="tunnel_error_already_exists">Туннель “%s” уже существует</string>
<string name="tunnel_error_invalid_name">Неправильное имя</string>
<string name="tunnel_list_placeholder">Добавьте туннель с помощью синей кнопки</string>
<string name="tunnel_name">Название туннеля</string>
<string name="tunnel_on_error">Не удалось включить туннель (wgTurnOn вернул %d)</string>
<string name="tunnel_rename_error">Не удалось переименовать туннель: %s</string>
<string name="tunnel_rename_success">Туннель успешно переименован в “%s”</string>
<string name="type_name_go_userspace">Перейти в пространство пользователя</string>
<string name="type_name_kernel_module">Версия модуля ядра</string>
<string name="unknown_error">Неизвестная ошибка</string>
<string name="version_summary">%1$s бэкенд v%2$s</string>
<string name="version_summary_checking">Проверка %s бэкенд версии</string>
<string name="version_summary_unknown">Неизвестная версия %s версия</string>
<string name="version_title">WireGuard для Android v%s</string>
<string name="vpn_not_authorized_error">VPN-сервис не авторизован пользователем</string>
<string name="vpn_start_error">Не удалось запустить службу Android VPN</string>
<string name="zip_export_error">Не удалось экспортировать туннели: %s</string>
<string name="zip_export_success">Сохранено в “%s”</string>
<string name="zip_export_summary">Zip-архив будет сохранен в папке загрузок</string>
<string name="zip_export_title">Экспорт туннелей в Zip-архив</string>
<string name="key_length_error">Неверная длина ключа</string>
<string name="key_contents_error">Плохие символы в ключе</string>
</resources>
+15
View File
@@ -59,6 +59,7 @@
<string name="create_from_file">Create from file or archive</string>
<string name="create_from_qr_code">Create from QR code</string>
<string name="create_output_dir_error">Cannot create output directory</string>
<string name="create_downloads_file_error">Cannot create file in downloads directory</string>
<string name="create_temp_dir_error">Cannot create local temporary directory</string>
<string name="create_tunnel">Create Tunnel</string>
<string name="dark_theme_summary_off">Currently using light (day) theme</string>
@@ -94,7 +95,14 @@
<string name="log_export_success">Saved to “%s”</string>
<string name="log_export_summary">Log file will be saved to downloads folder</string>
<string name="log_export_title">Export log file</string>
<string name="logcat_error">Unable to run logcat: </string>
<string name="module_version_error">Unable to determine kernel module version</string>
<string name="module_installer_not_found">No modules are available for your device</string>
<string name="module_installer_initial">The experimental kernel module can improve performance</string>
<string name="module_installer_success">Success. The application will restart in 5 seconds</string>
<string name="module_installer_title">Download and install kernel module</string>
<string name="module_installer_working">Downloading and installing…</string>
<string name="module_installer_error">Something went wrong. Please try again</string>
<string name="mtu">MTU</string>
<string name="multiple_tunnels_error">Only one userspace tunnel can run at a time</string>
<string name="name">Name</string>
@@ -136,6 +144,13 @@
<string name="tools_installer_title">Install command line tools</string>
<string name="tools_installer_working">Installing wg and wg-quick</string>
<string name="tools_unavailable_error">Required tools unavailable</string>
<string name="transfer">Transfer</string>
<string name="transfer_rx_tx">rx: %s, tx: %s</string>
<string name="transfer_bytes">%d B</string>
<string name="transfer_kibibytes">%.2f KiB</string>
<string name="transfer_mibibytes">%.2f MiB</string>
<string name="transfer_gibibytes">%.2f GiB</string>
<string name="transfer_tibibytes">%.2f TiB</string>
<string name="tun_create_error">Unable to create tun device</string>
<string name="tunnel_config_error">Unable to configure tunnel (wg-quick returned %d)</string>
<string name="tunnel_create_error">Unable to create tunnel: %s</string>
+13
View File
@@ -5,6 +5,19 @@
<item name="colorAccent">@color/accent</item>
</style>
<style name="NoBackgroundTheme" parent="AppTheme">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowActionBar">false</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:background">@android:color/transparent</item>
<item name="colorPrimaryDark">@android:color/transparent</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowEnterAnimation">@android:anim/fade_in</item>
<item name="android:windowExitAnimation">@android:anim/fade_out</item>
</style>
<style name="fab_label" parent="TextAppearance.AppCompat.Inverse">
<item name="android:background">@drawable/fab_label_background</item>
<item name="android:textColor">@color/fab_label_text_color</item>
+1
View File
@@ -6,6 +6,7 @@
android:key="restore_on_boot"
android:summary="@string/restore_on_boot_summary"
android:title="@string/restore_on_boot_title" />
<com.wireguard.android.preference.ModuleDownloaderPreference android:key="module_downloader" />
<com.wireguard.android.preference.ToolsInstallerPreference android:key="tools_installer" />
<com.wireguard.android.preference.ZipExporterPreference />
<com.wireguard.android.preference.LogExporterPreference />
+6 -4
View File
@@ -8,12 +8,14 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
# Work around https://github.com/android-ndk/ndk/issues/602
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold")
add_executable(libwg-quick.so wireguard/src/tools/wg-quick/android.c ndk-compat/compat.c)
target_compile_options(libwg-quick.so PUBLIC -O3 -std=gnu11 -Wall -pedantic -Wno-missing-field-initializers -include ${CMAKE_CURRENT_SOURCE_DIR}/ndk-compat/compat.h -DWG_PACKAGE_NAME=\"${ANDROID_PACKAGE_NAME}\")
add_executable(libwg-quick.so wireguard-tools/src/wg-quick/android.c ndk-compat/compat.c)
target_compile_options(libwg-quick.so PUBLIC -O3 -std=gnu11 -Wall -include ${CMAKE_CURRENT_SOURCE_DIR}/ndk-compat/compat.h -DWG_PACKAGE_NAME=\"${ANDROID_PACKAGE_NAME}\")
target_link_libraries(libwg-quick.so -ldl)
file(GLOB WG_SOURCES wireguard/src/tools/*.c libmnl/src/*.c ndk-compat/compat.c)
file(GLOB WG_SOURCES wireguard-tools/src/*.c ndk-compat/compat.c)
add_executable(libwg.so ${WG_SOURCES})
target_compile_options(libwg.so PUBLIC -idirafter "${CMAKE_CURRENT_SOURCE_DIR}/libmnl/include/" -I "${CMAKE_CURRENT_SOURCE_DIR}/wireguard/src/tools/" -O3 -std=gnu11 -D_GNU_SOURCE -include ${CMAKE_CURRENT_SOURCE_DIR}/ndk-compat/compat.h -DHAVE_VISIBILITY_HIDDEN -DRUNSTATEDIR=\"/data/data/${ANDROID_PACKAGE_NAME}/cache\" -Wno-pointer-arith -Wno-unused-parameter)
target_include_directories(libwg.so PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/wireguard-tools/src/uapi/" "${CMAKE_CURRENT_SOURCE_DIR}/wireguard-tools/src/")
target_compile_options(libwg.so PUBLIC -O3 -std=gnu11 -D_GNU_SOURCE -include ${CMAKE_CURRENT_SOURCE_DIR}/ndk-compat/compat.h -DHAVE_VISIBILITY_HIDDEN -DRUNSTATEDIR=\"/data/data/${ANDROID_PACKAGE_NAME}/cache\")
add_custom_target(libwg-go.so WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libwg-go" COMMENT "Building wireguard-go" VERBATIM COMMAND make
ANDROID_ARCH_NAME=${ANDROID_ARCH_NAME}
+10 -24
View File
@@ -20,30 +20,16 @@ export GOARCH := $(NDK_GO_ARCH_MAP_$(ANDROID_ARCH_NAME))
export GOOS := android
export CGO_ENABLED := 1
DESIRED_GO_VERSION := 1.13.7
default: $(DESTDIR)/libwg-go.so
GOBUILDARCH := $(NDK_GO_ARCH_MAP_$(shell uname -m))
GOBUILDOS := $(shell uname -s | tr '[:upper:]' '[:lower:]')
GOBUILDVERSION := 1.12.5
GOBUILDTARBALL := https://dl.google.com/go/go$(GOBUILDVERSION).$(GOBUILDOS)-$(GOBUILDARCH).tar.gz
GOBUILDVERSION_NEEDED := go version go$(GOBUILDVERSION) $(GOBUILDOS)/$(GOBUILDARCH)
export GOROOT := $(BUILDDIR)/goroot
export GOPATH := $(BUILDDIR)/gopath
export PATH := $(GOROOT)/bin:$(PATH)
GOBUILDVERSION_CURRENT := $(shell $(GOROOT)/bin/go version 2>/dev/null)
ifneq ($(GOBUILDVERSION_NEEDED),$(GOBUILDVERSION_CURRENT))
$(shell rm -f $(GOROOT)/bin/go)
endif
$(GOROOT)/bin/go:
rm -rf "$(GOROOT)"
mkdir -p "$(GOROOT)"
curl "$(GOBUILDTARBALL)" | tar -C "$(GOROOT)" --strip-components=1 -xzf - || { rm -rf "$(GOROOT)"; exit 1; }
patch -p1 -f -N -r- -d "$(GOROOT)" < goruntime-boottime-over-monotonic.diff || { rm -rf "$(GOROOT)"; exit 1; }
$(BUILDDIR)/go-$(DESIRED_GO_VERSION)/.prepared:
mkdir -p "$(dir $@)"
curl "https://dl.google.com/go/go$(DESIRED_GO_VERSION).$(shell uname -s | tr '[:upper:]' '[:lower:]')-$(NDK_GO_ARCH_MAP_$(shell uname -m)).tar.gz" | tar -C "$(dir $@)" --strip-components=1 -xzf -
patch -p1 -f -N -r- -d "$(dir $@)" < goruntime-boottime-over-monotonic.diff
touch "$@"
$(shell test "$$(cat $(BUILDDIR)/.gobuildversion 2>/dev/null)" = "$(GOBUILDVERSION_CURRENT)" || rm -f "$(DESTDIR)/libwg-go.so")
$(DESTDIR)/libwg-go.so: $(GOROOT)/bin/go
go get -tags linux || { chmod -fR +w "$(GOPATH)/pkg/mod"; rm -rf "$(GOPATH)/pkg/mod"; exit 1; }
chmod -fR +w "$(GOPATH)/pkg/mod"
go build -tags linux -ldflags="-X main.socketDirectory=/data/data/$(ANDROID_PACKAGE_NAME)/cache/wireguard" -v -o "$@" -buildmode c-shared
go version > $(BUILDDIR)/.gobuildversion
$(DESTDIR)/libwg-go.so: export PATH := $(BUILDDIR)/go-$(DESIRED_GO_VERSION)/bin/:$(PATH)
$(DESTDIR)/libwg-go.so: $(BUILDDIR)/go-$(DESIRED_GO_VERSION)/.prepared go.mod
go build -tags linux -ldflags="-X golang.zx2c4.com/wireguard/ipc.socketDirectory=/data/data/$(ANDROID_PACKAGE_NAME)/cache/wireguard" -v -trimpath -o "$@" -buildmode c-shared
+17
View File
@@ -15,6 +15,7 @@ import (
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/ipc"
"golang.zx2c4.com/wireguard/tun"
"bytes"
"log"
"math"
"net"
@@ -168,6 +169,22 @@ func wgGetSocketV6(tunnelHandle int32) int32 {
return int32(fd)
}
//export wgGetConfig
func wgGetConfig(tunnelHandle int32) *C.char {
handle, ok := tunnelHandles[tunnelHandle]
if !ok {
return nil
}
settings := new(bytes.Buffer)
writer := bufio.NewWriter(settings)
err := handle.device.IpcGetOperation(writer)
if err != nil {
return nil
}
writer.Flush()
return C.CString(settings.String())
}
//export wgVersion
func wgVersion() *C.char {
return C.CString(device.WireGuardGoVersion)
+5 -5
View File
@@ -1,10 +1,10 @@
module golang.zx2c4.com/wireguard/android
go 1.12
go 1.13
require (
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 // indirect
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 // indirect
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb
golang.zx2c4.com/wireguard v0.0.20190518-0.20190605110920-108c37a05639
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad // indirect
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa // indirect
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82
golang.zx2c4.com/wireguard v0.0.20200121
)
+14 -14
View File
@@ -1,19 +1,19 @@
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f h1:R423Cnkcp5JABoeemiGEPlt9tHXFfw5kvc0yqlxRPWo=
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad h1:Jh8cai0fqIK+f6nG0UgPW5wFk8wmiMhM3AyciDBdtQg=
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5 h1:f005F/Jl5JLP036x7QIvUVhNTqxvSYwFIiyOh2q12iU=
golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.zx2c4.com/wireguard v0.0.20190518-0.20190605110920-108c37a05639 h1:AoX5+g0OBk+KqTTMVl4YPFZ9ioU2tPW1YwtzaVWdORA=
golang.zx2c4.com/wireguard v0.0.20190518-0.20190605110920-108c37a05639/go.mod h1:8X7vp4RrsvM83bde6vQ94DsL4ZpjUViVUym8aa8zGhs=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.zx2c4.com/wireguard v0.0.20200121 h1:vcswa5Q6f+sylDfjqyrVNNrjsFUUbPsgAQTBCAg/Qf8=
golang.zx2c4.com/wireguard v0.0.20200121/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4=
@@ -1,4 +1,4 @@
From 6998a7866b8428fd49c31506795c9f8154826d13 Mon Sep 17 00:00:00 2001
From b19623e7673a4d6743745382d5d38751b64e011d Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Wed, 27 Feb 2019 05:05:44 +0100
Subject: [PATCH] runtime: use CLOCK_BOOTTIME in nanotime on Linux
@@ -28,7 +28,7 @@ Change-Id: I7b2a6ca0c5bc5fce57ec0eeafe7b68270b429321
8 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/src/runtime/sys_linux_386.s b/src/runtime/sys_linux_386.s
index 40b55a67eb..6105780ff4 100644
index 72c43bd9da..daadfe32a9 100644
--- a/src/runtime/sys_linux_386.s
+++ b/src/runtime/sys_linux_386.s
@@ -288,13 +288,13 @@ noswitch:
@@ -48,7 +48,7 @@ index 40b55a67eb..6105780ff4 100644
INVOKE_SYSCALL
diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s
index b709f77060..18a1f1d43a 100644
index 5c300f553d..e4a6f12ec6 100644
--- a/src/runtime/sys_linux_amd64.s
+++ b/src/runtime/sys_linux_amd64.s
@@ -261,7 +261,7 @@ noswitch:
@@ -61,7 +61,7 @@ index b709f77060..18a1f1d43a 100644
CALL AX
MOVQ 0(SP), AX // sec
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index 43a58335c8..8b93635f4f 100644
index 9c7398451c..61b6cd91f6 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -11,7 +11,7 @@
@@ -83,7 +83,7 @@ index 43a58335c8..8b93635f4f 100644
MOVW runtime·vdsoClockgettimeSym(SB), R11
CMP $0, R11
diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s
index 8b344be8f8..daf142fba0 100644
index 2835b6ca1c..346ca9cfce 100644
--- a/src/runtime/sys_linux_arm64.s
+++ b/src/runtime/sys_linux_arm64.s
@@ -13,7 +13,7 @@
@@ -105,7 +105,7 @@ index 8b344be8f8..daf142fba0 100644
CBZ R2, fallback
BL (R2)
diff --git a/src/runtime/sys_linux_mips64x.s b/src/runtime/sys_linux_mips64x.s
index c45703d228..9842b596e7 100644
index 33ed1050c2..59a5be179c 100644
--- a/src/runtime/sys_linux_mips64x.s
+++ b/src/runtime/sys_linux_mips64x.s
@@ -189,7 +189,7 @@ TEXT runtime·walltime(SB),NOSPLIT,$16
@@ -118,10 +118,10 @@ index c45703d228..9842b596e7 100644
MOVV $SYS_clock_gettime, R2
SYSCALL
diff --git a/src/runtime/sys_linux_mipsx.s b/src/runtime/sys_linux_mipsx.s
index f362b0f3f1..5ab866e047 100644
index 6e539fbc6f..55b2bf7156 100644
--- a/src/runtime/sys_linux_mipsx.s
+++ b/src/runtime/sys_linux_mipsx.s
@@ -193,7 +193,7 @@ TEXT runtime·walltime(SB),NOSPLIT,$8-12
@@ -194,7 +194,7 @@ TEXT runtime·walltime(SB),NOSPLIT,$8-12
RET
TEXT runtime·nanotime(SB),NOSPLIT,$8-8
@@ -131,7 +131,7 @@ index f362b0f3f1..5ab866e047 100644
MOVW $SYS_clock_gettime, R2
SYSCALL
diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s
index 6835f434de..46618b2d91 100644
index 13d23156bd..f67e5062aa 100644
--- a/src/runtime/sys_linux_ppc64x.s
+++ b/src/runtime/sys_linux_ppc64x.s
@@ -204,7 +204,7 @@ fallback:
@@ -144,7 +144,7 @@ index 6835f434de..46618b2d91 100644
MOVD R1, R15 // R15 is unchanged by C code
MOVD g_m(g), R21 // R21 = m
diff --git a/src/runtime/sys_linux_s390x.s b/src/runtime/sys_linux_s390x.s
index c79ceea751..44e3258e60 100644
index 58b36dff0a..cb92e9a402 100644
--- a/src/runtime/sys_linux_s390x.s
+++ b/src/runtime/sys_linux_s390x.s
@@ -180,7 +180,7 @@ TEXT runtime·walltime(SB),NOSPLIT,$16
@@ -157,5 +157,5 @@ index c79ceea751..44e3258e60 100644
MOVW $SYS_clock_gettime, R1
SYSCALL
--
2.20.1
2.23.0
+12
View File
@@ -12,6 +12,7 @@ extern int wgTurnOn(struct go_string ifname, int tun_fd, struct go_string settin
extern void wgTurnOff(int handle);
extern int wgGetSocketV4(int handle);
extern int wgGetSocketV6(int handle);
extern char *wgGetConfig(int handle);
extern char *wgVersion();
JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgTurnOn(JNIEnv *env, jclass c, jstring ifname, jint tun_fd, jstring settings)
@@ -47,6 +48,17 @@ JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgGetSocketV
return wgGetSocketV6(handle);
}
JNIEXPORT jstring JNICALL Java_com_wireguard_android_backend_GoBackend_wgGetConfig(JNIEnv *env, jclass c, jint handle)
{
jstring ret;
char *config = wgGetConfig(handle);
if (!config)
return NULL;
ret = (*env)->NewStringUTF(env, config);
free(config);
return ret;
}
JNIEXPORT jstring JNICALL Java_com_wireguard_android_backend_GoBackend_wgVersion(JNIEnv *env, jclass c)
{
jstring ret;
+8 -1
View File
@@ -7,7 +7,7 @@ allprojects {
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.3.1'
classpath 'com.android.tools.build:gradle:3.5.3'
}
repositories {
google()
@@ -18,3 +18,10 @@ buildscript {
task clean(type: Delete) {
delete rootProject.buildDir
}
tasks {
wrapper {
gradleVersion = "6.1"
distributionType = Wrapper.DistributionType.ALL
}
}
Binary file not shown.
+1 -2
View File
@@ -1,6 +1,5 @@
#Sun Feb 17 03:37:07 CET 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
Vendored
+31 -20
View File
@@ -1,5 +1,21 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
@@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
@@ -109,8 +125,8 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
@@ -138,19 +154,19 @@ if $cygwin ; then
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
i=`expr $i + 1`
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
@@ -159,14 +175,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"