Net::Telnet and SMTP

Discussion in 'Perl Misc' started by crr, Jun 14, 2005.

  1. crr

    crr Guest

    I originally tried this out over in comp.lang.perl.modules, but didn't
    really get anywhere, so I thought I'd take a crack at it over here.

    Hi all,

    I'm using Net::Telnet to test an SMTP proxy product and I've run into
    an issue with it.

    First, I'm trying to send a sequence of commands and then log both the
    commands sent and the response from the server into a log file. The
    responses need to match up EXACTLY to the commands to which they are in
    response. Second, I've tried Net::SMTP and it doesn't quite do what I
    need. Since the product I'm testing may have to deal with......er,
    impolite SMTP clients (read: crackers) I want to make sure that if the
    SMTP protocol being sent is broken that the proxy reponds in a correct
    (read: secure) way. Unfortunately Net::SMTP doesn't give me the level
    of control I need....mostly because it's too polite. ;)

    I've included the script and a sample text file (that feeds the scripts
    the commands) below. It's been since sometime in v4 since I last did
    anything with PERL (unfortunately) so I apologize in advance for the
    mess. :)

    Thanks,

    crr

    ************************************Script**************************************
    #This script reads from a generated smtp test file and writes to a log
    file in
    #the logs directory, which will be created under the directory from
    which the
    #test is run. I recommend that you place the test file in the same dir
    as the
    #script, if for no other reason than that you won't have to maintain in
    the
    #script the location from which you're running the file.
    #
    #test file format note:
    #The first line of the test file *must* contain the dns name (if you're
    using
    # DNS) or the IP address of the server under test, followed by a colon
    :)) and
    # the port to which you're connecting, typically 25
    # You can place comments in the test file by prepending the line with a
    #. Note
    # that this can only be placed at the start of the line
    # Each test should beging with "***Start test" (without quotes) and end
    with
    # "***Stop test"

    use strict;
    #no strict 'refs';
    use Net::Telnet;

    #set the test and log file names, and some globals
    my $testfilename = "smtptests.txt";
    my $t = localtime(time());
    my $logfilename = "./logs/smtplog${t}.txt";
    our $testcount = 0;
    our $debug = 1;

    open TESTFILE, $testfilename or die "Cannot open test file,
    ${testfilename}";

    #print $logfilename;
    if (-e $logfilename) {
    die "Log file ${logfilename} already exists!";
    }

    mkdir 'logs', 0744;

    open LOGFILE, ">${logfilename}" or die "Cannot open log file,
    ${logfilename}";
    if ($debug) {print "*****Created log file\n";}

    #grab the server and port out of the first line of the file
    my ($server, $port) = split (/\:/, getline(*TESTFILE));

    #create the telnet object and set some initial values
    our $telnet = new Net::Telnet (Timeout => 660,
    Telnetmode => 0,
    Host => $server,
    Port => $port,
    Prompt => '//',
    Errmode => 'die');
    #need to set the prompt to null, since SMTP doesn't have a prompt,
    large timeout is
    #for testing our timeout

    #timeout exception for debugging the script
    $telnet->timeout(30) if ($debug);

    if ($debug) {print "*****Telnet object created\n";}

    $t = localtime(time());
    print LOGFILE "Starting test of server ${server} at ${t}\n";

    #begin processing the main part of the file
    processfile(*TESTFILE, *LOGFILE);

    close TESTFILE;
    close LOGFILE;

    #print "${server}";
    #print $port;

    #processfile is where the main work of the program is coordinated. it
    reads
    #commands from the test file and organizes the starting and stopping of
    each
    #test
    sub processfile {
    if ($debug) {print "*****Entering processfile\n";}
    my $TF = shift;
    my $LOG = shift;
    my $line = getline($TF);

    if ($line eq eof) {return 0;}

    if ($debug) {print $line;}
    while ($line ne eof) {
    # checks the line and read if it's a command to start a
    test
    if ($line eq "***Start test\n") {
    print "*****Starting test\n" if ($debug);
    $testcount++;
    print $LOG "Starting test ${testcount}\n";
    if (defined(dotest($TF, $LOG))) {
    print $LOG "Test ${testcount}
    finished\n";
    } else {
    print $LOG "Test ${testcount}
    failed\n";
    }#end else
    }#end if
    #We should never encounter a stop test line in
    processfile
    if ($line eq "***Stop test\n") {die "Error in test
    file!"}

    $line = getline($TF);
    if ($debug) {print $line;}
    }#end while

    return 0;

    #once we've started a test, dotest actually runs the commands,
    including opening
    #the telnet session
    sub dotest {
    my $TF = shift;
    my $LOG = shift;
    my @response = ();

    print "*****Entered dotest\n" if ($debug);

    my $line = getline($TF);
    $telnet->input_log($LOG);
    print $LOG "Recd: ";
    $telnet->open();
    print "*****Telnet session open\n" if ($debug);

    #Try a short delay
    delay(.1);

    $telnet->get(); #read output for input_log
    #my $firstline = $telnet->getline();
    #print $LOG "Recd: ${firstline}";

    while($line ne "***Stop test\n"){
    print $LOG "Sent: ${line}";
    print $LOG "Recd: ";
    print $LOG $telnet->cmd(String => $line);

    #Try a short delay between sending command and reading output
    delay(5);
    $telnet->getline();

    #if (substr($line, 0, 4) eq "ehlo") {
    #@response = $telnet->getlines(All => "");
    #} else {@response =
    $telnet->getline();}

    #print $LOG "Recd: @{response}";
    $line = getline($TF);
    }#end while
    #$telnet->dump_log('') if ($debug);

    $telnet->cmd(String => localtime(time())) if ($debug);
    $telnet->close();

    return 0;
    }#end dotest

    }#end processfile

    #Small sub to strip out comments in the test file and exit gracefully
    if we've
    #reached the end of the input file
    sub getline {
    my $TF = shift;
    my $gotline = 0;
    my $line = '';

    while (!($gotline)) {
    $line = <$TF>;
    if (eof($TF)) {
    print "*****EOF reached\n" if ($debug);
    print $line if ($debug);
    exit;}
    $gotline = 1;
    my @a = split (//, $line);
    if ($a[0] eq '#') {$gotline = 0;}
    }#end while

    #print "${line}";
    return $line;

    }#end getline

    #small sub to insert a variable length time delay
    sub delay {
    my $delaytime = shift;

    my $returntime = (time + $delaytime);
    while(1) {
    if (time >= $returntime) {return;}
    }

    }#end delay

    ************************************text
    file*************************************
    10.113.15.66:25
    #Test comment
    ***Start test
    ehlo test.com
    mail from:
    rcpt to:
    data
    To: bob
    From: Bill
    Subject: test
    This is a test email
    ..
    ***Stop test
    crr, Jun 14, 2005
    #1
    1. Advertising

  2. On 14 Jun 2005 11:18:34 -0700, crr wrote:

    > I originally tried this out over in comp.lang.perl.modules, but didn't
    > really get anywhere, so I thought I'd take a crack at it over here.
    >
    > Hi all,
    >
    > I'm using Net::Telnet to test an SMTP proxy product and I've run into
    > an issue with it.
    >
    > First, I'm trying to send a sequence of commands and then log both the
    > commands sent and the response from the server into a log file. The
    > responses need to match up EXACTLY to the commands to which they are in
    > response. Second, I've tried Net::SMTP and it doesn't quite do what I
    > need. Since the product I'm testing may have to deal with......er,
    > impolite SMTP clients (read: crackers) I want to make sure that if the
    > SMTP protocol being sent is broken that the proxy reponds in a correct
    > (read: secure) way. Unfortunately Net::SMTP doesn't give me the level
    > of control I need....mostly because it's too polite. ;)
    >

    <snip>
    Hi

    It isn't clear what your problem is. What issue are you having with your
    first requirement and what is the smallest complete program that will
    demonstrate this?

    I am not particularly familiar with Net::Telnet or Net::SMTP, but I would
    be tempted to use Expect.

    Mark
    Mark Clements, Jun 14, 2005
    #2
    1. Advertising

  3. crr

    Mike Guest

    Mark Clements wrote:

    > On 14 Jun 2005 11:18:34 -0700, crr wrote:
    >
    >
    >>I originally tried this out over in comp.lang.perl.modules, but didn't
    >>really get anywhere, so I thought I'd take a crack at it over here.
    >>
    >>Hi all,
    >>
    >>I'm using Net::Telnet to test an SMTP proxy product and I've run into
    >>an issue with it.
    >>
    >>First, I'm trying to send a sequence of commands and then log both the
    >>commands sent and the response from the server into a log file. The
    >>responses need to match up EXACTLY to the commands to which they are in
    >>response. Second, I've tried Net::SMTP and it doesn't quite do what I
    >>need. Since the product I'm testing may have to deal with......er,
    >>impolite SMTP clients (read: crackers) I want to make sure that if the
    >>SMTP protocol being sent is broken that the proxy reponds in a correct
    >>(read: secure) way. Unfortunately Net::SMTP doesn't give me the level
    >>of control I need....mostly because it's too polite. ;)
    >>

    >
    > <snip>
    > Hi
    >
    > It isn't clear what your problem is. What issue are you having with your
    > first requirement and what is the smallest complete program that will
    > demonstrate this?
    >
    > I am not particularly familiar with Net::Telnet or Net::SMTP, but I would
    > be tempted to use Expect.
    >
    > Mark



    Dump_log input_log and Output_log arguments will give you text files
    with all the input.. all the output and everything in order both hex and
    ascii .

    You should be able to see the transactions back and forth no problem..
    the text logs are primarily used for debug purposes but will work nicely
    for what you need.

    Its all in the readme

    Mike
    Mike, Jun 15, 2005
    #3
  4. crr

    crr Guest

    Sorry, it seemed clear when I wrote the message, but then I've been
    staring at this problem for two days! :)

    My main issue is that the messages returned by the server are not
    making it back to be read by the client side. It seems that if I do a
    completely valid smtp session, I eventually get all the messages when I
    do my final $obj->get(), but I can't get them to appear in-line with
    the command that generated them. I also cannot get them to appear when
    I do a shortened smtp session (such as when I generate an error) even
    when I do a final get() (or getline() or getlines()).

    I'm not sure if I'm hitting some sort of buffer limit or what, but the
    initial messages don't have this problem. Frex, I get the smtp
    greeting immediately, as well as the response to the EHLO command.

    Thanks in advance for the help.

    crr
    crr, Jun 17, 2005
    #4
  5. crr

    crr Guest

    Hi, thanks for the response.

    I'm actually using input_log, and I still don't see the messages
    returned. Like I mentioned above, I can somtimes get them, but not
    until I do my final get() after a complete smtp session, but if I do
    something to generate an error (such as issuing smtp commands out of
    order, etc.) I cannot get the error message returned by the server,
    which is real interest here anyway.

    Do you know if input_log has some sort of buffer limit before it writes
    to the filehandle? Or is there some reason that it's not writing
    immediately, except in the cases of the smtp greeting and the EHLO
    response? Even in those cases, I have to do an $obj->get() before the
    responses will be logged.

    Thanks again for the help,

    crr
    crr, Jun 17, 2005
    #5
  6. "crr" <> wrote in news:1119027092.183211.282440
    @g43g2000cwa.googlegroups.com:

    > Sorry, it seemed clear when I wrote the message,


    Similarly, the context may seem clear to you now, when you are writing the
    message, but *please* quote the appropriate amount of context when you
    post a reply so that your readers can understand you without having to
    hunt for messages (i) that may never have arrived on their newsserver,
    (ii) may not have arrived on their newsserver yet, (iii) may have expired
    on their newsserver, or people may simply not have threading on.

    Google Groups is great as an archive but makes a lousy platform for
    participating in UseNet discussions. You will have to make an extra effort
    and follow established UseNet practice.

    For help on how to make sure you can maximize the usefulness of this group
    to you, please read the posting guidelines.

    Sinan

    --
    A. Sinan Unur <>
    (reverse each component and remove .invalid for email address)

    comp.lang.perl.misc guidelines on the WWW:
    http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html
    A. Sinan Unur, Jun 17, 2005
    #6
  7. crr

    Mike Guest

    crr wrote:
    > Hi, thanks for the response.
    >
    > I'm actually using input_log, and I still don't see the messages
    > returned. Like I mentioned above, I can somtimes get them, but not
    > until I do my final get() after a complete smtp session, but if I do
    > something to generate an error (such as issuing smtp commands out of
    > order, etc.) I cannot get the error message returned by the server,
    > which is real interest here anyway.
    >
    > Do you know if input_log has some sort of buffer limit before it writes
    > to the filehandle? Or is there some reason that it's not writing
    > immediately, except in the cases of the smtp greeting and the EHLO
    > response? Even in those cases, I have to do an $obj->get() before the
    > responses will be logged.
    >
    > Thanks again for the help,
    >
    > crr
    >



    Yeah .. you will see input in the input log.. any returned messages will
    be in output log... use it and see.
    Mike, Jun 20, 2005
    #7
  8. crr

    crr Guest

    Jim Gibson wrote:

    > If you don't follow these guidelines, you will reduce the probability
    > of getting good answers. Many of the most knowledgable Perl experts
    > here have stopped reading posts from Google users because they too
    > often violate the guidelines for this group. You should consider using
    > another source for Usenet groups and using a real newsreader that does
    > not have these problems.


    Bleh, sorry....I don't typically use Google Groups, so I wasn't aware
    that it's...er, impolite....and wasn't aware how to make Google quote a
    reply. Unfortunately, Google is my only choice here at work for
    UseNet, so there we are. I'll take more care in the future when using
    Google Groups, though hopefully I won't have to use it very often
    (painful is not the word for it).

    Thanks,

    crr
    crr, Jun 20, 2005
    #8
  9. crr

    crr Guest

    A. Sinan Unur wrote:
    > "crr" <> wrote in news:1119027092.183211.282440
    > @g43g2000cwa.googlegroups.com:
    > Google Groups is great as an archive but makes a lousy platform for
    > participating in UseNet discussions. You will have to make an extra effort
    > and follow established UseNet practice.


    Amen to *that*, and if I had any other choice, I'd be using my nice
    sane newsreader at home, but alas, alack, welladay and so forth, I'm
    stuck with Google here at work. I will make an effort to use Google
    more politely, now that I know how to get it to do what I want.

    Thanks,

    crr
    crr, Jun 20, 2005
    #9
  10. "crr" <> wrote in
    news::

    > A. Sinan Unur wrote:
    >> "crr" <> wrote in
    >> news:1119027092.183211.282440 @g43g2000cwa.googlegroups.com:
    >> Google Groups is great as an archive but makes a lousy platform for
    >> participating in UseNet discussions. You will have to make an extra
    >> effort and follow established UseNet practice.

    >
    > Amen to *that*, and if I had any other choice, I'd be using my nice
    > sane newsreader at home, but alas, alack, welladay and so forth, I'm
    > stuck with Google here at work. I will make an effort to use Google
    > more politely, now that I know how to get it to do what I want.
    >
    > Thanks,


    No, thank you very much for understanding our concern, and doing your
    share.

    Sinan

    --
    A. Sinan Unur <>
    (reverse each component and remove .invalid for email address)

    comp.lang.perl.misc guidelines on the WWW:
    http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html
    A. Sinan Unur, Jun 20, 2005
    #10
  11. crr

    crr Guest

    Mike wrote:
    > Yeah .. you will see input in the input log.. any returned messages will
    > be in output log... use it and see.


    I've tried both input_log and output_log, but still get bubkiss. I
    also don't even see the responses with dump_log. Also, it seems like
    it's reversed from what I would consider logical. Which is to say, the
    input_log shows what's returned and the output_log shows the commands
    I'm sending.

    I just double checked it, and it does work reverse of what I would
    expect. So if I do output_log instead of input_log, I get the commands
    I'm sending, and if I do input_log instead of output_log I get (some)
    of the responses to the commands I send, but only if I do a get() or
    getline() after the command.

    Any thoughts on why that is?

    Thanks,

    crr
    crr, Jun 20, 2005
    #11
  12. crr

    crr Guest

    Mark Clements wrote:
    > Hi
    >
    > It isn't clear what your problem is. What issue are you having with your
    > first requirement and what is the smallest complete program that will
    > demonstrate this?
    >
    > I am not particularly familiar with Net::Telnet or Net::SMTP, but I would
    > be tempted to use Expect.


    I've started looking into Expect, and it seems like it might make the
    task a bit easier; unfortunately my time window is too short (read:
    this week) for me to get up to speed enough on Expect to be able to
    port it over there, since I've not used Expect or tcl before.

    Well, mostly my problem is that I'm not getting the responses back
    immediately from the commands I'm sending to the server. In some cases
    (the SMTP greeting and the response to the EHLO) I get the response
    back immediately (either through input_log or by get()/getline()) and
    in the case of the others (mail from:, rcpt to:, data, etc) I don't get
    any responses until the the final get() or getline() whether I'm using
    input_log or not.

    >From what I can tell, input_log should give me the responses of the

    server as they happen, but instead it seems to be queuing them up and
    spitting them all at me, but not until I do a get(). Frex, if I leave
    of the last get(), I never get the response to the mail from: rcpt to:,
    data or quit commands.

    To give you an idea, here's what the resultant log file looks like,
    below that I've included what it should look like:

    Thanks again for all the help.

    crr


    Starting test of server 10.113.15.66 at Mon Jun 20 10:28:38 2005
    Starting test 1
    220 ACE66.roke.com ESMTP Service (Lotus Domino Release 6.5.3) ready at
    Mon, 20 Jun 2005 10:33:54 -0400
    ehlo test.com
    250-ACE66.roke.com Hello test.com ([10.113.15.67]), pleased to meet you
    250-HELP
    250-SIZE
    250 PIPELINING
    mail from:
    rcpt to:
    data
    To: bob
    From: Bill
    Subject: test
    This is a test email
    Mon Jun 20 10:28:58 2005
    ..
    quit
    250 ... Sender OK
    250 ... Recipient OK
    354 Enter message, end with "." on a line by itself
    250 Message accepted for delivery
    221 ACE66.roke.com SMTP Service closing transmission channel
    Test 1 finished


    What it *should* look like is this:

    Starting test of server 10.113.15.66 at Mon Jun 20 10:28:38 2005
    Starting test 1
    220 ACE66.roke.com ESMTP Service (Lotus Domino Release 6.5.3) ready at
    Mon, 20 Jun 2005 10:33:54 -0400
    ehlo test.com
    250-ACE66.roke.com Hello test.com ([10.113.15.67]), pleased to meet you
    250-HELP
    250-SIZE
    250 PIPELINING
    mail from:
    250 ... Sender OK
    rcpt to:
    250 ... Recipient OK
    data
    354 Enter message, end with "." on a line by itself
    To: bob
    From: Bill
    Subject: test
    This is a test email
    Mon Jun 20 10:28:58 2005
    ..
    250 Message accepted for delivery
    quit
    221 ACE66.roke.com SMTP Service closing transmission channel
    Test 1 finished
    crr, Jun 20, 2005
    #12
  13. crr

    Mike Guest

    crr wrote:

    > Mike wrote:
    >
    >>Yeah .. you will see input in the input log.. any returned messages will
    >>be in output log... use it and see.

    >
    >
    > I've tried both input_log and output_log, but still get bubkiss. I
    > also don't even see the responses with dump_log. Also, it seems like
    > it's reversed from what I would consider logical. Which is to say, the
    > input_log shows what's returned and the output_log shows the commands
    > I'm sending.
    >
    > I just double checked it, and it does work reverse of what I would
    > expect. So if I do output_log instead of input_log, I get the commands
    > I'm sending, and if I do input_log instead of output_log I get (some)
    > of the responses to the commands I send, but only if I do a get() or
    > getline() after the command.
    >
    > Any thoughts on why that is?
    >
    > Thanks,
    >
    > crr
    >

    Ahhhh so its not being flushed...

    Sometimes when dealing with routers and other devices i have to send a
    carriage return after a command in order to get the result of the
    previous command. I believe there is a way to change this behavior.. but
    i have been content with just sending carriage returns..

    $connection->print("");

    Mike
    Mike, Jun 21, 2005
    #13
  14. crr

    crr Guest

    Mike wrote:
    > Ahhhh so its not being flushed...
    >
    > Sometimes when dealing with routers and other devices i have to send a
    > carriage return after a command in order to get the result of the
    > previous command. I believe there is a way to change this behavior.. but
    > i have been content with just sending carriage returns..


    Hrm, well it seems to be a bit more complex than that. I wrote up a
    quick test script to see if I could work out somethings without mucking
    about with my full script. The first test I wrote up worked great,
    with perfectly interspersed commands and responses, just like I need.
    I then proceeded to implement these changes into my main script, but I
    still see the same erroneous behaviour from before where I only see the
    smtp greeting and the response to the ehlo command.

    So I created a second script that includes all the calls to the telnet
    object in a subroutine (much like my main script) and see the same
    problems again, but this time I noted that the email isn't going
    though. Long story short (too late, I know) I realized I was passing
    the arrays incorrectly.

    For whatever reason, it definitely seems to like my reading the files
    separately into an array and then issuing the commands from that,
    rather than reading them directly from the file. Could be I introduce
    some sort of a race between the IO to and from the files and telnet
    object.

    For those interested, I'll include the shorter script that does the
    trick, which I've backstitched into my main script.

    Thanks again for the help.

    crr

    ********************Script************************************
    use strict;
    use warnings;
    use Net::Telnet;

    my $server = '10.113.15.66';
    my $port = '25';
    my $t = localtime(time());
    my $logfilename = "./logs/smtplog${t}.txt";
    my @smtp = ("ehlo test.com", "mail from: bob\@test.com", "rcpt to:
    nadmin\@ace66.roke.com", "data", "From: bob", "To: bill", "Subject:
    This is a test", "This is a test email!", ".", "quit");
    our $stopreading = 0;
    my @smtp2 = ("ehlo test.com", "mail from: bob\@test.com", "data",
    "quit");

    if (-e $logfilename) {
    die "Log file ${logfilename} already exists!";
    }
    mkdir 'logs', 0744;

    open LOGFILE, ">${logfilename}" or die "Cannot open log file,
    ${logfilename}";

    our $telnet = new Net::Telnet (Timeout => 30,
    Telnetmode => 0,
    Host => $server,
    Port => $port,
    Prompt => '//',
    Errmode => 'die',
    Binmode => 0,
    Input_log => *LOGFILE,
    Output_log => *LOGFILE);

    dotest(\@smtp, \@smtp2);


    sub dotest {

    my ($smtpcommands, $smtpcommands2) = @_;

    $telnet->open;
    delay(2);
    $telnet->get;

    foreach my $element (@{$smtpcommands}) {
    $telnet->print($element);
    delay(2);
    #don't want to wait for responses after we read the response to the
    #data command, since there ain't none, but we want to start reading
    #again once we hit the end of the data section
    if ($element eq ".") {$stopreading = 0;}
    unless($stopreading) {$telnet->get;}
    if ($element eq "data") {$stopreading = 1;}
    }#end foreach

    $telnet->open;
    delay(2);
    $telnet->get;
    foreach my $element (@{$smtpcommands2}) {
    $telnet->print($element);
    delay(2);
    if ($element eq ".") {$stopreading = 0;}
    unless($stopreading) {$telnet->get;}
    if ($element eq "data") {$stopreading = 1;}
    }#end foreach
    }#end dotest

    #small sub to introduce a delay in the code
    sub delay {
    my $delaytime = shift;
    my $returntime = (time() + $delaytime);

    while (1) {
    if (time() >= $returntime) {return;}
    }#end while
    }#end delay
    crr, Jun 21, 2005
    #14
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    3
    Views:
    1,073
    Roedy Green
    Jan 24, 2006
  2. Alex Hunsley
    Replies:
    4
    Views:
    3,461
    Tim Williams (gmail)
    Jun 29, 2004
  3. Raaijmakers, Vincent \(GE Infrastructure\)

    RE: sending of mail (smtp) - connection refused - but smtp serveris running!

    Raaijmakers, Vincent \(GE Infrastructure\), Jun 29, 2004, in forum: Python
    Replies:
    0
    Views:
    879
    Raaijmakers, Vincent \(GE Infrastructure\)
    Jun 29, 2004
  4. Jim Isaacson
    Replies:
    5
    Views:
    603
    Default User
    Nov 5, 2004
  5. Carcarius
    Replies:
    0
    Views:
    292
    Carcarius
    Dec 6, 2007
Loading...

Share This Page