diff options
author | bptato <nincsnevem662@gmail.com> | 2024-10-13 15:06:20 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2024-10-13 15:06:20 +0200 |
commit | b773f053478dfae83719417b434f9e232d374b0b (patch) | |
tree | db7e449c42c734df581a00a7dbdf41c9e86f3946 | |
parent | a252f9695d8c95d2eb1aaf7d25e720ac84765be6 (diff) | |
download | chawan-b773f053478dfae83719417b434f9e232d374b0b.tar.gz |
lcgi: support HTTP proxy
not quite sure this approach is right, because it still won't work with HTTPS without linking everything with OpenSSL... maybe a socks5 bridge through a UNIX socket would work better?
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | adapter/protocol/lcgi.nim | 67 |
2 files changed, 53 insertions, 15 deletions
diff --git a/Makefile b/Makefile index 587d0ba6..52c75e55 100644 --- a/Makefile +++ b/Makefile @@ -113,6 +113,7 @@ $(OUTDIR_CGI_BIN)/canvas: src/types/canvastypes.nim src/types/path.nim \ $(OUTDIR_CGI_BIN)/resize: adapter/img/stb_image_resize.h adapter/img/stb_image_resize.c \ src/utils/sandbox.nim $(dynstream) $(twtstr) $(OUTDIR_LIBEXEC)/urlenc: $(twtstr) +$(OUTDIR_LIBEXEC)/nc: $(lcgi) $(OUTDIR_LIBEXEC)/gopher2html: adapter/gophertypes.nim $(twtstr) $(OUTDIR_LIBEXEC)/ansi2html: src/types/color.nim src/io/poll.nim $(twtstr) $(dynstream) $(OUTDIR_LIBEXEC)/md2html: $(twtstr) diff --git a/adapter/protocol/lcgi.nim b/adapter/protocol/lcgi.nim index 89932ba9..590c63c8 100644 --- a/adapter/protocol/lcgi.nim +++ b/adapter/protocol/lcgi.nim @@ -73,7 +73,8 @@ proc authenticateSocks5(os, ps: PosixStream; buf: array[2, uint8]; else: os.die("ProxyInvalidResponse received wrong auth method " & $buf[1]) -proc sendSocks5Domain(os, ps: PosixStream; host, port: string) = +proc sendSocks5Domain(os, ps: PosixStream; host, port: string; + outIpv6: var bool) = if host.len > 255: os.die("InternalError", "host too long to send to proxy") let dstaddr = "\x03" & char(host.len) & host @@ -93,21 +94,25 @@ proc sendSocks5Domain(os, ps: PosixStream; host, port: string) = of 0x01: var ipv4 = default(array[4, uint8]) ps.recvDataLoop(ipv4) + outIpv6 = false of 0x03: var len = [0u8] ps.recvDataLoop(len) var domain = newString(int(len[0])) ps.recvDataLoop(domain) + # we don't really know, so just assume it's ipv4. + outIpv6 = false of 0x04: var ipv6 = default(array[16, uint8]) ps.recvDataLoop(ipv6) + outIpv6 = true else: os.die("ProxyInvalidResponse") var bndport = default(array[2, uint8]) ps.recvDataLoop(bndport) proc connectSocks5Socket(os: PosixStream; host, port, proxyHost, proxyPort, - proxyUser, proxyPass: string): PosixStream = + proxyUser, proxyPass: string; outIpv6: var bool): PosixStream = var dummy = false let ps = os.connectSocket(proxyHost, proxyPort, "FailedToResolveProxy", "ProxyRefusedToConnect", dummy) @@ -117,15 +122,42 @@ proc connectSocks5Socket(os: PosixStream; host, port, proxyHost, proxyPort, var buf = default(array[2, uint8]) ps.recvDataLoop(buf) os.authenticateSocks5(ps, buf, proxyUser, proxyPass) - os.sendSocks5Domain(ps, host, port) + os.sendSocks5Domain(ps, host, port, outIpv6) + return ps + +proc connectHTTPSocket(os: PosixStream; host, port, proxyHost, proxyPort, + proxyUser, proxyPass: string): PosixStream = + var dummy = false + let ps = os.connectSocket(proxyHost, proxyPort, "FailedToResolveProxy", + "ProxyRefusedToConnect", dummy) + var buf = "CONNECT " & host & ':' & port & " HTTP/1.1\r\n" + buf &= "Host: " & host & ':' & port & "\r\n" + if proxyUser != "" or proxyPass != "": + let s = btoa(proxyUser & ' ' & proxyPass) + buf &= "Proxy-Authorization: basic " & s & "\r\n" + buf &= "\r\n" + ps.sendDataLoop(buf) + var res = "" + var crlfState = 0 + while crlfState < 4: + var buf = [char(0)] + let n = ps.recvData(buf) + if n == 0: + break + let expected = ['\r', '\n'][crlfState mod 2] + if buf[0] == expected: + inc crlfState + else: + crlfState = 0 + res &= buf[0] + if not res.startsWithIgnoreCase("HTTP/1.1 200") and + not res.startsWithIgnoreCase("HTTP/1.0 200"): + os.die("ProxyRefusedToConnect") return ps proc connectProxySocket(os: PosixStream; host, port, proxy: string; outIpv6: var bool): PosixStream = let scheme = proxy.until(':') - # We always use socks5h, actually. - if scheme != "socks5" and scheme != "socks5h": - os.die("InternalError", "only socks5 proxy is supported") var i = scheme.len + 1 while i < proxy.len and proxy[i] == '/': inc i @@ -138,16 +170,21 @@ proc connectProxySocket(os: PosixStream; host, port, proxy: string; pass = auth.after(':') i = authi + 1 var proxyHost = "" - while i < proxy.len: - let c = proxy[i] - if c == ':': - inc i - break - if c != '/': - proxyHost &= c + while i < proxy.len and proxy[i] notin {':', '/'}: + proxyHost &= proxy[i] + inc i + inc i + var proxyPort = "" + while i < proxy.len and proxy[i] in AsciiDigit: + proxyPort &= proxy[i] inc i - let proxyPort = proxy.substr(i) - return os.connectSocks5Socket(host, port, proxyHost, proxyPort, user, pass) + if scheme == "socks5" or scheme == "socks5h": + # We always use socks5h, actually. + return os.connectSocks5Socket(host, port, proxyHost, proxyPort, user, pass, + outIpv6) + elif scheme == "http": + return os.connectHTTPSocket(host, port, proxyHost, proxyPort, user, pass) + os.die("InternalError", "only socks5 or http proxies are supported") # Note: outIpv6 is not read; it just indicates whether the socket's # address is IPv6. |