et_server.pl 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. #!/usr/bin/perl
  2. # et_server/et_client: an "ssh -Rport" replacement.
  3. # Problem: webserver is behind a firewall without the possibility of opening a
  4. # hole in th firewall. Solution: start et_server on a publicly available host,
  5. # and connect to it via et_client from inside of the firewall.
  6. use warnings;
  7. use strict;
  8. use IO::Socket;
  9. die "Usage: et_server.pl controlPort serverPort\n"
  10. if(int(@ARGV) != 2);
  11. my $csfd = IO::Socket::INET->new(LocalPort=>$ARGV[0], Listen=>10, ReuseAddr=>1);
  12. die "Opening port $ARGV[0]: $!\n" if(!$csfd);
  13. my $sfd = IO::Socket::INET->new(LocalPort=>$ARGV[1], Listen=>10, ReuseAddr=>1);
  14. die "Opening port $ARGV[1]: $!\n" if(!$sfd);
  15. print "Serverports opened, waiting for et_client\n";
  16. my @clientinfo = $csfd->accept();
  17. my $cfd = $clientinfo[0];
  18. my ($port, $iaddr) = sockaddr_in($clientinfo[1]);
  19. print "et called from ".inet_ntoa($iaddr).":$port\n";
  20. my %clients;
  21. for(;;) {
  22. my ($rin,$rout) = ('','');
  23. vec($rin, $sfd->fileno(), 1) = 1;
  24. vec($rin, $cfd->fileno(), 1) = 1;
  25. vec($rin, $csfd->fileno(), 1) = 1;
  26. foreach my $c (keys %clients) {
  27. vec($rin, fileno($clients{$c}{fd}), 1) = 1;
  28. }
  29. my $nfound = select($rout=$rin, undef, undef, undef);
  30. if($nfound < 0) {
  31. print("select: $!");
  32. last;
  33. }
  34. # New server connection
  35. if(vec($rout, $sfd->fileno(), 1)) {
  36. #print "SRV: ACC\n";
  37. my @clientinfo = $sfd->accept();
  38. if(!@clientinfo) {
  39. print "Accept failed: $!";
  40. next;
  41. }
  42. my $fd = $clientinfo[0];
  43. $clients{$fd}{fd} = $fd;
  44. syswrite($cfd, "1");
  45. print "Local conn request\n";
  46. }
  47. # New et-line
  48. if(vec($rout, $csfd->fileno(), 1)) {
  49. #print "CTL: ACC\n";
  50. my @clientinfo = $csfd->accept();
  51. if(!@clientinfo) {
  52. print "Accept failed: $!\n";
  53. next;
  54. }
  55. my $fd = $clientinfo[0];
  56. my $peer;
  57. map { $peer = $_ if(!defined($clients{$_}{peer})) } keys %clients;
  58. if(!$peer) {
  59. close($fd);
  60. print "ET without request\n";
  61. next;
  62. }
  63. $clients{$fd}{fd} = $fd;
  64. my ($port, $iaddr) = sockaddr_in($clientinfo[1]);
  65. $clients{$fd}{fd} = $fd;
  66. $clients{$fd}{addr} = inet_ntoa($iaddr) . ":$port";
  67. $clients{$fd}{peer} = $peer;
  68. $clients{$peer}{peer} = $fd;
  69. if($clients{$peer}{buf}) {
  70. syswrite($fd, $clients{$peer}{buf});
  71. delete($clients{$peer}{buf});
  72. }
  73. print "ET line established\n";
  74. }
  75. if(vec($rout, $cfd->fileno(), 1)) {
  76. print "ET client left, exiting\n";
  77. exit(1);
  78. }
  79. # Data from one of the clients
  80. CLIENT:foreach my $c (keys %clients) {
  81. next if(!vec($rout, fileno($clients{$c}{fd}), 1));
  82. my $peer = $clients{$c}{peer}; $peer = "" if(!$peer);
  83. my $addr = $clients{$c}{addr}; $addr = "" if(!$addr);
  84. my $buf;
  85. my $ret = sysread($clients{$c}{fd}, $buf, 256);
  86. #print "C:$c: P:$peer R:$ret\n";
  87. if(!defined($ret) || $ret <= 0) {
  88. print "Client $addr left us\n";
  89. if($peer) {
  90. close($clients{$peer}{fd}); delete($clients{$peer});
  91. }
  92. close($clients{$c}{fd}); delete($clients{$c});
  93. last CLIENT;
  94. }
  95. if($peer) {
  96. while(length($buf)) {
  97. my $ret = syswrite($clients{$peer}{fd}, $buf);
  98. if(!$ret) {
  99. print "Write error to $peer from $c\n";
  100. close($clients{$peer}{fd}); delete($clients{$peer});
  101. close($clients{$c}{fd}); delete($clients{$c});
  102. last CLIENT;
  103. }
  104. $buf = substr($buf, $ret);
  105. }
  106. } else {
  107. $clients{$c}{buf} = "" if(!defined($clients{$c}{buf}));
  108. $clients{$c}{buf} .= $buf;
  109. }
  110. }
  111. }