├── .idea
├── .name
├── vcs.xml
├── dictionaries
│ └── muizzuabbas.xml
├── misc.xml
├── runConfigurations.xml
├── gradle.xml
└── codeStyles
│ └── Project.xml
├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── styles.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── layout
│ │ │ │ └── activity_main.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── drawable
│ │ │ │ └── ic_launcher_background.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── xyz
│ │ │ └── oboloi
│ │ │ └── openvpnexample
│ │ │ └── MainActivity.java
│ ├── test
│ │ └── java
│ │ │ └── xyz
│ │ │ └── oboloi
│ │ │ └── openvpnexample
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── xyz
│ │ └── oboloi
│ │ └── openvpnexample
│ │ └── ExampleInstrumentedTest.java
├── libs
│ └── armeabi-v7a
│ │ └── libopvpnutil.so
├── proguard-rules.pro
└── build.gradle
├── openvpn
├── consumer-rules.pro
├── .gitignore
├── src
│ ├── main
│ │ ├── aidl
│ │ │ └── de
│ │ │ │ └── blinkt
│ │ │ │ └── openvpn
│ │ │ │ ├── core
│ │ │ │ ├── LogItem.aidl
│ │ │ │ ├── ConnectionStatus.aidl
│ │ │ │ ├── TrafficHistory.aidl
│ │ │ │ ├── IOpenVPNServiceInternal.aidl
│ │ │ │ ├── IStatusCallbacks.aidl
│ │ │ │ └── IServiceStatus.aidl
│ │ │ │ └── api
│ │ │ │ ├── APIVpnProfile.aidl
│ │ │ │ ├── IOpenVPNStatusCallback.aidl
│ │ │ │ └── IOpenVPNAPIService.aidl
│ │ ├── assets
│ │ │ ├── pie_openvpn.arm64-v8a
│ │ │ ├── nopie_openvpn.arm64-v8a
│ │ │ ├── pie_openvpn.armeabi-v7a
│ │ │ └── nopie_openvpn.armeabi-v7a
│ │ ├── jniLibs
│ │ │ └── armeabi-v7a
│ │ │ │ ├── libopenvpn.so
│ │ │ │ ├── libjbcrypto.so
│ │ │ │ └── libopvpnutil.so
│ │ ├── res
│ │ │ ├── drawable-xxhdpi
│ │ │ │ └── ic_help.png
│ │ │ ├── drawable-xhdpi
│ │ │ │ └── ic_connection_icon.png
│ │ │ ├── values
│ │ │ │ ├── plurals.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── untranslatable.xml
│ │ │ │ └── strings.xml
│ │ │ ├── layout
│ │ │ │ ├── launchvpn.xml
│ │ │ │ ├── userpass.xml
│ │ │ │ └── api_confirm.xml
│ │ │ └── drawable
│ │ │ │ └── progressbar.xml
│ │ ├── java
│ │ │ ├── xyz
│ │ │ │ └── oboloi
│ │ │ │ │ └── openvpn
│ │ │ │ │ ├── OnVPNStatusChangeListener.java
│ │ │ │ │ ├── DataCleanManager.java
│ │ │ │ │ ├── ProfileAsync.java
│ │ │ │ │ └── OboloiVPN.java
│ │ │ ├── org
│ │ │ │ └── spongycastle
│ │ │ │ │ └── util
│ │ │ │ │ ├── io
│ │ │ │ │ └── pem
│ │ │ │ │ │ ├── PemObjectGenerator.java
│ │ │ │ │ │ ├── PemGenerationException.java
│ │ │ │ │ │ ├── PemHeader.java
│ │ │ │ │ │ ├── PemObject.java
│ │ │ │ │ │ ├── PemReader.java
│ │ │ │ │ │ └── PemWriter.java
│ │ │ │ │ └── encoders
│ │ │ │ │ ├── Encoder.java
│ │ │ │ │ ├── Base64.java
│ │ │ │ │ └── Base64Encoder.java
│ │ │ └── de
│ │ │ │ └── blinkt
│ │ │ │ └── openvpn
│ │ │ │ ├── api
│ │ │ │ ├── SecurityRemoteException.java
│ │ │ │ ├── GrantPermissionsActivity.java
│ │ │ │ ├── APIVpnProfile.java
│ │ │ │ ├── ExternalAppDatabase.java
│ │ │ │ └── ConfirmDialog.java
│ │ │ │ └── core
│ │ │ │ ├── NativeUtils.java
│ │ │ │ ├── Preferences.java
│ │ │ │ ├── OpenVPNManagement.java
│ │ │ │ ├── ConnectionStatus.java
│ │ │ │ ├── PasswordCache.java
│ │ │ │ ├── ProxyDetection.java
│ │ │ │ ├── Connection.java
│ │ │ │ ├── CIDRIP.java
│ │ │ │ ├── LollipopDeviceStateListener.java
│ │ │ │ ├── App.java
│ │ │ │ ├── StatusListener.java
│ │ │ │ ├── VPNLaunchHelper.java
│ │ │ │ ├── TrafficHistory.java
│ │ │ │ ├── LogFileHandler.java
│ │ │ │ ├── X509Utils.java
│ │ │ │ ├── OpenVPNStatusService.java
│ │ │ │ ├── OpenVPNThread.java
│ │ │ │ ├── ProfileManager.java
│ │ │ │ └── DeviceStateReceiver.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── xyz
│ │ │ └── oboloi
│ │ │ └── openvpn
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── xyz
│ │ └── oboloi
│ │ └── openvpn
│ │ └── ExampleInstrumentedTest.java
├── libs
│ ├── arm64
│ │ └── libopvpnutil.so
│ └── armeabi-v7a
│ │ ├── libjbcrypto.so
│ │ ├── libopenvpn.so
│ │ └── libopvpnutil.so
├── proguard-rules.pro
└── build.gradle
├── README.md
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── LICENSE
├── gradle.properties
├── gradlew.bat
└── gradlew
/.idea/.name:
--------------------------------------------------------------------------------
1 | OpenVPNExample
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/openvpn/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/openvpn/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OpenVPN-Android
2 | OpenVPN library for android
3 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':openvpn'
2 | rootProject.name='OpenVPNExample'
3 |
--------------------------------------------------------------------------------
/openvpn/src/main/aidl/de/blinkt/openvpn/core/LogItem.aidl:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | parcelable LogItem;
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | OpenVPNExample
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/openvpn/libs/arm64/libopvpnutil.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/openvpn/libs/arm64/libopvpnutil.so
--------------------------------------------------------------------------------
/app/libs/armeabi-v7a/libopvpnutil.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/app/libs/armeabi-v7a/libopvpnutil.so
--------------------------------------------------------------------------------
/openvpn/src/main/aidl/de/blinkt/openvpn/api/APIVpnProfile.aidl:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.api;
2 |
3 | parcelable APIVpnProfile;
4 |
--------------------------------------------------------------------------------
/openvpn/libs/armeabi-v7a/libjbcrypto.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/openvpn/libs/armeabi-v7a/libjbcrypto.so
--------------------------------------------------------------------------------
/openvpn/libs/armeabi-v7a/libopenvpn.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/openvpn/libs/armeabi-v7a/libopenvpn.so
--------------------------------------------------------------------------------
/openvpn/libs/armeabi-v7a/libopvpnutil.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/openvpn/libs/armeabi-v7a/libopvpnutil.so
--------------------------------------------------------------------------------
/openvpn/src/main/aidl/de/blinkt/openvpn/core/ConnectionStatus.aidl:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | parcelable ConnectionStatus;
--------------------------------------------------------------------------------
/openvpn/src/main/aidl/de/blinkt/openvpn/core/TrafficHistory.aidl:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 |
4 | parcelable TrafficHistory;
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/openvpn/src/main/assets/pie_openvpn.arm64-v8a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/openvpn/src/main/assets/pie_openvpn.arm64-v8a
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/openvpn/src/main/assets/nopie_openvpn.arm64-v8a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/openvpn/src/main/assets/nopie_openvpn.arm64-v8a
--------------------------------------------------------------------------------
/openvpn/src/main/assets/pie_openvpn.armeabi-v7a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/openvpn/src/main/assets/pie_openvpn.armeabi-v7a
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/openvpn/src/main/assets/nopie_openvpn.armeabi-v7a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/openvpn/src/main/assets/nopie_openvpn.armeabi-v7a
--------------------------------------------------------------------------------
/openvpn/src/main/jniLibs/armeabi-v7a/libopenvpn.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/openvpn/src/main/jniLibs/armeabi-v7a/libopenvpn.so
--------------------------------------------------------------------------------
/openvpn/src/main/res/drawable-xxhdpi/ic_help.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/openvpn/src/main/res/drawable-xxhdpi/ic_help.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/openvpn/src/main/jniLibs/armeabi-v7a/libjbcrypto.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/openvpn/src/main/jniLibs/armeabi-v7a/libjbcrypto.so
--------------------------------------------------------------------------------
/openvpn/src/main/jniLibs/armeabi-v7a/libopvpnutil.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/openvpn/src/main/jniLibs/armeabi-v7a/libopvpnutil.so
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/openvpn/src/main/res/drawable-xhdpi/ic_connection_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/muizzu/OpenVPN-Android/HEAD/openvpn/src/main/res/drawable-xhdpi/ic_connection_icon.png
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/dictionaries/muizzuabbas.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | oboloi
5 | ovpn
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Aug 26 23:44:35 MVT 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
7 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/xyz/oboloi/openvpn/OnVPNStatusChangeListener.java:
--------------------------------------------------------------------------------
1 | package xyz.oboloi.openvpn;
2 |
3 | public interface OnVPNStatusChangeListener
4 | {
5 | public void onProfileLoaded(boolean profileLoaded);
6 | public void onVPNStatusChanged(boolean vpnActivated);
7 |
8 | }
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/org/spongycastle/util/io/pem/PemObjectGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2014 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package org.spongycastle.util.io.pem;
6 |
7 | public interface PemObjectGenerator {
8 | PemObject generate() throws PemGenerationException;
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/api/SecurityRemoteException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.api;
6 | import android.os.RemoteException;
7 |
8 | public class SecurityRemoteException extends RemoteException {
9 | /**
10 | *
11 | */
12 | private static final long serialVersionUID = 1L;
13 | }
14 |
--------------------------------------------------------------------------------
/openvpn/src/test/java/xyz/oboloi/openvpn/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package xyz.oboloi.openvpn;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/test/java/xyz/oboloi/openvpnexample/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package xyz.oboloi.openvpnexample;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/openvpn/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNStatusCallback.aidl:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.api;
2 |
3 | /**
4 | * Example of a callback interface used by IRemoteService to send
5 | * synchronous notifications back to its clients. Note that this is a
6 | * one-way interface so the server does not block waiting for the client.
7 | */
8 | interface IOpenVPNStatusCallback {
9 | /**
10 | * Called when the service has a new status for you.
11 | */
12 | oneway void newStatus(in String uuid, in String state, in String message, in String level);
13 | }
14 |
--------------------------------------------------------------------------------
/openvpn/src/main/res/values/plurals.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - One month left
5 | - %d months left
6 |
7 |
8 | - One day left
9 | - %d days left
10 |
11 |
12 | - One hour left
13 | - %d hours left
14 |
15 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/openvpn/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #17C7D1
4 | #17C7D1
5 | #17C7D1
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | #17C7D1
15 | #37E7F1
16 | #47F7FF
17 | #BB47F7FF
18 |
19 |
--------------------------------------------------------------------------------
/openvpn/src/main/res/layout/launchvpn.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
10 |
11 |
16 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/openvpn/src/main/aidl/de/blinkt/openvpn/core/IOpenVPNServiceInternal.aidl:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 |
6 | package de.blinkt.openvpn.core;
7 |
8 | /**
9 | * Created by arne on 15.11.16.
10 | */
11 |
12 | interface IOpenVPNServiceInternal {
13 |
14 | boolean protect(int fd);
15 |
16 | void userPause(boolean b);
17 |
18 | /**
19 | * @param replaceConnection True if the VPN is connected by a new connection.
20 | * @return true if there was a process that has been send a stop signal
21 | */
22 | boolean stopVPN(boolean replaceConnection);
23 | }
24 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/org/spongycastle/util/encoders/Encoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2014 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package org.spongycastle.util.encoders;
6 |
7 | import java.io.IOException;
8 | import java.io.OutputStream;
9 |
10 | /**
11 | * Encode and decode byte arrays (typically from binary to 7-bit ASCII
12 | * encodings).
13 | */
14 | public interface Encoder {
15 | int encode(byte[] data, int off, int length, OutputStream out) throws IOException;
16 |
17 | int decode(byte[] data, int off, int length, OutputStream out) throws IOException;
18 |
19 | int decode(String data, OutputStream out) throws IOException;
20 | }
21 |
--------------------------------------------------------------------------------
/openvpn/src/main/res/drawable/progressbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/org/spongycastle/util/io/pem/PemGenerationException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2014 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package org.spongycastle.util.io.pem;
6 |
7 | import java.io.IOException;
8 |
9 | @SuppressWarnings("serial")
10 | public class PemGenerationException extends IOException {
11 | private Throwable cause;
12 |
13 | public PemGenerationException(String message, Throwable cause) {
14 | super(message);
15 | this.cause = cause;
16 | }
17 |
18 | public PemGenerationException(String message) {
19 | super(message);
20 | }
21 |
22 | public Throwable getCause() {
23 | return cause;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/openvpn/src/main/aidl/de/blinkt/openvpn/core/IStatusCallbacks.aidl:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 |
6 | package de.blinkt.openvpn.core;
7 |
8 | import de.blinkt.openvpn.core.LogItem;
9 | import de.blinkt.openvpn.core.ConnectionStatus;
10 |
11 |
12 |
13 | interface IStatusCallbacks {
14 | /**
15 | * Called when the service has a new status for you.
16 | */
17 | oneway void newLogItem(in LogItem item);
18 |
19 | oneway void updateStateString(in String state, in String msg, in int resid, in ConnectionStatus level);
20 |
21 | oneway void updateByteCount(long inBytes, long outBytes);
22 |
23 | oneway void connectedVPN(String uuid);
24 | }
25 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/openvpn/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/NativeUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 |
7 | import android.os.Build;
8 |
9 | import java.security.InvalidKeyException;
10 |
11 | public class NativeUtils {
12 | static {
13 | System.loadLibrary("opvpnutil");
14 | if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN)
15 | System.loadLibrary("jbcrypto");
16 | }
17 | public static native byte[] rsasign(byte[] input, int pkey) throws InvalidKeyException;
18 | public static native String[] getIfconfig() throws IllegalArgumentException;
19 | static native void jniclose(int fdint);
20 | public static native String getNativeAPI();
21 | }
22 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/Preferences.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 | import android.content.Context;
7 | import android.content.SharedPreferences;
8 |
9 | /**
10 | * Created by arne on 08.01.17.
11 | */
12 | // Until I find a good solution
13 | public class Preferences {
14 | static SharedPreferences getSharedPreferencesMulti(String name, Context c) {
15 | return c.getSharedPreferences(name, Context.MODE_MULTI_PROCESS | Context.MODE_PRIVATE);
16 | }
17 | public static SharedPreferences getDefaultSharedPreferences(Context c) {
18 | return c.getSharedPreferences(c.getPackageName() + "_preferences", Context.MODE_MULTI_PROCESS | Context.MODE_PRIVATE);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
--------------------------------------------------------------------------------
/openvpn/src/main/res/values/untranslatable.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 | Unknown state
9 |
10 |
11 | Waiting for user permission to use VPN API
12 | Waiting for user VPN password
13 | VPN password input dialog cancelled
14 | VPN API permission dialog cancelled
15 |
16 |
17 |
--------------------------------------------------------------------------------
/openvpn/src/androidTest/java/xyz/oboloi/openvpn/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package xyz.oboloi.openvpn;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 |
25 | assertEquals("xyz.oboloi.openvpn.test", appContext.getPackageName());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/xyz/oboloi/openvpnexample/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package xyz.oboloi.openvpnexample;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 |
25 | assertEquals("xyz.oboloi.openvpnexample", appContext.getPackageName());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/api/GrantPermissionsActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.api;
6 | import android.app.Activity;
7 | import android.content.Intent;
8 | import android.net.VpnService;
9 |
10 | public class GrantPermissionsActivity extends Activity {
11 | private static final int VPN_PREPARE = 0;
12 | @Override
13 | protected void onStart() {
14 | super.onStart();
15 | Intent i = VpnService.prepare(this);
16 | if (i == null)
17 | onActivityResult(VPN_PREPARE, RESULT_OK, null);
18 | else
19 | startActivityForResult(i, VPN_PREPARE);
20 | }
21 | @Override
22 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
23 | super.onActivityResult(requestCode, resultCode, data);
24 | setResult(resultCode);
25 | finish();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/OpenVPNManagement.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 | public interface OpenVPNManagement {
7 | int mBytecountInterval = 2;
8 | void reconnect();
9 | void pause(pauseReason reason);
10 | void resume();
11 | /**
12 | * @param replaceConnection True if the VPN is connected by a new connection.
13 | * @return true if there was a process that has been send a stop signal
14 | */
15 | boolean stopVPN(boolean replaceConnection);
16 | /*
17 | * Rebind the interface
18 | */
19 | void networkChange(boolean sameNetwork);
20 | void setPauseCallback(PausedStateCallback callback);
21 | enum pauseReason {
22 | noNetwork,
23 | userPause,
24 | screenOff,
25 | }
26 | interface PausedStateCallback {
27 | boolean shouldBeRunning();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Muizzu Abbas
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 |
21 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 | defaultConfig {
6 | applicationId "xyz.oboloi.openvpnexample"
7 | minSdkVersion 22
8 | targetSdkVersion 28
9 | versionCode 1
10 | versionName "1.0"
11 | ndk {
12 | abiFilters "armeabi-v7a"//, "x86","arm64-v8a","x86_64"
13 | }
14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | implementation fileTree(dir: 'libs', include: ['*.jar'])
26 | implementation 'androidx.appcompat:appcompat:1.0.2'
27 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
28 | implementation project (":openvpn")
29 | testImplementation 'junit:junit:4.12'
30 | androidTestImplementation 'androidx.test:runner:1.2.0'
31 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
32 | }
33 |
--------------------------------------------------------------------------------
/openvpn/src/main/aidl/de/blinkt/openvpn/core/IServiceStatus.aidl:
--------------------------------------------------------------------------------
1 | // StatusIPC.aidl
2 | package de.blinkt.openvpn.core;
3 |
4 | // Declare any non-default types here with import statements
5 | import de.blinkt.openvpn.core.IStatusCallbacks;
6 | import android.os.ParcelFileDescriptor;
7 | import de.blinkt.openvpn.core.TrafficHistory;
8 |
9 |
10 | interface IServiceStatus {
11 | /**
12 | * Registers to receive OpenVPN Status Updates and gets a
13 | * ParcelFileDescript back that contains the log up to that point
14 | */
15 | ParcelFileDescriptor registerStatusCallback(in IStatusCallbacks cb);
16 |
17 | /**
18 | * Remove a previously registered callback interface.
19 | */
20 | void unregisterStatusCallback(in IStatusCallbacks cb);
21 |
22 | /**
23 | * Returns the last connedcted VPN
24 | */
25 | String getLastConnectedVPN();
26 |
27 | /**
28 | * Sets a cached password
29 | */
30 | void setCachedPassword(in String uuid, int type, String password);
31 |
32 | /**
33 | * Gets the traffic history
34 | */
35 | TrafficHistory getTrafficHistory();
36 | }
37 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/ConnectionStatus.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 | import android.os.Parcel;
7 | import android.os.Parcelable;
8 |
9 | /**
10 | * Created by arne on 08.11.16.
11 | */
12 | public enum ConnectionStatus implements Parcelable {
13 | LEVEL_CONNECTED,
14 | LEVEL_VPNPAUSED,
15 | LEVEL_CONNECTING_SERVER_REPLIED,
16 | LEVEL_CONNECTING_NO_SERVER_REPLY_YET,
17 | LEVEL_NONETWORK,
18 | LEVEL_NOTCONNECTED,
19 | LEVEL_START,
20 | LEVEL_AUTH_FAILED,
21 | LEVEL_WAITING_FOR_USER_INPUT,
22 | UNKNOWN_LEVEL;
23 | public static final Creator CREATOR = new Creator() {
24 | @Override
25 | public ConnectionStatus createFromParcel(Parcel in) {
26 | return ConnectionStatus.values()[in.readInt()];
27 | }
28 | @Override
29 | public ConnectionStatus[] newArray(int size) {
30 | return new ConnectionStatus[size];
31 | }
32 | };
33 | @Override
34 | public void writeToParcel(Parcel dest, int flags) {
35 | dest.writeInt(ordinal());
36 | }
37 | @Override
38 | public int describeContents() {
39 | return 0;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/openvpn/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 28
5 |
6 |
7 | defaultConfig {
8 | minSdkVersion 22
9 | targetSdkVersion 28
10 | versionCode 1
11 | versionName "1.0"
12 | ndk {
13 | abiFilters "armeabi-v7a"//, "x86","arm64-v8a","x86_64"
14 | }
15 | }
16 |
17 |
18 | sourceSets {
19 | main {
20 | jniLibs.srcDirs = ['libs']
21 | }
22 | }
23 |
24 | }
25 | android.lintOptions {
26 | disable 'MissingTranslation'//, 'ManifestResource'
27 | }
28 | dependencies {
29 | implementation fileTree(include: ['*.jar','*.so'], dir: 'libs')
30 | // implementation fileTree(dir: 'libs', include: ['*.jar'])
31 | implementation 'androidx.appcompat:appcompat:1.0.2'
32 | implementation 'com.google.android.material:material:1.0.0'
33 | implementation 'androidx.cardview:cardview:1.0.0'
34 | implementation 'com.github.dmytrodanylyk.android-process-button:library:1.0.4'
35 |
36 | implementation 'androidx.appcompat:appcompat:1.0.2'
37 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
38 | testImplementation 'junit:junit:4.12'
39 | implementation 'junit:junit:4.12'
40 | androidTestImplementation 'androidx.test:runner:1.2.0'
41 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
42 | }
43 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/org/spongycastle/util/io/pem/PemHeader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2014 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package org.spongycastle.util.io.pem;
6 |
7 | public class PemHeader {
8 | private String name;
9 | private String value;
10 |
11 | public PemHeader(String name, String value) {
12 | this.name = name;
13 | this.value = value;
14 | }
15 |
16 | public String getName() {
17 | return name;
18 | }
19 |
20 | public String getValue() {
21 | return value;
22 | }
23 |
24 | public int hashCode() {
25 | return getHashCode(this.name) + 31 * getHashCode(this.value);
26 | }
27 |
28 | public boolean equals(Object o) {
29 | if (!(o instanceof PemHeader)) {
30 | return false;
31 | }
32 | PemHeader other = (PemHeader) o;
33 | return other == this || (isEqual(this.name, other.name) && isEqual(this.value, other.value));
34 | }
35 |
36 | private int getHashCode(String s) {
37 | if (s == null) {
38 | return 1;
39 | }
40 | return s.hashCode();
41 | }
42 |
43 | private boolean isEqual(String s1, String s2) {
44 | if (s1 == s2) {
45 | return true;
46 | }
47 | if (s1 == null || s2 == null) {
48 | return false;
49 | }
50 | return s1.equals(s2);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/org/spongycastle/util/io/pem/PemObject.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2014 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package org.spongycastle.util.io.pem;
6 |
7 | import java.util.ArrayList;
8 | import java.util.Collections;
9 | import java.util.List;
10 |
11 | @SuppressWarnings("all")
12 | public class PemObject implements PemObjectGenerator {
13 | private static final List EMPTY_LIST = Collections.unmodifiableList(new ArrayList());
14 | private String type;
15 | private List headers;
16 | private byte[] content;
17 |
18 | /**
19 | * Generic constructor for object without headers.
20 | *
21 | * @param type pem object type.
22 | * @param content the binary content of the object.
23 | */
24 | public PemObject(String type, byte[] content) {
25 | this(type, EMPTY_LIST, content);
26 | }
27 |
28 | /**
29 | * Generic constructor for object with headers.
30 | *
31 | * @param type pem object type.
32 | * @param headers a list of PemHeader objects.
33 | * @param content the binary content of the object.
34 | */
35 | public PemObject(String type, List headers, byte[] content) {
36 | this.type = type;
37 | this.headers = Collections.unmodifiableList(headers);
38 | this.content = content;
39 | }
40 |
41 | public String getType() {
42 | return type;
43 | }
44 |
45 | public List getHeaders() {
46 | return headers;
47 | }
48 |
49 | public byte[] getContent() {
50 | return content;
51 | }
52 |
53 | public PemObject generate() throws PemGenerationException {
54 | return this;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/api/APIVpnProfile.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.api;
6 | import android.os.Parcel;
7 | import android.os.Parcelable;
8 |
9 | public class APIVpnProfile implements Parcelable {
10 | public static final Creator CREATOR
11 | = new Creator() {
12 | public APIVpnProfile createFromParcel(Parcel in) {
13 | return new APIVpnProfile(in);
14 | }
15 | public APIVpnProfile[] newArray(int size) {
16 | return new APIVpnProfile[size];
17 | }
18 | };
19 | public final String mUUID;
20 | public final String mName;
21 | //public final String mProfileCreator;
22 | public final boolean mUserEditable;
23 | public APIVpnProfile(Parcel in) {
24 | mUUID = in.readString();
25 | mName = in.readString();
26 | mUserEditable = in.readInt() != 0;
27 | //mProfileCreator = in.readString();
28 | }
29 | public APIVpnProfile(String uuidString, String name, boolean userEditable, String profileCreator) {
30 | mUUID = uuidString;
31 | mName = name;
32 | mUserEditable = userEditable;
33 | //mProfileCreator = profileCreator;
34 | }
35 | @Override
36 | public int describeContents() {
37 | return 0;
38 | }
39 | @Override
40 | public void writeToParcel(Parcel dest, int flags) {
41 | dest.writeString(mUUID);
42 | dest.writeString(mName);
43 | if (mUserEditable)
44 | dest.writeInt(0);
45 | else
46 | dest.writeInt(1);
47 | //dest.writeString(mProfileCreator);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/openvpn/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/PasswordCache.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 | import java.util.UUID;
7 |
8 | /**
9 | * Created by arne on 15.12.16.
10 | */
11 | public class PasswordCache {
12 | public static final int PCKS12ORCERTPASSWORD = 2;
13 | public static final int AUTHPASSWORD = 3;
14 | private static PasswordCache mInstance;
15 | final private UUID mUuid;
16 | private String mKeyOrPkcs12Password;
17 | private String mAuthPassword;
18 | private PasswordCache(UUID uuid) {
19 | mUuid = uuid;
20 | }
21 | public static PasswordCache getInstance(UUID uuid) {
22 | if (mInstance == null || !mInstance.mUuid.equals(uuid)) {
23 | mInstance = new PasswordCache(uuid);
24 | }
25 | return mInstance;
26 | }
27 | public static String getPKCS12orCertificatePassword(UUID uuid, boolean resetPw) {
28 | String pwcopy = getInstance(uuid).mKeyOrPkcs12Password;
29 | if (resetPw)
30 | getInstance(uuid).mKeyOrPkcs12Password = null;
31 | return pwcopy;
32 | }
33 | public static String getAuthPassword(UUID uuid, boolean resetPW) {
34 | String pwcopy = getInstance(uuid).mAuthPassword;
35 | if (resetPW)
36 | getInstance(uuid).mAuthPassword = null;
37 | return pwcopy;
38 | }
39 | public static void setCachedPassword(String uuid, int type, String password) {
40 | PasswordCache instance = getInstance(UUID.fromString(uuid));
41 | switch (type) {
42 | case PCKS12ORCERTPASSWORD:
43 | instance.mKeyOrPkcs12Password = password;
44 | break;
45 | case AUTHPASSWORD:
46 | instance.mAuthPassword = password;
47 | break;
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/ProxyDetection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 |
7 | import xyz.oboloi.openvpn.R;
8 |
9 | import java.net.InetSocketAddress;
10 | import java.net.MalformedURLException;
11 | import java.net.Proxy;
12 | import java.net.ProxySelector;
13 | import java.net.SocketAddress;
14 | import java.net.URISyntaxException;
15 | import java.net.URL;
16 | import java.util.List;
17 |
18 | import de.blinkt.openvpn.VpnProfile;
19 |
20 | public class ProxyDetection {
21 | static SocketAddress detectProxy(VpnProfile vp) {
22 | // Construct a new url with https as protocol
23 | try {
24 | URL url = new URL(String.format("https://%s:%s", vp.mServerName, vp.mServerPort));
25 | Proxy proxy = getFirstProxy(url);
26 | if (proxy == null)
27 | return null;
28 | SocketAddress addr = proxy.address();
29 | if (addr instanceof InetSocketAddress) {
30 | return addr;
31 | }
32 | } catch (MalformedURLException e) {
33 | VpnStatus.logError(R.string.getproxy_error, e.getLocalizedMessage());
34 | } catch (URISyntaxException e) {
35 | VpnStatus.logError(R.string.getproxy_error, e.getLocalizedMessage());
36 | }
37 | return null;
38 | }
39 | static Proxy getFirstProxy(URL url) throws URISyntaxException {
40 | System.setProperty("java.net.useSystemProxies", "true");
41 | List proxylist = ProxySelector.getDefault().select(url.toURI());
42 | if (proxylist != null) {
43 | for (Proxy proxy : proxylist) {
44 | SocketAddress addr = proxy.address();
45 | if (addr != null) {
46 | return proxy;
47 | }
48 | }
49 | }
50 | return null;
51 | }
52 | }
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/Connection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 |
7 | import android.text.TextUtils;
8 |
9 | import java.io.Serializable;
10 | import java.util.Locale;
11 |
12 | public class Connection implements Serializable, Cloneable {
13 | public static final int CONNECTION_DEFAULT_TIMEOUT = 120;
14 | private static final long serialVersionUID = 92031902903829089L;
15 | public String mServerName = "openvpn.example.com";
16 | public String mServerPort = "1194";
17 | public boolean mUseUdp = true;
18 | public String mCustomConfiguration = "";
19 | public boolean mUseCustomConfig = false;
20 | public boolean mEnabled = true;
21 | public int mConnectTimeout = 0;
22 | public String getConnectionBlock() {
23 | String cfg = "";
24 | // Server Address
25 | cfg += "remote ";
26 | cfg += mServerName;
27 | cfg += " ";
28 | cfg += mServerPort;
29 | if (mUseUdp)
30 | cfg += " udp\n";
31 | else
32 | cfg += " tcp-client\n";
33 | if (mConnectTimeout != 0)
34 | cfg += String.format(Locale.US, " connect-timeout %d\n", mConnectTimeout);
35 | if (!TextUtils.isEmpty(mCustomConfiguration) && mUseCustomConfig) {
36 | cfg += mCustomConfiguration;
37 | cfg += "\n";
38 | }
39 | return cfg;
40 | }
41 | @Override
42 | public Connection clone() throws CloneNotSupportedException {
43 | return (Connection) super.clone();
44 | }
45 | public boolean isOnlyRemote() {
46 | return TextUtils.isEmpty(mCustomConfiguration) || !mUseCustomConfig;
47 | }
48 | public int getTimeout() {
49 | if (mConnectTimeout <= 0)
50 | return CONNECTION_DEFAULT_TIMEOUT;
51 | else
52 | return mConnectTimeout;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/CIDRIP.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 | import java.util.Locale;
7 |
8 | class CIDRIP {
9 | String mIp;
10 | int len;
11 | public CIDRIP(String ip, String mask) {
12 | mIp = ip;
13 | long netmask = getInt(mask);
14 | // Add 33. bit to ensure the loop terminates
15 | netmask += 1l << 32;
16 | int lenZeros = 0;
17 | while ((netmask & 0x1) == 0) {
18 | lenZeros++;
19 | netmask = netmask >> 1;
20 | }
21 | // Check if rest of netmask is only 1s
22 | if (netmask != (0x1ffffffffl >> lenZeros)) {
23 | // Asume no CIDR, set /32
24 | len = 32;
25 | } else {
26 | len = 32 - lenZeros;
27 | }
28 | }
29 | public CIDRIP(String address, int prefix_length) {
30 | len = prefix_length;
31 | mIp = address;
32 | }
33 | static long getInt(String ipaddr) {
34 | String[] ipt = ipaddr.split("\\.");
35 | long ip = 0;
36 | ip += Long.parseLong(ipt[0]) << 24;
37 | ip += Integer.parseInt(ipt[1]) << 16;
38 | ip += Integer.parseInt(ipt[2]) << 8;
39 | ip += Integer.parseInt(ipt[3]);
40 | return ip;
41 | }
42 | @Override
43 | public String toString() {
44 | return String.format(Locale.ENGLISH, "%s/%d", mIp, len);
45 | }
46 | public boolean normalise() {
47 | long ip = getInt(mIp);
48 | long newip = ip & (0xffffffffL << (32 - len));
49 | if (newip != ip) {
50 | mIp = String.format(Locale.US, "%d.%d.%d.%d", (newip & 0xff000000) >> 24, (newip & 0xff0000) >> 16, (newip & 0xff00) >> 8, newip & 0xff);
51 | return true;
52 | } else {
53 | return false;
54 | }
55 | }
56 | public long getInt() {
57 | return getInt(mIp);
58 | }
59 | }
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/api/ExternalAppDatabase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.api;
6 |
7 | import android.content.Context;
8 | import android.content.SharedPreferences;
9 | import android.content.SharedPreferences.Editor;
10 |
11 | import java.util.HashSet;
12 | import java.util.Set;
13 |
14 | import de.blinkt.openvpn.core.Preferences;
15 |
16 | public class ExternalAppDatabase {
17 | private final String PREFERENCES_KEY = "allowed_apps";
18 | Context mContext;
19 | public ExternalAppDatabase(Context c) {
20 | mContext = c;
21 | }
22 | boolean isAllowed(String packagename) {
23 | Set allowedapps = getExtAppList();
24 | return allowedapps.contains(packagename);
25 | }
26 | public Set getExtAppList() {
27 | SharedPreferences prefs = Preferences.getDefaultSharedPreferences(mContext);
28 | return prefs.getStringSet(PREFERENCES_KEY, new HashSet());
29 | }
30 | void addApp(String packagename) {
31 | Set allowedapps = getExtAppList();
32 | allowedapps.add(packagename);
33 | saveExtAppList(allowedapps);
34 | }
35 | private void saveExtAppList(Set allowedapps) {
36 | SharedPreferences prefs = Preferences.getDefaultSharedPreferences(mContext);
37 | Editor prefedit = prefs.edit();
38 | // Workaround for bug
39 | prefedit.putStringSet(PREFERENCES_KEY, allowedapps);
40 | int counter = prefs.getInt("counter", 0);
41 | prefedit.putInt("counter", counter + 1);
42 | prefedit.apply();
43 | }
44 | public void clearAllApiApps() {
45 | saveExtAppList(new HashSet());
46 | }
47 | public void removeApp(String packagename) {
48 | Set allowedapps = getExtAppList();
49 | allowedapps.remove(packagename);
50 | saveExtAppList(allowedapps);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/LollipopDeviceStateListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 | import android.annotation.TargetApi;
7 | import android.net.ConnectivityManager;
8 | import android.net.LinkProperties;
9 | import android.net.Network;
10 | import android.net.NetworkCapabilities;
11 | import android.os.Build;
12 |
13 | /**
14 | * Created by arne on 26.11.14.
15 | */
16 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
17 | public class LollipopDeviceStateListener extends ConnectivityManager.NetworkCallback {
18 | private String mLastConnectedStatus;
19 | private String mLastLinkProperties;
20 | private String mLastNetworkCapabilities;
21 | @Override
22 | public void onAvailable(Network network) {
23 | super.onAvailable(network);
24 | if (!network.toString().equals(mLastConnectedStatus)) {
25 | mLastConnectedStatus = network.toString();
26 | VpnStatus.logDebug("Connected to " + mLastConnectedStatus);
27 | }
28 | }
29 | @Override
30 | public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
31 | super.onLinkPropertiesChanged(network, linkProperties);
32 | if (!linkProperties.toString().equals(mLastLinkProperties)) {
33 | mLastLinkProperties = linkProperties.toString();
34 | VpnStatus.logDebug(String.format("Linkproperties of %s: %s", network, linkProperties));
35 | }
36 | }
37 | @Override
38 | public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
39 | super.onCapabilitiesChanged(network, networkCapabilities);
40 | if (!networkCapabilities.toString().equals(mLastNetworkCapabilities)) {
41 | mLastNetworkCapabilities = networkCapabilities.toString();
42 | VpnStatus.logDebug(String.format("Network capabilities of %s: %s", network, networkCapabilities));
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/openvpn/src/main/res/layout/userpass.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
13 |
23 |
24 |
34 |
35 |
43 |
44 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/org/spongycastle/util/io/pem/PemReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2014 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package org.spongycastle.util.io.pem;
6 |
7 | import org.spongycastle.util.encoders.Base64;
8 |
9 | import java.io.BufferedReader;
10 | import java.io.IOException;
11 | import java.io.Reader;
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | public class PemReader extends BufferedReader {
16 | private static final String BEGIN = "-----BEGIN ";
17 | private static final String END = "-----END ";
18 |
19 | public PemReader(Reader reader) {
20 | super(reader);
21 | }
22 |
23 | public PemObject readPemObject() throws IOException {
24 | String line = readLine();
25 | while (line != null && !line.startsWith(BEGIN)) {
26 | line = readLine();
27 | }
28 | if (line != null) {
29 | line = line.substring(BEGIN.length());
30 | int index = line.indexOf('-');
31 | String type = line.substring(0, index);
32 | if (index > 0) {
33 | return loadObject(type);
34 | }
35 | }
36 | return null;
37 | }
38 |
39 | private PemObject loadObject(String type) throws IOException {
40 | String line;
41 | String endMarker = END + type;
42 | StringBuilder buf = new StringBuilder();
43 | List headers = new ArrayList();
44 | while ((line = readLine()) != null) {
45 | if (line.indexOf(":") >= 0) {
46 | int index = line.indexOf(':');
47 | String hdr = line.substring(0, index);
48 | String value = line.substring(index + 1).trim();
49 | headers.add(new PemHeader(hdr, value));
50 | continue;
51 | }
52 | if (line.indexOf(endMarker) != -1) {
53 | break;
54 | }
55 | buf.append(line.trim());
56 | }
57 | if (line == null) {
58 | throw new IOException(endMarker + " not found");
59 | }
60 | return new PemObject(type, headers, Base64.decode(buf.toString()));
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
32 |
33 |
34 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/app/src/main/java/xyz/oboloi/openvpnexample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package xyz.oboloi.openvpnexample;
2 |
3 | import androidx.appcompat.app.AppCompatActivity;
4 |
5 |
6 | import android.os.Bundle;
7 | import android.util.Log;
8 | import android.view.View;
9 | import android.widget.Button;
10 |
11 | import xyz.oboloi.openvpn.OboloiVPN;
12 | import xyz.oboloi.openvpn.OnVPNStatusChangeListener;
13 |
14 | public class MainActivity extends AppCompatActivity {
15 |
16 | private Button btnConnect;
17 | private OboloiVPN oboloiVPN;
18 |
19 | @Override
20 | protected void onCreate(Bundle savedInstanceState) {
21 | super.onCreate(savedInstanceState);
22 | setContentView(R.layout.activity_main);
23 | btnConnect = findViewById(R.id.start);
24 | oboloiVPN = new OboloiVPN(MainActivity.this, getApplicationContext());
25 | //oboloiVPN.launchVPN("https://downloads.nordcdn.com/configs/files/ovpn_legacy/servers/al10.nordvpn.com.udp1194.ovpn");
26 | oboloiVPN.launchVPN("https://firebasestorage.googleapis.com/v0/b/bilet-oboloi.appspot.com/o/testclient.ovpn?alt=media&token=a9b788e9-efba-4107-8e14-abbf50d63e19");
27 |
28 |
29 | oboloiVPN.setOnVPNStatusChangeListener(new OnVPNStatusChangeListener() {
30 |
31 | @Override
32 | public void onProfileLoaded(boolean profileLoaded) {
33 | if(profileLoaded){
34 | btnConnect.setEnabled(true);
35 | }else {
36 | btnConnect.setEnabled(false);
37 | }
38 |
39 | }
40 | @Override
41 | public void onVPNStatusChanged(boolean vpnActivated) {
42 | if(vpnActivated){
43 | btnConnect.setText("disconnect");
44 | }else{
45 | btnConnect.setText("connect");
46 | }
47 | }
48 |
49 |
50 | });
51 |
52 |
53 | btnConnect.setOnClickListener(new View.OnClickListener() {
54 | @Override
55 | public void onClick(View v) {
56 |
57 | oboloiVPN.init();
58 |
59 | }
60 | });
61 |
62 | }
63 |
64 | // @Override
65 | // protected void onStop() {
66 | // oboloiVPN.onStop();
67 | // super.onStop();
68 | // }
69 |
70 | @Override
71 | protected void onResume() {
72 | super.onResume();
73 | oboloiVPN.onResume();
74 | }
75 |
76 | @Override
77 | protected void onPause() {
78 | super.onPause();
79 | oboloiVPN.onPause();
80 | }
81 |
82 |
83 | @Override
84 | public void finish() {
85 | super.finish();
86 | oboloiVPN.cleanup();
87 | }
88 |
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/openvpn/src/main/res/layout/api_confirm.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
21 |
22 |
27 |
28 |
34 |
35 |
41 |
42 |
47 |
48 |
49 |
56 |
57 |
64 |
65 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/xyz/oboloi/openvpn/DataCleanManager.java:
--------------------------------------------------------------------------------
1 | package xyz.oboloi.openvpn;
2 |
3 | import android.content.Context;
4 | import android.os.Environment;
5 |
6 | import java.io.File;
7 |
8 |
9 | public class DataCleanManager {
10 |
11 | public static void cleanCache(Context context) {
12 | deleteFilesByDirectory(context.getCacheDir());
13 | cleanExternalCache(context);
14 | }
15 |
16 |
17 | private static void deleteDatabases(Context context) {
18 | for (String database : context.databaseList()) {
19 | context.deleteDatabase(database);
20 | }
21 | }
22 |
23 |
24 | private static void cleanSharedPreference(Context context) {
25 | deleteFilesByDirectory(new File(/*"/data/data/" + context.getPackageName()*/ context.getFilesDir().getParent() + "/shared_prefs"));
26 | }
27 |
28 |
29 |
30 |
31 | private static void cleanFiles(Context context) {
32 | deleteFilesByDirectory(context.getFilesDir());
33 | }
34 |
35 |
36 | private static void cleanExternalCache(Context context) {
37 | if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
38 | deleteFilesByDirectory(context.getExternalCacheDir());
39 | }
40 | }
41 |
42 |
43 | // public static void cleanCustomCache(String filePath) {
44 | // deleteFilesByDirectory(new File(filePath));
45 | // }
46 |
47 |
48 | public static void cleanApplicationData(Context context/*, String... filepath*/) {
49 | cleanCache(context);
50 | // cleanExternalCache(context);
51 | // cleanDatabases(context);
52 | deleteDatabases(context);
53 | cleanSharedPreference(context);
54 | cleanFiles(context);
55 | // for (String filePath : filepath) {
56 | // cleanCustomCache(filePath);
57 | // }
58 | }
59 |
60 |
61 | private static void deleteFilesByDirectory(File directory) {
62 | if (directory != null && directory.exists() && directory.isDirectory()) {
63 | for (File item : directory.listFiles()) {
64 | item.delete();
65 | // item.deleteOnExit();
66 | }
67 | }
68 | }
69 |
70 |
71 |
72 | public static float getFolderSize(File file) {
73 | float size = 0;
74 | try {
75 | File[] fileList = file.listFiles();
76 | for (File aFileList : fileList) {
77 |
78 | if (aFileList.isDirectory()) {
79 | size = size + getFolderSize(aFileList);
80 | } else {
81 | size = size + aFileList.length();
82 | }
83 | }
84 | } catch (Exception e) {
85 | e.printStackTrace();
86 | return 0;
87 | }
88 | return size;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/openvpn/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl:
--------------------------------------------------------------------------------
1 | // IOpenVPNAPIService.aidl
2 | package de.blinkt.openvpn.api;
3 |
4 | import de.blinkt.openvpn.api.APIVpnProfile;
5 | import de.blinkt.openvpn.api.IOpenVPNStatusCallback;
6 |
7 | import android.content.Intent;
8 | import android.os.ParcelFileDescriptor;
9 |
10 | interface IOpenVPNAPIService {
11 | List getProfiles();
12 |
13 | void startProfile (String profileUUID);
14 |
15 | /** Use a profile with all certificates etc. embedded,
16 | * old version which does not return the UUID of the addded profile, see
17 | * below for a version that return the UUID on add */
18 | boolean addVPNProfile (String name, String config);
19 |
20 | /** start a profile using a config as inline string. Make sure that all needed data is inlined,
21 | * e.g., using ... or ...
22 | * See the OpenVPN manual page for more on inlining files */
23 | void startVPN (in String inlineconfig);
24 |
25 | /** This permission framework is used to avoid confused deputy style attack to the VPN
26 | * calling this will give null if the app is allowed to use the external API and an Intent
27 | * that can be launched to request permissions otherwise */
28 | Intent prepare (in String packagename);
29 |
30 | /** Used to trigger to the Android VPN permission dialog (VPNService.prepare()) in advance,
31 | * if this return null OpenVPN for ANdroid already has the permissions otherwise you can start the returned Intent
32 | * to let OpenVPN for Android request the permission */
33 | Intent prepareVPNService ();
34 |
35 | /* Disconnect the VPN */
36 | void disconnect();
37 |
38 | /* Pause the VPN (same as using the pause feature in the notifcation bar) */
39 | void pause();
40 |
41 | /* Resume the VPN (same as using the pause feature in the notifcation bar) */
42 | void resume();
43 |
44 | /**
45 | * Registers to receive OpenVPN Status Updates
46 | */
47 | void registerStatusCallback(in IOpenVPNStatusCallback cb);
48 |
49 | /**
50 | * Remove a previously registered callback interface.
51 | */
52 | void unregisterStatusCallback(in IOpenVPNStatusCallback cb);
53 |
54 | /** Remove a profile by UUID */
55 | void removeProfile (in String profileUUID);
56 |
57 | /** Request a socket to be protected as a VPN socket would be. Useful for creating
58 | * a helper socket for an app controlling OpenVPN
59 | * Before calling this function you should make sure OpenVPN for Android may actually
60 | * this function by checking if prepareVPNService returns null; */
61 | boolean protectSocket(in ParcelFileDescriptor fd);
62 |
63 |
64 | /** Use a profile with all certificates etc. embedded */
65 | APIVpnProfile addNewVPNProfile (String name, boolean userEditable, String config);
66 | }
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/App.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 |
7 | import android.annotation.TargetApi;
8 | import android.app.Application;
9 | import android.app.NotificationChannel;
10 | import android.app.NotificationManager;
11 | import android.content.Context;
12 | import android.graphics.Color;
13 | import android.os.Build;
14 |
15 | import xyz.oboloi.openvpn.R;
16 |
17 |
18 | //import com.onesignal.OneSignal;
19 | //import com.orm.SugarContext;
20 | //import com.oasisfeng.condom.CondomProcess;
21 |
22 | /*
23 | import org.acra.ACRA;
24 | import org.acra.ReportingInteractionMode;
25 | import org.acra.annotation.ReportsCrashes;
26 | */
27 | public class App extends /*com.orm.SugarApp*/ Application {
28 |
29 | @Override
30 | public void onCreate() {
31 | super.onCreate();
32 | // CondomProcess.installExceptDefaultProcess(this);
33 | PRNGFixes.apply();
34 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
35 | createNotificationChannels();
36 | }
37 | StatusListener mStatus = new StatusListener();
38 | mStatus.init(getApplicationContext());
39 | // OneSignal.startInit(this).inFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification).unsubscribeWhenNotificationsAreDisabled(true).init();
40 | // SugarContext.init(this);//初始化
41 | }
42 |
43 | public static boolean isStart;
44 |
45 | @TargetApi(Build.VERSION_CODES.O)
46 | private void createNotificationChannels() {
47 | NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
48 | // Background message
49 | String name = getString(R.string.channel_name_background);
50 | NotificationChannel mChannel = new NotificationChannel(OpenVPNService.NOTIFICATION_CHANNEL_BG_ID, name, NotificationManager.IMPORTANCE_MIN);
51 | mChannel.setDescription(getString(R.string.channel_description_background));
52 | mChannel.enableLights(false);
53 | mChannel.setLightColor(Color.DKGRAY);
54 | mNotificationManager.createNotificationChannel(mChannel);
55 | // Connection status change messages
56 | name = getString(R.string.channel_name_status);
57 | mChannel = new NotificationChannel(OpenVPNService.NOTIFICATION_CHANNEL_NEWSTATUS_ID, name, NotificationManager.IMPORTANCE_DEFAULT);
58 | mChannel.setDescription(getString(R.string.channel_description_status));
59 | mChannel.enableLights(true);
60 | mChannel.setLightColor(Color.BLUE);
61 | mNotificationManager.createNotificationChannel(mChannel);
62 | }
63 |
64 | // @Override
65 | // public void onTerminate() {
66 | // super.onTerminate();
67 | // SugarContext.terminate();//终止销毁
68 | // }
69 | }
70 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/org/spongycastle/util/encoders/Base64.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2014 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package org.spongycastle.util.encoders;
6 |
7 | import java.io.ByteArrayOutputStream;
8 | import java.io.IOException;
9 | import java.io.OutputStream;
10 |
11 | public class Base64 {
12 | private static final Encoder encoder = new Base64Encoder();
13 |
14 | /**
15 | * encode the input data producing a base 64 encoded byte array.
16 | *
17 | * @return a byte array containing the base 64 encoded data.
18 | */
19 | public static byte[] encode(byte[] data) {
20 | int len = (data.length + 2) / 3 * 4;
21 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
22 | try {
23 | encoder.encode(data, 0, data.length, bOut);
24 | } catch (IOException e) {
25 | throw new RuntimeException("exception encoding base64 string: " + e);
26 | }
27 | return bOut.toByteArray();
28 | }
29 |
30 | /**
31 | * Encode the byte data to base 64 writing it to the given output stream.
32 | *
33 | * @return the number of bytes produced.
34 | */
35 | public static int encode(byte[] data, OutputStream out) throws IOException {
36 | return encoder.encode(data, 0, data.length, out);
37 | }
38 |
39 | /**
40 | * Encode the byte data to base 64 writing it to the given output stream.
41 | *
42 | * @return the number of bytes produced.
43 | */
44 | public static int encode(byte[] data, int off, int length, OutputStream out) throws IOException {
45 | return encoder.encode(data, off, length, out);
46 | }
47 |
48 | /**
49 | * decode the base 64 encoded input data. It is assumed the input data is valid.
50 | *
51 | * @return a byte array representing the decoded data.
52 | */
53 | public static byte[] decode(byte[] data) {
54 | int len = data.length / 4 * 3;
55 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
56 | try {
57 | encoder.decode(data, 0, data.length, bOut);
58 | } catch (IOException e) {
59 | throw new RuntimeException("exception decoding base64 string: " + e);
60 | }
61 | return bOut.toByteArray();
62 | }
63 |
64 | /**
65 | * decode the base 64 encoded String data - whitespace will be ignored.
66 | *
67 | * @return a byte array representing the decoded data.
68 | */
69 | public static byte[] decode(String data) {
70 | int len = data.length() / 4 * 3;
71 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
72 | try {
73 | encoder.decode(data, bOut);
74 | } catch (IOException e) {
75 | throw new RuntimeException("exception decoding base64 string: " + e);
76 | }
77 | return bOut.toByteArray();
78 | }
79 |
80 | /**
81 | * decode the base 64 encoded String data writing it to the given output stream,
82 | * whitespace characters will be ignored.
83 | *
84 | * @return the number of bytes produced.
85 | */
86 | public static int decode(String data, OutputStream out) throws IOException {
87 | return encoder.decode(data, out);
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/StatusListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 |
7 | import android.content.ComponentName;
8 | import android.content.Context;
9 | import android.content.Intent;
10 | import android.content.ServiceConnection;
11 | import android.os.IBinder;
12 | import android.os.ParcelFileDescriptor;
13 | import android.os.RemoteException;
14 |
15 | import java.io.DataInputStream;
16 | import java.io.File;
17 | import java.io.IOException;
18 |
19 | /**
20 | * Created by arne on 09.11.16.
21 | */
22 | public class StatusListener {
23 | private File mCacheDir;
24 | private IStatusCallbacks mCallback = new IStatusCallbacks.Stub() {
25 | @Override
26 | public void newLogItem(LogItem item) throws RemoteException {
27 | VpnStatus.newLogItem(item);
28 | }
29 |
30 | @Override
31 | public void updateStateString(String state, String msg, int resid, ConnectionStatus level) throws RemoteException {
32 | VpnStatus.updateStateString(state, msg, resid, level);
33 | }
34 |
35 | @Override
36 | public void updateByteCount(long inBytes, long outBytes) throws RemoteException {
37 | VpnStatus.updateByteCount(inBytes, outBytes);
38 | }
39 |
40 | @Override
41 | public void connectedVPN(String uuid) throws RemoteException {
42 | VpnStatus.setConnectedVPNProfile(uuid);
43 | }
44 | };
45 | private ServiceConnection mConnection = new ServiceConnection() {
46 | @Override
47 | public void onServiceConnected(ComponentName className, IBinder service) {
48 | // We've bound to LocalService, cast the IBinder and get LocalService instance
49 | IServiceStatus serviceStatus = IServiceStatus.Stub.asInterface(service);
50 | try {
51 | /* Check if this a local service ... */
52 | if (service.queryLocalInterface("de.blinkt.openvpn.core.IServiceStatus") == null) {
53 | // Not a local service
54 | VpnStatus.setConnectedVPNProfile(serviceStatus.getLastConnectedVPN());
55 | VpnStatus.setTrafficHistory(serviceStatus.getTrafficHistory());
56 | ParcelFileDescriptor pfd = serviceStatus.registerStatusCallback(mCallback);
57 | DataInputStream fd = new DataInputStream(new ParcelFileDescriptor.AutoCloseInputStream(pfd));
58 | short len = fd.readShort();
59 | byte[] buf = new byte[65336];
60 | while (len != 0x7fff) {
61 | fd.readFully(buf, 0, len);
62 | LogItem logitem = new LogItem(buf, len);
63 | VpnStatus.newLogItem(logitem, false);
64 | len = fd.readShort();
65 | }
66 | fd.close();
67 | } else {
68 | VpnStatus.initLogCache(mCacheDir);
69 | }
70 | } catch (RemoteException | IOException e) {
71 | e.printStackTrace();
72 | VpnStatus.logException(e);
73 | }
74 | }
75 |
76 | @Override
77 | public void onServiceDisconnected(ComponentName arg0) {
78 | }
79 | };
80 |
81 | void init(Context c) {
82 | Intent intent = new Intent(c, OpenVPNStatusService.class);
83 | intent.setAction(OpenVPNService.START_SERVICE);
84 | mCacheDir = c.getCacheDir();
85 | c.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/org/spongycastle/util/io/pem/PemWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2014 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package org.spongycastle.util.io.pem;
6 |
7 | import org.spongycastle.util.encoders.Base64;
8 |
9 | import java.io.BufferedWriter;
10 | import java.io.IOException;
11 | import java.io.Writer;
12 | import java.util.Iterator;
13 |
14 | /**
15 | * A generic PEM writer, based on RFC 1421
16 | */
17 | @SuppressWarnings("all")
18 | public class PemWriter extends BufferedWriter {
19 | private static final int LINE_LENGTH = 64;
20 | private final int nlLength;
21 | private char[] buf = new char[LINE_LENGTH];
22 |
23 | /**
24 | * Base constructor.
25 | *
26 | * @param out output stream to use.
27 | */
28 | public PemWriter(Writer out) {
29 | super(out);
30 | String nl = System.getProperty("line.separator");
31 | if (nl != null) {
32 | nlLength = nl.length();
33 | } else {
34 | nlLength = 2;
35 | }
36 | }
37 |
38 | /**
39 | * Return the number of bytes or characters required to contain the
40 | * passed in object if it is PEM encoded.
41 | *
42 | * @param obj pem object to be output
43 | * @return an estimate of the number of bytes
44 | */
45 | public int getOutputSize(PemObject obj) {
46 | // BEGIN and END boundaries.
47 | int size = (2 * (obj.getType().length() + 10 + nlLength)) + 6 + 4;
48 | if (!obj.getHeaders().isEmpty()) {
49 | for (Iterator it = obj.getHeaders().iterator(); it.hasNext(); ) {
50 | PemHeader hdr = (PemHeader) it.next();
51 | size += hdr.getName().length() + ": ".length() + hdr.getValue().length() + nlLength;
52 | }
53 | size += nlLength;
54 | }
55 | // base64 encoding
56 | int dataLen = ((obj.getContent().length + 2) / 3) * 4;
57 | size += dataLen + (((dataLen + LINE_LENGTH - 1) / LINE_LENGTH) * nlLength);
58 | return size;
59 | }
60 |
61 | public void writeObject(PemObjectGenerator objGen) throws IOException {
62 | PemObject obj = objGen.generate();
63 | writePreEncapsulationBoundary(obj.getType());
64 | if (!obj.getHeaders().isEmpty()) {
65 | for (Iterator it = obj.getHeaders().iterator(); it.hasNext(); ) {
66 | PemHeader hdr = (PemHeader) it.next();
67 | this.write(hdr.getName());
68 | this.write(": ");
69 | this.write(hdr.getValue());
70 | this.newLine();
71 | }
72 | this.newLine();
73 | }
74 | writeEncoded(obj.getContent());
75 | writePostEncapsulationBoundary(obj.getType());
76 | }
77 |
78 | private void writeEncoded(byte[] bytes) throws IOException {
79 | bytes = Base64.encode(bytes);
80 | for (int i = 0; i < bytes.length; i += buf.length) {
81 | int index = 0;
82 | while (index != buf.length) {
83 | if ((i + index) >= bytes.length) {
84 | break;
85 | }
86 | buf[index] = (char) bytes[i + index];
87 | index++;
88 | }
89 | this.write(buf, 0, index);
90 | this.newLine();
91 | }
92 | }
93 |
94 | private void writePreEncapsulationBoundary(String type) throws IOException {
95 | this.write("-----BEGIN " + type + "-----");
96 | this.newLine();
97 | }
98 |
99 | private void writePostEncapsulationBoundary(String type) throws IOException {
100 | this.write("-----END " + type + "-----");
101 | this.newLine();
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | xmlns:android
14 |
15 | ^$
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | xmlns:.*
25 |
26 | ^$
27 |
28 |
29 | BY_NAME
30 |
31 |
32 |
33 |
34 |
35 |
36 | .*:id
37 |
38 | http://schemas.android.com/apk/res/android
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | .*:name
48 |
49 | http://schemas.android.com/apk/res/android
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | name
59 |
60 | ^$
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | style
70 |
71 | ^$
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | .*
81 |
82 | ^$
83 |
84 |
85 | BY_NAME
86 |
87 |
88 |
89 |
90 |
91 |
92 | .*
93 |
94 | http://schemas.android.com/apk/res/android
95 |
96 |
97 | ANDROID_ATTRIBUTE_ORDER
98 |
99 |
100 |
101 |
102 |
103 |
104 | .*
105 |
106 | .*
107 |
108 |
109 | BY_NAME
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/api/ConfirmDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2011 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package de.blinkt.openvpn.api;
17 |
18 | import android.app.Activity;
19 | import android.app.AlertDialog;
20 | import android.app.AlertDialog.Builder;
21 | import android.content.DialogInterface;
22 | import android.content.DialogInterface.OnShowListener;
23 | import android.content.pm.ApplicationInfo;
24 | import android.content.pm.PackageManager;
25 | import android.util.Log;
26 | import android.view.View;
27 | import android.widget.Button;
28 | import android.widget.CompoundButton;
29 | import android.widget.ImageView;
30 | import android.widget.TextView;
31 |
32 | import xyz.oboloi.openvpn.R;
33 |
34 | public class ConfirmDialog extends Activity implements CompoundButton.OnCheckedChangeListener, DialogInterface.OnClickListener {
35 | private static final String TAG = "OpenVPNVpnConfirm";
36 | private String mPackage;
37 | private Button mButton;
38 | private AlertDialog mAlert;
39 |
40 | @Override
41 | protected void onResume() {
42 | super.onResume();
43 | try {
44 | mPackage = getCallingPackage();
45 | if (mPackage == null) {
46 | finish();
47 | return;
48 | }
49 | PackageManager pm = getPackageManager();
50 | ApplicationInfo app = pm.getApplicationInfo(mPackage, 0);
51 | View view = View.inflate(this, R.layout.api_confirm, null);
52 | ((ImageView) view.findViewById(R.id.icon)).setImageDrawable(app.loadIcon(pm));
53 | ((TextView) view.findViewById(R.id.prompt)).setText(getString(R.string.prompt, app.loadLabel(pm), getString(R.string.app_name)));
54 | ((CompoundButton) view.findViewById(R.id.check)).setOnCheckedChangeListener(this);
55 | Builder builder = new Builder(this);
56 | builder.setView(view);
57 | builder.setIconAttribute(android.R.attr.alertDialogIcon);
58 | builder.setTitle(android.R.string.dialog_alert_title);
59 | builder.setPositiveButton(android.R.string.ok, this);
60 | builder.setNegativeButton(android.R.string.cancel, this);
61 | mAlert = builder.create();
62 | mAlert.setCanceledOnTouchOutside(false);
63 | mAlert.setOnShowListener(new OnShowListener() {
64 | @Override
65 | public void onShow(DialogInterface dialog) {
66 | mButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
67 | mButton.setEnabled(false);
68 | }
69 | });
70 | //setCloseOnTouchOutside(false);
71 | mAlert.show();
72 | } catch (Exception e) {
73 | Log.e(TAG, "onResume", e);
74 | finish();
75 | }
76 | }
77 |
78 | @Override
79 | public void onBackPressed() {
80 | setResult(RESULT_CANCELED);
81 | finish();
82 | }
83 |
84 | @Override
85 | public void onCheckedChanged(CompoundButton button, boolean checked) {
86 | mButton.setEnabled(checked);
87 | }
88 |
89 | @Override
90 | public void onClick(DialogInterface dialog, int which) {
91 | if (which == DialogInterface.BUTTON_POSITIVE) {
92 | ExternalAppDatabase extapps = new ExternalAppDatabase(this);
93 | extapps.addApp(mPackage);
94 | setResult(RESULT_OK);
95 | finish();
96 | }
97 | if (which == DialogInterface.BUTTON_NEGATIVE) {
98 | setResult(RESULT_CANCELED);
99 | finish();
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/xyz/oboloi/openvpn/ProfileAsync.java:
--------------------------------------------------------------------------------
1 | package xyz.oboloi.openvpn;
2 |
3 | import android.content.Context;
4 | import android.net.ConnectivityManager;
5 | import android.net.NetworkInfo;
6 | import android.os.AsyncTask;
7 | import android.os.Build;
8 |
9 | import java.io.BufferedReader;
10 | import java.io.IOException;
11 | import java.io.InputStream;
12 | import java.io.InputStreamReader;
13 | import java.lang.ref.WeakReference;
14 | import java.net.HttpURLConnection;
15 | import java.net.MalformedURLException;
16 | import java.net.URL;
17 |
18 | import de.blinkt.openvpn.VpnProfile;
19 | import de.blinkt.openvpn.core.ConfigParser;
20 | import de.blinkt.openvpn.core.ProfileManager;
21 |
22 | /**
23 | * ==================================================
24 | * Created by wang on 2017/11/15. gentlewxy@163.com
25 | * Description:
26 | * ==================================================
27 | */
28 |
29 | public class ProfileAsync extends AsyncTask {
30 |
31 | private WeakReference context;
32 | private OnProfileLoadListener onProfileLoadListener;
33 | private String ovpnUrl;
34 |
35 | public ProfileAsync(Context context, OnProfileLoadListener onProfileLoadListener, String ovpnUrl) {
36 | this.context = new WeakReference<>(context);
37 | this.onProfileLoadListener = onProfileLoadListener;
38 | this.ovpnUrl = ovpnUrl;
39 | }
40 |
41 | @Override
42 | protected void onPreExecute() {
43 | super.onPreExecute();
44 | Context context = this.context.get();
45 | if (context == null || onProfileLoadListener == null) {
46 | cancel(true);
47 | } else if (!isNetworkAvailable(context)) {
48 | cancel(true);
49 | onProfileLoadListener.onProfileLoadFailed("No Network");
50 | }
51 | }
52 |
53 | @Override
54 | protected Boolean doInBackground(Void... voids) {
55 | try {
56 | // InputStream inputStream = url.openConnection().getInputStream();
57 | URL url = new URL(ovpnUrl);
58 | HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
59 | httpURLConnection.setConnectTimeout(10 * 1000);
60 | httpURLConnection.setReadTimeout(10 * 1000);
61 | InputStream inputStream = httpURLConnection.getInputStream();
62 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream/*, Charset.forName("UTF-8")*/));
63 |
64 | ConfigParser cp = new ConfigParser();
65 | cp.parseConfig(bufferedReader);
66 | VpnProfile vp = cp.convertProfile();
67 | ProfileManager vpl = ProfileManager.getInstance(context.get());
68 | vp.mName = Build.MODEL;//
69 | vp.mUsername = null;
70 | vp.mPassword = null;
71 | vpl.addProfile(vp);
72 | vpl.saveProfile(context.get(), vp);
73 | vpl.saveProfileList(context.get());
74 |
75 | return true;
76 | } catch (MalformedURLException e) {
77 | cancel(true);
78 | onProfileLoadListener.onProfileLoadFailed("MalformedURLException");
79 | } catch (ConfigParser.ConfigParseError configParseError) {
80 | cancel(true);
81 | onProfileLoadListener.onProfileLoadFailed("ConfigParseError");
82 | } catch (IOException e) {
83 | cancel(true);
84 | onProfileLoadListener.onProfileLoadFailed("IOException");
85 | }
86 | return false;
87 | }
88 |
89 | @Override
90 | protected void onPostExecute(Boolean aVoid) {
91 | super.onPostExecute(aVoid);
92 | if (aVoid) {
93 | onProfileLoadListener.onProfileLoadSuccess();
94 | } else {
95 | onProfileLoadListener.onProfileLoadFailed("unknown error");
96 | }
97 | }
98 |
99 | public interface OnProfileLoadListener {
100 | void onProfileLoadSuccess();
101 |
102 | void onProfileLoadFailed(String msg);
103 | }
104 |
105 | private boolean isNetworkAvailable(Context context) {
106 | ConnectivityManager connectivityManager = (ConnectivityManager) context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
107 | if (connectivityManager == null) {
108 | return false;
109 | }
110 | NetworkInfo info = connectivityManager.getActiveNetworkInfo();
111 | return info != null && info.isAvailable() && info.isConnected();
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 |
7 | import android.annotation.TargetApi;
8 | import android.content.Context;
9 | import android.content.Intent;
10 | import android.os.Build;
11 |
12 | import xyz.oboloi.openvpn.R;
13 |
14 | import java.io.File;
15 | import java.io.FileOutputStream;
16 | import java.io.IOException;
17 | import java.io.InputStream;
18 | import java.util.Arrays;
19 | import java.util.Vector;
20 |
21 | import de.blinkt.openvpn.VpnProfile;
22 |
23 | public class VPNLaunchHelper {
24 | private static final String MININONPIEVPN = "nopie_openvpn";
25 | private static final String MINIPIEVPN = "pie_openvpn";
26 | private static final String OVPNCONFIGFILE = "android.conf";
27 | private static String writeMiniVPN(Context context) {
28 | String[] abis;
29 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
30 | abis = getSupportedABIsLollipop();
31 | else
32 | //noinspection deprecation
33 | abis = new String[]{Build.CPU_ABI, Build.CPU_ABI2};
34 | String nativeAPI = NativeUtils.getNativeAPI();
35 | if (!nativeAPI.equals(abis[0])) {
36 | VpnStatus.logWarning(R.string.abi_mismatch, Arrays.toString(abis), nativeAPI);
37 | abis = new String[]{nativeAPI};
38 | }
39 | for (String abi : abis) {
40 | File vpnExecutable = new File(context.getCacheDir(), "c_" + getMiniVPNExecutableName() + "." + abi);
41 | if ((vpnExecutable.exists() && vpnExecutable.canExecute()) || writeMiniVPNBinary(context, abi, vpnExecutable)) {
42 | return vpnExecutable.getPath();
43 | }
44 | }
45 | return null;
46 | }
47 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
48 | private static String[] getSupportedABIsLollipop() {
49 | return Build.SUPPORTED_ABIS;
50 | }
51 | private static String getMiniVPNExecutableName() {
52 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
53 | return MINIPIEVPN;
54 | else
55 | return MININONPIEVPN;
56 | }
57 | public static String[] replacePieWithNoPie(String[] mArgv) {
58 | mArgv[0] = mArgv[0].replace(MINIPIEVPN, MININONPIEVPN);
59 | return mArgv;
60 | }
61 | static String[] buildOpenvpnArgv(Context c) {
62 | Vector args = new Vector<>();
63 | String binaryName = writeMiniVPN(c);
64 | // Add fixed paramenters
65 | //args.add("/data/data/de.blinkt.openvpn/lib/openvpn");
66 | if (binaryName == null) {
67 | VpnStatus.logError("Error writing minivpn binary");
68 | return null;
69 | }
70 | args.add(binaryName);
71 | args.add("--config");
72 | args.add(getConfigFilePath(c));
73 | return args.toArray(new String[args.size()]);
74 | }
75 | private static boolean writeMiniVPNBinary(Context context, String abi, File mvpnout) {
76 | try {
77 | InputStream mvpn;
78 | try {
79 | mvpn = context.getAssets().open(getMiniVPNExecutableName() + "." + abi);
80 | } catch (IOException errabi) {
81 | VpnStatus.logInfo("Failed getting assets for archicture " + abi);
82 | return false;
83 | }
84 | FileOutputStream fout = new FileOutputStream(mvpnout);
85 | byte buf[] = new byte[4096];
86 | int lenread = mvpn.read(buf);
87 | while (lenread > 0) {
88 | fout.write(buf, 0, lenread);
89 | lenread = mvpn.read(buf);
90 | }
91 | fout.close();
92 | if (!mvpnout.setExecutable(true)) {
93 | VpnStatus.logError("Failed to make OpenVPN executable");
94 | return false;
95 | }
96 | return true;
97 | } catch (IOException e) {
98 | VpnStatus.logException(e);
99 | return false;
100 | }
101 | }
102 | public static void startOpenVpn(VpnProfile startprofile, Context context) {
103 | Intent startVPN = startprofile.prepareStartService(context);
104 | if (startVPN != null) {
105 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
106 | //noinspection NewApi
107 | context.startForegroundService(startVPN);
108 | else
109 | context.startService(startVPN);
110 | }
111 | }
112 | public static String getConfigFilePath(Context context) {
113 | return context.getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE;
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/xyz/oboloi/openvpn/OboloiVPN.java:
--------------------------------------------------------------------------------
1 | package xyz.oboloi.openvpn;
2 |
3 |
4 | import android.app.Activity;
5 | import android.content.ComponentName;
6 | import android.content.ContentProvider;
7 | import android.content.ContentValues;
8 | import android.content.Context;
9 | import android.content.Intent;
10 | import android.content.ServiceConnection;
11 | import android.database.Cursor;
12 | import android.net.Uri;
13 | import android.os.Build;
14 | import android.os.IBinder;
15 | import android.os.RemoteException;
16 | import android.util.Log;
17 | import android.widget.Button;
18 | import android.widget.Toast;
19 |
20 | import androidx.annotation.NonNull;
21 | import androidx.annotation.Nullable;
22 | import androidx.appcompat.app.AppCompatActivity;
23 | import androidx.lifecycle.LifecycleObserver;
24 |
25 | import java.util.Objects;
26 |
27 | import de.blinkt.openvpn.LaunchVPN;
28 | import de.blinkt.openvpn.VpnProfile;
29 | import de.blinkt.openvpn.core.App;
30 | import de.blinkt.openvpn.core.ConnectionStatus;
31 | import de.blinkt.openvpn.core.IOpenVPNServiceInternal;
32 | import de.blinkt.openvpn.core.OpenVPNService;
33 | import de.blinkt.openvpn.core.ProfileManager;
34 | import de.blinkt.openvpn.core.VpnStatus;
35 |
36 |
37 | public class OboloiVPN implements VpnStatus.ByteCountListener, VpnStatus.StateListener {
38 |
39 | // final OboloiVPN ourInstance = new OboloiVPN();
40 | private static IOpenVPNServiceInternal mService;
41 | private ProfileAsync profileAsync;
42 |
43 | private boolean profileStatus;
44 |
45 | private Activity activity;
46 | private Context context;
47 | private OnVPNStatusChangeListener listener;
48 |
49 | private boolean value;
50 |
51 | public void setOnVPNStatusChangeListener(OnVPNStatusChangeListener listener)
52 | {
53 | this.listener = listener;
54 | }
55 |
56 | private ServiceConnection mConnection = new ServiceConnection() {
57 | @Override
58 | public void onServiceConnected(ComponentName className, IBinder service) {
59 | mService = IOpenVPNServiceInternal.Stub.asInterface(service);
60 | }
61 |
62 | @Override
63 | public void onServiceDisconnected(ComponentName arg0) {
64 | mService = null;
65 | }
66 | };
67 |
68 |
69 | public OboloiVPN(Activity activity, Context context) {
70 | this.activity = activity;
71 | this.context = context;
72 |
73 | }
74 |
75 |
76 | public void launchVPN(String url) {
77 |
78 |
79 | if (!App.isStart) {
80 | DataCleanManager.cleanApplicationData(context);
81 | setProfileLoadStatus(false);
82 | profileAsync = new ProfileAsync(context, new ProfileAsync.OnProfileLoadListener() {
83 | @Override
84 | public void onProfileLoadSuccess() {
85 | setProfileLoadStatus(true);
86 | }
87 |
88 | @Override
89 | public void onProfileLoadFailed(String msg) {
90 |
91 | Toast.makeText(context, activity.getString(R.string.init_fail) + msg, Toast.LENGTH_SHORT).show();
92 | }
93 | }, url);
94 | profileAsync.execute();
95 | }
96 |
97 | }
98 |
99 |
100 | public void init() {
101 |
102 |
103 | Runnable r = new Runnable() {
104 | @Override
105 | public void run() {
106 | if (!App.isStart) {
107 | startVPN();
108 | App.isStart = true;
109 |
110 | } else {
111 | stopVPN();
112 | App.isStart = false;
113 |
114 | }
115 | }
116 | };
117 | r.run();
118 | }
119 |
120 | public void onStop() {
121 | VpnStatus.removeStateListener(this);
122 | VpnStatus.removeByteCountListener(this);
123 | }
124 |
125 | public void onResume() {
126 | VpnStatus.addStateListener(this);
127 | VpnStatus.addByteCountListener(this);
128 | Intent intent = new Intent(activity, OpenVPNService.class);
129 | intent.setAction(OpenVPNService.START_SERVICE);
130 | activity.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
131 | }
132 |
133 | public void onPause() {
134 | activity.unbindService(mConnection);
135 | }
136 |
137 | public void cleanup() {
138 | if (profileAsync != null && !profileAsync.isCancelled()) {
139 | profileAsync.cancel(true);
140 | }
141 | }
142 |
143 | private void startVPN() {
144 | try {
145 | ProfileManager pm = ProfileManager.getInstance(context);
146 | VpnProfile profile = pm.getProfileByName(Build.MODEL);
147 | startVPNConnection(profile);
148 | } catch (Exception ex) {
149 | App.isStart = false;
150 |
151 | }
152 | }
153 |
154 | private void stopVPN() {
155 | stopVPNConnection();
156 | setVPNStatus(false);
157 | //btnConnect.setText(getString(R.string.connect));
158 |
159 | }
160 |
161 | public boolean getVPNStatus() {
162 | return value;
163 | }
164 |
165 | public boolean getProfileStatus(){
166 | return profileStatus;
167 | }
168 |
169 |
170 | private void setVPNStatus(boolean value)
171 | {
172 | this.value = value;
173 |
174 | if(listener != null)
175 | {
176 | listener.onVPNStatusChanged(value);
177 | }
178 | }
179 |
180 | private void setProfileLoadStatus(boolean profileStatus){
181 | this.profileStatus = profileStatus;
182 |
183 | if(listener != null){
184 | listener.onProfileLoaded(profileStatus);
185 | }
186 | }
187 |
188 |
189 | // ------------- Functions Related to OpenVPN-------------
190 | private void startVPNConnection(VpnProfile vp) {
191 | Intent intent = new Intent(activity, LaunchVPN.class);
192 | intent.putExtra(LaunchVPN.EXTRA_KEY, vp.getUUID().toString());
193 | intent.setAction(Intent.ACTION_MAIN);
194 | activity.startActivity(intent);
195 | }
196 |
197 | private void stopVPNConnection() {
198 |
199 | ProfileManager.setConnectedVpnProfileDisconnected(context);
200 | if (mService != null) {
201 | try {
202 | mService.stopVPN(false);
203 | onStop();
204 | } catch (RemoteException e) {
205 | VpnStatus.logException(e);
206 | }
207 | }
208 | }
209 |
210 |
211 | @Override
212 | public void updateState(final String state, String logmessage, int localizedResId, ConnectionStatus level) {
213 | activity.runOnUiThread(new Runnable() {
214 | @Override
215 | public void run() {
216 | if (state.equals("CONNECTED")) {
217 | Log.e("status", "connected");
218 | App.isStart = true;
219 | setVPNStatus(true);
220 | }
221 |
222 | if (state.equals("AUTH_FAILED")) {
223 | Toast.makeText(activity, "Wrong Username or Password!", Toast.LENGTH_SHORT).show();
224 | setVPNStatus(false);
225 | }
226 |
227 |
228 | }
229 | });
230 | }
231 |
232 | @Override
233 | public void setConnectedVPN(String uuid) {
234 |
235 | }
236 |
237 | @Override
238 | public void updateByteCount(long in, long out, long diffIn, long diffOut) {
239 |
240 | }
241 |
242 |
243 | }
244 |
245 |
246 |
247 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/TrafficHistory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2017 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 |
7 | import android.os.Parcel;
8 | import android.os.Parcelable;
9 |
10 | import java.util.HashSet;
11 | import java.util.LinkedList;
12 | import java.util.Vector;
13 |
14 | import static java.lang.Math.max;
15 |
16 | /**
17 | * Created by arne on 23.05.17.
18 | */
19 | public class TrafficHistory implements Parcelable {
20 | public static final long PERIODS_TO_KEEP = 5;
21 | public static final int TIME_PERIOD_MINTUES = 60 * 1000;
22 | public static final int TIME_PERIOD_HOURS = 3600 * 1000;
23 | public static final Creator CREATOR = new Creator() {
24 | @Override
25 | public TrafficHistory createFromParcel(Parcel in) {
26 | return new TrafficHistory(in);
27 | }
28 | @Override
29 | public TrafficHistory[] newArray(int size) {
30 | return new TrafficHistory[size];
31 | }
32 | };
33 | private LinkedList trafficHistorySeconds = new LinkedList<>();
34 | private LinkedList trafficHistoryMinutes = new LinkedList<>();
35 | private LinkedList trafficHistoryHours = new LinkedList<>();
36 | private TrafficDatapoint lastSecondUsedForMinute;
37 | private TrafficDatapoint lastMinuteUsedForHours;
38 | public TrafficHistory() {
39 | }
40 | protected TrafficHistory(Parcel in) {
41 | in.readList(trafficHistorySeconds, getClass().getClassLoader());
42 | in.readList(trafficHistoryMinutes, getClass().getClassLoader());
43 | in.readList(trafficHistoryHours, getClass().getClassLoader());
44 | lastSecondUsedForMinute = in.readParcelable(getClass().getClassLoader());
45 | lastMinuteUsedForHours = in.readParcelable(getClass().getClassLoader());
46 | }
47 | public static LinkedList getDummyList() {
48 | LinkedList list = new LinkedList<>();
49 | list.add(new TrafficDatapoint(0, 0, System.currentTimeMillis()));
50 | return list;
51 | }
52 | public LastDiff getLastDiff(TrafficDatapoint tdp) {
53 | TrafficDatapoint lasttdp;
54 | if (trafficHistorySeconds.size() == 0)
55 | lasttdp = new TrafficDatapoint(0, 0, System.currentTimeMillis());
56 | else
57 | lasttdp = trafficHistorySeconds.getLast();
58 | if (tdp == null) {
59 | tdp = lasttdp;
60 | if (trafficHistorySeconds.size() < 2)
61 | lasttdp = tdp;
62 | else {
63 | trafficHistorySeconds.descendingIterator().next();
64 | tdp = trafficHistorySeconds.descendingIterator().next();
65 | }
66 | }
67 | return new LastDiff(lasttdp, tdp);
68 | }
69 | @Override
70 | public int describeContents() {
71 | return 0;
72 | }
73 | @Override
74 | public void writeToParcel(Parcel dest, int flags) {
75 | dest.writeList(trafficHistorySeconds);
76 | dest.writeList(trafficHistoryMinutes);
77 | dest.writeList(trafficHistoryHours);
78 | dest.writeParcelable(lastSecondUsedForMinute, 0);
79 | dest.writeParcelable(lastMinuteUsedForHours, 0);
80 | }
81 | public LinkedList getHours() {
82 | return trafficHistoryHours;
83 | }
84 | public LinkedList getMinutes() {
85 | return trafficHistoryMinutes;
86 | }
87 | public LinkedList getSeconds() {
88 | return trafficHistorySeconds;
89 | }
90 | LastDiff add(long in, long out) {
91 | TrafficDatapoint tdp = new TrafficDatapoint(in, out, System.currentTimeMillis());
92 | LastDiff diff = getLastDiff(tdp);
93 | addDataPoint(tdp);
94 | return diff;
95 | }
96 | private void addDataPoint(TrafficDatapoint tdp) {
97 | trafficHistorySeconds.add(tdp);
98 | if (lastSecondUsedForMinute == null) {
99 | lastSecondUsedForMinute = new TrafficDatapoint(0, 0, 0);
100 | lastMinuteUsedForHours = new TrafficDatapoint(0, 0, 0);
101 | }
102 | removeAndAverage(tdp, true);
103 | }
104 | private void removeAndAverage(TrafficDatapoint newTdp, boolean seconds) {
105 | HashSet toRemove = new HashSet<>();
106 | Vector toAverage = new Vector<>();
107 | long timePeriod;
108 | LinkedList tpList, nextList;
109 | TrafficDatapoint lastTsPeriod;
110 | if (seconds) {
111 | timePeriod = TIME_PERIOD_MINTUES;
112 | tpList = trafficHistorySeconds;
113 | nextList = trafficHistoryMinutes;
114 | lastTsPeriod = lastSecondUsedForMinute;
115 | } else {
116 | timePeriod = TIME_PERIOD_HOURS;
117 | tpList = trafficHistoryMinutes;
118 | nextList = trafficHistoryHours;
119 | lastTsPeriod = lastMinuteUsedForHours;
120 | }
121 | if (newTdp.timestamp / timePeriod > (lastTsPeriod.timestamp / timePeriod)) {
122 | nextList.add(newTdp);
123 | if (seconds) {
124 | lastSecondUsedForMinute = newTdp;
125 | removeAndAverage(newTdp, false);
126 | } else
127 | lastMinuteUsedForHours = newTdp;
128 | for (TrafficDatapoint tph : tpList) {
129 | // List is iteratered from oldest to newest, remembert first one that we did not
130 | if ((newTdp.timestamp - tph.timestamp) / timePeriod >= PERIODS_TO_KEEP)
131 | toRemove.add(tph);
132 | }
133 | tpList.removeAll(toRemove);
134 | }
135 | }
136 | public static class TrafficDatapoint implements Parcelable {
137 | public static final Creator CREATOR = new Creator() {
138 | @Override
139 | public TrafficDatapoint createFromParcel(Parcel in) {
140 | return new TrafficDatapoint(in);
141 | }
142 | @Override
143 | public TrafficDatapoint[] newArray(int size) {
144 | return new TrafficDatapoint[size];
145 | }
146 | };
147 | public final long timestamp;
148 | public final long in;
149 | public final long out;
150 | private TrafficDatapoint(long inBytes, long outBytes, long timestamp) {
151 | this.in = inBytes;
152 | this.out = outBytes;
153 | this.timestamp = timestamp;
154 | }
155 | private TrafficDatapoint(Parcel in) {
156 | timestamp = in.readLong();
157 | this.in = in.readLong();
158 | out = in.readLong();
159 | }
160 | @Override
161 | public int describeContents() {
162 | return 0;
163 | }
164 | @Override
165 | public void writeToParcel(Parcel dest, int flags) {
166 | dest.writeLong(timestamp);
167 | dest.writeLong(in);
168 | dest.writeLong(out);
169 | }
170 | }
171 | static class LastDiff {
172 | final private TrafficDatapoint tdp;
173 | final private TrafficDatapoint lasttdp;
174 | private LastDiff(TrafficDatapoint lasttdp, TrafficDatapoint tdp) {
175 | this.lasttdp = lasttdp;
176 | this.tdp = tdp;
177 | }
178 | public long getDiffOut() {
179 | return max(0, tdp.out - lasttdp.out);
180 | }
181 | public long getDiffIn() {
182 | return max(0, tdp.in - lasttdp.in);
183 | }
184 | public long getIn() {
185 | return tdp.in;
186 | }
187 | public long getOut() {
188 | return tdp.out;
189 | }
190 | }
191 | }
--------------------------------------------------------------------------------
/openvpn/src/main/java/org/spongycastle/util/encoders/Base64Encoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2014 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package org.spongycastle.util.encoders;
6 |
7 | import java.io.IOException;
8 | import java.io.OutputStream;
9 |
10 | public class Base64Encoder implements Encoder {
11 | protected final byte[] encodingTable = {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) '+', (byte) '/'};
12 | /*
13 | * set up the decoding table.
14 | */
15 | protected final byte[] decodingTable = new byte[128];
16 | protected byte padding = (byte) '=';
17 |
18 | public Base64Encoder() {
19 | initialiseDecodingTable();
20 | }
21 |
22 | protected void initialiseDecodingTable() {
23 | for (int i = 0; i < encodingTable.length; i++) {
24 | decodingTable[encodingTable[i]] = (byte) i;
25 | }
26 | }
27 |
28 | /**
29 | * encode the input data producing a base 64 output stream.
30 | *
31 | * @return the number of bytes produced.
32 | */
33 | public int encode(byte[] data, int off, int length, OutputStream out) throws IOException {
34 | int modulus = length % 3;
35 | int dataLength = (length - modulus);
36 | int a1, a2, a3;
37 | for (int i = off; i < off + dataLength; i += 3) {
38 | a1 = data[i] & 0xff;
39 | a2 = data[i + 1] & 0xff;
40 | a3 = data[i + 2] & 0xff;
41 | out.write(encodingTable[(a1 >>> 2) & 0x3f]);
42 | out.write(encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f]);
43 | out.write(encodingTable[((a2 << 2) | (a3 >>> 6)) & 0x3f]);
44 | out.write(encodingTable[a3 & 0x3f]);
45 | }
46 | /*
47 | * process the tail end.
48 | */
49 | int b1, b2, b3;
50 | int d1, d2;
51 | switch (modulus) {
52 | case 0: /* nothing left to do */
53 | break;
54 | case 1:
55 | d1 = data[off + dataLength] & 0xff;
56 | b1 = (d1 >>> 2) & 0x3f;
57 | b2 = (d1 << 4) & 0x3f;
58 | out.write(encodingTable[b1]);
59 | out.write(encodingTable[b2]);
60 | out.write(padding);
61 | out.write(padding);
62 | break;
63 | case 2:
64 | d1 = data[off + dataLength] & 0xff;
65 | d2 = data[off + dataLength + 1] & 0xff;
66 | b1 = (d1 >>> 2) & 0x3f;
67 | b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f;
68 | b3 = (d2 << 2) & 0x3f;
69 | out.write(encodingTable[b1]);
70 | out.write(encodingTable[b2]);
71 | out.write(encodingTable[b3]);
72 | out.write(padding);
73 | break;
74 | }
75 | return (dataLength / 3) * 4 + ((modulus == 0) ? 0 : 4);
76 | }
77 |
78 | private boolean ignore(char c) {
79 | return (c == '\n' || c == '\r' || c == '\t' || c == ' ');
80 | }
81 |
82 | /**
83 | * decode the base 64 encoded byte data writing it to the given output stream,
84 | * whitespace characters will be ignored.
85 | *
86 | * @return the number of bytes produced.
87 | */
88 | public int decode(byte[] data, int off, int length, OutputStream out) throws IOException {
89 | byte b1, b2, b3, b4;
90 | int outLen = 0;
91 | int end = off + length;
92 | while (end > off) {
93 | if (!ignore((char) data[end - 1])) {
94 | break;
95 | }
96 | end--;
97 | }
98 | int i = off;
99 | int finish = end - 4;
100 | i = nextI(data, i, finish);
101 | while (i < finish) {
102 | b1 = decodingTable[data[i++]];
103 | i = nextI(data, i, finish);
104 | b2 = decodingTable[data[i++]];
105 | i = nextI(data, i, finish);
106 | b3 = decodingTable[data[i++]];
107 | i = nextI(data, i, finish);
108 | b4 = decodingTable[data[i++]];
109 | out.write((b1 << 2) | (b2 >> 4));
110 | out.write((b2 << 4) | (b3 >> 2));
111 | out.write((b3 << 6) | b4);
112 | outLen += 3;
113 | i = nextI(data, i, finish);
114 | }
115 | outLen += decodeLastBlock(out, (char) data[end - 4], (char) data[end - 3], (char) data[end - 2], (char) data[end - 1]);
116 | return outLen;
117 | }
118 |
119 | private int nextI(byte[] data, int i, int finish) {
120 | while ((i < finish) && ignore((char) data[i])) {
121 | i++;
122 | }
123 | return i;
124 | }
125 |
126 | /**
127 | * decode the base 64 encoded String data writing it to the given output stream,
128 | * whitespace characters will be ignored.
129 | *
130 | * @return the number of bytes produced.
131 | */
132 | public int decode(String data, OutputStream out) throws IOException {
133 | byte b1, b2, b3, b4;
134 | int length = 0;
135 | int end = data.length();
136 | while (end > 0) {
137 | if (!ignore(data.charAt(end - 1))) {
138 | break;
139 | }
140 | end--;
141 | }
142 | int i = 0;
143 | int finish = end - 4;
144 | i = nextI(data, i, finish);
145 | while (i < finish) {
146 | b1 = decodingTable[data.charAt(i++)];
147 | i = nextI(data, i, finish);
148 | b2 = decodingTable[data.charAt(i++)];
149 | i = nextI(data, i, finish);
150 | b3 = decodingTable[data.charAt(i++)];
151 | i = nextI(data, i, finish);
152 | b4 = decodingTable[data.charAt(i++)];
153 | out.write((b1 << 2) | (b2 >> 4));
154 | out.write((b2 << 4) | (b3 >> 2));
155 | out.write((b3 << 6) | b4);
156 | length += 3;
157 | i = nextI(data, i, finish);
158 | }
159 | length += decodeLastBlock(out, data.charAt(end - 4), data.charAt(end - 3), data.charAt(end - 2), data.charAt(end - 1));
160 | return length;
161 | }
162 |
163 | private int decodeLastBlock(OutputStream out, char c1, char c2, char c3, char c4) throws IOException {
164 | byte b1, b2, b3, b4;
165 | if (c3 == padding) {
166 | b1 = decodingTable[c1];
167 | b2 = decodingTable[c2];
168 | out.write((b1 << 2) | (b2 >> 4));
169 | return 1;
170 | } else if (c4 == padding) {
171 | b1 = decodingTable[c1];
172 | b2 = decodingTable[c2];
173 | b3 = decodingTable[c3];
174 | out.write((b1 << 2) | (b2 >> 4));
175 | out.write((b2 << 4) | (b3 >> 2));
176 | return 2;
177 | } else {
178 | b1 = decodingTable[c1];
179 | b2 = decodingTable[c2];
180 | b3 = decodingTable[c3];
181 | b4 = decodingTable[c4];
182 | out.write((b1 << 2) | (b2 >> 4));
183 | out.write((b2 << 4) | (b3 >> 2));
184 | out.write((b3 << 6) | b4);
185 | return 3;
186 | }
187 | }
188 |
189 | private int nextI(String data, int i, int finish) {
190 | while ((i < finish) && ignore(data.charAt(i))) {
191 | i++;
192 | }
193 | return i;
194 | }
195 | }
196 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/LogFileHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2015 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 |
7 | import android.os.Handler;
8 | import android.os.Looper;
9 | import android.os.Message;
10 |
11 |
12 | import java.io.BufferedInputStream;
13 | import java.io.File;
14 | import java.io.FileInputStream;
15 | import java.io.FileNotFoundException;
16 | import java.io.FileOutputStream;
17 | import java.io.IOException;
18 | import java.io.InputStream;
19 | import java.io.OutputStream;
20 | import java.io.UnsupportedEncodingException;
21 | import java.nio.BufferOverflowException;
22 | import java.nio.ByteBuffer;
23 | import java.util.Locale;
24 |
25 | import xyz.oboloi.openvpn.R;
26 |
27 | /**
28 | * Created by arne on 23.01.16.
29 | */
30 | class LogFileHandler extends Handler {
31 | public static final int LOG_MESSAGE = 103;
32 | public static final int MAGIC_BYTE = 0x55;
33 | public static final String LOGFILE_NAME = "logcache.dat";
34 | static final int TRIM_LOG_FILE = 100;
35 | static final int FLUSH_TO_DISK = 101;
36 | static final int LOG_INIT = 102;
37 | private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
38 | protected OutputStream mLogFile;
39 | public LogFileHandler(Looper looper) {
40 | super(looper);
41 | }
42 | public static String bytesToHex(byte[] bytes, int len) {
43 | len = Math.min(bytes.length, len);
44 | char[] hexChars = new char[len * 2];
45 | for (int j = 0; j < len; j++) {
46 | int v = bytes[j] & 0xFF;
47 | hexChars[j * 2] = hexArray[v >>> 4];
48 | hexChars[j * 2 + 1] = hexArray[v & 0x0F];
49 | }
50 | return new String(hexChars);
51 | }
52 | @Override
53 | public void handleMessage(Message msg) {
54 | try {
55 | if (msg.what == LOG_INIT) {
56 | if (mLogFile != null)
57 | throw new RuntimeException("mLogFile not null");
58 | readLogCache((File) msg.obj);
59 | openLogFile((File) msg.obj);
60 | } else if (msg.what == LOG_MESSAGE && msg.obj instanceof LogItem) {
61 | // Ignore log messages if not yet initialized
62 | if (mLogFile == null)
63 | return;
64 | writeLogItemToDisk((LogItem) msg.obj);
65 | } else if (msg.what == TRIM_LOG_FILE) {
66 | trimLogFile();
67 | for (LogItem li : VpnStatus.getlogbuffer())
68 | writeLogItemToDisk(li);
69 | } else if (msg.what == FLUSH_TO_DISK) {
70 | flushToDisk();
71 | }
72 | } catch (IOException | BufferOverflowException e) {
73 | e.printStackTrace();
74 | VpnStatus.logError("Error during log cache: " + msg.what);
75 | VpnStatus.logException(e);
76 | }
77 | }
78 | private void flushToDisk() throws IOException {
79 | mLogFile.flush();
80 | }
81 | private void trimLogFile() {
82 | try {
83 | mLogFile.flush();
84 | ((FileOutputStream) mLogFile).getChannel().truncate(0);
85 | } catch (IOException e) {
86 | e.printStackTrace();
87 | }
88 | }
89 | private void writeLogItemToDisk(LogItem li) throws IOException {
90 | // We do not really care if the log cache breaks between Android upgrades,
91 | // write binary format to disc
92 | byte[] liBytes = li.getMarschaledBytes();
93 | writeEscapedBytes(liBytes);
94 | }
95 | public void writeEscapedBytes(byte[] bytes) throws IOException {
96 | int magic = 0;
97 | for (byte b : bytes)
98 | if (b == MAGIC_BYTE || b == MAGIC_BYTE + 1)
99 | magic++;
100 | byte eBytes[] = new byte[bytes.length + magic];
101 | int i = 0;
102 | for (byte b : bytes) {
103 | if (b == MAGIC_BYTE || b == MAGIC_BYTE + 1) {
104 | eBytes[i++] = MAGIC_BYTE + 1;
105 | eBytes[i++] = (byte) (b - MAGIC_BYTE);
106 | } else {
107 | eBytes[i++] = b;
108 | }
109 | }
110 | byte[] lenBytes = ByteBuffer.allocate(4).putInt(bytes.length).array();
111 | synchronized (mLogFile) {
112 | mLogFile.write(MAGIC_BYTE);
113 | mLogFile.write(lenBytes);
114 | mLogFile.write(eBytes);
115 | }
116 | }
117 | private void openLogFile(File cacheDir) throws FileNotFoundException {
118 | File logfile = new File(cacheDir, LOGFILE_NAME);
119 | mLogFile = new FileOutputStream(logfile);
120 | }
121 | private void readLogCache(File cacheDir) {
122 | try {
123 | File logfile = new File(cacheDir, LOGFILE_NAME);
124 | if (!logfile.exists() || !logfile.canRead())
125 | return;
126 | readCacheContents(new FileInputStream(logfile));
127 | } catch (IOException | RuntimeException e) {
128 | VpnStatus.logError("Reading cached logfile failed");
129 | VpnStatus.logException(e);
130 | e.printStackTrace();
131 | // ignore reading file error
132 | } finally {
133 | synchronized (VpnStatus.readFileLock) {
134 | VpnStatus.readFileLog = true;
135 | VpnStatus.readFileLock.notifyAll();
136 | }
137 | }
138 | }
139 | protected void readCacheContents(InputStream in) throws IOException {
140 | BufferedInputStream logFile = new BufferedInputStream(in);
141 | byte[] buf = new byte[16384];
142 | int read = logFile.read(buf, 0, 5);
143 | int itemsRead = 0;
144 | readloop:
145 | while (read >= 5) {
146 | int skipped = 0;
147 | while (buf[skipped] != MAGIC_BYTE) {
148 | skipped++;
149 | if (!(logFile.read(buf, skipped + 4, 1) == 1) || skipped + 10 > buf.length) {
150 | VpnStatus.logDebug(String.format(Locale.US, "Skipped %d bytes and no a magic byte found", skipped));
151 | break readloop;
152 | }
153 | }
154 | if (skipped > 0)
155 | VpnStatus.logDebug(String.format(Locale.US, "Skipped %d bytes before finding a magic byte", skipped));
156 | int len = ByteBuffer.wrap(buf, skipped + 1, 4).asIntBuffer().get();
157 | // Marshalled LogItem
158 | int pos = 0;
159 | byte buf2[] = new byte[buf.length];
160 | while (pos < len) {
161 | byte b = (byte) logFile.read();
162 | if (b == MAGIC_BYTE) {
163 | VpnStatus.logDebug(String.format(Locale.US, "Unexpected magic byte found at pos %d, abort current log item", pos));
164 | read = logFile.read(buf, 1, 4) + 1;
165 | continue readloop;
166 | } else if (b == MAGIC_BYTE + 1) {
167 | b = (byte) logFile.read();
168 | if (b == 0)
169 | b = MAGIC_BYTE;
170 | else if (b == 1)
171 | b = MAGIC_BYTE + 1;
172 | else {
173 | VpnStatus.logDebug(String.format(Locale.US, "Escaped byte not 0 or 1: %d", b));
174 | read = logFile.read(buf, 1, 4) + 1;
175 | continue readloop;
176 | }
177 | }
178 | buf2[pos++] = b;
179 | }
180 | restoreLogItem(buf2, len);
181 | //Next item
182 | read = logFile.read(buf, 0, 5);
183 | itemsRead++;
184 | if (itemsRead > 2 * VpnStatus.MAXLOGENTRIES) {
185 | VpnStatus.logError("Too many logentries read from cache, aborting.");
186 | read = 0;
187 | }
188 | }
189 | VpnStatus.logDebug(R.string.reread_log, itemsRead);
190 | }
191 | protected void restoreLogItem(byte[] buf, int len) throws UnsupportedEncodingException {
192 | LogItem li = new LogItem(buf, len);
193 | if (li.verify()) {
194 | VpnStatus.newLogItem(li, true);
195 | } else {
196 | VpnStatus.logError(String.format(Locale.getDefault(),
197 | "Could not read log item from file: %d: %s",
198 | len, bytesToHex(buf, Math.max(len, 80))));
199 | }
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/X509Utils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 |
7 | import android.annotation.SuppressLint;
8 | import android.content.Context;
9 | import android.content.res.Resources;
10 | import android.text.TextUtils;
11 |
12 | import xyz.oboloi.openvpn.R;
13 |
14 | import org.spongycastle.util.io.pem.PemObject;
15 | import org.spongycastle.util.io.pem.PemReader;
16 |
17 | import java.io.ByteArrayInputStream;
18 | import java.io.File;
19 | import java.io.FileInputStream;
20 | import java.io.FileNotFoundException;
21 | import java.io.FileReader;
22 | import java.io.IOException;
23 | import java.io.InputStream;
24 | import java.io.Reader;
25 | import java.io.StringReader;
26 | import java.lang.reflect.InvocationTargetException;
27 | import java.lang.reflect.Method;
28 | import java.security.cert.Certificate;
29 | import java.security.cert.CertificateException;
30 | import java.security.cert.CertificateExpiredException;
31 | import java.security.cert.CertificateFactory;
32 | import java.security.cert.CertificateNotYetValidException;
33 | import java.security.cert.X509Certificate;
34 | import java.util.Date;
35 | import java.util.Hashtable;
36 | import java.util.Vector;
37 |
38 | import javax.security.auth.x500.X500Principal;
39 |
40 | import de.blinkt.openvpn.VpnProfile;
41 |
42 | public class X509Utils {
43 | public static Certificate[] getCertificatesFromFile(String certfilename) throws FileNotFoundException, CertificateException {
44 | CertificateFactory certFact = CertificateFactory.getInstance("X.509");
45 | Vector certificates = new Vector<>();
46 | if (VpnProfile.isEmbedded(certfilename)) {
47 | int subIndex = certfilename.indexOf("-----BEGIN CERTIFICATE-----");
48 | do {
49 | // The java certifcate reader is ... kind of stupid
50 | // It does NOT ignore chars before the --BEGIN ...
51 | subIndex = Math.max(0, subIndex);
52 | InputStream inStream = new ByteArrayInputStream(certfilename.substring(subIndex).getBytes());
53 | certificates.add(certFact.generateCertificate(inStream));
54 | subIndex = certfilename.indexOf("-----BEGIN CERTIFICATE-----", subIndex + 1);
55 | } while (subIndex > 0);
56 | return certificates.toArray(new Certificate[certificates.size()]);
57 | } else {
58 | InputStream inStream = new FileInputStream(certfilename);
59 | return new Certificate[]{certFact.generateCertificate(inStream)};
60 | }
61 | }
62 | public static PemObject readPemObjectFromFile(String keyfilename) throws IOException {
63 | Reader inStream;
64 | if (VpnProfile.isEmbedded(keyfilename))
65 | inStream = new StringReader(VpnProfile.getEmbeddedContent(keyfilename));
66 | else
67 | inStream = new FileReader(new File(keyfilename));
68 | PemReader pr = new PemReader(inStream);
69 | PemObject r = pr.readPemObject();
70 | pr.close();
71 | return r;
72 | }
73 | public static String getCertificateFriendlyName(Context c, String filename) {
74 | if (!TextUtils.isEmpty(filename)) {
75 | try {
76 | X509Certificate cert = (X509Certificate) getCertificatesFromFile(filename)[0];
77 | String friendlycn = getCertificateFriendlyName(cert);
78 | friendlycn = getCertificateValidityString(cert, c.getResources()) + friendlycn;
79 | return friendlycn;
80 | } catch (Exception e) {
81 | VpnStatus.logError("Could not read certificate" + e.getLocalizedMessage());
82 | }
83 | }
84 | return c.getString(R.string.cannotparsecert);
85 | }
86 | public static String getCertificateValidityString(X509Certificate cert, Resources res) {
87 | try {
88 | cert.checkValidity();
89 | } catch (CertificateExpiredException ce) {
90 | return "EXPIRED: ";
91 | } catch (CertificateNotYetValidException cny) {
92 | return "NOT YET VALID: ";
93 | }
94 | Date certNotAfter = cert.getNotAfter();
95 | Date now = new Date();
96 | long timeLeft = certNotAfter.getTime() - now.getTime(); // Time left in ms
97 | // More than 72h left, display days
98 | // More than 3 months display months
99 | if (timeLeft > 90l * 24 * 3600 * 1000) {
100 | long months = getMonthsDifference(now, certNotAfter);
101 | return res.getQuantityString(R.plurals.months_left, (int) months, months);
102 | } else if (timeLeft > 72 * 3600 * 1000) {
103 | long days = timeLeft / (24 * 3600 * 1000);
104 | return res.getQuantityString(R.plurals.days_left, (int) days, days);
105 | } else {
106 | long hours = timeLeft / (3600 * 1000);
107 | return res.getQuantityString(R.plurals.hours_left, (int) hours, hours);
108 | }
109 | }
110 | public static int getMonthsDifference(Date date1, Date date2) {
111 | int m1 = date1.getYear() * 12 + date1.getMonth();
112 | int m2 = date2.getYear() * 12 + date2.getMonth();
113 | return m2 - m1 + 1;
114 | }
115 | public static String getCertificateFriendlyName(X509Certificate cert) {
116 | X500Principal principal = cert.getSubjectX500Principal();
117 | byte[] encodedSubject = principal.getEncoded();
118 | String friendlyName = null;
119 | /* Hack so we do not have to ship a whole Spongy/bouncycastle */
120 | Exception exp = null;
121 | try {
122 | @SuppressLint("PrivateApi") Class X509NameClass = Class.forName("com.android.org.bouncycastle.asn1.x509.X509Name");
123 | Method getInstance = X509NameClass.getMethod("getInstance", Object.class);
124 | Hashtable defaultSymbols = (Hashtable) X509NameClass.getField("DefaultSymbols").get(X509NameClass);
125 | if (!defaultSymbols.containsKey("1.2.840.113549.1.9.1"))
126 | defaultSymbols.put("1.2.840.113549.1.9.1", "eMail");
127 | Object subjectName = getInstance.invoke(X509NameClass, encodedSubject);
128 | Method toString = X509NameClass.getMethod("toString", boolean.class, Hashtable.class);
129 | friendlyName = (String) toString.invoke(subjectName, true, defaultSymbols);
130 | } catch (ClassNotFoundException e) {
131 | exp = e;
132 | } catch (NoSuchMethodException e) {
133 | exp = e;
134 | } catch (InvocationTargetException e) {
135 | exp = e;
136 | } catch (IllegalAccessException e) {
137 | exp = e;
138 | } catch (NoSuchFieldException e) {
139 | exp = e;
140 | }
141 | if (exp != null)
142 | VpnStatus.logException("Getting X509 Name from certificate", exp);
143 | /* Fallback if the reflection method did not work */
144 | if (friendlyName == null)
145 | friendlyName = principal.getName();
146 | // Really evil hack to decode email address
147 | // See: http://code.google.com/p/android/issues/detail?id=21531
148 | String[] parts = friendlyName.split(",");
149 | for (int i = 0; i < parts.length; i++) {
150 | String part = parts[i];
151 | if (part.startsWith("1.2.840.113549.1.9.1=#16")) {
152 | parts[i] = "email=" + ia5decode(part.replace("1.2.840.113549.1.9.1=#16", ""));
153 | }
154 | }
155 | friendlyName = TextUtils.join(",", parts);
156 | return friendlyName;
157 | }
158 | public static boolean isPrintableChar(char c) {
159 | Character.UnicodeBlock block = Character.UnicodeBlock.of(c);
160 | return (!Character.isISOControl(c)) &&
161 | block != null &&
162 | block != Character.UnicodeBlock.SPECIALS;
163 | }
164 | private static String ia5decode(String ia5string) {
165 | String d = "";
166 | for (int i = 1; i < ia5string.length(); i = i + 2) {
167 | String hexstr = ia5string.substring(i - 1, i + 1);
168 | char c = (char) Integer.parseInt(hexstr, 16);
169 | if (isPrintableChar(c)) {
170 | d += c;
171 | } else if (i == 1 && (c == 0x12 || c == 0x1b)) {
172 | // ignore
173 | } else {
174 | d += "\\x" + hexstr;
175 | }
176 | }
177 | return d;
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/OpenVPNStatusService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 |
7 | import android.app.Service;
8 | import android.content.Intent;
9 | import android.os.Build;
10 | import android.os.Handler;
11 | import android.os.IBinder;
12 | import android.os.Message;
13 | import android.os.ParcelFileDescriptor;
14 | import android.os.RemoteCallbackList;
15 | import android.os.RemoteException;
16 | import android.util.Pair;
17 |
18 | import androidx.annotation.Nullable;
19 |
20 | import java.io.DataOutputStream;
21 | import java.io.IOException;
22 | import java.lang.ref.WeakReference;
23 |
24 | /**
25 | * Created by arne on 08.11.16.
26 | */
27 | public class OpenVPNStatusService extends Service implements VpnStatus.LogListener, VpnStatus.ByteCountListener, VpnStatus.StateListener {
28 | static final RemoteCallbackList mCallbacks =
29 | new RemoteCallbackList<>();
30 | private static final OpenVPNStatusHandler mHandler = new OpenVPNStatusHandler();
31 | private static final int SEND_NEW_LOGITEM = 100;
32 | private static final int SEND_NEW_STATE = 101;
33 | private static final int SEND_NEW_BYTECOUNT = 102;
34 | private static final int SEND_NEW_CONNECTED_VPN = 103;
35 | static UpdateMessage mLastUpdateMessage;
36 | private static final IServiceStatus.Stub mBinder = new IServiceStatus.Stub() {
37 | @Override
38 | public ParcelFileDescriptor registerStatusCallback(IStatusCallbacks cb) throws RemoteException {
39 | final LogItem[] logbuffer = VpnStatus.getlogbuffer();
40 | if (mLastUpdateMessage != null)
41 | sendUpdate(cb, mLastUpdateMessage);
42 | mCallbacks.register(cb);
43 | try {
44 | final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
45 | new Thread("pushLogs") {
46 | @Override
47 | public void run() {
48 | DataOutputStream fd = new DataOutputStream(new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1]));
49 | try {
50 | synchronized (VpnStatus.readFileLock) {
51 | if (!VpnStatus.readFileLog) {
52 | VpnStatus.readFileLock.wait();
53 | }
54 | }
55 | } catch (InterruptedException e) {
56 | VpnStatus.logException(e);
57 | }
58 | try {
59 | for (LogItem logItem : logbuffer) {
60 | byte[] bytes = logItem.getMarschaledBytes();
61 | fd.writeShort(bytes.length);
62 | fd.write(bytes);
63 | }
64 | // Mark end
65 | fd.writeShort(0x7fff);
66 | fd.close();
67 | } catch (IOException e) {
68 | e.printStackTrace();
69 | }
70 | }
71 | }.start();
72 | return pipe[0];
73 | } catch (IOException e) {
74 | e.printStackTrace();
75 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
76 | throw new RemoteException(e.getMessage());
77 | }
78 | return null;
79 | }
80 | }
81 | @Override
82 | public void unregisterStatusCallback(IStatusCallbacks cb) throws RemoteException {
83 | mCallbacks.unregister(cb);
84 | }
85 | @Override
86 | public String getLastConnectedVPN() throws RemoteException {
87 | return VpnStatus.getLastConnectedVPNProfile();
88 | }
89 | @Override
90 | public void setCachedPassword(String uuid, int type, String password) {
91 | PasswordCache.setCachedPassword(uuid, type, password);
92 | }
93 | @Override
94 | public TrafficHistory getTrafficHistory() throws RemoteException {
95 | return VpnStatus.trafficHistory;
96 | }
97 | };
98 | private static void sendUpdate(IStatusCallbacks broadcastItem,
99 | UpdateMessage um) throws RemoteException {
100 | broadcastItem.updateStateString(um.state, um.logmessage, um.resId, um.level);
101 | }
102 | @Nullable
103 | @Override
104 | public IBinder onBind(Intent intent) {
105 | return mBinder;
106 | }
107 | @Override
108 | public void onCreate() {
109 | super.onCreate();
110 | VpnStatus.addLogListener(this);
111 | VpnStatus.addByteCountListener(this);
112 | VpnStatus.addStateListener(this);
113 | mHandler.setService(this);
114 | }
115 | @Override
116 | public void onDestroy() {
117 | super.onDestroy();
118 | VpnStatus.removeLogListener(this);
119 | VpnStatus.removeByteCountListener(this);
120 | VpnStatus.removeStateListener(this);
121 | mCallbacks.kill();
122 | }
123 | @Override
124 | public void newLog(LogItem logItem) {
125 | Message msg = mHandler.obtainMessage(SEND_NEW_LOGITEM, logItem);
126 | msg.sendToTarget();
127 | }
128 | @Override
129 | public void updateByteCount(long in, long out, long diffIn, long diffOut) {
130 | Message msg = mHandler.obtainMessage(SEND_NEW_BYTECOUNT, Pair.create(in, out));
131 | msg.sendToTarget();
132 | }
133 | @Override
134 | public void updateState(String state, String logmessage, int localizedResId, ConnectionStatus level) {
135 | mLastUpdateMessage = new UpdateMessage(state, logmessage, localizedResId, level);
136 | Message msg = mHandler.obtainMessage(SEND_NEW_STATE, mLastUpdateMessage);
137 | msg.sendToTarget();
138 | }
139 | @Override
140 | public void setConnectedVPN(String uuid) {
141 | Message msg = mHandler.obtainMessage(SEND_NEW_CONNECTED_VPN, uuid);
142 | msg.sendToTarget();
143 | }
144 | static class UpdateMessage {
145 | public String state;
146 | public String logmessage;
147 | public ConnectionStatus level;
148 | int resId;
149 | UpdateMessage(String state, String logmessage, int resId, ConnectionStatus level) {
150 | this.state = state;
151 | this.resId = resId;
152 | this.logmessage = logmessage;
153 | this.level = level;
154 | }
155 | }
156 | private static class OpenVPNStatusHandler extends Handler {
157 | WeakReference service = null;
158 | private void setService(OpenVPNStatusService statusService) {
159 | service = new WeakReference<>(statusService);
160 | }
161 | @Override
162 | public void handleMessage(Message msg) {
163 | RemoteCallbackList callbacks;
164 | if (service == null || service.get() == null)
165 | return;
166 | callbacks = service.get().mCallbacks;
167 | // Broadcast to all clients the new value.
168 | final int N = callbacks.beginBroadcast();
169 | for (int i = 0; i < N; i++) {
170 | try {
171 | IStatusCallbacks broadcastItem = callbacks.getBroadcastItem(i);
172 | switch (msg.what) {
173 | case SEND_NEW_LOGITEM:
174 | broadcastItem.newLogItem((LogItem) msg.obj);
175 | break;
176 | case SEND_NEW_BYTECOUNT:
177 | Pair inout = (Pair) msg.obj;
178 | broadcastItem.updateByteCount(inout.first, inout.second);
179 | break;
180 | case SEND_NEW_STATE:
181 | sendUpdate(broadcastItem, (UpdateMessage) msg.obj);
182 | break;
183 | case SEND_NEW_CONNECTED_VPN:
184 | broadcastItem.connectedVPN((String) msg.obj);
185 | break;
186 | }
187 | } catch (RemoteException e) {
188 | // The RemoteCallbackList will take care of removing
189 | // the dead object for us.
190 | }
191 | }
192 | callbacks.finishBroadcast();
193 | }
194 | }
195 | }
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 |
7 | import android.annotation.SuppressLint;
8 |
9 | import xyz.oboloi.openvpn.R;
10 |
11 | import java.io.BufferedReader;
12 | import java.io.BufferedWriter;
13 | import java.io.FileWriter;
14 | import java.io.IOException;
15 | import java.io.InputStream;
16 | import java.io.InputStreamReader;
17 | import java.text.SimpleDateFormat;
18 | import java.util.Collections;
19 | import java.util.Date;
20 | import java.util.LinkedList;
21 | import java.util.Locale;
22 | import java.util.regex.Matcher;
23 | import java.util.regex.Pattern;
24 |
25 | //import android.util.Log;
26 |
27 | public class OpenVPNThread implements Runnable {
28 | public static final int M_FATAL = (1 << 4);
29 | public static final int M_NONFATAL = (1 << 5);
30 | public static final int M_WARN = (1 << 6);
31 | public static final int M_DEBUG = (1 << 7);
32 | private static final String DUMP_PATH_STRING = "Dump path: ";
33 | @SuppressLint("SdCardPath")
34 | private static final String BROKEN_PIE_SUPPORT = "/data/data/com.wxy.vpn2018/cache/pievpn";
35 | private final static String BROKEN_PIE_SUPPORT2 = "syntax error";
36 | private static final String TAG = "OpenVPN";
37 | private String[] mArgv;
38 | private Process mProcess;
39 | private String mNativeDir;
40 | private OpenVPNService mService;
41 | private String mDumpPath;
42 | private boolean mBrokenPie = false;
43 | private boolean mNoProcessExitStatus = false;
44 |
45 | public OpenVPNThread(OpenVPNService service, String[] argv, String nativelibdir) {
46 | mArgv = argv;
47 | mNativeDir = nativelibdir;
48 | mService = service;
49 | }
50 |
51 | public void stopProcess() {
52 | mProcess.destroy();
53 | }
54 |
55 | void setReplaceConnection() {
56 | mNoProcessExitStatus = true;
57 | }
58 |
59 | @Override
60 | public void run() {
61 | try {
62 | // Log.e(TAG, "Starting openvpn");
63 | startOpenVPNThreadArgs(mArgv);
64 | // Log.e(TAG, "OpenVPN process exited");
65 | } catch (Exception e) {
66 | VpnStatus.logException("Starting OpenVPN Thread", e);
67 | // Log.e(TAG, "OpenVPNThread Got " + e.toString());
68 | } finally {
69 | int exitvalue = 0;
70 | try {
71 | if (mProcess != null) exitvalue = mProcess.waitFor();
72 | } catch (IllegalThreadStateException ite) {
73 | VpnStatus.logError("Illegal Thread state: " + ite.getLocalizedMessage());
74 | } catch (InterruptedException ie) {
75 | VpnStatus.logError("InterruptedException: " + ie.getLocalizedMessage());
76 | }
77 | if (exitvalue != 0) {
78 | VpnStatus.logError("Process exited with exit value " + exitvalue);
79 | if (mBrokenPie) {
80 | /* This will probably fail since the NoPIE binary is probably not written */
81 | String[] noPieArgv = VPNLaunchHelper.replacePieWithNoPie(mArgv);
82 | // We are already noPIE, nothing to gain
83 | if (!noPieArgv.equals(mArgv)) {
84 | mArgv = noPieArgv;
85 | VpnStatus.logInfo("PIE Version could not be executed. Trying no PIE version");
86 | run();
87 | }
88 | }
89 | }
90 | if (!mNoProcessExitStatus) {
91 | VpnStatus.updateStateString("NOPROCESS", "No process running.", R.string.state_noprocess, ConnectionStatus.LEVEL_NOTCONNECTED);
92 | }
93 | if (mDumpPath != null) {
94 | try {
95 | BufferedWriter logout = new BufferedWriter(new FileWriter(mDumpPath + ".log"));
96 | SimpleDateFormat timeformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.GERMAN);
97 | for (LogItem li : VpnStatus.getlogbuffer()) {
98 | String time = timeformat.format(new Date(li.getLogtime()));
99 | logout.write(time + " " + li.getString(mService) + "\n");
100 | }
101 | logout.close();
102 | VpnStatus.logError(R.string.minidump_generated);
103 | } catch (IOException e) {
104 | VpnStatus.logError("Writing minidump log: " + e.getLocalizedMessage());
105 | }
106 | }
107 | mService.processDied();
108 | // Log.e(TAG, "Exiting");
109 | }
110 | }
111 |
112 | private void startOpenVPNThreadArgs(String[] argv) {
113 | LinkedList argvlist = new LinkedList<>();
114 | Collections.addAll(argvlist, argv);
115 | ProcessBuilder pb = new ProcessBuilder(argvlist);
116 | // Hack O rama
117 | String lbpath = genLibraryPath(argv, pb);
118 | pb.environment().put("LD_LIBRARY_PATH", lbpath);
119 | pb.redirectErrorStream(true);
120 | try {
121 | mProcess = pb.start();
122 | // Close the output, since we don't need it
123 | mProcess.getOutputStream().close();
124 | InputStream in = mProcess.getInputStream();
125 | BufferedReader br = new BufferedReader(new InputStreamReader(in));
126 | while (true) {
127 | String logline = br.readLine();
128 | if (logline == null) {
129 | return;
130 | }
131 | if (logline.startsWith(DUMP_PATH_STRING)) {
132 | mDumpPath = logline.substring(DUMP_PATH_STRING.length());
133 | }
134 | if (logline.startsWith(BROKEN_PIE_SUPPORT) || logline.contains(BROKEN_PIE_SUPPORT2)) {
135 | mBrokenPie = true;
136 | }
137 | // 1380308330.240114 18000002 Send to HTTP proxy: 'X-Online-Host: bla.blabla.com'
138 | Pattern p = Pattern.compile("(\\d+).(\\d+) ([0-9a-f])+ (.*)");
139 | Matcher m = p.matcher(logline);
140 | int logerror = 0;
141 | if (m.matches()) {
142 | int flags = Integer.parseInt(m.group(3), 16);
143 | String msg = m.group(4);
144 | int logLevel = flags & 0x0F;
145 | VpnStatus.LogLevel logStatus = VpnStatus.LogLevel.INFO;
146 | if ((flags & M_FATAL) != 0) {
147 | logStatus = VpnStatus.LogLevel.ERROR;
148 | } else if ((flags & M_NONFATAL) != 0) {
149 | logStatus = VpnStatus.LogLevel.WARNING;
150 | } else if ((flags & M_WARN) != 0) {
151 | logStatus = VpnStatus.LogLevel.WARNING;
152 | } else if ((flags & M_DEBUG) != 0) {
153 | logStatus = VpnStatus.LogLevel.VERBOSE;
154 | }
155 | if (msg.startsWith("MANAGEMENT: CMD")) {
156 | logLevel = Math.max(4, logLevel);
157 | }
158 | if ((msg.endsWith("md too weak") && msg.startsWith("OpenSSL: error")) || msg.contains("error:140AB18E")) {
159 | logerror = 1;
160 | }
161 | VpnStatus.logMessageOpenVPN(logStatus, logLevel, msg);
162 | if (logerror == 1) {
163 | VpnStatus.logError("OpenSSL reproted a certificate with a weak hash, please the in app FAQ about weak hashes");
164 | }
165 | } else {
166 | VpnStatus.logInfo("P:" + logline);
167 | }
168 | if (Thread.interrupted()) {
169 | throw new InterruptedException("OpenVpn process was killed form java code");
170 | }
171 | }
172 | } catch (InterruptedException | IOException e) {
173 | VpnStatus.logException("Error reading from output of OpenVPN process", e);
174 | stopProcess();
175 | }
176 | }
177 |
178 | private String genLibraryPath(String[] argv, ProcessBuilder pb) {
179 | // Hack until I find a good way to get the real library path
180 | String applibpath = argv[0].replaceFirst("/cache/.*$", "/lib");
181 | String lbpath = pb.environment().get("LD_LIBRARY_PATH");
182 | if (lbpath == null) lbpath = applibpath;
183 | else lbpath = applibpath + ":" + lbpath;
184 | if (!applibpath.equals(mNativeDir)) {
185 | lbpath = mNativeDir + ":" + lbpath;
186 | }
187 | return lbpath;
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/ProfileManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 |
7 | import android.app.Activity;
8 | import android.content.Context;
9 | import android.content.SharedPreferences;
10 | import android.content.SharedPreferences.Editor;
11 |
12 | import java.io.IOException;
13 | import java.io.ObjectInputStream;
14 | import java.io.ObjectOutputStream;
15 | import java.util.Collection;
16 | import java.util.HashMap;
17 | import java.util.HashSet;
18 | import java.util.Locale;
19 | import java.util.Set;
20 |
21 | import de.blinkt.openvpn.VpnProfile;
22 |
23 | public class ProfileManager {
24 | private static final String PREFS_NAME = "VPNList";
25 | private static final String LAST_CONNECTED_PROFILE = "lastConnectedProfile";
26 | private static final String TEMPORARY_PROFILE_FILENAME = "temporary-vpn-profile";
27 | private static ProfileManager instance;
28 | private static VpnProfile mLastConnectedVpn = null;
29 | private static VpnProfile tmpprofile = null;
30 | private HashMap profiles = new HashMap<>();
31 |
32 | private ProfileManager() {
33 | }
34 |
35 | private static VpnProfile get(String key) {
36 | if (tmpprofile != null && tmpprofile.getUUIDString().equals(key)) return tmpprofile;
37 | if (instance == null) return null;
38 | return instance.profiles.get(key);
39 | }
40 |
41 | private static void checkInstance(Context context) {
42 | if (instance == null) {
43 | instance = new ProfileManager();
44 | instance.loadVPNList(context);
45 | }
46 | }
47 |
48 | synchronized public static ProfileManager getInstance(Context context) {
49 | checkInstance(context);
50 | return instance;
51 | }
52 |
53 | public static void setConnectedVpnProfileDisconnected(Context c) {
54 | SharedPreferences prefs = Preferences.getDefaultSharedPreferences(c);
55 | Editor prefsedit = prefs.edit();
56 | prefsedit.putString(LAST_CONNECTED_PROFILE, null);
57 | prefsedit.apply();
58 | }
59 |
60 | /**
61 | * Sets the profile that is connected (to connect if the service restarts)
62 | */
63 | public static void setConnectedVpnProfile(Context c, VpnProfile connectedProfile) {
64 | SharedPreferences prefs = Preferences.getDefaultSharedPreferences(c);
65 | Editor prefsedit = prefs.edit();
66 | prefsedit.putString(LAST_CONNECTED_PROFILE, connectedProfile.getUUIDString());
67 | prefsedit.apply();
68 | mLastConnectedVpn = connectedProfile;
69 | }
70 |
71 | /**
72 | * Returns the profile that was last connected (to connect if the service restarts)
73 | */
74 | public static VpnProfile getLastConnectedProfile(Context c) {
75 | SharedPreferences prefs = Preferences.getDefaultSharedPreferences(c);
76 | String lastConnectedProfile = prefs.getString(LAST_CONNECTED_PROFILE, null);
77 | if (lastConnectedProfile != null) return get(c, lastConnectedProfile);
78 | else return null;
79 | }
80 |
81 | public static void setTemporaryProfile(Context c, VpnProfile tmp) {
82 | ProfileManager.tmpprofile = tmp;
83 | saveProfile(c, tmp, true, true);
84 | }
85 |
86 | public static boolean isTempProfile() {
87 | return mLastConnectedVpn != null && mLastConnectedVpn == tmpprofile;
88 | }
89 |
90 | private static void saveProfile(Context context, VpnProfile profile, boolean updateVersion, boolean isTemporary) {
91 | if (updateVersion) profile.mVersion += 1;
92 | ObjectOutputStream vpnFile;
93 | String filename = profile.getUUID().toString() + ".vp";
94 | if (isTemporary) filename = TEMPORARY_PROFILE_FILENAME + ".vp";
95 | try {
96 | vpnFile = new ObjectOutputStream(context.openFileOutput(filename, Activity.MODE_PRIVATE));
97 | vpnFile.writeObject(profile);
98 | vpnFile.flush();
99 | vpnFile.close();
100 | } catch (IOException e) {
101 | VpnStatus.logException("saving VPN profile", e);
102 | throw new RuntimeException(e);
103 | }
104 | }
105 |
106 | public static VpnProfile get(Context context, String profileUUID) {
107 | return get(context, profileUUID, 0, 10);
108 | }
109 |
110 | public static VpnProfile get(Context context, String profileUUID, int version, int tries) {
111 | checkInstance(context);
112 | VpnProfile profile = get(profileUUID);
113 | int tried = 0;
114 | while ((profile == null || profile.mVersion < version) && (tried++ < tries)) {
115 | try {
116 | Thread.sleep(100);
117 | } catch (InterruptedException ignored) {
118 | }
119 | instance.loadVPNList(context);
120 | profile = get(profileUUID);
121 | int ver = profile == null ? -1 : profile.mVersion;
122 | }
123 | if (tried > 5) {
124 | int ver = profile == null ? -1 : profile.mVersion;
125 | VpnStatus.logError(String.format(Locale.US, "Used x %d tries to get current version (%d/%d) of the profile", tried, ver, version));
126 | }
127 | return profile;
128 | }
129 |
130 | public static VpnProfile getLastConnectedVpn() {
131 | return mLastConnectedVpn;
132 | }
133 |
134 | public static VpnProfile getAlwaysOnVPN(Context context) {
135 | checkInstance(context);
136 | SharedPreferences prefs = Preferences.getDefaultSharedPreferences(context);
137 | String uuid = prefs.getString("alwaysOnVpn", null);
138 | return get(uuid);
139 | }
140 |
141 | public static void updateLRU(Context c, VpnProfile profile) {
142 | profile.mLastUsed = System.currentTimeMillis();
143 | // LRU does not change the profile, no need for the service to refresh
144 | if (profile != tmpprofile) saveProfile(c, profile, false, false);
145 | }
146 |
147 | public Collection getProfiles() {
148 | return profiles.values();
149 | }
150 |
151 | public VpnProfile getProfileByName(String name) {
152 | for (VpnProfile vpnp : profiles.values()) {
153 | if (vpnp.getName().equals(name)) {
154 | return vpnp;
155 | }
156 | }
157 | return null;
158 | }
159 |
160 | public void saveProfileList(Context context) {
161 | SharedPreferences sharedprefs = Preferences.getSharedPreferencesMulti(PREFS_NAME, context);
162 | Editor editor = sharedprefs.edit();
163 | editor.putStringSet("vpnlist", profiles.keySet());
164 | // For reasing I do not understand at all
165 | // Android saves my prefs file only one time
166 | // if I remove the debug code below :(
167 | int counter = sharedprefs.getInt("counter", 0);
168 | editor.putInt("counter", counter + 1);
169 | editor.apply();
170 | }
171 |
172 | public void addProfile(VpnProfile profile) {
173 | profiles.put(profile.getUUID().toString(), profile);
174 | }
175 |
176 | public void saveProfile(Context context, VpnProfile profile) {
177 | saveProfile(context, profile, true, false);
178 | }
179 |
180 | private void loadVPNList(Context context) {
181 | profiles = new HashMap<>();
182 | SharedPreferences listpref = Preferences.getSharedPreferencesMulti(PREFS_NAME, context);
183 | Set vlist = listpref.getStringSet("vpnlist", null);
184 | if (vlist == null) {
185 | vlist = new HashSet<>();
186 | }
187 | // Always try to load the temporary profile
188 | vlist.add(TEMPORARY_PROFILE_FILENAME);
189 | for (String vpnentry : vlist) {
190 | try {
191 | ObjectInputStream vpnfile = new ObjectInputStream(context.openFileInput(vpnentry + ".vp"));
192 | VpnProfile vp = ((VpnProfile) vpnfile.readObject());
193 | // Sanity check
194 | if (vp == null || vp.mName == null || vp.getUUID() == null) continue;
195 | vp.upgradeProfile();
196 | if (vpnentry.equals(TEMPORARY_PROFILE_FILENAME)) {
197 | tmpprofile = vp;
198 | } else {
199 | profiles.put(vp.getUUID().toString(), vp);
200 | }
201 | } catch (IOException | ClassNotFoundException e) {
202 | if (!vpnentry.equals(TEMPORARY_PROFILE_FILENAME)) VpnStatus.logException("Loading VPN List", e);
203 | }
204 | }
205 | }
206 |
207 | public void removeProfile(Context context, VpnProfile profile) {
208 | String vpnentry = profile.getUUID().toString();
209 | profiles.remove(vpnentry);
210 | saveProfileList(context);
211 | context.deleteFile(vpnentry + ".vp");
212 | if (mLastConnectedVpn == profile) mLastConnectedVpn = null;
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/openvpn/src/main/java/de/blinkt/openvpn/core/DeviceStateReceiver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2016 Arne Schwabe
3 | * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
4 | */
5 | package de.blinkt.openvpn.core;
6 |
7 | import android.content.BroadcastReceiver;
8 | import android.content.Context;
9 | import android.content.Intent;
10 | import android.content.SharedPreferences;
11 | import android.net.ConnectivityManager;
12 | import android.net.NetworkInfo;
13 | import android.net.NetworkInfo.State;
14 | import android.os.Handler;
15 |
16 |
17 | import java.util.LinkedList;
18 |
19 | import de.blinkt.openvpn.core.VpnStatus.ByteCountListener;
20 | import xyz.oboloi.openvpn.R;
21 |
22 | import static de.blinkt.openvpn.core.OpenVPNManagement.pauseReason;
23 |
24 | public class DeviceStateReceiver extends BroadcastReceiver implements ByteCountListener, OpenVPNManagement.PausedStateCallback {
25 | private final Handler mDisconnectHandler;
26 | // Window time in s
27 | private final int TRAFFIC_WINDOW = 60;
28 | // Data traffic limit in bytes
29 | private final long TRAFFIC_LIMIT = 64 * 1024;
30 | // Time to wait after network disconnect to pause the VPN
31 | private final int DISCONNECT_WAIT = 20;
32 | connectState network = connectState.DISCONNECTED;
33 | connectState screen = connectState.SHOULDBECONNECTED;
34 | connectState userpause = connectState.SHOULDBECONNECTED;
35 | private int lastNetwork = -1;
36 | private OpenVPNManagement mManagement;
37 | private String lastStateMsg = null;
38 | private Runnable mDelayDisconnectRunnable = new Runnable() {
39 | @Override
40 | public void run() {
41 | if (!(network == connectState.PENDINGDISCONNECT)) return;
42 | network = connectState.DISCONNECTED;
43 | // Set screen state to be disconnected if disconnect pending
44 | if (screen == connectState.PENDINGDISCONNECT) screen = connectState.DISCONNECTED;
45 | mManagement.pause(getPauseReason());
46 | }
47 | };
48 | private NetworkInfo lastConnectedNetwork;
49 | private LinkedList trafficdata = new LinkedList<>();
50 |
51 | public DeviceStateReceiver(OpenVPNManagement magnagement) {
52 | super();
53 | mManagement = magnagement;
54 | mManagement.setPauseCallback(this);
55 | mDisconnectHandler = new Handler();
56 | }
57 |
58 | public static boolean equalsObj(Object a, Object b) {
59 | return (a == null) ? (b == null) : a.equals(b);
60 | }
61 |
62 | @Override
63 | public boolean shouldBeRunning() {
64 | return shouldBeConnected();
65 | }
66 |
67 | @Override
68 | public void updateByteCount(long in, long out, long diffIn, long diffOut) {
69 | if (screen != connectState.PENDINGDISCONNECT) return;
70 | long total = diffIn + diffOut;
71 | trafficdata.add(new Datapoint(System.currentTimeMillis(), total));
72 | while (trafficdata.getFirst().timestamp <= (System.currentTimeMillis() - TRAFFIC_WINDOW * 1000)) {
73 | trafficdata.removeFirst();
74 | }
75 | long windowtraffic = 0;
76 | for (Datapoint dp : trafficdata)
77 | windowtraffic += dp.data;
78 | if (windowtraffic < TRAFFIC_LIMIT) {
79 | screen = connectState.DISCONNECTED;
80 | VpnStatus.logInfo(R.string.screenoff_pause, "64 kB", TRAFFIC_WINDOW);
81 | mManagement.pause(getPauseReason());
82 | }
83 | }
84 |
85 | public void userPause(boolean pause) {
86 | if (pause) {
87 | userpause = connectState.DISCONNECTED;
88 | // Check if we should disconnect
89 | mManagement.pause(getPauseReason());
90 | } else {
91 | boolean wereConnected = shouldBeConnected();
92 | userpause = connectState.SHOULDBECONNECTED;
93 | if (shouldBeConnected() && !wereConnected) mManagement.resume();
94 | else
95 | // Update the reason why we currently paused
96 | mManagement.pause(getPauseReason());
97 | }
98 | }
99 |
100 | @Override
101 | public void onReceive(Context context, Intent intent) {
102 | SharedPreferences prefs = Preferences.getDefaultSharedPreferences(context);
103 | if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
104 | networkStateChange(context);
105 | } else if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
106 | boolean screenOffPause = prefs.getBoolean("screenoff", false);
107 | if (screenOffPause) {
108 | if (ProfileManager.getLastConnectedVpn() != null && !ProfileManager.getLastConnectedVpn().mPersistTun) VpnStatus.logError(R.string.screen_nopersistenttun);
109 | screen = connectState.PENDINGDISCONNECT;
110 | fillTrafficData();
111 | if (network == connectState.DISCONNECTED || userpause == connectState.DISCONNECTED) screen = connectState.DISCONNECTED;
112 | }
113 | } else if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {
114 | // Network was disabled because screen off
115 | boolean connected = shouldBeConnected();
116 | screen = connectState.SHOULDBECONNECTED;
117 | /* We should connect now, cancel any outstanding disconnect timer */
118 | mDisconnectHandler.removeCallbacks(mDelayDisconnectRunnable);
119 | /* should be connected has changed because the screen is on now, connect the VPN */
120 | if (shouldBeConnected() != connected) mManagement.resume();
121 | else if (!shouldBeConnected())
122 | /*Update the reason why we are still paused */ mManagement.pause(getPauseReason());
123 | }
124 | }
125 |
126 | private void fillTrafficData() {
127 | trafficdata.add(new Datapoint(System.currentTimeMillis(), TRAFFIC_LIMIT));
128 | }
129 |
130 | public void networkStateChange(Context context) {
131 | NetworkInfo networkInfo = getCurrentNetworkInfo(context);
132 | SharedPreferences prefs = Preferences.getDefaultSharedPreferences(context);
133 | boolean sendusr1 = prefs.getBoolean("netchangereconnect", true);
134 | String netstatestring;
135 | if (networkInfo == null) {
136 | netstatestring = "not connected";
137 | } else {
138 | String subtype = networkInfo.getSubtypeName();
139 | if (subtype == null) subtype = "";
140 | String extrainfo = networkInfo.getExtraInfo();
141 | if (extrainfo == null) extrainfo = "";
142 | /*
143 | if(networkInfo.getType()==android.net.ConnectivityManager.TYPE_WIFI) {
144 | WifiManager wifiMgr = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
145 | WifiInfo wifiinfo = wifiMgr.getConnectionInfo();
146 | extrainfo+=wifiinfo.getBSSID();
147 | subtype += wifiinfo.getNetworkId();
148 | }*/
149 | netstatestring = String.format("%2$s %4$s to %1$s %3$s", networkInfo.getTypeName(), networkInfo.getDetailedState(), extrainfo, subtype);
150 | }
151 | if (networkInfo != null && networkInfo.getState() == State.CONNECTED) {
152 | int newnet = networkInfo.getType();
153 | boolean pendingDisconnect = (network == connectState.PENDINGDISCONNECT);
154 | network = connectState.SHOULDBECONNECTED;
155 | boolean sameNetwork;
156 | sameNetwork = !(lastConnectedNetwork == null || lastConnectedNetwork.getType() != networkInfo.getType() || !equalsObj(lastConnectedNetwork.getExtraInfo(), networkInfo.getExtraInfo()));
157 | /* Same network, connection still 'established' */
158 | if (pendingDisconnect && sameNetwork) {
159 | mDisconnectHandler.removeCallbacks(mDelayDisconnectRunnable);
160 | // Reprotect the sockets just be sure
161 | mManagement.networkChange(true);
162 | } else {
163 | /* Different network or connection not established anymore */
164 | if (screen == connectState.PENDINGDISCONNECT) screen = connectState.DISCONNECTED;
165 | if (shouldBeConnected()) {
166 | mDisconnectHandler.removeCallbacks(mDelayDisconnectRunnable);
167 | if (pendingDisconnect || !sameNetwork) mManagement.networkChange(sameNetwork);
168 | else mManagement.resume();
169 | }
170 | lastNetwork = newnet;
171 | lastConnectedNetwork = networkInfo;
172 | }
173 | } else if (networkInfo == null) {
174 | // Not connected, stop openvpn, set last connected network to no network
175 | lastNetwork = -1;
176 | if (sendusr1) {
177 | network = connectState.PENDINGDISCONNECT;
178 | mDisconnectHandler.postDelayed(mDelayDisconnectRunnable, DISCONNECT_WAIT * 1000);
179 | }
180 | }
181 | if (!netstatestring.equals(lastStateMsg)) VpnStatus.logInfo(R.string.netstatus, netstatestring);
182 | VpnStatus.logDebug(String.format("Debug state info: %s, pause: %s, shouldbeconnected: %s, network: %s ", netstatestring, getPauseReason(), shouldBeConnected(), network));
183 | lastStateMsg = netstatestring;
184 | }
185 |
186 | public boolean isUserPaused() {
187 | return userpause == connectState.DISCONNECTED;
188 | }
189 |
190 | private boolean shouldBeConnected() {
191 | return (screen == connectState.SHOULDBECONNECTED && userpause == connectState.SHOULDBECONNECTED && network == connectState.SHOULDBECONNECTED);
192 | }
193 |
194 | private pauseReason getPauseReason() {
195 | if (userpause == connectState.DISCONNECTED) return pauseReason.userPause;
196 | if (screen == connectState.DISCONNECTED) return pauseReason.screenOff;
197 | if (network == connectState.DISCONNECTED) return pauseReason.noNetwork;
198 | return pauseReason.userPause;
199 | }
200 |
201 | private NetworkInfo getCurrentNetworkInfo(Context context) {
202 | ConnectivityManager conn = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
203 | return conn.getActiveNetworkInfo();
204 | }
205 |
206 | private enum connectState {
207 | SHOULDBECONNECTED, PENDINGDISCONNECT, DISCONNECTED
208 | }
209 |
210 | private static class Datapoint {
211 | long timestamp;
212 | long data;
213 |
214 | private Datapoint(long t, long d) {
215 | timestamp = t;
216 | data = d;
217 | }
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/openvpn/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | OpenVPN
3 | Connect
4 | Disconnect
5 | Error
6 | Connecting…
7 | Initing…
8 | About
9 | init failed:
10 | load data failed:
11 | Not show more
12 |
13 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | Username
29 | You must select a User certificate
30 | You must select a CA certificate
31 | No error found
32 | Error in Configuration
33 | Error parsing the IPv4 address
34 | Error parsing the custom routes
35 | Connecting to VPN…
36 | Profile specified in shortcut not found
37 | Route rejected by Android
38 | On some custom ICS images the permission on /dev/tun might be wrong, or the tun module might be missing completely. For CM9 images try the fix ownership option under general settings
39 | Failed to open the tun interface
40 | "Error: "
41 | Opening tun interface:
42 | Local IPv4: %1$s/%2$d IPv6: %3$s MTU: %4$d
43 | DNS Server: %1$s, Domain: %2$s
44 | Routes: %1$s %2$s
45 | Routes excluded: %1$s %2$s
46 | VpnService routes installed: %1$s %2$s
47 | Got interface information %1$s and %2$s, assuming second address is peer address of remote. Using /32 netmask for local IP. Mode given by OpenVPN is \"%3$s\".
48 | Cannot make sense of %1$s and %2$s as IP route with CIDR netmask, using /32 as netmask.
49 | Corrected route %1$s/%2$s to %3$s/%2$s
50 | Cannot access the Android Keychain Certificates. This can be caused by a firmware upgrade or by restoring a backup of the app/app settings. Please edit the VPN and reselect the certificate under basic settings to recreate the permission to access the certificate.
51 | Your image does not support the VPNService API, sorry :(
52 | Refusing to open tun device without IP information
53 | PKCS12 File Encryption Key
54 | Private Key Password
55 | Password
56 | Building configuration…
57 | Network Status: %s
58 | No CA Certificate returned while reading from Android keystore. Authentication will probably fail.
59 | %10$s %9$s running on %3$s %1$s (%2$s), Android %6$s (%7$s) API %4$d, ABI %5$s, (%8$s)
60 | Error signing with Android keystore key %1$s: %2$s
61 | No DNS servers being used. Name resolution may not work. Consider setting custom DNS Servers. Please also note that Android will keep using your proxy settings specified for your mobile/Wi-Fi connection when no DNS servers are set.
62 | Could not add DNS Server \"%1$s\", rejected by the system: %2$s
63 | Could not configure IP Address \"%1$s\", rejected by the system: %2$s
64 | Error getting proxy settings: %s
65 | Using proxy %1$s %2$d
66 | OpenVPN crashed unexpectedly. Please consider using the send Minidump option in the main menu
67 | %1$s - %2$s
68 | %1$s - %2$s
69 | %1$s - %3$s, %2$s
70 | Connecting
71 | Waiting for server reply
72 | Authenticating
73 | Getting client configuration
74 | Assigning IP addresses
75 | Adding routes
76 | Connected
77 | Disconnect
78 | Reconnecting
79 | Exiting
80 | Not running
81 | Resolving host names
82 | Connecting (TCP)
83 | Authentication failed
84 | Waiting for usable network
85 | ↓:%2$s(%1$s)-↑:%4$s(%3$s)
86 | Not connected
87 | Some versions of Android 4.1 have problems if the name of the keystore certificate contains non alphanumeric characters (like spaces, underscores or dashes). Try to reimport the certificate without special characters
88 | built by %s
89 | debug build
90 | official build
91 | %1$s attempts to control %2$s
92 | By proceeding, you are giving the application permission to completely control OpenVPN for Android and to intercept all network traffic.Do NOT accept unless you trust the application. Otherwise, you run the risk of having your data compromised by malicious software."
93 | I trust this application.
94 | Pausing connection in screen off state: less than %1$s in %2$ss
95 | Warning: Persistent tun not enabled for this VPN. Traffic will use the normal Internet connection when the screen is off.
96 | Save Password
97 | VPN pause requested by user
98 | VPN paused - screen off
99 | Cannot display certificate information
100 | Icon of app trying to use OpenVPN for Android
101 | Show password
102 | KeyChain Access error: %s
103 | Unhandled exception: %1$s\n\n%2$s
104 | %3$s: %1$s\n\n%2$s
105 | Vpn topology \"%3$s\" specified but ifconfig %1$s %2$s looks more like an IP address with a network mask. Assuming \"subnet\" topology.
106 | Allowed VPN apps: %1$s
107 | Disallowed VPN apps: %1$s
108 | Package %s is no longer installed, removing it from app allow/disallow list
109 | You need to define and enable at least one remote server.
110 | Ignoring multicast route: %s
111 | Restarting OpenVPN Service (App crashed probably crashed or killed for memory pressure)
112 | No allowed app added. Adding ourselves (%s) to have at least one app in the allowed app list to not allow all apps
113 | Preferred native ABI precedence of this device (%1$s) and ABI reported by native libraries (%2$s) mismatch
114 | VPN permission revoked by OS (e.g. other VPN program started), stopping VPN
115 | Need %1$s
116 | Please enter the password for profile %1$s
117 | tls-auth file is missing
118 | Missing user certificate or user certifcate key file
119 | Missing CA certificate
120 | Reread (%d) log items from log cache file
121 | Waiting %ss seconds between connection attempt
122 | Networks more .. -> VPNS]]>
123 | Config uses option tls-remote that was deprecated in 2.3 and finally removed in 2.4
124 | %.0f bit/s
125 | %.1f kbit/s
126 | %.1f Mbit/s
127 | %.1f Gbit/s
128 | %.0f B
129 | %.1f kB
130 | %.1f MB
131 | %.1f GB
132 | Connection statistics
133 | Ongoing statistics of the established OpenVPN connection
134 | Connection status change
135 | Status changes of the OpenVPN connection (Connecting, authenticating,…)
136 |
137 |
--------------------------------------------------------------------------------