/*
** iplog_config.c - iplog configuration parser.
** Copyright (C) 2001 Ryan McCabe <odin@numb.org>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License, version 2,
** as published by the Free Software Foundation.
**
** 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
**
** $Id: iplog_config.c,v 1.26 2001/01/01 16:02:14 odin Exp $
*/
#include <config.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <iplog.h>
#include <arpa/inet.h>
#include <iplog_options.h>
#include <iplog_config.h>
static int get_icmp_type(const u_char *, struct port_range *);
static int get_addr(const u_char *, ipaddr_t *, ipaddr_t *, size_t);
static int get_addrrange(const u_char *, struct addr_entry *, ipaddr_t *, size_t);
static int get_port(const u_char *, int, const u_char *);
static int get_portrange(const u_char *, struct port_range *, u_int prot);
static bool port_match(const struct port_range *, in_port_t port);
static bool type_match(const struct port_range *, in_port_t port);
static bool addr_match(const struct addr_entry *, ipaddr_t addr);
static void enter_state(u_int new_state);
static void exit_state(void);
static const u_char *proto_list[] = { "tcp", "udp", "icmp" };
static u_char errbuf[512];
static struct filter_data *filters[3] = { NULL, NULL, NULL };
static u_int current_state = STATE_INITIAL;
static struct state_stack *state_stack = NULL;
/*
** Check whether the ICMP packet pointed to by "ip" matches any filters.
** Returns true if it matches, false if it doesn't.
*/
bool icmp_filter(u_int prot, const struct ip *ip, u_char type) {
const struct filter_data *rule, *head = filters[prot];
for (rule = head ; rule != NULL ; rule = rule->next) {
if ((addr_match(&rule->src, ip->ip_src.s_addr) ^ rule->src.not) &&
(addr_match(&rule->dst, ip->ip_dst.s_addr) ^ rule->dst.not) &&
(type_match(&rule->dport, type) ^ rule->dport.not))
return (false ^ rule->not);
}
return (false);
}
/*
** Check whether the packet pointed to by "ip" matches any filters.
** Returns true if it matches, false if it doesn't.
*/
bool tcp_filter(u_int p, const struct ip *ip, in_port_t sprt, in_port_t dprt) {
const struct filter_data *rule, *head = filters[p];
for (rule = head ; rule != NULL ; rule = rule->next) {
if ((addr_match(&rule->src, ip->ip_src.s_addr) ^ rule->src.not) &&
(addr_match(&rule->dst, ip->ip_dst.s_addr) ^ rule->dst.not) &&
(port_match(&rule->dport, htons(dprt) ^ rule->dport.not)) &&
(port_match(&rule->sport, htons(sprt) ^ rule->sport.not)))
{
return (false ^ rule->not);
}
}
return (false);
}
/*
** Enter the state specified by "new_state." Push the current state
** onto the state stack.
*/
static void enter_state(u_int new_state) {
struct state_stack *ns = xmalloc(sizeof(struct state_stack));
ns->state = current_state;
ns->next = state_stack;
state_stack = ns;
current_state = new_state;
}
/*
** Exit the current state. Pop the last state off the state stack.
*/
static void exit_state(void) {
u_int new_state;
struct state_stack *save;
#ifdef DEBUG
if (state_stack == NULL)
fatal("BUG: State stack is empty.");
#endif
new_state = state_stack->state;
save = state_stack;
state_stack = state_stack->next;
free(save);
current_state = new_state;
}
/*
** Exit the current state, and enter the state specified by "x."
*/
#define xenter_state(x) \
do { \
exit_state(); \
enter_state((x)); \
} while (0)
/*
** Checks whether the host in "test" matches "host." Returns true if they
** match, false if they don't.
*/
static bool addr_match(const struct addr_entry *test, ipaddr_t host) {
if (test->addr == 0 || host == 0 || test->addr == host)
return (true);
if (((host ^ test->addr) & test->mask) == 0)
return (true);
return (false);
}
/*
** Checks whether the ICMP types match. Returns true if they match,
** false if they don't.
*/
static bool type_match(const struct port_range *test, in_port_t port) {
if (test->min == TYPE_MATCH_ALL || test->min == port)
return (true);
return (false);
}
/*
** Checks whether "port" matches the specified port range. Returns true
** if it matches, false if it doesn't.
*/
static bool port_match(const struct port_range *test, in_port_t port) {
if (test->max == 0 && test->min == 0)
return (true);
if (test->max == test->min)
return (test->max == port);
if (!test->max)
return (test->min <= port);
else if (!test->min)
return (test->max >= port);
else
return ((test->max >= port) && (test->min <= port));
return (false);
}
/*
** Finds all the IP addresses for "hostname." Writes the first IP address to
** "addr" and the others to "list." On success, returns the number of IP
** addresses found, excluding the primary IP. On failure, it returns -1.
*/
static int get_addr(const u_char *hostname, ipaddr_t *addr,
ipaddr_t *list, size_t siz)
{
#ifdef HAVE_INET_ATON
struct in_addr in;
#endif
struct hostent *host;
if (isdigit(hostname[strlen(hostname) - 1])) {
u_char *p = (typeof(p)) hostname, i;
for (i = 0 ; *p != '\0' ; p++) {
if (*p == '.')
++i;
}
if (i != 3) {
u_char short_host[MAX_IPLEN];
xstrncpy(short_host, hostname, sizeof(short_host));
switch (i) {
case 0:
xstrncat(short_host, ".0", sizeof(short_host));
case 1:
xstrncat(short_host, ".0", sizeof(short_host));
case 2:
xstrncat(short_host, ".0", sizeof(short_host));
}
#ifdef HAVE_INET_ATON
inet_aton(short_host, &in);
*addr = in.s_addr;
#else
*addr = inet_addr(short_host);
#endif
return (0);
}
}
host = gethostbyname(hostname);
if (host != NULL) {
u_char **p;
*addr = *((ipaddr_t *) host->h_addr);
p = (typeof(p)) host->h_addr_list;
if (list != NULL && *(p + 1) != NULL) {
size_t i;
for (i = 0 ; i < siz && *p != NULL ; p++, i++)
list[i] = *(ipaddr_t *) *p;
return (i);
}
return (0);
} else {
#ifdef HAVE_INET_ATON
if (inet_aton(hostname, &in) != 0)
*addr = in.s_addr;
#else
*addr = inet_addr(hostname);
#endif
return (0);
}
return (-1);
}
/*
** Converts the string "str" to an ICMP code. Returns the ICMP code on success.
** Returns -1 on failure.
*/
static int get_icmp_type(const u_char *str, struct port_range *dst) {
char *nptr;
int type;
if (*str == '!') {
dst->not = true;
++str;
}
type = strtol(str, &nptr, 10);
if (*nptr == '\0') {
if (type < 0 || type > 18)
return (-1);
dst->min = type;
return (0);
}
if (!strncasecmp(str, "ICMP_", 5))
str += 5;
if (!strncasecmp(str, "ECHOREPLY", 5))
dst->min = ICMP_ECHO_REPLY;
else if (!strncasecmp(str, "ECHO", 2))
dst->min = ICMP_ECHO;
else if (!strncasecmp(str, "UNREACH", 4))
dst->min = ICMP_DEST_UNREACHABLE;
else if (!strncasecmp(str, "REDIRECT", 3))
dst->min = ICMP_REDIRECT;
else if (!strncasecmp(str, "ROUTERADVERT", 9))
dst->min = ICMP_ROUTER_ADVERT;
else if (!strncasecmp(str, "ROUTERSOLICIT", 9))
dst->min = ICMP_ROUTER_SOLICIT;
else if (!strncasecmp(str, "TIMXCEED", 5))
dst->min = ICMP_TIME_EXCEEDED;
else if (!strncasecmp(str, "TIMESTAMP_REPLY", 10))
dst->min = ICMP_TIMESTAMP_REPLY;
else if (!strncasecmp(str, "TSTAMP", 6))
dst->min = ICMP_TIMESTAMP;
else if (!strncasecmp(str, "IREQREPLY", 5))
dst->min = ICMP_INFO_REPLY;
else if (!strncasecmp(str, "IREQ", 2))
dst->min = ICMP_INFO_REQUEST;
else if (!strncasecmp(str, "MASKREPLY", 5))
dst->min = ICMP_ADDRESS_REPLY;
else if (!strncasecmp(str, "MASKREQ", 2))
dst->min = ICMP_ADDRESS;
else if (!strncasecmp(str, "PARAMPROB", 4))
dst->min = ICMP_PARAMETER_PROBLEM;
else if (!strncasecmp(str, "SOURCEQUENCH", 3))
dst->min = ICMP_SOURCE_QUENCH;
else {
snprintf(errbuf, sizeof(errbuf), "Unknown ICMP type: %s", str);
return (-1);
}
return (0);
}
/*
** Extracts a port from string "s." Returns the port number on success
** and -1 on failure.
*/
static int get_port(const u_char *s, int wildcard, const u_char *proto) {
int port;
if (!strcasecmp(s, EVERYTHING))
port = wildcard;
else {
char *nptr;
port = strtol(s, &nptr, 10);
if (*nptr != '\0') {
struct servent *se = getservbyname(s, proto);
if (se == NULL) {
snprintf(errbuf, sizeof(errbuf), "Invalid port: \"%s\"", s);
return (-1);
}
port = htons(se->s_port);
}
}
return (port);
}
/*
** Extracts an address range from the string "str." Returns the number
** of IP addresses found on success and -1 on failure.
*/
static int get_addrrange(const u_char *str,
struct addr_entry *addr,
ipaddr_t *list,
size_t siz)
{
u_char *p, *q;
int i = 0;
if (*str == '!') {
addr->not = true;
++str;
}
p = strchr(str, '/');
if (p != NULL) {
*p++ = '\0';
for (q = p ; *q != '\0' ; q++) {
if (!isdigit(*q)) {
i = 1;
break;
}
}
if (i == 1) {
if (get_addr(p, &addr->mask, NULL, 0) == -1) {
snprintf(errbuf, sizeof(errbuf), "Invalid mask: %s", str);
return (-1);
}
} else {
if (!strcasecmp(p, EVERYTHING))
addr->mask = MASK_MATCH_ALL;
else {
char *nptr;
i = strtoul(p, &nptr, 10);
if (*nptr == '\0') {
if (i >= 1 && i <= 32) {
addr->mask = htonl(~((1 << (32 - i)) - 1));
} else {
snprintf(errbuf, sizeof(errbuf),
"Invalid mask: must be in range 1 - 32");
return (-1);
}
} else {
snprintf(errbuf, sizeof(errbuf), "Invalid mask: %s", str);
return (-1);
}
}
}
} else
addr->mask = MASK_MATCH_ONE;
if (!strcasecmp(str, EVERYTHING))
addr->addr = 0;
else {
i = get_addr(str, &addr->addr, list, siz);
if (i == -1)
snprintf(errbuf, sizeof(errbuf), "Unknown host: %s", str);
return (i);
}
return (0);
}
/*
** Extracts a port range from the string "str." Returns 0 on success and
** -1 on failure.
*/
static int get_portrange(const u_char *str, struct port_range *port, u_int prot)
{
const u_char *proto = proto_list[prot];
u_char *p;
int min_p, max_p;
if (*str == '!') {
port->not = true;
++str;
} else
port->not = false;
p = strchr(str, ':');
if (p != NULL)
*p++ = '\0';
min_p = get_port(str, MIN_PORT, proto);
if (min_p == -1)
return (-1);
if (p != NULL) {
/* Allow for stuff like 6000: */
if (*p == '\0')
max_p = MAX_PORT;
else {
max_p = get_port(p, MAX_PORT, proto);
if (max_p == -1)
return (-1);
}
} else
max_p = min_p;
if ((min_p & MAX_PORT) != min_p ||
(max_p & MAX_PORT) != max_p)
{
snprintf(errbuf, sizeof(errbuf),
"Error: Ports must be between 1 and 65535");
return (-1);
}
if (min_p > max_p) {
snprintf(errbuf, sizeof(errbuf),
"Error: Minimum port (%d) is greater than the maximum port (%d)",
min_p, max_p);
return (-1);
}
port->min = min_p;
port->max = max_p;
return (0);
}
/*
** Read in the configuration file, parse rules. "filename" specifies the
** path of the config file.
**
** Who needs lex/yacc?
*/
void parse_config(const u_char *filename) {
FILE *fp;
u_char buf[8192], *token;
u_int prot = 0, line_number = 0;
struct filter_data *frule = NULL;
extern u_char *user, *group, *ifstring, *logfile, *lockfile, *pcap_network;
extern int facility, priority;
ipaddr_t dadr[32], sadr[32];
/* Avoid spurious gcc warnings.. */
struct port_range *prange = NULL;
struct addr_entry *adrent = NULL;
ssize_t dcnt = 0, scnt = 0, res;
bool src_set = 0, dst_set = 0, sport_set = 0, dport_set = 0, itype_set = 0;
u_int32_t temp_flags = 0;
fp = fopen(filename, "r");
/*
** Don't yell if the file doesn't exist.
*/
if (fp == NULL) {
if (errno != ENOENT)
mysyslog("Unable to open %s: %s\n", filename, strerror(errno));
return;
}
top:
while (get_line(fp, buf, sizeof(buf) - 1) != EOF) {
++line_number;
if (current_state != STATE_COMMENT) {
src_set = dst_set = sport_set = dport_set = itype_set = false;
dcnt = scnt = res = 0;
temp_flags = 0;
#ifdef DEBUG
if (current_state != STATE_INITIAL) {
fatal("BUG: [line %u] State should be 0 (is %u)",
line_number, current_state);
}
#endif
}
token = strtok(buf, " \t\n");
if (token == NULL) {
if (current_state != STATE_INITIAL &&
current_state != STATE_COMMENT)
{
mysyslog("[line %u] Premature EOL", line_number);
}
continue;
}
do {
top2:
if (!strncmp(token, "/*", 2)) {
enter_state(STATE_COMMENT);
token += 2;
} else if (current_state != STATE_COMMENT && *token == '#') {
if (current_state != STATE_INITIAL)
goto got_eol;
if (frule != NULL)
xfree(frule);
goto top;
}
switch (current_state) {
case STATE_INITIAL:
if (!strcasecmp(token, "set"))
enter_state(STATE_SET);
else if (!strcasecmp(token, "log")) {
frule = xmalloc(sizeof(struct filter_data));
frule->not = false;
enter_state(STATE_FILTER_PROT);
} else if (!strcasecmp(token, "ignore")) {
frule = xmalloc(sizeof(struct filter_data));
frule->not = true;
enter_state(STATE_FILTER_PROT);
} else if (!strncasecmp(token, "interface", 9))
enter_state(STATE_INTERFACE);
else if (!strcasecmp(token, "logfile"))
enter_state(STATE_LOGFILE);
else if (!strcasecmp(token, "pid-file"))
enter_state(STATE_LOCKFILE);
else if (!strcasecmp(token, "user"))
enter_state(STATE_USER);
else if (!strcasecmp(token, "group"))
enter_state(STATE_GROUP);
else if (!strcasecmp(token, "facility"))
enter_state(STATE_FACILITY);
else if (!strcasecmp(token, "priority"))
enter_state(STATE_PRIORITY);
else if (!strcasecmp(token, "promisc"))
enter_state(STATE_PROMISC);
else {
mysyslog("[line %d] Invalid rule: %s",
line_number, token);
goto top;
}
if (current_state == STATE_FILTER_PROT) {
frule->sport.min = MIN_PORT;
frule->sport.max = MAX_PORT;
frule->sport.not = false;
frule->dport.min = MIN_PORT;
frule->dport.max = MAX_PORT;
frule->dport.not = false;
frule->src.addr = ADDR_MATCH_ALL;
frule->src.mask = MASK_MATCH_ONE;
frule->src.not = false;
frule->dst.addr = ADDR_MATCH_ALL;
frule->dst.mask = MASK_MATCH_ONE;
frule->dst.not = false;
}
break;
case STATE_USER:
if (user != NULL)
free(user);
user = xstrdup(token);
exit_state();
break;
case STATE_GROUP:
if (group != NULL)
free(group);
group = xstrdup(token);
exit_state();
break;
case STATE_LOGFILE:
if (logfile != NULL)
free(logfile);
logfile = xstrdup(token);
exit_state();
break;
case STATE_LOCKFILE:
if (lockfile != NULL)
free(lockfile);
lockfile = xstrdup(token);
exit_state();
break;
case STATE_FACILITY:
facility = get_facility(token);
exit_state();
break;
case STATE_PRIORITY:
priority = get_priority(token);
exit_state();
break;
case STATE_INTERFACE:
if (ifstring != NULL)
free(ifstring);
ifstring = xstrdup(token);
exit_state();
break;
case STATE_PROMISC:
flags |= (PROMISC | LOG_DEST);
if (pcap_network != NULL)
free(pcap_network);
pcap_network = xstrdup(token);
exit_state();
break;
case STATE_SET:
if (!strcasecmp(token, "tcp"))
temp_flags |= LOG_TCP;
else if (!strcasecmp(token, "udp"))
temp_flags |= LOG_UDP;
else if (!strcasecmp(token, "icmp"))
temp_flags |= LOG_ICMP;
else if (!strcasecmp(token, "frag"))
temp_flags |= LOG_FRAG;
else if (!strcasecmp(token, "smurf"))
temp_flags |= SMURF;
else if (!strcasecmp(token, "bogus"))
temp_flags |= BOGUS;
else if (!strcasecmp(token, "log_ip"))
temp_flags |= LOG_IP;
else if (!strcasecmp(token, "log_dest"))
temp_flags |= LOG_DEST;
else if (!strcasecmp(token, "stdout"))
temp_flags |= LOG_STDOUT;
else if (!strcasecmp(token, "no_fork"))
temp_flags |= NO_FORK;
else if (!strcasecmp(token, "verbose"))
temp_flags |= VERBOSE;
else if (!strcasecmp(token, "fin_scan"))
temp_flags |= FIN_SCAN;
else if (!strcasecmp(token, "syn_scan"))
temp_flags |= SYN_SCAN;
else if (!strcasecmp(token, "udp_scan"))
temp_flags |= UDP_SCAN;
else if (!strcasecmp(token, "portscan"))
temp_flags |= PORTSCAN;
else if (!strcasecmp(token, "fool_nmap"))
temp_flags |= FOOL_NMAP;
else if (!strcasecmp(token, "xmas_scan"))
temp_flags |= XMAS_SCAN;
else if (!strcasecmp(token, "null_scan"))
temp_flags |= NULL_SCAN;
else if (!strcasecmp(token, "get_ident"))
temp_flags |= GET_IDENT;
else if (!strcasecmp(token, "dns_cache"))
temp_flags |= DNS_CACHE;
else if (!strcasecmp(token, "syn_flood"))
temp_flags |= SYN_FLOOD;
else if (!strcasecmp(token, "ignore_dns"))
temp_flags |= IGNORE_NS;
else if (!strcasecmp(token, "ping_flood"))
temp_flags |= PING_FLOOD;
else if (!strcasecmp(token, "scans_only"))
temp_flags |= SCANS_ONLY;
else if (!strcasecmp(token, "traceroute"))
temp_flags |= TRACEROUTE;
else if (!strcasecmp(token, "udp_resolve"))
temp_flags |= UDP_RES;
else if (!strcasecmp(token, "tcp_resolve"))
temp_flags |= TCP_RES;
else if (!strcasecmp(token, "icmp_resolve"))
temp_flags |= ICMP_RES;
else if (!strcasecmp(token, "disable_resolver"))
temp_flags |= NO_RESOLV;
else {
mysyslog("[line %d] Invalid \"set\" target: %s",
line_number, token);
}
xenter_state(STATE_NEED_BOOL);
break;
case STATE_NEED_BOOL:
if (!strcasecmp(token, "true"))
flags |= temp_flags;
else if (!strcasecmp(token, "false"))
flags &= ~temp_flags;
else {
mysyslog("[line %u] Invalid boolean token: %s",
line_number, token);
}
exit_state();
break;
case STATE_FILTER_PROT:
if (!strcasecmp(token, "tcp"))
prot = FIL_TCP;
else if (!strcasecmp(token, "udp"))
prot = FIL_UDP;
else if (!strcasecmp(token, "icmp")) {
prot = FIL_ICMP;
frule->dport.min = TYPE_MATCH_ALL;
} else {
mysyslog("[line %u] Invalid protocol: %s",
line_number, token);
xfree(frule);
exit_state();
goto top;
}
xenter_state(STATE_FILTER);
break;
case STATE_FILTER:
if (!strcasecmp(token, "from")) {
if (src_set != false) {
mysyslog("[line %u] \"from\" already set.",
line_number);
xfree(frule);
exit_state();
goto top;
}
++src_set;
adrent = &frule->src;
enter_state(STATE_NEED_ARANGE);
} else if (!strcasecmp(token, "to")) {
if (dst_set != false) {
mysyslog("[line %u] \"to\" already set.",
line_number);
xfree(frule);
exit_state();
goto top;
}
++dst_set;
adrent = &frule->dst;
enter_state(STATE_NEED_ARANGE);
} else if (prot == FIL_TCP || prot == FIL_UDP) {
if (!strcasecmp(token, "sport")) {
if (sport_set != false) {
mysyslog("[line %u] \"sport\" already set.",
line_number);
xfree(frule);
exit_state();
goto top;
}
++sport_set;
prange = &frule->sport;
enter_state(STATE_NEED_PRANGE);
} else if (!strcasecmp(token, "dport")) {
if (dport_set != false) {
mysyslog("[line %u] \"dport\" already set.",
line_number);
xfree(frule);
exit_state();
goto top;
}
++dport_set;
prange = &frule->dport;
enter_state(STATE_NEED_PRANGE);
} else {
mysyslog("[line %u] Invalid filter keyword: %s",
line_number, token);
xfree(frule);
exit_state();
goto top;
}
} else if (prot == FIL_ICMP) {
if (!strcasecmp(token, "type")) {
if (itype_set != false) {
mysyslog("[line %u] \"type\" already set.",
line_number);
xfree(frule);
exit_state();
goto top;
}
++itype_set;
enter_state(STATE_NEED_ITYPE);
} else {
mysyslog("[line %u] Invalid filter keyword: %s",
line_number, token);
xfree(frule);
exit_state();
goto top;
}
} else {
mysyslog("[line %u] Invalid filter keyword: %s",
line_number, token);
xfree(frule);
exit_state();
goto top;
}
/* Only EOL (or an error) takes us out of this state. */
break;
case STATE_NEED_ARANGE:
if (adrent == &frule->src) {
scnt = get_addrrange(token, adrent, sadr, sizeof(sadr));
res = scnt;
} else {
dcnt = get_addrrange(token, adrent, dadr, sizeof(dadr));
res = dcnt;
}
exit_state();
if (res == -1) {
mysyslog("[line %u] %s", line_number, errbuf);
xfree(frule);
exit_state();
goto top;
}
break;
case STATE_NEED_PRANGE:
res = get_portrange(token, prange, prot);
exit_state();
if (res == -1) {
mysyslog("[line %u] %s", line_number, errbuf);
xfree(frule);
exit_state();
goto top;
}
break;
case STATE_NEED_ITYPE:
res = get_icmp_type(token, &frule->dport);
exit_state();
if (res == -1) {
mysyslog("[line %u] %s", line_number, errbuf);
xfree(frule);
exit_state();
goto top;
}
break;
case STATE_COMMENT:
{
u_char *ret;
ret = strstr(token, "*/");
if (ret != NULL) {
exit_state();
token = ret + 2;
while (*token == ' ' || *token == '\t')
++token;
if (*token != '\0')
goto top2;
}
break;
}
}
token = strtok(NULL, " \t\n");
if (token == NULL) {
u_char *errstr = NULL;
got_eol:
/* We've reached EOL. */
switch (current_state) {
case STATE_INITIAL:
case STATE_COMMENT:
break;
case STATE_NEED_BOOL:
/* True is implicit if no argument is provided. */
flags |= temp_flags;
exit_state();
break;
case STATE_FILTER:
if (dport_set == false && sport_set == false &&
dst_set == false && src_set == false &&
itype_set == false)
{
switch (prot) {
case FIL_TCP:
temp_flags = LOG_TCP;
break;
case FIL_UDP:
temp_flags = LOG_UDP;
break;
case FIL_ICMP:
temp_flags = LOG_ICMP;
break;
}
if (frule->not == true)
flags &= ~temp_flags;
else
flags |= temp_flags;
xfree(frule);
exit_state();
break;
}
if (scnt == 0 && dcnt == 0) {
if (frule->not == false)
list_prepend(frule, &filters[prot]);
else
list_append(frule, &filters[prot]);
frule = NULL;
} else {
/* Don't even ask about the variable names.. */
size_t bd, sd, id, j;
ipaddr_t *bp, *sp, *bl, *sl;
if (scnt > dcnt) {
bd = scnt;
sd = dcnt;
bp = &frule->src.addr;
sp = &frule->dst.addr;
bl = sadr;
sl = dadr;
} else {
bd = dcnt;
sd = scnt;
bp = &frule->dst.addr;
sp = &frule->src.addr;
bl = dadr;
sl = sadr;
}
for (id = 0 ; id < bd ; id++) {
*bp = bl[id];
for (j = 0 ; j < sd ; j++) {
*sp = sl[j];
if (frule->not == false) {
list_copy_prepend(frule, &filters[prot],
sizeof(struct filter_data));
} else {
list_copy_append(frule, &filters[prot],
sizeof(struct filter_data));
}
}
if (sd == 0) {
if (frule->not == false) {
list_copy_prepend(frule, &filters[prot],
sizeof(struct filter_data));
} else {
list_copy_append(frule, &filters[prot],
sizeof(struct filter_data));
}
}
}
xfree(frule);
}
exit_state();
break;
/*
** Being in any of the following states is an indication
** that something went wrong.
*/
case STATE_USER:
errstr = "user parameter";
break;
case STATE_GROUP:
errstr = "group parameter";
break;
case STATE_LOGFILE:
errstr = "log file parameter";
break;
case STATE_PRIORITY:
errstr = "syslog priority parameter";
break;
case STATE_FACILITY:
errstr = "syslog facility parameter";
break;
case STATE_INTERFACE:
errstr = "interface parameter";
break;
case STATE_PROMISC:
errstr = "network parameter";
break;
case STATE_SET:
errstr = "set target";
break;
case STATE_FILTER_PROT:
errstr = "protocol parameter";
break;
case STATE_NEED_ITYPE:
errstr = "ICMP type";
exit_state();
break;
case STATE_NEED_ARANGE:
errstr = "address parameter";
exit_state();
break;
case STATE_NEED_PRANGE:
errstr = "port parameter";
exit_state();
break;
}
if (errstr != NULL) {
if (frule != NULL)
xfree(frule);
exit_state();
mysyslog("[line %u] Missing %s", line_number, errstr);
}
/* Proceed to the next line. */
break;
}
/* Proceed to the next token. */
} while (1);
}
if (current_state != STATE_INITIAL) {
if (current_state == STATE_COMMENT)
mysyslog("%s: Parse Error: Unterminated comment.", filename);
else {
#ifdef DEBUG
fatal("BUG: [line %u] State should be 0 (is %u)",
line_number, current_state);
#endif
}
}
list_destroy(state_stack, NULL);
fclose(fp);
}
/*
** Add filter rules to ignore DNS traffic from all the hosts listed as
** name servers in /etc/resolv.conf.
*/
int add_dns_ignore_rules(void) {
struct filter_data fil_data;
u_char buf[1024], *p;
FILE *fp;
ipaddr_t list[32];
ssize_t num_addr;
fp = fopen(NS_FILE, "r");
if (fp == NULL)
return (-1);
fil_data.sport.min = 53;
fil_data.sport.max = 53;
fil_data.sport.not = false;
fil_data.dport.min = MIN_PORT;
fil_data.dport.max = MAX_PORT;
fil_data.dport.not = false;
fil_data.src.mask = MASK_MATCH_ONE;
fil_data.src.not = false;
fil_data.dst.addr = ADDR_MATCH_ALL;
fil_data.dst.mask = MASK_MATCH_ONE;
fil_data.dst.not = false;
fil_data.not = true;
while (get_line(fp, buf, sizeof(buf) - 1) != EOF) {
p = strtok(buf, " \t");
if (p == NULL)
continue;
if (strcmp(p, "nameserver"))
continue;
p = strtok(NULL, " \t");
if (p == NULL)
continue;
num_addr = get_addr(p, &fil_data.src.addr, list, sizeof(list));
if (num_addr == -1)
continue;
list_copy_prepend(&fil_data, &filters[FIL_UDP], sizeof(fil_data));
if (num_addr > 0) {
ssize_t i;
for (i = 0 ; i < num_addr ; i++) {
fil_data.src.addr = list[i];
list_copy_prepend(&fil_data, &filters[FIL_UDP], sizeof(fil_data));
}
}
}
fclose(fp);
return (0);
}
#ifdef HAVE_PTHREAD_CANCEL
/*
** Destroy the filter rules list for the protocol specified by "prot."
*/
void destroy_filter_list(u_int prot) {
list_destroy(filters[prot], NULL);
filters[prot] = NULL;
}
#endif
/* vim:ts=4:sw=8:tw=0 */
syntax highlighted by Code2HTML, v. 0.9.1