summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornpmccallum <npmccallum@c587cffe-e639-0410-9787-d7902ae8ed56>2007-12-12 22:19:30 +0000
committernpmccallum <npmccallum@c587cffe-e639-0410-9787-d7902ae8ed56>2007-12-12 22:19:30 +0000
commit3ac1e5a02463e34caa72b2bd74b8e58dede02b2a (patch)
tree74c024ce21f085cb2c61d2d4b8547e57a44d3bc0
parent11188f6e7bb3cd89cab1b5f584071237ac832f12 (diff)
downloadlibproxy-git-3ac1e5a02463e34caa72b2bd74b8e58dede02b2a.tar.gz
reworked IP handling so that ignores could be implemented
-rw-r--r--src/lib/Makefile.am4
-rw-r--r--src/lib/dns.c2
-rw-r--r--src/lib/ip.c234
-rw-r--r--src/lib/ip.h95
-rw-r--r--src/lib/pac.c5
-rw-r--r--src/lib/proxy_factory.c225
-rw-r--r--src/lib/url.c123
-rw-r--r--src/lib/url.h14
-rw-r--r--src/plugins/mozjs.c54
-rw-r--r--src/plugins/networkmanager.c1
10 files changed, 367 insertions, 390 deletions
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 955007e..f320af6 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -1,6 +1,6 @@
lib_LTLIBRARIES = libproxy.la
-libproxy_la_SOURCES = misc.c ip.c url.c pac.c dhcp.c dns.c slp.c wpad.c proxy_factory.c config_file.c \
- misc.h ip.h url.h pac.h dhcp.h dns.h slp.h wpad.h proxy_factory.h proxy.h config_file.h
+libproxy_la_SOURCES = misc.c url.c pac.c dhcp.c dns.c slp.c wpad.c proxy_factory.c config_file.c \
+ misc.h url.h pac.h dhcp.h dns.h slp.h wpad.h proxy_factory.h proxy.h config_file.h
libproxy_la_CFLAGS = -Wall
libproxy_la_LDFLAGS = -lm
diff --git a/src/lib/dns.c b/src/lib/dns.c
index 9fb5d44..e7f13cb 100644
--- a/src/lib/dns.c
+++ b/src/lib/dns.c
@@ -20,6 +20,7 @@
#include <string.h>
#include <errno.h>
#include <stdio.h>
+#include <netdb.h>
#define __USE_BSD
#include <unistd.h>
@@ -78,6 +79,7 @@ get_domain_name()
hostname = px_malloc0((++i + 1) * 128);
// Lookup the hostname
+ // TODO: Make this whole process not suck
struct hostent *host_info = gethostbyname(hostname);
if (host_info)
{
diff --git a/src/lib/ip.c b/src/lib/ip.c
deleted file mode 100644
index 36d0c80..0000000
--- a/src/lib/ip.c
+++ /dev/null
@@ -1,234 +0,0 @@
-/*******************************************************************************
- * libproxy - A library for proxy configuration
- * Copyright (C) 2006 Nathaniel McCallum <nathaniel@natemccallum.com>
- *
- * 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 3 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
- ******************************************************************************/
-
-#include <stdint.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <netdb.h>
-#include <stdio.h>
-
-#include "misc.h"
-#include "ip.h"
-
-/**
- * pxIP object. All fields are private.
- */
-struct _IP {
- pxIPVersion version;
- int length;
- char data[16];
-};
-
-/**
- * Opens an IP connection to the IP address at the specified port and connection type.
- * @conntype The type of connection to create (TCP or UDP)
- * @port The port to connect to
- * @return The open socket from the connection
- */
-int
-px_ip_connect(pxIP *self, pxIPConnectionType conntype, int port)
-{
- struct sockaddr *dest_addr;
- int addr_len = 0, domain = 0;
-
- if (self->version == pxIPv4) // Create IPv4 dest_addr
- {
- struct sockaddr_in *tmp = px_malloc0(sizeof(struct sockaddr_in));
- tmp->sin_family = AF_INET;
- memcpy(&(tmp->sin_addr.s_addr), self->data, self->length);
- tmp->sin_port = htons(port);
- dest_addr = (struct sockaddr *) tmp;
- addr_len = sizeof(struct sockaddr_in);
- domain = PF_INET;
- }
- else if (self->version == pxIPv6) // Create IPv6 dest_addr
- {
- struct sockaddr_in6 *tmp = px_malloc0(sizeof(struct sockaddr_in6));
- tmp->sin6_family = AF_INET6;
- memcpy(&(tmp->sin6_addr.in6_u), self->data, self->length);
- tmp->sin6_port = htons(port);
- dest_addr = (struct sockaddr *) tmp;
- addr_len = sizeof(struct sockaddr_in6);
- domain = PF_INET6;
- }
- else
- return -1;
-
- // Create socket
- int sock = -1;
- if (conntype == TCP) sock = socket(domain, SOCK_STREAM, 0);
- else if (conntype == UDP) sock = socket(domain, SOCK_DGRAM, 0);
-
- // Make sure we have a valid socket
- if (sock < 0) { px_free(dest_addr); return sock; }
-
- // Connect
- if (connect(sock, dest_addr, addr_len))
- {
- close(sock);
- px_free(dest_addr);
- return -1;
- }
-
- px_free(dest_addr);
- return sock;
-}
-
-/**
- * Frees an pxIP object
- */
-void
-px_ip_free(pxIP *self)
-{
- px_free(self);
-}
-
-/**
- * Returns the version of the IP address (pxIPv4 or pxIPv6)
- * @return pxIPv4 or pxIPv6
- */
-pxIPVersion
-px_ip_get_version(pxIP *self)
-{
- return self->version;
-}
-
-/**
- * Creates a new pxIP from raw data.
- * @version The version of the IP address (pxIPv4 or pxIPv6)
- * @data The raw data to use (correct byte order is assumed)
- * @return New pxIP from the raw data
- */
-pxIP *
-px_ip_new_from_data(pxIPVersion version, char *data)
-{
- if (!data) return NULL;
-
- // Create the pxIP object
- pxIP *self = px_malloc0(sizeof(pxIP));
-
- // Set the version and length
- self->version = version;
- if (version == pxIPv4) self->length = 4;
- else if (version == pxIPv6) self->length = 16;
- else { px_free(self); return NULL; }
-
- // Copy the byte data
- memcpy(self->data, data, self->length);
- return self;
-}
-
-/**
- * Creates a new pxIP from a hostent struct
- * @host The hostent struct to use
- * @return The first pxIP from the hostent struct
- */
-pxIP *
-px_ip_new_from_hostent(const struct hostent *host)
-{
- if (!host) return NULL;
-
- if (host->h_addrtype == AF_INET)
- return px_ip_new_from_data(pxIPv4, host->h_addr);
- else if (host->h_addrtype == AF_INET6)
- return px_ip_new_from_data(pxIPv6, host->h_addr);
-
- return NULL;
-}
-
-/**
- * Creates all possible new pxIPs from a hostent struct
- * @host The hostent struct to use
- * @return NULL-terminated array of all possible pxIPs
- */
-pxIP **
-px_ip_new_from_hostent_all(const struct hostent *host)
-{
- int version, count;
- if (!host) return NULL;
-
- // Get the version
- if (host->h_addrtype == AF_INET) version = pxIPv4;
- else if (host->h_addrtype == AF_INET6) version = pxIPv6;
- else return NULL;
-
- // Count the total ip addresses
- for (count = 0 ; host->h_addr_list[count] ; count++);
-
- // Allocate
- pxIP **ips = px_malloc0(sizeof(pxIP *) * (count + 1));
-
- // Create
- for (count = 0 ; host->h_addr_list[count] ; count++)
- {
- ips[count] = px_ip_new_from_data(version, host->h_addr_list[count]);
- if (!ips[count]) goto error;
- }
-
- return ips;
-
- error:
- for (count = 0 ; host->h_addr_list[count] ; count++)
- px_free(ips[count]);
- px_free(ips);
- return NULL;
-}
-
-/**
- * Creates a string representation of the IP address.
- * @return Newly allocated string representing the IP address
- */
-char *
-px_ip_to_string(pxIP *self)
-{
- if (self->version != pxIPv4 && self->version != pxIPv6) return NULL;
-
- char *string = px_malloc0(40);
- if (self->version == pxIPv4)
- sprintf(string, "%hhu.%hhu.%hhu.%hhu", self->data[0],
- self->data[1],
- self->data[2],
- self->data[3]);
- else if (self->version == pxIPv6)
- sprintf(string, "%hhx%hhx:%hhx%hhx:%hhx%hhx:%hhx%hhx:%hhx%hhx:%hhx%hhx:%hhx%hhx:%hhx%hhx",
- self->data[0],
- self->data[1],
- self->data[2],
- self->data[3],
- self->data[4],
- self->data[5],
- self->data[6],
- self->data[7],
- self->data[8],
- self->data[9],
- self->data[10],
- self->data[11],
- self->data[12],
- self->data[13],
- self->data[14],
- self->data[15]);
-
- return string;
-}
-
-
diff --git a/src/lib/ip.h b/src/lib/ip.h
deleted file mode 100644
index 38c5cff..0000000
--- a/src/lib/ip.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*******************************************************************************
- * libproxy - A library for proxy configuration
- * Copyright (C) 2006 Nathaniel McCallum <nathaniel@natemccallum.com>
- *
- * 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 3 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
- ******************************************************************************/
-
-#ifndef IP_H_
-#define IP_H_
-
-#include <netdb.h> // For struct hostent
-
-/**
- * Version of the pxIP protocol to use
- */
-enum _pxIPVersion {
- pxIPv4 = 4,
- pxIPv6 = 6,
-};
-typedef enum _pxIPVersion pxIPVersion;
-
-/**
- * Types of pxIP connections
- */
-enum _pxIPConnectionType {
- TCP = 0,
- UDP = 1,
-};
-typedef enum _pxIPConnectionType pxIPConnectionType;
-
-/**
- * pxIP object. All fields are private.
- */
-typedef struct _IP pxIP;
-
-/**
- * Opens an IP connection to the IP address at the specified port and connection type.
- * @conntype The type of connection to create (TCP or UDP)
- * @port The port to connect to
- * @return The open socket from the connection
- */
-int px_ip_connect(pxIP *self, pxIPConnectionType conntype, int port);
-
-/**
- * Frees an pxIP object
- */
-void px_ip_free(pxIP *self);
-
-/**
- * Returns the version of the IP address (pxIPv4 or pxIPv6)
- * @return pxIPv4 or pxIPv6
- */
-pxIPVersion px_ip_get_version(pxIP *self);
-
-/**
- * Creates a new pxIP from raw data.
- * @version The version of the IP address (pxIPv4 or pxIPv6)
- * @data The raw data to use (correct byte order is assumed)
- * @return New pxIP from the raw data
- */
-pxIP *px_ip_new_from_data(pxIPVersion version, char *data);
-
-/**
- * Creates a new pxIP from a hostent struct
- * @host The hostent struct to use
- * @return The first pxIP from the hostent struct
- */
-pxIP *px_ip_new_from_hostent(const struct hostent *host);
-
-/**
- * Creates all possible new pxIPs from a hostent struct
- * @host The hostent struct to use
- * @return NULL-terminated array of all possible pxIPs
- */
-pxIP **px_ip_new_from_hostent_all(const struct hostent *host);
-
-/**
- * Creates a string representation of the IP address.
- * @return Newly allocated string representing the IP address
- */
-char *px_ip_to_string(pxIP *self);
-
-#endif /*IP_H_*/
diff --git a/src/lib/pac.c b/src/lib/pac.c
index a5983bb..8bef64f 100644
--- a/src/lib/pac.c
+++ b/src/lib/pac.c
@@ -19,6 +19,9 @@
#include <unistd.h>
#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
#include "url.h"
#include "misc.h"
@@ -122,7 +125,7 @@ px_pac_reload(pxPAC *self)
unsigned long int content_length = 0;
// Get the pxPAC
- sock = px_url_open(self->url, headers);
+ sock = px_url_get(self->url, headers);
if (sock < 0) return false;
// Verify status line
diff --git a/src/lib/proxy_factory.c b/src/lib/proxy_factory.c
index 993b49d..8304661 100644
--- a/src/lib/proxy_factory.c
+++ b/src/lib/proxy_factory.c
@@ -25,6 +25,9 @@
#include <stdio.h>
#include <dlfcn.h>
#include <math.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
#include "misc.h"
#include "proxy_factory.h"
@@ -90,23 +93,202 @@ _format_pac_response(char *response)
return chain;
}
-static int
-_ignore (pxURL *url, char *ignore)
+static inline bool
+_endswith(char *string, char *suffix)
{
- // Look at envvar ignores (man wget), gnome, kde, firefox, mac osx, windows
- // Want to support:
- // IP -- 192.168.4.27 (glob?) including IPv6
- // Netmask -- 192.168.4.0/24 OR 255.255.255.0
- // hostname: -- xyz.cypress.com - exact match
- // -- .cypress.com - ends with
- // -- *.cypress.com - glob
- // URL -- http://www.google.com/bunnies/ - basically a starts with
- // -- http://www.google.com/bunnies* - globs, would match /bunnies_happy
- // If one of these formats are supported by NONE of the configuration sources, we should drop it to avoid complexity
-
- return 0;
+ int st_len = strlen(string);
+ int su_len = strlen(suffix);
+
+ return (st_len >= su_len && !strcmp(string + (st_len-su_len), suffix));
+}
+
+static bool
+_sockaddr_equals(const struct sockaddr *ip_a, const struct sockaddr *ip_b, const struct sockaddr *nm)
+{
+ if (!ip_a || !ip_b) return false;
+ if (ip_a->sa_family != ip_b->sa_family) return false;
+ if (nm && ip_a->sa_family != nm->sa_family) return false;
+
+ // Setup the arrays
+ uint8_t bytes = 0, *a_data = NULL, *b_data = NULL, *nm_data = NULL;
+ if (ip_a->sa_family == AF_INET)
+ {
+ bytes = 32 / 8;
+ a_data = (uint8_t *) &((struct sockaddr_in *) ip_a)->sin_addr;
+ b_data = (uint8_t *) &((struct sockaddr_in *) ip_b)->sin_addr;
+ nm_data = nm ? (uint8_t *) &((struct sockaddr_in *) nm)->sin_addr : NULL;
+ }
+ else if (ip_a->sa_family == AF_INET6)
+ {
+ bytes = 128 / 8;
+ a_data = (uint8_t *) &((struct sockaddr_in6 *) ip_a)->sin6_addr;
+ b_data = (uint8_t *) &((struct sockaddr_in6 *) ip_b)->sin6_addr;
+ nm_data = nm ? (uint8_t *) &((struct sockaddr_in6 *) nm)->sin6_addr : NULL;
+ }
+ else
+ return false;
+
+ for (int i=0 ; i < bytes ; i++)
+ {
+ if (nm && (a_data[i] & nm_data[i]) != (b_data[i] & nm_data[i]))
+ return false;
+ else if (a_data[i] != b_data[i])
+ return false;
+ }
+ return true;
+}
+
+static struct sockaddr *
+_sockaddr_from_string(const char *ip, uint32_t len)
+{
+ if (!ip) return NULL;
+ struct sockaddr *result = NULL;
+
+ // Copy the string
+ if (len >= 0)
+ ip = px_strndup(ip, len);
+ else
+ ip = px_strdup(ip);
+
+ // Try to parse IPv4
+ result = px_malloc0(sizeof(struct sockaddr_in));
+ result->sa_family = AF_INET;
+ if (inet_pton(AF_INET, ip, &((struct sockaddr_in *) result)->sin_addr) > 0)
+ goto out;
+
+ // Try to parse IPv6
+ px_free(result);
+ result = px_malloc0(sizeof(struct sockaddr_in6));
+ result->sa_family = AF_INET6;
+ if (inet_pton(AF_INET6, ip, &((struct sockaddr_in6 *) result)->sin6_addr) > 0)
+ goto out;
+
+ // No address found
+ px_free(result);
+ result = NULL;
+ out:
+ px_free((char *) ip);
+ return result;
+}
+
+static struct sockaddr *
+_sockaddr_from_cidr(int af, int cidr)
+{
+ // TODO: Support CIDR notation
+ return NULL;
+}
+
+static bool
+_ip_ignore(pxURL *url, char *ignore)
+{
+ if (!url || !ignore) return false;
+
+ bool result = false;
+ uint32_t port = 0;
+ const struct sockaddr *dst_ip = px_url_get_ip_no_dns(url);
+ struct sockaddr *ign_ip = NULL, *net_ip = NULL;
+
+ // IPv4
+ // IPv6
+ if ((ign_ip = _sockaddr_from_string(ignore, -1)))
+ goto out;
+
+ // IPv4/CIDR
+ // IPv4/IPv4
+ // IPv6/CIDR
+ // IPv6/IPv6
+ if (strchr(ignore, '/'))
+ {
+ ign_ip = _sockaddr_from_string(ignore, strchr(ignore, '/') - ignore);
+ net_ip = _sockaddr_from_string(strchr(ignore, '/') + 1, -1);
+
+ // If CIDR notation was used, get the netmask
+ if (ign_ip && !net_ip)
+ {
+ uint32_t cidr = 0;
+ if (sscanf(strchr(ignore, '/') + 1, "%d", &cidr) == 1)
+ net_ip = _sockaddr_from_cidr(ign_ip->sa_family, cidr);
+ }
+
+ if (ign_ip && net_ip && ign_ip->sa_family == net_ip->sa_family)
+ goto out;
+
+ px_free(ign_ip);
+ px_free(net_ip);
+ ign_ip = NULL;
+ net_ip = NULL;
+ }
+
+ // IPv4:port
+ // [IPv6]:port
+ if (strrchr(ignore, ':') && sscanf(strrchr(ignore, ':'), ":%u", &port) == 1 && port > 0)
+ {
+ ign_ip = _sockaddr_from_string(ignore, strrchr(ignore, ':') - ignore);
+
+ // Make sure this really is just a port and not just an IPv6 address
+ if (ign_ip && (ign_ip->sa_family != AF_INET6 || ignore[0] == '['))
+ goto out;
+
+ px_free(ign_ip);
+ ign_ip = NULL;
+ port = 0;
+ }
+
+ out:
+ result = _sockaddr_equals(dst_ip, ign_ip, net_ip);
+ px_free(ign_ip);
+ px_free(net_ip);
+ return port != 0 ? (port == px_url_get_port(url) && result): result;
}
+static inline bool
+_domain_ignore(pxURL *url, char *ignore)
+{
+ if (!url || !ignore)
+ return false;
+
+ // Get our URL's hostname and port
+ char *host = px_strdup(px_url_get_host(url));
+ int port = px_url_get_port(url);
+
+ // Get our ignore pattern's hostname and port
+ char *ihost = px_strdup(ignore);
+ int iport = 0;
+ if (strchr(ihost, ':'))
+ {
+ char *tmp = strchr(ihost, ':');
+ if (sscanf(tmp+1, "%d", &iport) == 1)
+ *tmp = '\0';
+ else
+ iport = 0;
+ }
+
+ // Hostname match (domain.com or domain.com:80)
+ if (!strcmp(host, ihost))
+ if (!iport || port == iport)
+ goto match;
+
+ // Endswith (.domain.com or .domain.com:80)
+ if (ihost[0] == '.' && _endswith(host, ihost))
+ if (!iport || port == iport)
+ goto match;
+
+ // Glob (*.domain.com or *.domain.com:80)
+ if (ihost[0] == '*' && _endswith(host, ihost+1))
+ if (!iport || port == iport)
+ goto match;
+
+ // No match was found
+ px_free(host);
+ px_free(ihost);
+ return false;
+
+ // A match was found
+ match:
+ px_free(host);
+ px_free(ihost);
+ return true;
+}
/**
* Creates a new pxProxyFactory instance. This instance
@@ -426,10 +608,17 @@ px_proxy_factory_get_proxies (pxProxyFactory *self, char *url)
config->url = px_strdup("wpad://");
}
- // TODO: Ignores
-
- if(_ignore(realurl, config->ignore))
- goto do_return;
+ // Check our ignore patterns
+ char **ignores = px_strsplit(config->ignore, ",");
+ for (int i=0 ; ignores[i] ; i++)
+ {
+ if (_domain_ignore(realurl, ignores[i]) || _ip_ignore(realurl, ignores[i]))
+ {
+ px_strfreev(ignores);
+ goto do_return;
+ }
+ }
+ px_strfreev(ignores);
// If we have a wpad config
if (!strcmp(config->url, "wpad://"))
diff --git a/src/lib/url.c b/src/lib/url.c
index a9a70d2..495e04e 100644
--- a/src/lib/url.c
+++ b/src/lib/url.c
@@ -23,6 +23,9 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
#include "misc.h"
#include "url.h"
@@ -31,12 +34,12 @@
* pxURL object. All fields are private.
*/
struct _pxURL {
- char *url;
- char *scheme;
- char *host;
- int port;
- char *path;
- pxIP **ips;
+ char *url;
+ char *scheme;
+ char *host;
+ int port;
+ char *path;
+ struct sockaddr **ips;
};
/**
@@ -53,7 +56,7 @@ px_url_free(pxURL *self)
if (self->ips)
{
for (int i=0 ; self->ips[i] ; i++)
- px_ip_free(self->ips[i]);
+ px_free(self->ips[i]);
px_free(self->ips);
}
px_free(self);
@@ -78,7 +81,7 @@ px_url_is_valid(const char *url)
* @return Socket to read the response on.
*/
int
-px_url_open(pxURL *self, const char **headers)
+px_url_get(pxURL *self, const char **headers)
{
char *request = NULL;
char *joined_headers = NULL;
@@ -88,9 +91,21 @@ px_url_open(pxURL *self, const char **headers)
if (!px_url_get_ips(self)) goto error;
// Iterate through each pxIP trying to make a connection
- px_url_get_ips(self); // Do lookup
for (int i = 0 ; self->ips && self->ips[i] && sock < 0 ; i++)
- sock = px_ip_connect(self->ips[i], TCP, px_url_get_port(self));
+ {
+ sock = socket(self->ips[i]->sa_family, SOCK_STREAM, 0);
+ if (sock < 0) continue;
+
+ if (self->ips[i]->sa_family == AF_INET &&
+ !connect(sock, self->ips[i], sizeof(struct sockaddr_in)))
+ break;
+ else if (self->ips[i]->sa_family == AF_INET6 &&
+ !connect(sock, self->ips[i], sizeof(struct sockaddr_in6)))
+ break;
+
+ close(sock);
+ sock = -1;
+ }
if (sock < 0) goto error;
// Merge optional headers
@@ -143,18 +158,96 @@ px_url_get_host(pxURL *self)
}
/**
- * @return pxIP address of the host in the pxURL
+ * Get the IP address of the hostname in this pxURL without using DNS.
+ * @return IP address of the host in the pxURL.
+ */
+const struct sockaddr *
+px_url_get_ip_no_dns(pxURL *self)
+{
+ if (!self) return NULL;
+
+ // Check the cache
+ if (self->ips && self->ips[0])
+ return (const struct sockaddr *) self->ips[0];
+ px_free(self->ips);
+
+ // Try for IPv4 first
+ struct sockaddr *ip = px_malloc0(sizeof(struct sockaddr_in));
+ if (inet_pton(AF_INET, px_url_get_host(self), &((struct sockaddr_in *) ip)->sin_addr) > 0)
+ {
+ self->ips = px_malloc0(sizeof(struct sockaddr *) * 2);
+ self->ips[0] = ip;
+ self->ips[0]->sa_family = AF_INET;
+ return (const struct sockaddr *) self->ips[0];
+ }
+ px_free(ip);
+
+ // Try for IPv6 next
+ ip = px_malloc0(sizeof(struct sockaddr_in6));
+ if (inet_pton(AF_INET6, px_url_get_host(self), &((struct sockaddr_in6 *) ip)->sin6_addr) > 0)
+ {
+ self->ips = px_malloc0(sizeof(struct sockaddr *) * 2);
+ self->ips[0] = ip;
+ self->ips[0]->sa_family = AF_INET6;
+ return (const struct sockaddr *) self->ips[0];
+ }
+ px_free(ip);
+
+ // The hostname was not an IP address
+ return NULL;
+}
+
+/**
+ * Get the IP addresses of the hostname in this pxURL. Use DNS if necessary.
+ * @return IP addresses of the host in the pxURL.
*/
-const pxIP **
+const struct sockaddr **
px_url_get_ips(pxURL *self)
{
if (!self) return NULL;
// Check the cache
- if (self->ips) return (const pxIP **) self->ips;
+ if (self->ips) return (const struct sockaddr **) self->ips;
+
+ // Check without DNS first
+ if (px_url_get_ip_no_dns(self)) return (const struct sockaddr **) self->ips;
+
+ // Check DNS for IPs
+ struct addrinfo *info;
+ if (!getaddrinfo(px_url_get_host(self), NULL, NULL, &info))
+ {
+ struct addrinfo *first = info;
+ int count;
+
+ // Count how many IPs we got back
+ for (count=0 ; info ; info = info->ai_next)
+ count++;
+
+ // Copy the sockaddr's into self->ips
+ info = first;
+ self->ips = px_malloc0(sizeof(struct sockaddr *) * ++count);
+ for (int i=0 ; info ; info = info->ai_next)
+ {
+ if (info->ai_addr->sa_family == AF_INET)
+ {
+ self->ips[i] = px_malloc0(sizeof(struct sockaddr_in));
+ memcpy(self->ips[i], info->ai_addr, sizeof(struct sockaddr_in));
+ ((struct sockaddr_in *) self->ips[i++])->sin_port = htons(self->port);
+ }
+ else if (info->ai_addr->sa_family == AF_INET6)
+ {
+ self->ips[i] = px_malloc0(sizeof(struct sockaddr_in6));
+ memcpy(self->ips[i], info->ai_addr, sizeof(struct sockaddr_in6));
+ ((struct sockaddr_in6 *) self->ips[i++])->sin6_port = htons(self->port);
+ }
+ }
+
+ freeaddrinfo(first);
+ return (const struct sockaddr **) self->ips;
+ }
- self->ips = px_ip_new_from_hostent_all(gethostbyname(self->host));
- return (const pxIP **) self->ips;
+ // No addresses found
+ return NULL;
}
/**
diff --git a/src/lib/url.h b/src/lib/url.h
index c1bf98f..1485704 100644
--- a/src/lib/url.h
+++ b/src/lib/url.h
@@ -20,7 +20,6 @@
#ifndef URL_H_
#define URL_H_
-#include "ip.h" // For class pxURL
#include "stdbool.h" // For type bool
/**
@@ -44,7 +43,7 @@ bool px_url_is_valid(const char *url);
* @headers A list of headers to be included in the request.
* @return Socket to read the response on.
*/
-int px_url_open(pxURL *self, const char **headers);
+int px_url_get(pxURL *self, const char **headers);
/**
* @return Host portion of the pxURL
@@ -52,9 +51,16 @@ int px_url_open(pxURL *self, const char **headers);
const char *px_url_get_host(pxURL *self);
/**
- * @return pxIP address of the host in the pxURL
+ * Get the IP addresses of the hostname in this pxURL without using DNS.
+ * @return IP addresses of the host in the pxURL.
*/
-const pxIP **px_url_get_ips(pxURL *self);
+const struct sockaddr *px_url_get_ip_no_dns(pxURL *self);
+
+/**
+ * Get the IP addresses of the hostname in this pxURL. Use DNS if necessary.
+ * @return IP addresses of the host in the pxURL.
+ */
+const struct sockaddr **px_url_get_ips(pxURL *self);
/**
* @return Path portion of the pxURL
diff --git a/src/plugins/mozjs.c b/src/plugins/mozjs.c
index 672e3c6..3000e15 100644
--- a/src/plugins/mozjs.c
+++ b/src/plugins/mozjs.c
@@ -19,6 +19,10 @@
#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/inet.h>
#define __USE_BSD
#include <unistd.h>
@@ -29,34 +33,42 @@
#include "pacutils.h"
static JSBool dnsResolve(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- char *host, *tmp;
-
// Get hostname argument
- host = px_strdup(JS_GetStringBytes(JS_ValueToString(cx, argv[0])));
+ char *tmp = px_strdup(JS_GetStringBytes(JS_ValueToString(cx, argv[0])));
// Look it up
- struct hostent *host_info = gethostbyname(host);
- px_free(host);
+ struct addrinfo *info;
+ if (getaddrinfo(tmp, NULL, NULL, &info))
+ goto error;
+ px_free(tmp);
- // If we found it...
- if (host_info && host_info->h_length == 4) {
- // Allocate our host string
- host = JS_malloc(cx, 16);
- if (!host) { *rval = JSVAL_NULL; return true; }
-
- // Generate host string
- tmp = host_info->h_addr_list[0];
- sprintf(host, "%hhu.%hhu.%hhu.%hhu", tmp[0], tmp[1], tmp[2], tmp[3]);
-
- // Return
- JSString *ip = JS_NewString(cx, host, strlen(host));
- *rval = STRING_TO_JSVAL(ip);
+ // Try for IPv4
+ tmp = px_malloc0(INET_ADDRSTRLEN+1);
+ if (inet_ntop(info->ai_family,
+ &((struct sockaddr_in *) info->ai_addr)->sin_addr,
+ tmp, INET_ADDRSTRLEN+1) > 0)
+ {
+ JSString *ip = JS_NewString(cx, tmp, strlen(tmp));
+ *rval = STRING_TO_JSVAL(ip);
return true;
}
- // Return
- *rval = JSVAL_NULL;
- return true;
+ // Try for IPv6
+ px_free(tmp);
+ tmp = px_malloc0(INET6_ADDRSTRLEN+1);
+ if (inet_ntop(info->ai_family,
+ &((struct sockaddr_in6 *) info->ai_addr)->sin6_addr,
+ tmp, INET6_ADDRSTRLEN+1) > 0)
+ {
+ JSString *ip = JS_NewString(cx, tmp, strlen(tmp));
+ *rval = STRING_TO_JSVAL(ip);
+ return true;
+ }
+
+ error:
+ px_free(tmp);
+ *rval = JSVAL_NULL;
+ return true;
}
static JSBool myIpAddress(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
diff --git a/src/plugins/networkmanager.c b/src/plugins/networkmanager.c
index 68c3a8f..2ebbd43 100644
--- a/src/plugins/networkmanager.c
+++ b/src/plugins/networkmanager.c
@@ -19,6 +19,7 @@
#include <stdlib.h>
#include <string.h>
+#include <stdint.h>
#include <misc.h>
#include <proxy_factory.h>