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_OOM "\nOut of memory\n"
48 #define MS_URGENT_FILE "urgent.txt"
49 #define MS_MOTD_FILE "motd.txt"
50 #define MS_BAN_FILE "master_bans.txt"
54 typedef struct ms_ban_record_s
{
59 struct ms_ban_record_s
*next
;
60 struct ms_ban_record_s
*prev
;
72 enet_uint8 s_protocol
;
78 typedef struct ms_server_s ms_server
;
80 const char ms_game_ver
[] = "0.63";
81 char ms_motd
[255] = "";
82 char ms_urgent
[255] = "";
86 int ms_checkmultiple
= 0;
91 enet_uint8 b_send
[NET_BUFSIZE
];
93 ENetHost
*ms_host
= NULL
;
94 ENetPeer
*ms_peers
[NET_MAXCLIENTS
];
96 ms_server ms_srv
[MS_MAXSRVS
];
97 enet_uint8 ms_count
= 0;
99 ms_ban_record
*ms_bans
;
101 // fake servers to show on old versions of the game
102 static const ms_server ms_fake_srv
[] = {
106 .s_name
= "! \xc2\xc0\xd8\xc0 \xca\xce\xcf\xc8\xdf \xc8\xc3\xd0\xdb "
107 "\xd3\xd1\xd2\xc0\xd0\xc5\xcb\xc0! "
108 "\xd1\xca\xc0\xd7\xc0\xc9\xd2\xc5 \xcd\xce\xc2\xd3\xde C "
110 .s_map
= "! Your game is outdated. "
111 "Get latest version at doom2d.org !",
117 .s_name
= "! \xcf\xd0\xce\xc1\xd0\xce\xd1\xdcTE \xcf\xce\xd0\xd2\xdb "
118 "25666 \xc8 57133 HA CEPBEPE \xcf\xc5\xd0\xc5\xc4 \xc8\xc3\xd0\xce\xc9 !",
119 .s_map
= "! Forward ports 25666 and 57133 before hosting !",
124 #define MS_FAKESRVS (sizeof(ms_fake_srv) / sizeof(ms_fake_srv[0]))
126 void i_usage (void) {
127 printf("Usage: d2df_master -p port_number [-t timeout_seconds]\n");
132 void i_version (void) {
133 printf("Doom 2D Forever master server v%s\n", MS_VERSION
);
138 void d_error (const char *msg
, int fatal
) {
140 fprintf(stderr
, "FATAL ERROR: %s\n", msg
);
143 fprintf(stderr
, "ERROR: %s\n", msg
);
148 void d_getargs (int argc
, char *argv
[]) {
155 for (int i
= 1; i
< argc
; ++i
) {
156 if (!strcmp(argv
[i
], "-v")) {
160 } else if (!strcmp(argv
[i
], "-p")) {
162 d_error("Specify a port value!", 1);
165 ms_port
= atoi(argv
[++i
]);
167 } else if (!strcmp(argv
[i
], "-t") & (i
+ 1 < argc
)) {
168 ms_timeout
= atoi(argv
[++i
]);
169 } else if (!strcmp(argv
[i
], "--check-multihost")) {
170 ms_checkmultiple
= 1;
177 int d_readtextfile (const char *fname
, char *buf
, size_t max
) {
178 FILE *f
= fopen(fname
, "r");
179 char *const end
= buf
+ max
- 1;
183 char *const lend
= ln
+ max
- 1;
184 while (p
< end
&& fgets(ln
, max
, f
)) {
185 for (char *n
= ln
; n
< lend
&& *n
&& *n
!= '\r' && *n
!= '\n'; ++n
) {
198 int d_strisprint (const char *str
) {
199 if (!str
|| !*str
) return 0;
200 for (const char *p
= str
; p
&& *p
; ++p
)
201 if (isprint(*p
) || *p
> 0x7f) return 1;
206 const char *d_strtime(const time_t t
) {
207 static char buf
[128];
208 struct tm
*ptm
= localtime(&t
);
209 strftime(buf
, sizeof(buf
), "%c", ptm
);
214 enet_uint8
b_read_uint8 (enet_uint8 buf
[], size_t *pos
) {
215 return buf
[(*pos
)++];
219 enet_uint16
b_read_uint16 (enet_uint8 buf
[], size_t *pos
) {
222 ret
= *(enet_uint16
*)(buf
+ *pos
);
223 *pos
+= sizeof(enet_uint16
);
229 char* b_read_dstring (enet_uint8 buf
[], size_t *pos
) {
232 size_t len
= b_read_uint8(buf
, pos
);
234 ret
= malloc(len
+ 1);
236 memmove(ret
, (char*)(buf
+ *pos
), len
);
244 void b_write_uint8 (enet_uint8 buf
[], size_t *pos
, enet_uint8 val
) {
249 void b_write_uint16 (enet_uint8 buf
[], size_t *pos
, enet_uint16 val
) {
250 *(enet_uint16
*)(buf
+ *pos
) = val
;
251 *pos
+= sizeof(enet_uint16
);
255 void b_write_dstring (enet_uint8 buf
[], size_t *pos
, const char* val
) {
256 enet_uint8 len
= strlen(val
);
257 b_write_uint8(buf
, pos
, len
);
259 memmove((char*)(buf
+ *pos
), val
, len
);
264 void b_write_server (enet_uint8 buf
[], size_t *pos
, ms_server s
) {
265 b_write_dstring(b_send
, pos
, s
.s_ip
);
266 b_write_uint16 (b_send
, pos
, s
.s_port
);
267 b_write_dstring(b_send
, pos
, s
.s_name
);
268 b_write_dstring(b_send
, pos
, s
.s_map
);
269 b_write_uint8 (b_send
, pos
, s
.s_mode
);
270 b_write_uint8 (b_send
, pos
, s
.s_plrs
);
271 b_write_uint8 (b_send
, pos
, s
.s_maxplrs
);
272 b_write_uint8 (b_send
, pos
, s
.s_protocol
);
273 b_write_uint8 (b_send
, pos
, s
.s_pw
);
277 time_t ban_get_time(const int cnt
) {
278 static const time_t times
[] = {
287 static const size_t numtimes
= sizeof(times
) / sizeof(*times
);
289 if (cnt
>= numtimes
|| cnt
< 0)
290 return times
[numtimes
- 1];
296 ms_ban_record
*ban_check (const ENetAddress
*addr
) {
297 const time_t now
= time(NULL
);
299 for (ms_ban_record
*b
= ms_bans
; b
; b
= b
->next
) {
300 if (b
->mask
.host
== addr
->host
) {
301 if (b
->cur_ban
> now
)
310 ms_ban_record
*ban_record_check (const ENetAddress
*addr
) {
311 for (ms_ban_record
*b
= ms_bans
; b
; b
= b
->next
) {
312 if (b
->mask
.host
== addr
->host
)
319 ms_ban_record
*ban_record_add_addr (const ENetAddress
*addr
, const int cnt
, const time_t cur
) {
320 ms_ban_record
*rec
= ban_record_check(addr
);
323 rec
= calloc(1, sizeof(*rec
));
324 if (!rec
) return NULL
;
326 enet_address_get_host_ip(addr
, rec
->ip
, 17);
328 rec
->ban_count
= cnt
;
331 if (ms_bans
) ms_bans
->prev
= rec
;
339 ms_ban_record
*ban_record_add_ip (const char *ip
, const int cnt
, const time_t cur
) {
341 if (enet_address_set_host_ip(&addr
, ip
) != 0) {
342 fprintf(stderr
, LC_MS_BADADR
, ip
);
345 return ban_record_add_addr(&addr
, cnt
, cur
);
349 void ban_load_list (const char *fname
) {
350 FILE *f
= fopen(fname
, "r");
352 d_error(LC_MS_NOBANS
, 0);
356 char ln
[256] = { 0 };
358 while (fgets(ln
, sizeof(ln
), f
)) {
359 for (int i
= sizeof(ln
) - 1; i
>= 0; --i
)
360 if (ln
[i
] == '\n' || ln
[i
] == '\r')
367 sscanf(ln
, "%16s %ld %d", ip
, &exp
, &count
);
369 if (ban_record_add_ip(ip
, count
, exp
))
370 printf(LC_MS_BANNED
, ip
, d_strtime(exp
), LC_MS_BANLIST
, count
);
377 void ban_save_list (const char *fname
) {
378 FILE *f
= fopen(fname
, "w");
380 d_error(LC_MS_NOBANS
, 0);
384 for (ms_ban_record
*rec
= ms_bans
; rec
; rec
= rec
->next
)
386 fprintf(f
, "%s %ld %d\n", rec
->ip
, rec
->cur_ban
, rec
->ban_count
);
392 int ban_heur (const ms_server
*srv
, const time_t now
) {
395 // can't have more than 24 maxplayers; can't have more than max
396 if (srv
->s_plrs
> srv
->s_maxplrs
|| srv
->s_maxplrs
> 24 || srv
->s_maxplrs
== 0)
399 // name and map have to be non-garbage
400 if (!d_strisprint(srv
->s_map
) || !d_strisprint(srv
->s_name
))
403 // these protocols don't exist
404 if (srv
->s_protocol
< 100 || srv
->s_protocol
> 250)
407 // the game doesn't allow server names longer than 64 chars
408 if (strlen(srv
->s_name
) > 64)
411 // game mode has to actually exist
415 // password field can be either 0 or 1
419 // port has to be set, although the game allows you to set it to 0
421 // score += MS_MAXHEUR;
423 // servers usually don't update more often than once every 30 seconds
424 if (now
- srv
->lasttime
< 5)
425 score
+= MS_MAXHEUR
/ 2;
430 void erase_banned_host(char* ip
) {
431 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
432 if (ms_srv
[i
].s_ip
== ip
) {
438 time_t get_sum_lasttime(char* ip
) {
439 time_t sumLastTime
= 0;
440 const time_t now
= time(NULL
);
441 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
442 if (ms_srv
[i
].used
&& (strncmp(ip
, ms_srv
[i
].s_ip
, 16) == 0)) {
443 sumLastTime
= sumLastTime
+ (now
- ms_srv
[i
].lasttime
);
449 void ban_add (const ENetAddress
*addr
, const char *reason
) {
450 const time_t now
= time(NULL
);
452 ms_ban_record
*rec
= ban_record_add_addr(addr
, 0, 0);
453 if (!rec
) d_error(LC_MS_OOM
, 1);
455 rec
->cur_ban
= now
+ ban_get_time(rec
->ban_count
);
458 printf(LC_MS_BANNED
, rec
->ip
, d_strtime(rec
->cur_ban
), reason
, rec
->ban_count
);
460 ban_save_list(MS_BAN_FILE
);
461 erase_banned_host(rec
->ip
);
465 void d_deinit(void) {
466 ban_save_list(MS_BAN_FILE
);
469 int count_servers(char* ip
) {
470 int sameHostServers
= 0;
471 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
472 if ((strncmp(ip
, ms_srv
[i
].s_ip
, 16) == 0)) {
476 return sameHostServers
;
482 int main (int argc
, char *argv
[]) {
483 d_getargs(argc
, argv
);
485 if (enet_initialize()) {
486 d_error("Could not init ENet!", 1);
490 printf(LC_MS_INIT
, ms_port
);
492 d_readtextfile(MS_MOTD_FILE
, ms_motd
, sizeof(ms_motd
));
493 d_readtextfile(MS_URGENT_FILE
, ms_urgent
, sizeof(ms_urgent
));
494 ban_load_list(MS_BAN_FILE
);
496 if (ms_motd
[0]) printf(LC_MS_MOTD
, ms_motd
);
497 if (ms_urgent
[0]) printf(LC_MS_URGENT
, ms_urgent
);
499 for (int i
= 0; i
< NET_MAXCLIENTS
; ++i
) ms_peers
[i
] = NULL
;
501 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
503 ms_srv
[i
].s_ip
[0] = '\0';
504 ms_srv
[i
].s_name
[0] = '\0';
505 ms_srv
[i
].s_map
[0] = '\0';
506 ms_srv
[i
].deathtime
= 0;
510 addr
.host
= ENET_HOST_ANY
;
513 ms_host
= enet_host_create(&addr
, NET_MAXCLIENTS
, NET_CHANS
, 0, 0);
515 d_error("Could not create host on specified port!", 1);
523 enet_uint8 msg
= 255;
526 enet_uint16 port
= 0;
530 char *clientver
= NULL
;
535 enet_uint8 proto
= 0;
538 while (enet_host_service(ms_host
, &event
, 5000) > 0) {
539 if (event
.peer
&& ban_check(&(event
.peer
->address
)))
542 const time_t now
= time(NULL
);
544 switch (event
.type
) {
545 case ENET_EVENT_TYPE_CONNECT
:
546 printf(LC_MS_CONN
, event
.peer
->address
.host
, event
.peer
->address
.port
);
549 case ENET_EVENT_TYPE_RECEIVE
:
550 if (!event
.peer
) continue;
553 msg
= b_read_uint8(event
.packet
->data
, &b_read
);
557 enet_address_get_host_ip(&(event
.peer
->address
), ip
, 17);
558 port
= b_read_uint16(event
.packet
->data
, &b_read
);
560 name
= b_read_dstring(event
.packet
->data
, &b_read
);
561 map
= b_read_dstring(event
.packet
->data
, &b_read
);
562 gm
= b_read_uint8(event
.packet
->data
, &b_read
);
564 pl
= b_read_uint8(event
.packet
->data
, &b_read
);
565 mpl
= b_read_uint8(event
.packet
->data
, &b_read
);
567 proto
= b_read_uint8(event
.packet
->data
, &b_read
);
568 pw
= b_read_uint8(event
.packet
->data
, &b_read
);
570 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
571 if (ms_srv
[i
].used
) {
572 if ((strncmp(ip
, ms_srv
[i
].s_ip
, 16) == 0) && (ms_srv
[i
].s_port
== port
)) {
573 if (ban_heur(ms_srv
+ i
, now
) >= MS_MAXHEUR
) {
574 ban_add(&(event
.peer
->address
), LC_MS_BANHEUR
);
578 strncpy(ms_srv
[i
].s_map
, map
, sizeof(ms_srv
[i
].s_map
));
579 strncpy(ms_srv
[i
].s_name
, name
, sizeof(ms_srv
[i
].s_name
));
580 ms_srv
[i
].s_plrs
= pl
;
581 ms_srv
[i
].s_maxplrs
= mpl
;
583 ms_srv
[i
].s_mode
= gm
;
585 ms_srv
[i
].deathtime
= now
+ ms_timeout
;
586 ms_srv
[i
].lasttime
= now
;
588 printf(LC_MS_UPD
, i
, ip
, port
, name
, map
, gm
, pl
, mpl
, proto
, pw
);
592 int countServer
= count_servers(ip
);
593 if (countServer
> MS_MAXHOST
) {
594 ban_add(&(event
.peer
->address
), LC_MS_BANTOOMUCH
);
597 else if (ms_checkmultiple
&& countServer
> 1) {
598 if (get_sum_lasttime(ip
) < (countServer
*3)) {
599 ban_add(&(event
.peer
->address
), LC_MS_BANSPAM
);
603 strncpy(ms_srv
[i
].s_ip
, ip
, sizeof(ms_srv
[i
].s_ip
));
604 strncpy(ms_srv
[i
].s_map
, map
, sizeof(ms_srv
[i
].s_map
));
605 strncpy(ms_srv
[i
].s_name
, name
, sizeof(ms_srv
[i
].s_name
));
606 ms_srv
[i
].s_port
= port
;
607 ms_srv
[i
].s_plrs
= pl
;
608 ms_srv
[i
].s_maxplrs
= mpl
;
610 ms_srv
[i
].s_mode
= gm
;
611 ms_srv
[i
].s_protocol
= proto
;
612 ms_srv
[i
].deathtime
= now
+ ms_timeout
;
613 ms_srv
[i
].lasttime
= now
;
615 if (ban_heur(ms_srv
+ i
, now
) >= MS_MAXHEUR
) {
616 ban_add(&(event
.peer
->address
), LC_MS_BANHEUR
);
622 printf(LC_MS_ADD
, i
, ip
, port
, name
, map
, gm
, pl
, mpl
, proto
, pw
);
633 enet_address_get_host_ip(&(event
.peer
->address
), ip
, 17);
634 port
= b_read_uint16(event
.packet
->data
, &b_read
);
635 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
636 if (ms_srv
[i
].used
) {
637 if ((strncmp(ip
, ms_srv
[i
].s_ip
, 16) == 0) && (ms_srv
[i
].s_port
== port
)) {
638 if (ban_heur(ms_srv
+ i
, now
) >= MS_MAXHEUR
) {
639 ban_add(&(event
.peer
->address
), LC_MS_BANHEUR
);
643 printf(LC_MS_RM
, i
, ip
, port
);
652 b_write_uint8(b_send
, &b_write
, NET_MSG_LIST
);
654 if (event
.packet
->dataLength
> 2) {
655 // holy shit a fresh client
656 clientver
= b_read_dstring(event
.packet
->data
, &b_read
);
657 b_write_uint8(b_send
, &b_write
, ms_count
);
659 // old client, feed them bullshit first
660 b_write_uint8(b_send
, &b_write
, ms_count
+ 2);
661 for (int i
= 0; i
< MS_FAKESRVS
; ++i
)
662 b_write_server(b_send
, &b_write
, ms_fake_srv
[i
]);
665 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
666 if (ms_srv
[i
].used
) b_write_server(b_send
, &b_write
, ms_srv
[i
]);
670 // TODO: check if this client is outdated (?) and send back new verstring
671 // for now just write the same shit back
672 b_write_dstring(b_send
, &b_write
, clientver
);
673 // write the motd and urgent message
674 b_write_dstring(b_send
, &b_write
, ms_motd
);
675 b_write_dstring(b_send
, &b_write
, ms_urgent
);
678 ENetPacket
*p
= enet_packet_create(b_send
, b_write
, ENET_PACKET_FLAG_RELIABLE
);
679 enet_peer_send(event
.peer
, NET_CH_MAIN
, p
);
680 enet_host_flush(ms_host
);
682 printf(LC_MS_LIST
, event
.peer
->address
.host
, event
.peer
->address
.port
, clientver
? clientver
: "<old>");
688 enet_packet_destroy(event
.packet
);
696 time_t now
= time(NULL
);
697 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
698 if (ms_srv
[i
].used
) {
699 if (ms_srv
[i
].deathtime
<= now
) {
701 printf(LC_MS_TIME
, i
, ms_srv
[i
].s_ip
, ms_srv
[i
].s_port
);