spacer Hacker Newsletter - a weekly newsletter of the best articles on startups, programming, and more. All links are curated by hand from Hacker News.

Unix Shell 43 Comments May 06, 2010

Turn any Linux computer into SOCKS5 proxy in one command

I thought I'd do a shorter article on catonmat this time. It goes hand in hand with my upcoming article series on "100% technical guide to anonymity" and it's much easier to write larger articles in smaller pieces. Then I can edit them together and produce the final article.

This article will be interesting for those who didn't know it already -- you can turn any Linux computer into a SOCKS5 (and SOCKS4) proxy in just one command:

ssh -N -D 0.0.0.0:1080 localhost

And it doesn't require root privileges. The ssh command starts up dynamic -D port forwarding on port 1080 and talks to the clients via SOCSK5 or SOCKS4 protocols, just like a regular SOCKS5 proxy would! The -N option makes sure ssh stays idle and doesn't execute any commands on localhost.

If you also wish the command to go into background as a daemon, then add -f option:

ssh -f -N -D 0.0.0.0:1080 localhost

To use it, just make your software use SOCKS5 proxy on your Linux computer's IP, port 1080, and you're done, all your requests now get proxied.

Access control can be implemented via iptables. For example, to allow only people from the ip 1.2.3.4 to use the SOCKS5 proxy, add the following iptables rules:

iptables -A INPUT --src 1.2.3.4 -p tcp --dport 1080 -j ACCEPT
iptables -A INPUT -p tcp --dport 1080 -j REJECT

The first rule says, allow anyone from 1.2.3.4 to connect to port 1080, and the other rule says, deny everyone else from connecting to port 1080.

Surely, executing iptables requires root privileges. If you don't have root privileges, and you don't want to leave your proxy open (and you really don't want to do that), you'll have to use some kind of a simple TCP proxy wrapper to do access control.

Here, I wrote one in Perl. It's called tcp-proxy.pl and it uses IO::Socket::INET to abstract sockets, and IO::Select to do connection multiplexing.

#!/usr/bin/perl
#

use warnings;
use strict;

use IO::Socket::INET;
use IO::Select;

my @allowed_ips = ('1.2.3.4', '5.6.7.8', '127.0.0.1', '192.168.1.2');
my $ioset = IO::Select->new;
my %socket_map;

my $debug = 1;

sub new_conn {
    my ($host, $port) = @_;
    return IO::Socket::INET->new(
        PeerAddr => $host,
        PeerPort => $port
    ) || die "Unable to connect to $host:$port: $!";
}

sub new_server {
    my ($host, $port) = @_;
    my $server = IO::Socket::INET->new(
        LocalAddr => $host,
        LocalPort => $port,
        ReuseAddr => 1,
        Listen    => 100
    ) || die "Unable to listen on $host:$port: $!";
}

sub new_connection {
    my $server = shift;
    my $client = $server->accept;
    my $client_ip = client_ip($client);

    unless (client_allowed($client)) {
        print "Connection from $client_ip denied.\n" if $debug;
        $client->close;
        return;
    }
    print "Connection from $client_ip accepted.\n" if $debug;

    my $remote = new_conn('localhost', 55555);
    $ioset->add($client);
    $ioset->add($remote);

    $socket_map{$client} = $remote;
    $socket_map{$remote} = $client;
}

sub close_connection {
    my $client = shift;
    my $client_ip = client_ip($client);
    my $remote = $socket_map{$client};
    
    $ioset->remove($client);
    $ioset->remove($remote);

    delete $socket_map{$client};
    delete $socket_map{$remote};

    $client->close;
    $remote->close;

    print "Connection from $client_ip closed.\n" if $debug;
}

sub client_ip {
    my $client = shift;
    return inet_ntoa($client->sockaddr);
}

sub client_allowed {
    my $client = shift;
    my $client_ip = client_ip($client);
    return grep { $_ eq $client_ip } @allowed_ips;
}

print "Starting a server on 0.0.0.0:1080\n";
my $server = new_server('0.0.0.0', 1080);
$ioset->add($server);

while (1) {
    for my $socket ($ioset->can_read) {
        if ($socket == $server) {
            new_connection($server);
        }
        else {
            next unless exists $socket_map{$socket};
            my $remote = $socket_map{$socket};
            my $buffer;
            my $read = $socket->sysread($buffer, 4096);
            if ($read) {
                $remote->syswrite($buffer);
            }
            else {
                close_connection($socket);
            }
        }
    }
}

To use it, you'll have to make a change to the previous configuration. Instead of running ssh SOCKS5 proxy on 0.0.0.0:1080, you'll need to run it on localhost:55555,

ssh -f -N -D 55555 localhost

After that, run the tcp-proxy.pl,

perl tcp-proxy.pl &

The TCP proxy will start listening on 0.0.0.0:1080 and will redirect only the allowed IPs in @allowed_ips list to localhost:55555.

Another possibility is to use another computer instead of your own as exit node. What I mean is you can do the following:

ssh -f -N -D 1080 other_computer.com

This will set up a SOCKS5 proxy on localhost:1080 but when you use it, ssh will automatically tunnel your requests (encrypted) via other_computer.com. This way you can hide what you're doing on the Internet from anyone who might be sniffing your link. They will see that you're doing something but the traffic will be encrypted so they won't be able to tell what you're doing.

That's it. You're now the proxy king!

Download tcp-proxy.pl

Download link: tcp proxy (tcp-proxy.pl)
Download URL: www.catonmat.net/download/tcp-proxy.pl
Downloaded: 2067 times

I also pushed the tcp-proxy.pl to GitHub: tcp-proxy.pl on GitHub. This project is also pretty nifty to generalize and make a program that redirects between any number of hosts:ports, not just two.

PS. I will probably also write "A definitive guide to ssh port forwarding" some time in the future because it's an interesting but little understood topic.

Tags: 1080, access control, io-select, io-socket, io-socket-net, iptables, perl, proxy, proxy server, socks4, socks5, ssh, tcp proxy
43 Comments 145,194 Views Short URL

Related Posts

  • A TCP Proxy in Perl
  • Announcing Tunnels for Browserling
  • Perl Special Variable Cheat Sheet
  • Christmas Tree in the Shell
  • Difference Between Edsger Dijkstra and Larry Wall
  • Perl's pack/unpack and printf Cheat Sheet
  • Golfing the Extraction of IP Addresses from ifconfig
  • Famous Perl One-Liners Explained, Part I: File Spacing
  • Recursive Regular Expressions
  • Traffic Accounting with Linux IPTables

Comments

spacer
matt musselman Permalink
May 06, 2010, 23:59

Thanks for writing this! It broke it down very nicely, and I've been meaning to learn more about this kind of stuff for a while now. I am definitely interested in reading "A definitive guide to ssh port forwarding" when that comes around.

Reply to this comment
spacer
Peteris Krumins pkrumins Permalink
May 07, 2010, 17:51

Thanks for the comment. If you follow my blog you'll know when I start writing it. It will probably be part of 100% technical guide to anonymity as it has much to do with anonymity. I will also split it up in several parts because it's easier to write articles incrementally.

Reply to this comment
spacer
Paul Anak George Albert paulgalbert Permalink
May 07, 2010, 00:42

Nicely written, and easy to understand. Well done!
I have been using ssh -f -n -N -D for quite sometimes, and it really helps.

Reply to this comment
spacer
Peteris Krumins pkrumins Permalink
May 07, 2010, 17:51

The -n is an option I hadn't noticed. Thanks for mentioning it.

Reply to this comment
spacer
Anon Permalink
May 07, 2010, 13:38

SOCKS, besides being an abysmally awful protocol, is not supported by the majority of Internet software, so the advice you give is of limited usefulness. When I am confronted with a thoroughly hostile firewall, I depend on Net::Proxy. Accept no lesser substitutes.

Reply to this comment
spacer
Peteris Krumins pkrumins Permalink
May 07, 2010, 18:13

On Linux you can LD_PRELOAD trick to make any software use a socks proxy. Socksify does that, also tsocks does that.

Net::Proxy indeed is a good one. Much better than my primitive tcp-proxy. But I wrote it out of curiosity, hadn't used IO::Socket and IO::Select in ages and wanted to refresh my knoweldge.

Reply to this comment
spacer
przemoc Permalink
May 11, 2010, 21:07

If you want to make some SOCKS proxy available to all your applications, possibly better way than using tsocks is implementing iptables-based solution with the help of redsocks (git repository). See my tip Making SOCKS proxy transparent for example.

Another useful (in this context) ssh option is -g, but it requires turning GatewayPorts on in sshd_config.

Reply to this comment
spacer
Wayne Scott Permalink
May 07, 2010, 14:09

You might want to checkout this command I have been using:

github.com/apenwarr/sshuttle

Reply to this comment
spacer
Peteris Krumins pkrumins Permalink
May 07, 2010, 18:04

Wow, that is awesome software. Thanks for linking. I'm going to try it!

Reply to this comment
spacer
imsorry sorry Permalink
May 07, 2010, 14:42

great tips.
if sshd port not 22,use "-p "
ssh -f -p your_sshd_port -n -N -D bindip:1080 localhost

Reply to this comment
spacer
Peteris Krumins pkrumins Permalink
May 07, 2010, 18:04

Good tip. Thanks for writing it!

Reply to this comment
spacer
just curious Permalink
May 07, 2010, 16:30

How much money do you make through ads?

Reply to this comment
spacer
Peteris Krumins pkrumins Permalink
May 07, 2010, 18:08

Not much.

Reply to this comment
spacer
Krum Permalink
May 07, 2010, 17:10

yes - thats a great feature of the ssh client. I used it quite often when i was too lazy to do vpn configs for some nets behind router - just running sshd with correct restriction on the gateway will save you alot of time (at least saved me, cause i am not admin :). But for some time I am just linking some remote ports on the localhost:
ssh -L 8080:localhost:80 someuser@somehost
Its quite usefull too if you have remote server behind router with access only to ssh port.
About the article - very usefull - thought about "-f" option and how nice its usage is

Reply to this comment
spacer
Peteris Krumins pkrumins Permalink
May 07, 2010, 18:12

Yes, local port forwarding is awesome. I am going to describe it in more detail in my definitive guide to ssh port forwarding.

Reply to this comment
spacer
Paul M. Permalink
May 07, 2010, 17:55

If you're concerned about limiting access to your ssh pseudo-proxy and it's running locally, why not just have ssh bind to localhost, rather than 0.0.0.0?

Reply to this comment
spacer
Peteris Krumins pkrumins Permalink
May 07, 2010, 18:11

For example, you want to give your friend socks5 access but you don't have root on the machine and you don't want everyone to have open access to it. Then as I described, you can start the socks5 proxy on, let's say, port 55555, and provide ip based access control via tcp-proxy.pl which would listen on port 0.0.0.0:1080 and forward requests to localhost:55555.

Reply to this comment
spacer
Paul Permalink
May 08, 2010, 08:19

>Turn any Linux computer into SOCKS5 proxy
Iptables, ok - but Perl and ssh on "any Linux computer"?!

Reply to this comment
spacer
Peteris Krumins pkrumins Permalink
May 08, 2010, 14:24

Yeah, Perl and ssh is almost on any Linux computer.

Reply to this comment
spacer
Satish Permalink
May 08, 2010, 10:56

I have been trying to proxy my IE instance in Win 7 to go through a similar setup via putty but unfortunately IE -> Options -> Connections -> Settings is disabled. I still haven't figured out how to get this working with IE though :(

Reply to this comment
spacer
Peteris Krumins pkrumins Permalink
May 08, 2010, 14:25

You must be using a limited user account.

Reply to this comment
spacer
Anonymous Permalink
May 08, 2010, 17:18

If you're into anonymity, check www.i2p2.de/

Reply to this comment
spacer
beneedy Permalink
May 09, 2010, 21:45

I think I have it partially working, but when I configure my browser with the proxy settings I just get a blank white screen to whatever website I am visiting. The webpage says it is done loading, but just no content... What do you think the problem is?

Reply to this comment
spacer
Catalin Permalink
May 11, 2010, 14:07

Nice , but i use python script not perl :D.

Reply to this comment
spacer
kangu Permalink
May 11, 2010, 18:27

Thanks petter it's well written and easy to follow on with!

Reply to this comment
spacer
mwicat Permalink
May 13, 2010, 08:10

when speaking about source host ACLs, socat utility fits perfectly in this task:
socat tcp-listen:4444,range=192.168.100.1/32,reuseaddr,fork tcp:localhost:3333

...to relay between 0.0.0.0:4444 and localhost:3333 passing only 192.168.100.1, range=192.168.100.0/24 for whole network and finally utilize the power of tcp wrappers with:
socat tcp-listen:4444,allow-table=iplist,reuseaddr,fork tcp:localhost:3333
# iplist contents:
ALL: 192.168.100.1: ALLOW
ALL: ALL: DENY

Reply to this comment
spacer
nme Permalink
May 13, 2010, 12:50

A lot of work which could be simplified. U use windows too much ;)

$ sudo -i
# iptables -N proxy_allowed
# iptables -A proxy_allowed -s [ALLOWED_IP] -j RETURN
[...]
# iptables -A proxy_allowed -j DROP
# iptables -A INPUT --syn --dport 1080 -j proxy_allowed
# exit
$
$ ssh -g -D 1080 [REMOTE_IP]

no wrapper is required. if u wish to harden the solution use some knocking (or ping with specified packet length and iptables "recent" module) and/or ip-mac association.

socks does not offer much, to redirect dns or udp traffic it is better to use ppp over ssh or vpn (which I consider preferred).. openvpn is free and there is extremally simple windows gui client.

take care!

ps. python > perl ;P

Reply to this comment
spacer
Alphazo Permalink
July 08, 2010, 07:44

100% agree... "-D 1080" is all what you need. I like to add -p 443 to in order to make the SSH traffic less visible ;)

Then to avoid DNS leaks under Firefox, just make sure to set the two following variables to 1 under about:config.

network.proxy.network.proxy.socks_remote_dns = 1
network.proxy.socks_remote_dns = 1

When I Wireshark the above config I can only see HTTPS traffic even when typing non-working URLs.

Reply to this comment
spacer
ctrl_ Permalink
May 18, 2010, 07:57

Is there a log file where I can see the traffic when doing this?

Reply to this comment
spacer
Ashok Permalink
August 19, 2010, 11:50

Is this wiki.przemoc.net/tips/linux#making_socks_proxy_transparent are same as SocksCap?

Reply to this comment
spacer
peter Permalink
August 25, 2010, 12:43
gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.