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