Git fork
at reftables-rust 48 lines 1.2 kB view raw
1use strict; 2use IO::Select; 3use IO::Socket::UNIX; 4use IO::Socket::INET; 5 6my $path = shift; 7 8unlink($path); 9my $server = IO::Socket::UNIX->new(Listen => 1, Local => $path) 10 or die "unable to listen on $path: $!"; 11 12$| = 1; 13print "ready\n"; 14 15while (my $client = $server->accept()) { 16 sysread $client, my $buf, 8; 17 my ($version, $cmd, $port, $ip) = unpack 'CCnN', $buf; 18 next unless $version == 4; # socks4 19 next unless $cmd == 1; # TCP stream connection 20 21 # skip NUL-terminated id 22 while (sysread $client, my $char, 1) { 23 last unless ord($char); 24 } 25 26 # version(0), reply(5a == granted), port (ignored), ip (ignored) 27 syswrite $client, "\x00\x5a\x00\x00\x00\x00\x00\x00"; 28 29 my $remote = IO::Socket::INET->new(PeerHost => $ip, PeerPort => $port) 30 or die "unable to connect to $ip/$port: $!"; 31 32 my $io = IO::Select->new($client, $remote); 33 while ($io->count) { 34 for my $fh ($io->can_read(0)) { 35 for my $pair ([$client, $remote], [$remote, $client]) { 36 my ($from, $to) = @$pair; 37 next unless $fh == $from; 38 39 my $r = sysread $from, my $buf, 1024; 40 if (!defined $r || $r <= 0) { 41 $io->remove($from); 42 next; 43 } 44 syswrite $to, $buf; 45 } 46 } 47 } 48}