Article 10162 of comp.lang.perl:
Xref: feenix.metronet.com comp.lang.perl:10162 comp.mail.sendmail:4507 alt.sources:2703 comp.unix.admin:9062
Path: feenix.metronet.com!news.ecn.bgu.edu!usenet.ins.cwru.edu!agate!overload.lbl.gov!lll-winken.llnl.gov!fastrac.llnl.gov!usenet.ee.pdx.edu!usenet.ee.pdx.edu!trent
From:
[email protected] (Trent A. Fisher)
Newsgroups: comp.lang.perl,comp.mail.sendmail,alt.sources,comp.unix.admin
Subject: Re: expn program for sendmail
Date: 26 Jan 1994 01:05:12 GMT
Organization: Portland State University, CS Dept.
Lines: 333
Distribution: world
Message-ID: <
[email protected]>
References: <
[email protected]>
NNTP-Posting-Host: sirius.cs.pdx.edu
In-reply-to: Tom Christiansen's message of Tue, 25 Jan 1994 20:14:19 GMT
X-spook-bait: munitions Kennedy Khaddafi NSA Waco, Texas Ft. Bragg
Archive-name: chkaddr
Submitted-by:
[email protected]
In article <
[email protected]> Tom Christiansen writes:
> Here's a brief program to expand remote aliases using the
> smtp daemon on the farside, e.g.: [...]
Well, here's my program to do something similar, except mine will
recursively resolve each address until it hits non-forwarding login or
an error. For example, running it on
[email protected] will give
you (indentation shows recursion level):
[email protected]
\trent
[email protected]
"|/usr/local/mh/lib/slocal -user trent"
You need to have 'nslookup' in your path, to do MX record checking (I
haven't tested this code thouroughly. Other than this, I have been
using this for a year or two, and, hopefully, have most of the kinks
worked out.
Send any suggestion, comments, fixes to
[email protected].
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
# chkaddr
# This archive created: Tue Jan 25 16:56:28 1994
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'chkaddr'" '(6009 characters)'
cat << \SATANOSCILATEMYMETALICSONATAS > 'chkaddr'
#!/usr/local/bin/perl
#
# Check a given (internet) e-mail address via smtp (vrfy command)
#
# Copyright (C) 1991-4 Trent A. Fisher (
[email protected])
# With portions of code stolen from
[email protected] (Eric Young)
#
# 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# Usage:
# chkaddr [-v] [-d n] addrs...
# -v lets you snoop on the smtp connection
# -d n maximum depth to search
# adrrs are e-mail addresses, if there is no '@domain',
# '@localhost' will be appended
#
# Todo:
# - do a HELO (need FQDN of hostname, how do we get that??)
# - use EXPN instead of VRFY (both??)
# - implement some way of caching smtp connections, e.g. if
# three people in a mailing list have their mail forwarded to
# the same machine, this program will open an smtp connection
# three times.
# - handle addresses which are not fully domained, i.e.
#
[email protected]
# foo@blatz (should be blatz.mit.edu)
# (My systems don't do this, but some do)
# - look up full names via finger?
#
require 'sys/socket.ph';
require 'sys/errno.ph';
require 'getopts.pl';
$snoop = 0; # Watch smtp conversations
$MAXDEPTH = 17; # maximum mail hops (to stop recursion)
$timeout = 30;
# get any MX records for a given host
# talk to nslookup to get the info
sub getmx
{
local($host) = @_;
local(@mxhosts);
local($tmpfile)="/tmp/pmx$$z";
# prepare the file to give to nslookup
open(TMP, ">$tmpfile") || die "$tmpfile";
print TMP "set type=MX\n$host\n";
close TMP;
# feed nslookup our input file...
open(NS, "nslookup <$tmpfile |") || die "nslookup";
while (<NS>)
{
if (/$host\s+preference\s+=\s+(\d+).*exchanger\s+=\s+([^\s]+)/)
{
next if $host eq $2;
push(@mxhosts, $2);
# do something with preference, someday??
}
}
close(NS);
unlink($tmpfile);
return(@mxhosts);
}
sub startsmtp
{
local($name)=@_;
local($status);
local($n,$aliases,$proto,$port,$type,$len,$thisaddr,$thataddr);
local($this, $that, $sockaddr);
$sockaddr='Sna4x8';
chop($hostname=`hostname`);
($n,$aliases,$proto)=getprotobyname('tcp');
($n,$aliases,$port)=getservbyname('smtp','tcp');
($n,$aliases,$type,$len,$thisaddr)=gethostbyname($hostname);
($n,$aliases,$type,$len,$thataddr)=gethostbyname($name);
if (!defined $thataddr)
{
# at this point we check for an MX record
@mxhosts = &getmx($name);
if (@mxhosts)
{
print " "x$depth,
"Mail for $name is handled by @mxhosts\n";
}
else
{
print " "x$depth,
"I can't locate $name, hopefully sendmail can\n";
}
return(0);
}
$this=pack($sockaddr,&AF_INET,0,$thisaddr);
$that=pack($sockaddr,&AF_INET,$port,$thataddr);
socket(SMTP,&PF_INET,&SOCK_STREAM,$proto) || die "socket: $!";
bind(SMTP,$this) || die "bind: $!";
$status = connect(SMTP,$that);
if ($status == 0)
{
print " "x$depth, "Host $name is ";
if ($! == &ECONNREFUSED)
{
print "fascist\n";
}
elsif ($status == &ETIMEDOUT)
{
print "down?\n";
}
else
{
print "having problems: ", $!, "\n";
}
return(0);
}
select(SMTP); $|=1;
select(STDIN); $|=1;
select(STDOUT); $|=1;
# get the header out of the way
while (<SMTP>)
{
print if ($snoop);
last if (/^220 /);
if (/^[24]21 /)
{
print "Host $name doesn't want to talk to us :-(\n";
alarm(0);
return(0);
}
}
# be polite and do a HELO ??
# need to get our own FQDN
return(1);
}
# when sendmail 8 came out I found out I should actually be using expn.
sub vrfy_cmd
{
local($name)=@_;
local(@ret);
print SMTP "EXPN $name\n";
while(<SMTP>)
{
print if ($snoop);
if (/^250([ -]).*<([^>]+)>/)
{
push(@ret, $2);
last if $1 ne "-";
}
else
{
print; # some sort of error
last;
}
}
return(@ret);
}
sub quitsmtp
{
print SMTP "QUIT\n";
$_=<SMTP>;
print if ($snoop);
print STDOUT "close bad: $_" unless (/^221 /);
}
sub timeout
{
die " "x($depth+1)."host $host won't talk to us.\n";
}
#
# get a list of e-mail addresses
#
sub vrfy
{
local($name, $host) = @_;
local(@ret);
# set up the timeout and the connection
$SIG{'ALRM'}='timeout';
eval 'alarm($timeout); $r = &startsmtp($host);' ||
print $@;
alarm(0);
return() unless $r;
@ret = &vrfy_cmd($name);
do quitsmtp;
return(@ret);
}
#
# this recursive routine will, given an e-mail address, find out what
# it resolves to (via smtp).
#
sub checkit
{
local($name, $host, $depth) = @_;
local(@addrs);
# prevent infinite recursion
if ($depth > $MAXDEPTH)
{
print " "x($depth+1),
"This looks like a mail loop to me.\n";
return;
}
@addrs = &vrfy($name, $host);
# print "@addrs\n";
foreach (@addrs)
{
print " "x$depth, "$_\n";
next if /^\\?[^@]+$/; # local address
# some smtps return the same e-mail address
# thus causing a loop
if (/$name@$host/i)
{
print " "x($depth+1),
"warning! twisted smtp daemon.\n";
return;
}
if (/^([\w-]+)@([\w.-]+)$/)
{
do checkit($1, $2, $depth+1);
}
else
{
print " "x($depth+1),
"I don't understand this address, I hope you do\n";
}
}
}
#------------------------------------------------------------------------
# main program
#
&Getopts("vd:");
$snoop = $opt_v;
$MAXDEPTH = $opt_d if $opt_d;
foreach (@ARGV)
{
if (/^([\w-]+)@([\w.-]+)$/)
{
print "$_\n";
do checkit($1, $2, 1);
}
else # must be a local address
{
print "$_@localhost\n";
do checkit($_, "localhost", 1);
}
}
SATANOSCILATEMYMETALICSONATAS
if test 6009 -ne "`wc -c < 'chkaddr'`"
then
echo shar: "error transmitting 'chkaddr'" '(should have been 6009 characters)'
fi
chmod 755 'chkaddr'
exit 0
# End of shell archive
--
Trent A. Fisher, Systems Manager/Administrator/Programmer
Portland State University
[email protected]
Computer Science Dept. Stop Software Monopolies! Join the LPF
"Don't ask me how it works, or I'll start to whimper." -- Arthur Dent