ebeb2c5c9a5d7640b8ff04e3fdb9bd4a6a85c6d9
8 #include <enet/types.h>
10 #define MS_VERSION "0.2"
11 #define MS_MAXSRVS 128
13 #define MS_MAXBANS 256
14 #define MS_TIMEOUT 100
15 #define MS_BANTIME (3 * 86400)
16 #define MS_MAXHEUR 100
21 #define NET_MAXCLIENTS 64
23 #define NET_BUFSIZE 65536
25 #define NET_MSG_ADD 200
26 #define NET_MSG_RM 201
27 #define NET_MSG_LIST 202
29 #define LC_MS_INIT "D2DF master server starting on port %d...\n"
30 #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"
31 #define LC_MS_UPD "\nUpdated server #%d (%s:%d):\n%s\n%s (%d)\n%d/%d plrs\nproto: %d pw?: %d\n"
32 #define LC_MS_RM "\nRemoved server #%d (%s:%d) by request.\n"
33 #define LC_MS_TIME "\nServer #%d (%s:%d) timed out.\n"
34 #define LC_MS_LIST "\nSent server list to %x:%u (ver. %s).\n"
35 #define LC_MS_DIE "\nD2DF master server shutting down...\n"
36 #define LC_MS_CONN "\nIncoming connection from %x:%u...\n"
37 #define LC_MS_MOTD "\nMOTD: %s\n"
38 #define LC_MS_URGENT "\nURGENT: %s\n"
39 #define LC_MS_BANNED "\nBanned %s until %s, reason: %s (#%d)\n"
40 #define LC_MS_NOBANS "\nCould not load ban list from file\n"
41 #define LC_MS_BADADR "\nBad address in file: %s\n"
42 #define LC_MS_BANHEUR "tripped heuristic check"
43 #define LC_MS_BANTOOMUCH "created too many servers"
44 #define LC_MS_BANSPAM "suspicious multiple server activity"
45 #define LC_MS_BANLIST "address in ban list"
46 #define LC_MS_BANTRASH "garbage server data"
47 #define LC_MS_BANINVAL "invalid message ID"
48 #define LC_MS_OOM "\nOut of memory\n"
50 #define MS_URGENT_FILE "urgent.txt"
51 #define MS_MOTD_FILE "motd.txt"
52 #define MS_BAN_FILE "master_bans.txt"
56 typedef struct ms_ban_record_s
{
61 struct ms_ban_record_s
*next
;
62 struct ms_ban_record_s
*prev
;
74 enet_uint8 s_protocol
;
80 typedef struct ms_server_s ms_server
;
82 typedef struct enet_buf_s
{
89 const char ms_game_ver
[] = "0.63";
90 char ms_motd
[255] = "";
91 char ms_urgent
[255] = "";
95 int ms_checkmultiple
= 0;
97 enet_uint8 b_send_data
[NET_BUFSIZE
];
98 enet_buf b_send
= { .data
= b_send_data
, .size
= sizeof(b_send_data
) };
101 ENetHost
*ms_host
= NULL
;
102 ENetPeer
*ms_peers
[NET_MAXCLIENTS
];
104 ms_server ms_srv
[MS_MAXSRVS
];
105 enet_uint8 ms_count
= 0;
107 ms_ban_record
*ms_bans
;
109 // fake servers to show on old versions of the game
110 static const ms_server ms_fake_srv
[] = {
114 .s_name
= "! \xc2\xc0\xd8\xc0 \xca\xce\xcf\xc8\xdf \xc8\xc3\xd0\xdb "
115 "\xd3\xd1\xd2\xc0\xd0\xc5\xcb\xc0! "
116 "\xd1\xca\xc0\xd7\xc0\xc9\xd2\xc5 \xcd\xce\xc2\xd3\xde C "
118 .s_map
= "! Your game is outdated. "
119 "Get latest version at doom2d.org !",
125 .s_name
= "! \xcf\xd0\xce\xc1\xd0\xce\xd1\xdcTE \xcf\xce\xd0\xd2\xdb "
126 "25666 \xc8 57133 HA CEPBEPE \xcf\xc5\xd0\xc5\xc4 \xc8\xc3\xd0\xce\xc9 !",
127 .s_map
= "! Forward ports 25666 and 57133 before hosting !",
132 #define MS_FAKESRVS (sizeof(ms_fake_srv) / sizeof(ms_fake_srv[0]))
134 void i_usage (void) {
135 printf("Usage: d2df_master -p port_number [-t timeout_seconds]\n");
140 void i_version (void) {
141 printf("Doom 2D Forever master server v%s\n", MS_VERSION
);
146 void d_error (const char *msg
, int fatal
) {
148 fprintf(stderr
, "FATAL ERROR: %s\n", msg
);
151 fprintf(stderr
, "ERROR: %s\n", msg
);
156 void d_getargs (int argc
, char *argv
[]) {
163 for (int i
= 1; i
< argc
; ++i
) {
164 if (!strcmp(argv
[i
], "-v")) {
168 } else if (!strcmp(argv
[i
], "-p")) {
170 d_error("Specify a port value!", 1);
173 ms_port
= atoi(argv
[++i
]);
175 } else if (!strcmp(argv
[i
], "-t") & (i
+ 1 < argc
)) {
176 ms_timeout
= atoi(argv
[++i
]);
177 } else if (!strcmp(argv
[i
], "--check-multihost")) {
178 ms_checkmultiple
= 1;
185 int d_readtextfile (const char *fname
, char *buf
, size_t max
) {
186 FILE *f
= fopen(fname
, "r");
187 char *const end
= buf
+ max
- 1;
191 char *const lend
= ln
+ max
- 1;
192 while (p
< end
&& fgets(ln
, max
, f
)) {
193 for (char *n
= ln
; n
< lend
&& *n
&& *n
!= '\r' && *n
!= '\n'; ++n
) {
206 int d_strisprint (const char *str
) {
207 if (!str
|| !*str
) return 0;
208 for (const char *p
= str
; p
&& *p
; ++p
)
209 if (isprint(*p
) || *p
> 0x7f) return 1;
214 const char *d_strtime(const time_t t
) {
215 static char buf
[128];
216 struct tm
*ptm
= localtime(&t
);
217 strftime(buf
, sizeof(buf
), "%c", ptm
);
222 static inline int b_enough_left(enet_buf
*buf
, size_t size
) {
223 if (buf
->pos
+ size
> buf
->size
) {
231 enet_uint8
b_read_uint8 (enet_buf
*buf
) {
232 if (b_enough_left(buf
, 1))
233 return buf
->data
[buf
->pos
++];
238 enet_uint16
b_read_uint16 (enet_buf
*buf
) {
241 if (b_enough_left(buf
, sizeof(ret
))) {
242 ret
= *(enet_uint16
*)(buf
->data
+ buf
->pos
);
243 buf
->pos
+= sizeof(ret
);
250 char* b_read_dstring (enet_buf
*buf
) {
253 if (b_enough_left(buf
, 1)) {
254 size_t len
= b_read_uint8(buf
);
255 if (b_enough_left(buf
, len
)) {
256 ret
= malloc(len
+ 1);
257 memmove(ret
, (char*)(buf
->data
+ buf
->pos
), len
);
267 void b_write_uint8 (enet_buf
*buf
, enet_uint8 val
) {
268 buf
->data
[buf
->pos
++] = val
;
272 void b_write_uint16 (enet_buf
*buf
, enet_uint16 val
) {
273 *(enet_uint16
*)(buf
->data
+ buf
->pos
) = val
;
274 buf
->pos
+= sizeof(val
);
278 void b_write_dstring (enet_buf
*buf
, const char* val
) {
279 enet_uint8 len
= strlen(val
);
280 b_write_uint8(buf
, len
);
282 memmove((char*)(buf
->data
+ buf
->pos
), val
, len
);
287 void b_write_server (enet_buf
*b_send
, ms_server s
) {
288 b_write_dstring(b_send
, s
.s_ip
);
289 b_write_uint16 (b_send
, s
.s_port
);
290 b_write_dstring(b_send
, s
.s_name
);
291 b_write_dstring(b_send
, s
.s_map
);
292 b_write_uint8 (b_send
, s
.s_mode
);
293 b_write_uint8 (b_send
, s
.s_plrs
);
294 b_write_uint8 (b_send
, s
.s_maxplrs
);
295 b_write_uint8 (b_send
, s
.s_protocol
);
296 b_write_uint8 (b_send
, s
.s_pw
);
300 time_t ban_get_time(const int cnt
) {
301 static const time_t times
[] = {
310 static const size_t numtimes
= sizeof(times
) / sizeof(*times
);
312 if (cnt
>= numtimes
|| cnt
< 0)
313 return times
[numtimes
- 1];
319 ms_ban_record
*ban_check (const ENetAddress
*addr
) {
320 const time_t now
= time(NULL
);
322 for (ms_ban_record
*b
= ms_bans
; b
; b
= b
->next
) {
323 if (b
->mask
.host
== addr
->host
) {
324 if (b
->cur_ban
> now
)
333 ms_ban_record
*ban_record_check (const ENetAddress
*addr
) {
334 for (ms_ban_record
*b
= ms_bans
; b
; b
= b
->next
) {
335 if (b
->mask
.host
== addr
->host
)
342 ms_ban_record
*ban_record_add_addr (const ENetAddress
*addr
, const int cnt
, const time_t cur
) {
343 ms_ban_record
*rec
= ban_record_check(addr
);
346 rec
= calloc(1, sizeof(*rec
));
347 if (!rec
) return NULL
;
349 enet_address_get_host_ip(addr
, rec
->ip
, 17);
351 rec
->ban_count
= cnt
;
354 if (ms_bans
) ms_bans
->prev
= rec
;
362 ms_ban_record
*ban_record_add_ip (const char *ip
, const int cnt
, const time_t cur
) {
364 if (enet_address_set_host_ip(&addr
, ip
) != 0) {
365 fprintf(stderr
, LC_MS_BADADR
, ip
);
368 return ban_record_add_addr(&addr
, cnt
, cur
);
372 void ban_load_list (const char *fname
) {
373 FILE *f
= fopen(fname
, "r");
375 d_error(LC_MS_NOBANS
, 0);
379 char ln
[256] = { 0 };
381 while (fgets(ln
, sizeof(ln
), f
)) {
382 for (int i
= sizeof(ln
) - 1; i
>= 0; --i
)
383 if (ln
[i
] == '\n' || ln
[i
] == '\r')
390 sscanf(ln
, "%16s %ld %d", ip
, &exp
, &count
);
392 if (ban_record_add_ip(ip
, count
, exp
))
393 printf(LC_MS_BANNED
, ip
, d_strtime(exp
), LC_MS_BANLIST
, count
);
400 void ban_save_list (const char *fname
) {
401 FILE *f
= fopen(fname
, "w");
403 d_error(LC_MS_NOBANS
, 0);
407 for (ms_ban_record
*rec
= ms_bans
; rec
; rec
= rec
->next
)
409 fprintf(f
, "%s %ld %d\n", rec
->ip
, rec
->cur_ban
, rec
->ban_count
);
415 int ban_heur (const ms_server
*srv
, const time_t now
) {
418 // can't have more than 24 maxplayers; can't have more than max
419 if (srv
->s_plrs
> srv
->s_maxplrs
|| srv
->s_maxplrs
> 24 || srv
->s_maxplrs
== 0)
422 // name and map have to be non-garbage
423 if (!d_strisprint(srv
->s_map
) || !d_strisprint(srv
->s_name
))
426 // these protocols don't exist
427 if (srv
->s_protocol
< 100 || srv
->s_protocol
> 250)
430 // the game doesn't allow server names longer than 64 chars
431 if (strlen(srv
->s_name
) > 64)
434 // game mode has to actually exist
438 // password field can be either 0 or 1
442 // port has to be set, although the game allows you to set it to 0
444 // score += MS_MAXHEUR;
446 // servers usually don't update more often than once every 30 seconds
447 if (now
- srv
->lasttime
< 5)
448 score
+= MS_MAXHEUR
/ 2;
453 void erase_banned_host(const char *ip
) {
454 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
455 if (!strcmp(ms_srv
[i
].s_ip
, ip
)) {
456 if (ms_srv
[i
].used
) {
464 time_t get_sum_lasttime(char* ip
) {
465 time_t sumLastTime
= 0;
466 const time_t now
= time(NULL
);
467 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
468 if (ms_srv
[i
].used
&& (strncmp(ip
, ms_srv
[i
].s_ip
, 16) == 0)) {
469 sumLastTime
= sumLastTime
+ (now
- ms_srv
[i
].lasttime
);
475 void ban_add (const ENetAddress
*addr
, const char *reason
) {
476 const time_t now
= time(NULL
);
478 ms_ban_record
*rec
= ban_record_add_addr(addr
, 0, 0);
479 if (!rec
) d_error(LC_MS_OOM
, 1);
481 rec
->cur_ban
= now
+ ban_get_time(rec
->ban_count
);
484 printf(LC_MS_BANNED
, rec
->ip
, d_strtime(rec
->cur_ban
), reason
, rec
->ban_count
);
486 ban_save_list(MS_BAN_FILE
);
487 erase_banned_host(rec
->ip
);
491 void d_deinit(void) {
492 ban_save_list(MS_BAN_FILE
);
495 int count_servers(char* ip
) {
496 int sameHostServers
= 0;
497 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
498 if ((strncmp(ip
, ms_srv
[i
].s_ip
, 16) == 0)) {
502 return sameHostServers
;
506 #define CHECK_RECV_OVERFLOW(addr) \
507 if (b_recv.overflow) { \
508 ban_add(addr, LC_MS_BANTRASH); \
512 int main (int argc
, char *argv
[]) {
513 d_getargs(argc
, argv
);
515 if (enet_initialize()) {
516 d_error("Could not init ENet!", 1);
520 printf(LC_MS_INIT
, ms_port
);
522 d_readtextfile(MS_MOTD_FILE
, ms_motd
, sizeof(ms_motd
));
523 d_readtextfile(MS_URGENT_FILE
, ms_urgent
, sizeof(ms_urgent
));
524 ban_load_list(MS_BAN_FILE
);
526 if (ms_motd
[0]) printf(LC_MS_MOTD
, ms_motd
);
527 if (ms_urgent
[0]) printf(LC_MS_URGENT
, ms_urgent
);
529 for (int i
= 0; i
< NET_MAXCLIENTS
; ++i
) ms_peers
[i
] = NULL
;
531 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
533 ms_srv
[i
].s_ip
[0] = '\0';
534 ms_srv
[i
].s_name
[0] = '\0';
535 ms_srv
[i
].s_map
[0] = '\0';
536 ms_srv
[i
].deathtime
= 0;
540 addr
.host
= ENET_HOST_ANY
;
543 ms_host
= enet_host_create(&addr
, NET_MAXCLIENTS
, NET_CHANS
, 0, 0);
545 d_error("Could not create host on specified port!", 1);
553 enet_uint8 msg
= 255;
556 enet_uint16 port
= 0;
560 char *clientver
= NULL
;
565 enet_uint8 proto
= 0;
568 while (enet_host_service(ms_host
, &event
, 5000) > 0) {
569 if (event
.peer
&& ban_check(&(event
.peer
->address
)))
572 const time_t now
= time(NULL
);
574 switch (event
.type
) {
575 case ENET_EVENT_TYPE_CONNECT
:
576 printf(LC_MS_CONN
, event
.peer
->address
.host
, event
.peer
->address
.port
);
579 case ENET_EVENT_TYPE_RECEIVE
:
580 if (!event
.peer
) continue;
584 b_recv
.data
= event
.packet
->data
;
585 b_recv
.size
= event
.packet
->dataLength
;
586 msg
= b_read_uint8(&b_recv
);
590 enet_address_get_host_ip(&(event
.peer
->address
), ip
, 17);
591 port
= b_read_uint16(&b_recv
);
593 name
= b_read_dstring(&b_recv
);
594 map
= b_read_dstring(&b_recv
);
595 gm
= b_read_uint8(&b_recv
);
597 pl
= b_read_uint8(&b_recv
);
598 mpl
= b_read_uint8(&b_recv
);
600 proto
= b_read_uint8(&b_recv
);
601 pw
= b_read_uint8(&b_recv
);
603 CHECK_RECV_OVERFLOW(&(event
.peer
->address
));
605 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
606 if (ms_srv
[i
].used
) {
607 if ((strncmp(ip
, ms_srv
[i
].s_ip
, 16) == 0) && (ms_srv
[i
].s_port
== port
)) {
608 strncpy(ms_srv
[i
].s_map
, map
, sizeof(ms_srv
[i
].s_map
) - 1);
609 strncpy(ms_srv
[i
].s_name
, name
, sizeof(ms_srv
[i
].s_name
) - 1);
610 ms_srv
[i
].s_plrs
= pl
;
611 ms_srv
[i
].s_maxplrs
= mpl
;
613 ms_srv
[i
].s_mode
= gm
;
615 if (ban_heur(ms_srv
+ i
, now
) >= MS_MAXHEUR
) {
616 ban_add(&(event
.peer
->address
), LC_MS_BANHEUR
);
620 ms_srv
[i
].deathtime
= now
+ ms_timeout
;
621 ms_srv
[i
].lasttime
= now
;
623 printf(LC_MS_UPD
, i
, ip
, port
, name
, map
, gm
, pl
, mpl
, proto
, pw
);
627 int countServer
= count_servers(ip
);
628 if (countServer
> MS_MAXHOST
) {
629 ban_add(&(event
.peer
->address
), LC_MS_BANTOOMUCH
);
632 else if (ms_checkmultiple
&& countServer
> 1) {
633 if (get_sum_lasttime(ip
) < (countServer
*3)) {
634 ban_add(&(event
.peer
->address
), LC_MS_BANSPAM
);
638 strncpy(ms_srv
[i
].s_ip
, ip
, sizeof(ms_srv
[i
].s_ip
) - 1);
639 strncpy(ms_srv
[i
].s_map
, map
, sizeof(ms_srv
[i
].s_map
) - 1);
640 strncpy(ms_srv
[i
].s_name
, name
, sizeof(ms_srv
[i
].s_name
) - 1);
641 ms_srv
[i
].s_port
= port
;
642 ms_srv
[i
].s_plrs
= pl
;
643 ms_srv
[i
].s_maxplrs
= mpl
;
645 ms_srv
[i
].s_mode
= gm
;
646 ms_srv
[i
].s_protocol
= proto
;
647 ms_srv
[i
].deathtime
= now
+ ms_timeout
;
648 ms_srv
[i
].lasttime
= now
;
650 if (ban_heur(ms_srv
+ i
, now
) >= MS_MAXHEUR
) {
651 ban_add(&(event
.peer
->address
), LC_MS_BANHEUR
);
657 printf(LC_MS_ADD
, i
, ip
, port
, name
, map
, gm
, pl
, mpl
, proto
, pw
);
668 enet_address_get_host_ip(&(event
.peer
->address
), ip
, 17);
669 port
= b_read_uint16(&b_recv
);
670 CHECK_RECV_OVERFLOW(&(event
.peer
->address
));
671 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
672 if (ms_srv
[i
].used
) {
673 if ((strncmp(ip
, ms_srv
[i
].s_ip
, 16) == 0) && (ms_srv
[i
].s_port
== port
)) {
674 if (ban_heur(ms_srv
+ i
, now
) >= MS_MAXHEUR
) {
675 ban_add(&(event
.peer
->address
), LC_MS_BANHEUR
);
679 printf(LC_MS_RM
, i
, ip
, port
);
688 b_write_uint8(&b_send
, NET_MSG_LIST
);
690 if (event
.packet
->dataLength
> 2) {
691 // holy shit a fresh client
692 clientver
= b_read_dstring(&b_recv
);
693 b_write_uint8(&b_send
, ms_count
);
695 // old client, feed them bullshit first
696 b_write_uint8(&b_send
, ms_count
+ 2);
697 for (int i
= 0; i
< MS_FAKESRVS
; ++i
)
698 b_write_server(&b_send
, ms_fake_srv
[i
]);
701 CHECK_RECV_OVERFLOW(&(event
.peer
->address
));
703 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
705 b_write_server(&b_send
, ms_srv
[i
]);
709 // TODO: check if this client is outdated (?) and send back new verstring
710 // for now just write the same shit back
711 b_write_dstring(&b_send
, clientver
);
712 // write the motd and urgent message
713 b_write_dstring(&b_send
, ms_motd
);
714 b_write_dstring(&b_send
, ms_urgent
);
717 ENetPacket
*p
= enet_packet_create(b_send
.data
, b_send
.pos
, ENET_PACKET_FLAG_RELIABLE
);
718 enet_peer_send(event
.peer
, NET_CH_MAIN
, p
);
719 enet_host_flush(ms_host
);
721 printf(LC_MS_LIST
, event
.peer
->address
.host
, event
.peer
->address
.port
, clientver
? clientver
: "<old>");
727 // cheeky cunt sending invalid messages
728 ban_add(&(event
.peer
->address
), LC_MS_BANINVAL
);
732 enet_packet_destroy(event
.packet
);
740 time_t now
= time(NULL
);
741 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
742 if (ms_srv
[i
].used
) {
743 if (ms_srv
[i
].deathtime
<= now
) {
745 printf(LC_MS_TIME
, i
, ms_srv
[i
].s_ip
, ms_srv
[i
].s_port
);