package Check; use base Bbs; use strict; sub from # 値のチェック { my ($bbs_name, $bbs_path, $dat_path, $time, $key, $subject, $submit, $name, $mail, $message, $cap) = ( $_[0]->from('bbs'), $_[0]->path('bbs'), $_[0]->path('dat'), $_[0]->from('time'), $_[0]->from('key'), $_[0]->from('subject'), $_[0]->from('submit'), $_[0]->from('name'), $_[0]->from('mail'), $_[0]->from('message'), $_[0]->flag('cap')); my $imode = $_[0]->flag('ua_imode'); my ($open_port,$flag); my ($host,$use_proxy)=$_[0]->get_host(); $host =~ s/\[.*\]//; $_[0]->error('えらー','フォーム情報がおかしいですよ。[undef bbs]',undef,$Bbs::_BBS_STATUS_ERROR), return unless $bbs_name; $_[0]->error('えらー','フォーム情報がおかしいですよ。[undef time]',undef,$Bbs::_BBS_STATUS_ERROR), return unless $time; $_[0]->error('えらー','フォーム情報がおかしいですよ。[time]',undef,$Bbs::_BBS_STATUS_ERROR), return if $time =~ /\D/g; $_[0]->error('えらー','フォーム情報がおかしいですよ。[key]',undef,$Bbs::_BBS_STATUS_ERROR), return if $key =~ /\D/g; $_[0]->error('えらー','フォーム情報がおかしいですよ。[bbs]',undef,$Bbs::_BBS_STATUS_ERROR), return if $bbs_name =~ /\W/g; $_[0]->error('えらー','フォーム情報がおかしいですよ。[key & subject]',undef,$Bbs::_BBS_STATUS_ERROR), return if $key && $subject; $_[0]->error('えらー','フォーム情報がおかしいですよ。[time over]',undef,$Bbs::_BBS_STATUS_ERROR), return if ($time+$_[0]->conf('limit_fromtime')) < time; $_[0]->error('えらー','ぶらうざ変ですよ。[post data]',undef,$Bbs::_BBS_STATUS_ERROR), return unless ( $submit eq '書き込む' || $submit eq 'かきこむ' || $submit =~ /新規/ ) || length $_[0]->from('check') != 0 || length $_[0]->from('code') != 0; $_[0]->error('えらー','ぶらうざ変ですよ。[referer]',undef,$Bbs::_BBS_STATUS_ERROR), return unless $ENV{'HTTP_REFERER'} =~ /$ENV{'HTTP_HOST'}|$bbs_name|subbbs\.cgi/ || $imode || length $_[0]->from('check') != 0 || length $_[0]->from('code') != 0; $_[0]->error('えらー','文字化けしちゃうよ。','Shift-JISで書いてください。',$Bbs::_BBS_STATUS_ERROR), return if ( $submit !~ /^[\x81-\x95|\xE0-\xEF]/ || length $_[0]->from('submit') < 6 ); if($_[0]->setting('PROXY_CHECK')){ $_[0]->error('えらー','PROXYは規制中です。','PROXYをはずしてください。',$Bbs::_BBS_STATUS_ERROR), return if $use_proxy != 0; $_[0]->error('えらー','PROXYは規制中です。','JPドメインから書き込んでください。',$Bbs::_BBS_STATUS_ERROR), return if $host !~ /jp$/; $_[0]->error('えらー','PROXYは規制中です。','JPドメインからスレッドを立ててください。',$Bbs::_BBS_STATUS_ERROR), return if ! $subject && $host !~ /jp$/; $_[0]->error('えらー','PROXYは規制中です。','ホスト名が解決できないです。',$Bbs::_BBS_STATUS_ERROR), return if $host =~ /\d$/; } $_[0]->error('えらー','サブジェクトがないですよ。',undef,$Bbs::_BBS_STATUS_ERROR), return if length $subject == 0 && $_[0]->flag('make_dat'); $_[0]->error('えらー','名前がないですよ。',undef,$Bbs::_BBS_STATUS_ERROR), return if length $name == 0 && $_[0]->setting('NAME_CHECK') && !$cap; $_[0]->error('えらー','本文がないですよ。',undef,$Bbs::_BBS_STATUS_ERROR), return if length $message == 0; $_[0]->error('えらー','そんな掲示板は無いです。',undef,$Bbs::_BBS_STATUS_ERROR), return unless -e $bbs_path; $_[0]->error('えらー','subject.txtがないですよ。',undef,$Bbs::_BBS_STATUS_ERROR), return unless -e $bbs_path.$_[0]->conf('subject'); $_[0]->error('えらー','掲示板の設定がないですよ。',undef,$Bbs::_BBS_STATUS_ERROR), return unless -e $bbs_path.$_[0]->conf('setting'); $_[0]->error('えらー','スレッドがないか書き込めないですよ。',undef,$Bbs::_BBS_STATUS_ERROR), return unless -w $dat_path.$key.'.dat' || $_[0]->flag('make_dat'); $_[0]->error('えらー','処理が混んでいます。','戻ってちょっと待ってから書き込んでくださいね。',$Bbs::_BBS_STATUS_ERROR), return if $_[0]->setting('ASETTYA_DAME') > (time - (stat _)[9]); $_[0]->error('えらー',"スレッド[$key.dat]は".$_[0]->conf('limit_dat_file_size').'バイト以上になったので書き込めません。','新しいスレッドを立ててね。',$Bbs::_BBS_STATUS_ERROR), return if -s _ > $_[0]->conf('limit_dat_file_size'); $_[0]->error('えらー','長すぎる行があります。',undef,$Bbs::_BBS_STATUS_ERROR), return if $_[0]->Check::line_length(); $_[0]->error('えらー','名前が長すぎですよ。',undef,$Bbs::_BBS_STATUS_ERROR), return if (length $name > $_[0]->setting('LIMIT_NAME')) && !$cap; $_[0]->error('えらー','メールアドレスが長すぎですよ。',undef,$Bbs::_BBS_STATUS_ERROR), return if (length $mail > $_[0]->setting('LIMIT_MAIL')) && !$cap; $_[0]->error('えらー','サブジェクトが長すぎですよ。',undef,$Bbs::_BBS_STATUS_ERROR), return if (length $subject > $_[0]->setting('LIMIT_SUBJECT')) && !$cap; $_[0]->error('えらー','本文が長すぎですよ。',undef,$Bbs::_BBS_STATUS_ERROR), return if (length $message > $_[0]->setting('LIMIT_MESSAGE')) && !$cap; $_[0]->error('えらー','名前に変な文字列がまざっているよ。',undef,$Bbs::_BBS_STATUS_ERROR), return unless $name =~ /^(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC]|[\xA1-\xDF]|[\x20-\x7E])*$/; $_[0]->error('えらー','メールアドレスに変な文字列がまざっているよ。',undef,$Bbs::_BBS_STATUS_ERROR), return unless $mail =~ /^(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC]|[\xA1-\xDF]|[\x20-\x7E])*$/; $_[0]->error('えらー','サブジェクトに変な文字列がまざっているよ。',undef,$Bbs::_BBS_STATUS_ERROR), return unless $subject =~ /^(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC]|[\xA1-\xDF]|[\x20-\x7E])*$/; $_[0]->error('えらー','本文に変な文字列がまざっているよ。',undef,$Bbs::_BBS_STATUS_ERROR), return unless $message =~ /^(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC]|[\xA1-\xDF]|[\x20-\x7E])*$/; $_[0]->error('えらー','本文の改行が多すぎですよ。',undef,$Bbs::_BBS_STATUS_ERROR), return if $_[0]->conf('limit_line_break') < $_[0]->counter('replace_line_break'); $_[0]->error('えらー','レスアンカーが多すぎですよ。',undef,$Bbs::_BBS_STATUS_ERROR), return if $_[0]->conf('limit_res_anchor') < $_[0]->counter('replace_resanchor'); return $_[0] if $cap && $_[0]->setting('CAP_CHECK') ne 'checked'; # キャップ持ちはここでチェック終了 $_[0]->error('えらー','ホスト '.$host.' からのアクセスは規制されています。','管理者に問い合わせてみてください。',$Bbs::_BBS_STATUS_ERROR), return if !$cap && $_[0]->Check::log_ban(); $_[0]->error('えらー','2重書き込みの様ですよ。',undef,$Bbs::_BBS_STATUS_ERROR), return if $_[0]->flag('write_dat') && $_[0]->Check::log_response(); $_[0]->error('えらー','スレッド立てすぎですよ。','しばらくの間は、このホストからの新規スレッドの作成は出来ません。',$Bbs::_BBS_STATUS_ERROR), return if $_[0]->flag('make_dat') && !$cap && $_[0]->Check::log_thread(); if ( $_[0]->setting('PROXY_CHECK') ) { ($flag,$open_port) = $_[0]->Check::proxy_list(); $_[0]->error('えらー','PROXY '.$ENV{'REMOTE_ADDR'}.'は規制中です。 ',$open_port.'番 のポートが開いているので規制されています。PROXYをはずしてください。',$Bbs::_BBS_STATUS_ERROR), return if $flag; # ポートスキャンチェック $flag=0; my $h = (localtime time)[2]; $flag=1 if $host =~ /^mail|^ns|^dns|^ftp|^[^\.]\.[^\.]$/i; # 通常ありえない変なホスト名の場合はスキャンを行う $flag=1 unless $host =~ /ne\.jp|or\.jp|ad\.jp|bbtec\.net/i || ($host =~ /\.jp$|bbtec\.net/i && $h >= 9 && $h <= 17); # jpとYBBはスキャン除外 #debug $flag=1 if $_[0]->from('mail') =~ /\@portscan/; # 強制ポートスキャン #debug if ( $flag ) { ($flag,$open_port) = $_[0]->Check::port(); $_[0]->error('えらー','PROXYは規制中です。', 'ホスト '.$ENV{'REMOTE_ADDR'}.' は '.$open_port.'番 のポートが開いています。プロバイダかシステム管理者、又は、掲示板管理者に相談してみてください。',$Bbs::_BBS_STATUS_ERROR), return if $flag; } } # 連投チェック if ( $_[0]->flag('write_dat') && !$_[0]->flag('make_dat') && !defined $_[0]->from('check') ) { my $count; ($flag, $count) = $_[0]->Check::log_caution(); $_[0]->error(undef,undef,'これ以上書くとアクセス規制されます。もし書き込んだ場合あなたのホスト '.$host.' からの書き込みは一切拒否されます。'."\n",$Bbs::_BBS_STATUS_NOTICE), $_[0]->from('check'=>'[荒らし?][連続投稿]'), return if $count >= $_[0]->setting('PING_IYADURA'); $count = 0; ($flag, $count) = $_[0]->Check::log_succession_response(); $_[0]->flag('caution'=>1) if $count >= $_[0]->setting('RES_KAKISUGI'); $_[0]->error('ちゅうい','書き込みは完了しましたが連続投稿の注意が出ています。','注意されすぎるとアクセス規制されるかも。',$Bbs::_BBS_STATUS_CAUTION) if $_[0]->flag('caution'); } elsif ( !$_[0]->flag('write_dat') && $_[0]->flag('make_dat') && !defined $_[0]->from('check') ) { } elsif ( defined $_[0]->from('check') && index($_[0]->from('check'), '[') > -1 ) { # $_[0]->from('check') ne '' ) { $_[0]->flag('ban'=>1); } $_[0]; } sub port # ポートスキャン { #return if $ENV{'REMOTE_ADDR'} eq '127.0.0.1'; #ループバックアドレスは勘弁しちゃる my @port_list = split ',', ($_[0]->conf('check_port_list') || '80,8080'); my $time_out = $_[0]->conf('check_port_timeout') || 1; my ($port, $flag); foreach(@port_list){ eval{ local $SIG{'ALRM'} = sub{ die 'alarm'; }; eval{alarm $time_out;}; my $addr = gethostbyname( $ENV{'REMOTE_ADDR'} ) || die 'host'; my $sock_addr = pack 'SnA4x8', 2, $_, $addr; socket( SOCK, 2, 1, 6 ) || die 'socket'; connect( SOCK, $sock_addr ) || die 'connect'; die 'open'; }; $flag=1, $port = $_, last if index($@,'open') > -1;# =~ /open/g; } wantarray ? ($flag,$port) : $flag ; } sub log_thread # スレ立てすぎチェック {require Log; $_[0]->Check::_parse_log( $_[0]->path('bbs').$_[0]->file('thread'), $_[0]->Log::format( $_[0]->conf('delimiter'), '(?:.*)', '(?:.*)', undef), 0 );} sub log_response # 2重カキコチェック {require Log; $_[0]->Check::_parse_log( $_[0]->path('bbs').$_[0]->file('response'), $_[0]->Log::format( $_[0]->conf('delimiter'), $_[0]->from('time'), '(?:.*)', undef), 0 );} sub log_succession_response # 連続投稿チェック {require Log; my ($flag, $count) = $_[0]->Check::_parse_log( $_[0]->path('bbs').$_[0]->file('response'), $_[0]->Log::format( $_[0]->conf('delimiter'), '(?:.*)', '(?:.*)', undef), 1 ); ($flag, $count);} sub log_caution # 注意チェック {require Log; my ($flag, $count) = $_[0]->Check::_parse_log( $_[0]->path('bbs').$_[0]->file('caution'), $_[0]->Log::format( $_[0]->conf('delimiter'), '(?:.*)', '(?:.*)', undef), 1 ); ($flag, $count);} sub log_ban # アク禁チェック {require Log; $_[0]->Check::_parse_log( $_[0]->path('bbs').$_[0]->file('ban'), $_[0]->Log::format( $_[0]->conf('delimiter'), '(?:.*)', '(?:.*)', undef), 0 );} sub log_gonta # 板毎のアク禁チェック {require Log; $_[0]->Check::_parse_log( $_[0]->path('gonta').$_[0]->from('bbs').'.cgi', $_[0]->Log::format( $_[0]->conf('delimiter'), '(?:.*)', '(?:.*)', undef), 0 );} sub _parse_log # ログチェック { my $file = $_[1]; my $format = $_[2]; my $mode = $_[3]; # 0:ログとマッチする行が見つかった時点でチェック終了 1:全ての行をチェックしてついでにマッチした行がいくつあるかチェック my $flag; my $count=0; return unless open(FH, "<$file"); if ($mode==1) {while(){chomp;$flag = 1, $count++ if $_ =~ /^$format/;}} else {while(){chomp;$flag = 1, last if /^$format/;}} close FH; wantarray ? ($flag,$count) : $flag ; } sub proxy_list # アク禁串リストチェック { my $file = $_[0]->path('proxy') . $_[0]->file('proxy'); my $port; my $flag; return unless open FH, "<$file"; while(){ chomp; /^(.*):+?(\d*)$/; $port=$2; $flag=1, last if index($ENV{'REMOTE_ADDR'},$1) > -1;# =~ /$1/; } close FH; wantarray ? ($flag,$port) : $flag ; } sub line_length { my $br = $_[0]->conf('line_break'); my $limit = $_[0]->conf('limit_line_length'); my @msg = split $br, $_[0]->from('message'); return 1 if grep( length($_) > $limit, @msg ); return; } 1; __END__