1 package nl.openfortress.android6bed4;
3 import android.app.Activity;
4 import android.content.Intent;
5 import android.net.VpnService;
6 import android.net.VpnService.Builder;
7 import android.os.Bundle;
8 import android.os.ParcelFileDescriptor;
9 import android.view.View;
10 import android.text.TextWatcher;
11 import android.text.Editable;
12 import android.widget.TextView;
13 import android.widget.CheckBox;
14 import android.widget.EditText;
15 import android.widget.Switch;
17 import java.io.IOException;
21 public class Android6bed4 extends Activity implements TextWatcher {
23 private DatagramSocket uplink = null;
25 private boolean persist = false;
27 public InetSocketAddress publicserver;
29 private Intent mktun_intent;
31 private boolean interactive = false;
33 private int local_port = 0;
37 * User interface, with method names as specified in the XML file layout/user_interface.xml
41 * User interface: onPersistClick is called when the checkbox is toggled that changes reboot behaviour.
43 public void onPersistClick (View vw) {
44 persist = ((Switch) vw).isChecked ();
48 // Switching off the boot persistency is done immediately
49 //TODO// Store "persistent := false"
53 // Switching on boot persistency is only done after success
58 * User interface: onDefaultRouteClick is called when the switch is toggled between a /64 and a /0 prefix.
60 public void onDefaultRouteClick (View vw) {
61 boolean defaultroute = ((Switch) vw).isChecked ();
66 * User interface: onEnablerClick is called when the switch is toggled that enables/disables the tunnel.
68 public void onEnablerClick (View vw) {
69 boolean enable = ((Switch) vw).isChecked ();
73 // Enable the 6bed4 tunnel
75 TextView tv = (TextView) findViewById (R.id.tunserver_ip_string);
76 String pubsrv_ip = tv.getText ().toString ().trim ();
77 if (pubsrv_ip.length () == 0) {
78 pubsrv_ip = "145.136.0.1";
80 publicserver = new InetSocketAddress (Inet4Address.getByName (pubsrv_ip), 25788);
81 } catch (Throwable thr) {
83 Switch sv = (Switch) findViewById (R.id.enable_6bed4);
84 sv.setChecked (false);
88 // Extract local UDP port from GUI (or already have it setup, for better recycling)
91 TextView tv = (TextView) findViewById (R.id.tunclient_port_number);
92 new_port = new Integer (tv.getText ().toString ().trim ()).intValue () & 0xfffe;
93 } catch (Throwable thr) {
94 new_port = local_port;
97 DatagramSocket new_uplink;
98 if ((new_port > 0) && (new_port <= 65535) && ((new_port & 0x0001) == 0x0000)) {
99 new_uplink = new DatagramSocket (new_port);
101 new_uplink = new DatagramSocket ();
102 new_port = new_uplink.getPort ();
104 if (uplink != null) {
107 local_port = new_port;
109 } catch (SocketException se) {
111 Switch sv = (Switch) findViewById (R.id.enable_6bed4);
112 sv.setChecked (false);
116 setup_tunnel ((Inet6Address) Inet6Address.getByName ("::1")); /* TODO: Note here, not with a static IPv6 address */
120 } catch (UnknownHostException uhe) {
121 Switch sv = (Switch) findViewById (R.id.enable_6bed4);
122 sv.setChecked (false);
125 //TODO// Wait for 1s or so, reporting the state? Or link back from tunsvc to view?
130 * User interface: Change to either text field -- meaning, disable any current tunnel (and the enabler widget).
132 public void afterTextChanged (Editable s) { ; }
133 public void onTextChanged (CharSequence s, int start, int count, int after) { ; }
134 public void beforeTextChanged (CharSequence s, int start, int count, int after) {
139 * State management interface, called from Android OS. Thee onXXX() conform to a state diagram.
141 * @see http://developer.android.com/reference/android/app/Activity.html#SavingPersistentState
143 protected void onCreate (Bundle savedInstanceState) {
144 super.onCreate (savedInstanceState);
145 TunnelService tunsvc = TunnelService.theTunnelService ();
146 if (tunsvc != null) {
147 uplink = tunsvc.uplink;
150 uplink = new DatagramSocket (); //TODO// Remove port (to unfix it)
151 } catch (IOException ioe) {
154 mktun_intent = VpnService.prepare (this);
155 boolean have_tunnel = (TunnelService.theTunnelService () != null);
156 interactive = (mktun_intent == null) || (tunsvc != null);
157 //TODO:USE?// savedInstanceState.getBoolean ("persist_accross_reboots", false);
158 //TODO:USE?// savedInstanceState.getBoolean ("overtake_default_route", true);
159 //TODO:USE?// savedInstanceState.getString ("tunserver_ip", "145.136.0.1");
160 //TODO:USE?// savedInstanceState.getInt ("tunclient_port", 0);
163 setContentView (R.layout.user_interface);
164 tv = (TextView) findViewById (R.id.tunserver_ip_string);
165 tv.addTextChangedListener (this);
166 tv = (TextView) findViewById (R.id.tunclient_port_number);
167 tv.addTextChangedListener (this);
168 sv = (Switch) findViewById (R.id.enable_6bed4);
169 sv.setChecked (have_tunnel);
170 sv = (Switch) findViewById (R.id.overtake_default_route);
171 sv.setChecked (true);
172 sv = (Switch) findViewById (R.id.persist_accross_reboots);
173 sv.setChecked (false);
176 protected void onStart () {
180 // This is a new start of the VPN
182 //TODO// extract public server address from params
183 publicserver = new InetSocketAddress (Inet4Address.getByName ("145.136.0.1"), 25788); /* TODO:FIXED */
184 } catch (UnknownHostException uhe) {
188 setup_tunnel ((Inet6Address) Inet6Address.getByName ("::1")); /* TODO: Note here, not with a static IPv6 address */
189 } catch (UnknownHostException uhe) {
195 protected void onResume () {
197 /* TODO: Check if the IPv6 address is still the same? Also run after onStart! */
200 protected void onPause () {
202 /* TODO: Nothing to do I suppose... try to avoid loosing IPv6 address? */
205 protected void onStop () {
209 protected void onRestart () {
213 protected void onDestroy () {
219 *** Internal affairs -- tunnel service setup. ***
222 public void setup_tunnel (Inet6Address addr6bed4) {
224 // Prepare the context for the VPN
225 if (mktun_intent == null) {
226 mktun_intent = VpnService.prepare (this);
228 //TODO:ALT// Intent mktun_intent = TunnelService.prepare (this);
229 if (mktun_intent != null) {
230 // This is a new start of the VPN
231 this.startActivityForResult (mktun_intent, 0);
234 // Already started, apparently OK, so proceed to startup
235 this.onActivityResult (0, Activity.RESULT_OK, null);
239 synchronized protected void onActivityResult (int reqcode, int resultcode, Intent data) {
240 if (resultcode == Activity.RESULT_OK) {
242 // Cleanup any prior tunnel file descriptors
245 // Setup a new tunnel
246 // TODO: Due to this statement, two tunnel interfaces get created;
247 // without it, none are created. Not sure what to think
248 // of it... need to leave it like this for now.
249 TunnelService downlink = new TunnelService (uplink, publicserver);
250 if (downlink != null) {
251 downlink = new TunnelService (); /*TODO:HUH?*/
258 // Result is not OK -- tear down the tunnel
263 private void teardown_tunnel () {
264 TunnelService tunsvc = TunnelService.theTunnelService ();
265 if (tunsvc != null) {
267 Switch enabler = (Switch) findViewById (R.id.enable_6bed4);
268 enabler.setChecked (false);
273 synchronized public void onRevoke () {
274 if (downlink != null) {
275 downlink.teardown ();