View Single Post
  #1  
Old 03-24-2008, 06:48 PM
TheLieka
Developer
 
Join Date: Oct 2004
Location: THE ATL (wut wut)
Posts: 325
Default Limiting client connections by IP address (Integrated into Rules System)

I've seen several people asking / talking about limiting client connections by IP address lately, so I figure I'd just post my implementation of it. Give it a try and let me know what you think.

.\common\ruletypes.h


Change:
Code:
RULE_CATEGORY( World )
RULE_INT ( World, ZoneAutobootTimeoutMS, 60000 )
RULE_INT ( World, ClientKeepaliveTimeoutMS, 65000 )
RULE_CATEGORY_END()
To:
Code:
RULE_CATEGORY( World )
RULE_INT ( World, ZoneAutobootTimeoutMS, 60000 )
RULE_INT ( World, ClientKeepaliveTimeoutMS, 65000 )
RULE_INT ( World, MaxClientsPerIP, -1 ) //Lieka Edit: Maximum number of clients allowed to connect per IP address.  Default value: -1 (feature disabled)
RULE_INT ( World, ExemptMaxClientsStatus, -1 ) //Lieka Edit: Exempt accounts from the MaxClientsPerIP rule, if their status is >= this value.  Default value: -1 (feature disabled)
RULE_CATEGORY_END()

.\world\clientlist.h


Change:
Code:
void	ClientUpdate(ZoneServer* zoneserver, ServerClientList_Struct* scl);
void	CLERemoveZSRef(ZoneServer* iZS);
ClientListEntry* CheckAuth(int32 iLSID, const char* iKey);
ClientListEntry* CheckAuth(const char* iName, const char* iPassword);
ClientListEntry* CheckAuth(int32 id, const char* iKey, int32 ip);
ClientListEntry* FindCharacter(const char* name);
ClientListEntry* FindCLEByAccountID(int32 iAccID);
ClientListEntry* FindCLEByCharacterID(int32 iAccID);
ClientListEntry* GetCLE(int32 iID);
void	CLCheckStale();
void	CLEKeepAlive(int32 numupdates, int32* wid);
void	CLEAdd(int32 iLSID, const char* iLoginName, const char* iLoginKey, sint16 iWorldAdmin = 0, int32 ip = 0, uint8 local=0);
void	UpdateClientGuild(int32 char_id, int32 guild_id);
To:

Code:
void	ClientUpdate(ZoneServer* zoneserver, ServerClientList_Struct* scl);
void	CLERemoveZSRef(ZoneServer* iZS);
ClientListEntry* CheckAuth(int32 iLSID, const char* iKey);
ClientListEntry* CheckAuth(const char* iName, const char* iPassword);
ClientListEntry* CheckAuth(int32 id, const char* iKey, int32 ip);
ClientListEntry* FindCharacter(const char* name);
ClientListEntry* FindCLEByAccountID(int32 iAccID);
ClientListEntry* FindCLEByCharacterID(int32 iAccID);
ClientListEntry* GetCLE(int32 iID);
void	GetCLEIP(int32 iIP);
void	CLCheckStale();
void	CLEKeepAlive(int32 numupdates, int32* wid);
void	CLEAdd(int32 iLSID, const char* iLoginName, const char* iLoginKey, sint16 iWorldAdmin = 0, int32 ip = 0, uint8 local=0);
void	UpdateClientGuild(int32 char_id, int32 guild_id);
.\world\clientlist.cpp

After:
Code:
void ClientList::CLERemoveZSRef(ZoneServer* iZS) {
	LinkedListIterator<ClientListEntry*> iterator(clientlist);

	iterator.Reset();
	while(iterator.MoreElements()) {
		if (iterator.GetData()->Server() == iZS) {
			iterator.GetData()->ClearServer(); // calling this before LeavingZone() makes CLE not update the number of players in a zone
			iterator.GetData()->LeavingZone();
		}
		iterator.Advance();
	}
}

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:
Code:
 //Lieka Edit Begin:  Check current CLE Entry IPs against incoming connection

void ClientList::GetCLEIP(int32 iIP) {
	ClientListEntry* countCLEIPs = 0;
	LinkedListIterator<ClientListEntry*> iterator(clientlist);

	int IPInstances = 0;
	iterator.Reset();
	while(iterator.MoreElements()) {
		countCLEIPs = iterator.GetData();
		if ((countCLEIPs->GetIP() == iIP) && ((countCLEIPs->Admin() <= (RuleI(World, ExemptMaxClientsStatus))) || (RuleI(World, ExemptMaxClientsStatus) < 0)) {
			IPInstances++;
			if (IPInstances > (RuleI(World, MaxClientsPerIP)){
				countCLEIPs->SetOnline(CLE_Status_Offline);
				iterator.RemoveCurrent();
			}
		}
		iterator.Advance();
	}
}
//Lieka Edit End

.\world\client.cpp


After:
Code:
		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:
Code:

if (RuleI(World, MaxClientsPerIP) >= 0) {
client_list.GetCLEIP(this->GetIP());  //Lieka Edit Begin:  Check current CLE Entry IPs against incoming connection
}
Required SQL:
Code:
Insert into rule_values values (0, 'World:MaxClientsPerIP', -1);
Insert into rule_values values (0, 'World:ExemptMaxClientsStatus', -1);
There are 2 new rule values.
World:MaxClientsPerIP = Maximum number of simultaneous EQ Client connections allowed per IP address. Set the rule value to -1 to disable this feature.
World:ExemptMaxClientsStatus = Minimum Account status to exempt the MaxClientsPerIP rule. This is helpful for the inevitable random family of 16 that live together, and all want to play on your server, as well as GMs, Devs, and QA staff. Again, set the rule value to -1 to disable this feature.

It's commented throughout, but let me know if you have questions.

Thanks,
Dax
__________________
Daxum



Former ServerOp - Vallon Zek / Tallon Zek Emu Server - Legit / Guild PvP - (2007 - 2011 RIP)

Last edited by KLS; 06-15-2008 at 01:08 PM..