From 6557d31b7de9cc092277580dde71f412e78e4889 Mon Sep 17 00:00:00 2001 From: Olaf Rempel Date: Thu, 2 Feb 2006 16:31:52 +0100 Subject: [PATCH] Version 0.40 --- Makefile | 2 +- include/plugin.h | 1 + plugins/doom3.c | 2 +- plugins/{halo.c => gamespy1.c} | 38 ++- plugins/{battlefield1942.c => gamespy2.c} | 17 +- plugins/{quake3.c => q3engine.c} | 26 +- plugins/quake2.c | 6 +- plugins/ut.c | 26 +- src/logging.c | 14 +- src/main.c | 8 +- src/plugin_helper.c | 16 ++ src/scanner.c | 14 +- src/serverlist.c | 28 +- tools/masterquery.c | 317 ++++++++++++++-------- 14 files changed, 345 insertions(+), 170 deletions(-) rename plugins/{halo.c => gamespy1.c} (68%) rename plugins/{battlefield1942.c => gamespy2.c} (85%) rename plugins/{quake3.c => q3engine.c} (82%) diff --git a/Makefile b/Makefile index 33b1c69..26d5f3b 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # Toplevel Makefile MASTER_SRC := client.c daemon.c logging.c main.c plugin.c plugin_helper.c scanner.c serverlist.c -PLUGIN_SRC := hlswproxy.c quake3.c quake2.c halo.c doom3.c ut.c battlefield1942.c +PLUGIN_SRC := hlswproxy.c q3engine.c quake2.c gamespy1.c gamespy2.c ut.c doom3.c CFLAGS := -Wall -I. -I./include -g # ############################ diff --git a/include/plugin.h b/include/plugin.h index c03b116..4ac8199 100644 --- a/include/plugin.h +++ b/include/plugin.h @@ -23,6 +23,7 @@ extern int server_add_pkt(unsigned int gameid, struct net_pkt *pkt); extern char * pkt_ntoa(struct net_pkt *pkt); extern unsigned short pkt_getport(struct net_pkt *pkt); +extern int pkt_atoi(struct net_pkt *pkt, void *p); struct hlswmaster_plugin { /* must be first */ diff --git a/plugins/doom3.c b/plugins/doom3.c index e2dafd0..4c0add3 100644 --- a/plugins/doom3.c +++ b/plugins/doom3.c @@ -21,7 +21,7 @@ #include "plugin.h" struct scan_ports port_arr[] = { - { 27666, 27673, 38 }, /* Doom 3 */ + { 27666, 27673, 38 }, /* Doom 3 */ { 0,0,0 } }; diff --git a/plugins/halo.c b/plugins/gamespy1.c similarity index 68% rename from plugins/halo.c rename to plugins/gamespy1.c index f89a6e9..280241f 100644 --- a/plugins/halo.c +++ b/plugins/gamespy1.c @@ -20,24 +20,50 @@ #include #include "plugin.h" -static char scanmsg[] = { 0xFE, 0xFD, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static char replymsg[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +struct scan_ports port_arr[] = { + { 22000, 22010, 16 }, /* Battlefield 1942 */ + { 0, 0, 0 } +}; + +static char scanmsg[] = "\\info\\"; +static char bf1942_reply[] = "\\gameId\\BF1942\\"; +static char hostport_search[] = "\\hostport\\"; int scan(void) { - pkt_send(NULL, 2302, scanmsg, sizeof(scanmsg)); + pkt_send_portarr(NULL, port_arr, scanmsg, strlen(scanmsg)); return 1; } int parse(struct net_pkt *pkt) { - if (pkt_memcmp(pkt, 0, replymsg, sizeof(replymsg))) + int gameid, port; + void *p; + + if (!(gameid = pkt_check_portarr(pkt, port_arr))) return 0; - server_add_pkt(30, pkt); + switch (gameid) { + case 16: /* battlefield 1942 */ + if (!pkt_memmem(pkt, 0, bf1942_reply, strlen(bf1942_reply))) + return 0; + + p = pkt_memmem(pkt, 0, hostport_search, strlen(hostport_search)); + if (!p) + return 0; + + port = pkt_atoi(pkt, p + strlen(hostport_search)); + server_add(gameid, pkt->addr.sin_addr.s_addr, port, ntohs(pkt->addr.sin_port)); + break; + + default: + server_add_pkt(gameid, pkt); + break; + } + return 1; } static struct hlswmaster_plugin plugin = { - .name = "halo", + .name = "gamespy1", .scan = &scan, .parse = &parse, }; diff --git a/plugins/battlefield1942.c b/plugins/gamespy2.c similarity index 85% rename from plugins/battlefield1942.c rename to plugins/gamespy2.c index e354af9..a250c39 100644 --- a/plugins/battlefield1942.c +++ b/plugins/gamespy2.c @@ -21,34 +21,33 @@ #include "plugin.h" struct scan_ports port_arr[] = { - { 22000, 22010, 16 }, /* Battlefield 1942 */ + { 2302, 2302, 30 }, /* halo */ { 0,0,0 } }; -static char scanmsg[] = "\\info\\"; -static char replymsg[] = "ut "; +static char scanmsg[] = { 0xFE, 0xFD, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00, 0x00 }; +static char replymsg[] = { 0x00, 0xDE, 0xAD, 0xBE, 0xEF }; int scan(void) { - pkt_send_portarr(NULL, port_arr, scanmsg, strlen(scanmsg)); + pkt_send_portarr(NULL, port_arr, scanmsg, sizeof(scanmsg)); return 1; } -/* TODO: port2 parsen */ int parse(struct net_pkt *pkt) { int gameid; - if (pkt_memcmp(pkt, 0, replymsg, strlen(replymsg))) - return 0; - if (!(gameid = pkt_check_portarr(pkt, port_arr))) return 0; + + if (pkt_memcmp(pkt, 0, replymsg, sizeof(replymsg))) + return 0; server_add_pkt(gameid, pkt); return 1; } static struct hlswmaster_plugin plugin = { - .name = "battlefield1942", + .name = "gamespy2", .scan = &scan, .parse = &parse, }; diff --git a/plugins/quake3.c b/plugins/q3engine.c similarity index 82% rename from plugins/quake3.c rename to plugins/q3engine.c index 315900d..735fe4f 100644 --- a/plugins/quake3.c +++ b/plugins/q3engine.c @@ -21,13 +21,13 @@ #include "plugin.h" struct scan_ports port_arr[] = { - { 27960, 27963, 6 }, /* Quake3 */ - { 28960, 28963, 31 }, /* Call of Duty */ + { 27960, 27969, 6 }, /* Quake3(6), Elite Force(7) */ + { 28960, 28963, 31 }, /* Call of Duty(31) */ { 0,0,0 } }; -static char scanmsg[] = "\xff\xff\xff\xffgetInfo"; -static char replymsg[] = "\xff\xff\xff\xffinfoResponse"; +static char scanmsg[] = "\xff\xff\xff\xffgetStatus"; +static char replymsg[] = "\xff\xff\xff\xffstatusResponse"; int scan(void) { pkt_send_portarr(NULL, port_arr, scanmsg, strlen(scanmsg)); @@ -37,18 +37,30 @@ int scan(void) { int parse(struct net_pkt *pkt) { int gameid; + if (!(gameid = pkt_check_portarr(pkt, port_arr))) + return 0; + if (pkt_memcmp(pkt, 0, replymsg, strlen(replymsg))) return 0; - if (!(gameid = pkt_check_portarr(pkt, port_arr))) - return 0; + if (gameid == 6) { + if (pkt_memmem(pkt, 0, "\\version\\Q3 ", 12)) { + gameid = 6; + + } else if (pkt_memmem(pkt, 0, "\\version\\ST:V ", 14)) { + gameid = 7; + + } else { + return 0; + } + } server_add_pkt(gameid, pkt); return 1; } static struct hlswmaster_plugin plugin = { - .name = "quake3", + .name = "q3engine", .scan = &scan, .parse = &parse, }; diff --git a/plugins/quake2.c b/plugins/quake2.c index b19bd29..efd41d9 100644 --- a/plugins/quake2.c +++ b/plugins/quake2.c @@ -20,14 +20,18 @@ #include #include "plugin.h" -static char scanmsg[] = "\xff\xff\xff\xffinfo"; +static char scanmsg[] = "\xff\xff\xff\xffinfo 34"; int scan(void) { pkt_send(NULL, 27910, scanmsg, strlen(scanmsg)); return 1; } +/* TODO: src port checken */ int parse(struct net_pkt *pkt) { + if (pkt_getport(pkt) != 27910) + return 0; + if (pkt_memcmp(pkt, 0, scanmsg, strlen(scanmsg))) return 0; diff --git a/plugins/ut.c b/plugins/ut.c index 0287f91..5a853fe 100644 --- a/plugins/ut.c +++ b/plugins/ut.c @@ -26,24 +26,36 @@ struct scan_ports port_arr[] = { }; static char scanmsg[] = "REPORTQUERY"; -static char replymsg[] = "ut "; +static char ut_reply[] = "ut "; int scan(void) { pkt_send_portarr(NULL, port_arr, scanmsg, strlen(scanmsg)); return 1; } -/* TODO: port2 parsen */ int parse(struct net_pkt *pkt) { - int gameid; - - if (pkt_memcmp(pkt, 0, replymsg, strlen(replymsg))) - return 0; + int gameid, port; + void *p; if (!(gameid = pkt_check_portarr(pkt, port_arr))) return 0; + + switch (gameid) { + case 5: /* Unreal Tournament */ + p = pkt_memmem(pkt, 0, ut_reply, strlen(ut_reply)); + if (!p) + return 0; + + port = pkt_atoi(pkt, p + strlen(ut_reply)); + + server_add(gameid, pkt->addr.sin_addr.s_addr, port -1, port); + break; + + default: + server_add_pkt(gameid, pkt); + break; + } - server_add_pkt(gameid, pkt); return 1; } diff --git a/src/logging.c b/src/logging.c index af5ed5f..9a1ed2d 100644 --- a/src/logging.c +++ b/src/logging.c @@ -61,18 +61,18 @@ void log_open(char *logfile) { */ void log_print(const char *fmt, ...) { va_list az; - time_t tzgr; - char tbuf[64]; char buffer[256]; va_start(az, fmt); vsprintf(buffer, fmt, az); va_end(az); - time(&tzgr); - strftime(tbuf, 64, "%b %d %H:%M:%S :", localtime(&tzgr)); - if (log_fd) { + time_t tzgr; + char tbuf[64]; + time(&tzgr); + strftime(tbuf, 64, "%b %d %H:%M:%S :", localtime(&tzgr)); + if (errno) { fprintf(log_fd, "%s %s: %s\n", tbuf, buffer, strerror(errno)); } else { @@ -80,9 +80,9 @@ void log_print(const char *fmt, ...) { } } else { if (errno) { - fprintf(stderr, "%s %s: %s\n", tbuf, buffer, strerror(errno)); + fprintf(stderr, "%s: %s\n", buffer, strerror(errno)); } else { - fprintf(stderr, "%s %s\n", tbuf, buffer); + fprintf(stderr, "%s\n", buffer); } } errno = 0; diff --git a/src/main.c b/src/main.c index da19958..4b0c903 100644 --- a/src/main.c +++ b/src/main.c @@ -78,13 +78,13 @@ int main(int argc, char *argv[]) { } - plugin_load("plugins/hlswproxy.so"); - plugin_load("plugins/quake3.so"); +// plugin_load("plugins/hlswproxy.so"); + plugin_load("plugins/q3engine.so"); plugin_load("plugins/quake2.so"); - plugin_load("plugins/halo.so"); + plugin_load("plugins/gamespy1.so"); + plugin_load("plugins/gamespy2.so"); plugin_load("plugins/doom3.so"); plugin_load("plugins/ut.so"); - plugin_load("plugins/battlefield1942.so"); scan_init(); diff --git a/src/plugin_helper.c b/src/plugin_helper.c index a240350..1f836fd 100644 --- a/src/plugin_helper.c +++ b/src/plugin_helper.c @@ -174,3 +174,19 @@ char * pkt_ntoa(struct net_pkt *pkt) { unsigned short pkt_getport(struct net_pkt *pkt) { return ntohs(pkt->addr.sin_port); } + +/** + * pkt_atoi() + * gibt den integer in dem paket ab der position zurueck + * + * @param struct net_pkt *pkt + * @return int + */ +int pkt_atoi(struct net_pkt *pkt, void *p) { + /* check buffer bounds */ + if ((void *)pkt->buf > p || ((void *)pkt->buf + pkt->size) < p) + return 0; + + // TODO: kann ueber paketlaenge lesen + return atoi(p); +} diff --git a/src/scanner.c b/src/scanner.c index 5addd6a..a8c7bd3 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -65,7 +65,7 @@ void scan_transmit(void) { list_del(&pkt->list); free(pkt); - usleep(100000); + usleep(10000); } sleep(30); @@ -91,17 +91,21 @@ void scan_receive(void) { ioctl(scan_sock, FIONREAD, &recvsize); - if (recvsize <= 0) + if (recvsize <= 0) { + log_print("scan_receive(): drop short packet"); continue; - - if (!(pkt = malloc(sizeof(struct net_pkt) + recvsize))) + } + + if (!(pkt = malloc(sizeof(struct net_pkt) + recvsize))) { + log_print("scan_receive(): malloc()"); continue; + } i = sizeof(struct sockaddr_in); pkt->size = recvfrom(scan_sock, pkt->buf, recvsize, 0, (struct sockaddr *)&pkt->addr, &i); if (!plugins_parse(pkt)) - log_print("received unknown packet\n"); + log_print("scan_receive(): received unknown packet"); free(pkt); } diff --git a/src/serverlist.c b/src/serverlist.c index dbc17fe..1aebbb7 100644 --- a/src/serverlist.c +++ b/src/serverlist.c @@ -32,6 +32,8 @@ #include "plugin.h" #include "list.h" +#define DEBUG 1 + LIST_HEAD(server_list); /* sichert die server liste */ @@ -80,12 +82,14 @@ int server_add(u_int16_t gameid, u_int32_t ip, u_int16_t port1, u_int16_t port2) pthread_mutex_unlock(&server_list_lock); return 0; } - - struct in_addr tmp; - tmp.s_addr = server.ip; - printf("new server: gameid=%d ip=%s port1=%d port2=%d\n", - server.gameid, inet_ntoa(tmp), server.port1, server.port2); - +#ifdef DEBUG + { + struct in_addr tmp; + tmp.s_addr = server.ip; + printf("server_add_new: gameid=%d ip=%s port1=%d port2=%d\n", + server.gameid, inet_ntoa(tmp), server.port1, server.port2); + } +#endif memcpy(nserver, &server, sizeof(struct game_server)); list_add_tail(&nserver->list, &server_list); } @@ -106,7 +110,7 @@ int server_add(u_int16_t gameid, u_int32_t ip, u_int16_t port1, u_int16_t port2) */ void server_collector(void) { struct game_server *server, *tmp; - unsigned long now, timeout = 120; + unsigned long now, timeout = 60; while (1) { sleep(5); @@ -114,7 +118,15 @@ void server_collector(void) { now = time(NULL); pthread_mutex_lock(&server_list_lock); list_for_each_entry_safe(server, tmp, &server_list, list) { - if (server->modtime + timeout < now) { + if ((server->modtime + timeout) < now) { +#ifdef DEBUG + { + struct in_addr tmp2; + tmp2.s_addr = server->ip; + printf("server timeout: gameid=%d ip=%s port1=%d port2=%d\n", + server->gameid, inet_ntoa(tmp2), server->port1, server->port2); + } +#endif list_del(&server->list); free(server); continue; diff --git a/tools/masterquery.c b/tools/masterquery.c index ce663ea..079a60e 100644 --- a/tools/masterquery.c +++ b/tools/masterquery.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -17,133 +18,221 @@ struct _entry { u_int16_t port2; } __attribute__ ((packed)); -static char scanmsg[] = "\xFF\xFF\xFF\xFFHLSWLANSEARCH"; +static char hlswheader[] = "\xFF\xFF\xFF\xFFHLSWLANSEARCH"; -char *gameid2name[] = { "Unknown", // 0 - "HL", - "Q1", - "Q2", - "Q3Comp", - "UT", - "Q3", - "EF", - "RtCW", - "GSProt", - "CCR", // 10 - "MoHAA", - "JK2", - "SoF2", - "UT2K3", - "AAO", - "BF1942", - "AvP2", - "Rune", - "IGI2", - "NWN", // 20 - "MoHAAS", - "OPF", - "OPFR", - "DVS", - "ET", - "EF2", - "JK3", - "MoHAAB", - "Tribes2", - "HALO", // 30 - "CoD", - "Savage", - "UT2K4", - "HLSteam", - "BFV", - "GS2Prot", - "PK", - "D3", - "OGPProt", - "HL2", // 40 - "TribesV", - "CoDUO" }; +static char *id2name[] = { + "Unknown", // 0 + "Halflife", + "Quake 1", + "Quake 2", + "Q3Comp", + "Unreal Tournament", + "Quake 3 Arena", + "Elite Force", + "Return to Castle Wolfenstein", + "GSProt", + "Command & Conquer Renegade", // 10 + "Medal of Honor: Allied Assault", + "Jedi Knight 2", + "Soldier of Fortune", + "Unreal Tournament 2003", + "America's Army: Operations", + "Battlefield 1942", + "Alien vs. Predator 2", + "Rune", + "Project IGI2: Covert Strike", + "Never Winter Nights", // 20 + "Medal of Honor: Allied Assault Spearhead", + "Operation Flashpoint", + "Operation Flashpoint Resistance", + "Devastation", + "Wolfenstein - Enemy Territory", + "Elite Force 2", + "Jedi Knight 3", + "Medal of Honor: Allied Assault Breakthrough", + "Tribes 2", + "Halo", // 30 + "Call of Duty", + "Savage: The Battle for Newerth", + "Unreal Tournament 2004", + "HLSteam", + "Battlefield Vietnam", + "GS2Prot", + "Pain Killer", + "Doom 3", + "OGPProt", + "Halflife 2", // 40 + "Tribes Vengeance", + "Call of Duty: United Offensive" +}; -int main(int argc, char *argv[]) { - struct sockaddr_in dst; - struct timeval tv; - struct _entry *srv; - fd_set fdsel, fdcpy; - int sock, i = 1, recvsize; - void *pkt; +static struct option opts[] = { + {"destination", 1, 0, 'd'}, + {"intervall", 1, 0, 'i'}, + {"help", 0, 0, 'h'}, + {0, 0, 0, 0} +}; +static int sock; + +static void parse_pkt(struct sockaddr_in *src, void *pkt, unsigned int size) { + struct _entry *server; + struct in_addr tmp; + + if (size < sizeof(hlswheader) || strncmp(pkt, hlswheader, sizeof(hlswheader))) { + printf("received INVALID packet from: %15s:%-5d size=%d\n", + inet_ntoa(src->sin_addr), ntohs(src->sin_port), size); + + } else { + printf("received hlsw packet from: %15s:%-5d size=%d\n", + inet_ntoa(src->sin_addr), ntohs(src->sin_port), size); + + server = pkt + sizeof(hlswheader); + while ((void *)server < pkt + size) { + tmp.s_addr = server->ip; + printf(" ip=%15s port1=%5d port2=%5d gameid=%2d (%s)\n", + inet_ntoa(tmp), server->port1, server->port2, + server->gameid, id2name[server->gameid]); + server++; + } + } +} + +static int scan_init() { + int i = 1; + if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket()"); - exit(-1); + return -1; } if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i))) { perror("setsockopt()"); - exit(-1); + return -1; } - dst.sin_family = AF_INET; - dst.sin_port = htons(7130); - inet_aton("0.0.0.0", &dst.sin_addr); - - if (bind(sock, (struct sockaddr *)&dst, sizeof(dst)) < 0) { - perror("bind()"); - exit(-1); - } - - dst.sin_port = htons(7140); - inet_aton("255.255.255.255", &dst.sin_addr); - - if (sendto(sock, scanmsg, sizeof(scanmsg), 0, (struct sockaddr *)&dst, sizeof(dst)) < 0) { + return 0; +} + +static int scan_transmit(struct sockaddr_in *dst) { + if (sendto(sock, hlswheader, sizeof(hlswheader), 0, (struct sockaddr *)dst, sizeof(struct sockaddr_in)) < 0) { perror("sendto()"); - exit(-1); - } - - FD_ZERO(&fdsel); - FD_SET(sock, &fdsel); - - tv.tv_sec = 1; - tv.tv_usec = 0; - - while (1) { - memcpy(&fdcpy, &fdsel, sizeof(fdsel)); - if (select(FD_SETSIZE, &fdcpy, NULL, NULL, &tv) < 0) { - perror("select"); - exit(-1); - } - - if (tv.tv_sec == 0 && tv.tv_usec == 0) - exit(0); - - ioctl(sock, FIONREAD, &recvsize); - - if (recvsize <= 0) { - continue; - } - - if (!(pkt = malloc(recvsize))) { - perror("malloc()"); - exit(-1); - } - - i = sizeof(struct sockaddr_in); - recvsize = recvfrom(sock, pkt, recvsize, 0, (struct sockaddr *)&dst, &i); - - printf("received packet from: %s:%d size=%d\n", - inet_ntoa(dst.sin_addr), ntohs(dst.sin_port), recvsize); - - srv = pkt + sizeof(scanmsg); - while ((void *)srv < pkt + recvsize) { - dst.sin_addr.s_addr = srv->ip; - printf(" ip=%s port1=%d port2=%d gameid=%d (%s)\n", - inet_ntoa(dst.sin_addr), - srv->port1, - srv->port2, - srv->gameid, - gameid2name[srv->gameid]); - srv++; - } - free(pkt); + return -1; } return 0; } + +static int scan_receive() { + struct sockaddr_in src; + struct timeval tv; + fd_set fdsel; + unsigned int i = 1, recvsize; + void *pkt; + + FD_ZERO(&fdsel); + FD_SET(sock, &fdsel); + + tv.tv_sec = 1; + tv.tv_usec = 0; + + while (1) { + if (select(FD_SETSIZE, &fdsel, NULL, NULL, &tv) < 0) { + perror("select"); + return -1; + } + + /* timeout: our exit */ + if (tv.tv_sec == 0 && tv.tv_usec == 0) + break; + + /* get packetsize */ + if (ioctl(sock, FIONREAD, &recvsize) == -1) { + perror("ioctl"); + return -1; + } + + if (recvsize > 0) { + if (!(pkt = malloc(recvsize))) { + perror("malloc()"); + return -1; + } + + i = sizeof(struct sockaddr_in); + recvsize = recvfrom(sock, pkt, recvsize, 0, (struct sockaddr *)&src, &i); + + parse_pkt(&src, pkt, recvsize); + + free(pkt); + } + } + + return 0; +} + +int main(int argc, char *argv[]) { + struct sockaddr_in dst; + int arg = 0, code = 0; + int freq = -1; + + dst.sin_family = AF_INET; + dst.sin_port = htons(7140); + inet_aton("255.255.255.255", &dst.sin_addr); + + while (code != -1) { + code = getopt_long(argc, argv, "d:i:h", opts, &arg); + + switch (code) { + case 'd': /* destination */ + if (inet_pton(dst.sin_family, optarg, &dst.sin_addr) <= 0) { + fprintf(stderr, "invalid destination: %s\n", optarg); + exit(-1); + } + break; + + case 'i': /* intervall */ + freq = atoi(optarg); + if (freq < 1) { + fprintf(stderr, "invalid interval: %s\n", optarg); + exit(-1); + } + break; + + case 'h': /* help */ + printf("Usage: masterquery [options]\n" + "Options: \n" + " --destination -d scan destination \n" + " --intervall -i scan intervall in seconds\n" + " --help -h this help\n" + "\n"); + exit(0); + break; + + case '?': /* error */ + exit(-1); + break; + + default: /* unknown / all options parsed */ + break; + } + } + + if (scan_init()) + exit(-1); + + while (1) { + if (scan_transmit(&dst)) + exit(-1); + + if (scan_receive()) + exit(-1); + + if (freq < 0) + break; + + sleep(freq -1); + } + + close(sock); + return 0; +}