added bin/test.plto gitignore. Updated gp to loop
[clearscm.git] / bin / tunnel.pl
1 #!/usr/bin/perl
2
3 =pod
4
5 =head1 NAME $RCSfile: tunnel.pl,v $
6
7 Set up a tunnel for emailing
8
9 =head1 VERSION
10
11 =over
12
13 =item Author
14
15 Andrew DeFaria <Andrew@ClearSCM.com>
16
17 =item Revision:
18
19 $Revision: 1.0 $
20
21 =item Created:
22
23 Wed 19 Aug 2020 09:09:09 AM MST
24
25 =item Modified:
26
27 $Date: $
28
29 =back
30
31 =head1 SYNOPSIS
32
33   Usage: tunnel.pl [-u|sage] [-h|elp] [-ve|rbose] [-d|ebug]
34
35   Where:
36     -u|sage:      Displays this usage
37     -h|elp:       Display full help
38     -ve|rbose:    Be verbose
39     -d|ebug:      Output debug messages
40     -host1:       First host for tunnel (Default: localhost)
41     -port1:       Port for host1
42     -host2:       Second host for tunnel (Default: defaria.com)
43     -port2:       Port for host2
44     -a|nnounce:   Whether to announce startup (Default false)
45     -ap|pend      Append to logfile (Default: Noappend)
46     -maxtretries: Maximum number of retry attempt to reestablish tunnel
47                   (Default 3)
48     -nodaemon:    Whether to go into daemon mode (Default: Daemon mode)
49
50 =head1 DESCRIPTION
51
52 This script sets up an SSH tunnel for the purposes of emailing.
53
54 =cut
55
56 use strict;
57 use warnings;
58
59 use File::Temp qw(tempfile);
60 use FindBin;
61 use Getopt::Long;
62 use Net::OpenSSH;
63 use POSIX ':sys_wait_h';
64
65 use lib "$FindBin::Bin/../lib";
66
67 use Pod::Usage;
68
69 use Display;
70 use Logger;
71 use Speak;
72 use Utils;
73
74 local $0 = $FindBin::Script;
75
76 my $VERSION  = '$Revision: 1.0 $';
77   ($VERSION) = ($VERSION =~ /\$Revision: (.*) /);
78
79 my %opts = (
80   usage      => sub { pod2usage },
81   help       => sub { pod2usage (-verbose => 2)},
82   verbose    => sub { set_verbose },
83   debug      => sub { set_debug },
84   host1      => 'localhost',
85   port1      => 1025,
86   host2      => 'defaria.com',
87   port2      => 25,
88   remotehost => 'defaria.com',
89   maxretries => 3,
90 );
91
92 # Perlcritic complains if $DB::OUT is used only once.
93 no warnings;
94 $opts{daemon} = 1 unless defined $DB::OUT;
95 use warnings;
96
97 my ($log, $ssh);
98
99 sub Report ($;$) {
100   my ($msg, $err) = @_;
101
102   speak $msg, $log;
103
104   if ($err) {
105     $log->err($msg, $err);
106   } else {
107     $log->err($msg);
108   } # if
109
110   return;
111 } # Report
112
113 sub interrupt {
114    Report "Tunnel killed unexpectedly", 1;
115
116    kill 'INT', $ssh->get_master_pid;
117
118    return;
119 } # interrupt
120
121 sub tunnel() {
122   my $tunnelStr = "-NL$opts{host1}:$opts{port1}:$opts{host2}:$opts{port2}";
123
124   my $retryattempts = 0;
125
126 RETRY:
127   my ($fh, $filename) = tempfile;
128
129   $ssh = Net::OpenSSH->new(
130     $opts{remotehost},
131     master_opts         => $tunnelStr,
132     default_stderr_file => $filename
133   );
134
135   Report("Unable to establish ssh tunnel " . $ssh->error, 1) if $ssh->error;
136
137   # Check to see if address is already in use
138   my @lines = <$fh>;
139
140   close $fh;
141
142   unlink $filename;
143
144   if (grep { /address already in use/i } @lines) {
145     Report 'Unable to start tunnel - Address already in use', 1;
146   } else {
147     my $msg  = 'Ssh tunnel ';
148        $msg .= $retryattempts ? 'reestablished' : 'established';
149
150     speak $msg, $log if $opts{announce};
151
152     $log->msg($msg);
153
154     # Reset retry attempts since we reestablished the tunnel
155     $retryattempts = 0 if $retryattempts;
156
157     # Wait for master to exit
158     waitpid($ssh->get_master_pid, WUNTRACED);
159
160     Report("Ssh tunnel terminated unexpectedly - Maximum retry count hit ($opts{maxretries}) - giving up", 1)
161       if $retryattempts++ >= $opts{maxretries};
162
163     undef $ssh;
164
165     goto RETRY;
166   } # if
167
168   return;
169 } # tunnel
170
171 ## Main
172 GetOptions (
173   \%opts,
174   'usage',
175   'help',
176   'verbose',
177   'debug',
178   'host1',
179   'host2',
180   'port1',
181   'port2',
182   'announce!',
183   'maxretries=i',
184   'daemon!',
185   'append',
186 ) || Usage;
187
188 $log = Logger->new(
189   path        => '/var/local/log',
190   name        => "$Logger::me",
191   timestamped => 'yes',
192   append      => $opts{append},
193 );
194
195 $log->msg("$FindBin::Script v$VERSION");
196
197 $SIG{INT} = $SIG{TERM} = \&interrupt;
198
199 EnterDaemonMode unless $opts{daemon} and get_debug;
200
201 tunnel;