312 lines
9.9 KiB
Plaintext
312 lines
9.9 KiB
Plaintext
patch retrieved from
|
|
https://lists.gnu.org/archive/html/lynx-dev/2019-09/txtdZJkhuP5_U.txt
|
|
|
|
context:
|
|
https://lists.gnu.org/archive/html/lynx-dev/2019-09/msg00030.html
|
|
|
|
summary: adds socks5 support to lynx through a "-socks5-proxy" flag.
|
|
this change has been upstreamed, but a stable release containing this change is
|
|
not yet available. without this, lynx cannot be used with tor under lix os.
|
|
(torsocks hooks into the dynamic library loading mechanism, which is not used at
|
|
all by statically-linked binaries.)
|
|
|
|
diff --git a/WWW/Library/Implementation/HTTCP.c b/WWW/Library/Implementation/HTTCP.c
|
|
index 4669efd4..75f3a161 100644
|
|
--- a/WWW/Library/Implementation/HTTCP.c
|
|
+++ b/WWW/Library/Implementation/HTTCP.c
|
|
@@ -1825,6 +1825,10 @@ int HTDoConnect(const char *url,
|
|
int default_port,
|
|
int *s)
|
|
{
|
|
+ /* On error goto jout */
|
|
+ char *socks5_host;
|
|
+ int socks5_host_len, socks5_port;
|
|
+ const char *socks5_orig_url;
|
|
int status = 0;
|
|
char *line = NULL;
|
|
char *p1 = NULL;
|
|
@@ -1836,7 +1840,45 @@ int HTDoConnect(const char *url,
|
|
#else
|
|
struct sockaddr_in sock_A;
|
|
struct sockaddr_in *soc_in = &sock_A;
|
|
+#endif
|
|
+
|
|
+ /* In case of a present SOCKS5 proxy, marshal */
|
|
+ if((socks5_orig_url = socks5_proxy) != NULL){
|
|
+ size_t i;
|
|
+ int xport;
|
|
+
|
|
+ xport = default_port;
|
|
+ socks5_orig_url = url;
|
|
+
|
|
+ /* Get node name and optional port number of wanted URL */
|
|
+ p1 = HTParse(url, "", PARSE_HOST);
|
|
+ socks5_host = NULL;
|
|
+ StrAllocCopy(socks5_host, p1);
|
|
+ strip_userid(socks5_host, FALSE);
|
|
+ FREE(p1);
|
|
+
|
|
+ if((i = strlen(socks5_host)) > 255){
|
|
+ HTAlert(gettext("SOCKS5: hostname too long."));
|
|
+ goto jout;
|
|
+ }
|
|
+ socks5_host_len = (int)i;
|
|
+
|
|
+ if(HTParsePort((char*)url, &socks5_port) == NULL)
|
|
+ socks5_port = xport;
|
|
+
|
|
+ /* And switch over to our SOCKS5 config; in order to embed that into
|
|
+ * lynx environment, prepend protocol prefix */
|
|
+ default_port = 1080; /* RFC 1928 */
|
|
+ HTSACat(&p1, "socks://");
|
|
+ HTSACat(&p1, socks5_proxy);
|
|
+ url = p1;
|
|
+ p1 = NULL;
|
|
+
|
|
+ protocol = HTSprintf0(NULL, gettext("(for %s at %s) SOCKS5"),
|
|
+ protocol, socks5_host);
|
|
+ }
|
|
|
|
+#ifndef INET6
|
|
/*
|
|
* Set up defaults.
|
|
*/
|
|
@@ -1859,11 +1901,10 @@ int HTDoConnect(const char *url,
|
|
/* HTParseInet() is useless! */
|
|
res0 = HTGetAddrInfo(host, default_port);
|
|
if (res0 == NULL) {
|
|
- HTSprintf0(&line, gettext("Unable to locate remote host %s."), host);
|
|
- _HTProgress(line);
|
|
- FREE(host);
|
|
- FREE(line);
|
|
- return HT_NO_DATA;
|
|
+ HTSprintf0(&line, gettext("Unable to locate remote host %s."), host);
|
|
+ _HTProgress(line);
|
|
+ status = HT_NO_DATA;
|
|
+ goto jout;
|
|
}
|
|
#else
|
|
status = HTParseInet(soc_in, host);
|
|
@@ -1882,16 +1923,12 @@ int HTDoConnect(const char *url,
|
|
}
|
|
status = HT_NO_DATA;
|
|
}
|
|
- FREE(host);
|
|
- FREE(line);
|
|
- return status;
|
|
+ goto jout;
|
|
}
|
|
#endif /* INET6 */
|
|
|
|
HTSprintf0(&line, gettext("Making %s connection to %s"), protocol, host);
|
|
_HTProgress(line);
|
|
- FREE(host);
|
|
- FREE(line);
|
|
|
|
/*
|
|
* Now, let's get a socket set up from the server for the data.
|
|
@@ -1900,7 +1937,8 @@ int HTDoConnect(const char *url,
|
|
*s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
if (*s == -1) {
|
|
HTAlert(gettext("socket failed."));
|
|
- return HT_NO_DATA;
|
|
+ status = HT_NO_DATA;
|
|
+ goto jout;
|
|
}
|
|
#else
|
|
for (res = res0; res; res = res->ai_next) {
|
|
@@ -1916,7 +1954,6 @@ int HTDoConnect(const char *url,
|
|
gettext("socket failed: family %d addr %s port %s."),
|
|
res->ai_family, hostbuf, portbuf);
|
|
_HTProgress(line);
|
|
- FREE(line);
|
|
continue;
|
|
}
|
|
#endif /* INET6 */
|
|
@@ -2005,13 +2042,13 @@ int HTDoConnect(const char *url,
|
|
if ((tries++ / TRIES_PER_SECOND) >= connect_timeout) {
|
|
HTAlert(gettext("Connection failed (too many retries)."));
|
|
#ifdef INET6
|
|
- FREE(line);
|
|
#ifndef NSL_FORK
|
|
if (res0)
|
|
freeaddrinfo(res0);
|
|
#endif
|
|
#endif /* INET6 */
|
|
- return HT_NO_DATA;
|
|
+ status = HT_NO_DATA;
|
|
+ goto jout;
|
|
}
|
|
set_timeout(&select_timeout);
|
|
FD_ZERO(&writefds);
|
|
@@ -2204,7 +2241,6 @@ int HTDoConnect(const char *url,
|
|
#endif /* !DOSPATH || __DJGPP__ */
|
|
|
|
#ifdef INET6
|
|
- FREE(line);
|
|
#ifdef NSL_FORK
|
|
FREE_NSL_FORK(res0);
|
|
#else
|
|
@@ -2212,6 +2248,109 @@ int HTDoConnect(const char *url,
|
|
freeaddrinfo(res0);
|
|
#endif
|
|
#endif /* INET6 */
|
|
+
|
|
+ /* Now if this was a SOCKS5 proxy connection, go for the real one */
|
|
+ if(status >= 0 && socks5_orig_url != NULL){
|
|
+ unsigned char pbuf[4 + 1 + 255 + 2];
|
|
+ size_t i;
|
|
+ char const *emsg;
|
|
+
|
|
+ /* RFC 1928: version identifier/method selection message */
|
|
+ pbuf[0] = 0x05; /* VER: protocol version: X'05' */
|
|
+ pbuf[1] = 0x01; /* NMETHODS: 1 */
|
|
+ pbuf[2] = 0x00; /* METHOD: X'00' NO AUTHENTICATION REQUIRED */
|
|
+ if(write(*s, pbuf, 3) != 3){
|
|
+jerrsocks:
|
|
+ HTAlert(LYStrerror(errno));
|
|
+jesocks:
|
|
+ NETCLOSE(*s);
|
|
+ status = HT_NO_CONNECTION;
|
|
+ goto jout;
|
|
+ }
|
|
+
|
|
+ /* Receive greeting */
|
|
+ if(HTDoRead(*s, pbuf, 2) != 2)
|
|
+ goto jerrsocks;
|
|
+ if(pbuf[0] != 0x05 || pbuf[1] != 0x00){
|
|
+jesocksreply:
|
|
+ emsg = N_("unexpected reply\n");
|
|
+jesocksreplymsg:
|
|
+ HTAlert(gettext(emsg));
|
|
+ goto jesocks;
|
|
+ }
|
|
+
|
|
+ /* RFC 1928: CONNECT request */
|
|
+ HTSprintf0(&line, gettext("SOCKS5: connecting to %s"), socks5_host);
|
|
+ _HTProgress(line);
|
|
+ pbuf[0] = 0x05; /* VER: protocol version: X'05' */
|
|
+ pbuf[1] = 0x01; /* CMD: CONNECT X'01' */
|
|
+ pbuf[2] = 0x00; /* RESERVED */
|
|
+ pbuf[3] = 0x03; /* ATYP: domain name */
|
|
+ pbuf[4] = (unsigned char)socks5_host_len;
|
|
+ memcpy(&pbuf[i = 5], socks5_host, socks5_host_len);
|
|
+ i += socks5_host_len;
|
|
+ /* C99 */{
|
|
+ unsigned short x; /* XXX 16-bit? */
|
|
+
|
|
+ x = htons(socks5_port);
|
|
+ memcpy(&pbuf[i], (unsigned char*)&x, sizeof x);
|
|
+ i += sizeof x;
|
|
+ }
|
|
+ if((size_t)write(*s, pbuf, i) != i)
|
|
+ goto jerrsocks;
|
|
+
|
|
+ /* Connect result */
|
|
+ if((i = HTDoRead(*s, pbuf, 4)) != 4)
|
|
+ goto jerrsocks;
|
|
+ /* Version 5, reserved must be 0 */
|
|
+ if(pbuf[0] != 0x05 || pbuf[2] != 0x00)
|
|
+ goto jesocksreply;
|
|
+ /* Result */
|
|
+ switch(pbuf[1]){
|
|
+ case 0x00: emsg = NULL; break;
|
|
+ case 0x01: emsg = N_("SOCKS server failure"); break;
|
|
+ case 0x02: emsg = N_("connection not allowed by ruleset"); break;
|
|
+ case 0x03: emsg = N_("network unreachable"); break;
|
|
+ case 0x04: emsg = N_("host unreachable"); break;
|
|
+ case 0x05: emsg = N_("connection refused"); break;
|
|
+ case 0x06: emsg = N_("TTL expired"); break;
|
|
+ case 0x07: emsg = N_("command not supported"); break;
|
|
+ case 0x08: emsg = N_("address type not supported"); break;
|
|
+ default: emsg = N_("unknown SOCKS error code"); break;
|
|
+ }
|
|
+ if(emsg != NULL)
|
|
+ goto jesocksreplymsg;
|
|
+
|
|
+ /* Address type variable; read the BND.PORT with it.
|
|
+ * This is actually false since RFC 1928 says that the BND.ADDR reply
|
|
+ * to CONNECT contains the IP address, so only 0x01 and 0x04 are
|
|
+ * allowed */
|
|
+ switch(pbuf[3]){
|
|
+ case 0x01: i = 4; break;
|
|
+ case 0x03: i = 1; break;
|
|
+ case 0x04: i = 16; break;
|
|
+ default: goto jesocksreply;
|
|
+ }
|
|
+ i += sizeof(unsigned short);
|
|
+ if((size_t)HTDoRead(*s, pbuf, i) != i)
|
|
+ goto jerrsocks;
|
|
+ if(i == 1 + sizeof(unsigned short)){
|
|
+ i = pbuf[0];
|
|
+ if((size_t)HTDoRead(*s, pbuf, i) != i)
|
|
+ goto jerrsocks;
|
|
+ }
|
|
+ }
|
|
+
|
|
+jout:
|
|
+ if(socks5_proxy != NULL){
|
|
+ FREE(url);
|
|
+ FREE(protocol);
|
|
+ FREE(socks5_host);
|
|
+ }
|
|
+ if(host != NULL);
|
|
+ FREE(host);
|
|
+ if(line != NULL)
|
|
+ FREE(line);
|
|
return status;
|
|
}
|
|
|
|
diff --git a/lynx.man b/lynx.man
|
|
index ff4eb1b8..5a43c71a 100644
|
|
--- a/lynx.man
|
|
+++ b/lynx.man
|
|
@@ -804,6 +804,11 @@ If enabled the transfer rate is shown in bytes/second.
|
|
If disabled, no transfer rate is shown.
|
|
Use lynx.cfg or the options menu to select KB/second and/or ETA.
|
|
.TP
|
|
+.B \-socks5-proxy=URL
|
|
+(Via which) SOCKS5 proxy to connect.
|
|
+This controls the builtin SOCKS5 support, and is therefore unrelated to
|
|
+the option \fB\-nosocks\fP.
|
|
+.TP
|
|
.B \-soft_dquotes
|
|
toggles emulation of the old Netscape and Mosaic bug which
|
|
treated \*(``>\*('' as a co-terminator for double-quotes and tags.
|
|
diff --git a/src/LYGlobalDefs.h b/src/LYGlobalDefs.h
|
|
index e1203c02..577a5948 100644
|
|
--- a/src/LYGlobalDefs.h
|
|
+++ b/src/LYGlobalDefs.h
|
|
@@ -441,6 +441,7 @@ extern "C" {
|
|
extern BOOLEAN debug_display_partial; /* show with MessageSecs delay */
|
|
extern BOOLEAN display_partial_flag; /* permanent flag, not mutable */
|
|
#endif
|
|
+ extern char *socks5_proxy;
|
|
extern char *form_post_data; /* User data for post form */
|
|
extern char *form_get_data; /* User data for get form */
|
|
extern char *http_error_file; /* Place HTTP status code in this file */
|
|
diff --git a/src/LYMain.c b/src/LYMain.c
|
|
index 36c22ed5..46b8cee8 100644
|
|
--- a/src/LYMain.c
|
|
+++ b/src/LYMain.c
|
|
@@ -635,6 +635,8 @@ BOOLEAN debug_display_partial = FALSE; /* Show with MessageSecs delay */
|
|
int partial_threshold = -1; /* # of lines to be d/l'ed until we repaint */
|
|
#endif
|
|
|
|
+char *socks5_proxy = NULL;
|
|
+
|
|
BOOLEAN LYNonRestartingSIGWINCH = FALSE;
|
|
BOOLEAN LYReuseTempfiles = FALSE;
|
|
BOOLEAN LYUseBuiltinSuffixes = TRUE;
|
|
@@ -3910,6 +3912,10 @@ saves session to that file on exit"
|
|
"toggles display of transfer rate"
|
|
),
|
|
#endif
|
|
+ PARSE_STR(
|
|
+ "socks5-proxy", 2|NEED_LYSTRING_ARG, socks5_proxy,
|
|
+ "=URL\n(via which) SOCKS5 proxy to connect (unrelated to -nosocks!)"
|
|
+ ),
|
|
PARSE_SET(
|
|
"soft_dquotes", 4|TOGGLE_ARG, soft_dquotes,
|
|
"toggles emulation of the old Netscape and Mosaic\n\
|