Репозиторий Sisyphus
Последнее обновление: 1 октября 2023 | Пакетов: 18631 | Посещений: 37415037
en ru br
Репозитории ALT
S:2.2.8-alt1
5.1: 2.2.6-alt2
4.1: 2.2.6-alt2
4.0: 2.2.6-alt2
3.0: 2.2.5-alt2
www.altlinux.org/Changes

Группа :: Система/Серверы
Пакет: scanlogd

 Главная   Изменения   Спек   Патчи   Исходники   Загрузить   Gear   Bugs and FR  Repocop 

scanlogd-2.2.6/000075500000000000000000000000001060744672400133235ustar00rootroot00000000000000scanlogd-2.2.6/Makefile000064400000000000000000000022071060744672400147640ustar00rootroot00000000000000CC = gcc
LD = $(CC)
RM = rm -f
CFLAGS = -Wall -O2 -fomit-frame-pointer
LDFLAGS = -s

PCAP_H = -I/usr/include/pcap
PCAP_L = -lpcap

NIDS_H = -I/usr/local/include
NIDS_L = -L/usr/local/lib -lnids -lnet -lpcap

PROJ = scanlogd

OBJS_COMMON = scanlogd.o
OBJS = $(OBJS_COMMON) in_linux.o in_nids.o in_pcap.o

default:
@echo "You need to choose a packet capture interface. Use one of:"
@echo " make linux to use the raw socket interface on Linux"
@echo " make libnids to use libnids (with libpcap and libnet)"
@echo " make libpcap to use libpcap alone"
@echo "See the man page for a short explanation of the interfaces."

linux: $(OBJS_COMMON) in_linux.o
$(LD) $(LDFLAGS) $(OBJS_COMMON) in_linux.o -o scanlogd

libnids: $(OBJS_COMMON) in_nids.o
$(LD) $(LDFLAGS) $(OBJS_COMMON) in_nids.o $(NIDS_L) -o scanlogd

libpcap: $(OBJS_COMMON) in_pcap.o
$(LD) $(LDFLAGS) $(OBJS_COMMON) in_pcap.o $(PCAP_L) -o scanlogd

in_pcap.o: params.h in.h
$(CC) $(CFLAGS) $(PCAP_H) -c in_pcap.c

in_nids.o: params.h in.h
$(CC) $(CFLAGS) $(NIDS_H) -c in_nids.c

scanlogd.o: params.h in.h
in_linux.o: params.h in.h

.c.o:
$(CC) $(CFLAGS) -c $*.c

clean:
$(RM) $(PROJ) $(OBJS)
scanlogd-2.2.6/in.h000064400000000000000000000012771060744672400141110ustar00rootroot00000000000000/*
* Generic packet capture interface for scanlogd.
*/

#ifndef _SCANLOGD_IN_H
#define _SCANLOGD_IN_H

#define _BSD_SOURCE
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>

#ifndef IP_MF
#define IP_MF 0x2000
#endif
#ifndef IP_OFFMASK
#define IP_OFFMASK 0x1fff
#endif

/*
* Packet header as read from a packet capture interface. In reality, the
* TCP header can be at a different offset; this is just to get the total
* size right.
*/
struct header {
struct ip ip;
struct tcphdr tcp;
char space[60 - sizeof(struct ip)];
};

extern int in_init(void);
extern void in_run(void (*process_packet)(struct header *packet, int size));

#endif
scanlogd-2.2.6/in_linux.c000064400000000000000000000016421060744672400153170ustar00rootroot00000000000000#define _BSD_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>

#include "params.h"
#include "in.h"

#ifndef __linux__
#warning "This code will only work on Linux; use an alternate make target"
#endif
#ifdef SCANLOGD_DEVICE
#warning "SCANLOGD_DEVICE makes no sense for the Linux raw socket interface"
#endif
#if SCANLOGD_PROMISC
#warning "SCANLOGD_PROMISC makes no sense for the Linux raw socket interface"
#endif

static int raw;

int in_init(void)
{
if ((raw = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
perror("socket");
return 1;
}

return 0;
}

void in_run(void (*process_packet)(struct header *packet, int size))
{
struct header packet;
int size;

while (1)
if ((size = read(raw, &packet, sizeof(packet))) >= sizeof(packet.ip))
process_packet(&packet, size);
}
scanlogd-2.2.6/in_nids.c000064400000000000000000000033221060744672400151120ustar00rootroot00000000000000#define _BSD_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>

#include <nids.h>

#include "params.h"
#include "in.h"

#if !SCANLOGD_PROMISC
#if !(defined(NIDS_MAJOR) && (NIDS_MAJOR > 1 || NIDS_MINOR >= 14))
#warning "SCANLOGD_PROMISC is 0, but your libnids will set PROMISC anyway"
#endif
#endif

static void (*scanlogd_process_packet)(struct header *packet, int size);

static void nids_process_packet(struct ip *packet)
{
/* Sanity check to make sure we calculate the packet size correctly. We
* don't expect any fragments here since libnids should have defragmented
* stuff for us; this is for testing with nids_register_ip_frag(). */
if (packet->ip_off & htons(IP_MF | IP_OFFMASK))
return;

scanlogd_process_packet((struct header *)packet,
(unsigned int)ntohs(packet->ip_len));
}

static void dummy_syslog(int type, int errnum, struct ip *iph, void *data)
{
}

int in_init(void)
{
#ifdef SCANLOGD_DEVICE
nids_params.device = SCANLOGD_DEVICE;
#endif

#if defined(NIDS_MAJOR) && (NIDS_MAJOR > 1 || NIDS_MINOR >= 14)
nids_params.n_tcp_streams = 0;
#else
nids_params.n_tcp_streams = 1;
#endif
nids_params.n_hosts = HASH_SIZE;
nids_params.syslog = dummy_syslog;
nids_params.scan_num_hosts = 0;
nids_params.pcap_filter = SCANLOGD_PCAP_FILTER;
#if defined(NIDS_MAJOR) && (NIDS_MAJOR > 1 || NIDS_MINOR >= 14)
nids_params.promisc = SCANLOGD_PROMISC;
#endif

if (!nids_init()) {
fprintf(stderr, "nids_init: %s\n", nids_errbuf);
return 1;
}

return 0;
}

void in_run(void (*process_packet)(struct header *packet, int size))
{
scanlogd_process_packet = process_packet;
nids_register_ip(nids_process_packet);

nids_run();
}
scanlogd-2.2.6/in_pcap.c000064400000000000000000000022741060744672400151050ustar00rootroot00000000000000#define _BSD_SOURCE
#include <stdio.h>

#include <pcap.h>

#include "params.h"
#include "in.h"

static pcap_t *p;

int in_init(void)
{
char *device;
char error[PCAP_ERRBUF_SIZE];
struct bpf_program filter;

#ifdef SCANLOGD_DEVICE
device = SCANLOGD_DEVICE;
#else
if (!(device = pcap_lookupdev(error))) {
fprintf(stderr, "pcap_lookupdev: %s\n", error);
return 1;
}
#endif

if (!(p = pcap_open_live(device, sizeof(struct header),
SCANLOGD_PROMISC, 0, error))) {
fprintf(stderr, "pcap_open_live: %s\n", error);
return 1;
}

if (pcap_compile(p, &filter, SCANLOGD_PCAP_FILTER, 1, 0)) {
pcap_perror(p, "pcap_compile");
return 1;
}

if (pcap_setfilter(p, &filter)) {
pcap_perror(p, "pcap_setfilter");
return 1;
}

return 0;
}

void in_run(void (*process_packet)(struct header *packet, int size))
{
int hw_size, size;
char *packet;
struct pcap_pkthdr header;

switch (pcap_datalink(p)) {
case DLT_RAW:
case DLT_SLIP:
hw_size = 0;

case DLT_PPP:
hw_size = 4;

case DLT_EN10MB:
default:
hw_size = 14;
}

while (1)
if ((packet = (char *)pcap_next(p, &header))) {
packet += hw_size;
size = header.caplen - hw_size;
process_packet((struct header *)packet, size);
}
}
scanlogd-2.2.6/params.h000064400000000000000000000054601060744672400147640ustar00rootroot00000000000000/*
* Configurable compile-time parameters for scanlogd.
*/

#ifndef _SCANLOGD_PARAMS_H
#define _SCANLOGD_PARAMS_H

#include <time.h>
#include <syslog.h>

/*
* An unprivileged dummy user to run as. The user and its UID must not be
* used for any other purpose (that is, don't use "nobody" here). You can
* #undef this to let scanlogd run as root, but this is not recommended.
*/
#define SCANLOGD_USER "scanlogd"

/*
* An empty directory to chroot to. The directory and its parent directories
* must not be writable by anyone but root.
*/
#define SCANLOGD_CHROOT "/var/empty"

/*
* Device to monitor, if you're using libnids or libpcap directly. #undef
* this either if you're using the raw socket interface on Linux instead,
* or if you'd like to let libpcap autodetect this for you.
*
* Recent versions of libpcap support magic device name "any" and recent
* libnids supports magic device name "all".
*/
#undef SCANLOGD_DEVICE

/*
* Whether we want scanlogd to set the device into promiscuous mode, for
* use with libpcap.
*/
#define SCANLOGD_PROMISC 0

/*
* The libpcap filter expression to use when scanlogd is built with libnids
* or direct libpcap support. The intent is to reduce CPU load by hopefully
* filtering out most of the uninteresting packets at the kernel level if
* supported by libpcap on a given platform.
*/
#define SCANLOGD_PCAP_FILTER \
"tcp and " \
"((tcp[13] != 0x10 and tcp[13] != 0x18) or ip[6:2] & 0x3fff != 0)"

/*
* High port numbers have a lower weight to reduce the frequency of false
* positives, such as from passive mode FTP transfers.
*/
#define PORT_WEIGHT_PRIV 3
#define PORT_WEIGHT_HIGH 1

/*
* Port scan detection thresholds: at least COUNT ports need to be scanned
* from the same source, with no longer than DELAY seconds between ports.
*/
#define SCAN_MIN_COUNT 7
#define SCAN_MAX_COUNT (SCAN_MIN_COUNT * PORT_WEIGHT_PRIV)
#define SCAN_WEIGHT_THRESHOLD SCAN_MAX_COUNT
#define SCAN_DELAY_THRESHOLD 3

/*
* Log flood detection thresholds: temporarily stop logging if more than
* COUNT port scans are detected with no longer than DELAY seconds between
* them.
*/
#define LOG_COUNT_THRESHOLD 5
#define LOG_DELAY_THRESHOLD 20

/*
* Log line length limit, such as to fit into one SMS message. #undef this
* for no limit.
*/
#define LOG_MAX_LENGTH (160 - 40)

/*
* You might want to adjust these for using your tiny append-only log file.
*/
#define SYSLOG_IDENT "scanlogd"
#define SYSLOG_FACILITY LOG_DAEMON
#define SYSLOG_LEVEL LOG_ALERT

/*
* Keep track of up to LIST_SIZE source addresses, using a hash table of
* HASH_SIZE entries for faster lookups, but limiting hash collisions to
* HASH_MAX source addresses per the same hash value.
*/
#define LIST_SIZE 0x100
#define HASH_LOG 9
#define HASH_SIZE (1 << HASH_LOG)
#define HASH_MAX 0x10

#endif
scanlogd-2.2.6/scanlogd.8000064400000000000000000000076001060744672400152110ustar00rootroot00000000000000.TH SCANLOGD 8 "2 June 2004" "Openwall Project" "System Administration"
.SH NAME
scanlogd \- detects and logs TCP port scans
.SH SYNOPSIS
.B scanlogd
.SH DESCRIPTION
.B scanlogd
detects port scans and writes one line per scan via the
.BR syslog (3)
mechanism. If a source address sends multiple
packets to different ports in a short time, the event will be
logged. The format of the messages is:
.LP
.BR saddr "[:" sport "] to " daddr " [and others,] ports " port "[, " port "...], ..., " flags "[, TOS " TOS "][, TTL " TTL "] @" HH:MM:SS
.PP
The fields in square brackets are optional;
.BR sport ", " TOS ", and " TTL
will only be displayed if they were constant during the scan.
.PP
The
.B flags
field represents TCP control bits seen in packets
coming to the system from the address of the scan. It is a
combination of eight characters, with each corresponding to
one of the six defined and two reserved TCP control bits (see
RFC 793). Control bits that were always set are encoded with an
uppercase letter, and a lowercase letter is used if the bit was
always clear. A question mark is used to indicate bits that
changed from packet to packet.
.SH INTERFACES
In order to do its job,
.B scanlogd
needs a way to obtain raw IP packets that either come to the system
.B scanlogd
is running on, or travel across a network segment that is directly
connected to the system. Current versions of
.B scanlogd
can be built with support for one of several packet capture interfaces.
.PP
.B scanlogd
is aware of the
.B raw socket
interface on Linux,
.BR libnids ,
and
.BR libpcap .
.PP
The use of
.B libpcap
alone is discouraged. If you're on a system other than Linux and/or
want to monitor the traffic of an entire network at once, you should
be using
.B libnids
in order to handle fragmented IP packets.
.SH COMPILE-TIME DEFAULTS
At least 7 different privileged or 21 non-privileged ports, or a
weighted combination of those, have to be accessed with no longer
than 3 seconds between the accesses to be treated as a scan.
If more than 5 scans are detected within 20 seconds, that event
will be logged and logging will be stopped temporarily.
.PP
Logging is done with a facility of
.B daemon
and a priority level
.BR alert .
.PP
.B scanlogd
should be started as root since it needs access to a packet capture
interface.
By default, it chroots to
.I /var/empty
and switches to running as user
.B scanlogd
after the packet capture interface is initialized.
.SH EXIT STATUS
If the daemon couldn't start up successfully, it will exit with a
status of 1.
.SH USAGE
You're expected to create a dummy user for
.B scanlogd
to run as. Make sure you allocate unique UID and GID to the user.
.PP
In most cases,
.B scanlogd
should be started from a rc.d script on system startup.
.PP
In /etc/syslog.conf you may use something like:
.PP
daemon.alert /var/log/alert
.SH SECURITY NOTES
As the name indicates,
.B scanlogd
only logs port scans.
.B It does not prevent them.
You will only receive summarized information in the system's log.
.PP
Obviously, the source address of port scans can be spoofed.
.B Don't take any action against the source of attacks
.B unless other evidence is available.
Sometimes IP addresses are shared between many people; this is the
case for ISP shell servers, dynamic dialup pools, and corporate
networks behind NAT (masquerading).
.SH BUGS
Due to the nature of port scans, both false positives (detecting a
scan when there isn't one) and false negatives (not detecting a scan
when there's one) are possible. In particular, false positives occur
when many small files are transferred rapidly with passive mode FTP.
.SH AUTHORS
.nf
Solar Designer <solar at openwall.com>
.fi
Steffen Dettmer <steffen at dett.de>
wrote the initial version of this manual page.
.SH SEE ALSO
.BR syslog (3),
.BR syslog.conf (5),
.BR libnids (3),
.BR pcap (3)
.nf
.BR scanlogd " home page: http://www.openwall.com/scanlogd/"
.BR "Phrack Magazine" ", issue 53, article 13"
scanlogd-2.2.6/scanlogd.c000064400000000000000000000276771060744672400153040ustar00rootroot00000000000000/*
* scanlogd by Solar Designer <solar at openwall.com>.
*
* You're allowed to do whatever you like with this software (including
* re-distribution in any form, with or without modification), provided
* that credit is given where it is due and any modified versions are
* marked as such.
*
* There's absolutely no warranty.
*/

#define _BSD_SOURCE
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <syslog.h>
#include <sys/times.h>
#include <sys/types.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>

#include "params.h"
#include "in.h"

static clock_t scan_delay_threshold, log_delay_threshold;

#define HF_DADDR_CHANGING 0x01
#define HF_SPORT_CHANGING 0x02
#define HF_TOS_CHANGING 0x04
#define HF_TTL_CHANGING 0x08

/*
* Information we keep per each source address.
*/
struct host {
struct host *next; /* Next entry with the same hash */
clock_t timestamp; /* Last update time */
time_t start; /* Entry creation time */
struct in_addr saddr, daddr; /* Source and destination addresses */
unsigned short sport; /* Source port */
int count; /* Number of ports in the list */
int weight; /* Total weight of ports in the list */
unsigned short ports[SCAN_MAX_COUNT - 1]; /* List of ports */
unsigned char tos; /* TOS */
unsigned char ttl; /* TTL */
unsigned char flags_or; /* TCP flags OR mask */
unsigned char flags_and; /* TCP flags AND mask */
unsigned char flags; /* HF_ flags bitmask */
};

/*
* State information.
*/
static struct {
struct host list[LIST_SIZE]; /* List of source addresses */
struct host *hash[HASH_SIZE]; /* Hash: pointers into the list */
int index; /* Oldest entry to be replaced */
} state;

/*
* Convert an IP address into a hash table index.
*/
static int hashfunc(struct in_addr addr)
{
unsigned int value;
int hash;

value = addr.s_addr;
hash = 0;
do {
hash ^= value;
} while ((value >>= HASH_LOG));

return hash & (HASH_SIZE - 1);
}

/*
* Log this port scan.
*/
static void do_log(struct host *info)
{
int limit;
char s_saddr[32];
char s_daddr[64 + 8 * SCAN_MAX_COUNT];
char s_flags[16];
char s_tos[16];
char s_ttl[16];
char s_time[32];
int index, size;
unsigned char mask;

/* We try to log everything we can at first, then remove port numbers one
* by one if necessary until we fit into the maximum allowed length */
limit = info->count;
prepare:

/* Source address and port number, if fixed */
snprintf(s_saddr, sizeof(s_saddr),
(info->flags & HF_SPORT_CHANGING) ? "%s" : "%s:%u",
inet_ntoa(info->saddr),
(unsigned int)ntohs(info->sport));

/* Destination address */
snprintf(s_daddr, sizeof(s_daddr), "%s%s ports ",
inet_ntoa(info->daddr),
(info->flags & HF_DADDR_CHANGING) ? " and others," : "");

/* Scanned port numbers */
for (index = 0; index < limit; index++) {
size = strlen(s_daddr);
#ifdef LOG_MAX_LENGTH
if (size >= LOG_MAX_LENGTH) {
limit = index;
break;
}
#endif
snprintf(s_daddr + size, sizeof(s_daddr) - size,
"%u, ", (unsigned int)ntohs(info->ports[index]));
}

/* TCP flags: lowercase letters for "always clear", uppercase for "always
* set", and question marks for "sometimes set". */
for (index = 0; index < 8; index++) {
mask = 1 << index;
if ((info->flags_or & mask) == (info->flags_and & mask)) {
s_flags[index] = "fsrpauxy"[index];
if (info->flags_or & mask)
s_flags[index] =
toupper((int)(unsigned char)s_flags[index]);
} else
s_flags[index] = '?';
}
s_flags[index] = 0;

/* TOS, if fixed */
snprintf(s_tos, sizeof(s_tos),
(info->flags & HF_TOS_CHANGING) ? "" : ", TOS %02x",
(unsigned int)info->tos);

/* TTL, if fixed */
snprintf(s_ttl, sizeof(s_ttl),
(info->flags & HF_TTL_CHANGING) ? "" : ", TTL %u",
(unsigned int)info->ttl);

/* Scan start time */
strftime(s_time, sizeof(s_time), "%X", localtime(&info->start));

/* Check against the length limit, and possibly re-format everything */
#ifdef LOG_MAX_LENGTH
if (strlen(s_saddr) + strlen(s_daddr) +
strlen(s_tos) + strlen(s_ttl) + strlen(s_time) +
(4 + 5 + 8 + 2) > LOG_MAX_LENGTH) {
if (--limit > 0) goto prepare;
}
#endif

/* Log it all */
syslog(SYSLOG_LEVEL,
"%s to %s..., %s%s%s @%s",
s_saddr, s_daddr, s_flags, s_tos, s_ttl, s_time);
}

/*
* Log this port scan unless we're being flooded.
*/
static void safe_log(struct host *info)
{
static clock_t last = 0;
static int count = 0;
clock_t now;

now = info->timestamp;
if (now - last > log_delay_threshold || now < last) count = 0;
if (++count <= LOG_COUNT_THRESHOLD + 1) last = now;

if (count <= LOG_COUNT_THRESHOLD)
do_log(info);
else if (count == LOG_COUNT_THRESHOLD + 1)
syslog(SYSLOG_LEVEL, "More possible port scans follow");
}

/*
* Process a TCP packet.
*/
static void process_packet(struct header *packet, int size)
{
struct ip *ip;
struct tcphdr *tcp;
struct in_addr addr;
unsigned short port;
unsigned char flags;
struct tms buf;
clock_t now;
struct host *current, *last, **head;
int hash, index, count;

/* Get the IP and TCP headers */
ip = &packet->ip;
tcp = (struct tcphdr *)((char *)packet + ((int)ip->ip_hl << 2));

/* Sanity check */
if (ip->ip_p != IPPROTO_TCP || (ip->ip_off & htons(IP_OFFMASK)) ||
(char *)tcp + sizeof(struct tcphdr) > (char *)packet + size)
return;

/* Get the source address, destination port, and TCP flags */
addr = ip->ip_src;
port = tcp->th_dport;
flags = tcp->th_flags;

/* We're using IP address 0.0.0.0 for a special purpose here, so don't let
* them spoof us. */
if (!addr.s_addr) return;

/* Use times(2) here not to depend on someone setting the time while we're
* running; we need to be careful with possible return value overflows. */
now = times(&buf);

/* Do we know this source address already? */
count = 0;
last = NULL;
if ((current = *(head = &state.hash[hash = hashfunc(addr)])))
do {
if (current->saddr.s_addr == addr.s_addr) break;
count++;
if (current->next) last = current;
} while ((current = current->next));

/* We know this address, and the entry isn't too old. Update it. */
if (current)
if (now - current->timestamp <= scan_delay_threshold &&
now >= current->timestamp) {
/* Just update the TCP flags if we've seen this port already */
for (index = 0; index < current->count; index++)
if (current->ports[index] == port) {
current->flags_or |= flags;
current->flags_and &= flags;
return;
}

/* ACK and/or RST to a new port? This could be an outgoing connection. */
if (flags & (TH_ACK | TH_RST)) return;

/* Packet to a new port, and not ACK: update the timestamp */
current->timestamp = now;

/* Logged this scan already? Then leave. */
if (current->weight >= SCAN_WEIGHT_THRESHOLD) return;

/* Update the TCP flags */
current->flags_or |= flags;
current->flags_and &= flags;

/* Specify if destination address, source port, TOS, or TTL are not fixed */
if (current->daddr.s_addr != ip->ip_dst.s_addr)
current->flags |= HF_DADDR_CHANGING;
if (current->sport != tcp->th_sport)
current->flags |= HF_SPORT_CHANGING;
if (current->tos != ip->ip_tos)
current->flags |= HF_TOS_CHANGING;
if (current->ttl != ip->ip_ttl)
current->flags |= HF_TTL_CHANGING;

/* Update the total weight */
current->weight += (ntohs(port) < 1024) ?
PORT_WEIGHT_PRIV : PORT_WEIGHT_HIGH;

/* Got enough destination ports to decide that this is a scan? Then log it. */
if (current->weight >= SCAN_WEIGHT_THRESHOLD) {
safe_log(current);
return;
}

/* Remember the new port */
if (current->count < SCAN_MAX_COUNT)
current->ports[current->count++] = port;

return;
}

/* We know this address, but the entry is outdated. Mark it unused and
* remove from the hash table. We'll allocate a new entry instead since
* this one might get re-used too soon. */
if (current) {
current->saddr.s_addr = 0;

if (last)
last->next = last->next->next;
else if (*head)
*head = (*head)->next;
last = NULL;
}

/* We don't need an ACK from a new source address */
if (flags & TH_ACK) return;

/* Got too many source addresses with the same hash value? Then remove the
* oldest one from the hash table, so that they can't take too much of our
* CPU time even with carefully chosen spoofed IP addresses. */
if (count >= HASH_MAX && last) last->next = NULL;

/* We're going to re-use the oldest list entry, so remove it from the hash
* table first (if it is really already in use, and isn't removed from the
* hash table already because of the HASH_MAX check above). */

/* First, find it */
if (state.list[state.index].saddr.s_addr)
head = &state.hash[hashfunc(state.list[state.index].saddr)];
else
head = &last;
last = NULL;
if ((current = *head))
do {
if (current == &state.list[state.index]) break;
last = current;
} while ((current = current->next));

/* Then, remove it */
if (current) {
if (last)
last->next = last->next->next;
else if (*head)
*head = (*head)->next;
}

/* Get our list entry */
current = &state.list[state.index++];
if (state.index >= LIST_SIZE) state.index = 0;

/* Link it into the hash table */
head = &state.hash[hash];
current->next = *head;
*head = current;

/* And fill in the fields */
current->timestamp = now;
current->start = time(NULL);
current->saddr = addr;
current->daddr = ip->ip_dst;
current->sport = tcp->th_sport;
current->count = 1;
current->weight = (ntohs(port) < 1024) ?
PORT_WEIGHT_PRIV : PORT_WEIGHT_HIGH;
current->ports[0] = port;
current->tos = ip->ip_tos;
current->ttl = ip->ip_ttl;
current->flags_or = current->flags_and = flags;
current->flags = 0;
}

/*
* Simple, but we only expect errors at startup, so this should suffice.
*/
void pexit(char *name)
{
perror(name);
exit(1);
}

#ifdef SCANLOGD_USER
static void drop_root(void)
{
struct passwd *pw;
gid_t groups[2];

errno = 0;
if (!(pw = getpwnam(SCANLOGD_USER))) {
fprintf(stderr,
"getpwnam(\"" SCANLOGD_USER "\"): %s\n",
errno ? strerror(errno) : "No such user");
exit(1);
}

#ifdef SCANLOGD_CHROOT
if (chroot(SCANLOGD_CHROOT)) return pexit("chroot");
if (chdir("/")) return pexit("chdir");
#endif

groups[0] = groups[1] = pw->pw_gid;
if (setgroups(1, groups)) pexit("setgroups");
if (setgid(pw->pw_gid)) pexit("setgid");
if (setuid(pw->pw_uid)) pexit("setuid");
}
#elif defined(SCANLOGD_CHROOT)
#warning SCANLOGD_CHROOT makes no sense without SCANLOGD_USER; ignored.
#endif

/*
* Hmm, what could this be?
*/
int main(void)
{
int dev_null_fd;
clock_t clk_tck;

/* Initialize the packet capture interface */
if (in_init()) return 1;

/* Prepare for daemonizing */
chdir("/");
setsid();

/* Must do these before chroot'ing */
tzset();
openlog(SYSLOG_IDENT, LOG_NDELAY, SYSLOG_FACILITY);
dev_null_fd = open("/dev/null", O_RDONLY);

/* Also do this early - who knows what this system's sysconf() relies upon */
#if defined(_SC_CLK_TCK) || !defined(CLK_TCK)
clk_tck = sysconf(_SC_CLK_TCK);
#else
clk_tck = CLK_TCK;
#endif
scan_delay_threshold = SCAN_DELAY_THRESHOLD * clk_tck;
log_delay_threshold = LOG_DELAY_THRESHOLD * clk_tck;

/* We can drop root now */
#ifdef SCANLOGD_USER
drop_root();
#endif

/* Become a daemon */
switch (fork()) {
case -1:
pexit("fork");

case 0:
break;

default:
/* in_init() could have registered an atexit(3) function to restore the
* interface, but this is not a real exit, yet (in fact, we're starting
* up), so we use _exit(2) rather than exit(3) here */
_exit(0);
}

setsid();

/* Just assume that stdin, stdout, and stderr fd's were open at startup and
* thus are indeed not allocated to anything else. */
if (dev_null_fd >= 0) {
dup2(dev_null_fd, STDIN_FILENO);
dup2(dev_null_fd, STDOUT_FILENO);
dup2(dev_null_fd, STDERR_FILENO);
if (dev_null_fd >= 3) close(dev_null_fd);
}

/* Initialize the state. All source IP addresses are set to 0.0.0.0, which
* means the list entries aren't in use yet. */
memset(&state, 0, sizeof(state));

/* Let's start */
in_run(process_packet);

/* We shouldn't reach this */
return 1;
}
scanlogd-2.2.6/scanlogd.init000064400000000000000000000013001060744672400157740ustar00rootroot00000000000000#!/bin/sh
# $Owl$
#
# chkconfig: - 35 85
# description: \
# scanlogd detects and logs TCP port scans.
# processname: scanlogd

# Source function library.
. /etc/rc.d/init.d/functions

OWL_STARTUP_ENABLE=1

case "$1" in
start)
if [ "0$OWL_STARTUP_VERSION" -ge 3 ]; then
daemon --expect-user scanlogd scanlogd
else
daemon scanlogd
fi
;;
stop)
if [ "0$OWL_STARTUP_VERSION" -ge 3 ]; then
killproc --expect-user scanlogd scanlogd
else
killproc scanlogd
fi
;;
restart)
$0 stop
$0 start
;;
status)
if [ "0$OWL_STARTUP_VERSION" -ge 3 ]; then
status --expect-user scanlogd scanlogd
else
status scanlogd
fi
;;
*)
echo "Usage: scanlogd {start|stop|restart|status}"
exit 1
esac

exit $?
scanlogd-2.2.6/scanlogd.spec000064400000000000000000000064371060744672400160030ustar00rootroot00000000000000# $Owl$

Summary: A tool to detect and log TCP port scans.
Name: scanlogd
Version: 2.2.6
Release: owl1
License: relaxed BSD and (L)GPL-compatible
Group: System Environment/Daemons
URL: http://www.openwall.com/scanlogd/
Source: ftp://ftp.openwall.com/pub/projects/scanlogd/scanlogd-%version.tar.gz
PreReq: /sbin/chkconfig, grep, shadow-utils
BuildRoot: /override/%name-%version

%description
scanlogd detects port scans and writes one line per scan via the syslog(3)
mechanism. If a source address sends multiple packets to different ports
in a short time, the event will be logged.

%prep
%setup -q

%build
%__make linux CFLAGS="-Wall %optflags"

%install
rm -rf %buildroot
mkdir -p %buildroot{%_sbindir,%_mandir/man8,/etc/rc.d/init.d}

install -m 700 scanlogd %buildroot%_sbindir/
install -m 644 scanlogd.8 %buildroot%_mandir/man8/
install -m 700 scanlogd.init %buildroot/etc/rc.d/init.d/scanlogd

%pre
grep -q ^scanlogd: /etc/group || groupadd -g 199 scanlogd
grep -q ^scanlogd: /etc/passwd ||
useradd -g scanlogd -u 199 -d / -s /bin/false -M scanlogd
rm -f /var/run/scanlogd.restart
if [ $1 -ge 2 ]; then
/etc/rc.d/init.d/scanlogd status && touch /var/run/scanlogd.restart || :
/etc/rc.d/init.d/scanlogd stop || :
fi

%post
/sbin/chkconfig --add scanlogd
test -f /var/run/scanlogd.restart && /etc/rc.d/init.d/scanlogd start || :
rm -f /var/run/scanlogd.restart

%preun
if [ $1 -eq 0 ]; then
/etc/rc.d/init.d/scanlogd stop || :
/sbin/chkconfig --del scanlogd
fi

%files
%defattr(-,root,root)
%_sbindir/scanlogd
%_mandir/man8/scanlogd.8*
%config /etc/rc.d/init.d/scanlogd

%changelog
* Sun Mar 05 2006 Solar Designer <solar-at-owl.openwall.com> 2.2.6-owl1
- Use sysconf(_SC_CLK_TCK) instead of CLK_TCK when _SC_CLK_TCK is known to be
available or CLK_TCK is not.

* Thu Jun 10 2004 Solar Designer <solar-at-owl.openwall.com> 2.2.5-owl1
- Dropped the cleanup() stuff because it was not async-signal-safe and
to implement it properly would depend on pcap_breakloop() and on a
non-existent(?) equivalent for it with libnids; this code was only used
when running as root which is something to not do anyway.

* Thu Jun 03 2004 Solar Designer <solar-at-owl.openwall.com> 2.2.4-owl1
- Detach from the tty by opening /dev/null on fd 0, 1, 2.

* Wed Jun 02 2004 Solar Designer <solar-at-owl.openwall.com> 2.2.3-owl1
- When built with libnids or direct libpcap support, use Pavel Kankovsky's
smart pcap expression, with a minor enhancement.
- Explained "any" and "all" magic device names in a comment in params.h.
- Dropped the rlog stuff; librlog was never released.
- chroot to /var/empty.
- Do register scanlogd with chkconfig, but don't enable it for any runlevels
by default.
- Moved this spec file and the init script to under scanlogd/ to include
them in the non-Owl-specific distribution of scanlogd.

* Sun May 23 2004 Solar Designer <solar-at-owl.openwall.com> 2.2.2-owl1
- #include <stdlib.h> for exit(3) (apparently this is actually needed on
FreeBSD).
- Obfuscated e-mail addresses in the man page and sources.

* Wed May 08 2002 Solar Designer <solar-at-owl.openwall.com> 2.2.1-owl1
- Start after syslogd.
- Don't abuse glibc-internal __feature macros.

* Wed Feb 06 2002 Solar Designer <solar-at-owl.openwall.com>
- Enforce our new spec file conventions.

* Thu Jul 12 2001 Solar Designer <solar-at-owl.openwall.com>
- Packaged scanlogd for Owl.
 
дизайн и разработка: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
текущий майнтейнер: Michael Shigorin