"Fossies" - the Fresh Open Source Software Archive

Member "scanlogd-2.2.8/scanlogd.c" (10 Mar 2021, 11982 Bytes) of package /linux/misc/scanlogd-2.2.8.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "scanlogd.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.2.7_vs_2.2.8.

    1 /*
    2  * Copyright (c) 1998-2012 by Solar Designer
    3  * See LICENSE
    4  */
    5 
    6 #define _BSD_SOURCE
    7 #define _DEFAULT_SOURCE
    8 #include <stdio.h>
    9 #include <fcntl.h>
   10 #include <stdlib.h>
   11 #include <unistd.h>
   12 #include <signal.h>
   13 #include <string.h>
   14 #include <ctype.h>
   15 #include <errno.h>
   16 #include <pwd.h>
   17 #include <grp.h>
   18 #include <time.h>
   19 #include <syslog.h>
   20 #include <sys/times.h>
   21 #include <sys/types.h>
   22 #include <netinet/in_systm.h>
   23 #include <netinet/in.h>
   24 #include <netinet/ip.h>
   25 #include <netinet/tcp.h>
   26 #include <arpa/inet.h>
   27 
   28 #include "params.h"
   29 #include "in.h"
   30 
   31 static clock_t scan_delay_threshold, log_delay_threshold;
   32 
   33 #define HF_DADDR_CHANGING       0x01
   34 #define HF_SPORT_CHANGING       0x02
   35 #define HF_TOS_CHANGING         0x04
   36 #define HF_TTL_CHANGING         0x08
   37 
   38 /*
   39  * Information we keep per each source address.
   40  */
   41 struct host {
   42     struct host *next;      /* Next entry with the same hash */
   43     clock_t timestamp;      /* Last update time */
   44     time_t start;           /* Entry creation time */
   45     struct in_addr saddr, daddr;    /* Source and destination addresses */
   46     unsigned short sport;       /* Source port */
   47     int count;          /* Number of ports in the list */
   48     int weight;         /* Total weight of ports in the list */
   49     unsigned short ports[SCAN_MAX_COUNT - 1];   /* List of ports */
   50     unsigned char tos;      /* TOS */
   51     unsigned char ttl;      /* TTL */
   52     unsigned char flags_or;     /* TCP flags OR mask */
   53     unsigned char flags_and;    /* TCP flags AND mask */
   54     unsigned char flags;        /* HF_ flags bitmask */
   55 };
   56 
   57 /*
   58  * State information.
   59  */
   60 static struct {
   61     struct host list[LIST_SIZE];    /* List of source addresses */
   62     struct host *hash[HASH_SIZE];   /* Hash: pointers into the list */
   63     int index;          /* Oldest entry to be replaced */
   64 } state;
   65 
   66 /*
   67  * Convert an IP address into a hash table index.
   68  */
   69 static int hashfunc(struct in_addr addr)
   70 {
   71     unsigned int value;
   72     int hash;
   73 
   74     value = addr.s_addr;
   75     hash = 0;
   76     do {
   77         hash ^= value;
   78     } while ((value >>= HASH_LOG));
   79 
   80     return hash & (HASH_SIZE - 1);
   81 }
   82 
   83 /*
   84  * Log this port scan.
   85  */
   86 static void do_log(struct host *info)
   87 {
   88     int limit;
   89     char s_saddr[32];
   90     char s_daddr[64 + 8 * SCAN_MAX_COUNT];
   91     char s_flags[16];
   92     char s_tos[16];
   93     char s_ttl[16];
   94     char s_time[32];
   95     int index, size;
   96     unsigned char mask;
   97 
   98 /* We try to log everything we can at first, then remove port numbers one
   99  * by one if necessary until we fit into the maximum allowed length */
  100     limit = info->count;
  101 prepare:
  102 
  103 /* Source address and port number, if fixed */
  104     snprintf(s_saddr, sizeof(s_saddr),
  105         (info->flags & HF_SPORT_CHANGING) ? "%s" : "%s:%u",
  106         inet_ntoa(info->saddr),
  107         (unsigned int)ntohs(info->sport));
  108 
  109 /* Destination address */
  110     snprintf(s_daddr, sizeof(s_daddr), "%s%s ports ",
  111         inet_ntoa(info->daddr),
  112         (info->flags & HF_DADDR_CHANGING) ? " and others," : "");
  113 
  114 /* Scanned port numbers */
  115     for (index = 0; index < limit; index++) {
  116         size = strlen(s_daddr);
  117 #ifdef LOG_MAX_LENGTH
  118         if (size >= LOG_MAX_LENGTH) {
  119             limit = index;
  120             break;
  121         }
  122 #endif
  123         snprintf(s_daddr + size, sizeof(s_daddr) - size,
  124             "%u, ", (unsigned int)ntohs(info->ports[index]));
  125     }
  126 
  127 /* TCP flags: lowercase letters for "always clear", uppercase for "always
  128  * set", and question marks for "sometimes set". */
  129     for (index = 0; index < 8; index++) {
  130         mask = 1 << index;
  131         if ((info->flags_or & mask) == (info->flags_and & mask)) {
  132             s_flags[index] = "fsrpauxy"[index];
  133             if (info->flags_or & mask)
  134                 s_flags[index] =
  135                     toupper((int)(unsigned char)s_flags[index]);
  136         } else
  137             s_flags[index] = '?';
  138     }
  139     s_flags[index] = 0;
  140 
  141 /* TOS, if fixed */
  142     snprintf(s_tos, sizeof(s_tos),
  143         (info->flags & HF_TOS_CHANGING) ? "" : ", TOS %02x",
  144         (unsigned int)info->tos);
  145 
  146 /* TTL, if fixed */
  147     snprintf(s_ttl, sizeof(s_ttl),
  148         (info->flags & HF_TTL_CHANGING) ? "" : ", TTL %u",
  149         (unsigned int)info->ttl);
  150 
  151 /* Scan start time */
  152     strftime(s_time, sizeof(s_time), "%X", localtime(&info->start));
  153 
  154 /* Check against the length limit, and possibly re-format everything */
  155 #ifdef LOG_MAX_LENGTH
  156     if (strlen(s_saddr) + strlen(s_daddr) +
  157         strlen(s_tos) + strlen(s_ttl) + strlen(s_time) +
  158         (4 + 5 + 8 + 2) > LOG_MAX_LENGTH) {
  159         if (--limit > 0) goto prepare;
  160     }
  161 #endif
  162 
  163 /* Log it all */
  164     syslog(SYSLOG_LEVEL,
  165         "%s to %s..., %s%s%s @%s",
  166         s_saddr, s_daddr, s_flags, s_tos, s_ttl, s_time);
  167 }
  168 
  169 /*
  170  * Log this port scan unless we're being flooded.
  171  */
  172 static void safe_log(struct host *info)
  173 {
  174     static clock_t last = 0;
  175     static int count = 0;
  176     clock_t now;
  177 
  178     now = info->timestamp;
  179     if (now - last > log_delay_threshold || now < last) count = 0;
  180     if (++count <= LOG_COUNT_THRESHOLD + 1) last = now;
  181 
  182     if (count <= LOG_COUNT_THRESHOLD)
  183         do_log(info);
  184     else if (count == LOG_COUNT_THRESHOLD + 1)
  185         syslog(SYSLOG_LEVEL, "More possible port scans follow");
  186 }
  187 
  188 /*
  189  * Process a TCP packet.
  190  */
  191 static void process_packet(struct header *packet, int size)
  192 {
  193     struct ip *ip;
  194     struct tcphdr *tcp;
  195     struct in_addr addr;
  196     unsigned short port;
  197     unsigned char flags;
  198     struct tms buf;
  199     clock_t now;
  200     struct host *current, *last, **head;
  201     int hash, index, count;
  202 
  203 /* Get the IP and TCP headers */
  204     ip = &packet->ip;
  205     tcp = (struct tcphdr *)((char *)packet + ((int)ip->ip_hl << 2));
  206 
  207 /* Sanity check */
  208     if (ip->ip_p != IPPROTO_TCP || (ip->ip_off & htons(IP_OFFMASK)) ||
  209         (char *)tcp + sizeof(struct tcphdr) > (char *)packet + size)
  210         return;
  211 
  212 /* Get the source address, destination port, and TCP flags */
  213     addr = ip->ip_src;
  214     port = tcp->th_dport;
  215     flags = tcp->th_flags;
  216 
  217 /* We're using IP address 0.0.0.0 for a special purpose here, so don't let
  218  * them spoof us. */
  219     if (!addr.s_addr) return;
  220 
  221 /* Use times(2) here not to depend on someone setting the time while we're
  222  * running; we need to be careful with possible return value overflows. */
  223     now = times(&buf);
  224 
  225 /* Do we know this source address already? */
  226     count = 0;
  227     last = NULL;
  228     if ((current = *(head = &state.hash[hash = hashfunc(addr)])))
  229     do {
  230         if (current->saddr.s_addr == addr.s_addr) break;
  231         count++;
  232         if (current->next) last = current;
  233     } while ((current = current->next));
  234 
  235 /* We know this address, and the entry isn't too old.  Update it. */
  236     if (current)
  237     if (now - current->timestamp <= scan_delay_threshold &&
  238         now >= current->timestamp) {
  239 /* Just update the TCP flags if we've seen this port already */
  240         for (index = 0; index < current->count; index++)
  241         if (current->ports[index] == port) {
  242             current->flags_or |= flags;
  243             current->flags_and &= flags;
  244             return;
  245         }
  246 
  247 /* ACK and/or RST to a new port?  This could be an outgoing connection. */
  248         if (flags & (TH_ACK | TH_RST)) return;
  249 
  250 /* Packet to a new port, and not ACK: update the timestamp */
  251         current->timestamp = now;
  252 
  253 /* Logged this scan already?  Then leave. */
  254         if (current->weight >= SCAN_WEIGHT_THRESHOLD) return;
  255 
  256 /* Update the TCP flags */
  257         current->flags_or |= flags;
  258         current->flags_and &= flags;
  259 
  260 /* Specify if destination address, source port, TOS, or TTL are not fixed */
  261         if (current->daddr.s_addr != ip->ip_dst.s_addr)
  262             current->flags |= HF_DADDR_CHANGING;
  263         if (current->sport != tcp->th_sport)
  264             current->flags |= HF_SPORT_CHANGING;
  265         if (current->tos != ip->ip_tos)
  266             current->flags |= HF_TOS_CHANGING;
  267         if (current->ttl != ip->ip_ttl)
  268             current->flags |= HF_TTL_CHANGING;
  269 
  270 /* Update the total weight */
  271         current->weight += (ntohs(port) < 1024) ?
  272             PORT_WEIGHT_PRIV : PORT_WEIGHT_HIGH;
  273 
  274 /* Got enough destination ports to decide that this is a scan?  Then log it. */
  275         if (current->weight >= SCAN_WEIGHT_THRESHOLD) {
  276             safe_log(current);
  277             return;
  278         }
  279 
  280 /* Remember the new port */
  281         if (current->count < SCAN_MAX_COUNT - 1)
  282             current->ports[current->count++] = port;
  283 
  284         return;
  285     }
  286 
  287 /* We know this address, but the entry is outdated.  Mark it unused and
  288  * remove from the hash table.  We'll allocate a new entry instead since
  289  * this one might get re-used too soon. */
  290     if (current) {
  291         current->saddr.s_addr = 0;
  292 
  293         if (last)
  294             last->next = last->next->next;
  295         else if (*head)
  296             *head = (*head)->next;
  297         last = NULL;
  298     }
  299 
  300 /* We don't need an ACK from a new source address */
  301     if (flags & TH_ACK) return;
  302 
  303 /* Got too many source addresses with the same hash value?  Then remove the
  304  * oldest one from the hash table, so that they can't take too much of our
  305  * CPU time even with carefully chosen spoofed IP addresses. */
  306     if (count >= HASH_MAX && last) last->next = NULL;
  307 
  308 /* We're going to re-use the oldest list entry, so remove it from the hash
  309  * table first (if it is really already in use, and isn't removed from the
  310  * hash table already because of the HASH_MAX check above). */
  311 
  312 /* First, find it */
  313     if (state.list[state.index].saddr.s_addr)
  314         head = &state.hash[hashfunc(state.list[state.index].saddr)];
  315     else
  316         head = &last;
  317     last = NULL;
  318     if ((current = *head))
  319     do {
  320         if (current == &state.list[state.index]) break;
  321         last = current;
  322     } while ((current = current->next));
  323 
  324 /* Then, remove it */
  325     if (current) {
  326         if (last)
  327             last->next = last->next->next;
  328         else if (*head)
  329             *head = (*head)->next;
  330     }
  331 
  332 /* Get our list entry */
  333     current = &state.list[state.index++];
  334     if (state.index >= LIST_SIZE) state.index = 0;
  335 
  336 /* Link it into the hash table */
  337     head = &state.hash[hash];
  338     current->next = *head;
  339     *head = current;
  340 
  341 /* And fill in the fields */
  342     current->timestamp = now;
  343     current->start = time(NULL);
  344     current->saddr = addr;
  345     current->daddr = ip->ip_dst;
  346     current->sport = tcp->th_sport;
  347     current->count = 1;
  348     current->weight = (ntohs(port) < 1024) ?
  349         PORT_WEIGHT_PRIV : PORT_WEIGHT_HIGH;
  350     current->ports[0] = port;
  351     current->tos = ip->ip_tos;
  352     current->ttl = ip->ip_ttl;
  353     current->flags_or = current->flags_and = flags;
  354     current->flags = 0;
  355 }
  356 
  357 /*
  358  * Simple, but we only expect errors at startup, so this should suffice.
  359  */
  360 void pexit(char *name)
  361 {
  362     perror(name);
  363     exit(1);
  364 }
  365 
  366 #ifdef SCANLOGD_USER
  367 static void drop_root(void)
  368 {
  369     struct passwd *pw;
  370     gid_t groups[2];
  371 
  372     errno = 0;
  373     if (!(pw = getpwnam(SCANLOGD_USER))) {
  374         fprintf(stderr,
  375             "getpwnam(\"" SCANLOGD_USER "\"): %s\n",
  376             errno ? strerror(errno) : "No such user");
  377         exit(1);
  378     }
  379 
  380 #ifdef SCANLOGD_CHROOT
  381     if (chroot(SCANLOGD_CHROOT)) return pexit("chroot");
  382     if (chdir("/")) return pexit("chdir");
  383 #endif
  384 
  385     groups[0] = groups[1] = pw->pw_gid;
  386     if (setgroups(1, groups)) pexit("setgroups");
  387     if (setgid(pw->pw_gid)) pexit("setgid");
  388     if (setuid(pw->pw_uid)) pexit("setuid");
  389 }
  390 #elif defined(SCANLOGD_CHROOT)
  391 #warning SCANLOGD_CHROOT makes no sense without SCANLOGD_USER; ignored.
  392 #endif
  393 
  394 /*
  395  * Hmm, what could this be?
  396  */
  397 int main(void)
  398 {
  399     int dev_null_fd;
  400     clock_t clk_tck;
  401 
  402 /* Initialize the packet capture interface */
  403     if (in_init()) return 1;
  404 
  405 /* Prepare for daemonizing */
  406     chdir("/");
  407     setsid();
  408 
  409 /* Must do these before chroot'ing */
  410     tzset();
  411     openlog(SYSLOG_IDENT, LOG_NDELAY, SYSLOG_FACILITY);
  412     dev_null_fd = open("/dev/null", O_RDONLY);
  413 
  414 /* Also do this early - who knows what this system's sysconf() relies upon */
  415 #if defined(_SC_CLK_TCK) || !defined(CLK_TCK)
  416     clk_tck = sysconf(_SC_CLK_TCK);
  417 #else
  418     clk_tck = CLK_TCK;
  419 #endif
  420     scan_delay_threshold = SCAN_DELAY_THRESHOLD * clk_tck;
  421     log_delay_threshold = LOG_DELAY_THRESHOLD * clk_tck;
  422 
  423 /* We can drop root now */
  424 #ifdef SCANLOGD_USER
  425     drop_root();
  426 #endif
  427 
  428 /* Become a daemon */
  429     switch (fork()) {
  430     case -1:
  431         pexit("fork");
  432 
  433     case 0:
  434         break;
  435 
  436     default:
  437 /* in_init() could have registered an atexit(3) function to restore the
  438  * interface, but this is not a real exit, yet (in fact, we're starting
  439  * up), so we use _exit(2) rather than exit(3) here */
  440         _exit(0);
  441     }
  442 
  443     setsid();
  444 
  445 /* Just assume that stdin, stdout, and stderr fd's were open at startup and
  446  * thus are indeed not allocated to anything else. */
  447     if (dev_null_fd >= 0) {
  448         dup2(dev_null_fd, STDIN_FILENO);
  449         dup2(dev_null_fd, STDOUT_FILENO);
  450         dup2(dev_null_fd, STDERR_FILENO);
  451         if (dev_null_fd >= 3) close(dev_null_fd);
  452     }
  453 
  454 /* Initialize the state.  All source IP addresses are set to 0.0.0.0, which
  455  * means the list entries aren't in use yet. */
  456     memset(&state, 0, sizeof(state));
  457 
  458 /* Let's start */
  459     in_run(process_packet);
  460 
  461 /* We shouldn't reach this */
  462     return 1;
  463 }