finished the ban support

This commit is contained in:
Magnus Auvinen 2009-01-10 10:27:25 +00:00
parent b281831d5d
commit b42eb55794
7 changed files with 224 additions and 102 deletions

View file

@ -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

View file

@ -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)

View file

@ -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 */

View file

@ -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)

View file

@ -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);

View file

@ -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,29 +154,52 @@ int netserver_ban_num(NETSERVER *s)
return count;
}
int netserver_ban_remove(NETSERVER *s, NETADDR addr)
static void netserver_ban_remove_by_object(NETSERVER *s, NETBAN *ban)
{
return 0;
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_add(NETSERVER *s, NETADDR addr, int type, int seconds)
int netserver_ban_remove(NETSERVER *s, NETADDR addr)
{
int iphash = (addr.ip[0]+addr.ip[1]+addr.ip[2]+addr.ip[3])&0xff;
unsigned stamp = time_timestamp() + seconds;
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 seconds)
{
int iphash = (addr.ip[0]+addr.ip[1]+addr.ip[2]+addr.ip[3])&0xff;
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)
@ -159,48 +207,45 @@ int netserver_ban_add(NETSERVER *s, NETADDR addr, int type, int seconds)
/* 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)
MACRO_LIST_UNLINK(ban, s->banpool_firstfree, prev, next);
/* setup the ban info */
ban->info.expires = stamp;
ban->info.type = type;
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;
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 || insert_after->info.expires > stamp)
if(insert_after)
{
/* insert first */
s->banpool_firstused = ban;
ban->next = insert_after;
ban->prev = 0;
MACRO_LIST_LINK_AFTER(ban, insert_after, prev, next);
}
else
{
/* insert after */
ban->next = insert_after->next;
ban->prev = insert_after;
if(ban->next)
ban->next->prev = ban;
insert_after->next = ban;
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++)
{
@ -223,12 +268,13 @@ int netserver_ban_add(NETSERVER *s, NETADDR addr, int type, int seconds)
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)
{
@ -297,12 +368,6 @@ int netserver_recv(NETSERVER *s, NETCHUNK *chunk)
{
found = 0;
if(ban && ban->info.expires > now)
{
/* TODO: soft ban, reply with a message */
}
else
{
/* check if we already got this client */
for(i = 0; i < s->max_clients; i++)
{
@ -331,8 +396,8 @@ int netserver_recv(NETSERVER *s, NETCHUNK *chunk)
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));
}
}
}

View file

@ -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, 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_add(addr, 2, 60);
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);