#include #include #include #include #include #include #include #include #include #include #include #include #include struct _entry { uint16_t gameid; uint32_t ip; uint16_t port1; uint16_t port2; } __attribute__ ((packed)); static char hlswheader[] = "\xFF\xFF\xFF\xFFHLSWLANSEARCH"; #define id2name_count (sizeof(id2name) / sizeof(char *) -1) static char *id2name[] = { "Unknown", // 0 "Halflife", "Quake 1", "Quake 2", "Q3Comp", "Unreal Tournament", // 5 "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", // 15 "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", //25 "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", // 35 "GS2Prot", "Pain Killer", "Doom 3", "OGPProt", "Halflife 2", // 40 "Tribes Vengeance", "Call of Duty: United Offensive", "Starwars: Battlefront (?)", "SWAT 4", "Battlefield 2", // 45 "unknown", "Quake 4", "Call of Duty 2", "unknown", "FEAR", // 50 "Warsow(?)" }; static int sock, verbose = 0; 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 count=%d\n", inet_ntoa(src->sin_addr), ntohs(src->sin_port), size, ((size > sizeof(hlswheader)) ? (size - sizeof(hlswheader)) / sizeof(struct _entry) : 0)); if (verbose) { 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, server->gameid <= id2name_count ? id2name[server->gameid] : "unknown"); server++; } } } } static int scan_init() { sock = socket(PF_INET, SOCK_DGRAM, 0); if (sock < 0) { perror("socket()"); return -1; } unsigned int i = 1; if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i))) { perror("setsockopt()"); return -1; } 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()"); 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; /* timeout */ while (tv.tv_sec > 0 || tv.tv_usec > 0) { if (select(FD_SETSIZE, &fdsel, NULL, NULL, &tv) < 0) { perror("select()"); return -1; } /* 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; } static struct option opts[] = { {"destination", 1, 0, 'd'}, {"intervall", 1, 0, 'i'}, {"verbose", 0, 0, 'v'}, {"help", 0, 0, 'h'}, {0, 0, 0, 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:vh", 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 'v': /* verbose */ verbose = 1; break; case 'h': /* help */ printf("Usage: masterquery [options]\n" "Options: \n" " --destination -d scan destination \n" " --intervall -i scan intervall in seconds\n" " --verbose -v verbose: show packet content\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); do { if (scan_transmit(&dst)) exit(-1); if (scan_receive()) exit(-1); } while (freq >= 1 && !sleep(freq -1)); close(sock); return 0; }