From 0492d8ce897d3c98f97673b5d3fb312778865f63 Mon Sep 17 00:00:00 2001 From: rudolfkoenig <> Date: Tue, 19 Feb 2013 18:15:17 +0000 Subject: [PATCH] Connecting to a TCP/IP port behind a non-modified firewall git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@2766 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- contrib/et_client.pl | 91 ++++++++++++++++++++++++++++++ contrib/et_server.pl | 128 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 219 insertions(+) create mode 100644 contrib/et_client.pl create mode 100644 contrib/et_server.pl diff --git a/contrib/et_client.pl b/contrib/et_client.pl new file mode 100644 index 000000000..5467a55c8 --- /dev/null +++ b/contrib/et_client.pl @@ -0,0 +1,91 @@ +#!/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_client.pl et_serverhost:Port localhost:Port\n" + if(int(@ARGV) != 2); + +my $cfd = IO::Socket::INET->new(PeerAddr=>$ARGV[0]); +die "Opening port $ARGV[0]: $!\n" if(!$cfd); + +my %clients; +for(;;) { + my ($rin,$rout) = ('',''); + vec($rin, $cfd->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 et-line request + if(vec($rout, $cfd->fileno(), 1)) { + my $buf; + my $ret = sysread($cfd, $buf, 1); + if(!defined($ret) || $ret <= 0) { + print "ET_Server left us\n"; + exit(1); + } + my $fd1 = IO::Socket::INET->new(PeerAddr=>$ARGV[0]); + if(!$fd1) { + print "Connect to $ARGV[0] failed"; + exit(1); + } + my $fd2 = IO::Socket::INET->new(PeerAddr=>$ARGV[1]); + if(!$fd2) { + print "Connect to $ARGV[1] failed"; + exit(1); + } + + $clients{$fd1}{fd} = $fd1; + $clients{$fd2}{fd} = $fd2; + $clients{$fd1}{peer} = $fd2; + $clients{$fd2}{peer} = $fd1; + $clients{$fd1}{type} = "ET"; + $clients{$fd2}{type} = "LC"; + print "ET line established\n"; + } + + # Data from one of the clients +CLIENT:foreach my $c (keys %clients) { + my $fno = fileno($clients{$c}{fd}); + next if(!vec($rout, $fno, 1)); + + my $peer = $clients{$c}{peer}; + + my $buf; + my $ret = sysread($clients{$c}{fd}, $buf, 256); + #print "$c: $ret\n"; + if(!defined($ret) || $ret <= 0) { + print "Client $fno left us ($clients{$c}{type})\n"; + if($peer) { + close($clients{$peer}{fd}); delete($clients{$peer}); + } + close($clients{$c}{fd}); delete($clients{$c}); + last CLIENT; + } + + while(length($buf)) { + my $ret = syswrite($clients{$peer}{fd}, $buf); + if(!$ret) { + print "Write error to peer of $fno ($clients{$c}{type})\n"; + close($clients{$peer}{fd}); delete($clients{$peer}); + close($clients{$c}{fd}); delete($clients{$c}); + last CLIENT; + } + $buf = substr($buf, $ret); + } + + } +} diff --git a/contrib/et_server.pl b/contrib/et_server.pl new file mode 100644 index 000000000..940604aca --- /dev/null +++ b/contrib/et_server.pl @@ -0,0 +1,128 @@ +#!/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; + + } + } +}