This is the new home of the egghelp.org community forum.
All data has been migrated (including user logins/passwords) to a new phpBB version.


For more information, see this announcement post. Click the X in the top right-corner of this box to dismiss this message.

Bans

Issues often discussed about Tcl scripting. Check before posting a scripting question.
Post Reply
User avatar
user
 
Posts: 1452
Joined: Tue Mar 18, 2003 9:58 pm
Location: Norway

Bans

Post by user »

Placing bans

I've seen many questions about changing the banmask used in eggdrop scripts. There is a pretty simple (and obvious) solution: Replace the internal maskhost-command with a proc that returns the type of mask you'd like. Then make sure all your scripts use this proc.

Adding the bans to your internal banlist is done via newban (global ban) or newchanban (channel ban) and the rest (placing the ban on channels, enforcing etc) is controlled via channel settings. If you, for some reason, don't want to use the internal banlist, use pushmode to place a ban directly on some channel. (look the commands up in tcl-commands.doc if you don't know their syntax)

As for the bans created by the built in flood/autokick/revenge-mechanisms, you'll need to make a script that takes care of the banning via your own maskhost proc if you want custom ban types. The flood kicks are easy; just 'bind flud' and add a tiny proc. Revenge and +k require alot more in terms of code as you'll need to implement the entire feature in tcl (unless you know C and feel like messing with the eggdrop code)

This is sort of off-topic, but I've also seen a couple of requests regarding placing a different type of ban than the one matching a joining/nick changing user. E.g.: someone joins matching your ban for "guest*!*@*" and you want to ban *!*@their.host.tld to keep them out for a while. Again; this requires a tcl script as the bans added via the built in ban mechanism are used for both the internal matching AND placing the actual ban on irc.

I won't address the last two paragraphs any further in this post, but here's a proc to replace the internal maskhost command...

usage: maskhost <nick!ident@host.tld> [type]

The type is optional, meaning you can leave it out and call the proc just like the built in command. The default type (see below) is used if you do that. This proc is a bit stricter than the built in command when it comes to accepting input...the "name" to be masked must contain a "!" and a "@" and there has to be at least one char on each side and between these two (which makes perfect sense if you expect the proc to produce output resembling the desired type's description)

Types supported by my proc (stolen from mirc):
0: *!user@full.host.tld
1: *!*user@full.host.tld
2: *!*@full.host.tld
3: *!*user@*.host.tld
4: *!*@*.host.tld
5: nick!user@full.host.tld
6: nick!*user@full.host.tld
7: nick!*@full.host.tld
8: nick!*user@*.host.tld
9: nick!*@*.host.tld
NOTE: if the host is an ip, the last octet will be an asterisk (*) for the types that have one of those after the "@" in the type list above. If the host is a name, but there is no subdomain and/or second level domain, the entire hostname will be returned. Any tilde(s) in the start of the ident/username will be trimmed off for the types that contain "!*user@"
E.g.:
"maskhost nick!~id@127.0.0.1 3" returns *!*id@127.0.0.*
"maskhost nick!~id@pretty.lame.tld 3" returns *!*id@*.lame.tld
"maskhost nick!~id@lame.tld 3" returns *!*id@lame.tld

Code: Select all

# Setting:
set maskhostDefaultType 3

# The proc:
proc maskhost [list name [list type $maskhostDefaultType]] {
	if {[scan $name {%[^!]!%[^@]@%s} nick user host]!=3} {
		error "Usage: maskhost <nick!user@host> \[type\]"
	}
	if [string match {[3489]} $type] {
		if [string match {*[0-9]} $host] {
			set host [join [lrange [split $host .] 0 2] .].*
		} elseif {[string match *.*.* $host]} {
			set host *.[join [lrange [split $host .] end-1 end] .]
		}
	}
	if [string match {[1368]} $type] {
		set user *[string trimleft $user ~]
	} elseif {[string match {[2479]} $type]} {
		set user *
	}
	if [string match {[01234]} $type] {
		set nick *
	}
	set name $nick!$user@$host
}
Matching bans.

Different irc networks have different ways of dealing with case sensitivity. rfc-compliant ircds consider {, } and | the lowercase versions of [, ] and \, others see them as entirely different characters. This means there's no single way to match bans that will work on all networks. Your matching code must be tailored to the particular ircd you're running the script on. (The detection of what type of matching is used on your network can be done using a raw bind (005))

I've seen many people use string match to do ban matching without thinking about the special meaning square brackets ([]) and backslash (\) have in a glob pattern. The glob pattern used by string match is NOT the same as a ban on irc. To have the brackets and backslashes treated like normal characters by string match, you must escape them ...or, for rfc-compliant networks, replace them with their "lowercase" counterparts.

If you have a hard time understanding what kind of problems failing to deal with these special chars might lead to, here's an example for you: Let's say you have the ban [die]!*@* in one of your scripts, then someone by that nick joins (or whatever triggering a match check), but nothing happens...why? The unescaped brackets are interpreted as "match any one of these 3 letters" (d, i OR e) and the brackets themselves are discarded in the actual matching, so you end up with a mismatch for the nick [die], but your mask is matching 3 other single letter nicks. :P

I'm tired of writing...please let me know if you spot any errors/i left something out/you need examples/more info on some of this. (post below)
Last edited by user on Tue Dec 14, 2004 10:07 pm, edited 1 time in total.
Have you ever read "The Manual"?
User avatar
awyeah
Revered One
Posts: 1580
Joined: Mon Apr 26, 2004 2:37 am
Location: Switzerland
Contact:

Post by awyeah »

Here, is another script which I use for placing bans it is quite more sophisticated. I found it from MC_8's more_tools.tcl package. It is free for scripters to use in their scripts.

It has a maskhosttype which has 10 types of regular bans and 10 types of bans by replacing numbers with "?'s" wildcards, in total 20. But I've modified it to replace those numbers by "*'s" wildcards as well making it give 30 types of banmasks.

Code: Select all

# maskhostbytype <nick!ident@host.domain> [type]
#     version:
#       v2.2
#     information (mc.moretools command):
#       Masks <nick!ident@host.domain> by <type>.  If [type] is not specified,
#       then 5 is assumed.
#       Valid types are:
#        -1 - nick*!*@*
#         0 - *!user@host.domain
#         1 - *!*user@host.domain
#         2 - *!*@host.domain
#         3 - *!*user@*.domain
#         4 - *!*@*.domain
#         5 - nick!user@host.domain
#         6 - nick!*user@host.domain
#         7 - nick!*@host.domain
#         8 - nick!*user@*.domain
#         9 - nick!*@*.domain
#       You can also specify a type of 10-19 which corresponds to types 0-9,
#       using this sub rule;  If host.domain is a:
#         name - Instead of using a * wildcard to replace portions of the
#                host.domain, it replaces the numbers in the host.domain with a
#                '?' (question mark) wildcard.
#         ip   - It will mask as normal, with no '?' (question mark)
#                replacements as does hostname.
#       You can also specify a type of 20-29 which corresponds to types 10-19,
#       only by replacing '?' with the wildcard * everywhere.
#     examples:
#       maskhostbytype MC_8!mc8@austin001.rr.com 3 => *!*mc8@*.rr.com
#       maskhostbytype MC_8!mc8@austin001.rr.com 13 => *!*mc8@austin???.rr.com
#       maskhostbytype MC_8!mc8@austin001.rr.com 23 => *!*mc8@austin*.rr.com
#     credits:
#       mIRC - using its numbering system for [type].
#     returns:
#       - <nick!user@host.domain> masked accordingly.

#Set the type of wildcard masking to use.
#NOTE: This is only effects bans from 10-29.
#USAGE: [1/2] - (1=?, 2=*)
set wildcardtype "2"

proc maskhostbytype {{args ""}} {
 global wildcardtype
  badargs $args 1 2 "nick!ident@host.domain ?type?"
  unlist $args nuhost type
  set type [expr {($type == "")?5:$type}]
  if {![regexp -- {^(1?[0-9]|-1)$} $type]} {
    set valid "-1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 {or 19}"
    error "bad type \"$type\": must be [join $valid ", "]"
  }
  set ident_max-length 9; set host_max-length 63
  if {![regexp -- {^(.*[^!])!((.*)@(.*))$} $nuhost -> nick uhost ident host]} {
    error "invalid nick!ident@host.domain: $nuhost"
  }
  if {$type == "-1"} {return $nick*!*@*}
  set maskhost 1
  if {[string length $type] == "2"} {
    if {[info tclversion] < "8.1"} {
      set re_syntax_1 {([12][0-9][0-9]|[1-9][0-9]|[1-9])}
      set re_syntax_2 {([12][0-9][0-9]|[1-9][0-9]|[0-9])}
    } else {
      set re_syntax_1 {([12]\d{2}|[1-9][0-9]|[1-9])}
      set re_syntax_2 {([12]\d{2}|[1-9][0-9]|[0-9])}
    }
    set re_syntax ^$re_syntax_1\\.$re_syntax_2\\.$re_syntax_2\\.$re_syntax_2\$
    if {![regexp -- $re_syntax $host]} {
    if {($wildcardtype = 1)} {
      regsub -all -- {[0-9]} $host ? host
      }
    if {($wildcardtype = 2)} {
      regsub -all -- {[0-9]} $host * host
      }
      set maskhost 0
    }; set type [string index $type 1]
  }
  if {[string match {[0-4]} $type]} {set nick *}
  if {[string match {[2479]} $type]} {set ident *}
  if {[string match {[1368]} $type]} {regsub -- {^~?(.*)$} $ident *\\1 ident}
  if {[string match {[3489]} $type] && $maskhost} {
    set host [lindex [split [maskhost $host] @] end]
  }
  if {[set length [string length $ident]] > ${ident_max-length}} {
    set ident *[string range $ident [expr $length-${ident_max-length}] end]
  }
  if {[set length [string length $host]] > ${host_max-length}} {
    set host *[string range $host [expr $length-${host_max-length}] end]
  }
  return $nick!$ident@$host
}


proc badargs {{args ""}} {
  if {[llength $args] < 4} {
    error {
      wrong # args: should be "badargs args min_llength max_llength argNames"
    }
  }
  set index 0
  foreach varName [list args min max names] {
    set check_$varName [lindex $args $index]
    incr index
  }
  if {[regexp -- {([^0-9])} $check_min -> bad]} {
    error "bad number \"$bad\" in: $check_min"
  }
  if {[regexp -- {([^0-9])} $check_max -> bad] && ($check_max != "end")} {
    error "bad number \"$bad\" in: $check_max"
  }
  if {[catch {llength $check_args} llength]} {
    set check_args [split $check_args]
    set llength $check_args
  }
  if {($llength < $check_min) || (($llength != "end") &&
      ($llength > $check_max))} {
    if {[info level] == "1"} {return 1}
    error "wrong # args: should be \"[lindex [info level -1] 0] $check_names\""
  }; return 0
}

proc unlist {{args ""}} {
  badargs $args 1 end "argsList ?varName varName ...?"
  set argList [lindex $args 0]
  set argList [expr {([catch {llength $argList}])?[split $argList]:$argList}]
  set argNames [lrange $args 1 end]
  if {![llength $argNames]} {
    return [expr {(![catch {llength $argList}])?
      [join $argList]:$argList}]
  }
  for {set index 0} {$index < [llength $argNames]} {incr index 1} {
    set argName     [lindex $argNames $index]
    set argListItem [lindex $argList  $index]
    set argName_ [expr {([catch {llength $argName}])?[split $argName]:$argName}]
    set setTo   [lindex $argName_ 1]
    set argName [lindex $argName_ 0]
    if {$argName == ""} {continue}
    upvar 1 $argName var
    if {[expr $index+1] > [llength $argList]} {
      if {[llength $argName_] == "2"} {set var $setTo}
    } else {
      if {$argName == "args"} {
        set var [lrange $argList $index end]
        incr index [expr [llength $var]-1]
      } else {set var $argListItem}
    }
  }; return $index
}
Now for the example:

Code: Select all

Now in your main proc, where you want to ban the user with the selected type of banmask you want, you can simply use:

#This will choose the '12' type of banmask.
set banmask [maskhostbytype $nick!$uhost 12]

#Then futher onwards you can ban the user, with the $banmask variable.
putquick "MODE $chan +b $banmask"
·­awyeah·

==================================
Facebook: jawad@idsia.ch (Jay Dee)
PS: Guys, I don't accept script helps or requests personally anymore.
==================================
User avatar
user
&nbsp;
Posts: 1452
Joined: Tue Mar 18, 2003 9:58 pm
Location: Norway

Post by user »

awyeah wrote:Here, is another script which I use for placing bans it is quite more sophisticated.
If by "sophisticated" you mean "bloated, buggy and weird", sure. :P
Is this a recent version of MC_8's code? It's got obvious bugs that I don't think would make it into a release...like:
if {($wildcardtype = 1)} {
regsub -all -- {[0-9]} $host ? host
}
if {($wildcardtype = 2)} {
regsub -all -- {[0-9]} $host * host
}
set maskhost 0
}
Here's a tweaked version of my proc that should do the same (i didn't duplicate the bugs):

Code: Select all

# Setting:
set maskhostDefaultType 3

# The proc:
proc maskhost [list name [list type $maskhostDefaultType]] {
	if {[scan $name {%[^!]!%[^@]@%s} nick user host]!=3} {
		error "Usage: maskhost <nick!user@host> \[type\]"
	}
	if {![string is int -strict $type]||$type<-1||$type>29} {
		error "Invalid ban type."
	}
	if {$type==-1} {return $nick*!*@*}
	set ip [string match {*[0-9]} $host]
	if {$type<10||$ip} {
		if {[string match {[3489]} [expr {$type%10}]]} {
			if $ip {
				set host [join [lrange [split $host .] 0 2] .].*
			} elseif {[string match *.*.* $host]} {
				set host *.[join [lrange [split $host .] end-1 end] .]
			}
		}
	} elseif {$type>19} {
		regsub -all {[0-9]+} $host * host
	} else {
		regsub -all {[0-9]} $host ? host
	}
#?	if {[string len $host]>63} {set $host *[string range $host end-62 end]}
	set type [expr {$type%10}]
	if [string match {[1368]} $type] {
		set user *[string trimleft $user ~]
	} elseif {[string match {[2479]} $type]} {
		set user *
	}
#?	if {[string len $user]>9} {set user *[string range $user end-8 end]}
	if [string match {[01234]} $type] {
		set nick *
	}
	set name $nick!$user@$host
}
PS: don't use type -1 for anything automated or you could find your bot banning your friends.
Eg: someone wants to have some fun with "someone"... they change their nick to part of that nick (s, so, som, some, someo or someon) and do what ever it takes to get banned with that mask. (which will, of course, match "someone" too)
Have you ever read "The Manual"?
User avatar
demond
Revered One
Posts: 3073
Joined: Sat Jun 12, 2004 9:58 am
Location: San Francisco, CA
Contact:

Post by demond »

it might be worth mentioning that most of the established and widely-used ircds today (hybrid7/ratbox, ircu, irc2.10) support CIDR (Classless Inter-Domain Routing) bans; such bans allow for finer tuning of who's banned, for example:

if you need to ban an IP range that doesn't fall in the class scheme A.B.C.D, say 1.2.3.0 - 1.2.3.127, you can't use the classic octet masking (1.2.3.* would ban also 1.2.3.128 - 1.2.3.255, and that isn't what you want); you have to use a CIDR ban: 1.2.3.0/25 (if you were to ban 1.2.3.128 - 1.2.3.255, you would use 1.2.3.128/25); in this case, 25 is the CIDR prefix length and means first 25 bits of the 32-bit IP address are fixed and the rest 7 may vary

for more info on CIDR notation click here

as of present, eggdrop doesn't support CIDR bans - you can place botbans in CIDR format, but they won't be matched
User avatar
demond
Revered One
Posts: 3073
Joined: Sat Jun 12, 2004 9:58 am
Location: San Francisco, CA
Contact:

Post by demond »

on a side note, here's a little known, but useful ban feature of the aforementioned ircds:

you can ban a whole vhosted site by IP mask; for example, if you have problems with some l33t gang of monkeys using a bunch of hosts in several domains - stupid.foo.com, dumb.bar.net, lame.info etc., but all of them resolving to 1.2.3.4, 1.2.3.5, 1.2.3.6 etc. in the 1.2.3 C-class network, you ban them all by setting just a single (sticky!) ban - *!*@1.2.3.*

this is possible because for every IRC user, the server keeps a data field called 'sockhost', which actually contains user's IP, regardless whether his/her host resolves or not; and that field is matched (on join attempt) against the channel ban list first, prior matching user's host
User avatar
user
&nbsp;
Posts: 1452
Joined: Tue Mar 18, 2003 9:58 pm
Location: Norway

updated maskhost proc

Post by user »

A little rewrite of the first version of my maskhost proc... this one will use eggdrop's maskhost command to do the masking of the host name/ip, which will make it a little bit faster, make it support ipv6 and create better masks for "tld"'s like .co.uk

Code: Select all

if {![llength [info procs maskhost]]&&[llength [info commands maskhost]]} {
	rename maskhost eggmaskhost
}
proc maskhost {name {type 3}} { 
	if {[scan $name {%[^!]!%[^@]@%s} nick user host]!=3} { 
		error "usage: [lindex [info level 0] 0] <nick!user@host> \[type\]" 
	} 
	if {[string match {[3489]} $type]} {
		set host [lindex [split [eggmaskhost $host] @] 1]
	} 
	if {[string match {[1368]} $type]} { 
		set user *[string trimleft $user ~] 
	} elseif {[string match {[2479]} $type]} { 
		set user * 
	} 
	if {[string match {[01234]} $type]} { 
		set nick * 
	} 
	set name $nick!$user@$host 
}
Have you ever read "The Manual"?
t
timew
Voice
Posts: 7
Joined: Thu Feb 10, 2005 7:29 am

Post by timew »

Hi, I'd like to use this script, is there any way it can be modified so that it looks for a user in the channel then kicks them as well.

Say I have the variable type permanantly set to 2 which is my favourite ban type in mirc as well, then all I have to type is .userban *!*@user.host (kinda like the internal eggdrop one already) then it'll kick and ban at this host.

The reason i do ask this is because i'd like this code called up from another script (a voting script) and i only want the input to be the banmask then the script should be able to work out the nick to ban from.

I need this because during the voting process, the user could kick evade by simply changing his nick.

This type of mod would be useful for other scripts as well. Please help :P
User avatar
user
&nbsp;
Posts: 1452
Joined: Tue Mar 18, 2003 9:58 pm
Location: Norway

Post by user »

timew wrote:Hi, I'd like to use this script
My script is for creating ban masks, not matching bans (take a look at the first post in this thread if you want to know more about matching)
To get your bot to kick people based on bans, all you have to do is '.chanset #chan +enforcebans'.
If you don't want enforcebans to do the job, you can create a ban using 'newban' or 'newchanban' and use 'matchban' to determine if a person is matching the ban... or you could write your own matching proc based on the info in my first post.
Have you ever read "The Manual"?
Post Reply