/*************************************************************************** * 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 #include #include #include #include #include "netpkt.h" #include "plugin.h" #include "plugin_helper.h" #include "logging.h" struct validnet_entry { struct list_head list; struct in_addr ip; struct in_addr netmask; }; static LIST_HEAD(validnet_list); 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 char scanmsg3[] = "\xff\xff\xff\xff" "TSource Engine Query"; static int scan(void) { pkt_send_portarr(NULL, port_arr, scanmsg1, strlen(scanmsg1)); pkt_send_portarr(NULL, port_arr, scanmsg2, strlen(scanmsg2)); pkt_send_portarr(NULL, port_arr, scanmsg3, strlen(scanmsg3)); return 1; } static int parse(struct net_pkt *pkt) { struct in_addr tmp; int port, count, pos; 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 */ struct validnet_entry *entry; list_for_each_entry(entry, &validnet_list, list) { if (((entry->ip.s_addr ^ tmp.s_addr) & entry->netmask.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; } // TODO: wrong place int parse_ipmask(const char *value, struct in_addr *ip, struct in_addr *netmask) { char *buf = strdup(value); if (buf == NULL) return -1; int retval = -1; char *p = strchr(buf, '/'); /* valid_net x.x.x.x */ if (p == NULL) { /* single ip */ if (inet_pton(AF_INET, buf, ip) > 0) { netmask->s_addr = 0xFFFFFFFF; retval = 0; } /* valid_net x.x.x.x/x.x.x.x or x.x.x.x/xx */ } else { *p = 0x00; /* ip */ if (inet_pton(AF_INET, buf, &ip) > 0) { /* x.x.x.x/x.x.x.x */ if (inet_pton(AF_INET, p+1, netmask) > 0) { retval = 0; /* x.x.x.x/xx */ } else { int mask = atoi(p+1); if (mask >= 0 && mask <= 32) { netmask->s_addr = htonl(0xFFFFFFFF << (32 - mask)); retval = 0; } } } *p = '/'; } free(buf); return retval; } static int init_callback(const char *value, void *privdata) { struct validnet_entry *entry = malloc(sizeof(struct validnet_entry)); if (entry == NULL) { log_print(LOG_ERROR, "halflife_init(): out of memory"); return -1; } if (parse_ipmask(value, &entry->ip, &entry->netmask) != 0) { log_print(LOG_WARN, " invalid dst: %s", value); free(entry); return -1; } list_add(&entry->list, &validnet_list); return 0; } static int init(void) { config_get_strings("halflife", "valid_net", init_callback, NULL); return 0; } struct hlswmaster_plugin plugin = { .name = "halflife", .scan = &scan, .parse = &parse, .init = &init, };