Version 0.60

- added receive-queue
- changed plugin_helper api from void* to uint offsets
- gamespy1 multi-packet response support
- q3engine plugin rewrite
- added halflife plugin
This commit is contained in:
Olaf Rempel 2006-02-02 16:47:20 +01:00
parent 861d41be08
commit 90d33bffbf
29 changed files with 881 additions and 269 deletions

View File

@ -1,5 +1,12 @@
* Sun 15 May 2005 Olaf Rempel <razzor@kopf-tisch.de> 0.60
- added receive-queue
- changed plugin_helper api from void* to uint offsets
- gamespy1 multi-packet response support
- q3engine plugin rewrite
- added halflife plugin
* Tue 19 Apr 2005 Olaf Rempel <razzor@kopf-tisch.de> 0.53
- code cleanup (mostly doxygen tags)
- code cleanup
- added doxygen file
* Thu 31 Mar 2005 Olaf Rempel <razzor@kopf-tisch.de> 0.52

View File

@ -2,4 +2,4 @@ AUTOMAKE_OPTIONS = foreign no-dependencies
SUBDIRS = src plugins tools
EXTRA_DIST = TODO autogen.sh hlswmaster.conf contrib
EXTRA_DIST = TODO autogen.sh hlswmaster.conf doc

View File

@ -174,7 +174,7 @@ sysconfdir = @sysconfdir@
target_alias = @target_alias@
AUTOMAKE_OPTIONS = foreign no-dependencies
SUBDIRS = src plugins tools
EXTRA_DIST = TODO autogen.sh hlswmaster.conf contrib
EXTRA_DIST = TODO autogen.sh hlswmaster.conf doc
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-recursive

3
TODO
View File

@ -5,13 +5,11 @@
- auf mehreren/allen interfaces gleichzeitig scannen
geht das ueberhaupt? ohne root rechte?
- threads ueberwachen
- threadpool fuer client-thread?
- statistiken? webserver? gamespy-export?
- Makefile: stripping binarys?
und natuerlich:
- weitere spiele finden:
Halflife
Quake 1
Command & Conquer Renegade
Medal of Honor: Allied Assault
@ -26,7 +24,6 @@ und natuerlich:
Tribes 2
Savage: The Battle for Newerth
Pain Killer
Halflife 2
Tribes Vengeance
- vorhandene parser debuggen & verbessern

20
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.59 for hlswmaster 0.53.
# Generated by GNU Autoconf 2.59 for hlswmaster 0.60.
#
# Report bugs to <Olaf Rempel <razzor@kopf-tisch.de>>.
#
@ -423,8 +423,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='hlswmaster'
PACKAGE_TARNAME='hlswmaster'
PACKAGE_VERSION='0.53'
PACKAGE_STRING='hlswmaster 0.53'
PACKAGE_VERSION='0.60'
PACKAGE_STRING='hlswmaster 0.60'
PACKAGE_BUGREPORT='Olaf Rempel <razzor@kopf-tisch.de>'
# Factoring default headers for most tests.
@ -953,7 +953,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures hlswmaster 0.53 to adapt to many kinds of systems.
\`configure' configures hlswmaster 0.60 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1019,7 +1019,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of hlswmaster 0.53:";;
short | recursive ) echo "Configuration of hlswmaster 0.60:";;
esac
cat <<\_ACEOF
@ -1160,7 +1160,7 @@ fi
test -n "$ac_init_help" && exit 0
if $ac_init_version; then
cat <<\_ACEOF
hlswmaster configure 0.53
hlswmaster configure 0.60
generated by GNU Autoconf 2.59
Copyright (C) 2003 Free Software Foundation, Inc.
@ -1174,7 +1174,7 @@ cat >&5 <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by hlswmaster $as_me 0.53, which was
It was created by hlswmaster $as_me 0.60, which was
generated by GNU Autoconf 2.59. Invocation command line was
$ $0 $@
@ -1818,7 +1818,7 @@ fi
# Define the identity of the package.
PACKAGE=hlswmaster
VERSION=0.53
VERSION=0.60
cat >>confdefs.h <<_ACEOF
@ -21419,7 +21419,7 @@ _ASBOX
} >&5
cat >&5 <<_CSEOF
This file was extended by hlswmaster $as_me 0.53, which was
This file was extended by hlswmaster $as_me 0.60, which was
generated by GNU Autoconf 2.59. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -21482,7 +21482,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
hlswmaster config.status 0.53
hlswmaster config.status 0.60
configured by $0, generated by GNU Autoconf 2.59,
with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"

View File

@ -1,8 +1,8 @@
dnl projekname, version, bugsto
AC_INIT(hlswmaster, 0.53, [Olaf Rempel <razzor@kopf-tisch.de>])
AC_INIT(hlswmaster, 0.60, [Olaf Rempel <razzor@kopf-tisch.de>])
dnl same for automake
AM_INIT_AUTOMAKE(hlswmaster, 0.53)
AM_INIT_AUTOMAKE(hlswmaster, 0.60)
dnl do not rebuild configure
AM_MAINTAINER_MODE

View File

@ -5,7 +5,7 @@
#---------------------------------------------------------------------------
PROJECT_NAME = hlswmaster
PROJECT_NUMBER = 0.53
OUTPUT_DIRECTORY = ../doc
OUTPUT_DIRECTORY = .
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
USE_WINDOWS_ENCODING = NO

View File

@ -10,7 +10,7 @@ scan_interval 30
serverlist_interval 5
# server timeout after X seconds
serverlist_timeout 30
serverlist_timeout 60
# plugin data timeout every X seconds
plugin_timeout 30
@ -19,7 +19,8 @@ plugin_timeout 30
master_ip 0.0.0.0
# load these plugins
plugin plugins/.libs/hlswproxy.so
#plugin plugins/.libs/hlswproxy.so
plugin plugins/.libs/halflife.so
plugin plugins/.libs/q3engine.so
plugin plugins/.libs/quake2.so
plugin plugins/.libs/gamespy1.so
@ -30,6 +31,12 @@ plugin plugins/.libs/doom3.so
logfile hlswmaster.log
[hlswproxy]
# ask these hlswmasters
scan_ip 10.10.0.1
scan_ip 10.10.0.2
[halflife]
# allow these nets
valid_net 10.10.0.0/16
valid_net 172.16.0.0/16

View File

@ -2,13 +2,13 @@
#define _LIST_H
/*
* stolen from linux kernel (2.6.11)
* stolen from linux kernel 2.6.11 (http://kernel.org/)
* linux/include/linux/stddef.h (offsetoff)
* linux/include/linux/kernel.h (container_of)
* linux/include/linux/list.h (*list*)
* linux/include/linux/netfilter_ipv4/listhelp.h (LIST_FIND)
*
* modified by Olaf Rempel
* modified by Olaf Rempel <razzor@kopf-tisch.de>
*/
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

View File

@ -5,6 +5,15 @@
#include "configfile.h"
#include "list.h"
// paket nicht akzeptiert, free() muss noch aufgerufen werden
#define PARSE_REJECT 0
// paket akzeptiert, free() muss noch aufgerufen werden
#define PARSE_ACCEPT 1
// paket akzeptiert, free() wurde schon, oder darf noch aufgerufen werden
#define PARSE_ACCEPT_FREED 2
struct hlswmaster_plugin {
struct list_head list;

View File

@ -18,12 +18,16 @@ extern int pkt_send_portarr(struct in_addr *dstip, struct scan_ports *portarr, c
extern int pkt_check_portarr(struct net_pkt *pkt, struct scan_ports *portarr);
extern int pkt_memcmp(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size);
extern void * pkt_memmem(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size);
extern int pkt_memmem(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size);
extern struct net_pkt * pkt_merge(struct net_pkt *pkt1, struct net_pkt *pkt2);
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);
extern int pkt_sameaddr(struct net_pkt *pkt1, struct net_pkt *pkt2);
extern int pkt_parse_int(struct net_pkt *pkt, unsigned int offset, int *val);
extern int pkt_parse_ip(struct net_pkt *pkt, int offset, struct in_addr *ip);
extern char * pkt_print(struct net_pkt *pkt);
#endif /* _PLUGIN_HELPER_H */

View File

@ -4,7 +4,7 @@ EXTRA_DIST = skel.c
INCLUDES = -I../include
pkgdata_LTLIBRARIES = doom3.la gamespy1.la gamespy2.la hlswproxy.la q3engine.la quake2.la
pkgdata_LTLIBRARIES = doom3.la gamespy1.la gamespy2.la halflife.la hlswproxy.la q3engine.la quake2.la
doom3_la_SOURCES = doom3.c
doom3_la_LDFLAGS = -module -avoid-version
@ -15,6 +15,9 @@ gamespy1_la_LDFLAGS = -module -avoid-version
gamespy2_la_SOURCES = gamespy2.c
gamespy2_la_LDFLAGS = -module -avoid-version
halflife_la_SOURCES = halflife.c
halflife_la_LDFLAGS = -module -avoid-version
hlswproxy_la_SOURCES = hlswproxy.c
hlswproxy_la_LDFLAGS = -module -avoid-version

View File

@ -14,7 +14,7 @@
@SET_MAKE@
SOURCES = $(doom3_la_SOURCES) $(gamespy1_la_SOURCES) $(gamespy2_la_SOURCES) $(hlswproxy_la_SOURCES) $(q3engine_la_SOURCES) $(quake2_la_SOURCES)
SOURCES = $(doom3_la_SOURCES) $(gamespy1_la_SOURCES) $(gamespy2_la_SOURCES) $(halflife_la_SOURCES) $(hlswproxy_la_SOURCES) $(q3engine_la_SOURCES) $(quake2_la_SOURCES)
srcdir = @srcdir@
top_srcdir = @top_srcdir@
@ -65,6 +65,9 @@ gamespy1_la_OBJECTS = $(am_gamespy1_la_OBJECTS)
gamespy2_la_LIBADD =
am_gamespy2_la_OBJECTS = gamespy2.lo
gamespy2_la_OBJECTS = $(am_gamespy2_la_OBJECTS)
halflife_la_LIBADD =
am_halflife_la_OBJECTS = halflife.lo
halflife_la_OBJECTS = $(am_halflife_la_OBJECTS)
hlswproxy_la_LIBADD =
am_hlswproxy_la_OBJECTS = hlswproxy.lo
hlswproxy_la_OBJECTS = $(am_hlswproxy_la_OBJECTS)
@ -86,11 +89,13 @@ CCLD = $(CC)
LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(doom3_la_SOURCES) $(gamespy1_la_SOURCES) \
$(gamespy2_la_SOURCES) $(hlswproxy_la_SOURCES) \
$(q3engine_la_SOURCES) $(quake2_la_SOURCES)
$(gamespy2_la_SOURCES) $(halflife_la_SOURCES) \
$(hlswproxy_la_SOURCES) $(q3engine_la_SOURCES) \
$(quake2_la_SOURCES)
DIST_SOURCES = $(doom3_la_SOURCES) $(gamespy1_la_SOURCES) \
$(gamespy2_la_SOURCES) $(hlswproxy_la_SOURCES) \
$(q3engine_la_SOURCES) $(quake2_la_SOURCES)
$(gamespy2_la_SOURCES) $(halflife_la_SOURCES) \
$(hlswproxy_la_SOURCES) $(q3engine_la_SOURCES) \
$(quake2_la_SOURCES)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@ -196,13 +201,15 @@ target_alias = @target_alias@
AUTOMAKE_OPTIONS = foreign no-dependencies
EXTRA_DIST = skel.c
INCLUDES = -I../include
pkgdata_LTLIBRARIES = doom3.la gamespy1.la gamespy2.la hlswproxy.la q3engine.la quake2.la
pkgdata_LTLIBRARIES = doom3.la gamespy1.la gamespy2.la halflife.la hlswproxy.la q3engine.la quake2.la
doom3_la_SOURCES = doom3.c
doom3_la_LDFLAGS = -module -avoid-version
gamespy1_la_SOURCES = gamespy1.c
gamespy1_la_LDFLAGS = -module -avoid-version
gamespy2_la_SOURCES = gamespy2.c
gamespy2_la_LDFLAGS = -module -avoid-version
halflife_la_SOURCES = halflife.c
halflife_la_LDFLAGS = -module -avoid-version
hlswproxy_la_SOURCES = hlswproxy.c
hlswproxy_la_LDFLAGS = -module -avoid-version
q3engine_la_SOURCES = q3engine.c
@ -275,6 +282,8 @@ gamespy1.la: $(gamespy1_la_OBJECTS) $(gamespy1_la_DEPENDENCIES)
$(LINK) -rpath $(pkgdatadir) $(gamespy1_la_LDFLAGS) $(gamespy1_la_OBJECTS) $(gamespy1_la_LIBADD) $(LIBS)
gamespy2.la: $(gamespy2_la_OBJECTS) $(gamespy2_la_DEPENDENCIES)
$(LINK) -rpath $(pkgdatadir) $(gamespy2_la_LDFLAGS) $(gamespy2_la_OBJECTS) $(gamespy2_la_LIBADD) $(LIBS)
halflife.la: $(halflife_la_OBJECTS) $(halflife_la_DEPENDENCIES)
$(LINK) -rpath $(pkgdatadir) $(halflife_la_LDFLAGS) $(halflife_la_OBJECTS) $(halflife_la_LIBADD) $(LIBS)
hlswproxy.la: $(hlswproxy_la_OBJECTS) $(hlswproxy_la_DEPENDENCIES)
$(LINK) -rpath $(pkgdatadir) $(hlswproxy_la_LDFLAGS) $(hlswproxy_la_OBJECTS) $(hlswproxy_la_LIBADD) $(LIBS)
q3engine.la: $(q3engine_la_OBJECTS) $(q3engine_la_DEPENDENCIES)

View File

@ -28,22 +28,24 @@ static struct scan_ports port_arr[] = {
static char scanmsg[] = "\xff\xffgetInfo";
static char replymsg[] = "\xff\xffinfoResponse";
static int scan(void) {
static int scan(void)
{
pkt_send_portarr(NULL, port_arr, scanmsg, strlen(scanmsg));
return 1;
}
static int parse(struct net_pkt *pkt) {
static int parse(struct net_pkt *pkt)
{
int gameid;
if (!(gameid = pkt_check_portarr(pkt, port_arr)))
return 0;
return PARSE_REJECT;
if (pkt_memcmp(pkt, 0, replymsg, strlen(replymsg)))
return 0;
return PARSE_REJECT;
server_add_pkt(gameid, pkt);
return 1;
return PARSE_ACCEPT;
}
struct hlswmaster_plugin plugin = {

View File

@ -29,89 +29,227 @@ static struct scan_ports port_arr[] = {
{ 0, 0, 0 }
};
static char scanmsg[] = "\\status\\";
static char ut_reply[] = "\\gamename\\ut\\";
static char ut2k3_reply[] = "\\gamename\\ut2\\";
static char ut2k4_reply[] = "\\gamename\\ut2004\\";
static char bf1942_reply[] = "\\gamename\\bfield1942\\";
static char bfv_reply[] = "\\game_id\\bfvietnam\\";
static char avp2_reply[] = "\\gamename\\avp2\\";
static char igi2_reply[] = "\\gamename\\projectigi2r\\";
static char hostport_search[] = "\\hostport\\";
struct gs1_part {
struct list_head list;
unsigned long timeout;
unsigned int queryid;
unsigned int subid;
struct net_pkt *pkt;
};
static int scan(void) {
static LIST_HEAD(gs1_partlist);
static char scanmsg[] = "\\status\\";
static char search_queryid[] = "\\queryid\\";
static char search_final[] = "\\final\\";
static char search_hostport[] = "\\hostport\\";
static char search_gamename[] = "\\gamename\\";
static char search_gameid[] = "\\game_id\\";
static char reply_ut[] = "ut\\";
static char reply_ut2k3[] = "ut2\\";
static char reply_ut2k4[] = "ut2004\\";
static char reply_bf1942[] = "bfield1942\\";
static char reply_bfv[] = "bfvietnam\\";
static char reply_poe[] = "poe\\";
static char reply_opk[] = "opk\\";
static char reply_avp2[] = "avp2\\";
static char reply_igi2[] = "projectigi2r\\";
static int scan(void)
{
pkt_send_portarr(NULL, port_arr, scanmsg, strlen(scanmsg));
return 1;
}
static int parse(struct net_pkt *pkt) {
int gameid, port;
void *p;
static struct net_pkt * gs1_pkt_merge(struct net_pkt *pkt, unsigned int queryid, unsigned int subid)
{
struct net_pkt *retpkt = NULL;
struct gs1_part *part, *tmp;
unsigned int i = 1, found = 0, notfound = 0;
// wenn paket non-final ist, in liste speichern
// NULL zurueckgeben
if (pkt_memmem(pkt, 0, search_final, strlen(search_final)) == -1) {
part = malloc(sizeof(struct gs1_part));
part->timeout = time(NULL);
part->queryid = queryid;
part->subid = subid;
part->pkt = pkt;
if (!(gameid = pkt_check_portarr(pkt, port_arr)))
return 0;
// in liste packen
list_add_tail(&part->list, &gs1_partlist);
return NULL;
}
// wenn paket final ist, dann mit evtl. non-final paketen mergen
// komplettes Paket zurueckgeben
while (i < subid && notfound <= subid) {
found = 0;
list_for_each_entry_safe(part, tmp, &gs1_partlist, list) {
if (pkt_sameaddr(part->pkt, pkt) && (part->queryid == queryid) && part->subid == i) {
if (retpkt != NULL) {
struct net_pkt *retpkt2 = retpkt;
retpkt = pkt_merge(retpkt, part->pkt);
free(retpkt2);
free(part->pkt);
} else {
retpkt = part->pkt;
}
list_del(&part->list);
free(part);
found = 1;
i++;
}
}
if (found == 0)
notfound++;
}
/* merge error, eat last paket, cleanup */
if (i != subid || notfound > subid) {
log_print("gs1: merging error!");
free(pkt);
return NULL;
}
return (retpkt != NULL) ? pkt_merge(retpkt, pkt) : pkt;
}
static int parse_real(struct net_pkt *pkt, int gameid)
{
int port, offset, pos1, pos2;
pos1 = pkt_memmem(pkt, 0, search_gamename, strlen(search_gamename));
pos1 += strlen(search_gamename);
pos2 = pkt_memmem(pkt, 0, search_gameid, strlen(search_gameid));
pos2 += strlen(search_gameid);
switch (gameid) {
case 5:/* unreal tournament 2k3 */
if (pkt_memmem(pkt, 0, ut_reply, strlen(ut_reply)))
case 5:/* unreal tournament */
if (!pkt_memcmp(pkt, pos1, reply_ut, strlen(reply_ut)))
gameid = 5;
/* unreal tournament 2k3 */
else if (pkt_memmem(pkt, 0, ut2k3_reply, strlen(ut2k3_reply)))
else if (!pkt_memcmp(pkt, pos1, reply_ut2k3, strlen(reply_ut2k4)))
gameid = 14;
/* unreal tournament 2k4 */
else if (pkt_memmem(pkt, 0, ut2k4_reply, strlen(ut2k4_reply)))
else if (!pkt_memcmp(pkt, pos1, reply_ut2k4, strlen(reply_ut2k4)))
gameid = 33;
else
return 0;
return PARSE_REJECT;
break;
case 16:/* battlefield 1942 */
if (!pkt_memmem(pkt, 0, bf1942_reply, strlen(bf1942_reply)))
return 0;
case 35:/* battlefield vietnam */
if (!pkt_memcmp(pkt, pos1, reply_bf1942, strlen(reply_bf1942)))
gameid = 16;
else if (!pkt_memcmp(pkt, pos2, reply_bfv, strlen(reply_bfv)))
gameid = 35;
else if (!pkt_memcmp(pkt, pos2, reply_poe, strlen(reply_poe)))
gameid = 35;
else if (!pkt_memcmp(pkt, pos2, reply_opk, strlen(reply_opk)))
gameid = 35;
else
return PARSE_REJECT;
break;
case 17:/* alien vs. predator 2 */
if (!pkt_memmem(pkt, 0, avp2_reply, strlen(avp2_reply)))
return 0;
if (!pkt_memcmp(pkt, pos1, reply_avp2, strlen(reply_avp2)))
gameid = 17;
else
return PARSE_REJECT;
break;
case 19:/* project igi2 covert strike */
if (!pkt_memmem(pkt, 0, igi2_reply, strlen(igi2_reply)))
return 0;
if (!pkt_memcmp(pkt, pos1, reply_igi2, strlen(reply_igi2)))
gameid = 19;
else
return PARSE_REJECT;
break;
case 35:/* battlefield vietnam */
if (!pkt_memmem(pkt, 0, bfv_reply, strlen(bfv_reply)))
return 0;
break;
default:
return 0;
return PARSE_REJECT;
}
/* hostport angabe suchen */
p = pkt_memmem(pkt, 0, hostport_search, strlen(hostport_search));
if (p) {
port = pkt_atoi(pkt, p + strlen(hostport_search));
}
offset = pkt_memmem(pkt, 0, search_hostport, strlen(search_hostport));
if (offset != -1)
pkt_parse_int(pkt, offset + strlen(search_hostport), &port);
/* wenn ein hostport angegeben wurde, und das nicht der src port ist
** beide ports in die serverliste uebernehmen
*/
if (p && port != ntohs(pkt->addr.sin_port)) {
/*
* wenn ein hostport angegeben wurde, und das nicht der src port ist
* beide ports in die serverliste uebernehmen
*/
if ((offset != -1) && (port != ntohs(pkt->addr.sin_port))) {
server_add(gameid, pkt->addr.sin_addr.s_addr, port, ntohs(pkt->addr.sin_port));
} else {
server_add_pkt(gameid, pkt);
}
return PARSE_ACCEPT;
}
static int parse(struct net_pkt *pkt)
{
struct net_pkt *pkt2;
int gameid, pos, offset, queryid, subid, retval;
return 1;
if (!(gameid = pkt_check_portarr(pkt, port_arr)))
return PARSE_REJECT;
/* eat ut connection attemps */
if (gameid == 5 && pkt->size <= 6)
return PARSE_ACCEPT;
if ((offset = pkt_memmem(pkt, 0, search_queryid, strlen(search_queryid))) == -1)
return PARSE_REJECT;
pos = offset + strlen(search_queryid);
if ((offset = pkt_parse_int(pkt, pos, &queryid)) == 0)
return PARSE_REJECT;
pos += offset +1;
if ((offset = pkt_parse_int(pkt, pos, &subid)) == 0)
return PARSE_REJECT;
/* multipaket antworten zusammenfassen
* wenn paket non-final, dann einfach annehmen
*/
if ((pkt2 = gs1_pkt_merge(pkt, queryid, subid)) == NULL)
return PARSE_ACCEPT_FREED;
retval = parse_real(pkt2, gameid);
/* free merged packet */
if (pkt != pkt2)
free(pkt2);
return retval;
}
static int gc(int timeout) {
struct gs1_part *part, *tmp;
unsigned long now = time(NULL);
list_for_each_entry_safe(part, tmp, &gs1_partlist, list) {
if (part->timeout + timeout < now) {
log_print("gs1: removing dead fragment");
list_del(&part->list);
free(part->pkt);
free(part);
}
}
}
struct hlswmaster_plugin plugin = {
.name = "gamespy1",
.scan = &scan,
.parse = &parse,
.gc = &gc,
};

View File

@ -22,28 +22,31 @@
static struct scan_ports port_arr[] = {
{ 2302, 2302, 30 }, /* halo(30) */
{ 3455, 3455, 37 }, /* painkiller(34) */
{ 0,0,0 }
};
static char scanmsg[] = { 0xFE, 0xFD, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00, 0x00 };
static char replymsg[] = { 0x00, 0xDE, 0xAD, 0xBE, 0xEF };
static int scan(void) {
static int scan(void)
{
pkt_send_portarr(NULL, port_arr, scanmsg, sizeof(scanmsg));
return 1;
}
static int parse(struct net_pkt *pkt) {
static int parse(struct net_pkt *pkt)
{
int gameid;
if (!(gameid = pkt_check_portarr(pkt, port_arr)))
return 0;
return PARSE_REJECT;
if (pkt_memcmp(pkt, 0, replymsg, sizeof(replymsg)))
return 0;
return PARSE_REJECT;
server_add_pkt(gameid, pkt);
return 1;
return PARSE_ACCEPT;
}
struct hlswmaster_plugin plugin = {

180
plugins/halflife.c Normal file
View File

@ -0,0 +1,180 @@
/***************************************************************************
* Copyright (C) 04/2005 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <string.h>
#include "plugin_helper.h"
struct net_entry {
struct in_addr ip;
struct in_addr mask;
};
static struct net_entry *net_arr = NULL;
static int net_arr_size = 0;
static struct scan_ports port_arr[] = {
{ 27015, 27024, 1 }, /* cs/hl */
{ 0, 0, 0 }
};
static char scanmsg1[] = "\xff\xff\xff\xff" "details";
static char scanmsg2[] = "\xff\xff\xff\xff\x54";
static int scan(void)
{
pkt_send_portarr(NULL, port_arr, scanmsg1, strlen(scanmsg1));
pkt_send_portarr(NULL, port_arr, scanmsg2, strlen(scanmsg2));
return 1;
}
static int parse(struct net_pkt *pkt)
{
struct in_addr tmp;
int port, count, pos, i;
if (!pkt_check_portarr(pkt, port_arr))
return PARSE_REJECT;
// check 0xFF 0xFF 0xFF 0xFF
if (pkt_memcmp(pkt, 0, scanmsg1, 4))
return PARSE_REJECT;
/* check for short answer without ip/port */
if (pkt->size >= 5 && pkt->buf[4] == 'm' && pkt->buf[5] == 0x00) {
server_add_pkt(1, pkt);
return PARSE_ACCEPT;
}
/* second query?! */
if (pkt->size >= 5 && pkt->buf[4] == 'I' && pkt->buf[5] == 0x07) {
server_add_pkt(40, pkt);
return PARSE_ACCEPT;
}
/* parse server IP */
pos = 5;
if ((count = pkt_parse_ip(pkt, pos, &tmp)) == 0)
return PARSE_REJECT;
/* parse server port */
pos += count +1;
if ((count = pkt_parse_int(pkt, pos, &port)) == 0)
return PARSE_REJECT;
/* check server IP */
for (i = 0; i < net_arr_size; i++) {
if (((net_arr[i].ip.s_addr ^ tmp.s_addr) & net_arr[i].mask.s_addr) == 0) {
server_add(1, tmp.s_addr, port, 0);
return PARSE_ACCEPT;
}
}
server_add(1, pkt->addr.sin_addr.s_addr, port, 0);
return PARSE_ACCEPT;
}
static int parse_net(char *buf, struct net_entry *net)
{
char *p;
/* valid_net x.x.x.x */
if ((p = strchr(buf, '/')) == NULL) {
/* ip */
if (inet_pton(AF_INET, buf, &net->ip) <= 0)
return 0;
/* mask */
net->mask.s_addr = 0xFFFFFFFF;
return 1;
/* valid_net x.x.x.x/x.x.x.x oder x.x.x.x/xx */
} else {
int retval, mask;
*p = 0x00;
/* ip */
if (inet_pton(AF_INET, buf, &net->ip) <= 0) {
retval = 0;
/* x.x.x.x/x.x.x.x */
} else if (inet_pton(AF_INET, p+1, &net->mask) > 0) {
retval = 1;
/* x.x.x.x/xx */
} else {
mask = atoi(p+1);
if (mask >= 0 && mask <= 32) {
net->mask.s_addr = htonl(0xFFFFFFFF << (32 - mask));
retval = 1;
} else {
retval = 0;
}
}
*p = '/';
return retval;
}
}
static int init(struct conf_section *section)
{
struct conf_tupel *tupel;
static char buf[32];
int i = 0, j;
list_for_each_entry(tupel, &section->tupel, list)
if (!strcmp(tupel->option, "valid_net"))
i++;
if (i == 0 || !(net_arr = malloc(sizeof(struct net_entry) * i)))
return 0;
i = 0;
list_for_each_entry(tupel, &section->tupel, list) {
if (strcmp(tupel->option, "valid_net"))
continue;
if (parse_net(tupel->parameter, &net_arr[i])) {
j = sprintf(buf, " adding: %s", inet_ntoa(net_arr[i].ip));
sprintf(buf + j, "/%s", inet_ntoa(net_arr[i].mask));
log_print(buf);
i++;
} else {
log_print(" invalid net: %s", tupel->parameter);
}
}
net_arr_size = i;
return 1;
}
static int fini()
{
if (net_arr_size > 0 && net_arr)
free(net_arr);
}
struct hlswmaster_plugin plugin = {
.name = "halflife",
.scan = &scan,
.parse = &parse,
.init = &init,
.fini = &fini,
};

View File

@ -26,7 +26,7 @@
#include "plugin_helper.h"
struct _entry {
struct hlsw_entry {
u_int16_t gameid;
u_int32_t ip;
u_int16_t port1;
@ -38,17 +38,19 @@ static int ip_arr_size = 0;
static char scanmsg[] = "\xff\xff\xff\xffHLSWLANSEARCH";
static int scan(void) {
static int scan(void)
{
int i;
for (i = 0; i < ip_arr_size; i++)
pkt_send(&ip_arr[i], 7140, scanmsg, sizeof(scanmsg));
return 1;
}
static int parse(struct net_pkt *pkt) {
struct _entry *server;
static int parse(struct net_pkt *pkt)
{
struct hlsw_entry *server;
if (pkt_getport(pkt) != 7140)
return 0;
return PARSE_REJECT;
server = (void *)pkt->buf + sizeof(scanmsg);
@ -56,10 +58,12 @@ static int parse(struct net_pkt *pkt) {
server_add(server->gameid, server->ip, server->port1, server->port2);
server++;
}
return 1;
return PARSE_ACCEPT;
}
static int init(struct conf_section *section) {
static int init(struct conf_section *section)
{
struct conf_tupel *tupel;
int i = 0;
list_for_each_entry(tupel, &section->tupel, list)
@ -81,11 +85,11 @@ static int init(struct conf_section *section) {
}
}
ip_arr_size = i;
log_print(" added %d master server(s)", i);
return 1;
}
static int fini() {
static int fini()
{
if (ip_arr_size > 0 && ip_arr)
free(ip_arr);
}

View File

@ -22,82 +22,79 @@
static struct scan_ports port_arr[] = {
{ 27960, 27969, 6 }, /* q3(6), ef(7), et25), rtcw(8) */
{ 28070, 28070, 12 }, /* jk2(12) TODO: UNTESTED */
{ 28070, 28070, 12 }, /* jk2(12) */
{ 28960, 28963, 31 }, /* cod(31), cod:uo(42) */
{ 29070, 29070, 27 }, /* jk3(27) TODO: UNTESTED */
{ 29070, 29070, 27 }, /* jk3(27) */
{ 0,0,0 }
};
static char scanmsg[] = "\xff\xff\xff\xffgetStatus";
static char replymsg[] = "\xff\xff\xff\xffstatusResponse";
static char search_version[] = "\\version\\";
static char search_gamename[] = "\\gamename\\";
static char reply_q3[] = "Q3 ";
static char reply_ef[] = "ST:V HM ";
static char reply_rtcw[] = "Wolf ";
static char reply_et[] = "ET";
static char reply_jk2[] = "JK2MP";
static char reply_jk3[] = "JAmp";
static char reply_cod[] = "Call of Duty\\";
static char reply_coduo[] = "CoD:United Offensive\\";
static char q3_reply[] = "\\version\\Q3 ";
static char ef_reply[] = "\\version\\ST:V HM ";
static char rtcw_reply[] = "\\version\\Wolf ";
static char et_reply[] = "\\version\\ET ";
static char jk2_reply[] = "\\version\\JK2MP ";
static char jk3_reply[] = "\\version\\JAmp ";
static char cod_reply[] = "\\gamename\\Call of Duty\\";
static char coduo_reply[] = "\\gamename\\CoD:United Offensive\\";
static int scan(void) {
static int scan(void)
{
pkt_send_portarr(NULL, port_arr, scanmsg, strlen(scanmsg));
return 1;
}
static int parse(struct net_pkt *pkt) {
int gameid;
if (!(gameid = pkt_check_portarr(pkt, port_arr)))
return 0;
static int parse(struct net_pkt *pkt)
{
int gameid = 0, pos1, pos2;
if (!pkt_check_portarr(pkt, port_arr))
return PARSE_REJECT;
if (pkt_memcmp(pkt, 0, replymsg, strlen(replymsg)))
return 0;
return PARSE_REJECT;
switch (gameid) {
case 6: /* q3, ef, et, rtcw */
if (pkt_memmem(pkt, 0, q3_reply, strlen(q3_reply))) {
pos1 = pkt_memmem(pkt, 0, search_version, strlen(search_version));
pos2 = pkt_memmem(pkt, 0, search_gamename, strlen(search_gamename));
if (pos1 != -1) {
pos1 += strlen(search_version);
if (!pkt_memcmp(pkt, pos1, reply_q3, strlen(reply_q3)))
gameid = 6;
} else if (pkt_memmem(pkt, 0, ef_reply, strlen(ef_reply))) {
else if (!pkt_memcmp(pkt, pos1, reply_ef, strlen(reply_ef)))
gameid = 7;
} else if (pkt_memmem(pkt, 0, rtcw_reply, strlen(rtcw_reply))) {
else if (!pkt_memcmp(pkt, pos1, reply_rtcw, strlen(reply_rtcw)))
gameid = 8;
} else if (pkt_memmem(pkt, 0, et_reply, strlen(et_reply))) {
else if (!pkt_memcmp(pkt, pos1, reply_et, strlen(reply_et)))
gameid = 25;
} else {
return 0;
}
break;
case 12: /* jedi knight 2 */
if (!pkt_memmem(pkt, 0, jk2_reply, strlen(jk2_reply)))
return 0;
break;
case 27: /* jedi knight 3 */
if (!pkt_memmem(pkt, 0, jk3_reply, strlen(jk3_reply)))
return 0;
break;
case 31: /* cod, cod:uo */
if (pkt_memmem(pkt, 0, cod_reply, strlen(cod_reply))) {
gameid = 31;
else if (!pkt_memcmp(pkt, pos1, reply_jk2, strlen(reply_jk2)))
gameid = 12;
} else if (pkt_memmem(pkt, 0, coduo_reply, strlen(coduo_reply))) {
gameid = 42;
} else {
return 0;
}
break;
else if (!pkt_memcmp(pkt, pos1, reply_jk3, strlen(reply_jk3)))
gameid = 27;
}
if (gameid == 0 && pos2 != -1) {
pos2 += strlen(search_gamename);
if (!pkt_memcmp(pkt, pos2, reply_cod, strlen(reply_cod)))
gameid = 31;
else if (!pkt_memcmp(pkt, pos2, reply_coduo, strlen(reply_coduo)))
gameid = 42;
}
if (gameid == 0)
return PARSE_REJECT;
server_add_pkt(gameid, pkt);
return 1;
return PARSE_ACCEPT;
}
struct hlswmaster_plugin plugin = {

View File

@ -20,22 +20,24 @@
#include <string.h>
#include "plugin_helper.h"
static char scanmsg[] = "\xff\xff\xff\xffinfo 34";
static char scanmsg[] = "\xff\xff\xff\xffinfo 34"; /* q2(3) */
static int scan(void) {
static int scan(void)
{
pkt_send(NULL, 27910, scanmsg, strlen(scanmsg));
return 1;
}
static int parse(struct net_pkt *pkt) {
static int parse(struct net_pkt *pkt)
{
if (pkt_getport(pkt) != 27910)
return 0;
return PARSE_REJECT;
if (pkt_memcmp(pkt, 0, scanmsg, strlen(scanmsg)))
return 0;
return PARSE_REJECT;
server_add_pkt(3, pkt);
return 1;
return PARSE_ACCEPT;
}
struct hlswmaster_plugin plugin = {

View File

@ -38,7 +38,7 @@ static int scan(void) {
struct in_addr tmp;
inet_aton("192.168.1.100", &tmp)
pkt_send(&tmp, 8888, myscan, strlen(myscan));
/* an portrange(s) senden */
struct scan_ports port_arr[] = {
{ 27960, 27963, 0 }, /* von 27960-27963 scannen */
@ -62,44 +62,48 @@ static int scan(void) {
static int parse(struct net_pkt *pkt) {
/* checken ob das paket vom richtigen port kommt: */
if (pkt_getport(pkt) != 27910)
return 0;
return PARSE_REJECT;
/* bei einem port_arr checken ob es von einem der angefragten ports kommt */
int gameid;
if (!(gameid = pkt_check_portarr(pkt, port_arr)))
return 0;
return PARSE_REJECT;
/* gameid enthaelt nun den dritten wert einer passenden port_arr zeile */
/* paketinhalt checken (packet = "good morning dave\x00") */
char mycmp1[] = "good";
if (pkt_memcmp(pkt, 0, mycmp1, strlen(mycmp1)))
return 0;
return PARSE_REJECT;
/* paketinhalt mit offset */
char mycmp2[] = "morning";
if (pkt_memcmp(pkt, 5, mycmp2, strlen(mycmp2)))
return 0;
return PARSE_REJECT;
/* suchen ob paketinhalt vorhanden ist (packet = "blablablablabla\hostport\7777\blablabla") */
char mymem[] = "\\hostport\\";
void *p
p = pkt_memmem(pkt, 0, mymem, strlen(mymem));
if (!p)
return 0;
if (p == -1)
return PARSE_REJECT;
/* ints aus paket parsen: */
p += strlen(mymem);
port2 = pkt_atoi(pkt, p);
int port2;
if (pkt_parse_int(pkt, offset, &port2) == 0)
return PARSE_REJECT;
/* src ip des pakets */
printf("server found: %s\n", pkt_ntoa(pkt));
/* server zu interner liste hinzufuegen: (port1 = port, port2 = 0)*/
server_add_pkt(gameid, pkt);
/* server mit zwei ports zur liste hinzufuegen: */
server_add(gameid, pkt->addr.sin_addr.s_addr, port1, port2);
return PARSE_ACCEPT;
}
/**

View File

@ -59,8 +59,9 @@ static pthread_mutex_t client_pkt_list_lock = PTHREAD_MUTEX_INITIALIZER;
* @param *unused
* @return true wenn das paket noch nicht voll ist
*/
static inline int client_pkt_not_full(const struct client_pkt *cpkt, void *unused) {
return (cpkt->size > (MAX_PKT_LEN - HLSW_ENTRY_LEN));
static inline int client_pkt_not_full(const struct client_pkt *cpkt, void *unused)
{
return (cpkt->size <= (MAX_PKT_LEN - HLSW_ENTRY_LEN));
}
/**
@ -70,7 +71,8 @@ static inline int client_pkt_not_full(const struct client_pkt *cpkt, void *unuse
* @param *list liste die das neue paket aufnimmt
* @return pointer auf ein neues paket oder NULL bei fehler
*/
static struct client_pkt * client_pkt_add_real(struct list_head *list) {
static struct client_pkt * client_pkt_add_real(struct list_head *list)
{
struct client_pkt *cpkt;
cpkt = malloc(sizeof(struct client_pkt) + MAX_PKT_LEN);
@ -81,7 +83,7 @@ static struct client_pkt * client_pkt_add_real(struct list_head *list) {
memcpy(cpkt->buf, HLSW_HEADER, HLSW_HEADER_LEN);
cpkt->size = HLSW_HEADER_LEN;
/* am anfang eingliedern! */
/* am anfang eingliedern! (suche nach freien paket schneller) */
list_add(&cpkt->list, list);
}
return cpkt;
@ -95,7 +97,8 @@ static struct client_pkt * client_pkt_add_real(struct list_head *list) {
* @param *server pointer den server
* @return false bei fehler
*/
int client_pkt_add(struct game_server *server) {
int client_pkt_add(struct game_server *server)
{
struct client_pkt *cpkt;
/* sucht ein freies paket, oder erzeugt eins */
@ -117,7 +120,8 @@ int client_pkt_add(struct game_server *server) {
*
* @return true
*/
int client_pkt_commit() {
int client_pkt_commit()
{
struct list_head old_list, *cpkt, *tmp;
/* wenn die liste leer ist, nur HLSW-header verschicken */
@ -148,7 +152,8 @@ int client_pkt_commit() {
* client_handler()
* empfaengt und beantwortet die HLSW anfragen der clients
*/
void client_handler(void) {
void client_handler(void)
{
struct client_pkt *cpkt;
struct sockaddr_in dst;
int sock, i;

View File

@ -40,7 +40,8 @@ static LIST_HEAD(config_list);
*
* @todo sectionname ist nicht eindeutig
*/
static struct conf_section * config_add_section(char *name) {
static struct conf_section * config_add_section(char *name)
{
struct conf_section *section;
if (!name)
@ -66,7 +67,8 @@ static struct conf_section * config_add_section(char *name) {
* @param *parameter wert der option
* @return false bei fehler
*/
static int config_add_tupel(struct conf_section *section, char *option, char *parameter) {
static int config_add_tupel(struct conf_section *section, char *option, char *parameter)
{
struct conf_tupel *tupel;
if (!section || !option || !parameter)
@ -88,7 +90,8 @@ static int config_add_tupel(struct conf_section *section, char *option, char *pa
* config_free()
* entfernt die config_liste aus dem Speicher
*/
static void config_free() {
static void config_free()
{
struct conf_section *section, *section_tmp;
struct conf_tupel *tupel, *tupel_tmp;
@ -111,7 +114,8 @@ static void config_free() {
* @param *config filename des configfiles
* @return false bei fehler
*/
int config_parse(char *config) {
int config_parse(char *config)
{
struct conf_section *section = NULL;
FILE *fz;
int i = 0, ret = 1;
@ -189,7 +193,8 @@ int config_parse(char *config) {
* @param *name name der section
* @return pointer auf die section, oder NULL bei fehler
*/
struct conf_section * config_get_section(char *name) {
struct conf_section * config_get_section(char *name)
{
struct conf_section *section;
list_for_each_entry(section, &config_list, list) {
@ -208,7 +213,8 @@ struct conf_section * config_get_section(char *name) {
* @param *option option name
* @return pointer auf den parameter string oder NULL bei fehler
*/
char * config_get_parameter(struct conf_section *section, char *option) {
char * config_get_parameter(struct conf_section *section, char *option)
{
struct conf_tupel *tupel;
list_for_each_entry(tupel, &section->tupel, list) {
@ -227,7 +233,8 @@ char * config_get_parameter(struct conf_section *section, char *option) {
* @param *def default string
* @return parameter string oder default string bei fehler
*/
char * config_get_string(char *section, char *option, char *def) {
char * config_get_string(char *section, char *option, char *def)
{
struct conf_section *tmp;
char *ret;
@ -247,7 +254,8 @@ char * config_get_string(char *section, char *option, char *def) {
* @param *def default wert
* @return parameter wert oder default wert bei fehler
*/
int config_get_int(char *section, char *option, int def) {
int config_get_int(char *section, char *option, int def)
{
char *ret;
ret = config_get_string(section, option, NULL);

View File

@ -37,9 +37,10 @@ static FILE *log_fd = NULL;
*
* @todo code vereinfachen?
*/
void log_print(const char *fmt, ...) {
void log_print(const char *fmt, ...)
{
va_list az;
char buffer[256];
char *buffer = malloc(8192);
va_start(az, fmt);
vsprintf(buffer, fmt, az);
@ -69,13 +70,15 @@ void log_print(const char *fmt, ...) {
}
}
errno = 0;
free(buffer);
}
/**
* log_close()
* schliesst das logfile
*/
static void log_close() {
static void log_close()
{
fclose(log_fd);
}
@ -86,7 +89,8 @@ static void log_close() {
* @param logfile filename des logfiles
* @return false bei fehler
*/
int log_init(char *logfile) {
int log_init(char *logfile)
{
if ((log_fd = fopen(logfile, "a" )) == NULL) {
log_print("log_open('%s'): %s", logfile);
return 0;

View File

@ -37,11 +37,12 @@ static struct option opts[] = {
{0, 0, 0, 0}
};
int main(int argc, char *argv[]) {
int main(int argc, char *argv[])
{
pthread_t thread1, thread2, thread3;
int arg = 0, code = 0, debug = 0;
char *config = NULL, *user = NULL, *logfile;
while (code != -1) {
code = getopt_long(argc, argv, "c:u:dh", opts, &arg);
@ -85,7 +86,7 @@ int main(int argc, char *argv[]) {
log_print("unknown user: %s", user);
exit(-1);
}
if (setgid(pwl->pw_gid) || setuid(pwl->pw_uid)) {
log_print("setgid/setuid");
exit(-1);
@ -102,13 +103,13 @@ int main(int argc, char *argv[]) {
/* start logging */
if (!log_init(logfile))
exit(-1);
/* zum daemon mutieren */
daemon(-1, 0);
}
log_print("hlswmaster started (user: %s, pid: %d)", getpwuid(getuid())->pw_name, getpid());
/* init scan engine */
if (!scan_init())
exit(-1);

View File

@ -40,7 +40,8 @@ static pthread_mutex_t plugin_lock = PTHREAD_MUTEX_INITIALIZER;
* @param *name filename des plugins
* @return false on error
*/
int plugin_load(char *name) {
int plugin_load(char *name)
{
struct hlswmaster_plugin *plugin;
void *tmp;
struct conf_section *section;
@ -82,7 +83,8 @@ int plugin_load(char *name) {
*
* @return false on error
*/
int plugin_load_all() {
int plugin_load_all()
{
struct conf_section *section;
struct conf_tupel *tupel;
@ -102,7 +104,8 @@ int plugin_load_all() {
*
* @return false on error
*/
int plugin_unload_all() {
int plugin_unload_all()
{
struct hlswmaster_plugin *plugin, *tmp;
pthread_mutex_lock(&plugin_lock);
@ -125,7 +128,8 @@ int plugin_unload_all() {
*
* @return true
*/
int plugins_scan(void) {
int plugins_scan(void)
{
struct hlswmaster_plugin *plugin;
pthread_mutex_lock(&plugin_lock);
@ -144,22 +148,25 @@ int plugins_scan(void) {
* bis ein Plugin das Paket annimmt
*
* @param *pkt das zu parsene paket
* @return false wenn kein Plugin das Paket angenommen hat
* @return false wenn kein Plugin das Paket angenommen,
* sonst rueckgabewert des Plugins
*/
int plugins_parse(struct net_pkt *pkt) {
int plugins_parse(struct net_pkt *pkt)
{
struct hlswmaster_plugin *plugin;
int retval;
pthread_mutex_lock(&plugin_lock);
list_for_each_entry(plugin, &plugin_list, list) {
/* wenn vorhanden die parse funktion aufrufen */
if (plugin->parse && plugin->parse(pkt)) {
if (plugin->parse && (retval = plugin->parse(pkt))) {
pthread_mutex_unlock(&plugin_lock);
return 1;
return retval;
}
}
pthread_mutex_unlock(&plugin_lock);
return 0;
return PARSE_REJECT;
}
/**
@ -169,7 +176,8 @@ int plugins_parse(struct net_pkt *pkt) {
* @param timeout timeout interval in sekunden
* @return true
*/
int plugins_gc(unsigned long timeout) {
int plugins_gc(unsigned long timeout)
{
struct hlswmaster_plugin *plugin;
pthread_mutex_lock(&plugin_lock);

View File

@ -46,10 +46,11 @@
* @param size groesse der daten
* @return false bei fehler
*/
int pkt_send_portarr(struct in_addr *dstip, struct scan_ports *portarr, char *buf, unsigned int size) {
int pkt_send_portarr(struct in_addr *dstip, struct scan_ports *portarr, char *buf, unsigned int size)
{
unsigned short port;
int ret = 1;
while (portarr && portarr->portlo) {
for (port = portarr->portlo; port <= portarr->porthi; port++)
if (!pkt_send(dstip, port, buf, size))
@ -68,7 +69,8 @@ int pkt_send_portarr(struct in_addr *dstip, struct scan_ports *portarr, char *bu
* @param *portarr ports die angenommen werden
* @return die gameid der portrange oder 0 wenn nicht vorhanden
*/
int pkt_check_portarr(struct net_pkt *pkt, struct scan_ports *portarr) {
int pkt_check_portarr(struct net_pkt *pkt, struct scan_ports *portarr)
{
unsigned short port;
while (portarr && portarr->portlo) {
for (port = portarr->portlo; port <= portarr->porthi; port++)
@ -88,12 +90,13 @@ int pkt_check_portarr(struct net_pkt *pkt, struct scan_ports *portarr) {
* @param offset offset ab dem verglichen wird
* @param *search daten nach denen gesucht wird
* @param size laenge der daten
* @return true wenn gleich
* @return false wenn gleich
*
* @todo return false wenn offset + size >= pkt->size ?
*/
int pkt_memcmp(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size) {
int pkt_memcmp(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size)
{
if (offset >= pkt->size)
return 1;
@ -112,13 +115,42 @@ int pkt_memcmp(struct net_pkt *pkt, unsigned int offset, char *search, unsigned
* @param offset offset ab dem gesucht wird
* @param *search daten nach denen gesucht wird
* @param size laenge der daten
* @return pointer auf den string im Paket, oder NULL wenn nicht gefunden
* @return offset auf den string im Paket, oder -1 wenn nicht gefunden
*/
void * pkt_memmem(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size) {
if (offset >= pkt->size)
return NULL;
int pkt_memmem(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size)
{
void *found;
return memmem(pkt->buf + offset, pkt->size, search, size);
if (offset >= pkt->size)
return -1;
found = memmem(pkt->buf + offset, pkt->size, search, size);
return (found == NULL) ? -1 : (found - (void *)pkt->buf);
}
/**
* pkt_merge()
* fuegt zwei pakete zu einem zusammen
* die header werden vom ersten Paket uebernommen
* die pakete werden nicht gefreed(!)
*
* @param *pkt1 erstes Paket
* @param *pkt2 zweites Paket
* @return zusammengefasstes Paket
*/
struct net_pkt * pkt_merge(struct net_pkt *pkt1, struct net_pkt *pkt2)
{
struct net_pkt *ret;
ret = malloc(sizeof(struct net_pkt) + pkt1->size + pkt2->size);
memcpy(&ret->addr, &pkt1->addr, sizeof(ret->addr));
ret->size = pkt1->size + pkt2->size;
memcpy(ret->buf, pkt1->buf, pkt1->size);
memcpy(ret->buf + pkt1->size, pkt2->buf, pkt2->size);
return ret;
}
/**
@ -129,7 +161,8 @@ void * pkt_memmem(struct net_pkt *pkt, unsigned int offset, char *search, unsign
* @param *pkt daten vom gameserver (fuer ip/port)
* @return false bei fehler
*/
int server_add_pkt(unsigned int gameid, struct net_pkt *pkt) {
int server_add_pkt(unsigned int gameid, struct net_pkt *pkt)
{
return server_add(gameid, pkt->addr.sin_addr.s_addr, ntohs(pkt->addr.sin_port), 0);
}
@ -140,7 +173,8 @@ int server_add_pkt(unsigned int gameid, struct net_pkt *pkt) {
* @param *pkt daten vom gameserver
* @return pointer auf String
*/
char * pkt_ntoa(struct net_pkt *pkt) {
char * pkt_ntoa(struct net_pkt *pkt)
{
return inet_ntoa(pkt->addr.sin_addr);
}
@ -151,31 +185,121 @@ char * pkt_ntoa(struct net_pkt *pkt) {
* @param *pkt daten vom gameserver
* @return portnummer
*/
unsigned short pkt_getport(struct net_pkt *pkt) {
unsigned short pkt_getport(struct net_pkt *pkt)
{
return ntohs(pkt->addr.sin_port);
}
/**
* pkt_atoi()
* pkt_sameaddr()
* vergleicht die Adressen zweier Pakete
*
* @param *pkt1 Paket 1
* @param *pkt2 Paket 2
* @return true wenn Adressen gleich
*/
int pkt_sameaddr(struct net_pkt *pkt1, struct net_pkt *pkt2)
{
return (pkt1->addr.sin_addr.s_addr == pkt2->addr.sin_addr.s_addr) &&
(pkt1->addr.sin_port == pkt2->addr.sin_port);
}
/**
* pkt_parse_int()
* gibt die dezimalzahl in dem paket ab einer position zurueck
*
* @param *pkt daten vom gameserver
* @param *p pointer auf den begin des integers
* @return wert des integers oder 0 bei fehler
* @param offset offset auf den begin des integers
* @param *val pointer auf das ergebnis
* @return Anzahl der gelesenen Zeichen oder 0 bei fehler
*/
int pkt_atoi(struct net_pkt *pkt, void *p) {
int val = 0;
void *max = ((void *)pkt->buf + pkt->size);
char *c = p;
int pkt_parse_int(struct net_pkt *pkt, unsigned int offset, int *val)
{
unsigned char *max = pkt->buf + pkt->size;
unsigned char *c = pkt->buf + offset;
/* untere grenze abtesten */
if ((void *)pkt->buf > p || p > max)
return 0;
if (pkt->buf > c || c > max)
return -1;
*val = 0;
/* ziffern einlesen */
while (isdigit(*c) && (void *)c < max)
val = (val * 10) + (*c++ - 0x30);
while (isdigit(*c) && c < max)
*val = (*val * 10) + (*c++ - 0x30);
return val;
return (c - (pkt->buf + offset));
}
/**
* pkt_parse_ip()
* gibt die IP in *.*.*.* ab p als integer zurueck
*
* @param *pkt daten vom gameserver
* @param offset offset auf den begin der IP
* @param *ip pointer auf eine in_addr struct
* @return Anzahl der gelesenen Zeichen oder 0 bei Fehler
*/
int pkt_parse_ip(struct net_pkt *pkt, int offset, struct in_addr *ip)
{
int i, tmp, count, pos = offset;
ip->s_addr = 0;
for (i = 0; i < 4; i++) {
count = pkt_parse_int(pkt, pos, &tmp);
pos += count;
if (count == 0 || tmp < 0 || tmp > 255)
return 0;
ip->s_addr = ip->s_addr>>8 | tmp<<24;
if (i != 3 && pkt->buf[pos++] != '.')
return 0;
}
return pos - offset;
}
/**
* pkt_print()
* gibt ein paket als hex-dump aus
*
* @param *pkt daten vom gameserver
* @return char pointer auf hex-dump
*/
char * pkt_print(struct net_pkt *pkt)
{
int pos = 0, i = 0, j;
char *buf = malloc(pkt->size * 4 + 64);
while (pos < pkt->size) {
i += sprintf(buf + i, "%04X: ", pos);
for (j = 0; j < 16; j++) {
if (pos + j < pkt->size)
i += sprintf(buf + i, "%02X", pkt->buf[pos + j]);
else
i += sprintf(buf + i, " ");
if (j % 2)
buf[i++] = ' ';
}
for (j = 0; j < 16; j++) {
if (pos + j < pkt->size) {
unsigned char val = pkt->buf[pos + j];
if (val >= 0x20 && val < 0x80)
buf[i++] = val;
else
buf[i++] = '.';
} else {
buf[i++] = ' ';
}
}
pos += 16;
buf[i++] = '\r';
buf[i++] = '\n';
}
buf[i] = 0;
return buf;
}

View File

@ -27,22 +27,39 @@
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>
#include "list.h"
#include "netpkt.h"
#include "configfile.h"
#include "hlswmaster.h"
#include "plugin.h"
#include "plugin_helper.h"
#define DEBUG 1
struct rx_entry {
struct list_head list;
struct net_pkt *pkt;
};
/** rx packet liste */
static LIST_HEAD(rxlist);
/** sichert die rx liste */
static pthread_mutex_t rxlist_lock = PTHREAD_MUTEX_INITIALIZER;
/** anzahl der pakete in der rxlist */
static sem_t rxlist_sem;
/** interne serverliste */
static LIST_HEAD(serverlist);
/** sichert die interne serverliste */
static pthread_mutex_t serverlist_lock = PTHREAD_MUTEX_INITIALIZER;
/* scan socket */
/** scan socket */
static int scan_sock;
/**
@ -53,7 +70,8 @@ static int scan_sock;
* @param *b gameserver 2
* @return true wenn es sich um den selben server handelt
*/
static inline int server_cmp(const struct game_server *a, struct game_server *b) {
static inline int server_cmp(const struct game_server *a, struct game_server *b)
{
return (a->gameid == b->gameid && a->ip == b->ip &&
a->port1 == b->port1 && a->port2 == b->port2);
}
@ -66,10 +84,11 @@ static inline int server_cmp(const struct game_server *a, struct game_server *b)
* @param gameid gameid des servers
* @param ip ip des servers
* @param port1 erster port
* @param port2 zweiter port
* @param port2 zweiter port
* @return false bei fehler
*/
int server_add(u_int16_t gameid, u_int32_t ip, u_int16_t port1, u_int16_t port2) {
int server_add(u_int16_t gameid, u_int32_t ip, u_int16_t port1, u_int16_t port2)
{
struct game_server server, *nserver;
server.gameid = gameid;
@ -99,7 +118,7 @@ int server_add(u_int16_t gameid, u_int32_t ip, u_int16_t port1, u_int16_t port2)
memcpy(nserver, &server, sizeof(struct game_server));
list_add_tail(&nserver->list, &serverlist);
}
/* modtime anpassen */
nserver->modtime = time(NULL);
@ -114,7 +133,8 @@ int server_add(u_int16_t gameid, u_int32_t ip, u_int16_t port1, u_int16_t port2)
*
* @param timeout timeout in sekunden
*/
static void serverlist_refresh(long timeout) {
static void serverlist_refresh(long timeout)
{
struct game_server *server, *tmp;
long now = time(NULL);
@ -151,35 +171,87 @@ static void serverlist_refresh(long timeout) {
* @param size groesse der daten
* @return false bei fehler
*/
int pkt_send(struct in_addr *dstip, unsigned int dstport, char *buf, unsigned int size) {
int pkt_send(struct in_addr *dstip, unsigned int dstport, char *buf, unsigned int size)
{
struct sockaddr_in addr;
int ret = 1;
addr.sin_family = AF_INET;
addr.sin_port = htons(dstport);
addr.sin_addr.s_addr = (dstip ? dstip->s_addr : 0xFFFFFFFF);
if (sendto(scan_sock, buf, size, 0, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
log_print("scan_send(): sendto()");
ret = 0;
}
usleep(10000);
return ret;
}
/**
* scan_control()
* triggert den scan der plugins
* arbeitet dann die sender queue ab
* triggert den gc der plugins
* scan_receive_real()
* arbeitet die receive queue ab
*/
void scan_control(void) {
struct net_pkt *pkt, *tmp;
long now;
void scan_receive_real(void)
{
struct rx_entry *rx;
struct net_pkt *pkt;
int cnt, retval;
do {
sem_wait(&rxlist_sem);
pthread_mutex_lock(&rxlist_lock);
rx = list_entry(rxlist.next, struct rx_entry, list);
list_del(&rx->list);
pthread_mutex_unlock(&rxlist_lock);
pkt = rx->pkt;
free(rx);
retval = plugins_parse(pkt);
switch (retval) {
case PARSE_REJECT:
log_print("scan_receive(): unknown packet: %s:%d size:%d",
inet_ntoa(pkt->addr.sin_addr),
ntohs(pkt->addr.sin_port),
pkt->size);
#if 0
{
char *p = pkt_print(pkt);
log_print("%s", p);
free(p);
}
#endif
case PARSE_ACCEPT:
free(pkt);
case PARSE_ACCEPT_FREED:
break;
}
sem_getvalue(&rxlist_sem, &cnt);
} while (cnt > 0);
}
/**
* scan_control()
* triggert den gc der plugins
* triggert den serverlist_refresh
* triggert den scan der plugins
* arbeitet die rx queue ab
*/
void scan_control(void)
{
long last_plugin_gc = 0, last_list_refresh = 0, last_scan = 0;
int plugin_timeout, list_timeout, list_refresh, scan_interval;
int cnt;
long now;
plugin_timeout = config_get_int("global", "plugin_timeout", 30);
list_timeout = config_get_int("global", "serverlist_timeout", 30);
list_refresh = config_get_int("global", "serverlist_refresh", 5);
@ -190,10 +262,10 @@ void scan_control(void) {
log_print(" serverlist_refresh: %ds", list_refresh);
log_print(" serverlist_timeout: %ds", list_timeout);
log_print(" plugin_timeout: %d", plugin_timeout);
while (1) {
now = time(NULL);
/* interne plugin daten aufraeumen */
if (last_plugin_gc + plugin_timeout < now) {
last_plugin_gc = now;
@ -205,29 +277,36 @@ void scan_control(void) {
last_list_refresh = now;
serverlist_refresh(list_timeout);
}
/* neuen scan ausloesen */
if (last_scan + scan_interval < now) {
last_scan = now;
plugins_scan();
}
sleep(1);
/* empfangene daten parsen */
sem_getvalue(&rxlist_sem, &cnt);
if (cnt > 0)
scan_receive_real();
usleep(500000);
}
}
/**
* scan_receive()
* wartet auf serverantworten und uebergibt die pakete den
* plugins zur auswertung
* wartet auf serverantworten und uebergibt die pakete der
* receive queue
*/
void scan_receive(void) {
void scan_receive(void)
{
struct net_pkt *pkt;
struct rx_entry *rx;
fd_set fdsel, fdcpy;
int recvsize, i;
log_print("thread_start: scan_receiver");
FD_ZERO(&fdsel);
FD_SET(scan_sock, &fdsel);
@ -235,13 +314,11 @@ void scan_receive(void) {
memcpy(&fdcpy, &fdsel, sizeof(fdsel));
select(FD_SETSIZE, &fdcpy, NULL, NULL, NULL);
ioctl(scan_sock, FIONREAD, &recvsize);
if (recvsize <= 0) {
log_print("scan_receive(): drop short packet");
if (ioctl(scan_sock, FIONREAD, &recvsize) == -1) {
log_print("scan_receive(): ioctl()");
continue;
}
if (!(pkt = malloc(sizeof(struct net_pkt) + recvsize))) {
log_print("scan_receive(): malloc()");
continue;
@ -250,29 +327,40 @@ void scan_receive(void) {
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("scan_receive(): unknown packet: %s:%d size:%d",
inet_ntoa(pkt->addr.sin_addr), ntohs(pkt->addr.sin_port), pkt->size);
if (pkt->size == 0) {
free(pkt);
continue;
}
rx = malloc(sizeof(struct rx_entry));
rx->pkt = pkt;
free(pkt);
pthread_mutex_lock(&rxlist_lock);
list_add_tail(&rx->list, &rxlist);
pthread_mutex_unlock(&rxlist_lock);
sem_post(&rxlist_sem);
}
}
/**
* schliesst den server scan socket
*/
static void scan_close() {
static void scan_close()
{
close(scan_sock);
sem_destroy(&rxlist_sem);
}
/**
* scan_init()
* initialisiert den socket fuer den server scan
* initialisiert die rxlist semaphore
*
* @return false on error
*/
int scan_init() {
int scan_init()
{
struct sockaddr_in dst;
int i = 1, port;
char *ip;
@ -298,12 +386,15 @@ int scan_init() {
log_print("scan_init(): setsockopt()");
return 0;
}
if (atexit(scan_close) != 0) {
log_print("scan_init(): atexit()");
return 0;
}
log_print("scan socket initialized (%s:%d)", ip, port);
sem_init(&rxlist_sem, 0, 0);
return 1;
}

View File

@ -68,7 +68,8 @@ static char *id2name[] = {
static int sock, verbose = 0;
static void parse_pkt(struct sockaddr_in *src, void *pkt, unsigned int size) {
static void parse_pkt(struct sockaddr_in *src, void *pkt, unsigned int size)
{
struct _entry *server;
struct in_addr tmp;
@ -77,7 +78,7 @@ static void parse_pkt(struct sockaddr_in *src, void *pkt, unsigned int size) {
inet_ntoa(src->sin_addr), ntohs(src->sin_port), size);
} else {
printf("received hlsw packet from: %15s:%-5d size=%d\n count=%d",
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));
@ -94,7 +95,8 @@ static void parse_pkt(struct sockaddr_in *src, void *pkt, unsigned int size) {
}
}
static int scan_init() {
static int scan_init()
{
int i = 1;
if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
@ -110,7 +112,8 @@ static int scan_init() {
return 0;
}
static int scan_transmit(struct sockaddr_in *dst) {
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;
@ -119,7 +122,8 @@ static int scan_transmit(struct sockaddr_in *dst) {
return 0;
}
static int scan_receive() {
static int scan_receive()
{
struct sockaddr_in src;
struct timeval tv;
fd_set fdsel;
@ -171,7 +175,8 @@ static struct option opts[] = {
{0, 0, 0, 0}
};
int main(int argc, char *argv[]) {
int main(int argc, char *argv[])
{
struct sockaddr_in dst;
int arg = 0, code = 0;
int freq = -1;