Chromium Code Reviews| 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) |