/* pdumpq - Pcap Dump for Linux/Netfilter QUEUE * * Copyright (C) 2001 Ian Jones * * 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 void set_signals (void) { v.sa.sa_handler = q_handler; sigemptyset (&v.sa.sa_mask); sigaddset (&v.sa.sa_mask, SIGTERM); sigaddset (&v.sa.sa_mask, SIGHUP); #ifdef MAIL if (v.mail) sigaddset (&v.sa.sa_mask, SIGALRM); #endif /* MAIL */ v.sa.sa_flags = 0; sigaction (SIGTERM, &v.sa, 0); sigaction (SIGHUP, &v.sa, 0); #ifdef MAIL if (v.mail) sigaction (SIGALRM, &v.sa, 0); #endif /* MAIL */ } pid_t is_running (void) { pid_t pid; int err; FILE *fp; if ((fp = fopen (PIDFILE, "r")) != NULL) { fscanf (fp, "%d", &pid); fclose (fp); if (kill (pid, 0) == -1) { err = errno; if (err == EPERM) crash ("KILL:pdumpq"); /* stale pid, remove it */ unlink (PIDFILE); return err == ESRCH ? 0 : -1; } else { /* return pid of running process */ return pid; } } else { if (errno == EACCES) crash ("PIDFILE:pdumpq"); return 0; } } void detach (void) { pid_t pid; int i; FILE *fp; if (pid = is_running ()) { fprintf (stderr, "Process [%d] already running, use '-k' to kill.\n", pid); exit (1); } if (pid = fork ()) { if ((fp = fopen (PIDFILE, "w")) == NULL) crash ("pdumpq"); fprintf (fp, "%d", pid); fclose (fp); exit (0); } if (pid == -1) crash ("fork:pdumpq"); setsid (); #ifndef _SC_OPEN_MAX #define _SC_OPEN_MAX 256 #endif for (i = 0; i < (_SC_OPEN_MAX); i++) close (i); openlog ("pdumpq", LOG_CONS | LOG_PID, LOG_DAEMON); syslog (LOG_INFO, "deamon started"); v.daemon = 2; } void ipq_init (void) { v.h = ipq_create_handle (0); if (!v.h || (ipq_set_mode (v.h, IPQ_COPY_PACKET, 0) < 0)) { ipq_perror ("create_handle"); fprintf (stderr, "Is module ip_queue loaded?"); ipq_destroy_handle (v.h); exit (1); } } void process_pkt (ipq_packet_msg_t * m, unsigned int verdict) { if (!dump_pkt (m, v.file)) crash ("dump_pkt"); #ifdef MAIL if (v.mail) mail_enqueue (m); #endif /* MAIL */ ipq_set_verdict (v.h, m->packet_id, verdict, 0, NULL); } int open_file (char *fn) { int fd; if (strcmp (v.dumpfile, "stdout") == 0) { v.file = stdout; return write_file_header (v.file); } rotate (fn); /* rotate logs on restart */ if ( (fd = open (fn, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) == -1) return -1; if ((v.file = fdopen (fd, "a")) == NULL) return -1; return write_file_header (v.file); } /* signal handler */ void q_handler (int sig) { if (sig == SIGTERM || sig == SIGHUP) { ipq_destroy_handle (v.h); /* signal safe? */ unlink (PIDFILE); syslog (LOG_INFO, "deamon killed"); exit (0); } #ifdef MAIL if (v.mail && sig == SIGALRM && queue->num > 0) queue->flush = 1; #endif /*MAIL */ } void crash (char *error) { if (v.daemon != 2) perror (error); else syslog (LOG_INFO, "EXITING! %s: %s", error, errno > sys_nerr - 1 ? "Unknown Error" : sys_errlist[errno]); exit (1); } /* rotate dump files using an incrementing suffix */ void rotate (char *fn) { int stack; char *name, *old; if (access (fn, R_OK) == -1) { if (errno == ENOENT) return; else crash ("rotating dumpfile:pdumpq"); } if (v.rotate == 0) { if (unlink (fn) == -1 && errno == EACCES) crash ("unable to clobber:pdumpq"); return; } stack = 0; while (1) { /* note: stack autoincrement */ asprintf (&name, "%s.%d", fn, ++stack); if (access (name, R_OK) == -1) { if (errno != ENOENT) crash ("rotating dumpfile:pdumpq"); while (stack) { if (stack == 1) { rename (fn, name); free (name); name = fn; stack--; } else { asprintf (&old, "%s.%d", fn, --stack); if (stack + 1 == v.rotate) { unlink (old); } else if (stack < v.rotate) rename (old, name); free (name); name = old; } } break; } free (name); } } int gmt2local (time_t t) /* ripped from snort, from tcpdump */ { register int dt, dir; register struct tm *gmt, *loc; struct tm sgmt; if (t == 0) t = time (NULL); gmt = &sgmt; *gmt = *gmtime (&t); loc = localtime (&t); dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + (loc->tm_min - gmt->tm_min) * 60; dir = loc->tm_year - gmt->tm_year; if (dir == 0) dir = loc->tm_yday - gmt->tm_yday; dt += dir * 24 * 60 * 60; return (dt); }