Commit 51cfddd2 authored by flypig's avatar flypig

[mdm] Add global proxy plugin. Contributes to JB#43758

1. Add dbus interface for activation and configuration
2. Integrate global proxy into pacrunner plugin
3. Handle config files for the global proxy
4. Add unit tests and docs
5. Use org.sailfishos.connman as dbus interface name
6. Avoid infinite cycle updating config from file
7. Ensure all memory is freed correctly.
parent 0e53004c
......@@ -295,7 +295,8 @@ endif
noinst_PROGRAMS += unit/test-access unit/test-ippool \
unit/test-sailfish_access unit/test-vpn-settings \
unit/test-sailfish_iptables_ext unit/test-service
unit/test-sailfish_iptables_ext unit/test-service \
unit/test-globalproxy
if TEST_COVERAGE
COVERAGE_OPT = --coverage
......@@ -356,9 +357,19 @@ unit_test_sailfish_iptables_ext_SOURCES = $(backtrace_sources) \
unit_test_sailfish_iptables_ext_LDADD = @GLIB_LIBS@ @XTABLES_LIBS@ \
@LIBIPTC_LIBS@ @DBUS_LIBS@ -ldl
unit_test_globalproxy_CFLAGS = -DDEFAULT_STORAGE_ROOT=\""$(storageroot)\"" \
$(COVERAGE_OPT) $(AM_CFLAGS) @DBUS_CFLAGS@ \
-DSTATEDIR=\""$(statedir)"\"
unit_test_globalproxy_SOURCES = unit/test-globalproxy.c \
$(backtrace_sources) \
src/connman.h src/log.c src/error.c \
src/inotify.c src/storage.c src/dbus.c
unit_test_globalproxy_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ -ldl
TESTS = unit/test-access unit/test-ippool \
unit/test-sailfish_access unit/test-vpn-settings \
unit/test-sailfish_iptables_ext unit/test-service
unit/test-sailfish_iptables_ext unit/test-service \
unit/test-globalproxy
if SAILFISH_WAKEUP_TIMER
unit_test_sailfish_wakeup_timer_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
......@@ -493,7 +504,7 @@ EXTRA_DIST += doc/overview-api.txt doc/behavior-api.txt \
doc/clock-api.txt doc/session-api.txt \
doc/session-overview.txt doc/backtrace.txt \
doc/advanced-configuration.txt \
doc/vpn-config-format.txt \
doc/vpn-config-format.txt doc/globalproxy-api.txt\
doc/vpn-connection-api.txt \
doc/vpn-manager-api.txt doc/vpn-overview.txt \
doc/session-policy-format.txt \
......
......@@ -302,3 +302,9 @@ if POLKIT
$(AM_V_GEN)cp $< $@
endif
endif
if GLOBALPROXY
builtin_modules += globalproxy
builtin_sources += plugins/globalproxy.c
src_connmand_CFLAGS += -DGLOBALPROXY_PLUGIN
endif
......@@ -471,6 +471,12 @@ if (test "${need_glibutil}" = "yes"); then
LIBS="$LIBS $GLIBUTIL_LIBS"
fi
AC_ARG_ENABLE(globalproxy, AC_HELP_STRING([--disable-globalproxy],
[disable global proxy support]),
[enable_globalproxy=${enableval}])
AM_CONDITIONAL(GLOBALPROXY, test "${enable_globalproxy}" != "no")
AC_ARG_ENABLE(test-coverage,
AC_HELP_STRING([--enable-test-coverage], [enable test code coverage]),
[enable_test_coverage=${enableval}], [enable_test_coverage="no"])
......
Global proxy
============
Service net.connman
Interface org.sailfishos.connman.GlobalProxy
Object path /
Methods dict GetProperty(string name)
Returns properties for the global proxy. The
properties are returned independent of whether
the global proxy is active or not.
See the properties section for possible properties.
Possible Errors: [service].Error.InvalidArguments
void SetProperty(string name, variant value)
Changes the value of the specified property. On
success a PropertyChanged signal will be emitted.
See the properties section for possible properties.
Possible Errors: [service].Error.InvalidArguments
[service].Error.InvalidProperty
Signals PropertyChanged(string name, variant value)
This signal indicates a changed value of the given
property.
Properties boolean Active [readwrite]
The active state of the global proxy. If set to true,
the global proxy values will be returned by the
globalproxy methods. Otherwise the service value
will be returned.
dict Configuration [readwrite]
The configuration of the global proxy.
string Method [readwrite]
Possible values are "direct", "auto" and
"manual".
In case of "auto" method, the URL file can be
provided unless you want to let DHCP/WPAD
auto-discover to be tried. In such case if DHCP
and WPAD auto-discover methods fails then
method will be "direct".
In case of "direct" no additional information
are provided. For the "manual" method the
Servers have to be set, Excludes is optional.
string URL [readwrite]
Automatic proxy configuration URL. Used by
"auto" method.
array{string} Servers [readwrite]
Used when "manual" method is set.
List of proxy URIs. The URI without a protocol
will be interpreted as the generic proxy URI.
All others will target a specific protocol and
only once.
Example for generic proxy server entry would
be like this: "server.example.com:911".
array{string} Excludes [readwrite]
Used when "manual" method is set.
List of hosts which can be accessed directly.
Connman configuration file format for global proxy
**************************************************
The persistent state of the global proxy is retained in the global proxy
configuration file. This is expected to have the filename
STORAGEDIR/global_proxy/settings. STORAGEDIR by default points to
/var/lib/connman/.
For general information about how connman configuration files are structured,
please refer to config-format.txt.
If the configuration file is changed, connman will update the global proxy
settings to reflect the values stored in the file. Contrariwise if the global
proxy configuration is changed (e.g. in response to a dbus call) the file
will be updated to reflect the new configuration.
The format of the global proxy configuration file mirrors the fields used in
configuration files for services related to proxy configuration. The format of
the file can be summarised as follows (with a more detailed explanation below).
[global proxy]
Active = <true|false>
Proxy.Method = <direct|manual|auto>
Proxy.Servers = <url;...>
Proxy.Excludes = <domain;...>
Proxy.URL = <url>
Global proxy section [global proxy]
===================================
This is currently the only section in a global proxy configuration file.
Allowed fields:
- Active: This field can take a value of "true" or "false". Each service can
have its own individual proxy settings, but if the global proxy is active, it
will override the proxy configurations of the individual services.
- Proxy.Method: This field represents the type of proxy to use. It takes one
of the values "direct", "manual" or "auto". When the method is "direct", no
proxy will be used and requests will be passed directly to their destination.
When the method is "manual" a "Proxy.Servers" field must be provided listing
the proxies to use for requests; an optional "Proxy.Excludes" field may also
be included in this case. When the method is "auto" a "Proxy.URL" field must
be included to identify the location of a pac file that will be downloaded and
queried in order to determine the appropriate proxy to use.
- Proxy.Servers: A semicolon-separated list of servers to use as proxies. Each
server should include a transport prefix (e.g. "https://") and a port number
postfix (e.g. :8080). This field is required if the method is set to "manual",
otherwise it's optional.
- Proxy.Excludes: A semicolon-separated list of domains which are to be
contacted directly (i.e. without first going via the proxy). This field
applies in the case the method is set to "manual", and is optional.
- Proxy.URL: A URL pointing to a pac file to query in order to establish the
appropriate proxy to use. This field is required if the method is set to
"auto", otherwise it's optional.
Examples
========
The following file will override any service-specific proxy settings, so that
no proxy is used.
[global proxy]
Active = true
Proxy.Method = direct
The following file will override any service-specific proxy settings, so that
either https://jolla.com, or http://mer.org will be used as a proxy. No proxy
will be used for requests to the sailfishos.org domain.
[global proxy]
Active = true
Proxy.Method = direct
Proxy.Servers = https://jolla.com;http://mer.org;
Proxy.Excludes = sailfishos.org
The following file will override any service-specific proxy settings. The pac
file located at https://jolla.com/example.pac will be used to determine the
proxy to use for each request.
[global proxy]
Active = true
Proxy.Method = auto
Proxy.URL = https://jolla.com/example.pac
The following file configures the global proxy, but does not active it.
[global proxy]
Active = false
Proxy.Method = manual
Proxy.Servers = https://jolla.com;http://mer.org;
Proxy.Excludes = jolla.com;mer.org;
This diff is collapsed.
/*
* Connection Manager
*
* Copyright (C) 2018 Jolla Ltd. All rights reserved.
* Contact: David Llewellyn-Jones <david.llewellyn-jones@jolla.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*/
#ifndef __CONNMAN_GLOBALPROXY_H
#define __CONNMAN_GLOBALPROXY_H
#include <stdbool.h>
#include <connman/service.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* SECTION:globalproxy
* @title: globalproxy premitives
* @short_description: Functions for handling global proxy settings
*/
#define GLOBALPROXY_CONNMAN_INTERFACE "org.sailfishos.connman.GlobalProxy"
#define GLOBALPROXY_DBUS_PATH "/"
#define GLOBAL_PROXY_NOTIFIER_PRIORITY_LOW (-100)
#define GLOBAL_PROXY_NOTIFIER_PRIORITY_DEFAULT (0)
#define GLOBAL_PROXY_NOTIFIER_PRIORITY_HIGH (100)
struct global_proxy_notifier {
const char *name;
int priority;
void (*active_changed) (bool enabled);
void (*config_changed) ();
void (*proxy_changed) ();
/* Placeholders for future extensions */
//void (*_reserved[10])(void);
/* api_level will remain zero (and ignored) until we run out of
* the above placeholders. Hopefully, forever. */
//int api_level;
};
// Externally exposed functions
gboolean global_proxy_get_active();
enum connman_service_proxy_method global_proxy_get_proxy_method();
char **global_proxy_get_proxy_servers();
char **global_proxy_get_proxy_excludes();
const char *global_proxy_get_proxy_url();
const char *global_proxy_get_proxy_autoconfig();
// Functions for registering notification modules
int global_proxy_notifier_register(struct global_proxy_notifier *notifier);
void global_proxy_notifier_unregister(struct global_proxy_notifier *notifier);
// Functions for use with pacrunner plugin, which return service or
// global proxy settings depending on whether the global proxy is
// active or not
enum connman_service_proxy_method service_or_global_proxy_get_proxy_method(struct connman_service *service);
char **service_or_global_proxy_get_proxy_servers(struct connman_service *service);
char **service_or_global_proxy_get_proxy_excludes(struct connman_service *service);
const char *service_or_global_proxy_get_proxy_url(struct connman_service *service);
const char *service_or_global_proxy_get_proxy_autoconfig(struct connman_service *service);
// Functions which return null if the global proxy is active, or the
// service value otherwise. The original service functions aren't
// specifically proxy-related functions.
char *service_or_global_proxy_get_interface(struct connman_service *service);
const char *service_or_global_proxy_get_domainname(struct connman_service *service);
char **service_or_global_get_nameservers(struct connman_service *service);
#ifdef __cplusplus
}
#endif
#endif /* __CONNMAN_GLOBALPROXY_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/
......@@ -44,6 +44,28 @@
#define DBUS_TIMEOUT 5000
#ifdef GLOBALPROXY_PLUGIN
#include "globalproxy.h"
#define GET_PROXY_METHOD service_or_global_proxy_get_proxy_method
#define GET_PROXY_SERVERS service_or_global_proxy_get_proxy_servers
#define GET_PROXY_EXCLUDES service_or_global_proxy_get_proxy_excludes
#define GET_PROXY_URL service_or_global_proxy_get_proxy_url
#define GET_PROXY_AUTOCONFIG service_or_global_proxy_get_proxy_autoconfig
#define GET_PROXY_SERVICE_INTERFACE service_or_global_proxy_get_interface
#define GET_PROXY_DOMAINNAME service_or_global_proxy_get_domainname
#define GET_PROXY_NAMESERVERS service_or_global_get_nameservers
#else
#define GET_PROXY_METHOD connman_service_get_proxy_method
#define GET_PROXY_SERVERS connman_service_get_proxy_servers
#define GET_PROXY_EXCLUDES connman_service_get_proxy_excludes
#define GET_PROXY_URL connman_service_get_proxy_url
#define GET_PROXY_AUTOCONFIG connman_service_get_proxy_autoconfig
#define GET_PROXY_SERVICE_INTERFACE connman_service_get_interface
#define GET_PROXY_DOMAINNAME connman_service_get_domainname
#define GET_PROXY_NAMESERVERS connman_service_get_nameservers
#endif
struct proxy_data {
struct connman_service *service;
char *url;
......@@ -119,7 +141,7 @@ static void create_proxy_configuration(void)
dbus_message_iter_init_append(msg, &iter);
connman_dbus_dict_open(&iter, &dict);
switch(connman_service_get_proxy_method(default_service)) {
switch(GET_PROXY_METHOD(default_service)) {
case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
connman_dbus_dict_close(&iter, &dict);
goto done;
......@@ -129,7 +151,7 @@ static void create_proxy_configuration(void)
case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
method = "manual";
str_list = connman_service_get_proxy_servers(default_service);
str_list = GET_PROXY_SERVERS(default_service);
if (!str_list) {
connman_dbus_dict_close(&iter, &dict);
goto done;
......@@ -140,7 +162,7 @@ static void create_proxy_configuration(void)
str_list);
g_strfreev(str_list);
str_list = connman_service_get_proxy_excludes(default_service);
str_list = GET_PROXY_EXCLUDES(default_service);
if (!str_list)
break;
......@@ -153,9 +175,9 @@ static void create_proxy_configuration(void)
case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
method = "auto";
str = connman_service_get_proxy_url(default_service);
str = GET_PROXY_URL(default_service);
if (!str) {
str = connman_service_get_proxy_autoconfig(
str = GET_PROXY_AUTOCONFIG(
default_service);
if (!str) {
connman_dbus_dict_close(&iter, &dict);
......@@ -171,19 +193,19 @@ static void create_proxy_configuration(void)
connman_dbus_dict_append_basic(&dict, "Method",
DBUS_TYPE_STRING, &method);
interface = connman_service_get_interface(default_service);
interface = GET_PROXY_SERVICE_INTERFACE(default_service);
if (interface) {
connman_dbus_dict_append_basic(&dict, "Interface",
DBUS_TYPE_STRING, &interface);
g_free(interface);
}
str = connman_service_get_domainname(default_service);
str = GET_PROXY_DOMAINNAME(default_service);
if (str)
connman_dbus_dict_append_array(&dict, "Domains",
DBUS_TYPE_STRING, append_string, &str);
str_list = connman_service_get_nameservers(default_service);
str_list = GET_PROXY_NAMESERVERS(default_service);
if (str_list)
connman_dbus_dict_append_array(&dict, "Nameservers",
DBUS_TYPE_STRING, append_string_list,
......@@ -293,6 +315,25 @@ static struct connman_notifier pacrunner_notifier = {
.proxy_changed = proxy_changed,
};
#ifdef GLOBALPROXY_PLUGIN
static void global_proxy_changed()
{
DBG("Global proxy changed");
if (!daemon_running)
return;
destroy_proxy_configuration();
create_proxy_configuration();
}
static struct global_proxy_notifier pacrunner_global_proxy_notifier = {
.name = "pacrunner",
.proxy_changed = global_proxy_changed,
};
#endif
static void pacrunner_connect(DBusConnection *conn, void *user_data)
{
DBG("");
......@@ -457,11 +498,19 @@ static int pacrunner_init(void)
connman_proxy_driver_register(&pacrunner_proxy);
#ifdef GLOBALPROXY_PLUGIN
global_proxy_notifier_register(&pacrunner_global_proxy_notifier);
#endif
return 0;
}
static void pacrunner_exit(void)
{
#ifdef GLOBALPROXY_PLUGIN
global_proxy_notifier_unregister(&pacrunner_global_proxy_notifier);
#endif
connman_proxy_driver_unregister(&pacrunner_proxy);
connman_notifier_unregister(&pacrunner_notifier);
......
......@@ -3409,11 +3409,17 @@ enum connman_service_proxy_method connman_service_get_proxy_method(
char **connman_service_get_proxy_servers(struct connman_service *service)
{
if (!service)
return NULL;
return g_strdupv(service->proxies);
}
char **connman_service_get_proxy_excludes(struct connman_service *service)
{
if (!service)
return NULL;
return g_strdupv(service->excludes);
}
......
This diff is collapsed.
......@@ -126,6 +126,7 @@ Documentation for connman.
--enable-sailfish-usb-tethering \
--enable-sailfish-wifi \
--enable-sailfish-access \
--enable-globalproxy \
--disable-gadget \
--with-systemdunitdir=/%{_lib}/systemd/system \
--enable-systemd \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment