diff options
Diffstat (limited to 'src/de/blinkt/openvpn')
-rw-r--r-- | src/de/blinkt/openvpn/OpenVPN.java | 16 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/OpenVpnService.java | 69 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/Settings_Authentication.java | 6 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/Settings_IP.java | 11 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/ShowConfigFragment.java | 12 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/VPNPreferences.java | 4 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/VPNProfileList.java | 2 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/VpnProfile.java | 113 |
8 files changed, 182 insertions, 51 deletions
diff --git a/src/de/blinkt/openvpn/OpenVPN.java b/src/de/blinkt/openvpn/OpenVPN.java index bca276c9..c3d92a4c 100644 --- a/src/de/blinkt/openvpn/OpenVPN.java +++ b/src/de/blinkt/openvpn/OpenVPN.java @@ -8,7 +8,6 @@ import android.util.Log; public class OpenVPN { private static OpenVpnService mOpenVpnService; - private static String localip; private static final int MAXLOGENTRIES = 500; public static native int startOpenVPNThread(); public static native int startOpenVPNThreadArgs(String argv[]); @@ -32,14 +31,15 @@ public class OpenVPN { } static void addRoute(String dest,String mask, String gw) { - Log.i("openvpn" ,"Got Routing information " + dest + " " + mask + " " + gw ); + Log.i("openvpn" ,"Got Routing information " + dest + " " + mask + " " + gw ); + mOpenVpnService.addRoute(dest,mask); } synchronized static void logMessage(int level,String prefix, String message) { - logbuffer.addFirst(prefix + " " + message); + logbuffer.addLast(prefix + " " + message); if(logbuffer.size()>MAXLOGENTRIES) - logbuffer.removeLast(); + logbuffer.removeFirst(); // The garbage collector does not collect the String from native // but kills me for logging 100 messages with too many references :( @@ -62,10 +62,10 @@ public class OpenVPN { } - static void addInterfaceInfo(int mtu, String local, String remote) + static void addInterfaceInfo(int mtu, String local, String netmask) { - Log.i("openvpn","Got interface info M" + mtu + " L: " + local + "R: " + remote); - localip=local; + Log.i("openvpn","Got interface info M" + mtu + " L: " + local + "NM: " + netmask); + mOpenVpnService.setLocalIP(local,netmask); } static void addDns(String dns) { @@ -96,7 +96,7 @@ public class OpenVPN { public static int openTunDevice() { Log.d(TAG,"Opening tun device"); - ParcelFileDescriptor pfd = mOpenVpnService.openTun(localip); + ParcelFileDescriptor pfd = mOpenVpnService.openTun(); return pfd.detachFd(); } //! Dummy method being called to force loading of JNI Libraries diff --git a/src/de/blinkt/openvpn/OpenVpnService.java b/src/de/blinkt/openvpn/OpenVpnService.java index 1cc5b2ec..39d73adb 100644 --- a/src/de/blinkt/openvpn/OpenVpnService.java +++ b/src/de/blinkt/openvpn/OpenVpnService.java @@ -21,6 +21,8 @@ import java.net.UnknownHostException; import java.util.Arrays; import java.util.Vector; +import de.blinkt.openvpn.OpenVpnService.CIDRIP; + import android.app.PendingIntent; import android.content.Intent; import android.net.LocalSocket; @@ -38,7 +40,8 @@ public class OpenVpnService extends VpnService implements Handler.Callback, Runn private String[] mArgv; private Handler mHandler; - private Thread mThread; + // Only one VPN, make this thread shared between all instances + private static Thread mThread; private ParcelFileDescriptor mInterface; @@ -48,6 +51,36 @@ public class OpenVpnService extends VpnService implements Handler.Callback, Runn private String mDomain=null; + private Vector<CIDRIP> mRoutes=new Vector<CIDRIP>(); + + private CIDRIP mLocalIP; + + + class CIDRIP{ + String mIp; + int len; + public CIDRIP(String ip, String mask){ + mIp=ip; + String[] ipt = mask.split("\\."); + long netmask=0; + + netmask += Integer.parseInt(ipt[0]); + netmask += Integer.parseInt(ipt[1])<< 8; + netmask += Integer.parseInt(ipt[2])<< 16; + netmask += Integer.parseInt(ipt[3])<< 24; + + len =0; + while((netmask & 0x1) == 1) { + len++; + netmask = netmask >> 1; + } + } + @Override + public String toString() { + return String.format("%s/%d",mIp,len); + } + } + @Override public void onRevoke() { managmentCommand("signal SIGINT\n"); @@ -216,19 +249,31 @@ public class OpenVpnService extends VpnService implements Handler.Callback, Runn } - public ParcelFileDescriptor openTun(String localip) { - // FIXME: hardcoded assumptions + public ParcelFileDescriptor openTun() { Builder builder = new Builder(); - builder.addRoute("0.0.0.0", 0); - builder.addAddress(localip, 24 ); + + builder.addAddress(mLocalIP.mIp, mLocalIP.len); + for (String dns : mDnslist ) { builder.addDnsServer(dns); } - + + + for (CIDRIP route:mRoutes) { + builder.addRoute(route.mIp, route.len); + } + if(mDomain!=null) builder.addSearchDomain(mDomain); - builder.setSession(mProfile.mName + " - " + localip); + + mDnslist.clear(); + mRoutes.clear(); + + + builder.setSession(mProfile.mName + " - " + mLocalIP); + + // Let the configure Button show the Log Intent intent = new Intent(getBaseContext(),LogWindow.class); PendingIntent startLW = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0); builder.setConfigureIntent(startLW); @@ -248,4 +293,14 @@ public class OpenVpnService extends VpnService implements Handler.Callback, Runn mDomain=domain; } } + + + public void addRoute(String dest, String mask) { + mRoutes.add(new CIDRIP(dest, mask)); + } + + + public void setLocalIP(String local, String netmask) { + mLocalIP = new CIDRIP(local, netmask); + } } diff --git a/src/de/blinkt/openvpn/Settings_Authentication.java b/src/de/blinkt/openvpn/Settings_Authentication.java index f3ebb36d..4c70344d 100644 --- a/src/de/blinkt/openvpn/Settings_Authentication.java +++ b/src/de/blinkt/openvpn/Settings_Authentication.java @@ -58,7 +58,7 @@ public class Settings_Authentication extends PreferenceFragment implements OnPre mUseTLSAuth.setChecked(mProfile.mUseTLSAuth); mTLSAuthFile.setSummary(mProfile.mTLSAuthFilename); - //mTLSAuthDirection.setValue(mProfile.mTLSAuthDirection); + mTLSAuthDirection.setValue(mProfile.mTLSAuthDirection); } private void saveSettings() { @@ -72,10 +72,10 @@ public class Settings_Authentication extends PreferenceFragment implements OnPre else mProfile.mTLSAuthFilename = mTLSAuthFile.getSummary().toString(); - if(mTLSAuthDirection.getEntry()==null) + if(mTLSAuthDirection.getValue()==null) mProfile.mTLSAuthDirection=null; else - mProfile.mTLSAuthDirection = mTLSAuthDirection.getEntry().toString(); + mProfile.mTLSAuthDirection = mTLSAuthDirection.getValue().toString(); } @Override diff --git a/src/de/blinkt/openvpn/Settings_IP.java b/src/de/blinkt/openvpn/Settings_IP.java index c2b1ed71..de625d22 100644 --- a/src/de/blinkt/openvpn/Settings_IP.java +++ b/src/de/blinkt/openvpn/Settings_IP.java @@ -19,6 +19,7 @@ public class Settings_IP extends PreferenceFragment implements OnPreferenceChang private EditTextPreference mCustomRoutes; private CheckBoxPreference mUseDefaultRoute; private VpnProfile mProfile; + private CheckBoxPreference mRouteNoPull; @Override public void onCreate(Bundle savedInstanceState) { @@ -45,6 +46,7 @@ public class Settings_IP extends PreferenceFragment implements OnPreferenceChang mDNS2 = (EditTextPreference) findPreference("dns2"); mCustomRoutes = (EditTextPreference) findPreference("customRoutes"); mUseDefaultRoute = (CheckBoxPreference) findPreference("useDefaultRoute"); + mRouteNoPull = (CheckBoxPreference) findPreference("routenopull"); mIPv4.setOnPreferenceChangeListener(this); mIPv6.setOnPreferenceChangeListener(this); @@ -72,6 +74,7 @@ public class Settings_IP extends PreferenceFragment implements OnPreferenceChang mSearchdomain.setText(mProfile.mSearchDomain); mUseDefaultRoute.setChecked(mProfile.mUseDefaultRoute); mCustomRoutes.setText(mProfile.mCustomRoutes); + mRouteNoPull.setChecked(mProfile.mRoutenopull); // Sets Summary onPreferenceChange(mIPv4, mIPv4.getText()); @@ -105,7 +108,7 @@ public class Settings_IP extends PreferenceFragment implements OnPreferenceChang mProfile.mSearchDomain = mSearchdomain.getText(); mProfile.mUseDefaultRoute = mUseDefaultRoute.isChecked(); mProfile.mCustomRoutes = mCustomRoutes.getText(); - + mProfile.mRoutenopull = mRouteNoPull.isChecked(); } @@ -120,10 +123,10 @@ public class Settings_IP extends PreferenceFragment implements OnPreferenceChang preference.setSummary((String)newValue); if(preference== mUsePull || preference == mOverrideDNS) - if(preference==mOverrideDNS) + if(preference==mOverrideDNS) { // Set so the function gets the right value mOverrideDNS.setChecked((Boolean) newValue); - + } setDNSState(); saveSettings(); @@ -133,6 +136,7 @@ public class Settings_IP extends PreferenceFragment implements OnPreferenceChang private void setDNSState() { boolean enabled; mOverrideDNS.setEnabled(mUsePull.isChecked()); + mRouteNoPull.setEnabled(mUsePull.isChecked()); if(!mUsePull.isChecked()) enabled =true; else if (mOverrideDNS.isChecked()) @@ -143,6 +147,7 @@ public class Settings_IP extends PreferenceFragment implements OnPreferenceChang mDNS1.setEnabled(enabled); mDNS2.setEnabled(enabled); mSearchdomain.setEnabled(enabled); + } diff --git a/src/de/blinkt/openvpn/ShowConfigFragment.java b/src/de/blinkt/openvpn/ShowConfigFragment.java index a69d835a..68898e07 100644 --- a/src/de/blinkt/openvpn/ShowConfigFragment.java +++ b/src/de/blinkt/openvpn/ShowConfigFragment.java @@ -13,10 +13,18 @@ public class ShowConfigFragment extends Fragment { { String profileUUID = getArguments().getString(getActivity().getPackageName() + ".profileUUID"); VpnProfile vp = ProfileManager.get(profileUUID); - String cfg=vp.getConfigFile(getActivity().getCacheDir()); View v=inflater.inflate(R.layout.viewconfig, container,false); TextView cv = (TextView) v.findViewById(R.id.configview); - cv.setText(cfg); + + int check=vp.checkProfile(); + if(check!=R.string.no_error_found) { + cv.setText(check); + } + else { + String cfg=vp.getConfigFile(getActivity().getCacheDir()); + + cv.setText(cfg); + } return v; }; } diff --git a/src/de/blinkt/openvpn/VPNPreferences.java b/src/de/blinkt/openvpn/VPNPreferences.java index 4b1c7377..771cd902 100644 --- a/src/de/blinkt/openvpn/VPNPreferences.java +++ b/src/de/blinkt/openvpn/VPNPreferences.java @@ -44,11 +44,11 @@ public class VPNPreferences extends PreferenceActivity { - if (hasHeaders()) { + /* if (hasHeaders()) { Button button = new Button(this); button.setText("Save"); setListFooter(button); - } + } */ } diff --git a/src/de/blinkt/openvpn/VPNProfileList.java b/src/de/blinkt/openvpn/VPNProfileList.java index f77c8639..8f4304dc 100644 --- a/src/de/blinkt/openvpn/VPNProfileList.java +++ b/src/de/blinkt/openvpn/VPNProfileList.java @@ -184,7 +184,7 @@ public class VPNProfileList extends PreferenceFragment implements VpnPreference startActivity(startLW); - OpenVPN.logMessage(0, "", "Building confugration..."); + OpenVPN.logMessage(0, "", "Building configration..."); Intent startVPN = mSelectedVPN.prepareIntent(getActivity()); diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java index e17fb8ff..2df4ec39 100644 --- a/src/de/blinkt/openvpn/VpnProfile.java +++ b/src/de/blinkt/openvpn/VpnProfile.java @@ -12,6 +12,7 @@ import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.util.Collection; import java.util.Random; import java.util.UUID; import java.util.Vector; @@ -35,7 +36,7 @@ public class VpnProfile implements Serializable{ static final int TYPE_KEYSTORE=2; public static final int TYPE_USERPASS = 3; public static final int TYPE_STATICKEYS = 4; - + private static final String OVPNCONFIGFILE = "android.conf"; // Keep in order of parceling @@ -71,6 +72,7 @@ public class VpnProfile implements Serializable{ public String mRemoteCN=""; private String mPassword; private String mUsername; + public boolean mRoutenopull=false; public int describeContents() { @@ -145,27 +147,27 @@ public class VpnProfile implements Serializable{ return mName; } - + public String getConfigFile(File cacheDir) { String cfg=""; - - + + // TODO "--remote-cert-eku", "TLS Web Server Authentication" - + boolean useTLSClient = (mAuthenticationType != TYPE_STATICKEYS); - + if(useTLSClient && mUsePull) cfg+="client\n"; else if (mUsePull) cfg+="pull\n"; else if(useTLSClient) - cfg+="tls-client"; - - + cfg+="tls-client\n"; + + cfg+="verb 2\n"; @@ -240,19 +242,30 @@ public class VpnProfile implements Serializable{ // Basic Settings if(!mUsePull ) { - cfg +="ifconfig " + mIPv4Address + " 255.255.255.255\n"; + cfg +="ifconfig " + cidrToIPAndNetmask(mIPv4Address) + "\n"; } - + + if(mUsePull && mRoutenopull) + cfg += "route-nopull\n"; + + if(mUseDefaultRoute) + cfg += "route 0.0.0.0 0.0.0.0\n"; + else + for(String route:getCustomRoutes()) { + cfg += "route " + route + "\n"; + } + + if(mOverrideDNS || !mUsePull) { if(!mDNS1.equals("") && mDNS1!=null) cfg+="dhcp-option DNS " + mDNS1 + "\n"; if(!mDNS2.equals("") && mDNS2!=null) cfg+="dhcp-option DNS " + mDNS2 + "\n"; - + } - - + + // Authentication if(mCheckRemoteCN) { if(mRemoteCN == null || mRemoteCN.equals("") ) @@ -262,9 +275,52 @@ public class VpnProfile implements Serializable{ } if(mExpectTLSCert) cfg += "remote-cert-tls server\n"; - + return cfg; } + + private Collection<String> getCustomRoutes() { + Vector<String> cidrRoutes=new Vector<String>(); + for(String route:mCustomRoutes.split("[\n \t]")) { + if(!route.equals("")) { + String cidrroute = cidrToIPAndNetmask(route); + if(cidrRoutes == null) + return null; + + cidrRoutes.add(cidrroute); + } + } + + return cidrRoutes; + } + + private String cidrToIPAndNetmask(String route) { + String[] parts = route.split("/"); + + // No /xx, return verbatim + if (parts.length ==1) + return route; + + if (parts.length!=2) + return null; + int len; + try { + len = Integer.parseInt(parts[1]); + } catch(NumberFormatException ne) { + return null; + } + if (len <0 || len >32) + return null; + + + long nm = 0xffffffffl; + nm = (nm << len) & 0xffffffffl; + + String netmask =String.format("%d.%d.%d.%d", (nm & 0xff000000) >> 24,(nm & 0xff0000) >> 16, (nm & 0xff00) >> 8 ,nm & 0xff ); + return parts[0] + " " + netmask; + } + + private String[] buildOpenvpnArgv(File cacheDir) { @@ -290,8 +346,8 @@ public class VpnProfile implements Serializable{ public Intent prepareIntent(Activity activity) { String prefix = activity.getPackageName(); - - Intent intent = new Intent(activity,OpenVpnService.class); + + Intent intent = new Intent(activity,OpenVpnService.class); intent.putExtra(prefix + ".ARGV" , buildOpenvpnArgv(activity.getCacheDir())); @@ -304,14 +360,14 @@ public class VpnProfile implements Serializable{ String pkcs12pw = savePKCS12(activity); intent.putExtra(prefix + ".PKCS12PASS", pkcs12pw); } - + if(mAuthenticationType == VpnProfile.TYPE_USERPASS) { intent.putExtra(prefix + ".USERNAME", mUsername); intent.putExtra(prefix + ".PASSWORD", mPassword); } - + intent.putExtra(prefix + ".profileUUID", mUuid.toString()); - + try { FileWriter cfg = new FileWriter(activity.getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE); cfg.write(getConfigFile(activity.getCacheDir())); @@ -320,10 +376,10 @@ public class VpnProfile implements Serializable{ } catch (IOException e) { e.printStackTrace(); } - + return intent; } - + private String getRandomPW() { String pw= ""; // Put enough digits togher to make a password :) @@ -373,11 +429,18 @@ public class VpnProfile implements Serializable{ int checkProfile() { if(mAuthenticationType==TYPE_KEYSTORE && mAlias==null) return R.string.no_keystore_cert_selected; - - + + if(!mUsePull) { + if(mIPv4Address == null || cidrToIPAndNetmask(mIPv4Address) == null) + return R.string.ipv4_format_error; + + } + if(!mUseDefaultRoute && getCustomRoutes()==null) + return R.string.custom_route_format_error; + // Everything okay return R.string.no_error_found; - + } |