My name is Philipp C. Heckel and I write about nerdy things.

Circumvent Internet blockages/filters/censorship with socksproxy and netcat


Linux, Scripting, Security

Circumvent Internet blockages/filters/censorship with socksproxy and netcat


These days, ISPs are often forced to block the access to certain sites, because their government considers these sites dangerous and/or illegal. While one could certainly discuss the usefulness of such measures in great detail, this tiny post focuses on the more interesting subject of how to circumvent these blockages. It’s not a lenghty post, and it doesn’t show all the ways there are, but I’ll show two simple ways to circumvent Internet non-DNS-based filters.


Content


1. The quick and dirty method (with nc, sed and mkfifo)

This is a method I discovered while I was analyzing the Internet filter of Virgin Media UK (of course, only out of curiosity!). It works good enough to browse a site, but it can only handle one connection at a time, so it’s not a long term solution.

The basic idea of this is based on the fact that some filters (including Virgin Media’s filter) can’t analyze the entire TCP stream, but only the beginning of it (maybe they can, but don’t want to). If they detect that the first HTTP request is for a blocked site, they intervene. If not, they let it through. Virgin Media’s filter is even dumber. A single new lines (\r\n) at the beginning of a TCP socket lets the rest of the traffic on that socket through:

While the above command is useful to retrieve a single HTML page or resource on the command line, it does not work from a web browser. To fix that, we can use a FIFO pipe and some more netcat magic. After running this command, we’ll be able to browse the blocked site by opening http://localhost:1337/ in the browser:

The basic idea of the approach above is to route all HTTP traffic for a certain site through a socket on localhost, modify that traffic on the fly, and then send it off to the actual server. In this case, all we want to do is add a new line before each GET request.

To open the socket on the localhost, nc -l -p 1337 (netcat) is used. This command opens a TCP socket and writes everything to STDOUT that is written to it, and redirects responses from STDIN to the client. In this case, all incoming requests are redirected to sed which is used to modify the incoming request: Here, we know that we’re browsing in the browser via http://localhost:1337/, but that the request are actually meant for http://blockedsite.tld/, so we’re replacing that (sed -u -e "s/localhost:1337/blockedsite.tld/"). In addition to that, we don’t want to retrieve any compressed content, so we’ll “disable” the Accept-Encoding header (sed -u -e "s/Accept-Encoding/X-Accept-Encoding/". The actual magic happens in sed -u -e "s/GET/\nGET/", when we prepend every GET request with an extra new line.

After the HTTP request has been altered, we send it off to the real site (nc blockedsite.tld 80). This will obviously only work if the DNS request resolves to the correct IP address. If not, enter the IP address of the site instead of blockedsite.tld above.

The HTTP response is again written to STDOUT, and by replacing blockedsite.tld with localhost:1337, we make sure that the links on that site still work (sed -u -e "s/blockedsite.tld/localhost:1337/g").

Lastly, we pipe the modified HTTP response to the named/FIFO pipe we created at /tmp/fifo. This named pipe is used to redirect the HTTP response back to netcat, which will then forward it to the browser. All in all, the flow looks like this:

Browser[HTTP GET] –> nc[localhost:1337] –> sed[modify HTTP GET] –> nc[redirect HTTP GET] –> Blockedsite –> nc[redirect HTTP response] –> sed[modify HTTP response] –> pipe[write to /tmp/fifo] –> cat[read from /tmp/fifo, write to STDOUT] –> nc[read from STDIN, write to socket] –> Browser[read HTTP response from socket]

2. The proper method (with a SOCKS proxy)

Since the above method probably doesn’t work for every ISP and for every filter, this method is much more generic. However, unlike the quick and dirty method above, it requires a a server in a non-blocked country. Assuming you have one like this, e.g. one in Germany, you can install a SOCKS proxy on it and forward IP packets through it. Using ssh -D, this can be achieved very easily. SOCKS wraps the TCP stream into its own protocol, and thereby slips through most of the filters. I’ve depicted tha tin the following picture:

It’s important to know that the communication is still unencrypted, so an ISP is technically able to block these connections as well. However monitoring all connections on all ports and all TCP streams is highly resource intensive and blockage is very unlikely.

2.1. Manual method (no extra software needed)

Running the following command on the server in the non-blocked country, the ssh command will act as a SOCKS proxy:

Once a client (e.g. a browser) is configured to use this proxy, all packets will be routed to this server and then to its final destination. Please note that this command will accept all connections, regardless of the IP address they are connecting from. To limit access to the proxy, make sure to only allow connections from your IP addresses. Assuming that 1.2.3.4 and 1.2.3.5 are allow, this is how this might look like:

2.2. socksproxy: The 2-minute method!

To ease the use of the ssh and iptables command, I’ve written a little script called socksproxy that automatically launches the SOCKS proxy at startup, and manages the allowed IP addresses automatically (or at least more easily). It is available on GitHub and releases are also published on my Debian/APT archive.

To install it, simply run the following commands (if you are on a Debian-based system):

Once you’ve installed it, edit the config file at /etc/socksproxy.conf and add the allowed IP addresses and (if you like) the port on which the proxy should run on:

Then start the SOCKS proxy by running:

You can now add it to your browser / operating system config and you are ready to surf via your proxy host. Using a browser extension such as FoxyProxy, you can easily switch between proxy and non-proxy mode:

Let me know if you have any questions, or if things don’t work they are supposed to!

2 Comments

  1. dmn

    Socks is not encrypted protocol, some people can misunderstand this.
    Setting up that kind of proxy on other host will not improve security.


  2. Philipp C. Heckel

    Thanks for the comment. I mentioned that, although it’s not highlighted: “It’s important to know that the communication is still unencrypted”. I’ll make it bold.