Permalink
Browse files

Core/PacketIO: Implemented possibility to ban client addons serverside

  • Loading branch information...
1 parent 140614b commit d24ef896dfd9932ca8b74b5683fdda71b77f0287 @Shauren Shauren committed Apr 5, 2013
@@ -214,6 +214,32 @@ LOCK TABLES `auctionhouse` WRITE;
UNLOCK TABLES;
--
+-- Table structure for table `banned_addons`
+--
+
+DROP TABLE IF EXISTS `banned_addons`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `banned_addons` (
+ `Id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+ `Name` varchar(255) NOT NULL,
+ `Version` varchar(255) NOT NULL DEFAULT '',
+ `Timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`Id`),
+ UNIQUE KEY `idx_name_ver` (`Name`, `Version`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `banned_addons`
+--
+
+LOCK TABLES `banned_addons` WRITE;
+/*!40000 ALTER TABLE `banned_addons` DISABLE KEYS */;
+/*!40000 ALTER TABLE `banned_addons` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
-- Table structure for table `bugreport`
--
@@ -0,0 +1,9 @@
+DROP TABLE IF EXISTS `banned_addons`;
+CREATE TABLE `banned_addons` (
+ `Id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+ `Name` varchar(255) NOT NULL,
+ `Version` varchar(255) NOT NULL DEFAULT '',
+ `Timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`Id`),
+ UNIQUE KEY `idx_name_ver` (`Name`, `Version`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@@ -18,10 +18,10 @@
#include "AddonMgr.h"
#include "DatabaseEnv.h"
+#include "DBCStores.h"
#include "Log.h"
#include "Timer.h"
-
-#include <list>
+#include <openssl/md5.h>
namespace AddonMgr
{
@@ -34,35 +34,66 @@ namespace
typedef std::list<SavedAddon> SavedAddonsList;
SavedAddonsList m_knownAddons;
+
+ BannedAddonList m_bannedAddons;
}
void LoadFromDB()
{
uint32 oldMSTime = getMSTime();
QueryResult result = CharacterDatabase.Query("SELECT name, crc FROM addons");
- if (!result)
+ if (result)
{
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 known addons. DB table `addons` is empty!");
- return;
- }
+ uint32 count = 0;
- uint32 count = 0;
+ do
+ {
+ Field* fields = result->Fetch();
- do
- {
- Field* fields = result->Fetch();
+ std::string name = fields[0].GetString();
+ uint32 crc = fields[1].GetUInt32();
- std::string name = fields[0].GetString();
- uint32 crc = fields[1].GetUInt32();
+ m_knownAddons.push_back(SavedAddon(name, crc));
- m_knownAddons.push_back(SavedAddon(name, crc));
+ ++count;
+ }
+ while (result->NextRow());
- ++count;
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u known addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
- while (result->NextRow());
+ else
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 known addons. DB table `addons` is empty!");
+
+ oldMSTime = getMSTime();
+ result = CharacterDatabase.Query("SELECT id, name, version, UNIX_TIMESTAMP(timestamp) FROM banned_addons");
+ if (result)
+ {
+ uint32 count = 0;
+ uint32 dbcMaxBannedAddon = sBannedAddOnsStore.GetNumRows();
+
+ do
+ {
+ Field* fields = result->Fetch();
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u known addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+ BannedAddon addon;
+ addon.Id = fields[0].GetUInt32() + dbcMaxBannedAddon;
+ addon.Timestamp = uint32(fields[3].GetUInt64());
+
+ std::string name = fields[1].GetString();
+ std::string version = fields[2].GetString();
+
+ MD5(reinterpret_cast<uint8 const*>(name.c_str()), name.length(), addon.NameMD5);
+ MD5(reinterpret_cast<uint8 const*>(version.c_str()), version.length(), addon.VersionMD5);
+
+ m_bannedAddons.push_back(addon);
+
+ ++count;
+ }
+ while (result->NextRow());
+
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u banned addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+ }
}
void SaveAddon(AddonInfo const& addon)
@@ -91,4 +122,9 @@ SavedAddon const* GetAddonInfo(const std::string& name)
return NULL;
}
+BannedAddonList const* GetBannedAddons()
+{
+ return &m_bannedAddons;
+}
+
} // Namespace
@@ -21,6 +21,7 @@
#include "Define.h"
#include <string>
+#include <list>
struct AddonInfo
{
@@ -37,7 +38,7 @@ struct AddonInfo
struct SavedAddon
{
- SavedAddon(const std::string& name, uint32 crc) : Name(name)
+ SavedAddon(std::string const& name, uint32 crc) : Name(name)
{
CRC = crc;
}
@@ -46,13 +47,24 @@ struct SavedAddon
uint32 CRC;
};
-#define STANDARD_ADDON_CRC 0x4c1c776d
+struct BannedAddon
+{
+ uint32 Id;
+ uint8 NameMD5[16];
+ uint8 VersionMD5[16];
+ uint32 Timestamp;
+};
+
+#define STANDARD_ADDON_CRC 0x4C1C776D
namespace AddonMgr
{
void LoadFromDB();
void SaveAddon(AddonInfo const& addon);
SavedAddon const* GetAddonInfo(const std::string& name);
+
+ typedef std::list<BannedAddon> BannedAddonList;
+ BannedAddonList const* GetBannedAddons();
}
#endif
@@ -61,6 +61,7 @@ DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore(AchievementCrite
DBCStorage <AreaTriggerEntry> sAreaTriggerStore(AreaTriggerEntryfmt);
DBCStorage <AuctionHouseEntry> sAuctionHouseStore(AuctionHouseEntryfmt);
DBCStorage <BankBagSlotPricesEntry> sBankBagSlotPricesStore(BankBagSlotPricesEntryfmt);
+DBCStorage <BannedAddOnsEntry> sBannedAddOnsStore(BannedAddOnsfmt);
DBCStorage <BattlemasterListEntry> sBattlemasterListStore(BattlemasterListEntryfmt);
DBCStorage <BarberShopStyleEntry> sBarberShopStyleStore(BarberShopStyleEntryfmt);
DBCStorage <CharStartOutfitEntry> sCharStartOutfitStore(CharStartOutfitEntryfmt);
@@ -286,6 +287,7 @@ void LoadDBCStores(const std::string& dataPath)
LoadDBC(availableDbcLocales, bad_dbc_files, sAreaPOIStore, dbcPath, "AreaPOI.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sAuctionHouseStore, dbcPath, "AuctionHouse.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sBankBagSlotPricesStore, dbcPath, "BankBagSlotPrices.dbc");
+ LoadDBC(availableDbcLocales, bad_dbc_files, sBannedAddOnsStore, dbcPath, "BannedAddOns.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sBattlemasterListStore, dbcPath, "BattlemasterList.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sBarberShopStyleStore, dbcPath, "BarberShopStyle.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sCharStartOutfitStore, dbcPath, "CharStartOutfit.dbc");
@@ -75,6 +75,7 @@ extern DBCStorage <AreaPOIEntry> sAreaPOIStore;
extern DBCStorage <AreaTriggerEntry> sAreaTriggerStore;
extern DBCStorage <AuctionHouseEntry> sAuctionHouseStore;
extern DBCStorage <BankBagSlotPricesEntry> sBankBagSlotPricesStore;
+extern DBCStorage <BannedAddOnsEntry> sBannedAddOnsStore;
extern DBCStorage <BarberShopStyleEntry> sBarberShopStyleStore;
extern DBCStorage <BattlemasterListEntry> sBattlemasterListStore;
extern DBCStorage <ChatChannelsEntry> sChatChannelsStore;
@@ -596,6 +596,15 @@ struct BankBagSlotPricesEntry
uint32 price;
};
+struct BannedAddOnsEntry
+{
+ uint32 Id;
+ // uint32 NameMD5[4];
+ // uint32 VersionMD5[4];
+ // uint32 Timestamp;
+ // uint32 State;
+};
+
struct BarberShopStyleEntry
{
uint32 Id; // 0
@@ -29,6 +29,7 @@ char const AreaPOIEntryfmt[] = "niiiiiiiiiiifffixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
char const AreaTriggerEntryfmt[] = "niffffffff";
char const AuctionHouseEntryfmt[] = "niiixxxxxxxxxxxxxxxxx";
char const BankBagSlotPricesEntryfmt[] = "ni";
+char const BannedAddOnsfmt[] = "nxxxxxxxxxx";
char const BarberShopStyleEntryfmt[] = "nixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiii";
char const BattlemasterListEntryfmt[] = "niiiiiiiiixssssssssssssssssxiixx";
char const CharStartOutfitEntryfmt[] = "dbbbXiiiiiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
@@ -960,12 +960,7 @@ void WorldSession::ReadAddonsInfo(WorldPacket &data)
SavedAddon const* savedAddon = AddonMgr::GetAddonInfo(addonName);
if (savedAddon)
{
- bool match = true;
-
if (addon.CRC != savedAddon->CRC)
- match = false;
-
- if (!match)
sLog->outInfo(LOG_FILTER_GENERAL, "ADDON: %s was known, but didn't match known CRC (0x%x)!", addon.Name.c_str(), savedAddon->CRC);
else
sLog->outInfo(LOG_FILTER_GENERAL, "ADDON: %s was known, CRC is correct (0x%x)", addon.Name.c_str(), savedAddon->CRC);
@@ -984,9 +979,6 @@ void WorldSession::ReadAddonsInfo(WorldPacket &data)
uint32 currentTime;
addonInfo >> currentTime;
sLog->outDebug(LOG_FILTER_NETWORKIO, "ADDON: CurrentTime: %u", currentTime);
-
- if (addonInfo.rpos() != addonInfo.size())
- sLog->outDebug(LOG_FILTER_NETWORKIO, "packet under-read!");
}
else
sLog->outError(LOG_FILTER_GENERAL, "Addon packet uncompress error!");
@@ -1037,18 +1029,23 @@ void WorldSession::SendAddonsInfo()
data << uint32(0); /// @todo Find out the meaning of this.
}
- uint8 unk3 = 0; // 0 is sent here
- data << uint8(unk3);
- if (unk3)
- {
- // String, length 256 (null terminated)
- data << uint8(0);
- }
+ data << uint8(0); // uses URL
+ //if (usesURL)
+ // data << uint8(0); // URL
}
m_addonsList.clear();
- data << uint32(0); // count for an unknown for loop
+ AddonMgr::BannedAddonList const* bannedAddons = AddonMgr::GetBannedAddons();
+ data << uint32(bannedAddons->size());
+ for (AddonMgr::BannedAddonList::const_iterator itr = bannedAddons->begin(); itr != bannedAddons->end(); ++itr)
+ {
+ data << uint32(itr->Id);
+ data.append(itr->NameMD5, sizeof(itr->NameMD5));
+ data.append(itr->VersionMD5, sizeof(itr->VersionMD5));
+ data << uint32(itr->Timestamp);
+ data << uint32(1); // IsBanned
+ }
SendPacket(&data);
}

10 comments on commit d24ef89

Contributor

soulfrost replied Apr 5, 2013

BannedAddOnsfmt[] = "nxxxxxxxxxx";
+struct BannedAddOnsEntry
+{

  • uint32 Id;
  • // uint32 NameMD5[4];
  • // uint32 VersionMD5[4];
  • // uint32 Timestamp;
  • // uint32 State;
    +};

still not done?

Member

Shauren replied Apr 5, 2013

@soulforst: that DBC is unused serverside (client handles it). I only needed to load it to get max entry from it

Contributor

soulfrost replied Apr 5, 2013

What about blocking addons not available at the time of 3.3.5 on the official server?

Contributor

SignFinder replied Apr 8, 2013

How add cheat addons to table?

how does it work in general indeed?? for example if i ant to ban gearscore?

Contributor

Jayz33 replied Apr 9, 2013

Example to block GearScoreLite version 3x04:

INSERT INTO `banned_addons` (
`Id` ,
`Name` ,
`Version` ,
`Timestamp`
)
VALUES (
NULL ,  'GearScoreLite',  '3x04', 
CURRENT_TIMESTAMP
);


AddOn name = the name of the addon folder (NOT NECESSARILY THE ADDON TITLE!)
Version = the value of the version property in the .TOC file of the addOn e.g. GearScoreLite.toc:
# Interface: 30300
# Title: GearScoreLite
# Notes: Quickly and easily judge a player's level of Gear.
# Version: 3x04
# Author: Mirrikat45
Member

Shauren replied Apr 9, 2013

You can also leave version as empty string - matches all versions then

Contributor

Zakamurite replied Apr 10, 2013

what about addons with non-standart titles like this?

## Interface: 20400
## Author: Kydori
## Name: Aesa
## Title: Aesa |cff7fff7f0.9.2|r
## Notes: Enemy cooldown tracker.
## Notes-zhCN: µР¶ФАдИґјЖК±Жч.
## DefaultState: Enabled
## OptionalDeps: Ace3, LibSharedMedia-3.0
## SavedVariables: AesaDB
## Version: 0.9.2
## X-Embeds: Ace3, LibSharedMedia-3.0
## X-Category: Combat
## X-eMail: kydori@gmail.com
Contributor

Subv replied Apr 10, 2013

@Zakamurite The name of the containing folder

Member

Shauren replied Apr 10, 2013

Or the name of .toc file without extension (must be the same as folder name anyway, but hey, i can tell you that)

Please sign in to comment.