#!/usr/bin/env perl
#!E:/ProgramFilesXP/Programming/Compiler/Perl/ActivePerl/bin/perl.exe
#!E:/ProgramFilesXP/Programming/Compiler/Perl/ActivePerl5.8/bin/perl.exe
binmode STDIN;
binmode STDOUT;
#=========================================================================
#・ソフト名称 WebProxy
#・作者 Lunar Night
#・バージョン 1.7.8
#・対応OS WinNT/UNIX系OS (Perl5 + Socket CGIが正常に動作すること)
#・種別 フリーソフト(商用利用する場合は別途規模により料金頂きます
#・概要 PerlProxyです
#・連絡先 lunar-night@ninus.ocn.ne.jp
#・ホームページ http://www.age.jp/~lunar/
#=========================================================================
#詳細はReadme.txt参照
$log_mode = "2"; #---ログ記録モード(0=なし、1=日単位、2=月単位)
$log_folder = "./sysdata/logs/"; #---ログ格納フォルダ
$system_folder = "./sysdata/"; #---システム一時フォルダ
$session_folder = "./sysdata/session/"; #---セッション記録フォルダ
$version = "1.7.8"; #---バージョン番号(変更しないで!)
#---ライブラリ設定
$lib_http = './lib/httpcontrol.pl';
$lib_jcode = './lib/jcode.pl';
$lib_des = './lib/des.pl';
$lib_md5 = './lib/md5.pl';
$lib_encrypt = './lib/encrypt.pl';
$lib_mojicode = './lib/mojicode.pl';
#---デフォルトヘッダー設定
$def_header = <<'HEAD';
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
HEAD
#---ダウンロード時にファイル名を通知するファイルの拡張子
%down_file_type = ('lzh' => 1,
'zip' => 1,
'gz' => 1,
'gca' => 1,
'yz1' => 1,
'exe' => 1,
'dat' => 1);
#---解析対象とするタグ
%replace_taglist = ('iframe' => 1,
'input' => 1,
'frame' => 1,
'a' => 1,
'area' => 1,
'td' => 1,
'tr' => 1,
'body' => 1,
'script' => 1,
'link' => 1,
'img' => 1,
'image' => 1,
'embed' => 1);
#---解析対象外とするファイル名の拡張子
%replace_filter = ('src'=> 1);
#------以下メインロジック-----#
#---Base64変換ハッシュ
%b64_encode = (
'000000', 'A', '000001', 'B', '000010', 'C', '000011', 'D',
'000100', 'E', '000101', 'F', '000110', 'G', '000111', 'H',
'001000', 'I', '001001', 'J', '001010', 'K', '001011', 'L',
'001100', 'M', '001101', 'N', '001110', 'O', '001111', 'P',
'010000', 'Q', '010001', 'R', '010010', 'S', '010011', 'T',
'010100', 'U', '010101', 'V', '010110', 'W', '010111', 'X',
'011000', 'Y', '011001', 'Z', '011010', 'a', '011011', 'b',
'011100', 'c', '011101', 'd', '011110', 'e', '011111', 'f',
'100000', 'g', '100001', 'h', '100010', 'i', '100011', 'j',
'100100', 'k', '100101', 'l', '100110', 'm', '100111', 'n',
'101000', 'o', '101001', 'p', '101010', 'q', '101011', 'r',
'101100', 's', '101101', 't', '101110', 'u', '101111', 'v',
'110000', 'w', '110001', 'x', '110010', 'y', '110011', 'z',
'110100', '0', '110101', '1', '110110', '2', '110111', '3',
'111000', '4', '111001', '5', '111010', '6', '111011', '7',
'111100', '8', '111101', '9', '111110', '+', '111111', '/',
);
@zero = ( '', '00000', '0000', '000', '00', '0' );
@pad = ( '', '===', '==', '=' );
#---月変換ハッシュ(^^;
%month_hash = ( 'Jan' => '01',
'Feb' => '02',
'Mar' => '03',
'Apr' => '04',
'May' => '05',
'Jun' => '06',
'Jul' => '07',
'Aug' => '08',
'Sep' => '09',
'Oct' => '10',
'Nov' => '11',
'Dec' => '12' );
require $lib_http; #---HTTPコントローラー
require $lib_jcode; #---日本語文字コード変換ライブラリ
require $lib_des; #---DES暗号化ライブラリ
require $lib_md5; #---MD5ハッシングライブラリ
require $lib_encrypt; #---暗号化補助ライブラリ
#---ファイル名設定
($tmp) = $0 =~ /([^\/\\]+)$/;
$filename = $tmp;
#---環境変数読み込み
$c_len = $ENV{'CONTENT_LENGTH'};
$query = $ENV{'QUERY_STRING' };
#---Cookie読み込み
%cookie = ();
&read_cookie(*cookie);
#---Signature読み込み
&mk_signature();
#---SystemInformation
if ($query eq "account_ctl"){ &syscheck();}
if ($query ne ""){
($s_id,$s_len,$query) = split(/:/,$query);
#---セッション読み込み
*hash_p = &read_session($s_id);
$ch_type1 = $hash_p{'ch_type1' };
$ch_type2 = $hash_p{'ch_type2' };
$usecookie= $hash_p{'cookie' };
$ftp_type = $hash_p{'ftp_type' };
$ftp_mail = $hash_p{'ftp_mail' };
$con_type = $hash_p{'con_type' };
$agent = $hash_p{'agent' };
$cryptseed= $hash_p{'crypt_s' };
$now_page = $hash_p{'page' };
$refer_f = $hash_p{'refer_f' };
$option_h = $hash_p{'opt_header'};
$auth_dat = $hash_p{'auth_dat' };
$random_f = $hash_p{'random_f' };
$b64_encf = $hash_p{'b64_enc' };
if ($cryptseed ne ""){
$random_s = "";
$random_s = $cookie{"c_seed"} if $random_f eq "1";
&encrypt("set_pass",$cryptseed.$random_s);
($rc,$query1) = &encrypt("decrypt",substr($query,0,$s_len),'b64') if $b64_encf eq "1";
($rc,$query1) = &encrypt("decrypt",substr($query,0,$s_len)) if $b64_encf ne "1";
if ($rc ne "1"){ &error($rc);}
$str = "crypt ";
}else{
$query1 = substr($query,0,$s_len);
$query1 =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack('H2', $1)/eg;
$str = "normal ";
}
$query = $query1.substr($query,$s_len);
&write_log($str."GET sub $query");
&http_get($query);
}elsif($c_len != 0){
%in = ();
&read_stdin(*in);
$ch_type1 = $in{'ch_type1' };
$ch_type2 = $in{'ch_type2' };
$usecookie= $in{'cookie' };
$ftp_type = $in{'ftp_type' };
$ftp_mail = $in{'ftp_mail' };
$con_type = $in{'con_type' };
$crypt = $in{'crypt' };
$agent = $in{'agent' };
$form_ctl = $in{'wp_form_ctl' };
$refer_f = $in{'refer_f' };
$s_id = $in{'wp_session_id'};
$option_h = $in{'opt_header' };
$random_f = $in{'random_f' };
$b64_encf = $in{'b64_enc' };
if ($form_ctl eq "top" && $crypt ne ""){
$cryptseed = time();
$random_s = "";
$random_s = unpack('H*',&md5::convert(rand())) if $random_f eq "1";
$in{"crypt_s"} = $cryptseed;
$add_cookie = "Set-Cookie: c_seed=$random_s;\n";
&encrypt("set_pass",$cryptseed.$random_s);
$str = "crypt ";
}else{
$cryptseed = "";
$str = "normal ";
}
#---セッション情報書き込み
&write_session($s_id,*in);
$buf = 'page:'.$in{'page'};
&write_log($str."GET top $buf");
&http_get($buf);
}
$s_id = &new_session();
print <
WebProxy Ver$version
WebProxy Ver$version
HTML
exit;
sub http_get{
($query) = @_;
$meth = substr($query,0,index($query,':'));
$url = substr($query,index($query,':')+1);
$now_url = $url;
#---認証?
$auth_pass = "";
if ($meth eq "auth" ){ ($auth_pass) = &http_auth_set($url);}
else {
if ($hash_p{"auth_dat"} ne ""){
$len = 0;
foreach $a (split(/\n/,$hash_p{"auth_dat"})){
($tmp_url,$tmp_pass) = split(/\0/,$a);
if (index($url,$tmp_url) == 0){
if (length($tmp_url) > $len){
$auth_pass = $tmp_pass;
$len = length($tmp_url);
}
}
}
}
}
#---FTP?
if ($meth eq "ftp" ){ &ftp_get($url);}
if ($url =~ /^ftp:\/\//){ &ftp_get($url);}
#---URL階層処理用データ
&set_base_addr($url);
#---POST/GETデータ処理
$send_jump_sub = "";
if ($con_type eq "" || $con_type eq "keep"){ $con = "Keep-Alive";}
else { $con = "close"; }
#---拡張ヘッダー
%add_header = ();
if ($option_h eq ""){ $option_h = $def_header;}
foreach $a (split(/\n/,$option_h)){
($key,$val) = split(/\s*:\s*/,$a);
$posi = index($a,':');
$key = substr($a,0,$posi);
$val = substr($a,$posi+1);
$key = lc($key);
$add_header{$key} = $val;
}
$add_header{"connection"} = $con;
$add_header{"referer"} = $now_page if $refer_f ne "";
$add_header{"authorization"} = "Basic $auth_pass" if $auth_pass ne "";
$content_len = $ENV{'CONTENT_LENGTH'};
if ($meth eq "post"){ $send_jump_sub = "main::http_send";
$add_header{"content-length"} = $content_len;
$add_header{"content-type" } = $ENV{'CONTENT_TYPE'};
}
elsif($meth eq "get" ){ read(STDIN,$buf,$content_len);
$url .= "?".$buf;
}
if ($usecookie eq "2"){
(*cookie) = &get_cookie($url);
}
%input_hash = ("url" => $url,
"data_jump" => "main::http_read",
"send_jump" => $send_jump_sub,
"add_head" => *add_header,
"cookie_data"=> *cookie);
($res,*out_head,*out_data) = &httpcontrol(*input_hash);
if ($res != 1){ &error($res);}
exit;
}
sub ftp_get{
($url) = @_;
require './lib/ftpcontrol.pl';
$url =~ m!(\w+:)?(//)?([^:/]*)?(:([0-9]+)?)?(/.*)?!;
if ($ftp_type eq ""){ &error("FTP通信は利用不可に設定されています");}
if ($1 ne "ftp:" ){ &error("不正なFTPアドレスです:$url"); }
if ($3) {$host = $3;}
if ($5) {$port = $5;}
if ($6) {$path = $6;}
#---ディレクトリ?
if ($path =~ /\/$/){ &ftp_list($url);}
$out_head = "";
%ftp_con = ("host" => $host,
"port" => $port,
"user" => "Anonymous",
"pass" => $ftp_mail);
%ftp_opt = ("transfer_mode" => "pasv",
"target" => $path,
"jump" => 'main::ftp_output');
($rc) = &ftpcontrol("login","",*ftp_con);
if (substr($rc,0,5) eq "ERROR"){ &error($rc);}
($rc) = &ftpcontrol("get_file",*ftp_opt,*ftp_con);
if (substr($rc,0,5) eq "ERROR"){ &error($rc);}
($rc) = &ftpcontrol("logout",*ftp_opt,*ftp_con);
if (substr($rc,0,5) eq "ERROR"){ &error($rc);}
exit;
}
sub ftp_output{
($dat) = @_;
if ($out_head eq ""){
($file) = $path =~ /\/([^\/]+$)/;
print "Content-type: application/octet-stream\n";
print "Content-Disposition: attachment; filename=\"$file\"\n\n";
$out_head = "1";
}
print $dat;
}
sub ftp_list{
($url) = @_;
$url =~ m!(\w+:)?(//)?([^:/]*)?(:([0-9]+)?)?(/.*)?!;
if ($ftp_type eq ""){ &error("FTP通信は利用不可に設定されています");}
if ($1 ne "ftp:" ){ &error("不正なFTPアドレスです:$url"); }
if ($3) {$host = $3;}
if ($5) {$port = $5;}
if ($6) {$path = $6;}
%ftp_con = ("host" => $host,
"port" => $port,
"user" => "Anonymous",
"pass" => $ftp_mail);
%ftp_opt = ("transfer_mode" => "pasv",
"path" => $path );
($rc) = &ftpcontrol("login","",*ftp_con);
if (substr($rc,0,5) eq "ERROR"){ &error($rc);}
($rc) = &ftpcontrol("filelist",*ftp_opt,*ftp_con);
if (substr($rc,0,5) eq "ERROR"){ &error($rc);}
*dsp_list = $rc;
($rc) = &ftpcontrol("logout",*ftp_opt,*ftp_con);
if (substr($rc,0,5) eq "ERROR"){ &error($rc);}
#---Fileリスト解析
$def_year = (localtime())[5];
$def_year += 1900;
$out_size=0;
$dirs = "";
$files = "";
foreach $a (@dsp_list){
if ($a =~ /^total/){ next;}
($perm,$type,$user,$group,$size,$month,$day,$time,$file) =
$a =~ /([^\s]+)\s*(\d+)\s*([^\s]+)\s*([^\s]+)\s*(\d+)\s*(\w+)\s*(\d+)\s*([\d:]+)\s*([^\n]+)/;
if ($time !~ /(\d*):(\d*)/){ $year = $time; $time = "";}
else { $year = $def_year; }
if ($day < 10){ $day = "0".$day;}
$date = $year."/".$month_hash{$month}."/".$day." ".$time;
if ($file eq "." || $file eq ".."){ next;}
if (substr($perm,0,1) eq "d"){
$str = $url.$file."/";
$link= &encode("ftp:$str");
&jcode'convert(*file,"euc");
$dirs .= "| $file/ | $date | $size |
\n";
}else{
$str = $url.$file;
$link= &encode("ftp:$str");
&jcode'convert(*file,"euc");
$files .= "| $file | $date | $size |
\n";
}
}
@item = split(/\//,$url);
pop(@item);
$str = join("/",@item)."/";
$link= &encode("ftp:$str");
$parent = "| ../ | - | - |
";
print <
Index of $path At $host - WebProxy Ver$version
WebProxy Ver$version - FTP Proxy
Index of $path At $host |
| Name |
Date |
Size |
|
$parent
$dirs
| |
$files
|
HTML
exit;
}
sub http_send{
$buf_size = 10240;
$max_size = $content_len;
$now_size = 0;
while($max_size > $now_size){
read(STDIN,$buf,$buf_size);
$now_size += length($buf);
&http_control'http_tr($buf);
}
}
sub encode{
($dat) = @_;
if ($cryptseed ne ""){
$dat = &encrypt("encrypt",$dat,'b64') if $b64_encf eq "1";
$dat = &encrypt("encrypt",$dat ) if $b64_encf ne "1";;
}else{
$dat =~ s/(\W)/'%' . unpack('H2', $1)/eg;
}
$len = length($dat);
return("$s_id:$len:$dat");
}
sub set_base_addr{
$url = $_[0];
($prot,$host,$addr) = $url =~ /(s?https?:\/\/)([^\/]+)([^\?]*)/;
$str = "";
$addr =~ s/([^\/]*)$//;
@addr_array = ();
if ($url =~ /s?https?:\/\/[^\/]+$/ || $addr eq "/"){
@addr_array = ($prot.$host."/");
$addr = $prot.$host."/";
}else{
foreach $a (split(/\//,$addr)){
$str .= $a."/";
unshift(@addr_array,$prot.$host.$str);
}
}
}
sub http_read{
$flag = 0;
%http_outhead= ();
$http_msg = &http_control'http_rc();
$http_msg =~ s/\r//;
$http_msg =~ s/\n//;
$http_type = lc(substr($http_msg,0,8));
$html_data = "";
#---ヘッダー読み込み
while(1){
$buf = &http_control'http_rc();
#---切り替え
if ($buf eq "\r\n" || $buf eq "\n"){ last;}
$buf =~ s/\r//;
$buf =~ s/\n//;
$data = index($buf,":");
$key = substr($buf,0,$data);
$val = substr($buf,$data+2);
if (lc($key) eq "set-cookie"){ $http_outhead{lc($key)} .= "$buf\n";}
else { $http_outhead{lc($key)} .= $val; }
}
#---KeepAlive確認
$content_size = 0;
if ($http_type eq "http/1.1" && $http_outhead{"content-length"} eq ""){ $flag = 1;}
elsif($http_type eq "http/1.1" && $http_outhead{"content-length"} ne ""){ $flag = 2;}
else { $flag = 3;}
#---Keep-Aliveタイプ1
$bad_data = "";
if ($flag == 1){
$content_size = &http_control'http_rc();
$tmp = $content_size;
$tmp =~ s/\r|\n| //g;
if ($tmp =~ /[^0-9a-fA-F]/ ||
$tmp eq "" ){ $flag = 3;
$bad_data = $content_size; }
else { $http_outhead{"content-length"} = hex($tmp);}
}
#---Keep-Aliveタイプ2
if ($flag == 2 || $flag == 1){
$content_size = $http_outhead{"content-length"};
$buf_size = 10240;
}
#---ダウンロードファイル名指定
($down_type) = $url =~ /\.([^\.]+)$/;
if ($http_outhead{"content-disposition"} eq "" &&
$down_file_type{lc($down_type)} == 1 ){ ($down_name) = $url =~ /\/([^\/]+)$/;
$http_outhead{"content-disposition"} = "attachment; filename=\"$down_name\"";}
#---text/htmlのときの処理
$http_outhead{"content-length"} = "" if $http_outhead{"content-type"} eq "text/html";
#---認証あり?
if ($http_outhead{"www-authenticate"} ne ""){
($auth_name) = $http_outhead{"www-authenticate"} =~ /realm\s*=\s*\"*([^\"]+)\"*/;
&http_auth($auth_name);
return(1);
}
#---ヘッダー出力
&output_header(*http_outhead,$flag);
if ($http_outhead{"content-type"} =~ /text\/html/i){ $out_flag = 1;}
elsif($http_outhead{"content-type"} eq "" ){ $out_flag = 1;}
elsif($http_outhead{"content-type"} =~ /text\//i &&
$url =~ /\.css$/i ){ $out_flag = 2;}
elsif($htto_outhead{"content-type"} =~ /text\/css/i ){ $out_flag = 2;}
else { $out_flag = 3;}
#---データ取得タイプ1
if ($flag == 1 || $flag == 2){
$last_f = 0;
while($content_size > 0){
if ($content_size <= $buf_size){ $read_size = $content_size;
$last_f = 1 if $flag == 1;
$content_size = 0; }
else { $read_size = $buf_size;
$content_size -= $buf_size; }
$buf = &http_control'http_rc($read_size);
$content_size += $read_size - length($buf);
if ($out_flag == 1 ||
$out_flag == 2){ $html_data .= $buf; }
elsif($out_flag == 3){ print $buf; }
if ($last_f == 1){ $tmp = &http_control'http_rc();$tmp = &http_control'http_rc();
$tmp =~ s/\r|\n| //g;
$content_size = hex($tmp);
if ($content_size != 0){ $last_f = 0;}
else { last; }
}
}
}
#---データ取得タイプ2
if ($flag == 3){
if ($out_flag == 1 ||
$out_flag == 2){ $html_data .= $bad_data;}
elsif($out_flag == 3){ print $bad_data; }
while(1){
$buf = &http_control'http_rc();
if ($out_flag == 1||
$out_flag == 2){ $html_data .= $buf;}
elsif($out_flag == 3){ print $buf; }
if (index($buf,"\n") < 0){ last;}
}
}
#---HTMLデータ解析
if ($out_flag == 1){
($match,$code) = &jcode'getcode(*html_data);
# if ($code ne "euc" &&
# $code ne "sjis"&&
# $code ne "jis"){ $code = "";}
# $tmpstr= "";
# if ($code eq ""){
# foreach $ctx (split(/\n/,$html_data)){
# &jcode'convert(*ctx,"euc");
# $tmpstr .= $ctx."\n";
# }
# $html_data = $tmpstr;
# }else{
# &jcode'convert(*html_data,"euc",$code);
# }
&jcode'convert(*html_data,"euc",$code) if $code ne "";
#---Script修正
$html_data =~ s/(