b6d2cd7d8e64b5449ec7df340e8bb868cdc161c6
5 #include <enet/types.h>
8 #define MS_VERSION "0.2"
10 #define MS_MAXBANS 256
11 #define MS_TIMEOUT 100
12 #define MS_BANTIME (3 * 86400)
13 #define MS_MAXHEUR 100
18 #define NET_MAXCLIENTS 64
20 #define NET_BUFSIZE 65536
22 #define NET_MSG_ADD 200
23 #define NET_MSG_RM 201
24 #define NET_MSG_LIST 202
26 #define LC_MS_INIT "D2DF master server starting on port %d...\n"
27 #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"
28 #define LC_MS_UPD "\nUpdated server #%d (%s:%d):\n%s\n%s (%d)\n%d/%d plrs\nproto: %d pw?: %d\n"
29 #define LC_MS_RM "\nRemoved server #%d (%s:%d) by request.\n"
30 #define LC_MS_TIME "\nServer #%d (%s:%d) timed out.\n"
31 #define LC_MS_LIST "\nSent server list to %x:%u (ver. %s).\n"
32 #define LC_MS_DIE "\nD2DF master server shutting down...\n"
33 #define LC_MS_CONN "\nIncoming connection from %x:%u...\n"
34 #define LC_MS_MOTD "\nMOTD: %s\n"
35 #define LC_MS_URGENT "\nURGENT: %s\n"
36 #define LC_MS_BANNED "\nBanned %s until %s, reason: %s (#%d)\n"
37 #define LC_MS_NOBANS "\nCould not load ban list from file\n"
38 #define LC_MS_BADADR "\nBad address in file: %s\n"
39 #define LC_MS_BANHEUR "tripped heuristic check"
40 #define LC_MS_BANLIST "address in ban list"
41 #define LC_MS_OOM "\nOut of memory\n"
43 #define MS_URGENT_FILE "urgent.txt"
44 #define MS_MOTD_FILE "motd.txt"
45 #define MS_BAN_FILE "master_bans.txt"
49 typedef struct ms_ban_record_s
{
54 struct ms_ban_record_s
*next
;
55 struct ms_ban_record_s
*prev
;
67 enet_uint8 s_protocol
;
73 typedef struct ms_server_s ms_server
;
75 const char ms_game_ver
[] = "0.63";
76 char ms_motd
[255] = "";
77 char ms_urgent
[255] = "";
85 enet_uint8 b_send
[NET_BUFSIZE
];
87 ENetHost
*ms_host
= NULL
;
88 ENetPeer
*ms_peers
[NET_MAXCLIENTS
];
90 ms_server ms_srv
[MS_MAXSRVS
];
91 enet_uint8 ms_count
= 0;
93 ms_ban_record
*ms_bans
;
95 // fake servers to show on old versions of the game
96 static const ms_server ms_fake_srv
[] = {
100 .s_name
= "! \xc2\xc0\xd8\xc0 \xca\xce\xcf\xc8\xdf \xc8\xc3\xd0\xdb "
101 "\xd3\xd1\xd2\xc0\xd0\xc5\xcb\xc0! "
102 "\xd1\xca\xc0\xd7\xc0\xc9\xd2\xc5 \xcd\xce\xc2\xd3\xde C "
104 .s_map
= "! Your game is outdated. "
105 "Get latest version at doom2d.org !",
111 .s_name
= "! \xcf\xd0\xce\xc1\xd0\xce\xd1\xdcTE \xcf\xce\xd0\xd2\xdb "
112 "25666 \xc8 57133 HA CEPBEPE \xcf\xc5\xd0\xc5\xc4 \xc8\xc3\xd0\xce\xc9 !",
113 .s_map
= "! Forward ports 25666 and 57133 before hosting !",
118 #define MS_FAKESRVS (sizeof(ms_fake_srv) / sizeof(ms_fake_srv[0]))
120 void i_usage (void) {
121 printf("Usage: d2df_master -p port_number [-t timeout_seconds]\n");
126 void i_version (void) {
127 printf("Doom 2D Forever master server v%s\n", MS_VERSION
);
132 void d_error (const char *msg
, int fatal
) {
134 fprintf(stderr
, "FATAL ERROR: %s\n", msg
);
137 fprintf(stderr
, "ERROR: %s\n", msg
);
142 void d_getargs (int argc
, char *argv
[]) {
149 for (int i
= 1; i
< argc
; ++i
) {
150 if (!strcmp(argv
[i
], "-v")) {
154 } else if (!strcmp(argv
[i
], "-p")) {
156 d_error("Specify a port value!", 1);
159 ms_port
= atoi(argv
[++i
]);
161 } else if (!strcmp(argv
[i
], "-t") & (i
+ 1 < argc
)) {
162 ms_timeout
= atoi(argv
[++i
]);
168 int d_readtextfile (const char *fname
, char *buf
, size_t max
) {
169 FILE *f
= fopen(fname
, "r");
170 char *const end
= buf
+ max
- 1;
174 char *const lend
= ln
+ max
- 1;
175 while (p
< end
&& fgets(ln
, max
, f
)) {
176 for (char *n
= ln
; n
< lend
&& *n
&& *n
!= '\r' && *n
!= '\n'; ++n
) {
189 int d_strisprint (const char *str
) {
190 if (!str
|| !*str
) return 0;
191 for (const char *p
= str
; p
&& *p
; ++p
)
192 if (isprint(*p
) || *p
> 0x7f) return 1;
197 const char *d_strtime(const time_t t
) {
198 static char buf
[128];
199 struct tm
*ptm
= localtime(&t
);
200 strftime(buf
, sizeof(buf
), "%c", ptm
);
205 enet_uint8
b_read_uint8 (enet_uint8 buf
[], size_t *pos
) {
206 return buf
[(*pos
)++];
210 enet_uint16
b_read_uint16 (enet_uint8 buf
[], size_t *pos
) {
213 ret
= *(enet_uint16
*)(buf
+ *pos
);
214 *pos
+= sizeof(enet_uint16
);
220 char* b_read_dstring (enet_uint8 buf
[], size_t *pos
) {
223 size_t len
= b_read_uint8(buf
, pos
);
225 ret
= malloc(len
+ 1);
227 memmove(ret
, (char*)(buf
+ *pos
), len
);
235 void b_write_uint8 (enet_uint8 buf
[], size_t *pos
, enet_uint8 val
) {
240 void b_write_uint16 (enet_uint8 buf
[], size_t *pos
, enet_uint16 val
) {
241 *(enet_uint16
*)(buf
+ *pos
) = val
;
242 *pos
+= sizeof(enet_uint16
);
246 void b_write_dstring (enet_uint8 buf
[], size_t *pos
, const char* val
) {
247 enet_uint8 len
= strlen(val
);
248 b_write_uint8(buf
, pos
, len
);
250 memmove((char*)(buf
+ *pos
), val
, len
);
255 void b_write_server (enet_uint8 buf
[], size_t *pos
, ms_server s
) {
256 b_write_dstring(b_send
, pos
, s
.s_ip
);
257 b_write_uint16 (b_send
, pos
, s
.s_port
);
258 b_write_dstring(b_send
, pos
, s
.s_name
);
259 b_write_dstring(b_send
, pos
, s
.s_map
);
260 b_write_uint8 (b_send
, pos
, s
.s_mode
);
261 b_write_uint8 (b_send
, pos
, s
.s_plrs
);
262 b_write_uint8 (b_send
, pos
, s
.s_maxplrs
);
263 b_write_uint8 (b_send
, pos
, s
.s_protocol
);
264 b_write_uint8 (b_send
, pos
, s
.s_pw
);
268 time_t ban_get_time(const int cnt
) {
269 static const time_t times
[] = {
278 static const size_t numtimes
= sizeof(times
) / sizeof(*times
);
280 if (cnt
>= numtimes
|| cnt
< 0)
281 return times
[numtimes
- 1];
287 ms_ban_record
*ban_check (const ENetAddress
*addr
) {
288 const time_t now
= time(NULL
);
290 for (ms_ban_record
*b
= ms_bans
; b
; b
= b
->next
) {
291 if (b
->mask
.host
== addr
->host
) {
292 if (b
->cur_ban
> now
)
301 ms_ban_record
*ban_record_check (const ENetAddress
*addr
) {
302 for (ms_ban_record
*b
= ms_bans
; b
; b
= b
->next
) {
303 if (b
->mask
.host
== addr
->host
)
310 ms_ban_record
*ban_record_add_addr (const ENetAddress
*addr
, const int cnt
, const time_t cur
) {
311 ms_ban_record
*rec
= ban_record_check(addr
);
314 rec
= calloc(1, sizeof(*rec
));
315 if (!rec
) return NULL
;
317 enet_address_get_host_ip(addr
, rec
->ip
, 17);
319 rec
->ban_count
= cnt
;
322 if (ms_bans
) ms_bans
->prev
= rec
;
330 ms_ban_record
*ban_record_add_ip (const char *ip
, const int cnt
, const time_t cur
) {
332 if (enet_address_set_host_ip(&addr
, ip
) != 0) {
333 fprintf(stderr
, LC_MS_BADADR
, ip
);
336 return ban_record_add_addr(&addr
, cnt
, cur
);
340 void ban_load_list (const char *fname
) {
341 FILE *f
= fopen(fname
, "r");
343 d_error(LC_MS_NOBANS
, 0);
347 char ln
[256] = { 0 };
349 while (fgets(ln
, sizeof(ln
), f
)) {
350 for (int i
= sizeof(ln
) - 1; i
>= 0; --i
)
351 if (ln
[i
] == '\n' || ln
[i
] == '\r')
358 sscanf(ln
, "%16s %ld %d", ip
, &exp
, &count
);
360 if (ban_record_add_ip(ip
, count
, exp
))
361 printf(LC_MS_BANNED
, ip
, d_strtime(exp
), LC_MS_BANLIST
, count
);
368 void ban_save_list (const char *fname
) {
369 FILE *f
= fopen(fname
, "w");
371 d_error(LC_MS_NOBANS
, 0);
375 for (ms_ban_record
*rec
= ms_bans
; rec
; rec
= rec
->next
)
377 fprintf(f
, "%s %ld %d\n", rec
->ip
, rec
->cur_ban
, rec
->ban_count
);
383 int ban_heur (const ms_server
*srv
, const time_t now
) {
386 // can't have more than 24 maxplayers; can't have more than max
387 if (srv
->s_plrs
> srv
->s_maxplrs
|| srv
->s_maxplrs
> 24)
390 // name and map have to be non-garbage
391 if (!d_strisprint(srv
->s_map
) || !d_strisprint(srv
->s_name
))
394 // these protocols don't exist
395 if (srv
->s_protocol
< 100 || srv
->s_protocol
> 250)
398 // the game doesn't allow server names longer than 64 chars
399 if (strlen(srv
->s_name
) > 64)
402 // game mode has to actually exist
406 // password field can be either 0 or 1
410 // port has to be set, although the game allows you to set it to 0
412 // score += MS_MAXHEUR;
414 // servers usually don't update more often than once every 30 seconds
415 if (now
- srv
->lasttime
< 5)
416 score
+= MS_MAXHEUR
/ 2;
422 void ban_add (const ENetAddress
*addr
, const char *reason
) {
423 const time_t now
= time(NULL
);
425 ms_ban_record
*rec
= ban_record_add_addr(addr
, 0, 0);
426 if (!rec
) d_error(LC_MS_OOM
, 1);
428 rec
->cur_ban
= now
+ ban_get_time(rec
->ban_count
);
431 printf(LC_MS_BANNED
, rec
->ip
, d_strtime(rec
->cur_ban
), reason
, rec
->ban_count
);
433 ban_save_list(MS_BAN_FILE
);
437 void d_deinit(void) {
438 ban_save_list(MS_BAN_FILE
);
442 int main (int argc
, char *argv
[]) {
443 d_getargs(argc
, argv
);
445 if (enet_initialize()) {
446 d_error("Could not init ENet!", 1);
450 printf(LC_MS_INIT
, ms_port
);
452 d_readtextfile(MS_MOTD_FILE
, ms_motd
, sizeof(ms_motd
));
453 d_readtextfile(MS_URGENT_FILE
, ms_urgent
, sizeof(ms_urgent
));
454 ban_load_list(MS_BAN_FILE
);
456 if (ms_motd
[0]) printf(LC_MS_MOTD
, ms_motd
);
457 if (ms_urgent
[0]) printf(LC_MS_URGENT
, ms_urgent
);
459 for (int i
= 0; i
< NET_MAXCLIENTS
; ++i
) ms_peers
[i
] = NULL
;
461 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
463 ms_srv
[i
].s_ip
[0] = '\0';
464 ms_srv
[i
].s_name
[0] = '\0';
465 ms_srv
[i
].s_map
[0] = '\0';
466 ms_srv
[i
].deathtime
= 0;
470 addr
.host
= ENET_HOST_ANY
;
473 ms_host
= enet_host_create(&addr
, NET_MAXCLIENTS
, NET_CHANS
, 0, 0);
475 d_error("Could not create host on specified port!", 1);
483 enet_uint8 msg
= 255;
486 enet_uint16 port
= 0;
490 char *clientver
= NULL
;
495 enet_uint8 proto
= 0;
498 while (enet_host_service(ms_host
, &event
, 5000) > 0) {
499 if (event
.peer
&& ban_check(&(event
.peer
->address
)))
502 const time_t now
= time(NULL
);
504 switch (event
.type
) {
505 case ENET_EVENT_TYPE_CONNECT
:
506 printf(LC_MS_CONN
, event
.peer
->address
.host
, event
.peer
->address
.port
);
509 case ENET_EVENT_TYPE_RECEIVE
:
510 if (!event
.peer
) continue;
513 msg
= b_read_uint8(event
.packet
->data
, &b_read
);
517 enet_address_get_host_ip(&(event
.peer
->address
), ip
, 17);
518 port
= b_read_uint16(event
.packet
->data
, &b_read
);
520 name
= b_read_dstring(event
.packet
->data
, &b_read
);
521 map
= b_read_dstring(event
.packet
->data
, &b_read
);
522 gm
= b_read_uint8(event
.packet
->data
, &b_read
);
524 pl
= b_read_uint8(event
.packet
->data
, &b_read
);
525 mpl
= b_read_uint8(event
.packet
->data
, &b_read
);
527 proto
= b_read_uint8(event
.packet
->data
, &b_read
);
528 pw
= b_read_uint8(event
.packet
->data
, &b_read
);
530 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
531 if (ms_srv
[i
].used
) {
532 if ((strncmp(ip
, ms_srv
[i
].s_ip
, 16) == 0) && (ms_srv
[i
].s_port
== port
)) {
533 if (ban_heur(ms_srv
+ i
, now
) >= MS_MAXHEUR
) {
534 ban_add(&(event
.peer
->address
), LC_MS_BANHEUR
);
538 strncpy(ms_srv
[i
].s_map
, map
, sizeof(ms_srv
[i
].s_map
));
539 strncpy(ms_srv
[i
].s_name
, name
, sizeof(ms_srv
[i
].s_name
));
540 ms_srv
[i
].s_plrs
= pl
;
541 ms_srv
[i
].s_maxplrs
= mpl
;
543 ms_srv
[i
].s_mode
= gm
;
545 ms_srv
[i
].deathtime
= now
+ ms_timeout
;
546 ms_srv
[i
].lasttime
= now
;
548 printf(LC_MS_UPD
, i
, ip
, port
, name
, map
, gm
, pl
, mpl
, proto
, pw
);
552 strncpy(ms_srv
[i
].s_ip
, ip
, sizeof(ms_srv
[i
].s_ip
));
553 strncpy(ms_srv
[i
].s_map
, map
, sizeof(ms_srv
[i
].s_map
));
554 strncpy(ms_srv
[i
].s_name
, name
, sizeof(ms_srv
[i
].s_name
));
555 ms_srv
[i
].s_port
= port
;
556 ms_srv
[i
].s_plrs
= pl
;
557 ms_srv
[i
].s_maxplrs
= mpl
;
559 ms_srv
[i
].s_mode
= gm
;
560 ms_srv
[i
].s_protocol
= proto
;
561 ms_srv
[i
].deathtime
= now
+ ms_timeout
;
562 ms_srv
[i
].lasttime
= now
;
564 if (ban_heur(ms_srv
+ i
, now
) >= MS_MAXHEUR
) {
565 ban_add(&(event
.peer
->address
), LC_MS_BANHEUR
);
571 printf(LC_MS_ADD
, i
, ip
, port
, name
, map
, gm
, pl
, mpl
, proto
, pw
);
582 enet_address_get_host_ip(&(event
.peer
->address
), ip
, 17);
583 port
= b_read_uint16(event
.packet
->data
, &b_read
);
584 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
585 if (ms_srv
[i
].used
) {
586 if ((strncmp(ip
, ms_srv
[i
].s_ip
, 16) == 0) && (ms_srv
[i
].s_port
== port
)) {
587 if (ban_heur(ms_srv
+ i
, now
) >= MS_MAXHEUR
) {
588 ban_add(&(event
.peer
->address
), LC_MS_BANHEUR
);
592 printf(LC_MS_RM
, i
, ip
, port
);
601 b_write_uint8(b_send
, &b_write
, NET_MSG_LIST
);
603 if (event
.packet
->dataLength
> 2) {
604 // holy shit a fresh client
605 clientver
= b_read_dstring(event
.packet
->data
, &b_read
);
606 b_write_uint8(b_send
, &b_write
, ms_count
);
608 // old client, feed them bullshit first
609 b_write_uint8(b_send
, &b_write
, ms_count
+ 2);
610 for (int i
= 0; i
< MS_FAKESRVS
; ++i
)
611 b_write_server(b_send
, &b_write
, ms_fake_srv
[i
]);
614 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
615 if (ms_srv
[i
].used
) b_write_server(b_send
, &b_write
, ms_srv
[i
]);
619 // TODO: check if this client is outdated (?) and send back new verstring
620 // for now just write the same shit back
621 b_write_dstring(b_send
, &b_write
, clientver
);
622 // write the motd and urgent message
623 b_write_dstring(b_send
, &b_write
, ms_motd
);
624 b_write_dstring(b_send
, &b_write
, ms_urgent
);
627 ENetPacket
*p
= enet_packet_create(b_send
, b_write
, ENET_PACKET_FLAG_RELIABLE
);
628 enet_peer_send(event
.peer
, NET_CH_MAIN
, p
);
629 enet_host_flush(ms_host
);
631 printf(LC_MS_LIST
, event
.peer
->address
.host
, event
.peer
->address
.port
, clientver
? clientver
: "<old>");
637 enet_packet_destroy(event
.packet
);
645 time_t now
= time(NULL
);
646 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
647 if (ms_srv
[i
].used
) {
648 if (ms_srv
[i
].deathtime
<= now
) {
650 printf(LC_MS_TIME
, i
, ms_srv
[i
].s_ip
, ms_srv
[i
].s_port
);