1 /* Copyright (C) Doom 2D: Forever Developers
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.
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.
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/>.
27 #include <sys/types.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
56 #define SV_MAX_PLAYERS 24
57 #define SV_MAX_GAMEMODE 5
58 #define SV_NEW_SERVER_INTERVAL 3
60 #define MAX_STRLEN 0xFF
81 SV_FL_PASSWORD
= 1 << 0,
82 SV_FL_VERIFIED
= 1 << 1,
83 SV_FL_MAX
= SV_FL_PASSWORD
| SV_FL_VERIFIED
,
86 typedef struct enet_buf_s
{
93 typedef struct ban_record_s
{
98 struct ban_record_s
*next
;
99 struct ban_record_s
*prev
;
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
109 enet_uint8 maxplayers
;
110 char name
[MAX_STRLEN
+ 2];
111 char map
[MAX_STRLEN
+ 2];
114 ENetPeer
*peer
; // who sent this server in
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 "
130 .map
= "! Your game is outdated. "
131 "Get latest version at doom2d.org !",
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 !",
141 static const int num_fake_servers
= sizeof(fake_servers
) / sizeof(*fake_servers
);
144 static ban_record_t
*banlist
;
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
;
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
) {
170 while (isspace(*p
)) ++p
;
171 const size_t len
= strlen(p
);
173 for (size_t i
= len
- 1; i
&& isspace(p
[i
]); --i
)
179 static char *u_vabuf(void) {
180 static char vabuf
[4][MAX_STRLEN
];
182 char *ret
= vabuf
[idx
++];
183 if (idx
>= 4) idx
= 0;
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
);
194 static inline const char *u_logprefix(const enum log_severity_e s
) {
196 case LOG_WARN
: return "WARNING: ";
197 case LOG_ERROR
: return "ERROR: ";
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
));
211 static void __attribute__((noreturn
)) u_fatal(const char *fmt
, ...) {
212 fprintf(stderr
, "[%s] FATAL ERROR:\n", u_strtime(time(NULL
)));
215 vfprintf(stderr
, fmt
, args
);
217 fprintf(stderr
, "\n");
222 static bool u_strisprint(const char *str
) {
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)
233 static bool u_strisver(const char *str
) {
236 for (const char *p
= str
; *p
; ++p
) {
237 // version strings consist of 0-9 . and space
238 if (!isdigit(*p
) && *p
!= '.' && *p
!= ' ')
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);
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;
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
) {
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
) {
297 static enet_uint8
b_read_uint8(enet_buf_t
*buf
) {
298 if (b_enough_left(buf
, 1))
299 return buf
->data
[buf
->pos
++];
303 static enet_uint16
b_read_uint16(enet_buf_t
*buf
) {
306 if (b_enough_left(buf
, sizeof(ret
))) {
307 ret
= *(enet_uint16
*)(buf
->data
+ buf
->pos
);
308 buf
->pos
+= sizeof(ret
);
314 static char *b_read_dstring(enet_buf_t
*buf
) {
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
);
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
);
337 } else if (out_size
) {
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
);
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
) {
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
);
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
) {
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
) {
409 for (int i
= 0; i
< max_servers
; ++i
) {
410 if (servers
[i
].host
&& (servers
[i
].host
& mask
) == host
)
416 static time_t sv_last_timestamp_for_host(enet_uint32 host
, enet_uint32 mask
) {
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
;
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
440 static inline void sv_clear_peer(ENetPeer
*peer
) {
441 server_t
*sv
= peer
->data
;
448 /* ban list functions */
450 static inline time_t ban_get_time(const int cnt
) {
451 static const time_t times
[] = {
461 static const size_t numtimes
= sizeof(times
) / sizeof(*times
);
463 if (cnt
>= numtimes
|| cnt
< 0)
464 return times
[numtimes
- 1];
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
)
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
))
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
);
494 rec
= calloc(1, sizeof(*rec
));
495 if (!rec
) return NULL
;
497 rec
->host
= host
& mask
;
499 if (rec
->mask
== 0) rec
->mask
= NET_FULLMASK
;
500 rec
->ban_count
= cnt
;
503 if (banlist
) banlist
->prev
= 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
, '/');
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)
526 // transform prefix length into mask
527 *out_mask
= u_prefixtomask(prefix
);
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
);
536 u_log(LOG_ERROR
, "banlist: `%s` is not a valid address", ip
);
539 return ban_record_add_addr(host
, mask
, cnt
, cur
);
542 static void ban_free_list(void) {
543 ban_record_t
*rec
= banlist
;
545 ban_record_t
*next
= rec
->next
;
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
)) {
557 if (b
->next
) b
->next
->prev
= b
->prev
;
558 if (b
->prev
) b
->prev
->next
= b
->next
;
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
);
570 u_log(LOG_ERROR
, "unban: `%s` is not a valid address", ip
);
573 return ban_record_remove_addr(host
, mask
);
576 static void ban_load_list(const char *fname
) {
577 FILE *f
= fopen(fname
, "r");
579 u_log(LOG_WARN
, "banlist: could not open %s for reading", fname
);
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')
593 char ip
[21] = { 0 }; // optionally includes the "/nn" prefix length at the end
596 if (sscanf(ln
, "%20s %d %d", ip
, &expd
, &count
) < 3) {
597 u_log(LOG_ERROR
, "banlist: malformed line: `%s`", ln
);
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
);
609 static void ban_save_list(const char *fname
) {
610 FILE *f
= fopen(fname
, "w");
612 u_log(LOG_ERROR
, "banlist: could not open %s for writing", fname
);
616 for (ban_record_t
*rec
= banlist
; rec
; rec
= rec
->next
) {
618 fprintf(f
, "%s/%u %d %d\n", u_iptostr(rec
->host
), u_masktoprefix(rec
->mask
), (int)rec
->cur_ban
, rec
->ban_count
);
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)
628 // name and map have to be non-garbage
629 if (!u_strisprint(srv
->map
) || !u_strisprint(srv
->name
))
631 // these protocols don't exist
632 if (srv
->proto
< SV_PROTO_MIN
|| srv
->proto
> SV_PROTO_MAX
)
634 // the game doesn't allow server names longer than 64 chars
635 if (strlen(srv
->name
) > SV_NAME_MAX
)
637 // game mode has to actually exist
638 if (srv
->gamemode
> SV_MAX_GAMEMODE
)
640 // flags field can't be higher than the sum of all the flags
641 if (srv
->flags
> SV_FL_MAX
)
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
);
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
)
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
);
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
)
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
));
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
) {
695 ban_add(peer
->address
.host
, reason
);
697 enet_peer_reset(peer
);
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
));
714 io_fd
= open(MS_PIPE_FILE
, O_RDONLY
| O_NONBLOCK
);
716 u_log(LOG_ERROR
, "io_install_pipe(): open(): %s", strerror(errno
));
717 remove(MS_PIPE_FILE
);
724 static void io_uninstall_pipe(void) {
729 remove(MS_PIPE_FILE
);
732 static void io_read_commands(void) {
737 const int cmd_len
= read(io_fd
, cmd
, sizeof(cmd
) - 1);
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
);
747 u_log(LOG_ERROR
, "ban: `%s` is not a valid address", ip
);
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
);
756 u_log(LOG_ERROR
, "ban: `%s` is not a valid address", ip
);
759 ban_remove_mask(host
, mask
);
760 } else if (!strncmp(cmd
, "reload", 6)) {
761 u_log(LOG_WARN
, "reloading banlist");
763 ban_load_list(MS_BAN_FILE
);
764 } else if (!strncmp(cmd
, "die", 3)) {
765 u_log(LOG_WARN
, "shutting down");
772 static void deinit(void) {
773 // ban_save_list(MS_BAN_FILE);
776 enet_host_destroy(ms_host
);
785 static bool handle_msg(const enet_uint8 msgid
, ENetPeer
*peer
) {
787 server_t tmpsv
= { 0 };
788 char clientver
[MAX_STRLEN
] = { 0 };
789 const time_t now
= time(NULL
);
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");
807 sv
= sv_find_or_add(peer
->address
.host
, tmpsv
.port
);
809 u_log(LOG_ERROR
, "ran out of server slots trying to add %s:%d", u_iptostr(peer
->address
.host
), tmpsv
.port
);
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");
826 // only then update the times
827 sv
->death_time
= now
+ ms_sv_timeout
;
829 // check if we're updating from a new peer
830 if (sv
->peer
!= peer
) {
831 // if there was an old one, kill it
833 sv
->peer
->data
= NULL
;
834 enet_peer_reset(sv
->peer
);
839 u_log(LOG_NOTE
, "updated server #%d:", sv
- servers
);
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");
850 // FIXME: commented out as this might trip when the master restarts
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");
861 // then add that shit
863 sv
->host
= peer
->address
.host
;
864 sv
->death_time
= now
+ ms_sv_timeout
;
866 if (!ban_sanity_check(sv
)) {
869 ban_peer(peer
, "tripped sanity check");
875 u_log(LOG_NOTE
, "added new server #%d:", sv
- servers
);
881 tmpsv
.port
= b_read_uint16(&buf_recv
);
882 if (buf_recv
.overflow
) {
883 ban_peer(peer
, "malformed MSG_RM");
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
889 enet_peer_disconnect_later(peer
, 0);
894 buf_send
.overflow
= 0;
895 b_write_uint8(&buf_send
, NET_MSG_LIST
);
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
);
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");
914 if (clientver
[0] && !u_strisver(clientver
)) {
915 ban_peer(peer
, "malformed MSG_LIST clientver");
919 for (int i
= 0; i
< max_servers
; ++i
) {
921 b_write_server(&buf_send
, servers
+ i
);
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
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>");
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
);
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
]))
970 fprintf(stderr
, "expected integer value after %s\n", name
);
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
);
984 static bool parse_args(int argc
, char **argv
) {
988 if (!strcmp(argv
[1], "-h")) {
993 for (int i
= 1; i
< argc
; ++i
) {
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
);
1005 fprintf(stderr
, "unknown or invalid argument: %s\n", argv
[i
]);
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");
1029 cl_last_addr
= peer
->address
.host
;
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
);
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
);
1058 u_log(LOG_NOTE
, "urgentmsg: %s", ms_urgent
);
1060 ban_load_list(MS_BAN_FILE
);
1070 addr
.port
= ms_port
;
1071 ms_host
= enet_host_create(&addr
, MS_MAX_CLIENTS
, NET_CH_COUNT
+ 1, 0, 0);
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;
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
));
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");
1092 enet_peer_timeout(event
.peer
, 0, 0, ms_cl_timeout
* 1000);
1095 case ENET_EVENT_TYPE_RECEIVE
:
1096 if (!event
.packet
|| event
.packet
->dataLength
== 0) {
1097 ban_peer(event
.peer
, "empty packet");
1100 // set up receive buffer
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");
1113 case ENET_EVENT_TYPE_DISCONNECT
:
1115 // u_log(LOG_NOTE, "%s:%d disconnected", u_iptostr(event.peer->address.host), event.peer->address.port);
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
);
1128 buf_recv
.data
= NULL
;
1129 enet_packet_destroy(event
.packet
);
1133 const time_t now
= time(NULL
);
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
);
1144 // read commands from pipe