/*
** iplog_options.c - iplog command line argument handler.
** Copyright (C) 1999-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_options.c,v 1.33 2001/01/01 16:02:14 odin Exp $
*/

#include <config.h>

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <syslog.h>
#include <string.h>
#include <sys/types.h>

#ifndef HAVE_GETOPT_LONG
#	include <gnu/getopt.h>
#else
#	include <getopt.h>
#endif

#include <iplog.h>
#include <iplog_options.h>
#include <iplog_config.h>

#define IS_DEFAULT(x) (opt_enabled((x)) ? '*' : ' ')

u_int32_t flags = ~0 &	~(	GET_IDENT | NO_RESOLV | FOOL_NMAP | NO_FORK |
							VERBOSE | LOG_STDOUT | IGNORE_NS | LOG_IP |
							PROMISC | LOG_DEST | SCANS_ONLY);

extern int facility;
extern int priority;
extern u_char *pcap_network;

static void enable(const u_char *arg, u_int32_t flag);
static void print_help(void);

/*
** Available: A,B,C,E,G,H,J,K,M,O,Q,W,X,Y,Z,j,r
*/

static const char opts[] = "DFILNPRSTUVa:bcdefg:hi:kl:mnopstu:vwxyz";

static const struct option longopts[] = {
	{"tcp",					optional_argument,	0, 10},
	{"udp",					optional_argument,	0, 11},
	{"icmp",				optional_argument,	0, 12},
	{"facility",			required_argument,	0, 13},
	{"priority",			required_argument,	0, 14},
	{"pid-file",			required_argument,	0, 15},
	{"kill",				no_argument,		0, 'k'},
	{"user",				required_argument,	0, 'u'},
	{"group",				required_argument,	0, 'g'},
	{"ignore",				no_argument,		0, 'd'},
	{"restart",				no_argument,		0, 'R'},
	{"no-fork",				no_argument,		0, 'o'},
	{"stdout",				no_argument,		0, 'L'},
	{"promisc",				required_argument,	0, 'a'},
	{"logfile",				required_argument,	0, 'l'},
	{"verbose",				optional_argument,	0, 'V'},
	{"log-ip",				optional_argument,	0, 'w'},
	{"log-dest",			optional_argument,	0, 'D'},
	{"fool-nmap",			optional_argument,	0, 'z'},
	{"dns-cache",			optional_argument,	0, 'c'},
	{"interface",			required_argument,	0, 'i'},
	{"get-ident",			optional_argument,	0, 'e'},
	{"scans-only",			optional_argument,	0, 'm'},
	{"tcp-resolve",			optional_argument,	0, 'T'},
	{"udp-resolve",			optional_argument,	0, 'U'},
	{"icmp-resolve",		optional_argument,	0, 'I'},
	{"disable-resolver",	no_argument,		0, 'N'},
	{"detect-syn-flood",	optional_argument,	0, 's'},
	{"detect-frag",			optional_argument,	0, 'y'},
	{"detect-smurf",		optional_argument,	0, 'S'},
	{"detect-bogus",		optional_argument,	0, 'b'},
	{"detect-portscan",		optional_argument,	0, 'p'},
	{"detect-udp-scan",		optional_argument,	0, 'F'},
	{"detect-ping-flood",	optional_argument,	0, 'P'},
	{"detect-fin-scan",		optional_argument,	0, 'f'},
	{"detect-syn-scan",		optional_argument,	0, 'q'},
	{"detect-xmas-scan",	optional_argument,	0, 'x'},
	{"detect-null-scan",	optional_argument,	0, 'n'},
	{"detect-traceroute",	optional_argument,	0, 't'},
	{"log-frag",			optional_argument,	0, 'y'},
	{"log-smurf",			optional_argument,	0, 'S'},
	{"log-bogus",			optional_argument,	0, 'b'},
	{"log-portscan",		optional_argument,	0, 'p'},
	{"log-udp-scan",		optional_argument,	0, 'F'},
	{"log-ping-flood",		optional_argument,	0, 'P'},
	{"log-fin-scan",		optional_argument,	0, 'f'},
	{"log-syn-scan",		optional_argument,	0, 'q'},
	{"log-xmas-scan",		optional_argument,	0, 'x'},
	{"log-null-scan",		optional_argument,	0, 'n'},
	{"log-traceroute",		optional_argument,	0, 't'},
	{"version",				no_argument,		0, 'v'},
	{"help",				no_argument,		0, 'h'},
	{NULL, 0, NULL, 0}
};

/*
** Parses command-line flags.
*/

void get_options(int argc, char *const argv[]) {
	extern u_char *logfile, *lockfile, *user, *group, *ifstring;
	int opt;

	while ((opt = getopt_long(argc, argv, opts, longopts, NULL)) != EOF) {
		switch (opt) {
			case 10:
				enable(optarg, LOG_TCP);
				break;
			case 11:
				enable(optarg, LOG_UDP);
				break;
			case 12:
				enable(optarg, LOG_ICMP);
				break;
			case 13:
				facility = get_facility(optarg);
				break;
			case 14:
				priority = get_priority(optarg);
				break;
			case 15:
				if (lockfile != NULL)
					free(lockfile);
				lockfile = xstrdup(optarg);
				break;
			case 'w':
				enable(optarg, LOG_IP);
				break;
			case 'd':
				flags |= IGNORE_NS;
				break;
			case 'u':
				if (user != NULL)
					free(user);
				user = xstrdup(optarg);
				break;
			case 'g':
				if (group != NULL)
					free(group);
				group = xstrdup(optarg);
				break;
			case 'k':
				kill_iplog(15, lockfile);
				break;
			case 'l':
				if (opt_enabled(LOG_STDOUT)) {
					mysyslog("Warning: Overriding --stdout");
					flags &= ~LOG_STDOUT;
				} else if (logfile != NULL)
					free(logfile);
				logfile = xstrdup(optarg);
				break;
			case 'L':
				if (logfile != NULL) {
					mysyslog("Warning: Overriding --logfile");
					xfree(logfile);
				}
				flags |= LOG_STDOUT;
				break;
			case 'm':
				enable(optarg, SCANS_ONLY);
				break;
			case 'o':
				flags |= NO_FORK;
				break;
			case 'c':
				enable(optarg, DNS_CACHE);
				break;
			case 'y':
				enable(optarg, LOG_FRAG);
				break;
			case 'a':
				flags |= (PROMISC | LOG_DEST);
				if (pcap_network != NULL)
					free(pcap_network);
				pcap_network = xstrdup(optarg);
				break;
			case 'D':
				enable(optarg, LOG_DEST);
				break;
			case 'e':
#ifdef __linux__
				enable(optarg, GET_IDENT);
#else
				mysyslog("Ident lookups are only supported on Linux.");
#endif
				break;
			case 'T':
				enable(optarg, TCP_RES);
				break;
			case 'U':
				enable(optarg, UDP_RES);
				break;
			case 'V':
				enable(optarg, VERBOSE);
				break;
			case 'I':
				enable(optarg, ICMP_RES);
				break;
			case 'S':
				enable(optarg, SMURF);
				break;
			case 'b':
				enable(optarg, BOGUS);
				break;
			case 'P':
				enable(optarg, PING_FLOOD);
				break;
			case 'p':
				enable(optarg, PORTSCAN);
				break;
			case 'x':
				enable(optarg, XMAS_SCAN);
				break;
			case 'f':
				enable(optarg, FIN_SCAN);
				break;
			case 'q':
				enable(optarg, SYN_SCAN);
				break;
			case 'F':
				enable(optarg, UDP_SCAN);
				break;
			case 'N':
				flags |= NO_RESOLV;
				break;
			case 'n':
				enable(optarg, NULL_SCAN);
				break;
			case 's':
				enable(optarg, SYN_FLOOD);
				break;
			case 't':
				enable(optarg, TRACEROUTE);
				break;
			case 'i':
				if (ifstring != NULL)
					free(ifstring);
				ifstring = xstrdup(optarg);
				break;
			case 'R':
				kill_iplog(1, lockfile);
				break;
			case 'z':
				enable(optarg, FOOL_NMAP);
				break;
			case 'v':
				mysyslog("iplog version %s\nby %s\n%s",
					VERSION, AUTHORS, WEBPAGE);
				exit(0);
			case 'h':
			default:
				print_help();
				break;
		}
	}
}

/*
** Checks whether a flag should be enabled or not.
*/

static void enable(const u_char *arg, u_int32_t flag) {
	if (arg == NULL || !strcasecmp(arg, "yes") || !strcasecmp(arg, "true"))
		flags |= flag;
	else if (!strcasecmp(arg, "no") || !strcasecmp(arg, "false"))
		flags &= ~flag;
	else if (!strcasecmp(arg, "toggle"))
		flags ^= flag;
	else {
		fatal("Arguments must be either \"yes\", \"true\", \"no\", "
			"\"false\" or \"toggle\".\nYou gave \"%s\"", optarg);
	}
}

/*
** Converts the string "new_facility" to a syslog(3) facility.  Returns
** the new facility on success and the default facility on failure.
*/

int get_facility(const u_char *new_facility) {
	int fac = FACILITY;

	if (!strncasecmp(new_facility, "log_", 4))
		new_facility += 4;

	if (!strcasecmp(new_facility, "auth"))
		fac = LOG_AUTH;
#ifdef LOG_AUTHPRIV
	else if (!strcasecmp(new_facility, "authpriv"))
		fac = LOG_AUTHPRIV;
#endif
	else if (!strcasecmp(new_facility, "cron"))
		fac = LOG_CRON;
	else if (!strcasecmp(new_facility, "daemon"))
		fac = LOG_DAEMON;
#ifdef LOG_FTP
	else if (!strcasecmp(new_facility, "ftp"))
		fac = LOG_FTP;
#endif
	else if (!strcasecmp(new_facility, "kern"))
		fac = LOG_KERN;
	else if (!strcasecmp(new_facility, "lpr"))
		fac = LOG_LPR;
	else if (!strcasecmp(new_facility, "mail"))
		fac = LOG_MAIL;
	else if (!strcasecmp(new_facility, "news"))
		fac = LOG_NEWS;
	else if (!strcasecmp(new_facility, "security"))
		fac = LOG_AUTH;
	else if (!strcasecmp(new_facility, "syslog"))
		fac = LOG_SYSLOG;
	else if (!strcasecmp(new_facility, "user"))
		fac = LOG_USER;
	else if (!strcasecmp(new_facility, "uucp"))
		fac = LOG_UUCP;
	else if (!strcasecmp(new_facility, "local0"))
		fac = LOG_LOCAL0;
	else if (!strcasecmp(new_facility, "local1"))
		fac = LOG_LOCAL1;
	else if (!strcasecmp(new_facility, "local2"))
		fac = LOG_LOCAL2;
	else if (!strcasecmp(new_facility, "local3"))
		fac = LOG_LOCAL3;
	else if (!strcasecmp(new_facility, "local4"))
		fac = LOG_LOCAL4;
	else if (!strcasecmp(new_facility, "local5"))
		fac = LOG_LOCAL5;
	else if (!strcasecmp(new_facility, "local6"))
		fac = LOG_LOCAL6;
	else if (!strcasecmp(new_facility, "local7"))
		fac = LOG_LOCAL7;
	else
		mysyslog("Invalid facility: \"%s\" - falling back to default.",
				new_facility);

	return (fac);
}

/*
** Converts the string "new_priority" to a syslog(3) priority.  Returns
** the new priority on success and the default priority on failure.
*/

int get_priority(const u_char *new_priority) {
	int pri = PRIORITY;

	if (!strncasecmp(new_priority, "log_", 4))
		new_priority += 4;

	if (!strcasecmp(new_priority, "alert"))
		pri = LOG_ALERT;
	else if (!strcasecmp(new_priority, "crit"))
		pri = LOG_CRIT;
	else if (!strcasecmp(new_priority, "debug"))
		pri = LOG_DEBUG;
	else if (!strcasecmp(new_priority, "emerg"))
		pri = LOG_EMERG;
	else if (!strcasecmp(new_priority, "err"))
		pri = LOG_ERR;
	else if (!strcasecmp(new_priority, "error"))
		pri = LOG_ERR;
	else if (!strcasecmp(new_priority, "info"))
		pri = LOG_INFO;
	else if (!strcasecmp(new_priority, "notice"))
		pri = LOG_NOTICE;
	else if (!strcasecmp(new_priority, "panic"))
		pri = LOG_EMERG;
	else if (!strcasecmp(new_priority, "warn"))
		pri = LOG_WARNING;
	else if (!strcasecmp(new_priority, "warning"))
		pri = LOG_WARNING;
	else
		mysyslog("Invalid priority: \"%s\" - falling back to default.",
				new_priority);

	return (pri);
}

/*
** Simplifies options, checks that no options conflict.
*/

void check_options(void) {
	if (!opt_enabled(LOG_TCP | LOG_UDP | LOG_ICMP))
		fatal("Told not to log anything.  Exiting.");

	if (opt_enabled(PROMISC) && opt_enabled(GET_IDENT))
		fatal("The promisc and get_ident flags are not compatible.");

	if (opt_enabled(NO_RESOLV))
		flags &= ~(TCP_RES | UDP_RES | ICMP_RES);
	else if (!(flags & (TCP_RES | UDP_RES | ICMP_RES)))
		flags |= NO_RESOLV;

	if (!opt_enabled(TCP_RES))
		flags &= ~SYN_FLOOD;

	if (opt_enabled(DNS_CACHE) && opt_enabled(NO_RESOLV))
		flags ^= DNS_CACHE;

	if (opt_enabled(SMURF) && !opt_enabled(LOG_ICMP | LOG_UDP))
		flags ^= SMURF;

	if (!opt_enabled(LOG_TCP))
		flags &= ~(PORTSCAN | NULL_SCAN | FIN_SCAN | XMAS_SCAN);

	if (!opt_enabled(LOG_ICMP))
		flags &= ~PING_FLOOD;

	if (!opt_enabled(LOG_UDP))
		flags &= ~(UDP_SCAN | IGNORE_NS);

	if (opt_enabled(FOOL_NMAP) && get_raw_sock() == false)
		flags ^= FOOL_NMAP;
}

/*
** Print all command-line options to the screen.
*/

static void print_help(void) {
	mysyslog(
"Usage:  "PACKAGE"  [options] (Denotes enabled by default)\n\n"
"--user      or -u <user|UID>     Run as specified the user or UID.\n"
"--group     or -g <group|GID>    Run with specified the group or GID.\n"
"--logfile   or -l <file>         Log to <file>.\n"
"--pid-file  <file>               Use <file> as the pid file.\n"
"--ignore    or -d                Ignore DNS traffic from nameservers listed in\n"
                                 "/etc/resolv.conf.\n"
"--interface or -i <if0,...,ifN>  Listen on the specified interface(s).\n"
"--promisc   or -a <network>      Log traffic to all hosts on <network>.\n"
"--kill      or -k                Kill iplog, if it is running.\n"
"--restart   or -R                Restart iplog, if it is running.\n"
"--no-fork   or -o                Run in the foreground.\n"
"--stdout    or -L                Log to stdout.\n"
"--help      or -h                This help screen.\n"
"--version   or -v                Print version information and exit.\n\n"

"--facility <facility>            Use the specified syslog facility.\n"
"--priority <priority>            Use the specified syslog priority.\n\n"

"--tcp[=true|false|toggle]                      %cLog TCP traffic.\n"
"--udp[=true|false|toggle]                      %cLog UDP traffic.\n"
"--icmp[=true|false|toggle]                     %cLog ICMP traffic.\n\n"

"--log-ip[=true|false|toggle]            or -w  %cLog IP along with hostname.\n"
"--log-dest[=true|false|toggle]          or -D  %cLog the destination of traffic.\n"
"--dns-cache[=true|false|toggle]         or -c  %cUse the built-in DNS cache.\n"
"--get-ident[=true|false|toggle]         or -e  %cGet ident info on connections\n"
                                                "to listening ports.\n\n"

"--tcp-resolve[=true|false|toggle]       or -T  %cResolve IPs of TCP traffic.\n"
"--udp-resolve[=true|false|toggle]       or -U  %cResolve IPs of UDP traffic.\n"
"--icmp-resolve[=true|false|toggle]      or -I  %cResolve IPs of ICMP traffic.\n"
"--disable-resolver                      or -N  %cDo not resolve any IPs.\n\n"

"--verbose[=true|false|toggle]           or -V  %cBe verbose.\n"
"--fool-nmap[=true|false|toggle]         or -z  %cFool nmaps OS detection.\n"
"--scans-only[=true|false|toggle]        or -m  %cOnly log scans.\n"
"--detect-syn-flood[=true|false|toggle]  or -s  %cStop resolving IPs if a\n"
                                                "SYN flood is detected.\n\n"

"--log-frag[=true|false|toggle]          or -y  %cLog fragment attacks.\n"
"--log-traceroute[=true|false|toggle]    or -t  %cLog traceroutes.\n"
"--log-ping-flood[=true|false|toggle]    or -P  %cLog ICMP ping floods.\n"
"--log-smurf[=true|false|toggle]         or -S  %cLog smurf attacks.\n"
"--log-bogus[=true|false|toggle]         or -b  %cLog bogus TCP flags.\n"
"--log-portscan[=true|false|toggle]      or -p  %cLog port scans.\n"
"--log-udp-scan[=true|false|toggle]      or -F  %cLog UDP scans/floods.\n"
"--log-fin-scan[=true|false|toggle]      or -f  %cLog FIN scans.\n"
"--log-syn-scan[=true|false|toggle]      or -q  %cLog SYN scans.\n"
"--log-xmas-scan[=true|false|toggle]     or -x  %cLog Xmas scans.\n"
"--log-null-scan[=true|false|toggle]     or -n  %cLog null scans.\n",
IS_DEFAULT(LOG_TCP),	IS_DEFAULT(LOG_UDP),	IS_DEFAULT(LOG_ICMP),
IS_DEFAULT(LOG_IP),		IS_DEFAULT(LOG_DEST),	IS_DEFAULT(DNS_CACHE),
IS_DEFAULT(GET_IDENT),	IS_DEFAULT(TCP_RES),	IS_DEFAULT(UDP_RES),
IS_DEFAULT(ICMP_RES),	IS_DEFAULT(NO_RESOLV),	IS_DEFAULT(VERBOSE),
IS_DEFAULT(FOOL_NMAP),	IS_DEFAULT(SCANS_ONLY),	IS_DEFAULT(SYN_FLOOD),
IS_DEFAULT(LOG_FRAG),	IS_DEFAULT(TRACEROUTE),	IS_DEFAULT(PING_FLOOD),
IS_DEFAULT(SMURF),		IS_DEFAULT(BOGUS),		IS_DEFAULT(PORTSCAN),
IS_DEFAULT(UDP_SCAN),	IS_DEFAULT(FIN_SCAN),	IS_DEFAULT(SYN_SCAN),
IS_DEFAULT(XMAS_SCAN),	IS_DEFAULT(NULL_SCAN));
	exit(0);
}

/* vim:ts=4:sw=8:tw=0 */


syntax highlighted by Code2HTML, v. 0.9.1