| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- #!/usr/bin/perl
- # et_server/et_client: an "ssh -Rport" replacement.
- # Problem: webserver is behind a firewall without the possibility of opening a
- # hole in th firewall. Solution: start et_server on a publicly available host,
- # and connect to it via et_client from inside of the firewall.
- use warnings;
- use strict;
- use IO::Socket;
- die "Usage: et_server.pl controlPort serverPort\n"
- if(int(@ARGV) != 2);
- my $csfd = IO::Socket::INET->new(LocalPort=>$ARGV[0], Listen=>10, ReuseAddr=>1);
- die "Opening port $ARGV[0]: $!\n" if(!$csfd);
- my $sfd = IO::Socket::INET->new(LocalPort=>$ARGV[1], Listen=>10, ReuseAddr=>1);
- die "Opening port $ARGV[1]: $!\n" if(!$sfd);
- print "Serverports opened, waiting for et_client\n";
- my @clientinfo = $csfd->accept();
- my $cfd = $clientinfo[0];
- my ($port, $iaddr) = sockaddr_in($clientinfo[1]);
- print "et called from ".inet_ntoa($iaddr).":$port\n";
- my %clients;
- for(;;) {
- my ($rin,$rout) = ('','');
- vec($rin, $sfd->fileno(), 1) = 1;
- vec($rin, $cfd->fileno(), 1) = 1;
- vec($rin, $csfd->fileno(), 1) = 1;
- foreach my $c (keys %clients) {
- vec($rin, fileno($clients{$c}{fd}), 1) = 1;
- }
- my $nfound = select($rout=$rin, undef, undef, undef);
- if($nfound < 0) {
- print("select: $!");
- last;
- }
- # New server connection
- if(vec($rout, $sfd->fileno(), 1)) {
- #print "SRV: ACC\n";
- my @clientinfo = $sfd->accept();
- if(!@clientinfo) {
- print "Accept failed: $!";
- next;
- }
- my $fd = $clientinfo[0];
- $clients{$fd}{fd} = $fd;
- syswrite($cfd, "1");
- print "Local conn request\n";
- }
- # New et-line
- if(vec($rout, $csfd->fileno(), 1)) {
- #print "CTL: ACC\n";
- my @clientinfo = $csfd->accept();
- if(!@clientinfo) {
- print "Accept failed: $!\n";
- next;
- }
- my $fd = $clientinfo[0];
- my $peer;
- map { $peer = $_ if(!defined($clients{$_}{peer})) } keys %clients;
- if(!$peer) {
- close($fd);
- print "ET without request\n";
- next;
- }
- $clients{$fd}{fd} = $fd;
- my ($port, $iaddr) = sockaddr_in($clientinfo[1]);
- $clients{$fd}{fd} = $fd;
- $clients{$fd}{addr} = inet_ntoa($iaddr) . ":$port";
- $clients{$fd}{peer} = $peer;
- $clients{$peer}{peer} = $fd;
- if($clients{$peer}{buf}) {
- syswrite($fd, $clients{$peer}{buf});
- delete($clients{$peer}{buf});
- }
- print "ET line established\n";
- }
- if(vec($rout, $cfd->fileno(), 1)) {
- print "ET client left, exiting\n";
- exit(1);
- }
- # Data from one of the clients
- CLIENT:foreach my $c (keys %clients) {
- next if(!vec($rout, fileno($clients{$c}{fd}), 1));
- my $peer = $clients{$c}{peer}; $peer = "" if(!$peer);
- my $addr = $clients{$c}{addr}; $addr = "" if(!$addr);
- my $buf;
- my $ret = sysread($clients{$c}{fd}, $buf, 256);
- #print "C:$c: P:$peer R:$ret\n";
- if(!defined($ret) || $ret <= 0) {
- print "Client $addr left us\n";
- if($peer) {
- close($clients{$peer}{fd}); delete($clients{$peer});
- }
- close($clients{$c}{fd}); delete($clients{$c});
- last CLIENT;
- }
- if($peer) {
- while(length($buf)) {
- my $ret = syswrite($clients{$peer}{fd}, $buf);
- if(!$ret) {
- print "Write error to $peer from $c\n";
- close($clients{$peer}{fd}); delete($clients{$peer});
- close($clients{$c}{fd}); delete($clients{$c});
- last CLIENT;
- }
- $buf = substr($buf, $ret);
- }
- } else {
- $clients{$c}{buf} = "" if(!defined($clients{$c}{buf}));
- $clients{$c}{buf} .= $buf;
- }
- }
- }
|