DEADSOFTWARE

183d7454a8d2dc3601ddd2e3b2b9a9f1a1936e04
[d2df-sdl.git] / src / mastersrv / master.c
1 /* Copyright (C) Doom 2D: Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, version 3 of the License ONLY.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 */
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <stdint.h>
19 #include <stdbool.h>
20 #include <stdarg.h>
21 #include <ctype.h>
22 #include <string.h>
23 #include <time.h>
24 #include <signal.h>
26 #define ENET_DEBUG 1
27 #include <enet/enet.h>
28 #include <enet/types.h>
30 #define MS_VERSION "0.3"
31 #define MS_MAX_SERVERS 128
32 #define MS_MAX_CLIENTS (MS_MAX_SERVERS + 1)
33 #define MS_URGENT_FILE "urgent.txt"
34 #define MS_MOTD_FILE "motd.txt"
35 #define MS_BAN_FILE "master_bans.txt"
37 #define DEFAULT_SPAM_CAP 10
38 #define DEFAULT_MAX_SERVERS MS_MAX_SERVERS
39 #define DEFAULT_MAX_PER_HOST 4
40 #define DEFAULT_SERVER_TIMEOUT 100
41 #define DEFAULT_CLIENT_TIMEOUT 3
42 #define DEFAULT_SPAM_TIMEOUT 1
43 #define DEFAULT_PORT 25665
45 #define NET_BUFSIZE 65536
46 #define NET_FULLMASK 0xFFFFFFFF
48 #define SV_PROTO_MIN 140
49 #define SV_PROTO_MAX 210
50 #define SV_NAME_MAX 64
51 #define SV_MAP_MAX 64
52 #define SV_MAX_PLAYERS 24
53 #define SV_MAX_GAMEMODE 5
54 #define SV_NEW_SERVER_INTERVAL 3
56 #define MAX_STRLEN 0xFF
58 enum log_severity_e {
59 LOG_NOTE,
60 LOG_WARN,
61 LOG_ERROR
62 };
64 enum net_ch_e {
65 NET_CH_MAIN,
66 NET_CH_UPD,
67 NET_CH_COUNT
68 };
70 enum net_msg_e {
71 NET_MSG_ADD = 200,
72 NET_MSG_RM = 201,
73 NET_MSG_LIST = 202
74 };
76 enum sv_flags_e {
77 SV_FL_PASSWORD = 1 << 0,
78 SV_FL_VERIFIED = 1 << 1,
79 SV_FL_MAX = SV_FL_PASSWORD | SV_FL_VERIFIED,
80 };
82 typedef struct enet_buf_s {
83 enet_uint8 *data;
84 size_t size;
85 size_t pos;
86 int overflow;
87 } enet_buf_t;
89 typedef struct ban_record_s {
90 enet_uint32 host;
91 enet_uint32 mask;
92 int ban_count;
93 time_t cur_ban;
94 struct ban_record_s *next;
95 struct ban_record_s *prev;
96 } ban_record_t;
98 typedef struct server_s {
99 enet_uint32 host; // BE; 0 means this slot is unused
100 enet_uint16 port; // LE, which is what the game and enet both expect
101 enet_uint8 flags;
102 enet_uint8 proto;
103 enet_uint8 gamemode;
104 enet_uint8 players;
105 enet_uint8 maxplayers;
106 char name[MAX_STRLEN + 2];
107 char map[MAX_STRLEN + 2];
108 time_t death_time;
109 time_t timestamp;
110 ENetPeer *peer; // who sent this server in
111 } server_t;
113 // real servers
114 static server_t servers[MS_MAX_SERVERS];
115 static int max_servers = DEFAULT_MAX_SERVERS;
116 static int max_servers_per_host = DEFAULT_MAX_PER_HOST;
117 static int num_servers = 0;
119 // fake servers to show on old versions of the game
120 static const server_t fake_servers[] = {
122 .name = "! \xc2\xc0\xd8\xc0 \xca\xce\xcf\xc8\xdf \xc8\xc3\xd0\xdb "
123 "\xd3\xd1\xd2\xc0\xd0\xc5\xcb\xc0! "
124 "\xd1\xca\xc0\xd7\xc0\xc9\xd2\xc5 \xcd\xce\xc2\xd3\xde C "
125 "doom2d.org !",
126 .map = "! Your game is outdated. "
127 "Get latest version at doom2d.org !",
128 .proto = 255,
129 },
131 .name = "! \xcf\xd0\xce\xc1\xd0\xce\xd1\xdcTE \xcf\xce\xd0\xd2\xdb "
132 "25666 \xc8 57133 HA CEPBEPE \xcf\xc5\xd0\xc5\xc4 \xc8\xc3\xd0\xce\xc9 !",
133 .map = "! Forward ports 25666 and 57133 before hosting !",
134 .proto = 255,
135 },
136 };
137 static const int num_fake_servers = sizeof(fake_servers) / sizeof(*fake_servers);
139 // ban list
140 static ban_record_t *banlist;
142 // settings
143 static int ms_port = DEFAULT_PORT;
144 static int ms_sv_timeout = DEFAULT_SERVER_TIMEOUT;
145 static int ms_cl_timeout = DEFAULT_CLIENT_TIMEOUT;
146 static int ms_spam_timeout = DEFAULT_SPAM_TIMEOUT;
147 static int ms_spam_cap = DEFAULT_SPAM_CAP;
148 static char ms_motd[MAX_STRLEN + 1] = "";
149 static char ms_urgent[MAX_STRLEN + 1] = "";
150 static ENetHost *ms_host;
152 // network buffers
153 static enet_uint8 buf_send_data[NET_BUFSIZE];
154 static enet_buf_t buf_send = { .data = buf_send_data, .size = sizeof(buf_send_data) };
155 static enet_buf_t buf_recv; // rx data supplied by enet packets
157 // stupid client spam filter
158 static enet_uint32 cl_last_addr;
159 static time_t cl_last_time;
160 static int cl_spam_cnt;
162 /* common utility functions */
164 static char *u_vabuf(void) {
165 static char vabuf[4][MAX_STRLEN];
166 static int idx = 0;
167 char *ret = vabuf[idx++];
168 if (idx >= 4) idx = 0;
169 return ret;
172 static const char *u_strtime(const time_t t) {
173 char *buf = u_vabuf();
174 struct tm *ptm = localtime(&t);
175 strftime(buf, MAX_STRLEN - 1, "%d/%m/%y %H:%M:%S", ptm);
176 return buf;
179 static inline const char *u_logprefix(const enum log_severity_e s) {
180 switch (s) {
181 case LOG_WARN: return "WARNING: ";
182 case LOG_ERROR: return "ERROR: ";
183 default: return "";
187 static void u_log(const enum log_severity_e severity, const char *fmt, ...) {
188 printf("[%s] %s", u_strtime(time(NULL)), u_logprefix(severity));
189 va_list args;
190 va_start(args, fmt);
191 vprintf(fmt, args);
192 va_end(args);
193 printf("\n");
196 static void __attribute__((noreturn)) u_fatal(const char *fmt, ...) {
197 fprintf(stderr, "[%s] FATAL ERROR:\n", u_strtime(time(NULL)));
198 va_list args;
199 va_start(args, fmt);
200 vfprintf(stderr, fmt, args);
201 va_end(args);
202 fprintf(stderr, "\n");
203 fflush(stderr);
204 exit(1);
207 static bool u_strisprint(const char *str) {
208 if (!str || !*str)
209 return false;
210 for (const char *p = str; *p; ++p) {
211 // only stuff before space, DEL, NBSP and SHY are considered garbage since we're on 1251
212 if (*p < 0x20 || *p == 0x7F || *p == 0xA0 || *p == 0xAD)
213 return false;
215 return true;
218 static bool u_strisver(const char *str) {
219 if (!str || !*str)
220 return false;
221 for (const char *p = str; *p; ++p) {
222 // version strings consist of 0-9 . and space
223 if (!isdigit(*p) && *p != '.' && *p != ' ')
224 return false;
226 return true;
229 static const char *u_iptostr(const enet_uint32 host) {
230 ENetAddress addr = { .host = host, .port = 0 };
231 char *buf = u_vabuf();
232 enet_address_get_host_ip(&addr, buf, MAX_STRLEN - 1);
233 return buf;
236 static bool u_readtextfile(const char *fname, char *buf, size_t max) {
237 FILE *f = fopen(fname, "r");
238 char *const end = buf + max - 1;
239 char *p = buf;
240 if (f) {
241 char ln[max];
242 char *const lend = ln + max - 1;
243 while (p < end && fgets(ln, max, f)) {
244 for (char *n = ln; n < lend && *n && *n != '\r' && *n != '\n'; ++n) {
245 *(p++) = *n;
246 if (p == end) break;
249 *p = '\0';
250 fclose(f);
251 return true;
253 return false;
256 static inline enet_uint32 u_prefixtomask(const enet_uint32 prefix) {
257 return ENET_HOST_TO_NET_32((0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF);
260 static inline enet_uint32 u_masktoprefix(const enet_uint32 mask) {
261 return (32 - __builtin_ctz(mask));
264 static inline void u_printsv(const server_t *sv) {
265 printf("* addr: %s:%d\n", u_iptostr(sv->host), sv->port);
266 printf("* name: %s\n", sv->name);
267 printf("* map: %s (mode %d)\n", sv->map, sv->gamemode);
268 printf("* plrs: %d/%d\n", sv->players, sv->maxplayers);
269 printf("* flag: %04x\n", sv->flags);
272 /* buffer utility functions */
274 static inline int b_enough_left(enet_buf_t *buf, size_t size) {
275 if (buf->pos + size > buf->size) {
276 buf->overflow = 1;
277 return 0;
279 return 1;
282 static enet_uint8 b_read_uint8(enet_buf_t *buf) {
283 if (b_enough_left(buf, 1))
284 return buf->data[buf->pos++];
285 return 0;
288 static enet_uint16 b_read_uint16(enet_buf_t *buf) {
289 enet_uint16 ret = 0;
291 if (b_enough_left(buf, sizeof(ret))) {
292 ret = *(enet_uint16*)(buf->data + buf->pos);
293 buf->pos += sizeof(ret);
296 return ret;
299 static char *b_read_dstring(enet_buf_t *buf) {
300 char *ret = NULL;
302 if (b_enough_left(buf, 1)) {
303 const size_t len = b_read_uint8(buf);
304 if (b_enough_left(buf, len)) {
305 ret = malloc(len + 1);
306 memmove(ret, (char*)(buf->data + buf->pos), len);
307 buf->pos += len;
308 ret[len] = '\0';
312 return ret;
315 static char *b_read_dstring_to(enet_buf_t *buf, char *out, size_t out_size) {
316 if (b_enough_left(buf, 1)) {
317 const size_t len = b_read_uint8(buf);
318 if (b_enough_left(buf, len)) {
319 if (len < out_size) {
320 memmove(out, (char*)(buf->data + buf->pos), len);
321 out[len] = '\0';
322 } else if (out_size) {
323 out[0] = '\0';
325 buf->pos += len;
326 return out;
329 return NULL;
332 static void b_write_uint8(enet_buf_t *buf, enet_uint8 val) {
333 buf->data[buf->pos++] = val;
336 static void b_write_uint16(enet_buf_t *buf, enet_uint16 val) {
337 *(enet_uint16*)(buf->data + buf->pos) = val;
338 buf->pos += sizeof(val);
341 static void b_write_dstring(enet_buf_t *buf, const char* val) {
342 enet_uint8 len = strlen(val);
343 b_write_uint8(buf, len);
344 memmove((char*)(buf->data + buf->pos), val, len);
345 buf->pos += len;
348 void b_write_server(enet_buf_t *buf, const server_t *s) {
349 b_write_dstring(buf, u_iptostr(s->host));
350 b_write_uint16 (buf, s->port);
351 b_write_dstring(buf, s->name);
352 b_write_dstring(buf, s->map);
353 b_write_uint8 (buf, s->gamemode);
354 b_write_uint8 (buf, s->players);
355 b_write_uint8 (buf, s->maxplayers);
356 b_write_uint8 (buf, s->proto);
357 b_write_uint8 (buf, (s->flags & SV_FL_PASSWORD));
360 /* server functions */
362 static inline void sv_remove(server_t *sv) {
363 if (sv->host) {
364 // drop the associated peer, if any
365 if (sv->peer && sv->peer->state == ENET_PEER_STATE_CONNECTED && sv->peer->data == sv) {
366 sv->peer->data = NULL;
367 enet_peer_reset(sv->peer);
369 sv->host = 0;
370 sv->port = 0;
371 sv->peer = NULL;
372 --num_servers;
376 static void sv_remove_by_addr(const enet_uint32 host, const enet_uint16 port) {
377 for (int i = 0; i < max_servers; ++i) {
378 if (servers[i].host == host && servers[i].port == port)
379 sv_remove(servers + i);
383 static void sv_remove_by_host(enet_uint32 host, enet_uint32 mask) {
384 host &= mask;
385 for (int i = 0; i < max_servers; ++i) {
386 if (servers[i].host && (servers[i].host & mask) == host)
387 sv_remove(servers + i);
391 static int sv_count_by_host(enet_uint32 host, enet_uint32 mask) {
392 host &= mask;
393 int count = 0;
394 for (int i = 0; i < max_servers; ++i) {
395 if (servers[i].host && (servers[i].host & mask) == host)
396 ++count;
398 return count;
401 static time_t sv_last_timestamp_for_host(enet_uint32 host, enet_uint32 mask) {
402 host &= mask;
403 time_t last = 0;
404 for (int i = 0; i < max_servers; ++i) {
405 if (servers[i].host && (servers[i].host & mask) == host) {
406 if (servers[i].timestamp > last)
407 last = servers[i].timestamp;
410 return last;
413 static inline server_t *sv_find_or_add(const enet_uint32 host, const enet_uint32 port) {
414 server_t *empty = NULL;
415 for (int i = 0; i < max_servers; ++i) {
416 server_t *s = servers + i;
417 if (s->host == host && s->port == port)
418 return s; // this server already exists
419 if (!s->host && !empty)
420 empty = s; // remember the first empty slot in case it's needed later
422 return empty;
425 static inline void sv_clear_peer(ENetPeer *peer) {
426 server_t *sv = peer->data;
427 if (sv) {
428 sv->peer = NULL;
429 peer->data = NULL;
433 /* ban list functions */
435 static inline time_t ban_get_time(const int cnt) {
436 static const time_t times[] = {
437 1 * 5 * 60,
438 1 * 30 * 60,
439 1 * 60 * 60,
440 24 * 60 * 60,
441 72 * 60 * 60,
442 720 * 60 * 60,
443 8760 * 60 * 60,
444 };
446 static const size_t numtimes = sizeof(times) / sizeof(*times);
448 if (cnt >= numtimes || cnt < 0)
449 return times[numtimes - 1];
451 return times[cnt];
454 static ban_record_t *ban_check(const enet_uint32 host) {
455 const time_t now = time(NULL);
457 for (ban_record_t *b = banlist; b; b = b->next) {
458 if ((b->host & b->mask) == (host & b->mask)) {
459 if (b->cur_ban > now)
460 return b;
464 return NULL;
467 static inline ban_record_t *ban_record_check(const enet_uint32 host) {
468 for (ban_record_t *b = banlist; b; b = b->next) {
469 if ((b->host & b->mask) == (host & b->mask))
470 return b;
472 return NULL;
475 static ban_record_t *ban_record_add_addr(const enet_uint32 host, const enet_uint32 mask, const int cnt, const time_t cur) {
476 ban_record_t *rec = ban_record_check(host);
477 if (rec) return rec;
479 rec = calloc(1, sizeof(*rec));
480 if (!rec) return NULL;
482 rec->host = host & mask;
483 rec->mask = mask;
484 if (rec->mask == 0) rec->mask = NET_FULLMASK;
485 rec->ban_count = cnt;
486 rec->cur_ban = cur;
488 if (banlist) banlist->prev = rec;
489 rec->next = banlist;
490 banlist = rec;
492 return rec;
495 static ban_record_t *ban_record_add_ip(const char *ip, const int cnt, const time_t cur) {
496 enet_uint32 prefix = 32;
498 // find and get the prefix length, if any
499 char ip_copy[24] = { 0 };
500 strncpy(ip_copy, ip, sizeof(ip_copy) - 1);
501 char *slash = strrchr(ip_copy, '/');
502 if (slash) {
503 *slash++ = '\0'; // strip the prefix length off
504 if (*slash) prefix = atoi(slash);
507 ENetAddress addr = { 0 };
508 if (enet_address_set_host_ip(&addr, ip_copy) != 0) {
509 u_log(LOG_ERROR, "banlist: `%s` is not a valid IP address", ip_copy);
510 return NULL;
513 // transform prefix length into mask
514 const enet_uint32 mask = u_prefixtomask(prefix);
516 return ban_record_add_addr(addr.host, mask, cnt, cur);
519 static void ban_free_list(void) {
520 ban_record_t *rec = banlist;
521 while (rec) {
522 ban_record_t *next = rec->next;
523 free(rec);
524 rec = next;
526 banlist = NULL;
529 static void ban_load_list(const char *fname) {
530 FILE *f = fopen(fname, "r");
531 if (!f) {
532 u_log(LOG_WARN, "banlist: could not open %s for reading", fname);
533 return;
536 char ln[MAX_STRLEN] = { 0 };
538 while (fgets(ln, sizeof(ln), f)) {
539 for (int i = sizeof(ln) - 1; i >= 0; --i)
540 if (ln[i] == '\n' || ln[i] == '\r')
541 ln[i] = 0;
543 if (ln[0] == 0)
544 continue;
546 char ip[21] = { 0 }; // optionally includes the "/nn" prefix length at the end
547 time_t exp = 0;
548 int count = 0;
549 if (sscanf(ln, "%20s %ld %d", ip, &exp, &count) < 3) {
550 u_log(LOG_ERROR, "banlist: malformed line: `%s`", ln);
551 continue;
554 if (ban_record_add_ip(ip, count, exp))
555 u_log(LOG_NOTE, "banlist: banned %s until %s (ban level %d)", ip, u_strtime(exp), count);
558 fclose(f);
561 static void ban_save_list(const char *fname) {
562 FILE *f = fopen(fname, "w");
563 if (!f) {
564 u_log(LOG_ERROR, "banlist: could not open %s for writing", fname);
565 return;
568 for (ban_record_t *rec = banlist; rec; rec = rec->next) {
569 if (rec->ban_count)
570 fprintf(f, "%s/%u %ld %d\n", u_iptostr(rec->host), u_masktoprefix(rec->mask), rec->cur_ban, rec->ban_count);
573 fclose(f);
576 static bool ban_sanity_check(const server_t *srv) {
577 // can't have more than 24 maxplayers; can't have more than max
578 if (srv->players > srv->maxplayers || srv->maxplayers > SV_MAX_PLAYERS || srv->maxplayers == 0)
579 return false;
580 // name and map have to be non-garbage
581 if (!u_strisprint(srv->map) || !u_strisprint(srv->name))
582 return false;
583 // these protocols don't exist
584 if (srv->proto < SV_PROTO_MIN || srv->proto > SV_PROTO_MAX)
585 return false;
586 // the game doesn't allow server names longer than 64 chars
587 if (strlen(srv->name) > SV_NAME_MAX)
588 return false;
589 // game mode has to actually exist
590 if (srv->gamemode > SV_MAX_GAMEMODE)
591 return false;
592 // flags field can't be higher than the sum of all the flags
593 if (srv->flags > SV_FL_MAX)
594 return false;
595 return true;
598 static void ban_add(const enet_uint32 host, const char *reason) {
599 const time_t now = time(NULL);
601 ban_record_t *rec = ban_record_add_addr(host, NET_FULLMASK, 0, 0);
602 if (!rec) u_fatal("OOM trying to ban %s", u_iptostr(host));
604 rec->cur_ban = now + ban_get_time(rec->ban_count);
605 rec->ban_count++;
607 u_log(LOG_NOTE, "banned %s until %s, reason: %s, ban level: %d", u_iptostr(rec->host), u_strtime(rec->cur_ban), reason, rec->ban_count);
609 ban_save_list(MS_BAN_FILE);
611 sv_remove_by_host(host, NET_FULLMASK);
613 if (host == cl_last_addr)
614 cl_last_addr = 0;
617 static inline void ban_peer(ENetPeer *peer, const char *reason) {
618 if (peer) {
619 ban_add(peer->address.host, reason);
620 sv_clear_peer(peer);
621 enet_peer_reset(peer);
625 /* main */
627 static void deinit(void) {
628 // ban_save_list(MS_BAN_FILE);
629 ban_free_list();
630 if (ms_host) {
631 enet_host_destroy(ms_host);
632 ms_host = NULL;
634 enet_deinitialize();
637 #ifdef SIGUSR1
638 static void sigusr_handler(int signum) {
639 if (signum == SIGUSR1) {
640 u_log(LOG_WARN, "received SIGUSR1, reloading banlist");
641 ban_free_list();
642 ban_load_list(MS_BAN_FILE);
645 #endif
647 static bool handle_msg(const enet_uint8 msgid, ENetPeer *peer) {
648 server_t *sv = NULL;
649 server_t tmpsv = { 0 };
650 char clientver[MAX_STRLEN] = { 0 };
651 const time_t now = time(NULL);
653 switch (msgid) {
654 case NET_MSG_ADD:
655 tmpsv.port = b_read_uint16(&buf_recv);
656 b_read_dstring_to(&buf_recv, tmpsv.name, sizeof(tmpsv.name));
657 b_read_dstring_to(&buf_recv, tmpsv.map, sizeof(tmpsv.map));
658 tmpsv.gamemode = b_read_uint8(&buf_recv);
659 tmpsv.players = b_read_uint8(&buf_recv);
660 tmpsv.maxplayers = b_read_uint8(&buf_recv);
661 tmpsv.proto = b_read_uint8(&buf_recv);
662 tmpsv.flags = b_read_uint8(&buf_recv);
664 if (buf_recv.overflow) {
665 ban_peer(peer, "malformed MSG_ADD");
666 return true;
669 sv = sv_find_or_add(peer->address.host, tmpsv.port);
670 if (!sv) {
671 u_log(LOG_ERROR, "ran out of server slots trying to add %s:%d", u_iptostr(peer->address.host), tmpsv.port);
672 return true;
675 if (sv->host == peer->address.host) {
676 // old server; update it
677 memcpy(sv->map, tmpsv.map, sizeof(sv->map));
678 memcpy(sv->name, tmpsv.name, sizeof(sv->name));
679 sv->players = tmpsv.players;
680 sv->maxplayers = tmpsv.maxplayers;
681 sv->flags = tmpsv.flags;
682 sv->gamemode = tmpsv.gamemode;
683 // first check if the new values are garbage
684 if (!ban_sanity_check(sv)) {
685 ban_peer(peer, "tripped sanity check");
686 return true;
688 // only then update the times
689 sv->death_time = now + ms_sv_timeout;
690 sv->timestamp = now;
691 // check if we're updating from a new peer
692 if (sv->peer != peer) {
693 // if there was an old one, kill it
694 if (sv->peer) {
695 sv->peer->data = NULL;
696 enet_peer_reset(sv->peer);
698 sv->peer = peer;
699 peer->data = sv;
701 u_log(LOG_NOTE, "updated server #%d:", sv - servers);
702 u_printsv(sv);
703 } else {
704 // new server; first check if this host is creating too many servers in the list
705 if (max_servers_per_host) {
706 const int count = sv_count_by_host(peer->address.host, NET_FULLMASK);
707 if (count >= max_servers_per_host) {
708 ban_peer(peer, "too many servers in list");
709 return true;
711 /*
712 // FIXME: commented out as this might trip when the master restarts
713 if (count > 0) {
714 // check if this is too soon to create a new server
715 const time_t delta = now - sv_last_timestamp_for_host(peer->address.host, NET_FULLMASK);
716 if (delta < count * SV_NEW_SERVER_INTERVAL) {
717 ban_peer(peer, "creating servers too fast");
718 return true;
721 */
723 // then add that shit
724 *sv = tmpsv;
725 sv->host = peer->address.host;
726 sv->death_time = now + ms_sv_timeout;
727 sv->timestamp = now;
728 if (!ban_sanity_check(sv)) {
729 sv->host = 0;
730 sv->port = 0;
731 ban_peer(peer, "tripped sanity check");
732 return true;
734 sv->peer = peer;
735 peer->data = sv;
736 ++num_servers;
737 u_log(LOG_NOTE, "added new server #%d:", sv - servers);
738 u_printsv(sv);
740 return true;
742 case NET_MSG_RM:
743 tmpsv.port = b_read_uint16(&buf_recv);
744 if (buf_recv.overflow) {
745 ban_peer(peer, "malformed MSG_RM");
746 return true;
748 sv_remove_by_addr(peer->address.host, tmpsv.port);
749 // this peer can be disconnected pretty much immediately since he has no servers left, tell him to fuck off
750 sv_clear_peer(peer);
751 enet_peer_disconnect_later(peer, 0);
752 return true;
754 case NET_MSG_LIST:
755 buf_send.pos = 0;
756 buf_send.overflow = 0;
757 b_write_uint8(&buf_send, NET_MSG_LIST);
759 clientver[0] = 0;
760 if (buf_recv.size > 2) {
761 // holy shit a fresh client
762 b_read_dstring_to(&buf_recv, clientver, sizeof(clientver));
763 b_write_uint8(&buf_send, num_servers);
764 } else {
765 // old client; feed him fake servers first
766 b_write_uint8(&buf_send, num_servers + num_fake_servers);
767 for (int i = 0; i < num_fake_servers; ++i)
768 b_write_server(&buf_send, &fake_servers[i]);
771 if (buf_recv.overflow) {
772 ban_peer(peer, "malformed MSG_LIST");
773 return true;
776 if (clientver[0] && !u_strisver(clientver)) {
777 ban_peer(peer, "malformed MSG_LIST clientver");
778 return true;
781 for (int i = 0; i < max_servers; ++i) {
782 if (servers[i].host)
783 b_write_server(&buf_send, servers + i);
786 if (clientver[0]) {
787 // TODO: check if this client is outdated (?) and send back new verstring
788 // for now just write the same shit back
789 b_write_dstring(&buf_send, clientver);
790 // write the motd and urgent message
791 b_write_dstring(&buf_send, ms_motd);
792 b_write_dstring(&buf_send, ms_urgent);
795 ENetPacket *p = enet_packet_create(buf_send.data, buf_send.pos, ENET_PACKET_FLAG_RELIABLE);
796 enet_peer_send(peer, NET_CH_MAIN, p);
797 // enet_host_flush(ms_host);
799 // this peer can be disconnected pretty much immediately after receiving the server list, tell him to fuck off
800 sv_clear_peer(peer);
801 enet_peer_disconnect_later(peer, 0);
803 u_log(LOG_NOTE, "sent server list to %s:%d (ver %s)", u_iptostr(peer->address.host), peer->address.port, clientver[0] ? clientver : "<old>");
804 return true;
806 default:
807 break;
810 return false;
813 static void print_usage(void) {
814 printf("Usage: d2df_master [OPTIONS...]\n");
815 printf("Available options:\n");
816 printf("-h show this message and exit\n");
817 printf("-p N listen on port N (default: %d)\n", DEFAULT_PORT);
818 printf("-t N seconds before server is removed from list (default: %d)\n", DEFAULT_SERVER_TIMEOUT);
819 printf("-c N how long a client is allowed to hold the connection active (default: %d)\n", DEFAULT_CLIENT_TIMEOUT);
820 printf("-s N max number of servers in server list, 1-%d (default: %d)\n", MS_MAX_SERVERS, DEFAULT_MAX_SERVERS);
821 printf("-d N if N > 0, disallow more than N servers on the same IP (default: %d)\n", DEFAULT_MAX_PER_HOST);
822 printf("-f N crappy spam filter: ban clients after they send N requests in a row too fast (default: %d)\n", DEFAULT_SPAM_CAP);
823 printf("-w N how often does a client have to send packets for the filter to kick in, i.e. once every N sec (default: %d)\n", DEFAULT_SPAM_TIMEOUT);
824 fflush(stdout);
827 static inline bool parse_int_arg(int argc, char **argv, const int i, const char *name, int vmin, int vmax, int *outval) {
828 if (strcmp(name, argv[i]))
829 return false;
831 if (i >= argc - 1) {
832 fprintf(stderr, "expected integer value after %s\n", name);
833 return false;
836 const int v = atoi(argv[i + 1]);
837 if (v < vmin || v > vmax) {
838 fprintf(stderr, "expected integer value in range %d - %d\n", vmin, vmax);
839 return false;
842 *outval = v;
843 return true;
846 static bool parse_args(int argc, char **argv) {
847 if (argc < 2)
848 return true;
850 if (!strcmp(argv[1], "-h")) {
851 print_usage();
852 return false;
855 for (int i = 1; i < argc; ++i) {
856 const bool success =
857 parse_int_arg(argc, argv, i, "-p", 1, 0xFFFF, &ms_port)
858 || parse_int_arg(argc, argv, i, "-t", 1, 0x7FFFFFFF, &ms_sv_timeout)
859 || parse_int_arg(argc, argv, i, "-c", 1, 0x7FFFFFFF, &ms_cl_timeout)
860 || parse_int_arg(argc, argv, i, "-s", 1, MS_MAX_SERVERS, &max_servers)
861 || parse_int_arg(argc, argv, i, "-d", 0, MS_MAX_SERVERS, &max_servers_per_host)
862 || parse_int_arg(argc, argv, i, "-f", 0, 0xFFFF, &ms_spam_cap)
863 || parse_int_arg(argc, argv, i, "-w", 1, 0x7FFFFFFF, &ms_spam_timeout);
864 if (success) {
865 ++i;
866 } else {
867 fprintf(stderr, "unknown or invalid argument: %s\n", argv[i]);
868 return false;
872 return true;
875 // a stupid thing to filter sustained spam from a single IP
876 static bool spam_filter(ENetPeer *peer, const time_t now) {
877 if (peer->address.host == cl_last_addr) {
878 // spam === sending shit faster than once a second
879 if (now - cl_last_time < ms_spam_timeout) {
880 if (cl_spam_cnt > 1)
881 u_log(LOG_WARN, "address %s is sending packets too fast", u_iptostr(peer->address.host));
882 if (++cl_spam_cnt >= ms_spam_cap) {
883 ban_peer(peer, "spam");
884 cl_last_addr = 0;
885 return true;
887 } else {
888 cl_spam_cnt = 0;
890 } else {
891 cl_last_addr = peer->address.host;
892 cl_spam_cnt = 0;
894 cl_last_time = now;
895 return false;
898 // filter incoming UDP packets before the protocol kicks in
899 static int packet_filter(ENetHost *host, ENetEvent *event) {
900 return !!ban_check(host->receivedAddress.host);
903 int main(int argc, char **argv) {
904 if (enet_initialize() != 0)
905 u_fatal("could not init enet");
907 if (!parse_args(argc, argv))
908 return 1; // early exit
910 u_log(LOG_NOTE, "d2df master server starting on port %d", ms_port);
912 if (!u_readtextfile(MS_MOTD_FILE, ms_motd, sizeof(ms_motd)))
913 u_log(LOG_NOTE, "couldn't read motd from %s", MS_MOTD_FILE);
914 else
915 u_log(LOG_NOTE, "motd: %s", ms_motd);
917 if (!u_readtextfile(MS_URGENT_FILE, ms_urgent, sizeof(ms_urgent)))
918 u_log(LOG_NOTE, "couldn't read urgentmsg from %s", MS_URGENT_FILE);
919 else
920 u_log(LOG_NOTE, "urgentmsg: %s", ms_urgent);
922 ban_load_list(MS_BAN_FILE);
924 atexit(deinit);
926 #ifdef SIGUSR1
927 signal(SIGUSR1, sigusr_handler);
928 #endif
930 ENetAddress addr;
931 addr.host = 0;
932 addr.port = ms_port;
933 ms_host = enet_host_create(&addr, MS_MAX_CLIENTS, NET_CH_COUNT + 1, 0, 0);
934 if (!ms_host)
935 u_fatal("could not create enet host on port %d", ms_port);
937 ms_host->intercept = packet_filter;
939 bool running = true;
940 enet_uint8 msgid = 0;
941 ENetEvent event;
942 while (running) {
943 while (enet_host_service(ms_host, &event, 10) > 0) {
944 const time_t now = time(NULL);
945 const bool filtered = !event.peer || (ms_spam_cap && spam_filter(event.peer, now));
947 if (!filtered) {
948 switch (event.type) {
949 case ENET_EVENT_TYPE_CONNECT:
950 u_log(LOG_NOTE, "%s:%d connected", u_iptostr(event.peer->address.host), event.peer->address.port);
951 if (event.peer->channelCount != NET_CH_COUNT)
952 ban_peer(event.peer, "what is this");
953 else
954 enet_peer_timeout(event.peer, 0, 0, ms_cl_timeout * 1000);
955 break;
957 case ENET_EVENT_TYPE_RECEIVE:
958 if (!event.packet || event.packet->dataLength == 0) {
959 ban_peer(event.peer, "empty packet");
960 break;
962 // set up receive buffer
963 buf_recv.pos = 0;
964 buf_recv.overflow = 0;
965 buf_recv.data = event.packet->data;
966 buf_recv.size = event.packet->dataLength;
967 // read message id and handle the message
968 msgid = b_read_uint8(&buf_recv);
969 if (!handle_msg(msgid, event.peer)) {
970 // cheeky cunt sending invalid messages
971 ban_peer(event.peer, "unknown message");
973 break;
975 case ENET_EVENT_TYPE_DISCONNECT:
977 // u_log(LOG_NOTE, "%s:%d disconnected", u_iptostr(event.peer->address.host), event.peer->address.port);
978 break;
980 default:
981 break;
983 } else if (event.peer) {
984 // u_log(LOG_WARN, "filtered event %d from %s", event.type, u_iptostr(event.peer->address.host));
985 sv_clear_peer(event.peer);
986 enet_peer_reset(event.peer);
989 if (event.packet) {
990 buf_recv.data = NULL;
991 enet_packet_destroy(event.packet);
995 const time_t now = time(NULL);
997 // time out servers
998 for (int i = 0; i < max_servers; ++i) {
999 if (servers[i].host && servers[i].death_time <= now) {
1000 u_log(LOG_NOTE, "server #%d %s:%d timed out", i, u_iptostr(servers[i].host), servers[i].port);
1001 sv_remove(servers + i);