2006-02-02 16:29:30 +01:00
|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 03/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. *
|
|
|
|
***************************************************************************/
|
2006-11-24 21:53:25 +01:00
|
|
|
#include <stdlib.h>
|
2006-02-02 16:29:30 +01:00
|
|
|
#include <string.h>
|
2006-11-24 21:53:25 +01:00
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
#include "logging.h"
|
|
|
|
#include "event.h"
|
|
|
|
#include "netpkt.h"
|
|
|
|
#include "plugin.h"
|
2006-02-02 16:43:41 +01:00
|
|
|
#include "plugin_helper.h"
|
2006-02-02 16:29:30 +01:00
|
|
|
|
2006-02-02 16:41:56 +01:00
|
|
|
static struct scan_ports port_arr[] = {
|
2006-02-02 16:52:26 +01:00
|
|
|
{ 7777, 7788, 5 }, /* ut(5), ut2k3(14), rune(18), ut2k4(33), aao(15) */
|
2006-02-02 16:43:41 +01:00
|
|
|
{ 22000, 22010, 16 }, /* bf1942(16) */
|
|
|
|
{ 23000, 23010, 35 }, /* bfv(35) */
|
|
|
|
{ 26001, 26011, 19 }, /* igi2(19) */
|
|
|
|
{ 27888, 27888, 17 }, /* avp2(17) (nur der standart-port..) */
|
2006-02-02 16:49:14 +01:00
|
|
|
{ 0, 0, 0 }
|
2006-02-02 16:29:30 +01:00
|
|
|
};
|
|
|
|
|
2006-02-02 16:47:20 +01:00
|
|
|
struct gs1_part {
|
|
|
|
struct list_head list;
|
|
|
|
unsigned long timeout;
|
|
|
|
unsigned int queryid;
|
|
|
|
unsigned int subid;
|
|
|
|
struct net_pkt *pkt;
|
|
|
|
};
|
|
|
|
|
|
|
|
static LIST_HEAD(gs1_partlist);
|
|
|
|
|
2006-02-02 16:43:41 +01:00
|
|
|
static char scanmsg[] = "\\status\\";
|
2006-02-02 16:47:20 +01:00
|
|
|
|
|
|
|
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\\";
|
2006-02-02 16:51:01 +01:00
|
|
|
static char reply_bfv1[] = "bfvietnam\\";
|
|
|
|
static char reply_bfv2[] = "BFVIETNAM\\";
|
2006-02-02 16:47:20 +01:00
|
|
|
static char reply_poe[] = "poe\\";
|
|
|
|
static char reply_opk[] = "opk\\";
|
|
|
|
static char reply_avp2[] = "avp2\\";
|
|
|
|
static char reply_igi2[] = "projectigi2r\\";
|
2006-02-02 16:51:01 +01:00
|
|
|
static char reply_aao[] = "armygame\\";
|
2006-02-02 16:52:26 +01:00
|
|
|
static char reply_rune[] = "rune\\";
|
2006-02-02 16:47:20 +01:00
|
|
|
|
|
|
|
static int scan(void)
|
|
|
|
{
|
2006-02-02 16:29:30 +01:00
|
|
|
pkt_send_portarr(NULL, port_arr, scanmsg, strlen(scanmsg));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-02-02 16:47:20 +01:00
|
|
|
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;
|
2006-11-24 21:53:25 +01:00
|
|
|
|
2006-02-02 16:47:20 +01:00
|
|
|
// 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;
|
2006-02-02 16:43:41 +01:00
|
|
|
|
2006-02-02 16:47:20 +01:00
|
|
|
// 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) {
|
2006-11-24 21:53:25 +01:00
|
|
|
log_print(LOG_INFO, "gs1: merging error!");
|
2006-02-02 16:47:20 +01:00
|
|
|
free(pkt);
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-02-02 16:29:30 +01:00
|
|
|
|
2006-02-02 16:47:20 +01:00
|
|
|
return (retpkt != NULL) ? pkt_merge(retpkt, pkt) : pkt;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int parse_real(struct net_pkt *pkt, int gameid)
|
|
|
|
{
|
|
|
|
int port, offset, pos1, pos2;
|
2006-11-24 21:53:25 +01:00
|
|
|
|
2006-02-02 16:47:20 +01:00
|
|
|
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);
|
2006-11-24 21:53:25 +01:00
|
|
|
|
2006-02-02 16:31:52 +01:00
|
|
|
switch (gameid) {
|
2006-02-02 16:47:20 +01:00
|
|
|
case 5:/* unreal tournament */
|
|
|
|
if (!pkt_memcmp(pkt, pos1, reply_ut, strlen(reply_ut)))
|
2006-02-02 16:43:41 +01:00
|
|
|
gameid = 5;
|
|
|
|
|
|
|
|
/* unreal tournament 2k3 */
|
2006-02-02 16:47:20 +01:00
|
|
|
else if (!pkt_memcmp(pkt, pos1, reply_ut2k3, strlen(reply_ut2k4)))
|
2006-02-02 16:43:41 +01:00
|
|
|
gameid = 14;
|
|
|
|
|
|
|
|
/* unreal tournament 2k4 */
|
2006-02-02 16:47:20 +01:00
|
|
|
else if (!pkt_memcmp(pkt, pos1, reply_ut2k4, strlen(reply_ut2k4)))
|
2006-02-02 16:43:41 +01:00
|
|
|
gameid = 33;
|
2006-11-24 21:53:25 +01:00
|
|
|
|
2006-02-02 16:51:01 +01:00
|
|
|
/* americas army operations */
|
|
|
|
else if (!pkt_memcmp(pkt, pos1, reply_aao, strlen(reply_aao)))
|
|
|
|
gameid = 15;
|
2006-02-02 16:43:41 +01:00
|
|
|
else
|
2006-02-02 16:47:20 +01:00
|
|
|
return PARSE_REJECT;
|
2006-02-02 16:43:41 +01:00
|
|
|
break;
|
2006-02-02 16:31:52 +01:00
|
|
|
|
2006-02-02 16:43:41 +01:00
|
|
|
case 16:/* battlefield 1942 */
|
2006-02-02 16:47:20 +01:00
|
|
|
case 35:/* battlefield vietnam */
|
|
|
|
if (!pkt_memcmp(pkt, pos1, reply_bf1942, strlen(reply_bf1942)))
|
|
|
|
gameid = 16;
|
|
|
|
|
2006-02-02 16:51:01 +01:00
|
|
|
else if (!pkt_memcmp(pkt, pos2, reply_bfv1, strlen(reply_bfv1)))
|
|
|
|
gameid = 35;
|
2006-11-24 21:53:25 +01:00
|
|
|
|
2006-02-02 16:51:01 +01:00
|
|
|
else if (!pkt_memcmp(pkt, pos2, reply_bfv2, strlen(reply_bfv2)))
|
2006-02-02 16:47:20 +01:00
|
|
|
gameid = 35;
|
2006-11-24 21:53:25 +01:00
|
|
|
|
2006-02-02 16:47:20 +01:00
|
|
|
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;
|
2006-02-02 16:43:41 +01:00
|
|
|
break;
|
2006-02-02 16:31:52 +01:00
|
|
|
|
2006-02-02 16:43:41 +01:00
|
|
|
case 17:/* alien vs. predator 2 */
|
2006-02-02 16:47:20 +01:00
|
|
|
if (!pkt_memcmp(pkt, pos1, reply_avp2, strlen(reply_avp2)))
|
|
|
|
gameid = 17;
|
|
|
|
else
|
|
|
|
return PARSE_REJECT;
|
2006-02-02 16:43:41 +01:00
|
|
|
break;
|
2006-02-02 16:47:20 +01:00
|
|
|
|
2006-02-02 16:52:26 +01:00
|
|
|
case 18:/* rune */
|
|
|
|
if (!pkt_memcmp(pkt, pos1, reply_rune, strlen(reply_rune)))
|
|
|
|
gameid = 18;
|
|
|
|
else
|
|
|
|
return PARSE_REJECT;
|
|
|
|
break;
|
|
|
|
|
2006-02-02 16:43:41 +01:00
|
|
|
case 19:/* project igi2 covert strike */
|
2006-02-02 16:47:20 +01:00
|
|
|
if (!pkt_memcmp(pkt, pos1, reply_igi2, strlen(reply_igi2)))
|
|
|
|
gameid = 19;
|
|
|
|
else
|
|
|
|
return PARSE_REJECT;
|
2006-02-02 16:31:52 +01:00
|
|
|
break;
|
2006-02-02 16:47:20 +01:00
|
|
|
|
2006-02-02 16:31:52 +01:00
|
|
|
default:
|
2006-02-02 16:47:20 +01:00
|
|
|
return PARSE_REJECT;
|
2006-02-02 16:43:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* hostport angabe suchen */
|
2006-02-02 16:47:20 +01:00
|
|
|
offset = pkt_memmem(pkt, 0, search_hostport, strlen(search_hostport));
|
|
|
|
if (offset != -1)
|
|
|
|
pkt_parse_int(pkt, offset + strlen(search_hostport), &port);
|
2006-02-02 16:43:41 +01:00
|
|
|
|
2006-02-02 16:47:20 +01:00
|
|
|
/*
|
|
|
|
* 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))) {
|
2006-02-02 16:43:41 +01:00
|
|
|
server_add(gameid, pkt->addr.sin_addr.s_addr, port, ntohs(pkt->addr.sin_port));
|
|
|
|
} else {
|
2006-02-02 16:31:52 +01:00
|
|
|
server_add_pkt(gameid, pkt);
|
|
|
|
}
|
2006-02-02 16:47:20 +01:00
|
|
|
|
|
|
|
return PARSE_ACCEPT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int parse(struct net_pkt *pkt)
|
|
|
|
{
|
|
|
|
struct net_pkt *pkt2;
|
|
|
|
int gameid, pos, offset, queryid, subid, retval;
|
2006-11-24 21:53:25 +01:00
|
|
|
|
2006-02-02 16:47:20 +01:00
|
|
|
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;
|
2006-11-24 21:53:25 +01:00
|
|
|
|
2006-02-02 16:47:20 +01:00
|
|
|
pos = offset + strlen(search_queryid);
|
|
|
|
if ((offset = pkt_parse_int(pkt, pos, &queryid)) == 0)
|
|
|
|
return PARSE_REJECT;
|
2006-11-24 21:53:25 +01:00
|
|
|
|
2006-02-02 16:47:20 +01:00
|
|
|
pos += offset +1;
|
|
|
|
if ((offset = pkt_parse_int(pkt, pos, &subid)) == 0)
|
|
|
|
return PARSE_REJECT;
|
2006-11-24 21:53:25 +01:00
|
|
|
|
2006-02-02 16:47:20 +01:00
|
|
|
/* 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);
|
2006-11-24 21:53:25 +01:00
|
|
|
|
2006-02-02 16:47:20 +01:00
|
|
|
/* free merged packet */
|
|
|
|
if (pkt != pkt2)
|
|
|
|
free(pkt2);
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
static int gc(void *privdata) {
|
|
|
|
|
|
|
|
unsigned int timeout = (int)privdata;
|
2006-02-02 16:47:20 +01:00
|
|
|
unsigned long now = time(NULL);
|
2006-11-24 21:53:25 +01:00
|
|
|
|
|
|
|
struct gs1_part *part, *tmp;
|
2006-02-02 16:47:20 +01:00
|
|
|
list_for_each_entry_safe(part, tmp, &gs1_partlist, list) {
|
|
|
|
if (part->timeout + timeout < now) {
|
2006-11-24 21:53:25 +01:00
|
|
|
log_print(LOG_INFO, "gs1: removing dead fragment");
|
2006-02-02 16:47:20 +01:00
|
|
|
list_del(&part->list);
|
|
|
|
free(part->pkt);
|
|
|
|
free(part);
|
|
|
|
}
|
|
|
|
}
|
2006-11-24 21:53:25 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int init(void)
|
|
|
|
{
|
|
|
|
int timeout = config_get_int("gamespy1", "gc_timeout", 90);
|
|
|
|
|
|
|
|
struct timeval tv;
|
|
|
|
tv.tv_sec = timeout;
|
|
|
|
tv.tv_usec = 0;
|
|
|
|
event_add_timeout(&tv, gc, (void *)timeout);
|
|
|
|
|
|
|
|
return 0;
|
2006-02-02 16:29:30 +01:00
|
|
|
}
|
|
|
|
|
2006-02-02 16:41:56 +01:00
|
|
|
struct hlswmaster_plugin plugin = {
|
2006-02-02 16:31:52 +01:00
|
|
|
.name = "gamespy1",
|
2006-02-02 16:29:30 +01:00
|
|
|
.scan = &scan,
|
|
|
|
.parse = &parse,
|
2006-11-24 21:53:25 +01:00
|
|
|
.init = &init,
|
2006-02-02 16:29:30 +01:00
|
|
|
};
|