[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