summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2016-10-04 12:21:40 +0200
committerThomas Haller <thaller@redhat.com>2016-10-04 12:22:18 +0200
commit6e9abe3d88148b92978400c5155c48ec29372f2e (patch)
treee87d3a45169534a892aee74ba24ae2bbd4e505e9
parenta5a36d6dfe0b3b4c69d25fae8c70ee07093d3f7b (diff)
parent1f2a0dc70b3c3a225327c5470895c988ec981d21 (diff)
downloadNetworkManager-6e9abe3d88148b92978400c5155c48ec29372f2e.tar.gz
proxy: merge branch 'th/proxy'
https://mail.gnome.org/archives/networkmanager-list/2016-August/msg00072.html https://bugzilla.gnome.org/show_bug.cgi?id=772042
-rw-r--r--TODO59
-rw-r--r--callouts/nm-dispatcher-utils.c44
-rw-r--r--callouts/nm-dispatcher-utils.h2
-rw-r--r--callouts/nm-dispatcher.c6
-rw-r--r--callouts/tests/dispatcher-external6
-rw-r--r--callouts/tests/dispatcher-up6
-rw-r--r--callouts/tests/dispatcher-vpn-down6
-rw-r--r--callouts/tests/dispatcher-vpn-up6
-rw-r--r--callouts/tests/test-dispatcher-envp.c42
-rw-r--r--clients/cli/common.c76
-rw-r--r--clients/cli/common.h1
-rw-r--r--clients/cli/connections.c22
-rw-r--r--clients/cli/devices.c5
-rw-r--r--clients/cli/settings.c163
-rw-r--r--clients/cli/settings.h2
-rw-r--r--libnm-core/Makefile.libnm-core2
-rw-r--r--libnm-core/nm-connection.c18
-rw-r--r--libnm-core/nm-connection.h2
-rw-r--r--libnm-core/nm-core-internal.h1
-rw-r--r--libnm-core/nm-core-types.h1
-rw-r--r--libnm-core/nm-setting-proxy.c330
-rw-r--r--libnm-core/nm-setting-proxy.h88
-rw-r--r--libnm-core/nm-vpn-dbus-interface.h3
-rw-r--r--libnm/NetworkManager.h1
-rw-r--r--libnm/libnm.ver8
-rw-r--r--man/nmcli.xml13
-rw-r--r--po/POTFILES.in1
-rw-r--r--src/Makefile.am9
-rw-r--r--src/devices/nm-device.c73
-rw-r--r--src/devices/nm-device.h3
-rw-r--r--src/nm-dispatcher.c70
-rw-r--r--src/nm-dispatcher.h2
-rw-r--r--src/nm-logging.c3
-rw-r--r--src/nm-logging.h1
-rw-r--r--src/nm-pacrunner-manager.c474
-rw-r--r--src/nm-pacrunner-manager.h45
-rw-r--r--src/nm-proxy-config.c187
-rw-r--r--src/nm-proxy-config.h57
-rw-r--r--src/nm-types.h2
-rw-r--r--src/settings/nm-settings.c1
-rw-r--r--src/settings/plugins/ifcfg-rh/reader.c63
-rw-r--r--src/settings/plugins/ifcfg-rh/writer.c48
-rw-r--r--src/vpn-manager/nm-vpn-connection.c43
-rw-r--r--src/vpn-manager/nm-vpn-connection.h2
44 files changed, 1922 insertions, 75 deletions
diff --git a/TODO b/TODO
index 96dc81b797..86fef82be9 100644
--- a/TODO
+++ b/TODO
@@ -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);