2006-02-02 16:24:06 +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. *
|
|
|
|
***************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
2006-11-24 21:53:25 +01:00
|
|
|
|
2006-02-02 16:24:06 +01:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/ip.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
#include "event.h"
|
2006-02-02 16:24:06 +01:00
|
|
|
#include "netpkt.h"
|
2006-02-02 16:41:56 +01:00
|
|
|
#include "configfile.h"
|
2006-02-02 16:47:20 +01:00
|
|
|
#include "plugin.h"
|
2006-11-24 21:53:25 +01:00
|
|
|
#include "scanner.h"
|
|
|
|
#include "logging.h"
|
|
|
|
#include "gamelist.h"
|
2006-02-02 16:24:06 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
static LIST_HEAD(tx_queue);
|
2006-02-02 16:24:06 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
static int scan_sock;
|
2006-02-02 16:47:20 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
int pkt_send(struct in_addr *dstip, unsigned int dstport, char *buf, unsigned int size)
|
|
|
|
{
|
|
|
|
struct net_pkt *pkt = malloc(sizeof(struct net_pkt) + size);
|
|
|
|
if (pkt == NULL) {
|
|
|
|
log_print(LOG_WARN, "pkt_send(): out of memory");
|
|
|
|
return -1;
|
|
|
|
}
|
2006-02-02 16:47:20 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
pkt->addr.sin_family = AF_INET;
|
|
|
|
pkt->addr.sin_port = htons(dstport);
|
|
|
|
pkt->addr.sin_addr.s_addr = (dstip ? dstip->s_addr : 0xFFFFFFFF);
|
2006-02-02 16:47:20 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
memcpy(pkt->buf, buf, size);
|
|
|
|
pkt->size = size;
|
2006-02-02 16:47:20 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
list_add_tail(&pkt->list, &tx_queue);
|
|
|
|
return 0;
|
|
|
|
}
|
2006-02-02 16:43:41 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
static int scanner_transmit(void *privdata)
|
|
|
|
{
|
|
|
|
if (list_empty(&tx_queue))
|
|
|
|
return -1;
|
2006-02-02 16:43:41 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
struct net_pkt *pkt;
|
|
|
|
pkt = list_entry(tx_queue.next, struct net_pkt, list);
|
|
|
|
list_del(&pkt->list);
|
2006-02-02 16:24:06 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
int ret = sendto(scan_sock, pkt->buf, pkt->size, 0, (struct sockaddr *)&pkt->addr, sizeof(pkt->addr));
|
|
|
|
if (ret <= 0)
|
|
|
|
log_print(LOG_WARN, "scanner_transmit(): sendto()");
|
|
|
|
|
|
|
|
return 0;
|
2006-02-02 16:24:06 +01:00
|
|
|
}
|
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
static int scanner_scan(void *privdata)
|
2006-02-02 16:47:20 +01:00
|
|
|
{
|
2006-11-24 21:53:25 +01:00
|
|
|
plugins_scan();
|
2006-02-02 16:47:20 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
struct timeval tv;
|
|
|
|
tv.tv_sec = 0;
|
|
|
|
tv.tv_usec = 10000;
|
2006-02-02 16:43:41 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
event_add_timeout(&tv, scanner_transmit, NULL);
|
|
|
|
return 0;
|
2006-02-02 16:43:41 +01:00
|
|
|
}
|
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
static int scanner_receive(int fd, void *privdata)
|
2006-02-02 16:47:20 +01:00
|
|
|
{
|
2006-11-24 21:53:25 +01:00
|
|
|
int recvsize;
|
|
|
|
if (ioctl(fd, FIONREAD, &recvsize) == -1) {
|
|
|
|
log_print(LOG_WARN, "scanner_receive(): ioctl(FIONREAD)");
|
|
|
|
return 0;
|
2006-02-02 16:43:41 +01:00
|
|
|
}
|
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
struct net_pkt *pkt = malloc(sizeof(struct net_pkt) + recvsize);
|
|
|
|
if (pkt == NULL) {
|
|
|
|
log_print(LOG_WARN, "scanner_receive(): out of memory");
|
|
|
|
return 0;
|
|
|
|
}
|
2006-02-02 16:47:20 +01:00
|
|
|
|
2006-12-20 20:47:47 +01:00
|
|
|
unsigned int i = sizeof(struct sockaddr_in);
|
2006-11-24 21:53:25 +01:00
|
|
|
pkt->size = recvfrom(fd, pkt->buf, recvsize, 0, (struct sockaddr *)&pkt->addr, &i);
|
2006-02-02 16:47:20 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
if (pkt->size < 0) {
|
|
|
|
log_print(LOG_WARN, "scanner_receive(): recvfrom()");
|
|
|
|
free(pkt);
|
|
|
|
return 0;
|
2006-02-02 16:44:46 +01:00
|
|
|
}
|
2006-02-02 16:47:20 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
switch (plugins_parse(pkt)) {
|
2006-12-20 20:47:47 +01:00
|
|
|
case PARSE_REJECT: {
|
|
|
|
char *pkt_str = pkt_print(pkt);
|
|
|
|
log_print(LOG_INFO, "scanner_receive(): unknown packet: %s:%d size:%d\n%s",
|
2006-11-24 21:53:25 +01:00
|
|
|
inet_ntoa(pkt->addr.sin_addr),
|
|
|
|
ntohs(pkt->addr.sin_port),
|
2006-12-20 20:47:47 +01:00
|
|
|
pkt->size, pkt_str);
|
|
|
|
|
|
|
|
free(pkt_str);
|
|
|
|
}
|
2006-02-02 16:43:41 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
case PARSE_ACCEPT:
|
|
|
|
free(pkt);
|
2006-02-02 16:47:20 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
case PARSE_ACCEPT_FREED:
|
|
|
|
break;
|
2006-02-02 16:24:06 +01:00
|
|
|
}
|
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
return 0;
|
2006-02-02 16:24:06 +01:00
|
|
|
}
|
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
int scanner_init()
|
2006-02-02 16:47:20 +01:00
|
|
|
{
|
2006-11-24 21:53:25 +01:00
|
|
|
scan_sock = socket(PF_INET, SOCK_DGRAM, 0);
|
|
|
|
if (scan_sock < 0) {
|
|
|
|
log_print(LOG_ERROR, "scan_init(): socket()");
|
|
|
|
return -1;
|
2006-02-02 16:24:06 +01:00
|
|
|
}
|
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
struct sockaddr_in src;
|
|
|
|
char *addr = config_get_string("global", "scanner_src", "0.0.0.0:7130");
|
|
|
|
if (parse_saddr(addr, &src) != 0) {
|
|
|
|
log_print(LOG_ERROR, "server_init(): invalid scanner_src '%s'", addr);
|
|
|
|
return -1;
|
|
|
|
}
|
2006-02-02 16:24:06 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
if (bind(scan_sock, (struct sockaddr *)&src, sizeof(src)) < 0) {
|
|
|
|
log_print(LOG_ERROR, "scan_init(): bind()");
|
|
|
|
return -1;
|
2006-02-02 16:24:06 +01:00
|
|
|
}
|
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
int j = 1;
|
|
|
|
if (setsockopt(scan_sock, SOL_SOCKET, SO_BROADCAST, &j, sizeof(j))) {
|
|
|
|
log_print(LOG_ERROR, "scan_init(): setsockopt(SO_BROADCAST)");
|
|
|
|
return -1;
|
2006-02-02 16:24:06 +01:00
|
|
|
}
|
2006-02-02 16:47:20 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
int rxsize = 1<<20;
|
|
|
|
if (setsockopt(scan_sock, SOL_SOCKET, SO_RCVBUF, &rxsize, sizeof(rxsize))) {
|
|
|
|
log_print(LOG_ERROR, "scan_init(): setsockopt(SO_RCVBUF)");
|
|
|
|
return -1;
|
2006-02-02 16:41:56 +01:00
|
|
|
}
|
2006-02-02 16:24:06 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
event_add_readfd(scan_sock, scanner_receive, NULL);
|
|
|
|
log_print(LOG_INFO, "scan socket initialized (%s:%d)", inet_ntoa(src.sin_addr), ntohs(src.sin_port));
|
|
|
|
|
|
|
|
struct timeval tv;
|
|
|
|
tv.tv_sec = config_get_int("global", "scan_interval", 60);
|
|
|
|
tv.tv_usec = 0;
|
|
|
|
|
|
|
|
event_add_timeout(&tv, scanner_scan, NULL);
|
2006-02-02 16:47:20 +01:00
|
|
|
|
2006-11-24 21:53:25 +01:00
|
|
|
scanner_scan(NULL);
|
|
|
|
return 0;
|
2006-02-02 16:24:06 +01:00
|
|
|
}
|