/* vim: set shiftwidth=3 softtabstop=3 expandtab: */
/*
* Copyright (C) 2002 Erik Fears
*
* 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 "setup.h"
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <string.h>
#endif
#ifdef TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#include <errno.h>
#include <fcntl.h>
#ifdef HAVE_SYS_POLL_H
# include <sys/poll.h>
#endif
#include "inet.h"
#include "compat.h"
#include "config.h"
#include "irc.h"
#include "log.h"
#include "opercmd.h"
#include "stats.h"
#include "dnsbl.h"
#include "extern.h"
#include "options.h"
#include "negcache.h"
#include "malloc.h"
#include "match.h"
#include "scan.h"
/* Libopm */
#include "libopm/src/opm.h"
#include "libopm/src/opm_common.h"
#include "libopm/src/opm_error.h"
#include "libopm/src/opm_types.h"
/* GLOBAL LISTS */
static list_t *SCANNERS = NULL; /* List of OPM_T */
static list_t *MASKS = NULL; /* Associative list of masks->scanners */
/* Negative Cache */
struct cnode *nc_head;
/* Function declarations */
struct scan_struct *scan_create(char **, char *);
void scan_free(struct scan_struct *);
static void scan_irckline(struct scan_struct *, char *, char *);
static void scan_negative(struct scan_struct *);
static void scan_log(OPM_REMOTE_T *);
/** Callbacks for LIBOPM */
void scan_open_proxy(OPM_T *, OPM_REMOTE_T *, int, void *);
void scan_negotiation_failed(OPM_T *, OPM_REMOTE_T *, int, void *);
static void scan_timeout(OPM_T *, OPM_REMOTE_T *, int, void *);
static void scan_end(OPM_T *, OPM_REMOTE_T *, int, void *);
static void scan_handle_error(OPM_T *, OPM_REMOTE_T *, int, void *);
extern FILE *scanlogfile;
/* scan_cycle
*
* Perform scanner tasks.
*/
void scan_cycle()
{
node_t *p;
struct scanner_struct *scs;
/* Cycle through the blacklist first.. */
dnsbl_cycle();
/* Cycle each scanner object */
LIST_FOREACH(p, SCANNERS->head)
{
scs = (struct scanner_struct *) p->data;
opm_cycle(scs->scanner);
}
}
/* scan_timer
*
* Perform actions that are to be performed every ~1 second.
*
* Parameters: NONE
* Return: NONE
*
*/
void scan_timer(void)
{
static int nc_counter;
if (OptionsItem->negcache > 0)
{
if (nc_counter++ >= NEG_CACHE_REBUILD)
{
/*
* Time to rebuild the negative
* cache.
*/
if(OPT_DEBUG)
log_printf("SCAN -> Rebuilding negative cache");
negcache_rebuild();
nc_counter = 0;
}
}
}
/* scan_gettype(int protocol)
*
* Return human readable name of OPM PROTOCOL given OPM_TYPE_PROTOCOL
*
* Parameters:
* protocol: Protocol to return (from libopm/src/opm_types.h)
*
* Return:
* Pointer to static string containing human readable form of protocol
* name
*
*/
char *scan_gettype(int protocol)
{
unsigned int i;
static char *undef = "undefined";
static struct protocol_assoc protocols[] =
{
{ OPM_TYPE_HTTP, "HTTP" },
{ OPM_TYPE_HTTPPOST, "HTTPPOST" },
{ OPM_TYPE_SOCKS4, "SOCKS4" },
{ OPM_TYPE_SOCKS5, "SOCKS5" },
{ OPM_TYPE_WINGATE, "WINGATE" },
{ OPM_TYPE_ROUTER, "ROUTER" }
};
for(i = 0; i < (sizeof(protocols) / sizeof(struct protocol_assoc)); i++)
if(protocol == protocols[i].type)
return protocols[i].name;
return undef;
}
/* scan_init
Initialize scanner and masks list based on configuration.
Parameters:
None
Return:
None
*/
void scan_init()
{
node_t *p, *p2, *p3, *p4, *node;
struct UserConf *uc;
struct ScannerConf *sc;
struct ProtocolConf *pc;
struct scanner_struct *scs;
char *mask;
char *scannername;
/* FIXME: If rehash code is ever added, cleanup would need done here. */
SCANNERS = list_create();
MASKS = list_create();
/* Setup each individual scanner */
LIST_FOREACH(p, ScannerItemList->head)
{
sc = p->data;
scs = MyMalloc(sizeof *scs);
if(OPT_DEBUG)
log_printf("SCAN -> Setting up scanner [%s]", sc->name);
/* Build the scanner */
scs->scanner = opm_create();
scs->name = (char *) DupString(sc->name);
scs->masks = list_create();
/* Setup configuration */
opm_config(scs->scanner, OPM_CONFIG_FD_LIMIT, &(sc->fd));
opm_config(scs->scanner, OPM_CONFIG_SCAN_IP, sc->target_ip);
opm_config(scs->scanner, OPM_CONFIG_SCAN_PORT, &(sc->target_port));
opm_config(scs->scanner, OPM_CONFIG_TIMEOUT, &(sc->timeout));
opm_config(scs->scanner, OPM_CONFIG_MAX_READ, &(sc->max_read));
opm_config(scs->scanner, OPM_CONFIG_BIND_IP, sc->vhost);
/* add target strings */
LIST_FOREACH(p2, sc->target_string->head)
opm_config(scs->scanner, OPM_CONFIG_TARGET_STRING, (char *) p2->data);
/* Setup callbacks */
opm_callback(scs->scanner, OPM_CALLBACK_OPENPROXY, &scan_open_proxy, scs);
opm_callback(scs->scanner, OPM_CALLBACK_NEGFAIL, &scan_negotiation_failed, scs);
opm_callback(scs->scanner, OPM_CALLBACK_TIMEOUT, &scan_timeout, scs);
opm_callback(scs->scanner, OPM_CALLBACK_END, &scan_end, scs);
opm_callback(scs->scanner, OPM_CALLBACK_ERROR, &scan_handle_error, scs);
/* Setup the protocols */
LIST_FOREACH(p2, sc->protocols->head)
{
pc = (struct ProtocolConf *) p2->data;
if(OPT_DEBUG >= 2)
{
log_printf("SCAN -> Adding protocol %s:%d to scanner [%s]",
scan_gettype(pc->type), pc->port, scs->name);
}
if(opm_addtype(scs->scanner, pc->type, pc->port) == OPM_ERR_BADPROTOCOL)
{
log_printf("SCAN -> Error bad protocol %s:%d in scanner [%s]",
scan_gettype(pc->type), pc->port, scs->name);
}
}
node = node_create(scs);
list_add(SCANNERS, node);
}
/* Give scanners a list of masks they scan */
LIST_FOREACH(p, SCANNERS->head)
{
scs = (struct scanner_struct *) p->data;
LIST_FOREACH(p2, UserItemList->head)
{
uc = (struct UserConf *) p2->data;
LIST_FOREACH(p3, uc->scanners->head)
{
scannername = (char *) p3->data;
/* Add all these masks to scanner */
if(strcasecmp(scannername, scs->name) == 0)
{
LIST_FOREACH(p4, uc->masks->head)
{
mask = (char *) p4->data;
if(OPT_DEBUG)
{
log_printf("SCAN -> Linking the mask [%s] to scanner "
"[%s]", mask, scannername);
}
node = node_create(DupString(mask));
list_add(scs->masks, node);
}
break;
}
}
}
}
/* Initialise negative cache */
if (OptionsItem->negcache > 0)
{
if(OPT_DEBUG >= 2)
log_printf("SCAN -> Initializing negative cache");
nc_init(&nc_head);
}
}
/* scan_connect
*
* scan_connect is called when m_notice (irc.c) matches a connection
* notice and parses the connecting user out of it.
*
* Parameters:
* user: Parsed items from the connection notice:
* user[0] = connecting users nickname
* user[1] = connecting users username
* user[2] = connecting users hostname
* user[3] = connecting users IP
* msg = Original connect notice
* Return: NONE
*
*/
void scan_connect(char **user, char *msg)
{
struct bopm_sockaddr ip;
node_t *p, *p2;
struct scan_struct *ss;
struct scanner_struct *scs;
char *scsmask;
int ret;
/*
* Have to use MSGLENMAX here because it is unknown what the max size of
* username/hostname can be. Some ircds use really mad values for
* these.
*/
static char mask[MSGLENMAX];
static char ipmask[MSGLENMAX];
/* Check negcache before anything */
if(OptionsItem->negcache > 0)
{
if (!inet_pton(AF_INET, user[3], &(ip.sa4.sin_addr)))
{
log_printf("SCAN -> Invalid IPv4 address '%s'!", user[3]);
return;
}
else
{
if(check_neg_cache(ip.sa4.sin_addr.s_addr) != NULL)
{
if(OPT_DEBUG)
{
log_printf("SCAN -> %s!%s@%s (%s) is negatively cached. "
"Skipping all tests.", user[0], user[1], user[2],
user[3]);
}
return;
}
}
}
/* Generate user mask */
snprintf(mask, MSGLENMAX, "%s!%s@%s", user[0], user[1], user[2]);
snprintf(ipmask, MSGLENMAX, "%s!%s@%s", user[0], user[1], user[3]);
/* Check exempt list now that we have a mask */
if(scan_checkexempt(mask, ipmask))
{
if(OPT_DEBUG)
log_printf("SCAN -> %s is exempt from scanning", mask);
return;
}
/* create scan_struct */
ss = scan_create(user, msg);
/* Store ss in the remote struct, so that in callbacks we have ss */
ss->remote->data = ss;
/* Start checking our DNSBLs */
if(LIST_SIZE(OpmItem->blacklists) > 0)
dnsbl_add(ss);
/* Add ss->remote to all matching scanners */
LIST_FOREACH(p, SCANNERS->head)
{
scs = (struct scanner_struct *) p->data;
LIST_FOREACH(p2, scs->masks->head)
{
scsmask = (char *) p2->data;
if(match(scsmask, mask))
{
if(OPT_DEBUG)
{
log_printf("SCAN -> Passing %s to scanner [%s]", mask,
scs->name);
}
if((ret = opm_scan(scs->scanner, ss->remote)) != OPM_SUCCESS)
{
switch(ret)
{
case OPM_ERR_NOPROTOCOLS:
continue;
break;
case OPM_ERR_BADADDR:
log_printf("OPM -> Bad address %s [%s].",
ss->manual_target->name, ss->ip);
break;
default:
log_printf("OPM -> Unknown error %s [%s].",
ss->manual_target->name, ss->ip);
break;
}
}
else
ss->scans++; /* Increase scan count only if OPM_SUCCESS */
break; /* Continue to next scanner */
}
}
}
/* All scanners returned !OPM_SUCCESS and there were no dnsbl checks */
if(ss->scans == 0)
scan_free(ss);
}
/* scan_create
*
* Allocate scan struct, including user information and REMOTE
* for LIBOPM.
*
* Parameters:
* user: Parsed items from the connection notice:
* user[0] = connecting users nickname
* user[1] = connecting users username
* user[2] = connecting users hostname
* user[3] = connecting users IP
* msg = Original connect notice (used as PROOF)
*
* Return: Pointer to new scan_struct
*
*/
struct scan_struct *scan_create(char **user, char *msg)
{
struct scan_struct *ss;
ss = MyMalloc(sizeof *ss);
ss->irc_nick = (char *) DupString(user[0]);
ss->irc_username = (char *) DupString(user[1]);
ss->irc_hostname = (char *) DupString(user[2]);
ss->ip = (char *) DupString(user[3]);
ss->proof = (char *) DupString(msg);
ss->remote = opm_remote_create(ss->ip);
ss->scans = 0;
ss->positive = 0;
ss->manual_target = NULL;
assert(ss->remote);
return ss;
}
/* scan_free
*
* Free a scan_struct. This should only be done if the scan struct has
* no scans left!
*
* Parameters:
* ss: scan_struct to free
*
* Return: NONE
*
*/
void scan_free(struct scan_struct *ss)
{
if(ss == NULL)
return;
MyFree(ss->irc_nick);
MyFree(ss->irc_username);
MyFree(ss->irc_hostname);
MyFree(ss->ip);
MyFree(ss->proof);
opm_remote_free(ss->remote);
MyFree(ss);
}
/* scan_checkfinished
*
* Check if a scan is complete (ss->scans <= 0)
* and free it if need be.
*
*/
void scan_checkfinished(struct scan_struct *ss)
{
if(ss->scans <= 0)
{
if(ss->manual_target != NULL)
{
irc_send("PRIVMSG %s :CHECK -> All tests on %s completed.",
ss->manual_target->name, ss->ip);
}
else
{
if(OPT_DEBUG)
{
/* If there was a manual_target, then irc_nick, etc is NULL. */
log_printf("SCAN -> All tests on %s!%s@%s complete.",
ss->irc_nick, ss->irc_username, ss->irc_hostname);
}
/* Scan was a negative */
if(!ss->positive)
scan_negative(ss);
}
scan_free(ss);
}
}
/* scan_positive
*
* Remote host (defined by ss) has been found positive by one or more
* tests.
*
* Parameters:
* ss: scan_struct containing information regarding positive host
* kline: command to send to IRC server to ban the user (see scan_irckline)
* type: string of the type of proxy found to be running on the host
*
* Return: NONE
*
*/
void scan_positive(struct scan_struct *ss, char *kline, char *type)
{
node_t *node;
OPM_T *scanner;
/* If already a positive, don't kline/close again */
if(ss->positive)
return;
/* Format KLINE and send to IRC server */
scan_irckline(ss, kline, type);
/* Speed up the cleanup procedure */
/* Close all scans prematurely */
LIST_FOREACH(node, SCANNERS->head)
{
scanner = (OPM_T *) ((struct scanner_struct *) node->data)->scanner;
opm_end(scanner, ss->remote);
}
/* Set it as a positive (to avoid a scan_negative call later on */
ss->positive = 1;
}
/* scan_open_proxy CALLBACK
*
* Called by libopm when a proxy is verified open.
*
* Parameters:
* scanner: Scanner that found the open proxy.
* remote: Remote struct containing information regarding remote end
*
* Return: NONE
*
*/
void scan_open_proxy(OPM_T *scanner, OPM_REMOTE_T *remote, int notused,
void *data)
{
struct scan_struct *ss;
struct scanner_struct *scs;
USE_VAR(scanner);
USE_VAR(notused);
/* Record that a scan happened */
scan_log(remote);
scs = (struct scanner_struct *) data;
ss = (struct scan_struct *) remote->data;
if(ss->manual_target == NULL)
{
/* kline and close scan */
scan_positive(ss, IRCItem->kline, scan_gettype(remote->protocol));
/* Report to blacklist */
dnsbl_report(ss);
irc_send_channels("OPEN PROXY -> %s!%s@%s %s:%d (%s) [%s]",
ss->irc_nick, ss->irc_username, ss->irc_hostname, remote->ip,
remote->port, scan_gettype(remote->protocol), scs->name);
log_printf("SCAN -> OPEN PROXY %s!%s@%s %s:%d (%s) [%s]",
ss->irc_nick, ss->irc_username, ss->irc_hostname, remote->ip,
remote->port, scan_gettype(remote->protocol), scs->name);
}
else
{
irc_send("PRIVMSG %s :CHECK -> OPEN PROXY %s:%d (%s) [%s]",
ss->manual_target->name, remote->ip, remote->port,
scan_gettype(remote->protocol), scs->name);
log_printf("SCAN -> OPEN PROXY %s:%d (%s) [%s]", remote->ip,
remote->port, scan_gettype(remote->protocol), scs->name);
}
/* Record the proxy for stats purposes */
stats_openproxy(remote->protocol);
}
/* scan_negotiation_failed CALLBACK
*
* Called by libopm when negotiation of a specific protocol failed.
*
* Parameters:
* scanner: Scanner where the negotiation failed.
* remote: Remote struct containing information regarding remote end
*
* Return: NONE
*
*/
void scan_negotiation_failed(OPM_T *scanner, OPM_REMOTE_T *remote,
int notused, void *data)
{
struct scan_struct *ss;
struct scanner_struct *scs;
USE_VAR(scanner);
USE_VAR(notused);
/* Record that a scan happened */
scan_log(remote);
scs = (struct scanner_struct *) data;
ss = (struct scan_struct *) remote->data;
if(OPT_DEBUG)
{
log_printf("SCAN -> Negotiation failed %s:%d (%s) [%s] (%d bytes read)",
remote->ip, remote->port, scan_gettype(remote->protocol),
scs->name, remote->bytes_read);
}
/*
if(ss->manual_target != NULL)
{
irc_send("PRIVMSG %s :CHECK -> Negotiation failed %s:%d (%s) [%s] "
"(%d bytes read)", ss->manual_target->name, remote->ip,
remote->port, scan_gettype(remote->protocol), scs->name,
remote->bytes_read);
}
*/
}
/* scan_timeout CALLBACK
*
* Called by libopm when the negotiation of a specific protocol timed out.
*
* Parameters:
* scanner: Scanner where the connection timed out.
* remote: Remote struct containing information regarding remote end
*
* Return: NONE
*
*/
static void scan_timeout(OPM_T *scanner, OPM_REMOTE_T *remote, int notused,
void *data)
{
struct scan_struct *ss;
struct scanner_struct *scs;
USE_VAR(scanner);
USE_VAR(notused);
/* Record that a scan happened */
scan_log(remote);
scs = (struct scanner_struct *) data;
ss = (struct scan_struct *) remote->data;
if(OPT_DEBUG)
{
log_printf("SCAN -> Negotiation timed out %s:%d (%s) [%s] "
"(%d bytes read)", remote->ip, remote->port,
scan_gettype(remote->protocol), scs->name,
remote->bytes_read);
}
/*
if(ss->manual_target != NULL)
{
irc_send("PRIVMSG %s :CHECK -> Negotiation timed out %s:%d (%s) [%s] "
"(%d bytes read)", ss->manual_target->name, remote->ip,
remote->port, scan_gettype(remote->protocol), scs->name,
remote->bytes_read);
}
*/
}
/* scan_end CALLBACK
*
* Called by libopm when a specific SCAN has completed (all protocols in
* that scan).
*
* Parameters:
* scanner: Scanner the scan ended on.
* remote: Remote struct containing information regarding remote end
*
* Return: NONE
*
*/
static void scan_end(OPM_T *scanner, OPM_REMOTE_T *remote, int notused,
void *data)
{
struct scan_struct *ss;
struct scanner_struct *scs;
USE_VAR(scanner);
USE_VAR(notused);
scs = (struct scanner_struct *) data;
ss = (struct scan_struct *) remote->data;
if(OPT_DEBUG)
log_printf("SCAN -> Scan %s [%s] completed", remote->ip, scs->name);
ss->scans--;
scan_checkfinished(ss);
}
/* scan_handle_error CALLBACK
*
* Called by libopm when an error occurs with a specific connection. This
* does not mean the entire scan has ended.
*
* Parameters:
* scanner: Scanner where the error occured.
* remote: Remote struct containing information regarding remote end
* err: OPM_ERROR code describing the error.
*
* Return: NONE
*
*/
static void scan_handle_error(OPM_T *scanner, OPM_REMOTE_T *remote,
int err, void *data)
{
struct scan_struct *ss;
struct scanner_struct *scs;
USE_VAR(scanner);
scs = (struct scanner_struct *) data;
ss = (struct scan_struct *) remote->data;
switch(err)
{
case OPM_ERR_MAX_READ:
if(OPT_DEBUG >= 2)
{
log_printf("SCAN -> Max read on %s:%d (%s) [%s] (%d bytes read)",
remote->ip, remote->port, scan_gettype(remote->protocol),
scs->name, remote->bytes_read);
}
if(ss->manual_target != NULL)
{
irc_send("PRIVMSG %s :CHECK -> Negotiation failed %s:%d (%s) "
"[%s] (%d bytes read)", ss->manual_target->name,
remote->ip, remote->port, scan_gettype(remote->protocol),
scs->name, remote->bytes_read);
}
break;
case OPM_ERR_BIND:
log_printf("SCAN -> Bind error on %s:%d (%s) [%s]", remote->ip,
remote->port, scan_gettype(remote->protocol), scs->name);
break;
case OPM_ERR_NOFD:
log_printf("SCAN -> File descriptor allocation error %s:%d (%s) "
"[%s]", remote->ip, remote->port,
scan_gettype(remote->protocol), scs->name);
if(ss->manual_target != NULL)
{
irc_send("PRIVMSG %s :CHECK -> Scan failed %s:%d (%s) [%s] "
"(file descriptor allocation error)",
ss->manual_target->name, remote->ip, remote->port,
scan_gettype(remote->protocol), scs->name);
}
break;
default: /* Unknown Error! */
if(OPT_DEBUG)
{
log_printf("SCAN -> Unknown error %s:%d (%s) [%s]", remote->ip,
remote->port, scan_gettype(remote->protocol), scs->name);
}
break;
}
}
/* scan_negative
*
* Remote host (defined by ss) has passed all tests.
*
* Parameters:
* ss: scan_struct containing information regarding negative host.
*
* Return: NONE
*
*/
static void scan_negative(struct scan_struct *ss)
{
/* Insert IP in negcache */
if(OptionsItem->negcache > 0)
{
if(OPT_DEBUG >= 2)
log_printf("SCAN -> Adding %s to negative cache", ss->ip);
negcache_insert(ss->ip);
}
}
/* scan_irckline
*
* ss has been found as a positive host and is to be klined.
* Format a kline message using the kline message provided
* as a format, then pass it to irc_send() to be sent to the remote server.
*
* Parameters:
* ss: scan_struct containing information regarding host to be klined
* format: kline message to format
* type: type of proxy found (%t format character)
*
* Return: NONE
*
*/
static void scan_irckline(struct scan_struct *ss, char *format, char *type)
{
char message[MSGLENMAX]; /* OUTPUT */
unsigned short pos = 0; /* position in format */
unsigned short len = 0; /* position in message */
unsigned short size = 0; /* temporary size buffer */
unsigned int i;
struct kline_format_assoc table[] =
{
{'i', (void *) NULL, FORMATTYPE_STRING },
{'h', (void *) NULL, FORMATTYPE_STRING },
{'u', (void *) NULL, FORMATTYPE_STRING },
{'n', (void *) NULL, FORMATTYPE_STRING },
{'t', (void *) NULL, FORMATTYPE_STRING }
};
table[0].data = ss->ip;
table[1].data = ss->irc_hostname;
table[2].data = ss->irc_username;
table[3].data = ss->irc_nick;
table[4].data = type;
/*
* Copy format to message character by character, inserting any matching
* data after %.
*/
while(format[pos] != '\0' && len < (MSGLENMAX - 2))
{
switch(format[pos])
{
case '%':
/* % is the last char in the string, move on */
if(format[pos + 1] == '\0')
continue;
/* %% escapes % and becomes % */
if(format[pos + 1] == '%')
{
message[len++] = '%';
pos++; /* skip past the escaped % */
break;
}
/* Safe to check against table now */
for(i = 0; i < (sizeof(table) / sizeof(struct kline_format_assoc)); i++)
{
if(table[i].key == format[pos + 1])
{
switch(table[i].type)
{
case FORMATTYPE_STRING:
size = strlen( (char *) table[i].data);
/* Check if the new string can fit! */
if( (size + len) > (MSGLENMAX - 1) )
break;
else
{
strcat(message, (char *) table[i].data);
len += size;
}
default:
break;
}
}
}
/* Skip key character */
pos++;
break;
default:
message[len++] = format[pos];
message[len] = '\0';
break;
}
/* continue to next character in format */
pos++;
}
irc_send("%s", message);
}
/* scan_manual
*
* Create a manual scan. A manual scan is a scan where the
* scan_struct contains a manual_target pointer.
*/
void scan_manual(char *param, struct ChannelConf *target)
{
struct in_addr *addr;
struct scan_struct *ss;
struct scanner_struct *scs;
char *ip;
char *scannername;
node_t *p;
int ret;
/* If there were no parameters sent, simply alert the user and return */
if(param == NULL)
{
irc_send("PRIVMSG %s :OPM -> Invalid parameters.", target->name);
return;
}
/* Try to extract a scanner name from param, otherwise we'll be
adding to all scanners */
ip = param;
if((scannername = strchr(param, ' ')) != NULL)
{
*scannername = '\0';
scannername++;
}
ss = MyMalloc(sizeof *ss);
/* If IP is a hostname, resolve it using gethostbyname (which will block!) */
if (!(addr = firedns_resolveip4(ip)))
{
irc_send("PRIVMSG %s :CHECK -> Error resolving host '%s': %s",
target->name, ip, firedns_strerror(fdns_errno));
return;
}
/* IP = the resolved IP now (it was the ip OR hostname before) */
ip = inet_ntoa(*addr);
/* These don't exist in a manual scan */
ss->irc_nick = NULL;
ss->irc_username = NULL;
ss->irc_hostname = NULL;
ss->proof = NULL;
ss->ip = DupString(ip);
ss->remote = opm_remote_create(ss->ip);
ss->remote->data = ss;
ss->scans = 0;
ss->positive = 0;
ss->manual_target = target;
assert(ss->remote);
if(scannername != NULL)
{
irc_send("PRIVMSG %s :CHECK -> Checking '%s' for open proxies [%s]",
target->name, ip, scannername);
}
else
{
irc_send("PRIVMSG %s :CHECK -> Checking '%s' for open proxies on all "
"scanners", target->name, ip);
}
if(LIST_SIZE(OpmItem->blacklists) > 0)
dnsbl_add(ss);
/* Add ss->remote to all scanners */
LIST_FOREACH(p, SCANNERS->head)
{
scs = (struct scanner_struct *) p->data;
/* If we have a scannername, only allow that scanner
to be used */
if(scannername != NULL)
if(strcasecmp(scannername, scs->name))
continue;
if(OPT_DEBUG)
{
log_printf("SCAN -> Passing %s to scanner [%s] (MANUAL SCAN)", ip,
scs->name);
}
if((ret = opm_scan(scs->scanner, ss->remote)) != OPM_SUCCESS)
{
switch(ret)
{
case OPM_ERR_NOPROTOCOLS:
break;
case OPM_ERR_BADADDR:
irc_send("PRIVMSG %s :OPM -> Bad address %s [%s]",
ss->manual_target->name, ss->ip, scs->name);
break;
default:
irc_send("PRIVMSG %s :OPM -> Unknown error %s [%s]",
ss->manual_target->name, ss->ip, scs->name);
break;
}
}
else
ss->scans++; /* Increase scan count only if OPM_SUCCESS */
}
/* If all of the scanners gave !OPM_SUCCESS and there were no dnsbl checks,
cleanup here */
if(ss->scans == 0)
{
if(scannername != NULL)
{
irc_send("PRIVMSG %s :CHECK -> No such scanner '%s', or '%s' has "
"0 protocols.", ss->manual_target->name, scannername,
scannername);
}
irc_send("PRIVMSG %s :CHECK -> No scans active on '%s', aborting scan.",
ss->manual_target->name, ss->ip);
scan_free(ss);
}
}
/* scan_checkexempt
*
* Check mask against exempt list.
*
* Parameters:
* mask: Mask to check
*
* Return:
* 1 if mask is in list
* 0 if mask is not in list
*/
int scan_checkexempt(char *mask, char *ipmask)
{
node_t *node;
char *exempt_mask;
LIST_FOREACH(node, ExemptItem->masks->head)
{
exempt_mask = (char *) node->data;
if(match(exempt_mask, mask) || match(exempt_mask, ipmask))
return 1;
}
return 0;
}
/* scan_log
*
* Log the fact that a given ip/port/protocol has just been scanned, if the
* user has asked for this to be logged.
*
* Parameters:
* remote: OPM_REMOTE_T for the remote end
*/
static void scan_log(OPM_REMOTE_T *remote)
{
char buf_present[25];
time_t present;
struct tm *tm_present;
struct scan_struct *ss = (struct scan_struct *) remote->data;
if(!(OptionsItem->scanlog && scanlogfile))
return;
time(&present);
tm_present = gmtime(&present);
strftime(buf_present, sizeof(buf_present), "%b %d %H:%M:%S %Y", tm_present);
fprintf(scanlogfile, "[%s] %s:%d (%s) \"%s\"\n", buf_present,
remote->ip, remote->port, scan_gettype(remote->protocol), ss->proof);
fflush(scanlogfile);
}
syntax highlighted by Code2HTML, v. 0.9.1