On this page:
socks5-connect
«provide»1
make-socks5-proxy
«provide»2

1 Provides🔗ℹ

 (require socks5) package: socks5

procedure

(socks5-connect socks-host 
  socks-port 
  dest-host 
  dest-port 
  [#:username-password username-password]) 
  
input-port? output-port?
  socks-host : string?
  socks-port : positive-integer?
  dest-host : string?
  dest-port : positive-integer?
  username-password : (cons/c bytes? bytes?) = #f
Establishes a TCP connection to dest-host:dest-port via the SOCKS5 server socks-host:socks-port. If the connection was successful, socks5-connect returns a pair of ports like tcp-connect, where the output port sends data and the input port receives data. Data transmission works exactly as though the ports were directly connected to the destination, but all data actually goes via the SOCKS5 server.

socks-host is the IP or hostname of the SOCKS5 server to connect to.

dest-host is the IP or hostname of the destination server to connect to via the proxy. If it is a hostname, it will be resolved to an IP address by the proxy server. If this behaviour is undesirable, you can locally resolve the IP and pass it instead of the hostname.

As a limitation of the SOCKS5 protocol, the username and password will be transmitted through the network in cleartext.

#:username-password (optional) is a pair of a username and password to try, as bytes. Not all SOCKS5 servers require authentication.

Example usage

;establish connection to example.com:80 via the proxy 127.0.0.1:1080
(define-values (in out)
  (socks5-connect "127.0.0.1" 1080 "example.com" 80))
;send HTTP request
(displayln
 (string-append
  "GET / HTTP/1.1\r\n"
  "Host: example.com\r\n"
  "Connection: close\r\n\r\n")
 out)
;send TCP FIN
(close-output-port out)
;print the server's response
(copy-port in (current-output-port))

Closing ports

Closing ports generally works in a reasonable way.

Just like the ports from tcp-connect, closing the output port means no more data will be sent, and triggers a TCP FIN notice. The SOCKS5 server forwards TCP FIN to the destination.

The destination server can also close its side of the connection at any time by sending TCP FIN, which closes the input port here (trying to read will return eof). After both sides have sent TCP FIN, the connection is considered fully closed.

When used with the HTTP protocol, if the request headers have Connection: close, then the server will close its side of the connection immediately after finishing its response. In order to fully close the connection, simply close the output port. (I suggest doing this immediately after sending the HTTP request.)

If the request headers have Connection: keep-alive, multiple HTTP requests can be sent through the same TCP connection. The server won’t automatically close its side of the connection (unless it gets bored through inactivity). This situation is also simple to deal with: closing the output port will show the server that the requests are over, and it will close its side of the connection too.

Typed Racket definition

(provide socks5-connect)
(: socks5-connect (String Positive-Integer String Positive-Integer [#:username-password (Option (Pair Bytes Bytes))]
                   -> (Values Input-Port Output-Port)))
(define (socks5-connect socks-host socks-port dest-host dest-port #:username-password [username-password #f])
  «socks-connect-body»)

procedure

(make-socks5-proxy socks-host 
  socks-port 
  [matches? 
  #:username-password username-password]) 
  proxy?
  socks-host : string?
  socks-port : positive-integer?
  matches? : (url? . -> . boolean?) = (λ (_) #t)
  username-password : (cons/c bytes? bytes?) = #f
This is intended to only be used with the proxies feature of http-easy.

socks-host is the IP or hostname of the SOCKS5 server to connect to.

matches? is a function that takes a URL and returns whether it should be handled by this proxy.

As a limitation of the SOCKS5 protocol, the username and password will be transmitted through the network in cleartext.

#:username-password (optional) is a pair of a username and password to try, as bytes. Not all SOCKS5 servers require authentication.

Example usage

(define my-proxy (make-socks5-proxy "127.0.0.1" 1080))
(define my-session (make-session #:proxies (list my-proxy)))
(define my-response (session-request my-session "https://example.com"))
(response-body my-response)

Typed Racket definition

(provide make-socks5-proxy)
(: make-socks5-proxy ((String Positive-Integer) (Proxy-Matches? #:username-password (Option (Pair Bytes Bytes)))
                      . ->* . Proxy))
(define (make-socks5-proxy socks-host socks-port [matches? (λ (_) #t)] #:username-password [username-password #f])
  «make-socks5-proxy-body»)