diff options
44 files changed, 1922 insertions, 75 deletions
@@ -245,65 +245,6 @@ because the user has no physical access to the router itself, but has been given as passphrase/PSK instead. -* Proxies - -HTTP and other proxies are per-connection configuration. It's highly unlikely -that the same proxy you need to use at work is used at home or in a coffee shop. -Thus, it makes sense that which proxy settings to use should be updated when -network connections change. NetworkManager is a perfect place to do this since -it tracks which network connections are active, and it already queries the -network for automatic proxy configuration via DHCP and WPAD. - -However, proxy handling is complicated and may require use of Javascript to -parse PAC files provided by WPAD, and this is not something NetworkManager -should do itself. Instead, that should be left to "proxy handlers", or external -utilities like libproxy or pacrunner that take raw proxy information, parse it, -and tell applications what proxy server to use for a specific network resource. -NetworkManager should provide all the proxy information it can find to these -external proxy handlers via the D-Bus interface and dispatcher scripts. - -We should add a new NMSetting subclass called NMSettingProxy that holds -necessary proxy configuration. The properties of this setting should be a -superset of what is provided in the Firefox proxy configuration screen and the -various desktop environment proxy configuration tools like the GNOME Network -Proxy control panel; this should include at a minimum: - - method: "auto", "manual", "none" - default-proxy: string - default-proxy-port: uint - default-always: boolean (use default proxy for all protocols) - ssl-proxy: string - ssl-proxy-port: uint - ftp-proxy: string - ftp-proxy-port: uint - socks-proxy: string - socks-proxy-port: uint - socks-version: uint, either 4 or 5 - no-proxy-for: array of strings (things not to use the proxy for, ie ".foobar.com", - "192.168.0.1/24", an IPv6 address, etc) - pac-url: string (URL of PAC file, overrides DHCP-provided WPAD value) - (FIXME: proxy authentication? do we need separate user/pass properties for - each protocol type? should NM handle proxy auth or should it be punted - to each application?) - -After completing IP configuration but still during the NM_DEVICE_STATE_IP_CONFIG -activation stage, NetworkManager would merge the automatically supplied proxy -configuration (from DHCP's WPAD option) with user-provided overrides from the -NMSettingProxy export the resulting proxy configuration via D-Bus and dispatcher -scripts. The 'default' connection's proxy configuration would be preferred, so -we'd have to update proxy configuration from nm-policy.c the same time we update -DNS information and the default route. - -Merged proxy information should be exposed in two places. First, it should be -exported over D-Bus as a property of the org.freedesktop.NetworkManager.Device -interface. This property should be named "ProxyInfo" and should have the -D-Bus signature "a{sv}" (eg, dictionary) and should mirror the properties from -the NMSettingProxy object. - -Second, it should be exported via the dispatcher to dispatcher scripts when -with the "up" and "down" events. - - * Better Tablet/Mobile Behavior There are a few components to this: diff --git a/callouts/nm-dispatcher-utils.c b/callouts/nm-dispatcher-utils.c index 78ef8dd271..64a4b9ef6c 100644 --- a/callouts/nm-dispatcher-utils.c +++ b/callouts/nm-dispatcher-utils.c @@ -101,6 +101,46 @@ add_domains (GSList *items, } static GSList * +construct_proxy_items (GSList *items, GVariant *proxy_config, const char *prefix) +{ + GVariant *val; + + if (proxy_config == NULL) + return items; + + if (prefix == NULL) + prefix = ""; + + /* PAC Url */ + val = g_variant_lookup_value (proxy_config, "pac-url", G_VARIANT_TYPE_STRING); + if (val) { + char *str; + + str = g_strdup_printf ("%sPROXY_PAC_URL=%s", + prefix, + g_variant_get_string (val, NULL)); + + items = g_slist_prepend (items, str); + g_variant_unref (val); + } + + /* PAC Script */ + val = g_variant_lookup_value (proxy_config, "pac-script", G_VARIANT_TYPE_STRING); + if (val) { + char *str; + + str = g_strdup_printf ("%sPROXY_PAC_SCRIPT=%s", + prefix, + g_variant_get_string (val, NULL)); + + items = g_slist_prepend (items, str); + g_variant_unref (val); + } + + return items; +} + +static GSList * construct_ip4_items (GSList *items, GVariant *ip4_config, const char *prefix) { GPtrArray *addresses, *routes; @@ -323,12 +363,14 @@ nm_dispatcher_utils_construct_envp (const char *action, GVariant *connection_dict, GVariant *connection_props, GVariant *device_props, + GVariant *device_proxy_props, GVariant *device_ip4_props, GVariant *device_ip6_props, GVariant *device_dhcp4_props, GVariant *device_dhcp6_props, const char *connectivity_state, const char *vpn_ip_iface, + GVariant *vpn_proxy_props, GVariant *vpn_ip4_props, GVariant *vpn_ip6_props, char **out_iface, @@ -443,6 +485,7 @@ nm_dispatcher_utils_construct_envp (const char *action, /* Device it's aren't valid if the device isn't activated */ if (iface && (dev_state == NM_DEVICE_STATE_ACTIVATED)) { + items = construct_proxy_items (items, device_proxy_props, NULL); items = construct_ip4_items (items, device_ip4_props, NULL); items = construct_ip6_items (items, device_ip6_props, NULL); items = construct_device_dhcp4_items (items, device_dhcp4_props); @@ -451,6 +494,7 @@ nm_dispatcher_utils_construct_envp (const char *action, if (vpn_ip_iface) { items = g_slist_prepend (items, g_strdup_printf ("VPN_IP_IFACE=%s", vpn_ip_iface)); + items = construct_proxy_items (items, vpn_proxy_props, "VPN_"); items = construct_ip4_items (items, vpn_ip4_props, "VPN_"); items = construct_ip6_items (items, vpn_ip6_props, "VPN_"); } diff --git a/callouts/nm-dispatcher-utils.h b/callouts/nm-dispatcher-utils.h index 6a10d4c311..a603432668 100644 --- a/callouts/nm-dispatcher-utils.h +++ b/callouts/nm-dispatcher-utils.h @@ -26,12 +26,14 @@ nm_dispatcher_utils_construct_envp (const char *action, GVariant *connection_dict, GVariant *connection_props, GVariant *device_props, + GVariant *device_proxy_props, GVariant *device_ip4_props, GVariant *device_ip6_props, GVariant *device_dhcp4_props, GVariant *device_dhcp6_props, const char *connectivity_state, const char *vpn_ip_iface, + GVariant *vpn_proxy_props, GVariant *vpn_ip4_props, GVariant *vpn_ip6_props, char **out_iface, diff --git a/callouts/nm-dispatcher.c b/callouts/nm-dispatcher.c index 94bd132418..6bb5221858 100644 --- a/callouts/nm-dispatcher.c +++ b/callouts/nm-dispatcher.c @@ -76,12 +76,14 @@ handle_action (NMDBusDispatcher *dbus_dispatcher, GVariant *connection_dict, GVariant *connection_props, GVariant *device_props, + GVariant *device_proxy_props, GVariant *device_ip4_props, GVariant *device_ip6_props, GVariant *device_dhcp4_props, GVariant *device_dhcp6_props, const char *connectivity_state, const char *vpn_ip_iface, + GVariant *vpn_proxy_props, GVariant *vpn_ip4_props, GVariant *vpn_ip6_props, gboolean request_debug, @@ -665,12 +667,14 @@ handle_action (NMDBusDispatcher *dbus_dispatcher, GVariant *connection_dict, GVariant *connection_props, GVariant *device_props, + GVariant *device_proxy_props, GVariant *device_ip4_props, GVariant *device_ip6_props, GVariant *device_dhcp4_props, GVariant *device_dhcp6_props, const char *connectivity_state, const char *vpn_ip_iface, + GVariant *vpn_proxy_props, GVariant *vpn_ip4_props, GVariant *vpn_ip6_props, gboolean request_debug, @@ -697,12 +701,14 @@ handle_action (NMDBusDispatcher *dbus_dispatcher, connection_dict, connection_props, device_props, + device_proxy_props, device_ip4_props, device_ip6_props, device_dhcp4_props, device_dhcp6_props, connectivity_state, vpn_ip_iface, + vpn_proxy_props, vpn_ip4_props, vpn_ip6_props, &request->iface, diff --git a/callouts/tests/dispatcher-external b/callouts/tests/dispatcher-external index 5430bec28b..a8c129c9e8 100644 --- a/callouts/tests/dispatcher-external +++ b/callouts/tests/dispatcher-external @@ -12,6 +12,10 @@ type=13 interface=virbr0 path=/org/freedesktop/NetworkManager/Devices/0 +[proxy] +pac-url=http://networkmanager.com/proxy.pac +pac-script="function FindProxyForURL (url, host) {}" + [ip4] addresses=192.168.122.1/24 0.0.0.0 domains= @@ -26,6 +30,8 @@ CONNECTION_ID=virbr0 CONNECTION_EXTERNAL=1 DEVICE_IFACE=virbr0 DEVICE_IP_IFACE=virbr0 +PROXY_PAC_URL=http://networkmanager.com/proxy.pac +PROXY_PAC_SCRIPT="function FindProxyForURL (url, host) {}" IP4_NUM_ADDRESSES=1 IP4_ADDRESS_0=192.168.122.1/24 0.0.0.0 IP4_GATEWAY=0.0.0.0 diff --git a/callouts/tests/dispatcher-up b/callouts/tests/dispatcher-up index 463409e27c..44eb9f7c22 100644 --- a/callouts/tests/dispatcher-up +++ b/callouts/tests/dispatcher-up @@ -25,6 +25,10 @@ broadcast_address=192.168.1.255 subnet_mask=255.255.255.0 expiry=1304300446 +[proxy] +pac-url=http://networkmanager.com/proxy.pac +pac-script="function FindProxyForURL (url, host) {}" + [ip4] addresses=192.168.1.119/24 192.168.1.1 nameservers=68.87.77.134 68.87.72.134 192.168.1.1 @@ -38,6 +42,8 @@ CONNECTION_ID=Random Connection CONNECTION_FILENAME=/callouts/tests/dispatcher-up DEVICE_IFACE=wlan0 DEVICE_IP_IFACE=wlan0 +PROXY_PAC_URL=http://networkmanager.com/proxy.pac +PROXY_PAC_SCRIPT="function FindProxyForURL (url, host) {}" IP4_ADDRESS_0=192.168.1.119/24 192.168.1.1 IP4_NUM_ADDRESSES=1 IP4_NAMESERVERS=68.87.77.134 68.87.72.134 192.168.1.1 diff --git a/callouts/tests/dispatcher-vpn-down b/callouts/tests/dispatcher-vpn-down index 18267f841d..1de7e233a5 100644 --- a/callouts/tests/dispatcher-vpn-down +++ b/callouts/tests/dispatcher-vpn-down @@ -25,6 +25,10 @@ broadcast_address=192.168.1.255 subnet_mask=255.255.255.0 expiry=1304349405 +[proxy] +pac-url=http://networkmanager.com/proxy.pac +pac-script="function FindProxyForURL (url, host) {}" + [ip4] addresses=192.168.1.119/24 192.168.1.1 nameservers=68.87.77.134 68.87.72.134 192.168.1.1 @@ -38,6 +42,8 @@ CONNECTION_ID=Random Connection CONNECTION_FILENAME=/callouts/tests/dispatcher-vpn-down DEVICE_IFACE=wlan0 DEVICE_IP_IFACE=tun0 +PROXY_PAC_URL=http://networkmanager.com/proxy.pac +PROXY_PAC_SCRIPT="function FindProxyForURL (url, host) {}" IP4_ADDRESS_0=192.168.1.119/24 192.168.1.1 IP4_NUM_ADDRESSES=1 IP4_NAMESERVERS=68.87.77.134 68.87.72.134 192.168.1.1 diff --git a/callouts/tests/dispatcher-vpn-up b/callouts/tests/dispatcher-vpn-up index 181ecb53a6..d16e58234d 100644 --- a/callouts/tests/dispatcher-vpn-up +++ b/callouts/tests/dispatcher-vpn-up @@ -25,6 +25,10 @@ broadcast_address=192.168.1.255 subnet_mask=255.255.255.0 expiry=1304349405 +[proxy] +pac-url=http://networkmanager.com/proxy.pac +pac-script="function FindProxyForURL (url, host) {}" + [ip4] addresses=192.168.1.119/24 192.168.1.1 nameservers=68.87.77.134 68.87.72.134 192.168.1.1 @@ -38,6 +42,8 @@ CONNECTION_ID=Random Connection CONNECTION_FILENAME=/callouts/tests/dispatcher-vpn-up DEVICE_IFACE=wlan0 DEVICE_IP_IFACE=tun0 +PROXY_PAC_URL=http://networkmanager.com/proxy.pac +PROXY_PAC_SCRIPT="function FindProxyForURL (url, host) {}" IP4_ADDRESS_0=192.168.1.119/24 192.168.1.1 IP4_NUM_ADDRESSES=1 IP4_NAMESERVERS=68.87.77.134 68.87.72.134 192.168.1.1 diff --git a/callouts/tests/test-dispatcher-envp.c b/callouts/tests/test-dispatcher-envp.c index 354ab2c5b2..383beaab75 100644 --- a/callouts/tests/test-dispatcher-envp.c +++ b/callouts/tests/test-dispatcher-envp.c @@ -194,6 +194,33 @@ add_uint_array (GKeyFile *kf, } static gboolean +parse_proxy (GKeyFile *kf, GVariant **out_props, const char *section, GError **error) +{ + GVariantBuilder props; + char *tmp; + + g_variant_builder_init (&props, G_VARIANT_TYPE ("a{sv}")); + + tmp = g_key_file_get_string (kf, section, "pac-url", error); + if (tmp == NULL) + return FALSE; + g_variant_builder_add (&props, "{sv}", + "pac-url", + g_variant_new_string (tmp)); + g_free (tmp); + + tmp = g_key_file_get_string (kf, section, "pac-script", error); + if (tmp == NULL) + return FALSE; + g_variant_builder_add (&props, "{sv}", + "pac-script", + g_variant_new_string (tmp)); + g_free (tmp); + *out_props = g_variant_builder_end (&props); + return TRUE; +} + +static gboolean parse_ip4 (GKeyFile *kf, GVariant **out_props, const char *section, GError **error) { GVariantBuilder props; @@ -357,12 +384,14 @@ get_dispatcher_file (const char *file, GVariant **out_con_dict, GVariant **out_con_props, GVariant **out_device_props, + GVariant **out_device_proxy_props, GVariant **out_device_ip4_props, GVariant **out_device_ip6_props, GVariant **out_device_dhcp4_props, GVariant **out_device_dhcp6_props, char **out_connectivity_state, char **out_vpn_ip_iface, + GVariant **out_vpn_proxy_props, GVariant **out_vpn_ip4_props, GVariant **out_vpn_ip6_props, char **out_expected_iface, @@ -378,12 +407,14 @@ get_dispatcher_file (const char *file, g_assert (out_con_dict && !*out_con_dict); g_assert (out_con_props && !*out_con_props); g_assert (out_device_props && !*out_device_props); + g_assert (out_device_proxy_props && !*out_device_proxy_props); g_assert (out_device_ip4_props && !*out_device_ip4_props); g_assert (out_device_ip6_props && !*out_device_ip6_props); g_assert (out_device_dhcp4_props && !*out_device_dhcp4_props); g_assert (out_device_dhcp6_props && !*out_device_dhcp6_props); g_assert (out_connectivity_state && !*out_connectivity_state); g_assert (out_vpn_ip_iface && !*out_vpn_ip_iface); + g_assert (out_vpn_proxy_props && !*out_vpn_proxy_props); g_assert (out_vpn_ip4_props && !*out_vpn_ip4_props); g_assert (out_vpn_ip6_props && !*out_vpn_ip6_props); g_assert (out_expected_iface && !*out_expected_iface); @@ -408,6 +439,11 @@ get_dispatcher_file (const char *file, if (!parse_device (kf, out_device_props, error)) goto out; + if (g_key_file_has_group (kf, "proxy")) { + if (!parse_proxy (kf, out_device_proxy_props, "proxy", error)) + goto out; + } + if (g_key_file_has_group (kf, "ip4")) { if (!parse_ip4 (kf, out_device_ip4_props, "ip4", error)) goto out; @@ -452,12 +488,14 @@ test_generic (const char *file, const char *override_vpn_ip_iface) gs_unref_variant GVariant *con_dict = NULL; gs_unref_variant GVariant *con_props = NULL; gs_unref_variant GVariant *device_props = NULL; + gs_unref_variant GVariant *device_proxy_props = NULL; gs_unref_variant GVariant *device_ip4_props = NULL; gs_unref_variant GVariant *device_ip6_props = NULL; gs_unref_variant GVariant *device_dhcp4_props = NULL; gs_unref_variant GVariant *device_dhcp6_props = NULL; gs_free char *connectivity_change = NULL; gs_free char *vpn_ip_iface = NULL; + gs_unref_variant GVariant *vpn_proxy_props = NULL; gs_unref_variant GVariant *vpn_ip4_props = NULL; gs_unref_variant GVariant *vpn_ip6_props = NULL; gs_free char *expected_iface = NULL; @@ -477,12 +515,14 @@ test_generic (const char *file, const char *override_vpn_ip_iface) &con_dict, &con_props, &device_props, + &device_proxy_props, &device_ip4_props, &device_ip6_props, &device_dhcp4_props, &device_dhcp6_props, &connectivity_change, &vpn_ip_iface, + &vpn_proxy_props, &vpn_ip4_props, &vpn_ip6_props, &expected_iface, @@ -498,12 +538,14 @@ test_generic (const char *file, const char *override_vpn_ip_iface) con_dict, con_props, device_props, + device_proxy_props, device_ip4_props, device_ip6_props, device_dhcp4_props, device_dhcp6_props, connectivity_change, override_vpn_ip_iface ? override_vpn_ip_iface : vpn_ip_iface, + vpn_proxy_props, vpn_ip4_props, vpn_ip6_props, &out_iface, diff --git a/clients/cli/common.c b/clients/cli/common.c index efe41cc6e4..8e25dbffd3 100644 --- a/clients/cli/common.c +++ b/clients/cli/common.c @@ -900,6 +900,82 @@ nmc_team_check_config (const char *config, char **out_config, GError **error) } /* + * nmc_proxy_check_script: + * @script: file name with PAC script, or raw PAC Script data + * @out_script: raw PAC Script (with removed new-line characters) + * @error: location to store error, or %NULL + * + * Check PAC Script from @script parameter and return the checked/sanitized + * config in @out_script. + * + * Returns: %TRUE if the script is valid, %FALSE if it is invalid + */ +gboolean +nmc_proxy_check_script (const char *script, char **out_script, GError **error) +{ + enum { + _PAC_SCRIPT_TYPE_GUESS, + _PAC_SCRIPT_TYPE_FILE, + _PAC_SCRIPT_TYPE_JSON, + } desired_type = _PAC_SCRIPT_TYPE_GUESS; + const char *filename = NULL; + size_t c_len = 0; + gs_free char *script_clone = NULL; + + *out_script = NULL; + + if (!script || !script[0]) + return TRUE; + + if (g_str_has_prefix (script, "file://")) { + script += NM_STRLEN ("file://"); + desired_type = _PAC_SCRIPT_TYPE_FILE; + } else if (g_str_has_prefix (script, "js://")) { + script += NM_STRLEN ("js://"); + desired_type = _PAC_SCRIPT_TYPE_JSON; + } + + if (NM_IN_SET (desired_type, _PAC_SCRIPT_TYPE_FILE, _PAC_SCRIPT_TYPE_GUESS)) { + gs_free char *contents = NULL; + + if (!g_file_get_contents (script, &contents, &c_len, NULL)) { + if (desired_type == _PAC_SCRIPT_TYPE_FILE) { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("cannot read pac-script from file '%s'"), + script); + return FALSE; + } + } else { + if (c_len != strlen (contents)) { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("file '%s' contains non-valid utf-8"), + script); + return FALSE; + } + filename = script; + script = script_clone = g_steal_pointer (&contents); + } + } + + if ( !strstr (script, "FindProxyForURL") + || !g_utf8_validate (script, -1, NULL)) { + if (filename) { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("'%s' does not contain a valid PAC Script"), filename); + } else { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Not a valid PAC Script")); + } + return FALSE; + } + + *out_script = (script == script_clone) + ? g_steal_pointer (&script_clone) + : g_strdup (script); + return TRUE; +} + +/* * nmc_find_connection: * @connections: array of NMConnections to search in * @filter_type: "id", "uuid", "path" or %NULL diff --git a/clients/cli/common.h b/clients/cli/common.h index 114a8e634d..1887e910b1 100644 --- a/clients/cli/common.h +++ b/clients/cli/common.h @@ -44,6 +44,7 @@ nmc_vlan_parse_priority_maps (const char *priority_map, const char *nmc_bond_validate_mode (const char *mode, GError **error); gboolean nmc_team_check_config (const char *config, char **out_config, GError **error); +gboolean nmc_proxy_check_script (const char *script, char **out_script, GError **error); NMConnection *nmc_find_connection (const GPtrArray *connections, const char *filter_type, diff --git a/clients/cli/connections.c b/clients/cli/connections.c index 0a64e2fb7f..61350da395 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -170,6 +170,7 @@ NmcOutputField nmc_fields_settings_names[] = { SETTING_FIELD (NM_SETTING_IP_TUNNEL_SETTING_NAME, nmc_fields_setting_ip_tunnel + 1), /* 26 */ SETTING_FIELD (NM_SETTING_MACVLAN_SETTING_NAME, nmc_fields_setting_macvlan + 1), /* 27 */ SETTING_FIELD (NM_SETTING_VXLAN_SETTING_NAME, nmc_fields_setting_vxlan + 1), /* 28 */ + SETTING_FIELD (NM_SETTING_PROXY_SETTING_NAME, nmc_fields_setting_proxy + 1), /* 29 */ {NULL, NULL, 0, NULL, NULL, FALSE, FALSE, 0} }; #define NMC_FIELDS_SETTINGS_NAMES_ALL_X NM_SETTING_CONNECTION_SETTING_NAME","\ @@ -199,7 +200,8 @@ NmcOutputField nmc_fields_settings_names[] = { NM_SETTING_TUN_SETTING_NAME"," \ NM_SETTING_IP_TUNNEL_SETTING_NAME"," \ NM_SETTING_MACVLAN_SETTING_NAME"," \ - NM_SETTING_VXLAN_SETTING_NAME + NM_SETTING_VXLAN_SETTING_NAME"," \ + NM_SETTING_PROXY_SETTING_NAME #define NMC_FIELDS_SETTINGS_NAMES_ALL NMC_FIELDS_SETTINGS_NAMES_ALL_X /* Active connection data */ @@ -2995,6 +2997,7 @@ static const NameItem nmc_bridge_slave_settings [] = { static const NameItem nmc_no_slave_settings [] = { { NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL, FALSE }, { NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL, FALSE }, + { NM_SETTING_PROXY_SETTING_NAME, NULL, NULL, FALSE }, { NULL, NULL, NULL, FALSE } }; @@ -4301,6 +4304,10 @@ static OptionInfo option_info[] = { { NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_ADDRESSES, "ip6", OPTION_MULTI, N_("IPv6 address (IP[/plen]) [none]"), NULL, set_ip6_address, NULL }, { NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_GATEWAY, "gw6", OPTION_NONE, N_("IPv6 gateway [none]"), NULL, NULL, NULL }, + { NM_SETTING_PROXY_SETTING_NAME, NM_SETTING_PROXY_METHOD, "method", OPTION_NONE, N_("Proxy method"), NULL, NULL, NULL }, + { NM_SETTING_PROXY_SETTING_NAME, NM_SETTING_PROXY_BROWSER_ONLY, "browser-only", OPTION_NONE, N_("Browser Only"), NULL, NULL, NULL }, + { NM_SETTING_PROXY_SETTING_NAME, NM_SETTING_PROXY_PAC_URL, "pac-url", OPTION_NONE, N_("PAC Url"), NULL, NULL, NULL }, + { NM_SETTING_PROXY_SETTING_NAME, NM_SETTING_PROXY_PAC_SCRIPT, "pac-script", OPTION_NONE, N_("PAC Script"), NULL, NULL, NULL }, { NULL, NULL, NULL, OPTION_NONE, NULL, NULL, NULL, NULL }, }; @@ -4803,6 +4810,8 @@ setting_name_to_name (const char *name) return _("IPv4 protocol"); if (strcmp (name, NM_SETTING_IP6_CONFIG_SETTING_NAME) == 0) return _("IPv6 protocol"); + if (strcmp (name, NM_SETTING_PROXY_SETTING_NAME) == 0) + return _("Proxy"); /* Should not happen; but let's still try to be somewhat sensible. */ return name; @@ -7087,6 +7096,8 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t nmc_setting_ip4_connect_handlers (NM_SETTING_IP_CONFIG (setting)); else if (NM_IS_SETTING_IP6_CONFIG (setting)) nmc_setting_ip6_connect_handlers (NM_SETTING_IP_CONFIG (setting)); + else if (NM_IS_SETTING_PROXY (setting)) + nmc_setting_proxy_connect_handlers (NM_SETTING_PROXY (setting)); nm_connection_add_setting (connection, setting); } @@ -7733,6 +7744,11 @@ editor_init_new_connection (NmCli *nmc, NMConnection *connection) setting = nm_setting_ip6_config_new (); nmc_setting_custom_init (setting); nm_connection_add_setting (connection, setting); + + /* Also Proxy Setting */ + setting = nm_setting_proxy_new (); + nmc_setting_custom_init (setting); + nm_connection_add_setting (connection, setting); } } @@ -7740,11 +7756,13 @@ static void editor_init_existing_connection (NMConnection *connection) { NMSettingIPConfig *s_ip4, *s_ip6; + NMSettingProxy *s_proxy; NMSettingWireless *s_wireless; NMSettingConnection *s_con; s_ip4 = nm_connection_get_setting_ip4_config (connection); s_ip6 = nm_connection_get_setting_ip6_config (connection); + s_proxy = nm_connection_get_setting_proxy (connection); s_wireless = nm_connection_get_setting_wireless (connection); s_con = nm_connection_get_setting_connection (connection); @@ -7752,6 +7770,8 @@ editor_init_existing_connection (NMConnection *connection) nmc_setting_ip4_connect_handlers (s_ip4); if (s_ip6) nmc_setting_ip6_connect_handlers (s_ip6); + if (s_proxy) + nmc_setting_proxy_connect_handlers (s_proxy); if (s_wireless) nmc_setting_wireless_connect_handlers (s_wireless); if (s_con) diff --git a/clients/cli/devices.c b/clients/cli/devices.c index 550f0c2e1d..5409452f36 100644 --- a/clients/cli/devices.c +++ b/clients/cli/devices.c @@ -3313,6 +3313,7 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) NMSettingWireless *s_wifi; NMSettingWirelessSecurity *s_wsec; NMSettingIPConfig *s_ip4, *s_ip6; + NMSettingProxy *s_proxy; GBytes *ssid_bytes; GError *error = NULL; @@ -3479,6 +3480,10 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) nm_connection_add_setting (connection, NM_SETTING (s_ip6)); g_object_set (s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL); + s_proxy = (NMSettingProxy *) nm_setting_proxy_new (); + nm_connection_add_setting (connection, NM_SETTING (s_proxy)); + g_object_set (s_proxy, NM_SETTING_PROXY_METHOD, NM_SETTING_PROXY_METHOD_NONE, NULL); + /* Activate the connection now */ nmc->nowait_flag = (nmc->timeout == 0); nmc->should_wait++; diff --git a/clients/cli/settings.c b/clients/cli/settings.c index ee167d2c6a..dd777b2b2b 100644 --- a/clients/cli/settings.c +++ b/clients/cli/settings.c @@ -795,6 +795,20 @@ NmcOutputField nmc_fields_setting_vxlan[] = { NM_SETTING_VXLAN_L2_MISS","\ NM_SETTING_VXLAN_L3_MISS +/* Available fields for NM_SETTING_PROXY_SETTING_NAME */ +NmcOutputField nmc_fields_setting_proxy[] = { + SETTING_FIELD ("name"), /* 0 */ + SETTING_FIELD (NM_SETTING_PROXY_METHOD), /* 1 */ + SETTING_FIELD (NM_SETTING_PROXY_BROWSER_ONLY), /* 2 */ + SETTING_FIELD (NM_SETTING_PROXY_PAC_URL), /* 3 */ + SETTING_FIELD (NM_SETTING_PROXY_PAC_SCRIPT), /* 4 */ + {NULL, NULL, 0, NULL, FALSE, FALSE, 0} +}; +#define NMC_FIELDS_SETTING_PROXY_ALL "name"","\ + NM_SETTING_PROXY_METHOD","\ + NM_SETTING_PROXY_BROWSER_ONLY","\ + NM_SETTING_PROXY_PAC_URL","\ + NM_SETTING_PROXY_PAC_SCRIPT /*----------------------------------------------------------------------------*/ static char * wep_key_type_to_string (NMWepKeyType type) @@ -2100,6 +2114,65 @@ DEFINE_GETTER (nmc_property_vxlan_get_rsc, NM_SETTING_VXLAN_RSC) DEFINE_GETTER (nmc_property_vxlan_get_l2_miss, NM_SETTING_VXLAN_L2_MISS) DEFINE_GETTER (nmc_property_vxlan_get_l3_miss, NM_SETTING_VXLAN_L3_MISS) +/* --- NM_SETTING_PROXY_SETTING_NAME property get functions --- */ +DEFINE_GETTER (nmc_property_proxy_get_browser_only, NM_SETTING_PROXY_BROWSER_ONLY) +DEFINE_GETTER (nmc_property_proxy_get_pac_url, NM_SETTING_PROXY_PAC_URL) +DEFINE_GETTER (nmc_property_proxy_get_pac_script, NM_SETTING_PROXY_PAC_SCRIPT) + +static char * +nmc_property_proxy_get_method (NMSetting *setting, NmcPropertyGetType get_type) +{ + NMSettingProxy *s_proxy = NM_SETTING_PROXY (setting); + NMSettingProxyMethod method; + + method = nm_setting_proxy_get_method (s_proxy); + return nm_utils_enum_to_str (nm_setting_proxy_method_get_type (), method); +} + +static gboolean +nmc_property_proxy_set_method (NMSetting *setting, const char *prop, + const char *val, GError **error) +{ + NMSettingProxyMethod method; + gboolean ret; + + ret = nm_utils_enum_from_str (nm_setting_proxy_method_get_type(), val, + (int *) &method, NULL); + + if (!ret) { + gs_free const char **values = NULL; + gs_free char *values_str = NULL; + + values = nm_utils_enum_get_values (nm_setting_proxy_method_get_type (), + NM_SETTING_PROXY_METHOD_AUTO, + G_MAXINT); + values_str = g_strjoinv (",", (char **) values); + g_set_error (error, 1, 0, _("invalid method '%s', use one of %s"), + val, values_str); + + return FALSE; + } + + g_object_set (setting, prop, method, NULL); + return TRUE; +} + +static gboolean +nmc_property_proxy_set_pac_script (NMSetting *setting, const char *prop, + const char *val, GError **error) +{ + char *script = NULL; + + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (!nmc_proxy_check_script (val, &script, error)) { + return FALSE; + } + g_object_set (setting, prop, script, NULL); + g_free (script); + return TRUE; +} + /*----------------------------------------------------------------------------*/ static void @@ -2311,6 +2384,21 @@ ipv6_method_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data) } static void +proxy_method_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data) +{ + NMSettingProxyMethod method; + + method = nm_setting_proxy_get_method (NM_SETTING_PROXY (object)); + + if (method == NM_SETTING_PROXY_METHOD_NONE) { + g_object_set (object, + NM_SETTING_PROXY_PAC_URL, NULL, + NM_SETTING_PROXY_PAC_SCRIPT, NULL, + NULL); + } +} + +static void wireless_band_channel_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data) { const char *value = NULL, *mode; @@ -2388,6 +2476,15 @@ nmc_setting_ip6_connect_handlers (NMSettingIPConfig *setting) } void +nmc_setting_proxy_connect_handlers (NMSettingProxy *setting) +{ + g_return_if_fail (NM_IS_SETTING_PROXY (setting)); + + g_signal_connect (setting, "notify::" NM_SETTING_PROXY_METHOD, + G_CALLBACK (proxy_method_changed_cb), NULL); +} + +void nmc_setting_wireless_connect_handlers (NMSettingWireless *setting) { g_return_if_fail (NM_IS_SETTING_WIRELESS (setting)); @@ -2460,6 +2557,10 @@ nmc_setting_custom_init (NMSetting *setting) g_object_set (NM_SETTING_IP_CONFIG (setting), NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL); + } else if (NM_IS_SETTING_PROXY (setting)) { + g_object_set (NM_SETTING_PROXY (setting), + NM_SETTING_PROXY_METHOD, NM_SETTING_PROXY_METHOD_NONE, + NULL); } else if (NM_IS_SETTING_TUN (setting)) { g_object_set (NM_SETTING_TUN (setting), NM_SETTING_TUN_MODE, NM_SETTING_TUN_MODE_TUN, @@ -7787,6 +7888,36 @@ nmc_properties_init (void) NULL, NULL, NULL); + + /* Add editable properties for NM_SETTING_PROXY_SETTING_NAME */ + nmc_add_prop_funcs (GLUE (PROXY, METHOD), + nmc_property_proxy_get_method, + nmc_property_proxy_set_method, + NULL, + NULL, + NULL, + NULL); + nmc_add_prop_funcs (GLUE (PROXY, BROWSER_ONLY), + nmc_property_proxy_get_browser_only, + nmc_property_set_bool, + NULL, + NULL, + NULL, + NULL); + nmc_add_prop_funcs (GLUE (PROXY, PAC_URL), + nmc_property_proxy_get_pac_url, + nmc_property_set_string, + NULL, + NULL, + NULL, + NULL); + nmc_add_prop_funcs (GLUE (PROXY, PAC_SCRIPT), + nmc_property_proxy_get_pac_script, + nmc_property_proxy_set_pac_script, + NULL, + NULL, + NULL, + NULL); } void @@ -9042,7 +9173,7 @@ setting_macvlan_details (NMSetting *setting, NmCli *nmc, const char *one_prop, return TRUE; } - static gboolean +static gboolean setting_vxlan_details (NMSetting *setting, NmCli *nmc, const char *one_prop, gboolean secrets) { NMSettingVxlan *s_vxlan = NM_SETTING_VXLAN (setting); @@ -9083,6 +9214,35 @@ setting_vxlan_details (NMSetting *setting, NmCli *nmc, const char *one_prop, gb return TRUE; } +static gboolean +setting_proxy_details (NMSetting *setting, NmCli *nmc, const char *one_prop, gboolean secrets) +{ + NMSettingProxy *s_proxy = NM_SETTING_PROXY (setting); + NmcOutputField *tmpl, *arr; + size_t tmpl_len; + + g_return_val_if_fail (NM_IS_SETTING_PROXY (s_proxy), FALSE); + + tmpl = nmc_fields_setting_proxy; + tmpl_len = sizeof (nmc_fields_setting_proxy); + nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_PROXY_ALL, + tmpl, FALSE, NULL, NULL); + arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES); + g_ptr_array_add (nmc->output_data, arr); + + arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX); + set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting))); + set_val_str (arr, 1, nmc_property_proxy_get_method (setting, NMC_PROPERTY_GET_PRETTY)); + set_val_str (arr, 2, nmc_property_proxy_get_browser_only (setting, NMC_PROPERTY_GET_PRETTY)); + set_val_str (arr, 3, nmc_property_proxy_get_pac_url (setting, NMC_PROPERTY_GET_PRETTY)); + set_val_str (arr, 4, nmc_property_proxy_get_pac_script (setting, NMC_PROPERTY_GET_PRETTY)); + g_ptr_array_add (nmc->output_data, arr); + + print_data (nmc); /* Print all data */ + + return TRUE; +} + typedef struct { const char *sname; gboolean (*func) (NMSetting *setting, NmCli *nmc, const char *one_prop, gboolean secrets); @@ -9118,6 +9278,7 @@ static const SettingDetails detail_printers[] = { { NM_SETTING_IP_TUNNEL_SETTING_NAME, setting_ip_tunnel_details }, { NM_SETTING_MACVLAN_SETTING_NAME, setting_macvlan_details }, { NM_SETTING_VXLAN_SETTING_NAME, setting_vxlan_details }, + { NM_SETTING_PROXY_SETTING_NAME, setting_proxy_details }, { NULL }, }; diff --git a/clients/cli/settings.h b/clients/cli/settings.h index 33900510fd..9ef9c270d2 100644 --- a/clients/cli/settings.h +++ b/clients/cli/settings.h @@ -32,6 +32,7 @@ NMSetting *nmc_setting_new_for_name (const char *name); void nmc_setting_custom_init (NMSetting *setting); void nmc_setting_ip4_connect_handlers (NMSettingIPConfig *setting); void nmc_setting_ip6_connect_handlers (NMSettingIPConfig *setting); +void nmc_setting_proxy_connect_handlers (NMSettingProxy *setting); void nmc_setting_wireless_connect_handlers (NMSettingWireless *setting); void nmc_setting_connection_connect_handlers (NMSettingConnection *setting, NMConnection *connection); @@ -92,5 +93,6 @@ extern NmcOutputField nmc_fields_setting_tun[]; extern NmcOutputField nmc_fields_setting_ip_tunnel[]; extern NmcOutputField nmc_fields_setting_macvlan[]; extern NmcOutputField nmc_fields_setting_vxlan[]; +extern NmcOutputField nmc_fields_setting_proxy[]; #endif /* NMC_SETTINGS_H */ diff --git a/libnm-core/Makefile.libnm-core b/libnm-core/Makefile.libnm-core index 52c71da5b7..72bfcae860 100644 --- a/libnm-core/Makefile.libnm-core +++ b/libnm-core/Makefile.libnm-core @@ -32,6 +32,7 @@ libnm_core_headers = \ $(core)/nm-setting-olpc-mesh.h \ $(core)/nm-setting-ppp.h \ $(core)/nm-setting-pppoe.h \ + $(core)/nm-setting-proxy.h \ $(core)/nm-setting-serial.h \ $(core)/nm-setting-team-port.h \ $(core)/nm-setting-team.h \ @@ -94,6 +95,7 @@ libnm_core_sources = \ $(core)/nm-setting-olpc-mesh.c \ $(core)/nm-setting-ppp.c \ $(core)/nm-setting-pppoe.c \ + $(core)/nm-setting-proxy.c \ $(core)/nm-setting-serial.c \ $(core)/nm-setting-team-port.c \ $(core)/nm-setting-team.c \ diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index 5632b1883e..9e9ab930ef 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -2181,6 +2181,24 @@ nm_connection_get_setting_pppoe (NMConnection *connection) } /** + * nm_connection_get_setting_proxy: + * @connection: the #NMConnection + * + * A shortcut to return any #NMSettingProxy the connection might contain. + * + * Returns:an #NMSettingProxy if the connection contains one, otherwise %NULL + * + * Since: 1.6 + **/ +NMSettingProxy * +nm_connection_get_setting_proxy (NMConnection *connection) +{ + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + + return (NMSettingProxy *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PROXY); +} + +/** * nm_connection_get_setting_serial: * @connection: the #NMConnection * diff --git a/libnm-core/nm-connection.h b/libnm-core/nm-connection.h index 21e30422c8..4de15c9263 100644 --- a/libnm-core/nm-connection.h +++ b/libnm-core/nm-connection.h @@ -211,6 +211,8 @@ NMSettingMacvlan * nm_connection_get_setting_macvlan (NMConnec NMSettingOlpcMesh * nm_connection_get_setting_olpc_mesh (NMConnection *connection); NMSettingPpp * nm_connection_get_setting_ppp (NMConnection *connection); NMSettingPppoe * nm_connection_get_setting_pppoe (NMConnection *connection); +NM_AVAILABLE_IN_1_6 +NMSettingProxy * nm_connection_get_setting_proxy (NMConnection *connection); NMSettingSerial * nm_connection_get_setting_serial (NMConnection *connection); NMSettingTun * nm_connection_get_setting_tun (NMConnection *connection); NMSettingVpn * nm_connection_get_setting_vpn (NMConnection *connection); diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index d7ad49b0f7..0ea59e4f08 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -49,6 +49,7 @@ #include "nm-setting-gsm.h" #include "nm-setting-infiniband.h" #include "nm-setting-ip-tunnel.h" +#include "nm-setting-proxy.h" #include "nm-setting-ip4-config.h" #include "nm-setting-ip6-config.h" #include "nm-setting-macvlan.h" diff --git a/libnm-core/nm-core-types.h b/libnm-core/nm-core-types.h index cd19923b7e..8e7c0ce8c6 100644 --- a/libnm-core/nm-core-types.h +++ b/libnm-core/nm-core-types.h @@ -43,6 +43,7 @@ typedef struct _NMSettingGsm NMSettingGsm; typedef struct _NMSettingInfiniband NMSettingInfiniband; typedef struct _NMSettingIPConfig NMSettingIPConfig; typedef struct _NMSettingIPTunnel NMSettingIPTunnel; +typedef struct _NMSettingProxy NMSettingProxy; typedef struct _NMSettingIP4Config NMSettingIP4Config; typedef struct _NMSettingIP6Config NMSettingIP6Config; typedef struct _NMSettingMacvlan NMSettingMacvlan; diff --git a/libnm-core/nm-setting-proxy.c b/libnm-core/nm-setting-proxy.c new file mode 100644 index 0000000000..1cfd7cd491 --- /dev/null +++ b/libnm-core/nm-setting-proxy.c @@ -0,0 +1,330 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2016 Atul Anand <atulhjp@gmail.com>. + */ + +#include "nm-default.h" + +#include "nm-setting-proxy.h" +#include "nm-utils.h" +#include "nm-setting-private.h" + +/** + * SECTION:nm-setting-proxy + * @short_description: Describes Proxy Url, Script and other related properties + * + * The #NMSettingProxy object is a #NMSetting subclass that describes properties + * related to Proxy settings like Pac Url, Pac Script etc. + * + * NetworkManager support 2 values for the #NMSettingProxy:method property for + * proxy. If "auto" is specified then WPAD takes places and the appropriate details + * are pushed into PacRunner or user can override this URL with a new PAC url or a + * PAC Script. If "none" is selected then no proxy configuration is given to PacRunner + * to fulfill client queries. + **/ + +G_DEFINE_TYPE_WITH_CODE (NMSettingProxy, nm_setting_proxy, NM_TYPE_SETTING, + _nm_register_setting (PROXY, 4)) +NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_PROXY) + +#define NM_SETTING_PROXY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_PROXY, NMSettingProxyPrivate)) + +typedef struct { + NMSettingProxyMethod method; + gboolean browser_only; + char *pac_url; + char *pac_script; +} NMSettingProxyPrivate; + +enum { + PROP_0, + PROP_METHOD, + PROP_BROWSER_ONLY, + PROP_PAC_URL, + PROP_PAC_SCRIPT, + + LAST_PROP +}; + +/** + * nm_setting_proxy_new: + * + * Creates a new #NMSettingProxy object. + * + * Returns: the new empty #NMSettingProxy object + * + * Since: 1.6 + **/ +NMSetting * +nm_setting_proxy_new (void) +{ + return (NMSetting *) g_object_new (NM_TYPE_SETTING_PROXY, NULL); +} + +/** + * nm_setting_proxy_get_method: + * @setting: the #NMSettingProxy + * + * Returns the proxy configuration method. By default the value is "NONE". + * "NONE" should be selected for a connection intended for direct network + * access. + * + * Returns: the proxy configuration method + * + * Since: 1.6 + **/ +NMSettingProxyMethod +nm_setting_proxy_get_method (NMSettingProxy *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_PROXY (setting), NM_SETTING_PROXY_METHOD_NONE); + + return NM_SETTING_PROXY_GET_PRIVATE (setting)->method; +} + +/** + * nm_setting_proxy_get_browser_only: + * @setting: the #NMSettingProxy + * + * Returns: TRUE if this proxy configuration is only for Browser + * clients/schemes otherwise FALSE. + * + * Since: 1.6 + **/ +gboolean +nm_setting_proxy_get_browser_only (NMSettingProxy *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_PROXY (setting), FALSE); + + return NM_SETTING_PROXY_GET_PRIVATE (setting)->browser_only; +} + +/** + * nm_setting_proxy_get_pac_url: + * @setting: the #NMSettingProxy + * + * Returns: the PAC url for obtaining PAC file + * + * Since: 1.6 + **/ +const char * +nm_setting_proxy_get_pac_url (NMSettingProxy *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_PROXY (setting), NULL); + + return NM_SETTING_PROXY_GET_PRIVATE (setting)->pac_url; +} + +/** + * nm_setting_proxy_get_pac_script: + * @setting: the #NMSettingProxy + * + * Returns: the PAC Script + * + * Since: 1.6 + **/ +const char * +nm_setting_proxy_get_pac_script (NMSettingProxy *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_PROXY (setting), NULL); + + return NM_SETTING_PROXY_GET_PRIVATE (setting)->pac_script; +} + +static gboolean +verify (NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingProxyPrivate *priv = NM_SETTING_PROXY_GET_PRIVATE (setting); + NMSettingProxyMethod method; + + method = priv->method; + if (method == NM_SETTING_PROXY_METHOD_NONE) { + if (priv->pac_url) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("this property is not allowed for method none")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_PROXY_SETTING_NAME, NM_SETTING_PROXY_PAC_URL); + return FALSE; + } + + if (priv->pac_script) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("this property is not allowed for method none")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_PROXY_SETTING_NAME, NM_SETTING_PROXY_PAC_SCRIPT); + return FALSE; + } + } + + if (priv->pac_script && strlen (priv->pac_script) > 1*1024*1024) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("the script is too large")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_PROXY_SETTING_NAME, NM_SETTING_PROXY_PAC_SCRIPT); + return FALSE; + } + + return TRUE; +} + +static void +nm_setting_proxy_init (NMSettingProxy *setting) +{ + NMSettingProxyPrivate *priv = NM_SETTING_PROXY_GET_PRIVATE (setting); + + priv->method = NM_SETTING_PROXY_METHOD_NONE; +} + +static void +finalize (GObject *object) +{ + NMSettingProxy *self = NM_SETTING_PROXY (object); + NMSettingProxyPrivate *priv = NM_SETTING_PROXY_GET_PRIVATE (self); + + g_free (priv->pac_url); + g_free (priv->pac_script); + + G_OBJECT_CLASS (nm_setting_proxy_parent_class)->finalize (object); +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMSettingProxy *setting = NM_SETTING_PROXY (object); + + switch (prop_id) { + case PROP_METHOD: + g_value_set_int (value, nm_setting_proxy_get_method (setting)); + break; + case PROP_BROWSER_ONLY: + g_value_set_boolean (value, nm_setting_proxy_get_browser_only (setting)); + break; + case PROP_PAC_URL: + g_value_set_string (value, nm_setting_proxy_get_pac_url (setting)); + break; + case PROP_PAC_SCRIPT: + g_value_set_string (value, nm_setting_proxy_get_pac_script (setting)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMSettingProxyPrivate *priv = NM_SETTING_PROXY_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_METHOD: + priv->method = g_value_get_int (value); + break; + case PROP_BROWSER_ONLY: + priv->browser_only = g_value_get_boolean (value); + break; + case PROP_PAC_URL: + g_free (priv->pac_url); + priv->pac_url = g_value_dup_string (value); + break; + case PROP_PAC_SCRIPT: + g_free (priv->pac_script); + priv->pac_script = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_setting_proxy_class_init (NMSettingProxyClass *setting_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (setting_class); + NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class); + + g_type_class_add_private (setting_class, sizeof (NMSettingProxyPrivate)); + + /* virtual methods */ + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->finalize = finalize; + parent_class->verify = verify; + + /** + * NMSettingProxy:method: + * + * Method for proxy configuration, Default is "NONE" + * + * Since: 1.6 + **/ + g_object_class_install_property + (object_class, PROP_METHOD, + g_param_spec_int (NM_SETTING_PROXY_METHOD, "", "", + G_MININT32, G_MAXINT32, NM_SETTING_PROXY_METHOD_NONE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingProxy:browser-only: + * + * TRUE if Proxy is for Browser Stuff. + * + * Since: 1.6 + **/ + g_object_class_install_property + (object_class, PROP_BROWSER_ONLY, + g_param_spec_boolean (NM_SETTING_PROXY_BROWSER_ONLY, "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingProxy:pac-url: + * + * PAC Url for obtaining PAC File. + * + * Since: 1.6 + **/ + g_object_class_install_property + (object_class, PROP_PAC_URL, + g_param_spec_string (NM_SETTING_PROXY_PAC_URL, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingProxy:pac-script: + * + * PAC Script For the connection. + * + * Since: 1.6 + **/ + g_object_class_install_property + (object_class, PROP_PAC_SCRIPT, + g_param_spec_string (NM_SETTING_PROXY_PAC_SCRIPT, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/libnm-core/nm-setting-proxy.h b/libnm-core/nm-setting-proxy.h new file mode 100644 index 0000000000..c51359fb22 --- /dev/null +++ b/libnm-core/nm-setting-proxy.h @@ -0,0 +1,88 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2016 Atul Anand <atulhjp@gmail.com>. + */ + +#ifndef __NM_SETTING_PROXY_H__ +#define __NM_SETTING_PROXY_H__ + +#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION) +#error "Only <NetworkManager.h> can be included directly." +#endif + +#include <nm-setting.h> + +G_BEGIN_DECLS + +/** + * NMSettingProxyMethod: + * @NM_SETTING_PROXY_METHOD_AUTO: DHCP obtained Proxy/ Manual override + * @NM_SETTING_PROXY_METHOD_NONE: No Proxy for the Connection + * + * The Proxy method. + * + * Since: 1.6 + */ +typedef enum { + NM_SETTING_PROXY_METHOD_AUTO = 0, + NM_SETTING_PROXY_METHOD_NONE +} NMSettingProxyMethod; + +#define NM_TYPE_SETTING_PROXY (nm_setting_proxy_get_type ()) +#define NM_SETTING_PROXY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_PROXY, NMSettingProxy)) +#define NM_SETTING_PROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_PROXY, NMSettingProxyClass)) +#define NM_IS_SETTING_PROXY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_PROXY)) +#define NM_IS_SETTING_PROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTING_PROXY)) +#define NM_SETTING_PROXY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_PROXY, NMSettingProxyClass)) + +#define NM_SETTING_PROXY_SETTING_NAME "proxy" + +#define NM_SETTING_PROXY_METHOD "method" +#define NM_SETTING_PROXY_BROWSER_ONLY "browser-only" +#define NM_SETTING_PROXY_PAC_URL "pac-url" +#define NM_SETTING_PROXY_PAC_SCRIPT "pac-script" + +struct _NMSettingProxy { + NMSetting parent; +}; + +typedef struct { + NMSettingClass parent; + + gpointer padding[4]; +} NMSettingProxyClass; + +NM_AVAILABLE_IN_1_6 +GType nm_setting_proxy_get_type (void); + +NM_AVAILABLE_IN_1_6 +NMSetting *nm_setting_proxy_new (void); + +NM_AVAILABLE_IN_1_6 +NMSettingProxyMethod nm_setting_proxy_get_method (NMSettingProxy *setting); +NM_AVAILABLE_IN_1_6 +gboolean nm_setting_proxy_get_browser_only (NMSettingProxy *setting); +NM_AVAILABLE_IN_1_6 +const char *nm_setting_proxy_get_pac_url (NMSettingProxy *setting); +NM_AVAILABLE_IN_1_6 +const char *nm_setting_proxy_get_pac_script (NMSettingProxy *setting); + +G_END_DECLS + +#endif /* __NM_SETTING_PROXY_H__ */ diff --git a/libnm-core/nm-vpn-dbus-interface.h b/libnm-core/nm-vpn-dbus-interface.h index 3295a1aeaf..1495c95526 100644 --- a/libnm-core/nm-vpn-dbus-interface.h +++ b/libnm-core/nm-vpn-dbus-interface.h @@ -183,6 +183,9 @@ typedef enum { /* string: VPN interface name (tun0, tap0, etc) */ #define NM_VPN_PLUGIN_CONFIG_TUNDEV "tundev" +/* string: Proxy PAC */ +#define NM_VPN_PLUGIN_CONFIG_PROXY_PAC "pac" + /* string: Login message */ #define NM_VPN_PLUGIN_CONFIG_BANNER "banner" diff --git a/libnm/NetworkManager.h b/libnm/NetworkManager.h index b5dab8fd84..cca05cffdd 100644 --- a/libnm/NetworkManager.h +++ b/libnm/NetworkManager.h @@ -62,6 +62,7 @@ #include <nm-setting-infiniband.h> #include <nm-setting-ip-config.h> #include <nm-setting-ip-tunnel.h> +#include <nm-setting-proxy.h> #include <nm-setting-ip4-config.h> #include <nm-setting-ip6-config.h> #include <nm-setting-macvlan.h> diff --git a/libnm/libnm.ver b/libnm/libnm.ver index bfd15b0b9e..46e91d9e93 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1087,5 +1087,13 @@ global: libnm_1_6_0 { global: nm_capability_get_type; + nm_connection_get_setting_proxy; + nm_setting_proxy_get_type; + nm_setting_proxy_new; + nm_setting_proxy_get_method; + nm_setting_proxy_method_get_type; + nm_setting_proxy_get_browser_only; + nm_setting_proxy_get_pac_url; + nm_setting_proxy_get_pac_script; nm_utils_is_json_object; } libnm_1_4_0; diff --git a/man/nmcli.xml b/man/nmcli.xml index 965c05f955..3b6cc9ff3e 100644 --- a/man/nmcli.xml +++ b/man/nmcli.xml @@ -1983,6 +1983,19 @@ It's equivalent of using <literal>+ipv6.addresses</literal> syntax.</entry> </tbody> </tgroup></table> + <table><title>Proxy options</title><tgroup cols="3"> + <thead> + <row><entry>Alias</entry><entry>Property</entry><entry>Note</entry></row> + </thead> + <tbody> + <row> + <entry align="left"></entry> + <entry align="left"><link linkend="nm-settings.property.proxy.pac-script">proxy.pac-script</link></entry> + <entry align="left" valign="top">Read the java script pac-script from file or pass it directly on the command line. Prefix the value with "file://" or "js://" to force one or the other.</entry> + </row> + </tbody> + </tgroup></table> + </refsect1> <refsect1 id='environment_variables'><title>Environment Variables</title> diff --git a/po/POTFILES.in b/po/POTFILES.in index 71cf45f23c..18c9b47b5c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -71,6 +71,7 @@ libnm-core/nm-setting-macvlan.c libnm-core/nm-setting-olpc-mesh.c libnm-core/nm-setting-ppp.c libnm-core/nm-setting-pppoe.c +libnm-core/nm-setting-proxy.c libnm-core/nm-setting-team.c libnm-core/nm-setting-team-port.c libnm-core/nm-setting-tun.c diff --git a/src/Makefile.am b/src/Makefile.am index 6e2742a8d0..f5213834da 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -442,6 +442,8 @@ libNetworkManager_la_SOURCES = \ nm-exported-object.h \ nm-firewall-manager.c \ nm-firewall-manager.h \ + nm-proxy-config.c \ + nm-proxy-config.h \ nm-ip4-config.c \ nm-ip4-config.h \ nm-ip6-config.c \ @@ -456,6 +458,8 @@ libNetworkManager_la_SOURCES = \ nm-manager.h \ nm-multi-index.c \ nm-multi-index.h \ + nm-pacrunner-manager.c \ + nm-pacrunner-manager.h \ nm-policy.c \ nm-policy.h \ nm-rfkill-manager.c \ @@ -556,6 +560,9 @@ nm_iface_helper_SOURCES = \ platform/wifi/wifi-utils.c \ platform/wifi/wifi-utils.h \ \ + nm-pacrunner-manager.c \ + nm-pacrunner-manager.h \ + \ rdisc/nm-lndp-rdisc.c \ rdisc/nm-lndp-rdisc.h \ rdisc/nm-rdisc.c \ @@ -566,6 +573,8 @@ nm_iface_helper_SOURCES = \ \ nm-exported-object.c \ nm-exported-object.h \ + nm-proxy-config.c \ + nm-proxy-config.h \ nm-ip4-config.c \ nm-ip4-config.h \ nm-ip6-config.c \ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index e2cd28f911..5fd0a187f7 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -45,8 +45,10 @@ #include "nm-lndp-rdisc.h" #include "nm-dhcp-manager.h" #include "nm-act-request.h" +#include "nm-proxy-config.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" +#include "nm-pacrunner-manager.h" #include "nm-dnsmasq-manager.h" #include "nm-dhcp4-config.h" #include "nm-dhcp6-config.h" @@ -294,6 +296,10 @@ typedef struct _NMDevicePrivate { guint32 dhcp_timeout; char * dhcp_anycast_address; + /* Proxy Configuration */ + NMProxyConfig *proxy_config; + NMPacrunnerManager *pacrunner_manager; + /* IP4 configuration info */ NMIP4Config * ip4_config; /* Combined config from VPN, settings, and device */ union { @@ -416,6 +422,8 @@ typedef struct _NMDevicePrivate { } NMDevicePrivate; +static void nm_device_set_proxy_config (NMDevice *self, GHashTable *options); + static gboolean nm_device_set_ip4_config (NMDevice *self, NMIP4Config *config, guint32 default_route_metric, @@ -5072,6 +5080,8 @@ dhcp4_state_changed (NMDhcpClient *client, break; } + nm_device_set_proxy_config (self, options); + nm_dhcp4_config_set_options (priv->dhcp4.config, options); _notify (self, PROP_DHCP4_CONFIG); priv->dhcp4.num_tries_left = DHCP_NUM_TRIES_MAX; @@ -6982,6 +6992,9 @@ activate_stage3_ip_config_start (NMDevice *self) && !nm_device_activate_stage3_ip6_start (self)) return; + /* Proxy */ + nm_device_set_proxy_config (self, NULL); + check_ip_state (self, TRUE); } @@ -8517,8 +8530,50 @@ nm_device_is_activating (NMDevice *self) return priv->act_handle4.id ? TRUE : FALSE; } -/* IP Configuration stuff */ +NMProxyConfig * +nm_device_get_proxy_config (NMDevice *self) +{ + g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + + return NM_DEVICE_GET_PRIVATE (self)->proxy_config; +} + +static void +nm_device_set_proxy_config (NMDevice *self, GHashTable *options) +{ + NMDevicePrivate *priv; + NMConnection *connection; + NMSettingProxy *s_proxy = NULL; + char *pac = NULL; + + g_return_if_fail (NM_IS_DEVICE (self)); + + priv = NM_DEVICE_GET_PRIVATE (self); + + g_clear_object (&priv->proxy_config); + priv->proxy_config = nm_proxy_config_new (); + + if (options) { + pac = g_hash_table_lookup (options, "wpad"); + if (pac) { + nm_proxy_config_set_method (priv->proxy_config, NM_PROXY_CONFIG_METHOD_AUTO); + nm_proxy_config_set_pac_url (priv->proxy_config, pac); + _LOGD (LOGD_PROXY, "proxy: PAC url \"%s\"", pac); + } else { + nm_proxy_config_set_method (priv->proxy_config, NM_PROXY_CONFIG_METHOD_NONE); + _LOGD (LOGD_PROXY, "proxy: PAC url not obtained from DHCP server"); + } + } + + connection = nm_device_get_applied_connection (self); + if (connection) + s_proxy = nm_connection_get_setting_proxy (connection); + if (s_proxy) + nm_proxy_config_merge_setting (priv->proxy_config, s_proxy); +} + +/* IP Configuration stuff */ NMDhcp4Config * nm_device_get_dhcp4_config (NMDevice *self) { @@ -10735,6 +10790,7 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) */ nm_device_set_ip4_config (self, NULL, 0, TRUE, TRUE, NULL); nm_device_set_ip6_config (self, NULL, TRUE, TRUE, NULL); + g_clear_object (&priv->proxy_config); g_clear_object (&priv->con_ip4_config); g_clear_object (&priv->dev_ip4_config); g_clear_object (&priv->ext_ip4_config); @@ -11325,6 +11381,9 @@ _set_state_full (NMDevice *self, deactivate_dispatcher_complete (0, self); } } + + /* Remove config from PacRunner */ + nm_pacrunner_manager_remove (priv->pacrunner_manager, nm_device_get_ip_iface (self)); break; case NM_DEVICE_STATE_DISCONNECTED: if ( priv->queued_act_request @@ -11348,6 +11407,14 @@ _set_state_full (NMDevice *self, nm_act_request_get_settings_connection (req), nm_act_request_get_applied_connection (req), self, NULL, NULL, NULL); + + if (priv->proxy_config) { + nm_pacrunner_manager_send (priv->pacrunner_manager, + nm_device_get_ip_iface (self), + priv->proxy_config, + priv->ip4_config, + priv->ip6_config); + } break; case NM_DEVICE_STATE_FAILED: /* Usually upon failure the activation chain is interrupted in @@ -12164,6 +12231,8 @@ nm_device_init (NMDevice *self) priv->available_connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL); priv->ip6_saved_properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); + priv->pacrunner_manager = g_object_ref (nm_pacrunner_manager_get ()); + priv->default_route.v4_is_assumed = TRUE; priv->default_route.v6_is_assumed = TRUE; @@ -12275,6 +12344,8 @@ dispose (GObject *object) dispatcher_cleanup (self); + g_clear_object (&priv->pacrunner_manager); + _cleanup_generic_pre (self, CLEANUP_TYPE_KEEP); g_warn_if_fail (priv->slaves == NULL); diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 812a8608a1..ceee6c0b83 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -366,9 +366,10 @@ const char * nm_device_get_permanent_hw_address (NMDevice *dev, gboolean fallback_fake); const char * nm_device_get_initial_hw_address (NMDevice *dev); +NMProxyConfig * nm_device_get_proxy_config (NMDevice *dev); + NMDhcp4Config * nm_device_get_dhcp4_config (NMDevice *dev); NMDhcp6Config * nm_device_get_dhcp6_config (NMDevice *dev); - NMIP4Config * nm_device_get_ip4_config (NMDevice *dev); void nm_device_replace_vpn4_config (NMDevice *dev, NMIP4Config *old, diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c index df9be2e711..64ebfc66d4 100644 --- a/src/nm-dispatcher.c +++ b/src/nm-dispatcher.c @@ -32,6 +32,7 @@ #include "nm-device.h" #include "nm-dhcp4-config.h" #include "nm-dhcp6-config.h" +#include "nm-proxy-config.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" #include "nm-manager.h" @@ -91,6 +92,29 @@ _get_monitor_by_action (DispatcherAction action) } static void +dump_proxy_to_props (NMProxyConfig *proxy, GVariantBuilder *builder) +{ + const char *pac_url = NULL, *pac_script = NULL; + + if (nm_proxy_config_get_method (proxy) == NM_PROXY_CONFIG_METHOD_NONE) + return; + + pac_url = nm_proxy_config_get_pac_url (proxy); + if (pac_url) { + g_variant_builder_add (builder, "{sv}", + "pac-url", + g_variant_new_string (pac_url)); + } + + pac_script = nm_proxy_config_get_pac_script (proxy); + if (pac_script) { + g_variant_builder_add (builder, "{sv}", + "pac-script", + g_variant_new_string (pac_script)); + } +} + +static void dump_ip4_to_props (NMIP4Config *ip4, GVariantBuilder *builder) { GVariantBuilder int_builder; @@ -231,11 +255,13 @@ dump_ip6_to_props (NMIP6Config *ip6, GVariantBuilder *builder) static void fill_device_props (NMDevice *device, GVariantBuilder *dev_builder, + GVariantBuilder *proxy_builder, GVariantBuilder *ip4_builder, GVariantBuilder *ip6_builder, GVariant **dhcp4_props, GVariant **dhcp6_props) { + NMProxyConfig *proxy_config; NMIP4Config *ip4_config; NMIP6Config *ip6_config; NMDhcp4Config *dhcp4_config; @@ -254,6 +280,10 @@ fill_device_props (NMDevice *device, g_variant_builder_add (dev_builder, "{sv}", NMD_DEVICE_PROPS_PATH, g_variant_new_object_path (nm_exported_object_get_path (NM_EXPORTED_OBJECT (device)))); + proxy_config = nm_device_get_proxy_config (device); + if (proxy_config) + dump_proxy_to_props (proxy_config, proxy_builder); + ip4_config = nm_device_get_ip4_config (device); if (ip4_config) dump_ip4_to_props (ip4_config, ip4_builder); @@ -272,11 +302,15 @@ fill_device_props (NMDevice *device, } static void -fill_vpn_props (NMIP4Config *ip4_config, +fill_vpn_props (NMProxyConfig *proxy_config, + NMIP4Config *ip4_config, NMIP6Config *ip6_config, + GVariantBuilder *proxy_builder, GVariantBuilder *ip4_builder, GVariantBuilder *ip6_builder) { + if (proxy_config) + dump_proxy_to_props (proxy_config, proxy_builder); if (ip4_config) dump_ip4_to_props (ip4_config, ip4_builder); if (ip6_config) @@ -454,6 +488,7 @@ _dispatcher_call (DispatcherAction action, NMDevice *device, NMConnectivityState connectivity_state, const char *vpn_iface, + NMProxyConfig *vpn_proxy_config, NMIP4Config *vpn_ip4_config, NMIP6Config *vpn_ip6_config, DispatcherFunc callback, @@ -463,10 +498,12 @@ _dispatcher_call (DispatcherAction action, GVariant *connection_dict; GVariantBuilder connection_props; GVariantBuilder device_props; + GVariantBuilder device_proxy_props; GVariantBuilder device_ip4_props; GVariantBuilder device_ip6_props; GVariant *device_dhcp4_props = NULL; GVariant *device_dhcp6_props = NULL; + GVariantBuilder vpn_proxy_props; GVariantBuilder vpn_ip4_props; GVariantBuilder vpn_ip6_props; DispatchInfo *info = NULL; @@ -551,8 +588,10 @@ _dispatcher_call (DispatcherAction action, } g_variant_builder_init (&device_props, G_VARIANT_TYPE_VARDICT); + g_variant_builder_init (&device_proxy_props, G_VARIANT_TYPE_VARDICT); g_variant_builder_init (&device_ip4_props, G_VARIANT_TYPE_VARDICT); g_variant_builder_init (&device_ip6_props, G_VARIANT_TYPE_VARDICT); + g_variant_builder_init (&vpn_proxy_props, G_VARIANT_TYPE_VARDICT); g_variant_builder_init (&vpn_ip4_props, G_VARIANT_TYPE_VARDICT); g_variant_builder_init (&vpn_ip6_props, G_VARIANT_TYPE_VARDICT); @@ -561,13 +600,16 @@ _dispatcher_call (DispatcherAction action, && action != DISPATCHER_ACTION_CONNECTIVITY_CHANGE) { fill_device_props (device, &device_props, + &device_proxy_props, &device_ip4_props, &device_ip6_props, &device_dhcp4_props, &device_dhcp6_props); if (vpn_ip4_config || vpn_ip6_config) { - fill_vpn_props (vpn_ip4_config, + fill_vpn_props (vpn_proxy_config, + vpn_ip4_config, vpn_ip6_config, + &vpn_proxy_props, &vpn_ip4_props, &vpn_ip6_props); } @@ -584,17 +626,19 @@ _dispatcher_call (DispatcherAction action, GVariantIter *results; ret = _nm_dbus_proxy_call_sync (dispatcher_proxy, "Action", - g_variant_new ("(s@a{sa{sv}}a{sv}a{sv}a{sv}a{sv}@a{sv}@a{sv}ssa{sv}a{sv}b)", + g_variant_new ("(s@a{sa{sv}}a{sv}a{sv}a{sv}a{sv}a{sv}@a{sv}@a{sv}ssa{sv}a{sv}a{sv}b)", action_to_string (action), connection_dict, &connection_props, &device_props, + &device_proxy_props, &device_ip4_props, &device_ip6_props, device_dhcp4_props, device_dhcp6_props, nm_connectivity_state_to_string (connectivity_state), vpn_iface ? vpn_iface : "", + &vpn_proxy_props, &vpn_ip4_props, &vpn_ip6_props, nm_logging_enabled (LOGL_DEBUG, LOGD_DISPATCH)), @@ -620,17 +664,19 @@ _dispatcher_call (DispatcherAction action, info->callback = callback; info->user_data = user_data; g_dbus_proxy_call (dispatcher_proxy, "Action", - g_variant_new ("(s@a{sa{sv}}a{sv}a{sv}a{sv}a{sv}@a{sv}@a{sv}ssa{sv}a{sv}b)", + g_variant_new ("(s@a{sa{sv}}a{sv}a{sv}a{sv}a{sv}a{sv}@a{sv}@a{sv}ssa{sv}a{sv}a{sv}b)", action_to_string (action), connection_dict, &connection_props, &device_props, + &device_proxy_props, &device_ip4_props, &device_ip6_props, device_dhcp4_props, device_dhcp6_props, nm_connectivity_state_to_string (connectivity_state), vpn_iface ? vpn_iface : "", + &vpn_proxy_props, &vpn_ip4_props, &vpn_ip6_props, nm_logging_enabled (LOGL_DEBUG, LOGD_DISPATCH)), @@ -680,7 +726,7 @@ nm_dispatcher_call (DispatcherAction action, guint *out_call_id) { return _dispatcher_call (action, FALSE, settings_connection, applied_connection, device, - NM_CONNECTIVITY_UNKNOWN, NULL, NULL, NULL, + NM_CONNECTIVITY_UNKNOWN, NULL, NULL, NULL, NULL, callback, user_data, out_call_id); } @@ -703,7 +749,7 @@ nm_dispatcher_call_sync (DispatcherAction action, NMDevice *device) { return _dispatcher_call (action, TRUE, settings_connection, applied_connection, device, - NM_CONNECTIVITY_UNKNOWN, NULL, NULL, NULL, NULL, NULL, NULL); + NM_CONNECTIVITY_UNKNOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL); } /** @@ -713,6 +759,7 @@ nm_dispatcher_call_sync (DispatcherAction action, * @applied_connection: the currently applied connection * @parent_device: the parent #NMDevice of the VPN connection * @vpn_iface: the IP interface of the VPN tunnel, if any + * @vpn_proxy_config: the #NMProxyConfig of the VPN connection * @vpn_ip4_config: the #NMIP4Config of the VPN connection * @vpn_ip6_config: the #NMIP6Config of the VPN connection * @callback: a caller-supplied callback to execute when done @@ -731,6 +778,7 @@ nm_dispatcher_call_vpn (DispatcherAction action, NMConnection *applied_connection, NMDevice *parent_device, const char *vpn_iface, + NMProxyConfig *vpn_proxy_config, NMIP4Config *vpn_ip4_config, NMIP6Config *vpn_ip6_config, DispatcherFunc callback, @@ -738,8 +786,8 @@ nm_dispatcher_call_vpn (DispatcherAction action, guint *out_call_id) { return _dispatcher_call (action, FALSE, settings_connection, applied_connection, - parent_device, NM_CONNECTIVITY_UNKNOWN, vpn_iface, vpn_ip4_config, - vpn_ip6_config, callback, user_data, out_call_id); + parent_device, NM_CONNECTIVITY_UNKNOWN, vpn_iface, vpn_proxy_config, + vpn_ip4_config, vpn_ip6_config, callback, user_data, out_call_id); } /** @@ -749,6 +797,7 @@ nm_dispatcher_call_vpn (DispatcherAction action, * @applied_connection: the currently applied connection * @parent_device: the parent #NMDevice of the VPN connection * @vpn_iface: the IP interface of the VPN tunnel, if any + * @vpn_proxy_config: the #NMProxyConfig of the VPN connection * @vpn_ip4_config: the #NMIP4Config of the VPN connection * @vpn_ip6_config: the #NMIP6Config of the VPN connection * @@ -763,11 +812,12 @@ nm_dispatcher_call_vpn_sync (DispatcherAction action, NMConnection *applied_connection, NMDevice *parent_device, const char *vpn_iface, + NMProxyConfig *vpn_proxy_config, NMIP4Config *vpn_ip4_config, NMIP6Config *vpn_ip6_config) { return _dispatcher_call (action, TRUE, settings_connection, applied_connection, - parent_device, NM_CONNECTIVITY_UNKNOWN, vpn_iface, + parent_device, NM_CONNECTIVITY_UNKNOWN, vpn_iface, vpn_proxy_config, vpn_ip4_config, vpn_ip6_config, NULL, NULL, NULL); } @@ -785,7 +835,7 @@ nm_dispatcher_call_connectivity (DispatcherAction action, NMConnectivityState connectivity_state) { return _dispatcher_call (action, FALSE, NULL, NULL, NULL, connectivity_state, - NULL, NULL, NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL, NULL, NULL); } void diff --git a/src/nm-dispatcher.h b/src/nm-dispatcher.h index 62818c4563..7ea1a6b8ae 100644 --- a/src/nm-dispatcher.h +++ b/src/nm-dispatcher.h @@ -61,6 +61,7 @@ gboolean nm_dispatcher_call_vpn (DispatcherAction action, NMConnection *applied_connection, NMDevice *parent_device, const char *vpn_iface, + NMProxyConfig *vpn_proxy_config, NMIP4Config *vpn_ip4_config, NMIP6Config *vpn_ip6_config, DispatcherFunc callback, @@ -72,6 +73,7 @@ gboolean nm_dispatcher_call_vpn_sync (DispatcherAction action, NMConnection *applied_connection, NMDevice *parent_device, const char *vpn_iface, + NMProxyConfig *vpn_proxy_config, NMIP4Config *vpn_ip4_config, NMIP6Config *vpn_ip6_config); diff --git a/src/nm-logging.c b/src/nm-logging.c index 1dc9237ae2..51dd2aad2c 100644 --- a/src/nm-logging.c +++ b/src/nm-logging.c @@ -90,7 +90,7 @@ static struct { char *logging_domains_to_string; const LogLevelDesc level_desc[_LOGL_N]; -#define _DOMAIN_DESC_LEN 38 +#define _DOMAIN_DESC_LEN 39 /* Would be nice to use C99 flexible array member here, * but that feature doesn't seem well supported. */ const LogDesc domain_desc[_DOMAIN_DESC_LEN]; @@ -145,6 +145,7 @@ static struct { { LOGD_AUDIT, "AUDIT" }, { LOGD_SYSTEMD, "SYSTEMD" }, { LOGD_VPN_PLUGIN,"VPN_PLUGIN" }, + { LOGD_PROXY, "PROXY" }, { 0, NULL } /* keep _DOMAIN_DESC_LEN in sync */ }, diff --git a/src/nm-logging.h b/src/nm-logging.h index 9e2b0108ef..9f85c16990 100644 --- a/src/nm-logging.h +++ b/src/nm-logging.h @@ -66,6 +66,7 @@ typedef enum { /*< skip >*/ LOGD_AUDIT = (1LL << 34), LOGD_SYSTEMD = (1LL << 35), LOGD_VPN_PLUGIN = (1LL << 36), + LOGD_PROXY = (1LL << 37), __LOGD_MAX, LOGD_ALL = (((__LOGD_MAX - 1LL) << 1) - 1LL), diff --git a/src/nm-pacrunner-manager.c b/src/nm-pacrunner-manager.c new file mode 100644 index 0000000000..66fe589e79 --- /dev/null +++ b/src/nm-pacrunner-manager.c @@ -0,0 +1,474 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * (C) Copyright 2016 Atul Anand <atulhjp@gmail.com>. + */ + +#include "nm-default.h" + +#include "nm-pacrunner-manager.h" + +#include "nm-utils.h" +#include "nm-platform.h" +#include "nm-proxy-config.h" +#include "nm-ip4-config.h" +#include "nm-ip6-config.h" + +#define PACRUNNER_DBUS_SERVICE "org.pacrunner" +#define PACRUNNER_DBUS_INTERFACE "org.pacrunner.Manager" +#define PACRUNNER_DBUS_PATH "/org/pacrunner/manager" + +/*****************************************************************************/ + +struct remove_data { + char *iface; + char *path; +}; + +typedef struct { + char *iface; + GPtrArray *domains; + GDBusProxy *pacrunner; + GCancellable *pacrunner_cancellable; + GList *args; + GList *remove; +} NMPacrunnerManagerPrivate; + +struct _NMPacrunnerManager { + GObject parent; + NMPacrunnerManagerPrivate _priv; +}; + +struct _NMPacrunnerManagerClass { + GObjectClass parent; +}; + +G_DEFINE_TYPE (NMPacrunnerManager, nm_pacrunner_manager, G_TYPE_OBJECT) + +#define NM_PACRUNNER_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMPacrunnerManager, NM_IS_PACRUNNER_MANAGER) + +/*****************************************************************************/ + +NM_DEFINE_SINGLETON_GETTER (NMPacrunnerManager, nm_pacrunner_manager_get, NM_TYPE_PACRUNNER_MANAGER); + +/*****************************************************************************/ + +#define _NMLOG_DOMAIN LOGD_PROXY +#define _NMLOG_PREFIX_NAME "pacrunner" +#define _NMLOG(level, ...) \ + G_STMT_START { \ + nm_log ((level), _NMLOG_DOMAIN, \ + "%s[%p]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + (self) /* Beware: must not dereference @self (see pacrunner_remove_done) */\ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } G_STMT_END + +/*****************************************************************************/ + +static void +remove_data_destroy (struct remove_data *data) +{ + g_return_if_fail (data != NULL); + + g_free (data->iface); + g_free (data->path); + memset (data, 0, sizeof (struct remove_data)); + g_free (data); +} + +static void +add_proxy_config (NMPacrunnerManager *self, GVariantBuilder *proxy_data, const NMProxyConfig *proxy_config) +{ + const char *pac_url, *pac_script; + NMProxyConfigMethod method; + + method = nm_proxy_config_get_method (proxy_config); + + if (method == NM_PROXY_CONFIG_METHOD_AUTO) { + pac_url = nm_proxy_config_get_pac_url (proxy_config); + if (pac_url) { + g_variant_builder_add (proxy_data, "{sv}", + "URL", + g_variant_new_string (pac_url)); + } + + pac_script = nm_proxy_config_get_pac_script (proxy_config); + if (pac_script) { + g_variant_builder_add (proxy_data, "{sv}", + "Script", + g_variant_new_string (pac_script)); + } + } + + g_variant_builder_add (proxy_data, "{sv}", + "BrowserOnly", + g_variant_new_boolean (nm_proxy_config_get_browser_only (proxy_config))); +} + +static void +add_ip4_config (NMPacrunnerManager *self, GVariantBuilder *proxy_data, NMIP4Config *ip4) +{ + NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); + int i; + char *cidr = NULL; + + /* Extract Searches */ + for (i = 0; i < nm_ip4_config_get_num_searches (ip4); i++) + g_ptr_array_add (priv->domains, g_strdup (nm_ip4_config_get_search (ip4, i))); + + /* Extract domains */ + for (i = 0; i < nm_ip4_config_get_num_domains (ip4); i++) + g_ptr_array_add (priv->domains, g_strdup (nm_ip4_config_get_domain (ip4, i))); + + /* Add Addresses and routes in CIDR form */ + for (i = 0; i < nm_ip4_config_get_num_addresses (ip4); i++) { + const NMPlatformIP4Address *address = nm_ip4_config_get_address (ip4, i); + + cidr = g_strdup_printf ("%s/%u", + nm_utils_inet4_ntop (address->address, NULL), + address->plen); + g_ptr_array_add (priv->domains, g_strdup (cidr)); + g_free (cidr); + } + + for (i = 0; i < nm_ip4_config_get_num_routes (ip4); i++) { + const NMPlatformIP4Route *routes = nm_ip4_config_get_route (ip4, i); + + cidr = g_strdup_printf ("%s/%u", + nm_utils_inet4_ntop (routes->network, NULL), + routes->plen); + g_ptr_array_add (priv->domains, g_strdup (cidr)); + g_free (cidr); + } +} + +static void +add_ip6_config (NMPacrunnerManager *self, GVariantBuilder *proxy_data, NMIP6Config *ip6) +{ + NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); + int i; + char *cidr = NULL; + + /* Extract searches */ + for (i = 0; i < nm_ip6_config_get_num_searches (ip6); i++) + g_ptr_array_add (priv->domains, g_strdup (nm_ip6_config_get_search (ip6, i))); + + /* Extract domains */ + for (i = 0; i < nm_ip6_config_get_num_domains (ip6); i++) + g_ptr_array_add (priv->domains, g_strdup (nm_ip6_config_get_domain (ip6, i))); + + /* Add Addresses and routes in CIDR form */ + for (i = 0; i < nm_ip6_config_get_num_addresses (ip6); i++) { + const NMPlatformIP6Address *address = nm_ip6_config_get_address (ip6, i); + + cidr = g_strdup_printf ("%s/%u", + nm_utils_inet6_ntop (&address->address, NULL), + address->plen); + g_ptr_array_add (priv->domains, g_strdup (cidr)); + g_free (cidr); + } + + for (i = 0; i < nm_ip6_config_get_num_routes (ip6); i++) { + const NMPlatformIP6Route *routes = nm_ip6_config_get_route (ip6, i); + + cidr = g_strdup_printf ("%s/%u", + nm_utils_inet6_ntop (&routes->network, NULL), + routes->plen); + g_ptr_array_add (priv->domains, g_strdup (cidr)); + g_free (cidr); + } +} + +static void +pacrunner_send_done (GObject *source, GAsyncResult *res, gpointer user_data) +{ + NMPacrunnerManager *self = NM_PACRUNNER_MANAGER (user_data); + NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *variant = NULL; + const char *path = NULL; + GList *iter = NULL; + gboolean found = FALSE; + + variant = g_dbus_proxy_call_finish (priv->pacrunner, res, &error); + if (!variant) { + _LOGD ("sending proxy config to pacrunner failed: %s", error->message); + } else { + struct remove_data *data; + g_variant_get (variant, "(&o)", &path); + + /* Replace the old path (if any) of proxy config with the new one returned + * from CreateProxyConfiguration() DBus method on PacRunner. + */ + for (iter = g_list_first (priv->remove); iter; iter = g_list_next (iter)) { + struct remove_data *r = iter->data; + if (g_strcmp0 (priv->iface, r->iface) == 0) { + g_free (r->path); + r->path = g_strdup (path); + found = TRUE; + break; + } + } + + if (!found) { + data = g_malloc0 (sizeof (struct remove_data)); + data->iface = g_strdup (priv->iface); + data->path = g_strdup (path); + priv->remove = g_list_append (priv->remove, data); + _LOGD ("proxy config sent to pacrunner"); + } + } +} + +static void +send_pacrunner_proxy_data (NMPacrunnerManager *self, GVariant *pacrunner_manager_args) +{ + NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); + + if (!pacrunner_manager_args) + return; + + if (priv->pacrunner) + g_dbus_proxy_call (priv->pacrunner, + "CreateProxyConfiguration", + pacrunner_manager_args, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback) pacrunner_send_done, + self); +} + +static void +name_owner_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + NMPacrunnerManager *self = NM_PACRUNNER_MANAGER (user_data); + NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); + gs_free char *owner = NULL; + GList *iter = NULL; + + owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (object)); + if (owner) { + _LOGD ("PacRunner appeared as %s", owner); + for (iter = g_list_first(priv->args); iter; iter = g_list_next(iter)) { + send_pacrunner_proxy_data (self, iter->data); + } + } else { + _LOGD ("PacRunner disappeared"); + } +} + +static void +pacrunner_proxy_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + NMPacrunnerManager *self = user_data; + NMPacrunnerManagerPrivate *priv; + GError *error = NULL; + GDBusProxy *proxy; + + proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + if (!proxy) { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + _LOGW ("failed to connect to pacrunner via DBus: %s", error->message); + g_error_free (error); + return; + } + + priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); + + priv->pacrunner = proxy; + nm_clear_g_cancellable (&priv->pacrunner_cancellable); + + g_signal_connect (priv->pacrunner, "notify::g-name-owner", + G_CALLBACK (name_owner_changed), self); +} + +/** + * nm_pacrunner_manager_send(): + * @self: the #NMPacrunnerManager + * @iface: the iface for the connection or %NULL + * @proxy_config: Proxy config of the connection + * @ip4_conifg: IP4 Cofig of the connection + * @ip6_config: IP6 Config of the connection + */ +void +nm_pacrunner_manager_send (NMPacrunnerManager *self, + const char *iface, + NMProxyConfig *proxy_config, + NMIP4Config *ip4_config, + NMIP6Config *ip6_config) +{ + char **strv = NULL; + NMProxyConfigMethod method; + NMPacrunnerManagerPrivate *priv; + GVariantBuilder proxy_data; + GVariant *pacrunner_manager_args; + + g_return_if_fail (NM_IS_PACRUNNER_MANAGER (self)); + g_return_if_fail (proxy_config); + + priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); + + g_free (priv->iface); + priv->iface = g_strdup (iface); + + g_variant_builder_init (&proxy_data, G_VARIANT_TYPE_VARDICT); + + g_variant_builder_add (&proxy_data, "{sv}", + "Interface", + g_variant_new_string (iface)); + + method = nm_proxy_config_get_method (proxy_config); + switch (method) { + case NM_PROXY_CONFIG_METHOD_AUTO: + g_variant_builder_add (&proxy_data, "{sv}", + "Method", + g_variant_new_string ("auto")); + + break; + case NM_PROXY_CONFIG_METHOD_NONE: + g_variant_builder_add (&proxy_data, "{sv}", + "Method", + g_variant_new_string ("direct")); + } + + priv->domains = g_ptr_array_new_with_free_func (g_free); + + /* Extract stuff from Configs */ + add_proxy_config (self, &proxy_data, proxy_config); + + if (ip4_config) + add_ip4_config (self, &proxy_data, ip4_config); + if (ip6_config) + add_ip6_config (self, &proxy_data, ip6_config); + + g_ptr_array_add (priv->domains, NULL); + strv = (char **) g_ptr_array_free (priv->domains, (priv->domains->len == 1)); + + if (strv) { + g_variant_builder_add (&proxy_data, "{sv}", + "Domains", + g_variant_new_strv ((const char *const *) strv, -1)); + g_strfreev (strv); + } + + pacrunner_manager_args = g_variant_ref_sink (g_variant_new ("(a{sv})", &proxy_data)); + priv->args = g_list_append (priv->args, pacrunner_manager_args); + + /* Send if PacRunner is available on Bus, otherwise + * argument has already been appended above to be + * sent when PacRunner appears. + */ + send_pacrunner_proxy_data (self, pacrunner_manager_args); +} + +static void +pacrunner_remove_done (GObject *source, GAsyncResult *res, gpointer user_data) +{ + /* @self may be a dangling pointer. However, we don't use it as the + * logging macro below does not dereference @self. */ + NMPacrunnerManager *self = user_data; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *ret = NULL; + + ret = g_dbus_proxy_call_finish ((GDBusProxy *) source, res, &error); + + if (!ret) + _LOGD ("Couldn't remove proxy config from pacrunner: %s", error->message); + else + _LOGD ("Sucessfully removed proxy config from pacrunner"); +} + +/** + * nm_pacrunner_manager_remove(): + * @self: the #NMPacrunnerManager + * @iface: the iface for the connection to be removed + * from PacRunner + */ +void +nm_pacrunner_manager_remove (NMPacrunnerManager *self, const char *iface) +{ + NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); + GList *list; + + for (list = g_list_first(priv->remove); list; list = g_list_next(list)) { + struct remove_data *data = list->data; + if (g_strcmp0 (data->iface, iface) == 0) { + if (priv->pacrunner && data->path) + g_dbus_proxy_call (priv->pacrunner, + "DestroyProxyConfiguration", + g_variant_new ("(o)", data->path), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback) pacrunner_remove_done, + self); + break; + } + } +} + +/*****************************************************************************/ + +static void +nm_pacrunner_manager_init (NMPacrunnerManager *self) +{ + NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); + + priv->pacrunner_cancellable = g_cancellable_new (); + + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + PACRUNNER_DBUS_SERVICE, + PACRUNNER_DBUS_PATH, + PACRUNNER_DBUS_INTERFACE, + priv->pacrunner_cancellable, + (GAsyncReadyCallback) pacrunner_proxy_cb, + self); +} + +static void +dispose (GObject *object) +{ + NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE ((NMPacrunnerManager *) object); + + g_clear_pointer (&priv->iface, g_free); + + nm_clear_g_cancellable (&priv->pacrunner_cancellable); + + g_clear_object (&priv->pacrunner); + + g_list_free_full (priv->args, (GDestroyNotify) g_variant_unref); + priv->args = NULL; + + g_list_free_full (priv->remove, (GDestroyNotify) remove_data_destroy); + priv->remove = NULL; + + G_OBJECT_CLASS (nm_pacrunner_manager_parent_class)->dispose (object); +} + +static void +nm_pacrunner_manager_class_init (NMPacrunnerManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = dispose; +} diff --git a/src/nm-pacrunner-manager.h b/src/nm-pacrunner-manager.h new file mode 100644 index 0000000000..99e8511580 --- /dev/null +++ b/src/nm-pacrunner-manager.h @@ -0,0 +1,45 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * (C) Copyright 2016 Atul Anand <atulhjp@gmail.com>. + */ + +#ifndef __NETWORKMANAGER_PACRUNNER_MANAGER_H__ +#define __NETWORKMANAGER_PACRUNNER_MANAGER_H__ + +#define NM_TYPE_PACRUNNER_MANAGER (nm_pacrunner_manager_get_type ()) +#define NM_PACRUNNER_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_PACRUNNER_MANAGER, NMPacrunnerManager)) +#define NM_PACRUNNER_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_PACRUNNER_MANAGER, NMPacrunnerManagerClass)) +#define NM_IS_PACRUNNER_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_PACRUNNER_MANAGER)) +#define NM_IS_PACRUNNER_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_PACRUNNER_MANAGER)) +#define NM_PACRUNNER_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_PACRUNNER_MANAGER, NMPacrunnerManagerClass)) + +typedef struct _NMPacrunnerManagerClass NMPacrunnerManagerClass; + +GType nm_pacrunner_manager_get_type (void); + +NMPacrunnerManager *nm_pacrunner_manager_get (void); + +void nm_pacrunner_manager_send (NMPacrunnerManager *self, + const char *iface, + NMProxyConfig *proxy_config, + NMIP4Config *ip4_config, + NMIP6Config *ip6_config); + +void nm_pacrunner_manager_remove (NMPacrunnerManager *self, const char *iface); + +#endif /* __NETWORKMANAGER_PACRUNNER_MANAGER_H__ */ diff --git a/src/nm-proxy-config.c b/src/nm-proxy-config.c new file mode 100644 index 0000000000..e051367a9f --- /dev/null +++ b/src/nm-proxy-config.c @@ -0,0 +1,187 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * (C) Copyright 2016 Atul Anand <atulhjp@gmail.com>. + */ + +#include "nm-default.h" + +#include "nm-proxy-config.h" + +#include <stdlib.h> + +#include "nm-core-internal.h" + +/*****************************************************************************/ + +typedef struct { + NMProxyConfigMethod method; + gboolean browser_only; + char *pac_url; + char *pac_script; +} NMProxyConfigPrivate; + +struct _NMProxyConfig { + GObject parent; + NMProxyConfigPrivate _priv; +}; + +struct _NMProxyConfigClass { + GObjectClass parent; +}; + +G_DEFINE_TYPE (NMProxyConfig, nm_proxy_config, G_TYPE_OBJECT) + +#define NM_PROXY_CONFIG_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMProxyConfig, NM_IS_PROXY_CONFIG) + +/*****************************************************************************/ + +void +nm_proxy_config_set_method (NMProxyConfig *config, NMProxyConfigMethod method) +{ + NMProxyConfigPrivate *priv = NM_PROXY_CONFIG_GET_PRIVATE (config); + + priv->method = method; +} + +NMProxyConfigMethod +nm_proxy_config_get_method (const NMProxyConfig *config) +{ + const NMProxyConfigPrivate *priv = NM_PROXY_CONFIG_GET_PRIVATE (config); + + return priv->method; +} + +void +nm_proxy_config_merge_setting (NMProxyConfig *config, NMSettingProxy *setting) +{ + const char *tmp = NULL; + NMProxyConfigPrivate *priv; + NMSettingProxyMethod method; + + if (!setting) + return; + + g_return_if_fail (NM_IS_SETTING_PROXY (setting)); + + priv = NM_PROXY_CONFIG_GET_PRIVATE (config); + + g_clear_pointer (&priv->pac_script, g_free); + + method = nm_setting_proxy_get_method (setting); + switch (method) { + case NM_SETTING_PROXY_METHOD_AUTO: + priv->method = NM_PROXY_CONFIG_METHOD_AUTO; + + /* Free DHCP Obtained PAC Url (i.e Option 252) + * only when libnm overrides it. + */ + tmp = nm_setting_proxy_get_pac_url (setting); + if (tmp) { + g_free (priv->pac_url); + priv->pac_url = g_strdup (tmp); + } + + tmp = nm_setting_proxy_get_pac_script (setting); + priv->pac_script = g_strdup (tmp); + + break; + case NM_SETTING_PROXY_METHOD_NONE: + priv->method = NM_PROXY_CONFIG_METHOD_NONE; + break; + } + + priv->browser_only = nm_setting_proxy_get_browser_only (setting); +} + +gboolean +nm_proxy_config_get_browser_only (const NMProxyConfig *config) +{ + const NMProxyConfigPrivate *priv = NM_PROXY_CONFIG_GET_PRIVATE (config); + + return priv->browser_only; +} + +void +nm_proxy_config_set_pac_url (NMProxyConfig *config, const char *url) +{ + NMProxyConfigPrivate *priv = NM_PROXY_CONFIG_GET_PRIVATE (config); + + g_free (priv->pac_url); + priv->pac_url = g_strdup (url); +} + +const char * +nm_proxy_config_get_pac_url (const NMProxyConfig *config) +{ + const NMProxyConfigPrivate *priv = NM_PROXY_CONFIG_GET_PRIVATE (config); + + return priv->pac_url; +} + +void +nm_proxy_config_set_pac_script (NMProxyConfig *config, const char *script) +{ + NMProxyConfigPrivate *priv = NM_PROXY_CONFIG_GET_PRIVATE (config); + + g_free (priv->pac_script); + priv->pac_script = g_strdup (script); +} + +const char * +nm_proxy_config_get_pac_script (const NMProxyConfig *config) +{ + const NMProxyConfigPrivate *priv = NM_PROXY_CONFIG_GET_PRIVATE (config); + + return priv->pac_script; +} + +/*****************************************************************************/ + +static void +nm_proxy_config_init (NMProxyConfig *config) +{ + NMProxyConfigPrivate *priv = NM_PROXY_CONFIG_GET_PRIVATE (config); + + priv->method = NM_PROXY_CONFIG_METHOD_NONE; +} + +NMProxyConfig * +nm_proxy_config_new (void) +{ + return NM_PROXY_CONFIG (g_object_new (NM_TYPE_PROXY_CONFIG, NULL)); +} + +static void +finalize (GObject *object) +{ + NMProxyConfig *self = NM_PROXY_CONFIG (object); + NMProxyConfigPrivate *priv = NM_PROXY_CONFIG_GET_PRIVATE (self); + + g_free (priv->pac_url); + g_free (priv->pac_script); + + G_OBJECT_CLASS (nm_proxy_config_parent_class)->finalize (object); +} + +static void +nm_proxy_config_class_init (NMProxyConfigClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = finalize; +} diff --git a/src/nm-proxy-config.h b/src/nm-proxy-config.h new file mode 100644 index 0000000000..2712e43fba --- /dev/null +++ b/src/nm-proxy-config.h @@ -0,0 +1,57 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * (C) Copyright 2016 Atul Anand <atulhjp@gmail.com>. + */ + +#ifndef __NETWORKMANAGER_PROXY_CONFIG_H__ +#define __NETWORKMANAGER_PROXY_CONFIG_H__ + +#include "nm-setting-proxy.h" + +typedef enum { + NM_PROXY_CONFIG_METHOD_AUTO = 0, + NM_PROXY_CONFIG_METHOD_NONE +} NMProxyConfigMethod; + +#define NM_TYPE_PROXY_CONFIG (nm_proxy_config_get_type ()) +#define NM_PROXY_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_PROXY_CONFIG, NMProxyConfig)) +#define NM_PROXY_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_PROXY_CONFIG, NMProxyConfigClass)) +#define NM_IS_PROXY_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_PROXY_CONFIG)) +#define NM_IS_PROXY_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_PROXY_CONFIG)) +#define NM_PROXY_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_PROXY_CONFIG, NMProxyConfigClass)) + +typedef struct _NMProxyConfigClass NMProxyConfigClass; + +GType nm_proxy_config_get_type (void); + +NMProxyConfig * nm_proxy_config_new (void); + +void nm_proxy_config_set_method (NMProxyConfig *config, NMProxyConfigMethod method); +NMProxyConfigMethod nm_proxy_config_get_method (const NMProxyConfig *config); + +void nm_proxy_config_merge_setting (NMProxyConfig *config, NMSettingProxy *setting); + +gboolean nm_proxy_config_get_browser_only (const NMProxyConfig *config); + +void nm_proxy_config_set_pac_url (NMProxyConfig *config, const char *url); +const char * nm_proxy_config_get_pac_url (const NMProxyConfig *config); + +void nm_proxy_config_set_pac_script (NMProxyConfig *config, const char *script); +const char * nm_proxy_config_get_pac_script (const NMProxyConfig *config); + +#endif /* __NETWORKMANAGER_PROXY_CONFIG_H__ */ diff --git a/src/nm-types.h b/src/nm-types.h index 8d8c02af61..45c9284f3f 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -42,11 +42,13 @@ typedef struct _NMDefaultRouteManager NMDefaultRouteManager; typedef struct _NMDevice NMDevice; typedef struct _NMDhcp4Config NMDhcp4Config; typedef struct _NMDhcp6Config NMDhcp6Config; +typedef struct _NMProxyConfig NMProxyConfig; typedef struct _NMIP4Config NMIP4Config; typedef struct _NMIP6Config NMIP6Config; typedef struct _NMManager NMManager; typedef struct _NMPolicy NMPolicy; typedef struct _NMRfkillManager NMRfkillManager; +typedef struct _NMPacrunnerManager NMPacrunnerManager; typedef struct _NMRouteManager NMRouteManager; typedef struct _NMSessionMonitor NMSessionMonitor; typedef struct _NMSleepMonitor NMSleepMonitor; diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 06d261af86..3f2e38c3a6 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -57,6 +57,7 @@ #include "nm-setting-adsl.h" #include "nm-setting-wireless.h" #include "nm-setting-wireless-security.h" +#include "nm-setting-proxy.h" #include "nm-setting-bond.h" #include "nm-utils.h" #include "nm-core-internal.h" diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c index 80c6ca1553..bf15d32d29 100644 --- a/src/settings/plugins/ifcfg-rh/reader.c +++ b/src/settings/plugins/ifcfg-rh/reader.c @@ -48,6 +48,7 @@ #include "nm-setting-bridge.h" #include "nm-setting-bridge-port.h" #include "nm-setting-dcb.h" +#include "nm-setting-proxy.h" #include "nm-setting-generic.h" #include "nm-core-internal.h" #include "nm-utils.h" @@ -899,6 +900,62 @@ error: return success; } +static NMSetting * +make_proxy_setting (shvarFile *ifcfg, GError **error) +{ + NMSettingProxy *s_proxy = NULL; + char *value = NULL; + NMSettingProxyMethod method; + + value = svGetValue (ifcfg, "PROXY_METHOD", FALSE); + if (!value) + return NULL; + + if (!g_ascii_strcasecmp (value, "auto")) + method = NM_SETTING_PROXY_METHOD_AUTO; + else + method = NM_SETTING_PROXY_METHOD_NONE; + g_free (value); + + s_proxy = (NMSettingProxy *) nm_setting_proxy_new (); + + switch (method) { + case NM_SETTING_PROXY_METHOD_AUTO: + g_object_set (s_proxy, + NM_SETTING_PROXY_METHOD, NM_SETTING_PROXY_METHOD_AUTO, + NULL); + + value = svGetValue (ifcfg, "PAC_URL", FALSE); + if (value) { + value = g_strstrip (value); + g_object_set (s_proxy, NM_SETTING_PROXY_PAC_URL, value, NULL); + g_free (value); + } + + value = svGetValue (ifcfg, "PAC_SCRIPT", FALSE); + if (value) { + value = g_strstrip (value); + g_object_set (s_proxy, NM_SETTING_PROXY_PAC_SCRIPT, value, NULL); + g_free (value); + } + + break; + case NM_SETTING_PROXY_METHOD_NONE: + g_object_set (s_proxy, + NM_SETTING_PROXY_METHOD, NM_SETTING_PROXY_METHOD_NONE, + NULL); + } + + value = svGetValue (ifcfg, "BROWSER_ONLY", FALSE); + if (value) { + if (!g_ascii_strcasecmp (value, "yes")) { + g_object_set (s_proxy, NM_SETTING_PROXY_BROWSER_ONLY, TRUE, NULL); + g_free (value); + } + } + + return NM_SETTING (s_proxy); +} static NMSetting * make_ip4_setting (shvarFile *ifcfg, @@ -4962,7 +5019,7 @@ connection_from_file_full (const char *filename, shvarFile *parsed; gs_free char *type = NULL; char *devtype, *bootproto; - NMSetting *s_ip4, *s_ip6, *s_port, *s_dcb = NULL; + NMSetting *s_ip4, *s_ip6, *s_proxy, *s_port, *s_dcb = NULL; const char *ifcfg_name = NULL; g_return_val_if_fail (filename != NULL, NULL); @@ -5179,6 +5236,10 @@ connection_from_file_full (const char *filename, */ check_dns_search_domains (parsed, s_ip4, s_ip6); + s_proxy = make_proxy_setting (parsed, error); + if (s_proxy) + nm_connection_add_setting (connection, s_proxy); + /* Bridge port? */ s_port = make_bridge_port_setting (parsed); if (s_port) diff --git a/src/settings/plugins/ifcfg-rh/writer.c b/src/settings/plugins/ifcfg-rh/writer.c index dcc48f2acc..383337c77f 100644 --- a/src/settings/plugins/ifcfg-rh/writer.c +++ b/src/settings/plugins/ifcfg-rh/writer.c @@ -36,6 +36,7 @@ #include "nm-setting-wired.h" #include "nm-setting-wireless.h" #include "nm-setting-8021x.h" +#include "nm-setting-proxy.h" #include "nm-setting-ip4-config.h" #include "nm-setting-ip6-config.h" #include "nm-setting-pppoe.h" @@ -1998,6 +1999,50 @@ error: } static gboolean +write_proxy_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) +{ + NMSettingProxy *s_proxy; + NMSettingProxyMethod method; + const char *pac_url, *pac_script; + gboolean browser_only; + + s_proxy = nm_connection_get_setting_proxy (connection); + if (!s_proxy) + return TRUE; + + svSetValue (ifcfg, "BROWSER_ONLY", NULL, FALSE); + svSetValue (ifcfg, "PAC_URL", NULL, FALSE); + svSetValue (ifcfg, "PAC_SCRIPT", NULL, FALSE); + + method = nm_setting_proxy_get_method (s_proxy); + switch (method) { + case NM_SETTING_PROXY_METHOD_AUTO: + svSetValue (ifcfg, "PROXY_METHOD", "auto", FALSE); + + pac_url = nm_setting_proxy_get_pac_url (s_proxy); + if (pac_url) + svSetValue (ifcfg, "PAC_URL", pac_url, FALSE); + + pac_script = nm_setting_proxy_get_pac_script (s_proxy); + if (pac_script) + svSetValue (ifcfg, "PAC_SCRIPT", pac_script, FALSE); + + break; + case NM_SETTING_PROXY_METHOD_NONE: + svSetValue (ifcfg, "PROXY_METHOD", "none", FALSE); + /* Write nothing more */ + } + + browser_only = nm_setting_proxy_get_browser_only (s_proxy); + if (browser_only) + svSetValue (ifcfg, "BROWSER_ONLY", "yes", FALSE); + else + svSetValue (ifcfg, "BROWSER_ONLY", "no", FALSE); + + return TRUE; +} + +static gboolean write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) { NMSettingIPConfig *s_ip4; @@ -2887,6 +2932,9 @@ write_connection (NMConnection *connection, if (!write_dcb_setting (connection, ifcfg, error)) goto out; + if (!write_proxy_setting (connection, ifcfg, error)) + goto out; + svSetValue (ifcfg, "DHCP_HOSTNAME", NULL, FALSE); svSetValue (ifcfg, "DHCP_FQDN", NULL, FALSE); diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index 6e10576efe..fbdd77e993 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -32,6 +32,7 @@ #include <unistd.h> #include <syslog.h> +#include "nm-proxy-config.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" #include "nm-platform.h" @@ -41,6 +42,7 @@ #include "nm-dispatcher.h" #include "nm-agent-manager.h" #include "nm-core-internal.h" +#include "nm-pacrunner-manager.h" #include "nm-default-route-manager.h" #include "nm-route-manager.h" #include "nm-firewall-manager.h" @@ -124,6 +126,7 @@ typedef struct { GCancellable *cancellable; GVariant *connect_hash; guint connect_timeout; + NMProxyConfig *proxy_config; gboolean has_ip4; NMIP4Config *ip4_config; guint32 ip4_internal_gw; @@ -537,6 +540,7 @@ _set_vpn_state (NMVpnConnection *self, _get_applied_connection (self), parent_dev, priv->ip_iface, + priv->proxy_config, priv->ip4_config, priv->ip6_config, dispatcher_pre_up_done, @@ -556,11 +560,20 @@ _set_vpn_state (NMVpnConnection *self, _get_applied_connection (self), parent_dev, priv->ip_iface, + priv->proxy_config, priv->ip4_config, priv->ip6_config, NULL, NULL, NULL); + + if (priv->proxy_config) { + nm_pacrunner_manager_send (nm_pacrunner_manager_get (), + priv->ip_iface, + priv->proxy_config, + priv->ip4_config, + priv->ip6_config); + } break; case STATE_DEACTIVATING: if (quitting) { @@ -569,6 +582,7 @@ _set_vpn_state (NMVpnConnection *self, _get_applied_connection (self), parent_dev, priv->ip_iface, + priv->proxy_config, priv->ip4_config, priv->ip6_config); } else { @@ -577,6 +591,7 @@ _set_vpn_state (NMVpnConnection *self, _get_applied_connection (self), parent_dev, priv->ip_iface, + priv->proxy_config, priv->ip4_config, priv->ip6_config, dispatcher_pre_down_done, @@ -586,6 +601,9 @@ _set_vpn_state (NMVpnConnection *self, dispatcher_pre_down_done (0, self); } } + + /* Remove config from PacRunner */ + nm_pacrunner_manager_remove (nm_pacrunner_manager_get(), priv->ip_iface); break; case STATE_FAILED: case STATE_DISCONNECTED: @@ -599,6 +617,7 @@ _set_vpn_state (NMVpnConnection *self, parent_dev, priv->ip_iface, NULL, + NULL, NULL); } else { nm_dispatcher_call_vpn (DISPATCHER_ACTION_VPN_DOWN, @@ -610,6 +629,7 @@ _set_vpn_state (NMVpnConnection *self, NULL, NULL, NULL, + NULL, NULL); } } @@ -1277,6 +1297,20 @@ process_generic_config (NMVpnConnection *self, GVariant *dict) _notify (self, PROP_BANNER); } + /* Proxy Config */ + g_clear_object (&priv->proxy_config); + priv->proxy_config = nm_proxy_config_new (); + + if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_PROXY_PAC, "&s", &str)) { + nm_proxy_config_set_method (priv->proxy_config, NM_PROXY_CONFIG_METHOD_AUTO); + nm_proxy_config_set_pac_url (priv->proxy_config, str); + } else + nm_proxy_config_set_method (priv->proxy_config, NM_PROXY_CONFIG_METHOD_NONE); + + /* User overrides if any from the NMConnection's Proxy settings */ + nm_proxy_config_merge_setting (priv->proxy_config, + nm_connection_get_setting_proxy (_get_applied_connection (self))); + /* External world-visible address of the VPN server */ priv->ip4_external_gw = 0; g_clear_pointer (&priv->ip6_external_gw, g_free); @@ -2199,6 +2233,14 @@ nm_vpn_connection_get_banner (NMVpnConnection *self) return NM_VPN_CONNECTION_GET_PRIVATE (self)->banner; } +NMProxyConfig * +nm_vpn_connection_get_proxy_config (NMVpnConnection *self) +{ + g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), NULL); + + return NM_VPN_CONNECTION_GET_PRIVATE (self)->proxy_config; +} + NMIP4Config * nm_vpn_connection_get_ip4_config (NMVpnConnection *self) { @@ -2597,6 +2639,7 @@ dispose (GObject *object) g_cancellable_cancel (priv->cancellable); g_clear_object (&priv->cancellable); } + g_clear_object (&priv->proxy_config); nm_exported_object_clear_and_unexport (&priv->ip4_config); nm_exported_object_clear_and_unexport (&priv->ip6_config); g_clear_object (&priv->proxy); diff --git a/src/vpn-manager/nm-vpn-connection.h b/src/vpn-manager/nm-vpn-connection.h index 635ef33659..6037295e22 100644 --- a/src/vpn-manager/nm-vpn-connection.h +++ b/src/vpn-manager/nm-vpn-connection.h @@ -68,6 +68,8 @@ void nm_vpn_connection_disconnect (NMVpnConnection *self, NMVpnConnectionStateReason reason, gboolean quitting); +NMProxyConfig * nm_vpn_connection_get_proxy_config (NMVpnConnection *self); + NMIP4Config * nm_vpn_connection_get_ip4_config (NMVpnConnection *self); NMIP6Config * nm_vpn_connection_get_ip6_config (NMVpnConnection *self); const char * nm_vpn_connection_get_ip_iface (NMVpnConnection *self, gboolean fallback_device); |