PDA

View Full Version : Banning IPs at the World Server (Integrated into Rules)


TheLieka
03-26-2008, 05:59 PM
I want to preface that I have not tested this code. I do believe that it will accomplish its goal (and I know that it compiles), but I don't have a dev server up to test it at the moment.

Give it a shot and let me know what you think.

.\common\database.h

Change:

bool CheckNameFilter(const char* name);
bool CheckUsedName(const char* name);
int32 GetAccountIDByChar(const char* charname, int32* oCharID = 0);
uint32 GetAccountIDByChar(uint32 char_id);
int32 GetAccountIDByName(const char* accname, sint16* status = 0, int32* lsid = 0);
void GetAccountName(int32 accountid, char* name, int32* oLSAccountID = 0);
void GetCharName(int32 char_id, char* name);
int32 GetCharacterInfo(const char* iName, int32* oAccID = 0, int32* oZoneID = 0, float* oX = 0, float* oY = 0, float* oZ = 0);
int32 GetCharacterID(const char *name);

To:

bool CheckNameFilter(const char* name);
bool CheckUsedName(const char* name);
int32 GetAccountIDByChar(const char* charname, int32* oCharID = 0);
uint32 GetAccountIDByChar(uint32 char_id);
int32 GetAccountIDByName(const char* accname, sint16* status = 0, int32* lsid = 0);
void GetAccountName(int32 accountid, char* name, int32* oLSAccountID = 0);
void GetCharName(int32 char_id, char* name);
int32 GetCharacterInfo(const char* iName, int32* oAccID = 0, int32* oZoneID = 0, float* oX = 0, float* oY = 0, float* oZ = 0);
int32 GetCharacterID(const char *name);
bool CheckBannedIPs(int32 loginIP); //Lieka Edit: Check incomming connection against banned IP table.



.\common\database.cpp


After:

int32 Database::CheckLogin(const char* name, const char* password, sint16* oStatus) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;

if(strlen(name) >= 50 || strlen(password) >= 50)
return(0);

char tmpUN[100];
char tmpPW[100];
DoEscapeString(tmpUN, name, strlen(name));
DoEscapeString(tmpPW, password, strlen(password));

if (RunQuery(query, MakeAnyLenString(&query,
"SELECT id, status FROM account WHERE name='%s' AND password is not null "
"and length(password) > 0 and (password='%s' or password=MD5('%s'))",
tmpUN, tmpPW, tmpPW), errbuf, &result)) {
safe_delete_array(query);
if (mysql_num_rows(result) == 1)
{
row = mysql_fetch_row(result);
int32 id = atoi(row[0]);
if (oStatus)
*oStatus = atoi(row[1]);
mysql_free_result(result);
return id;
}
else
{
mysql_free_result(result);
return 0;
}
mysql_free_result(result);
}
else
{
cerr << "Error in CheckLogin query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return false;
}

return 0;
}


Add:

//Lieka Edit: Get Banned IP Address List - Only return false if the incoming connection's IP address is not present in the banned_ips table.
bool Database::CheckBannedIPs(int32 loginIP)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;

if (RunQuery(query, MakeAnyLenString(&query, "SELECT ip_address FROM Banned_IPs WHERE ip_address='%i'", loginIP), errbuf, &result)) {
safe_delete_array(query);
if (mysql_num_rows(result) == 1)
{
mysql_free_result(result);
return true;
}
else
{
mysql_free_result(result);
return false;
}
mysql_free_result(result);
}
else
{
cerr << "Error in CheckBannedIPs query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return true;
}

return true;
}
//End Lieka Edit

.\world\client.cpp

After:
case OP_EnterWorld: // Enter world
{
if (GetAccountID() == 0) {
clog(WORLD__CLIENT_ERR,"Enter world with no logged in account");
eqs->Close();
break;
}
if(GetAdmin() < 0)
{
clog(WORLD__CLIENT,"Account banned or suspended.");
eqs->Close();
break;
}

Add:

//Lieka Edit Begin
if (RuleI(World, UseBannedIPsTable) == 1) {
if (database.CheckBannedIPs(this->GetIP())) {//Lieka Edit: Check banned_ips table against incoming connection
client_list.RemoveBannedIPs(this->GetIP()); //Lieka Edit: Terminate all sessions with this IP address.
clog(WORLD__CLIENT,"IP Address banned.");
}
}//Lieka Edit End


.\world\clientlist.h

After:

ClientListEntry* GetCLE(int32 iID);

Add:

void RemoveBannedIPs(int32 bIP); //Lieka Edit



.\world\clientlist.cpp

After:

ClientListEntry* ClientList::GetCLE(int32 iID) {
LinkedListIterator<ClientListEntry*> iterator(clientlist);


iterator.Reset();
while(iterator.MoreElements()) {
if (iterator.GetData()->GetID() == iID) {
return iterator.GetData();
}
iterator.Advance();
}
return 0;
}

Add:

//Lieka Edit Begin: Terminate all active sessions that exist with a banned IP.
void ClientList::RemoveBannedIPs(int32 bIP) {
ClientListEntry* countCLEIPs = 0;
LinkedListIterator<ClientListEntry*> iterator(clientlist);

iterator.Reset();
while (iterator.MoreElements()) {
countCLEIPs = iterator.GetData();
if (countCLEIPs->GetIP() == bIP) {
countCLEIPs->SetOnline(CLE_Status_Offline);
iterator.RemoveCurrent();
}
iterator.Advance();
}
}
//Lieka Edit End

Required SQL:
CREATE TABLE `Banned_IPs` (
`ip_address` VARCHAR(32) NOT NULL,
PRIMARY KEY (`ip_address`)
)
ENGINE = InnoDB;

Insert into rule_values values (0, 'World:UseBannedIPsTable', 0);

There is 1 new rule created from this:
World:UseBannedIPsTable = Toggle whether or not to check incoming client connections against the Banned_IPs table. Set this value to 0 to disable this feature.

There is 1 table created from this:
Banned_IPs = this table has 1 column "ip_address". Place IP addresses into this field that should be denied access to your server.

If this code works well, I will create an in-game "#ipban <charname>" command to accompany it.

Thanks,
Dax

Semedaien
03-27-2008, 08:42 AM
very nice job, will let ya know how it works

leslamarch
03-27-2008, 09:39 AM
heya Dax,
For this to work wouldn't you need to place this RULE_INT ( World, UseBannedIPsTable, 0 ) in ruletypes.h ? or did i missing something.
Please correct me if I'm wrong.

TheLieka
03-27-2008, 09:42 AM
You're right, it's in my code, but I missed it when I was doing my diff. Thanks Les.

Dax

TheLieka
04-19-2008, 12:33 AM
Ok, I apologize for letting these submissions sit here unfixed for a couple of weeks, but the good news is, I've had some time this week to make some necessary adjustments.

I basically completely reworked the way I was looking at IP banning - this way happens earlier and before the connection is added to the CLE, so it should be better for performance, etc (plus it actually works, where the other one didn't).

Here's the run-down:
Added Rule: World:UseBannedIPsTable (default value: false (feature disabled))
Added #Command: #ipban (default status 200).
Syntax: #ipban [ip address]
When #ipban adds an IP into the Banned_IPs table, it also adds the GM's name to the "notes" section.

Let me know what you think.

Required SQL:
CREATE TABLE `banned_ips` (
`ip_address` varchar(32) NOT NULL,
`notes` varchar(32) default NULL,
PRIMARY KEY (`ip_address`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

insert into rule_values values (0, 'World:UseBannedIPsTable', 'true');
insert into commands values ('ipban', 200);

This diff was taken against 0.7.0-1106
diff C:/1106/zone/command.h C:/vztz/zone/command.h
231a232
> void command_ipban(Client *c, const Seperator *sep);
diff C:/1106/zone/command.cpp C:/vztz/zone/command.cpp
362a363
> command_add("ipban","[IP Address] - Ban IP by character name",200,command_ipban) ||
1366a1368
> t->CastToClient()->cheat_timer.Start(3500,false); //Lieka: Prevent Zone-to-Zone GM Summons from triggering the MQZone and MQWarp detectors.
1412c1414
< if (sep->IsNumber(2) || sep->IsNumber(3) || sep->IsNumber(4))
---
> if (sep->IsNumber(2) || sep->IsNumber(3) || sep->IsNumber(4)) {
1413a1416
> c->CastToClient()->cheat_timer.Start(3500,false); //Lieka: Not sure why we put this here... should be an admin if you are zoning to special coordinates by this point.
1414a1418
> }
5149a5154,5168
>
> void command_ipban(Client *c, const Seperator *sep)
> {
> if(sep->arg[1] == 0)
> {
> c->Message(0, "Usage: #ipban [xxx.xxx.xxx.xxx]");
> } else {
> if(database.AddBannedIP(sep->arg[1], c->GetName())) {
> c->Message(0, "%s has been successfully added to the Banned_IPs table by %s",sep->arg[1], c->GetName());
> } else {
> c->Message(0, "IPBan Failed (IP address is possibly already in the table?)");
> }
> }
> }
>
diff C:/1106/world/net.cpp C:/vztz/world/net.cpp
361,364c361,378
< _log(WORLD__CLIENT, "New client from %s:%d", inet_ntoa(in), ntohs(eqsi->GetRemotePort()));
< Client* client = new Client(eqsi);
< // @merth: client->zoneattempt=0;
< client_list.Add(client);
---
> if (RuleB(World, UseBannedIPsTable)){ //Lieka: Check to see if we have the responsibility for blocking IPs.
> _log(WORLD__CLIENT, "Checking inbound connection %s against BannedIPs table", inet_ntoa(in));
> if (!database.CheckBannedIPs(inet_ntoa(in))){ //Lieka: Check inbound IP against banned IP table.
> _log(WORLD__CLIENT, "Connection %s PASSED banned IPs check. Processing connection.", inet_ntoa(in));
> Client* client = new Client(eqsi);
> // @merth: client->zoneattempt=0;
> client_list.Add(client);
> } else {
> _log(WORLD__CLIENT, "Connection from %s FAILED banned IPs check. Closing connection.", inet_ntoa(in));
> eqsi->Close(); //Lieka: If the inbound IP is on the banned table, close the EQStream.
> }
> }
> if (!RuleB(World, UseBannedIPsTable)){
> _log(WORLD__CLIENT, "New connection from %s:%d, processing connection", inet_ntoa(in), ntohs(eqsi->GetRemotePort()));
> Client* client = new Client(eqsi);
> // @merth: client->zoneattempt=0;
> client_list.Add(client);
> }
diff C:/1106/common/ruletypes.h C:/vztz/common/ruletypes.h
69a70
> RULE_BOOL ( World, UseBannedIPsTable, false ) //Lieka Edit: Check banned IP table before accepting connections to the world server. Default value: false (feature disabled)
diff C:/1106/common/database.h C:/vztz/common/database.h
139a140,141
> bool CheckBannedIPs(const char* loginIP); //Lieka Edit: Check incomming connection against banned IP table.
> bool AddBannedIP(char* bannedIP, const char* notes); //Lieka Edit: Add IP address to the Banned_IPs table.
diff C:/1106/common/database.cpp C:/vztz/common/database.cpp
207a208,257
> //Lieka: Get Banned IP Address List - Only return false if the incoming connection's IP address is not present in the banned_ips table.
> bool Database::CheckBannedIPs(const char* loginIP)
> {
> char errbuf[MYSQL_ERRMSG_SIZE];
> char *query = 0;
> MYSQL_RES *result;
> MYSQL_ROW row;
> //cout << "Checking against Banned IPs table."<< endl; //Lieka: Debugging
> if (RunQuery(query, MakeAnyLenString(&query, "SELECT ip_address FROM Banned_IPs WHERE ip_address='%s'", loginIP), errbuf, &result)) {
> safe_delete_array(query);
> if (mysql_num_rows(result) != 0)
> {
> //cout << loginIP << " was present in the banned IPs table" << endl; //Lieka: Debugging
> mysql_free_result(result);
> return true;
> }
> else
> {
> //cout << loginIP << " was not present in the banned IPs table." << endl; //Lieka: Debugging
> mysql_free_result(result);
> return false;
> }
> mysql_free_result(result);
> }
> else
> {
> cerr << "Error in CheckBannedIPs query '" << query << "' " << errbuf << endl;
> safe_delete_array(query);
> return true;
> }
>
> return true;
> }
>
> bool Database::AddBannedIP(char* bannedIP, const char* notes)
> {
> char errbuf[MYSQL_ERRMSG_SIZE];
> char *query = 0;
>
> if (!RunQuery(query, MakeAnyLenString(&query, "INSERT into Banned_IPs SET ip_address='%s', notes='%s'", bannedIP, notes), errbuf)) {
> cerr << "Error in ReserveName query '" << query << "' " << errbuf << endl;
> safe_delete_array(query);
> return false;
> }
> safe_delete_array(query);
> return true;
> }
>
> //End Lieka Edit
>
1458c1508
< return true;
---
> return true;

Dax

P.S. I would have just updated the thread in the submission forum, but it's locked. ;)

TheLieka
04-19-2008, 12:47 AM
Correction: Part of the MQWarp detector code got caught in the last diff. ;) Here's the diff without that part.

diff C:/1106/zone/command.h C:/vztz/zone/command.h
231a232
> void command_ipban(Client *c, const Seperator *sep);
diff C:/1106/zone/command.cpp C:/vztz/zone/command.cpp
362a363
> command_add("ipban","[IP address] - Ban IP by character name",200,command_ipban) ||
1366a1368
>
> void command_ipban(Client *c, const Seperator *sep)
> {
> if(sep->arg[1] == 0)
> {
> c->Message(0, "Usage: #ipban [xxx.xxx.xxx.xxx]");
> } else {
> if(database.AddBannedIP(sep->arg[1], c->GetName())) {
> c->Message(0, "%s has been successfully added to the Banned_IPs table by %s",sep->arg[1], c->GetName());
> } else {
> c->Message(0, "IPBan Failed (IP address is possibly already in the table?)");
> }
> }
> }
>
diff C:/1106/world/net.cpp C:/vztz/world/net.cpp
361,364c361,378
< _log(WORLD__CLIENT, "New client from %s:%d", inet_ntoa(in), ntohs(eqsi->GetRemotePort()));
< Client* client = new Client(eqsi);
< // @merth: client->zoneattempt=0;
< client_list.Add(client);
---
> if (RuleB(World, UseBannedIPsTable)){ //Lieka: Check to see if we have the responsibility for blocking IPs.
> _log(WORLD__CLIENT, "Checking inbound connection %s against BannedIPs table", inet_ntoa(in));
> if (!database.CheckBannedIPs(inet_ntoa(in))){ //Lieka: Check inbound IP against banned IP table.
> _log(WORLD__CLIENT, "Connection %s PASSED banned IPs check. Processing connection.", inet_ntoa(in));
> Client* client = new Client(eqsi);
> // @merth: client->zoneattempt=0;
> client_list.Add(client);
> } else {
> _log(WORLD__CLIENT, "Connection from %s FAILED banned IPs check. Closing connection.", inet_ntoa(in));
> eqsi->Close(); //Lieka: If the inbound IP is on the banned table, close the EQStream.
> }
> }
> if (!RuleB(World, UseBannedIPsTable)){
> _log(WORLD__CLIENT, "New connection from %s:%d, processing connection", inet_ntoa(in), ntohs(eqsi->GetRemotePort()));
> Client* client = new Client(eqsi);
> // @merth: client->zoneattempt=0;
> client_list.Add(client);
> }
diff C:/1106/common/ruletypes.h C:/vztz/common/ruletypes.h
69a70
> RULE_BOOL ( World, UseBannedIPsTable, false ) //Lieka Edit: Check banned IP table before accepting connections to the world server. Default value: false (feature disabled)
diff C:/1106/common/database.h C:/vztz/common/database.h
139a140,141
> bool CheckBannedIPs(const char* loginIP); //Lieka Edit: Check incomming connection against banned IP table.
> bool AddBannedIP(char* bannedIP, const char* notes); //Lieka Edit: Add IP address to the Banned_IPs table.
diff C:/1106/common/database.cpp C:/vztz/common/database.cpp
207a208,257
> //Lieka: Get Banned IP Address List - Only return false if the incoming connection's IP address is not present in the banned_ips table.
> bool Database::CheckBannedIPs(const char* loginIP)
> {
> char errbuf[MYSQL_ERRMSG_SIZE];
> char *query = 0;
> MYSQL_RES *result;
> MYSQL_ROW row;
> //cout << "Checking against Banned IPs table."<< endl; //Lieka: Debugging
> if (RunQuery(query, MakeAnyLenString(&query, "SELECT ip_address FROM Banned_IPs WHERE ip_address='%s'", loginIP), errbuf, &result)) {
> safe_delete_array(query);
> if (mysql_num_rows(result) != 0)
> {
> //cout << loginIP << " was present in the banned IPs table" << endl; //Lieka: Debugging
> mysql_free_result(result);
> return true;
> }
> else
> {
> //cout << loginIP << " was not present in the banned IPs table." << endl; //Lieka: Debugging
> mysql_free_result(result);
> return false;
> }
> mysql_free_result(result);
> }
> else
> {
> cerr << "Error in CheckBannedIPs query '" << query << "' " << errbuf << endl;
> safe_delete_array(query);
> return true;
> }
>
> return true;
> }
>
> bool Database::AddBannedIP(char* bannedIP, const char* notes)
> {
> char errbuf[MYSQL_ERRMSG_SIZE];
> char *query = 0;
>
> if (!RunQuery(query, MakeAnyLenString(&query, "INSERT into Banned_IPs SET ip_address='%s', notes='%s'", bannedIP, notes), errbuf)) {
> cerr << "Error in ReserveName query '" << query << "' " << errbuf << endl;
> safe_delete_array(query);
> return false;
> }
> safe_delete_array(query);
> return true;
> }
>
> //End Lieka Edit

Dax

Angelox
04-19-2008, 06:10 AM
Sorry, unlocked now and merged thread

TheLieka
04-19-2008, 10:41 AM
Thanks Angelox.

Scorpious2k
06-20-2008, 05:42 PM
This should magically appear in version 1116.

Scorpious2k
06-21-2008, 01:57 PM
Slight delay here, there are some inconsistencies among the different versions of the code here. I tried to sort it out, but it would really help if someone has the working versions of the programs involved with this code in that I could work with...

cavedude
06-21-2008, 05:17 PM
I'm not quite sure what you're asking, but everything needed for this patch is in post 6. All of the code in posts above that are broken/obsolete and not needed. If that's not what you need, I apologize for the misunderstanding :)

EDIT: I should also note, some of the incorrect code from above is in the stock EQEmu source, and needs to be removed prior to updating us with the diff in post 6.

Scorpious2k
06-21-2008, 05:58 PM
I should also note, some of the incorrect code from above is in the stock EQEmu source, and needs to be removed prior to updating us with the diff in post 6.

That's the problem. I was hoping someone had the programs from above that are correct so i could merge the new stuff in and the "bad" stuff out.

cavedude
06-21-2008, 06:52 PM
I have a diff worked out. The only problem is the format of world/clientlist.cpp is messed up, so when I edit I am unable to get a clean diff. When I work that out, I'll zip up the diff and the changed files and post.

cavedude
06-21-2008, 07:12 PM
Alright, this: http://projecteq.net/ipban.rar

Contains a diff of all required changes, as well as the changed files.

As I said above, world/clientlist.cpp has corrupt line endings, so when I edit the file diff wants to remove and recreate the whole file, so I left it out of the diff. The file is in that package though, and the only change to clientlist.cpp is to find this block of code:

//Lieka Edit Begin: Terminate all active sessions that exist with a banned IP.
void ClientList::RemoveBannedIPs(int32 bIP) {
ClientListEntry* countCLEIPs = 0;
LinkedListIterator<ClientListEntry*> iterator(clientlist);

iterator.Reset();
while (iterator.MoreElements()) {
countCLEIPs = iterator.GetData();
if (countCLEIPs->GetIP() == bIP) {
countCLEIPs->SetOnline(CLE_Status_Offline);
iterator.RemoveCurrent();
}
iterator.Advance();
}
}
//Lieka Edit End

and remove it, as it is no longer needed. Be carfeful not to remove the code above it, which is also Lieka's but is for the IP limiting system.

KLS
06-22-2008, 04:08 AM
Updated code applied.

Scorpious2k
06-22-2008, 10:36 AM
Updated code applied.

Thanks KLS. I had started this, but am going to be away from the computer most of the day so I am glad it got done. I hate seeing things sit undone (or half done)