Index: plugins/l2tpipsec.c |
diff --git a/plugins/l2tpipsec.c b/plugins/l2tpipsec.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..51122aa45d8c5d40227b2970f7f14f57e25cd5ca |
--- /dev/null |
+++ b/plugins/l2tpipsec.c |
@@ -0,0 +1,226 @@ |
+/* |
+ * L2TP/IPsec VPN plugin. |
+ * |
+ * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ * |
+ */ |
+ |
+#ifdef HAVE_CONFIG_H |
+#include <config.h> |
+#endif |
+ |
+#include <string.h> |
+#include <errno.h> |
+#include <unistd.h> |
+#include <sys/types.h> |
+#include <sys/stat.h> |
+#include <fcntl.h> |
+ |
+#include <stdio.h> |
+#include <net/if.h> |
+ |
+#include <glib.h> |
+ |
+#define CONNMAN_API_SUBJECT_TO_CHANGE |
+#include <connman/plugin.h> |
+#include <connman/provider.h> |
+#include <connman/log.h> |
+#include <connman/task.h> |
+#include <connman/dbus.h> |
+#include <connman/inet.h> |
+ |
+#include "vpn.h" |
+ |
+#define _DBG_VPN(fmt, arg...) DBG(DBG_VPN, fmt, ## arg) |
+ |
+static DBusConnection *connection; |
+ |
+static DBusMessage *li_get_sec(struct connman_task *task, |
+ DBusMessage *msg, void *user_data) |
+{ |
+ const char *user, *passwd; |
+ struct connman_provider *provider = user_data; |
+ |
+ DBG(DBG_VPN, "li_get_sec: security request"); |
+ |
+ if (dbus_message_get_no_reply(msg) == FALSE) { |
+ DBusMessage *reply; |
+ |
+ user = connman_provider_get_string(provider, "L2TPIPsec.User"); |
+ passwd = connman_provider_get_string(provider, |
+ "L2TPIPsec.Password"); |
+ |
+ if (user == NULL || strlen(user) == 0 || |
+ passwd == NULL || strlen(passwd) == 0) |
Sam Leffler
2011/03/04 17:47:45
debug msg or connman_error?
kmixter1
2011/03/05 09:30:51
Done.
|
+ return NULL; |
+ |
+ reply = dbus_message_new_method_return(msg); |
+ if (reply == NULL) |
+ return NULL; |
+ |
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &user, |
+ DBUS_TYPE_STRING, &passwd, |
+ DBUS_TYPE_INVALID); |
+ |
+ return reply; |
+ } |
+ |
+ return NULL; |
+} |
+ |
+static int li_notify(DBusMessage *msg, struct connman_provider *provider) |
+{ |
+ DBusMessageIter iter, dict; |
+ const char *reason, *key, *value; |
+ char *ifname = NULL; |
+ char *dns1 = NULL; |
+ char *dns2 = NULL; |
+ struct connman_ipaddress ipaddr; |
+ |
+ DBG(DBG_VPN, "li_notify: interface up message"); |
+ |
+ dbus_message_iter_init(msg, &iter); |
+ |
+ dbus_message_iter_get_basic(&iter, &reason); |
+ dbus_message_iter_next(&iter); |
+ |
+ if (!provider) { |
Sam Leffler
2011/03/04 17:47:45
prevailing style is to compare ptr's to NULL
kmixter1
2011/03/05 09:30:51
Done.
|
+ connman_error("No provider found"); |
Sam Leffler
2011/03/04 17:47:45
uniquely identify; e.g. connman_error("%s: no prov
kmixter1
2011/03/05 09:30:51
Done.
|
+ return VPN_STATE_FAILURE; |
+ } |
+ |
+ if (strcmp(reason, "connect")) |
+ return VPN_STATE_DISCONNECT; |
+ |
+ memset(&ipaddr, 0, sizeof(ipaddr)); |
+ ipaddr.af = AF_INET; |
+ ipaddr.mask |= CONNMAN_IPCONFIG_AF; |
+ |
+ dbus_message_iter_recurse(&iter, &dict); |
+ |
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { |
+ DBusMessageIter entry; |
+ |
+ dbus_message_iter_recurse(&dict, &entry); |
+ dbus_message_iter_get_basic(&entry, &key); |
+ dbus_message_iter_next(&entry); |
+ dbus_message_iter_get_basic(&entry, &value); |
+ |
+ DBG(DBG_VPN, "%s = %s", key, value); |
Sam Leffler
2011/03/04 17:47:45
_DBG_VPN
kmixter1
2011/03/05 09:30:51
Done.
|
+ |
+ if (!strcmp(key, "INTERNAL_IP4_ADDRESS")) { |
+ ipaddr.local = g_strdup(value); |
+ ipaddr.mask |= CONNMAN_IPCONFIG_LOCAL; |
+ } else if (!strcmp(key, "EXTERNAL_IP4_ADDRESS")) { |
+ ipaddr.peer = g_strdup(value); |
kmixter1
2011/03/04 02:06:02
I'm getting 0.0.0.0 from the pppd plugin. Trying
kmixter1
2011/03/05 09:30:51
FWIW, I found the peer address and it's now return
|
+ ipaddr.mask |= CONNMAN_IPCONFIG_PEER; |
+ } else if (!strcmp(key, "DNS1")) { |
+ dns1 = g_strdup(value); |
+ } else if (!strcmp(key, "DNS2")) { |
+ dns2 = g_strdup(value); |
+ } else if (!strcmp(key, "INTERNAL_IFNAME")) { |
+ ifname = g_strdup(value); |
+ } |
+ |
+ dbus_message_iter_next(&dict); |
+ } |
+ |
+ ipaddr.dns_servers = g_try_new0(gchar *, 3); |
+ if (dns1 != NULL) { |
+ ipaddr.dns_servers[0] = dns1; |
+ if (dns2 != NULL) |
+ ipaddr.dns_servers[1] = dns2; |
+ ipaddr.mask |= CONNMAN_IPCONFIG_DNS; |
+ } |
+ |
+ /* TODO(kmixter): Should this go before or after ipconfig_set? |
+ No routes come through? */ |
Sam Leffler
2011/03/04 17:47:45
should not matter because the ipconfig settings ar
kmixter1
2011/03/05 09:30:51
Done.
|
+ if (vpn_set_ifname(provider, ifname) <0) { |
+ g_free(ifname); |
+ return VPN_STATE_FAILURE; |
+ } |
+ |
+ DBG(DBG_VPN, "li_notify: doing ipconfig set"); |
+ |
+ connman_provider_ipconfig_set(provider, &ipaddr); |
kmixter1
2011/03/04 02:06:02
So this is failing... it fails because ipv4config
Sam Leffler
2011/03/04 17:47:45
Can't comment on upstream. We allocate ipv4config
kmixter1
2011/03/05 09:30:51
Sort of - it tries to enter that state but ultimat
|
+ |
+ g_free(ifname); |
+ g_free(dns1); |
+ g_free(dns2); |
+ g_strfreev(ipaddr.dns_servers); /* TODO(kmixter): OK to free? */ |
+ |
+ return VPN_STATE_CONNECT; |
+} |
+ |
+static int li_connect(struct connman_provider *provider, |
+ struct connman_task *task, const char *if_name) |
+{ |
+#define OPT_STR(property, option) do { \ |
+ const char *s = connman_provider_get_string(provider, property); \ |
+ if (s != NULL) \ |
+ connman_task_add_argument(task, option, (char *)s); \ |
+} while (0) |
+#define OPT_BOOL(property, option) do { \ |
+ const char *s = connman_provider_get_string(provider, property); \ |
+ if (s != NULL) \ |
+ connman_task_add_argument(task, option, NULL); \ |
+} while (0) |
+ const char *vpnhost; |
+ int err, fd; |
+ |
+ if (connman_task_set_notify(task, "getsec", |
+ li_get_sec, provider)) |
+ return -ENOMEM; |
+ |
+ vpnhost = connman_provider_get_string(provider, "Host"); |
+ if (!vpnhost) { |
+ connman_error("%s: host not set; cannot enable VPN", __func__); |
+ return -EINVAL; |
+ } |
+ |
+ connman_task_add_argument(task, "--remote", (char *)vpnhost); |
+ // TODO: figure out the local address. |
+ connman_task_add_argument(task, "--local", "172.22.75.194"); |
+ connman_task_add_argument(task, "--pppd_plugin", |
+ SCRIPTDIR "/libppp-plugin.so"); |
+ OPT_STR("L2TPIPsec.CACert", "--server_ca_file"); |
+ OPT_STR("L2TPIPsec.Key", "--client_key_file"); |
+ OPT_STR("L2TPIPsec.Cert", "--client_cert_file"); |
+ OPT_STR("L2TPIPsec.PSK", "--psk_file"); |
+ OPT_STR("L2TPIPsec.User", "--user"); |
+ |
+ fd = fileno(stderr); |
+ err = connman_task_run(task, vpn_died, provider, |
+ NULL, &fd, &fd); |
+ if (err < 0) { |
+ connman_error("l2tpipsec failed to start"); |
+ return -EIO; |
+ } |
+ |
+ return 0; |
+} |
+ |
+static struct vpn_driver vpn_driver = { |
+ .flags = VPN_FLAG_NO_TUN, |
+ .notify = li_notify, |
+ .connect = li_connect, |
+}; |
+ |
+static int li_init(void) |
+{ |
+ connection = connman_dbus_get_connection(); |
+ |
+ return vpn_register("l2tpipsec", &vpn_driver, L2TPIPSEC); |
+} |
+ |
+static void li_exit(void) |
+{ |
+ vpn_unregister("l2tpipsec"); |
+ |
+ dbus_connection_unref(connection); |
+} |
+ |
+CONNMAN_PLUGIN_DEFINE(l2tpipsec, "l2tpipsec plugin", VERSION, |
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, li_init, li_exit) |