[systemd-devel] [RFC 3/6] proxy-discoveryd: Add PAC support through duktape js engine
Tomasz Bursztyka
tomasz.bursztyka at linux.intel.com
Fri Apr 10 05:17:40 PDT 2015
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 \
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
+
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;
+
+ ifr.ifr_ifindex = ifindex;
+
+ if (ioctl(sk, SIOCGIFNAME, &ifr) < 0 || ioctl(sk, SIOCGIFADDR, &ifr) < 0) {
+ close(sk);
+ return -1;
+ }
+
+ address->in = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
+
+ close(sk);
+
+ return 0;
+}
+
+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;
+
+ *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
More information about the systemd-devel
mailing list