#!/usr/bin/perl # SMTPman - the MANual SMTP server # Ryan Doyle 2009 use Term::ANSIColor qw(:constants); use IO::Socket; use Switch; my $tcp_port = '2500'; if($ARGV[0] eq "-h" or $ARGV[0] eq "--help"){ print "Usage: smtpman.pl\n\n"; print "Change the port by editing smtpman.pl. Default is 2500\n\n"; print "smtpman is a MANual SMTP server. That's right, you will need to manually\n"; print "enter in the SMTP commands to receive email. A fantastic advantage of\n"; print "running a manual mail server is the 100% effectiveness against spam. NO\n"; print "filtering software can successfully claim that it is 100% effective. Now\n"; print "all the postmaster has to do is sit infront of a terminal window and accept\n"; print "email on behalf of its users\n\n"; print "ryandoyle.net - 2009\n\n"; exit; } print "\n\tsmtpman - The MANual SMTP Server v0.1\n"; print "\t ryandoyle.net - 2009\n\n"; print "Opening socket...\n"; # Create new socket my $sock = new IO::Socket::INET ( LocalPort => $tcp_port, Proto => 'tcp', Listen => 1, Reuse => 1 ); # Check socket was created if(!$sock){ print "ERROR Creating socket!!"; die(); } # Let user know new socket was created print "Socket created. Listening for new SMTP connections on port $tcp_port\n\n"; print "At any time if you want to end the connection, send a 5XX error\n"; print "(part of SMTP) such as 554 to gracefully end the SMTP conversation\n"; print "or send KILL (smtpman specific) to sever the TCP connection\n\n\n"; # Accept new connections while($new_sock = $sock->accept()){ print BLINK, "***A new client has connected!***\n\n", RESET; print BLUE, " Send a greeting banner. This needs to be atleast 220 \n and should also include the host name\n", RESET; print BLUE, " EG: \"220 mail.example.com\"\n\n", RESET; print GREEN, "smtp> ", RESET; $greeting = <>; $new_sock->send($greeting); # Now we need to loop until we end the conversation while(defined($cmd = <$new_sock>)){ # If the client is sending data, then we don't want to process commands if($dataactive != 1){ # Print out the client's command print RED, "\n\n".$cmd."\n", RESET; switch($cmd){ case(m/DATA/i) { print BLUE, " Client wants to send data, send a 354\n", RESET; print BLUE, " EG: \"354 go ahead, end with . on a new line\"\n\n"; # Now that the client is sending data, let the program know $dataactive = 1; } case(m/HELO/i){ print BLUE, " Client is saying hello, check to make sure this greeting is correct\n"; print BLUE, " and that you want to accept mail using a 250 command\n", RESET; print BLUE, " EG: \"250 Hello outmail.example.net, hows it going??\"\n\n", RESET; } case(m/EHLO/i){ print BLUE, " Client is sending a EHLO (simmilar to a HELO). If you want to accept\n"; print BLUE, " its mail, send a 250 command\n", RESET; print BLUE, " EG: \"250 Hello outmail.example.net, hows it going??\"\n\n", RESET; } case(m/MAIL/i){ print BLUE, " Client wants to send an email from the address listed above. Make sure\n"; print BLUE, " that this email address is allowed to send email to your organisation\n"; print BLUE, " and send a 250 back\n", RESET; print BLUE, " EG: \"250 bob\@example.net? got it.\"\n\n"; } case(m/RCPT/i){ print BLUE, " Client wants to send its email to the address listed above. Make sure\n"; print BLUE, " that this address exists in your organisation and send a 250 if you want\n"; print BLUE, " to receive it\n", RESET; print BLUE, " EG: \"250 alright got it. You can send to noni\@example.com\"\n\n", RESET; } case(m/RSET/i){ print BLUE, " Client wants to reset the current SMTP conversation, send a 250 if its ok\n"; print BLUE, " EG: \"250 forgetting about to and from address and clearing the email data\"\n\n", RESET; $msgdata = 0; } case(m/NOOP/i){ print BLUE, " Client is sending a NOOP, no operation. Send a 250 back to confirm\n"; print BLUE, " EG: \"250 stop wasting my time\"\n\n"; } case(m/QUIT/i){ print BLUE, " Client wants to quit the connection, send a 250 to confirm\n"; print BLUE, " EG: \"250 ending connection now\"\n\n"; } else{ print BLUE, " The client is sending a command that smtpman does not know\n"; print BLUE, " send a 500 command to terminate the connection\n\n", RESET; } } # Get our command and then send it back print GREEN, "smtp> ", RESET; $retcmd = <>; if($retcmd =~ /^KILL/i){ print BLINK, "Closing socket!\n\n", RESET; close($new_sock); # Flush the message data $msgdata = 0; } else{ $new_sock->send($retcmd); } # If the command was to quit, then close the socket and prompt to save the message if($cmd =~ m/QUIT/i){ # Check if there was an email and give the option to save it if there was if($msgdata){ print BLUE, " Do you want to save the data from the email? (y/n)\n\n", RESET; print "Save? "; $save = <>; if($save =~ m/y/i){ $time = time; open(MSG, ">$time.msg"); print MSG $msgdata; close(MSG); print "Message saved to $time.msg\n\n" } # Flush the message data $msgdata = 0; } print BLINK, "*** Socket Closed ***!\n\n", RESET; close($new_sock); print "Waiting for new client...\n\n"; } } # We are in the process of recieving data else{ if($cmd =~ m/^\.\r\n/){ $dataactive = 0; print BLUE, "End of message, send a 250 to the client to confirm\n", RESET; print BLUE, "EG: \"250 okay got the email\"\n\n"; print GREEN, "smtp> ", RESET; $retcmd = <>; $new_sock->send($retcmd); } else{ print RED, $cmd, RESET; $msgdata = $msgdata.$cmd; } } } }