diff --git a/ripecheck.tcl b/ripecheck.tcl index 8013e3e..2b00764 100644 --- a/ripecheck.tcl +++ b/ripecheck.tcl @@ -110,20 +110,22 @@ # RIPE Country Checker -# --- Settings --- +if {[namespace exists ::ripecheck]} {namespace delete ::ripecheck} +namespace eval ::ripecheck { + # --- Settings --- -# RIPE query timeout setting, default 5 seconds -set rtimeout 5 + # RIPE query timeout setting, default 5 seconds + variable rtimeout 5 -# Set console output flag, for debug purpose (default d, ie .console +d) -set conflag d + # Set console output flag, for debug purpose (default d, ie .console +d) + variable conflag d -# Path to netmask file -set iplistfile "scripts/iplist.txt" - -# Path to channel settings file -set ripechanfile "ripecheckchan.dat" + # Path to netmask file + variable iplistfile "scripts/iplist.txt" + # Path to channel settings file + variable chanfile "ripecheckchan.dat" +} # ---- Only edit stuff below this line if you know what you are doing ---- # Channel flags @@ -137,653 +139,646 @@ setudef int ripecheck.bantime package require ip # Bindings -bind join - *!*@* _ripecheck_onjoin -bind dcc -|- testripecheck _testripecheck -bind dcc m|ov +ripetopdom _+ripetopdom -bind dcc m|ov -ripetopdom _-ripetopdom -bind dcc m|ov +ripetopresolv _+ripetopresolv -bind dcc m|ov -ripetopresolv _-ripetopresolv -bind dcc m|ov ripebanr _ripebanreason -bind dcc -|- ripesettings _ripesettings -bind dcc -|- help _ripe_help_dcc -bind pub -|- !ripecheck _pubripecheck - -# Global variables -set ver "2.6.1" -set maskarray [list] - -# Parse ip list file -if {[file exists $iplistfile]} { - set fid [open $iplistfile r] - while { ![eof $fid] } { - gets $fid line - if {[regexp {^\#} $line]} { - continue - } - regexp {^([0-9\.\/]+)[[:space:]]+([a-z\.]+)} $line dummy mask whoisdb - lappend maskarray $mask - set maskhash($mask) $whoisdb - } - close $fid - putloglev $conflag * "ripecheck: DEBUG - IP file loaded with [llength $maskarray] netmasks" -} - -# Read settings - only at startup -if {[file exists $ripechanfile]} { - set fchan [open $ripechanfile r] - while { ![eof $fchan] } { - gets $fchan line - if {[regexp {^\#} $line]} { - set chanarr([string tolower [lindex [split $line :] 0]]) [split [lindex [split $line :] 1] ,] - } elseif {[regexp {^topresolv} $line]} { - set topresolv([string tolower [lindex [split $line :] 1]]) [split [lindex [split $line :] 2] ,] - } elseif {[regexp {^config} $line]} { - set ripeconfig([lindex [split $line :] 1]) [lindex [split $line :] 2] +bind join - *!*@* $::ripecheck::onJoin +bind dcc -|- testripecheck $::ripecheck::test +bind dcc m|ov +ripetopdom $::ripecheck::addTopDom +bind dcc m|ov -ripetopdom $::ripecheck::delTopDom +bind dcc m|ov +ripetopresolv $::ripecheck::addTopResolve +bind dcc m|ov -ripetopresolv $::ripecheck::delTopResolve +bind dcc m|ov ripebanr $::ripecheck::banReason +bind dcc -|- ripesettings $::ripecheck::ripeSettings +bind dcc -|- help $::ripecheck::help +bind pub -|- !ripecheck $::ripecheck::pubRipeCheck + +namespace eval ::ripecheck { + # Global variables + variable version "2.6.1" + variable maskarray [list] + + # Parse ip list file + if {[file exists $::ripecheck::iplistfile]} { + set fid [open $::ripecheck::iplistfile r] + while { ![eof $fid] } { + gets $fid line + if {[regexp {^\#} $line]} { + continue + } + regexp {^([0-9\.\/]+)[[:space:]]+([a-z\.]+)} $line dummy mask whoisdb + lappend ::ripecheck::maskarray $mask + variable maskhash($mask) $whoisdb } + close $fid + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - IP file loaded with [llength $::ripecheck::maskarray] netmasks" + } + + # Read settings - only at startup + if {[file exists $::ripecheck::chanfile]} { + set fchan [open $::ripecheck::chanfile r] + while { ![eof $fchan] } { + gets $fchan line + if {[regexp {^\#} $line]} { + variable chanarr([string tolower [lindex [split $line :] 0]]) [split [lindex [split $line :] 1] ,] + } elseif {[regexp {^topresolv} $line]} { + variable topresolv([string tolower [lindex [split $line :] 1]]) [split [lindex [split $line :] 2] ,] + } elseif {[regexp {^config} $line]} { + variable config([lindex [split $line :] 1]) [lindex [split $line :] 2] + } + } + close $fchan + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - Channel file loaded with settings for [array size ::ripecheck::chanarr] channel(s)" + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - Top resolv domains loaded for [array size ::ripecheck::topresolv] channel(s)" } - close $fchan - putloglev $conflag * "ripecheck: DEBUG - Channel file loaded with settings for [array size chanarr] channel(s)" - putloglev $conflag * "ripecheck: DEBUG - Top resolv domains loaded for [array size topresolv] channel(s)" -} -# Functions -proc _ripecheck_onjoin { nick host handle channel } { - global topresolv chanarr conflag ripeconfig + # Functions + proc onJoin { nick host handle channel } { + # Lower case channel + set channel [string tolower $channel] - # Lower case channel - set channel [string tolower $channel] - - # Only run if channel is defined - if {![channel get $channel ripecheck]} { return 0 } - - # Exclude ops, voice, friends - if {[matchattr $handle fov|fov $channel]} { - putloglev $conflag * "ripecheck: $nick is on exempt list" - return 0 - } + # Only run if channel is defined + if {![channel get $channel ripecheck]} { return 0 } - # Check if channel has a domain list or complain about it and then abort - if {![info exists chanarr($channel)]} { - putlog "ripecheck: Ripecheck is enabled but $channel has no domain list!" - return 0 - } + # Exclude ops, voice, friends + if {[matchattr $handle fov|fov $channel]} { + putloglev $::ripecheck::conflag * "ripecheck: $nick is on exempt list" + return 0 + } - # Get IP/Host part - regexp ".+@(.+)" $host matches iphost + # Check if channel has a domain list or complain about it and then abort + if {![info exists ::ripecheck::chanarr($channel)]} { + putlog "ripecheck: Ripecheck is enabled but $channel has no domain list!" + return 0 + } - # Top domain ban if enabled - if {[channel get $channel ripecheck.topban]} { - set htopdom [lindex [split $iphost "."] end] - foreach domain $chanarr($channel) { - if {![string compare $htopdom $domain]} { - set template [list %nick% $nick \ - %domain% $domain] - set bantime [channel get $channel ripecheck.bantime] - if {[info exists ripeconfig(bantopreason)]} { - set banreason [ripe_replace $ripeconfig(bantopreason) $template] - } else { - set banreason "RIPE Country Check: Top domain .$domain is banned." + # Get IP/Host part + regexp ".+@(.+)" $host matches iphost + + # Top domain ban if enabled + if {[channel get $channel ripecheck.topban]} { + set htopdom [lindex [split $iphost "."] end] + foreach domain $::ripecheck::chanarr($channel) { + if {![string compare $htopdom $domain]} { + set template [list %nick% $nick \ + %domain% $domain] + set bantime [channel get $channel ripecheck.bantime] + if {[info exists ::ripecheck::config(bantopreason)]} { + set banreason [::ripecheck::templateReplace $::ripecheck::config(bantopreason) $template] + } else { + set banreason "RIPE Country Check: Top domain .$domain is banned." + } + putlog "ripecheck: Matched top domain '$domain' banning *!*.$domain for $bantime minute(s)" + newchanban $channel "*!*@*.$domain" ripecheck $banreason $bantime + + return 0 } - putlog "ripecheck: Matched top domain '$domain' banning *!*.$domain for $bantime minute(s)" - newchanban $channel "*!*@*.$domain" ripecheck $banreason $bantime - - return 0 } } - } - # Only run RIPE check on numeric IP unless ripecheck.topchk is enabled - if {[regexp {[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$} $iphost]} { - putloglev $conflag * "ripecheck: DEBUG - Found numeric IP $iphost ... scanning" - whois_find_server $iphost $iphost 1 $nick $channel $host 0 - } elseif {[channel get $channel ripecheck.topchk]} { - # Check if channel has a resolv domain list or complain about it and then abort - if {![info exists topresolv($channel)]} { - putlog "ripecheck: Ripecheck is enabled but $channel has no resolv domain list!" - return 0 - } + # Only run RIPE check on numeric IP unless ripecheck.topchk is enabled + if {[regexp {[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$} $iphost]} { + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - Found numeric IP $iphost ... scanning" + ::ripecheck::whoisFindServer $iphost $iphost 1 $nick $channel $host 0 + } elseif {[channel get $channel ripecheck.topchk]} { + # Check if channel has a resolv domain list or complain about it and then abort + if {![info exists topresolv($channel)]} { + putlog "ripecheck: Ripecheck is enabled but $channel has no resolv domain list!" + return 0 + } - putloglev $conflag * "ripecheck: DEBUG - Trying to resolve host ..." + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - Trying to resolve host ..." - set htopdom [lindex [split $iphost "."] end] - foreach domain $topresolv($channel) { - putloglev $conflag * "ripecheck: DEBUG - domain: $domain ip: $iphost" - if {[regexp "^$domain$" $htopdom]} { - putloglev $conflag * "ripecheck: DEBUG - Matched resolve domain '$domain'" - dnslookup $iphost whois_find_server $nick $channel $host 0 - # Break the loop since we found a match - break + set htopdom [lindex [split $iphost "."] end] + foreach domain $topresolv($channel) { + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - domain: $domain ip: $iphost" + if {[regexp "^$domain$" $htopdom]} { + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - Matched resolve domain '$domain'" + dnslookup $iphost ::ripecheck::whoisFindServer $nick $channel $host 0 + # Break the loop since we found a match + break + } } } } -} - -proc ripecheck { ip host nick channel orghost ripe } { - global chanarr ripeconfig - set bantime [channel get $channel ripecheck.bantime] - foreach country $chanarr($channel) { - if {![string compare $ripe $country]} { - set template [list %nick% $nick \ - %ripe% $ripe] - if {[info exists ripeconfig(banreason)]} { - set banreason [ripe_replace $ripeconfig(banreason) $template] - } else { - set banreason "RIPE Country Check: Matched .$ripe" + proc ripecheck { ip host nick channel orghost ripe } { + set bantime [channel get $channel ripecheck.bantime] + foreach country $::ripecheck::chanarr($channel) { + if {![string compare $ripe $country]} { + set template [list %nick% $nick \ + %ripe% $ripe] + if {[info exists ::ripecheck::config(banreason)]} { + set banreason [ripe_replace $::ripecheck::config(banreason) $template] + } else { + set banreason "RIPE Country Check: Matched .$ripe" + } + putlog "ripecheck: Matched country '$ripe' banning $nick!$orghost for $bantime minute(s)" + newchanban $channel "*!*@$host" ripecheck $banreason $bantime + # Break the loop since we found a match + break } - putlog "ripecheck: Matched country '$ripe' banning $nick!$orghost for $bantime minute(s)" - newchanban $channel "*!*@$host" ripecheck $banreason $bantime - # Break the loop since we found a match - break } } -} -proc _testripecheck { nick idx arg } { - global topresolv conflag + proc test { nick idx arg } { + global topresolv conflag - if {[llength [split $arg]] != 2} { - _ripe_help_dcc $nick $idx testripecheck; return 0 - } + if {[llength [split $arg]] != 2} { + _ripe_help_dcc $nick $idx testripecheck; return 0 + } - foreach {channel ip} $arg {break} - set ip [string tolower $ip] - set channel [string tolower $channel] + foreach {channel ip} $arg {break} + set ip [string tolower $ip] + set channel [string tolower $channel] - if {[validchan $channel]} { - if {[regexp {[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$} $ip]} { - whois_find_server $ip "" "" $nick $channel "" 1 - } else { - putloglev $conflag * "ripecheck: DEBUG - Resolving..." - set htopdom [lindex [split $ip "."] end] - foreach domain $topresolv($channel) { - putloglev $conflag * "ripecheck: DEBUG - channel: $channel domain: $domain ip: $ip top domain: $htopdom" - if {[regexp "^$domain$" $htopdom]} { - putloglev $conflag * "ripecheck: DEBUG - Matched resolve domain '$domain' for $channel" - dnslookup $ip whois_find_server $nick $channel "" 1 - # Break the loop since we found a match - break + if {[validchan $channel]} { + if {[regexp {[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$} $ip]} { + whois_find_server $ip "" "" $nick $channel "" 1 + } else { + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - Resolving..." + set htopdom [lindex [split $ip "."] end] + foreach domain $topresolv($channel) { + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - channel: $channel domain: $domain ip: $ip top domain: $htopdom" + if {[regexp "^$domain$" $htopdom]} { + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - Matched resolve domain '$domain' for $channel" + dnslookup $ip whois_find_server $nick $channel "" 1 + # Break the loop since we found a match + break + } } } + } else { + putdcc $idx "\002RIPECHECK\002: Invalid channel $channel" } - } else { - putdcc $idx "\002RIPECHECK\002: Invalid channel $channel" } -} -proc testripecheck { ip host channel ripe } { - global chanarr conflag - putloglev $conflag * "ripecheck: DEBUG - Got country: $ripe" - foreach country $chanarr($channel) { - if {![string compare $ripe $country]} { - putloglev $conflag * "ripecheck: DEBUG - Matched '$ripe' for $ip on channel $channel." - # Break the loop since we found a match - break + proc testripecheck { ip host channel ripe } { + global chanarr conflag + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - Got country: $ripe" + foreach country $chanarr($channel) { + if {![string compare $ripe $country]} { + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - Matched '$ripe' for $ip on channel $channel." + # Break the loop since we found a match + break + } } } -} -proc _pubripecheck { nick host handle channel ip } { - set channel [string tolower $channel] + proc pubRipeCheck { nick host handle channel ip } { + set channel [string tolower $channel] - if {![channel get $channel ripecheck.pubcmd]} { return 0 } + if {![channel get $channel ripecheck.pubcmd]} { return 0 } - if {[regexp {[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$} $ip]} { - whois_find_server $ip $ip "" $nick $channel "" 2 - } else { - dnslookup $ip whois_find_server $nick $channel "" 2 + if {[regexp {[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$} $ip]} { + whois_find_server $ip $ip "" $nick $channel "" 2 + } else { + dnslookup $ip whois_find_server $nick $channel "" 2 + } } -} -# Lookup which whois server to query and call whois_connect -proc whois_find_server { ip host status nick channel orghost test } { - global maskhash maskarray conflag + # Lookup which whois server to query and call whois_connect + proc whoisFindServer { ip host status nick channel orghost test } { + if {$status == 0} { + putlog "ripecheck: Couldn't resolve '$host'. No further action taken." + return 0 + } - if {$status == 0} { - putlog "ripecheck: Couldn't resolve '$host'. No further action taken." - return 0 - } + set matchmask [::ip::longestPrefixMatch $ip $::ripecheck::maskarray] + set whoisdb [string tolower $::ripecheck::maskhash($matchmask)] + set whoisport 43 - set matchmask [::ip::longestPrefixMatch $ip $maskarray] - set whoisdb [string tolower $maskhash($matchmask)] - set whoisport 43 + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - Matching mask $matchmask using whois DB: $whoisdb" - putloglev $conflag * "ripecheck: DEBUG - Matching mask $matchmask using whois DB: $whoisdb" + if { $whoisdb == "unallocated" } { + putlog "ripecheck: Unallocated netmask, bailing out!" + return -1 + } - if { $whoisdb == "unallocated" } { - putlog "ripecheck: Unallocated netmask, bailing out!" - return -1 + ::ripecheck::whoisConnect $ip $host $nick $channel $orghost $whoisdb $whoisport $test } - whois_connect $ip $host $nick $channel $orghost $whoisdb $whoisport $test -} - -proc whois_connect { ip host nick channel orghost whoisdb whoisport test } { - global rtimeout conflag - - # Setup timeout - after $rtimeout * 1000 set ::state "timeout" + proc whoisConnect { ip host nick channel orghost whoisdb whoisport test } { + # Setup timeout + after $rtimeout * 1000 set ::state "timeout" - if {[catch {socket -async $whoisdb $whoisport} sock]} { - putlog "ripecheck: ERROR: Failed to connect to server $whoisdb!" ; return -1 - } - fconfigure $sock -buffering line - fileevent $sock writable [list whois_callback $ip $host $nick $channel $orghost $sock $whoisdb $test] - vwait ::state - if { $::state == "timeout" } { - putlog "ripecheck: ERROR: Connection timeout against $whoisdb"; return -1 + if {[catch {socket -async $whoisdb $whoisport} sock]} { + putlog "ripecheck: ERROR: Failed to connect to server $whoisdb!" ; return -1 + } + fconfigure $sock -buffering line + fileevent $sock writable [list ::ripecheck::whoisCallback $ip $host $nick $channel $orghost $sock $whoisdb $test] + vwait ::state + if { $::state == "timeout" } { + putlog "ripecheck: ERROR: Connection timeout against $whoisdb"; return -1 + } } -} - -proc whois_callback { ip host nick channel orghost sock whoisdb test } { - global ::state conflag - putloglev $conflag * "ripecheck: DEBUG - Entering whois_callback..." + proc whoisCallback { ip host nick channel orghost sock whoisdb test } { + global ::state - if {[string equal {} [fconfigure $sock -error]]} { - puts $sock $ip - flush $sock - - putloglev $conflag * "ripecheck: DEBUG - State 'connected' with '$whoisdb'" + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - Entering whois_callback..." - set ::state "connected" + if {[string equal {} [fconfigure $sock -error]]} { + puts $sock $ip + flush $sock + + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - State 'connected' with '$whoisdb'" - while {![eof $sock]} { - set row [gets $sock] + set ::state "connected" - if {[regexp -line -nocase {referralserver:\s*(.*)} $row -> referral]} { - set referral [string tolower $referral] - putloglev $conflag * "ripecheck: DEBUG - Found whois referral server: $referral" - - # Extract the whois server from $referral - if {[regexp -line -nocase {^whois://(.*[^/])/?} $referral -> referral]} { - foreach {referral whoisport} [split $referral :] { break } + while {![eof $sock]} { + set row [gets $sock] - # Set default port if empty - if {$whoisport == ""} { - set whoisport 43 - } - - # Close socket, don't want to many sockets open simultaneously - close $sock + if {[regexp -line -nocase {referralserver:\s*(.*)} $row -> referral]} { + set referral [string tolower $referral] + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - Found whois referral server: $referral" - # Time for some recursive looping ;) - putloglev $conflag * "ripecheck: DEBUG - Following referral server, new server is '$referral', port '$whoisport'" - whois_connect $ip $host $nick $channel $orghost $referral $whoisport $test + # Extract the whois server from $referral + if {[regexp -line -nocase {^whois://(.*[^/])/?} $referral -> referral]} { + foreach {referral whoisport} [split $referral :] { break } + + # Set default port if empty + if {$whoisport == ""} { + set whoisport 43 + } + + # Close socket, don't want to many sockets open simultaneously + close $sock + + # Time for some recursive looping ;) + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - Following referral server, new server is '$referral', port '$whoisport'" + ::ripecheck::whoisConnect $ip $host $nick $channel $orghost $referral $whoisport $test + + return 0 + } elseif {[regexp -line -nocase {^rwhois://.*} $referral]} { + # Ignore rwhois for now + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - Ignoring rwhois referral" + continue + } else { + putlog "ripecheck: ERROR: Unknown referral type from '$whoisdb' for ip '$ip', please bug report this line." + close $sock; return -1 + } + } elseif {[regexp -line -nocase {country:\s*([a-z]{2,4})} $row -> country]} { + set country [string tolower $country] + } + } - return 0 - } elseif {[regexp -line -nocase {^rwhois://.*} $referral]} { - # Ignore rwhois for now - putloglev $conflag * "ripecheck: DEBUG - Ignoring rwhois referral" - continue + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - End of while-loop in whois_callback" + + if {[info exists country]} { + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - $whoisdb answer: $country Test: $test" + if {$test == 1} { + ::ripecheck::testripecheck $ip $host $channel $country + } elseif {$test == 2} { + puthelp "PRIVMSG $channel :ripecheck: $host is located in '$country'" } else { - putlog "ripecheck: ERROR: Unknown referral type from '$whoisdb' for ip '$ip', please bug report this line." - close $sock; return -1 + ::ripecheck::ripecheck $ip $host $nick $channel $orghost $country } - } elseif {[regexp -line -nocase {country:\s*([a-z]{2,4})} $row -> country]} { - set country [string tolower $country] + } else { + putlog "ripecheck: No country found for '$ip'. No further action taken. (Possible bug?)" } + + close $sock + } else { + set ::state "timeout" } + } + + # Add top resolv domain for channel and write settings to file + proc addTopResolve { nick idx arg } { + global chanarr topresolv conflag - putloglev $conflag * "ripecheck: DEBUG - End of while-loop in whois_callback" + if {[llength [split $arg]] != 2} { + _ripe_help_dcc $nick $idx +ripetopresolv; return 0 + } - if {[info exists country]} { - putloglev $conflag * "ripecheck: DEBUG - $whoisdb answer: $country Test: $test" - if {$test == 1} { - testripecheck $ip $host $channel $country - } elseif {$test == 2} { - puthelp "PRIVMSG $channel :ripecheck: $host is located in '$country'" + foreach {channel topdom} $arg {break} + + set channel [string tolower $channel] + set topdom [string tolower $topdom] + + if {[validchan $channel]} { + # It's pointless to set a resolv domain if no domains have been added for banning on the + # current channel. + if {[info exists chanarr($channel)]} { + # If data exist extract into a list + if {[info exists topresolv($channel)]} { + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - topresolv exists" + set dlist $topresolv($channel) + # top domain doesn't exist so lets add it + if {[lsearch -exact $dlist $topdom] == -1 } { + lappend dlist $topdom + set topresolv($channel) $dlist + } else { + putdcc $idx "\002RIPECHECK\002: Resolve domain '$topdom' already exist on $channel"; return 0 + } + } else { + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - topresolv doesn't exist" + set dlist [list $topdom] + set topresolv($channel) $dlist + } + # Write to the ripecheck channel file + write_settings + putdcc $idx "\002RIPECHECK\002: Top resolve domain '$topdom' successfully added to $channel." } else { - ripecheck $ip $host $nick $channel $orghost $country + putdcc $idx "\002RIPECHECK\002: You need to add a top domain for $channel before adding a resolve domain." } } else { - putlog "ripecheck: No country found for '$ip'. No further action taken. (Possible bug?)" + putdcc $idx "\002RIPECHECK\002: Invalid channel: $channel" } - - close $sock - } else { - set ::state "timeout" } -} -# Add top resolv domain for channel and write settings to file -proc _+ripetopresolv { nick idx arg } { - global chanarr topresolv conflag + # Remove resolve domain from channel and write settings to file + proc delTopResolve { nick idx arg } { + global chanarr topresolv conflag - if {[llength [split $arg]] != 2} { - _ripe_help_dcc $nick $idx +ripetopresolv; return 0 - } - - foreach {channel topdom} $arg {break} + if {[llength [split $arg]] != 2} { + _ripe_help_dcc $nick $idx -ripetopresolv; return 0 + } - set channel [string tolower $channel] - set topdom [string tolower $topdom] + foreach {channel topdom} $arg {break} - if {[validchan $channel]} { - # It's pointless to set a resolv domain if no domains have been added for banning on the - # current channel. - if {[info exists chanarr($channel)]} { - # If data exist extract into a list + set channel [string tolower $channel] + set topdom [string tolower $topdom] + + if {[validchan $channel]} { if {[info exists topresolv($channel)]} { - putloglev $conflag * "ripecheck: DEBUG - topresolv exists" + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - topresolv($channel) exists" set dlist $topresolv($channel) - # top domain doesn't exist so lets add it - if {[lsearch -exact $dlist $topdom] == -1 } { - lappend dlist $topdom - set topresolv($channel) $dlist + # resolve domain exist so lets remove it + set dlist_index [lsearch -exact $dlist $topdom] + if {$dlist_index != -1 } { + set dlist [lreplace $dlist $dlist_index $dlist_index] + # More magic, lets clear array if the list is empty + if {[llength $dlist] > 0} { + set topresolv($channel) $dlist + } else { + unset topresolv($channel) + } } else { - putdcc $idx "\002RIPECHECK\002: Resolve domain '$topdom' already exist on $channel"; return 0 + putdcc $idx "\002RIPECHECK\002: Resolve domain '$topdom' doesn't exist on $channel"; return 0 } + } else { - putloglev $conflag * "ripecheck: DEBUG - topresolv doesn't exist" - set dlist [list $topdom] - set topresolv($channel) $dlist + putdcc $idx "\002RIPECHECK\002: Nothing to do, no settings found for $channel." } # Write to the ripecheck channel file write_settings - putdcc $idx "\002RIPECHECK\002: Top resolve domain '$topdom' successfully added to $channel." + putdcc $idx "\002RIPECHECK\002: Resolve domain '$topdom' successfully removed from $channel." + } else { - putdcc $idx "\002RIPECHECK\002: You need to add a top domain for $channel before adding a resolve domain." + putdcc $idx "\002RIPECHECK\002: Invalid channel: $channel" } - } else { - putdcc $idx "\002RIPECHECK\002: Invalid channel: $channel" } -} -# Remove resolve domain from channel and write settings to file -proc _-ripetopresolv { nick idx arg } { - global chanarr topresolv conflag + # List channel and top resolv domains + proc _ripesettings { nick idx arg } { + global chanarr topresolv ripeconfig ver - if {[llength [split $arg]] != 2} { - _ripe_help_dcc $nick $idx -ripetopresolv; return 0 - } - - foreach {channel topdom} $arg {break} - - set channel [string tolower $channel] - set topdom [string tolower $topdom] - - if {[validchan $channel]} { - if {[info exists topresolv($channel)]} { - putloglev $conflag * "ripecheck: DEBUG - topresolv($channel) exists" - set dlist $topresolv($channel) - # resolve domain exist so lets remove it - set dlist_index [lsearch -exact $dlist $topdom] - if {$dlist_index != -1 } { - set dlist [lreplace $dlist $dlist_index $dlist_index] - # More magic, lets clear array if the list is empty - if {[llength $dlist] > 0} { - set topresolv($channel) $dlist - } else { - unset topresolv($channel) - } - } else { - putdcc $idx "\002RIPECHECK\002: Resolve domain '$topdom' doesn't exist on $channel"; return 0 + putdcc $idx "### \002Settings\002 - Ripecheck v$ver by Ratler ###" + if {[array size chanarr] > 0 && [array size topresolv] > 0} { + foreach channel [array names chanarr] { + putdcc $idx "### \002Channel:\002 $channel" + putdcc $idx " \002Banned domains:\002 [join $chanarr($channel) ", "]" + putdcc $idx " \002Resolve domains:\002 [join $topresolv($channel) ", "]" } - } else { - putdcc $idx "\002RIPECHECK\002: Nothing to do, no settings found for $channel." + putdcc $idx "### No channel settings exist." } - # Write to the ripecheck channel file - write_settings - putdcc $idx "\002RIPECHECK\002: Resolve domain '$topdom' successfully removed from $channel." - - } else { - putdcc $idx "\002RIPECHECK\002: Invalid channel: $channel" - } -} - -# List channel and top resolv domains -proc _ripesettings { nick idx arg } { - global chanarr topresolv ripeconfig ver - - putdcc $idx "### \002Settings\002 - Ripecheck v$ver by Ratler ###" - if {[array size chanarr] > 0 && [array size topresolv] > 0} { - foreach channel [array names chanarr] { - putdcc $idx "### \002Channel:\002 $channel" - putdcc $idx " \002Banned domains:\002 [join $chanarr($channel) ", "]" - putdcc $idx " \002Resolve domains:\002 [join $topresolv($channel) ", "]" + if {[info exists ripeconfig(banreason)]} { + putdcc $idx "### \002Ban reason:\002 [join $ripeconfig(banreason)]" + } + if {[info exists ripeconfig(bantopreason)]} { + putdcc $idx "### \002Ban TLD reason:\002 [join $ripeconfig(bantopreason)]" } - } else { - putdcc $idx "### No channel settings exist." - } - if {[info exists ripeconfig(banreason)]} { - putdcc $idx "### \002Ban reason:\002 [join $ripeconfig(banreason)]" - } - if {[info exists ripeconfig(bantopreason)]} { - putdcc $idx "### \002Ban TLD reason:\002 [join $ripeconfig(bantopreason)]" } -} -# Add top domain to channel and write settings to file -proc _+ripetopdom { nick idx arg } { - global chanarr topresolv conflag + # Add top domain to channel and write settings to file + proc addTopDom { nick idx arg } { + global chanarr topresolv conflag - if {[llength [split $arg]] != 2} { - _ripe_help_dcc $nick $idx +ripetopdom; return 0 - } + if {[llength [split $arg]] != 2} { + _ripe_help_dcc $nick $idx +ripetopdom; return 0 + } - foreach {channel topdom} $arg {break} + foreach {channel topdom} $arg {break} - set channel [string tolower $channel] - set topdom [string tolower $topdom] + set channel [string tolower $channel] + set topdom [string tolower $topdom] - if {[validchan $channel]} { - # If data exist extract into a list - if {[info exists chanarr($channel)]} { - putloglev $conflag * "ripecheck: DEBUG - chanarr exists" - set dlist $chanarr($channel) - # top domain doesn't exist so lets add it - if {[lsearch -exact $dlist $topdom] == -1 } { - lappend dlist $topdom - set chanarr($channel) $dlist + if {[validchan $channel]} { + # If data exist extract into a list + if {[info exists chanarr($channel)]} { + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - chanarr exists" + set dlist $chanarr($channel) + # top domain doesn't exist so lets add it + if {[lsearch -exact $dlist $topdom] == -1 } { + lappend dlist $topdom + set chanarr($channel) $dlist + } else { + putdcc $idx "\002RIPECHECK\002: Domain '$topdom' already exist on $channel"; return 0 + } } else { - putdcc $idx "\002RIPECHECK\002: Domain '$topdom' already exist on $channel"; return 0 + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - chanarr doesn't exist" + set dlist [list $topdom] + set chanarr($channel) $dlist } + # Write to the ripecheck channel file + write_settings + putdcc $idx "\002RIPECHECK\002: Top domain '$topdom' successfully added to $channel." } else { - putloglev $conflag * "ripecheck: DEBUG - chanarr doesn't exist" - set dlist [list $topdom] - set chanarr($channel) $dlist - } - # Write to the ripecheck channel file - write_settings - putdcc $idx "\002RIPECHECK\002: Top domain '$topdom' successfully added to $channel." - } else { - putdcc $idx "\002RIPECHECK\002: Invalid channel: $channel" + putdcc $idx "\002RIPECHECK\002: Invalid channel: $channel" + } } -} -# Remove top domain for channel and write settings to file -proc _-ripetopdom { nick idx arg } { - global chanarr topresolv conflag + # Remove top domain for channel and write settings to file + proc delTopDom { nick idx arg } { + global chanarr topresolv conflag - if {[llength [split $arg]] != 2} { - _ripe_help_dcc $nick $idx -ripetopdom; return 0 - } + if {[llength [split $arg]] != 2} { + _ripe_help_dcc $nick $idx -ripetopdom; return 0 + } - foreach {channel topdom} $arg {break} - - set channel [string tolower $channel] - set topdom [string tolower $topdom] - - if {[validchan $channel]} { - if {[info exists chanarr($channel)]} { - putloglev $conflag * "ripecheck: DEBUG - chanarr($channel) exists" - set dlist $chanarr($channel) - # top domain doesn't exist so lets add it - set dlist_index [lsearch -exact $dlist $topdom] - if {$dlist_index != -1 } { - set dlist [lreplace $dlist $dlist_index $dlist_index] - # More magic, clear array if list is empty - if {[llength $dlist] > 0} { - set chanarr($channel) $dlist + foreach {channel topdom} $arg {break} + + set channel [string tolower $channel] + set topdom [string tolower $topdom] + + if {[validchan $channel]} { + if {[info exists chanarr($channel)]} { + putloglev $::ripecheck::conflag * "ripecheck: DEBUG - chanarr($channel) exists" + set dlist $chanarr($channel) + # top domain doesn't exist so lets add it + set dlist_index [lsearch -exact $dlist $topdom] + if {$dlist_index != -1 } { + set dlist [lreplace $dlist $dlist_index $dlist_index] + # More magic, clear array if list is empty + if {[llength $dlist] > 0} { + set chanarr($channel) $dlist + } else { + unset chanarr($channel) + } } else { - unset chanarr($channel) + putdcc $idx "\002RIPECHECK\002: Domain '$topdom' doesn't exist on $channel"; return 0 } + } else { - putdcc $idx "\002RIPECHECK\002: Domain '$topdom' doesn't exist on $channel"; return 0 + putdcc $idx "\002RIPECHECK\002: Nothing to do, no settings found for $channel." } + # Write to the ripecheck channel file + write_settings + putdcc $idx "\002RIPECHECK\002: Top domain '$topdom' successfully removed from $channel." } else { - putdcc $idx "\002RIPECHECK\002: Nothing to do, no settings found for $channel." + putdcc $idx "\002RIPECHECK\002: Invalid channel: $channel" } - # Write to the ripecheck channel file - write_settings - putdcc $idx "\002RIPECHECK\002: Top domain '$topdom' successfully removed from $channel." - - } else { - putdcc $idx "\002RIPECHECK\002: Invalid channel: $channel" } -} -proc _ripebanreason { nick idx arg } { - global ripeconfig + proc _ripebanreason { nick idx arg } { + global ripeconfig - if {!([llength [split $arg]] > 0)} { - _ripe_help_dcc $nick $idx ripebanr; return 0 - } + if {!([llength [split $arg]] > 0)} { + _ripe_help_dcc $nick $idx ripebanr; return 0 + } - set type [lindex [split $arg] 0] - set text [lrange [split $arg] 1 end] - - if {($type == "banreason") || ($type == "bantopreason") } { - # Lets clear the ban reason - if {$text == "" && [info exists ripeconfig($type)]} { - unset ripeconfig($type) - putdcc $idx "\002RIPECHECK\002: Successfully removed '$type'" - } elseif {$text != ""} { - set ripeconfig($type) $text - putdcc $idx "\002RIPECHECK\002: Successfully added '$type' value '$text'" - } - write_settings - } else { - _ripe_help_dcc $nick $idx ripebanr; return 0 + set type [lindex [split $arg] 0] + set text [lrange [split $arg] 1 end] + + if {($type == "banreason") || ($type == "bantopreason") } { + # Lets clear the ban reason + if {$text == "" && [info exists ripeconfig($type)]} { + unset ripeconfig($type) + putdcc $idx "\002RIPECHECK\002: Successfully removed '$type'" + } elseif {$text != ""} { + set ripeconfig($type) $text + putdcc $idx "\002RIPECHECK\002: Successfully added '$type' value '$text'" + } + write_settings + } else { + _ripe_help_dcc $nick $idx ripebanr; return 0 + } } -} -proc ripe_replace { text subs } { - foreach {arg1 arg2} $subs { - regsub -all -- $arg1 $text $arg2 text + proc templateReplace { text subs } { + foreach {arg1 arg2} $subs { + regsub -all -- $arg1 $text $arg2 text + } + return $text } - return $text -} -proc write_settings { } { - global ripechanfile chanarr topresolv ripeconfig + proc write_settings { } { + global ripechanfile chanarr topresolv ripeconfig - # Backup file in case something goes wrong - if {[file exists $ripechanfile]} { - # Don't backup a zero byte file - if {[file size $ripechanfile] > 0} { - file copy -force $ripechanfile $ripechanfile.bak + # Backup file in case something goes wrong + if {[file exists $ripechanfile]} { + # Don't backup a zero byte file + if {[file size $ripechanfile] > 0} { + file copy -force $ripechanfile $ripechanfile.bak + } } - } - set fp [open $ripechanfile w] + set fp [open $ripechanfile w] - foreach key [array names chanarr] { - puts $fp "$key:[join $chanarr($key) ,]" - } - foreach key [array names topresolv] { - puts $fp "topresolv:$key:[join $topresolv($key) ,]" - } - foreach key [array names ripeconfig] { - puts $fp "config:$key:[join $ripeconfig($key)]" - } - close $fp -} - -proc _ripe_help_dcc { hand idx args } { - global ver - - switch -- $args { - ripecheck { - putidx $idx "### \002ripecheck v$ver\002 by Ratler ###"; putidx $idx "" - putidx $idx "### \002chanset <+/->ripecheck\002" - putidx $idx " Enable (+) or disable (-) the script for specified channel" - putidx $idx "### \002chanset ripecheck.bantime \002" - putidx $idx " For how long should the ban be active in minutes" - putidx $idx "### \002chanset <+/->ripecheck.topchk\002" - putidx $idx " Enable (+) or disable (-) top domain resolve check" - putidx $idx "### \002chanset <+/->ripecheck.topban\002" - putidx $idx " Enable (+) or disable (-) top domain banning based on the topdomain list" - putidx $idx "### \002chanset <+/->ripecheck.pubcmd\002" - putidx $idx " Enable (+) or disable (-) public commands (!ripecheck)" - putidx $idx "### \002+ripetopresolv \002" - putidx $idx " Add a top domain or regexp pattern that you want to resolve for" - putidx $idx " further ripe checking. It's possible that domains like com, info, org" - putidx $idx " could be from a country that is banned in the top domain list." - putidx $idx " Example (match .com): .+ripetopresolv #channel com" - putidx $idx " Example (match everything): .+ripetopresolv #channel .*" - putidx $idx " Example (match .a-f*): .+ripetopresolv #channel \[a-f\]*" - putidx $idx "### \002-ripetopresolv \002" - putidx $idx " Remove a top resolve domain or regexp pattern from the channel that" - putidx $idx " you no longer wish to resolve." - putidx $idx "### \002+ripetopdom \002" - putidx $idx " Add a top domain for the channel that you wish to ban" - putidx $idx " Example: .+ripetopdom #channel ro" - putidx $idx "### \002-ripetopdom \002" - putidx $idx " Remove a top domain from the channel that you no longer" - putidx $idx " wish to ban" - putidx $idx "### \002ripebanr \[text\]\002" - putidx $idx " Set custom ban reasons for 'banreason' and 'bantopreason'." - putidx $idx " To restore the default message run the above command without \[text\]" - putidx $idx " The \[text\] support substitutional keywords, current keywords are:" - putidx $idx " %domain% = Topdomain used in 'bantopreason'" - putidx $idx " %ripe% = Country code from the whois server, used in 'banreason'" - putidx $idx " %nick% = Nickname for the user being banned, used in both 'banreason' and 'bantopreason'" - putidx $idx " Example (topdomain reason): .ripebanr bantopreason Hello '%nick%, TLD '%domain%' is not allowed here" - putidx $idx " Example (standard reason): .ripebanr banreason Sorry '%ripe' not allowed in here" - putidx $idx " Example (restore default ban reason): .ripebanr banreason" - putidx $idx "### \002ripesettings\002" - putidx $idx " List current channel settings" - putidx $idx "### \002testripecheck \002" - putidx $idx " Test your settings against a specific channel, don't" - putidx $idx " forget to enable debug console to see the output" - putidx $idx " from testripecheck, ie .console +d" - putidx $idx "### \002help ripecheck\002" - putidx $idx " This help page you're currently viewing" - } - +ripetopresolv { - putidx $idx "Usage: \002+ripetopresolv \002" - putidx $idx " Add a top domain or regexp pattern that you want to resolve for" - putidx $idx " further ripe checking. It's possible that domains like com, info, org" - putidx $idx " could be from a country that is banned in the top domain list." - putidx $idx " Example (match .com): .+ripetopresolv #channel com" - putidx $idx " Example (match everything): .+ripetopresolv #channel .*" - putidx $idx " Example (match .a-f*): .+ripetopresolv #channel \[a-f\]*" - } - -ripetopresolv { - putidx $idx "Usage: \002-ripetopresolv \002" - putidx $idx " Remove a top resolve domain or regexp pattern from the channel that" - putidx $idx " you no longer wish to resolve." - } - +ripetopdom { - putidx $idx "Usage: \002+ripetopdom \002" - putidx $idx " Add a top domain for the channel that you wish to ban" - putidx $idx " Example: .+ripetopdom #channel ro" - } - -ripetopdom { - putidx $idx "Usage: \002-ripetopdom \002" - putidx $idx " Remove a top domain from the channel that you no longer" - putidx $idx " wish to ban" - } - ripebanr { - putidx $idx "Usage: \002ripebanr \[text\]\002" - putidx $idx " Set custom ban reasons for 'banreason' and 'bantopreason'." - putidx $idx " To restore the default message run the above command without \[text\]" - putidx $idx " The \[text\] support substitutional keywords, current keywords are:" - putidx $idx " %domain% = Topdomain used in 'bantopreason'" - putidx $idx " %ripe% = Country code from the whois server, used in 'banreason'" - putidx $idx " %nick% = Nickname for the user being banned, used in both 'banreason' and 'bantopreason'" - putidx $idx " Example (topdomain reason): .ripebanr bantopreason Hello '%nick%, TLD '%domain%' is not allowed here" - putidx $idx " Example (standard reason): .ripebanr banreason Sorry '%ripe' not allowed in here" - putidx $idx " Example (restore default ban reason): .ripebanr banreason" - } - testripecheck { - putidx $idx "Usage: \002testripecheck \002" - } - default {*dcc:help $hand $idx [join $args]; return 0} + foreach key [array names chanarr] { + puts $fp "$key:[join $chanarr($key) ,]" + } + foreach key [array names topresolv] { + puts $fp "topresolv:$key:[join $topresolv($key) ,]" + } + foreach key [array names ripeconfig] { + puts $fp "config:$key:[join $ripeconfig($key)]" + } + close $fp + } + + proc _ripe_help_dcc { hand idx args } { + global ver + + switch -- $args { + ripecheck { + putidx $idx "### \002ripecheck v$ver\002 by Ratler ###"; putidx $idx "" + putidx $idx "### \002chanset <+/->ripecheck\002" + putidx $idx " Enable (+) or disable (-) the script for specified channel" + putidx $idx "### \002chanset ripecheck.bantime \002" + putidx $idx " For how long should the ban be active in minutes" + putidx $idx "### \002chanset <+/->ripecheck.topchk\002" + putidx $idx " Enable (+) or disable (-) top domain resolve check" + putidx $idx "### \002chanset <+/->ripecheck.topban\002" + putidx $idx " Enable (+) or disable (-) top domain banning based on the topdomain list" + putidx $idx "### \002chanset <+/->ripecheck.pubcmd\002" + putidx $idx " Enable (+) or disable (-) public commands (!ripecheck)" + putidx $idx "### \002+ripetopresolv \002" + putidx $idx " Add a top domain or regexp pattern that you want to resolve for" + putidx $idx " further ripe checking. It's possible that domains like com, info, org" + putidx $idx " could be from a country that is banned in the top domain list." + putidx $idx " Example (match .com): .+ripetopresolv #channel com" + putidx $idx " Example (match everything): .+ripetopresolv #channel .*" + putidx $idx " Example (match .a-f*): .+ripetopresolv #channel \[a-f\]*" + putidx $idx "### \002-ripetopresolv \002" + putidx $idx " Remove a top resolve domain or regexp pattern from the channel that" + putidx $idx " you no longer wish to resolve." + putidx $idx "### \002+ripetopdom \002" + putidx $idx " Add a top domain for the channel that you wish to ban" + putidx $idx " Example: .+ripetopdom #channel ro" + putidx $idx "### \002-ripetopdom \002" + putidx $idx " Remove a top domain from the channel that you no longer" + putidx $idx " wish to ban" + putidx $idx "### \002ripebanr \[text\]\002" + putidx $idx " Set custom ban reasons for 'banreason' and 'bantopreason'." + putidx $idx " To restore the default message run the above command without \[text\]" + putidx $idx " The \[text\] support substitutional keywords, current keywords are:" + putidx $idx " %domain% = Topdomain used in 'bantopreason'" + putidx $idx " %ripe% = Country code from the whois server, used in 'banreason'" + putidx $idx " %nick% = Nickname for the user being banned, used in both 'banreason' and 'bantopreason'" + putidx $idx " Example (topdomain reason): .ripebanr bantopreason Hello '%nick%, TLD '%domain%' is not allowed here" + putidx $idx " Example (standard reason): .ripebanr banreason Sorry '%ripe' not allowed in here" + putidx $idx " Example (restore default ban reason): .ripebanr banreason" + putidx $idx "### \002ripesettings\002" + putidx $idx " List current channel settings" + putidx $idx "### \002testripecheck \002" + putidx $idx " Test your settings against a specific channel, don't" + putidx $idx " forget to enable debug console to see the output" + putidx $idx " from testripecheck, ie .console +d" + putidx $idx "### \002help ripecheck\002" + putidx $idx " This help page you're currently viewing" + } + +ripetopresolv { + putidx $idx "Usage: \002+ripetopresolv \002" + putidx $idx " Add a top domain or regexp pattern that you want to resolve for" + putidx $idx " further ripe checking. It's possible that domains like com, info, org" + putidx $idx " could be from a country that is banned in the top domain list." + putidx $idx " Example (match .com): .+ripetopresolv #channel com" + putidx $idx " Example (match everything): .+ripetopresolv #channel .*" + putidx $idx " Example (match .a-f*): .+ripetopresolv #channel \[a-f\]*" + } + -ripetopresolv { + putidx $idx "Usage: \002-ripetopresolv \002" + putidx $idx " Remove a top resolve domain or regexp pattern from the channel that" + putidx $idx " you no longer wish to resolve." + } + +ripetopdom { + putidx $idx "Usage: \002+ripetopdom \002" + putidx $idx " Add a top domain for the channel that you wish to ban" + putidx $idx " Example: .+ripetopdom #channel ro" + } + -ripetopdom { + putidx $idx "Usage: \002-ripetopdom \002" + putidx $idx " Remove a top domain from the channel that you no longer" + putidx $idx " wish to ban" + } + ripebanr { + putidx $idx "Usage: \002ripebanr \[text\]\002" + putidx $idx " Set custom ban reasons for 'banreason' and 'bantopreason'." + putidx $idx " To restore the default message run the above command without \[text\]" + putidx $idx " The \[text\] support substitutional keywords, current keywords are:" + putidx $idx " %domain% = Topdomain used in 'bantopreason'" + putidx $idx " %ripe% = Country code from the whois server, used in 'banreason'" + putidx $idx " %nick% = Nickname for the user being banned, used in both 'banreason' and 'bantopreason'" + putidx $idx " Example (topdomain reason): .ripebanr bantopreason Hello '%nick%, TLD '%domain%' is not allowed here" + putidx $idx " Example (standard reason): .ripebanr banreason Sorry '%ripe' not allowed in here" + putidx $idx " Example (restore default ban reason): .ripebanr banreason" + } + testripecheck { + putidx $idx "Usage: \002testripecheck \002" + } + default {*dcc:help $hand $idx [join $args]; return 0} + } } } - putlog "ripecheck v$ver by Ratler loaded"