diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 361d6d5b74885..b46903687b5ec 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -70,6 +70,8 @@ var/forbid_singulo_possession = 0 var/useircbot = 0 + var/check_randomizer = 0 + //IP Intel vars var/ipintel_email var/ipintel_rating_bad = 1 @@ -402,6 +404,8 @@ config.notify_new_player_age = text2num(value) if("irc_first_connection_alert") config.irc_first_connection_alert = 1 + if("check_randomizer") + config.check_randomizer = 1 if("ipintel_email") if (value != "ch@nge.me") config.ipintel_email = value diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 894e6a23ab4f5..a56341692f131 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -290,7 +290,7 @@ var/next_external_rsc = 0 if (!dbcon.IsConnected()) return - var/sql_ckey = sanitizeSQL(src.ckey) + var/sql_ckey = sanitizeSQL(ckey) var/DBQuery/query_ip = dbcon.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ip = '[address]' AND ckey != '[sql_ckey]'") query_ip.Execute() @@ -304,15 +304,18 @@ var/next_external_rsc = 0 while (query_cid.NextRow()) related_accounts_cid += "[query_cid.item[1]], " + var/admin_rank = "Player" + if (src.holder && src.holder.rank) + admin_rank = src.holder.rank.name + else + if (check_randomizer()) + return + var/watchreason = check_watchlist(sql_ckey) if(watchreason) message_admins("Notice: [key_name_admin(src)] is on the watchlist and has just connected - Reason: [watchreason]") send2irc_adminless_only("Watchlist", "[key_name(src)] is on the watchlist and has just connected - Reason: [watchreason]") - var/admin_rank = "Player" - if (src.holder && src.holder.rank) - admin_rank = src.holder.rank.name - var/sql_ip = sanitizeSQL(src.address) var/sql_computerid = sanitizeSQL(src.computer_id) var/sql_admin_rank = sanitizeSQL(admin_rank) @@ -326,6 +329,85 @@ var/next_external_rsc = 0 var/DBQuery/query_accesslog = dbcon.NewQuery("INSERT INTO `[format_table_name("connection_log")]` (`id`,`datetime`,`serverip`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),'[serverip]','[sql_ckey]','[sql_ip]','[sql_computerid]');") query_accesslog.Execute() +/client/proc/check_randomizer() + . = FALSE + if (!config.check_randomizer) + return + var/static/cidcheck = list() + var/static/cidcheck_failedckeys = list() //to avoid spamming the admins if the same guy keeps trying. + + var/oldcid = cidcheck[ckey] + if (oldcid) + if (oldcid != computer_id) //IT CHANGED!!! + cidcheck -= ckey //so they can try again after removing the cid randomizer. + + src << "Connection Error:" + src << "Invalid ComputerID(spoofed). Please remove the ComputerID spoofer from your byond installation and try again." + + if (!cidcheck_failedckeys[ckey]) + message_admins("[key_name(src)] has been detected as using a cid randomizer. Connection rejected.") + send2irc_adminless_only("CidRandomizer", "[key_name(src)] has been detected as using a cid randomizer. Connection rejected.") + cidcheck_failedckeys[ckey] = 1 + note_randomizer_user() + + log_access("Failed Login: [key] [computer_id] [address] - CID randomizer confirmed (oldcid: [oldcid])") + + del(src) + return TRUE + else + if (cidcheck_failedckeys[ckey]) + message_admins("[key_name_admin(src)] has been allowed to connect after showing they removed their cid randomizer") + send2irc_adminless_only("CidRandomizer", "[key_name(src)] has been allowed to connect after showing they removed their cid randomizer.") + cidcheck_failedckeys -= ckey + cidcheck -= ckey + else + var/sql_ckey = sanitizeSQL(ckey) + var/DBQuery/query_cidcheck = dbcon.NewQuery("SELECT computerid FROM [format_table_name("player")] WHERE ckey = '[sql_ckey]'") + query_cidcheck.Execute() + + var/lastcid + if (query_cidcheck.NextRow()) + lastcid = query_cidcheck.item[1] + + if (computer_id != lastcid) + cidcheck[ckey] = computer_id + log_access("Failed Login: [key] [computer_id] [address] - CID randomizer check") + + var/url = winget(src, null, "url") + //special javascript to make them reconnect under a new window. + src << browse("byond://[url]", "border=0;titlebar=0;size=1x1") + winset(src, "reconnectbutton", "is-disable=true") //reconnect keeps the same cid in the randomizer, they could use this button to fake it. + sleep(10) //browse is queued, we don't want them to disconnect before getting the browse() command. + + //teeheehee (in case the above method doesn't work, its not 100% reliable.) + src << "
Network connection shutting down due to read error." + del(src) + return TRUE + +/client/proc/note_randomizer_user() + var/const/adminckey = "CID RANDOMIZER DETECTOR" + var/sql_ckey = sanitizeSQL(ckey) + //check to see if we noted them in the last day. + var/DBQuery/query_get_notes = dbcon.NewQuery("SELECT id FROM [format_table_name("notes")] WHERE ckey = '[sql_ckey]' AND adminckey = '[adminckey]' AND timestamp + INTERVAL 1 DAY < NOW()") + if(!query_get_notes.Execute()) + var/err = query_get_notes.ErrorMsg() + log_game("SQL ERROR obtaining id from notes table. Error : \[[err]\]\n") + return + if (query_get_notes.NextRow()) + return + + //regardless of above, make sure their last note is not from us, as no point in repeating the same note over and over. + query_get_notes = dbcon.NewQuery("SELECT adminckey FROM [format_table_name("notes")] WHERE ckey = '[sql_ckey]' ORDER BY timestamp DESC LIMIT 1") + if(!query_get_notes.Execute()) + var/err = query_get_notes.ErrorMsg() + log_game("SQL ERROR obtaining id from notes table. Error : \[[err]\]\n") + return + if (query_get_notes.NextRow()) + if (query_get_notes.item[1] == adminckey) + return + add_note(ckey, "Detected as using a cid randomizer.", null, adminckey, logged = 0) + + /client/proc/check_ip_intel() set waitfor = 0 //we sleep when getting the intel, no need to hold up the client connection while we sleep if (config.ipintel_email) @@ -381,4 +463,4 @@ var/next_external_rsc = 0 //Hook, override it to run code when dir changes //Like for /atoms, but clients are their own snowflake FUCK /client/proc/setDir(newdir) - dir = newdir \ No newline at end of file + dir = newdir diff --git a/config/config.txt b/config/config.txt index 46204abb1aa67..a4303b822ac7f 100644 --- a/config/config.txt +++ b/config/config.txt @@ -111,6 +111,9 @@ HOSTEDBY Yournamehere ## Uncomment this to stop people connecting to your server without a registered ckey. (i.e. guest-* are all blocked from connecting) GUEST_BAN +## Comment to disable checking for the cid randomizer dll. (disabled if database isn't enabled or connected) +CHECK_RANDOMIZER + ### IPINTEL: ### This allows you to detect likely proxies by checking ips against getipintel.net ## Rating to warn at: (0.90 is good, 1 is 100% likely to be a spammer/proxy, 0.8 is 80%, etc) anything equal to or higher then this number triggers an admin warning diff --git a/interface/skin.dmf b/interface/skin.dmf index f9fa3f4a69a48..335caf261184d 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -631,7 +631,7 @@ menu "menu" elem name = "" category = "&File" - elem + elem "reconnectbutton" name = "&Reconnect" category = "&File" command = ".reconnect"