vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration information from VPN plugins to the backend. Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and Ip6Config. "Config" contains information which is neither IPv4 nor IPv6 specific, and also indicates which of Ip4Config and Ip6Config are present. Ip4Config now only contains the IPv4-specific bits of configuration. There is backward compatibility in both directions: if the daemon is new and the VPN plugin is old, then NM will notice that the plugin emitted the Ip4Config signal without having emitted the Config signal first, and so will assume that it is IPv4-only, and that the generic bits of configuration have been included with the Ip4Config. If the daemon is old and the plugin is new, then NMVPNPlugin will copy the values from the generic config into the IPv4 config as well. (In fact, NMVPNPlugin *always* does this, because it's harmless, and it's easier than actually checking the daemon version.) Currently the VPN is still configured all-at-once, after both IPv4 and IPv6 information has been received, but the APIs allow for the possibility of configuring them one at a time in the future.
This commit is contained in:
@@ -114,8 +114,28 @@ typedef enum {
|
||||
} NMVPNPluginFailure;
|
||||
|
||||
|
||||
/*** Generic config ***/
|
||||
|
||||
/* string: VPN interface name (tun0, tap0, etc) */
|
||||
#define NM_VPN_PLUGIN_CONFIG_TUNDEV "tundev"
|
||||
|
||||
/* string: Login message */
|
||||
#define NM_VPN_PLUGIN_CONFIG_BANNER "banner"
|
||||
|
||||
/* uint32 / array of uint8: IP address of the public external VPN gateway (network byte order) */
|
||||
#define NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY "gateway"
|
||||
#define NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY "gateway"
|
||||
|
||||
/* uint32: Maximum Transfer Unit that the VPN interface should use */
|
||||
#define NM_VPN_PLUGIN_CONFIG_MTU "mtu"
|
||||
|
||||
/* boolean: Has IP4 configuration? */
|
||||
#define NM_VPN_PLUGIN_CONFIG_HAS_IP4 "has-ip4"
|
||||
|
||||
/* boolean: Has IP6 configuration? */
|
||||
#define NM_VPN_PLUGIN_CONFIG_HAS_IP6 "has-ip6"
|
||||
|
||||
|
||||
/*** Ip4Config ***/
|
||||
|
||||
/* uint32: IP address of the internal gateway of the subnet the VPN interface is
|
||||
* on, if the VPN uses subnet configuration (network byte order)
|
||||
@@ -142,30 +162,14 @@ typedef enum {
|
||||
/* uint32: Message Segment Size that the VPN interface should use */
|
||||
#define NM_VPN_PLUGIN_IP4_CONFIG_MSS "mss"
|
||||
|
||||
/* uint32: Maximum Transfer Unit that the VPN interface should use */
|
||||
#define NM_VPN_PLUGIN_IP4_CONFIG_MTU "mtu"
|
||||
|
||||
/* string: VPN interface name (tun0, tap0, etc) */
|
||||
#define NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV "tundev"
|
||||
|
||||
/* string: DNS domain name */
|
||||
#define NM_VPN_PLUGIN_IP4_CONFIG_DOMAIN "domain"
|
||||
|
||||
/* array of strings: DNS domain names */
|
||||
#define NM_VPN_PLUGIN_IP4_CONFIG_DOMAINS "domains"
|
||||
|
||||
/* string: Login message */
|
||||
#define NM_VPN_PLUGIN_IP4_CONFIG_BANNER "banner"
|
||||
|
||||
/* array of array of uint32: custom routes the client should apply. NOTE: NM
|
||||
* expects the D-Bus argument signature "aau" here. i.e., an array of
|
||||
* routes, where each route is a 4-element array of uint32 values.
|
||||
*
|
||||
* Each route consists of the following 4 uint32 values, in this order:
|
||||
* 1: destination IP address (network byte order)
|
||||
* 2: destination prefix (1 - 32 inclusive)
|
||||
* 3: IP address of next hop (network byte order)
|
||||
* 4: route metric
|
||||
/* [ip4 routes]: custom routes the client should apply, in the format used
|
||||
* by nm_utils_ip4_routes_to/from_gvalue
|
||||
*/
|
||||
#define NM_VPN_PLUGIN_IP4_CONFIG_ROUTES "routes"
|
||||
|
||||
@@ -175,5 +179,52 @@ typedef enum {
|
||||
/* Deprecated */
|
||||
#define NM_VPN_PLUGIN_IP4_CONFIG_GATEWAY NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY
|
||||
|
||||
/* Legacy IP4 items; these are included in the IP4 config by older plugins,
|
||||
* but in the generic config by newer plugins.
|
||||
*/
|
||||
|
||||
#define NM_VPN_PLUGIN_IP4_CONFIG_BANNER NM_VPN_PLUGIN_CONFIG_BANNER
|
||||
#define NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY
|
||||
#define NM_VPN_PLUGIN_IP4_CONFIG_MTU NM_VPN_PLUGIN_CONFIG_MTU
|
||||
#define NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV NM_VPN_PLUGIN_CONFIG_TUNDEV
|
||||
|
||||
|
||||
/*** Ip6Config ***/
|
||||
|
||||
/* array of uint8: IP address of the internal gateway of the subnet the VPN interface is
|
||||
* on, if the VPN uses subnet configuration (network byte order)
|
||||
*/
|
||||
#define NM_VPN_PLUGIN_IP6_CONFIG_INT_GATEWAY "internal-gateway"
|
||||
|
||||
/* array of uint8: internal IP address of the local VPN interface (network byte order) */
|
||||
#define NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS "address"
|
||||
|
||||
/* array of uint8: IP address of the other side of Point-to-Point connection if the VPN
|
||||
* uses Point-to-Point configuration. (network byte order)
|
||||
*/
|
||||
#define NM_VPN_PLUGIN_IP6_CONFIG_PTP "ptp"
|
||||
|
||||
/* uint32: prefix length of the VPN interface; 1 - 128 inclusive */
|
||||
#define NM_VPN_PLUGIN_IP6_CONFIG_PREFIX "prefix"
|
||||
|
||||
/* array of array of uint8: IP addresses of DNS servers for the VPN (network byte order) */
|
||||
#define NM_VPN_PLUGIN_IP6_CONFIG_DNS "dns"
|
||||
|
||||
/* uint32: Message Segment Size that the VPN interface should use */
|
||||
#define NM_VPN_PLUGIN_IP6_CONFIG_MSS "mss"
|
||||
|
||||
/* string: DNS domain name */
|
||||
#define NM_VPN_PLUGIN_IP6_CONFIG_DOMAIN "domain"
|
||||
|
||||
/* array of strings: DNS domain names */
|
||||
#define NM_VPN_PLUGIN_IP6_CONFIG_DOMAINS "domains"
|
||||
|
||||
/* [ip6 routes]: custom routes the client should apply, in the format used
|
||||
* by nm_utils_ip6_routes_to/from_gvalue
|
||||
*/
|
||||
#define NM_VPN_PLUGIN_IP6_CONFIG_ROUTES "routes"
|
||||
|
||||
/* boolean: prevent this VPN connection from ever getting the default route */
|
||||
#define NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT "never-default"
|
||||
|
||||
#endif /* NETWORK_MANAGER_VPN_H */
|
||||
|
@@ -55,6 +55,18 @@
|
||||
</tp:possible-errors>
|
||||
</method>
|
||||
|
||||
<method name="SetConfig">
|
||||
<tp:docstring>
|
||||
Set generic connection details on the connection.
|
||||
</tp:docstring>
|
||||
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_vpn_plugin_set_config"/>
|
||||
<arg name="config" type="a{sv}" direction="in" tp:type="String_Variant_Map">
|
||||
<tp:docstring>
|
||||
Generic configuration details for the connection.
|
||||
</tp:docstring>
|
||||
</arg>
|
||||
</method>
|
||||
|
||||
<method name="SetIp4Config">
|
||||
<tp:docstring>
|
||||
Set IPv4 details on the connection.
|
||||
@@ -62,7 +74,21 @@
|
||||
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_vpn_plugin_set_ip4_config"/>
|
||||
<arg name="config" type="a{sv}" direction="in" tp:type="String_Variant_Map">
|
||||
<tp:docstring>
|
||||
Ip4Config details for the conneciton.
|
||||
Ip4Config details for the connection. You must call
|
||||
SetConfig() before calling this.
|
||||
</tp:docstring>
|
||||
</arg>
|
||||
</method>
|
||||
|
||||
<method name="SetIp6Config">
|
||||
<tp:docstring>
|
||||
Set IPv6 details on the connection.
|
||||
</tp:docstring>
|
||||
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_vpn_plugin_set_ip6_config"/>
|
||||
<arg name="config" type="a{sv}" direction="in" tp:type="String_Variant_Map">
|
||||
<tp:docstring>
|
||||
Ip6Config details for the connection. You must call
|
||||
SetConfig() before calling this.
|
||||
</tp:docstring>
|
||||
</arg>
|
||||
</method>
|
||||
@@ -96,6 +122,17 @@
|
||||
</arg>
|
||||
</signal>
|
||||
|
||||
<signal name="Config">
|
||||
<tp:docstring>
|
||||
The plugin obtained generic configuration information.
|
||||
</tp:docstring>
|
||||
<arg name="config" type="a{sv}" tp:type="String_Variant_Map">
|
||||
<tp:docstring>
|
||||
The configuration information.
|
||||
</tp:docstring>
|
||||
</arg>
|
||||
</signal>
|
||||
|
||||
<signal name="Ip4Config">
|
||||
<tp:docstring>
|
||||
The plugin obtained an IPv4 configuration.
|
||||
@@ -107,6 +144,17 @@
|
||||
</arg>
|
||||
</signal>
|
||||
|
||||
<signal name="Ip6Config">
|
||||
<tp:docstring>
|
||||
The plugin obtained an IPv6 configuration.
|
||||
</tp:docstring>
|
||||
<arg name="ip6config" type="a{sv}" tp:type="String_Variant_Map">
|
||||
<tp:docstring>
|
||||
The IPv6 configuration.
|
||||
</tp:docstring>
|
||||
</arg>
|
||||
</signal>
|
||||
|
||||
<signal name="LoginBanner">
|
||||
<tp:docstring>
|
||||
Emitted when the plugin receives a login banner from the VPN service.
|
||||
|
@@ -24,7 +24,9 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "nm-vpn-plugin-utils.h"
|
||||
#include "nm-vpn-plugin.h"
|
||||
#include "nm-setting-private.h"
|
||||
#include "nm-dbus-glib-types.h"
|
||||
|
||||
#define DATA_KEY_TAG "DATA_KEY="
|
||||
#define DATA_VAL_TAG "DATA_VAL="
|
||||
@@ -185,4 +187,3 @@ nm_vpn_plugin_utils_get_secret_flags (GHashTable *data,
|
||||
g_free (flag_name);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
@@ -41,10 +41,18 @@ static gboolean impl_vpn_plugin_need_secrets (NMVPNPlugin *plugin,
|
||||
static gboolean impl_vpn_plugin_disconnect (NMVPNPlugin *plugin,
|
||||
GError **err);
|
||||
|
||||
static gboolean impl_vpn_plugin_set_config (NMVPNPlugin *plugin,
|
||||
GHashTable *config,
|
||||
GError **err);
|
||||
|
||||
static gboolean impl_vpn_plugin_set_ip4_config (NMVPNPlugin *plugin,
|
||||
GHashTable *config,
|
||||
GError **err);
|
||||
|
||||
static gboolean impl_vpn_plugin_set_ip6_config (NMVPNPlugin *plugin,
|
||||
GHashTable *config,
|
||||
GError **err);
|
||||
|
||||
static gboolean impl_vpn_plugin_set_failure (NMVPNPlugin *plugin,
|
||||
char *reason,
|
||||
GError **err);
|
||||
@@ -67,13 +75,21 @@ typedef struct {
|
||||
guint connect_timer;
|
||||
guint quit_timer;
|
||||
guint fail_stop_id;
|
||||
|
||||
gboolean has_ip4, got_ip4;
|
||||
gboolean has_ip6, got_ip6;
|
||||
|
||||
/* Config stuff copied from config to ip4config */
|
||||
GValue banner, tundev, gateway, mtu;
|
||||
} NMVPNPluginPrivate;
|
||||
|
||||
#define NM_VPN_PLUGIN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_VPN_PLUGIN, NMVPNPluginPrivate))
|
||||
|
||||
enum {
|
||||
STATE_CHANGED,
|
||||
CONFIG,
|
||||
IP4_CONFIG,
|
||||
IP6_CONFIG,
|
||||
LOGIN_BANNER,
|
||||
FAILURE,
|
||||
QUIT,
|
||||
@@ -315,15 +331,107 @@ nm_vpn_plugin_connect (NMVPNPlugin *plugin,
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
nm_vpn_plugin_set_config (NMVPNPlugin *plugin,
|
||||
GHashTable *config)
|
||||
{
|
||||
NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
|
||||
GValue *val;
|
||||
|
||||
g_return_if_fail (NM_IS_VPN_PLUGIN (plugin));
|
||||
g_return_if_fail (config != NULL);
|
||||
|
||||
val = g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_HAS_IP4);
|
||||
if (val && g_value_get_boolean (val))
|
||||
priv->has_ip4 = TRUE;
|
||||
val = g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_HAS_IP6);
|
||||
if (val && g_value_get_boolean (val))
|
||||
priv->has_ip6 = TRUE;
|
||||
|
||||
g_warn_if_fail (priv->has_ip4 || priv->has_ip6);
|
||||
|
||||
/* Record the items that need to also be inserted into the
|
||||
* ip4config, for compatibility with older daemons.
|
||||
*/
|
||||
val = g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_BANNER);
|
||||
if (val) {
|
||||
g_value_init (&priv->banner, G_VALUE_TYPE (val));
|
||||
g_value_copy (val, &priv->banner);
|
||||
}
|
||||
val = g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_TUNDEV);
|
||||
if (val) {
|
||||
g_value_init (&priv->tundev, G_VALUE_TYPE (val));
|
||||
g_value_copy (val, &priv->tundev);
|
||||
}
|
||||
val = g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY);
|
||||
if (val) {
|
||||
g_value_init (&priv->gateway, G_VALUE_TYPE (val));
|
||||
g_value_copy (val, &priv->gateway);
|
||||
}
|
||||
val = g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_MTU);
|
||||
if (val) {
|
||||
g_value_init (&priv->mtu, G_VALUE_TYPE (val));
|
||||
g_value_copy (val, &priv->mtu);
|
||||
}
|
||||
|
||||
g_signal_emit (plugin, signals[CONFIG], 0, config);
|
||||
}
|
||||
|
||||
void
|
||||
nm_vpn_plugin_set_ip4_config (NMVPNPlugin *plugin,
|
||||
GHashTable *ip4_config)
|
||||
{
|
||||
NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
|
||||
GHashTable *combined_config;
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
g_return_if_fail (NM_IS_VPN_PLUGIN (plugin));
|
||||
g_return_if_fail (ip4_config != NULL);
|
||||
|
||||
g_signal_emit (plugin, signals[IP4_CONFIG], 0, ip4_config);
|
||||
priv->got_ip4 = TRUE;
|
||||
|
||||
/* Older NetworkManager daemons expect all config info to be in
|
||||
* the ip4 config, so they won't even notice the "config" signal
|
||||
* being emitted. So just copy all of that data into the ip4
|
||||
* config too.
|
||||
*/
|
||||
combined_config = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
g_hash_table_iter_init (&iter, ip4_config);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
g_hash_table_insert (combined_config, key, value);
|
||||
|
||||
if (G_VALUE_TYPE (&priv->banner) != G_TYPE_INVALID)
|
||||
g_hash_table_insert (combined_config, NM_VPN_PLUGIN_IP4_CONFIG_BANNER, &priv->banner);
|
||||
if (G_VALUE_TYPE (&priv->tundev) != G_TYPE_INVALID)
|
||||
g_hash_table_insert (combined_config, NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV, &priv->tundev);
|
||||
if (G_VALUE_TYPE (&priv->gateway) != G_TYPE_INVALID)
|
||||
g_hash_table_insert (combined_config, NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY, &priv->gateway);
|
||||
if (G_VALUE_TYPE (&priv->mtu) != G_TYPE_INVALID)
|
||||
g_hash_table_insert (combined_config, NM_VPN_PLUGIN_IP4_CONFIG_MTU, &priv->mtu);
|
||||
|
||||
g_signal_emit (plugin, signals[IP4_CONFIG], 0, combined_config);
|
||||
g_hash_table_destroy (combined_config);
|
||||
|
||||
if ( priv->has_ip4 == priv->got_ip4
|
||||
&& priv->has_ip6 == priv->got_ip6)
|
||||
nm_vpn_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STARTED);
|
||||
}
|
||||
|
||||
void
|
||||
nm_vpn_plugin_set_ip6_config (NMVPNPlugin *plugin,
|
||||
GHashTable *ip6_config)
|
||||
{
|
||||
NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
|
||||
|
||||
g_return_if_fail (NM_IS_VPN_PLUGIN (plugin));
|
||||
g_return_if_fail (ip6_config != NULL);
|
||||
|
||||
priv->got_ip6 = TRUE;
|
||||
g_signal_emit (plugin, signals[IP6_CONFIG], 0, ip6_config);
|
||||
|
||||
if ( priv->has_ip4 == priv->got_ip4
|
||||
&& priv->has_ip6 == priv->got_ip6)
|
||||
nm_vpn_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STARTED);
|
||||
}
|
||||
|
||||
@@ -412,6 +520,16 @@ impl_vpn_plugin_disconnect (NMVPNPlugin *plugin,
|
||||
return nm_vpn_plugin_disconnect (plugin, err);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
impl_vpn_plugin_set_config (NMVPNPlugin *plugin,
|
||||
GHashTable *config,
|
||||
GError **err)
|
||||
{
|
||||
nm_vpn_plugin_set_config (plugin, config);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
impl_vpn_plugin_set_ip4_config (NMVPNPlugin *plugin,
|
||||
GHashTable *config,
|
||||
@@ -422,6 +540,16 @@ impl_vpn_plugin_set_ip4_config (NMVPNPlugin *plugin,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
impl_vpn_plugin_set_ip6_config (NMVPNPlugin *plugin,
|
||||
GHashTable *config,
|
||||
GError **err)
|
||||
{
|
||||
nm_vpn_plugin_set_ip6_config (plugin, config);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
impl_vpn_plugin_set_failure (NMVPNPlugin *plugin,
|
||||
char *reason,
|
||||
@@ -615,6 +743,11 @@ finalize (GObject *object)
|
||||
nm_vpn_plugin_set_connection (plugin, NULL);
|
||||
g_free (priv->dbus_service_name);
|
||||
|
||||
g_value_unset (&priv->banner);
|
||||
g_value_unset (&priv->tundev);
|
||||
g_value_unset (&priv->gateway);
|
||||
g_value_unset (&priv->mtu);
|
||||
|
||||
G_OBJECT_CLASS (nm_vpn_plugin_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@@ -725,6 +858,16 @@ nm_vpn_plugin_class_init (NMVPNPluginClass *plugin_class)
|
||||
G_TYPE_NONE, 1,
|
||||
G_TYPE_UINT);
|
||||
|
||||
signals[CONFIG] =
|
||||
g_signal_new ("config",
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (NMVPNPluginClass, config),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__BOXED,
|
||||
G_TYPE_NONE, 1,
|
||||
DBUS_TYPE_G_MAP_OF_VARIANT);
|
||||
|
||||
signals[IP4_CONFIG] =
|
||||
g_signal_new ("ip4-config",
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
@@ -735,6 +878,16 @@ nm_vpn_plugin_class_init (NMVPNPluginClass *plugin_class)
|
||||
G_TYPE_NONE, 1,
|
||||
DBUS_TYPE_G_MAP_OF_VARIANT);
|
||||
|
||||
signals[IP6_CONFIG] =
|
||||
g_signal_new ("ip6-config",
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (NMVPNPluginClass, ip6_config),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__BOXED,
|
||||
G_TYPE_NONE, 1,
|
||||
DBUS_TYPE_G_MAP_OF_VARIANT);
|
||||
|
||||
signals[LOGIN_BANNER] =
|
||||
g_signal_new ("login-banner",
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
|
@@ -91,13 +91,17 @@ typedef struct {
|
||||
|
||||
void (*quit) (NMVPNPlugin *plugin);
|
||||
|
||||
void (*config) (NMVPNPlugin *plugin,
|
||||
GHashTable *config);
|
||||
|
||||
void (*ip6_config) (NMVPNPlugin *plugin,
|
||||
GHashTable *config);
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_reserved1) (void);
|
||||
void (*_reserved2) (void);
|
||||
void (*_reserved3) (void);
|
||||
void (*_reserved4) (void);
|
||||
void (*_reserved5) (void);
|
||||
void (*_reserved6) (void);
|
||||
} NMVPNPluginClass;
|
||||
|
||||
GType nm_vpn_plugin_get_type (void);
|
||||
@@ -115,9 +119,15 @@ void nm_vpn_plugin_set_login_banner (NMVPNPlugin *plugin,
|
||||
void nm_vpn_plugin_failure (NMVPNPlugin *plugin,
|
||||
NMVPNPluginFailure reason);
|
||||
|
||||
void nm_vpn_plugin_set_config (NMVPNPlugin *plugin,
|
||||
GHashTable *config);
|
||||
|
||||
void nm_vpn_plugin_set_ip4_config (NMVPNPlugin *plugin,
|
||||
GHashTable *ip4_config);
|
||||
|
||||
void nm_vpn_plugin_set_ip6_config (NMVPNPlugin *plugin,
|
||||
GHashTable *ip6_config);
|
||||
|
||||
gboolean nm_vpn_plugin_disconnect (NMVPNPlugin *plugin,
|
||||
GError **err);
|
||||
|
||||
|
@@ -908,8 +908,6 @@ nm_dns_manager_add_ip6_config (NMDnsManager *mgr,
|
||||
|
||||
switch (cfg_type) {
|
||||
case NM_DNS_IP_CONFIG_TYPE_VPN:
|
||||
/* FIXME: not quite yet... */
|
||||
g_return_val_if_fail (cfg_type != NM_DNS_IP_CONFIG_TYPE_VPN, FALSE);
|
||||
priv->ip6_vpn_config = config;
|
||||
break;
|
||||
case NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE:
|
||||
|
@@ -449,9 +449,7 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
|
||||
int ip_ifindex = 0;
|
||||
|
||||
best = get_best_ip4_device (policy->manager, &best_req);
|
||||
if (!best)
|
||||
goto out;
|
||||
if (!force_update && (best == policy->default_device4))
|
||||
if (!force_update && best && (best == policy->default_device4))
|
||||
goto out;
|
||||
|
||||
/* If a VPN connection is active, it is preferred */
|
||||
@@ -469,7 +467,7 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
|
||||
|
||||
/* Check the active IP4 config from the VPN service daemon */
|
||||
ip4_config = nm_vpn_connection_get_ip4_config (candidate);
|
||||
if (ip4_config && nm_ip4_config_get_never_default (ip4_config))
|
||||
if (!ip4_config || nm_ip4_config_get_never_default (ip4_config))
|
||||
can_default = FALSE;
|
||||
|
||||
/* Check the user's preference from the NMConnection */
|
||||
@@ -481,6 +479,7 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
|
||||
if (can_default && (vpn_state == NM_VPN_CONNECTION_STATE_ACTIVATED)) {
|
||||
NMIP4Config *parent_ip4;
|
||||
NMDevice *parent;
|
||||
guint32 parent_mss;
|
||||
|
||||
ip_iface = nm_vpn_connection_get_ip_iface (candidate);
|
||||
ip_ifindex = nm_vpn_connection_get_ip_ifindex (candidate);
|
||||
@@ -489,13 +488,14 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
|
||||
|
||||
parent = nm_vpn_connection_get_parent_device (candidate);
|
||||
parent_ip4 = nm_device_get_ip4_config (parent);
|
||||
parent_mss = parent_ip4 ? nm_ip4_config_get_mss (parent_ip4) : 0;
|
||||
|
||||
nm_system_replace_default_ip4_route_vpn (ip_ifindex,
|
||||
nm_ip4_address_get_gateway (addr),
|
||||
nm_vpn_connection_get_ip4_internal_gateway (candidate),
|
||||
nm_ip4_config_get_mss (ip4_config),
|
||||
nm_device_get_ip_ifindex (parent),
|
||||
nm_ip4_config_get_mss (parent_ip4));
|
||||
parent_mss);
|
||||
|
||||
dns_type = NM_DNS_IP_CONFIG_TYPE_VPN;
|
||||
}
|
||||
@@ -504,6 +504,9 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
|
||||
|
||||
/* The best device gets the default route if a VPN connection didn't */
|
||||
if (!ip_iface || !ip4_config) {
|
||||
if (!best)
|
||||
goto out;
|
||||
|
||||
connection = nm_act_request_get_connection (best_req);
|
||||
ip_iface = nm_device_get_ip_iface (best);
|
||||
ip_ifindex = nm_device_get_ip_ifindex (best);
|
||||
@@ -570,9 +573,7 @@ update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
|
||||
NMActRequest *best_req = NULL;
|
||||
NMDnsManager *dns_mgr;
|
||||
GSList *devices = NULL, *iter;
|
||||
#if 0
|
||||
GSList *vpns;
|
||||
#endif
|
||||
NMIP6Config *ip6_config = NULL;
|
||||
NMIP6Address *addr;
|
||||
const char *ip_iface = NULL;
|
||||
@@ -582,12 +583,9 @@ update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
|
||||
const char *connection_id;
|
||||
|
||||
best = get_best_ip6_device (policy->manager, &best_req);
|
||||
if (!best)
|
||||
goto out;
|
||||
if (!force_update && (best == policy->default_device6))
|
||||
if (!force_update && best && (best == policy->default_device6))
|
||||
goto out;
|
||||
|
||||
#if 0
|
||||
/* If a VPN connection is active, it is preferred */
|
||||
vpns = nm_vpn_manager_get_active_connections (policy->vpn_manager);
|
||||
for (iter = vpns; iter; iter = g_slist_next (iter)) {
|
||||
@@ -600,6 +598,13 @@ update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
|
||||
/* If it's marked 'never-default', don't make it default */
|
||||
vpn_connection = nm_vpn_connection_get_connection (candidate);
|
||||
g_assert (vpn_connection);
|
||||
|
||||
/* Check the active IP6 config from the VPN service daemon */
|
||||
ip6_config = nm_vpn_connection_get_ip6_config (candidate);
|
||||
if (!ip6_config || nm_ip6_config_get_never_default (ip6_config))
|
||||
can_default = FALSE;
|
||||
|
||||
/* Check the user's preference from the NMConnection */
|
||||
s_ip6 = nm_connection_get_setting_ip6_config (vpn_connection);
|
||||
if (s_ip6 && nm_setting_ip6_config_get_never_default (s_ip6))
|
||||
can_default = FALSE;
|
||||
@@ -608,30 +613,34 @@ update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
|
||||
if (can_default && (vpn_state == NM_VPN_CONNECTION_STATE_ACTIVATED)) {
|
||||
NMIP6Config *parent_ip6;
|
||||
NMDevice *parent;
|
||||
guint32 parent_mss;
|
||||
|
||||
ip_iface = nm_vpn_connection_get_ip_iface (candidate);
|
||||
ip_ifindex = nm_vpn_connection_get_ip_ifindex (candidate);
|
||||
connection = nm_vpn_connection_get_connection (candidate);
|
||||
ip6_config = nm_vpn_connection_get_ip6_config (candidate);
|
||||
addr = nm_ip6_config_get_address (ip6_config, 0);
|
||||
|
||||
parent = nm_vpn_connection_get_parent_device (candidate);
|
||||
parent_ip6 = nm_device_get_ip6_config (parent);
|
||||
parent_mss = parent_ip6 ? nm_ip6_config_get_mss (parent_ip6) : 0;
|
||||
|
||||
nm_system_replace_default_ip6_route_vpn (ip_iface,
|
||||
nm_system_replace_default_ip6_route_vpn (ip_ifindex,
|
||||
nm_ip6_address_get_gateway (addr),
|
||||
nm_vpn_connection_get_ip4_internal_gateway (candidate),
|
||||
nm_ip6_config_get_mss (ip4_config),
|
||||
nm_device_get_ip_iface (parent),
|
||||
nm_ip6_config_get_mss (parent_ip4));
|
||||
nm_vpn_connection_get_ip6_internal_gateway (candidate),
|
||||
nm_ip6_config_get_mss (ip6_config),
|
||||
nm_device_get_ip_ifindex (parent),
|
||||
parent_mss);
|
||||
|
||||
dns_type = NM_DNS_IP_CONFIG_TYPE_VPN;
|
||||
}
|
||||
}
|
||||
g_slist_free (vpns);
|
||||
#endif
|
||||
|
||||
/* The best device gets the default route if a VPN connection didn't */
|
||||
if (!ip_iface || !ip6_config) {
|
||||
if (!best)
|
||||
goto out;
|
||||
|
||||
connection = nm_act_request_get_connection (best_req);
|
||||
ip_iface = nm_device_get_ip_iface (best);
|
||||
ip_ifindex = nm_device_get_ip_ifindex (best);
|
||||
|
106
src/nm-system.c
106
src/nm-system.c
@@ -992,7 +992,7 @@ nm_system_replace_default_ip4_route_vpn (int ifindex,
|
||||
goto out;
|
||||
|
||||
if ((err != -NLE_OBJ_NOTFOUND) && (err != -NLE_FAILURE)) {
|
||||
nm_log_err (LOGD_DEVICE | LOGD_IP4,
|
||||
nm_log_err (LOGD_DEVICE | LOGD_VPN | LOGD_IP4,
|
||||
"(%s): failed to set IPv4 default route: %d",
|
||||
iface, err);
|
||||
goto out;
|
||||
@@ -1007,7 +1007,7 @@ nm_system_replace_default_ip4_route_vpn (int ifindex,
|
||||
err = replace_default_ip4_route (ifindex, int_gw, mss);
|
||||
if (err != 0) {
|
||||
nm_netlink_route_delete (gw_route);
|
||||
nm_log_err (LOGD_DEVICE | LOGD_IP4,
|
||||
nm_log_err (LOGD_DEVICE | LOGD_VPN | LOGD_IP4,
|
||||
"(%s): failed to set IPv4 default route (pass #2): %d",
|
||||
iface, err);
|
||||
} else
|
||||
@@ -1072,7 +1072,7 @@ out:
|
||||
}
|
||||
|
||||
static struct rtnl_route *
|
||||
add_ip6_route_to_gateway (int ifindex, const struct in6_addr *gw)
|
||||
add_ip6_route_to_gateway (int ifindex, const struct in6_addr *gw, int mss)
|
||||
{
|
||||
struct nl_sock *nlh;
|
||||
struct rtnl_route *route = NULL;
|
||||
@@ -1082,7 +1082,7 @@ add_ip6_route_to_gateway (int ifindex, const struct in6_addr *gw)
|
||||
g_return_val_if_fail (nlh != NULL, NULL);
|
||||
|
||||
/* Gateway might be over a bridge; try adding a route to gateway first */
|
||||
route = nm_netlink_route_new (ifindex, AF_INET6, 0,
|
||||
route = nm_netlink_route_new (ifindex, AF_INET6, mss,
|
||||
NMNL_PROP_SCOPE, RT_SCOPE_LINK,
|
||||
NMNL_PROP_TABLE, RT_TABLE_MAIN,
|
||||
NULL);
|
||||
@@ -1106,7 +1106,7 @@ add_ip6_route_to_gateway (int ifindex, const struct in6_addr *gw)
|
||||
}
|
||||
|
||||
static int
|
||||
add_default_ip6_route (int ifindex, const struct in6_addr *gw)
|
||||
add_default_ip6_route (int ifindex, const struct in6_addr *gw, int mss)
|
||||
{
|
||||
struct rtnl_route *route = NULL;
|
||||
struct nl_sock *nlh;
|
||||
@@ -1117,7 +1117,7 @@ add_default_ip6_route (int ifindex, const struct in6_addr *gw)
|
||||
nlh = nm_netlink_get_default_handle ();
|
||||
g_return_val_if_fail (nlh != NULL, -ENOMEM);
|
||||
|
||||
route = nm_netlink_route_new (ifindex, AF_INET6, 0,
|
||||
route = nm_netlink_route_new (ifindex, AF_INET6, mss,
|
||||
NMNL_PROP_SCOPE, RT_SCOPE_UNIVERSE,
|
||||
NMNL_PROP_TABLE, RT_TABLE_MAIN,
|
||||
NMNL_PROP_PRIO, 1,
|
||||
@@ -1150,20 +1150,12 @@ find_static_default_routes (struct rtnl_route *route,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* nm_system_replace_default_ip6_route
|
||||
*
|
||||
* Replace default IPv6 route with one via the given gateway
|
||||
*
|
||||
*/
|
||||
gboolean
|
||||
nm_system_replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
|
||||
static int
|
||||
replace_default_ip6_route (int ifindex, const struct in6_addr *gw, int mss)
|
||||
{
|
||||
GList *def_routes, *iter;
|
||||
struct rtnl_route *route, *gw_route = NULL;
|
||||
gboolean success = FALSE;
|
||||
struct rtnl_route *route;
|
||||
char *iface;
|
||||
int err;
|
||||
|
||||
/* We can't just use NLM_F_REPLACE here like in the IPv4 case, because
|
||||
* the kernel doesn't like it if we replace the default routes it
|
||||
@@ -1187,11 +1179,25 @@ nm_system_replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
|
||||
}
|
||||
g_list_free (def_routes);
|
||||
|
||||
err = add_default_ip6_route (ifindex, gw);
|
||||
if (err == 0)
|
||||
return TRUE;
|
||||
return add_default_ip6_route (ifindex, gw, mss);
|
||||
}
|
||||
|
||||
if (err == -NLE_EXIST)
|
||||
/*
|
||||
* nm_system_replace_default_ip6_route
|
||||
*
|
||||
* Replace default IPv6 route with one via the given gateway
|
||||
*
|
||||
*/
|
||||
gboolean
|
||||
nm_system_replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
|
||||
{
|
||||
struct rtnl_route *gw_route = NULL;
|
||||
gboolean success = FALSE;
|
||||
char *iface;
|
||||
int err;
|
||||
|
||||
err = replace_default_ip6_route (ifindex, gw, 0);
|
||||
if (err == 0 || err == -NLE_EXIST)
|
||||
return TRUE;
|
||||
|
||||
iface = nm_netlink_index_to_iface (ifindex);
|
||||
@@ -1206,12 +1212,12 @@ nm_system_replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
|
||||
}
|
||||
|
||||
/* Try adding a direct route to the gateway first */
|
||||
gw_route = add_ip6_route_to_gateway (ifindex, gw);
|
||||
gw_route = add_ip6_route_to_gateway (ifindex, gw, 0);
|
||||
if (!gw_route)
|
||||
goto out;
|
||||
|
||||
/* Try adding the original route again */
|
||||
err = add_default_ip6_route (ifindex, gw);
|
||||
err = replace_default_ip6_route (ifindex, gw, 0);
|
||||
if (err != 0) {
|
||||
nm_netlink_route_delete (gw_route);
|
||||
nm_log_err (LOGD_DEVICE | LOGD_IP6,
|
||||
@@ -1227,6 +1233,60 @@ out:
|
||||
return success;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_system_replace_default_ip6_route_vpn (int ifindex,
|
||||
const struct in6_addr *ext_gw,
|
||||
const struct in6_addr *int_gw,
|
||||
guint32 mss,
|
||||
int parent_ifindex,
|
||||
guint32 parent_mss)
|
||||
{
|
||||
struct rtnl_route *gw_route = NULL;
|
||||
struct nl_sock *nlh;
|
||||
gboolean success = FALSE;
|
||||
int err;
|
||||
char *iface;
|
||||
|
||||
nlh = nm_netlink_get_default_handle ();
|
||||
g_return_val_if_fail (nlh != NULL, FALSE);
|
||||
|
||||
err = replace_default_ip6_route (ifindex, int_gw, mss);
|
||||
if (err == 0)
|
||||
return TRUE;
|
||||
|
||||
iface = nm_netlink_index_to_iface (ifindex);
|
||||
if (!iface)
|
||||
goto out;
|
||||
|
||||
if ((err != -NLE_OBJ_NOTFOUND) && (err != -NLE_FAILURE)) {
|
||||
nm_log_err (LOGD_DEVICE | LOGD_VPN | LOGD_IP6,
|
||||
"(%s): failed to set IPv6 default route: %d",
|
||||
iface, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Try adding a direct route to the gateway first */
|
||||
gw_route = add_ip6_route_to_gateway (parent_ifindex, ext_gw, parent_mss);
|
||||
if (!gw_route)
|
||||
goto out;
|
||||
|
||||
/* Try adding the original route again */
|
||||
err = replace_default_ip6_route (ifindex, int_gw, mss);
|
||||
if (err != 0) {
|
||||
nm_netlink_route_delete (gw_route);
|
||||
nm_log_err (LOGD_DEVICE | LOGD_VPN | LOGD_IP6,
|
||||
"(%s): failed to set IPv6 default route (pass #2): %d",
|
||||
iface, err);
|
||||
} else
|
||||
success = TRUE;
|
||||
|
||||
out:
|
||||
if (gw_route)
|
||||
rtnl_route_put (gw_route);
|
||||
g_free (iface);
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* nm_system_iface_flush_addresses
|
||||
*
|
||||
|
@@ -53,6 +53,13 @@ gboolean nm_system_replace_default_ip4_route_vpn (int ifindex,
|
||||
int parent_ifindex,
|
||||
guint32 parent_mss);
|
||||
|
||||
gboolean nm_system_replace_default_ip6_route_vpn (int ifindex,
|
||||
const struct in6_addr *ext_gw,
|
||||
const struct in6_addr *int_gw,
|
||||
guint32 mss,
|
||||
int parent_ifindex,
|
||||
guint32 parent_mss);
|
||||
|
||||
struct rtnl_route *nm_system_add_ip4_vpn_gateway_route (NMDevice *parent_device,
|
||||
guint32 vpn_gw);
|
||||
struct rtnl_route *nm_system_add_ip6_vpn_gateway_route (NMDevice *parent_device,
|
||||
|
@@ -84,13 +84,18 @@ typedef struct {
|
||||
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;
|
||||
@@ -180,7 +185,7 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
|
||||
priv->parent_dev,
|
||||
ip_iface,
|
||||
priv->ip4_config,
|
||||
NULL);
|
||||
priv->ip6_config);
|
||||
break;
|
||||
case NM_VPN_CONNECTION_STATE_FAILED:
|
||||
case NM_VPN_CONNECTION_STATE_DISCONNECTED:
|
||||
@@ -421,7 +426,7 @@ ip_address_to_string (guint32 numeric)
|
||||
}
|
||||
|
||||
static const char *
|
||||
ip6_address_to_string (struct in6_addr *addr)
|
||||
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)) {
|
||||
@@ -437,6 +442,7 @@ print_vpn_config (NMVPNConnection *connection)
|
||||
{
|
||||
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
|
||||
NMIP4Address *addr;
|
||||
NMIP6Address *addr6;
|
||||
char *dns_domain = NULL;
|
||||
guint32 num, i;
|
||||
|
||||
@@ -448,41 +454,87 @@ print_vpn_config (NMVPNConnection *connection)
|
||||
ip6_address_to_string (priv->ip6_external_gw));
|
||||
}
|
||||
|
||||
nm_log_info (LOGD_VPN, "Tunnel Device: %s", priv->ip_iface);
|
||||
|
||||
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, "Tunnel Device: %s", priv->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",
|
||||
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));
|
||||
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",
|
||||
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_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 IP4 DNS: %s",
|
||||
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)");
|
||||
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));
|
||||
|
||||
num = nm_ip6_config_get_num_routes (priv->ip6_config);
|
||||
for (i = 0; i < num; i++) {
|
||||
NMIP6Route *route;
|
||||
|
||||
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 (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:");
|
||||
@@ -492,6 +544,186 @@ print_vpn_config (NMVPNConnection *connection)
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
nm_vpn_connection_apply_config (NMVPNConnection *connection)
|
||||
{
|
||||
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
|
||||
NMDnsManager *dns_mgr;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Add the VPN to DNS */
|
||||
dns_mgr = nm_dns_manager_get (NULL);
|
||||
if (priv->ip4_config) {
|
||||
nm_dns_manager_add_ip4_config (dns_mgr, priv->ip_iface, priv->ip4_config,
|
||||
NM_DNS_IP_CONFIG_TYPE_VPN);
|
||||
}
|
||||
if (priv->ip6_config) {
|
||||
nm_dns_manager_add_ip6_config (dns_mgr, priv->ip_iface, priv->ip6_config,
|
||||
NM_DNS_IP_CONFIG_TYPE_VPN);
|
||||
}
|
||||
g_object_unref (dns_mgr);
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
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!");
|
||||
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);
|
||||
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,
|
||||
@@ -505,47 +737,25 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
|
||||
GValue *val;
|
||||
int i;
|
||||
|
||||
nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) reply received.",
|
||||
if (priv->has_ip4) {
|
||||
nm_log_info (LOGD_VPN, "VPN connection '%s' (IP4 Config Get) reply received.",
|
||||
nm_vpn_connection_get_name (connection));
|
||||
} else {
|
||||
nm_log_info (LOGD_VPN, "VPN connection '%s' (IP4 Config Get) reply received from old-style plugin.",
|
||||
nm_vpn_connection_get_name (connection));
|
||||
|
||||
g_source_remove (priv->ipconfig_timeout);
|
||||
priv->ipconfig_timeout = 0;
|
||||
/* 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 ();
|
||||
|
||||
val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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_IP4_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);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
addr = nm_ip4_address_new ();
|
||||
nm_ip4_address_set_prefix (addr, 24); /* default to class C */
|
||||
if (priv->ip4_external_gw)
|
||||
@@ -573,7 +783,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);
|
||||
@@ -596,9 +808,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)
|
||||
@@ -613,12 +824,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;
|
||||
@@ -635,8 +840,10 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
|
||||
*/
|
||||
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_get_prefix (route) == 32) {
|
||||
nm_ip4_route_unref (route);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Otherwise accept the VPN-provided route */
|
||||
nm_ip4_config_take_route (config, route);
|
||||
@@ -649,50 +856,143 @@ 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));
|
||||
|
||||
priv->ip4_config = config;
|
||||
print_vpn_config (connection);
|
||||
|
||||
/* 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 */
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
|
||||
nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) complete.",
|
||||
nm_log_info (LOGD_VPN, "VPN connection '%s' (IP6 Config Get) reply received.",
|
||||
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;
|
||||
|
||||
config = nm_ip6_config_new ();
|
||||
|
||||
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:
|
||||
g_clear_object (&priv->ip4_config);
|
||||
val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS);
|
||||
if (val) {
|
||||
GByteArray *ba = g_value_get_boxed (val);
|
||||
|
||||
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);
|
||||
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
|
||||
@@ -781,9 +1081,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);
|
||||
@@ -791,6 +1100,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,
|
||||
@@ -883,6 +1200,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)
|
||||
{
|
||||
@@ -915,6 +1240,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)
|
||||
@@ -1090,10 +1423,6 @@ vpn_cleanup (NMVPNConnection *connection)
|
||||
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) {
|
||||
@@ -1106,7 +1435,29 @@ vpn_cleanup (NMVPNConnection *connection)
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->ip6_config) {
|
||||
NMIP6Config *parent_config;
|
||||
NMDnsManager *dns_mgr;
|
||||
|
||||
/* Remove attributes of the VPN's IP6 Config */
|
||||
dns_mgr = nm_dns_manager_get (NULL);
|
||||
nm_dns_manager_remove_ip6_config (dns_mgr, priv->ip_iface, priv->ip6_config);
|
||||
g_object_unref (dns_mgr);
|
||||
|
||||
/* Reset routes and addresses of the currently active device */
|
||||
parent_config = nm_device_get_ip6_config (priv->parent_dev);
|
||||
if (parent_config) {
|
||||
if (!nm_system_apply_ip6_config (nm_device_get_ip_ifindex (priv->parent_dev),
|
||||
nm_device_get_ip6_config (priv->parent_dev),
|
||||
nm_device_get_priority (priv->parent_dev),
|
||||
NM_IP6_COMPARE_FLAG_ADDRESSES | NM_IP6_COMPARE_FLAG_ROUTES)) {
|
||||
nm_log_err (LOGD_VPN, "failed to re-apply VPN parent device addresses and routes.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->gw_route) {
|
||||
nm_netlink_route_delete (priv->gw_route);
|
||||
rtnl_route_put (priv->gw_route);
|
||||
priv->gw_route = NULL;
|
||||
}
|
||||
@@ -1192,6 +1543,8 @@ 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);
|
||||
|
||||
@@ -1207,6 +1560,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);
|
||||
|
@@ -68,9 +68,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 */
|
||||
|
Reference in New Issue
Block a user