# winident.tcl v1.2 - by FireEgl@EFNet - April 5, 2001 ### Description: # Implementation of an ident server meant to be used on "WinDrops". ### Features: # It automatically turns itself on and off when needed so it (usually) # shouldn't conflict with other identd's that do the same. ### Notes/Suggestions: # * If you use mIRC be sure that it's Identd setting # "Enable only when connecting" is CHECKED in Options. # * Use at least Eggdrop v1.4.4 (stable), or v1.5.5 (development) for this script to work best. # * For older versions it uses a kludge method for detecting if it needs # to be turned on or off, and is more likely to conflict with other # ident servers that may be running. # * If you run several bots on the same machine then set their server-timeout # setting differently in their configs. This will stop them from timing out and # trying to turn on their identd and connecting back to a server at the same time. # * Make sure that your bot is able to connect to all the servers in its # $servers list, so that the identd will only be listening for a short time. ### Known Problems: # * For old Eggdrops (using the kludge method), the first server the bot tries # to connect to after it disconnects from one may not get an ident responce. (rare) # * Sometimes (using the kludge method), the Identd thinks it's on, when it's really not. (very rare) # * If Eggdrop crashes it's possible that the identd port will get stuck open. (only a reboot will fix it) ### DCC Commands: # .ident on|off - Will temporarily turn the identd on or off (until the bot thinks it needs it on or off again). # .ident status - Tells you if the identd is listening or not, and what it's replying with. # .ident reset - Resets your ident responce to what you have defined as $username in your Eggdrops config. # .ident - Will temporarily change your ident responce (until you rehash). # History: # 1.0 - Released. # 1.1 - Updated to enable non-kludge operation on the current 1.5.4 CVS. # 1.2 - Added the ident(kludge) option (because it didn't properly detect your Eggdrop version before). ### Comments? Suggestions? # Email me at FireEgl@Windrop.cjb.net ### If you need help, here's some places to find it: # First, sure to get the latest "Windrop" from http://Windrop.cjb.net # http://WindropFAQ.tsx.org - A mini-FAQ with focus on newbies to Eggdrop and to the Cygwin (Windows) ports. # http://WindropCVS.tsx.org - Kirben's Eggdrop CVS ports. # Subscribe to the WinDrop mail list @ http://Egg95.ListBot.com # #EggHeads on EFNet - Ask general Eggdrop questions here, even scripting questions. # http://www.EggHelp.org - slennox's Eggdrop Page; get netbots.tcl from here!!! # http://EggTCL.tsx.org - My Eggdrop scripts page. =) # #Windrop and #WinDropHelp on EFNet - Also visit http://Windrop.tsx.org ### Options: ## Set this to the ident you want to have: # Leave as $username*** for it use the $username setting you defined in your # Eggdrop config, along with up to 3 random alphanumeric characters at the end. # (You can use *'s (for alphanumeric) or ?'s (for digit) as wildcards here to # have random characters put in place of them whenever an ident is requested.) set ident(username) "$username***" ## You prolly shouldn't need to touch these: set ident(system) "UNIX" set ident(port) "113" set ident(timeout) "${server-timeout}" ## If you're using an old Eggdrop (Windrop) version ## v1.4.4 or less; or v1.5.3 or less enable this option set ident(kludge) 0 ### Begin Script: ## (Don't change anything below here...) # Fixed version of randstring found in alltools.tcl: if {(("[info procs randstring]" == "") || (("[info procs randstring]" == "randstring") && ("[randstring 1]" == "")))} { proc randstring {length} { set count [string length [set chars "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"]] for {set i 0} {$i < $length} {incr i} { append result [string index $chars [rand $count]] } return "$result" } } # Also in alltools.tcl, but including it here in case you're not loading alltools.tcl: if {[info procs isnumber] == ""} { proc isnumber {string} { if {([string compare $string ""]) && (![regexp \[^0-9\] $string])} then { return 1 } { return 0 } } } # dcc command to let you control the identd: bind dcc n ident dcc:ident bind dcc n winident dcc:ident proc dcc:ident {hand idx arg} { global ident username server switch -- "[string tolower [lindex [set arg [split $arg]] 0]]" { "on" { switch -- "[identon]" { "0" { putdcc $idx "Identd was Already On, Listening On Port $ident(port), Replying as $ident(username)" } "1" { putlog "Identd: Listening On Port $ident(port), Replying as $ident(username)" } "-1" { putlog "Identd: Couldn't Open Port $ident(port).. Another Identd Running Somewhere?" } } } "off" { switch -- "[identoff]" { "0" { putdcc $idx "Identd Already Disabled." } "1" { putlog "Identd: Disabled." if {(($ident(kludge)) && ("$server" == ""))} { putdcc $idx "Identd can't be turned off while the bot is trying to connect to a server." } } "-1" { putdcc $idx "Identd Already Disabled. (Tried to Close)" } } } "status" { if {[info exists ident(server-socket)]} { putdcc $idx "Identd is currently enabled and responding as $ident(username)" } else { putdcc $idx "Identd is currently disabled." } } "reset" { putlog "Identd: Set Ident to [set ident(username) $username]" } "set" { if {[llength "[set newident [lindex $arg 1]]"] > 1 } { putlog "Ident: Set Ident to [set ident(username) $newident]" } else { putdcc $idx "Usage: .ident set " } } "default" { if {([llength "$arg"] < 1) || ("[string tolower $arg]" == "help")} { putdcc $idx "Usage: .ident on|off|status|reset|set " } else { putlog "Identd: Set Ident to [set ident(username) [join $arg]]" } } } } # Turns the identd on unless it's already on: # Returns 1 on success, 0 for already running, and -1 for error (another Ident is probably running). proc identon {} { global ident if {(![info exists ident(server-socket)]) || (!$ident(kludge))} { if {[catch { set ident(server-socket) [socket -server connect:ident $ident(port)] } grr]} { if {[info exists ident(server-socket)]} { return 0 } { return -1 } } else { fconfigure $ident(server-socket) -buffering line return 1 } } return 0 } # Turns the identd off unless it's already off: # Returns 1 for success, 0 for already disabled, and -1 for error (it tried to close a non-existable sock aka "already disabled"). proc identoff {} { global ident if {([info exists ident(server-socket)]) || (!$ident(kludge))} { if {[catch { close $ident(server-socket) }]} { catch { unset ident(server-socket) } return -1 } else { catch { unset ident(server-socket) } return 1 } } return 0 } # Accepts the ident connections: proc connect:ident {sock address clientport} { fconfigure $sock -buffering line putlog "Identd: Connect from $address:$clientport..." fileevent $sock readable [list readable:ident $sock $address $clientport] global ident utimer $ident(timeout) [split "timeout:ident $sock $address $clientport"] set ident($sock,$clientport) "" } # Reads from the client and responds: proc readable:ident {sock address clientport} { if {[gets $sock got] != -1} { global ident set got [split $got] # More RFC 1413 compliant than mIRC. =P if {(((![string match "*, *" "[join $got]"]) && (([llength $got] != 3) || ([llength $got] != 2))) || ([string length $got] > 16) || ([string length $got] < 3))} { puts $sock "[join $got] : ERROR : UNKNOWN-ERROR" putlog "Identd: Replied: [join $got] : ERROR : UNKNOWN-ERROR" } elseif {((![isnumber [join [lindex [split $got ,] 0]]]) || (![isnumber [join [lindex [split $got ,] 1]]]) || ([join [lindex [split $got ,] 1]] > 65535) || ([join [lindex [split $got ,] 1]] < 1) || ([join [lindex [split $got ,] 0]] > 65535) || ([join [lindex [split $got ,] 0]] < 1))} { puts $sock "[join $got] : ERROR : INVALID-PORT" putlog "Identd: Replied: [join $got] : ERROR : INVALID-PORT" } else { set username $ident(username) while {[regsub -- \\? $username [rand 10] username]} { continue } while {[regsub -- \\* $username [randstring 1] username]} { continue } puts $sock "[join $got] : USERID : $ident(system) : $username" putlog "Identd: Replied: [join $got] : USERID : $ident(system) : $username" } } if {!$ident(kludge)} { switch -- "[identoff]" { "0" { putlog "Identd Already Disabled." } "1" { putlog "Identd: Disabled." } "-1" { putlog "Identd Already Disabled. (Tried to Close)" } } } close:ident $sock $clientport } # Closes the client socket and returns 1 for success or 0 for error. proc close:ident {sock clientport} { global ident if {[info exists ident($sock,$clientport)]} { catch { fileevent $sock readable {} } catch { close $sock } unset ident($sock,$clientport) return 1 } return 0 } # Thingie that closes the client connection if it's left idle too long: proc timeout:ident {sock address clientport} { global ident if {[close:ident $sock $clientport]} { putlog "Identd: Connection to $address:$clientport Timed Out." } } if {"[string tolower [lindex [split [lindex [split [info nameofexecutable] /] end] .] end]]" != "exe"} { putlog "Identd: I don't know why you're using winident.tcl on your system, but it probably won't work on anything but Windows." } # Older bots probably don't have these events, but we do the bindings just in case: bind evnt - connect-server evnt:ident bind evnt - init-server evnt:ident # bind evnt - disconnect-server evnt:ident # These are here so that the bot can close the identd port before it dies... # (It's possible that the port can get stuck open, and only a reboot will let you get it back.) bind evnt - sigterm evnt:ident bind evnt - sigquit evnt:ident bind evnt - sigill evnt:ident bind evnt - sighup evnt:ident bind evnt - prerehash evnt:ident proc evnt:ident {arg} { global ident switch -- "$arg" { "connect-server" { switch -- "[identon]" { "0" { putlog "Identd was Already On, Listening On Port $ident(port), Replying as $ident(username)" } "1" { putlog "Identd: Listening On Port $ident(port), Replying as $ident(username)" } "-1" { putlog "Identd: Couldn't Open Port $ident(port).. Another Identd Running Somewhere?" } } } "default" { switch -- "[identoff]" { "0" { putlog "Identd Already Disabled." } "1" { putlog "Identd: Disabled." } "-1" { putlog "Identd Already Disabled. (Tried to Close)" } } } } } # These are here in case people forgot or don't like typing a space between .ident and on/off. =P bind dcc n identon dcc:identon bind dcc n winidenton dcc:identon proc dcc:identon {hand idx arg} { global ident switch -- "[identon]" { "0" { putdcc $idx "Identd was Already On, Listening On Port $ident(port), Replying as $ident(username)" } "1" { putlog "Identd: Listening On Port $ident(port), Replying as $ident(username)" } "-1" { putlog "Identd: Couldn't Open Port $ident(port).. Another Identd Running Somewhere?" } } } bind dcc n identoff dcc:identoff bind dcc n winidentoff dcc:identoff proc dcc:identoff {hand idx arg} { global ident switch -- "[identoff]" { "0" { putdcc $idx "Identd Already Disabled." } "1" { putlog "Identd: Disabled." } "-1" { putdcc $idx "Identd Already Disabled. (Tried to Close)" } } } # Use different methods depending on the Eggdrop version: # Do you know how hard it is to distinguish between CVS and release, and 1.4 and 1.5?? =P if {(($ident(kludge) == 0) || (([lindex $version 2] == "CVS") && ([lindex $version 1] >= 1040403) && (([string compare [lindex $version 3] ""]) && (![regexp \[^0-9\] [lindex $version 3]])) && ([lindex $version 3] >= 959114934)) || (([lindex $version 1] >= 1040400) && ([string range [lindex $version 1] 0 2] == "104") && ([lindex $version 2] != "CVS")) || ([lindex $version 1] >= 1050403) && (([string compare [lindex $version 3] ""]) && (![regexp \[^0-9\] [lindex $version 3]])) && ([lindex $version 3] >= 959114934))} { set ident(kludge) 0 } else { putlog "winident.tcl - Using kludge method, upgrade your Eggdrop!" set ident(kludge) 1 # This one checks once per second to see if we're not on a server # and if we're not then starts the identd. proc identcheckserver {} { global server ident foreach t "[utimers]" { if {"[lindex $t 1]" == "identcheckserver"} { killutimer "[lindex $t 2]" } } if {"$server" == ""} { if {[identon] == 1} { putlog "Identd: Listening On Port $ident(port), Replying as $ident(username)" } } utimer 1 identcheckserver } identcheckserver # This one disables the identd upon successful connection to a server: bind raw - "001" connect:identoff proc connect:identoff {from key arg} { switch -- "[identoff]" { "0" { putlog "Identd Already Disabled." } "1" { putlog "Identd: Disabled." } "-1" { putlog "Identd Already Disabled. (Tried to Close)" } } } } putlog "winident.tcl v1.2 - by FireEgl@EFNet - Loaded."