#! /usr/bin/perl ### ### this is to place an ssh tunnel to the SMTP server sending your messages and running a process that ### repeatedly sends a HELO/QUIT command pair to the server to keep the tunnelling alive, despite timeouts ### Copyright (C) 2006 Marco Danelutto, Dept. Computer Science, Univ. Pisa, Italy ### ### This program is free software; you can redistribute it and/or ### modify it under the terms of the GNU General Public License ### as published by the Free Software Foundation; either version 2 ### of the License, or (at your option) any later version. ### ### This program is distributed in the hope that it will be useful, ### but WITHOUT ANY WARRANTY; without even the implied warranty of ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ### GNU General Public License for more details. ### ### You should have received a copy of the GNU General Public License ### along with this program; if not, write to the Free Software ### Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ####################################################################################################################################### ### this are the default parameters used in case the -d option is specified or in case one of the parameters are not specified ####################################################################################################################################### $defaultLocalPort = 34343; ### dummy local port, probably unused $defaulttunnelhostname = "pacifico.di.unipi.it"; ### cannot tunnel directly on mailserver, therefore use another machine $defaultsmtpserver = "mailserver.di.unipi.it"; ### the target mailserver $defaultSeconds = 180; ### send an HELO/QUIT message onto the tunnel every 3 minutes, by default ### uncomment the following line to see debug printouts $debug = 1; ### comment this line to avoid printouts ... #################################################################################################################################### ######################################### do not modify code below this line ####################################################### #################################################################################################################################### $maiscriptversion = "1.01"; use Getopt::Std; use IO::Socket::INET; getopts("hl:t:s:m:dvu:"); if ($opt_h) { print "mailscript.pl [-h] -l localport -t tunnelhostname -s serverhostname -m keepaliveloopSeconds\n"; print " -h prints this help\n"; print " -l localport uses localport to set up the local end of the ssh tunnel. This is the port to be used to connect to SMTP server on localhost (127.0.0.1)\n"; print " -t tunnelhostname this is the name of the host to use for the tunnelling. Must be reachable by ssh \n"; print " -s serverhostname this is the name of the mailserver\n"; print " -m s this is the amount of minutes to wait before sending a new keepalive HELO/QUIT to the mailserver\n"; print " -u username this is the login name to be used on the remote host\n"; print " -d verbose mode on\n"; print " -v print the version number\n"; exit; } ### ### handle parameters from command line ### if ($opt_l) { $localport = $opt_l; } else { $localport = $defaultLocalPort; } print "Using local port $localport\n"; if ($opt_t) { $tunnelhostname = $opt_t; } else { $tunnelhostname =$defaulttunnelhostname; } if ($opt_s) { $smtpserver = $opt_s; } else { $smtpserver = $defaultsmtpserver; } if ($opt_m) { $seconds = $opt_m * 60; } else { $seconds = $defaultSeconds; } if ($opt_u) { $remoteusername = $opt_u."@"; } else { $remoteusername = ""; } if ($opt_v) { print "mailscript.pl version $maiscriptversion\n"; exit; } print "Performing keepalive each $seconds seconds\n"; ### ### set up process to perform tunnelling periodic "refresh" ### $pidRefresh = fork; if ($pidRefresh == 0) { ### ### this is the "refresh" process ### sleep ($seconds < $defaultSeconds ? $defaultSeconds : $seconds); ### wait for the tunnelling process started (this should be relaced by a more correct ### attempt to connect to the local port, actually if($debug) { print "Entering the refresh process .... \n"; } while(1==1) { if($debug) { print "Looping ... \n"; } ### in an infinite loop ### connect to the SMTP server $remote = "127.0.0.1"; $socket = IO::Socket::INET->new(PeerAddr => $remote, PeerPort => $localport, Proto => "tcp", Type => SOCK_STREAM) or die "Couldn't connect to $remote:$localport : $!\n"; ### in questo caso devo invece ritentare, visto che potrebbe essere terminata la connessione per via di uno sleep ### send an HELO message print $socket "HELO keep.me.alive\n"; ### wait answer and then send the quit message $answer = <$socket>; if($debug) { print "Sent HELO keep.me.alive\nReceived $answer\n"; } print $socket "QUIT"; ### that's all, connection alive $answer = <$socket>; if($debug) { print "Sent QUIT\nReceived $answer\n"; } close($socket); ### wait the loop timeout ... if($debug) { print "HELO/QUIT sent!\n"; } sleep $seconds; ### ... then restart } die "Error while executing refresh of ssh tunnel on port $localport\n"; } else { ### this is main process if($debug) { print "Tunnel refresh process created\n"; } $tunnelPid = fork; if ($tunnelPid == 0) { ### ### this is the tunnel process ... ### if($opt_d) { # -v or -d is the same ... plenty of options at the moment $debugssh = " -v -v -v "; } else { $debugssh = " "; } $tunnelcmd = "ssh $debugssh -N -L $localport:$smtpserver:25 $remoteusername$tunnelhostname"; if($debug) { print "Executing tunnel::)$tunnelcmd(::\n"; } exec $tunnelcmd or die "Cannot exec ssh tunnel command $tunnelcmd\n"; } else { ### this is the main process again print "Tunnel executed\n"; print "To interrupt the tunnel/keepalive service, please issue a ^C on the terminal\n"; sleep; $terminatecmd = "kill -9 $pidRefresh $tunnelPid"; if($debuf) { print "Going to execute a $terminatecmd\n"; } exit; } } die "terminated\n"; ###