DEADSOFTWARE

b6d2cd7d8e64b5449ec7df340e8bb868cdc161c6
[d2df-sdl.git] / src / mastersrv / master.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <enet/enet.h>
5 #include <enet/types.h>
6 #include <time.h>
8 #define MS_VERSION "0.2"
9 #define MS_MAXSRVS 128
10 #define MS_MAXBANS 256
11 #define MS_TIMEOUT 100
12 #define MS_BANTIME (3 * 86400)
13 #define MS_MAXHEUR 100
15 #define NET_CHANS 2
16 #define NET_CH_MAIN 0
17 #define NET_CH_UPD 1
18 #define NET_MAXCLIENTS 64
20 #define NET_BUFSIZE 65536
22 #define NET_MSG_ADD 200
23 #define NET_MSG_RM 201
24 #define NET_MSG_LIST 202
26 #define LC_MS_INIT "D2DF master server starting on port %d...\n"
27 #define LC_MS_ADD "\nAdded server in slot #%d:\n%s:%d\n%s\n%s (%d)\n%d/%d plrs\nproto: %d pw?: %d\n"
28 #define LC_MS_UPD "\nUpdated server #%d (%s:%d):\n%s\n%s (%d)\n%d/%d plrs\nproto: %d pw?: %d\n"
29 #define LC_MS_RM "\nRemoved server #%d (%s:%d) by request.\n"
30 #define LC_MS_TIME "\nServer #%d (%s:%d) timed out.\n"
31 #define LC_MS_LIST "\nSent server list to %x:%u (ver. %s).\n"
32 #define LC_MS_DIE "\nD2DF master server shutting down...\n"
33 #define LC_MS_CONN "\nIncoming connection from %x:%u...\n"
34 #define LC_MS_MOTD "\nMOTD: %s\n"
35 #define LC_MS_URGENT "\nURGENT: %s\n"
36 #define LC_MS_BANNED "\nBanned %s until %s, reason: %s (#%d)\n"
37 #define LC_MS_NOBANS "\nCould not load ban list from file\n"
38 #define LC_MS_BADADR "\nBad address in file: %s\n"
39 #define LC_MS_BANHEUR "tripped heuristic check"
40 #define LC_MS_BANLIST "address in ban list"
41 #define LC_MS_OOM "\nOut of memory\n"
43 #define MS_URGENT_FILE "urgent.txt"
44 #define MS_MOTD_FILE "motd.txt"
45 #define MS_BAN_FILE "master_bans.txt"
47 struct ms_ban_s;
49 typedef struct ms_ban_record_s {
50 ENetAddress mask;
51 char ip[18];
52 int ban_count;
53 time_t cur_ban;
54 struct ms_ban_record_s *next;
55 struct ms_ban_record_s *prev;
56 } ms_ban_record;
58 struct ms_server_s {
59 enet_uint8 used;
60 char s_ip[17];
61 char s_name[256];
62 char s_map[256];
63 enet_uint8 s_pw;
64 enet_uint8 s_plrs;
65 enet_uint8 s_maxplrs;
66 enet_uint8 s_mode;
67 enet_uint8 s_protocol;
68 enet_uint16 s_port;
69 time_t deathtime;
70 time_t lasttime;
71 };
73 typedef struct ms_server_s ms_server;
75 const char ms_game_ver[] = "0.63";
76 char ms_motd[255] = "";
77 char ms_urgent[255] = "";
79 int ms_port = 25660;
80 int ms_timeout = 100;
82 size_t b_read = 0;
83 size_t b_write = 0;
85 enet_uint8 b_send[NET_BUFSIZE];
87 ENetHost *ms_host = NULL;
88 ENetPeer *ms_peers[NET_MAXCLIENTS];
90 ms_server ms_srv[MS_MAXSRVS];
91 enet_uint8 ms_count = 0;
93 ms_ban_record *ms_bans;
95 // fake servers to show on old versions of the game
96 static const ms_server ms_fake_srv[] = {
97 {
98 .used = 1,
99 .s_ip = "0.0.0.0",
100 .s_name = "! \xc2\xc0\xd8\xc0 \xca\xce\xcf\xc8\xdf \xc8\xc3\xd0\xdb "
101 "\xd3\xd1\xd2\xc0\xd0\xc5\xcb\xc0! "
102 "\xd1\xca\xc0\xd7\xc0\xc9\xd2\xc5 \xcd\xce\xc2\xd3\xde C "
103 "doom2d.org !",
104 .s_map = "! Your game is outdated. "
105 "Get latest version at doom2d.org !",
106 .s_protocol = 255,
107 },
109 .used = 1,
110 .s_ip = "0.0.0.0",
111 .s_name = "! \xcf\xd0\xce\xc1\xd0\xce\xd1\xdcTE \xcf\xce\xd0\xd2\xdb "
112 "25666 \xc8 57133 HA CEPBEPE \xcf\xc5\xd0\xc5\xc4 \xc8\xc3\xd0\xce\xc9 !",
113 .s_map = "! Forward ports 25666 and 57133 before hosting !",
114 .s_protocol = 255,
115 },
116 };
118 #define MS_FAKESRVS (sizeof(ms_fake_srv) / sizeof(ms_fake_srv[0]))
120 void i_usage (void) {
121 printf("Usage: d2df_master -p port_number [-t timeout_seconds]\n");
122 fflush(stdout);
126 void i_version (void) {
127 printf("Doom 2D Forever master server v%s\n", MS_VERSION);
128 fflush(stdout);
132 void d_error (const char *msg, int fatal) {
133 if (fatal) {
134 fprintf(stderr, "FATAL ERROR: %s\n", msg);
135 exit(EXIT_FAILURE);
136 } else {
137 fprintf(stderr, "ERROR: %s\n", msg);
142 void d_getargs (int argc, char *argv[]) {
143 if (argc < 2) {
144 i_usage();
145 exit(0);
146 return;
149 for (int i = 1; i < argc; ++i) {
150 if (!strcmp(argv[i], "-v")) {
151 i_version();
152 exit(0);
153 return;
154 } else if (!strcmp(argv[i], "-p")) {
155 if (i + 1 >= argc) {
156 d_error("Specify a port value!", 1);
157 return;
158 } else {
159 ms_port = atoi(argv[++i]);
161 } else if (!strcmp(argv[i], "-t") & (i + 1 < argc)) {
162 ms_timeout = atoi(argv[++i]);
168 int d_readtextfile (const char *fname, char *buf, size_t max) {
169 FILE *f = fopen(fname, "r");
170 char *const end = buf + max - 1;
171 char *p = buf;
172 if (f) {
173 char ln[max];
174 char *const lend = ln + max - 1;
175 while (p < end && fgets(ln, max, f)) {
176 for (char *n = ln; n < lend && *n && *n != '\r' && *n != '\n'; ++n) {
177 *(p++) = *n;
178 if (p == end) break;
181 *p = '\0';
182 fclose(f);
183 return 0;
185 return 1;
189 int d_strisprint (const char *str) {
190 if (!str || !*str) return 0;
191 for (const char *p = str; p && *p; ++p)
192 if (isprint(*p) || *p > 0x7f) return 1;
193 return 0;
197 const char *d_strtime(const time_t t) {
198 static char buf[128];
199 struct tm *ptm = localtime(&t);
200 strftime(buf, sizeof(buf), "%c", ptm);
201 return buf;
205 enet_uint8 b_read_uint8 (enet_uint8 buf[], size_t *pos) {
206 return buf[(*pos)++];
210 enet_uint16 b_read_uint16 (enet_uint8 buf[], size_t *pos) {
211 enet_uint16 ret = 0;
213 ret = *(enet_uint16*)(buf + *pos);
214 *pos += sizeof(enet_uint16);
216 return ret;
220 char* b_read_dstring (enet_uint8 buf[], size_t *pos) {
221 char *ret = NULL;
223 size_t len = b_read_uint8(buf, pos);
225 ret = malloc(len + 1);
227 memmove(ret, (char*)(buf + *pos), len);
228 ret[len] = '\0';
229 *pos += len;
231 return ret;
235 void b_write_uint8 (enet_uint8 buf[], size_t *pos, enet_uint8 val) {
236 buf[(*pos)++] = val;
240 void b_write_uint16 (enet_uint8 buf[], size_t *pos, enet_uint16 val) {
241 *(enet_uint16*)(buf + *pos) = val;
242 *pos += sizeof(enet_uint16);
246 void b_write_dstring (enet_uint8 buf[], size_t *pos, const char* val) {
247 enet_uint8 len = strlen(val);
248 b_write_uint8(buf, pos, len);
250 memmove((char*)(buf + *pos), val, len);
251 *pos += len;
255 void b_write_server (enet_uint8 buf[], size_t *pos, ms_server s) {
256 b_write_dstring(b_send, pos, s.s_ip);
257 b_write_uint16 (b_send, pos, s.s_port);
258 b_write_dstring(b_send, pos, s.s_name);
259 b_write_dstring(b_send, pos, s.s_map);
260 b_write_uint8 (b_send, pos, s.s_mode);
261 b_write_uint8 (b_send, pos, s.s_plrs);
262 b_write_uint8 (b_send, pos, s.s_maxplrs);
263 b_write_uint8 (b_send, pos, s.s_protocol);
264 b_write_uint8 (b_send, pos, s.s_pw);
268 time_t ban_get_time(const int cnt) {
269 static const time_t times[] = {
270 1 * 5 * 60,
271 1 * 30 * 60,
272 1 * 60 * 60,
273 24 * 60 * 60,
274 72 * 60 * 60,
275 8760 * 60 * 60,
276 };
278 static const size_t numtimes = sizeof(times) / sizeof(*times);
280 if (cnt >= numtimes || cnt < 0)
281 return times[numtimes - 1];
283 return times[cnt];
287 ms_ban_record *ban_check (const ENetAddress *addr) {
288 const time_t now = time(NULL);
290 for (ms_ban_record *b = ms_bans; b; b = b->next) {
291 if (b->mask.host == addr->host) {
292 if (b->cur_ban > now)
293 return b;
297 return NULL;
301 ms_ban_record *ban_record_check (const ENetAddress *addr) {
302 for (ms_ban_record *b = ms_bans; b; b = b->next) {
303 if (b->mask.host == addr->host)
304 return b;
306 return NULL;
310 ms_ban_record *ban_record_add_addr (const ENetAddress *addr, const int cnt, const time_t cur) {
311 ms_ban_record *rec = ban_record_check(addr);
312 if (rec) return rec;
314 rec = calloc(1, sizeof(*rec));
315 if (!rec) return NULL;
317 enet_address_get_host_ip(addr, rec->ip, 17);
318 rec->mask = *addr;
319 rec->ban_count = cnt;
320 rec->cur_ban = cur;
322 if (ms_bans) ms_bans->prev = rec;
323 rec->next = ms_bans;
324 ms_bans = rec;
326 return rec;
330 ms_ban_record *ban_record_add_ip (const char *ip, const int cnt, const time_t cur) {
331 ENetAddress addr;
332 if (enet_address_set_host_ip(&addr, ip) != 0) {
333 fprintf(stderr, LC_MS_BADADR, ip);
334 return NULL;
336 return ban_record_add_addr(&addr, cnt, cur);
340 void ban_load_list (const char *fname) {
341 FILE *f = fopen(fname, "r");
342 if (!f) {
343 d_error(LC_MS_NOBANS, 0);
344 return;
347 char ln[256] = { 0 };
349 while (fgets(ln, sizeof(ln), f)) {
350 for (int i = sizeof(ln) - 1; i >= 0; --i)
351 if (ln[i] == '\n' || ln[i] == '\r')
352 ln[i] = 0;
354 char ip[17] = { 0 };
355 time_t exp = 0;
356 int count = 0;
358 sscanf(ln, "%16s %ld %d", ip, &exp, &count);
360 if (ban_record_add_ip(ip, count, exp))
361 printf(LC_MS_BANNED, ip, d_strtime(exp), LC_MS_BANLIST, count);
364 fclose(f);
368 void ban_save_list (const char *fname) {
369 FILE *f = fopen(fname, "w");
370 if (!f) {
371 d_error(LC_MS_NOBANS, 0);
372 return;
375 for (ms_ban_record *rec = ms_bans; rec; rec = rec->next)
376 if (rec->ban_count)
377 fprintf(f, "%s %ld %d\n", rec->ip, rec->cur_ban, rec->ban_count);
379 fclose(f);
383 int ban_heur (const ms_server *srv, const time_t now) {
384 int score = 0;
386 // can't have more than 24 maxplayers; can't have more than max
387 if (srv->s_plrs > srv->s_maxplrs || srv->s_maxplrs > 24)
388 score += MS_MAXHEUR;
390 // name and map have to be non-garbage
391 if (!d_strisprint(srv->s_map) || !d_strisprint(srv->s_name))
392 score += MS_MAXHEUR;
394 // these protocols don't exist
395 if (srv->s_protocol < 100 || srv->s_protocol > 250)
396 score += MS_MAXHEUR;
398 // the game doesn't allow server names longer than 64 chars
399 if (strlen(srv->s_name) > 64)
400 score += MS_MAXHEUR;
402 // game mode has to actually exist
403 if (srv->s_mode > 5)
404 score += MS_MAXHEUR;
406 // password field can be either 0 or 1
407 if (srv->s_pw > 1)
408 score += MS_MAXHEUR;
410 // port has to be set, although the game allows you to set it to 0
411 // if (!srv->s_port)
412 // score += MS_MAXHEUR;
414 // servers usually don't update more often than once every 30 seconds
415 if (now - srv->lasttime < 5)
416 score += MS_MAXHEUR / 2;
418 return score;
422 void ban_add (const ENetAddress *addr, const char *reason) {
423 const time_t now = time(NULL);
425 ms_ban_record *rec = ban_record_add_addr(addr, 0, 0);
426 if (!rec) d_error(LC_MS_OOM, 1);
428 rec->cur_ban = now + ban_get_time(rec->ban_count);
429 rec->ban_count++;
431 printf(LC_MS_BANNED, rec->ip, d_strtime(rec->cur_ban), reason, rec->ban_count);
433 ban_save_list(MS_BAN_FILE);
437 void d_deinit(void) {
438 ban_save_list(MS_BAN_FILE);
442 int main (int argc, char *argv[]) {
443 d_getargs(argc, argv);
445 if (enet_initialize()) {
446 d_error("Could not init ENet!", 1);
447 return EXIT_FAILURE;
450 printf(LC_MS_INIT, ms_port);
452 d_readtextfile(MS_MOTD_FILE, ms_motd, sizeof(ms_motd));
453 d_readtextfile(MS_URGENT_FILE, ms_urgent, sizeof(ms_urgent));
454 ban_load_list(MS_BAN_FILE);
456 if (ms_motd[0]) printf(LC_MS_MOTD, ms_motd);
457 if (ms_urgent[0]) printf(LC_MS_URGENT, ms_urgent);
459 for (int i = 0; i < NET_MAXCLIENTS; ++i) ms_peers[i] = NULL;
461 for (int i = 0; i < MS_MAXSRVS; ++i) {
462 ms_srv[i].used = 0;
463 ms_srv[i].s_ip[0] = '\0';
464 ms_srv[i].s_name[0] = '\0';
465 ms_srv[i].s_map[0] = '\0';
466 ms_srv[i].deathtime = 0;
469 ENetAddress addr;
470 addr.host = ENET_HOST_ANY;
471 addr.port = ms_port;
473 ms_host = enet_host_create(&addr, NET_MAXCLIENTS, NET_CHANS, 0, 0);
474 if (!ms_host) {
475 d_error("Could not create host on specified port!", 1);
476 return EXIT_FAILURE;
479 atexit(d_deinit);
481 ENetEvent event;
482 int shutdown = 0;
483 enet_uint8 msg = 255;
485 char ip[17];
486 enet_uint16 port = 0;
488 char *name = NULL;
489 char *map = NULL;
490 char *clientver = NULL;
491 enet_uint8 gm = 0;
492 enet_uint16 pl = 0;
493 enet_uint16 mpl = 0;
495 enet_uint8 proto = 0;
496 enet_uint8 pw = 0;
497 while (!shutdown) {
498 while (enet_host_service(ms_host, &event, 5000) > 0) {
499 if (event.peer && ban_check(&(event.peer->address)))
500 continue;
502 const time_t now = time(NULL);
504 switch (event.type) {
505 case ENET_EVENT_TYPE_CONNECT:
506 printf(LC_MS_CONN, event.peer->address.host, event.peer->address.port);
507 break;
509 case ENET_EVENT_TYPE_RECEIVE:
510 if (!event.peer) continue;
512 b_read = 0;
513 msg = b_read_uint8(event.packet->data, &b_read);
515 switch (msg) {
516 case NET_MSG_ADD:
517 enet_address_get_host_ip(&(event.peer->address), ip, 17);
518 port = b_read_uint16(event.packet->data, &b_read);
520 name = b_read_dstring(event.packet->data, &b_read);
521 map = b_read_dstring(event.packet->data, &b_read);
522 gm = b_read_uint8(event.packet->data, &b_read);
524 pl = b_read_uint8(event.packet->data, &b_read);
525 mpl = b_read_uint8(event.packet->data, &b_read);
527 proto = b_read_uint8(event.packet->data, &b_read);
528 pw = b_read_uint8(event.packet->data, &b_read);
530 for (int i = 0; i < MS_MAXSRVS; ++i) {
531 if (ms_srv[i].used) {
532 if ((strncmp(ip, ms_srv[i].s_ip, 16) == 0) && (ms_srv[i].s_port == port)) {
533 if (ban_heur(ms_srv + i, now) >= MS_MAXHEUR) {
534 ban_add(&(event.peer->address), LC_MS_BANHEUR);
535 break;
538 strncpy(ms_srv[i].s_map, map, sizeof(ms_srv[i].s_map));
539 strncpy(ms_srv[i].s_name, name, sizeof(ms_srv[i].s_name));
540 ms_srv[i].s_plrs = pl;
541 ms_srv[i].s_maxplrs = mpl;
542 ms_srv[i].s_pw = pw;
543 ms_srv[i].s_mode = gm;
545 ms_srv[i].deathtime = now + ms_timeout;
546 ms_srv[i].lasttime = now;
548 printf(LC_MS_UPD, i, ip, port, name, map, gm, pl, mpl, proto, pw);
549 break;
551 } else {
552 strncpy(ms_srv[i].s_ip, ip, sizeof(ms_srv[i].s_ip));
553 strncpy(ms_srv[i].s_map, map, sizeof(ms_srv[i].s_map));
554 strncpy(ms_srv[i].s_name, name, sizeof(ms_srv[i].s_name));
555 ms_srv[i].s_port = port;
556 ms_srv[i].s_plrs = pl;
557 ms_srv[i].s_maxplrs = mpl;
558 ms_srv[i].s_pw = pw;
559 ms_srv[i].s_mode = gm;
560 ms_srv[i].s_protocol = proto;
561 ms_srv[i].deathtime = now + ms_timeout;
562 ms_srv[i].lasttime = now;
564 if (ban_heur(ms_srv + i, now) >= MS_MAXHEUR) {
565 ban_add(&(event.peer->address), LC_MS_BANHEUR);
566 break;
569 ms_srv[i].used = 1;
571 printf(LC_MS_ADD, i, ip, port, name, map, gm, pl, mpl, proto, pw);
573 ++ms_count;
574 break;
577 free(name);
578 free(map);
579 break;
581 case NET_MSG_RM:
582 enet_address_get_host_ip(&(event.peer->address), ip, 17);
583 port = b_read_uint16(event.packet->data, &b_read);
584 for (int i = 0; i < MS_MAXSRVS; ++i) {
585 if (ms_srv[i].used) {
586 if ((strncmp(ip, ms_srv[i].s_ip, 16) == 0) && (ms_srv[i].s_port == port)) {
587 if (ban_heur(ms_srv + i, now) >= MS_MAXHEUR) {
588 ban_add(&(event.peer->address), LC_MS_BANHEUR);
589 break;
591 ms_srv[i].used = 0;
592 printf(LC_MS_RM, i, ip, port);
593 --ms_count;
597 break;
599 case NET_MSG_LIST:
600 b_write = 0;
601 b_write_uint8(b_send, &b_write, NET_MSG_LIST);
603 if (event.packet->dataLength > 2) {
604 // holy shit a fresh client
605 clientver = b_read_dstring(event.packet->data, &b_read);
606 b_write_uint8(b_send, &b_write, ms_count);
607 } else {
608 // old client, feed them bullshit first
609 b_write_uint8(b_send, &b_write, ms_count + 2);
610 for (int i = 0; i < MS_FAKESRVS; ++i)
611 b_write_server(b_send, &b_write, ms_fake_srv[i]);
614 for (int i = 0; i < MS_MAXSRVS; ++i) {
615 if (ms_srv[i].used) b_write_server(b_send, &b_write, ms_srv[i]);
618 if (clientver) {
619 // TODO: check if this client is outdated (?) and send back new verstring
620 // for now just write the same shit back
621 b_write_dstring(b_send, &b_write, clientver);
622 // write the motd and urgent message
623 b_write_dstring(b_send, &b_write, ms_motd);
624 b_write_dstring(b_send, &b_write, ms_urgent);
627 ENetPacket *p = enet_packet_create(b_send, b_write, ENET_PACKET_FLAG_RELIABLE);
628 enet_peer_send(event.peer, NET_CH_MAIN, p);
629 enet_host_flush(ms_host);
631 printf(LC_MS_LIST, event.peer->address.host, event.peer->address.port, clientver ? clientver : "<old>");
632 free(clientver);
633 clientver = NULL;
634 break;
637 enet_packet_destroy(event.packet);
638 break;
640 default:
641 break;
645 time_t now = time(NULL);
646 for (int i = 0; i < MS_MAXSRVS; ++i) {
647 if (ms_srv[i].used) {
648 if (ms_srv[i].deathtime <= now) {
649 ms_srv[i].used = 0;
650 printf(LC_MS_TIME, i, ms_srv[i].s_ip, ms_srv[i].s_port);
651 --ms_count;
657 printf(LC_MS_DIE);
659 return EXIT_SUCCESS;