diff --git a/list.cpp b/list.cpp new file mode 100644 index 0000000..3c4b5be --- /dev/null +++ b/list.cpp @@ -0,0 +1,150 @@ +#include +#include +#include + +#include "list.h" + +ListBase::ListBase() +{ +} + +ListBase::~ListBase() +{ + AutoMutex am(mutex); + while(!head.isEmpty()) + head.getNext()->del(); +} + +void ListBase::add(const void* part) +{ + ListEntryBase* entry = new ListEntryBase(part); + + AutoMutex am(mutex); + entry->add(&head, head.getNext()); +} + +void ListBase::addTail(const void* part) +{ + ListEntryBase* entry = new ListEntryBase(part); + + AutoMutex am(mutex); + entry->add(head.getPrev(), &head); +} + +void* ListBase::get() +{ + AutoMutex am(mutex); + ListEntryBase* entry = head.getNext(); + void* retval = entry->getPart(); + + if (!head.isEmpty()) { + entry->del(); + delete entry; + } + return retval; +} + +void* ListBase::getTail() +{ + AutoMutex am(mutex); + ListEntryBase* entry = head.getPrev(); + void* retval = entry->getPart(); + + if (!head.isEmpty()) { + entry->del(); + delete entry; + } + return retval; +} + +bool ListBase::isEmpty() const +{ + AutoMutex am((Mutex&)mutex); + return head.isEmpty(); +} + +IteratorBase* ListBase::createIterator() +{ + return new ListIteratorBase(this); +} + +ListBase::ListEntryBase::ListEntryBase(const void* part) +: prev(this), next(this), part(part) +{ +} + +ListBase::ListEntryBase::~ListEntryBase() +{ +} + +void ListBase::ListEntryBase::add(ListEntryBase* prev_, ListEntryBase* next_) +{ + this->next = next_; + this->prev = prev_; + next_->prev = this; + prev_->next = this; +} + +void ListBase::ListEntryBase::del() +{ + next->prev = prev; + prev->next = next; + next = prev = this; +} + +bool ListBase::ListEntryBase::isEmpty() const +{ + return (this->prev == this) && (this->next == this); +} + +void* ListBase::ListEntryBase::getPart() const +{ + // const void* -> void* + return (void*)part; +} + +ListBase::ListEntryBase* ListBase::ListEntryBase::getPrev() const +{ + return prev; +} + +ListBase::ListEntryBase* ListBase::ListEntryBase::getNext() const +{ + return next; +} + +ListBase::ListIteratorBase::ListIteratorBase(ListBase* list) +: list(list) +{ + list->mutex.lock(); + reset(); +} + +ListBase::ListIteratorBase::~ListIteratorBase() +{ + list->mutex.unlock(); +} + +bool ListBase::ListIteratorBase::hasNext() +{ + return (pos->getNext() != &list->head); +} + +void* ListBase::ListIteratorBase::next() +{ + pos = pos->getNext(); + return pos->getPart(); +} + +void ListBase::ListIteratorBase::remove() +{ + ListEntryBase* tmp = pos->getPrev(); + pos->del(); + pos = tmp; +} + +void ListBase::ListIteratorBase::reset() +{ + pos = &list->head; +} + diff --git a/masterquery.c b/masterquery.c new file mode 100644 index 0000000..a4667ab --- /dev/null +++ b/masterquery.c @@ -0,0 +1,252 @@ +#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"; + +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 + "?", + "Quake 4 (?)", + "Call of Duty 2" +}; + +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, id2name[server->gameid]); + server++; + } + } + } +} + +static int scan_init() +{ + int i = 1; + + if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + perror("socket()"); + return -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; +} diff --git a/mod_hlswproxy.cpp b/mod_hlswproxy.cpp new file mode 100644 index 0000000..d00b897 --- /dev/null +++ b/mod_hlswproxy.cpp @@ -0,0 +1,25 @@ +#include +#include "netpkt.h" +#include "modhelper.h" +#include "mod_hlswproxy.h" + +ModHlswProxy::ModHlswProxy(Config& conf) +{ + // TODO: implement +} + +ModHlswProxy::~ModHlswProxy() +{ + // TODO: implement +} + +void ModHlswProxy::scan(MultiSock* msock) +{ + // TODO: implement +} + +int ModHlswProxy::parse(NetPkt* pkt, GameList* glist) +{ + // TODO: implement + return PARSE_REJECT; +} diff --git a/mod_hlswproxy.h b/mod_hlswproxy.h new file mode 100644 index 0000000..8522461 --- /dev/null +++ b/mod_hlswproxy.h @@ -0,0 +1,18 @@ +#ifndef _MODHLSWPROXY_H_ +#define _MODHLSWPROXY_H_ + +#include "config.h" +#include "module.h" + +class ModHlswProxy : public Module { +public: + ModHlswProxy(Config& conf); + ~ModHlswProxy(); + + void scan(MultiSock* msock); + int parse(NetPkt* pkt, GameList* glist); + + const char* getName() { return "HlswProxy"; } +}; + +#endif // _MODHLSWPROXY_H_ diff --git a/mod_quake2.cpp b/mod_quake2.cpp new file mode 100644 index 0000000..410302f --- /dev/null +++ b/mod_quake2.cpp @@ -0,0 +1,27 @@ +#include +#include "netpkt.h" +#include "modhelper.h" +#include "mod_quake2.h" + +#define QUAKE2_PORT 27910 + +// scan for latest protocol version +static const char scanmsg[] = "\xff\xff\xff\xffinfo 34"; +static const char replyhead[] = "\xff\xff\xff\xffinfo"; + +void ModQuake2::scan(MultiSock* msock) +{ + ModHelper::send(msock, QUAKE2_PORT, scanmsg, strlen(scanmsg)); +} + +int ModQuake2::parse(NetPkt* pkt, GameList* glist) +{ + if (pkt->getPort() != QUAKE2_PORT) + return PARSE_REJECT; + + if (!pkt->compare(0, replyhead, strlen(replyhead))) + return PARSE_REJECT; + + glist->addGame(ID_Q2, pkt); + return PARSE_ACCEPT; +} diff --git a/mod_quake2.h b/mod_quake2.h new file mode 100644 index 0000000..fa81dfb --- /dev/null +++ b/mod_quake2.h @@ -0,0 +1,17 @@ +#ifndef _MODQUAKE2_H_ +#define _MODQUAKE2_H_ + +#include "module.h" + +class ModQuake2 : public Module { +public: + ModQuake2() {} + ~ModQuake2() {} + + void scan(MultiSock* msock); + int parse(NetPkt* pkt, GameList* slist); + + const char* getName() { return "Quake2 protocol"; } +}; + +#endif // _MODQUAKE2_H_ diff --git a/mod_ut.cpp b/mod_ut.cpp new file mode 100644 index 0000000..96ab339 --- /dev/null +++ b/mod_ut.cpp @@ -0,0 +1,26 @@ +#include +#include "netpkt.h" +#include "modhelper.h" +#include "mod_ut.h" + +#define UT2K4_PORT 10777 + +// there are more scans on different ports.. +static const char scanmsg[] = { 0x80, 0x00, 0x00, 0x00, 0x00 }; + +void ModUT::scan(MultiSock* msock) +{ + ModHelper::send(msock, UT2K4_PORT, scanmsg, sizeof(scanmsg)); +} + +int ModUT::parse(NetPkt* pkt, GameList* glist) +{ + if (pkt->getPort() != UT2K4_PORT) + return PARSE_REJECT; + + if (!pkt->compare(0, scanmsg, sizeof(scanmsg))) + return PARSE_REJECT; + + glist->addGame(ID_UT2K4, pkt); + return PARSE_ACCEPT; +} diff --git a/mod_ut.h b/mod_ut.h new file mode 100644 index 0000000..1956343 --- /dev/null +++ b/mod_ut.h @@ -0,0 +1,17 @@ +#ifndef _MODUT_H_ +#define _MODUT_H_ + +#include "module.h" + +class ModUT : public Module { +public: + ModUT() {} + ~ModUT() {} + + void scan(MultiSock* msock); + int parse(NetPkt* pkt, GameList* slist); + + const char* getName() { return "UT protocol (native)"; } +}; + +#endif // _MODUT_H_