├── AndroidManifest.xml
├── VpnServices
├── Android.mk
├── AndroidManifest.xml
├── MODULE_LICENSE_APACHE2
├── NOTICE
└── src
│ └── com
│ └── android
│ └── server
│ └── vpn
│ ├── DaemonProxy.java
│ ├── L2tpIpsecPskService.java
│ ├── L2tpIpsecService.java
│ ├── L2tpService.java
│ ├── PptpService.java
│ ├── VpnConnectingError.java
│ ├── VpnDaemons.java
│ ├── VpnService.java
│ └── VpnServiceBinder.java
├── bin
├── android-vpn-server.apk
├── android
│ ├── net
│ │ └── vpn
│ │ │ ├── IVpnService$Stub$Proxy.class
│ │ │ ├── IVpnService$Stub.class
│ │ │ ├── IVpnService.aidl
│ │ │ ├── IVpnService.class
│ │ │ ├── L2tpIpsecProfile.class
│ │ │ ├── L2tpIpsecPskProfile.class
│ │ │ ├── L2tpProfile.class
│ │ │ ├── PptpProfile.class
│ │ │ ├── VpnManager.class
│ │ │ ├── VpnProfile$1.class
│ │ │ ├── VpnProfile.aidl
│ │ │ ├── VpnProfile.class
│ │ │ ├── VpnState.class
│ │ │ ├── VpnTest$1.class
│ │ │ ├── VpnTest.class
│ │ │ └── VpnType.class
│ ├── os
│ │ └── SystemProperties.class
│ └── security
│ │ ├── Credentials.class
│ │ └── KeyStore.class
├── classes.dex
├── com
│ └── android
│ │ └── server
│ │ └── vpn
│ │ ├── DaemonProxy.class
│ │ ├── L2tpIpsecPskService.class
│ │ ├── L2tpIpsecService.class
│ │ ├── L2tpService.class
│ │ ├── PptpService.class
│ │ ├── R$attr.class
│ │ ├── R$drawable.class
│ │ ├── R$layout.class
│ │ ├── R$string.class
│ │ ├── R.class
│ │ ├── VpnConnectingError.class
│ │ ├── VpnDaemons.class
│ │ ├── VpnService$1.class
│ │ ├── VpnService$DaemonHelper.class
│ │ ├── VpnService$NotificationHelper.class
│ │ ├── VpnService.class
│ │ ├── VpnServiceBinder$1.class
│ │ ├── VpnServiceBinder$2.class
│ │ ├── VpnServiceBinder$3.class
│ │ └── VpnServiceBinder.class
├── org
│ └── zju
│ │ └── luojs
│ │ └── MyVpn.class
└── resources.ap_
├── default.properties
├── gen
├── android
│ └── net
│ │ └── vpn
│ │ └── IVpnService.java
└── com
│ └── android
│ └── server
│ └── vpn
│ └── R.java
├── proguard.cfg
├── res.tar
├── res
├── drawable
│ ├── vpn_connected.png
│ └── vpn_disconnected.png
├── layout
│ └── main.xml
├── values-ar
│ └── strings.xml
├── values-bg
│ └── strings.xml
├── values-ca
│ └── strings.xml
├── values-cs
│ └── strings.xml
├── values-da
│ └── strings.xml
├── values-de
│ └── strings.xml
├── values-el
│ └── strings.xml
├── values-en-rGB
│ └── strings.xml
├── values-es-rUS
│ └── strings.xml
├── values-es
│ └── strings.xml
├── values-fa
│ └── strings.xml
├── values-fi
│ └── strings.xml
├── values-fr
│ └── strings.xml
├── values-hr
│ └── strings.xml
├── values-hu
│ └── strings.xml
├── values-in
│ └── strings.xml
├── values-it
│ └── strings.xml
├── values-iw
│ └── strings.xml
├── values-ja
│ └── strings.xml
├── values-ko
│ └── strings.xml
├── values-lt
│ └── strings.xml
├── values-lv
│ └── strings.xml
├── values-nb
│ └── strings.xml
├── values-nl
│ └── strings.xml
├── values-pl
│ └── strings.xml
├── values-pt-rPT
│ └── strings.xml
├── values-pt
│ └── strings.xml
├── values-rm
│ └── strings.xml
├── values-ro
│ └── strings.xml
├── values-ru
│ └── strings.xml
├── values-sk
│ └── strings.xml
├── values-sl
│ └── strings.xml
├── values-sr
│ └── strings.xml
├── values-sv
│ └── strings.xml
├── values-th
│ └── strings.xml
├── values-tl
│ └── strings.xml
├── values-tr
│ └── strings.xml
├── values-uk
│ └── strings.xml
├── values-vi
│ └── strings.xml
├── values-zh-rCN
│ └── strings.xml
├── values-zh-rTW
│ └── strings.xml
└── values
│ └── strings.xml
└── src
├── android
├── net
│ └── vpn
│ │ ├── IVpnService.aidl
│ │ ├── L2tpIpsecProfile.java
│ │ ├── L2tpIpsecPskProfile.java
│ │ ├── L2tpProfile.java
│ │ ├── PptpProfile.java
│ │ ├── VpnManager.java
│ │ ├── VpnProfile.aidl
│ │ ├── VpnProfile.java
│ │ ├── VpnState.java
│ │ ├── VpnTest.java
│ │ └── VpnType.java
├── os
│ └── SystemProperties.java
└── security
│ ├── Credentials.java
│ └── KeyStore.java
├── com
└── android
│ └── server
│ └── vpn
│ ├── DaemonProxy.java
│ ├── L2tpIpsecPskService.java
│ ├── L2tpIpsecService.java
│ ├── L2tpService.java
│ ├── PptpService.java
│ ├── VpnConnectingError.java
│ ├── VpnDaemons.java
│ ├── VpnService.java
│ └── VpnServiceBinder.java
└── org
└── zju
└── luojs
└── MyVpn.java
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
12 |
13 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/VpnServices/Android.mk:
--------------------------------------------------------------------------------
1 | LOCAL_PATH:= $(call my-dir)
2 | include $(CLEAR_VARS)
3 |
4 | LOCAL_MODULE_TAGS := optional
5 |
6 | LOCAL_SRC_FILES := $(call all-subdir-java-files)
7 |
8 | LOCAL_JAVA_LIBRARIES :=
9 |
10 | LOCAL_PACKAGE_NAME := VpnServices
11 | LOCAL_CERTIFICATE := platform
12 |
13 | include $(BUILD_PACKAGE)
14 |
15 | ########################
16 | include $(call all-makefiles-under,$(LOCAL_PATH))
17 |
--------------------------------------------------------------------------------
/VpnServices/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
12 |
13 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/VpnServices/MODULE_LICENSE_APACHE2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/VpnServices/MODULE_LICENSE_APACHE2
--------------------------------------------------------------------------------
/VpnServices/NOTICE:
--------------------------------------------------------------------------------
1 |
2 | Copyright (c) 2005-2008, 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 |
7 | Unless required by applicable law or agreed to in writing, software
8 | distributed under the License is distributed on an "AS IS" BASIS,
9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | See the License for the specific language governing permissions and
11 | limitations under the License.
12 |
13 |
14 | Apache License
15 | Version 2.0, January 2004
16 | http://www.apache.org/licenses/
17 |
18 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
19 |
20 | 1. Definitions.
21 |
22 | "License" shall mean the terms and conditions for use, reproduction,
23 | and distribution as defined by Sections 1 through 9 of this document.
24 |
25 | "Licensor" shall mean the copyright owner or entity authorized by
26 | the copyright owner that is granting the License.
27 |
28 | "Legal Entity" shall mean the union of the acting entity and all
29 | other entities that control, are controlled by, or are under common
30 | control with that entity. For the purposes of this definition,
31 | "control" means (i) the power, direct or indirect, to cause the
32 | direction or management of such entity, whether by contract or
33 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
34 | outstanding shares, or (iii) beneficial ownership of such entity.
35 |
36 | "You" (or "Your") shall mean an individual or Legal Entity
37 | exercising permissions granted by this License.
38 |
39 | "Source" form shall mean the preferred form for making modifications,
40 | including but not limited to software source code, documentation
41 | source, and configuration files.
42 |
43 | "Object" form shall mean any form resulting from mechanical
44 | transformation or translation of a Source form, including but
45 | not limited to compiled object code, generated documentation,
46 | and conversions to other media types.
47 |
48 | "Work" shall mean the work of authorship, whether in Source or
49 | Object form, made available under the License, as indicated by a
50 | copyright notice that is included in or attached to the work
51 | (an example is provided in the Appendix below).
52 |
53 | "Derivative Works" shall mean any work, whether in Source or Object
54 | form, that is based on (or derived from) the Work and for which the
55 | editorial revisions, annotations, elaborations, or other modifications
56 | represent, as a whole, an original work of authorship. For the purposes
57 | of this License, Derivative Works shall not include works that remain
58 | separable from, or merely link (or bind by name) to the interfaces of,
59 | the Work and Derivative Works thereof.
60 |
61 | "Contribution" shall mean any work of authorship, including
62 | the original version of the Work and any modifications or additions
63 | to that Work or Derivative Works thereof, that is intentionally
64 | submitted to Licensor for inclusion in the Work by the copyright owner
65 | or by an individual or Legal Entity authorized to submit on behalf of
66 | the copyright owner. For the purposes of this definition, "submitted"
67 | means any form of electronic, verbal, or written communication sent
68 | to the Licensor or its representatives, including but not limited to
69 | communication on electronic mailing lists, source code control systems,
70 | and issue tracking systems that are managed by, or on behalf of, the
71 | Licensor for the purpose of discussing and improving the Work, but
72 | excluding communication that is conspicuously marked or otherwise
73 | designated in writing by the copyright owner as "Not a Contribution."
74 |
75 | "Contributor" shall mean Licensor and any individual or Legal Entity
76 | on behalf of whom a Contribution has been received by Licensor and
77 | subsequently incorporated within the Work.
78 |
79 | 2. Grant of Copyright License. Subject to the terms and conditions of
80 | this License, each Contributor hereby grants to You a perpetual,
81 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
82 | copyright license to reproduce, prepare Derivative Works of,
83 | publicly display, publicly perform, sublicense, and distribute the
84 | Work and such Derivative Works in Source or Object form.
85 |
86 | 3. Grant of Patent License. Subject to the terms and conditions of
87 | this License, each Contributor hereby grants to You a perpetual,
88 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
89 | (except as stated in this section) patent license to make, have made,
90 | use, offer to sell, sell, import, and otherwise transfer the Work,
91 | where such license applies only to those patent claims licensable
92 | by such Contributor that are necessarily infringed by their
93 | Contribution(s) alone or by combination of their Contribution(s)
94 | with the Work to which such Contribution(s) was submitted. If You
95 | institute patent litigation against any entity (including a
96 | cross-claim or counterclaim in a lawsuit) alleging that the Work
97 | or a Contribution incorporated within the Work constitutes direct
98 | or contributory patent infringement, then any patent licenses
99 | granted to You under this License for that Work shall terminate
100 | as of the date such litigation is filed.
101 |
102 | 4. Redistribution. You may reproduce and distribute copies of the
103 | Work or Derivative Works thereof in any medium, with or without
104 | modifications, and in Source or Object form, provided that You
105 | meet the following conditions:
106 |
107 | (a) You must give any other recipients of the Work or
108 | Derivative Works a copy of this License; and
109 |
110 | (b) You must cause any modified files to carry prominent notices
111 | stating that You changed the files; and
112 |
113 | (c) You must retain, in the Source form of any Derivative Works
114 | that You distribute, all copyright, patent, trademark, and
115 | attribution notices from the Source form of the Work,
116 | excluding those notices that do not pertain to any part of
117 | the Derivative Works; and
118 |
119 | (d) If the Work includes a "NOTICE" text file as part of its
120 | distribution, then any Derivative Works that You distribute must
121 | include a readable copy of the attribution notices contained
122 | within such NOTICE file, excluding those notices that do not
123 | pertain to any part of the Derivative Works, in at least one
124 | of the following places: within a NOTICE text file distributed
125 | as part of the Derivative Works; within the Source form or
126 | documentation, if provided along with the Derivative Works; or,
127 | within a display generated by the Derivative Works, if and
128 | wherever such third-party notices normally appear. The contents
129 | of the NOTICE file are for informational purposes only and
130 | do not modify the License. You may add Your own attribution
131 | notices within Derivative Works that You distribute, alongside
132 | or as an addendum to the NOTICE text from the Work, provided
133 | that such additional attribution notices cannot be construed
134 | as modifying the License.
135 |
136 | You may add Your own copyright statement to Your modifications and
137 | may provide additional or different license terms and conditions
138 | for use, reproduction, or distribution of Your modifications, or
139 | for any such Derivative Works as a whole, provided Your use,
140 | reproduction, and distribution of the Work otherwise complies with
141 | the conditions stated in this License.
142 |
143 | 5. Submission of Contributions. Unless You explicitly state otherwise,
144 | any Contribution intentionally submitted for inclusion in the Work
145 | by You to the Licensor shall be under the terms and conditions of
146 | this License, without any additional terms or conditions.
147 | Notwithstanding the above, nothing herein shall supersede or modify
148 | the terms of any separate license agreement you may have executed
149 | with Licensor regarding such Contributions.
150 |
151 | 6. Trademarks. This License does not grant permission to use the trade
152 | names, trademarks, service marks, or product names of the Licensor,
153 | except as required for reasonable and customary use in describing the
154 | origin of the Work and reproducing the content of the NOTICE file.
155 |
156 | 7. Disclaimer of Warranty. Unless required by applicable law or
157 | agreed to in writing, Licensor provides the Work (and each
158 | Contributor provides its Contributions) on an "AS IS" BASIS,
159 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
160 | implied, including, without limitation, any warranties or conditions
161 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
162 | PARTICULAR PURPOSE. You are solely responsible for determining the
163 | appropriateness of using or redistributing the Work and assume any
164 | risks associated with Your exercise of permissions under this License.
165 |
166 | 8. Limitation of Liability. In no event and under no legal theory,
167 | whether in tort (including negligence), contract, or otherwise,
168 | unless required by applicable law (such as deliberate and grossly
169 | negligent acts) or agreed to in writing, shall any Contributor be
170 | liable to You for damages, including any direct, indirect, special,
171 | incidental, or consequential damages of any character arising as a
172 | result of this License or out of the use or inability to use the
173 | Work (including but not limited to damages for loss of goodwill,
174 | work stoppage, computer failure or malfunction, or any and all
175 | other commercial damages or losses), even if such Contributor
176 | has been advised of the possibility of such damages.
177 |
178 | 9. Accepting Warranty or Additional Liability. While redistributing
179 | the Work or Derivative Works thereof, You may choose to offer,
180 | and charge a fee for, acceptance of support, warranty, indemnity,
181 | or other liability obligations and/or rights consistent with this
182 | License. However, in accepting such obligations, You may act only
183 | on Your own behalf and on Your sole responsibility, not on behalf
184 | of any other Contributor, and only if You agree to indemnify,
185 | defend, and hold each Contributor harmless for any liability
186 | incurred by, or claims asserted against, such Contributor by reason
187 | of your accepting any such warranty or additional liability.
188 |
189 | END OF TERMS AND CONDITIONS
190 |
191 |
--------------------------------------------------------------------------------
/VpnServices/src/com/android/server/vpn/DaemonProxy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package com.android.server.vpn;
18 |
19 | import android.net.LocalSocket;
20 | import android.net.LocalSocketAddress;
21 | import android.net.vpn.VpnManager;
22 | import android.os.SystemProperties;
23 | import android.util.Log;
24 |
25 | import java.io.IOException;
26 | import java.io.InputStream;
27 | import java.io.OutputStream;
28 | import java.io.Serializable;
29 |
30 | /**
31 | * Proxy to start, stop and interact with a VPN daemon.
32 | * The daemon is expected to accept connection through Unix domain socket.
33 | * When the proxy successfully starts the daemon, it will establish a socket
34 | * connection with the daemon, to both send commands to the daemon and receive
35 | * response and connecting error code from the daemon.
36 | */
37 | class DaemonProxy implements Serializable {
38 | private static final long serialVersionUID = 1L;
39 | private static final boolean DBG = true;
40 |
41 | private static final int WAITING_TIME = 15; // sec
42 |
43 | private static final String SVC_STATE_CMD_PREFIX = "init.svc.";
44 | private static final String SVC_START_CMD = "ctl.start";
45 | private static final String SVC_STOP_CMD = "ctl.stop";
46 | private static final String SVC_STATE_RUNNING = "running";
47 | private static final String SVC_STATE_STOPPED = "stopped";
48 |
49 | private static final int END_OF_ARGUMENTS = 255;
50 |
51 | private String mName;
52 | private String mTag;
53 | private transient LocalSocket mControlSocket;
54 |
55 | /**
56 | * Creates a proxy of the specified daemon.
57 | * @param daemonName name of the daemon
58 | */
59 | DaemonProxy(String daemonName) {
60 | mName = daemonName;
61 | mTag = "SProxy_" + daemonName;
62 | }
63 |
64 | String getName() {
65 | return mName;
66 | }
67 |
68 | void start() throws IOException {
69 | String svc = mName;
70 |
71 | Log.i(mTag, "Start VPN daemon: " + svc);
72 | SystemProperties.set(SVC_START_CMD, svc);
73 |
74 | if (!blockUntil(SVC_STATE_RUNNING, WAITING_TIME)) {
75 | throw new IOException("cannot start service: " + svc);
76 | } else {
77 | mControlSocket = createServiceSocket();
78 | }
79 | }
80 |
81 | void sendCommand(String ...args) throws IOException {
82 | OutputStream out = getControlSocketOutput();
83 | for (String arg : args) outputString(out, arg);
84 | out.write(END_OF_ARGUMENTS);
85 | out.flush();
86 |
87 | int result = getResultFromSocket(true);
88 | if (result != args.length) {
89 | throw new IOException("socket error, result from service: "
90 | + result);
91 | }
92 | }
93 |
94 | // returns 0 if nothing is in the receive buffer
95 | int getResultFromSocket() throws IOException {
96 | return getResultFromSocket(false);
97 | }
98 |
99 | void closeControlSocket() {
100 | if (mControlSocket == null) return;
101 | try {
102 | mControlSocket.close();
103 | } catch (IOException e) {
104 | Log.w(mTag, "close control socket", e);
105 | } finally {
106 | mControlSocket = null;
107 | }
108 | }
109 |
110 | void stop() {
111 | String svc = mName;
112 | Log.i(mTag, "Stop VPN daemon: " + svc);
113 | SystemProperties.set(SVC_STOP_CMD, svc);
114 | boolean success = blockUntil(SVC_STATE_STOPPED, 5);
115 | if (DBG) Log.d(mTag, "stopping " + svc + ", success? " + success);
116 | }
117 |
118 | boolean isStopped() {
119 | String cmd = SVC_STATE_CMD_PREFIX + mName;
120 | return SVC_STATE_STOPPED.equals(SystemProperties.get(cmd));
121 | }
122 |
123 | private int getResultFromSocket(boolean blocking) throws IOException {
124 | LocalSocket s = mControlSocket;
125 | if (s == null) return 0;
126 | InputStream in = s.getInputStream();
127 | if (!blocking && in.available() == 0) return 0;
128 |
129 | int data = in.read();
130 | Log.i(mTag, "got data from control socket: " + data);
131 |
132 | return data;
133 | }
134 |
135 | private LocalSocket createServiceSocket() throws IOException {
136 | LocalSocket s = new LocalSocket();
137 | LocalSocketAddress a = new LocalSocketAddress(mName,
138 | LocalSocketAddress.Namespace.RESERVED);
139 |
140 | // try a few times in case the service has not listen()ed
141 | IOException excp = null;
142 | for (int i = 0; i < 10; i++) {
143 | try {
144 | s.connect(a);
145 | return s;
146 | } catch (IOException e) {
147 | if (DBG) Log.d(mTag, "service not yet listen()ing; try again");
148 | excp = e;
149 | sleep(500);
150 | }
151 | }
152 | throw excp;
153 | }
154 |
155 | private OutputStream getControlSocketOutput() throws IOException {
156 | if (mControlSocket != null) {
157 | return mControlSocket.getOutputStream();
158 | } else {
159 | throw new IOException("no control socket available");
160 | }
161 | }
162 |
163 | /**
164 | * Waits for the process to be in the expected state. The method returns
165 | * false if after the specified duration (in seconds), the process is still
166 | * not in the expected state.
167 | */
168 | private boolean blockUntil(String expectedState, int waitTime) {
169 | String cmd = SVC_STATE_CMD_PREFIX + mName;
170 | int sleepTime = 200; // ms
171 | int n = waitTime * 1000 / sleepTime;
172 | for (int i = 0; i < n; i++) {
173 | if (expectedState.equals(SystemProperties.get(cmd))) {
174 | if (DBG) {
175 | Log.d(mTag, mName + " is " + expectedState + " after "
176 | + (i * sleepTime) + " msec");
177 | }
178 | break;
179 | }
180 | sleep(sleepTime);
181 | }
182 | return expectedState.equals(SystemProperties.get(cmd));
183 | }
184 |
185 | private void outputString(OutputStream out, String s) throws IOException {
186 | byte[] bytes = s.getBytes();
187 | out.write(bytes.length);
188 | out.write(bytes);
189 | out.flush();
190 | }
191 |
192 | private void sleep(int msec) {
193 | try {
194 | Thread.currentThread().sleep(msec);
195 | } catch (InterruptedException e) {
196 | throw new RuntimeException(e);
197 | }
198 | }
199 | }
200 |
--------------------------------------------------------------------------------
/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package com.android.server.vpn;
18 |
19 | import android.net.vpn.L2tpIpsecPskProfile;
20 |
21 | import java.io.IOException;
22 |
23 | /**
24 | * The service that manages the preshared key based L2TP-over-IPSec VPN
25 | * connection.
26 | */
27 | class L2tpIpsecPskService extends VpnService {
28 | private static final String IPSEC = "racoon";
29 |
30 | @Override
31 | protected void connect(String serverIp, String username, String password)
32 | throws IOException {
33 | L2tpIpsecPskProfile p = getProfile();
34 | VpnDaemons daemons = getDaemons();
35 |
36 | // IPSEC
37 | daemons.startIpsecForL2tp(serverIp, p.getPresharedKey())
38 | .closeControlSocket();
39 |
40 | sleep(2000); // 2 seconds
41 |
42 | // L2TP
43 | daemons.startL2tp(serverIp,
44 | (p.isSecretEnabled() ? p.getSecretString() : null),
45 | username, password);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package com.android.server.vpn;
18 |
19 | import android.net.vpn.L2tpIpsecProfile;
20 | import android.security.Credentials;
21 |
22 | import java.io.IOException;
23 |
24 | /**
25 | * The service that manages the certificate based L2TP-over-IPSec VPN connection.
26 | */
27 | class L2tpIpsecService extends VpnService {
28 | private static final String IPSEC = "racoon";
29 |
30 | @Override
31 | protected void connect(String serverIp, String username, String password)
32 | throws IOException {
33 | L2tpIpsecProfile p = getProfile();
34 | VpnDaemons daemons = getDaemons();
35 |
36 | // IPSEC
37 | DaemonProxy ipsec = daemons.startIpsecForL2tp(serverIp,
38 | Credentials.USER_PRIVATE_KEY + p.getUserCertificate(),
39 | Credentials.USER_CERTIFICATE + p.getUserCertificate(),
40 | Credentials.CA_CERTIFICATE + p.getCaCertificate());
41 | ipsec.closeControlSocket();
42 |
43 | sleep(2000); // 2 seconds
44 |
45 | // L2TP
46 | daemons.startL2tp(serverIp,
47 | (p.isSecretEnabled() ? p.getSecretString() : null),
48 | username, password);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/VpnServices/src/com/android/server/vpn/L2tpService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package com.android.server.vpn;
18 |
19 | import android.net.vpn.L2tpProfile;
20 |
21 | import java.io.IOException;
22 |
23 | /**
24 | * The service that manages the L2TP VPN connection.
25 | */
26 | class L2tpService extends VpnService {
27 | @Override
28 | protected void connect(String serverIp, String username, String password)
29 | throws IOException {
30 | L2tpProfile p = getProfile();
31 | getDaemons().startL2tp(serverIp,
32 | (p.isSecretEnabled() ? p.getSecretString() : null),
33 | username, password);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/VpnServices/src/com/android/server/vpn/PptpService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package com.android.server.vpn;
18 |
19 | import android.net.vpn.PptpProfile;
20 |
21 | import java.io.IOException;
22 |
23 | /**
24 | * The service that manages the PPTP VPN connection.
25 | */
26 | class PptpService extends VpnService {
27 | @Override
28 | protected void connect(String serverIp, String username, String password)
29 | throws IOException {
30 | PptpProfile p = getProfile();
31 | getDaemons().startPptp(serverIp, username, password,
32 | p.isEncryptionEnabled());
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/VpnServices/src/com/android/server/vpn/VpnConnectingError.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package com.android.server.vpn;
18 |
19 | import java.io.IOException;
20 |
21 | /**
22 | * Exception thrown when a connecting attempt fails.
23 | */
24 | class VpnConnectingError extends IOException {
25 | private int mErrorCode;
26 |
27 | VpnConnectingError(int errorCode) {
28 | super("Connecting error: " + errorCode);
29 | mErrorCode = errorCode;
30 | }
31 |
32 | int getErrorCode() {
33 | return mErrorCode;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/VpnServices/src/com/android/server/vpn/VpnDaemons.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package com.android.server.vpn;
18 |
19 | import android.util.Log;
20 |
21 | import java.io.IOException;
22 | import java.io.Serializable;
23 | import java.util.ArrayList;
24 | import java.util.Arrays;
25 | import java.util.List;
26 |
27 | /**
28 | * A helper class for managing native VPN daemons.
29 | */
30 | class VpnDaemons implements Serializable {
31 | static final long serialVersionUID = 1L;
32 | private final String TAG = VpnDaemons.class.getSimpleName();
33 |
34 | private static final String MTPD = "mtpd";
35 | private static final String IPSEC = "racoon";
36 |
37 | private static final String L2TP = "l2tp";
38 | private static final String L2TP_PORT = "1701";
39 |
40 | private static final String PPTP = "pptp";
41 | private static final String PPTP_PORT = "1723";
42 |
43 | private static final String VPN_LINKNAME = "vpn";
44 | private static final String PPP_ARGS_SEPARATOR = "";
45 |
46 | private List mDaemonList = new ArrayList();
47 |
48 | public DaemonProxy startL2tp(String serverIp, String secret,
49 | String username, String password) throws IOException {
50 | return startMtpd(L2TP, serverIp, L2TP_PORT, secret, username, password,
51 | false);
52 | }
53 |
54 | public DaemonProxy startPptp(String serverIp, String username,
55 | String password, boolean encryption) throws IOException {
56 | return startMtpd(PPTP, serverIp, PPTP_PORT, null, username, password,
57 | encryption);
58 | }
59 |
60 | public DaemonProxy startIpsecForL2tp(String serverIp, String pskKey)
61 | throws IOException {
62 | DaemonProxy ipsec = startDaemon(IPSEC);
63 | ipsec.sendCommand(serverIp, L2TP_PORT, pskKey);
64 | return ipsec;
65 | }
66 |
67 | public DaemonProxy startIpsecForL2tp(String serverIp, String userKeyKey,
68 | String userCertKey, String caCertKey) throws IOException {
69 | DaemonProxy ipsec = startDaemon(IPSEC);
70 | ipsec.sendCommand(serverIp, L2TP_PORT, userKeyKey, userCertKey,
71 | caCertKey);
72 | return ipsec;
73 | }
74 |
75 | public synchronized void stopAll() {
76 | new DaemonProxy(MTPD).stop();
77 | new DaemonProxy(IPSEC).stop();
78 | }
79 |
80 | public synchronized void closeSockets() {
81 | for (DaemonProxy s : mDaemonList) s.closeControlSocket();
82 | }
83 |
84 | public synchronized boolean anyDaemonStopped() {
85 | for (DaemonProxy s : mDaemonList) {
86 | if (s.isStopped()) {
87 | Log.w(TAG, " VPN daemon gone: " + s.getName());
88 | return true;
89 | }
90 | }
91 | return false;
92 | }
93 |
94 | public synchronized int getSocketError() {
95 | for (DaemonProxy s : mDaemonList) {
96 | int errCode = getResultFromSocket(s);
97 | if (errCode != 0) return errCode;
98 | }
99 | return 0;
100 | }
101 |
102 | private synchronized DaemonProxy startDaemon(String daemonName)
103 | throws IOException {
104 | DaemonProxy daemon = new DaemonProxy(daemonName);
105 | mDaemonList.add(daemon);
106 | daemon.start();
107 | return daemon;
108 | }
109 |
110 | private int getResultFromSocket(DaemonProxy s) {
111 | try {
112 | return s.getResultFromSocket();
113 | } catch (IOException e) {
114 | return -1;
115 | }
116 | }
117 |
118 | private DaemonProxy startMtpd(String protocol,
119 | String serverIp, String port, String secret, String username,
120 | String password, boolean encryption) throws IOException {
121 | ArrayList args = new ArrayList();
122 | args.addAll(Arrays.asList(protocol, serverIp, port));
123 | if (secret != null) args.add(secret);
124 | args.add(PPP_ARGS_SEPARATOR);
125 | addPppArguments(args, serverIp, username, password, encryption);
126 |
127 | DaemonProxy mtpd = startDaemon(MTPD);
128 | mtpd.sendCommand(args.toArray(new String[args.size()]));
129 | return mtpd;
130 | }
131 |
132 | private static void addPppArguments(ArrayList args, String serverIp,
133 | String username, String password, boolean encryption)
134 | throws IOException {
135 | args.addAll(Arrays.asList(
136 | "linkname", VPN_LINKNAME,
137 | "name", username,
138 | "password", password,
139 | "refuse-eap", "nodefaultroute", "usepeerdns",
140 | "idle", "1800",
141 | "mtu", "1400",
142 | "mru", "1400"));
143 | if (encryption) {
144 | args.add("+mppe");
145 | }
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/VpnServices/src/com/android/server/vpn/VpnService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package com.android.server.vpn;
18 |
19 | import android.app.Notification;
20 | import android.app.NotificationManager;
21 | import android.app.PendingIntent;
22 | import android.content.Context;
23 | import android.net.vpn.VpnManager;
24 | import android.net.vpn.VpnProfile;
25 | import android.net.vpn.VpnState;
26 | import android.os.SystemProperties;
27 | import android.text.TextUtils;
28 | import android.util.Log;
29 |
30 | import java.io.IOException;
31 | import java.io.Serializable;
32 | import java.net.DatagramSocket;
33 | import java.net.InetAddress;
34 | import java.net.NetworkInterface;
35 | import java.net.UnknownHostException;
36 |
37 | /**
38 | * The service base class for managing a type of VPN connection.
39 | */
40 | abstract class VpnService implements Serializable {
41 | static final long serialVersionUID = 1L;
42 | private static final boolean DBG = true;
43 | private static final int NOTIFICATION_ID = 1;
44 |
45 | private static final String DNS1 = "net.dns1";
46 | private static final String DNS2 = "net.dns2";
47 | private static final String VPN_DNS1 = "vpn.dns1";
48 | private static final String VPN_DNS2 = "vpn.dns2";
49 | private static final String VPN_STATUS = "vpn.status";
50 | private static final String VPN_IS_UP = "ok";
51 | private static final String VPN_IS_DOWN = "down";
52 |
53 | private static final String REMOTE_IP = "net.ipremote";
54 | private static final String DNS_DOMAIN_SUFFICES = "net.dns.search";
55 |
56 | private final String TAG = VpnService.class.getSimpleName();
57 |
58 | // FIXME: profile is only needed in connecting phase, so we can just save
59 | // the profile name and service class name for recovery
60 | E mProfile;
61 | transient VpnServiceBinder mContext;
62 |
63 | private VpnState mState = VpnState.IDLE;
64 | private Throwable mError;
65 |
66 | // connection settings
67 | private String mOriginalDns1;
68 | private String mOriginalDns2;
69 | private String mOriginalDomainSuffices;
70 | private String mLocalIp;
71 | private String mLocalIf;
72 |
73 | private long mStartTime; // VPN connection start time
74 |
75 | // for helping managing daemons
76 | private VpnDaemons mDaemons = new VpnDaemons();
77 |
78 | // for helping showing, updating notification
79 | private transient NotificationHelper mNotification;
80 |
81 | /**
82 | * Establishes a VPN connection with the specified username and password.
83 | */
84 | protected abstract void connect(String serverIp, String username,
85 | String password) throws IOException;
86 |
87 | /**
88 | * Returns the daemons management class for this service object.
89 | */
90 | protected VpnDaemons getDaemons() {
91 | return mDaemons;
92 | }
93 |
94 | /**
95 | * Returns the VPN profile associated with the connection.
96 | */
97 | protected E getProfile() {
98 | return mProfile;
99 | }
100 |
101 | /**
102 | * Returns the IP address of the specified host name.
103 | */
104 | protected String getIp(String hostName) throws IOException {
105 | return InetAddress.getByName(hostName).getHostAddress();
106 | }
107 |
108 | void setContext(VpnServiceBinder context, E profile) {
109 | mProfile = profile;
110 | recover(context);
111 | }
112 |
113 | void recover(VpnServiceBinder context) {
114 | mContext = context;
115 | mNotification = new NotificationHelper();
116 |
117 | if (VpnState.CONNECTED.equals(mState)) {
118 | Log.i("VpnService", " recovered: " + mProfile.getName());
119 | startConnectivityMonitor();
120 | }
121 | }
122 |
123 | VpnState getState() {
124 | return mState;
125 | }
126 |
127 | synchronized boolean onConnect(String username, String password) {
128 | try {
129 | setState(VpnState.CONNECTING);
130 |
131 | mDaemons.stopAll();
132 | String serverIp = getIp(getProfile().getServerName());
133 | saveLocalIpAndInterface(serverIp);
134 | onBeforeConnect();
135 | connect(serverIp, username, password);
136 | waitUntilConnectedOrTimedout();
137 | return true;
138 | } catch (Throwable e) {
139 | onError(e);
140 | return false;
141 | }
142 | }
143 |
144 | synchronized void onDisconnect() {
145 | try {
146 | Log.i(TAG, "disconnecting VPN...");
147 | setState(VpnState.DISCONNECTING);
148 | mNotification.showDisconnect();
149 |
150 | mDaemons.stopAll();
151 | } catch (Throwable e) {
152 | Log.e(TAG, "onDisconnect()", e);
153 | } finally {
154 | onFinalCleanUp();
155 | }
156 | }
157 |
158 | private void onError(Throwable error) {
159 | // error may occur during or after connection setup
160 | // and it may be due to one or all services gone
161 | if (mError != null) {
162 | Log.w(TAG, " multiple errors occur, record the last one: "
163 | + error);
164 | }
165 | Log.e(TAG, "onError()", error);
166 | mError = error;
167 | onDisconnect();
168 | }
169 |
170 | private void onError(int errorCode) {
171 | onError(new VpnConnectingError(errorCode));
172 | }
173 |
174 |
175 | private void onBeforeConnect() throws IOException {
176 | mNotification.disableNotification();
177 |
178 | SystemProperties.set(VPN_DNS1, "");
179 | SystemProperties.set(VPN_DNS2, "");
180 | SystemProperties.set(VPN_STATUS, VPN_IS_DOWN);
181 | if (DBG) {
182 | Log.d(TAG, " VPN UP: " + SystemProperties.get(VPN_STATUS));
183 | }
184 | }
185 |
186 | private void waitUntilConnectedOrTimedout() throws IOException {
187 | sleep(2000); // 2 seconds
188 | for (int i = 0; i < 80; i++) {
189 | if (mState != VpnState.CONNECTING) {
190 | break;
191 | } else if (VPN_IS_UP.equals(
192 | SystemProperties.get(VPN_STATUS))) {
193 | onConnected();
194 | return;
195 | } else {
196 | int err = mDaemons.getSocketError();
197 | if (err != 0) {
198 | onError(err);
199 | return;
200 | }
201 | }
202 | sleep(500); // 0.5 second
203 | }
204 |
205 | if (mState == VpnState.CONNECTING) {
206 | onError(new IOException("Connecting timed out"));
207 | }
208 | }
209 |
210 | private synchronized void onConnected() throws IOException {
211 | if (DBG) Log.d(TAG, "onConnected()");
212 |
213 | mDaemons.closeSockets();
214 | saveOriginalDns();
215 | saveAndSetDomainSuffices();
216 |
217 | mStartTime = System.currentTimeMillis();
218 |
219 | // Correct order to make sure VpnService doesn't break when killed:
220 | // (1) set state to CONNECTED
221 | // (2) save states
222 | // (3) set DNS
223 | setState(VpnState.CONNECTED);
224 | saveSelf();
225 | setVpnDns();
226 |
227 | startConnectivityMonitor();
228 | }
229 |
230 | private void saveSelf() throws IOException {
231 | mContext.saveStates();
232 | }
233 |
234 | private synchronized void onFinalCleanUp() {
235 | if (DBG) Log.d(TAG, "onFinalCleanUp()");
236 |
237 | if (mState == VpnState.IDLE) return;
238 |
239 | // keep the notification when error occurs
240 | if (!anyError()) mNotification.disableNotification();
241 |
242 | restoreOriginalDns();
243 | restoreOriginalDomainSuffices();
244 | setState(VpnState.IDLE);
245 |
246 | // stop the service itself
247 | SystemProperties.set(VPN_STATUS, VPN_IS_DOWN);
248 | mContext.removeStates();
249 | mContext.stopSelf();
250 | }
251 |
252 | private boolean anyError() {
253 | return (mError != null);
254 | }
255 |
256 | private void restoreOriginalDns() {
257 | // restore only if they are not overridden
258 | String vpnDns1 = SystemProperties.get(VPN_DNS1);
259 | if (vpnDns1.equals(SystemProperties.get(DNS1))) {
260 | Log.i(TAG, String.format("restore original dns prop: %s --> %s",
261 | SystemProperties.get(DNS1), mOriginalDns1));
262 | Log.i(TAG, String.format("restore original dns prop: %s --> %s",
263 | SystemProperties.get(DNS2), mOriginalDns2));
264 | SystemProperties.set(DNS1, mOriginalDns1);
265 | SystemProperties.set(DNS2, mOriginalDns2);
266 | }
267 | }
268 |
269 | private void saveOriginalDns() {
270 | mOriginalDns1 = SystemProperties.get(DNS1);
271 | mOriginalDns2 = SystemProperties.get(DNS2);
272 | Log.i(TAG, String.format("save original dns prop: %s, %s",
273 | mOriginalDns1, mOriginalDns2));
274 | }
275 |
276 | private void setVpnDns() {
277 | String vpnDns1 = SystemProperties.get(VPN_DNS1);
278 | String vpnDns2 = SystemProperties.get(VPN_DNS2);
279 | SystemProperties.set(DNS1, vpnDns1);
280 | SystemProperties.set(DNS2, vpnDns2);
281 | Log.i(TAG, String.format("set vpn dns prop: %s, %s",
282 | vpnDns1, vpnDns2));
283 | }
284 |
285 | private void saveAndSetDomainSuffices() {
286 | mOriginalDomainSuffices = SystemProperties.get(DNS_DOMAIN_SUFFICES);
287 | Log.i(TAG, "save original suffices: " + mOriginalDomainSuffices);
288 | String list = mProfile.getDomainSuffices();
289 | if (!TextUtils.isEmpty(list)) {
290 | SystemProperties.set(DNS_DOMAIN_SUFFICES, list);
291 | }
292 | }
293 |
294 | private void restoreOriginalDomainSuffices() {
295 | Log.i(TAG, "restore original suffices --> " + mOriginalDomainSuffices);
296 | SystemProperties.set(DNS_DOMAIN_SUFFICES, mOriginalDomainSuffices);
297 | }
298 |
299 | private void setState(VpnState newState) {
300 | mState = newState;
301 | broadcastConnectivity(newState);
302 | }
303 |
304 | private void broadcastConnectivity(VpnState s) {
305 | VpnManager m = new VpnManager(mContext);
306 | Throwable err = mError;
307 | if ((s == VpnState.IDLE) && (err != null)) {
308 | if (err instanceof UnknownHostException) {
309 | m.broadcastConnectivity(mProfile.getName(), s,
310 | VpnManager.VPN_ERROR_UNKNOWN_SERVER);
311 | } else if (err instanceof VpnConnectingError) {
312 | m.broadcastConnectivity(mProfile.getName(), s,
313 | ((VpnConnectingError) err).getErrorCode());
314 | } else if (VPN_IS_UP.equals(SystemProperties.get(VPN_STATUS))) {
315 | m.broadcastConnectivity(mProfile.getName(), s,
316 | VpnManager.VPN_ERROR_CONNECTION_LOST);
317 | } else {
318 | m.broadcastConnectivity(mProfile.getName(), s,
319 | VpnManager.VPN_ERROR_CONNECTION_FAILED);
320 | }
321 | } else {
322 | m.broadcastConnectivity(mProfile.getName(), s);
323 | }
324 | }
325 |
326 | private void startConnectivityMonitor() {
327 | new Thread(new Runnable() {
328 | public void run() {
329 | Log.i(TAG, "VPN connectivity monitor running");
330 | try {
331 | for (int i = 10; ; i--) {
332 | long now = System.currentTimeMillis();
333 |
334 | boolean heavyCheck = i == 0;
335 | synchronized (VpnService.this) {
336 | if (mState != VpnState.CONNECTED) break;
337 | mNotification.update(now);
338 |
339 | if (heavyCheck) {
340 | i = 10;
341 | if (checkConnectivity()) checkDns();
342 | }
343 | long t = 1000L - System.currentTimeMillis() + now;
344 | if (t > 100L) VpnService.this.wait(t);
345 | }
346 | }
347 | } catch (InterruptedException e) {
348 | onError(e);
349 | }
350 | Log.i(TAG, "VPN connectivity monitor stopped");
351 | }
352 | }).start();
353 | }
354 |
355 | private void saveLocalIpAndInterface(String serverIp) throws IOException {
356 | DatagramSocket s = new DatagramSocket();
357 | int port = 80; // arbitrary
358 | s.connect(InetAddress.getByName(serverIp), port);
359 | InetAddress localIp = s.getLocalAddress();
360 | mLocalIp = localIp.getHostAddress();
361 | NetworkInterface localIf = NetworkInterface.getByInetAddress(localIp);
362 | mLocalIf = (localIf == null) ? null : localIf.getName();
363 | if (TextUtils.isEmpty(mLocalIf)) {
364 | throw new IOException("Local interface is empty!");
365 | }
366 | if (DBG) {
367 | Log.d(TAG, " Local IP: " + mLocalIp + ", if: " + mLocalIf);
368 | }
369 | }
370 |
371 | // returns false if vpn connectivity is broken
372 | private boolean checkConnectivity() {
373 | if (mDaemons.anyDaemonStopped() || isLocalIpChanged()) {
374 | onError(new IOException("Connectivity lost"));
375 | return false;
376 | } else {
377 | return true;
378 | }
379 | }
380 |
381 | private void checkDns() {
382 | String dns1 = SystemProperties.get(DNS1);
383 | String vpnDns1 = SystemProperties.get(VPN_DNS1);
384 | if (!dns1.equals(vpnDns1) && dns1.equals(mOriginalDns1)) {
385 | // dhcp expires?
386 | setVpnDns();
387 | }
388 | }
389 |
390 | private boolean isLocalIpChanged() {
391 | try {
392 | InetAddress localIp = InetAddress.getByName(mLocalIp);
393 | NetworkInterface localIf =
394 | NetworkInterface.getByInetAddress(localIp);
395 | if (localIf == null || !mLocalIf.equals(localIf.getName())) {
396 | Log.w(TAG, " local If changed from " + mLocalIf
397 | + " to " + localIf);
398 | return true;
399 | } else {
400 | return false;
401 | }
402 | } catch (IOException e) {
403 | Log.w(TAG, "isLocalIpChanged()", e);
404 | return true;
405 | }
406 | }
407 |
408 | protected void sleep(int ms) {
409 | try {
410 | Thread.currentThread().sleep(ms);
411 | } catch (InterruptedException e) {
412 | }
413 | }
414 |
415 | private class DaemonHelper implements Serializable {
416 | }
417 |
418 | // Helper class for showing, updating notification.
419 | private class NotificationHelper {
420 | void update(long now) {
421 | String title = getNotificationTitle(true);
422 | Notification n = new Notification(R.drawable.vpn_connected, title,
423 | mStartTime);
424 | n.setLatestEventInfo(mContext, title,
425 | getConnectedNotificationMessage(now),
426 | prepareNotificationIntent());
427 | n.flags |= Notification.FLAG_NO_CLEAR;
428 | n.flags |= Notification.FLAG_ONGOING_EVENT;
429 | enableNotification(n);
430 | }
431 |
432 | void showDisconnect() {
433 | String title = getNotificationTitle(false);
434 | Notification n = new Notification(R.drawable.vpn_disconnected,
435 | title, System.currentTimeMillis());
436 | n.setLatestEventInfo(mContext, title,
437 | getDisconnectedNotificationMessage(),
438 | prepareNotificationIntent());
439 | n.flags |= Notification.FLAG_AUTO_CANCEL;
440 | disableNotification();
441 | enableNotification(n);
442 | }
443 |
444 | void disableNotification() {
445 | ((NotificationManager) mContext.getSystemService(
446 | Context.NOTIFICATION_SERVICE)).cancel(NOTIFICATION_ID);
447 | }
448 |
449 | private void enableNotification(Notification n) {
450 | ((NotificationManager) mContext.getSystemService(
451 | Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, n);
452 | }
453 |
454 | private PendingIntent prepareNotificationIntent() {
455 | return PendingIntent.getActivity(mContext, 0,
456 | new VpnManager(mContext).createSettingsActivityIntent(), 0);
457 | }
458 |
459 | private String getNotificationTitle(boolean connected) {
460 | String formatString = connected
461 | ? mContext.getString(
462 | R.string.vpn_notification_title_connected)
463 | : mContext.getString(
464 | R.string.vpn_notification_title_disconnected);
465 | return String.format(formatString, mProfile.getName());
466 | }
467 |
468 | private String getFormattedTime(int duration) {
469 | int hours = duration / 3600;
470 | StringBuilder sb = new StringBuilder();
471 | if (hours > 0) sb.append(hours).append(':');
472 | sb.append(String.format("%02d:%02d", (duration % 3600 / 60),
473 | (duration % 60)));
474 | return sb.toString();
475 | }
476 |
477 | private String getConnectedNotificationMessage(long now) {
478 | return getFormattedTime((int) (now - mStartTime) / 1000);
479 | }
480 |
481 | private String getDisconnectedNotificationMessage() {
482 | return mContext.getString(
483 | R.string.vpn_notification_hint_disconnected);
484 | }
485 | }
486 | }
487 |
--------------------------------------------------------------------------------
/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package com.android.server.vpn;
18 |
19 | import android.app.Service;
20 | import android.content.Intent;
21 | import android.net.vpn.IVpnService;
22 | import android.net.vpn.L2tpIpsecProfile;
23 | import android.net.vpn.L2tpIpsecPskProfile;
24 | import android.net.vpn.L2tpProfile;
25 | import android.net.vpn.PptpProfile;
26 | import android.net.vpn.VpnManager;
27 | import android.net.vpn.VpnProfile;
28 | import android.net.vpn.VpnState;
29 | import android.os.Environment;
30 | import android.os.IBinder;
31 | import android.os.SystemProperties;
32 | import android.util.Log;
33 |
34 | import java.io.File;
35 | import java.io.FileInputStream;
36 | import java.io.FileNotFoundException;
37 | import java.io.FileOutputStream;
38 | import java.io.IOException;
39 | import java.io.ObjectInputStream;
40 | import java.io.ObjectOutputStream;
41 |
42 | /**
43 | * The service class for managing a VPN connection. It implements the
44 | * {@link IVpnService} binder interface.
45 | */
46 | public class VpnServiceBinder extends Service {
47 | private static final String TAG = VpnServiceBinder.class.getSimpleName();
48 | private static final boolean DBG = true;
49 |
50 | private static final String STATES_FILE_RELATIVE_PATH = "/misc/vpn/.states";
51 |
52 | // The actual implementation is delegated to the VpnService class.
53 | private VpnService extends VpnProfile> mService;
54 |
55 | // TODO(oam): Test VPN when EFS is enabled (will do later)...
56 | private static String getStateFilePath() {
57 | // This call will return the correcu directory whether Encrypted FS is enabled or not
58 | // Disabled: /data/misc/vpn/.states Enabled: /data/secure/misc/vpn/.states
59 | return Environment.getSecureDataDirectory().getPath() + STATES_FILE_RELATIVE_PATH;
60 | }
61 |
62 | private final IBinder mBinder = new IVpnService.Stub() {
63 | public boolean connect(VpnProfile p, String username, String password) {
64 | return VpnServiceBinder.this.connect(p, username, password);
65 | }
66 |
67 | public void disconnect() {
68 | VpnServiceBinder.this.disconnect();
69 | }
70 |
71 | public void checkStatus(VpnProfile p) {
72 | VpnServiceBinder.this.checkStatus(p);
73 | }
74 | };
75 |
76 | @Override
77 | public void onCreate() {
78 | super.onCreate();
79 | checkSavedStates();
80 | }
81 |
82 |
83 | @Override
84 | public void onStart(Intent intent, int startId) {
85 | super.onStart(intent, startId);
86 | }
87 |
88 | @Override
89 | public IBinder onBind(Intent intent) {
90 | return mBinder;
91 | }
92 |
93 | void saveStates() throws IOException {
94 | if (DBG) Log.d("VpnServiceBinder", " saving states");
95 | ObjectOutputStream oos =
96 | new ObjectOutputStream(new FileOutputStream(getStateFilePath()));
97 | oos.writeObject(mService);
98 | oos.close();
99 | }
100 |
101 | void removeStates() {
102 | try {
103 | File f = new File(getStateFilePath());
104 | if (f.exists()) f.delete();
105 | } catch (Throwable e) {
106 | if (DBG) Log.d("VpnServiceBinder", " remove states: " + e);
107 | }
108 | }
109 |
110 | private synchronized boolean connect(final VpnProfile p,
111 | final String username, final String password) {
112 | if (mService != null) return false;
113 | final VpnService s = mService = createService(p);
114 |
115 | new Thread(new Runnable() {
116 | public void run() {
117 | s.onConnect(username, password);
118 | }
119 | }).start();
120 | return true;
121 | }
122 |
123 | private synchronized void disconnect() {
124 | if (mService == null) return;
125 | final VpnService s = mService;
126 |
127 | new Thread(new Runnable() {
128 | public void run() {
129 | s.onDisconnect();
130 | }
131 | }).start();
132 | }
133 |
134 | private synchronized void checkStatus(VpnProfile p) {
135 | if ((mService == null)
136 | || (!p.getName().equals(mService.mProfile.getName()))) {
137 | broadcastConnectivity(p.getName(), VpnState.IDLE);
138 | } else {
139 | broadcastConnectivity(p.getName(), mService.getState());
140 | }
141 | }
142 |
143 | private void checkSavedStates() {
144 | try {
145 | ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
146 | getStateFilePath()));
147 | mService = (VpnService extends VpnProfile>) ois.readObject();
148 | mService.recover(this);
149 | ois.close();
150 | } catch (FileNotFoundException e) {
151 | // do nothing
152 | } catch (Throwable e) {
153 | Log.i("VpnServiceBinder", "recovery error, remove states: " + e);
154 | removeStates();
155 | }
156 | }
157 |
158 | private VpnService extends VpnProfile> createService(VpnProfile p) {
159 | switch (p.getType()) {
160 | case L2TP:
161 | L2tpService l2tp = new L2tpService();
162 | l2tp.setContext(this, (L2tpProfile) p);
163 | return l2tp;
164 |
165 | case PPTP:
166 | PptpService pptp = new PptpService();
167 | pptp.setContext(this, (PptpProfile) p);
168 | return pptp;
169 |
170 | case L2TP_IPSEC_PSK:
171 | L2tpIpsecPskService psk = new L2tpIpsecPskService();
172 | psk.setContext(this, (L2tpIpsecPskProfile) p);
173 | return psk;
174 |
175 | case L2TP_IPSEC:
176 | L2tpIpsecService l2tpIpsec = new L2tpIpsecService();
177 | l2tpIpsec.setContext(this, (L2tpIpsecProfile) p);
178 | return l2tpIpsec;
179 |
180 | default:
181 | return null;
182 | }
183 | }
184 |
185 | private void broadcastConnectivity(String name, VpnState s) {
186 | new VpnManager(this).broadcastConnectivity(name, s);
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/bin/android-vpn-server.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/android-vpn-server.apk
--------------------------------------------------------------------------------
/bin/android/net/vpn/IVpnService$Stub$Proxy.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/android/net/vpn/IVpnService$Stub$Proxy.class
--------------------------------------------------------------------------------
/bin/android/net/vpn/IVpnService$Stub.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/android/net/vpn/IVpnService$Stub.class
--------------------------------------------------------------------------------
/bin/android/net/vpn/IVpnService.aidl:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package android.net.vpn;
18 |
19 | import android.net.vpn.VpnProfile;
20 |
21 | /**
22 | * Interface to access a VPN service.
23 | * {@hide}
24 | */
25 | interface IVpnService {
26 | /**
27 | * Sets up the VPN connection.
28 | * @param profile the profile object
29 | * @param username the username for authentication
30 | * @param password the corresponding password for authentication
31 | */
32 | boolean connect(in VpnProfile profile, String username, String password);
33 |
34 | /**
35 | * Tears down the VPN connection.
36 | */
37 | void disconnect();
38 |
39 | /**
40 | * Makes the service broadcast the connectivity state.
41 | */
42 | void checkStatus(in VpnProfile profile);
43 | }
44 |
--------------------------------------------------------------------------------
/bin/android/net/vpn/IVpnService.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/android/net/vpn/IVpnService.class
--------------------------------------------------------------------------------
/bin/android/net/vpn/L2tpIpsecProfile.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/android/net/vpn/L2tpIpsecProfile.class
--------------------------------------------------------------------------------
/bin/android/net/vpn/L2tpIpsecPskProfile.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/android/net/vpn/L2tpIpsecPskProfile.class
--------------------------------------------------------------------------------
/bin/android/net/vpn/L2tpProfile.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/android/net/vpn/L2tpProfile.class
--------------------------------------------------------------------------------
/bin/android/net/vpn/PptpProfile.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/android/net/vpn/PptpProfile.class
--------------------------------------------------------------------------------
/bin/android/net/vpn/VpnManager.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/android/net/vpn/VpnManager.class
--------------------------------------------------------------------------------
/bin/android/net/vpn/VpnProfile$1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/android/net/vpn/VpnProfile$1.class
--------------------------------------------------------------------------------
/bin/android/net/vpn/VpnProfile.aidl:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package android.net.vpn;
18 |
19 | parcelable VpnProfile;
20 |
--------------------------------------------------------------------------------
/bin/android/net/vpn/VpnProfile.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/android/net/vpn/VpnProfile.class
--------------------------------------------------------------------------------
/bin/android/net/vpn/VpnState.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/android/net/vpn/VpnState.class
--------------------------------------------------------------------------------
/bin/android/net/vpn/VpnTest$1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/android/net/vpn/VpnTest$1.class
--------------------------------------------------------------------------------
/bin/android/net/vpn/VpnTest.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/android/net/vpn/VpnTest.class
--------------------------------------------------------------------------------
/bin/android/net/vpn/VpnType.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/android/net/vpn/VpnType.class
--------------------------------------------------------------------------------
/bin/android/os/SystemProperties.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/android/os/SystemProperties.class
--------------------------------------------------------------------------------
/bin/android/security/Credentials.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/android/security/Credentials.class
--------------------------------------------------------------------------------
/bin/android/security/KeyStore.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/android/security/KeyStore.class
--------------------------------------------------------------------------------
/bin/classes.dex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/classes.dex
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/DaemonProxy.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/DaemonProxy.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/L2tpIpsecPskService.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/L2tpIpsecPskService.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/L2tpIpsecService.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/L2tpIpsecService.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/L2tpService.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/L2tpService.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/PptpService.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/PptpService.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/R$attr.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/R$attr.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/R$drawable.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/R$drawable.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/R$layout.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/R$layout.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/R$string.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/R$string.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/R.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/R.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/VpnConnectingError.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/VpnConnectingError.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/VpnDaemons.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/VpnDaemons.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/VpnService$1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/VpnService$1.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/VpnService$DaemonHelper.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/VpnService$DaemonHelper.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/VpnService$NotificationHelper.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/VpnService$NotificationHelper.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/VpnService.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/VpnService.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/VpnServiceBinder$1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/VpnServiceBinder$1.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/VpnServiceBinder$2.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/VpnServiceBinder$2.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/VpnServiceBinder$3.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/VpnServiceBinder$3.class
--------------------------------------------------------------------------------
/bin/com/android/server/vpn/VpnServiceBinder.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/com/android/server/vpn/VpnServiceBinder.class
--------------------------------------------------------------------------------
/bin/org/zju/luojs/MyVpn.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/org/zju/luojs/MyVpn.class
--------------------------------------------------------------------------------
/bin/resources.ap_:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/bin/resources.ap_
--------------------------------------------------------------------------------
/default.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "build.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | # Project target.
11 | target=android-8
12 |
--------------------------------------------------------------------------------
/gen/android/net/vpn/IVpnService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is auto-generated. DO NOT MODIFY.
3 | * Original file: /home/luojiesi/program/android-vpn-server/src/android/net/vpn/IVpnService.aidl
4 | */
5 | package android.net.vpn;
6 | /**
7 | * Interface to access a VPN service.
8 | * {@hide}
9 | */
10 | public interface IVpnService extends android.os.IInterface
11 | {
12 | /** Local-side IPC implementation stub class. */
13 | public static abstract class Stub extends android.os.Binder implements android.net.vpn.IVpnService
14 | {
15 | private static final java.lang.String DESCRIPTOR = "android.net.vpn.IVpnService";
16 | /** Construct the stub at attach it to the interface. */
17 | public Stub()
18 | {
19 | this.attachInterface(this, DESCRIPTOR);
20 | }
21 | /**
22 | * Cast an IBinder object into an android.net.vpn.IVpnService interface,
23 | * generating a proxy if needed.
24 | */
25 | public static android.net.vpn.IVpnService asInterface(android.os.IBinder obj)
26 | {
27 | if ((obj==null)) {
28 | return null;
29 | }
30 | android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
31 | if (((iin!=null)&&(iin instanceof android.net.vpn.IVpnService))) {
32 | return ((android.net.vpn.IVpnService)iin);
33 | }
34 | return new android.net.vpn.IVpnService.Stub.Proxy(obj);
35 | }
36 | public android.os.IBinder asBinder()
37 | {
38 | return this;
39 | }
40 | @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
41 | {
42 | switch (code)
43 | {
44 | case INTERFACE_TRANSACTION:
45 | {
46 | reply.writeString(DESCRIPTOR);
47 | return true;
48 | }
49 | case TRANSACTION_connect:
50 | {
51 | data.enforceInterface(DESCRIPTOR);
52 | android.net.vpn.VpnProfile _arg0;
53 | if ((0!=data.readInt())) {
54 | _arg0 = android.net.vpn.VpnProfile.CREATOR.createFromParcel(data);
55 | }
56 | else {
57 | _arg0 = null;
58 | }
59 | java.lang.String _arg1;
60 | _arg1 = data.readString();
61 | java.lang.String _arg2;
62 | _arg2 = data.readString();
63 | boolean _result = this.connect(_arg0, _arg1, _arg2);
64 | reply.writeNoException();
65 | reply.writeInt(((_result)?(1):(0)));
66 | return true;
67 | }
68 | case TRANSACTION_disconnect:
69 | {
70 | data.enforceInterface(DESCRIPTOR);
71 | this.disconnect();
72 | reply.writeNoException();
73 | return true;
74 | }
75 | case TRANSACTION_checkStatus:
76 | {
77 | data.enforceInterface(DESCRIPTOR);
78 | android.net.vpn.VpnProfile _arg0;
79 | if ((0!=data.readInt())) {
80 | _arg0 = android.net.vpn.VpnProfile.CREATOR.createFromParcel(data);
81 | }
82 | else {
83 | _arg0 = null;
84 | }
85 | this.checkStatus(_arg0);
86 | reply.writeNoException();
87 | return true;
88 | }
89 | }
90 | return super.onTransact(code, data, reply, flags);
91 | }
92 | private static class Proxy implements android.net.vpn.IVpnService
93 | {
94 | private android.os.IBinder mRemote;
95 | Proxy(android.os.IBinder remote)
96 | {
97 | mRemote = remote;
98 | }
99 | public android.os.IBinder asBinder()
100 | {
101 | return mRemote;
102 | }
103 | public java.lang.String getInterfaceDescriptor()
104 | {
105 | return DESCRIPTOR;
106 | }
107 | /**
108 | * Sets up the VPN connection.
109 | * @param profile the profile object
110 | * @param username the username for authentication
111 | * @param password the corresponding password for authentication
112 | */
113 | public boolean connect(android.net.vpn.VpnProfile profile, java.lang.String username, java.lang.String password) throws android.os.RemoteException
114 | {
115 | android.os.Parcel _data = android.os.Parcel.obtain();
116 | android.os.Parcel _reply = android.os.Parcel.obtain();
117 | boolean _result;
118 | try {
119 | _data.writeInterfaceToken(DESCRIPTOR);
120 | if ((profile!=null)) {
121 | _data.writeInt(1);
122 | profile.writeToParcel(_data, 0);
123 | }
124 | else {
125 | _data.writeInt(0);
126 | }
127 | _data.writeString(username);
128 | _data.writeString(password);
129 | mRemote.transact(Stub.TRANSACTION_connect, _data, _reply, 0);
130 | _reply.readException();
131 | _result = (0!=_reply.readInt());
132 | }
133 | finally {
134 | _reply.recycle();
135 | _data.recycle();
136 | }
137 | return _result;
138 | }
139 | /**
140 | * Tears down the VPN connection.
141 | */
142 | public void disconnect() throws android.os.RemoteException
143 | {
144 | android.os.Parcel _data = android.os.Parcel.obtain();
145 | android.os.Parcel _reply = android.os.Parcel.obtain();
146 | try {
147 | _data.writeInterfaceToken(DESCRIPTOR);
148 | mRemote.transact(Stub.TRANSACTION_disconnect, _data, _reply, 0);
149 | _reply.readException();
150 | }
151 | finally {
152 | _reply.recycle();
153 | _data.recycle();
154 | }
155 | }
156 | /**
157 | * Makes the service broadcast the connectivity state.
158 | */
159 | public void checkStatus(android.net.vpn.VpnProfile profile) throws android.os.RemoteException
160 | {
161 | android.os.Parcel _data = android.os.Parcel.obtain();
162 | android.os.Parcel _reply = android.os.Parcel.obtain();
163 | try {
164 | _data.writeInterfaceToken(DESCRIPTOR);
165 | if ((profile!=null)) {
166 | _data.writeInt(1);
167 | profile.writeToParcel(_data, 0);
168 | }
169 | else {
170 | _data.writeInt(0);
171 | }
172 | mRemote.transact(Stub.TRANSACTION_checkStatus, _data, _reply, 0);
173 | _reply.readException();
174 | }
175 | finally {
176 | _reply.recycle();
177 | _data.recycle();
178 | }
179 | }
180 | }
181 | static final int TRANSACTION_connect = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
182 | static final int TRANSACTION_disconnect = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
183 | static final int TRANSACTION_checkStatus = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
184 | }
185 | /**
186 | * Sets up the VPN connection.
187 | * @param profile the profile object
188 | * @param username the username for authentication
189 | * @param password the corresponding password for authentication
190 | */
191 | public boolean connect(android.net.vpn.VpnProfile profile, java.lang.String username, java.lang.String password) throws android.os.RemoteException;
192 | /**
193 | * Tears down the VPN connection.
194 | */
195 | public void disconnect() throws android.os.RemoteException;
196 | /**
197 | * Makes the service broadcast the connectivity state.
198 | */
199 | public void checkStatus(android.net.vpn.VpnProfile profile) throws android.os.RemoteException;
200 | }
201 |
--------------------------------------------------------------------------------
/gen/com/android/server/vpn/R.java:
--------------------------------------------------------------------------------
1 | /* AUTO-GENERATED FILE. DO NOT MODIFY.
2 | *
3 | * This class was automatically generated by the
4 | * aapt tool from the resource data it found. It
5 | * should not be modified by hand.
6 | */
7 |
8 | package com.android.server.vpn;
9 |
10 | public final class R {
11 | public static final class attr {
12 | }
13 | public static final class drawable {
14 | public static final int vpn_connected=0x7f020000;
15 | public static final int vpn_disconnected=0x7f020001;
16 | }
17 | public static final class layout {
18 | public static final int main=0x7f030000;
19 | }
20 | public static final class string {
21 | /** Title for the VPN Services activity.
22 | Title for the VPN Services activity.
23 | Title for the VPN Services activity.
24 | */
25 | public static final int app_label=0x7f040000;
26 | public static final int app_name=0x7f040001;
27 | public static final int l2tp_ipsec_crt_vpn_description=0x7f040008;
28 | public static final int l2tp_ipsec_psk_vpn_description=0x7f040007;
29 | public static final int l2tp_vpn_description=0x7f040006;
30 | public static final int pptp_vpn_description=0x7f040005;
31 | public static final int vpn_notification_hint_disconnected=0x7f040004;
32 | public static final int vpn_notification_title_connected=0x7f040002;
33 | public static final int vpn_notification_title_disconnected=0x7f040003;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/proguard.cfg:
--------------------------------------------------------------------------------
1 | -optimizationpasses 5
2 | -dontusemixedcaseclassnames
3 | -dontskipnonpubliclibraryclasses
4 | -dontpreverify
5 | -verbose
6 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
7 |
8 | -keep public class * extends android.app.Activity
9 | -keep public class * extends android.app.Application
10 | -keep public class * extends android.app.Service
11 | -keep public class * extends android.content.BroadcastReceiver
12 | -keep public class * extends android.content.ContentProvider
13 | -keep public class * extends android.app.backup.BackupAgentHelper
14 | -keep public class * extends android.preference.Preference
15 | -keep public class com.android.vending.licensing.ILicensingService
16 |
17 | -keepclasseswithmembernames class * {
18 | native ;
19 | }
20 |
21 | -keepclasseswithmembernames class * {
22 | public (android.content.Context, android.util.AttributeSet);
23 | }
24 |
25 | -keepclasseswithmembernames class * {
26 | public (android.content.Context, android.util.AttributeSet, int);
27 | }
28 |
29 | -keepclassmembers enum * {
30 | public static **[] values();
31 | public static ** valueOf(java.lang.String);
32 | }
33 |
34 | -keep class * implements android.os.Parcelable {
35 | public static final android.os.Parcelable$Creator *;
36 | }
37 |
--------------------------------------------------------------------------------
/res.tar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/res.tar
--------------------------------------------------------------------------------
/res/drawable/vpn_connected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/res/drawable/vpn_connected.png
--------------------------------------------------------------------------------
/res/drawable/vpn_disconnected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luojiesi/android-vpn-server/47abc36c075a58005a94be5970d002c96fdb5b85/res/drawable/vpn_disconnected.png
--------------------------------------------------------------------------------
/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/res/values-ar/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "خدمات الشبكة الظاهرية الخاصة (VPN)"
5 | "تم توصيل الشبكة الظاهرية الخاصة (VPN) لـ %s"
6 | "تم فصل الشبكة الظاهرية الخاصة (VPN) لـ %s"
7 | "يمكنك اللمس لإعادة الاتصال بالشبكة الظاهرية الخاصة (VPN)."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-bg/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "VPN услуги"
5 | "Връзката с VPN %s бе установена"
6 | "Връзката с VPN %s бе прекъсната"
7 | "Докоснете за повторно свързване с VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-ca/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "Serveis VPN"
5 | "VPN %s connectada"
6 | "VPN %s desconnectada"
7 | "Toqueu-ho per tornar-vos a connectar a una VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-cs/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "Služby VPN"
5 | "Síť VPN %s je připojena"
6 | "Síť VPN %s odpojena"
7 | "Dotykem se znovu připojíte k síti VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-da/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "VPN-tjenester"
5 | "%s VPN forbundet"
6 | "%s VPN afbrudt"
7 | "Tryk for at oprette forbindelse til et VPN igen."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-de/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "VPN-Dienste"
5 | "%s mit VPN verbunden"
6 | "%s von VPN getrennt"
7 | "Zur Wiederherstellung der Verbindung mit einem VPN berühren"
8 |
9 |
--------------------------------------------------------------------------------
/res/values-el/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "Υπηρεσίες VPN"
5 | "Το VPN %s συνδέθηκε"
6 | "Το VPN %s αποσυνδέθηκε"
7 | "Πατήστε για να επανασυνδεθείτε σε ένα VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-en-rGB/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "VPN Services"
5 | "%s VPN connected"
6 | "%s VPN disconnected"
7 | "Touch to reconnect to a VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-es-rUS/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | VPN Services
5 | VPN Services
6 |
7 | %s VPN connected
8 | %s VPN disconnected
9 | Touch to reconnect to a VPN.
10 | pptp_vpn_description
11 | l2tp_vpn_description
12 | l2tp_ipsec_psk_vpn_description
13 | l2tp_ipsec_crt_vpn_description
14 |
15 |
--------------------------------------------------------------------------------
/res/values-es/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "Servicios VPN"
5 | "VPN %s conectada"
6 | "VPN %s desconectada"
7 | "Toca para volver a conectarte a una red VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-fa/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "سرویس های VPN"
5 | "%s VPN وصل شد"
6 | "%s VPN قطع شد"
7 | "برای اتصال مجدد به VPN لمس کنید."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-fi/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "VPN-palvelut"
5 | "%s: VPN-yhteys muodostettu"
6 | "%s: VPN-yhteys katkaistu"
7 | "Yhdistä VPN-verkkoon uudelleen koskettamalla."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "Services VPN"
5 | "VPN %s connecté"
6 | "VPN %s déconnecté"
7 | "Touchez l\'écran pour vous reconnecter à un VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-hr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "VPN usluge"
5 | "%s VPN priključen"
6 | "%s VPN je isključen"
7 | "Dotaknite za ponovno povezivanje s VPN-om."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-hu/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "VPN-szolgáltatások"
5 | "Kapcsolódva a(z) %s virtuális magánhálózathoz"
6 | "Kapcsolat bontva a(z) %s virtuális magánhálózattal"
7 | "Érintse meg az újracsatlakozáshoz."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-in/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "Layanan VPN"
5 | "VPN %s terhubung"
6 | "VPN %s terputus"
7 | "Sentuh untuk terhubung kembali ke suatu VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-it/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "Servizi VPN"
5 | "VPN %s collegata"
6 | "VPN %s scollegata"
7 | "Tocca per riconnetterti a una rete VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-iw/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "שירותי VPN"
5 | "VPN של %s מחובר"
6 | "VPN של %s נותק"
7 | "גע כדי להתחבר שוב ל-VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-ja/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "VPNサービス"
5 | "%s VPNが接続されました"
6 | "%s VPNが切断されました"
7 | "タップしてVPNに再接続してください。"
8 |
9 |
--------------------------------------------------------------------------------
/res/values-ko/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "VPN 서비스"
5 | "%s VPN 연결됨"
6 | "%s VPN 연결 끊김"
7 | "VPN에 다시 연결하려면 터치하세요."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-lt/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "VPT paslaugos"
5 | "%s VPT prijungtas"
6 | "%s VPT atjungtas"
7 | "Palieskite, kad būtų iš naujo sujungta su VPT."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-lv/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "VPN pakalpojumi"
5 | "%s VPN ir savienots"
6 | "%s VPN ir atvienots"
7 | "Pieskarieties, lai atkārtoti izveidotu savienojumu ar VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-nb/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "VPN-tjenester"
5 | "Koblet til VPNet %s"
6 | "Koblet fra VPNet %s"
7 | "Trykk for å koble til et VPN på nytt"
8 |
9 |
--------------------------------------------------------------------------------
/res/values-nl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "VPN-services"
5 | "%s verbonden via VPN"
6 | "VPN-verbinding met %s verbroken"
7 | "Raak aan om opnieuw verbinding te maken met een VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-pl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "Usługi VPN"
5 | "Połączono z siecią VPN %s"
6 | "Rozłączono z siecią VPN %s"
7 | "Dotknij, aby ponownie połączyć się z siecią VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-pt-rPT/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "Serviços VPN"
5 | "VPN %s ligado"
6 | "VPN %s desligado"
7 | "Toque para voltar a ligar a uma VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-pt/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "Serviços de VPN"
5 | "VPN de %s conectada"
6 | "VPN de %s desconectada"
7 | "Toque para reconectar-se a uma VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-rm/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "Servetschs VPN"
5 | "VPN %s connectà"
6 | "VPN %s deconnectà"
7 | "Tutgar per reconnectar ad in VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-ro/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "Servicii VPN"
5 | "VPN %s conectat"
6 | "VPN %s deconectat"
7 | "Atingeţi pentru a vă reconecta la o reţea VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-ru/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "Службы VPN"
5 | "Сеть VPN (%s) подключена"
6 | "Сеть VPN (%s) отключена"
7 | "Нажмите, чтобы повторно подключиться к VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-sk/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "Služby VPN"
5 | "Sieť VPN %s je pripojená"
6 | "Sieť VPN %s odpojená"
7 | "Dotykom sa znova pripojíte k sieti VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-sl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "Storitve VPN"
5 | "VPN profila %s je povezan"
6 | "VPN profila %s je izklopljen"
7 | "Dotaknite se, če želite preklopiti v navidezno zasebno omrežje."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-sr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "VPN услуге"
5 | "%s VPN веза је успостављена"
6 | "%s VPN веза је прекинута"
7 | "Додирните да бисте се поново повезали са VPN-ом."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-sv/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "VPN-tjänster"
5 | "%s VPN anslutet"
6 | "%s VPN frånkopplat"
7 | "Tryck här om du vill återansluta till ett VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-th/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "บริการ VPN"
5 | "%s เชื่อมต่อ VPN แล้ว"
6 | "%s ตัดการเชื่อมต่อ VPN แล้ว"
7 | "แตะเพื่อเชื่อมต่อกับ VPN อีกครั้ง"
8 |
9 |
--------------------------------------------------------------------------------
/res/values-tl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "Mga serbisyo ng VPN"
5 | "Hindi konektado ang %s VPN"
6 | "Hindi konektado ang %s VPN"
7 | "Galawin upang muling kumonekta sa VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-tr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "VPN Hizmetleri"
5 | "%s VPN bağlandı"
6 | "%s VPN bağlantısı kesildi"
7 | "Bir VPN\'ye tekrar bağlanmak için dokunun."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-uk/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "Служби VPN"
5 | "%s підключ. ч-з VPN"
6 | "VPN %s роз\'єднано"
7 | "Натисн. для повт. з\'єдн. з VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-vi/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "Dịch vụ VPN"
5 | "Đã kết nối VPN %s"
6 | "Đã ngắt kết nối VPN %s"
7 | "Chạm để kết nối lại với VPN."
8 |
9 |
--------------------------------------------------------------------------------
/res/values-zh-rCN/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | VPN Services
5 | VPN Services
6 |
7 | %s VPN connected
8 | %s VPN disconnected
9 | Touch to reconnect to a VPN.
10 | pptp_vpn_description
11 | l2tp_vpn_description
12 | l2tp_ipsec_psk_vpn_description
13 | l2tp_ipsec_crt_vpn_description
14 |
15 |
--------------------------------------------------------------------------------
/res/values-zh-rTW/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | "VPN 服務"
5 | "%s VPN 已連線"
6 | "%s VPN 已中斷連線"
7 | "輕觸即可重新連線至 VPN。"
8 |
9 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | VPN Services
5 | android-vpn-server
6 |
7 | %s VPN connected
8 | %s VPN disconnected
9 | Touch to reconnect to a VPN.
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/android/net/vpn/IVpnService.aidl:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package android.net.vpn;
18 |
19 | import android.net.vpn.VpnProfile;
20 |
21 | /**
22 | * Interface to access a VPN service.
23 | * {@hide}
24 | */
25 | interface IVpnService {
26 | /**
27 | * Sets up the VPN connection.
28 | * @param profile the profile object
29 | * @param username the username for authentication
30 | * @param password the corresponding password for authentication
31 | */
32 | boolean connect(in VpnProfile profile, String username, String password);
33 |
34 | /**
35 | * Tears down the VPN connection.
36 | */
37 | void disconnect();
38 |
39 | /**
40 | * Makes the service broadcast the connectivity state.
41 | */
42 | void checkStatus(in VpnProfile profile);
43 | }
44 |
--------------------------------------------------------------------------------
/src/android/net/vpn/L2tpIpsecProfile.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package android.net.vpn;
18 |
19 | import android.os.Parcel;
20 |
21 | /**
22 | * The profile for certificate-based L2TP-over-IPSec type of VPN.
23 | * {@hide}
24 | */
25 | public class L2tpIpsecProfile extends L2tpProfile {
26 | private static final long serialVersionUID = 1L;
27 |
28 | private String mUserCertificate;
29 | private String mCaCertificate;
30 |
31 | @Override
32 | public VpnType getType() {
33 | return VpnType.L2TP_IPSEC;
34 | }
35 |
36 | public void setCaCertificate(String name) {
37 | mCaCertificate = name;
38 | }
39 |
40 | public String getCaCertificate() {
41 | return mCaCertificate;
42 | }
43 |
44 | public void setUserCertificate(String name) {
45 | mUserCertificate = name;
46 | }
47 |
48 | public String getUserCertificate() {
49 | return mUserCertificate;
50 | }
51 |
52 | @Override
53 | protected void readFromParcel(Parcel in) {
54 | super.readFromParcel(in);
55 | mCaCertificate = in.readString();
56 | mUserCertificate = in.readString();
57 | }
58 |
59 | @Override
60 | public void writeToParcel(Parcel parcel, int flags) {
61 | super.writeToParcel(parcel, flags);
62 | parcel.writeString(mCaCertificate);
63 | parcel.writeString(mUserCertificate);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/android/net/vpn/L2tpIpsecPskProfile.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package android.net.vpn;
18 |
19 | import android.os.Parcel;
20 |
21 | /**
22 | * The profile for pre-shared-key-based L2TP-over-IPSec type of VPN.
23 | * {@hide}
24 | */
25 | public class L2tpIpsecPskProfile extends L2tpProfile {
26 | private static final long serialVersionUID = 1L;
27 |
28 | private String mPresharedKey;
29 |
30 | @Override
31 | public VpnType getType() {
32 | return VpnType.L2TP_IPSEC_PSK;
33 | }
34 |
35 | public void setPresharedKey(String key) {
36 | mPresharedKey = key;
37 | }
38 |
39 | public String getPresharedKey() {
40 | return mPresharedKey;
41 | }
42 |
43 | @Override
44 | protected void readFromParcel(Parcel in) {
45 | super.readFromParcel(in);
46 | mPresharedKey = in.readString();
47 | }
48 |
49 | @Override
50 | public void writeToParcel(Parcel parcel, int flags) {
51 | super.writeToParcel(parcel, flags);
52 | parcel.writeString(mPresharedKey);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/android/net/vpn/L2tpProfile.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package android.net.vpn;
18 |
19 | import android.os.Parcel;
20 |
21 | /**
22 | * The profile for L2TP type of VPN.
23 | * {@hide}
24 | */
25 | public class L2tpProfile extends VpnProfile {
26 | private static final long serialVersionUID = 1L;
27 |
28 | private boolean mSecret;
29 | private String mSecretString;
30 |
31 | @Override
32 | public VpnType getType() {
33 | return VpnType.L2TP;
34 | }
35 |
36 | /**
37 | * Enables/disables the secret for authenticating tunnel connection.
38 | */
39 | public void setSecretEnabled(boolean enabled) {
40 | mSecret = enabled;
41 | }
42 |
43 | public boolean isSecretEnabled() {
44 | return mSecret;
45 | }
46 |
47 | public void setSecretString(String secret) {
48 | mSecretString = secret;
49 | }
50 |
51 | public String getSecretString() {
52 | return mSecretString;
53 | }
54 |
55 | @Override
56 | protected void readFromParcel(Parcel in) {
57 | super.readFromParcel(in);
58 | mSecret = in.readInt() > 0;
59 | mSecretString = in.readString();
60 | }
61 |
62 | @Override
63 | public void writeToParcel(Parcel parcel, int flags) {
64 | super.writeToParcel(parcel, flags);
65 | parcel.writeInt(mSecret ? 1 : 0);
66 | parcel.writeString(mSecretString);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/android/net/vpn/PptpProfile.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package android.net.vpn;
18 |
19 | import android.os.Parcel;
20 |
21 | /**
22 | * The profile for PPTP type of VPN.
23 | * {@hide}
24 | */
25 | public class PptpProfile extends VpnProfile {
26 | private static final long serialVersionUID = 1L;
27 | private boolean mEncryption = true;
28 |
29 | @Override
30 | public VpnType getType() {
31 | return VpnType.PPTP;
32 | }
33 |
34 | /**
35 | * Enables/disables the encryption for PPTP tunnel.
36 | */
37 | public void setEncryptionEnabled(boolean enabled) {
38 | mEncryption = enabled;
39 | }
40 |
41 | public boolean isEncryptionEnabled() {
42 | return mEncryption;
43 | }
44 |
45 | @Override
46 | protected void readFromParcel(Parcel in) {
47 | super.readFromParcel(in);
48 | mEncryption = in.readInt() > 0;
49 | }
50 |
51 | @Override
52 | public void writeToParcel(Parcel parcel, int flags) {
53 | super.writeToParcel(parcel, flags);
54 | parcel.writeInt(mEncryption ? 1 : 0);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/android/net/vpn/VpnManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package android.net.vpn;
18 |
19 | import java.io.File;
20 |
21 | import android.content.BroadcastReceiver;
22 | import android.content.Context;
23 | import android.content.Intent;
24 | import android.content.IntentFilter;
25 | import android.content.ServiceConnection;
26 | import android.os.Environment;
27 | import android.os.SystemProperties;
28 | import android.util.Log;
29 |
30 | /**
31 | * The class provides interface to manage all VPN-related tasks, including:
32 | *
33 | * - The list of supported VPN types.
34 | *
- API's to start/stop the service of a particular type.
35 | *
- API's to start the settings activity.
36 | *
- API's to create a profile.
37 | *
- API's to register/unregister a connectivity receiver and the keys to
38 | * access the fields in a connectivity broadcast event.
39 | *
40 | * {@hide}
41 | */
42 | public class VpnManager {
43 | // Action for broadcasting a connectivity state.
44 | private static final String ACTION_VPN_CONNECTIVITY = "vpn.connectivity";
45 | /** Key to the profile name of a connectivity broadcast event. */
46 | public static final String BROADCAST_PROFILE_NAME = "profile_name";
47 | /** Key to the connectivity state of a connectivity broadcast event. */
48 | public static final String BROADCAST_CONNECTION_STATE = "connection_state";
49 | /** Key to the error code of a connectivity broadcast event. */
50 | public static final String BROADCAST_ERROR_CODE = "err";
51 | /** Error code to indicate an error from authentication. */
52 | public static final int VPN_ERROR_AUTH = 51;
53 | /** Error code to indicate the connection attempt failed. */
54 | public static final int VPN_ERROR_CONNECTION_FAILED = 101;
55 | /** Error code to indicate the server is not known. */
56 | public static final int VPN_ERROR_UNKNOWN_SERVER = 102;
57 | /** Error code to indicate an error from challenge response. */
58 | public static final int VPN_ERROR_CHALLENGE = 5;
59 | /** Error code to indicate an error of remote server hanging up. */
60 | public static final int VPN_ERROR_REMOTE_HUNG_UP = 7;
61 | /** Error code to indicate an error of remote PPP server hanging up. */
62 | public static final int VPN_ERROR_REMOTE_PPP_HUNG_UP = 48;
63 | /** Error code to indicate a PPP negotiation error. */
64 | public static final int VPN_ERROR_PPP_NEGOTIATION_FAILED = 42;
65 | /** Error code to indicate an error of losing connectivity. */
66 | public static final int VPN_ERROR_CONNECTION_LOST = 103;
67 | /** Largest error code used by VPN. */
68 | public static final int VPN_ERROR_LARGEST = 200;
69 | /** Error code to indicate a successful connection. */
70 | public static final int VPN_ERROR_NO_ERROR = 0;
71 |
72 | public static final String PROFILES_PATH = "/misc/vpn/profiles";
73 |
74 | private static final String PACKAGE_PREFIX =
75 | VpnManager.class.getPackage().getName() + ".";
76 |
77 | // Action to start VPN service
78 | private static final String ACTION_VPN_SERVICE = PACKAGE_PREFIX + "SERVICE";
79 |
80 | // Action to start VPN settings
81 | private static final String ACTION_VPN_SETTINGS =
82 | PACKAGE_PREFIX + "SETTINGS";
83 |
84 | public static final String TAG = VpnManager.class.getSimpleName();
85 |
86 | // TODO(oam): Test VPN when EFS is enabled (will do later)...
87 | public static String getProfilePath() {
88 | return Environment.getDataDirectory().getPath() + PROFILES_PATH;
89 | }
90 |
91 | /**
92 | * Returns all supported VPN types.
93 | */
94 | public static VpnType[] getSupportedVpnTypes() {
95 | return VpnType.values();
96 | }
97 |
98 | private Context mContext;
99 |
100 | /**
101 | * Creates a manager object with the specified context.
102 | */
103 | public VpnManager(Context c) {
104 | mContext = c;
105 | }
106 |
107 | /**
108 | * Creates a VPN profile of the specified type.
109 | *
110 | * @param type the VPN type
111 | * @return the profile object
112 | */
113 | public VpnProfile createVpnProfile(VpnType type) {
114 | return createVpnProfile(type, false);
115 | }
116 |
117 | /**
118 | * Creates a VPN profile of the specified type.
119 | *
120 | * @param type the VPN type
121 | * @param customized true if the profile is custom made
122 | * @return the profile object
123 | */
124 | public VpnProfile createVpnProfile(VpnType type, boolean customized) {
125 | try {
126 | VpnProfile p = (VpnProfile) type.getProfileClass().newInstance();
127 | p.setCustomized(customized);
128 | return p;
129 | } catch (InstantiationException e) {
130 | return null;
131 | } catch (IllegalAccessException e) {
132 | return null;
133 | }
134 | }
135 |
136 | /**
137 | * Starts the VPN service to establish VPN connection.
138 | */
139 | public void startVpnService() {
140 | mContext.startService(new Intent(ACTION_VPN_SERVICE));
141 | }
142 |
143 | /**
144 | * Stops the VPN service.
145 | */
146 | public void stopVpnService() {
147 | mContext.stopService(new Intent(ACTION_VPN_SERVICE));
148 | }
149 |
150 | /**
151 | * Binds the specified ServiceConnection with the VPN service.
152 | */
153 | public boolean bindVpnService(ServiceConnection c) {
154 | if (!mContext.bindService(new Intent(ACTION_VPN_SERVICE), c, 0)) {
155 | Log.w(TAG, "failed to connect to VPN service");
156 | return false;
157 | } else {
158 | Log.d(TAG, "succeeded to connect to VPN service");
159 | return true;
160 | }
161 | }
162 |
163 | /** Broadcasts the connectivity state of the specified profile. */
164 | public void broadcastConnectivity(String profileName, VpnState s) {
165 | broadcastConnectivity(profileName, s, VPN_ERROR_NO_ERROR);
166 | }
167 |
168 | /** Broadcasts the connectivity state with an error code. */
169 | public void broadcastConnectivity(String profileName, VpnState s,
170 | int error) {
171 | Intent intent = new Intent(ACTION_VPN_CONNECTIVITY);
172 | intent.putExtra(BROADCAST_PROFILE_NAME, profileName);
173 | intent.putExtra(BROADCAST_CONNECTION_STATE, s);
174 | if (error != VPN_ERROR_NO_ERROR) {
175 | intent.putExtra(BROADCAST_ERROR_CODE, error);
176 | }
177 | mContext.sendBroadcast(intent);
178 | }
179 |
180 | public void registerConnectivityReceiver(BroadcastReceiver r) {
181 | IntentFilter filter = new IntentFilter();
182 | filter.addAction(VpnManager.ACTION_VPN_CONNECTIVITY);
183 | mContext.registerReceiver(r, filter);
184 | }
185 |
186 | public void unregisterConnectivityReceiver(BroadcastReceiver r) {
187 | mContext.unregisterReceiver(r);
188 | }
189 |
190 | /** Starts the VPN settings activity. */
191 | public void startSettingsActivity() {
192 | Intent intent = new Intent(ACTION_VPN_SETTINGS);
193 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
194 | mContext.startActivity(intent);
195 | }
196 |
197 | /** Creates an intent to start the VPN settings activity. */
198 | public Intent createSettingsActivityIntent() {
199 | Intent intent = new Intent(ACTION_VPN_SETTINGS);
200 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
201 | return intent;
202 | }
203 | }
204 |
--------------------------------------------------------------------------------
/src/android/net/vpn/VpnProfile.aidl:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package android.net.vpn;
18 |
19 | parcelable VpnProfile;
20 |
--------------------------------------------------------------------------------
/src/android/net/vpn/VpnProfile.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package android.net.vpn;
18 |
19 | import android.content.Context;
20 | import android.os.Parcel;
21 | import android.os.Parcelable;
22 |
23 | import java.io.IOException;
24 | import java.io.Serializable;
25 |
26 | /**
27 | * A VPN profile.
28 | * {@hide}
29 | */
30 | public abstract class VpnProfile implements Parcelable, Serializable {
31 | private static final long serialVersionUID = 1L;
32 | private String mName; // unique display name
33 | private String mId; // unique identifier
34 | private String mServerName; // VPN server name
35 | private String mDomainSuffices; // space separated list
36 | private String mRouteList; // space separated list
37 | private String mSavedUsername;
38 | private boolean mIsCustomized;
39 | private transient VpnState mState = VpnState.IDLE;
40 |
41 | /** Sets a user-friendly name for this profile. */
42 | public void setName(String name) {
43 | mName = name;
44 | }
45 |
46 | public String getName() {
47 | return mName;
48 | }
49 |
50 | /**
51 | * Sets an ID for this profile. The caller should make sure the
52 | * uniqueness of the ID.
53 | */
54 | public void setId(String id) {
55 | mId = id;
56 | }
57 |
58 | public String getId() {
59 | return mId;
60 | }
61 |
62 | /**
63 | * Sets the name of the VPN server. Used for DNS lookup.
64 | */
65 | public void setServerName(String name) {
66 | mServerName = name;
67 | }
68 |
69 | public String getServerName() {
70 | return mServerName;
71 | }
72 |
73 | /**
74 | * Sets the domain suffices for DNS resolution.
75 | *
76 | * @param entries a comma-separated list of domain suffices
77 | */
78 | public void setDomainSuffices(String entries) {
79 | mDomainSuffices = entries;
80 | }
81 |
82 | public String getDomainSuffices() {
83 | return mDomainSuffices;
84 | }
85 |
86 | /**
87 | * Sets the routing info for this VPN connection.
88 | *
89 | * @param entries a comma-separated list of routes; each entry is in the
90 | * format of "(network address)/(network mask)"
91 | */
92 | public void setRouteList(String entries) {
93 | mRouteList = entries;
94 | }
95 |
96 | public String getRouteList() {
97 | return mRouteList;
98 | }
99 |
100 | public void setSavedUsername(String name) {
101 | mSavedUsername = name;
102 | }
103 |
104 | public String getSavedUsername() {
105 | return mSavedUsername;
106 | }
107 |
108 | public void setState(VpnState state) {
109 | mState = state;
110 | }
111 |
112 | public VpnState getState() {
113 | return ((mState == null) ? VpnState.IDLE : mState);
114 | }
115 |
116 | public boolean isIdle() {
117 | return (mState == VpnState.IDLE);
118 | }
119 |
120 | /**
121 | * Returns whether this profile is custom made (as opposed to being
122 | * created by provided user interface).
123 | */
124 | public boolean isCustomized() {
125 | return mIsCustomized;
126 | }
127 |
128 | /**
129 | * Returns the VPN type of the profile.
130 | */
131 | public abstract VpnType getType();
132 |
133 | void setCustomized(boolean customized) {
134 | mIsCustomized = customized;
135 | }
136 |
137 | protected void readFromParcel(Parcel in) {
138 | mName = in.readString();
139 | mId = in.readString();
140 | mServerName = in.readString();
141 | mDomainSuffices = in.readString();
142 | mRouteList = in.readString();
143 | mSavedUsername = in.readString();
144 | }
145 |
146 | public static final Parcelable.Creator CREATOR =
147 | new Parcelable.Creator() {
148 | public VpnProfile createFromParcel(Parcel in) {
149 | VpnType type = Enum.valueOf(VpnType.class, in.readString());
150 | boolean customized = in.readInt() > 0;
151 | VpnProfile p = new VpnManager(null).createVpnProfile(type,
152 | customized);
153 | if (p == null) return null;
154 | p.readFromParcel(in);
155 | return p;
156 | }
157 |
158 | public VpnProfile[] newArray(int size) {
159 | return new VpnProfile[size];
160 | }
161 | };
162 |
163 | public void writeToParcel(Parcel parcel, int flags) {
164 | parcel.writeString(getType().toString());
165 | parcel.writeInt(mIsCustomized ? 1 : 0);
166 | parcel.writeString(mName);
167 | parcel.writeString(mId);
168 | parcel.writeString(mServerName);
169 | parcel.writeString(mDomainSuffices);
170 | parcel.writeString(mRouteList);
171 | parcel.writeString(mSavedUsername);
172 | }
173 |
174 | public int describeContents() {
175 | return 0;
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/src/android/net/vpn/VpnState.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package android.net.vpn;
18 |
19 | /**
20 | * Enumeration of all VPN states.
21 | *
22 | * A normal VPN connection lifetime starts in {@link IDLE}. When a new
23 | * connection is about to be set up, it goes to {@link CONNECTING} and then
24 | * {@link CONNECTED} if successful; back to {@link IDLE} if failed.
25 | * When the connection is about to be torn down, it goes to
26 | * {@link DISCONNECTING} and then {@link IDLE}.
27 | * {@link CANCELLED} is a state when a VPN connection attempt is aborted, and
28 | * is in transition to {@link IDLE}.
29 | * The {@link UNUSABLE} state indicates that the profile is not in a state for
30 | * connecting due to possibly the integrity of the fields or another profile is
31 | * connecting etc.
32 | * The {@link UNKNOWN} state indicates that the profile state is to be
33 | * determined.
34 | * {@hide}
35 | */
36 | public enum VpnState {
37 | CONNECTING, DISCONNECTING, CANCELLED, CONNECTED, IDLE, UNUSABLE, UNKNOWN
38 | }
39 |
--------------------------------------------------------------------------------
/src/android/net/vpn/VpnTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 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 |
17 | package android.net.vpn;
18 |
19 | import android.content.BroadcastReceiver;
20 | import android.content.Context;
21 | import android.content.Intent;
22 | import android.net.vpn.L2tpProfile;
23 | import android.net.vpn.L2tpIpsecProfile;
24 | import android.net.vpn.L2tpIpsecPskProfile;
25 | import android.net.vpn.PptpProfile;
26 | import android.net.vpn.VpnManager;
27 | import android.net.vpn.VpnProfile;
28 | import android.net.vpn.VpnState;
29 | import android.net.vpn.VpnType;
30 | import android.os.ConditionVariable;
31 | import android.os.Parcel;
32 | import android.test.AndroidTestCase;
33 | import android.test.suitebuilder.annotation.SmallTest;
34 | import android.text.TextUtils;
35 |
36 | /**
37 | * Unit test class to test VPN api
38 | * Use the below command to run the vpn unit test only
39 | * runtest vpntest or
40 | * adb shell am instrument -e class 'com.android.unit_tests.VpnTest'
41 | * -w com.android.unit_tests/android.test.InstrumentationTestRunner
42 | */
43 | public class VpnTest extends AndroidTestCase {
44 | private static final String NAME = "a name";
45 | private static final String SERVER_NAME = "a server name";
46 | private static final String ID = "some id";
47 | private static final String SUFFICES = "some suffices";
48 | private static final String ROUTES = "some routes";
49 | private static final String SAVED_NAME = "some name";
50 |
51 | @Override
52 | public void setUp() {
53 | }
54 |
55 | @Override
56 | public void tearDown() {
57 | }
58 |
59 | @SmallTest
60 | public void testVpnType() {
61 | testVpnType(VpnType.L2TP);
62 | testVpnType(VpnType.L2TP_IPSEC);
63 | testVpnType(VpnType.L2TP_IPSEC_PSK);
64 | testVpnType(VpnType.PPTP);
65 | }
66 |
67 | @SmallTest
68 | public void testVpnProfile() {
69 | VpnState state = VpnState.CONNECTING;
70 | testVpnProfile(createTestProfile(state), state);
71 | }
72 |
73 | @SmallTest
74 | public void testGetType() {
75 | assertEquals(VpnType.L2TP, new L2tpProfile().getType());
76 | assertEquals(VpnType.L2TP_IPSEC, new L2tpIpsecProfile().getType());
77 | assertEquals(VpnType.L2TP_IPSEC_PSK,
78 | new L2tpIpsecPskProfile().getType());
79 | assertEquals(VpnType.PPTP, new PptpProfile().getType());
80 | }
81 |
82 | @SmallTest
83 | public void testVpnTypes() {
84 | assertTrue(VpnManager.getSupportedVpnTypes().length > 0);
85 | }
86 |
87 | @SmallTest
88 | public void testGetTypeFromManager() {
89 | VpnManager m = new VpnManager(getContext());
90 | VpnType[] types = VpnManager.getSupportedVpnTypes();
91 | for (VpnType t : types) {
92 | assertEquals(t, m.createVpnProfile(t).getType());
93 | }
94 | }
95 |
96 | @SmallTest
97 | public void testParcelable() {
98 | VpnProfile p = createTestProfile(VpnState.CONNECTED);
99 | Parcel parcel = Parcel.obtain();
100 | p.writeToParcel(parcel, 0);
101 | parcel.setDataPosition(0);
102 |
103 | // VpnState is transient and not saved in the parcel
104 | testVpnProfile(VpnProfile.CREATOR.createFromParcel(parcel), null);
105 | }
106 |
107 | @SmallTest
108 | public void testReceiver() {
109 | final String profileName = "whatever";
110 | final VpnState state = VpnState.DISCONNECTING;
111 | final ConditionVariable cv = new ConditionVariable();
112 | cv.close();
113 | BroadcastReceiver r = new BroadcastReceiver() {
114 | public void onReceive(Context c, Intent i) {
115 | assertEquals(profileName,
116 | i.getStringExtra(VpnManager.BROADCAST_PROFILE_NAME));
117 | assertEquals(state, i.getSerializableExtra(
118 | VpnManager.BROADCAST_CONNECTION_STATE));
119 | cv.open();
120 | }
121 | };
122 |
123 | VpnManager m = new VpnManager(getContext());
124 | m.registerConnectivityReceiver(r);
125 | m.broadcastConnectivity(profileName, state);
126 |
127 | // fail it if onReceive() doesn't get executed in 5 sec
128 | assertTrue(cv.block(5000));
129 | }
130 |
131 | private void testVpnType(VpnType type) {
132 | assertFalse(TextUtils.isEmpty(type.getDisplayName()));
133 | assertNotNull(type.getProfileClass());
134 | }
135 |
136 | private VpnProfile createTestProfile(VpnState state) {
137 | VpnProfile p = new L2tpProfile();
138 | p.setName(NAME);
139 | p.setServerName(SERVER_NAME);
140 | p.setId(ID);
141 | p.setDomainSuffices(SUFFICES);
142 | p.setRouteList(ROUTES);
143 | p.setSavedUsername(SAVED_NAME);
144 | p.setState(state);
145 | return p;
146 | }
147 |
148 | private void testVpnProfile(VpnProfile p, VpnState state) {
149 | assertEquals(NAME, p.getName());
150 | assertEquals(SERVER_NAME, p.getServerName());
151 | assertEquals(ID, p.getId());
152 | assertEquals(SUFFICES, p.getDomainSuffices());
153 | assertEquals(ROUTES, p.getRouteList());
154 | assertEquals(SAVED_NAME, p.getSavedUsername());
155 | if (state != null) assertEquals(state, p.getState());
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/src/android/net/vpn/VpnType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package android.net.vpn;
18 |
19 | import com.android.server.vpn.R;
20 |
21 | /**
22 | * Enumeration of all supported VPN types.
23 | * {@hide}
24 | */
25 | public enum VpnType {
26 |
27 | PPTP("PPTP", R.string.pptp_vpn_description, PptpProfile.class),
28 | L2TP("L2TP", R.string.l2tp_vpn_description, L2tpProfile.class),
29 | L2TP_IPSEC_PSK("L2TP/IPSec PSK", R.string.l2tp_ipsec_psk_vpn_description,
30 | L2tpIpsecPskProfile.class),
31 | L2TP_IPSEC("L2TP/IPSec CRT", R.string.l2tp_ipsec_crt_vpn_description,
32 | L2tpIpsecProfile.class);
33 |
34 | VpnType(String displayName, int descriptionId,
35 | Class extends VpnProfile> klass) {
36 | mDisplayName = displayName;
37 | mDescriptionId = descriptionId;
38 | mClass = klass;
39 | }
40 |
41 | private String mDisplayName;
42 | private int mDescriptionId;
43 | private Class extends VpnProfile> mClass;
44 |
45 | public String getDisplayName() {
46 | return mDisplayName;
47 | }
48 |
49 | public int getDescriptionId() {
50 | return mDescriptionId;
51 | }
52 |
53 | public Class extends VpnProfile> getProfileClass() {
54 | return mClass;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/android/os/SystemProperties.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2006 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 |
17 | package android.os;
18 |
19 |
20 | /**
21 | * Gives access to the system properties store. The system properties
22 | * store contains a list of string key-value pairs.
23 | *
24 | * {@hide}
25 | */
26 | public class SystemProperties
27 | {
28 | public static final int PROP_NAME_MAX = 31;
29 | public static final int PROP_VALUE_MAX = 91;
30 |
31 | private static native String native_get(String key);
32 | private static native String native_get(String key, String def);
33 | private static native int native_get_int(String key, int def);
34 | private static native long native_get_long(String key, long def);
35 | private static native boolean native_get_boolean(String key, boolean def);
36 | private static native void native_set(String key, String def);
37 |
38 | /**
39 | * Get the value for the given key.
40 | * @return an empty string if the key isn't found
41 | * @throws IllegalArgumentException if the key exceeds 32 characters
42 | */
43 | public static String get(String key) {
44 | if (key.length() > PROP_NAME_MAX) {
45 | throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
46 | }
47 | return native_get(key);
48 | }
49 |
50 | /**
51 | * Get the value for the given key.
52 | * @return if the key isn't found, return def if it isn't null, or an empty string otherwise
53 | * @throws IllegalArgumentException if the key exceeds 32 characters
54 | */
55 | public static String get(String key, String def) {
56 | if (key.length() > PROP_NAME_MAX) {
57 | throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
58 | }
59 | return native_get(key, def);
60 | }
61 |
62 | /**
63 | * Get the value for the given key, and return as an integer.
64 | * @param key the key to lookup
65 | * @param def a default value to return
66 | * @return the key parsed as an integer, or def if the key isn't found or
67 | * cannot be parsed
68 | * @throws IllegalArgumentException if the key exceeds 32 characters
69 | */
70 | public static int getInt(String key, int def) {
71 | if (key.length() > PROP_NAME_MAX) {
72 | throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
73 | }
74 | return native_get_int(key, def);
75 | }
76 |
77 | /**
78 | * Get the value for the given key, and return as a long.
79 | * @param key the key to lookup
80 | * @param def a default value to return
81 | * @return the key parsed as a long, or def if the key isn't found or
82 | * cannot be parsed
83 | * @throws IllegalArgumentException if the key exceeds 32 characters
84 | */
85 | public static long getLong(String key, long def) {
86 | if (key.length() > PROP_NAME_MAX) {
87 | throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
88 | }
89 | return native_get_long(key, def);
90 | }
91 |
92 | /**
93 | * Get the value for the given key, returned as a boolean.
94 | * Values 'n', 'no', '0', 'false' or 'off' are considered false.
95 | * Values 'y', 'yes', '1', 'true' or 'on' are considered true.
96 | * (case insensitive).
97 | * If the key does not exist, or has any other value, then the default
98 | * result is returned.
99 | * @param key the key to lookup
100 | * @param def a default value to return
101 | * @return the key parsed as a boolean, or def if the key isn't found or is
102 | * not able to be parsed as a boolean.
103 | * @throws IllegalArgumentException if the key exceeds 32 characters
104 | */
105 | public static boolean getBoolean(String key, boolean def) {
106 | if (key.length() > PROP_NAME_MAX) {
107 | throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
108 | }
109 | return native_get_boolean(key, def);
110 | }
111 |
112 | /**
113 | * Set the value for the given key.
114 | * @throws IllegalArgumentException if the key exceeds 32 characters
115 | * @throws IllegalArgumentException if the value exceeds 92 characters
116 | */
117 | public static void set(String key, String val) {
118 | if (key.length() > PROP_NAME_MAX) {
119 | throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
120 | }
121 | if (val != null && val.length() > PROP_VALUE_MAX) {
122 | throw new IllegalArgumentException("val.length > " +
123 | PROP_VALUE_MAX);
124 | }
125 | native_set(key, val);
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/src/android/security/Credentials.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 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 |
17 | package android.security;
18 |
19 | import android.content.ActivityNotFoundException;
20 | import android.content.Context;
21 | import android.content.Intent;
22 | import android.util.Log;
23 |
24 | import java.security.KeyPair;
25 |
26 | /**
27 | * {@hide}
28 | */
29 | public class Credentials {
30 | private static final String LOGTAG = "Credentials";
31 |
32 | public static final String UNLOCK_ACTION = "android.credentials.UNLOCK";
33 |
34 | public static final String INSTALL_ACTION = "android.credentials.INSTALL";
35 |
36 | public static final String SYSTEM_INSTALL_ACTION = "android.credentials.SYSTEM_INSTALL";
37 |
38 | /** Key prefix for CA certificates. */
39 | public static final String CA_CERTIFICATE = "CACERT_";
40 |
41 | /** Key prefix for user certificates. */
42 | public static final String USER_CERTIFICATE = "USRCERT_";
43 |
44 | /** Key prefix for user private keys. */
45 | public static final String USER_PRIVATE_KEY = "USRPKEY_";
46 |
47 | /** Key prefix for VPN. */
48 | public static final String VPN = "VPN_";
49 |
50 | /** Key prefix for WIFI. */
51 | public static final String WIFI = "WIFI_";
52 |
53 | /** Data type for public keys. */
54 | public static final String PUBLIC_KEY = "KEY";
55 |
56 | /** Data type for private keys. */
57 | public static final String PRIVATE_KEY = "PKEY";
58 |
59 | /** Data type for certificates. */
60 | public static final String CERTIFICATE = "CERT";
61 |
62 | /** Data type for PKCS12. */
63 | public static final String PKCS12 = "PKCS12";
64 |
65 | private static Credentials singleton;
66 |
67 | public static Credentials getInstance() {
68 | if (singleton == null) {
69 | singleton = new Credentials();
70 | }
71 | return singleton;
72 | }
73 |
74 | public void unlock(Context context) {
75 | try {
76 | Intent intent = new Intent(UNLOCK_ACTION);
77 | context.startActivity(intent);
78 | } catch (ActivityNotFoundException e) {
79 | Log.w(LOGTAG, e.toString());
80 | }
81 | }
82 |
83 | public void install(Context context, KeyPair pair) {
84 | try {
85 | Intent intent = new Intent(INSTALL_ACTION);
86 | intent.putExtra(PRIVATE_KEY, pair.getPrivate().getEncoded());
87 | intent.putExtra(PUBLIC_KEY, pair.getPublic().getEncoded());
88 | context.startActivity(intent);
89 | } catch (ActivityNotFoundException e) {
90 | Log.w(LOGTAG, e.toString());
91 | }
92 | }
93 |
94 | public void install(Context context, String type, byte[] value) {
95 | try {
96 | Intent intent = new Intent(INSTALL_ACTION);
97 | intent.putExtra(type, value);
98 | context.startActivity(intent);
99 | } catch (ActivityNotFoundException e) {
100 | Log.w(LOGTAG, e.toString());
101 | }
102 | }
103 |
104 | public void installFromSdCard(Context context) {
105 | try {
106 | context.startActivity(new Intent(INSTALL_ACTION));
107 | } catch (ActivityNotFoundException e) {
108 | Log.w(LOGTAG, e.toString());
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/android/security/KeyStore.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 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 |
17 | package android.security;
18 |
19 | import android.net.LocalSocketAddress;
20 | import android.net.LocalSocket;
21 |
22 | import java.io.InputStream;
23 | import java.io.IOException;
24 | import java.io.OutputStream;
25 | import java.io.UnsupportedEncodingException;
26 | import java.util.ArrayList;
27 |
28 | /**
29 | * {@hide}
30 | */
31 | public class KeyStore {
32 | public static final int NO_ERROR = 1;
33 | public static final int LOCKED = 2;
34 | public static final int UNINITIALIZED = 3;
35 | public static final int SYSTEM_ERROR = 4;
36 | public static final int PROTOCOL_ERROR = 5;
37 | public static final int PERMISSION_DENIED = 6;
38 | public static final int KEY_NOT_FOUND = 7;
39 | public static final int VALUE_CORRUPTED = 8;
40 | public static final int UNDEFINED_ACTION = 9;
41 | public static final int WRONG_PASSWORD = 10;
42 |
43 | private static final LocalSocketAddress sAddress = new LocalSocketAddress(
44 | "keystore", LocalSocketAddress.Namespace.RESERVED);
45 |
46 | private int mError = NO_ERROR;
47 |
48 | private KeyStore() {}
49 |
50 | public static KeyStore getInstance() {
51 | return new KeyStore();
52 | }
53 |
54 | public int test() {
55 | execute('t');
56 | return mError;
57 | }
58 |
59 | public byte[] get(byte[] key) {
60 | ArrayList values = execute('g', key);
61 | return (values == null || values.isEmpty()) ? null : values.get(0);
62 | }
63 |
64 | public String get(String key) {
65 | byte[] value = get(getBytes(key));
66 | return (value == null) ? null : toString(value);
67 | }
68 |
69 | public boolean put(byte[] key, byte[] value) {
70 | execute('i', key, value);
71 | return mError == NO_ERROR;
72 | }
73 |
74 | public boolean put(String key, String value) {
75 | return put(getBytes(key), getBytes(value));
76 | }
77 |
78 | public boolean delete(byte[] key) {
79 | execute('d', key);
80 | return mError == NO_ERROR;
81 | }
82 |
83 | public boolean delete(String key) {
84 | return delete(getBytes(key));
85 | }
86 |
87 | public boolean contains(byte[] key) {
88 | execute('e', key);
89 | return mError == NO_ERROR;
90 | }
91 |
92 | public boolean contains(String key) {
93 | return contains(getBytes(key));
94 | }
95 |
96 | public byte[][] saw(byte[] prefix) {
97 | ArrayList values = execute('s', prefix);
98 | return (values == null) ? null : values.toArray(new byte[values.size()][]);
99 | }
100 |
101 | public String[] saw(String prefix) {
102 | byte[][] values = saw(getBytes(prefix));
103 | if (values == null) {
104 | return null;
105 | }
106 | String[] strings = new String[values.length];
107 | for (int i = 0; i < values.length; ++i) {
108 | strings[i] = toString(values[i]);
109 | }
110 | return strings;
111 | }
112 |
113 | public boolean reset() {
114 | execute('r');
115 | return mError == NO_ERROR;
116 | }
117 |
118 | public boolean password(byte[] oldPassword, byte[] newPassword) {
119 | execute('p', oldPassword, newPassword);
120 | return mError == NO_ERROR;
121 | }
122 |
123 | public boolean password(String oldPassword, String newPassword) {
124 | return password(getBytes(oldPassword), getBytes(newPassword));
125 | }
126 |
127 | public boolean password(byte[] password) {
128 | return password(password, password);
129 | }
130 |
131 | public boolean password(String password) {
132 | return password(getBytes(password));
133 | }
134 |
135 | public boolean lock() {
136 | execute('l');
137 | return mError == NO_ERROR;
138 | }
139 |
140 | public boolean unlock(byte[] password) {
141 | execute('u', password);
142 | return mError == NO_ERROR;
143 | }
144 |
145 | public boolean unlock(String password) {
146 | return unlock(getBytes(password));
147 | }
148 |
149 | public int getLastError() {
150 | return mError;
151 | }
152 |
153 | private ArrayList execute(int code, byte[]... parameters) {
154 | mError = PROTOCOL_ERROR;
155 |
156 | for (byte[] parameter : parameters) {
157 | if (parameter == null || parameter.length > 65535) {
158 | return null;
159 | }
160 | }
161 |
162 | LocalSocket socket = new LocalSocket();
163 | try {
164 | socket.connect(sAddress);
165 |
166 | OutputStream out = socket.getOutputStream();
167 | out.write(code);
168 | for (byte[] parameter : parameters) {
169 | out.write(parameter.length >> 8);
170 | out.write(parameter.length);
171 | out.write(parameter);
172 | }
173 | out.flush();
174 | socket.shutdownOutput();
175 |
176 | InputStream in = socket.getInputStream();
177 | if ((code = in.read()) != NO_ERROR) {
178 | if (code != -1) {
179 | mError = code;
180 | }
181 | return null;
182 | }
183 |
184 | ArrayList values = new ArrayList();
185 | while (true) {
186 | int i, j;
187 | if ((i = in.read()) == -1) {
188 | break;
189 | }
190 | if ((j = in.read()) == -1) {
191 | return null;
192 | }
193 | byte[] value = new byte[i << 8 | j];
194 | for (i = 0; i < value.length; i += j) {
195 | if ((j = in.read(value, i, value.length - i)) == -1) {
196 | return null;
197 | }
198 | }
199 | values.add(value);
200 | }
201 | mError = NO_ERROR;
202 | return values;
203 | } catch (IOException e) {
204 | // ignore
205 | } finally {
206 | try {
207 | socket.close();
208 | } catch (IOException e) {}
209 | }
210 | return null;
211 | }
212 |
213 | private static byte[] getBytes(String string) {
214 | try {
215 | return string.getBytes("UTF-8");
216 | } catch (UnsupportedEncodingException e) {
217 | // will never happen
218 | throw new RuntimeException(e);
219 | }
220 | }
221 |
222 | private static String toString(byte[] bytes) {
223 | try {
224 | return new String(bytes, "UTF-8");
225 | } catch (UnsupportedEncodingException e) {
226 | // will never happen
227 | throw new RuntimeException(e);
228 | }
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/src/com/android/server/vpn/DaemonProxy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package com.android.server.vpn;
18 |
19 | import android.net.LocalSocket;
20 | import android.net.LocalSocketAddress;
21 | import android.net.vpn.VpnManager;
22 | import android.os.SystemProperties;
23 | import android.util.Log;
24 |
25 | import java.io.IOException;
26 | import java.io.InputStream;
27 | import java.io.OutputStream;
28 | import java.io.Serializable;
29 |
30 | /**
31 | * Proxy to start, stop and interact with a VPN daemon.
32 | * The daemon is expected to accept connection through Unix domain socket.
33 | * When the proxy successfully starts the daemon, it will establish a socket
34 | * connection with the daemon, to both send commands to the daemon and receive
35 | * response and connecting error code from the daemon.
36 | */
37 | class DaemonProxy implements Serializable {
38 | private static final long serialVersionUID = 1L;
39 | private static final boolean DBG = true;
40 |
41 | private static final int WAITING_TIME = 15; // sec
42 |
43 | private static final String SVC_STATE_CMD_PREFIX = "init.svc.";
44 | private static final String SVC_START_CMD = "ctl.start";
45 | private static final String SVC_STOP_CMD = "ctl.stop";
46 | private static final String SVC_STATE_RUNNING = "running";
47 | private static final String SVC_STATE_STOPPED = "stopped";
48 |
49 | private static final int END_OF_ARGUMENTS = 255;
50 |
51 | private String mName;
52 | private String mTag;
53 | private transient LocalSocket mControlSocket;
54 |
55 | /**
56 | * Creates a proxy of the specified daemon.
57 | * @param daemonName name of the daemon
58 | */
59 | DaemonProxy(String daemonName) {
60 | mName = daemonName;
61 | mTag = "SProxy_" + daemonName;
62 | }
63 |
64 | String getName() {
65 | return mName;
66 | }
67 |
68 | void start() throws IOException {
69 | String svc = mName;
70 |
71 | Log.i(mTag, "Start VPN daemon: " + svc);
72 | SystemProperties.set(SVC_START_CMD, svc);
73 |
74 | if (!blockUntil(SVC_STATE_RUNNING, WAITING_TIME)) {
75 | throw new IOException("cannot start service: " + svc);
76 | } else {
77 | mControlSocket = createServiceSocket();
78 | }
79 | }
80 |
81 | void sendCommand(String ...args) throws IOException {
82 | OutputStream out = getControlSocketOutput();
83 | for (String arg : args) outputString(out, arg);
84 | out.write(END_OF_ARGUMENTS);
85 | out.flush();
86 |
87 | int result = getResultFromSocket(true);
88 | if (result != args.length) {
89 | throw new IOException("socket error, result from service: "
90 | + result);
91 | }
92 | }
93 |
94 | // returns 0 if nothing is in the receive buffer
95 | int getResultFromSocket() throws IOException {
96 | return getResultFromSocket(false);
97 | }
98 |
99 | void closeControlSocket() {
100 | if (mControlSocket == null) return;
101 | try {
102 | mControlSocket.close();
103 | } catch (IOException e) {
104 | Log.w(mTag, "close control socket", e);
105 | } finally {
106 | mControlSocket = null;
107 | }
108 | }
109 |
110 | void stop() {
111 | String svc = mName;
112 | Log.i(mTag, "Stop VPN daemon: " + svc);
113 | SystemProperties.set(SVC_STOP_CMD, svc);
114 | boolean success = blockUntil(SVC_STATE_STOPPED, 5);
115 | if (DBG) Log.d(mTag, "stopping " + svc + ", success? " + success);
116 | }
117 |
118 | boolean isStopped() {
119 | String cmd = SVC_STATE_CMD_PREFIX + mName;
120 | return SVC_STATE_STOPPED.equals(SystemProperties.get(cmd));
121 | }
122 |
123 | private int getResultFromSocket(boolean blocking) throws IOException {
124 | LocalSocket s = mControlSocket;
125 | if (s == null) return 0;
126 | InputStream in = s.getInputStream();
127 | if (!blocking && in.available() == 0) return 0;
128 |
129 | int data = in.read();
130 | Log.i(mTag, "got data from control socket: " + data);
131 |
132 | return data;
133 | }
134 |
135 | private LocalSocket createServiceSocket() throws IOException {
136 | LocalSocket s = new LocalSocket();
137 | LocalSocketAddress a = new LocalSocketAddress(mName,
138 | LocalSocketAddress.Namespace.RESERVED);
139 |
140 | // try a few times in case the service has not listen()ed
141 | IOException excp = null;
142 | for (int i = 0; i < 10; i++) {
143 | try {
144 | s.connect(a);
145 | return s;
146 | } catch (IOException e) {
147 | if (DBG) Log.d(mTag, "service not yet listen()ing; try again");
148 | excp = e;
149 | sleep(500);
150 | }
151 | }
152 | throw excp;
153 | }
154 |
155 | private OutputStream getControlSocketOutput() throws IOException {
156 | if (mControlSocket != null) {
157 | return mControlSocket.getOutputStream();
158 | } else {
159 | throw new IOException("no control socket available");
160 | }
161 | }
162 |
163 | /**
164 | * Waits for the process to be in the expected state. The method returns
165 | * false if after the specified duration (in seconds), the process is still
166 | * not in the expected state.
167 | */
168 | private boolean blockUntil(String expectedState, int waitTime) {
169 | String cmd = SVC_STATE_CMD_PREFIX + mName;
170 | int sleepTime = 200; // ms
171 | int n = waitTime * 1000 / sleepTime;
172 | for (int i = 0; i < n; i++) {
173 | if (expectedState.equals(SystemProperties.get(cmd))) {
174 | if (DBG) {
175 | Log.d(mTag, mName + " is " + expectedState + " after "
176 | + (i * sleepTime) + " msec");
177 | }
178 | break;
179 | }
180 | sleep(sleepTime);
181 | }
182 | return expectedState.equals(SystemProperties.get(cmd));
183 | }
184 |
185 | private void outputString(OutputStream out, String s) throws IOException {
186 | byte[] bytes = s.getBytes();
187 | out.write(bytes.length);
188 | out.write(bytes);
189 | out.flush();
190 | }
191 |
192 | private void sleep(int msec) {
193 | try {
194 | Thread.currentThread().sleep(msec);
195 | } catch (InterruptedException e) {
196 | throw new RuntimeException(e);
197 | }
198 | }
199 | }
200 |
--------------------------------------------------------------------------------
/src/com/android/server/vpn/L2tpIpsecPskService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package com.android.server.vpn;
18 |
19 | import android.net.vpn.L2tpIpsecPskProfile;
20 |
21 | import java.io.IOException;
22 |
23 | /**
24 | * The service that manages the preshared key based L2TP-over-IPSec VPN
25 | * connection.
26 | */
27 | class L2tpIpsecPskService extends VpnService {
28 | private static final String IPSEC = "racoon";
29 |
30 | @Override
31 | protected void connect(String serverIp, String username, String password)
32 | throws IOException {
33 | L2tpIpsecPskProfile p = getProfile();
34 | VpnDaemons daemons = getDaemons();
35 |
36 | // IPSEC
37 | daemons.startIpsecForL2tp(serverIp, p.getPresharedKey())
38 | .closeControlSocket();
39 |
40 | sleep(2000); // 2 seconds
41 |
42 | // L2TP
43 | daemons.startL2tp(serverIp,
44 | (p.isSecretEnabled() ? p.getSecretString() : null),
45 | username, password);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/com/android/server/vpn/L2tpIpsecService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package com.android.server.vpn;
18 |
19 | import android.net.vpn.L2tpIpsecProfile;
20 | import android.security.Credentials;
21 |
22 | import java.io.IOException;
23 |
24 | /**
25 | * The service that manages the certificate based L2TP-over-IPSec VPN connection.
26 | */
27 | class L2tpIpsecService extends VpnService {
28 | private static final String IPSEC = "racoon";
29 |
30 | @Override
31 | protected void connect(String serverIp, String username, String password)
32 | throws IOException {
33 | L2tpIpsecProfile p = getProfile();
34 | VpnDaemons daemons = getDaemons();
35 |
36 | // IPSEC
37 | DaemonProxy ipsec = daemons.startIpsecForL2tp(serverIp,
38 | Credentials.USER_PRIVATE_KEY + p.getUserCertificate(),
39 | Credentials.USER_CERTIFICATE + p.getUserCertificate(),
40 | Credentials.CA_CERTIFICATE + p.getCaCertificate());
41 | ipsec.closeControlSocket();
42 |
43 | sleep(2000); // 2 seconds
44 |
45 | // L2TP
46 | daemons.startL2tp(serverIp,
47 | (p.isSecretEnabled() ? p.getSecretString() : null),
48 | username, password);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/com/android/server/vpn/L2tpService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package com.android.server.vpn;
18 |
19 | import android.net.vpn.L2tpProfile;
20 |
21 | import java.io.IOException;
22 |
23 | /**
24 | * The service that manages the L2TP VPN connection.
25 | */
26 | class L2tpService extends VpnService {
27 | @Override
28 | protected void connect(String serverIp, String username, String password)
29 | throws IOException {
30 | L2tpProfile p = getProfile();
31 | getDaemons().startL2tp(serverIp,
32 | (p.isSecretEnabled() ? p.getSecretString() : null),
33 | username, password);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/com/android/server/vpn/PptpService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package com.android.server.vpn;
18 |
19 | import android.net.vpn.PptpProfile;
20 |
21 | import java.io.IOException;
22 |
23 | /**
24 | * The service that manages the PPTP VPN connection.
25 | */
26 | class PptpService extends VpnService {
27 | @Override
28 | protected void connect(String serverIp, String username, String password)
29 | throws IOException {
30 | PptpProfile p = getProfile();
31 | getDaemons().startPptp(serverIp, username, password,
32 | p.isEncryptionEnabled());
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/com/android/server/vpn/VpnConnectingError.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package com.android.server.vpn;
18 |
19 | import java.io.IOException;
20 |
21 | /**
22 | * Exception thrown when a connecting attempt fails.
23 | */
24 | class VpnConnectingError extends IOException {
25 | private int mErrorCode;
26 |
27 | VpnConnectingError(int errorCode) {
28 | super("Connecting error: " + errorCode);
29 | mErrorCode = errorCode;
30 | }
31 |
32 | int getErrorCode() {
33 | return mErrorCode;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/com/android/server/vpn/VpnDaemons.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package com.android.server.vpn;
18 |
19 | import android.util.Log;
20 |
21 | import java.io.IOException;
22 | import java.io.Serializable;
23 | import java.util.ArrayList;
24 | import java.util.Arrays;
25 | import java.util.List;
26 |
27 | /**
28 | * A helper class for managing native VPN daemons.
29 | */
30 | class VpnDaemons implements Serializable {
31 | static final long serialVersionUID = 1L;
32 | private final String TAG = VpnDaemons.class.getSimpleName();
33 |
34 | private static final String MTPD = "mtpd";
35 | private static final String IPSEC = "racoon";
36 |
37 | private static final String L2TP = "l2tp";
38 | private static final String L2TP_PORT = "1701";
39 |
40 | private static final String PPTP = "pptp";
41 | private static final String PPTP_PORT = "1723";
42 |
43 | private static final String VPN_LINKNAME = "vpn";
44 | private static final String PPP_ARGS_SEPARATOR = "";
45 |
46 | private List mDaemonList = new ArrayList();
47 |
48 | public DaemonProxy startL2tp(String serverIp, String secret,
49 | String username, String password) throws IOException {
50 | return startMtpd(L2TP, serverIp, L2TP_PORT, secret, username, password,
51 | false);
52 | }
53 |
54 | public DaemonProxy startPptp(String serverIp, String username,
55 | String password, boolean encryption) throws IOException {
56 | return startMtpd(PPTP, serverIp, PPTP_PORT, null, username, password,
57 | encryption);
58 | }
59 |
60 | public DaemonProxy startIpsecForL2tp(String serverIp, String pskKey)
61 | throws IOException {
62 | DaemonProxy ipsec = startDaemon(IPSEC);
63 | ipsec.sendCommand(serverIp, L2TP_PORT, pskKey);
64 | return ipsec;
65 | }
66 |
67 | public DaemonProxy startIpsecForL2tp(String serverIp, String userKeyKey,
68 | String userCertKey, String caCertKey) throws IOException {
69 | DaemonProxy ipsec = startDaemon(IPSEC);
70 | ipsec.sendCommand(serverIp, L2TP_PORT, userKeyKey, userCertKey,
71 | caCertKey);
72 | return ipsec;
73 | }
74 |
75 | public synchronized void stopAll() {
76 | new DaemonProxy(MTPD).stop();
77 | new DaemonProxy(IPSEC).stop();
78 | }
79 |
80 | public synchronized void closeSockets() {
81 | for (DaemonProxy s : mDaemonList) s.closeControlSocket();
82 | }
83 |
84 | public synchronized boolean anyDaemonStopped() {
85 | for (DaemonProxy s : mDaemonList) {
86 | if (s.isStopped()) {
87 | Log.w(TAG, " VPN daemon gone: " + s.getName());
88 | return true;
89 | }
90 | }
91 | return false;
92 | }
93 |
94 | public synchronized int getSocketError() {
95 | for (DaemonProxy s : mDaemonList) {
96 | int errCode = getResultFromSocket(s);
97 | if (errCode != 0) return errCode;
98 | }
99 | return 0;
100 | }
101 |
102 | private synchronized DaemonProxy startDaemon(String daemonName)
103 | throws IOException {
104 | DaemonProxy daemon = new DaemonProxy(daemonName);
105 | mDaemonList.add(daemon);
106 | daemon.start();
107 | return daemon;
108 | }
109 |
110 | private int getResultFromSocket(DaemonProxy s) {
111 | try {
112 | return s.getResultFromSocket();
113 | } catch (IOException e) {
114 | return -1;
115 | }
116 | }
117 |
118 | private DaemonProxy startMtpd(String protocol,
119 | String serverIp, String port, String secret, String username,
120 | String password, boolean encryption) throws IOException {
121 | ArrayList args = new ArrayList();
122 | args.addAll(Arrays.asList(protocol, serverIp, port));
123 | if (secret != null) args.add(secret);
124 | args.add(PPP_ARGS_SEPARATOR);
125 | addPppArguments(args, serverIp, username, password, encryption);
126 |
127 | DaemonProxy mtpd = startDaemon(MTPD);
128 | mtpd.sendCommand(args.toArray(new String[args.size()]));
129 | return mtpd;
130 | }
131 |
132 | private static void addPppArguments(ArrayList args, String serverIp,
133 | String username, String password, boolean encryption)
134 | throws IOException {
135 | args.addAll(Arrays.asList(
136 | "linkname", VPN_LINKNAME,
137 | "name", username,
138 | "password", password,
139 | "refuse-eap", "nodefaultroute", "usepeerdns",
140 | "idle", "1800",
141 | "mtu", "1400",
142 | "mru", "1400"));
143 | if (encryption) {
144 | args.add("+mppe");
145 | }
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/src/com/android/server/vpn/VpnService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package com.android.server.vpn;
18 |
19 | import com.android.server.vpn.R;
20 |
21 | import java.io.IOException;
22 | import java.io.Serializable;
23 | import java.net.DatagramSocket;
24 | import java.net.InetAddress;
25 | import java.net.NetworkInterface;
26 | import java.net.UnknownHostException;
27 |
28 | import android.app.Notification;
29 | import android.app.NotificationManager;
30 | import android.app.PendingIntent;
31 | import android.content.Context;
32 | import android.net.vpn.VpnManager;
33 | import android.net.vpn.VpnProfile;
34 | import android.net.vpn.VpnState;
35 | import android.os.SystemProperties;
36 | import android.text.TextUtils;
37 | import android.util.Log;
38 |
39 | /**
40 | * The service base class for managing a type of VPN connection.
41 | */
42 | abstract class VpnService implements Serializable {
43 | static final long serialVersionUID = 1L;
44 | private static final boolean DBG = true;
45 | private static final int NOTIFICATION_ID = 1;
46 |
47 | private static final String DNS1 = "net.dns1";
48 | private static final String DNS2 = "net.dns2";
49 | private static final String VPN_DNS1 = "vpn.dns1";
50 | private static final String VPN_DNS2 = "vpn.dns2";
51 | private static final String VPN_STATUS = "vpn.status";
52 | private static final String VPN_IS_UP = "ok";
53 | private static final String VPN_IS_DOWN = "down";
54 |
55 | private static final String REMOTE_IP = "net.ipremote";
56 | private static final String DNS_DOMAIN_SUFFICES = "net.dns.search";
57 |
58 | private final String TAG = VpnService.class.getSimpleName();
59 |
60 | // FIXME: profile is only needed in connecting phase, so we can just save
61 | // the profile name and service class name for recovery
62 | E mProfile;
63 | transient VpnServiceBinder mContext;
64 |
65 | private VpnState mState = VpnState.IDLE;
66 | private Throwable mError;
67 |
68 | // connection settings
69 | private String mOriginalDns1;
70 | private String mOriginalDns2;
71 | private String mOriginalDomainSuffices;
72 | private String mLocalIp;
73 | private String mLocalIf;
74 |
75 | private long mStartTime; // VPN connection start time
76 |
77 | // for helping managing daemons
78 | private VpnDaemons mDaemons = new VpnDaemons();
79 |
80 | // for helping showing, updating notification
81 | private transient NotificationHelper mNotification;
82 |
83 | /**
84 | * Establishes a VPN connection with the specified username and password.
85 | */
86 | protected abstract void connect(String serverIp, String username,
87 | String password) throws IOException;
88 |
89 | /**
90 | * Returns the daemons management class for this service object.
91 | */
92 | protected VpnDaemons getDaemons() {
93 | return mDaemons;
94 | }
95 |
96 | /**
97 | * Returns the VPN profile associated with the connection.
98 | */
99 | protected E getProfile() {
100 | return mProfile;
101 | }
102 |
103 | /**
104 | * Returns the IP address of the specified host name.
105 | */
106 | protected String getIp(String hostName) throws IOException {
107 | return InetAddress.getByName(hostName).getHostAddress();
108 | }
109 |
110 | void setContext(VpnServiceBinder context, E profile) {
111 | mProfile = profile;
112 | recover(context);
113 | }
114 |
115 | void recover(VpnServiceBinder context) {
116 | mContext = context;
117 | mNotification = new NotificationHelper();
118 |
119 | if (VpnState.CONNECTED.equals(mState)) {
120 | Log.i("VpnService", " recovered: " + mProfile.getName());
121 | startConnectivityMonitor();
122 | }
123 | }
124 |
125 | VpnState getState() {
126 | return mState;
127 | }
128 |
129 | synchronized boolean onConnect(String username, String password) {
130 | try {
131 | setState(VpnState.CONNECTING);
132 |
133 | mDaemons.stopAll();
134 | String serverIp = getIp(getProfile().getServerName());
135 | saveLocalIpAndInterface(serverIp);
136 | onBeforeConnect();
137 | connect(serverIp, username, password);
138 | waitUntilConnectedOrTimedout();
139 | return true;
140 | } catch (Throwable e) {
141 | onError(e);
142 | return false;
143 | }
144 | }
145 |
146 | synchronized void onDisconnect() {
147 | try {
148 | Log.i(TAG, "disconnecting VPN...");
149 | setState(VpnState.DISCONNECTING);
150 | mNotification.showDisconnect();
151 |
152 | mDaemons.stopAll();
153 | } catch (Throwable e) {
154 | Log.e(TAG, "onDisconnect()", e);
155 | } finally {
156 | onFinalCleanUp();
157 | }
158 | }
159 |
160 | private void onError(Throwable error) {
161 | // error may occur during or after connection setup
162 | // and it may be due to one or all services gone
163 | if (mError != null) {
164 | Log.w(TAG, " multiple errors occur, record the last one: "
165 | + error);
166 | }
167 | Log.e(TAG, "onError()", error);
168 | mError = error;
169 | onDisconnect();
170 | }
171 |
172 | private void onError(int errorCode) {
173 | onError(new VpnConnectingError(errorCode));
174 | }
175 |
176 |
177 | private void onBeforeConnect() throws IOException {
178 | mNotification.disableNotification();
179 |
180 | SystemProperties.set(VPN_DNS1, "");
181 | SystemProperties.set(VPN_DNS2, "");
182 | SystemProperties.set(VPN_STATUS, VPN_IS_DOWN);
183 | if (DBG) {
184 | Log.d(TAG, " VPN UP: " + SystemProperties.get(VPN_STATUS));
185 | }
186 | }
187 |
188 | private void waitUntilConnectedOrTimedout() throws IOException {
189 | sleep(2000); // 2 seconds
190 | for (int i = 0; i < 80; i++) {
191 | if (mState != VpnState.CONNECTING) {
192 | break;
193 | } else if (VPN_IS_UP.equals(
194 | SystemProperties.get(VPN_STATUS))) {
195 | onConnected();
196 | return;
197 | } else {
198 | int err = mDaemons.getSocketError();
199 | if (err != 0) {
200 | onError(err);
201 | return;
202 | }
203 | }
204 | sleep(500); // 0.5 second
205 | }
206 |
207 | if (mState == VpnState.CONNECTING) {
208 | onError(new IOException("Connecting timed out"));
209 | }
210 | }
211 |
212 | private synchronized void onConnected() throws IOException {
213 | if (DBG) Log.d(TAG, "onConnected()");
214 |
215 | mDaemons.closeSockets();
216 | saveOriginalDns();
217 | saveAndSetDomainSuffices();
218 |
219 | mStartTime = System.currentTimeMillis();
220 |
221 | // Correct order to make sure VpnService doesn't break when killed:
222 | // (1) set state to CONNECTED
223 | // (2) save states
224 | // (3) set DNS
225 | setState(VpnState.CONNECTED);
226 | saveSelf();
227 | setVpnDns();
228 |
229 | startConnectivityMonitor();
230 | }
231 |
232 | private void saveSelf() throws IOException {
233 | mContext.saveStates();
234 | }
235 |
236 | private synchronized void onFinalCleanUp() {
237 | if (DBG) Log.d(TAG, "onFinalCleanUp()");
238 |
239 | if (mState == VpnState.IDLE) return;
240 |
241 | // keep the notification when error occurs
242 | if (!anyError()) mNotification.disableNotification();
243 |
244 | restoreOriginalDns();
245 | restoreOriginalDomainSuffices();
246 | setState(VpnState.IDLE);
247 |
248 | // stop the service itself
249 | SystemProperties.set(VPN_STATUS, VPN_IS_DOWN);
250 | mContext.removeStates();
251 | mContext.stopSelf();
252 | }
253 |
254 | private boolean anyError() {
255 | return (mError != null);
256 | }
257 |
258 | private void restoreOriginalDns() {
259 | // restore only if they are not overridden
260 | String vpnDns1 = SystemProperties.get(VPN_DNS1);
261 | if (vpnDns1.equals(SystemProperties.get(DNS1))) {
262 | Log.i(TAG, String.format("restore original dns prop: %s --> %s",
263 | SystemProperties.get(DNS1), mOriginalDns1));
264 | Log.i(TAG, String.format("restore original dns prop: %s --> %s",
265 | SystemProperties.get(DNS2), mOriginalDns2));
266 | SystemProperties.set(DNS1, mOriginalDns1);
267 | SystemProperties.set(DNS2, mOriginalDns2);
268 | }
269 | }
270 |
271 | private void saveOriginalDns() {
272 | mOriginalDns1 = SystemProperties.get(DNS1);
273 | mOriginalDns2 = SystemProperties.get(DNS2);
274 | Log.i(TAG, String.format("save original dns prop: %s, %s",
275 | mOriginalDns1, mOriginalDns2));
276 | }
277 |
278 | private void setVpnDns() {
279 | String vpnDns1 = SystemProperties.get(VPN_DNS1);
280 | String vpnDns2 = SystemProperties.get(VPN_DNS2);
281 | SystemProperties.set(DNS1, vpnDns1);
282 | SystemProperties.set(DNS2, vpnDns2);
283 | Log.i(TAG, String.format("set vpn dns prop: %s, %s",
284 | vpnDns1, vpnDns2));
285 | }
286 |
287 | private void saveAndSetDomainSuffices() {
288 | mOriginalDomainSuffices = SystemProperties.get(DNS_DOMAIN_SUFFICES);
289 | Log.i(TAG, "save original suffices: " + mOriginalDomainSuffices);
290 | String list = mProfile.getDomainSuffices();
291 | if (!TextUtils.isEmpty(list)) {
292 | SystemProperties.set(DNS_DOMAIN_SUFFICES, list);
293 | }
294 | }
295 |
296 | private void restoreOriginalDomainSuffices() {
297 | Log.i(TAG, "restore original suffices --> " + mOriginalDomainSuffices);
298 | SystemProperties.set(DNS_DOMAIN_SUFFICES, mOriginalDomainSuffices);
299 | }
300 |
301 | private void setState(VpnState newState) {
302 | mState = newState;
303 | broadcastConnectivity(newState);
304 | }
305 |
306 | private void broadcastConnectivity(VpnState s) {
307 | VpnManager m = new VpnManager(mContext);
308 | Throwable err = mError;
309 | if ((s == VpnState.IDLE) && (err != null)) {
310 | if (err instanceof UnknownHostException) {
311 | m.broadcastConnectivity(mProfile.getName(), s,
312 | VpnManager.VPN_ERROR_UNKNOWN_SERVER);
313 | } else if (err instanceof VpnConnectingError) {
314 | m.broadcastConnectivity(mProfile.getName(), s,
315 | ((VpnConnectingError) err).getErrorCode());
316 | } else if (VPN_IS_UP.equals(SystemProperties.get(VPN_STATUS))) {
317 | m.broadcastConnectivity(mProfile.getName(), s,
318 | VpnManager.VPN_ERROR_CONNECTION_LOST);
319 | } else {
320 | m.broadcastConnectivity(mProfile.getName(), s,
321 | VpnManager.VPN_ERROR_CONNECTION_FAILED);
322 | }
323 | } else {
324 | m.broadcastConnectivity(mProfile.getName(), s);
325 | }
326 | }
327 |
328 | private void startConnectivityMonitor() {
329 | new Thread(new Runnable() {
330 | public void run() {
331 | Log.i(TAG, "VPN connectivity monitor running");
332 | try {
333 | for (int i = 10; ; i--) {
334 | long now = System.currentTimeMillis();
335 |
336 | boolean heavyCheck = i == 0;
337 | synchronized (VpnService.this) {
338 | if (mState != VpnState.CONNECTED) break;
339 | mNotification.update(now);
340 |
341 | if (heavyCheck) {
342 | i = 10;
343 | if (checkConnectivity()) checkDns();
344 | }
345 | long t = 1000L - System.currentTimeMillis() + now;
346 | if (t > 100L) VpnService.this.wait(t);
347 | }
348 | }
349 | } catch (InterruptedException e) {
350 | onError(e);
351 | }
352 | Log.i(TAG, "VPN connectivity monitor stopped");
353 | }
354 | }).start();
355 | }
356 |
357 | private void saveLocalIpAndInterface(String serverIp) throws IOException {
358 | DatagramSocket s = new DatagramSocket();
359 | int port = 80; // arbitrary
360 | s.connect(InetAddress.getByName(serverIp), port);
361 | InetAddress localIp = s.getLocalAddress();
362 | mLocalIp = localIp.getHostAddress();
363 | NetworkInterface localIf = NetworkInterface.getByInetAddress(localIp);
364 | mLocalIf = (localIf == null) ? null : localIf.getName();
365 | if (TextUtils.isEmpty(mLocalIf)) {
366 | throw new IOException("Local interface is empty!");
367 | }
368 | if (DBG) {
369 | Log.d(TAG, " Local IP: " + mLocalIp + ", if: " + mLocalIf);
370 | }
371 | }
372 |
373 | // returns false if vpn connectivity is broken
374 | private boolean checkConnectivity() {
375 | if (mDaemons.anyDaemonStopped() || isLocalIpChanged()) {
376 | onError(new IOException("Connectivity lost"));
377 | return false;
378 | } else {
379 | return true;
380 | }
381 | }
382 |
383 | private void checkDns() {
384 | String dns1 = SystemProperties.get(DNS1);
385 | String vpnDns1 = SystemProperties.get(VPN_DNS1);
386 | if (!dns1.equals(vpnDns1) && dns1.equals(mOriginalDns1)) {
387 | // dhcp expires?
388 | setVpnDns();
389 | }
390 | }
391 |
392 | private boolean isLocalIpChanged() {
393 | try {
394 | InetAddress localIp = InetAddress.getByName(mLocalIp);
395 | NetworkInterface localIf =
396 | NetworkInterface.getByInetAddress(localIp);
397 | if (localIf == null || !mLocalIf.equals(localIf.getName())) {
398 | Log.w(TAG, " local If changed from " + mLocalIf
399 | + " to " + localIf);
400 | return true;
401 | } else {
402 | return false;
403 | }
404 | } catch (IOException e) {
405 | Log.w(TAG, "isLocalIpChanged()", e);
406 | return true;
407 | }
408 | }
409 |
410 | protected void sleep(int ms) {
411 | try {
412 | Thread.currentThread().sleep(ms);
413 | } catch (InterruptedException e) {
414 | }
415 | }
416 |
417 | private class DaemonHelper implements Serializable {
418 | }
419 |
420 | // Helper class for showing, updating notification.
421 | private class NotificationHelper {
422 | void update(long now) {
423 | String title = getNotificationTitle(true);
424 | Notification n = new Notification(R.drawable.vpn_connected, title,
425 | mStartTime);
426 | n.setLatestEventInfo(mContext, title,
427 | getConnectedNotificationMessage(now),
428 | prepareNotificationIntent());
429 | n.flags |= Notification.FLAG_NO_CLEAR;
430 | n.flags |= Notification.FLAG_ONGOING_EVENT;
431 | enableNotification(n);
432 | }
433 |
434 | void showDisconnect() {
435 | String title = getNotificationTitle(false);
436 | Notification n = new Notification(R.drawable.vpn_disconnected,
437 | title, System.currentTimeMillis());
438 | n.setLatestEventInfo(mContext, title,
439 | getDisconnectedNotificationMessage(),
440 | prepareNotificationIntent());
441 | n.flags |= Notification.FLAG_AUTO_CANCEL;
442 | disableNotification();
443 | enableNotification(n);
444 | }
445 |
446 | void disableNotification() {
447 | ((NotificationManager) mContext.getSystemService(
448 | Context.NOTIFICATION_SERVICE)).cancel(NOTIFICATION_ID);
449 | }
450 |
451 | private void enableNotification(Notification n) {
452 | ((NotificationManager) mContext.getSystemService(
453 | Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, n);
454 | }
455 |
456 | private PendingIntent prepareNotificationIntent() {
457 | return PendingIntent.getActivity(mContext, 0,
458 | new VpnManager(mContext).createSettingsActivityIntent(), 0);
459 | }
460 |
461 | private String getNotificationTitle(boolean connected) {
462 | String formatString = connected
463 | ? mContext.getString(
464 | R.string.vpn_notification_title_connected)
465 | : mContext.getString(
466 | R.string.vpn_notification_title_disconnected);
467 | return String.format(formatString, mProfile.getName());
468 | }
469 |
470 | private String getFormattedTime(int duration) {
471 | int hours = duration / 3600;
472 | StringBuilder sb = new StringBuilder();
473 | if (hours > 0) sb.append(hours).append(':');
474 | sb.append(String.format("%02d:%02d", (duration % 3600 / 60),
475 | (duration % 60)));
476 | return sb.toString();
477 | }
478 |
479 | private String getConnectedNotificationMessage(long now) {
480 | return getFormattedTime((int) (now - mStartTime) / 1000);
481 | }
482 |
483 | private String getDisconnectedNotificationMessage() {
484 | return mContext.getString(
485 | R.string.vpn_notification_hint_disconnected);
486 | }
487 | }
488 | }
489 |
--------------------------------------------------------------------------------
/src/com/android/server/vpn/VpnServiceBinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009, 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 |
17 | package com.android.server.vpn;
18 |
19 | import android.app.Service;
20 | import android.content.Intent;
21 | import android.net.vpn.IVpnService;
22 | import android.net.vpn.L2tpIpsecProfile;
23 | import android.net.vpn.L2tpIpsecPskProfile;
24 | import android.net.vpn.L2tpProfile;
25 | import android.net.vpn.PptpProfile;
26 | import android.net.vpn.VpnManager;
27 | import android.net.vpn.VpnProfile;
28 | import android.net.vpn.VpnState;
29 | import android.os.Environment;
30 | import android.os.IBinder;
31 | import android.os.SystemProperties;
32 | import android.util.Log;
33 |
34 | import java.io.File;
35 | import java.io.FileInputStream;
36 | import java.io.FileNotFoundException;
37 | import java.io.FileOutputStream;
38 | import java.io.IOException;
39 | import java.io.ObjectInputStream;
40 | import java.io.ObjectOutputStream;
41 |
42 | /**
43 | * The service class for managing a VPN connection. It implements the
44 | * {@link IVpnService} binder interface.
45 | */
46 | public class VpnServiceBinder extends Service {
47 | private static final String TAG = VpnServiceBinder.class.getSimpleName();
48 | private static final boolean DBG = true;
49 |
50 | private static final String STATES_FILE_RELATIVE_PATH = "/misc/vpn/.states";
51 |
52 | // The actual implementation is delegated to the VpnService class.
53 | private VpnService extends VpnProfile> mService;
54 |
55 | private static String getStateFilePath() {
56 | return Environment.getDataDirectory().getPath() + STATES_FILE_RELATIVE_PATH;
57 | }
58 |
59 | private final IBinder mBinder = new IVpnService.Stub() {
60 | public boolean connect(VpnProfile p, String username, String password) {
61 | return VpnServiceBinder.this.connect(p, username, password);
62 | }
63 |
64 | public void disconnect() {
65 | VpnServiceBinder.this.disconnect();
66 | }
67 |
68 | public void checkStatus(VpnProfile p) {
69 | VpnServiceBinder.this.checkStatus(p);
70 | }
71 | };
72 |
73 | @Override
74 | public void onCreate() {
75 | super.onCreate();
76 | checkSavedStates();
77 | }
78 |
79 |
80 | @Override
81 | public void onStart(Intent intent, int startId) {
82 | super.onStart(intent, startId);
83 | }
84 |
85 | @Override
86 | public IBinder onBind(Intent intent) {
87 | return mBinder;
88 | }
89 |
90 | void saveStates() throws IOException {
91 | if (DBG) Log.d("VpnServiceBinder", " saving states");
92 | ObjectOutputStream oos =
93 | new ObjectOutputStream(new FileOutputStream(getStateFilePath()));
94 | oos.writeObject(mService);
95 | oos.close();
96 | }
97 |
98 | void removeStates() {
99 | try {
100 | File f = new File(getStateFilePath());
101 | if (f.exists()) f.delete();
102 | } catch (Throwable e) {
103 | if (DBG) Log.d("VpnServiceBinder", " remove states: " + e);
104 | }
105 | }
106 |
107 | private synchronized boolean connect(final VpnProfile p,
108 | final String username, final String password) {
109 | if (mService != null) return false;
110 | final VpnService s = mService = createService(p);
111 |
112 | new Thread(new Runnable() {
113 | public void run() {
114 | s.onConnect(username, password);
115 | }
116 | }).start();
117 | return true;
118 | }
119 |
120 | private synchronized void disconnect() {
121 | if (mService == null) return;
122 | final VpnService s = mService;
123 |
124 | new Thread(new Runnable() {
125 | public void run() {
126 | s.onDisconnect();
127 | }
128 | }).start();
129 | }
130 |
131 | private synchronized void checkStatus(VpnProfile p) {
132 | if ((mService == null)
133 | || (!p.getName().equals(mService.mProfile.getName()))) {
134 | broadcastConnectivity(p.getName(), VpnState.IDLE);
135 | } else {
136 | broadcastConnectivity(p.getName(), mService.getState());
137 | }
138 | }
139 |
140 | private void checkSavedStates() {
141 | try {
142 | ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
143 | getStateFilePath()));
144 | mService = (VpnService extends VpnProfile>) ois.readObject();
145 | mService.recover(this);
146 | ois.close();
147 | } catch (FileNotFoundException e) {
148 | // do nothing
149 | } catch (Throwable e) {
150 | Log.i("VpnServiceBinder", "recovery error, remove states: " + e);
151 | removeStates();
152 | }
153 | }
154 |
155 | private VpnService extends VpnProfile> createService(VpnProfile p) {
156 | switch (p.getType()) {
157 | case L2TP:
158 | L2tpService l2tp = new L2tpService();
159 | l2tp.setContext(this, (L2tpProfile) p);
160 | return l2tp;
161 |
162 | case PPTP:
163 | PptpService pptp = new PptpService();
164 | pptp.setContext(this, (PptpProfile) p);
165 | return pptp;
166 |
167 | case L2TP_IPSEC_PSK:
168 | L2tpIpsecPskService psk = new L2tpIpsecPskService();
169 | psk.setContext(this, (L2tpIpsecPskProfile) p);
170 | return psk;
171 |
172 | case L2TP_IPSEC:
173 | L2tpIpsecService l2tpIpsec = new L2tpIpsecService();
174 | l2tpIpsec.setContext(this, (L2tpIpsecProfile) p);
175 | return l2tpIpsec;
176 |
177 | default:
178 | return null;
179 | }
180 | }
181 |
182 | private void broadcastConnectivity(String name, VpnState s) {
183 | new VpnManager(this).broadcastConnectivity(name, s);
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/src/org/zju/luojs/MyVpn.java:
--------------------------------------------------------------------------------
1 | package org.zju.luojs;
2 |
3 | import com.android.server.vpn.R;
4 | import android.app.Activity;
5 | import android.os.Bundle;
6 | import android.widget.TextView;
7 |
8 | public class MyVpn extends Activity {
9 | /** Called when the activity is first created. */
10 | @Override
11 | public void onCreate(Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | setContentView(R.layout.main);
14 | }
15 | }
--------------------------------------------------------------------------------