[systemd-devel] [RFC 3/6] proxy-discoveryd: Add PAC support through duktape js engine
Tom Gundersen
teg at jklm.no
Fri Apr 10 06:20:18 PDT 2015
On Fri, Apr 10, 2015 at 2:17 PM, Tomasz Bursztyka
<tomasz.bursztyka at linux.intel.com> wrote:
> The proxy PAC file - basically a javascript file - will be executed through
> duktape js engine (duktape.org). For this to work, one will need to embed
> duktape.h/c files in src/proxy-discovery/.
>
> The current support is sub-optimal as it might generate context switches
> via ioctls or netlink calls. This will be fixed later on.
> ---
> Makefile.am | 7 ++
> src/proxy-discovery/proxy-discoveryd-pac.c | 185 +++++++++++++++++++++++++++++
> src/proxy-discovery/proxy-discoveryd.h | 13 ++
> 3 files changed, 205 insertions(+)
> create mode 100644 src/proxy-discovery/proxy-discoveryd-pac.c
>
> diff --git a/Makefile.am b/Makefile.am
> index 6e839b9..25ea0dd 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -5895,12 +5895,19 @@ rootlibexec_PROGRAMS += \
> systemd-proxy-discoveryd
>
> systemd_proxy_discoveryd_SOURCES = \
> + src/proxy-discovery/duktape.h \
> + src/proxy-discovery/duktape.c \
These files are not included in the patch, how do you intend to ship them?
> src/proxy-discovery/proxy-discoveryd.c \
> src/proxy-discovery/proxy-discoveryd.h \
> src/proxy-discovery/proxy-discoveryd-manager.c \
> + src/proxy-discovery/proxy-discoveryd-pac.c \
> src/proxy-discovery/proxy-discoveryd-proxy.c \
> src/proxy-discovery/proxy-discoveryd-proxy-gperf.c
>
> +systemd_proxy_discoveryd_CFLAGS = \
> + $(AM_CFLAGS) \
> + -fno-fast-math
Hm, what's this all about?
> +
> systemd_proxy_discoveryd_LDADD = \
> libsystemd-internal.la \
> libsystemd-shared.la
> diff --git a/src/proxy-discovery/proxy-discoveryd-pac.c b/src/proxy-discovery/proxy-discoveryd-pac.c
> new file mode 100644
> index 0000000..5c779bb
> --- /dev/null
> +++ b/src/proxy-discovery/proxy-discoveryd-pac.c
> @@ -0,0 +1,185 @@
> +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
> +
> +/***
> + This file is part of systemd.
> +
> + Copyright (C) 2015 Intel Corporation. All rights reserved.
> +
> + systemd 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.1 of the License, or
> + (at your option) any later version.
> +
> + systemd 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 systemd; If not, see <http://www.gnu.org/licenses/>.
> +***/
> +
> +#include "duktape.h"
> +
> +#include "proxy-discoveryd.h"
> +#include "local-addresses.h"
> +
> +#include <sys/types.h>
> +#include <sys/socket.h>
> +#include <netdb.h>
> +#include <net/if.h>
> +
> +struct PAC {
> + duk_context *ctx;
> +};
> +
> +static int get_addresses_from_interface(int ifindex, union in_addr_union *address) {
> + struct ifreq ifr = {};
> + int sk;
> +
> + sk = socket(AF_INET, SOCK_DGRAM, 0);
> + if (sk < 0)
> + return -1;
Never return 'made up' error values. In this case return -errno, for
internal code (where 'r' is used instead of errno) just return r.
> +
> + ifr.ifr_ifindex = ifindex;
> +
> + if (ioctl(sk, SIOCGIFNAME, &ifr) < 0 || ioctl(sk, SIOCGIFADDR, &ifr) < 0) {
> + close(sk);
> + return -1;
Same as above, return -errno. Also split this up into two:
r = ioctl(sk, SIOCGIFNAME, &ifr);
if (r < 0)
return -errno;
etc.
If you also use
_cleanup_close_ int sk = -1;
you don't have to worry about closing the socket.
> + }
> +
> + address->in = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
> +
> + close(sk);
> +
> + return 0;
> +}
The above function is fine as part of a prototype, but for the final
version we should use rtnl like everywhere else, no?
> +static int pac_dns_resolve(duk_context *ctx) {
> + _cleanup_free_ char *address = NULL;
> + struct addrinfo hints = {};
> + struct addrinfo *res, *addr;
> + const char *hostname;
> + int r;
> +
> + hostname = duk_require_string(ctx, 0);
> +
> + hints.ai_family = AF_INET;
> +
> + r = getaddrinfo(hostname, NULL, &hints, &res);
> + if (r != 0)
> + return 0;
> +
> + for (addr = res; addr; addr = addr->ai_next) {
> + union in_addr_union a;
> +
> + if (addr->ai_family != AF_INET ||
> + addr->ai_addrlen != sizeof(struct sockaddr_in))
> + continue;
> +
> + a.in = ((struct sockaddr_in *) addr->ai_addr)->sin_addr;
> + in_addr_to_string(AF_INET, &a, &address);
> +
> + break;
> + }
> +
> + freeaddrinfo(res);
> +
> + duk_push_string(ctx, address);
> +
> + return 1;
> +}
> +
> +static int pac_my_ip_address(duk_context *ctx) {
> + _cleanup_free_ struct local_address *gateways = NULL;
> + _cleanup_free_ char *address = NULL;
> + union in_addr_union addr;
> + int r;
> +
> + r = local_gateways(NULL, 0, AF_INET, &gateways);
> + if (r <= 0)
> + return 0;
> +
> + r = get_addresses_from_interface(gateways->ifindex, &addr);
> + if (r < 0)
> + return 0;
> +
> + in_addr_to_string(AF_INET, &addr, &address);
> +
> + duk_push_string(ctx, address);
> +
> + return 1;
> +}
> +
> +static int create_context(struct PAC *pac, char *pac_file, void *user_data) {
> + duk_context *ctx;
> +
> + ctx = duk_create_heap(NULL, NULL, NULL, NULL, NULL);
> + if (!ctx)
> + return -ENOMEM;
> +
> + duk_push_global_object(ctx);
> + duk_push_c_function(ctx, pac_dns_resolve, 1);
> + duk_put_prop_string(ctx, -2, "dnsResolve");
> + duk_push_c_function(ctx, pac_my_ip_address, 0);
> + duk_put_prop_string(ctx, -2, "myIpAddress");
> +
> + duk_push_pointer(ctx, user_data);
> + duk_put_prop_string(ctx, -2, "_user_data_");
> +
> + duk_pop(ctx);
> +
> + if (duk_peval_file(ctx, pac_file) != 0) {
> + duk_destroy_heap(ctx);
> + return -EINVAL;
> + }
> +
> + pac->ctx = ctx;
> +
> + return 0;
> +}
> +
> +int pac_load(Proxy *proxy, struct PAC **ret) {
> + _cleanup_pac_free_ struct PAC *pac = NULL;
> + int r;
> +
> + assert(proxy);
> + assert(ret);
> +
> + pac = new0(struct PAC, 1);
> + if (!pac)
> + return -ENOMEM;
> +
> + r = create_context(pac, proxy->pac_path, proxy);
> + if (r < 0)
> + return r;
> +
> + *ret = pac;
> + pac = NULL;
> +
> + return 0;
> +}
> +
> +void pac_free(struct PAC *pac) {
> + if (pac->ctx)
> + duk_destroy_heap(pac->ctx);
> +
> + free(pac);
> +}
> +
> +int pac_execute(struct PAC *pac, const char *url, const char *host, char **ret) {
> + duk_push_global_object(pac->ctx);
> + duk_get_prop_string(pac->ctx, -1, "FindProxyForURL");
> + duk_push_string(pac->ctx, url);
> + duk_push_string(pac->ctx, host);
> +
> + if (duk_pcall(pac->ctx, 2) != DUK_EXEC_SUCCESS)
> + return -1;
Return real error value, not -1.
> +
> + *ret = strdup(duk_to_string(pac->ctx, -1));
> +
> + duk_pop(pac->ctx);
> + duk_pop(pac->ctx);
> +
> + return 0;
> +}
> diff --git a/src/proxy-discovery/proxy-discoveryd.h b/src/proxy-discovery/proxy-discoveryd.h
> index f51fca5..17c5378 100644
> --- a/src/proxy-discovery/proxy-discoveryd.h
> +++ b/src/proxy-discovery/proxy-discoveryd.h
> @@ -35,10 +35,13 @@ struct Manager {
> LIST_HEAD(Proxy, default_proxies);
> };
>
> +struct PAC;
> +
> struct Proxy {
> Manager *manager;
>
> char *pac_path;
> + struct PAC *pac;
>
> LIST_FIELDS(Proxy, proxy_next);
> };
> @@ -63,3 +66,13 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Proxy*, proxy_free);
> #define _cleanup_proxy_free_ _cleanup_(proxy_freep)
>
> const struct ConfigPerfItem* proxy_discoveryd_proxy_gperf_lookup(const char *key, unsigned length);
> +
> +/* PAC */
> +
> +int pac_load(Proxy *proxy, struct PAC **ret);
> +void pac_free(struct PAC *pac);
> +
> +int pac_execute(struct PAC *pac, const char *url, const char *host, char **ret);
> +
> +DEFINE_TRIVIAL_CLEANUP_FUNC(struct PAC*, pac_free);
> +#define _cleanup_pac_free_ _cleanup_(pac_freep)
> --
> 2.0.5
>
> _______________________________________________
> systemd-devel mailing list
> systemd-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel
More information about the systemd-devel
mailing list