diff options
author | npmccallum <npmccallum@c587cffe-e639-0410-9787-d7902ae8ed56> | 2007-12-12 22:19:30 +0000 |
---|---|---|
committer | npmccallum <npmccallum@c587cffe-e639-0410-9787-d7902ae8ed56> | 2007-12-12 22:19:30 +0000 |
commit | 3ac1e5a02463e34caa72b2bd74b8e58dede02b2a (patch) | |
tree | 74c024ce21f085cb2c61d2d4b8547e57a44d3bc0 | |
parent | 11188f6e7bb3cd89cab1b5f584071237ac832f12 (diff) | |
download | libproxy-git-3ac1e5a02463e34caa72b2bd74b8e58dede02b2a.tar.gz |
reworked IP handling so that ignores could be implemented
-rw-r--r-- | src/lib/Makefile.am | 4 | ||||
-rw-r--r-- | src/lib/dns.c | 2 | ||||
-rw-r--r-- | src/lib/ip.c | 234 | ||||
-rw-r--r-- | src/lib/ip.h | 95 | ||||
-rw-r--r-- | src/lib/pac.c | 5 | ||||
-rw-r--r-- | src/lib/proxy_factory.c | 225 | ||||
-rw-r--r-- | src/lib/url.c | 123 | ||||
-rw-r--r-- | src/lib/url.h | 14 | ||||
-rw-r--r-- | src/plugins/mozjs.c | 54 | ||||
-rw-r--r-- | src/plugins/networkmanager.c | 1 |
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> |