DEADSOFTWARE

Game: Use proper syntax of sets for game options instead of raw bitwise operations
[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>
25 #include <fcntl.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
30 #include <enet/enet.h>
31 #include <enet/types.h>
33 #define MS_VERSION "0.3"
34 #define MS_MAX_SERVERS 128
35 #define MS_MAX_CLIENTS (MS_MAX_SERVERS + 1)
36 #define MS_URGENT_FILE "urgent.txt"
37 #define MS_MOTD_FILE "motd.txt"
38 #define MS_BAN_FILE "master_bans.txt"
39 #define MS_PIPE_FILE "d2df_master.pipe"
41 #define DEFAULT_SPAM_CAP 10
42 #define DEFAULT_MAX_SERVERS MS_MAX_SERVERS
43 #define DEFAULT_MAX_PER_HOST 4
44 #define DEFAULT_SERVER_TIMEOUT 100
45 #define DEFAULT_CLIENT_TIMEOUT 3
46 #define DEFAULT_SPAM_TIMEOUT 1
47 #define DEFAULT_PORT 25665
49 #define NET_BUFSIZE 65536
50 #define NET_FULLMASK 0xFFFFFFFF
52 #define SV_PROTO_MIN 140
53 #define SV_PROTO_MAX 210
54 #define SV_NAME_MAX 64
55 #define SV_MAP_MAX 64
56 #define SV_MAX_PLAYERS 24
57 #define SV_MAX_GAMEMODE 5
58 #define SV_NEW_SERVER_INTERVAL 3
60 #define MAX_STRLEN 0xFF
62 enum log_severity_e {
63 LOG_NOTE,
64 LOG_WARN,
65 LOG_ERROR
66 };
68 enum net_ch_e {
69 NET_CH_MAIN,
70 NET_CH_UPD,
71 NET_CH_COUNT
72 };
74 enum net_msg_e {
75 NET_MSG_ADD = 200,
76 NET_MSG_RM = 201,
77 NET_MSG_LIST = 202
78 };
80 enum sv_flags_e {
81 SV_FL_PASSWORD = 1 << 0,
82 SV_FL_VERIFIED = 1 << 1,
83 SV_FL_MAX = SV_FL_PASSWORD | SV_FL_VERIFIED,
84 };
86 typedef struct enet_buf_s {
87 enet_uint8 *data;
88 size_t size;
89 size_t pos;
90 int overflow;
91 } enet_buf_t;
93 typedef struct ban_record_s {
94 enet_uint32 host;
95 enet_uint32 mask;
96 int ban_count;
97 time_t cur_ban;
98 struct ban_record_s *next;
99 struct ban_record_s *prev;
100 } ban_record_t;
102 typedef struct server_s {
103 enet_uint32 host; // BE; 0 means this slot is unused
104 enet_uint16 port; // LE, which is what the game and enet both expect
105 enet_uint8 flags;
106 enet_uint8 proto;
107 enet_uint8 gamemode;
108 enet_uint8 players;
109 enet_uint8 maxplayers;
110 char name[MAX_STRLEN + 2];
111 char map[MAX_STRLEN + 2];
112 time_t death_time;
113 time_t timestamp;
114 ENetPeer *peer; // who sent this server in
115 } server_t;
117 // real servers
118 static server_t servers[MS_MAX_SERVERS];
119 static int max_servers = DEFAULT_MAX_SERVERS;
120 static int max_servers_per_host = DEFAULT_MAX_PER_HOST;
121 static int num_servers = 0;
123 // fake servers to show on old versions of the game
124 static const server_t fake_servers[] = {
126 .name = "! \xc2\xc0\xd8\xc0 \xca\xce\xcf\xc8\xdf \xc8\xc3\xd0\xdb "
127 "\xd3\xd1\xd2\xc0\xd0\xc5\xcb\xc0! "
128 "\xd1\xca\xc0\xd7\xc0\xc9\xd2\xc5 \xcd\xce\xc2\xd3\xde C "
129 "doom2d.org !",
130 .map = "! Your game is outdated. "
131 "Get latest version at doom2d.org !",
132 .proto = 255,
133 },
135 .name = "! \xcf\xd0\xce\xc1\xd0\xce\xd1\xdcTE \xcf\xce\xd0\xd2\xdb "
136 "25666 \xc8 57133 HA CEPBEPE \xcf\xc5\xd0\xc5\xc4 \xc8\xc3\xd0\xce\xc9 !",
137 .map = "! Forward ports 25666 and 57133 before hosting !",
138 .proto = 255,
139 },
140 };
141 static const int num_fake_servers = sizeof(fake_servers) / sizeof(*fake_servers);
143 // ban list
144 static ban_record_t *banlist;
146 // settings
147 static int ms_port = DEFAULT_PORT;
148 static int ms_sv_timeout = DEFAULT_SERVER_TIMEOUT;
149 static int ms_cl_timeout = DEFAULT_CLIENT_TIMEOUT;
150 static int ms_spam_timeout = DEFAULT_SPAM_TIMEOUT;
151 static int ms_spam_cap = DEFAULT_SPAM_CAP;
152 static char ms_motd[MAX_STRLEN + 1] = "";
153 static char ms_urgent[MAX_STRLEN + 1] = "";
154 static ENetHost *ms_host;
156 // network buffers
157 static enet_uint8 buf_send_data[NET_BUFSIZE];
158 static enet_buf_t buf_send = { .data = buf_send_data, .size = sizeof(buf_send_data) };
159 static enet_buf_t buf_recv; // rx data supplied by enet packets
161 // stupid client spam filter
162 static enet_uint32 cl_last_addr;
163 static time_t cl_last_time;
164 static int cl_spam_cnt;
166 /* common utility functions */
168 static char *u_strstrip(char *p) {
169 if (!p) return p;
170 while (isspace(*p)) ++p;
171 const size_t len = strlen(p);
172 if (len) {
173 for (size_t i = len - 1; i && isspace(p[i]); --i)
174 p[i] = '\0';
176 return p;
179 static char *u_vabuf(void) {
180 static char vabuf[4][MAX_STRLEN];
181 static int idx = 0;
182 char *ret = vabuf[idx++];
183 if (idx >= 4) idx = 0;
184 return ret;
187 static const char *u_strtime(const time_t t) {
188 char *buf = u_vabuf();
189 struct tm *ptm = localtime(&t);
190 strftime(buf, MAX_STRLEN - 1, "%d/%m/%y %H:%M:%S", ptm);
191 return buf;
194 static inline const char *u_logprefix(const enum log_severity_e s) {
195 switch (s) {
196 case LOG_WARN: return "WARNING: ";
197 case LOG_ERROR: return "ERROR: ";
198 default: return "";
202 static void u_log(const enum log_severity_e severity, const char *fmt, ...) {
203 printf("[%s] %s", u_strtime(time(NULL)), u_logprefix(severity));
204 va_list args;
205 va_start(args, fmt);
206 vprintf(fmt, args);
207 va_end(args);
208 printf("\n");
211 static void __attribute__((noreturn)) u_fatal(const char *fmt, ...) {
212 fprintf(stderr, "[%s] FATAL ERROR:\n", u_strtime(time(NULL)));
213 va_list args;
214 va_start(args, fmt);
215 vfprintf(stderr, fmt, args);
216 va_end(args);
217 fprintf(stderr, "\n");
218 fflush(stderr);
219 exit(1);
222 static bool u_strisprint(const char *str) {
223 if (!str || !*str)
224 return false;
225 for (const char *p = str; *p; ++p) {
226 // only stuff before space, DEL, NBSP and SHY are considered garbage since we're on 1251
227 if (*p < 0x20 || *p == 0x7F || *p == 0xA0 || *p == 0xAD)
228 return false;
230 return true;
233 static bool u_strisver(const char *str) {
234 if (!str || !*str)
235 return false;
236 for (const char *p = str; *p; ++p) {
237 // version strings consist of 0-9 . and space
238 if (!isdigit(*p) && *p != '.' && *p != ' ')
239 return false;
241 return true;
244 static const char *u_iptostr(const enet_uint32 host) {
245 ENetAddress addr = { .host = host, .port = 0 };
246 char *buf = u_vabuf();
247 enet_address_get_host_ip(&addr, buf, MAX_STRLEN - 1);
248 return buf;
251 static bool u_readtextfile(const char *fname, char *buf, size_t max) {
252 FILE *f = fopen(fname, "r");
253 char *const end = buf + max - 1;
254 char *p = buf;
255 if (f) {
256 char ln[max];
257 char *const lend = ln + max - 1;
258 while (p < end && fgets(ln, max, f)) {
259 for (char *n = ln; n < lend && *n && *n != '\r' && *n != '\n'; ++n) {
260 *(p++) = *n;
261 if (p == end) break;
264 *p = '\0';
265 fclose(f);
266 return true;
268 return false;
271 static inline enet_uint32 u_prefixtomask(const enet_uint32 prefix) {
272 return ENET_HOST_TO_NET_32((0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF);
275 static inline enet_uint32 u_masktoprefix(const enet_uint32 mask) {
276 return (32 - __builtin_ctz(ENET_NET_TO_HOST_32(mask)));
279 static inline void u_printsv(const server_t *sv) {
280 printf("* addr: %s:%d\n", u_iptostr(sv->host), sv->port);
281 printf("* name: %s\n", sv->name);
282 printf("* map: %s (mode %d)\n", sv->map, sv->gamemode);
283 printf("* plrs: %d/%d\n", sv->players, sv->maxplayers);
284 printf("* flag: %04x\n", sv->flags);
287 /* buffer utility functions */
289 static inline int b_enough_left(enet_buf_t *buf, size_t size) {
290 if (buf->pos + size > buf->size) {
291 buf->overflow = 1;
292 return 0;
294 return 1;
297 static enet_uint8 b_read_uint8(enet_buf_t *buf) {
298 if (b_enough_left(buf, 1))
299 return buf->data[buf->pos++];
300 return 0;
303 static enet_uint16 b_read_uint16(enet_buf_t *buf) {
304 enet_uint16 ret = 0;
306 if (b_enough_left(buf, sizeof(ret))) {
307 ret = *(enet_uint16*)(buf->data + buf->pos);
308 buf->pos += sizeof(ret);
311 return ret;
314 static char *b_read_dstring(enet_buf_t *buf) {
315 char *ret = NULL;
317 if (b_enough_left(buf, 1)) {
318 const size_t len = b_read_uint8(buf);
319 if (b_enough_left(buf, len)) {
320 ret = malloc(len + 1);
321 memmove(ret, (char*)(buf->data + buf->pos), len);
322 buf->pos += len;
323 ret[len] = '\0';
327 return ret;
330 static char *b_read_dstring_to(enet_buf_t *buf, char *out, size_t out_size) {
331 if (b_enough_left(buf, 1)) {
332 const size_t len = b_read_uint8(buf);
333 if (b_enough_left(buf, len)) {
334 if (len < out_size) {
335 memmove(out, (char*)(buf->data + buf->pos), len);
336 out[len] = '\0';
337 } else if (out_size) {
338 out[0] = '\0';
340 buf->pos += len;
341 return out;
344 return NULL;
347 static void b_write_uint8(enet_buf_t *buf, enet_uint8 val) {
348 buf->data[buf->pos++] = val;
351 static void b_write_uint16(enet_buf_t *buf, enet_uint16 val) {
352 *(enet_uint16*)(buf->data + buf->pos) = val;
353 buf->pos += sizeof(val);
356 static void b_write_dstring(enet_buf_t *buf, const char* val) {
357 enet_uint8 len = strlen(val);
358 b_write_uint8(buf, len);
359 memmove((char*)(buf->data + buf->pos), val, len);
360 buf->pos += len;
363 void b_write_server(enet_buf_t *buf, const server_t *s) {
364 b_write_dstring(buf, u_iptostr(s->host));
365 b_write_uint16 (buf, s->port);
366 b_write_dstring(buf, s->name);
367 b_write_dstring(buf, s->map);
368 b_write_uint8 (buf, s->gamemode);
369 b_write_uint8 (buf, s->players);
370 b_write_uint8 (buf, s->maxplayers);
371 b_write_uint8 (buf, s->proto);
372 b_write_uint8 (buf, (s->flags & SV_FL_PASSWORD));
375 /* server functions */
377 static inline void sv_remove(server_t *sv) {
378 if (sv->host) {
379 // drop the associated peer, if any
380 if (sv->peer && sv->peer->state == ENET_PEER_STATE_CONNECTED && sv->peer->data == sv) {
381 sv->peer->data = NULL;
382 enet_peer_reset(sv->peer);
384 sv->host = 0;
385 sv->port = 0;
386 sv->peer = NULL;
387 --num_servers;
391 static void sv_remove_by_addr(const enet_uint32 host, const enet_uint16 port) {
392 for (int i = 0; i < max_servers; ++i) {
393 if (servers[i].host == host && servers[i].port == port)
394 sv_remove(servers + i);
398 static void sv_remove_by_host(enet_uint32 host, enet_uint32 mask) {
399 host &= mask;
400 for (int i = 0; i < max_servers; ++i) {
401 if (servers[i].host && (servers[i].host & mask) == host)
402 sv_remove(servers + i);
406 static int sv_count_by_host(enet_uint32 host, enet_uint32 mask) {
407 host &= mask;
408 int count = 0;
409 for (int i = 0; i < max_servers; ++i) {
410 if (servers[i].host && (servers[i].host & mask) == host)
411 ++count;
413 return count;
416 static time_t sv_last_timestamp_for_host(enet_uint32 host, enet_uint32 mask) {
417 host &= mask;
418 time_t last = 0;
419 for (int i = 0; i < max_servers; ++i) {
420 if (servers[i].host && (servers[i].host & mask) == host) {
421 if (servers[i].timestamp > last)
422 last = servers[i].timestamp;
425 return last;
428 static inline server_t *sv_find_or_add(const enet_uint32 host, const enet_uint32 port) {
429 server_t *empty = NULL;
430 for (int i = 0; i < max_servers; ++i) {
431 server_t *s = servers + i;
432 if (s->host == host && s->port == port)
433 return s; // this server already exists
434 if (!s->host && !empty)
435 empty = s; // remember the first empty slot in case it's needed later
437 return empty;
440 static inline void sv_clear_peer(ENetPeer *peer) {
441 server_t *sv = peer->data;
442 if (sv) {
443 sv->peer = NULL;
444 peer->data = NULL;
448 /* ban list functions */
450 static inline time_t ban_get_time(const int cnt) {
451 static const time_t times[] = {
452 1 * 5 * 60,
453 1 * 30 * 60,
454 1 * 60 * 60,
455 24 * 60 * 60,
456 72 * 60 * 60,
457 720 * 60 * 60,
458 8760 * 60 * 60,
459 };
461 static const size_t numtimes = sizeof(times) / sizeof(*times);
463 if (cnt >= numtimes || cnt < 0)
464 return times[numtimes - 1];
466 return times[cnt];
469 static ban_record_t *ban_check(const enet_uint32 host) {
470 const time_t now = time(NULL);
472 for (ban_record_t *b = banlist; b; b = b->next) {
473 if ((b->host & b->mask) == (host & b->mask)) {
474 if (b->cur_ban > now)
475 return b;
479 return NULL;
482 static inline ban_record_t *ban_record_check(const enet_uint32 host) {
483 for (ban_record_t *b = banlist; b; b = b->next) {
484 if ((b->host & b->mask) == (host & b->mask))
485 return b;
487 return NULL;
490 static ban_record_t *ban_record_add_addr(const enet_uint32 host, const enet_uint32 mask, const int cnt, const time_t cur) {
491 ban_record_t *rec = ban_record_check(host);
492 if (rec) return rec;
494 rec = calloc(1, sizeof(*rec));
495 if (!rec) return NULL;
497 rec->host = host & mask;
498 rec->mask = mask;
499 if (rec->mask == 0) rec->mask = NET_FULLMASK;
500 rec->ban_count = cnt;
501 rec->cur_ban = cur;
503 if (banlist) banlist->prev = rec;
504 rec->next = banlist;
505 banlist = rec;
507 return rec;
510 static enet_uint32 ban_parse_ip_mask(const char *ip, enet_uint32 *out_mask) {
511 enet_uint32 prefix = 32;
513 // find and get the prefix length, if any
514 char ip_copy[24] = { 0 };
515 strncpy(ip_copy, ip, sizeof(ip_copy) - 1);
516 char *slash = strrchr(ip_copy, '/');
517 if (slash) {
518 *slash++ = '\0'; // strip the prefix length off
519 if (*slash) prefix = atoi(slash);
522 ENetAddress addr = { 0 };
523 if (enet_address_set_host_ip(&addr, ip_copy) != 0)
524 return 0;
526 // transform prefix length into mask
527 *out_mask = u_prefixtomask(prefix);
529 return addr.host;
532 static ban_record_t *ban_record_add_ip(const char *ip, const int cnt, const time_t cur) {
533 enet_uint32 mask = 0;
534 const enet_uint32 host = ban_parse_ip_mask(ip, &mask);
535 if (!host) {
536 u_log(LOG_ERROR, "banlist: `%s` is not a valid address", ip);
537 return NULL;
539 return ban_record_add_addr(host, mask, cnt, cur);
542 static void ban_free_list(void) {
543 ban_record_t *rec = banlist;
544 while (rec) {
545 ban_record_t *next = rec->next;
546 free(rec);
547 rec = next;
549 banlist = NULL;
552 static bool ban_record_remove_addr(const enet_uint32 host, const enet_uint32 mask) {
553 for (ban_record_t *b = banlist; b; b = b->next) {
554 if ((b->host == host) && (b->mask == mask)) {
555 if (b == banlist)
556 banlist = b->next;
557 if (b->next) b->next->prev = b->prev;
558 if (b->prev) b->prev->next = b->next;
559 free(b);
560 return true;
563 return false;
566 static bool ban_record_remove_ip(const char *ip) {
567 enet_uint32 mask = 0;
568 const enet_uint32 host = ban_parse_ip_mask(ip, &mask);
569 if (!host) {
570 u_log(LOG_ERROR, "unban: `%s` is not a valid address", ip);
571 return NULL;
573 return ban_record_remove_addr(host, mask);
576 static void ban_load_list(const char *fname) {
577 FILE *f = fopen(fname, "r");
578 if (!f) {
579 u_log(LOG_WARN, "banlist: could not open %s for reading", fname);
580 return;
583 char ln[MAX_STRLEN] = { 0 };
585 while (fgets(ln, sizeof(ln), f)) {
586 for (int i = sizeof(ln) - 1; i >= 0; --i)
587 if (ln[i] == '\n' || ln[i] == '\r')
588 ln[i] = 0;
590 if (ln[0] == 0)
591 continue;
593 char ip[21] = { 0 }; // optionally includes the "/nn" prefix length at the end
594 int expd = 0;
595 int count = 0;
596 if (sscanf(ln, "%20s %d %d", ip, &expd, &count) < 3) {
597 u_log(LOG_ERROR, "banlist: malformed line: `%s`", ln);
598 continue;
601 const time_t exp = (time_t)expd; // shut up gcc
602 if (ban_record_add_ip(ip, count, exp))
603 u_log(LOG_NOTE, "banlist: banned %s until %s (ban level %d)", ip, u_strtime(exp), count);
606 fclose(f);
609 static void ban_save_list(const char *fname) {
610 FILE *f = fopen(fname, "w");
611 if (!f) {
612 u_log(LOG_ERROR, "banlist: could not open %s for writing", fname);
613 return;
616 for (ban_record_t *rec = banlist; rec; rec = rec->next) {
617 if (rec->ban_count)
618 fprintf(f, "%s/%u %d %d\n", u_iptostr(rec->host), u_masktoprefix(rec->mask), (int)rec->cur_ban, rec->ban_count);
621 fclose(f);
624 static bool ban_sanity_check(const server_t *srv) {
625 // can't have more than 24 maxplayers; can't have more than max
626 if (srv->players > srv->maxplayers || srv->maxplayers > SV_MAX_PLAYERS || srv->maxplayers == 0)
627 return false;
628 // name and map have to be non-garbage
629 if (!u_strisprint(srv->map) || !u_strisprint(srv->name))
630 return false;
631 // these protocols don't exist
632 if (srv->proto < SV_PROTO_MIN || srv->proto > SV_PROTO_MAX)
633 return false;
634 // the game doesn't allow server names longer than 64 chars
635 if (strlen(srv->name) > SV_NAME_MAX)
636 return false;
637 // game mode has to actually exist
638 if (srv->gamemode > SV_MAX_GAMEMODE)
639 return false;
640 // flags field can't be higher than the sum of all the flags
641 if (srv->flags > SV_FL_MAX)
642 return false;
643 return true;
646 static void ban_add_mask(const enet_uint32 host, const enet_uint32 mask, const char *reason) {
647 const time_t now = time(NULL);
649 ban_record_t *rec = ban_record_add_addr(host, mask, 0, 0);
650 if (!rec) u_fatal("OOM trying to ban %s", u_iptostr(host));
652 rec->cur_ban = now + ban_get_time(rec->ban_count);
653 rec->ban_count++;
655 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);
657 ban_save_list(MS_BAN_FILE);
659 sv_remove_by_host(host, mask);
661 if (host == cl_last_addr)
662 cl_last_addr = 0;
665 static void ban_add(const enet_uint32 host, const char *reason) {
666 const time_t now = time(NULL);
668 ban_record_t *rec = ban_record_add_addr(host, NET_FULLMASK, 0, 0);
669 if (!rec) u_fatal("OOM trying to ban %s", u_iptostr(host));
671 rec->cur_ban = now + ban_get_time(rec->ban_count);
672 rec->ban_count++;
674 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);
676 ban_save_list(MS_BAN_FILE);
678 sv_remove_by_host(host, NET_FULLMASK);
680 if (host == cl_last_addr)
681 cl_last_addr = 0;
684 static void ban_remove_mask(const enet_uint32 host, const enet_uint32 mask) {
685 if (!ban_record_remove_addr(host, mask)) {
686 u_log(LOG_ERROR, "could not find %s in ban list", u_iptostr(host));
687 return;
689 u_log(LOG_NOTE, "unbanned %s", u_iptostr(host));
690 ban_save_list(MS_BAN_FILE);
693 static inline void ban_peer(ENetPeer *peer, const char *reason) {
694 if (peer) {
695 ban_add(peer->address.host, reason);
696 sv_clear_peer(peer);
697 enet_peer_reset(peer);
701 /* main */
703 #if ENABLE_PIPE
705 static int io_fd = -1;
707 static bool io_install_pipe(void) {
708 const int rc = mkfifo(MS_PIPE_FILE, 0664);
709 if (rc < 0 && errno != EEXIST) {
710 u_log(LOG_ERROR, "io_install_pipe(): mkfifo(): %s", strerror(errno));
711 return false;
714 io_fd = open(MS_PIPE_FILE, O_RDONLY | O_NONBLOCK);
715 if (io_fd < 0) {
716 u_log(LOG_ERROR, "io_install_pipe(): open(): %s", strerror(errno));
717 remove(MS_PIPE_FILE);
718 return false;
721 return true;
724 static void io_uninstall_pipe(void) {
725 if (io_fd >= 0) {
726 close(io_fd);
727 io_fd = -1;
729 remove(MS_PIPE_FILE);
732 static void io_read_commands(void) {
733 if (io_fd < 0)
734 return;
736 char cmd[128];
737 const int cmd_len = read(io_fd, cmd, sizeof(cmd) - 1);
738 if (cmd_len < 1)
739 return;
740 cmd[cmd_len] = '\0';
742 if (!strncmp(cmd, "ban ", 4)) {
743 const char *ip = u_strstrip(cmd + 4); // skip "ban "
744 enet_uint32 mask = 0;
745 enet_uint32 host = ban_parse_ip_mask(ip, &mask);
746 if (!host) {
747 u_log(LOG_ERROR, "ban: `%s` is not a valid address", ip);
748 return;
750 ban_add_mask(host, mask, "banned by console");
751 } else if (!strncmp(cmd, "unban ", 6)) {
752 const char *ip = u_strstrip(cmd + 6); // skip "unban "
753 enet_uint32 mask = 0;
754 enet_uint32 host = ban_parse_ip_mask(ip, &mask);
755 if (!host) {
756 u_log(LOG_ERROR, "ban: `%s` is not a valid address", ip);
757 return;
759 ban_remove_mask(host, mask);
760 } else if (!strncmp(cmd, "reload", 6)) {
761 u_log(LOG_WARN, "reloading banlist");
762 ban_free_list();
763 ban_load_list(MS_BAN_FILE);
764 } else if (!strncmp(cmd, "die", 3)) {
765 u_log(LOG_WARN, "shutting down");
766 exit(0);
770 #endif
772 static void deinit(void) {
773 // ban_save_list(MS_BAN_FILE);
774 ban_free_list();
775 if (ms_host) {
776 enet_host_destroy(ms_host);
777 ms_host = NULL;
779 enet_deinitialize();
780 #ifdef ENABLE_PIPE
781 io_uninstall_pipe();
782 #endif
785 static bool handle_msg(const enet_uint8 msgid, ENetPeer *peer) {
786 server_t *sv = NULL;
787 server_t tmpsv = { 0 };
788 char clientver[MAX_STRLEN] = { 0 };
789 const time_t now = time(NULL);
791 switch (msgid) {
792 case NET_MSG_ADD:
793 tmpsv.port = b_read_uint16(&buf_recv);
794 b_read_dstring_to(&buf_recv, tmpsv.name, sizeof(tmpsv.name));
795 b_read_dstring_to(&buf_recv, tmpsv.map, sizeof(tmpsv.map));
796 tmpsv.gamemode = b_read_uint8(&buf_recv);
797 tmpsv.players = b_read_uint8(&buf_recv);
798 tmpsv.maxplayers = b_read_uint8(&buf_recv);
799 tmpsv.proto = b_read_uint8(&buf_recv);
800 tmpsv.flags = b_read_uint8(&buf_recv);
802 if (buf_recv.overflow) {
803 ban_peer(peer, "malformed MSG_ADD");
804 return true;
807 sv = sv_find_or_add(peer->address.host, tmpsv.port);
808 if (!sv) {
809 u_log(LOG_ERROR, "ran out of server slots trying to add %s:%d", u_iptostr(peer->address.host), tmpsv.port);
810 return true;
813 if (sv->host == peer->address.host) {
814 // old server; update it
815 memcpy(sv->map, tmpsv.map, sizeof(sv->map));
816 memcpy(sv->name, tmpsv.name, sizeof(sv->name));
817 sv->players = tmpsv.players;
818 sv->maxplayers = tmpsv.maxplayers;
819 sv->flags = tmpsv.flags;
820 sv->gamemode = tmpsv.gamemode;
821 // first check if the new values are garbage
822 if (!ban_sanity_check(sv)) {
823 ban_peer(peer, "tripped sanity check");
824 return true;
826 // only then update the times
827 sv->death_time = now + ms_sv_timeout;
828 sv->timestamp = now;
829 // check if we're updating from a new peer
830 if (sv->peer != peer) {
831 // if there was an old one, kill it
832 if (sv->peer) {
833 sv->peer->data = NULL;
834 enet_peer_reset(sv->peer);
836 sv->peer = peer;
837 peer->data = sv;
839 u_log(LOG_NOTE, "updated server #%d:", sv - servers);
840 u_printsv(sv);
841 } else {
842 // new server; first check if this host is creating too many servers in the list
843 if (max_servers_per_host) {
844 const int count = sv_count_by_host(peer->address.host, NET_FULLMASK);
845 if (count >= max_servers_per_host) {
846 ban_peer(peer, "too many servers in list");
847 return true;
849 /*
850 // FIXME: commented out as this might trip when the master restarts
851 if (count > 0) {
852 // check if this is too soon to create a new server
853 const time_t delta = now - sv_last_timestamp_for_host(peer->address.host, NET_FULLMASK);
854 if (delta < count * SV_NEW_SERVER_INTERVAL) {
855 ban_peer(peer, "creating servers too fast");
856 return true;
859 */
861 // then add that shit
862 *sv = tmpsv;
863 sv->host = peer->address.host;
864 sv->death_time = now + ms_sv_timeout;
865 sv->timestamp = now;
866 if (!ban_sanity_check(sv)) {
867 sv->host = 0;
868 sv->port = 0;
869 ban_peer(peer, "tripped sanity check");
870 return true;
872 sv->peer = peer;
873 peer->data = sv;
874 ++num_servers;
875 u_log(LOG_NOTE, "added new server #%d:", sv - servers);
876 u_printsv(sv);
878 return true;
880 case NET_MSG_RM:
881 tmpsv.port = b_read_uint16(&buf_recv);
882 if (buf_recv.overflow) {
883 ban_peer(peer, "malformed MSG_RM");
884 return true;
886 sv_remove_by_addr(peer->address.host, tmpsv.port);
887 // this peer can be disconnected pretty much immediately since he has no servers left, tell him to fuck off
888 sv_clear_peer(peer);
889 enet_peer_disconnect_later(peer, 0);
890 return true;
892 case NET_MSG_LIST:
893 buf_send.pos = 0;
894 buf_send.overflow = 0;
895 b_write_uint8(&buf_send, NET_MSG_LIST);
897 clientver[0] = 0;
898 if (buf_recv.size > 2) {
899 // holy shit a fresh client
900 b_read_dstring_to(&buf_recv, clientver, sizeof(clientver));
901 b_write_uint8(&buf_send, num_servers);
902 } else {
903 // old client; feed him fake servers first
904 b_write_uint8(&buf_send, num_servers + num_fake_servers);
905 for (int i = 0; i < num_fake_servers; ++i)
906 b_write_server(&buf_send, &fake_servers[i]);
909 if (buf_recv.overflow) {
910 ban_peer(peer, "malformed MSG_LIST");
911 return true;
914 if (clientver[0] && !u_strisver(clientver)) {
915 ban_peer(peer, "malformed MSG_LIST clientver");
916 return true;
919 for (int i = 0; i < max_servers; ++i) {
920 if (servers[i].host)
921 b_write_server(&buf_send, servers + i);
924 if (clientver[0]) {
925 // TODO: check if this client is outdated (?) and send back new verstring
926 // for now just write the same shit back
927 b_write_dstring(&buf_send, clientver);
928 // write the motd and urgent message
929 b_write_dstring(&buf_send, ms_motd);
930 b_write_dstring(&buf_send, ms_urgent);
933 ENetPacket *p = enet_packet_create(buf_send.data, buf_send.pos, ENET_PACKET_FLAG_RELIABLE);
934 enet_peer_send(peer, NET_CH_MAIN, p);
935 // enet_host_flush(ms_host);
937 // this peer can be disconnected pretty much immediately after receiving the server list, tell him to fuck off
938 sv_clear_peer(peer);
939 enet_peer_disconnect_later(peer, 0);
941 u_log(LOG_NOTE, "sent server list to %s:%d (ver %s)", u_iptostr(peer->address.host), peer->address.port, clientver[0] ? clientver : "<old>");
942 return true;
944 default:
945 break;
948 return false;
951 static void print_usage(void) {
952 printf("Usage: d2df_master [OPTIONS...]\n");
953 printf("Available options:\n");
954 printf("-h show this message and exit\n");
955 printf("-p N listen on port N (default: %d)\n", DEFAULT_PORT);
956 printf("-t N seconds before server is removed from list (default: %d)\n", DEFAULT_SERVER_TIMEOUT);
957 printf("-c N how long a client is allowed to hold the connection active (default: %d)\n", DEFAULT_CLIENT_TIMEOUT);
958 printf("-s N max number of servers in server list, 1-%d (default: %d)\n", MS_MAX_SERVERS, DEFAULT_MAX_SERVERS);
959 printf("-d N if N > 0, disallow more than N servers on the same IP (default: %d)\n", DEFAULT_MAX_PER_HOST);
960 printf("-f N crappy spam filter: ban clients after they send N requests in a row too fast (default: %d)\n", DEFAULT_SPAM_CAP);
961 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);
962 fflush(stdout);
965 static inline bool parse_int_arg(int argc, char **argv, const int i, const char *name, int vmin, int vmax, int *outval) {
966 if (strcmp(name, argv[i]))
967 return false;
969 if (i >= argc - 1) {
970 fprintf(stderr, "expected integer value after %s\n", name);
971 return false;
974 const int v = atoi(argv[i + 1]);
975 if (v < vmin || v > vmax) {
976 fprintf(stderr, "expected integer value in range %d - %d\n", vmin, vmax);
977 return false;
980 *outval = v;
981 return true;
984 static bool parse_args(int argc, char **argv) {
985 if (argc < 2)
986 return true;
988 if (!strcmp(argv[1], "-h")) {
989 print_usage();
990 return false;
993 for (int i = 1; i < argc; ++i) {
994 const bool success =
995 parse_int_arg(argc, argv, i, "-p", 1, 0xFFFF, &ms_port)
996 || parse_int_arg(argc, argv, i, "-t", 1, 0x7FFFFFFF, &ms_sv_timeout)
997 || parse_int_arg(argc, argv, i, "-c", 1, 0x7FFFFFFF, &ms_cl_timeout)
998 || parse_int_arg(argc, argv, i, "-s", 1, MS_MAX_SERVERS, &max_servers)
999 || parse_int_arg(argc, argv, i, "-d", 0, MS_MAX_SERVERS, &max_servers_per_host)
1000 || parse_int_arg(argc, argv, i, "-f", 0, 0xFFFF, &ms_spam_cap)
1001 || parse_int_arg(argc, argv, i, "-w", 1, 0x7FFFFFFF, &ms_spam_timeout);
1002 if (success) {
1003 ++i;
1004 } else {
1005 fprintf(stderr, "unknown or invalid argument: %s\n", argv[i]);
1006 return false;
1010 return true;
1013 // a stupid thing to filter sustained spam from a single IP
1014 static bool spam_filter(ENetPeer *peer, const time_t now) {
1015 if (peer->address.host == cl_last_addr) {
1016 // spam === sending shit faster than once a second
1017 if (now - cl_last_time < ms_spam_timeout) {
1018 if (cl_spam_cnt > 1)
1019 u_log(LOG_WARN, "address %s is sending packets too fast", u_iptostr(peer->address.host));
1020 if (++cl_spam_cnt >= ms_spam_cap) {
1021 ban_peer(peer, "spam");
1022 cl_last_addr = 0;
1023 return true;
1025 } else {
1026 cl_spam_cnt = 0;
1028 } else {
1029 cl_last_addr = peer->address.host;
1030 cl_spam_cnt = 0;
1032 cl_last_time = now;
1033 return false;
1036 // filter incoming UDP packets before the protocol kicks in
1037 static int packet_filter(ENetHost *host, ENetEvent *event) {
1038 return !!ban_check(host->receivedAddress.host);
1041 int main(int argc, char **argv) {
1042 if (enet_initialize() != 0)
1043 u_fatal("could not init enet");
1045 if (!parse_args(argc, argv))
1046 return 1; // early exit
1048 u_log(LOG_NOTE, "d2df master server starting on port %d", ms_port);
1050 if (!u_readtextfile(MS_MOTD_FILE, ms_motd, sizeof(ms_motd)))
1051 u_log(LOG_NOTE, "couldn't read motd from %s", MS_MOTD_FILE);
1052 else
1053 u_log(LOG_NOTE, "motd: %s", ms_motd);
1055 if (!u_readtextfile(MS_URGENT_FILE, ms_urgent, sizeof(ms_urgent)))
1056 u_log(LOG_NOTE, "couldn't read urgentmsg from %s", MS_URGENT_FILE);
1057 else
1058 u_log(LOG_NOTE, "urgentmsg: %s", ms_urgent);
1060 ban_load_list(MS_BAN_FILE);
1062 atexit(deinit);
1064 #ifdef ENABLE_PIPE
1065 io_install_pipe();
1066 #endif
1068 ENetAddress addr;
1069 addr.host = 0;
1070 addr.port = ms_port;
1071 ms_host = enet_host_create(&addr, MS_MAX_CLIENTS, NET_CH_COUNT + 1, 0, 0);
1072 if (!ms_host)
1073 u_fatal("could not create enet host on port %d", ms_port);
1075 ms_host->intercept = packet_filter;
1077 bool running = true;
1078 enet_uint8 msgid = 0;
1079 ENetEvent event;
1080 while (running) {
1081 while (enet_host_service(ms_host, &event, 10) > 0) {
1082 const time_t now = time(NULL);
1083 const bool filtered = !event.peer || (ms_spam_cap && spam_filter(event.peer, now));
1085 if (!filtered) {
1086 switch (event.type) {
1087 case ENET_EVENT_TYPE_CONNECT:
1088 u_log(LOG_NOTE, "%s:%d connected", u_iptostr(event.peer->address.host), event.peer->address.port);
1089 if (event.peer->channelCount != NET_CH_COUNT)
1090 ban_peer(event.peer, "what is this");
1091 else
1092 enet_peer_timeout(event.peer, 0, 0, ms_cl_timeout * 1000);
1093 break;
1095 case ENET_EVENT_TYPE_RECEIVE:
1096 if (!event.packet || event.packet->dataLength == 0) {
1097 ban_peer(event.peer, "empty packet");
1098 break;
1100 // set up receive buffer
1101 buf_recv.pos = 0;
1102 buf_recv.overflow = 0;
1103 buf_recv.data = event.packet->data;
1104 buf_recv.size = event.packet->dataLength;
1105 // read message id and handle the message
1106 msgid = b_read_uint8(&buf_recv);
1107 if (!handle_msg(msgid, event.peer)) {
1108 // cheeky cunt sending invalid messages
1109 ban_peer(event.peer, "unknown message");
1111 break;
1113 case ENET_EVENT_TYPE_DISCONNECT:
1115 // u_log(LOG_NOTE, "%s:%d disconnected", u_iptostr(event.peer->address.host), event.peer->address.port);
1116 break;
1118 default:
1119 break;
1121 } else if (event.peer) {
1122 // u_log(LOG_WARN, "filtered event %d from %s", event.type, u_iptostr(event.peer->address.host));
1123 sv_clear_peer(event.peer);
1124 enet_peer_reset(event.peer);
1127 if (event.packet) {
1128 buf_recv.data = NULL;
1129 enet_packet_destroy(event.packet);
1133 const time_t now = time(NULL);
1135 // time out servers
1136 for (int i = 0; i < max_servers; ++i) {
1137 if (servers[i].host && servers[i].death_time <= now) {
1138 u_log(LOG_NOTE, "server #%d %s:%d timed out", i, u_iptostr(servers[i].host), servers[i].port);
1139 sv_remove(servers + i);
1143 #ifdef ENABLE_PIPE
1144 // read commands from pipe
1145 io_read_commands();
1146 #endif