diff options
| author | Michael Biebl <biebl@debian.org> | 2012-06-29 20:12:44 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2012-06-29 20:12:44 +0200 |
| commit | 867254ea7c2b193fecf8cd36cc6e5dc53c290d92 (patch) | |
| tree | 7c698b403882736ab70c3efd524c3460f08c391c /src/vpn-manager | |
| parent | de06e5715e780baade318f3490ac7a4c9ce84e32 (diff) | |
Imported Upstream version 0.9.5.95 upstream/0.9.5.95
Diffstat (limited to 'src/vpn-manager')
| -rw-r--r-- | src/vpn-manager/Makefile.am | 2 | ||||
| -rw-r--r-- | src/vpn-manager/Makefile.in | 14 | ||||
| -rw-r--r-- | src/vpn-manager/nm-vpn-connection.c | 851 | ||||
| -rw-r--r-- | src/vpn-manager/nm-vpn-connection.h | 10 | ||||
| -rw-r--r-- | src/vpn-manager/nm-vpn-manager.c | 17 | ||||
| -rw-r--r-- | src/vpn-manager/nm-vpn-manager.h | 6 | ||||
| -rw-r--r-- | src/vpn-manager/nm-vpn-service.c | 20 |
7 files changed, 664 insertions, 256 deletions
diff --git a/src/vpn-manager/Makefile.am b/src/vpn-manager/Makefile.am index c3c5b525..12e316d8 100644 --- a/src/vpn-manager/Makefile.am +++ b/src/vpn-manager/Makefile.am @@ -7,6 +7,7 @@ INCLUDES = \ -I${top_srcdir}/src/generated \ -I${top_builddir}/src/generated \ -I${top_srcdir}/src/logging \ + -I${top_srcdir}/src/posix-signals \ -I${top_srcdir}/src \ -I${top_srcdir}/src/dns-manager \ -DVPN_NAME_FILES_DIR=\""$(sysconfdir)/NetworkManager/VPN"\" @@ -31,6 +32,7 @@ libvpn_manager_la_CPPFLAGS = \ libvpn_manager_la_LIBADD = \ $(top_builddir)/src/generated/libnm-generated.la \ $(top_builddir)/src/logging/libnm-logging.la \ + $(top_builddir)/src/posix-signals/libnm-posix-signals.la \ $(top_builddir)/libnm-util/libnm-util.la \ $(LIBNL_LIBS) \ $(DBUS_LIBS) \ diff --git a/src/vpn-manager/Makefile.in b/src/vpn-manager/Makefile.in index 9a7e5e42..64a9c8c3 100644 --- a/src/vpn-manager/Makefile.in +++ b/src/vpn-manager/Makefile.in @@ -47,7 +47,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d @@ -59,6 +59,7 @@ am__DEPENDENCIES_1 = libvpn_manager_la_DEPENDENCIES = \ $(top_builddir)/src/generated/libnm-generated.la \ $(top_builddir)/src/logging/libnm-logging.la \ + $(top_builddir)/src/posix-signals/libnm-posix-signals.la \ $(top_builddir)/libnm-util/libnm-util.la $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_libvpn_manager_la_OBJECTS = libvpn_manager_la-nm-vpn-manager.lo \ @@ -171,6 +172,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ INTLTOOL_MERGE = @INTLTOOL_MERGE@ INTLTOOL_PERL = @INTLTOOL_PERL@ INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ +INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@ +INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@ +INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@ +INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@ INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@ @@ -266,6 +271,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@ USE_NLS = @USE_NLS@ UUID_CFLAGS = @UUID_CFLAGS@ UUID_LIBS = @UUID_LIBS@ +VAPIGEN = @VAPIGEN@ +VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@ +VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ @@ -304,6 +312,8 @@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +intltool__v_merge_options_ = @intltool__v_merge_options_@ +intltool__v_merge_options_0 = @intltool__v_merge_options_0@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ @@ -333,6 +343,7 @@ INCLUDES = \ -I${top_srcdir}/src/generated \ -I${top_builddir}/src/generated \ -I${top_srcdir}/src/logging \ + -I${top_srcdir}/src/posix-signals \ -I${top_srcdir}/src \ -I${top_srcdir}/src/dns-manager \ -DVPN_NAME_FILES_DIR=\""$(sysconfdir)/NetworkManager/VPN"\" @@ -355,6 +366,7 @@ libvpn_manager_la_CPPFLAGS = \ libvpn_manager_la_LIBADD = \ $(top_builddir)/src/generated/libnm-generated.la \ $(top_builddir)/src/logging/libnm-logging.la \ + $(top_builddir)/src/posix-signals/libnm-posix-signals.la \ $(top_builddir)/libnm-util/libnm-util.la \ $(LIBNL_LIBS) \ $(DBUS_LIBS) \ diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index b391f1ec..5f64153b 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -43,7 +43,6 @@ #include "nm-properties-changed-signal.h" #include "nm-dbus-glib-types.h" #include "NetworkManagerUtils.h" -#include "nm-dns-manager.h" #include "nm-netlink-monitor.h" #include "nm-netlink-utils.h" #include "nm-glib-compat.h" @@ -78,16 +77,24 @@ typedef struct { NMDevice *parent_dev; gulong device_monitor; gulong device_ip4; + gulong device_ip6; NMVPNConnectionState vpn_state; NMVPNConnectionStateReason failure_reason; DBusGProxy *proxy; guint ipconfig_timeout; + gboolean has_ip4; NMIP4Config *ip4_config; guint32 ip4_internal_gw; + guint32 ip4_external_gw; + gboolean has_ip6; + NMIP6Config *ip6_config; + struct in6_addr *ip6_internal_gw; + struct in6_addr *ip6_external_gw; char *ip_iface; int ip_ifindex; char *banner; + guint32 mtu; struct rtnl_route *gw_route; } NMVPNConnectionPrivate; @@ -133,13 +140,61 @@ ac_state_from_vpn_state (NMVPNConnectionState vpn_state) } static void +call_plugin_disconnect (NMVPNConnection *self) +{ + NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + GError *error = NULL; + + if (priv->proxy) { + org_freedesktop_NetworkManager_VPN_Plugin_disconnect (priv->proxy, &error); + if (error) + nm_log_warn (LOGD_VPN, "error disconnecting VPN: %s", error->message); + g_clear_error (&error); + + g_object_unref (priv->proxy); + priv->proxy = NULL; + } +} + +static void +vpn_cleanup (NMVPNConnection *connection) +{ + NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + + if (priv->ip_ifindex) { + nm_system_iface_set_up (priv->ip_ifindex, FALSE, NULL); + /* FIXME: use AF_UNSPEC here when we have IPv6 support */ + nm_system_iface_flush_routes (priv->ip_ifindex, AF_INET); + nm_system_iface_flush_addresses (priv->ip_ifindex, AF_UNSPEC); + } + + if (priv->gw_route) { + nm_netlink_route_delete (priv->gw_route); + rtnl_route_put (priv->gw_route); + priv->gw_route = NULL; + } + + g_free (priv->banner); + priv->banner = NULL; + + g_free (priv->ip_iface); + priv->ip_iface = NULL; + priv->ip_ifindex = 0; + + /* Clear out connection secrets to ensure that the settings service + * gets asked for them next time the connection is activated. + */ + if (priv->connection) + nm_connection_clear_secrets (priv->connection); +} + +static void nm_vpn_connection_set_vpn_state (NMVPNConnection *connection, NMVPNConnectionState vpn_state, NMVPNConnectionStateReason reason) { NMVPNConnectionPrivate *priv; NMVPNConnectionState old_vpn_state; - char *ip_iface; g_return_if_fail (NM_IS_VPN_CONNECTION (connection)); @@ -155,10 +210,12 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection, nm_active_connection_set_state (NM_ACTIVE_CONNECTION (connection), ac_state_from_vpn_state (vpn_state)); - /* Save ip_iface since when the VPN goes down it may get freed - * before we're done with it. - */ - ip_iface = g_strdup (priv->ip_iface); + /* Clear any in-progress secrets request */ + if (priv->secrets_id) { + nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection), priv->secrets_id); + priv->secrets_id = 0; + } + priv->secrets_idx = SECRETS_REQ_SYSTEM; /* The connection gets destroyed by the VPN manager when it enters the * disconnected/failed state, but we need to keep it around for a bit @@ -166,35 +223,50 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection, */ g_object_ref (connection); - g_signal_emit (connection, signals[VPN_STATE_CHANGED], 0, vpn_state, reason); + g_signal_emit (connection, signals[VPN_STATE_CHANGED], 0, vpn_state, old_vpn_state, reason); g_object_notify (G_OBJECT (connection), NM_VPN_CONNECTION_VPN_STATE); - /* Call dispatcher after the event gets processed internally */ switch (vpn_state) { + case NM_VPN_CONNECTION_STATE_NEED_AUTH: + /* Kick off the secrets requests; first we get existing system secrets + * and ask the plugin if these are sufficient, next we get all existing + * secrets from system and from user agents and ask the plugin again, + * and last we ask the user for new secrets if required. + */ + get_secrets (connection, SECRETS_REQ_SYSTEM); + break; case NM_VPN_CONNECTION_STATE_ACTIVATED: + /* Secrets no longer needed now that we're connected */ + nm_connection_clear_secrets (priv->connection); + + /* Let dispatcher scripts know we're up and running */ nm_utils_call_dispatcher ("vpn-up", priv->connection, priv->parent_dev, - ip_iface, + priv->ip_iface, priv->ip4_config, - NULL); + priv->ip6_config); break; case NM_VPN_CONNECTION_STATE_FAILED: case NM_VPN_CONNECTION_STATE_DISCONNECTED: if (old_vpn_state == NM_VPN_CONNECTION_STATE_ACTIVATED) { + /* Let dispatcher scripts know we're about to go down */ nm_utils_call_dispatcher ("vpn-down", priv->connection, priv->parent_dev, - ip_iface, + priv->ip_iface, NULL, NULL); } + + /* Tear down and clean up the connection */ + call_plugin_disconnect (connection); + vpn_cleanup (connection); break; default: break; } - g_free (ip_iface); g_object_unref (connection); } @@ -230,11 +302,34 @@ device_ip4_config_changed (NMDevice *device, || !nm_device_get_ip4_config (device)) return; - if (priv->gw_route) - rtnl_route_put (priv->gw_route); + /* Re-add the VPN gateway route */ + if (priv->ip4_external_gw) { + if (priv->gw_route) + rtnl_route_put (priv->gw_route); + priv->gw_route = nm_system_add_ip4_vpn_gateway_route (priv->parent_dev, + priv->ip4_external_gw); + } +} + +static void +device_ip6_config_changed (NMDevice *device, + GParamSpec *pspec, + gpointer user_data) +{ + NMVPNConnection *vpn = NM_VPN_CONNECTION (user_data); + NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (vpn); + + if ( (priv->vpn_state != NM_VPN_CONNECTION_STATE_ACTIVATED) + || !nm_device_get_ip6_config (device)) + return; /* Re-add the VPN gateway route */ - priv->gw_route = nm_system_add_ip4_vpn_gateway_route (priv->parent_dev, priv->ip4_config); + if (priv->ip6_external_gw) { + if (priv->gw_route) + rtnl_route_put (priv->gw_route); + priv->gw_route = nm_system_add_ip6_vpn_gateway_route (priv->parent_dev, + priv->ip6_external_gw); + } } NMVPNConnection * @@ -271,6 +366,9 @@ nm_vpn_connection_new (NMConnection *connection, priv->device_ip4 = g_signal_connect (parent_device, "notify::" NM_DEVICE_IP4_CONFIG, G_CALLBACK (device_ip4_config_changed), self); + priv->device_ip6 = g_signal_connect (parent_device, "notify::" NM_DEVICE_IP6_CONFIG, + G_CALLBACK (device_ip6_config_changed), + self); if (!nm_active_connection_export (NM_ACTIVE_CONNECTION (self), connection, @@ -372,17 +470,18 @@ plugin_state_changed (DBusGProxy *proxy, } } +static char addr_to_string_buf[INET6_ADDRSTRLEN + 1]; + static const char * ip_address_to_string (guint32 numeric) { struct in_addr temp_addr; - static char buf[INET_ADDRSTRLEN + 1]; - memset (&buf, '\0', sizeof (buf)); + memset (&addr_to_string_buf, '\0', sizeof (addr_to_string_buf)); temp_addr.s_addr = numeric; - if (inet_ntop (AF_INET, &temp_addr, buf, INET_ADDRSTRLEN)) { - return buf; + if (inet_ntop (AF_INET, &temp_addr, addr_to_string_buf, INET_ADDRSTRLEN)) { + return addr_to_string_buf; } else { nm_log_warn (LOGD_VPN, "error converting IP4 address 0x%X", ntohl (temp_addr.s_addr)); @@ -390,115 +489,340 @@ ip_address_to_string (guint32 numeric) } } +static const char * +ip6_address_to_string (const struct in6_addr *addr) +{ + memset (addr_to_string_buf, '\0', sizeof (addr_to_string_buf)); + if (inet_ntop (AF_INET6, addr, addr_to_string_buf, INET6_ADDRSTRLEN)) { + return addr_to_string_buf; + } else { + nm_log_warn (LOGD_VPN, "error converting IP6 address"); + return NULL; + } +} + static void -print_vpn_config (NMIP4Config *config, - guint32 internal_gw, - const char *ip_iface, - const char *banner) +print_vpn_config (NMVPNConnection *connection) { + NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); NMIP4Address *addr; + NMIP6Address *addr6; char *dns_domain = NULL; guint32 num, i; - g_return_if_fail (config != NULL); - - addr = nm_ip4_config_get_address (config, 0); - - nm_log_info (LOGD_VPN, "VPN Gateway: %s", ip_address_to_string (nm_ip4_address_get_gateway (addr))); - if (internal_gw) - nm_log_info (LOGD_VPN, "Internal Gateway: %s", ip_address_to_string (internal_gw)); - nm_log_info (LOGD_VPN, "Tunnel Device: %s", ip_iface); - nm_log_info (LOGD_VPN, "Internal IP4 Address: %s", ip_address_to_string (nm_ip4_address_get_address (addr))); - nm_log_info (LOGD_VPN, "Internal IP4 Prefix: %d", nm_ip4_address_get_prefix (addr)); - nm_log_info (LOGD_VPN, "Internal IP4 Point-to-Point Address: %s", - ip_address_to_string (nm_ip4_config_get_ptp_address (config))); - nm_log_info (LOGD_VPN, "Maximum Segment Size (MSS): %d", nm_ip4_config_get_mss (config)); - - num = nm_ip4_config_get_num_routes (config); - for (i = 0; i < num; i++) { - NMIP4Route *route; - - route = nm_ip4_config_get_route (config, i); - nm_log_info (LOGD_VPN, "Static Route: %s/%d Next Hop: %s", - ip_address_to_string (nm_ip4_route_get_dest (route)), - nm_ip4_route_get_prefix (route), - ip_address_to_string (nm_ip4_route_get_next_hop (route))); - } + if (priv->ip4_external_gw) { + nm_log_info (LOGD_VPN, "VPN Gateway: %s", + ip_address_to_string (priv->ip4_external_gw)); + } else if (priv->ip6_external_gw) { + nm_log_info (LOGD_VPN, "VPN Gateway: %s", + ip6_address_to_string (priv->ip6_external_gw)); + } - nm_log_info (LOGD_VPN, "Forbid Default Route: %s", - nm_ip4_config_get_never_default (config) ? "yes" : "no"); + nm_log_info (LOGD_VPN, "Tunnel Device: %s", priv->ip_iface); - num = nm_ip4_config_get_num_nameservers (config); - for (i = 0; i < num; i++) { - nm_log_info (LOGD_VPN, "Internal IP4 DNS: %s", - ip_address_to_string (nm_ip4_config_get_nameserver (config, i))); - } + if (priv->ip4_config) { + nm_log_info (LOGD_VPN, "IPv4 configuration:"); + + addr = nm_ip4_config_get_address (priv->ip4_config, 0); + + if (priv->ip4_internal_gw) + nm_log_info (LOGD_VPN, " Internal Gateway: %s", ip_address_to_string (priv->ip4_internal_gw)); + nm_log_info (LOGD_VPN, " Internal Address: %s", ip_address_to_string (nm_ip4_address_get_address (addr))); + nm_log_info (LOGD_VPN, " Internal Prefix: %d", nm_ip4_address_get_prefix (addr)); + nm_log_info (LOGD_VPN, " Internal Point-to-Point Address: %s", + ip_address_to_string (nm_ip4_config_get_ptp_address (priv->ip4_config))); + nm_log_info (LOGD_VPN, " Maximum Segment Size (MSS): %d", nm_ip4_config_get_mss (priv->ip4_config)); + + num = nm_ip4_config_get_num_routes (priv->ip4_config); + for (i = 0; i < num; i++) { + NMIP4Route *route; + + route = nm_ip4_config_get_route (priv->ip4_config, i); + nm_log_info (LOGD_VPN, " Static Route: %s/%d Next Hop: %s", + ip_address_to_string (nm_ip4_route_get_dest (route)), + nm_ip4_route_get_prefix (route), + ip_address_to_string (nm_ip4_route_get_next_hop (route))); + } + + nm_log_info (LOGD_VPN, " Forbid Default Route: %s", + nm_ip4_config_get_never_default (priv->ip4_config) ? "yes" : "no"); + + num = nm_ip4_config_get_num_nameservers (priv->ip4_config); + for (i = 0; i < num; i++) { + nm_log_info (LOGD_VPN, " Internal DNS: %s", + ip_address_to_string (nm_ip4_config_get_nameserver (priv->ip4_config, i))); + } + + if (nm_ip4_config_get_num_domains (priv->ip4_config) > 0) + dns_domain = (char *) nm_ip4_config_get_domain (priv->ip4_config, 0); + + nm_log_info (LOGD_VPN, " DNS Domain: '%s'", dns_domain ? dns_domain : "(none)"); + } else + nm_log_info (LOGD_VPN, "No IPv4 configuration"); + + if (priv->ip6_config) { + nm_log_info (LOGD_VPN, "IPv6 configuration:"); + + addr6 = nm_ip6_config_get_address (priv->ip6_config, 0); + + if (priv->ip6_internal_gw) + nm_log_info (LOGD_VPN, " Internal Gateway: %s", ip6_address_to_string (priv->ip6_internal_gw)); + nm_log_info (LOGD_VPN, " Internal Address: %s", ip6_address_to_string (nm_ip6_address_get_address (addr6))); + nm_log_info (LOGD_VPN, " Internal Prefix: %d", nm_ip6_address_get_prefix (addr6)); + nm_log_info (LOGD_VPN, " Internal Point-to-Point Address: %s", + ip6_address_to_string (nm_ip6_config_get_ptp_address (priv->ip6_config))); + nm_log_info (LOGD_VPN, " Maximum Segment Size (MSS): %d", nm_ip6_config_get_mss (priv->ip6_config)); - if (nm_ip4_config_get_num_domains (config) > 0) - dns_domain = (char *) nm_ip4_config_get_domain (config, 0); + num = nm_ip6_config_get_num_routes (priv->ip6_config); + for (i = 0; i < num; i++) { + NMIP6Route *route; - nm_log_info (LOGD_VPN, "DNS Domain: '%s'", dns_domain ? dns_domain : "(none)"); + route = nm_ip6_config_get_route (priv->ip6_config, i); + nm_log_info (LOGD_VPN, " Static Route: %s/%d Next Hop: %s", + ip6_address_to_string (nm_ip6_route_get_dest (route)), + nm_ip6_route_get_prefix (route), + ip6_address_to_string (nm_ip6_route_get_next_hop (route))); + } + + nm_log_info (LOGD_VPN, " Forbid Default Route: %s", + nm_ip6_config_get_never_default (priv->ip6_config) ? "yes" : "no"); + + num = nm_ip6_config_get_num_nameservers (priv->ip6_config); + for (i = 0; i < num; i++) { + nm_log_info (LOGD_VPN, " Internal DNS: %s", + ip6_address_to_string (nm_ip6_config_get_nameserver (priv->ip6_config, i))); + } - if (banner && strlen (banner)) { + if (nm_ip6_config_get_num_domains (priv->ip6_config) > 0) + dns_domain = (char *) nm_ip6_config_get_domain (priv->ip6_config, 0); + + nm_log_info (LOGD_VPN, " DNS Domain: '%s'", dns_domain ? dns_domain : "(none)"); + } else + nm_log_info (LOGD_VPN, "No IPv6 configuration"); + + if (priv->banner && strlen (priv->banner)) { nm_log_info (LOGD_VPN, "Login Banner:"); nm_log_info (LOGD_VPN, "-----------------------------------------"); - nm_log_info (LOGD_VPN, "%s", banner); + nm_log_info (LOGD_VPN, "%s", priv->banner); nm_log_info (LOGD_VPN, "-----------------------------------------"); } } -static void -nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, - GHashTable *config_hash, - gpointer user_data) +static gboolean +nm_vpn_connection_apply_config (NMVPNConnection *connection) { - NMVPNConnection *connection = NM_VPN_CONNECTION (user_data); NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); - NMSettingIP4Config *s_ip4; - NMIP4Address *addr; - NMIP4Config *config; - GValue *val; - int i; - guint32 vpn_ext_gw = 0; - nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) reply received.", + nm_system_iface_set_up (priv->ip_ifindex, TRUE, NULL); + + if (priv->ip4_config) { + if (!nm_system_apply_ip4_config (priv->ip_ifindex, priv->ip4_config, + 0, NM_IP4_COMPARE_FLAG_ALL)) + return FALSE; + } + + if (priv->ip6_config) { + if (!nm_system_apply_ip6_config (priv->ip_ifindex, priv->ip6_config, + 0, NM_IP6_COMPARE_FLAG_ALL)) + /* FIXME: remove ip4 config */ + return FALSE; + } + + /* Add any explicit route to the VPN gateway through the parent device */ + if (priv->ip4_external_gw) { + priv->gw_route = nm_system_add_ip4_vpn_gateway_route (priv->parent_dev, + priv->ip4_external_gw); + } else if (priv->ip6_external_gw) { + priv->gw_route = nm_system_add_ip6_vpn_gateway_route (priv->parent_dev, + priv->ip6_external_gw); + } else { + priv->gw_route = NULL; + } + + nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) complete.", nm_vpn_connection_get_name (connection)); + nm_vpn_connection_set_vpn_state (connection, + NM_VPN_CONNECTION_STATE_ACTIVATED, + NM_VPN_CONNECTION_STATE_REASON_NONE); + return TRUE; +} + +static void +nm_vpn_connection_config_maybe_complete (NMVPNConnection *connection, + gboolean success) +{ + NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + + if (priv->ipconfig_timeout == 0) { + /* config_complete() was already called with an error; + * ignore further calls. + */ + return; + } + + if (success) { + if ( (priv->has_ip4 && !priv->ip4_config) + || (priv->has_ip6 && !priv->ip6_config)) { + /* Need to wait for other config */ + return; + } + } g_source_remove (priv->ipconfig_timeout); priv->ipconfig_timeout = 0; - config = nm_ip4_config_new (); + if (success) { + print_vpn_config (connection); + + if (nm_vpn_connection_apply_config (connection)) + return; + } + + g_clear_object (&priv->ip4_config); + g_clear_object (&priv->ip6_config); - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV); + nm_log_warn (LOGD_VPN, "VPN connection '%s' did not receive valid IP config information.", + nm_vpn_connection_get_name (connection)); + nm_vpn_connection_set_vpn_state (connection, + NM_VPN_CONNECTION_STATE_FAILED, + NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID); +} + +static gboolean +process_generic_config (NMVPNConnection *connection, + GHashTable *config_hash) +{ + NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + GValue *val; + + val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_TUNDEV); if (val) priv->ip_iface = g_strdup (g_value_get_string (val)); else { nm_log_err (LOGD_VPN, "invalid or missing tunnel device received!"); - goto error; + nm_vpn_connection_config_maybe_complete (connection, FALSE); + return FALSE; } /* Grab the interface index for address/routing operations */ priv->ip_ifindex = nm_netlink_iface_to_index (priv->ip_iface); if (priv->ip_ifindex < 0) { nm_log_err (LOGD_VPN, "(%s): failed to look up VPN interface index", priv->ip_iface); - goto error; + nm_vpn_connection_config_maybe_complete (connection, FALSE); + return FALSE; + } + + val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_BANNER); + if (val) { + g_free (priv->banner); + priv->banner = g_strdup (g_value_get_string (val)); + } + + /* External world-visible address of the VPN server */ + priv->ip4_external_gw = 0; + priv->ip6_external_gw = NULL; + val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY); + if (val) { + if (G_VALUE_HOLDS (val, G_TYPE_UINT)) { + priv->ip4_external_gw = g_value_get_uint (val); + } else if (G_VALUE_HOLDS (val, DBUS_TYPE_G_UCHAR_ARRAY)) { + GByteArray *ba = g_value_get_boxed (val); + + if (ba->len == sizeof (struct in6_addr)) + priv->ip6_external_gw = g_memdup (ba->data, ba->len); + } else { + nm_log_err (LOGD_VPN, "(%s): VPN gateway is neither IPv4 nor IPv6", priv->ip_iface); + nm_vpn_connection_config_maybe_complete (connection, FALSE); + return FALSE; + } + } + + /* MTU; this is a per-connection value, though NM's API treats it + * like it's IP4-specific. So we store it for now and retrieve it + * later in ip4_config_get. + */ + val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_MTU); + if (val) + priv->mtu = g_value_get_uint (val); + else + priv->mtu = 0; + + return TRUE; +} + +static void +nm_vpn_connection_config_get (DBusGProxy *proxy, + GHashTable *config_hash, + gpointer user_data) +{ + NMVPNConnection *connection = NM_VPN_CONNECTION (user_data); + NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + GValue *val; + + nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) reply received.", + nm_vpn_connection_get_name (connection)); + + if (!process_generic_config (connection, config_hash)) + return; + + /* Note whether to expect IPv4 and IPv6 configs */ + val = g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_HAS_IP4); + priv->has_ip4 = val ? g_value_get_boolean (val) : FALSE; + g_clear_object (&priv->ip4_config); + + val = g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_HAS_IP6); + priv->has_ip6 = val ? g_value_get_boolean (val) : FALSE; + g_clear_object (&priv->ip6_config); +} + +static void +nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, + GHashTable *config_hash, + gpointer user_data) +{ + NMVPNConnection *connection = NM_VPN_CONNECTION (user_data); + NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + NMSettingIP4Config *s_ip4; + NMIP4Address *addr; + NMIP4Config *config; + GValue *val; + int i; + + if (priv->has_ip4) { + nm_log_info (LOGD_VPN, "VPN connection '%s' (IP4 Config Get) reply received.", + nm_vpn_connection_get_name (connection)); + + if (g_hash_table_size (config_hash) == 0) { + priv->has_ip4 = FALSE; + nm_vpn_connection_config_maybe_complete (connection, TRUE); + return; + } + } else { + nm_log_info (LOGD_VPN, "VPN connection '%s' (IP4 Config Get) reply received from old-style plugin.", + nm_vpn_connection_get_name (connection)); + + /* In the old API, the generic and IPv4 configuration items + * were mixed together. + */ + if (!process_generic_config (connection, config_hash)) + return; + + priv->has_ip4 = TRUE; + priv->has_ip6 = FALSE; } + config = nm_ip4_config_new (); + addr = nm_ip4_address_new (); nm_ip4_address_set_prefix (addr, 24); /* default to class C */ + if (priv->ip4_external_gw) + nm_ip4_address_set_gateway (addr, priv->ip4_external_gw); /* Internal address of the VPN subnet's gateway */ val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_INT_GATEWAY); if (val) priv->ip4_internal_gw = g_value_get_uint (val); - /* External world-visible address of the VPN server */ - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY); - if (val) { - nm_ip4_address_set_gateway (addr, g_value_get_uint (val)); - vpn_ext_gw = g_value_get_uint (val); - } - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS); if (val) nm_ip4_address_set_address (addr, g_value_get_uint (val)); @@ -516,7 +840,9 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, } else { nm_log_err (LOGD_VPN, "invalid IP4 config received!"); nm_ip4_address_unref (addr); - goto error; + g_object_unref (config); + nm_vpn_connection_config_maybe_complete (connection, FALSE); + return; } val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_DNS); @@ -539,9 +865,8 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, if (val) nm_ip4_config_set_mss (config, g_value_get_uint (val)); - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_MTU); - if (val) - nm_ip4_config_set_mtu (config, g_value_get_uint (val)); + if (priv->mtu) + nm_ip4_config_set_mtu (config, priv->mtu); val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_DOMAIN); if (val) @@ -556,12 +881,6 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, nm_ip4_config_add_domain (config, *domain); } - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_BANNER); - if (val) { - g_free (priv->banner); - priv->banner = g_strdup (g_value_get_string (val)); - } - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_ROUTES); if (val) { GSList *routes; @@ -576,10 +895,12 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, * the VPN server, we want to use the NM created route instead of * whatever the server provides. */ - if ( vpn_ext_gw - && nm_ip4_route_get_dest (route) == vpn_ext_gw - && nm_ip4_route_get_prefix (route) == 32) + if ( priv->ip4_external_gw + && nm_ip4_route_get_dest (route) == priv->ip4_external_gw + && nm_ip4_route_get_prefix (route) == 32) { + nm_ip4_route_unref (route); continue; + } /* Otherwise accept the VPN-provided route */ nm_ip4_config_take_route (config, route); @@ -592,42 +913,149 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, if (val && G_VALUE_HOLDS_BOOLEAN (val)) nm_ip4_config_set_never_default (config, g_value_get_boolean (val)); - print_vpn_config (config, priv->ip4_internal_gw, priv->ip_iface, priv->banner); - /* Merge in user overrides from the NMConnection's IPv4 setting */ s_ip4 = nm_connection_get_setting_ip4_config (priv->connection); nm_utils_merge_ip4_config (config, s_ip4); - nm_system_iface_set_up (priv->ip_ifindex, TRUE, NULL); + priv->ip4_config = config; + nm_vpn_connection_config_maybe_complete (connection, TRUE); +} - if (nm_system_apply_ip4_config (priv->ip_ifindex, config, 0, NM_IP4_COMPARE_FLAG_ALL)) { - NMDnsManager *dns_mgr; +static void +nm_vpn_connection_ip6_config_get (DBusGProxy *proxy, + GHashTable *config_hash, + gpointer user_data) +{ + NMVPNConnection *connection = NM_VPN_CONNECTION (user_data); + NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + NMSettingIP6Config *s_ip6; + NMIP6Address *addr; + NMIP6Config *config; + GValue *val; + int i; - /* Add any explicit route to the VPN gateway through the parent device */ - priv->gw_route = nm_system_add_ip4_vpn_gateway_route (priv->parent_dev, config); + nm_log_info (LOGD_VPN, "VPN connection '%s' (IP6 Config Get) reply received.", + nm_vpn_connection_get_name (connection)); - /* Add the VPN to DNS */ - dns_mgr = nm_dns_manager_get (NULL); - nm_dns_manager_add_ip4_config (dns_mgr, priv->ip_iface, config, NM_DNS_IP_CONFIG_TYPE_VPN); - g_object_unref (dns_mgr); + if (g_hash_table_size (config_hash) == 0) { + priv->has_ip6 = FALSE; + nm_vpn_connection_config_maybe_complete (connection, TRUE); + return; + } - priv->ip4_config = config; + config = nm_ip6_config_new (); - nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) complete.", - nm_vpn_connection_get_name (connection)); - nm_vpn_connection_set_vpn_state (connection, - NM_VPN_CONNECTION_STATE_ACTIVATED, - NM_VPN_CONNECTION_STATE_REASON_NONE); - return; + addr = nm_ip6_address_new (); + nm_ip6_address_set_prefix (addr, 128); /* default to class C */ + if (priv->ip6_external_gw) + nm_ip6_address_set_gateway (addr, priv->ip6_external_gw); + + /* Internal address of the VPN subnet's gateway */ + val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_INT_GATEWAY); + if (val) { + GByteArray *ba = g_value_get_boxed (val); + + if (ba->len == sizeof (struct in6_addr)) + priv->ip6_internal_gw = g_memdup (ba->data, ba->len); } -error: - nm_log_warn (LOGD_VPN, "VPN connection '%s' did not receive valid IP config information.", - nm_vpn_connection_get_name (connection)); - nm_vpn_connection_set_vpn_state (connection, - NM_VPN_CONNECTION_STATE_FAILED, - NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID); - g_object_unref (config); + val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS); + if (val) { + GByteArray *ba = g_value_get_boxed (val); + + if (ba->len == sizeof (struct in6_addr)) + nm_ip6_address_set_address (addr, (struct in6_addr *)ba->data); + } + + val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_PTP); + if (val) { + GByteArray *ba = g_value_get_boxed (val); + + if (ba->len == sizeof (struct in6_addr)) + nm_ip6_config_set_ptp_address (config, (struct in6_addr *)ba->data); + } + + val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_PREFIX); + if (val) + nm_ip6_address_set_prefix (addr, g_value_get_uint (val)); + + if (nm_ip6_address_get_address (addr) && nm_ip6_address_get_prefix (addr)) { + nm_ip6_config_take_address (config, addr); + } else { + nm_log_err (LOGD_VPN, "invalid IP6 config received!"); + nm_ip6_address_unref (addr); + g_object_unref (config); + nm_vpn_connection_config_maybe_complete (connection, FALSE); + } + + val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_DNS); + if (val) { + GPtrArray *dns = (GPtrArray *) g_value_get_boxed (val); + GByteArray *ba; + + for (i = 0; i < dns->len; i++) { + ba = dns->pdata[i]; + if (ba->len == sizeof (struct in6_addr)) + nm_ip6_config_add_nameserver (config, (struct in6_addr *)ba->data); + } + } + + val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_MSS); + if (val) + nm_ip6_config_set_mss (config, g_value_get_uint (val)); + + val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_DOMAIN); + if (val) + nm_ip6_config_add_domain (config, g_value_get_string (val)); + + val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_DOMAINS); + if (val) { + const char **domains = g_value_get_boxed (val); + const char **domain; + + for (domain = domains; domain && *domain; domain++) + nm_ip6_config_add_domain (config, *domain); + } + + val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_ROUTES); + if (val) { + GSList *routes; + GSList *iter; + + routes = nm_utils_ip6_routes_from_gvalue (val); + for (iter = routes; iter; iter = iter->next) { + NMIP6Route *route = iter->data; + + /* Ignore host routes to the VPN gateway since NM adds one itself + * below. Since NM knows more about the routing situation than + * the VPN server, we want to use the NM created route instead of + * whatever the server provides. + */ + if ( priv->ip6_external_gw + && nm_ip6_route_get_prefix (route) == 128 + && memcmp (nm_ip6_route_get_dest (route), priv->ip6_external_gw, + sizeof (struct in6_addr)) == 0) { + nm_ip6_route_unref (route); + continue; + } + + /* Otherwise accept the VPN-provided route */ + nm_ip6_config_take_route (config, route); + } + + g_slist_free (routes); + } + + val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT); + if (val && G_VALUE_HOLDS_BOOLEAN (val)) + nm_ip6_config_set_never_default (config, g_value_get_boolean (val)); + + /* Merge in user overrides from the NMConnection's IPv6 setting */ + s_ip6 = nm_connection_get_setting_ip6_config (priv->connection); + nm_utils_merge_ip6_config (config, s_ip6); + + priv->ip6_config = config; + nm_vpn_connection_config_maybe_complete (connection, TRUE); } static gboolean @@ -716,9 +1144,18 @@ really_activate (NMVPNConnection *connection, const char *username) priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); - /* Ip4Config signal */ dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, G_TYPE_VALUE, G_TYPE_INVALID); + + /* Config signal */ + dbus_g_proxy_add_signal (priv->proxy, "Config", + DBUS_TYPE_G_MAP_OF_VARIANT, + G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->proxy, "Config", + G_CALLBACK (nm_vpn_connection_config_get), + connection, NULL); + + /* Ip4Config signal */ dbus_g_proxy_add_signal (priv->proxy, "Ip4Config", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID); @@ -726,6 +1163,14 @@ really_activate (NMVPNConnection *connection, const char *username) G_CALLBACK (nm_vpn_connection_ip4_config_get), connection, NULL); + /* Ip6Config signal */ + dbus_g_proxy_add_signal (priv->proxy, "Ip6Config", + DBUS_TYPE_G_MAP_OF_VARIANT, + G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->proxy, "Ip6Config", + G_CALLBACK (nm_vpn_connection_ip6_config_get), + connection, NULL); + hash = _hash_with_username (priv->connection, username); org_freedesktop_NetworkManager_VPN_Plugin_connect_async (priv->proxy, hash, @@ -818,6 +1263,14 @@ nm_vpn_connection_get_ip4_config (NMVPNConnection *connection) return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip4_config; } +NMIP6Config * +nm_vpn_connection_get_ip6_config (NMVPNConnection *connection) +{ + g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL); + + return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip6_config; +} + const char * nm_vpn_connection_get_ip_iface (NMVPNConnection *connection) { @@ -850,6 +1303,14 @@ nm_vpn_connection_get_ip4_internal_gateway (NMVPNConnection *connection) return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip4_internal_gw; } +struct in6_addr * +nm_vpn_connection_get_ip6_internal_gateway (NMVPNConnection *connection) +{ + g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), 0); + + return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip6_internal_gw; +} + void nm_vpn_connection_fail (NMVPNConnection *connection, NMVPNConnectionStateReason reason) @@ -896,11 +1357,19 @@ plugin_need_secrets_cb (DBusGProxy *proxy, if (setting_name && strlen (setting_name)) { /* More secrets required */ - nm_log_dbg (LOGD_VPN, "(%s/%s) service indicated additional secrets required", - nm_connection_get_uuid (priv->connection), - nm_connection_get_id (priv->connection)); - get_secrets (self, priv->secrets_idx + 1); + if (priv->secrets_idx == SECRETS_REQ_NEW) { + nm_log_err (LOGD_VPN, "(%s/%s) final secrets request failed to provide sufficient secrets", + nm_connection_get_uuid (priv->connection), + nm_connection_get_id (priv->connection)); + nm_vpn_connection_fail (self, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS); + } else { + nm_log_dbg (LOGD_VPN, "(%s/%s) service indicated additional secrets required", + nm_connection_get_uuid (priv->connection), + nm_connection_get_id (priv->connection)); + + get_secrets (self, priv->secrets_idx + 1); + } return; } @@ -985,6 +1454,9 @@ get_secrets (NMVPNConnection *self, SecretsReq secrets_idx) g_assert_not_reached (); } + if (priv->user_requested) + flags |= NM_SETTINGS_GET_SECRETS_FLAG_USER_REQUESTED; + priv->secrets_id = nm_settings_connection_get_secrets (NM_SETTINGS_CONNECTION (priv->connection), filter_by_uid, priv->user_uid, @@ -1004,109 +1476,7 @@ get_secrets (NMVPNConnection *self, SecretsReq secrets_idx) } } -static void -vpn_cleanup (NMVPNConnection *connection) -{ - NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); - - if (priv->ip_ifindex) { - nm_system_iface_set_up (priv->ip_ifindex, FALSE, NULL); - /* FIXME: use AF_UNSPEC here when we have IPv6 support */ - nm_system_iface_flush_routes (priv->ip_ifindex, AF_INET); - nm_system_iface_flush_addresses (priv->ip_ifindex, AF_UNSPEC); - } - - if (priv->ip4_config) { - NMIP4Config *parent_config; - NMDnsManager *dns_mgr; - - /* Remove attributes of the VPN's IP4 Config */ - dns_mgr = nm_dns_manager_get (NULL); - nm_dns_manager_remove_ip4_config (dns_mgr, priv->ip_iface, priv->ip4_config); - g_object_unref (dns_mgr); - - /* Remove any previously added VPN gateway host route */ - if (priv->gw_route) - nm_netlink_route_delete (priv->gw_route); - - /* Reset routes and addresses of the currently active device */ - parent_config = nm_device_get_ip4_config (priv->parent_dev); - if (parent_config) { - if (!nm_system_apply_ip4_config (nm_device_get_ip_ifindex (priv->parent_dev), - nm_device_get_ip4_config (priv->parent_dev), - nm_device_get_priority (priv->parent_dev), - NM_IP4_COMPARE_FLAG_ADDRESSES | NM_IP4_COMPARE_FLAG_ROUTES)) { - nm_log_err (LOGD_VPN, "failed to re-apply VPN parent device addresses and routes."); - } - } - } - - if (priv->gw_route) { - rtnl_route_put (priv->gw_route); - priv->gw_route = NULL; - } - - g_free (priv->banner); - priv->banner = NULL; - - g_free (priv->ip_iface); - priv->ip_iface = NULL; - priv->ip_ifindex = 0; - - /* Clear out connection secrets to ensure that the settings service - * gets asked for them next time the connection is activated. - */ - if (priv->connection) - nm_connection_clear_secrets (priv->connection); -} - -static void -connection_state_changed (NMVPNConnection *self, - NMVPNConnectionState state, - NMVPNConnectionStateReason reason) -{ - NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - - /* Clear any in-progress secrets request */ - if (priv->secrets_id) { - nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection), priv->secrets_id); - priv->secrets_id = 0; - } - priv->secrets_idx = SECRETS_REQ_SYSTEM; - - switch (state) { - case NM_VPN_CONNECTION_STATE_NEED_AUTH: - /* Kick off the secrets requests; first we get existing system secrets - * and ask the plugin if these are sufficient, next we get all existing - * secrets from system and from user agents and ask the plugin again, - * and last we ask the user for new secrets if required. - */ - get_secrets (self, SECRETS_REQ_SYSTEM); - break; - case NM_VPN_CONNECTION_STATE_ACTIVATED: - /* Secrets no longer needed now that we're connected */ - nm_connection_clear_secrets (priv->connection); - break; - case NM_VPN_CONNECTION_STATE_DISCONNECTED: - case NM_VPN_CONNECTION_STATE_FAILED: - if (priv->proxy) { - GError *err = NULL; - - org_freedesktop_NetworkManager_VPN_Plugin_disconnect (priv->proxy, &err); - if (err) { - nm_log_warn (LOGD_VPN, "error disconnecting VPN: %s", err->message); - g_error_free (err); - } - - g_object_unref (priv->proxy); - priv->proxy = NULL; - } - vpn_cleanup (self); - break; - default: - break; - } -} +/******************************************************************************/ static void nm_vpn_connection_init (NMVPNConnection *self) @@ -1127,9 +1497,15 @@ dispose (GObject *object) if (priv->gw_route) rtnl_route_put (priv->gw_route); + if (priv->ip6_internal_gw) + g_free (priv->ip6_internal_gw); + if (priv->ip6_external_gw) + g_free (priv->ip6_external_gw); if (priv->device_ip4) g_signal_handler_disconnect (priv->parent_dev, priv->device_ip4); + if (priv->device_ip6) + g_signal_handler_disconnect (priv->parent_dev, priv->device_ip6); if (priv->device_monitor) g_signal_handler_disconnect (priv->parent_dev, priv->device_monitor); @@ -1138,6 +1514,8 @@ dispose (GObject *object) if (priv->ip4_config) g_object_unref (priv->ip4_config); + if (priv->ip6_config) + g_object_unref (priv->ip6_config); if (priv->ipconfig_timeout) g_source_remove (priv->ipconfig_timeout); @@ -1197,7 +1575,6 @@ nm_vpn_connection_class_init (NMVPNConnectionClass *connection_class) g_type_class_add_private (connection_class, sizeof (NMVPNConnectionPrivate)); /* virtual methods */ - connection_class->vpn_state_changed = connection_state_changed; object_class->get_property = get_property; object_class->dispose = dispose; object_class->finalize = finalize; @@ -1223,16 +1600,14 @@ nm_vpn_connection_class_init (NMVPNConnectionClass *connection_class) /* signals */ signals[VPN_STATE_CHANGED] = - g_signal_new ("vpn-state-changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMVPNConnectionClass, vpn_state_changed), - NULL, NULL, - _nm_marshal_VOID__UINT_UINT, - G_TYPE_NONE, 2, - G_TYPE_UINT, G_TYPE_UINT); + g_signal_new (NM_VPN_CONNECTION_VPN_STATE_CHANGED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + _nm_marshal_VOID__UINT_UINT_UINT, + G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT); dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (object_class), - &dbus_glib_nm_vpn_connection_object_info); + &dbus_glib_nm_vpn_connection_object_info); } diff --git a/src/vpn-manager/nm-vpn-connection.h b/src/vpn-manager/nm-vpn-connection.h index 93cc06d1..0e4f1a04 100644 --- a/src/vpn-manager/nm-vpn-connection.h +++ b/src/vpn-manager/nm-vpn-connection.h @@ -34,9 +34,14 @@ #define NM_IS_VPN_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_VPN_CONNECTION)) #define NM_VPN_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_VPN_CONNECTION, NMVPNConnectionClass)) +/* Properties */ #define NM_VPN_CONNECTION_VPN_STATE "vpn-state" #define NM_VPN_CONNECTION_BANNER "banner" +/* Signals */ +#define NM_VPN_CONNECTION_VPN_STATE_CHANGED "vpn-state-changed" + + typedef struct { NMActiveConnection parent; } NMVPNConnection; @@ -46,7 +51,8 @@ typedef struct { /* Signals */ void (*vpn_state_changed) (NMVPNConnection *connection, - NMVPNConnectionState state, + NMVPNConnectionState new_state, + NMVPNConnectionState old_state, NMVPNConnectionStateReason reason); } NMVPNConnectionClass; @@ -68,9 +74,11 @@ void nm_vpn_connection_fail (NMVPNConnection *connect void nm_vpn_connection_disconnect (NMVPNConnection *connection, NMVPNConnectionStateReason reason); NMIP4Config * nm_vpn_connection_get_ip4_config (NMVPNConnection *connection); +NMIP6Config * nm_vpn_connection_get_ip6_config (NMVPNConnection *connection); const char * nm_vpn_connection_get_ip_iface (NMVPNConnection *connection); int nm_vpn_connection_get_ip_ifindex (NMVPNConnection *connection); NMDevice * nm_vpn_connection_get_parent_device (NMVPNConnection *connection); guint32 nm_vpn_connection_get_ip4_internal_gateway (NMVPNConnection *connection); +struct in6_addr * nm_vpn_connection_get_ip6_internal_gateway (NMVPNConnection *connection); #endif /* NM_VPN_CONNECTION_H */ diff --git a/src/vpn-manager/nm-vpn-manager.c b/src/vpn-manager/nm-vpn-manager.c index 34131964..a462f547 100644 --- a/src/vpn-manager/nm-vpn-manager.c +++ b/src/vpn-manager/nm-vpn-manager.c @@ -115,19 +115,20 @@ find_active_vpn_connection_by_connection (NMVPNManager *self, NMConnection *conn static void connection_vpn_state_changed (NMVPNConnection *connection, - NMVPNConnectionState state, + NMVPNConnectionState new_state, + NMVPNConnectionState old_state, NMVPNConnectionStateReason reason, gpointer user_data) { NMVPNManager *manager = NM_VPN_MANAGER (user_data); - switch (state) { + switch (new_state) { case NM_VPN_CONNECTION_STATE_ACTIVATED: g_signal_emit (manager, signals[CONNECTION_ACTIVATED], 0, connection); break; case NM_VPN_CONNECTION_STATE_FAILED: case NM_VPN_CONNECTION_STATE_DISCONNECTED: - g_signal_emit (manager, signals[CONNECTION_DEACTIVATED], 0, connection, state, reason); + g_signal_emit (manager, signals[CONNECTION_DEACTIVATED], 0, connection, new_state, old_state, reason); break; default: break; @@ -188,7 +189,7 @@ nm_vpn_manager_activate_connection (NMVPNManager *manager, vpn = nm_vpn_service_activate (service, connection, device, specific_object, user_requested, user_uid, error); if (vpn) { - g_signal_connect (vpn, "vpn-state-changed", + g_signal_connect (vpn, NM_VPN_CONNECTION_VPN_STATE_CHANGED, G_CALLBACK (connection_vpn_state_changed), manager); } @@ -518,11 +519,9 @@ nm_vpn_manager_class_init (NMVPNManagerClass *manager_class) g_signal_new ("connection-deactivated", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMVPNManagerClass, connection_deactivated), - NULL, NULL, - _nm_marshal_VOID__OBJECT_UINT_UINT, - G_TYPE_NONE, 3, - G_TYPE_OBJECT, G_TYPE_UINT, G_TYPE_UINT); + 0, NULL, NULL, + _nm_marshal_VOID__OBJECT_UINT_UINT_UINT, + G_TYPE_NONE, 4, G_TYPE_OBJECT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT); dbus_g_error_domain_register (NM_VPN_MANAGER_ERROR, NULL, NM_TYPE_VPN_MANAGER_ERROR); } diff --git a/src/vpn-manager/nm-vpn-manager.h b/src/vpn-manager/nm-vpn-manager.h index cec370c8..17225b44 100644 --- a/src/vpn-manager/nm-vpn-manager.h +++ b/src/vpn-manager/nm-vpn-manager.h @@ -55,9 +55,13 @@ typedef struct { GObjectClass parent; /* Signals */ + void (*connection_activated) (NMVPNManager *manager, + NMVPNConnection *connection); + void (*connection_deactivated) (NMVPNManager *manager, NMVPNConnection *connection, - NMVPNConnectionState state, + NMVPNConnectionState new_state, + NMVPNConnectionState old_state, NMVPNConnectionStateReason reason); } NMVPNManagerClass; diff --git a/src/vpn-manager/nm-vpn-service.c b/src/vpn-manager/nm-vpn-service.c index 95e4f2b1..a2c8b100 100644 --- a/src/vpn-manager/nm-vpn-service.c +++ b/src/vpn-manager/nm-vpn-service.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2011 Red Hat, Inc. + * Copyright (C) 2005 - 2012 Red Hat, Inc. * Copyright (C) 2005 - 2008 Novell, Inc. */ @@ -31,6 +31,7 @@ #include "nm-vpn-service.h" #include "nm-dbus-manager.h" #include "nm-logging.h" +#include "nm-posix-signals.h" #include "nm-vpn-manager.h" #include "nm-glib-compat.h" @@ -168,6 +169,12 @@ nm_vpn_service_child_setup (gpointer user_data G_GNUC_UNUSED) /* We are in the child process at this point */ pid_t pid = getpid (); setpgid (pid, pid); + + /* + * We blocked signals in main(). We need to restore original signal + * mask for VPN service here so that it can receive signals. + */ + nm_unblock_posix_signals (NULL); } static void @@ -296,13 +303,14 @@ service_quit (gpointer user_data) static void connection_vpn_state_changed (NMVPNConnection *connection, - NMVPNConnectionState state, + NMVPNConnectionState new_state, + NMVPNConnectionState old_state, NMVPNConnectionStateReason reason, gpointer user_data) { NMVPNServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (user_data); - switch (state) { + switch (new_state) { case NM_VPN_CONNECTION_STATE_FAILED: case NM_VPN_CONNECTION_STATE_DISCONNECTED: /* Remove the connection from our list */ @@ -343,9 +351,9 @@ nm_vpn_service_activate (NMVPNService *service, clear_quit_timeout (service); vpn = nm_vpn_connection_new (connection, device, specific_object, user_requested, user_uid); - g_signal_connect (vpn, "vpn-state-changed", - G_CALLBACK (connection_vpn_state_changed), - service); + g_signal_connect (vpn, NM_VPN_CONNECTION_VPN_STATE_CHANGED, + G_CALLBACK (connection_vpn_state_changed), + service); priv->connections = g_slist_prepend (priv->connections, vpn); |