about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMagnus Auvinen <magnus.auvinen@gmail.com>2009-01-10 10:27:25 +0000
committerMagnus Auvinen <magnus.auvinen@gmail.com>2009-01-10 10:27:25 +0000
commitb42eb557946ccfc271a4af0a7787681e2345789c (patch)
tree3f7f2febeb3895337f2f6a45df99dcd71f086c78
parentb281831d5d3c9eadb92f6a88355a9174c670b40e (diff)
downloadzcatch-b42eb557946ccfc271a4af0a7787681e2345789c.tar.gz
zcatch-b42eb557946ccfc271a4af0a7787681e2345789c.zip
finished the ban support
-rw-r--r--src/engine/e_if_server.h2
-rw-r--r--src/engine/e_network.c14
-rw-r--r--src/engine/e_network.h3
-rw-r--r--src/engine/e_network_conn.c12
-rw-r--r--src/engine/e_network_internal.h2
-rw-r--r--src/engine/e_network_server.c225
-rw-r--r--src/engine/server/es_server.c60
7 files changed, 220 insertions, 98 deletions
diff --git a/src/engine/e_if_server.h b/src/engine/e_if_server.h
index b165ae3c..1acd184c 100644
--- a/src/engine/e_if_server.h
+++ b/src/engine/e_if_server.h
@@ -135,6 +135,6 @@ int server_tick();
 */
 int server_tickspeed();
 
-int server_ban_add(NETADDR addr, int type, int seconds);
+int server_ban_add(NETADDR addr, int seconds);
 int server_ban_remove(NETADDR addr);
 #endif
diff --git a/src/engine/e_network.c b/src/engine/e_network.c
index 0999d189..2b4ed013 100644
--- a/src/engine/e_network.c
+++ b/src/engine/e_network.c
@@ -264,6 +264,20 @@ unsigned char *unpack_chunk_header(unsigned char *data, NETCHUNKHEADER *header)
 }
 
 
+void send_controlmsg(NETSOCKET socket, NETADDR *addr, int ack, int controlmsg, const void *extra, int extra_size)
+{
+	NETPACKETCONSTRUCT construct;
+	construct.flags = NET_PACKETFLAG_CONTROL;
+	construct.ack = ack;
+	construct.num_chunks = 0;
+	construct.data_size = 1+extra_size;
+	construct.chunk_data[0] = controlmsg;
+	mem_copy(&construct.chunk_data[1], extra, extra_size);
+	
+	/* send the control message */
+	send_packet(socket, addr, &construct);
+}
+
 void netcommon_openlog(const char *sentlog, const char *recvlog)
 {
 	if(sentlog)
diff --git a/src/engine/e_network.h b/src/engine/e_network.h
index d90bd42f..04453cf9 100644
--- a/src/engine/e_network.h
+++ b/src/engine/e_network.h
@@ -18,7 +18,6 @@ typedef struct
 typedef struct
 {
 	NETADDR addr;
-	int type;
 	int expires;
 } NETBANINFO;
 
@@ -72,7 +71,7 @@ int netserver_drop(NETSERVER *s, int client_id, const char *reason);
 int netserver_client_addr(NETSERVER *s, int client_id, NETADDR *addr);
 int netserver_max_clients(NETSERVER *s);
 
-int netserver_ban_add(NETSERVER *s, NETADDR addr, int type, int seconds);
+int netserver_ban_add(NETSERVER *s, NETADDR addr, int seconds);
 int netserver_ban_remove(NETSERVER *s, NETADDR addr);
 int netserver_ban_num(NETSERVER *s); /* caution, slow */
 int netserver_ban_get(NETSERVER *s, int index, NETBANINFO *info); /* caution, slow */
diff --git a/src/engine/e_network_conn.c b/src/engine/e_network_conn.c
index a8ef588f..1d241d06 100644
--- a/src/engine/e_network_conn.c
+++ b/src/engine/e_network_conn.c
@@ -129,19 +129,11 @@ void conn_queue_chunk(NETCONNECTION *conn, int flags, int data_size, const void
 	}
 }
 
+
 static void conn_send_control(NETCONNECTION *conn, int controlmsg, const void *extra, int extra_size)
 {
-	NETPACKETCONSTRUCT construct;
-	construct.flags = NET_PACKETFLAG_CONTROL;
-	construct.ack = conn->ack;
-	construct.num_chunks = 0;
-	construct.data_size = 1+extra_size;
-	construct.chunk_data[0] = controlmsg;
-	mem_copy(&construct.chunk_data[1], extra, extra_size);
-	
 	/* send the control message */
-	send_packet(conn->socket, &conn->peeraddr, &construct);
-	conn->last_send_time = time_get();
+	send_controlmsg(conn->socket, &conn->peeraddr, conn->ack, controlmsg, extra, extra_size);
 }
 
 static void conn_resend_chunk(NETCONNECTION *conn, NETCHUNKDATA *resend)
diff --git a/src/engine/e_network_internal.h b/src/engine/e_network_internal.h
index 704f4f4a..6c58ec88 100644
--- a/src/engine/e_network_internal.h
+++ b/src/engine/e_network_internal.h
@@ -127,6 +127,7 @@ typedef struct NETRECVINFO
 	unsigned char buffer[NET_MAX_PACKETSIZE];
 } NETRECVINFO;
 
+/* */
 
 /* connection functions */
 void conn_init(NETCONNECTION *conn, NETSOCKET socket);
@@ -145,6 +146,7 @@ void recvinfo_start(NETRECVINFO *info, NETADDR *addr, NETCONNECTION *conn, int c
 int recvinfo_fetch_chunk(NETRECVINFO *info, NETCHUNK *chunk);
 
 /* misc helper functions */
+void send_controlmsg(NETSOCKET socket, NETADDR *addr, int ack, int controlmsg, const void *extra, int extra_size);
 void send_packet_connless(NETSOCKET socket, NETADDR *addr, const void *data, int data_size);
 void send_packet(NETSOCKET socket, NETADDR *addr, NETPACKETCONSTRUCT *packet);
 int unpack_packet(unsigned char *buffer, int size, NETPACKETCONSTRUCT *packet);
diff --git a/src/engine/e_network_server.c b/src/engine/e_network_server.c
index 7e60a9ce..8ec65504 100644
--- a/src/engine/e_network_server.c
+++ b/src/engine/e_network_server.c
@@ -11,13 +11,38 @@ typedef struct NETBAN
 {
 	NETBANINFO info;
 	
+	/* hash list */
 	struct NETBAN *hashnext;
 	struct NETBAN *hashprev;
 	
+	/* used or free list */
 	struct NETBAN *next;
 	struct NETBAN *prev;
 } NETBAN;
 
+#define MACRO_LIST_LINK_FIRST(object, first, prev, next) \
+	{ if(first) first->prev = object; \
+	object->prev = (void*)0; \
+	object->next = first; \
+	first = object; }
+	
+#define MACRO_LIST_LINK_AFTER(object, after, prev, next) \
+	{ object->prev = after; \
+	object->next = after->next; \
+	after->next = object; \
+	if(object->next) \
+		object->next->prev = object; \
+	}
+
+#define MACRO_LIST_UNLINK(object, first, prev, next) \
+	{ if(object->next) object->next->prev = object->prev; \
+	if(object->prev) object->prev->next = object->next; \
+	else first = object->next; \
+	object->next = 0; object->prev = 0; }
+	
+#define MACRO_LIST_FIND(start, next, expression) \
+	{ while(start && !(expression)) start = start->next; }
+
 struct NETSERVER
 {
 	NETSOCKET socket;
@@ -129,78 +154,98 @@ int netserver_ban_num(NETSERVER *s)
 	return count;
 }
 
+static void netserver_ban_remove_by_object(NETSERVER *s, NETBAN *ban)
+{
+	int iphash = (ban->info.addr.ip[0]+ban->info.addr.ip[1]+ban->info.addr.ip[2]+ban->info.addr.ip[3])&0xff;
+	dbg_msg("netserver", "removing ban on %d.%d.%d.%d",
+		ban->info.addr.ip[0], ban->info.addr.ip[1], ban->info.addr.ip[2], ban->info.addr.ip[3]);
+	MACRO_LIST_UNLINK(ban, s->banpool_firstused, prev, next);
+	MACRO_LIST_UNLINK(ban, s->bans[iphash], hashprev, hashnext);
+	MACRO_LIST_LINK_FIRST(ban, s->banpool_firstfree, prev, next);
+}
+
 int netserver_ban_remove(NETSERVER *s, NETADDR addr)
 {
-	return 0;
+	int iphash = (addr.ip[0]+addr.ip[1]+addr.ip[2]+addr.ip[3])&0xff;
+	NETBAN *ban = s->bans[iphash];
+	
+	MACRO_LIST_FIND(ban, hashnext, net_addr_comp(&ban->info.addr, &addr) == 0);
+	
+	if(ban)
+	{
+		netserver_ban_remove_by_object(s, ban);
+		return 0;
+	}
+	
+	return -1;
 }
 
-int netserver_ban_add(NETSERVER *s, NETADDR addr, int type, int seconds)
+int netserver_ban_add(NETSERVER *s, NETADDR addr, int seconds)
 {
 	int iphash = (addr.ip[0]+addr.ip[1]+addr.ip[2]+addr.ip[3])&0xff;
-	unsigned stamp = time_timestamp() + seconds;
+	unsigned stamp = 0xffffffff;
 	NETBAN *ban;
-	NETBAN *insert_after;
 	
+	/* remove the port */
+	addr.port = 0;
+	
+	if(seconds)
+		stamp = time_timestamp() + seconds;
+		
 	/* search to see if it already exists */
-	for(ban = s->bans[iphash]; ban; ban = ban->hashnext)
+	ban = s->bans[iphash];
+	MACRO_LIST_FIND(ban, hashnext, net_addr_comp(&ban->info.addr, &addr) == 0);
+	if(ban)
 	{
-		if(net_addr_comp(&ban->info.addr, &addr) == 0)
-		{
-			if(ban->info.expires < stamp)
-			{
-				/* decide what to do here */
-			}
-			return -1;
-		}
+		/* adjust the ban */
+		ban->info.expires = stamp;
+		return 0;
 	}
 	
 	if(!s->banpool_firstfree)
 		return -1;
 
-	/* fetch and clear the new ban */	
+	/* fetch and clear the new ban */
 	ban = s->banpool_firstfree;
-	s->banpool_firstfree->prev = 0;
-	ban->next = 0;
-	ban->prev = 0;
-	ban->info.expires = 0;
-	if(seconds)
-		ban->info.expires = stamp;
-	ban->info.type = type;
+	MACRO_LIST_UNLINK(ban, s->banpool_firstfree, prev, next);
+	
+	/* setup the ban info */
+	ban->info.expires = stamp;
 	ban->info.addr = addr;
 	
 	/* add it to the ban hash */
-	if(s->bans[iphash])
-		s->bans[iphash]->hashprev = ban;
-	ban->hashnext = s->bans[iphash];
-	ban->hashprev = 0;
-	s->bans[iphash] = ban;
+	MACRO_LIST_LINK_FIRST(ban, s->bans[iphash], hashprev, hashnext);
 	
 	/* insert it into the used list */
-	insert_after = s->banpool_firstused;
-	while(insert_after)
 	{
-		if(!insert_after->next)
-			break;
-		if(insert_after->next->info.expires < stamp)
-			break;
-		insert_after = insert_after->next;
-	}
-	
-	if(!insert_after || insert_after->info.expires > stamp)
-	{
-		/* insert first */
-		s->banpool_firstused = ban;
-		ban->next = insert_after;
-		ban->prev = 0;
-	}
-	else
-	{
-		/* insert after */
-		ban->next = insert_after->next;
-		ban->prev = insert_after;
-		if(ban->next)
-			ban->next->prev = ban;
-		insert_after->next = ban;
+		if(s->banpool_firstused)
+		{
+			NETBAN *insert_after = s->banpool_firstused;
+			MACRO_LIST_FIND(insert_after, next, stamp < insert_after->info.expires);
+			
+			if(insert_after)
+				insert_after = insert_after->prev;
+			else
+			{
+				/* add to last */
+				insert_after = s->banpool_firstused;
+				while(insert_after->next)
+					insert_after = insert_after->next;
+			}
+			
+			if(insert_after)
+			{
+				MACRO_LIST_LINK_AFTER(ban, insert_after, prev, next);
+			}
+			else
+			{
+				MACRO_LIST_LINK_FIRST(ban, s->banpool_firstused, prev, next);
+			}
+		}
+		else
+		{
+			MACRO_LIST_LINK_FIRST(ban, s->banpool_firstused, prev, next);
+		}
 	}
 
 	/* drop banned clients */	
@@ -210,9 +255,9 @@ int netserver_ban_add(NETSERVER *s, NETADDR addr, int type, int seconds)
 		NETADDR banaddr;
 		
 		if(seconds)
-			str_format(buf, sizeof(buf), "you have been banned for %d seconds", seconds);
+			str_format(buf, sizeof(buf), "you have been banned for %d minutes", seconds/60);
 		else
-			str_format(buf, sizeof(buf), "you have been banned");
+			str_format(buf, sizeof(buf), "you have been banned for life");
 		
 		for(i = 0; i < s->max_clients; i++)
 		{
@@ -222,13 +267,14 @@ int netserver_ban_add(NETSERVER *s, NETADDR addr, int type, int seconds)
 			if(net_addr_comp(&addr, &banaddr) == 0)
 				netserver_drop(s, i, buf);
 		}
-	}	
-	
+	}
 	return 0;
 }
 
 int netserver_update(NETSERVER *s)
 {
+	unsigned now = time_timestamp();
+	
 	int i;
 	for(i = 0; i < s->max_clients; i++)
 	{
@@ -236,6 +282,16 @@ int netserver_update(NETSERVER *s)
 		if(s->slots[i].conn.state == NET_CONNSTATE_ERROR)
 			netserver_drop(s, i, conn_error(&s->slots[i].conn));
 	}
+	
+	/* remove expired bans */
+	while(s->banpool_firstused && s->banpool_firstused->info.expires < now)
+	{
+		NETBAN *ban = s->banpool_firstused;
+		netserver_ban_remove_by_object(s, ban);
+	}
+	
+	(void)now;
+	
 	return 0;
 }
 
@@ -278,8 +334,23 @@ int netserver_recv(NETSERVER *s, NETCHUNK *chunk)
 			}
 			
 			/* check if we just should drop the packet */
-			if(ban && ban->info.type == NETBANTYPE_DROP && (!ban->info.expires || ban->info.expires > now))
+			if(ban)
+			{
+				// banned, reply with a message
+				char banstr[128];
+				if(ban->info.expires)
+				{
+					int mins = ((ban->info.expires - now)+59)/60;
+					if(mins == 1)
+						str_format(banstr, sizeof(banstr), "banned for %d minute", mins);
+					else
+						str_format(banstr, sizeof(banstr), "banned for %d minutes", mins);
+				}
+				else
+					str_format(banstr, sizeof(banstr), "banned for life");
+				send_controlmsg(s->socket, &addr, 0, NET_CTRLMSG_CLOSE, banstr, str_length(banstr)+1);
 				continue;
+			}
 			
 			if(s->recv.data.flags&NET_PACKETFLAG_CONNLESS)
 			{
@@ -296,43 +367,37 @@ int netserver_recv(NETSERVER *s, NETCHUNK *chunk)
 				if(s->recv.data.flags&NET_PACKETFLAG_CONTROL && s->recv.data.chunk_data[0] == NET_CTRLMSG_CONNECT)
 				{
 					found = 0;
-					
-					if(ban && ban->info.expires > now)
+				
+					/* check if we already got this client */
+					for(i = 0; i < s->max_clients; i++)
 					{
-						/* TODO: soft ban, reply with a message */
+						if(s->slots[i].conn.state != NET_CONNSTATE_OFFLINE &&
+							net_addr_comp(&s->slots[i].conn.peeraddr, &addr) == 0)
+						{
+							found = 1; /* silent ignore.. we got this client already */
+							break;
+						}
 					}
-					else
+					
+					/* client that wants to connect */
+					if(!found)
 					{
-						/* check if we already got this client */
 						for(i = 0; i < s->max_clients; i++)
 						{
-							if(s->slots[i].conn.state != NET_CONNSTATE_OFFLINE &&
-								net_addr_comp(&s->slots[i].conn.peeraddr, &addr) == 0)
+							if(s->slots[i].conn.state == NET_CONNSTATE_OFFLINE)
 							{
-								found = 1; /* silent ignore.. we got this client already */
+								found = 1;
+								conn_feed(&s->slots[i].conn, &s->recv.data, &addr);
+								if(s->new_client)
+									s->new_client(i, s->user_ptr);
 								break;
 							}
 						}
 						
-						/* client that wants to connect */
 						if(!found)
 						{
-							for(i = 0; i < s->max_clients; i++)
-							{
-								if(s->slots[i].conn.state == NET_CONNSTATE_OFFLINE)
-								{
-									found = 1;
-									conn_feed(&s->slots[i].conn, &s->recv.data, &addr);
-									if(s->new_client)
-										s->new_client(i, s->user_ptr);
-									break;
-								}
-							}
-							
-							if(!found)
-							{
-								/* TODO: send server full message */
-							}
+							const char fullmsg[] = "server is full";
+							send_controlmsg(s->socket, &addr, 0, NET_CTRLMSG_CLOSE, fullmsg, sizeof(fullmsg));
 						}
 					}
 				}
diff --git a/src/engine/server/es_server.c b/src/engine/server/es_server.c
index 05a98983..b8df0f50 100644
--- a/src/engine/server/es_server.c
+++ b/src/engine/server/es_server.c
@@ -824,9 +824,9 @@ static void server_process_client_packet(NETCHUNK *packet)
 }
 
 
-int server_ban_add(NETADDR addr, int type, int seconds)
+int server_ban_add(NETADDR addr, int seconds)
 {
-	return netserver_ban_add(net, addr, type, seconds);	
+	return netserver_ban_add(net, addr, seconds);	
 }
 
 int server_ban_remove(NETADDR addr)
@@ -1177,29 +1177,78 @@ static void con_kick(void *result, void *user_data)
 	server_kick(console_arg_int(result, 0), "kicked by console");
 }
 
+static int str_allnum(const char *str)
+{
+	while(*str)
+	{
+		if(!(*str >= '0' && *str <= '9'))
+			return 0;
+		str++;
+	}
+	return 1;
+}
+
 static void con_ban(void *result, void *user_data)
 {
 	NETADDR addr;
+	char addrstr[128];
 	const char *str = console_arg_string(result, 0);
+	int minutes = console_arg_int(result, 1);
+	
+	if(minutes == 0)
+		minutes = 30;
 	
 	if(net_addr_from_str(&addr, str) == 0)
-		server_ban_add(addr, 2, 60);
+		server_ban_add(addr, minutes*60);
+	else if(str_allnum(str))
+	{
+		NETADDR addr;
+		int cid = atoi(str);
+
+		if(cid < 0 || cid > MAX_CLIENTS || clients[cid].state == SRVCLIENT_STATE_EMPTY)
+		{
+			dbg_msg("server", "invalid client id");
+			return;
+		}
+
+		netserver_client_addr(net, cid, &addr);
+		server_ban_add(addr, minutes*60);
+	}
+	
+	addr.port = 0;
+	net_addr_str(&addr, addrstr, sizeof(addrstr));
+		
+	dbg_msg("server", "banned %s for %d minutes", addrstr, minutes);
 }
 
+static void con_unban(void *result, void *user_data)
+{
+	NETADDR addr;
+	const char *str = console_arg_string(result, 0);
+	
+	if(net_addr_from_str(&addr, str) == 0)
+		server_ban_remove(addr);
+	else
+		dbg_msg("server", "invalid network address");
+}
 
 static void con_bans(void *result, void *user_data)
 {
 	int i;
+	unsigned now = time_timestamp();
 	NETBANINFO info;
 	NETADDR addr;
 	int num = netserver_ban_num(net);
 	for(i = 0; i < num; i++)
 	{
+		unsigned t;
 		netserver_ban_get(net, i, &info);
 		addr = info.addr;
 		
-		dbg_msg("server", "#%d %d.%d.%d.%d", i, addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3]);
+		t = info.expires - now;
+		dbg_msg("server", "#%d %d.%d.%d.%d for %d minutes and %d seconds", i, addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3], t/60, t%60);
 	}
+	dbg_msg("server", "%d ban(s)", num);
 }
 
 static void con_status(void *result, void *user_data)
@@ -1238,7 +1287,8 @@ static void con_stoprecord(void *result, void *user_data)
 static void server_register_commands()
 {
 	MACRO_REGISTER_COMMAND("kick", "i", con_kick, 0);
-	MACRO_REGISTER_COMMAND("ban", "r", con_ban, 0);
+	MACRO_REGISTER_COMMAND("ban", "s?i", con_ban, 0);
+	MACRO_REGISTER_COMMAND("unban", "s", con_unban, 0);
 	MACRO_REGISTER_COMMAND("bans", "", con_bans, 0);
 	MACRO_REGISTER_COMMAND("status", "", con_status, 0);
 	MACRO_REGISTER_COMMAND("shutdown", "", con_shutdown, 0);