#!/usr/bin/perl # package Mail::SpamCannibal::PageIndex; # # cannibal.cgi or cannibal.plx # link admin.cgi or admin.plx # # version 2.16, 11-16-08 # # Copyright 2003 - 2008, Michael Robinton # # 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 2 of the License, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # use strict; #use diagnostics; use vars qw(%ftxt $timeout); $timeout = 15; # 15 second timeout for internal UDP PTR lookup use Mail::SpamCannibal; # just for version number use IPTables::IPv4::DBTarpit; # just for version number use Mail::SpamCannibal::IP2ccFlag; use Mail::SpamCannibal::ScriptSupport qw( doINCLUDE lookupIP validIP valid127 is_GENERIC ); use Net::DNS::Codes qw(:all); use Net::DNS::ToolKit qw( newhead gethead get_ns inet_aton inet_ntoa ttlAlpha2Num ); use Net::DNS::ToolKit::Utilities qw( id query question rlook_send rlook_rcv ); use Mail::SpamCannibal::BDBclient qw( dataquery retrieve INADDR_NONE ); ######################################################################### # Individual pages are put together by calling the html_cat routine. # # See: Mail::SpamCannibal::WebService &html_cat # ######################################################################### use Mail::SpamCannibal::WebService qw( sendhtml html_cat cookie_date get_query make_jsPOP_win ); use Mail::SpamCannibal::Session qw( decode sesswrap ); my $CONFIG = doINCLUDE '../config/sc_web.conf'; die "could not load config file" unless $CONFIG; my $OverRide = 0; # override mod perl output my ($admin,$sess,%extraheaders); my $expire = $CONFIG->{expire} || 300; # default expiration 5 minutes my $log_expire = $CONFIG->{log_expire} || 180; # default expiration 3 minutes my %query = get_query(); # check for query from LaBrea client & convert if necessary if ($query{query} && $query{query} =~ /(\d+\.\d+\.\d+\.\d+)/) { $query{page} = 'lookup'; $query{lookup} = $1; } # return session on success, undef otherwise # sub is_cookie() { return($ENV{HTTP_COOKIE} && $ENV{HTTP_COOKIE} =~ /SpamCannibal=([\w-]+\.[\w-]+\.\d+\.\d+\.[\w-]+)/) ? $1 : undef; } my $admses = 0; my $user; my $passexp = 0; if ($ENV{SCRIPT_FILENAME} && $ENV{SCRIPT_FILENAME} =~ m|/admin\..+$|) { $extraheaders{'Set-Cookie'} = 'SpamCannibal=on; path=/; expires='. cookie_date(1); if (($admin = $CONFIG->{wrapper}) && -e $admin && -x $admin && do { # return true if good session instantiated if ( $query{user} && ($_ = sesswrap("$admin newtick $query{user}")) && $_ =~ /^OK\s+([\w-]+\.[\w-]+\.\d+\.\d+\.[\w-]+)/) { $sess = $1; $query{page} = 'passwd'; } elsif ( defined $query{passwd} && ($sess = is_cookie) && ($_ = sesswrap("$admin login $sess $log_expire $query{passwd} $CONFIG->{maxretry}")) && ($query{page} = '2realAH') && ($_ =~ /^OK\s*([^\s]+)/ || ($_ =~ /^NOT OK\s*([^\s]+)/ && ($query{page} = 'passwd'))) && ($user = $1)) { 1; } elsif ( ($sess = is_cookie) && ($_ = sesswrap("$admin chksess $sess $expire")) && $_ =~ /^OK\s*([^\s]+)/ && ($user = $1)) { 1; } else { 0; } } ) { $extraheaders{'Set-Cookie'} = 'SpamCannibal='. $sess . '; path=/; expires='. cookie_date(time + $expire); $extraheaders{'Set-Cookie'} .= '; secure' if $CONFIG->{secure}; $query{page} = 'ahome' unless $query{page}; $admses = $expire - 60; # this is an admin session $admses = 0 if $admses < 0; $admses *= 1000; # session web page timeout } else { $query{page} = 'login' unless $query{page} eq '2realAH'; # reset to login indirectly if password expire } push @{$CONFIG->{static}}, @{$CONFIG->{admin}}; if ($CONFIG->{secure} && ! $ENV{SSL_SERVER_CN}) { # bail if not secure connection $query{page} = 'sorry'; } } else { $query{page} = 'home' unless $query{page}; } # %ftxt will contain a like hash of cached text and will already # exist if there is a previous instantiation of this script %ftxt = () unless %ftxt; my $bgcolor = ($CONFIG->{bgcolor} && $CONFIG->{bgcolor} =~ /^#[0-9a-fA-F]{6}$/) ? $CONFIG->{bgcolor} :'#ffffff'; $ftxt{bgcolor} = qq| bgcolor="$bgcolor" |; $ftxt{versions} = q| |; my $html = ''; my $pagerror = ''; PageGen: while (1) { # for static pages, just issue them my ($name,$nav); if ($admin) { # use nav2 for admin $nav = ($query{page} =~ /sorry|login|passwd/) # no nav bar for listed pages ? '' : 'nav2'; $ftxt{versions} .= make_jsPOP_win('passwd',300,200) if $query{page} eq 'login'; } else { $nav = 'nav'; } ###### STATIC pages except 'home' foreach $name (@{$CONFIG->{static}}) { if ($query{page} =~ /^$name/) { foreach (qw( top bgcolor top2 versions logo2 stats ), $nav, $name, ) { html_cat(\$html,$_,$CONFIG,\%ftxt); } $html .= $pagerror; last PageGen; } } ###### HOME if ($query{page} =~ /^home/) { foreach (qw( top bgcolor top2 versions logo1 stats ), 'nav', 'home', ) { html_cat(\$html,$_,$CONFIG,\%ftxt); } $html .= (exists $CONFIG->{reason} && $CONFIG->{reason}) ? $CONFIG->{reason} : q |SpamCannibal does not block email access except for IP addresses and generic netblocks that have sent or relayed what we believe to be spam or other unsolicited email directly to our email servers. Spam originating IP addresses are blocked ONLY for access to our mail servers, however, the database we use for that purpose is freely available for anyone to look at and use as they see fit. |; $html .= "
\n"; last PageGen; } ###### WHOIS if ($query{page} =~ /^whois/) { my $IP = ($query{whois} && $query{whois} =~ /(\d+\.\d+\.\d+\.\d+)/) ? $1 : ''; foreach (qw( top bgcolor top2 versions logo2 stats ), $nav, 'whois', ) { html_cat(\$html,$_,$CONFIG,\%ftxt); } if ($IP) { if ($ENV{HTTP_REFERER} !~ /$ENV{SERVER_NAME}/i || $ENV{HTTP_REFERER} =~ m|/\?|) { $html .= qq| Due to the excessive load placed on our system, we have disabled the ability for third party sites to query the Whois Proxy through the web interface. Please enter your request manually. |; } else { my $cc = (@_ = Mail::SpamCannibal::IP2ccFlag::get($IP)) ? qq|  $_[0]$_[0]| : ''; require Mail::SpamCannibal::WhoisIP; my $lkup = qq|$IP|; $html .= "
Whois response for: ${lkup}$cc
"; my $socket = rlook_send($IP,$timeout); my $wtxt = &Mail::SpamCannibal::WhoisIP::whoisIP($IP); my @hostname = rlook_rcv($socket,$timeout); foreach (@hostname) { $html .= "\n  " . $_ . "
"; }; $html .= "
". $wtxt ."
\n"; } } last PageGen; } ###### CONTACT if ($query{page} =~ /^contact/) { die "email contact not configured" unless $CONFIG->{email}; foreach (qw( top bgcolor top2 versions logo2 stats ), $nav, ) { html_cat(\$html,$_,$CONFIG,\%ftxt); } $html .= q|
|. ($ENV{REMOTE_HOST} || '') .' '. ($ENV{REMOTE_ADDR} || '') .q|
|; $html .= $pagerror if $pagerror; html_cat(\$html,'contact',$CONFIG,\%ftxt); last PageGen; } ###### SENDMSG if ($query{page} =~ /^sendmsg/) { die "email contact not configured" unless $CONFIG->{email}; my($sc,$bc,$socket,@hostname); my $IP = ($query{IP} && $query{IP} =~ /\d+\.\d+\.\d+\.\d+/) ? $& : ''; if ($IP) { require Mail::SpamCannibal::SiteConfig; $sc = $CONFIG->{SiteConfig} || do { require Mail::SpamCannibal::SiteConfig; new Mail::SpamCannibal::SiteConfig; }; $bc = $sc->{SPMCNBL_CONFIG_DIR} . '/sc_BlackList.conf'; $bc = doINCLUDE($bc) || die "could not load blacklist config file... $bc"; $bc = ($bc->{GENERIC} && $bc->{GENERIC}->{blockcontact}) ? $bc->{GENERIC} : 0; # $bc points to GENERIC hash } foreach (qw( top bgcolor top2 versions logo2 stats ), $nav, ) { html_cat(\$html,$_,$CONFIG,\%ftxt); } if ($ENV{HTTP_REFERER} !~ /$ENV{SERVER_NAME}/i) { $html .= q| Automated send not allowed. |; } elsif ( ! $IP) { $html .= q| Invalid IP address. | . $query{IP} .q| |; } elsif ( $bc && do { $socket = rlook_send($IP,$timeout); @hostname = rlook_rcv($socket,$timeout); is_GENERIC($bc,@hostname)} ) { $pagerror = $IP .q| not eligible for removal: GENERIC PTR
|; foreach (@hostname) { $pagerror .= $_ . q|
|; } $pagerror .= q|
|; $query{page} = 'contact'; $html = ''; next PageGen; } else { require Mail::SpamCannibal::SMTPsend; if ($CONFIG->{altMXhosts}) { *Mail::SpamCannibal::SMTPsend::getMXhosts = sub { return @{$CONFIG->{altMXhosts}}; $_ = \*Mail::SpamCannibal::SMTPsend::getMXhosts; # suppress warning message } } $html .= q| Message sent. |; my $webmsg = qq|Subject: spamcannibal web contact Remote Host: $ENV{REMOTE_HOST} Remote Addr: $ENV{REMOTE_ADDR} Email addr: $query{email} IP address: $query{IP} |; $_ = Mail::SpamCannibal::SMTPsend::sendmessage($webmsg . $query{message},$CONFIG->{email}); } last PageGen; } ###### LOOKUP if ($query{page} =~ /^lookup/) { my $IP = validIP($query{lookup}); foreach (qw( top bgcolor top2 versions logo2 stats ), $nav, 'lookup', ) { html_cat(\$html,$_,$CONFIG,\%ftxt); } $html .= $query{pagerror}; if ($IP) { if ($ENV{HTTP_REFERER} !~ /$ENV{SERVER_NAME}/i || $ENV{HTTP_REFERER} =~ m|/\?|) { $html .= qq| Automated lookups not allowed, click LOOKUP IP to continue. |; } else { require Mail::SpamCannibal::SiteConfig; my $sc = $CONFIG->{SiteConfig} || do { require Mail::SpamCannibal::SiteConfig; new Mail::SpamCannibal::SiteConfig; }; unless (exists $CONFIG->{bdbDAEMON}) { $CONFIG->{bdbDAEMON} = $sc->{SPMCNBL_ENVIRONMENT} .'/bdbread'; } my @ccs; my $cc = (@ccs = Mail::SpamCannibal::IP2ccFlag::get($IP)) ? qq|  $ccs[0]$_[0]| : ''; my $substr = qq|$IP|; $html .= q|
|; } my @hostname = rlook_rcv($socket,$timeout); $html .= '
Click for WhoisIP: |. $substr . $cc; if ($admin) { $html .= q | 
X
delete
X CIDR/24
|; } my $socket = rlook_send($IP,$timeout); my ($second,$text,$results); if(ref $CONFIG->{bdbDAEMON}) { # remote? ($second,$text) = lookupIP($sc,$IP,@{$CONFIG->{bdbDAEMON}}); } else { ($second,$text) = lookupIP($sc,$IP,$CONFIG->{bdbDAEMON},0); } if($second) { # if secondary db 'blcontrib' $text =~ s|(http://([\w\.\-\?#&=/]+))|\$2\|; $results = "\n

\n". $text; } else { $text =~ s//>/g; # unmask html > $text =~ s/$IP(\D)/$substr$1/g; $results = "\n

\n". $text ."\n
"; } my $ip_found = 1; if ($admin && $text =~ /^not\s+in\s+\w+\s+database/) { $ip_found = 0; $html .= q|
 
¤
add to tarpit
'; if (@hostname) { my $hostname = ''; foreach(@hostname) { $hostname .= $_ . "
\n"; } $html .= q||; } else { $html .= q|
 |. $hostname .q|
|; } if ($admin) { $html .= q| |; } $html .= q|
  
 PTR's 
 |. $ccs[2] .q|
|. $results .q|
|; if ($admin) { $html .= q|
|; use integer; my $found = 0; my $related = ''; $IP =~ /\d+\.\d+\.\d+\./; my $cidr = $&; # get CIDR differential data and recover minus's ($_ = sesswrap("$admin getC24 $sess $expire $IP")) =~ s/;/:-/g; if ($_ =~ /^OK\s+(.+)/) { my($vec,@vals) = split(':',$1); # differential values to @vals @_ = split('',$vec); my $timetag = 0; foreach(0..$#_) { next unless $_[$_]; $timetag += shift @vals; my $addr = "${cidr}$_"; next if $addr eq $IP; $found += 1; $related .= q||. $addr .q||. scalar localtime($timetag) .q| |; } } else { # response was NOT OK $html .= '
' . $_ . '

' } if ($found) { $html .= q|
|. $found .q| record|. (($found > 1) ? 's' : '') .q| in the same netblock

|. $related .q|
host addresslast contactdelete

TOP
|; } } } } last PageGen; } ###### LOGOUT if ($admin && $query{page} =~ /^logout/) { $_ = sesswrap("$admin rmvsess $sess"); $query{page} = 'login'; $extraheaders{'Set-Cookie'} = 'SpamCannibal=expired; path=/; expires='. cookie_date(1); next PageGen; } ###### USRUPD if ($admin && $query{page} =~ /^usrupd/) { $query{passwd} = '' unless $query{passwd}; $query{passwd2} = '' unless $query{passwd2}; $pagerror .= 'blank user name
' unless $query{newuser}; $pagerror .= 'new passwords do not match
' if $query{passwd} ne $query{passwd2}; unless ($pagerror) { $_ = sesswrap("$admin updpass $sess $expire $query{newuser} $query{passwd} $query{oldpasswd}"); $pagerror .= '' . $_ . '
' unless $_ =~ /^OK/; } if ($pagerror) { # NOTE: see javascript entry at bottom of this page near tag $query{page} = 'updpass'; } else { $query{page} = 'ahome'; } next PageGen; } ###### 2REALAH if ($admin && $query{page} =~ '2realAH') { $html = q| SpamCannibal |; } ###### AHOME if ($admin && $query{page} =~ 'ahome') { foreach (qw( top bgcolor top2 versions logo2 stats ), $nav, ) { html_cat(\$html,$_,$CONFIG,\%ftxt); } $sess =~ /^[\w-]+/; $user = $&; $html .= q|
Access granted for:
User:|. decode($user) .q|
Host:|. ($ENV{REMOTE_HOST} || 'unknown') .q|
IP:|. ($ENV{REMOTE_ADDR} || '') .q|
|. ($ENV{HTTP_USER_AGENT} || 'unknown') .q|
|; last PageGen; } ###### SPAMADD if ($admin && $query{page} =~ /^spamadd/) { require Mail::SpamCannibal::ParseMessage; import Mail::SpamCannibal::ParseMessage qw( array2string string2array ); my $host = validIP($query{host}); $pagerror .= $query{host} .' invalid host IP address
' unless $host; my @spam; $pagerror .= ' no SPAM evidence entered
' unless $query{spam} =~ /\S+/ && string2array($query{spam},\@spam); if ($pagerror) { $query{page} = 'spamlst'; next PageGen; } require Mail::SpamCannibal::SiteConfig; my $sc = $CONFIG->{SiteConfig} || do { require Mail::SpamCannibal::SiteConfig; new Mail::SpamCannibal::SiteConfig; }; unless (exists $CONFIG->{bdbDAEMON}) { $CONFIG->{bdbDAEMON} = $sc->{SPMCNBL_ENVIRONMENT} .'/bdbread'; } # is this a CIDR insertion request for CIDR/24 - CIDR/31 my $action = ($query{submit} =~ /^(\d+)$/ && $1 < 32 && $1 >23) ? 'insEBLK'.$1 : 'insEVD'; foreach(0..$#spam) { $spam[$_] = '>'. $spam[$_] if $spam[$_] eq '.' && $_ != $#spam; } push @spam, '.' if $spam[$#spam] ne '.'; my $spam = array2string(\@spam); $_ = sesswrap("$admin $action $sess $expire $host",$spam); if ($_ =~ /^OK/) { $query{page} = 'lookup'; $query{lookup} = $host; } else { $query{page} = 'spamlst'; $pagerror = ''. $_ .'
'; } next PageGen; } ###### BLKADD if ($admin && $query{page} =~ /^blkadd/) { my $host = validIP($query{host}); my $response = valid127($query{response}); my $remote = validIP($query{remote}); my $seconds = $query{expire} || 0; $seconds = ttlAlpha2Num($seconds) + time; $pagerror .= $query{host} .' invalid host IP address
' unless $host; $pagerror .= $query{response} .' invalid local DNSBL response IP
' unless $response && $response eq $query{response}; $pagerror .= 'no TXT record string found
' unless $query{error}; $pagerror .= $query{remote} .' invalid remote DNSBL response IP
' unless $remote; $pagerror .= ' missing zone
' unless $query{zone}; $pagerror .= $query{zone} .' no NS records for this zone
' unless !$query{zone} || do { my $querybuf = question($query{zone},T_A()); my $resp = query(\$querybuf); if ($resp) { # got answer my ($off,$id,$qr,$opcode,$aa,$tc,$rd,$ra,$mbz,$ad,$cd,$rcode, $qdcount,$ancount,$nscount,$arcount) = gethead(\$resp); $ancount; } else { 0; } }; if ($pagerror) { $query{page} = 'blklist'; } else { $_ = sesswrap(qq|$admin insBL $sess $expire $host $response "$query{error}" $remote $seconds $query{zone}|); if ($_ =~ /^OK/) { $query{page} = 'lookup'; $query{lookup} = $host; } else { $query{page} = 'blklist'; $pagerror = ''. $_ .'
'; } } next PageGen; } ###### DELETE if ($admin && ( $query{page} =~ /^delete/ || $query{page} =~ /^delBLK/ )) { my $action = ($query{page} =~ /^delBLK/) ? 'delBLK' : 'delete'; $_ = sesswrap("$admin $action $sess $expire $query{remove}"); unless ($_ =~ /^OK/) { $query{pagerror} = ''. $_ .'
'; } if ($action eq 'delete' && exists $query{rm}) { my @zap = split("\0",$query{rm}); foreach my $ip (@zap) { $_ = sesswrap("$admin $action $sess $expire $ip"); $query{pagerror} .= ''. $_ .'
' unless $_ =~ /^OK/; } } $query{page} = 'lookup'; $query{lookup} = $query{remove}; next PageGen; } ###### DELETE LIST if ($admin && $query{page} =~ /^delist/ ) { foreach (qw( top bgcolor top2 versions logo2 stats ), $nav, 'delist', ) { html_cat(\$html,$_,$CONFIG,\%ftxt); } if (exists $query{remove}) { my @zap = split(/\n/,$query{remove}); my $cnt = 0; foreach (@zap) { next unless $_ =~ /^\s*(\d+\.\d+\.\d+\.\d+)/; my $ip = $1; next if $_ =~ /\stimeout\s/; # skip if this is a timeout $_ = sesswrap("$admin delete $sess $expire $ip"); unless ($_ =~ /^OK/) { $query{pagerror} = ''. $_ .'
'; } $cnt++; } unless ($cnt) { $pagerror = 'no valid IP addresses
'; } $html .= $pagerror; } last PageGen; } ###### RDNSBLK if ($admin && $query{page} =~ /^rdnsblk/ ) { my $IP = validIP($query{lookup}); my $regexp = $query{regexp} || ''; foreach (qw( top bgcolor top2 versions logo2 stats ), $nav, 'rdnsblk', ) { html_cat(\$html,$_,$CONFIG,\%ftxt); } if ($IP && $IP =~ /(\d+)\.(\d+)\.(\d+)/) { my $revip = "${3}.${2}.${1}.in-addr.arpa"; my $match = "${&}."; my $sock = IO::Socket::INET->new( PeerAddr => inet_ntoa(scalar get_ns()), PeerPort => 53, Proto => 'udp', Type => IO::Socket::INET::SOCK_DGRAM, ) or print STDERR "could not open socket for rdns lookup\n"; my($buffer,$response); (my $rgx = $regexp) =~ s/\\/\\\\/g; $html .= q|
|; $OverRide = 1; local $| = 1; # flush buffer on each print statement print q |Content-type: text/html |; if (keys %extraheaders) { foreach(keys %extraheaders) { print $_,':: ',$extraheaders{"$_"}; } } print q| |, $html; $html = ''; my($get,$put,$parse) = new Net::DNS::ToolKit::RR; foreach (0..255) { my $name = join('.',$_,$revip); my $ip = $match . $_; my $bp = \$buffer; my $offset = newhead($bp, id(), BITS_QUERY | RD, 1,0,0,0, ); $offset = $put->Question(\$buffer,$offset,$name,T_PTR,C_IN); eval { local $SIG{ALRM} = sub {die "timeout"}; alarm 5; # 5 second timeout my $wrote = syswrite $sock, $buffer, $offset; my $urcv; die "failed to get UDP message" unless defined ($urcv = sysread($sock, $response, NS_PACKETSZ)); alarm 0; }; if ($@) { print "\n"; next; } $bp = \$response; my ($newoff,$id,$qr,$opcode,$aa,$tc,$rd,$ra,$mbz,$ad,$cd,$rcode, $qdcount,$ancount,$nscount,$arcount) = gethead($bp); next if ($rcode != NOERROR); my($type,$class,$ttl,$rdlength,@rdata); foreach(0..$qdcount -1) { ($newoff,$name,$type,$class) = $get->Question($bp,$newoff); my $line = ''; foreach(0..$ancount -1) { ($newoff, $name,$type,$class,$ttl,$rdlength,@rdata) = $get->next($bp,$newoff); $line .= qq|\n|; $ip = ' '; } next if $regexp && $line =~ /$regexp/i; print $line; } } close $sock; $html .= q|
$iptimeout ${timeout}s
$ip$rdata[0]
|; } last PageGen; } ###### VIEW DB if ($admin && $query{page} =~ /^viewdb/) { foreach (qw( top bgcolor top2 versions logo2 stats ), $nav, ) { html_cat(\$html,$_,$CONFIG,\%ftxt); } my $sc = $CONFIG->{SiteConfig} || do { require Mail::SpamCannibal::SiteConfig; new Mail::SpamCannibal::SiteConfig; }; unless (exists $CONFIG->{bdbDAEMON}) { $CONFIG->{bdbDAEMON} = $sc->{SPMCNBL_ENVIRONMENT} .'/bdbread'; } $html =~ s/onLoad/onUnLoad=\"popadclose();\" onLoad/; $html .= make_jsPOP_win('alookup',580,400); $html .= q|
|; my %records; foreach( $sc->{SPMCNBL_DB_TARPIT}, $sc->{SPMCNBL_DB_ARCHIVE}, $sc->{SPMCNBL_DB_CONTRIB}, $sc->{SPMCNBL_DB_EVIDENCE}, ) { $html .= q| |; } $html .= q|
Select DATABASE to view
|; my($key,$val); if(ref $CONFIG->{bdbDAEMON}) { # remote? ($key,$val) = dataquery(1,0,$_,@{$CONFIG->{bdbDAEMON}}); } else { ($key,$val) = dataquery(1,0,$_,$CONFIG->{bdbDAEMON},0); } if (!$key || $key eq &INADDR_NONE()) { $val = 'OFFLINE'; $records{$_} = 0; } else { $records{$_} = $val; # save record count } $html .= $val .q| recs
|. $_ .q|
|; my $ip = ''; unless ((my $db = $query{datab}) && (my $rectop = $records{"$query{datab}"})) { # no database view requested $html .= q|
|; last PageGen; } else { # database view requested my($count,@IPs); my $recno = $query{recno} || 1; if ($recno =~ /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/ || $recno =~ /(\d{1,3}\.\d{1,3}\.\d{1,3})/ || $recno =~ /(\d{1,3}\.\d{1,3})/ || $recno =~ /(\d{1,3})\./ ) { # search for IP $ip = $1; $count = $ip =~ tr/\.//; # rationalize IP address while($count < 3) { $count++; $ip .= '.0'; } my $naddr = inet_aton($ip); my $rmax = $rectop; my $rmin = 1; while (1) { $recno = int(($rmax + $rmin)/2); if(ref $CONFIG->{bdbDAEMON}) { # remote? $count = retrieve(2,$recno,$db,\@IPs,@{$CONFIG->{bdbDAEMON}}); } else { $count = retrieve(2,$recno,$db,\@IPs,$CONFIG->{bdbDAEMON},0); } unless ($count) { # database is empty $html .= q| |; last PageGen; } # check if found last if $count == 1; last if $naddr eq $IPs[0]; if ($naddr eq $IPs[1]) { $recno -= 1 if $recno > 1; last; } # not found, bracketed? last if $naddr gt $IPs[0] && $naddr lt $IPs[1]; # try again if ($naddr lt $IPs[0]) { # move toward rmin $rmax = $recno -1; } else { # move toard rmax $rmin = $recno +1; } last unless $rmax > $rmin && $rmin > 0 && $rmax <= $rectop; } } elsif ($recno =~ /\D/) { # contains invalid character $recno = 1; } # bound record number $recno = $rectop - 254 if $recno > $rectop - 254; $recno = 1 if $recno < 1; if(ref $CONFIG->{bdbDAEMON}) { # remote? $count = retrieve(255,$recno,$db,\@IPs,@{$CONFIG->{bdbDAEMON}}); } else { $count = retrieve(255,$recno,$db,\@IPs,$CONFIG->{bdbDAEMON},0); } unless ($count) { # if database empty $html .= q| |; last PageGen; } $html .= q|
  database: |. $db .q| rec# or dd.[dd.dd.dd]
BEGIN
<<PREVIOUS
NEXT>>
END
  GOTO >
 record number |. $recno; if ($ip) { $html .= '   IP '. $ip; } $html .= q|
|; for(my $i=0;$i <= $#IPs;$i += 5) { $html .= ''; foreach(0..4) { my $cell = ' '; if ($IPs[$i+$_]) { my $ip = inet_ntoa($IPs[$i+$_]); $cell = ($ip =~ /^127\./) ? $ip : # no link for internal addresses q||. $ip .q||; } $html .= q| \n|; } $html .= qq|\n|; } $html .= q|
|. $cell . qq|
|; } last PageGen; } ###### END page search $html .= q|Not Found

The URL requested was not found on this server |; last PageGen; # oops! } # Special handling items # updpass # spamlst # $html .= q| | if $query{page} =~ /^updpass/; $query{spam} =~ s/\r//g; $query{spam} =~ s/\n/\\n/g; $html .= q| | if $query{page} =~ /^spamlst/ && validIP($query{host}); # if this is an admin session, insert page timer $html .= q| | if $admses && $query{page} !~ /login|passwd|2realAH/; $html .= q| |; if ($OverRide) { $OverRide = 0; print $html; } else { sendhtml(\$html,\%extraheaders); } 1;