In Android 4.4 it is not possible to open a new tun device and then close
the old tun device without breaking the whole VPNService stack until the
device is rebooted.
Add new management method to ask the UI what method should be taken to
ensure the optimal solution for the situation. Then do open-before-close
or close-before-open inside open_tun() as requested.
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <
1395407925-25518-4-git-send-email-arne@rfc2549.org>
URL: http://article.gmane.org/gmane.network.openvpn.devel/8373
Signed-off-by: Gert Doering <gert@greenie.muc.de>
#ifdef TARGET_ANDROID
/* If we emulate persist-tun on android we still have to open a new tun and
- then close the old */
+ * then close the old */
int oldtunfd=-1;
if (c->c1.tuntap)
- oldtunfd = c->c1.tuntap->fd;
+ oldtunfd = c->c1.tuntap->fd;
#endif
/* initialize (but do not open) tun/tap object */
do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list,
c->c1.tuntap, c->plugins, c->c2.es);
}
-
+#ifdef TARGET_ANDROID
+ /* Store the old fd inside the fd so open_tun can use it */
+ c->c1.tuntap->fd = oldtunfd;
+#endif
/* open the tun device */
open_tun (c->options.dev, c->options.dev_type, c->options.dev_node,
c->c1.tuntap);
-#ifdef TARGET_ANDROID
- if (oldtunfd>=0)
- close(oldtunfd);
-#endif
+
/* set the hardware address */
if (c->options.lladdr)
set_lladdr(c->c1.tuntap->actual_name, c->options.lladdr, c->c2.es);
{
if ((flags & CC_USR1_TO_HUP)
|| (c->sig->source == SIG_SOURCE_HARD && (flags & CC_HARD_USR1_TO_HUP)))
- c->sig->signal_received = SIGHUP;
+ {
+ c->sig->signal_received = SIGHUP;
+ c->sig->signal_text = "close_context usr1 to hup";
+ }
}
if (!(flags & CC_NO_CLOSE))
management_query_user_pass(management, &up , command, GET_USER_PASS_NEED_OK,(void*) 0);
return strcmp ("ok", up.password)==0;
}
+
+/*
+ * In Android 4.4 it is not possible to open a new tun device and then close the
+ * old tun device without breaking the whole VPNService stack until the device
+ * is rebooted. This management method ask the UI what method should be taken to
+ * ensure the optimal solution for the situation
+ */
+int managment_android_persisttun_action (struct management *man)
+{
+ struct user_pass up;
+ CLEAR(up);
+ strcpy(up.username,"tunmethod");
+ management_query_user_pass(management, &up , "PERSIST_TUN_ACTION",
+ GET_USER_PASS_NEED_OK,(void*) 0);
+ if (!strcmp("NOACTION", up.password))
+ return ANDROID_KEEP_OLD_TUN;
+ else if (!strcmp ("OPEN_AFTER_CLOSE", up.password))
+ return ANDROID_OPEN_AFTER_CLOSE;
+ else if (!strcmp ("OPEN_BEFORE_CLOSE", up.password))
+ return ANDROID_OPEN_BEFORE_CLOSE;
+ else
+ msg (M_ERR, "Got unrecognised '%s' from management for PERSIST_TUN_ACTION query", up.password);
+
+ ASSERT(0);
+ return ANDROID_OPEN_AFTER_CLOSE;
+}
+
+
#endif
static int
#ifdef TARGET_ANDROID
bool management_android_control (struct management *man, const char *command, const char *msg);
+
+#define ANDROID_KEEP_OLD_TUN 1
+#define ANDROID_OPEN_AFTER_CLOSE 2
+#define ANDROID_OPEN_BEFORE_CLOSE 3
+int managment_android_persisttun_action (struct management *man);
#endif
bool management_should_daemonize (struct management *man);
struct gc_arena gc = gc_new ();
bool opentun;
+ int oldtunfd = tt->fd;
+
for (i = 0; i < tt->options.dns_len; ++i) {
management_android_control (management, "DNSSERVER",
- print_in_addr_t(tt->options.dns[i], 0, &gc));
+ print_in_addr_t(tt->options.dns[i], 0, &gc));
}
if(tt->options.domain)
management_android_control (management, "DNSDOMAIN", tt->options.domain);
- opentun = management_android_control (management, "OPENTUN", dev);
+ int android_method = managment_android_persisttun_action (management);
+
+ /* Android 4.4 workaround */
+ if (oldtunfd >=0 && android_method == ANDROID_OPEN_AFTER_CLOSE)
+ {
+ close(oldtunfd);
+ openvpn_sleep(2);
+ }
+
+ if (oldtunfd >=0 && android_method == ANDROID_KEEP_OLD_TUN) {
+ /* keep the old fd */
+ opentun = true;
+ } else {
+ opentun = management_android_control (management, "OPENTUN", dev);
+ /* Pick up the fd from management interface after calling the
+ * OPENTUN command */
+ tt->fd = management->connection.lastfdreceived;
+ management->connection.lastfdreceived=-1;
+ }
- /* Pick up the fd from management interface after calling the OPENTUN command */
- tt->fd = management->connection.lastfdreceived;
- management->connection.lastfdreceived=-1;
+ if (oldtunfd>=0 && android_method == ANDROID_OPEN_BEFORE_CLOSE)
+ close(oldtunfd);
/* Set the actual name to a dummy name */
tt->actual_name = string_alloc (ANDROID_TUNNAME, NULL);