summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArne Schwabe <arne@rfc2549.org>2014-01-21 20:37:31 +0100
committerArne Schwabe <arne@rfc2549.org>2014-01-21 20:37:31 +0100
commitb7968faa2a6dac1bd9641309ccf4c9a387bca26c (patch)
treeb73b91ede0a7b3257dda85c056873ceb8ef0db07
parentf3957386eb230ab85fa7d727c96d9ca6fe122ee3 (diff)
Add to code that allows excluding routes from the VPN
--HG-- extra : rebase_source : 7e20e643cb0949520b92f7ab7b623d6856ea4ef7
-rw-r--r--icsopenvpn.iml2
-rw-r--r--openvpn/config.h2
-rw-r--r--openvpn/configure.ac6
-rw-r--r--openvpn/doc/openvpn.810
-rw-r--r--openvpn/src/openvpn/ps.c3
-rw-r--r--openvpn/src/openvpn/route.c140
-rw-r--r--openvpn/src/openvpn/route.h10
-rw-r--r--openvpn/src/openvpn/socket.c3
-rw-r--r--openvpn/src/openvpn/ssl_polarssl.c13
-rw-r--r--openvpn/src/openvpn/ssl_verify_polarssl.c2
-rw-r--r--openvpn/src/openvpn/syshead.h7
-rw-r--r--openvpn/src/openvpn/tun.c6
-rw-r--r--openvpn/src/openvpn/win32.c2
-rwxr-xr-xres/values/strings.xml5
-rw-r--r--src/de/blinkt/openvpn/VpnProfile.java4
-rw-r--r--src/de/blinkt/openvpn/core/ConfigParser.java2
-rw-r--r--src/de/blinkt/openvpn/core/NetworkSpace.java244
-rw-r--r--src/de/blinkt/openvpn/core/OpenVpnManagementThread.java12
-rw-r--r--src/de/blinkt/openvpn/core/OpenVpnService.java109
-rw-r--r--src/de/blinkt/openvpn/core/VpnStatus.java7
20 files changed, 402 insertions, 187 deletions
diff --git a/icsopenvpn.iml b/icsopenvpn.iml
index 62aab261..866601d3 100644
--- a/icsopenvpn.iml
+++ b/icsopenvpn.iml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
+<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android" name="Android">
<configuration>
diff --git a/openvpn/config.h b/openvpn/config.h
index d281d33d..993a46f1 100644
--- a/openvpn/config.h
+++ b/openvpn/config.h
@@ -450,7 +450,7 @@
#define PACKAGE_NAME "OpenVPN"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "OpenVPN 2.4-icsopenvpn64"
+#define PACKAGE_STRING "OpenVPN 2.4-icsopenvpn"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "openvpn"
diff --git a/openvpn/configure.ac b/openvpn/configure.ac
index 636d4e25..380dcdbb 100644
--- a/openvpn/configure.ac
+++ b/openvpn/configure.ac
@@ -501,6 +501,12 @@ AC_CHECK_TYPE(
[[${SOCKET_INCLUDES}]]
)
AC_CHECK_TYPE(
+ [sa_family_t],
+ [AC_DEFINE([HAVE_SA_FAMILY_T], [1], [sa_family_t, needed to hold AF_* info])],
+ ,
+ [[${SOCKET_INCLUDES}]]
+)
+AC_CHECK_TYPE(
[struct sockaddr_in6],
,
[AC_MSG_ERROR([struct sockaddr_in6 not found, needed for ipv6 transport support.])],
diff --git a/openvpn/doc/openvpn.8 b/openvpn/doc/openvpn.8
index 0235c2c8..9eebf93e 100644
--- a/openvpn/doc/openvpn.8
+++ b/openvpn/doc/openvpn.8
@@ -2097,6 +2097,16 @@ In many cases, the
parameter can point to an empty directory, however
complications can result when scripts or restarts
are executed after the chroot operation.
+
+Note: if OpenVPN is built using the PolarSSL SSL
+library,
+.B \-\-chroot
+will only work if a /dev/urandom device node is available
+inside the chroot directory
+.B dir.
+This is due to the way PolarSSL works (it wants to open
+/dev/urandom every time randomness is needed, not just once
+at startup) and nothing OpenVPN can influence.
.\"*********************************************************
.TP
.B \-\-setcon context
diff --git a/openvpn/src/openvpn/ps.c b/openvpn/src/openvpn/ps.c
index b22653b4..901a094f 100644
--- a/openvpn/src/openvpn/ps.c
+++ b/openvpn/src/openvpn/ps.c
@@ -340,7 +340,8 @@ journal_add (const char *journal_dir, struct proxy_connection *pc, struct proxy_
fd = platform_open (jfn, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP);
if (fd != -1)
{
- write(fd, f, strlen(f));
+ if (write(fd, f, strlen(f)) != strlen(f))
+ msg(M_WARN, "PORT SHARE: writing to journal file (%s) failed", jfn);
close (fd);
cp->jfn = jfn;
}
diff --git a/openvpn/src/openvpn/route.c b/openvpn/src/openvpn/route.c
index 81ffa876..fa8221d4 100644
--- a/openvpn/src/openvpn/route.c
+++ b/openvpn/src/openvpn/route.c
@@ -49,7 +49,7 @@
#define METRIC_NOT_USED ((DWORD)-1)
#endif
-static void delete_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es);
+static void delete_route (struct route_ipv4 *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es);
static void get_bypass_addresses (struct route_bypass *rb, const unsigned int flags);
@@ -150,7 +150,7 @@ struct route_list *
new_route_list (const int max_routes, struct gc_arena *a)
{
struct route_list *ret;
- ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_list, struct route, max_routes, a);
+ ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_list, struct route_ipv4, max_routes, a);
ret->capacity = max_routes;
return ret;
}
@@ -165,7 +165,7 @@ new_route_ipv6_list (const int max_routes, struct gc_arena *a)
}
static const char *
-route_string (const struct route *r, struct gc_arena *gc)
+route_string (const struct route_ipv4 *r, struct gc_arena *gc)
{
struct buffer out = alloc_buf_gc (256, gc);
buf_printf (&out, "ROUTE network %s netmask %s gateway %s",
@@ -267,7 +267,7 @@ is_special_addr (const char *addr_str)
}
static bool
-init_route (struct route *r,
+init_route (struct route_ipv4 *r,
struct addrinfo **network_list,
const struct route_option *ro,
const struct route_list *rl)
@@ -484,7 +484,7 @@ void
clear_route_list (struct route_list *rl)
{
const int capacity = rl->capacity;
- const size_t rl_size = array_mult_safe (sizeof(struct route), capacity, sizeof(struct route_list));
+ const size_t rl_size = array_mult_safe (sizeof(struct route_ipv4), capacity, sizeof(struct route_list));
memset(rl, 0, rl_size);
rl->capacity = capacity;
}
@@ -519,7 +519,7 @@ add_block_local_item (struct route_list *rl,
&& rl->rgi.gateway.netmask < 0xFFFFFFFF
&& (rl->n)+2 <= rl->capacity)
{
- struct route r;
+ struct route_ipv4 r;
unsigned int l2;
/* split a route into two smaller blocking routes, and direct them to target */
@@ -649,7 +649,7 @@ init_route_list (struct route_list *rl,
for (i = 0; i < opt->n; ++i)
{
struct addrinfo* netlist;
- struct route r;
+ struct route_ipv4 r;
if (!init_route (&r,
&netlist,
@@ -760,7 +760,7 @@ add_route3 (in_addr_t network,
const struct route_gateway_info *rgi,
const struct env_set *es)
{
- struct route r;
+ struct route_ipv4 r;
CLEAR (r);
r.flags = RT_DEFINED;
r.network = network;
@@ -778,7 +778,7 @@ del_route3 (in_addr_t network,
const struct route_gateway_info *rgi,
const struct env_set *es)
{
- struct route r;
+ struct route_ipv4 r;
CLEAR (r);
r.flags = RT_DEFINED|RT_ADDED;
r.network = network;
@@ -1028,7 +1028,7 @@ add_routes (struct route_list *rl, struct route_ipv6_list *rl6, const struct tun
for (i = 0; i < rl->n; ++i)
{
- struct route *r = &rl->routes[i];
+ struct route_ipv4 *r = &rl->routes[i];
check_subnet_conflict (r->network, r->netmask, "route");
if (flags & ROUTE_DELETE_FIRST)
delete_route (r, tt, flags, &rl->rgi, es);
@@ -1060,7 +1060,7 @@ delete_routes (struct route_list *rl, struct route_ipv6_list *rl6,
int i;
for (i = rl->n - 1; i >= 0; --i)
{
- struct route * r = &rl->routes[i];
+ struct route_ipv4 * r = &rl->routes[i];
delete_route (r, tt, flags, &rl->rgi, es);
}
rl->iflags &= ~RL_ROUTES_ADDED;
@@ -1154,7 +1154,7 @@ print_default_gateway(const int msglevel, const struct route_gateway_info *rgi)
#endif
static void
-print_route (const struct route *r, int level)
+print_route (const struct route_ipv4 *r, int level)
{
struct gc_arena gc = gc_new ();
if (r->flags & RT_DEFINED)
@@ -1171,7 +1171,7 @@ print_routes (const struct route_list *rl, int level)
}
static void
-setenv_route (struct env_set *es, const struct route *r, int i)
+setenv_route (struct env_set *es, const struct route_ipv4 *r, int i)
{
struct gc_arena gc = gc_new ();
if (r->flags & RT_DEFINED)
@@ -1288,7 +1288,7 @@ is_on_link (const int is_local_route, const unsigned int flags, const struct rou
}
void
-add_route (struct route *r,
+add_route (struct route_ipv4 *r,
const struct tuntap *tt,
unsigned int flags,
const struct route_gateway_info *rgi, /* may be NULL */
@@ -1344,9 +1344,12 @@ add_route (struct route *r,
status = openvpn_execve_check (&argv, es, 0, "ERROR: Linux route add command failed");
#elif defined (TARGET_ANDROID)
- struct buffer out = alloc_buf_gc (64, &gc);
+ struct buffer out = alloc_buf_gc (128, &gc);
- buf_printf (&out, "%s %s", network, netmask);
+ if (rgi)
+ buf_printf (&out, "%s %s %s dev %s", network, netmask, gateway, rgi->iface);
+ else
+ buf_printf (&out, "%s %s %s", network, netmask, gateway);
management_android_control (management, "ROUTE", buf_bptr(&out));
#elif defined (WIN32)
@@ -1626,7 +1629,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
#elif defined (TARGET_ANDROID)
struct buffer out = alloc_buf_gc (64, &gc);
- buf_printf (&out, "%s/%d", network, r6->netbits);
+ buf_printf (&out, "%s/%d %s", network, r6->netbits, device);
management_android_control (management, "ROUTE6", buf_bptr(&out));
@@ -1741,7 +1744,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
}
static void
-delete_route (struct route *r,
+delete_route (struct route_ipv4 *r,
const struct tuntap *tt,
unsigned int flags,
const struct route_gateway_info *rgi,
@@ -2246,7 +2249,7 @@ get_default_gateway (struct route_gateway_info *rgi)
}
static DWORD
-windows_route_find_if_index (const struct route *r, const struct tuntap *tt)
+windows_route_find_if_index (const struct route_ipv4 *r, const struct tuntap *tt)
{
struct gc_arena gc = gc_new ();
DWORD ret = TUN_ADAPTER_INDEX_INVALID;
@@ -2291,7 +2294,7 @@ windows_route_find_if_index (const struct route *r, const struct tuntap *tt)
}
bool
-add_route_ipapi (const struct route *r, const struct tuntap *tt, DWORD adapter_index)
+add_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt, DWORD adapter_index)
{
struct gc_arena gc = gc_new ();
bool ret = false;
@@ -2365,7 +2368,7 @@ add_route_ipapi (const struct route *r, const struct tuntap *tt, DWORD adapter_i
}
bool
-del_route_ipapi (const struct route *r, const struct tuntap *tt)
+del_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt)
{
struct gc_arena gc = gc_new ();
bool ret = false;
@@ -2611,53 +2614,7 @@ get_default_gateway (struct route_gateway_info *rgi)
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
-
-/* all of this is taken from <net/route.h> in FreeBSD */
-#define RTA_DST 0x1
-#define RTA_GATEWAY 0x2
-#define RTA_NETMASK 0x4
-
-#define RTM_GET 0x4
-#define RTM_VERSION 5
-
-#define RTF_UP 0x1
-#define RTF_GATEWAY 0x2
-
-/*
- * These numbers are used by reliable protocols for determining
- * retransmission behavior and are included in the routing structure.
- */
-struct rt_metrics {
- u_long rmx_locks; /* Kernel must leave these values alone */
- u_long rmx_mtu; /* MTU for this path */
- u_long rmx_hopcount; /* max hops expected */
- u_long rmx_expire; /* lifetime for route, e.g. redirect */
- u_long rmx_recvpipe; /* inbound delay-bandwidth product */
- u_long rmx_sendpipe; /* outbound delay-bandwidth product */
- u_long rmx_ssthresh; /* outbound gateway buffer limit */
- u_long rmx_rtt; /* estimated round trip time */
- u_long rmx_rttvar; /* estimated rtt variance */
- u_long rmx_pksent; /* packets sent using this route */
- u_long rmx_filler[4]; /* will be used for T/TCP later */
-};
-
-/*
- * Structures for routing messages.
- */
-struct rt_msghdr {
- u_short rtm_msglen; /* to skip over non-understood messages */
- u_char rtm_version; /* future binary compatibility */
- u_char rtm_type; /* message type */
- u_short rtm_index; /* index for associated ifp */
- int rtm_flags; /* flags, incl. kern & message, e.g. DONE */
- int rtm_addrs; /* bitmask identifying sockaddrs in msg */
- pid_t rtm_pid; /* identify sender */
- int rtm_seq; /* for sender to identify action */
- int rtm_errno; /* why failed */
- int rtm_use; /* from rtentry */
- u_long rtm_inits; /* which metrics we are initializing */
- struct rt_metrics rtm_rmx; /* metrics themselves */
-};
+#include <net/route.h>
struct {
struct rt_msghdr m_rtm;
@@ -2976,52 +2933,7 @@ get_default_gateway (struct route_gateway_info *rgi)
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
-
-/* all of this is taken from <net/route.h> in OpenBSD 3.6 */
-#define RTA_DST 0x1 /* destination sockaddr present */
-#define RTA_GATEWAY 0x2 /* gateway sockaddr present */
-#define RTA_NETMASK 0x4 /* netmask sockaddr present */
-
-#define RTM_GET 0x4 /* Report Metrics */
-
-#define RTM_VERSION 3 /* Up the ante and ignore older versions */
-
-#define RTF_UP 0x1 /* route usable */
-#define RTF_GATEWAY 0x2 /* destination is a gateway */
-
-/*
- * Huge version for userland compatibility.
- */
-struct rt_metrics {
- u_long rmx_locks; /* Kernel must leave these values alone */
- u_long rmx_mtu; /* MTU for this path */
- u_long rmx_hopcount; /* max hops expected */
- u_long rmx_expire; /* lifetime for route, e.g. redirect */
- u_long rmx_recvpipe; /* inbound delay-bandwidth product */
- u_long rmx_sendpipe; /* outbound delay-bandwidth product */
- u_long rmx_ssthresh; /* outbound gateway buffer limit */
- u_long rmx_rtt; /* estimated round trip time */
- u_long rmx_rttvar; /* estimated rtt variance */
- u_long rmx_pksent; /* packets sent using this route */
-};
-
-/*
- * Structures for routing messages.
- */
-struct rt_msghdr {
- u_short rtm_msglen; /* to skip over non-understood messages */
- u_char rtm_version; /* future binary compatibility */
- u_char rtm_type; /* message type */
- u_short rtm_index; /* index for associated ifp */
- int rtm_flags; /* flags, incl. kern & message, e.g. DONE */
- int rtm_addrs; /* bitmask identifying sockaddrs in msg */
- pid_t rtm_pid; /* identify sender */
- int rtm_seq; /* for sender to identify action */
- int rtm_errno; /* why failed */
- int rtm_use; /* from rtentry */
- u_long rtm_inits; /* which metrics we are initializing */
- struct rt_metrics rtm_rmx; /* metrics themselves */
-};
+#include <net/route.h>
struct {
struct rt_msghdr m_rtm;
diff --git a/openvpn/src/openvpn/route.h b/openvpn/src/openvpn/route.h
index a40de32f..fe9b4616 100644
--- a/openvpn/src/openvpn/route.h
+++ b/openvpn/src/openvpn/route.h
@@ -110,7 +110,7 @@ struct route_ipv6_option_list {
struct route_ipv6_option routes_ipv6[EMPTY_ARRAY_SIZE];
};
-struct route {
+struct route_ipv4 {
# define RT_DEFINED (1<<0)
# define RT_ADDED (1<<1)
# define RT_METRIC_DEFINED (1<<2)
@@ -190,7 +190,7 @@ struct route_list {
unsigned int flags; /* RG_x flags */
int capacity;
int n;
- struct route routes[EMPTY_ARRAY_SIZE];
+ struct route_ipv4 routes[EMPTY_ARRAY_SIZE];
};
#if P2MP
@@ -223,7 +223,7 @@ struct route_ipv6_list *new_route_ipv6_list (const int max_routes, struct gc_are
void add_route_ipv6 (struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
void delete_route_ipv6 (const struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
-void add_route (struct route *r,
+void add_route (struct route_ipv4 *r,
const struct tuntap *tt,
unsigned int flags,
const struct route_gateway_info *rgi,
@@ -301,8 +301,8 @@ void print_routes (const struct route_list *rl, int level);
void show_routes (int msglev);
bool test_routes (const struct route_list *rl, const struct tuntap *tt);
-bool add_route_ipapi (const struct route *r, const struct tuntap *tt, DWORD adapter_index);
-bool del_route_ipapi (const struct route *r, const struct tuntap *tt);
+bool add_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt, DWORD adapter_index);
+bool del_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt);
#else
static inline bool test_routes (const struct route_list *rl, const struct tuntap *tt) { return true; }
diff --git a/openvpn/src/openvpn/socket.c b/openvpn/src/openvpn/socket.c
index 716512df..97f67563 100644
--- a/openvpn/src/openvpn/socket.c
+++ b/openvpn/src/openvpn/socket.c
@@ -1981,7 +1981,8 @@ link_socket_init_phase2 (struct link_socket *sock,
#endif
}
#ifdef TARGET_ANDROID
- protect_fd_nonlocal (sock->sd, &sock->info.lsa->actual.dest.addr.sa);
+ if (sock->sd != -1)
+ protect_fd_nonlocal (sock->sd, &sock->info.lsa->actual.dest.addr.sa);
#endif
if (sig_info && sig_info->signal_received)
goto done;
diff --git a/openvpn/src/openvpn/ssl_polarssl.c b/openvpn/src/openvpn/ssl_polarssl.c
index 47fb62a5..9dc4e879 100644
--- a/openvpn/src/openvpn/ssl_polarssl.c
+++ b/openvpn/src/openvpn/ssl_polarssl.c
@@ -49,6 +49,7 @@
#include <polarssl/havege.h>
#include "ssl_verify_polarssl.h"
+#include <polarssl/error.h>
#include <polarssl/pem.h>
void
@@ -284,7 +285,7 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file,
pem_password_callback(passbuf, 512, 0, NULL);
status = x509parse_key(ctx->priv_key,
priv_key_file_inline, strlen(priv_key_file_inline),
- passbuf, strlen(passbuf));
+ (unsigned char *) passbuf, strlen(passbuf));
}
}
else
@@ -481,7 +482,8 @@ void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,
if (ca_file && !strcmp (ca_file, INLINE_FILE_TAG) && ca_file_inline)
{
- if (0 != x509parse_crt(ctx->ca_chain, ca_file_inline, strlen(ca_file_inline)))
+ if (0 != x509parse_crt(ctx->ca_chain, (unsigned char *) ca_file_inline,
+ strlen(ca_file_inline)))
msg (M_FATAL, "Cannot load inline CA certificates");
}
else
@@ -501,8 +503,9 @@ tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs_file
if (!strcmp (extra_certs_file, INLINE_FILE_TAG) && extra_certs_file_inline)
{
- if (0 != x509parse_crt(ctx->crt_chain, extra_certs_file_inline,
- strlen(extra_certs_file_inline)))
+ if (0 != x509parse_crt(ctx->crt_chain,
+ (unsigned char *) extra_certs_file_inline,
+ strlen(extra_certs_file_inline)))
msg (M_FATAL, "Cannot load inline extra-certs file");
}
else
@@ -625,7 +628,7 @@ static void my_debug( void *ctx, int level, const char *str )
void tls_ctx_personalise_random(struct tls_root_ctx *ctx)
{
static char old_sha256_hash[32] = {0};
- char sha256_hash[32] = {0};
+ unsigned char sha256_hash[32] = {0};
ctr_drbg_context *cd_ctx = rand_ctx_get();
if (NULL != ctx->crt_chain)
diff --git a/openvpn/src/openvpn/ssl_verify_polarssl.c b/openvpn/src/openvpn/ssl_verify_polarssl.c
index 5db4f027..e5ccd904 100644
--- a/openvpn/src/openvpn/ssl_verify_polarssl.c
+++ b/openvpn/src/openvpn/ssl_verify_polarssl.c
@@ -125,8 +125,6 @@ x509_get_username (char *cn, int cn_len,
char *
x509_get_serial (x509_cert *cert, struct gc_arena *gc)
{
- int ret = 0;
- int i = 0;
char *buf = NULL;
size_t len = cert->serial.len * 3 + 1;
diff --git a/openvpn/src/openvpn/syshead.h b/openvpn/src/openvpn/syshead.h
index ab6fa01f..4050d548 100644
--- a/openvpn/src/openvpn/syshead.h
+++ b/openvpn/src/openvpn/syshead.h
@@ -426,6 +426,13 @@
#endif
/*
+ * Define type sa_family_t if it isn't defined in the socket headers
+ */
+#ifndef HAVE_SA_FAMILY_T
+typedef unsigned short sa_family_t;
+#endif
+
+/*
* Disable ESEC
*/
#if 0
diff --git a/openvpn/src/openvpn/tun.c b/openvpn/src/openvpn/tun.c
index 6460a369..4df271d5 100644
--- a/openvpn/src/openvpn/tun.c
+++ b/openvpn/src/openvpn/tun.c
@@ -909,7 +909,7 @@ do_ifconfig (struct tuntap *tt,
if (!tun && tt->topology == TOP_SUBNET)
{
/* Add a network route for the local tun interface */
- struct route r;
+ struct route_ipv4 r;
CLEAR (r);
r.flags = RT_DEFINED | RT_METRIC_DEFINED;
r.network = tt->local & tt->remote_netmask;
@@ -1106,7 +1106,7 @@ do_ifconfig (struct tuntap *tt,
/* Add a network route for the local tun interface */
if (!tun && tt->topology == TOP_SUBNET)
{
- struct route r;
+ struct route_ipv4 r;
CLEAR (r);
r.flags = RT_DEFINED;
r.network = tt->local & tt->remote_netmask;
@@ -1172,7 +1172,7 @@ do_ifconfig (struct tuntap *tt,
/* Add a network route for the local tun interface */
if (!tun && tt->topology == TOP_SUBNET)
{
- struct route r;
+ struct route_ipv4 r;
CLEAR (r);
r.flags = RT_DEFINED;
r.network = tt->local & tt->remote_netmask;
diff --git a/openvpn/src/openvpn/win32.c b/openvpn/src/openvpn/win32.c
index f35c96be..7c89a5a9 100644
--- a/openvpn/src/openvpn/win32.c
+++ b/openvpn/src/openvpn/win32.c
@@ -517,7 +517,7 @@ win32_signal_get (struct win32_signal *ws)
if (ret)
{
siginfo_static.signal_received = ret;
- siginfo_static.hard = true;
+ siginfo_static.source = SIG_SOURCE_HARD;
}
}
return ret;
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 792a5f89..34721515 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -97,8 +97,9 @@
<string name="last_openvpn_tun_config">Opening tun interface:</string>
<string name="local_ip_info">Local IPv4: %1$s/%2$d IPv6: %3$s MTU: %4$d</string>
<string name="dns_server_info">DNS Server: %1$s, Domain: %2$s</string>
- <string name="routes_info">Routes: %s</string>
- <string name="routes_info6">Routes IPv6: %s</string>
+ <string name="routes_info_incl">Routes: %1$s %2$s</string>
+ <string name="routes_info_excl">Routes excluded: %1$s %2$s</string>
+ <string name="routes_debug">VpnService routes installed: %1$s %2$s</string>
<string name="ip_not_cidr">Got interface information %1$s and %2$s, assuming second address is peer address of remote. Using /32 netmask for local IP. Mode given by OpenVPN is \"%3$s\".</string>
<string name="route_not_cidr">Cannot make sense of %1$s and %2$s as IP route with CIDR netmask, using /32 as netmask.</string>
<string name="route_not_netip">Corrected route %1$s/%2$s to %3$s/%2$s</string>
diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java
index d580829d..b016fb64 100644
--- a/src/de/blinkt/openvpn/VpnProfile.java
+++ b/src/de/blinkt/openvpn/VpnProfile.java
@@ -305,10 +305,10 @@ public class VpnProfile implements Serializable {
String routes = "";
int numroutes = 0;
if (mUseDefaultRoute)
- routes += "route 0.0.0.0 0.0.0.0\n";
+ routes += "route 0.0.0.0 0.0.0.0 vpn_gateway\n";
else
for (String route : getCustomRoutes()) {
- routes += "route " + route + "\n";
+ routes += "route " + route + "vpn_gateway\n";
numroutes++;
}
diff --git a/src/de/blinkt/openvpn/core/ConfigParser.java b/src/de/blinkt/openvpn/core/ConfigParser.java
index 103c208b..895f048e 100644
--- a/src/de/blinkt/openvpn/core/ConfigParser.java
+++ b/src/de/blinkt/openvpn/core/ConfigParser.java
@@ -12,7 +12,7 @@ import java.util.Vector;
//! Openvpn Config FIle Parser, probably not 100% accurate but close enough
-// And rember, this is valid :)
+// And remember, this is valid :)
// --<foo>
// bar
// </foo>
diff --git a/src/de/blinkt/openvpn/core/NetworkSpace.java b/src/de/blinkt/openvpn/core/NetworkSpace.java
new file mode 100644
index 00000000..3701c43d
--- /dev/null
+++ b/src/de/blinkt/openvpn/core/NetworkSpace.java
@@ -0,0 +1,244 @@
+package de.blinkt.openvpn.core;
+
+import android.text.TextUtils;
+
+import java.math.BigInteger;
+import java.net.Inet6Address;
+import java.util.*;
+
+public class NetworkSpace {
+
+
+ static class ipAddress implements Comparable<ipAddress> {
+ private BigInteger netAddress;
+ public int networkMask;
+ private boolean included;
+ private boolean isV4;
+
+
+ @Override
+ public int compareTo(ipAddress another) {
+ int comp = getFirstAddress().compareTo(another.getFirstAddress());
+ if (comp != 0)
+ return comp;
+
+ // bigger mask means smaller address block
+ if (networkMask > another.networkMask)
+ return -1;
+ else if (another.networkMask == networkMask)
+ return 0;
+ else
+ return 1;
+
+
+ }
+
+ public ipAddress(CIDRIP ip, boolean include) {
+ included = include;
+ netAddress = BigInteger.valueOf(ip.getInt());
+ networkMask = ip.len;
+ isV4 = true;
+ }
+
+ public ipAddress(Inet6Address address, int mask, boolean include) {
+ networkMask = mask;
+ included = include;
+
+ int s = 128;
+
+ netAddress = BigInteger.ZERO;
+ for (byte b : address.getAddress()) {
+ s -= 16;
+ netAddress = netAddress.add(BigInteger.valueOf(b).shiftLeft(s));
+ }
+ }
+
+ public BigInteger getLastAddress() {
+ return getMaskedAddress(true);
+ }
+
+
+ public BigInteger getFirstAddress() {
+ return getMaskedAddress(false);
+ }
+
+
+ private BigInteger getMaskedAddress(boolean one) {
+ BigInteger numAddress = netAddress;
+
+ int numBits;
+ if (isV4) {
+ numBits = 32 - networkMask;
+ } else {
+ numBits = 128 - networkMask;
+ }
+
+ for (int i = 0; i < numBits; i++) {
+ if (one)
+ numAddress = numAddress.setBit(i);
+ else
+ numAddress = numAddress.clearBit(i);
+ }
+ return numAddress;
+ }
+
+
+ @Override
+ public String toString() {
+ //String in = included ? "+" : "-";
+ if (isV4)
+ return String.format("%s/%d", getIPv4Address(), networkMask);
+ else
+ return String.format("%s/%d", getIPv6Address(), networkMask);
+ }
+
+ ipAddress(BigInteger baseAddress, int mask, boolean included, boolean isV4) {
+ this.netAddress = baseAddress;
+ this.networkMask = mask;
+ this.included = included;
+ this.isV4 = isV4;
+ }
+
+
+ public ipAddress[] split() {
+ ipAddress firsthalf = new ipAddress(getFirstAddress(), networkMask + 1, included, isV4);
+ ipAddress secondhalf = new ipAddress(firsthalf.getLastAddress().add(BigInteger.ONE), networkMask + 1, included, isV4);
+ assert secondhalf.getLastAddress().equals(getLastAddress());
+ return new ipAddress[]{firsthalf, secondhalf};
+ }
+
+ String getIPv4Address() {
+ assert (isV4);
+ assert (netAddress.longValue() <= 0xffffffffl);
+ assert (netAddress.longValue() >= 0);
+ long ip = netAddress.longValue();
+ return String.format("%d.%d.%d.%d", (ip >> 24) % 256, (ip >> 16) % 256, (ip >> 8) % 256, ip % 256);
+ }
+
+ String getIPv6Address() {
+ assert (!isV4);
+ BigInteger r = netAddress;
+ if (r.longValue() == 0)
+ return "::";
+
+ Vector<String> parts = new Vector<String>();
+ while (r.compareTo(BigInteger.ZERO) == 1) {
+ parts.add(0, String.format("%x", r.mod(BigInteger.valueOf(256)).longValue()));
+ r = r.shiftRight(16);
+ }
+
+ return TextUtils.join(":", parts);
+ }
+
+ public boolean containsNet(ipAddress network) {
+ return getFirstAddress().compareTo(network.getFirstAddress()) != 1 &&
+ getLastAddress().compareTo(network.getLastAddress()) != -1;
+ }
+ }
+
+
+ TreeSet<ipAddress> ipAddresses = new TreeSet<ipAddress>();
+
+
+ public Collection<ipAddress> getNetworks(boolean included) {
+ Vector<ipAddress> ips = new Vector<ipAddress>();
+ for (ipAddress ip : ipAddresses) {
+ if (ip.included == included)
+ ips.add(ip);
+ }
+ return ips;
+ }
+
+ public void clear() {
+ ipAddresses.clear();
+ }
+
+
+ void addIP(CIDRIP cidrIp, boolean include) {
+
+ ipAddresses.add(new ipAddress(cidrIp, include));
+ }
+
+ void addIPv6(Inet6Address address, int mask, boolean included) {
+ ipAddresses.add(new ipAddress(address, mask, included));
+ }
+
+ TreeSet<ipAddress> generateIPList() {
+ TreeSet<ipAddress> ipsSorted = new TreeSet<ipAddress>(ipAddresses);
+ Iterator<ipAddress> it = ipsSorted.iterator();
+
+ ipAddress currentNet = null;
+ if (it.hasNext())
+ currentNet = it.next();
+ while (it.hasNext()) {
+ // Check if it and the next of it are compatbile
+ ipAddress nextNet = it.next();
+
+ assert currentNet != null;
+ if (currentNet.getLastAddress().compareTo(nextNet.getFirstAddress()) == -1) {
+ // Everything good, no overlapping nothing to do
+ currentNet = nextNet;
+ } else {
+ // This network is smaller or equal to the next but has the same base address
+ if (currentNet.getFirstAddress().equals(nextNet.getFirstAddress()) && currentNet.networkMask >= nextNet.networkMask) {
+ if (currentNet.included == nextNet.included) {
+ ipsSorted.remove(currentNet);
+ } else {
+
+ // our currentnet is included in next and nextnet needs to be split
+ ipsSorted.remove(nextNet);
+ ipAddress[] newNets = nextNet.split();
+
+ if (newNets[0].getLastAddress().equals(currentNet.getLastAddress())) {
+ assert (newNets[0].networkMask == currentNet.networkMask);
+ // Don't add the lower half that would conflict with currentNet
+ } else {
+ ipsSorted.add(newNets[0]);
+ }
+
+ ipsSorted.add(newNets[1]);
+ }
+ } else {
+ assert (currentNet.networkMask < nextNet.networkMask);
+ assert (nextNet.getFirstAddress().compareTo(currentNet.getFirstAddress()) == 1);
+ // This network is bigger than the next and last ip of current >= next
+ assert (currentNet.getLastAddress().compareTo(nextNet.getLastAddress()) != -1);
+
+ if (currentNet.included == nextNet.included) {
+ ipsSorted.remove(nextNet);
+ } else {
+ ipsSorted.remove(currentNet);
+ ipAddress[] newNets = currentNet.split();
+
+ ipsSorted.add(newNets[0]);
+
+ if (newNets[1].networkMask == nextNet.networkMask) {
+ assert (newNets[1].getFirstAddress().equals(nextNet.getFirstAddress()));
+ assert (newNets[1].getLastAddress().equals(currentNet.getLastAddress()));
+ } else {
+ ipsSorted.add(newNets[1]);
+ }
+ }
+ }
+ // Reset iterator
+ it = ipsSorted.iterator();
+ currentNet = it.next();
+ }
+
+ }
+
+ return ipsSorted;
+ }
+
+ Collection<ipAddress> getPositiveIPList() {
+ TreeSet<ipAddress> ipsSorted = generateIPList();
+
+ Vector<ipAddress> ips = new Vector<ipAddress>();
+ for (ipAddress ia : ipsSorted) {
+ if (ia.included)
+ ips.add(ia);
+ }
+ return ips;
+ }
+
+}
diff --git a/src/de/blinkt/openvpn/core/OpenVpnManagementThread.java b/src/de/blinkt/openvpn/core/OpenVpnManagementThread.java
index 2fa407ca..5fa70cc8 100644
--- a/src/de/blinkt/openvpn/core/OpenVpnManagementThread.java
+++ b/src/de/blinkt/openvpn/core/OpenVpnManagementThread.java
@@ -379,9 +379,17 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
mOpenVPNService.setDomain(extra);
} else if (needed.equals("ROUTE")) {
String[] routeparts = extra.split(" ");
- mOpenVPNService.addRoute(routeparts[0], routeparts[1]);
+
+ if(routeparts.length>3) {
+ assert(routeparts[3].equals("dev"));
+ mOpenVPNService.addRoute(routeparts[0], routeparts[1], routeparts[2], routeparts[4]);
+ } else {
+ mOpenVPNService.addRoute(routeparts[0], routeparts[1], routeparts[2], null);
+ }
+
} else if (needed.equals("ROUTE6")) {
- mOpenVPNService.addRoutev6(extra);
+ String[] routeparts = extra.split(" ");
+ mOpenVPNService.addRoutev6(routeparts[0],routeparts[1]);
} else if (needed.equals("IFCONFIG")) {
String[] ifconfigparts = extra.split(" ");
int mtu = Integer.parseInt(ifconfigparts[2]);
diff --git a/src/de/blinkt/openvpn/core/OpenVpnService.java b/src/de/blinkt/openvpn/core/OpenVpnService.java
index 3de701b1..e485ee73 100644
--- a/src/de/blinkt/openvpn/core/OpenVpnService.java
+++ b/src/de/blinkt/openvpn/core/OpenVpnService.java
@@ -25,10 +25,15 @@ import de.blinkt.openvpn.core.VpnStatus.StateListener;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Vector;
+import static de.blinkt.openvpn.core.NetworkSpace.*;
import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.*;
public class OpenVpnService extends VpnService implements StateListener, Callback, ByteCountListener {
@@ -41,8 +46,8 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
private static final int OPENVPN_STATUS = 1;
private static boolean mNotificationAlwaysVisible = false;
private final Vector<String> mDnslist = new Vector<String>();
- private final Vector<CIDRIP> mRoutes = new Vector<CIDRIP>();
- private final Vector<String> mRoutesv6 = new Vector<String>();
+ private final NetworkSpace mRoutes = new NetworkSpace();
+ private final NetworkSpace mRoutesv6 = new NetworkSpace();
private final IBinder mBinder = new LocalBinder();
private Thread mProcessThread = null;
private VpnProfile mProfile;
@@ -255,8 +260,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
mDeviceStateReceiver = null;
}
- public void userPause (boolean shouldBePaused)
- {
+ public void userPause(boolean shouldBePaused) {
if (mDeviceStateReceiver != null)
mDeviceStateReceiver.userPause(shouldBePaused);
}
@@ -349,7 +353,6 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
}
-
Runnable processThread;
if (mOvpn3) {
@@ -396,21 +399,21 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
}
- private String getTunConfigString()
- {
+ private String getTunConfigString() {
// The format of the string is not important, only that
// two identical configurations produce the same result
- String cfg="TUNCFG UNQIUE STRING ips:";
-
- if (mLocalIP!=null)
- cfg+=mLocalIP.toString();
- if (mLocalIPv6!=null)
- cfg+=mLocalIPv6.toString();
-
- cfg+= "routes: " + TextUtils.join("|",mRoutes) + TextUtils.join("|",mRoutesv6);
- cfg+= "dns: " + TextUtils.join("|",mDnslist);
- cfg+= "domain: " + mDomain;
- cfg+= "mtu: " + mMtu;
+ String cfg = "TUNCFG UNQIUE STRING ips:";
+
+ if (mLocalIP != null)
+ cfg += mLocalIP.toString();
+ if (mLocalIPv6 != null)
+ cfg += mLocalIPv6.toString();
+
+ cfg += "routes: " + TextUtils.join("|", mRoutes.getNetworks(true)) + TextUtils.join("|", mRoutesv6.getNetworks(true));
+ cfg += "excl. routes:" + TextUtils.join("|", mRoutes.getNetworks(false)) + TextUtils.join("|", mRoutesv6.getNetworks(false));
+ cfg += "dns: " + TextUtils.join("|", mDnslist);
+ cfg += "domain: " + mDomain;
+ cfg += "mtu: " + mMtu;
return cfg;
}
@@ -455,20 +458,19 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
builder.setMtu(mMtu);
- for (CIDRIP route : mRoutes) {
+ for (NetworkSpace.ipAddress route : mRoutes.getPositiveIPList()) {
try {
- builder.addRoute(route.mIp, route.len);
+ builder.addRoute(route.getIPv4Address(), route.networkMask);
} catch (IllegalArgumentException ia) {
VpnStatus.logError(getString(R.string.route_rejected) + route + " " + ia.getLocalizedMessage());
}
}
- for (String v6route : mRoutesv6) {
+ for (NetworkSpace.ipAddress route6 : mRoutesv6.getPositiveIPList()) {
try {
- String[] v6parts = v6route.split("/");
- builder.addRoute(v6parts[0], Integer.parseInt(v6parts[1]));
+ builder.addRoute(route6.getIPv6Address(), route6.networkMask);
} catch (IllegalArgumentException ia) {
- VpnStatus.logError(getString(R.string.route_rejected) + v6route + " " + ia.getLocalizedMessage());
+ VpnStatus.logError(getString(R.string.route_rejected) + route6 + " " + ia.getLocalizedMessage());
}
}
@@ -477,9 +479,10 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
VpnStatus.logInfo(R.string.last_openvpn_tun_config);
VpnStatus.logInfo(R.string.local_ip_info, mLocalIP.mIp, mLocalIP.len, mLocalIPv6, mMtu);
- VpnStatus.logInfo(R.string.dns_server_info, joinString(mDnslist), mDomain);
- VpnStatus.logInfo(R.string.routes_info, joinString(mRoutes));
- VpnStatus.logInfo(R.string.routes_info6, joinString(mRoutesv6));
+ VpnStatus.logInfo(R.string.dns_server_info, TextUtils.join(", ", mDnslist), mDomain);
+ VpnStatus.logInfo(R.string.routes_info_incl, TextUtils.join(", ", mRoutes.getNetworks(true)), TextUtils.join(", ", mRoutesv6.getNetworks(true)));
+ VpnStatus.logInfo(R.string.routes_info_excl, TextUtils.join(", ", mRoutes.getNetworks(false)),TextUtils.join(", ", mRoutesv6.getNetworks(false)));
+ VpnStatus.logDebug(R.string.routes_debug, TextUtils.join(", ", mRoutes.getPositiveIPList()), TextUtils.join(", ", mRoutesv6.getPositiveIPList()));
String session = mProfile.mName;
if (mLocalIP != null && mLocalIPv6 != null)
@@ -518,18 +521,6 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
}
- // Ugly, but java has no such method
- private <T> String joinString(Vector<T> vec) {
- String ret = "";
- if (vec.size() > 0) {
- ret = vec.get(0).toString();
- for (int i = 1; i < vec.size(); i++) {
- ret = ret + ", " + vec.get(i).toString();
- }
- }
- return ret;
- }
-
public void addDNS(String dns) {
mDnslist.add(dns);
}
@@ -540,8 +531,17 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
}
}
- public void addRoute(String dest, String mask) {
+ public void addRoute(String dest, String mask, String gateway, String device) {
CIDRIP route = new CIDRIP(dest, mask);
+ boolean include = isAndroidTunDevice(device);
+
+ NetworkSpace.ipAddress gatewayIP = new NetworkSpace.ipAddress(new CIDRIP(gateway, 32),false);
+
+ NetworkSpace.ipAddress localNet = new NetworkSpace.ipAddress(mLocalIP,true);
+ if (localNet.containsNet(gatewayIP))
+ include =true;
+
+
if (route.len == 32 && !mask.equals("255.255.255.255")) {
VpnStatus.logWarning(R.string.route_not_cidr, dest, mask);
}
@@ -549,11 +549,30 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
if (route.normalise())
VpnStatus.logWarning(R.string.route_not_netip, dest, route.len, route.mIp);
- mRoutes.add(route);
+ mRoutes.addIP(route, include);
+ }
+
+ public void addRoutev6(String network, String device) {
+ String[] v6parts = network.split("/");
+ boolean included = isAndroidTunDevice(device);
+
+ // Tun is opened after ROUTE6, no device name may be present
+
+ try {
+ Inet6Address ip = (Inet6Address) InetAddress.getAllByName(v6parts[0])[0];
+ int mask = Integer.parseInt(v6parts[1]);
+ mRoutesv6.addIPv6(ip, mask, included);
+
+ } catch (UnknownHostException e) {
+ VpnStatus.logException(e);
+ }
+
+
}
- public void addRoutev6(String extra) {
- mRoutesv6.add(extra);
+ private boolean isAndroidTunDevice(String device) {
+ return device!=null &&
+ (device.startsWith("tun") || "(null)".equals(device) || "vpnservice-tun".equals(device));
}
public void setMtu(int mtu) {
@@ -657,9 +676,9 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
public String getTunReopenStatus() {
String currentConfiguration = getTunConfigString();
- if(currentConfiguration.equals(mLastTunCfg))
+ if (currentConfiguration.equals(mLastTunCfg))
return "NOACTION";
- else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
+ else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
return "OPEN_AFTER_CLOSE";
else
return "OPEN_BEFORE_CLOSE";
diff --git a/src/de/blinkt/openvpn/core/VpnStatus.java b/src/de/blinkt/openvpn/core/VpnStatus.java
index f2953240..d146aef8 100644
--- a/src/de/blinkt/openvpn/core/VpnStatus.java
+++ b/src/de/blinkt/openvpn/core/VpnStatus.java
@@ -479,7 +479,12 @@ public class VpnStatus {
newLogItem(new LogItem(LogLevel.INFO, resourceId, args));
}
- private synchronized static void newLogItem(LogItem logItem) {
+ public static void logDebug(int resourceId, Object... args) {
+ newLogItem(new LogItem(LogLevel.DEBUG, resourceId, args));
+ }
+
+
+ private synchronized static void newLogItem(LogItem logItem) {
logbuffer.addLast(logItem);
if(logbuffer.size()>MAXLOGENTRIES)
logbuffer.removeFirst();