Code: Select all
## mass-join-protection.tcl v1.6.1 (29Feb2016) by SpiKe^^ ##
# Mass joins, kick-ban on joins:seconds #
set mjp(flood) 3:2
# Mass joins kick-ban reason #
set mjp(reasn) "14Possible/Flooder/Spammer"
# Max number of bans to stack in one mode command #
set mjp(maxb) 6
# Max number of kicks to stack in one kick command # <- NEW SETTING <-
# NOTE: many networks allow more than one nick to be kicked per command. #
# set this at or below the max for your network.
set mjp(maxk) 3
# Length of time in minutes to ban mass join flooders #
# - set 0 to disable this script removing bans (ex. set mjp(btime) 0) #
set mjp(btime) 30
# After a valid mass join flood, script will continue #
# to kick-ban offenders for an additional 'x' seconds #
set mjp(xpire) 10
# Set the type of ban masks to use #
# 1 = use host/ip specific bans (ex. *!*@some.host.com) #
# 2 = use wide masked host/ip bans (ex. *!*@*.host.com) #
# note: setting 2 requires eggdrop 1.6.20 or newer. #
set mjp(btype) 2
# Set protected host(s) that should not be wide masked #
# - Example: set mjp(phost) "*.undernet.org"
# Note: this setting only applies to ban type 2 above! #
# Note: set empty to not protect any hosts (ex. set mjp(phost) "") #
# Note: space separated if listing more than one protected host #
set mjp(phost) ""
# Set channel mode(s) on flood detected. #
# - set empty to disable setting channel modes (ex. set mjp(mode) "") #
set mjp(mode) "Rm"
# Remove these channel modes after how many seconds? #
set mjp(mrem) 60000
# END OF SETTINGS # Don't edit below unless you know what you're doing #
bind join - * mjp_bindjoin
proc mjp_bindjoin {nick uhost hand chan} {
global mjp mjpc mjpq
if {[isbotnick $nick]} { return 0 }
if {[matchattr $hand f|f $chan]} { return 0 }
set uhost [string tolower $nick!$uhost]
set chan [string tolower $chan]
set utnow [unixtime]
set target [lindex $mjp(flood) 0]
if {[info exists mjpc($chan)]} {
set uhlist [lassign $mjpc($chan) cnt ut]
set utend [expr {$ut + [lindex $mjp(flood) 1]}]
set expire [expr {$utend + $mjp(xpire)}]
if {$cnt < $target} {
if {$utnow > $utend} { unset mjpc($chan) }
} elseif {$utnow > $expire} { unset mjpc($chan) }
}
if {![info exists mjpc($chan)]} {
set mjpc($chan) [list 1 $utnow $uhost]
return 0
}
incr cnt
if {$cnt <= $target} {
if {[lsearch $uhlist $uhost] == -1} { lappend uhlist $uhost }
if {$cnt < $target} {
set mjpc($chan) [linsert $uhlist 0 $cnt $ut]
} else {
set mjpc($chan) [list $cnt $ut]
if {$mjp(mode) ne "" && [string is digit -strict $mjp(mrem)]} {
putquick "MODE $chan +$mjp(mode)"
utimer $mjp(mrem) [list putquick "MODE $chan -$mjp(mode)"]
}
mjp_dobans $chan $uhlist
}
return 0
}
if {![info exists mjpq($chan)]} {
utimer 2 [list mjp_bque $chan]
set mjpq($chan) [list $uhost]
} elseif {[lsearch $mjpq($chan) $uhost] == -1} {
lappend mjpq($chan) $uhost
}
if {[llength $mjpq($chan)] >= $mjp(maxb)} {
mjp_dobans $chan $mjpq($chan)
set mjpq($chan) ""
}
return 0
}
proc mjp_dobans {chan uhlist} {
global mjp netsplit_detected
if {$netsplit_detected} return
if {![botisop $chan]} return
set banList ""
set nickList ""
foreach ele $uhlist {
scan $ele {%[^!]!%[^@]@%s} nick user host
if {$mjp(btype) == 2} {
set type 4
foreach ph $mjp(phost) {
if {[string match -nocase $ph $host]} {
set type 2 ; break
}
}
set bmask [maskhost $ele $type]
} else { set bmask "*!*@$host" }
if {[lsearch $banList $bmask] == -1} { lappend banList $bmask }
if {[lsearch $nickList $nick] == -1} { lappend nickList $nick }
}
stack_bans $chan $mjp(maxb) $banList
# begin new kick code #
foreach nk $nickList {
if {[onchan $nk $chan]} { lappend nkls $nk } else { continue }
if {[llength $nkls] == $mjp(maxk)} {
putquick "KICK $chan [join $nkls ,] :$mjp(reasn)"
unset nkls
}
}
if {[info exists nkls]} {
putquick "KICK $chan [join $nkls ,] :$mjp(reasn)"
}
# end new kick code #
if {$mjp(btime) > 0} {
set expire [expr {[unixtime] + $mjp(btime)}]
lappend mjp(rmls) [list $expire $chan $banList]
}
}
proc stack_bans {chan max banlist {opt +} } {
set len [llength $banlist]
while {$len > 0} {
if {$len > $max} {
set mode [string repeat "b" $max]
set masks [join [lrange $banlist 0 [expr {$max - 1}]]]
set banlist [lrange $banlist $max end]
incr len -$max
} else {
set mode [string repeat "b" $len]
set masks [join $banlist]
set len 0
}
putquick "MODE $chan ${opt}$mode $masks"
}
}
proc mjp_bque {chan} {
global mjpq
if {![info exists mjpq($chan)]} { return }
if {$mjpq($chan) eq ""} { unset mjpq($chan) ; return }
mjp_dobans $chan $mjpq($chan)
unset mjpq($chan)
}
proc mjp_breset {} {
global mjpc mjp
set utnow [unixtime]
set target [lindex $mjp(flood) 0]
foreach {key val} [array get mjpc] {
lassign $val cnt ut
set utend [expr {$ut + [lindex $mjp(flood) 1]}]
set expire [expr {$utend + $mjp(xpire)}]
if {$cnt < $target} {
if {$utnow > $utend} { unset mjpc($key) }
} elseif {$utnow > $expire} { unset mjpc($key) }
}
if {[info exists mjp(rmls)]} {
while {[llength $mjp(rmls)]} {
set next [lindex $mjp(rmls) 0]
lassign $next expire chan banList
if {$expire > $utnow} { break }
set mjp(rmls) [lreplace $mjp(rmls) 0 0]
if {![info exists rmAra($chan)]} { set rmAra($chan) $banList
} else { set rmAra($chan) [concat $rmAra($chan) $banList] }
}
foreach {key val} [array get rmAra] {
set banList ""
foreach mask $val {
if {![ischanban $mask $key]} { continue }
lappend banList $mask
}
if {$banList eq ""} { continue }
if {![botisop $key]} {
set mjp(rmls) [linsert $mjp(rmls) 0 [list $utnow $key $banList]]
} else { stack_bans $key $mjp(maxb) $banList - }
}
if {![llength $mjp(rmls)]} { unset mjp(rmls) }
}
utimer 30 [list mjp_breset]
}
if {![info exists mjp_running]} {
utimer 20 [list mjp_breset]
set mjp_running 1
}
set mjp(flood) [split $mjp(flood) :]
set mjp(btime) [expr {$mjp(btime) * 60}]
set mjp(phost) [split [string trim $mjp(phost)]]
if {$mjp(btime)==0 && [info exists mjp(rmls)]} { unset mjp(rmls) }
proc rdsb_unlock {chan lock} {
if {![botisop $chan]} return
set cm [lindex [split [getchanmode $chan] +] 1]
foreach m [split $lock ""] {
if {[lsearch -exact $cm $m] != -1} {
pushmode $chan -$m
}
}
}
set netsplit_detected 0
bind raw - QUIT netsplit:detect
proc netsplit:detect {from key arg} {
global netsplit_detected
if {[info exists netsplit_detected]} return
set arg [string trimleft [stripcodes bcruag $arg] :]
if {[string equal "Quit:" [string range $arg 0 4]]} return
if {![regexp -- {^([[:alnum:][:punct:]]+)[[:space:]]([[:alnum:][:punct:]]+)$} $text _arg s1 s2]} return
if {[string match "*.dal.net" $s1] && [string match "*.dal.net" $s2]} {
set netsplit_detected 1
utimer 180 [list netsplit:unlock]
}
}
proc netsplit:unlock args {
global netsplit_detected
set netsplit_detected 0
}
putlog "Loaded mass-join-protection.tcl v1.6.1 by SpiKe^^"