diff options
-rw-r--r-- | ChangeLog | 56 | ||||
-rw-r--r-- | src/NetworkManager.c | 5 | ||||
-rw-r--r-- | src/NetworkManagerPolicy.c | 148 | ||||
-rw-r--r-- | src/NetworkManagerPolicy.h | 3 | ||||
-rw-r--r-- | src/NetworkManagerSystem.c | 284 | ||||
-rw-r--r-- | src/NetworkManagerSystem.h | 23 | ||||
-rw-r--r-- | src/nm-device.c | 2 | ||||
-rw-r--r-- | src/vpn-manager/nm-vpn-connection.c | 80 | ||||
-rw-r--r-- | src/vpn-manager/nm-vpn-connection.h | 3 | ||||
-rw-r--r-- | src/vpn-manager/nm-vpn-manager.c | 33 | ||||
-rw-r--r-- | src/vpn-manager/nm-vpn-manager.h | 2 |
11 files changed, 418 insertions, 221 deletions
@@ -1,3 +1,59 @@ +2008-10-10 Dan Williams <dcbw@redhat.com> + + Rework default route handling to consolidate decisions in the policy, + and to take active VPN connections into account when changing the default + route (bgo #545912) + + * src/NetworkManager.c + - (main): pass the vpn_manager to the policy so it knows about active + VPN connections; clean up the named manager which wasn't done before + + * src/NetworkManagerPolicy.c + src/NetworkManagerPolicy.h + - (nm_policy_new): get a clue about the vpn_manager + - (update_default_route): remove, fold into update_routing_and_dns() + - (update_routing_and_dns): handle active VPN connections too; an + active VPN connection becomes the default route if it does not have + server-specified or user-specified custom routes. Otherwise, the + best active device gets the default route + - (vpn_connection_activated, vpn_connection_deactivated, nm_policy_new, + nm_policy_destroy): track VPN connection activation and deactivation + and update the default route when appropriate + + * src/NetworkManagerSystem.c + src/NetworkManagerSystem.h + - (nm_system_vpn_device_unset_from_ip4_config): remove, put functionality + in the VPN connection itself + - (nm_system_vpn_device_set_from_ip4_config, + nm_system_device_set_from_ip4_config): merge together to make + nm_system_apply_ip4_config() + - (add_vpn_gateway_route): add a route to the VPN's external gateway + via the parent device + - (nm_system_apply_ip4_config): simplify + - (add_ip4_route_to_gateway): new function; add a direct route to the + gateway if needed + - (nm_system_device_replace_default_ip4_route): simplify, break gateway + route stuff out into add_ip4_route_to_gateway() for clarity + + * src/nm-device.c + - (nm_device_set_ip4_config): update for nm_system_apply_ip4_config() + + * src/vpn-manager/nm-vpn-connection.c + src/vpn-manager/nm-vpn-connection.h + - (nm_vpn_connection_get_ip4_config, nm_vpn_connection_get_ip_iface, + nm_vpn_connection_get_parent_device): add + - (nm_vpn_connection_ip4_config_get): make the requirement of a tunnel + device explicit + - (connection_state_changed): update the named manager now that + nm_system_vpn_device_unset_from_ip4_config() is gone; do something + useful on errors + + * src/vpn-manager/nm-vpn-manager.c + src/vpn-manager/nm-vpn-manager.h + - Add a 'connection-activated' signal + - (nm_vpn_manager_get_active_connections): new function; mainly for the + policy to find out about active VPN connections + 2008-10-10 Tambet Ingo <tambet@gmail.com> * src/nm-logging.c (nm_logging_setup): Don't use LOG_CONS when running as diff --git a/src/NetworkManager.c b/src/NetworkManager.c index e3079db489..948fb664d3 100644 --- a/src/NetworkManager.c +++ b/src/NetworkManager.c @@ -308,7 +308,7 @@ main (int argc, char *argv[]) goto done; } - policy = nm_policy_new (manager); + policy = nm_policy_new (manager, vpn_manager); if (policy == NULL) { nm_error ("Failed to initialize the policy."); goto done; @@ -352,6 +352,9 @@ done: if (vpn_manager) g_object_unref (vpn_manager); + if (named_mgr) + g_object_unref (named_mgr); + if (sup_mgr) g_object_unref (sup_mgr); diff --git a/src/NetworkManagerPolicy.c b/src/NetworkManagerPolicy.c index 25024c2cc4..46c51e9d0f 100644 --- a/src/NetworkManagerPolicy.c +++ b/src/NetworkManagerPolicy.c @@ -43,6 +43,7 @@ #include "nm-setting-connection.h" #include "NetworkManagerSystem.h" #include "nm-named-manager.h" +#include "nm-vpn-manager.h" typedef struct LookupThread LookupThread; @@ -69,6 +70,10 @@ struct NMPolicy { GSList *signal_ids; GSList *dev_signal_ids; + NMVPNManager *vpn_manager; + gulong vpn_activated_id; + gulong vpn_deactivated_id; + NMDevice *default_device; LookupThread *lookup; @@ -462,34 +467,21 @@ update_system_hostname (NMPolicy *policy, NMDevice *best) } static void -update_default_route (NMPolicy *policy, NMDevice *new) -{ - const char *ip_iface; - - /* FIXME: Not sure if the following makes any sense. */ - /* If iface and ip_iface are the same, it's a regular network device and we - treat it as such. However, if they differ, it's most likely something like - a serial device with ppp interface, so route all the traffic to it. */ - ip_iface = nm_device_get_ip_iface (new); - if (strcmp (ip_iface, nm_device_get_iface (new))) { - nm_system_device_replace_default_ip4_route (ip_iface, 0, 0); - } else { - NMIP4Config *config; - const NMSettingIP4Address *def_addr; - - config = nm_device_get_ip4_config (new); - def_addr = nm_ip4_config_get_address (config, 0); - nm_system_device_replace_default_ip4_route (ip_iface, def_addr->gateway, nm_ip4_config_get_mss (config)); - } -} - -static void update_routing_and_dns (NMPolicy *policy, gboolean force_update) { + NMNamedIPConfigType dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE; NMDevice *best = NULL; NMActRequest *best_req = NULL; NMNamedManager *named_mgr; - GSList *devices = NULL, *iter; + GSList *devices = NULL, *iter, *vpns; + NMIP4Config *ip4_config = NULL; + const char *ip_iface = NULL; + const char *parent_iface = NULL; + NMVPNConnection *vpn = NULL; + NMConnection *connection = NULL; + NMSettingConnection *s_con = NULL; + guint32 parent_mss = 0; + guint32 gateway = 0; best = get_best_device (policy->manager, &best_req); if (!best) @@ -497,8 +489,69 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update) if (!force_update && (best == policy->default_device)) goto out; - update_default_route (policy, best); - + /* 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)) { + NMVPNConnection *candidate = NM_VPN_CONNECTION (iter->data); + + if (!vpn && (nm_vpn_connection_get_vpn_state (candidate) == NM_VPN_CONNECTION_STATE_ACTIVATED)) + vpn = g_object_ref (candidate); + g_object_unref (candidate); + } + g_slist_free (vpns); + + /* VPNs are the default route only if they don't have custom routes */ + if (vpn) { + NMIP4Config *vpn_config; + + vpn_config = nm_vpn_connection_get_ip4_config (vpn); + if (nm_ip4_config_get_num_routes (vpn_config) == 0) { + NMIP4Config *parent_ip4; + NMDevice *parent; + + connection = nm_vpn_connection_get_connection (vpn); + ip_iface = nm_vpn_connection_get_ip_iface (vpn); + ip4_config = vpn_config; + + parent = nm_vpn_connection_get_parent_device (vpn); + parent_iface = nm_device_get_ip_iface (parent); + parent_ip4 = nm_device_get_ip4_config (parent); + if (parent_ip4) + parent_mss = nm_ip4_config_get_mss (parent_ip4); + + dns_type = NM_NAMED_IP_CONFIG_TYPE_VPN; + } + g_object_unref (vpn); + } + + /* The best device gets the default route if a VPN connection didn't */ + if (!ip_iface || !ip4_config) { + const NMSettingIP4Address *addr; + + connection = nm_act_request_get_connection (best_req); + ip_iface = nm_device_get_ip_iface (best); + ip4_config = nm_device_get_ip4_config (best); + if (ip4_config) { + addr = nm_ip4_config_get_address (ip4_config, 0); + gateway = addr->gateway; + } + + dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE; + } + + if (!ip_iface || !ip4_config) { + nm_warning ("%s: couldn't determine IP interface (%p) or IPv4 config (%p)!", + __func__, ip_iface, ip4_config); + goto out; + } + + /* Set the new default route */ + nm_system_device_replace_default_ip4_route (ip_iface, + gateway, + nm_ip4_config_get_mss (ip4_config), + parent_iface, + parent_mss); + /* Update the default active connection. Only mark the new default * active connection after setting default = FALSE on all other connections * first. The order is important, we don't want two connections marked @@ -515,10 +568,7 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update) } named_mgr = nm_named_manager_get (); - nm_named_manager_add_ip4_config (named_mgr, - nm_device_get_ip_iface (best), - nm_device_get_ip4_config (best), - NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE); + nm_named_manager_add_ip4_config (named_mgr, ip_iface, ip4_config, dns_type); g_object_unref (named_mgr); /* Now set new default active connection _after_ updating DNS info, so that @@ -527,8 +577,13 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update) if (best_req) nm_act_request_set_default (best_req, TRUE); - nm_info ("Policy set (%s) as default device for routing and DNS.", - nm_device_get_iface (best)); + if (connection) + s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); + + if (s_con && s_con->id) + nm_info ("Policy set '%s' (%s) as default for routing and DNS.", s_con->id, ip_iface); + else + nm_info ("Policy set (%s) as default for routing and DNS.", ip_iface); out: /* Update the system hostname */ @@ -618,6 +673,24 @@ auto_activate_device (gpointer user_data) /*****************************************************************************/ static void +vpn_connection_activated (NMVPNManager *manager, + NMVPNConnection *vpn, + gpointer user_data) +{ + update_routing_and_dns ((NMPolicy *) user_data, TRUE); +} + +static void +vpn_connection_deactivated (NMVPNManager *manager, + NMVPNConnection *vpn, + NMVPNConnectionState state, + NMVPNConnectionStateReason reason, + gpointer user_data) +{ + update_routing_and_dns ((NMPolicy *) user_data, TRUE); +} + +static void global_state_changed (NMManager *manager, NMState state, gpointer user_data) { } @@ -868,7 +941,7 @@ connection_removed (NMManager *manager, } NMPolicy * -nm_policy_new (NMManager *manager) +nm_policy_new (NMManager *manager, NMVPNManager *vpn_manager) { NMPolicy *policy; static gboolean initialized = FALSE; @@ -881,6 +954,14 @@ nm_policy_new (NMManager *manager) policy->manager = g_object_ref (manager); policy->update_state_id = 0; + policy->vpn_manager = g_object_ref (vpn_manager); + id = g_signal_connect (policy->vpn_manager, "connection-activated", + G_CALLBACK (vpn_connection_activated), policy); + policy->vpn_activated_id = id; + id = g_signal_connect (policy->vpn_manager, "connection-deactivated", + G_CALLBACK (vpn_connection_deactivated), policy); + policy->vpn_deactivated_id = id; + id = g_signal_connect (manager, "state-changed", G_CALLBACK (global_state_changed), policy); policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id); @@ -944,6 +1025,9 @@ nm_policy_destroy (NMPolicy *policy) } g_slist_free (policy->pending_activation_checks); + g_signal_handler_disconnect (policy->vpn_manager, policy->vpn_activated_id); + g_signal_handler_disconnect (policy->vpn_manager, policy->vpn_deactivated_id); + for (iter = policy->signal_ids; iter; iter = g_slist_next (iter)) g_signal_handler_disconnect (policy->manager, (gulong) iter->data); g_slist_free (policy->signal_ids); diff --git a/src/NetworkManagerPolicy.h b/src/NetworkManagerPolicy.h index 9f2c52323d..5ab379f89a 100644 --- a/src/NetworkManagerPolicy.h +++ b/src/NetworkManagerPolicy.h @@ -24,12 +24,13 @@ #include "NetworkManager.h" #include "nm-manager.h" +#include "nm-vpn-manager.h" #include "nm-device.h" #include "nm-activation-request.h" typedef struct NMPolicy NMPolicy; -NMPolicy *nm_policy_new (NMManager *manager); +NMPolicy *nm_policy_new (NMManager *manager, NMVPNManager *vpn_manager); void nm_policy_destroy (NMPolicy *policy); #endif /* NETWORK_MANAGER_POLICY_H */ diff --git a/src/NetworkManagerSystem.c b/src/NetworkManagerSystem.c index 8f836d98a2..653e90a712 100644 --- a/src/NetworkManagerSystem.c +++ b/src/NetworkManagerSystem.c @@ -273,114 +273,75 @@ add_ip4_addresses (NMIP4Config *config, const char *iface) return TRUE; } -/* - * nm_system_device_set_from_ip4_config - * - * Set IPv4 configuration of the device from an NMIP4Config object. - * - */ -gboolean -nm_system_device_set_from_ip4_config (const char *iface, - NMIP4Config *config, - int priority) +static void +add_vpn_gateway_route (NMDevice *device, const char *iface, NMIP4Config *config) { - int len, i; + NMIP4Config *ad_config; + guint32 ad_gw = 0, vpn_gw = 0, i; + const NMSettingIP4Address *tmp; - g_return_val_if_fail (iface != NULL, FALSE); - g_return_val_if_fail (config != NULL, FALSE); + g_return_if_fail (NM_IS_DEVICE (device)); - if (!add_ip4_addresses (config, iface)) - return FALSE; - - sleep (1); + ad_config = nm_device_get_ip4_config (device); + g_return_if_fail (ad_config != NULL); - len = nm_ip4_config_get_num_routes (config); - for (i = 0; i < len; i++) { - const NMSettingIP4Route *route = nm_ip4_config_get_route (config, i); - - nm_system_device_set_ip4_route (iface, config, - route->address, - route->prefix, - route->next_hop, - route->metric, - nm_ip4_config_get_mss (config)); + /* Set up a route to the VPN gateway's public IP address through the default + * network device. + */ + for (i = 0; i < nm_ip4_config_get_num_addresses (ad_config); i++) { + tmp = nm_ip4_config_get_address (ad_config, i); + if (tmp->gateway) { + ad_gw = tmp->gateway; + break; + } } - if (nm_ip4_config_get_mtu (config)) - nm_system_device_set_mtu (iface, nm_ip4_config_get_mtu (config)); + if (!ad_gw) + return; - if (priority > 0) - nm_system_device_set_priority (iface, config, priority); + for (i = 0; i < nm_ip4_config_get_num_addresses (config); i++) { + tmp = nm_ip4_config_get_address (config, i); + if (tmp->gateway) { + vpn_gw = tmp->gateway; + break; + } + } - return TRUE; + nm_system_device_set_ip4_route (nm_device_get_ip_iface (device), + ad_config, vpn_gw, 32, ad_gw, 0, + nm_ip4_config_get_mss (ad_config)); } /* - * nm_system_vpn_device_set_from_ip4_config + * nm_system_apply_ip4_config * - * Set IPv4 configuration of a VPN device from an NMIP4Config object. + * Set IPv4 configuration of the device from an NMIP4Config object. * */ gboolean -nm_system_vpn_device_set_from_ip4_config (NMDevice *active_device, - const char *iface, - NMIP4Config *config) +nm_system_apply_ip4_config (NMDevice *device, + const char *iface, + NMIP4Config *config, + int priority, + gboolean is_vpn) { - NMIP4Config *ad_config = NULL; - NMNamedManager *named_mgr; - int num; int i; + g_return_val_if_fail (iface != NULL, FALSE); g_return_val_if_fail (config != NULL, FALSE); - /* Set up a route to the VPN gateway through the real network device */ - if (active_device && (ad_config = nm_device_get_ip4_config (active_device))) { - guint32 ad_gw = 0, vpn_gw = 0; - const NMSettingIP4Address *tmp; - - num = nm_ip4_config_get_num_addresses (ad_config); - for (i = 0; i < num; i++) { - tmp = nm_ip4_config_get_address (ad_config, i); - if (tmp->gateway) { - ad_gw = tmp->gateway; - break; - } - } - - if (ad_gw) { - num = nm_ip4_config_get_num_addresses (config); - for (i = 0; i < num; i++) { - tmp = nm_ip4_config_get_address (config, i); - if (tmp->gateway) { - vpn_gw = tmp->gateway; - break; - } - } - - nm_system_device_set_ip4_route (nm_device_get_ip_iface (active_device), - ad_config, vpn_gw, 32, ad_gw, 0, - nm_ip4_config_get_mss (config)); - } - } - - if (!iface || !strlen (iface)) - goto out; - - nm_system_device_set_up_down_with_iface (iface, TRUE, NULL); - if (!add_ip4_addresses (config, iface)) - goto out; + return FALSE; - /* Set the MTU */ - if (nm_ip4_config_get_mtu (config)) - nm_system_device_set_mtu (iface, nm_ip4_config_get_mtu (config)); + if (is_vpn) + add_vpn_gateway_route (device, iface, config); - /* Set routes */ - num = nm_ip4_config_get_num_routes (config); - for (i = 0; i < num; i++) { + sleep (1); + + for (i = 0; i < nm_ip4_config_get_num_routes (config); i++) { const NMSettingIP4Route *route = nm_ip4_config_get_route (config, i); - nm_system_device_set_ip4_route (iface, config, + nm_system_device_set_ip4_route (iface, config, route->address, route->prefix, route->next_hop, @@ -388,39 +349,15 @@ nm_system_vpn_device_set_from_ip4_config (NMDevice *active_device, nm_ip4_config_get_mss (config)); } - if (num == 0) - nm_system_device_replace_default_ip4_route (iface, 0, 0); - -out: - named_mgr = nm_named_manager_get (); - nm_named_manager_add_ip4_config (named_mgr, iface, config, NM_NAMED_IP_CONFIG_TYPE_VPN); - g_object_unref (named_mgr); - - return TRUE; -} - - -/* - * nm_system_vpn_device_unset_from_ip4_config - * - * Unset an IPv4 configuration of a VPN device from an NMIP4Config object. - * - */ -gboolean nm_system_vpn_device_unset_from_ip4_config (NMDevice *active_device, const char *iface, NMIP4Config *config) -{ - NMNamedManager *named_mgr; - - g_return_val_if_fail (active_device != NULL, FALSE); - g_return_val_if_fail (config != NULL, FALSE); + if (nm_ip4_config_get_mtu (config)) + nm_system_device_set_mtu (iface, nm_ip4_config_get_mtu (config)); - named_mgr = nm_named_manager_get (); - nm_named_manager_remove_ip4_config (named_mgr, iface, config); - g_object_unref (named_mgr); + if (priority > 0) + nm_system_device_set_priority (iface, config, priority); return TRUE; } - /* * nm_system_device_set_up_down * @@ -547,6 +484,55 @@ nm_system_device_set_mtu (const char *iface, guint32 mtu) return success; } +static struct rtnl_route * +add_ip4_route_to_gateway (const char *iface, guint32 gw, guint32 mss) +{ + struct nl_handle *nlh; + struct rtnl_route *route = NULL; + struct nl_addr *gw_addr = NULL; + int iface_idx, err; + + nlh = nm_netlink_get_default_handle (); + g_return_val_if_fail (nlh != NULL, NULL); + + iface_idx = nm_netlink_iface_to_index (iface); + if (iface_idx < 0) + return NULL; + + /* Gateway might be over a bridge; try adding a route to gateway first */ + route = rtnl_route_alloc (); + if (route == NULL) + return NULL; + + rtnl_route_set_oif (route, iface_idx); + rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE); + + gw_addr = nl_addr_build (AF_INET, &gw, sizeof (gw)); + if (!gw_addr) + goto error; + rtnl_route_set_dst (route, gw_addr); + nl_addr_put (gw_addr); + + if (mss) { + if (rtnl_route_set_metric (route, RTAX_ADVMSS, mss) < 0) + goto error; + } + + /* Add direct route to the gateway */ + err = rtnl_route_add (nlh, route, 0); + if (err) { + nm_warning ("Failed to add IPv4 default route on '%s': (%d) %s", + iface, err, nl_geterror ()); + goto error; + } + + return route; + +error: + rtnl_route_put (route); + return NULL; +} + /* * nm_system_replace_default_ip4_route * @@ -554,32 +540,35 @@ nm_system_device_set_mtu (const char *iface, guint32 mtu) * */ void -nm_system_device_replace_default_ip4_route (const char *iface, guint32 gw, guint32 mss) +nm_system_device_replace_default_ip4_route (const char *iface, + guint32 gw, + guint32 mss, + const char *parent_iface, + guint32 parent_mss) { - struct rtnl_route * route; - struct rtnl_route * route2 = NULL; - struct nl_handle * nlh; - struct nl_addr * gw_addr; + struct rtnl_route *route = NULL; + struct rtnl_route *gw_route = NULL; + struct nl_handle *nlh; + struct nl_addr *gw_addr = NULL; int iface_idx, err; + gboolean success = FALSE; nlh = nm_netlink_get_default_handle (); g_return_if_fail (nlh != NULL); + iface_idx = nm_netlink_iface_to_index (iface); + if (iface_idx < 0) + return; + route = rtnl_route_alloc(); g_return_if_fail (route != NULL); rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE); - - iface_idx = nm_netlink_iface_to_index (iface); - if (iface_idx < 0) - goto out; rtnl_route_set_oif (route, iface_idx); - /* Build up gateway address; a gateway of 0 (used in e.g. PPP links) means - * that all packets should be sent to the gateway since it's a point-to-point - * link and has no broadcast segment really. - */ - if (!(gw_addr = nl_addr_build (AF_INET, &gw, sizeof (gw)))) + /* Build up the gateway address */ + gw_addr = nl_addr_build (AF_INET, &gw, sizeof (gw)); + if (!gw_addr) goto out; rtnl_route_set_gateway (route, gw_addr); nl_addr_put (gw_addr); @@ -589,9 +578,11 @@ nm_system_device_replace_default_ip4_route (const char *iface, guint32 gw, guint goto out; } + /* Add the new default route */ err = rtnl_route_add (nlh, route, NLM_F_REPLACE); if (err == 0) { /* Everything good */ + success = TRUE; goto out; } else if (err != -ESRCH) { nm_warning ("rtnl_route_add() returned error %s (%d)\n%s", @@ -599,41 +590,26 @@ nm_system_device_replace_default_ip4_route (const char *iface, guint32 gw, guint goto out; } - /* Gateway might be over a bridge; try adding a route to gateway first */ - route2 = rtnl_route_alloc (); - if (route2 == NULL) - goto out; - rtnl_route_set_oif (route2, iface_idx); - rtnl_route_set_dst (route2, gw_addr); - - if (mss) { - if (rtnl_route_set_metric (route2, RTAX_ADVMSS, mss) < 0) - goto out; - } - - /* Add route to gateway over bridge */ - err = rtnl_route_add (nlh, route2, 0); - if (err) { - nm_warning ("Failed to add IPv4 default route on '%s': %s", - iface, - nl_geterror ()); + /* Try adding a direct route to the gateway first */ + gw_route = add_ip4_route_to_gateway (parent_iface ? parent_iface : iface, + gw, + parent_iface ? parent_mss : mss); + if (!gw_route) goto out; - } - /* Try adding the route again */ - err = rtnl_route_add (nlh, route, 0); - if (err) { - rtnl_route_del (nlh, route2, 0); - nm_warning ("Failed to set IPv4 default route on '%s': %s", - iface, - nl_geterror ()); + /* Try adding the original route again */ + err = rtnl_route_add (nlh, route, NLM_F_REPLACE); + if (err != 0) { + rtnl_route_del (nlh, gw_route, 0); + nm_warning ("Failed to set IPv4 default route on '%s': %s", iface, nl_geterror ()); } out: - if (route2) - rtnl_route_put (route2); + if (gw_route) + rtnl_route_put (gw_route); - rtnl_route_put (route); + if (route) + rtnl_route_put (route); } /* diff --git a/src/NetworkManagerSystem.h b/src/NetworkManagerSystem.h index 2a1503ee79..bd8df4af26 100644 --- a/src/NetworkManagerSystem.h +++ b/src/NetworkManagerSystem.h @@ -1,5 +1,4 @@ -/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ - +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * Dan Williams <dcbw@redhat.com> @@ -37,7 +36,9 @@ void nm_system_device_flush_ip4_routes_with_iface (const char *iface); void nm_system_device_replace_default_ip4_route (const char *iface, guint32 gw, - guint32 mss); + guint32 mss, + const char *parent_iface, + guint32 parent_mss); void nm_system_device_flush_ip4_addresses (NMDevice *dev); void nm_system_device_flush_ip4_addresses_with_iface (const char *iface); @@ -45,17 +46,11 @@ void nm_system_device_flush_ip4_addresses_with_iface (const char *iface); void nm_system_enable_loopback (void); void nm_system_update_dns (void); -gboolean nm_system_device_set_from_ip4_config (const char *iface, - NMIP4Config *config, - int priority); - -gboolean nm_system_vpn_device_set_from_ip4_config (NMDevice *active_device, - const char *iface, - NMIP4Config *config); - -gboolean nm_system_vpn_device_unset_from_ip4_config (NMDevice *active_device, - const char *iface, - NMIP4Config *config); +gboolean nm_system_apply_ip4_config (NMDevice *device, + const char *iface, + NMIP4Config *config, + int priority, + gboolean is_vpn); gboolean nm_system_device_set_up_down (NMDevice *dev, gboolean up, diff --git a/src/nm-device.c b/src/nm-device.c index a7a0fc6da3..1d5772e456 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -1919,7 +1919,7 @@ nm_device_set_ip4_config (NMDevice *self, NMIP4Config *config, NMDeviceStateReas if (!nm_ip4_config_get_dbus_path (config)) nm_ip4_config_export (config); - success = nm_system_device_set_from_ip4_config (ip_iface, config, nm_device_get_priority (self)); + success = nm_system_apply_ip4_config (self, ip_iface, config, nm_device_get_priority (self), FALSE); if (success) nm_device_update_ip4_address (self); diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index 6307aaa1c5..90c3691c37 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -46,6 +46,7 @@ #include "nm-properties-changed-signal.h" #include "nm-dbus-glib-types.h" #include "NetworkManagerUtils.h" +#include "nm-named-manager.h" #include "nm-vpn-connection-glue.h" @@ -354,8 +355,8 @@ print_vpn_config (NMIP4Config *config, static void nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, - GHashTable *config_hash, - gpointer user_data) + GHashTable *config_hash, + gpointer user_data) { NMVPNConnection *connection = NM_VPN_CONNECTION (user_data); NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); @@ -376,6 +377,14 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, addr = g_malloc0 (sizeof (NMSettingIP4Address)); addr->prefix = 24; /* default to class C */ + val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV); + if (val) + priv->tundev = g_strdup (g_value_get_string (val)); + else { + nm_warning ("%s: invalid or missing tunnel device received!", __func__); + goto error; + } + val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_GATEWAY); if (val) addr->gateway = g_value_get_uint (val); @@ -395,8 +404,9 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, if (addr->address && addr->prefix) { nm_ip4_config_take_address (config, addr); } else { - g_warning ("%s: invalid IP4 config received!", __func__); + nm_warning ("%s: invalid IP4 config received!", __func__); g_free (addr); + goto error; } val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_DNS); @@ -423,10 +433,6 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, if (val) nm_ip4_config_set_mtu (config, g_value_get_uint (val)); - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV); - if (val) - priv->tundev = g_strdup (g_value_get_string (val)); - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_DOMAIN); if (val) nm_ip4_config_add_domain (config, g_value_get_string (val)); @@ -452,26 +458,37 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, print_vpn_config (config, priv->tundev, priv->banner); - priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); - priv->ip4_config = config; - /* Merge in user overrides from the NMConnection's IPv4 setting */ s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (priv->connection, NM_TYPE_SETTING_IP4_CONFIG)); nm_utils_merge_ip4_config (config, s_ip4); - if (nm_system_vpn_device_set_from_ip4_config (priv->parent_dev, priv->tundev, priv->ip4_config)) { + nm_system_device_set_up_down_with_iface (priv->tundev, TRUE, NULL); + + if (nm_system_apply_ip4_config (priv->parent_dev, priv->tundev, config, 0, TRUE)) { + NMNamedManager *named_mgr; + + /* Add the VPN to DNS */ + named_mgr = nm_named_manager_get (); + nm_named_manager_add_ip4_config (named_mgr, priv->tundev, config, NM_NAMED_IP_CONFIG_TYPE_VPN); + g_object_unref (named_mgr); + + priv->ip4_config = config; + nm_info ("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); - } else { - nm_warning ("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); + return; } + +error: + nm_warning ("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); } static gboolean @@ -631,6 +648,30 @@ nm_vpn_connection_get_banner (NMVPNConnection *connection) return NM_VPN_CONNECTION_GET_PRIVATE (connection)->banner; } +NMIP4Config * +nm_vpn_connection_get_ip4_config (NMVPNConnection *connection) +{ + g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL); + + return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip4_config; +} + +const char * +nm_vpn_connection_get_ip_iface (NMVPNConnection *connection) +{ + g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL); + + return NM_VPN_CONNECTION_GET_PRIVATE (connection)->tundev; +} + +NMDevice * +nm_vpn_connection_get_parent_device (NMVPNConnection *connection) +{ + g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL); + + return NM_VPN_CONNECTION_GET_PRIVATE (connection)->parent_dev; +} + void nm_vpn_connection_fail (NMVPNConnection *connection, NMVPNConnectionStateReason reason) @@ -870,9 +911,12 @@ connection_state_changed (NMVPNConnection *connection, if (priv->ip4_config) { NMIP4Config *dev_ip4_config; + NMNamedManager *named_mgr; /* Remove attributes of the VPN's IP4 Config */ - nm_system_vpn_device_unset_from_ip4_config (priv->parent_dev, priv->tundev, priv->ip4_config); + named_mgr = nm_named_manager_get (); + nm_named_manager_remove_ip4_config (named_mgr, priv->tundev, priv->ip4_config); + g_object_unref (named_mgr); /* Reset routes, nameservers, and domains of the currently active device */ dev_ip4_config = nm_device_get_ip4_config (priv->parent_dev); diff --git a/src/vpn-manager/nm-vpn-connection.h b/src/vpn-manager/nm-vpn-connection.h index b642023733..7007b0bbc5 100644 --- a/src/vpn-manager/nm-vpn-connection.h +++ b/src/vpn-manager/nm-vpn-connection.h @@ -70,5 +70,8 @@ void nm_vpn_connection_fail (NMVPNConnection *connect NMVPNConnectionStateReason reason); void nm_vpn_connection_disconnect (NMVPNConnection *connection, NMVPNConnectionStateReason reason); +NMIP4Config * nm_vpn_connection_get_ip4_config (NMVPNConnection *connection); +const char * nm_vpn_connection_get_ip_iface (NMVPNConnection *connection); +NMDevice * nm_vpn_connection_get_parent_device (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 26c84e402a..e8e47c3a6d 100644 --- a/src/vpn-manager/nm-vpn-manager.c +++ b/src/vpn-manager/nm-vpn-manager.c @@ -20,6 +20,7 @@ typedef struct { } NMVPNManagerPrivate; enum { + CONNECTION_ACTIVATED, CONNECTION_DEACTIVATED, LAST_SIGNAL @@ -128,6 +129,9 @@ connection_vpn_state_changed (NMVPNConnection *connection, NMVPNManager *manager = NM_VPN_MANAGER (user_data); switch (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); @@ -259,6 +263,27 @@ nm_vpn_manager_add_active_connections (NMVPNManager *manager, } } +GSList * +nm_vpn_manager_get_active_connections (NMVPNManager *manager) +{ + NMVPNManagerPrivate *priv; + GSList *iter; + GSList *list = NULL; + + g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), NULL); + + priv = NM_VPN_MANAGER_GET_PRIVATE (manager); + for (iter = priv->services; iter; iter = g_slist_next (iter)) { + GSList *active, *elt; + + active = nm_vpn_service_get_active_connections (NM_VPN_SERVICE (iter->data)); + for (elt = active; elt; elt = g_slist_next (elt)) + list = g_slist_append (list, g_object_ref (NM_VPN_CONNECTION (elt->data))); + } + + return list; +} + NMVPNManager * nm_vpn_manager_get (void) { @@ -301,6 +326,14 @@ nm_vpn_manager_class_init (NMVPNManagerClass *manager_class) object_class->finalize = finalize; /* signals */ + signals[CONNECTION_ACTIVATED] = + g_signal_new ("connection-activated", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + signals[CONNECTION_DEACTIVATED] = g_signal_new ("connection-deactivated", G_OBJECT_CLASS_TYPE (object_class), diff --git a/src/vpn-manager/nm-vpn-manager.h b/src/vpn-manager/nm-vpn-manager.h index c4bb605e71..9d3bf4850a 100644 --- a/src/vpn-manager/nm-vpn-manager.h +++ b/src/vpn-manager/nm-vpn-manager.h @@ -61,4 +61,6 @@ void nm_vpn_manager_add_active_connections (NMVPNManager *manager, NMConnection *filter, GPtrArray *list); +GSList *nm_vpn_manager_get_active_connections (NMVPNManager *manager); + #endif /* NM_VPN_VPN_MANAGER_H */ |