From 86cb8933b476f4bb79bee028c8962fbfb20f7a0f Mon Sep 17 00:00:00 2001 From: cyan <> Date: Thu, 4 Sep 2003 11:36:29 +0000 Subject: [PATCH] Support Y:Lines, Z:Lines, and I:Lines, including IRC classes. Give opers their class as defined on the O:Line when going umode +o Close all client connections when the ircd becomes terminated. Changed all server_wallops to their proper Bahamut counterparts. Not all oper notices are global anymore, and fixed handling of KILL messages. Added LOCOPS as per Bahamut in anticipation of proper GLOBOPS and CHATOPS. --- exec/ircd.js | 219 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 160 insertions(+), 59 deletions(-) diff --git a/exec/ircd.js b/exec/ircd.js index bca45dfe22..5202c17010 100644 --- a/exec/ircd.js +++ b/exec/ircd.js @@ -26,7 +26,8 @@ load("nodedefs.js"); // IF you're making a custom version, it'd be appreciated if you left the // version number alone, and add a token in the form of +hack (i.e. 1.0+cyan) // This is so everyone knows your revision base, AND type of hack used. -var version = "1.0b"; +const VERSION = "1.0b"; +const VERSION_STR = "Synchronet IRC Daemon by Randy Sommerfeld <sysop@rrx.ca>"; // This will dump all I/O to and from the server to your Synchronet console. // It also enables some more verbose WALLOPS, especially as they pertain to // blocking functions. @@ -52,11 +53,6 @@ var resolve_hostnames = true; // freeze for the amount of time it takes to connect. var ob_sock_timeout = 3; -// these two are to be replaced by Y:Lines eventually. -var ping_time = 120; // PING clients idle beyond this many seconds -var pingtimeout_time = 30; // after sending PING, how long before we - // nuke them for a ping timeout? - // what our server is capable of from a server point of view. // TS3 = Version 3 of accepted interserver timestamp protocol. // NOQUIT = NOQUIT interserver command supported. @@ -144,6 +140,14 @@ function dec_to_ip(ip) { // TODO XXX :) } +function terminate_everything(terminate_reason) { + for(thisClient in Clients) { + client = Clients[thisClient]; + if (client.local) + client.quit(terminate_reason,false) + } +} + function searchbynick(nick) { if (!nick) return 0; @@ -187,6 +191,22 @@ function searchbyserver(server_name) { return 0; // looks like we failed after all that hard work :( } +function IRCClient_searchbyiline() { + for(thisILine in ILines) { + // FIXME: We don't compare connecting port for now. + if ( + (match_irc_mask(this.uprefix + "@" + + this.socket.remote_ip_address,ILines[thisILine].ipmask)) && + ((ILines[thisILine].password == "") || + (this.password == ILines[thisILine].password)) && + (match_irc_mask(this.uprefix + "@" + this.hostname, + ILines[thisILine].hostmask)) + ) + return ILines[thisILine].ircclass; + } + return 0; +} + // IRC is funky. A "string" in IRC is anything after a :, and anything before // that is usually treated as fixed arguments. So, this function is commonly // used to fetch 'strings' from all sorts of commands. PRIVMSG, NOTICE, @@ -215,11 +235,14 @@ function parse_username(str) { return str.slice(0,9); } -function server_wallops(str) { - wallopers(":" + servername + " WALLOPS :" + str); - server_bcast_to_servers(":" + servername + " WALLOPS :" + str); +function oper_notice(ntype,nmessage) { + for(thisoper in Clients) { + oper=Clients[thisoper]; + if ((oper.mode&USERMODE_OPER) && !oper.parent) + oper.rawout(":" + servername + " NOTICE " + oper.nick + " :*** " + ntype + " -- " + nmessage); + } } - + function create_ban_mask(str,kline) { tmp_banstr = new Array; tmp_banstr[0] = ""; @@ -294,17 +317,23 @@ function isklined(kl_str) { return 0; } +function iszlined(zl_ip) { + for(the_zl in ZLines) { + if (ZLines[the_zl].ipmask && + match_irc_mask(zl_ip,ZLines[the_zl].ipmask)) + return 1; + } + return 0; +} + function scan_for_klined_clients() { for(thisUser in Clients) { if (Clients[thisUser]) { theuser=Clients[thisUser]; if (theuser.local && !theuser.server && (theuser.conntype == TYPE_USER)) { - for(thiskl in KLines) { - if (KLines[thiskl].hostmask && - match_irc_mask(theuser.uprefix + "@" + theuser.hostname,KLines[thiskl].hostmask)) - theuser.quit("User has been K:Lined (" + KLines[thiskl].reason + ")"); - } + if (isklined(theuser.uprefix + "@" + theuser.hostname)) + theuser.quit("User has been K:Lined (" + KLines[thiskl].reason + ")"); } } } @@ -331,7 +360,7 @@ function connect_to_server(this_cline,the_port) { connect_sock = new Socket(); connect_sock.connect(this_cline.host,the_port,ob_sock_timeout); if (connect_sock.is_connected) { - server_wallops("Connected! Sending info.."); + oper_notice("Routing","Connected! Sending info..."); connect_sock.send("PASS " + this_cline.password + " :TS\r\n"); connect_sock.send("CAPAB " + server_capab + "\r\n"); connect_sock.send("SERVER " + servername + " 1 :" + serverdesc + "\r\n"); @@ -494,11 +523,14 @@ function read_config_file() { Admin2 = ""; Admin3 = ""; CLines = new Array(); + ILines = new Array(); KLines = new Array(); NLines = new Array(); OLines = new Array(); QLines = new Array(); ULines = new Array(); + YLines = new Array(); + ZLines = new Array(); fname=""; if (config_filename && config_filename.length) fname=system.ctrl_dir + config_filename; @@ -539,6 +571,11 @@ function read_config_file() { break; CLines.push(new CLine(arg[1],arg[2],arg[3],arg[4],arg[5])); break; + case "I": + if (!arg[5]) + break; + ILines.push(new ILine(arg[1],arg[2],arg[3],arg[4],arg[5])); + break; case "K": if (!arg[2]) break; @@ -563,7 +600,7 @@ function read_config_file() { case "O": if (!arg[5]) break; - OLines.push(new OLine(arg[1],arg[2],arg[3],arg[4],arg[5])); + OLines.push(new OLine(arg[1],arg[2],arg[3],arg[4],parseInt(arg[5]))); break; case "Q": if (!arg[3]) @@ -575,6 +612,16 @@ function read_config_file() { break; ULines.push(arg[1]); break; + case "Y": + if (!arg[5]) + break; + YLines[parseInt(arg[1])] = new YLine(parseInt(arg[2]),parseInt(arg[3]),parseInt(arg[4]),parseInt(arg[5])); + break; + case "Z": + if (!arg[2]) + break; + ZLines.push(new ZLine(arg[1],arg[2])); + break; case "#": case ";": default: @@ -587,6 +634,7 @@ function read_config_file() { log ("WARNING! No config file found or unable to open. Proceeding with defaults."); } scan_for_klined_clients(); + YLines[0] = new YLine(120,600,1,5050000); // default irc class } /////////////////////////////////////////////////////////////////////////////// @@ -623,7 +671,7 @@ for (cmdarg=0;cmdarg<argc;cmdarg++) { } read_config_file(); -log("Synchronet IRC Daemon (" + version + ") started."); +log("Synchronet IRC Daemon (" + VERSION + ") started."); ///// Main Loop ///// while (!server.terminated) { @@ -638,10 +686,15 @@ while (!server.terminated) { if (server.socket.poll()) { client_sock=server.socket.accept(); if(client_sock) { - new_id = get_next_clientid(); - Clients[new_id]=new IRCClient(client_sock,new_id,true,true); - if(server.client_add != undefined) - server.client_add(client_sock); + if (iszlined(client_sock.remote_ip_address)) { + client_sock.send(":" + servername + " 465 * :You've been Z:Lined from this server.\r\n"); + client_sock.close(); + } else { + new_id = get_next_clientid(); + Clients[new_id]=new IRCClient(client_sock,new_id,true,true); + if(server.client_add != undefined) + server.client_add(client_sock); + } } } @@ -661,12 +714,17 @@ while (!server.terminated) { if (CLines[thisCL].port && !(searchbyserver(CLines[thisCL].servername)) && ((time() - CLines[thisCL].lastconnect) > 30) ) { - server_wallops("!WARNING! Auto-connecting to " + CLines[thisCL].servername); + oper_notice("Routing","Auto-connecting to " + CLines[thisCL].servername); connect_to_server(CLines[thisCL]); } } } +// End of our run, so terminate everything before we go. +terminate_everything("Terminated."); + +//////////////////////////////// END OF MAIN //////////////////////////////// + // Client Object // FIXME: this whole thing is a mess. It should be cleaned up and streamlined. @@ -678,6 +736,7 @@ function IRCClient(socket,new_id,local_client,do_newconn) { this.uprefix = ""; this.hostname = ""; this.conntype = TYPE_UNREGISTERED; + this.ircclass = 0; this.idletime = ""; this.invited = ""; this.password = ""; @@ -686,6 +745,7 @@ function IRCClient(socket,new_id,local_client,do_newconn) { this.mode = USERMODE_NONE; this.socket = socket; this.channels = new Array(); + this.searchbyiline=IRCClient_searchbyiline; this.quit=IRCClient_Quit; this.netsplit=IRCClient_netsplit; this.ircnuh getter = function() { @@ -775,7 +835,7 @@ function IRCClient(socket,new_id,local_client,do_newconn) { went_into_hostname = time() - went_into_hostname; if (went_into_hostname == "NaN") went_into_hostname=0; - server_wallops("!DEBUG: resolve_host took " + went_into_hostname + " seconds."); + oper_notice("DEBUG","resolve_host took " + went_into_hostname + " seconds."); } } if (this.socket.remote_ip_address) @@ -819,7 +879,7 @@ function IRCClient_Quit(str,do_bcast) { if (this.local) { this.rawout("ERROR :Closing Link: [" + this.uprefix + "@" + this.hostname + "] (" + str + ")"); - server_wallops("Client Exiting: " + this.ircnuh + " (" + str + ")"); + oper_notice("Notice","Client exiting: " + this.nick + " (" + this.uprefix + "@" + this.hostname + ") [" + str + "] [" + this.decip + "]"); this.socket.close(); } @@ -851,20 +911,18 @@ function IRCClient_synchronize() { this.server_info(Clients[my_server]); } } - server_wallops("Sending NICK burst..."); for (my_client in Clients) { if ((Clients[my_client].conntype == TYPE_USER) || (Clients[my_client].conntype == TYPE_USER_REMOTE)) { this.server_nick_info(Clients[my_client]); } } - server_wallops("Sending CHANNEL burst..."); for (my_channel in Channels) { if (my_channel[0] == "#") { this.server_chan_info(Channels[my_channel]); } } - server_wallops("Sending TOPIC burst..."); + oper_notice("Routing","from " + servername + ": " + this.nick + " has processed user/channel burst, sending topic burst."); for (my_channel in Channels) { if ((my_channel[0] == "#") && Channels[my_channel].topic) { chan = Channels[my_channel]; @@ -872,6 +930,7 @@ function IRCClient_synchronize() { } } this.rawout("BURST 0"); // burst completed. + oper_notice("Routing","from " + servername + ": " + this.nick + " has processed topic burst (synched to network data)."); } function IRCClient_server_info(sni_server) { @@ -976,7 +1035,7 @@ function IRCClient_numeric(num, str) { //////////////////// Numeric Functions //////////////////// function IRCClient_numeric351() { - this.numeric(351, version + " " + servername + " :Synchronet IRC Daemon by Randy Sommerfeld <sysop@rrx.ca>"); + this.numeric(351, VERSION + " " + servername + " :(REV:" + REVISION + ") " + VERSION_STR); } function IRCClient_numeric353(chan, str) { @@ -1044,7 +1103,7 @@ function IRCClient_lusers() { } function IRCClient_motd() { - motd_file = new File(system.text_dir + "/ircmotd.txt"); + motd_file = new File(system.text_dir + "ircmotd.txt"); if (motd_file.open("r")) { this.numeric(375, ":- " + servername + " Message of the Day -"); this.numeric(372, ":- " + strftime("%m/%d/%Y %H:%M",motd_file.date)); @@ -1986,24 +2045,30 @@ function IRCClient_unregistered_commands(command, cmdline) { if (count_local_nicks() > hcc_users) hcc_users = count_local_nicks(); if (this.realname && this.uprefix && (this.nick != "*")) { + // Check for a valid I:Line. + this.ircclass = this.searchbyiline(); + if (!this.ircclass) { + this.quit("You are not authorized to use this server."); + return 0; + } // We meet registration criteria. Continue. hcc_counter++; this.conntype = TYPE_USER; this.numeric("001", ":Welcome to the Synchronet IRC Service, " + this.ircnuh); - this.numeric("002", ":Your host is " + servername + ", running Synchronet IRCD " + version); + this.numeric("002", ":Your host is " + servername + ", running Synchronet IRCD " + VERSION); this.numeric("003", ":This server was created " + strftime("%a %b %e %Y at %H:%M:%S %Z",server_uptime)); - this.numeric("004", servername + " " + version + " oi biklmnopstv"); + this.numeric("004", servername + " " + VERSION + " oi biklmnopstv"); this.numeric("005", "MODES=" + max_modes + " MAXCHANNELS=" + max_user_chans + " CHANNELLEN=" + max_chanlen + " MAXBANS=" + max_bans + " NICKLEN=" + max_nicklen + " TOPICLEN=" + max_topiclen + " KICKLEN=" + max_kicklen + " CHANTYPES=#& PREFIX=(ov)@+ NETWORK=Synchronet CASEMAPPING=ascii CHANMODES=b,k,l,imnpst STATUSMSG=@+ :are available on this server."); this.lusers(); this.motd(); - server_wallops("Client Connect: " + this.ircnuh + " (" + this.realname + ")"); + oper_notice("Notice","Client connecting: " + this.nick + " (" + this.uprefix + "@" + this.hostname + ") [" + this.socket.remote_ip_address + "] {1}"); if (server.client_update != undefined) server.client_update(this.socket, this.nick, this.hostname); server_bcast_to_servers("NICK " + this.nick + " 1 " + this.created + " " + this.get_usermode() + " " + this.uprefix + " " + this.hostname + " " + servername + " " + this.decip + " 0 :" + this.realname); } else if (this.nick.match("[.]") && this.hops && this.realname && this.server && (this.conntype == TYPE_SERVER)) { hcc_counter++; - server_wallops("SERVER Connect: " + this.nick + " (" + this.realname + ")"); + oper_notice("Routing","Link with " + this.nick + "[unknown@" + this.hostname + "] established, states: TS"); if (server.client_update != undefined) server.client_update(this.socket, this.nick, this.hostname); if (!this.sentps) { @@ -2079,7 +2144,7 @@ function IRCClient_registered_commands(command, cmdline) { this.server_notice("Invalid port: " + cmd[2]); break; } - server_wallops("Connecting to " + con_cline.servername + ":" + cmd[2] + " as per " + this.ircnuh); + oper_notice("Routing","from " + servername + ": Local CONNECT " + con_cline.servername + " " + cmd[2] + " from " + this.nick + "[" + this.uprefix + "@" + this.hostname + "]"); connect_to_server(con_cline,cmd[2]); break; case "DEBUG": @@ -2089,16 +2154,16 @@ function IRCClient_registered_commands(command, cmdline) { } if (debug) { debug=false; - server_wallops("Debug mode disabled by " + this.ircnuh); + oper_notice("Notice","Debug mode disabled by " + this.ircnuh); log("!NOTICE debug mode disabled by " + this.ircnuh); } else { debug=true; - server_wallops("Debug mode enabled by " + this.ircnuh); + oper_notice("Notice","Debug mode enabled by " + this.ircnuh); log("!NOTICE debug mode enabled by " + this.ircnuh); } break; case "INFO": - this.numeric("371", ":IRC Daemon for Synchronet Version " + version + " Copyright 2003 Randy Sommerfeld."); + this.numeric("371", ":IRC Daemon for Synchronet Version " + VERSION + " Copyright 2003 Randy Sommerfeld."); this.numeric("371", ":" + system.version_notice + " " + system.copyright + "."); this.numeric("371", ": "); this.numeric("371", ":--- A big thanks to the following for their assistance: ---"); @@ -2253,10 +2318,11 @@ function IRCClient_registered_commands(command, cmdline) { target = searchbynick(kills[kill]); if (!target) target = searchbynick(search_nickbuf(kills[kill])); - if (target) { - server_wallops("/KILL: " + this.nick + " -> " + target.nick + " (" + reason + ")"); + if (target && target.local) { + target.quit("Local kill by " + this.nick + " (" + reason + ")",true); + } else if (target) { server_bcast_to_servers(":" + this.nick + " KILL " + target.nick + " :" + reason); - target.quit("KILLED by " + this.nick + " (" + reason + ")",false); + target.quit("Killed (" + this.nick + " (" + reason + "))"); } else { this.numeric401(kills[kill]); } @@ -2281,7 +2347,7 @@ function IRCClient_registered_commands(command, cmdline) { break; } KLines.push(new KLine(kline_mask,ircstring(cmdline),"k")); - server_wallops("K:Line added by " + this.ircnuh + " for " + kline_mask + " (" + ircstring(cmdline) + ")"); + oper_notice("Notice", this.nick + " added temporary 99 min. k-line for [" + kline_mask + "] [0]"); scan_for_klined_clients(); break; case "UNKLINE": @@ -2303,7 +2369,7 @@ function IRCClient_registered_commands(command, cmdline) { break; } remove_kline(kline_mask); - server_wallops("K:Line removed by " + this.ircnuh + " for " + kline_mask); + oper_notice("Notice", this.nick + " has removed the K-Line for: [" + kline_mask + "] (1 matches)"); break; case "LINKS": for(thisServer in Clients) { @@ -2471,6 +2537,7 @@ function IRCClient_registered_commands(command, cmdline) { ((OLines[ol].password != "SYSTEM_PASSWORD") ))) { oper_success=true; + this.ircclass = OLines[ol].ircclass; break; } } @@ -2478,11 +2545,11 @@ function IRCClient_registered_commands(command, cmdline) { this.numeric("381", ":You are now an IRC operator."); this.mode|=USERMODE_OPER; this.rawout(":" + this.nick + " MODE " + this.nick + " +o"); - server_wallops(this.nick + " is now an IRC operator."); + oper_notice("Notice", this.nick + " (" + this.uprefix + "@" + this.hostname + ") is now operator (O)"); this.bcast_to_servers("MODE "+ this.nick +" +o"); } else { this.numeric("491", ":No O:Lines for your host. Attempt logged."); - server_wallops(this.ircnuh + " tried to OPER unsuccessfully!"); + oper_notice("Notice","Failed OPER attempt by " + this.nick + " (" + this.uprefix + "@" + this.hostname + ")"); log("!WARNING " + this.ircnuh + " tried to OPER unsuccessfully!"); } break; @@ -2537,7 +2604,6 @@ function IRCClient_registered_commands(command, cmdline) { break; } log("!ERROR! Shutting down the ircd as per " + this.ircnuh); - server_wallops("!ERROR! Shutting down the ircd as per " + this.ircnuh); terminated = true; break; case "REHASH": @@ -2545,7 +2611,8 @@ function IRCClient_registered_commands(command, cmdline) { this.numeric481(); break; } - server_wallops("Rehashing server config as per " + this.ircnuh); + this.numeric(382, this.nick + " ircd.conf :Rehashing."); + oper_notice("Notice",this.nick + " is rehashing Server config file while whistling innocently"); log("!NOTICE Rehashing server config as per " + this.ircnuh); read_config_file(); break; @@ -2554,8 +2621,10 @@ function IRCClient_registered_commands(command, cmdline) { this.numeric481(); break; } - server_wallops("RESTART command issued by " + this.ircnuh); - log("!RESTART command issued by " + this.ircnuh); + rs_str = "Aieeeee!!! Restarting server..."; + oper_notice("Notice",rs_str); + log("!WARNING " + rs_str + " per " + this.ircnuh); + terminate_everything(rs_str); exit(); break; case "SQUIT": @@ -2577,7 +2646,7 @@ function IRCClient_registered_commands(command, cmdline) { this.quit(reason); break; } - server_wallops("SQUIT for " + cmd[1] + " issued by " + this.ircnuh); + oper_notice("Routing","from " + servername + ": Received SQUIT " + cmd[1] + " from " + this.nick + "[" + this.uprefix + "@" + this.hostname + "] (" + ircstring(cmdline) + ")"); sq_server.quit(ircstring(cmdline)); break; case "STATS": @@ -2650,7 +2719,10 @@ function IRCClient_registered_commands(command, cmdline) { break; case "Y": case "y": - this.numeric(218,"Y <class> <pingfrequency> <connectfrequency> <maxsendq>"); + for (thisYL in YLines) { + var yl = YLines[thisYL]; + this.numeric(218,"Y " + thisYL + " " + yl.pingfreq + " " + yl.connfreq + " " + yl.maxlinks + " " + yl.sendq); + } break; default: break; @@ -2777,6 +2849,13 @@ function IRCClient_registered_commands(command, cmdline) { } this.numeric351(); break; + case "LOCOPS": + if (!(this.mode&USERMODE_OPER)) { + this.numeric481(); + break; + } + oper_notice("LocOps","from " + this.nick + ": " + ircstring(cmdline)); + break; case "GLOBOPS": case "WALLOPS": // allow non-opers to wallop for assistance, perhaps. @@ -2911,7 +2990,7 @@ function IRCClient_server_commands(origin, command, cmdline) { ThisOrigin.away = ircstring(cmdline); break; case "ERROR": - server_wallops("ERROR from " + ThisOrigin.nick + ": " + ircstring(cmdline)); + oper_notice("Notice", "ERROR :from " + ThisOrigin.nick + "[(+)0@" + this.hostname + "] -- " + ircstring(cmdline)); ThisOrigin.quit(); break; case "KICK": @@ -3292,15 +3371,17 @@ function IRCClient_work() { this.server_commands(origin,command,cmdline); } else { log("!ERROR: Client has bogus conntype!"); - server_wallops("!ERROR: Client has bogus conntype!"); + oper_notice("Notice","Client has bogus conntype!"); } } - if ( (this.pinged) && ((time() - this.pinged) > pingtimeout_time) ) { - this.pinged = false; - this.quit("Ping Timeout",true); - } else if (!this.pinged && ((time() - this.idletime) > ping_time)) { - this.pinged = time(); - this.rawout("PING :" + servername); + if (this.nick) { + if ( (this.pinged) && ((time() - this.pinged) > YLines[this.ircclass].pingfreq) ) { + this.pinged = false; + this.quit("Ping Timeout",true); + } else if (!this.pinged && ((time() - this.idletime) > YLines[this.ircclass].pingfreq)) { + this.pinged = time(); + this.rawout("PING :" + servername); + } } } @@ -3474,6 +3555,14 @@ function CLine(host,password,servername,port,ircclass) { this.lastconnect = 0; } +function ILine(ipmask,password,hostmask,port,ircclass) { + this.ipmask = ipmask; + this.password = password; + this.hostmask = hostmask; + this.port = port; + this.ircclass = ircclass; +} + function KLine(hostmask,reason,type) { this.hostmask = hostmask; this.reason = reason; @@ -3501,6 +3590,18 @@ function QLine(nick,reason) { this.reason = reason; } +function YLine(pingfreq,connfreq,maxlinks,sendq) { + this.pingfreq = pingfreq; + this.connfreq = connfreq; + this.maxlinks = maxlinks; + this.sendq = sendq; +} + +function ZLine(ipmask,reason) { + this.ipmask = ipmask; + this.reason = reason; +} + function WhoWas(nick,uprefix,host,realname,server,serverdesc) { this.nick = nick; this.uprefix = uprefix; -- GitLab