⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 expn.pl

📁 < linux网络编程工具>>配套源码
💻 PL
📖 第 1 页 / 共 3 页
字号:
#!/usr/bin/perl
'di ';
'ds 00 \\"';
'ig 00 ';
#
#       THIS PROGRAM IS ITS OWN MANUAL PAGE.  INSTALL IN man & bin.
#

use 5.001;
use IO::Socket;

# system requirements:
# 	must have 'nslookup' and 'hostname' programs.

# $OrigHeader: /home/muir/bin/RCS/expn,v 3.11 1997/09/10 08:14:02 muir Exp muir $

# TODO:
#	less magic should apply to command-line addresses
#	less magic should apply to local addresses
#	add magic to deal with cross-domain cnames
#	disconnect & reconnect after 25 commands to the same sendmail 8.8.* host

# Checklist: (hard addresses)
#	250 Kimmo Suominen <"|/usr/local/mh/lib/slocal -user kim"@grendel.tac.nyc.ny.us>
#	harry@hofmann.cs.Berkeley.EDU -> harry@tenet (.berkeley.edu)  [dead]
#	bks@cs.berkeley.edu -> shiva.CS (.berkeley.edu)		      [dead]
#	dan@tc.cornell.edu -> brown@tiberius (.tc.cornell.edu)

#############################################################################
#
#  Copyright (c) 1993 David Muir Sharnoff
#  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 the David Muir Sharnoff.
#  4. The name of David Sharnoff may not be used to endorse or promote products
#     derived from this software without specific prior written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE DAVID MUIR SHARNOFF ``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 DAVID MUIR SHARNOFF 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.
#
# This copyright notice derrived from material copyrighted by the Regents
# of the University of California.
#
# Contributions accepted.
#
#############################################################################

# overall structure:
#	in an effort to not trace each address individually, but rather
#	ask each server in turn a whole bunch of questions, addresses to
#	be expanded are queued up.
#
#	This means that all accounting w.r.t. an address must be stored in
#	various arrays.  Generally these arrays are indexed by the
#	string "$addr *** $server" where $addr is the address to be
#	expanded "foo" or maybe "foo@bar" and $server is the hostname
#	of the SMTP server to contact.
#

# important global variables:
#
# @hosts : list of servers still to be contacted
# $server : name of the current we are currently looking at
# @users = $users{@hosts[0]} : addresses to expand at this server
# $u = $users[0] : the current address being expanded
# $names{"$users[0] *** $server"} : the 'name' associated with the address
# $mxbacktrace{"$users[0] *** $server"} : record of mx expansion
# $mx_secondary{$server} : other mx relays at the same priority
# $domainify_fallback{"$users[0] *** $server"} : alternative names to try 
#	instead of $server if $server doesn't work
# $temporary_redirect{"$users[0] *** $server"} : when trying alternates,
#	temporarily channel all tries along current path
# $giveup{$server} : do not bother expanding addresses at $server
# $verbose : -v
# $watch : -w
# $vw : -v or -w
# $debug : -d
# $valid : -a
# $levels : -1
# $S : the socket connection to $server

$have_nslookup = 1;	# we have the nslookup program
$port = 'smtp';
$av0 = $0;
$ENV{'PATH'} .= ":/usr/etc" unless $ENV{'PATH'} =~ m,/usr/etc,;
$ENV{'PATH'} .= ":/usr/ucb" unless $ENV{'PATH'} =~ m,/usr/ucb,;
select(STDERR);

$0 = "$av0 - running hostname";
chop($name = `hostname || uname -n`);

$0 = "$av0 - lookup host FQDN and IP addr";
($hostname,$aliases,$type,$len,$thisaddr) = gethostbyname($name);

$0 = "$av0 - parsing args";
$usage = "Usage: $av0 [-1avwd] user[\@host] [user2[host2] ...]";
for $a (@ARGV) {
	die $usage if $a eq "-";
	while ($a =~ s/^(-.*)([1avwd])/$1/) {
		eval '$'."flag_$2 += 1";
	}
	next if $a eq "-";
	die $usage if $a =~ /^-/;
	&expn(&parse($a,$hostname,undef,1));
}
$verbose = $flag_v;
$watch = $flag_w;
$vw = $flag_v + $flag_w;
$debug = $flag_d;
$valid = $flag_a;
$levels = $flag_1;

die $usage unless @hosts;
if ($valid) {
	if ($valid == 1) {
		$validRequirement = 0.8;
	} elsif ($valid == 2) {
		$validRequirement = 1.0;
	} elsif ($valid == 3) {
		$validRequirement = 0.9;
	} else {
		$validRequirement = (1 - (1/($valid-3)));
		print "validRequirement = $validRequirement\n" if $debug;
	}
}

HOST:
while (@hosts) {
	$server = shift(@hosts);
	@users = split(' ',$users{$server});
	delete $users{$server};

	# is this server already known to be bad?
	$0 = "$av0 - looking up $server";
	if ($giveup{$server}) {
		&giveup('mx domainify',$giveup{$server});
		next;
	}

	# do we already have an mx record for this host?
	next HOST if &mxredirect($server,*users);

	# look it up, or try for an mx.
	$0 = "$av0 - gethostbyname($server)";

	($name,$aliases,$type,$len,$thataddr) = gethostbyname($server);
	# if we can't get an A record, try for an MX record.
	unless($thataddr) {
		&mxlookup(1,$server,"$server: could not resolve name",*users);
		next HOST;
	}
				
	# get a connection, or look for an mx
	$0 = "$av0 - socket to $server";

	$S = new IO::Socket::INET (
		'PeerAddr' => $server,
		'PeerPort' => $port,
		'Proto' => 'tcp');

	if (! $S || ($debug == 10 && $server =~ /relay\d.UU.NET$/i)) {
		$0 = "$av0 - $server: could not connect: $!\n";
		$emsg = $!;
		unless (&mxlookup(0,$server,"$server: could not connect: $!",*users)) {
			&giveup('mx',"$server: Could not connect: $emsg");
		}
		next HOST;
	}
	$S->autoflush(1);

	# read the greeting
	$0 = "$av0 - talking to $server";
	&alarm("greeting with $server",'');
	while(<$S>) {
		alarm(0);
		print if $watch;
		if (/^(\d+)([- ])/) {
			if ($1 != 220) {
				$0 = "$av0 - bad numeric response from $server";
				&alarm("giving up after bad response from $server",'');
				&read_response($2,$watch);
				alarm(0);
				print STDERR "$server: NOT 220 greeting: $_"
					if ($debug || $vw);
				if (&mxlookup(0,$server,"$server: did not respond with a 220 greeting",*users)) {
					close($S);
					next HOST;
				}
			}
			last if ($2 eq " ");
		} else {
			$0 = "$av0 - bad response from $server";
			print STDERR "$server: NOT 220 greeting: $_"
				if ($debug || $vw);
			unless (&mxlookup(0,$server,"$server: did not respond with SMTP codes",*users)) {
				&giveup('',"$server: did not talk SMTP");
			}
			close($S);
			next HOST;
		}
		&alarm("greeting with $server",'');
	}
	alarm(0);
	
	# if this causes problems, remove it
	$0 = "$av0 - sending helo to $server";
	&alarm("sending helo to $server","");
	&ps("helo $hostname");
	while(<$S>) {
		print if $watch;
		last if /^\d+ /;
	}
	alarm(0);

	# try the users, one by one
	USER:
	while(@users) {
		$u = shift(@users);
		$0 = "$av0 - expanding $u [\@$server]";

		# do we already have a name for this user?
		$oldname = $names{"$u *** $server"};

		print &compact($u,$server)." ->\n" if ($verbose && ! $valid);
		if ($valid) {
			#
			# when running with -a, we delay taking any action 
			# on the results of our query until we have looked
			# at the complete output.  @toFinal stores expansions
			# that will be final if we take them.  @toExpn stores
			# expnansions that are not final.  @isValid keeps
			# track of our ability to send mail to each of the
			# expansions.
			#
			@isValid = ();
			@toFinal = ();
			@toExpn = ();
		}

#		($ecode,@expansion) = &expn_vrfy($u,$server);
		(@foo) = &expn_vrfy($u,$server);
		($ecode,@expansion) = @foo;
		if ($ecode) {
			&giveup('',$ecode,$u);
			last USER;
		}

		for $s (@expansion) {
			$s =~ s/[\n\r]//g;
			$0 = "$av0 - parsing $server: $s";

			$skipwatch = $watch;

			if ($s =~ /^[25]51([- ]).*<(.+)>/) {
				print "$s" if $watch;
				print "(pretending 250$1<$2>)" if ($debug && $watch);
				print "\n" if $watch;
				$s = "250$1<$2>";
				$skipwatch = 0;
			}

			if ($s =~ /^250([- ])(.+)/) {
				print "$s\n" if $skipwatch;
				($done,$addr) = ($1,$2);
				($newhost, $newaddr, $newname) =  &parse($addr,$server,$oldname, $#expansion == 0);
				print "($newhost, $newaddr, $newname) = &parse($addr, $server, $oldname)\n" if $debug;
				if (! $newhost) {
					# no expansion is possible w/o a new server to call
					if ($valid) {
						push(@isValid, &validAddr($newaddr));
						push(@toFinal,$newaddr,$server,$newname);
					} else {
						&verbose(&final($newaddr,$server,$newname));
					}
				} else {
					$newmxhost = &mx($newhost,$newaddr);
					print "$newmxhost = &mx($newhost)\n" 
						if ($debug && $newhost ne $newmxhost);
					$0 = "$av0 - parsing $newaddr [@$newmxhost]";
					print "levels = $levels, level{$u *** $server} = ".$level{"$u *** $server"}."\n" if ($debug > 1);
					# If the new server is the current one, 
					# it would have expanded things for us
					# if it could have.  Mx records must be
					# followed to compare server names.
					# We are also done if the recursion
					# count has been exceeded.
					if (&trhost($newmxhost) eq &trhost($server) || ($levels && $level{"$u *** $server"} >= $levels)) {
						if ($valid) {
							push(@isValid, &validAddr($newaddr));
							push(@toFinal,$newaddr,$newmxhost,$newname);
						} else {
							&verbose(&final($newaddr,$newmxhost,$newname));
						}
					} else {
						# more work to do...
						if ($valid) {
							push(@isValid, &validAddr($newaddr));
							push(@toExpn,$newmxhost,$newaddr,$newname,$level{"$u *** $server"});
						} else {
							&verbose(&expn($newmxhost,$newaddr,$newname,$level{"$u *** $server"}));
						}
					}
				}
				last if ($done eq " ");
				next;
			}
			# 550 is a known code...  Should the be
			# included in -a output?  Might be a bug
			# here.  Does it matter?  Can assume that
			# there won't be UNKNOWN USER responses 
			# mixed with valid users?
			if ($s =~ /^(550)([- ])/) {
				if ($valid) {
					print STDERR "\@$server:$u ($oldname) USER UNKNOWN\n";
				} else {
					&verbose(&final($u,$server,$oldname,"USER UNKNOWN"));
				}
				last if ($2 eq " ");
				next;
			} 
			# 553 is a known code...  
			if ($s =~ /^(553)([- ])/) {
				if ($valid) {
					print STDERR "\@$server:$u ($oldname) USER AMBIGUOUS\n";
				} else {
					&verbose(&final($u,$server,$oldname,"USER AMBIGUOUS"));
				}
				last if ($2 eq " ");
				next;
			} 
			# 252 is a known code...  
			if ($s =~ /^(252)([- ])/) {
				if ($valid) {
					print STDERR "\@$server:$u ($oldname) REFUSED TO VRFY\n";
				} else {
					&verbose(&final($u,$server,$oldname,"REFUSED TO VRFY"));
				}
				last if ($2 eq " ");
				next;
			} 
			&giveup('',"$server: did not grok '$s'",$u);
			last USER;
		}

		if ($valid) {
			#
			# now we decide if we are going to take these
			# expansions or roll them back.
			#
			$avgValid = &average(@isValid);
			print "avgValid = $avgValid\n" if $debug;
			if ($avgValid >= $validRequirement) {
				print &compact($u,$server)." ->\n" if $verbose;
				while (@toExpn) {
					&verbose(&expn(splice(@toExpn,0,4)));
				}
				while (@toFinal) {
					&verbose(&final(splice(@toFinal,0,3)));
				}
			} else {
				print "Tossing some valid to avoid invalid ".&compact($u,$server)."\n" if ($avgValid > 0.0 && ($vw || $debug));
				print &compact($u,$server)." ->\n" if $verbose;
				&verbose(&final($u,$server,$newname));
			}
		}
	}

	&alarm("sending 'quit' to $server",'');
	$0 = "$av0 - sending 'quit' to $server";
	&ps("quit");
	while(<$S>) {
		print if $watch;
		last if /^\d+ /;
	}
	close($S);
	alarm(0);
}

$0 = "$av0 - printing final results";
print "----------\n" if $vw;
select(STDOUT);
for $f (sort @final) {
	print "$f\n";
}
unlink("/tmp/expn$$");
exit(0);


# abandon all attempts deliver to $server
# register the current addresses as the final ones
sub giveup
{
	local($redirect_okay,$reason,$user) = @_;
	local($us,@so,$nh,@remaining_users);
	local($pk,$file,$line);
	($pk, $file, $line) = caller;

	$0 = "$av0 - giving up on $server: $reason";
	#
	# add back a user if we gave up in the middle
	#
	push(@users,$user) if $user;
	#
	# don't bother with this system anymore
	#
	unless ($giveup{$server}) {
		$giveup{$server} = $reason;
		print STDERR "$reason\n";
	}
	print "Giveup at $file:$line!!! redirect okay = $redirect_okay; $reason\n" if $debug;
	#
	# Wait!
	# Before giving up, see if there is a chance that
	# there is another host to redirect to!
	# (Kids, don't do this at home!  Hacking is a dangerous
	# crime and you could end up behind bars.)
	#
	for $u (@users) {
		if ($redirect_okay =~ /\bmx\b/) {
			next if &try_fallback('mx',$u,*server,
				*mx_secondary,
				*already_mx_fellback);
		}
		if ($redirect_okay =~ /\bdomainify\b/) {
			next if &try_fallback('domainify',$u,*server,
				*domainify_fallback,
				*already_domainify_fellback);
		}
		push(@remaining_users,$u);
	}
	@users = @remaining_users;
	for $u (@users) {
		print &compact($u,$server)." ->\n" if ($verbose && $valid && $u);
		&verbose(&final($u,$server,$names{"$u *** $server"},$reason));
	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -