Am 10.05.12 00:09, schrieb Alon Bar-Lev:
> Hmmm... the fact that you are not using git, and create separate
> branch for the changes makes it very difficult to peak.
Sorry. I am new to git and the distributed version systems. I hope this
patch is better. I also pushed the changes to
https://github.com/schwabe/openvpn/.

> I see a mix of changes and a separate build system which I am not sure
> is needed. You build openvpn as a shared library, it is OK, I had this
> on my list, but why not use the current build to do so?
Building with the android build system was easier for me. Openvpn is
only build as a shared library but still used as a standalone
executable. This has to do with the apk packaging and the android market.
Transforming openvpn into a real library turned out to be more difficult
because there multiple points in the code where openvpn more or less
calls exit to clean up.

But before discussing the best way of building openvpn on android I
would rather like to get input on the other changes.


> I suggest you clone the repository at github, create a branch and
> order your changes.


that would mean to revert all changes, making the changes in small steps
and commiting each step? (I am still trying to learn how to work with git)

Arne
From b9a52d5ee919818a2e2ee525e0800e8e1f06b45f Mon Sep 17 00:00:00 2001
From: Arne Schwabe <a...@rfc2549.org>
Date: Wed, 9 May 2012 23:18:31 +0200
Subject: [PATCH 1/1] Openvpn for Android ICS API

---
 src/openvpn/error.c   |    2 +-
 src/openvpn/event.c   |    4 ++
 src/openvpn/init.c    |   12 +++++-
 src/openvpn/manage.c  |   99 ++++++++++++++++++++++++++++++++++++++++++++++++-
 src/openvpn/manage.h  |    5 ++
 src/openvpn/options.c |   16 +++++--
 src/openvpn/route.c   |   16 +++++++-
 src/openvpn/socket.c  |   14 ++++++-
 src/openvpn/ssl.c     |    2 +
 src/openvpn/syshead.h |    2 +-
 src/openvpn/tun.c     |   51 ++++++++++++++++++++++++-
 src/openvpn/tun.h     |   22 ++++++++++-
 12 files changed, 228 insertions(+), 17 deletions(-)

diff --git a/src/openvpn/error.c b/src/openvpn/error.c
index d6ad639..e2e24b1 100644
--- a/src/openvpn/error.c
+++ b/src/openvpn/error.c
@@ -312,7 +312,7 @@ void x_msg (const unsigned int flags, const char *format, 
...)
        }
     }
 
-  if (!(flags & M_MSG_VIRT_OUT))
+  if (!(flags & M_MSG_VIRT_OUT) )
     {
       if (use_syslog && !std_redir && !forked)
        {
diff --git a/src/openvpn/event.c b/src/openvpn/event.c
index 2a13e1c..0463d98 100644
--- a/src/openvpn/event.c
+++ b/src/openvpn/event.c
@@ -753,6 +753,10 @@ po_wait (struct event_set *es, const struct timeval *tv, 
struct event_set_return
              ++out;
              ++j;
            }
+      else if(pfdp->revents==0x0020) 
+        {
+            openvpn_exit (OPENVPN_EXIT_STATUS_ERROR);
+        }
          else if (pfdp->revents)
            {
              msg (D_EVENT_ERRORS, "Error: poll: unknown revents=0x%04x", 
(unsigned int)pfdp->revents);
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index 61ced5d..17e4f4a 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -1478,6 +1478,13 @@ do_open_tun (struct context *c)
          do_ifconfig (c->c1.tuntap, guess, TUN_MTU_SIZE (&c->c2.frame), 
c->c2.es);
        }
 
+        /* possibly add routes */
+        if(ifconfig_order() == ROUTE_BEFORE_TUN) {
+            if (!c->options.route_delay_defined)
+                do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list,
+                          c->c1.tuntap, c->plugins, c->c2.es);
+        }
+
       /* open the tun device */
       open_tun (c->options.dev, c->options.dev_type, c->options.dev_node,
                c->c1.tuntap);
@@ -1509,10 +1516,11 @@ do_open_tun (struct context *c)
                   c->c2.es);
 
       /* possibly add routes */
+        if(ifconfig_order() == ROUTE_AFTER_TUN) {
       if (!c->options.route_delay_defined)
        do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list,
                  c->c1.tuntap, c->plugins, c->c2.es);
-
+        }
       /*
        * Did tun/tap driver give us an MTU?
        */
@@ -2467,7 +2475,7 @@ do_option_warnings (struct context *c)
 {
   const struct options *o = &c->options;
 
-#if 1 /* JYFIXME -- port warning */
+#if 0 /* JYFIXME -- port warning */
   if (!o->ce.port_option_used && (o->ce.local_port == OPENVPN_PORT && 
o->ce.remote_port == OPENVPN_PORT))
     msg (M_WARN, "IMPORTANT: OpenVPN's default port number is now %d, based on 
an official port number assignment by IANA.  OpenVPN 2.0-beta16 and earlier 
used 5000 as the default port.",
         OPENVPN_PORT);
diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c
index 1dddd41..f7ca8e1 100644
--- a/src/openvpn/manage.c
+++ b/src/openvpn/manage.c
@@ -58,6 +58,9 @@
 #define MANAGEMENT_ECHO_FLAGS 0
 #endif
 
+#include <android/log.h>
+
+
 /* tag for blank username/password */
 static const char blank_up[] = "[[BLANK]]";
 
@@ -66,6 +69,9 @@ struct management *management; /* GLOBAL */
 /* static forward declarations */
 static void man_output_standalone (struct management *man, volatile int 
*signal_received);
 static void man_reset_client_socket (struct management *man, const bool 
exiting);
+static ssize_t write_fd (int fd, void *ptr, size_t nbytes, int flags, int 
sendfd);
+static ssize_t read_fd(int fd, void *ptr, size_t nbytes, int flags, int 
*recvfd);
+
 
 static void
 man_help ()
@@ -1805,6 +1811,7 @@ man_io_error (struct management *man, const char *prefix)
     return false;
 }
 
+
 static int
 man_read (struct management *man)
 {
@@ -1813,8 +1820,19 @@ man_read (struct management *man)
    */
   unsigned char buf[256];
   int len = 0;
+  int fd = -1;
 
+#ifdef TARGET_ANDROID
+    len = read_fd (man->connection.sd_cli, buf, sizeof (buf), MSG_NOSIGNAL, 
&fd);
+    __android_log_print(ANDROID_LOG_DEBUG,"openvpn-dbg","read_fd %d %d", len, 
fd);
+    if(fd >= 0) {
+        man->connection.lastfdreceived = fd;
+        if(len == 0) // No data message but a fd, return without resetting 
socket...
+            return 0;
+    }
+#else
   len = recv (man->connection.sd_cli, buf, sizeof (buf), MSG_NOSIGNAL);
+#endif
   if (len == 0)
     {
       man_reset_client_socket (man, false);
@@ -1891,6 +1909,12 @@ man_write (struct management *man)
   if (buf && BLEN (buf))
     {
       const int len = min_int (size_hint, BLEN (buf));
+#ifdef TARGET_ANDROID
+        if (man->connection.fdtosend > 0) {
+            sent = write_fd (man->connection.sd_cli, BPTR (buf), len, 
MSG_NOSIGNAL,man->connection.fdtosend);
+            man->connection.fdtosend = -1;
+        } else
+#endif
       sent = send (man->connection.sd_cli, BPTR (buf), len, MSG_NOSIGNAL);
       if (sent >= 0)
        {
@@ -2886,7 +2910,7 @@ management_event_loop_n_seconds (struct management *man, 
int sec)
  * Get a username/password from management channel in standalone mode.
  */
 bool
-management_query_user_pass (struct management *man,
+    management_query_user_pass (struct management *man,
                            struct user_pass *up,
                            const char *type,
                            const unsigned int flags,
@@ -3084,6 +3108,79 @@ management_query_rsa_sig (struct management *man,
 
 #endif
 
+#ifdef TARGET_ANDROID
+static ssize_t write_fd (int fd, void *ptr, size_t nbytes, int flags, int 
sendfd)
+{
+    struct msghdr msg;
+    struct iovec iov[1];
+    
+    union {
+        struct cmsghdr cm;
+        char    control[CMSG_SPACE(sizeof(int))];
+    } control_un;
+    struct cmsghdr *cmptr;
+    
+    msg.msg_control = control_un.control;
+    msg.msg_controllen = sizeof(control_un.control);
+    
+    cmptr = CMSG_FIRSTHDR(&msg);
+    cmptr->cmsg_len = CMSG_LEN(sizeof(int));
+    cmptr->cmsg_level = SOL_SOCKET;
+    cmptr->cmsg_type = SCM_RIGHTS;
+    *((int *) CMSG_DATA(cmptr)) = sendfd;
+    
+    msg.msg_name = NULL;
+    msg.msg_namelen = 0;
+    
+    iov[0].iov_base = ptr;
+    iov[0].iov_len = nbytes;
+    msg.msg_iov = iov;
+    msg.msg_iovlen = 1;
+    
+    return (sendmsg(fd, &msg, flags));
+}
+
+static ssize_t read_fd(int fd, void *ptr, size_t nbytes, int flags, int 
*recvfd)
+{
+    struct msghdr msghdr;
+    struct iovec iov[1];
+    ssize_t n;
+    
+    union {
+        struct cmsghdr cm;
+        char     control[CMSG_SPACE(sizeof (int))];
+    } control_un;
+    struct cmsghdr  *cmptr;
+    
+    msghdr.msg_control  = control_un.control;
+    msghdr.msg_controllen = sizeof(control_un.control);
+    
+    msghdr.msg_name = NULL;
+    msghdr.msg_namelen = 0;
+    
+    iov[0].iov_base = ptr;
+    iov[0].iov_len = nbytes;
+    msghdr.msg_iov = iov;
+    msghdr.msg_iovlen = 1;
+    
+    if ( (n = recvmsg(fd, &msghdr, flags)) <= 0)
+        return (n);
+    
+    if ( (cmptr = CMSG_FIRSTHDR(&msghdr)) != NULL &&
+        cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
+        if (cmptr->cmsg_level != SOL_SOCKET)
+            msg (M_ERR, "control level != SOL_SOCKET");
+        if (cmptr->cmsg_type != SCM_RIGHTS)
+            msg (M_ERR, "control type != SCM_RIGHTS");
+        *recvfd = *((int *) CMSG_DATA(cmptr));
+    } else
+        *recvfd = -1;           /* descriptor was not passed */
+    
+    return (n);
+}
+#endif
+
+
 /*
  * Return true if management_hold() would block
  */
diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h
index f681f8d..c7ffb42 100644
--- a/src/openvpn/manage.h
+++ b/src/openvpn/manage.h
@@ -303,6 +303,11 @@ struct man_connection {
 #ifdef MANAGMENT_EXTERNAL_KEY
   struct buffer_list *rsa_sig;
 #endif
+#ifdef TARGET_ANDROID
+    int fdtosend;
+    int lastfdreceived;
+#endif
+    
 };
 
 struct management
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 7769625..a2d0f6e 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -1140,7 +1140,9 @@ show_tuntap_options (const struct tuntap_options *o)
 }
 
 #endif
+#endif
 
+#if defined(WIN32) || defined(TARGET_ANDROID) 
 static void
 dhcp_option_address_parse (const char *name, const char *parm, in_addr_t 
*array, int *len, int msglevel)
 {
@@ -5469,6 +5471,11 @@ add_option (struct options *options,
       options->occ = false;
     }
 #endif
+  else if (streq (p[0], "tmp-dir") && p[1])
+  {
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+      options->tmp_dir = p[1];
+  }
 #if P2MP
 #if P2MP_SERVER
   else if (streq (p[0], "server") && p[1] && p[2])
@@ -5750,11 +5757,6 @@ add_option (struct options *options,
       warn_multiple_script (options->learn_address_script, "learn-address");
       options->learn_address_script = p[1];
     }
-  else if (streq (p[0], "tmp-dir") && p[1])
-    {
-      VERIFY_PERMISSION (OPT_P_GENERAL);
-      options->tmp_dir = p[1];
-    }
   else if (streq (p[0], "client-config-dir") && p[1])
     {
       VERIFY_PERMISSION (OPT_P_GENERAL);
@@ -6064,6 +6066,8 @@ add_option (struct options *options,
       to->ip_win32_type = index;
       to->ip_win32_defined = true; 
     }
+#endif
+#if defined(WIN32) || defined(TARGET_ANDROID)
   else if (streq (p[0], "dhcp-option") && p[1])
     {
       struct tuntap_options *o = &options->tuntap_options;
@@ -6115,6 +6119,8 @@ add_option (struct options *options,
        }
       o->dhcp_options = true;
     }
+#endif
+#ifdef WIN32
   else if (streq (p[0], "show-adapters"))
     {
       VERIFY_PERMISSION (OPT_P_GENERAL);
diff --git a/src/openvpn/route.c b/src/openvpn/route.c
index 7c25c77..99674e2 100644
--- a/src/openvpn/route.c
+++ b/src/openvpn/route.c
@@ -1344,6 +1344,17 @@ add_route (struct route *r,
   argv_msg (D_ROUTE, &argv);
   status = openvpn_execve_check (&argv, es, 0, "ERROR: Linux route add command 
failed");
 
+#elif defined (TARGET_ANDROID)
+
+    struct user_pass up;    
+    struct buffer out = alloc_buf_gc (64, &gc);
+
+    buf_printf (&out, "%s %s", network, netmask);
+
+    strcpy(up.username, buf_bptr(&out));
+    management_query_user_pass(management, &up , "ROUTE", 
GET_USER_PASS_NEED_OK,(void*) 0);
+
+
 #elif defined (WIN32)
   {
     DWORD ai = TUN_ADAPTER_INDEX_INVALID;
@@ -1847,7 +1858,8 @@ delete_route (struct route *r,
 
   argv_msg (D_ROUTE, &argv);
   openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD/NetBSD route delete 
command failed");
-
+#elif defined(TARGET_ANDROID)
+  msg (M_NONFATAL, "Sorry, deleting routes on Android is not possible. The 
VpnService API allows routes to be set on connect only.");
 #else
   msg (M_FATAL, "Sorry, but I don't know how to do 'route' commands on this 
operating system.  Try putting your routes in a --route-up script");
 #endif
@@ -2371,7 +2383,7 @@ show_routes (int msglev)
   gc_free (&gc);
 }
 
-#elif defined(TARGET_LINUX)
+#elif defined(TARGET_LINUX) || defined(TARGET_ANDROID)
 
 void
 get_default_gateway (struct route_gateway_info *rgi)
diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c
index 6b1f8d2..b92c282 100644
--- a/src/openvpn/socket.c
+++ b/src/openvpn/socket.c
@@ -38,6 +38,8 @@
 #include "ps.h"
 #include "manage.h"
 #include "misc.h"
+#include "manage.h"
+
 
 #include "memdbg.h"
 
@@ -857,7 +859,6 @@ create_socket_tcp (void)
       msg (M_SOCKERR, "TCP: Cannot setsockopt SO_LINGER on TCP socket");
   }
 #endif
-
   return sd;
 }
 
@@ -885,6 +886,7 @@ create_socket_udp (const unsigned int flags)
 #endif
     }
 #endif
+
   return sd;
 }
 
@@ -904,6 +906,7 @@ create_socket_udp6 (const unsigned int flags)
        msg(M_SOCKERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO");
     }
 #endif
+
   return sd;
 }
 
@@ -959,6 +962,15 @@ create_socket (struct link_socket *sock)
     {
       ASSERT (0);
     }
+#ifdef TARGET_ANDROID
+    struct user_pass up;
+    strcpy(up.username ,__func__);
+    management->connection.fdtosend = sock->sd;
+    management_query_user_pass(management, &up , "PROTECTFD", 
GET_USER_PASS_NEED_OK,(void*) 0);
+
+
+#endif
+    
 }
 
 /*
diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index 19512c0..9f570b9 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -1650,6 +1650,8 @@ push_peer_info(struct buffer *buf, struct tls_session 
*session)
       buf_printf (&out, "IV_PLAT=netbsd\n");
 #elif defined(TARGET_FREEBSD)
       buf_printf (&out, "IV_PLAT=freebsd\n");
+#elif defined(TARGET_ANDROID)
+      buf_printf(&out, "IV_PLAT=android\n");
 #elif defined(WIN32)
       buf_printf (&out, "IV_PLAT=win\n");
 #endif
diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h
index 3337764..8ce40f7 100644
--- a/src/openvpn/syshead.h
+++ b/src/openvpn/syshead.h
@@ -212,7 +212,7 @@
 #include <net/if_tap.h>
 #endif
 
-#ifdef TARGET_LINUX
+#if defined(TARGET_LINUX) || defined (TARGET_ANDROID)
 
 #if defined(HAVE_NETINET_IF_ETHER_H)
 #include <netinet/if_ether.h>
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index 633150f..158cd61 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -46,8 +46,9 @@
 #include "manage.h"
 #include "route.h"
 #include "win32.h"
-
 #include "memdbg.h"
+#include <string.h>
+
 
 #ifdef WIN32
 
@@ -768,6 +769,17 @@ do_ifconfig (struct tuntap *tt,
       tt->did_ifconfig = true;
 
 #endif /*ENABLE_IPROUTE*/
+#elif defined(TARGET_ANDROID)
+        
+        struct user_pass up;    
+        struct buffer out = alloc_buf_gc (64, &gc);
+        
+        buf_printf (&out, "%s %s %d", ifconfig_local, ifconfig_remote_netmask, 
tun_mtu);
+        
+        strcpy(up.username, buf_bptr(&out));
+        management_query_user_pass(management, &up , "IFCONFIG", 
GET_USER_PASS_NEED_OK,(void*) 0);
+        
+        
 #elif defined(TARGET_SOLARIS)
 
       /* Solaris 2.6 (and 7?) cannot set all parameters in one go...
@@ -1365,7 +1377,39 @@ close_tun_generic (struct tuntap *tt)
 
 #endif
 
-#if defined(TARGET_LINUX)
+#if defined(TARGET_LINUX) || defined(TARGET_ANDROID)
+
+#if defined (TARGET_ANDROID)
+void
+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct 
tuntap *tt)
+{
+    int i;
+    struct user_pass up;
+    struct gc_arena gc = gc_new ();
+    
+    for (i = 0; i < tt->options.dns_len; ++i) {
+        strcpy(up.username, print_in_addr_t(tt->options.dns[i], 0, &gc));
+        management_query_user_pass(management, &up , "DNSSERVER", 
GET_USER_PASS_NEED_OK,(void*) 0);
+    }
+
+    if(tt->options.domain) {
+        strcpy(up.username , tt->options.domain);
+        management_query_user_pass(management, &up , "DNSDOMAIN", 
GET_USER_PASS_NEED_OK,(void*) 0);
+    }
+    
+    strcpy(up.username , dev);
+    management_query_user_pass(management, &up , "OPENTUN", 
GET_USER_PASS_NEED_OK,(void*) 0);
+
+    tt->fd = management->connection.lastfdreceived;
+    management->connection.lastfdreceived=-1;
+    
+    if( (tt->fd < 0) || ! (strcmp("ok",up.password)==0)) {
+        msg (M_ERR, "ERROR: Cannot open TUN");
+    }
+    gc_free (&gc);
+}
+
+#else
 
 #ifdef HAVE_LINUX_IF_TUN_H     /* New driver support */
 
@@ -1411,7 +1455,7 @@ open_tun (const char *dev, const char *dev_type, const 
char *dev_node, struct tu
       if (!tt->ipv6)
        ifr.ifr_flags = IFF_NO_PI;
 
-#if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN)
+#if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN) && 
!defined(TARGET_ANDROID)
       ifr.ifr_flags |= IFF_ONE_QUEUE;
 #endif
 
@@ -1501,6 +1545,7 @@ open_tun (const char *dev, const char *dev_type, const 
char *dev_node, struct tu
 }
 
 #endif /* HAVE_LINUX_IF_TUN_H */
+#endif /* TARGET_ANDROID */
 
 #ifdef ENABLE_FEATURE_TUN_PERSIST
 
diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h
index 9bd990f..095e77e 100644
--- a/src/openvpn/tun.h
+++ b/src/openvpn/tun.h
@@ -38,7 +38,7 @@
 #include "proto.h"
 #include "misc.h"
 
-#ifdef WIN32
+#if defined(WIN32) || defined(TARGET_ANDROID)
 
 #define TUN_ADAPTER_INDEX_INVALID ((DWORD)-1)
 
@@ -76,6 +76,7 @@ struct tuntap_options {
 
   int netbios_node_type;     /* NBT 1,2,4,8 (46) */
 
+
 #define N_DHCP_ADDR 4        /* Max # of addresses allowed for
                                DNS, WINS, etc. */
 
@@ -292,11 +293,30 @@ ifconfig_order(void)
   return IFCONFIG_AFTER_TUN_OPEN;
 #elif defined(WIN32)
   return IFCONFIG_BEFORE_TUN_OPEN;
+#elif defined(TARGET_ANDROID)
+  return IFCONFIG_BEFORE_TUN_OPEN;
 #else
   return IFCONFIG_DEFAULT;
 #endif
 }
 
+#define ROUTE_BEFORE_TUN 0
+#define ROUTE_AFTER_TUN 1
+#define ROUTE_ORDER_DEFAULT ROUTE_AFTER_TUN
+
+static inline int
+route_order(void)
+{
+#if defined(TARGET_ANDROID)
+    return ROUTE_BEFORE_TUN;
+#else
+    return ROUTE_ORDER_DEFAULT;
+#endif
+}
+
+
+
+
 #ifdef WIN32
 
 #define TUN_PASS_BUFFER
-- 
1.7.5.4

Reply via email to