Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F154222359
D18908.id58467.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D18908.id58467.diff
View Options
Index: lib/libfetch/common.h
===================================================================
--- lib/libfetch/common.h
+++ lib/libfetch/common.h
@@ -70,12 +70,36 @@
const char *string;
};
+/* For SOCKS header size */
+#define HEAD_SIZE 4
+#define FQDN_SIZE 256
+#define PACK_SIZE 1
+#define PORT_SIZE 2
+#define BUFF_SIZE HEAD_SIZE + FQDN_SIZE + PACK_SIZE + PORT_SIZE
+
+/* SOCKS5 Request Header */
+#define SOCKS_VERSION 0x05
+/* SOCKS5 CMD */
+#define SOCKS_CONNECTION 0x01
+#define SOCKS_BIND 0x02
+#define SOCKS_UDP 0x03
+#define SOCKS_NOMETHODS 0xFF
+/* SOCKS5 Reserved */
+#define SOCKS_RSV 0x00
+/* SOCKS5 Address Type */
+#define SOCKS_ATYP_IPV4 0x01
+#define SOCKS_ATYP_DOMAINNAME 0x03
+#define SOCKS_ATYP_IPV6 0x04
+
/* for fetch_writev */
struct iovec;
void fetch_seterr(struct fetcherr *, int);
void fetch_syserr(void);
void fetch_info(const char *, ...) __printflike(1, 2);
+int fetch_socks5_getenv(char **host, int *port);
+int fetch_socks5_init(conn_t *conn, const char *host,
+ int port, int verbose);
int fetch_default_port(const char *);
int fetch_default_proxy_port(const char *);
struct addrinfo *fetch_resolve(const char *, int, int);
Index: lib/libfetch/common.c
===================================================================
--- lib/libfetch/common.c
+++ lib/libfetch/common.c
@@ -42,6 +42,7 @@
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <netdb.h>
#include <poll.h>
#include <pwd.h>
@@ -314,7 +315,6 @@
}
-
/*
* Bind a socket to a specific local address
*/
@@ -336,6 +336,194 @@
}
+/*
+ * SOCKS5 connection initiation, based on RFC 1928
+ * Default DNS resolution over SOCKS5
+ */
+int
+fetch_socks5_init(conn_t *conn, const char *host, int port, int verbose)
+{
+ /*
+ * Size is based on largest packet prefix (4 bytes) +
+ * Largest FQDN (256) + one byte size (1) +
+ * Port (2)
+ */
+ unsigned char buf[BUFF_SIZE];
+ unsigned char *ptr;
+
+ if (verbose)
+ fetch_info("Initializing SOCKS5 connection: %s:%d", host, port);
+
+ /* Connection initialization */
+ ptr = buf;
+ *ptr++ = SOCKS_VERSION_5;
+ *ptr++ = SOCKS_CONNECTION;
+ *ptr++ = SOCKS_RSV;
+
+ if (fetch_write(conn, buf, 3) != 3) {
+ fprintf(stderr, "SOCKS5: Failed to send selection method.\n");
+ goto fail;
+ }
+
+ /* Verify response from SOCKS5 server */
+ if (fetch_read(conn, buf, 2) != 2) {
+ fprintf(stderr, "SOCKS5: Failed to read method.\n");
+ goto fail;
+ }
+
+ ptr = buf;
+ if (ptr[0] != SOCKS_VERSION_5) {
+ fprintf(stderr, "SOCKS5: Currently only version 5 is implemented.\n");
+ goto fail;
+ }
+ if (ptr[1] == SOCKS_NOMETHODS) {
+ fprintf(stderr, "SOCKS5: No acceptable methods. Disconnecting.\n");
+ goto fail;
+ }
+ else if (ptr[1] != 0x00) {
+ fprintf(stderr, "SOCKS5: Method currently not implemented. Disconnecting.\n");
+ goto fail;
+ }
+
+ /* Send Request */
+ *ptr++ = SOCKS_VERSION_5;
+ *ptr++ = SOCKS_CONNECTION;
+ *ptr++ = SOCKS_RSV;
+ /* Encode all targets as a hostname to avoid DNS leaks */
+ *ptr++ = SOCKS_ATYP_DOMAINNAME;
+ if (strlen(host) > FQDN_SIZE) {
+ fprintf(stderr, "Hostname above 256 bytes, exiting.\n");
+ goto fail;
+ }
+ *ptr++ = strlen(host);
+ strncpy(ptr, host, strlen(host));
+ ptr = ptr + strlen(host);
+
+ port = htons(port);
+ *ptr++ = port & 0x00ff;
+ *ptr++ = (port & 0xff00) >> 8;
+
+ if (fetch_write(conn, buf, ptr - buf) != ptr - buf) {
+ fprintf(stderr, "SOCKS5: Failed to request.\n");
+ goto fail;
+ }
+
+ /* BND.ADDR is variable length, read the largest on non-blocking socket */
+ if (!fetch_read(conn, buf, BUFF_SIZE)) {
+ fprintf(stderr, "SOCKS5: Failed to receive reply.\n");
+ goto fail;
+ }
+
+ ptr = buf;
+ if (*ptr++ != SOCKS_VERSION_5) {
+ fprintf(stderr, "SOCKS5: Server responded with a non-version 5 response.\n");
+ goto fail;
+ }
+
+ switch(*ptr++) {
+ case 0x00:
+ break;
+ case 0x01:
+ fprintf(stderr, "SOCKS5: General server failure\n");
+ goto fail;
+ case 0x02:
+ fprintf(stderr, "SOCKS5: Connection not allowed by ruleset.\n");
+ goto fail;
+ case 0x03:
+ fprintf(stderr, "SOCKS5: Network unreachable.\n");
+ goto fail;
+ case 0x04:
+ fprintf(stderr, "SOCKS5: Host unreachable.\n");
+ goto fail;
+ case 0x05:
+ fprintf(stderr, "SOCKS5: Connection refused.\n");
+ goto fail;
+ case 0x06:
+ fprintf(stderr, "SOCKS5: TTL expired.\n");
+ goto fail;
+ case 0x07:
+ fprintf(stderr, "SOCKS5: Command not supported.\n");
+ goto fail;
+ case 0x08:
+ fprintf(stderr, "SOCKS5: Address type not supported.\n");
+ goto fail;
+ default:
+ fprintf(stderr, "SOCKS5: Unspecified failure.\n");
+ goto fail;
+ }
+
+ return (1);
+
+fail:
+ return (0);
+}
+
+/*
+ * Perform SOCKS5 initialization
+ */
+int
+fetch_socks5_getenv(char **host, int *port)
+{
+ char *socks5env, *endptr, *ext;
+
+ if (!(socks5env = getenv("SOCKS5_PROXY")) || !*socks5env) {
+ *host = NULL;
+ *port = -1;
+ return (1);
+ }
+
+ /* IPv6 addresses begin and end in brackets */
+ if (socks5env[0] == '[') {
+ if (socks5env[strlen(socks5env)-1] == ']') {
+ *host = strndup(socks5env, strlen(socks5env));
+ if (*host == NULL)
+ goto fail;
+ *port = 1080; /* Default port as defined in RFC1928 */
+ }
+ else {
+ ext = strstr(socks5env, "]:");
+ if (!ext) {
+ fprintf(stderr, "Bad SOCKS5_PROXY format, missing closing ']': %s\n",
+ socks5env);
+ return (0);
+ }
+ ext=ext+1;
+ *host = strndup(socks5env, (ext)-(socks5env));
+ if (*host == NULL)
+ goto fail;
+ *port = strtoimax(ext+1, (char **)&endptr, 10);
+ if (*port == 0 && errno == EINVAL) {
+ fprintf(stderr, "Bad SOCKS5_PROXY port: %s\n", socks5env);
+ return (0);
+ }
+ }
+ }
+ else {
+ ext = strrchr(socks5env, ':');
+ if (!ext) {
+ *host = strdup(socks5env);
+ *port = 1080;
+ }
+ else {
+ *host = strndup(socks5env, ext-socks5env);
+ if (*host == NULL)
+ goto fail;
+ *port = strtoimax(ext+1, (char **)&endptr, 10);
+ if (*port == 0 && errno == EINVAL) {
+ fprintf(stderr, "Bad SOCKS5_PROXY port: %s\n", socks5env);
+ return (0);
+ }
+ }
+ }
+
+ return (2);
+
+fail:
+ fprintf(stderr, "Failure to allocate memory, exiting.\n");
+ return (0);
+}
+
+
/*
* Establish a TCP connection to the specified port on the specified host.
*/
@@ -344,24 +532,41 @@
{
struct addrinfo *cais = NULL, *sais = NULL, *cai, *sai;
const char *bindaddr;
+ char *sockshost;
+ int socksport;
conn_t *conn = NULL;
int err = 0, sd = -1;
DEBUGF("---> %s:%d\n", host, port);
- /* resolve server address */
- if (verbose)
- fetch_info("resolving server address: %s:%d", host, port);
- if ((sais = fetch_resolve(host, port, af)) == NULL)
+ /* Check if SOCKS5_PROXY env variable is set */
+ if(!fetch_socks5_getenv(&sockshost, &socksport))
goto fail;
- /* resolve client address */
- bindaddr = getenv("FETCH_BIND_ADDRESS");
- if (bindaddr != NULL && *bindaddr != '\0') {
+ /* Not using SOCKS5 proxy */
+ if (!sockshost) {
+ /* resolve server address */
if (verbose)
- fetch_info("resolving client address: %s", bindaddr);
- if ((cais = fetch_resolve(bindaddr, 0, af)) == NULL)
+ fetch_info("resolving server address: %s:%d", host, port);
+ if ((sais = fetch_resolve(host, port, af)) == NULL)
goto fail;
+
+ /* resolve client address */
+ bindaddr = getenv("FETCH_BIND_ADDRESS");
+ if (bindaddr != NULL && *bindaddr != '\0') {
+ if (verbose)
+ fetch_info("resolving client address: %s", bindaddr);
+ if ((cais = fetch_resolve(bindaddr, 0, af)) == NULL)
+ goto fail;
+ }
+ }
+ else {
+ /* resolve socks5 proxy address */
+ if (verbose)
+ fetch_info("resolving SOCKS5 server address: %s:%d", sockshost, socksport);
+ if ((sais = fetch_resolve(sockshost, socksport, af)) == NULL) {
+ goto fail;
+ }
}
/* try each server address in turn */
@@ -389,13 +594,20 @@
sd = -1;
}
if (err != 0) {
- if (verbose)
+ if (verbose && !sockshost)
fetch_info("failed to connect to %s:%d", host, port);
+ else if (verbose && sockshost)
+ fetch_info("failed to connect to SOCKS5 server %s:%d", sockshost, socksport);
goto syserr;
}
+
if ((conn = fetch_reopen(sd)) == NULL)
goto syserr;
+
+ if (sockshost)
+ if (!fetch_socks5_init(conn, host, port, verbose))
+ goto fail;
if (cais != NULL)
freeaddrinfo(cais);
if (sais != NULL)
Index: lib/libfetch/fetch.3
===================================================================
--- lib/libfetch/fetch.3
+++ lib/libfetch/fetch.3
@@ -26,7 +26,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 18, 2016
+.Dd June 9, 2019
.Dt FETCH 3
.Os
.Sh NAME
@@ -652,6 +652,12 @@
Same as
.Ev NO_PROXY ,
for compatibility.
+.It Ev SOCKS5_PROXY
+Uses SOCKS version 5 to make connection.
+The format must be the IP or hostname followed by a colon for the port.
+IPv6 addresses must enclose the address in brackets.
+If no port is specified, the default is 1080.
+This setting will supercede a connection to an HTTP_PROXY.
.It Ev SSL_ALLOW_SSL3
Allow SSL version 3 when negotiating the connection (not recommended).
.It Ev SSL_CA_CERT_FILE
@@ -710,6 +716,21 @@
NO_PROXY=localhost,127.0.0.1
.Ed
.Pp
+To use a SOCKS5 proxy, set the
+.Ev SOCKS5_PROXY
+environment variable to a
+valid host or IP followed by an optional colon and the port.
+IPv6 addresses must be enclosed in brackets.
+The following are examples of valid settings:
+.Bd -literal -offset indent
+SOCKS5_PROXY=proxy.example.com
+SOCKS5_PROXY=proxy.example.com:1080
+SOCKS5_PROXY=192.0.2.0
+SOCKS5_PROXY=198.51.100.0:1080
+SOCKS5_PROXY=[2001:db8::1]
+SOCKS5_PROXY=[2001:db8::2]:1080
+.Ed
+.Pp
Access HTTPS website without any certificate verification whatsoever:
.Bd -literal -offset indent
SSL_NO_VERIFY_PEER=1
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Apr 28, 5:51 AM (3 h, 26 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32253962
Default Alt Text
D18908.id58467.diff (9 KB)
Attached To
Mode
D18908: Added SOCKS5 support to libfetch
Attached
Detach File
Event Timeline
Log In to Comment