New tunnel.pl
authorAndrew DeFaria <Andrew@DeFaria.com>
Fri, 19 Feb 2021 22:21:25 +0000 (14:21 -0800)
committerAndrew DeFaria <Andrew@DeFaria.com>
Fri, 19 Feb 2021 22:21:25 +0000 (14:21 -0800)
This now handles establishing the ssh tunnel for the propose of
tunneling email. Will handle restarting tunnel if it fails.

Still need to be able to test if the ssh tunnel is responding when the
network is switched to the VPN and back.

bin/tunnel.pl [new file with mode: 0755]
lib/Display.pm

diff --git a/bin/tunnel.pl b/bin/tunnel.pl
new file mode 100755 (executable)
index 0000000..2ee85f0
--- /dev/null
@@ -0,0 +1,211 @@
+#!/usr/bin/perl
+
+=pod
+
+=head1 NAME $RCSfile: tunnel.pl,v $
+
+Set up a tunnel for emailing
+
+=head1 VERSION
+
+=over
+
+=item Author
+
+Andrew DeFaria <Andrew@ClearSCM.com>
+
+=item Revision:
+
+$Revision: 1.0 $
+
+=item Created:
+
+Wed 19 Aug 2020 09:09:09 AM MST
+
+=item Modified:
+
+$Date: $
+
+=back
+
+=head1 SYNOPSIS
+
+ Usage: tunnel.pl [-u|sage] [-h|elp] [-ve|rbose] [-d|ebug]
+ Where:
+
+ -u|sage:      Displays this usage
+ -h|elp:       Display full help
+ -ve|rbose:    Be verbose
+ -d|ebug:      Output debug messages
+ -host1:       First host for tunnel (Default: localhost)
+ -port1:       Port for host1
+ -host2:       Second host for tunnel (Default: defaria.com)
+ -port2:       Port for host2
+ -a|nnounce:   Whether to announce startup (Default false)
+ -maxtretries: Maximum number of retry attempt to reestablish tunnel
+               (Default 3)
+ -nodaemon:    Whether to go into daemon mode (Default: Daemon mode)
+
+=head1 DESCRIPTION
+
+This script sets up an SSH tunnel for the purposes of emailing.
+
+=cut
+
+use strict;
+use warnings;
+
+use File::Temp qw(tempfile);
+use FindBin;
+use Getopt::Long;
+use Net::OpenSSH;
+use POSIX ':sys_wait_h';
+
+use lib "$FindBin::Bin/../lib";
+
+use Pod::Usage;
+
+use Display;
+use Logger;
+use Utils;
+
+my $VERSION  = '$Revision: 1.0 $';
+  ($VERSION) = ($VERSION =~ /\$Revision: (.*) /);
+
+my %opts = (
+  usage      => sub { pod2usage },
+  help       => sub { pod2usage (-verbose => 2)},
+  verbose    => sub { set_verbose },
+  debug      => sub { set_debug },
+  host1      => 'localhost',
+  port1      => 1025,
+  host2      => 'defaria.com',
+  port2      => 25,
+  remotehost => 'defaria.com',
+  maxretries => 3,
+  daemon     => 1,
+);
+
+my ($log, $ssh);
+
+sub Say($) {
+  my ($msg) = @_;
+
+  if (-f "$FindBin::Bin/shh") {
+    $log->msg("Not speaking because we were asked to be quiet - $msg");
+
+    return;
+  } # if
+
+  my ($status, @output) = Execute "/usr/local/bin/gt \"$msg\"";
+
+  $log->err("Unable to speak (Status: $status) - "
+          . join ("\n", @output), $status) if $status;
+
+  return;
+} # Say
+
+sub Report ($;$) {
+  my ($msg, $err) = @_;
+
+  Say $msg;
+
+  if ($err) {
+    $log->err($msg, $err);
+  } else {
+    $log->err($msg);
+  } # if
+
+  return;
+} # Report
+
+sub interrupt {
+   Report "Tunnel killed unexpectedly", 1;
+
+   kill 'INT', $ssh->get_master_pid;
+} # interrupt
+
+sub tunnel() {
+  my $tunnelStr = "-NL$opts{host1}:$opts{port1}:$opts{host2}:$opts{port2}";
+
+  my $retryattempts = 0;
+
+RETRY:
+  my ($fh, $filename) = tempfile;
+
+  my $ssh = Net::OpenSSH->new(
+    $opts{remotehost},
+    master_opts         => $tunnelStr,
+    default_stderr_file => $filename
+  );
+
+  Report("Unable to establish ssh tunnel " . $ssh->error, 1) if $ssh->error;
+
+  my @lines = <$fh>;
+
+  close $fh;
+
+  unlink $filename;
+
+  if (grep /address already in use/i, @lines) {
+    Report 'Unable to start tunnel - Address already in use', 1;
+  } else {
+    my $msg  = 'Ssh tunnel ';
+       $msg .= $retryattempts ? 'reestablished' : 'established';
+
+    Say $msg if $opts{announce};
+
+    $log->msg($msg);
+
+    # Wait for master to exit
+    waitpid($ssh->get_master_pid, WUNTRACED);
+
+    Report("Ssh tunnel terminated unexpectedly - Maximum retry count hit ($opts{maxretries}) - giving up", 1)
+      if $retryattempts++ >= $opts{maxretries};
+
+    $opts{announce} = $retryattempts;
+
+    Report 'Ssh tunnel terminated unexpectedly - Attempting restart';
+
+    goto RETRY;
+  } # if
+
+  return;
+} # tunnel
+
+## Main
+GetOptions (
+  \%opts,
+  'usage',
+  'help',
+  'verbose',
+  'debug',
+  'host1',
+  'host2',
+  'port1',
+  'port2',
+  'announce!',
+  'maxretries=i',
+  'daemon!',
+) || Usage;
+
+# Turn off daemon mode if we are in the Perl debugger;
+no warnings; # Ignore warning about used only once $DB::OUT when not in debugger
+$opts{daemon} = 0 if defined $DB::OUT;
+use warnings;
+
+$log = Logger->new(
+  path        => '/var/log',
+  name        => "$Logger::me",
+  timestamped => 'yes',
+  append      => 'yes',
+);
+
+$log->msg("$FindBin::Script v$VERSION");
+
+$SIG{INT} = $SIG{TERM} = \&interrupt;
+
+EnterDaemonMode if $opts{daemon};
+
+tunnel;
index f73a54b..d04471f 100644 (file)
@@ -153,11 +153,11 @@ Parameters:
 
 Message to display
 
 
 Message to display
 
-=item $handle:       
+=item $handle:
 
 File handle to display to (Default: STDERR)
 
 
 File handle to display to (Default: STDERR)
 
-=item $nolinefeed:   
+=item $nolinefeed:
 
 If defined no linefeed is displayed at the end of the message.
 
 
 If defined no linefeed is displayed at the end of the message.
 
@@ -185,28 +185,28 @@ Returns:
 
   return
     unless $debug;
 
   return
     unless $debug;
-  
+
   return
     if $debug == 0;
   return
     if $debug == 0;
-    
+
   $level ||= 1;
   $msg   ||= '';
 
   if (($handle and -t $handle) or (-t *STDERR)) {
     $msg = color ('cyan')
          . $me
   $level ||= 1;
   $msg   ||= '';
 
   if (($handle and -t $handle) or (-t *STDERR)) {
     $msg = color ('cyan')
          . $me
-        . color ('reset')
-        . ": "
-        . color ('magenta')
-        . "DEBUG"
-        . color ('reset')
-        . ": $msg";
+         . color ('reset')
+         . ': '
+         . color ('magenta')
+         . "DEBUG"
+         . color ('reset')
+         . ": $msg";
   } else {
     $msg = "$me: DEBUG: $msg";
   } # if
 
   display_err $msg, $handle, $nolinefeed if $debug and $level <= $debug;
   } else {
     $msg = "$me: DEBUG: $msg";
   } # if
 
   display_err $msg, $handle, $nolinefeed if $debug and $level <= $debug;
-  
+
   return;
 } # debug
 
   return;
 } # debug
 
@@ -214,13 +214,13 @@ sub debug1 ($;$$) {
   my ($msg, $handle, $nolinefeed) = @_;
 
   debug $msg, $handle, $nolinefeed, 1;
   my ($msg, $handle, $nolinefeed) = @_;
 
   debug $msg, $handle, $nolinefeed, 1;
-  
+
   return;
 } # debug1
 
 sub debug2 ($;$$) {
   my ($msg, $handle, $nolinefeed) = @_;
   return;
 } # debug1
 
 sub debug2 ($;$$) {
   my ($msg, $handle, $nolinefeed) = @_;
+
   debug $msg, $handle, $nolinefeed, 2;
 
   return;
   debug $msg, $handle, $nolinefeed, 2;
 
   return;
@@ -228,7 +228,7 @@ sub debug2 ($;$$) {
 
 sub debug3 ($;$$) {
   my ($msg, $handle, $nolinefeed) = @_;
 
 sub debug3 ($;$$) {
   my ($msg, $handle, $nolinefeed) = @_;
+
   debug $msg, $handle, $nolinefeed, 2;
 
   return;
   debug $msg, $handle, $nolinefeed, 2;
 
   return;
@@ -254,11 +254,11 @@ Parameters:
 
 Message to display
 
 
 Message to display
 
-=item $handle:       
+=item $handle:
 
 File handle to display to (Default: STDOUT)
 
 
 File handle to display to (Default: STDOUT)
 
-=item $nolinefeed:   
+=item $nolinefeed:
 
 If defined no linefeed is displayed at the end of the message.
 
 
 If defined no linefeed is displayed at the end of the message.
 
@@ -285,7 +285,7 @@ Returns:
 
   print $handle $msg;
   print $handle "\n" unless $nolinefeed;
 
   print $handle $msg;
   print $handle "\n" unless $nolinefeed;
-  
+
   return;
 } # display
 
   return;
 } # display
 
@@ -339,13 +339,13 @@ Returns:
 
   print $handle $msg;
   print $handle "\n" if !$nolinefeed;
 
   print $handle $msg;
   print $handle "\n" if !$nolinefeed;
-  
+
   return;
 } # display_err
 
 sub display_error ($;$$$) {
   my ($msg, $errno, $handle, $nolinefeed) = @_;
   return;
 } # display_err
 
 sub display_error ($;$$$) {
   my ($msg, $errno, $handle, $nolinefeed) = @_;
-  
+
 =pod
 
 =head2 display_error ($msg, $errno, $handle, $nolinefeed)
 =pod
 
 =head2 display_error ($msg, $errno, $handle, $nolinefeed)
@@ -393,37 +393,37 @@ Returns:
 =cut
 
   $msg ||= '';
 =cut
 
   $msg ||= '';
-  
+
   unless ($errno) {
     if (($handle and -t $handle) or (-t *STDERR) and ($Config{perl} ne 'ratlperl')) {
       $msg = color ('cyan') 
            . $me
            . color ('reset')
   unless ($errno) {
     if (($handle and -t $handle) or (-t *STDERR) and ($Config{perl} ne 'ratlperl')) {
       $msg = color ('cyan') 
            . $me
            . color ('reset')
-          . ": "
-          . color ('red')
-          . "ERROR"
-          . color ('reset')
-          . ": $msg";
+           . ': '
+           . color ('red')
+           . 'ERROR'
+           . color ('reset')
+           . ": $msg";
     } else {
       $msg = "$me: ERROR: $msg";
     } # if
   } else {
     if (($handle and -t $handle) or (-t *STDERR) and ($Config{perl} ne 'ratlperl')) {
       $msg = color ('cyan')
     } else {
       $msg = "$me: ERROR: $msg";
     } # if
   } else {
     if (($handle and -t $handle) or (-t *STDERR) and ($Config{perl} ne 'ratlperl')) {
       $msg = color ('cyan')
-          . $me
-          . color ('reset')
-          . ": "
-          . color ('red')
-          . "ERROR #$errno"
-          . color ('reset')
-          . ": $msg";
+           . $me
+           . color ('reset')
+           . ': '
+           . color ('red')
+           . "ERROR #$errno"
+           . color ('reset')
+           . ": $msg";
     } else {
       $msg = "$me: ERROR #$errno: $msg";
     } # if
   } # if
 
   display_err $msg, $handle, $nolinefeed;
     } else {
       $msg = "$me: ERROR #$errno: $msg";
     } # if
   } # if
 
   display_err $msg, $handle, $nolinefeed;
-  
+
   return;
 } # display_error
 
   return;
 } # display_error
 
@@ -446,7 +446,7 @@ Parameters:
 
 Message to display
 
 
 Message to display
 
-=item $handle:       
+=item $handle:
 
 File handle to display to (Default: STDOUT)
 
 
 File handle to display to (Default: STDOUT)
 
@@ -469,7 +469,7 @@ Returns:
 =cut
 
   display $msg, $handle, "nolf";
 =cut
 
   display $msg, $handle, "nolf";
-  
+
   return;
 } # display_nolf
 
   return;
 } # display_nolf
 
@@ -496,7 +496,7 @@ Parameters:
 
 Message to display
 
 
 Message to display
 
-=item $handle:       
+=item $handle:
 
 File handle to display to (Default: STDOUT)
 
 
 File handle to display to (Default: STDOUT)
 
@@ -525,7 +525,7 @@ Returns:
   display_error $msg, $errno, $handle, $nolinefeed;
 
   exit $errno if $errno;
   display_error $msg, $errno, $handle, $nolinefeed;
 
   exit $errno if $errno;
-  
+
   return;
 } # error
 
   return;
 } # error
 
@@ -709,7 +709,7 @@ Returns:
 
 sub set_me {
   my ($whoami) = @_;
 
 sub set_me {
   my ($whoami) = @_;
-  
+
 =pod
 
 =head2 set_me ($me)
 =pod
 
 =head2 set_me ($me)
@@ -742,7 +742,7 @@ Returns:
 =cut
 
   $me = $whoami;
 =cut
 
   $me = $whoami;
-  
+
   return;
 } # set_me
 
   return;
 } # set_me
 
@@ -880,7 +880,7 @@ Returns:
 
   return
     unless $trace;
 
   return
     unless $trace;
-    
+
   $msg    = $msg  ? ": $msg" : '';
   $type ||= 'In';
 
   $msg    = $msg  ? ": $msg" : '';
   $type ||= 'In';
 
@@ -902,21 +902,21 @@ Returns:
   if (-t STDOUT) {
     display color ('cyan')
           . "$type "
   if (-t STDOUT) {
     display color ('cyan')
           . "$type "
-         . color ('yellow')
-         . color ('bold')
-         . $subroutine
-         . color ('reset')
-         . $msg;
+          . color ('yellow')
+          . color ('bold')
+          . $subroutine
+          . color ('reset')
+          . $msg;
   } else {
     display "$type $subroutine$msg";
   } else {
     display "$type $subroutine$msg";
-  } # if    
+  } # if
 
   return $subroutine;
 } # trace
 
 sub trace_enter (;$) {
   my ($msg) = @_;
 
   return $subroutine;
 } # trace
 
 sub trace_enter (;$) {
   my ($msg) = @_;
-  
+
 =pod
 
 =head2 trace_enter
 =pod
 
 =head2 trace_enter
@@ -956,7 +956,7 @@ Returns:
 
 sub trace_exit (;$) {
   my ($msg) = @_;
 
 sub trace_exit (;$) {
   my ($msg) = @_;
-  
+
 =pod
 
 =head2 trace_exit
 =pod
 
 =head2 trace_exit
@@ -993,7 +993,7 @@ Returns:
 =cut
 
   trace $msg, "EXIT";
 =cut
 
   trace $msg, "EXIT";
-  
+
   return
 } # trace_exit
 
   return
 } # trace_exit
 
@@ -1055,33 +1055,33 @@ Returns:
 
   $level   ||= 1;
   $verbose ||= 0;
 
   $level   ||= 1;
   $verbose ||= 0;
-  
+
   display $msg, $handle, $nolinefeed if $verbose and $level <= $verbose;
   display $msg, $handle, $nolinefeed if $verbose and $level <= $verbose;
-  
+
   return;
 } # verbose
 
 sub verbose1 ($;$$) {
   my ($msg, $handle, $nolinefeed) = @_;
   return;
 } # verbose
 
 sub verbose1 ($;$$) {
   my ($msg, $handle, $nolinefeed) = @_;
-  
+
   verbose $msg, $$handle, $nolinefeed, 1;
   verbose $msg, $$handle, $nolinefeed, 1;
-  
+
   return;
 } # verbose1
 
 sub verbose2 ($;$$) {
   my ($msg, $handle, $nolinefeed) = @_;
   return;
 } # verbose1
 
 sub verbose2 ($;$$) {
   my ($msg, $handle, $nolinefeed) = @_;
-  
+
   verbose $msg, $handle, $nolinefeed, 2;
   verbose $msg, $handle, $nolinefeed, 2;
-  
+
   return;
 } # verbose1
 
 sub verbose3 ($;$$) {
   my ($msg, $handle, $nolinefeed) = @_;
   return;
 } # verbose1
 
 sub verbose3 ($;$$) {
   my ($msg, $handle, $nolinefeed) = @_;
-  
+
   verbose $msg, $handle, $nolinefeed, 3;
   verbose $msg, $handle, $nolinefeed, 3;
-  
+
   return;
 } # verbose1
 
   return;
 } # verbose1
 
@@ -1127,7 +1127,7 @@ Returns:
 =cut
 
   verbose $msg, $handle, "nolf";
 =cut
 
   verbose $msg, $handle, "nolf";
-  
+
   return;
 } # verbose_nolf
 
   return;
 } # verbose_nolf
 
@@ -1152,11 +1152,11 @@ Parameters:
 
 Message to display
 
 
 Message to display
 
-=item $handle:       
+=item $handle:
 
 File handle to display to (Default: STDOUT)
 
 
 File handle to display to (Default: STDOUT)
 
-=item $nolinefeed:   
+=item $nolinefeed:
 
 If defined no linefeed is displayed at the end of the message.
 
 
 If defined no linefeed is displayed at the end of the message.
 
@@ -1183,33 +1183,33 @@ Returns:
   unless ($warnno) {
     if (($handle and -t $handle) or (-t *STDERR) and ($Config{perl} ne 'ratlperl')) {
       $msg = color ('cyan')
   unless ($warnno) {
     if (($handle and -t $handle) or (-t *STDERR) and ($Config{perl} ne 'ratlperl')) {
       $msg = color ('cyan')
-          . $me
-          . color ('reset')
-          . ": "
-          . color ('yellow')
-          . "WARNING"
-          . color ('reset')
-          . ": $msg";
+           . $me
+           . color ('reset')
+           . ": "
+           . color ('yellow')
+           . "WARNING"
+           . color ('reset')
+           . ": $msg";
     } else {
       $msg = "$me: WARNING: $msg";
     } # if
   } else {
     if (($handle and -t $handle) or (-t *STDERR) and ($Config{perl} ne 'ratlperl')) {
       $msg = color ('cyan')
     } else {
       $msg = "$me: WARNING: $msg";
     } # if
   } else {
     if (($handle and -t $handle) or (-t *STDERR) and ($Config{perl} ne 'ratlperl')) {
       $msg = color ('cyan')
-          . $me
-          . color ('reset')
-          . ": "
-          . color ('yellow')
-          . "WARNING #$warnno"
-          . color ('reset')
-          . ": $msg";
+           . $me
+           . color ('reset')
+           . ": "
+           . color ('yellow')
+           . "WARNING #$warnno"
+           . color ('reset')
+           . ": $msg";
     } else {
       $msg = "$me: WARNING #$warnno: $msg";
     } # if
   } # if
 
   display_err $msg, $handle, $nolinefeed;
     } else {
       $msg = "$me: WARNING #$warnno: $msg";
     } # if
   } # if
 
   display_err $msg, $handle, $nolinefeed;
-  
+
   return;
 } # warning
 
   return;
 } # warning