#!/usr/local/bin/perl # # $Id: smtpkill,v 1.3 2002/06/11 14:24:57 dgregor Exp $ # # Copyright (c) 1998 Daniel J. Gregor, Jr., All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by Daniel J. Gregor, Jr. # 4. The name of Daniel J. Gregor, Jr. may not be used to endorse or promote # products derived from this software without specific prior written # permission. # # THIS SOFTWARE IS PROVIDED BY DANIEL J. GREGOR, JR. ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL DANIEL J. GREGOR, JR. BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # use IO::Socket; use IO::Select; use FileHandle; use POSIX; $usage = "smtpkill.pl [-p ] [-s ] [-b ] [-i ] [-w ] [-n ] [-l ] [-v] [-d] "; require 'getopt.pl'; chomp($hostname = `hostname`); $opt_p = 25; $opt_v = undef; # verbose $opt_d = undef; # debug $opt_q = undef; # quiet $opt_s = "Test message from smtpkill $hostname sent %c (Epoch: %s)"; $opt_b = "Test message"; $opt_B = undef; # A body file $opt_w = 0; # Wait between sending messages $opt_n = 1; # Number of children $opt_l = undef; # length of time to run $opt_i = undef; # Number of messages to send Getopt('psbwnliB'); die "Invalid number of arguments\nUsage:\t$usage\n" unless @ARGV == 3; if (defined($opt_i) && defined($opt_l)) { die "The options -i and -l are mutually exclusive\n"; } if (defined($opt_B)) { open(FILE, "<$opt_B") || die "could not open $opt_B: $!\n"; $opt_b = join('', ); } $host = shift(@ARGV); $from_addr = shift(@ARGV); $to_addr = shift(@ARGV); die "Number of children be greater than zero\n" unless ($opt_n > 0); $SIG{'INT'} = \&dokill; $parentpid = $$; $parentbegintime = time(); for ($children = 1; $children <= $opt_n; $children++) { warn "Starting child ${children}.\n" if $opt_v; unless (($childpid = fork())) { # this is the child $begintime = time(); $SIG{'INT'} = \&statsdie; for ($attempts = $count = 0; defined($opt_i) ? ($count < $opt_i) : 1; $attempts++) { sendmessage() && $count++; } statsdie(); } push(@children, $childpid); } warn "All children started.\n" if $opt_v; warn "*** Hit control-C to end test ***\n"; if ($opt_l) { sleep($opt_l); } else { while (@children > 0) { wait(); for ($i = 0; $i < @children; $i++) { if (!kill(0, $children[$i])) { warn "Child $i [" . $children[$i] . "] gone\n" if $opt_d; splice(@children, $i, 1); } } } } dokill(); sub dokill { warn "Killing children\n" if $opt_v; kill INT, @children; printf "user: %s, system: %s, children user: %s, children system: %s\n", times(); printf "Messages sent in %s seconds\n", time() - $parentbegintime; exit(0); } sub statsdie { $timelength = time() - $begintime; print "$$: made $attempts attempts, sent $count messages in $timelength seconds\n"; exit(0); } sub sendmessage { if (!defined($smtp = new IO::Socket::INET ( PeerAddr => $host, PeerPort => $opt_p, Proto => 'tcp', ))) { warn "[$$] Error creating socket: $!\n"; sleep (1 + $opt_w); return 0; } $smtp->autoflush(1); print("[$$] Connected to host " . $host . ".\n") if $opt_d; $status = $smtp->getline(); chomp($status); if (!($status =~ m/^2\d\d/)) { warn "[$$] Connect status: $status\n"; sleep (1 + $opt_w); return 0; } print("[$$] Host said hi: $status\n") if $opt_d; $hostname = `hostname`; chomp($hostname); smtpcommand("HELO $hostname", 'Saying HELO') || return 0; smtpcommand("MAIL FROM: <$from_addr>", 'MAIL FROM') || return 0; smtpcommand("RCPT TO: <$to_addr>", 'RCPT TO') || return 0; smtpcommand("DATA", 'DATA') || return 0; $smtp->print("From: <$from_addr>\r\n"); $smtp->print("To: <$to_addr>\r\n"); $smtp->print("Subject: " . POSIX::strftime($opt_s, localtime()) . "\r\n"); $smtp->print("\r\n"); $smtp->print($opt_b); $smtp->print("\r\n.\r\n"); smtpcommand("QUIT", 'QUIT') || return 0; sleep($opt_w); return 1; } sub smtpcommand { $command = shift(@_); $msg = shift(@_); $smtp->print("$command\r\n"); $status = $smtp->getline(); chomp($status); if (!($status =~ m/^[23]\d\d/)) { warn "[$$] Error response returned while $msg: $status\nWe said: $command\n"; return 0; } print("[$$] $msg: $status\n") if $opt_d; return 1; }