8 #include <enet/types.h>
10 #define MS_VERSION "0.2"
11 #define MS_MAXSRVS 128
12 #define MS_MAXBANS 256
13 #define MS_TIMEOUT 100
14 #define MS_BANTIME (3 * 86400)
15 #define MS_MAXHEUR 100
20 #define NET_MAXCLIENTS 64
22 #define NET_BUFSIZE 65536
24 #define NET_MSG_ADD 200
25 #define NET_MSG_RM 201
26 #define NET_MSG_LIST 202
28 #define LC_MS_INIT "D2DF master server starting on port %d...\n"
29 #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"
30 #define LC_MS_UPD "\nUpdated server #%d (%s:%d):\n%s\n%s (%d)\n%d/%d plrs\nproto: %d pw?: %d\n"
31 #define LC_MS_RM "\nRemoved server #%d (%s:%d) by request.\n"
32 #define LC_MS_TIME "\nServer #%d (%s:%d) timed out.\n"
33 #define LC_MS_LIST "\nSent server list to %x:%u (ver. %s).\n"
34 #define LC_MS_DIE "\nD2DF master server shutting down...\n"
35 #define LC_MS_CONN "\nIncoming connection from %x:%u...\n"
36 #define LC_MS_MOTD "\nMOTD: %s\n"
37 #define LC_MS_URGENT "\nURGENT: %s\n"
38 #define LC_MS_BANNED "\nBanned %s until %s, reason: %s (#%d)\n"
39 #define LC_MS_NOBANS "\nCould not load ban list from file\n"
40 #define LC_MS_BADADR "\nBad address in file: %s\n"
41 #define LC_MS_BANHEUR "tripped heuristic check"
42 #define LC_MS_BANLIST "address in ban list"
43 #define LC_MS_OOM "\nOut of memory\n"
45 #define MS_URGENT_FILE "urgent.txt"
46 #define MS_MOTD_FILE "motd.txt"
47 #define MS_BAN_FILE "master_bans.txt"
51 typedef struct ms_ban_record_s
{
56 struct ms_ban_record_s
*next
;
57 struct ms_ban_record_s
*prev
;
69 enet_uint8 s_protocol
;
75 typedef struct ms_server_s ms_server
;
77 const char ms_game_ver
[] = "0.63";
78 char ms_motd
[255] = "";
79 char ms_urgent
[255] = "";
87 enet_uint8 b_send
[NET_BUFSIZE
];
89 ENetHost
*ms_host
= NULL
;
90 ENetPeer
*ms_peers
[NET_MAXCLIENTS
];
92 ms_server ms_srv
[MS_MAXSRVS
];
93 enet_uint8 ms_count
= 0;
95 ms_ban_record
*ms_bans
;
97 // fake servers to show on old versions of the game
98 static const ms_server ms_fake_srv
[] = {
102 .s_name
= "! \xc2\xc0\xd8\xc0 \xca\xce\xcf\xc8\xdf \xc8\xc3\xd0\xdb "
103 "\xd3\xd1\xd2\xc0\xd0\xc5\xcb\xc0! "
104 "\xd1\xca\xc0\xd7\xc0\xc9\xd2\xc5 \xcd\xce\xc2\xd3\xde C "
106 .s_map
= "! Your game is outdated. "
107 "Get latest version at doom2d.org !",
113 .s_name
= "! \xcf\xd0\xce\xc1\xd0\xce\xd1\xdcTE \xcf\xce\xd0\xd2\xdb "
114 "25666 \xc8 57133 HA CEPBEPE \xcf\xc5\xd0\xc5\xc4 \xc8\xc3\xd0\xce\xc9 !",
115 .s_map
= "! Forward ports 25666 and 57133 before hosting !",
120 #define MS_FAKESRVS (sizeof(ms_fake_srv) / sizeof(ms_fake_srv[0]))
122 void i_usage (void) {
123 printf("Usage: d2df_master -p port_number [-t timeout_seconds]\n");
128 void i_version (void) {
129 printf("Doom 2D Forever master server v%s\n", MS_VERSION
);
134 void d_error (const char *msg
, int fatal
) {
136 fprintf(stderr
, "FATAL ERROR: %s\n", msg
);
139 fprintf(stderr
, "ERROR: %s\n", msg
);
144 void d_getargs (int argc
, char *argv
[]) {
151 for (int i
= 1; i
< argc
; ++i
) {
152 if (!strcmp(argv
[i
], "-v")) {
156 } else if (!strcmp(argv
[i
], "-p")) {
158 d_error("Specify a port value!", 1);
161 ms_port
= atoi(argv
[++i
]);
163 } else if (!strcmp(argv
[i
], "-t") & (i
+ 1 < argc
)) {
164 ms_timeout
= atoi(argv
[++i
]);
170 int d_readtextfile (const char *fname
, char *buf
, size_t max
) {
171 FILE *f
= fopen(fname
, "r");
172 char *const end
= buf
+ max
- 1;
176 char *const lend
= ln
+ max
- 1;
177 while (p
< end
&& fgets(ln
, max
, f
)) {
178 for (char *n
= ln
; n
< lend
&& *n
&& *n
!= '\r' && *n
!= '\n'; ++n
) {
191 int d_strisprint (const char *str
) {
192 if (!str
|| !*str
) return 0;
193 for (const char *p
= str
; p
&& *p
; ++p
)
194 if (isprint(*p
) || *p
> 0x7f) return 1;
199 const char *d_strtime(const time_t t
) {
200 static char buf
[128];
201 struct tm
*ptm
= localtime(&t
);
202 strftime(buf
, sizeof(buf
), "%c", ptm
);
207 enet_uint8
b_read_uint8 (enet_uint8 buf
[], size_t *pos
) {
208 return buf
[(*pos
)++];
212 enet_uint16
b_read_uint16 (enet_uint8 buf
[], size_t *pos
) {
215 ret
= *(enet_uint16
*)(buf
+ *pos
);
216 *pos
+= sizeof(enet_uint16
);
222 char* b_read_dstring (enet_uint8 buf
[], size_t *pos
) {
225 size_t len
= b_read_uint8(buf
, pos
);
227 ret
= malloc(len
+ 1);
229 memmove(ret
, (char*)(buf
+ *pos
), len
);
237 void b_write_uint8 (enet_uint8 buf
[], size_t *pos
, enet_uint8 val
) {
242 void b_write_uint16 (enet_uint8 buf
[], size_t *pos
, enet_uint16 val
) {
243 *(enet_uint16
*)(buf
+ *pos
) = val
;
244 *pos
+= sizeof(enet_uint16
);
248 void b_write_dstring (enet_uint8 buf
[], size_t *pos
, const char* val
) {
249 enet_uint8 len
= strlen(val
);
250 b_write_uint8(buf
, pos
, len
);
252 memmove((char*)(buf
+ *pos
), val
, len
);
257 void b_write_server (enet_uint8 buf
[], size_t *pos
, ms_server s
) {
258 b_write_dstring(b_send
, pos
, s
.s_ip
);
259 b_write_uint16 (b_send
, pos
, s
.s_port
);
260 b_write_dstring(b_send
, pos
, s
.s_name
);
261 b_write_dstring(b_send
, pos
, s
.s_map
);
262 b_write_uint8 (b_send
, pos
, s
.s_mode
);
263 b_write_uint8 (b_send
, pos
, s
.s_plrs
);
264 b_write_uint8 (b_send
, pos
, s
.s_maxplrs
);
265 b_write_uint8 (b_send
, pos
, s
.s_protocol
);
266 b_write_uint8 (b_send
, pos
, s
.s_pw
);
270 time_t ban_get_time(const int cnt
) {
271 static const time_t times
[] = {
280 static const size_t numtimes
= sizeof(times
) / sizeof(*times
);
282 if (cnt
>= numtimes
|| cnt
< 0)
283 return times
[numtimes
- 1];
289 ms_ban_record
*ban_check (const ENetAddress
*addr
) {
290 const time_t now
= time(NULL
);
292 for (ms_ban_record
*b
= ms_bans
; b
; b
= b
->next
) {
293 if (b
->mask
.host
== addr
->host
) {
294 if (b
->cur_ban
> now
)
303 ms_ban_record
*ban_record_check (const ENetAddress
*addr
) {
304 for (ms_ban_record
*b
= ms_bans
; b
; b
= b
->next
) {
305 if (b
->mask
.host
== addr
->host
)
312 ms_ban_record
*ban_record_add_addr (const ENetAddress
*addr
, const int cnt
, const time_t cur
) {
313 ms_ban_record
*rec
= ban_record_check(addr
);
316 rec
= calloc(1, sizeof(*rec
));
317 if (!rec
) return NULL
;
319 enet_address_get_host_ip(addr
, rec
->ip
, 17);
321 rec
->ban_count
= cnt
;
324 if (ms_bans
) ms_bans
->prev
= rec
;
332 ms_ban_record
*ban_record_add_ip (const char *ip
, const int cnt
, const time_t cur
) {
334 if (enet_address_set_host_ip(&addr
, ip
) != 0) {
335 fprintf(stderr
, LC_MS_BADADR
, ip
);
338 return ban_record_add_addr(&addr
, cnt
, cur
);
342 void ban_load_list (const char *fname
) {
343 FILE *f
= fopen(fname
, "r");
345 d_error(LC_MS_NOBANS
, 0);
349 char ln
[256] = { 0 };
351 while (fgets(ln
, sizeof(ln
), f
)) {
352 for (int i
= sizeof(ln
) - 1; i
>= 0; --i
)
353 if (ln
[i
] == '\n' || ln
[i
] == '\r')
360 sscanf(ln
, "%16s %ld %d", ip
, &exp
, &count
);
362 if (ban_record_add_ip(ip
, count
, exp
))
363 printf(LC_MS_BANNED
, ip
, d_strtime(exp
), LC_MS_BANLIST
, count
);
370 void ban_save_list (const char *fname
) {
371 FILE *f
= fopen(fname
, "w");
373 d_error(LC_MS_NOBANS
, 0);
377 for (ms_ban_record
*rec
= ms_bans
; rec
; rec
= rec
->next
)
379 fprintf(f
, "%s %ld %d\n", rec
->ip
, rec
->cur_ban
, rec
->ban_count
);
385 int ban_heur (const ms_server
*srv
, const time_t now
) {
388 // can't have more than 24 maxplayers; can't have more than max
389 if (srv
->s_plrs
> srv
->s_maxplrs
|| srv
->s_maxplrs
> 24)
392 // name and map have to be non-garbage
393 if (!d_strisprint(srv
->s_map
) || !d_strisprint(srv
->s_name
))
396 // these protocols don't exist
397 if (srv
->s_protocol
< 100 || srv
->s_protocol
> 250)
400 // the game doesn't allow server names longer than 64 chars
401 if (strlen(srv
->s_name
) > 64)
404 // game mode has to actually exist
408 // password field can be either 0 or 1
412 // port has to be set, although the game allows you to set it to 0
414 // score += MS_MAXHEUR;
416 // servers usually don't update more often than once every 30 seconds
417 if (now
- srv
->lasttime
< 5)
418 score
+= MS_MAXHEUR
/ 2;
424 void ban_add (const ENetAddress
*addr
, const char *reason
) {
425 const time_t now
= time(NULL
);
427 ms_ban_record
*rec
= ban_record_add_addr(addr
, 0, 0);
428 if (!rec
) d_error(LC_MS_OOM
, 1);
430 rec
->cur_ban
= now
+ ban_get_time(rec
->ban_count
);
433 printf(LC_MS_BANNED
, rec
->ip
, d_strtime(rec
->cur_ban
), reason
, rec
->ban_count
);
435 ban_save_list(MS_BAN_FILE
);
439 void d_deinit(void) {
440 ban_save_list(MS_BAN_FILE
);
444 int main (int argc
, char *argv
[]) {
445 d_getargs(argc
, argv
);
447 if (enet_initialize()) {
448 d_error("Could not init ENet!", 1);
452 printf(LC_MS_INIT
, ms_port
);
454 d_readtextfile(MS_MOTD_FILE
, ms_motd
, sizeof(ms_motd
));
455 d_readtextfile(MS_URGENT_FILE
, ms_urgent
, sizeof(ms_urgent
));
456 ban_load_list(MS_BAN_FILE
);
458 if (ms_motd
[0]) printf(LC_MS_MOTD
, ms_motd
);
459 if (ms_urgent
[0]) printf(LC_MS_URGENT
, ms_urgent
);
461 for (int i
= 0; i
< NET_MAXCLIENTS
; ++i
) ms_peers
[i
] = NULL
;
463 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
465 ms_srv
[i
].s_ip
[0] = '\0';
466 ms_srv
[i
].s_name
[0] = '\0';
467 ms_srv
[i
].s_map
[0] = '\0';
468 ms_srv
[i
].deathtime
= 0;
472 addr
.host
= ENET_HOST_ANY
;
475 ms_host
= enet_host_create(&addr
, NET_MAXCLIENTS
, NET_CHANS
, 0, 0);
477 d_error("Could not create host on specified port!", 1);
485 enet_uint8 msg
= 255;
488 enet_uint16 port
= 0;
492 char *clientver
= NULL
;
497 enet_uint8 proto
= 0;
500 while (enet_host_service(ms_host
, &event
, 5000) > 0) {
501 if (event
.peer
&& ban_check(&(event
.peer
->address
)))
504 const time_t now
= time(NULL
);
506 switch (event
.type
) {
507 case ENET_EVENT_TYPE_CONNECT
:
508 printf(LC_MS_CONN
, event
.peer
->address
.host
, event
.peer
->address
.port
);
511 case ENET_EVENT_TYPE_RECEIVE
:
512 if (!event
.peer
) continue;
515 msg
= b_read_uint8(event
.packet
->data
, &b_read
);
519 enet_address_get_host_ip(&(event
.peer
->address
), ip
, 17);
520 port
= b_read_uint16(event
.packet
->data
, &b_read
);
522 name
= b_read_dstring(event
.packet
->data
, &b_read
);
523 map
= b_read_dstring(event
.packet
->data
, &b_read
);
524 gm
= b_read_uint8(event
.packet
->data
, &b_read
);
526 pl
= b_read_uint8(event
.packet
->data
, &b_read
);
527 mpl
= b_read_uint8(event
.packet
->data
, &b_read
);
529 proto
= b_read_uint8(event
.packet
->data
, &b_read
);
530 pw
= b_read_uint8(event
.packet
->data
, &b_read
);
532 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
533 if (ms_srv
[i
].used
) {
534 if ((strncmp(ip
, ms_srv
[i
].s_ip
, 16) == 0) && (ms_srv
[i
].s_port
== port
)) {
535 if (ban_heur(ms_srv
+ i
, now
) >= MS_MAXHEUR
) {
536 ban_add(&(event
.peer
->address
), LC_MS_BANHEUR
);
540 strncpy(ms_srv
[i
].s_map
, map
, sizeof(ms_srv
[i
].s_map
));
541 strncpy(ms_srv
[i
].s_name
, name
, sizeof(ms_srv
[i
].s_name
));
542 ms_srv
[i
].s_plrs
= pl
;
543 ms_srv
[i
].s_maxplrs
= mpl
;
545 ms_srv
[i
].s_mode
= gm
;
547 ms_srv
[i
].deathtime
= now
+ ms_timeout
;
548 ms_srv
[i
].lasttime
= now
;
550 printf(LC_MS_UPD
, i
, ip
, port
, name
, map
, gm
, pl
, mpl
, proto
, pw
);
554 strncpy(ms_srv
[i
].s_ip
, ip
, sizeof(ms_srv
[i
].s_ip
));
555 strncpy(ms_srv
[i
].s_map
, map
, sizeof(ms_srv
[i
].s_map
));
556 strncpy(ms_srv
[i
].s_name
, name
, sizeof(ms_srv
[i
].s_name
));
557 ms_srv
[i
].s_port
= port
;
558 ms_srv
[i
].s_plrs
= pl
;
559 ms_srv
[i
].s_maxplrs
= mpl
;
561 ms_srv
[i
].s_mode
= gm
;
562 ms_srv
[i
].s_protocol
= proto
;
563 ms_srv
[i
].deathtime
= now
+ ms_timeout
;
564 ms_srv
[i
].lasttime
= now
;
566 if (ban_heur(ms_srv
+ i
, now
) >= MS_MAXHEUR
) {
567 ban_add(&(event
.peer
->address
), LC_MS_BANHEUR
);
573 printf(LC_MS_ADD
, i
, ip
, port
, name
, map
, gm
, pl
, mpl
, proto
, pw
);
584 enet_address_get_host_ip(&(event
.peer
->address
), ip
, 17);
585 port
= b_read_uint16(event
.packet
->data
, &b_read
);
586 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
587 if (ms_srv
[i
].used
) {
588 if ((strncmp(ip
, ms_srv
[i
].s_ip
, 16) == 0) && (ms_srv
[i
].s_port
== port
)) {
589 if (ban_heur(ms_srv
+ i
, now
) >= MS_MAXHEUR
) {
590 ban_add(&(event
.peer
->address
), LC_MS_BANHEUR
);
594 printf(LC_MS_RM
, i
, ip
, port
);
603 b_write_uint8(b_send
, &b_write
, NET_MSG_LIST
);
605 if (event
.packet
->dataLength
> 2) {
606 // holy shit a fresh client
607 clientver
= b_read_dstring(event
.packet
->data
, &b_read
);
608 b_write_uint8(b_send
, &b_write
, ms_count
);
610 // old client, feed them bullshit first
611 b_write_uint8(b_send
, &b_write
, ms_count
+ 2);
612 for (int i
= 0; i
< MS_FAKESRVS
; ++i
)
613 b_write_server(b_send
, &b_write
, ms_fake_srv
[i
]);
616 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
617 if (ms_srv
[i
].used
) b_write_server(b_send
, &b_write
, ms_srv
[i
]);
621 // TODO: check if this client is outdated (?) and send back new verstring
622 // for now just write the same shit back
623 b_write_dstring(b_send
, &b_write
, clientver
);
624 // write the motd and urgent message
625 b_write_dstring(b_send
, &b_write
, ms_motd
);
626 b_write_dstring(b_send
, &b_write
, ms_urgent
);
629 ENetPacket
*p
= enet_packet_create(b_send
, b_write
, ENET_PACKET_FLAG_RELIABLE
);
630 enet_peer_send(event
.peer
, NET_CH_MAIN
, p
);
631 enet_host_flush(ms_host
);
633 printf(LC_MS_LIST
, event
.peer
->address
.host
, event
.peer
->address
.port
, clientver
? clientver
: "<old>");
639 enet_packet_destroy(event
.packet
);
647 time_t now
= time(NULL
);
648 for (int i
= 0; i
< MS_MAXSRVS
; ++i
) {
649 if (ms_srv
[i
].used
) {
650 if (ms_srv
[i
].deathtime
<= now
) {
652 printf(LC_MS_TIME
, i
, ms_srv
[i
].s_ip
, ms_srv
[i
].s_port
);