tcpspy-1.7d.orig/0040775000175000017500000000000007425035777013720 5ustar spectraspectratcpspy-1.7d.orig/LICENCE0100644000175000017500000000277507305704534014702 0ustar spectraspectraThe following statement applies to tcpspy: Copyright (c) 2000, 2001 Tim J. Robbins. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. (The following line is not part of this licence) $Id: LICENCE,v 1.2 2001/01/05 14:06:02 fyre Stab $ tcpspy-1.7d.orig/Makefile0100644000175000017500000000253207305704422015340 0ustar spectraspectra# Makefile for tcpspy # Tim J. Robbins, 2000 # $Id: Makefile,v 2.5 2001/04/25 01:40:17 tim Stab $ # You may specify the syslog facility to use here. If in doubt, use LOG_DAEMON # or LOG_LOCAL[0-7]. See the syslog(3) manual page for a complete list of # facilities. CFLAGS+=-DFACILITY=LOG_LOCAL1 # You may also override the default number of buckets in the connection table # here, but this not usually necessary. #CFLAGS+=-DCONNTABLE_BUCKETS=5003 # Comment out the following line to enable debugging (slower!) CFLAGS+=-DNDEBUG # Add any other options for the compiler here CFLAGS+=-O2 -Wall -W default: tcpspy all: tcpspy doc tcpspy: log.o rule_lexer.o rule_grammar.o rule.o tcpspy.o gcc log.o rule_lexer.o rule_grammar.o rule.o tcpspy.o -o tcpspy log.o: log.c rule_lexer.o: rule_lexer.c rule_lexer.c: rule_grammar.c rule_lexer.l flex -Prule -orule_lexer.c rule_lexer.l rule_grammar.o: rule_grammar.c rule_grammar.c: rule_grammar.y bison -p rule -o rule_grammar.c -d rule_grammar.y rule.o: rule.c tcpspy.o: tcpspy.c doc: groff -Tps -man tcpspy.8 >tcpspy.ps ps2pdf tcpspy.ps tcpspy.pdf clean: rm -f log.o rule_lexer.o rule_grammar.o rule_lexer.c \ rule_grammar.c rule_grammar.h rule.o tcpspy.o tcpspy \ tcpspy.ps tcpspy.pdf install: tcpspy install -m 644 -D tcpspy.8 /usr/local/man/man8/tcpspy.8 install -m 755 -D tcpspy /usr/local/sbin/tcpspy tcpspy-1.7d.orig/README0100644000175000017500000000160607305704534014565 0ustar spectraspectraREADME for tcpspy 1.7 --------------------- 1. Introduction tcpspy is an administrators' tool that logs selecting incoming and outgoing TCP/IP connections. Please see the tcpspy(8) manual page for an extended description; `man 8 tcpspy' after installation, or `man ./tcpspy.8' now. 2. Compilation and Installation Instructions `make' to compile tcpspy, then `make install' to install it (to /usr/local by default, change the Makefile if you need it installed elsewhere). Provided you have the correct tools, `make doc' will convert the manual page to HTML, PostScript and PDF formats: groff and ghostscript (ps2pdf). 3. Running tcpspy Read the manual page. If you're not patient enough for that, type `tcpspy' and see what happens. 4. Copyright, Licence, Warranty See the file LICENCE for details. Tim J. Robbins $Id: README,v 2.7 2001/06/01 12:20:59 tim Stab $ tcpspy-1.7d.orig/log.c0100644000175000017500000001110107305704422014615 0ustar spectraspectra/* * log.c - Logging routines * * This file is part of tcpspy, a TCP/IP connection monitor. * * Copyright (c) 2000, 2001 Tim J. Robbins. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $Id: log.c,v 1.5 2001/01/05 14:05:47 fyre Stab $ */ #include #include #include #include #include #include #include #include "rcsid.h" RCSID("$Id: log.c,v 1.5 2001/01/05 14:05:47 fyre Stab $"); /* * Exported functions. */ void log_set_syslog (void); void log_set_stdout (void); void logmsg (const char *fmt, ...); void vlogmsg (const char *fmt, va_list ap); void panic (const char *fmt, ...); void vpanic (const char *fmt, va_list ap); /* * Internal helper functions. */ static void vlogmsg_i (int panic, const char *fmt, va_list ap); /* * Methods of logging, set via log_set_foo () family of functions. LM_SYSLOG * is the default. */ #define LM_SYSLOG 0 /* via syslog(3) */ #define LM_STDOUT 1 /* standard output */ static int logmethod = LM_SYSLOG; /* * log_set_syslog () * * Log via syslog(3). openlog () should be called before any of the logging * routines to set the ident and facility. */ void log_set_syslog (void) { logmethod = LM_SYSLOG; } /* * log_set_stdout () * * Log to standard output. */ void log_set_stdout (void) { logmethod = LM_STDOUT; } /* * logmsg () * * printf-style function to log messages of normal priority. */ void logmsg (const char *fmt, ...) { va_list ap; va_start (ap, fmt); vlogmsg (fmt, ap); va_end (ap); } /* * vlogmsg () * * vprintf-style function to log messages of normal priority. */ void vlogmsg (const char *fmt, va_list ap) { vlogmsg_i (0, fmt, ap); } /* * panic () * * printf-style function to log critical errors and terminate. */ void panic (const char *fmt, ...) { va_list ap; va_start (ap, fmt); vpanic (fmt, ap); /* Not reached, vpanic () exits */ va_end (ap); } /* * vpanic () * * vprintf-style function to log critical errors and terminate. */ void vpanic (const char *fmt, va_list ap) { vlogmsg_i (1, fmt, ap); exit (EXIT_FAILURE); } /* * vlogmsg_i () * * Internal routine called by logmsg (), vlogmsg (), panic () and vpanic (). * Logs message by specified method. */ static void vlogmsg_i (int panic, const char *fmt, va_list ap) { switch (logmethod) { case LM_SYSLOG: vsyslog (panic == 0 ? LOG_NOTICE : LOG_ERR, fmt, ap); break; case LM_STDOUT: { char timebuf[100]; time_t now; struct tm *t; FILE *fp; /* * Timestamp the message. If an error occurs, work * around it so messages aren't silently lost. */ if ((now = time (NULL)) == (time_t) -1) snprintf (timebuf, sizeof (timebuf), ""); else if ((t = localtime (&now)) == NULL) snprintf (timebuf, sizeof (timebuf), "EPOCH+%u", (unsigned int) now); else if (strftime (timebuf, sizeof (timebuf), "%b %d %H:%M:%S", t) == 0) snprintf (timebuf, sizeof (timebuf), "%u", (unsigned int) now); /* * Normal messages go to stdout, panic messages go * to stderr. */ fp = (panic == 0) ? stdout : stderr; fprintf (fp, "%s: ", timebuf); vfprintf (fp, fmt, ap); fputc ('\n', fp); fflush (fp); } break; default: assert (0); } } tcpspy-1.7d.orig/log.h0100644000175000017500000000354207305704441014635 0ustar spectraspectra/* * log.h - Logging routines * * This file is part of tcpspy, a TCP/IP connection monitor. * * Copyright (c) 2000, 2001 Tim J. Robbins. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $Id: log.h,v 1.2 2001/01/05 14:05:47 fyre Stab $ */ #ifndef LOG_H #define LOG_H #include void log_set_syslog (void); void log_set_stdout (void); void logmsg (const char *fmt, ...); void vlogmsg (const char *fmt, va_list ap); void panic (const char *fmt, ...); void vpanic (const char *fmt, va_list ap); #endif tcpspy-1.7d.orig/rcsid.h0100644000175000017500000000054207305704427015161 0ustar spectraspectra/* * rcsid.h - Revision Control System Id macro * * This file is part of tcpspy, a TCP/IP connection monitor. * * $Id: rcsid.h,v 1.1 2000/12/19 09:57:21 fyre Stab $ */ #ifndef RCSID_H #define RCSID_H #ifdef __GNUC__ # define RCSID(x) __attribute__ ((unused)) static char *rcsid = x #else # define RCSID(x) static char *rcsid = x #endif #endif tcpspy-1.7d.orig/rule.c0100644000175000017500000002645407424127102015020 0ustar spectraspectra/* * rule.c - Bytecode compiler and interpreter for rules * * This file is part of tcpspy, a TCP/IP connection monitor. * * Copyright (c) 2000, 2001, 2002 Tim J. Robbins. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $Id: rule.c,v 1.9 2001/01/05 14:04:41 fyre Stab $ */ /* * Rule Bytecode Generator and Interpreter * * This file contains the routines that are called by the parser to generate * bytecode, and the routines that execute the bytecode. */ #include #include #include #include #include #include "log.h" #include "rcsid.h" /* * These header files contain the data types used in "rule_grammar.h". */ #include #include #include #include "rule_grammar.h" #include "rule.h" RCSID("$Id: rule.c,v 1.9 2001/01/05 14:04:41 fyre Stab $"); typedef unsigned long bytecode_t; typedef unsigned char bool_t; /* * Exported functions. */ void rule_gen_user (uid_t uid); void rule_gen_lport (u_int16_t low, u_int16_t high); void rule_gen_rport (u_int16_t low, u_int16_t high); void rule_gen_laddr (u_int32_t addr, u_int32_t mask); void rule_gen_raddr (u_int32_t addr, u_int32_t mask); void rule_gen_exe (unsigned long estrid); void rule_gen_or (void); void rule_gen_and (void); void rule_gen_not (void); int rule_eval (uid_t r_uid, u_int32_t laddr, u_int16_t lport, u_int32_t raddr, u_int16_t rport, const char *mexe); void rule_parse (const char *r); unsigned long st_store (const char *s); /* * Internal helper functions. */ static void add_code (bytecode_t c); static const char *st_retrieve (unsigned long id); /* * Module-level variables. */ #define CODE_SIZE_STEP 512 #define STACK_SIZE_STEP 512 #define STRINGTAB_SIZE_STEP 16 /* * The bytecode is stored in an array that is resized according to demand * at runtime. */ static bytecode_t *code = NULL; static size_t code_size = 0 /* size of block pointed to by 'code' */, code_length = 0; /* number of instructions in 'code' */ /* * The string table is an array of pointers to strings. */ static char **stringtab = NULL; static size_t stringtab_size = 0, stringtab_length = 0; /* * Bytecode instructions. */ #define BC_NONE 0 #define BC_USER 1 #define BC_LPORT 2 #define BC_RPORT 3 #define BC_LADDR 4 #define BC_RADDR 5 #define BC_EXE 6 #define BC_OR 64 #define BC_AND 65 #define BC_NOT 66 /* * Comparisons. */ /* * rule_gen_user () * * Generate a user comparison. */ void rule_gen_user (uid_t uid) { add_code (BC_USER); add_code ((bytecode_t) uid); } /* * rule_gen_lport () * * Generate a local port comparison. */ void rule_gen_lport (u_int16_t low, u_int16_t high) { add_code (BC_LPORT); add_code ((bytecode_t) low); add_code ((bytecode_t) high); } /* * rule_gen_rport () * * Generate a remote port comparison. */ void rule_gen_rport (u_int16_t low, u_int16_t high) { add_code (BC_RPORT); add_code ((bytecode_t) low); add_code ((bytecode_t) high); } /* * rule_gen_laddr () * * Generate a local address comparison. */ void rule_gen_laddr (u_int32_t addr, u_int32_t mask) { add_code (BC_LADDR); add_code ((bytecode_t) addr); add_code ((bytecode_t) mask); } /* * rule_gen_raddr () * * Generate a remote address comparison. */ void rule_gen_raddr (u_int32_t addr, u_int32_t mask) { add_code (BC_RADDR); add_code ((bytecode_t) addr); add_code ((bytecode_t) mask); } /* * rule_gen_exe () * * Generate an executable filename comparison. */ void rule_gen_exe (unsigned long estrid) { add_code (BC_EXE); add_code ((bytecode_t) estrid); } /* * Logical Operations. */ /* * rule_gen_or () * * Generate a logical or. */ void rule_gen_or (void) { add_code (BC_OR); } /* * rule_gen_and () * * Generate a logical and. */ void rule_gen_and (void) { add_code (BC_AND); } /* * rule_gen_not () * * Generate a logical not. */ void rule_gen_not (void) { add_code (BC_NOT); } /* * Macros used by rule_eval (). */ /* * Code macros. */ #define NEXTCODE (assert (ip < code_length) , code[ip++]) #define PEEKCODE ((ip < code_length) ? code[ip] : BC_NONE) /* * Stack macros. */ #define POP (stack[--stack_ptr]) #define PEEK (stack[stack_ptr - 1]) #define PUSH(b) \ if ((stack_ptr + 1) > stack_size) { \ bool_t *p; \ \ stack_size += STACK_SIZE_STEP; \ if ((p = realloc (stack, sizeof (*p) * stack_size)) == NULL) \ panic ("tcpspy: memory exhausted\n"); \ stack = p; \ assert ((stack_ptr + 1) <= stack_size); \ } \ stack[stack_ptr++] = (b); /* * Optimisation macros. * * SHORTCIRCUIT: "Short circuit" optimisation: * 1. X OR Y is true if X is true, regardless of value of Y * 2. X AND Y is false if X is false, regardless of value of Y */ #define SHORTCIRCUIT \ if ((PEEKCODE == BC_OR) && (PEEK == 1)) { \ (void) NEXTCODE; \ (void) POP; \ PUSH (1); \ break; \ } else if ((PEEKCODE == BC_AND) && (PEEK == 0)) { \ (void) NEXTCODE; \ (void) POP; \ PUSH (0); \ break; \ } /* * rule_eval () * * Execute the rule on the provided connection information. * * Returns nonzero if the connection matches the rule, zero otherwise. */ int rule_eval (uid_t muid, u_int32_t mladdr, u_int16_t mlport, u_int32_t mraddr, u_int16_t mrport, const char *mexe) { size_t ip = 0; unsigned int c; static bool_t *stack = NULL; static size_t stack_size = 0, stack_ptr = 0; stack_ptr = 0; for (ip = 0; ip < code_length; ) { c = NEXTCODE; switch (c) { /* * Comparisons. */ case BC_USER: /* * User comparison. */ { uid_t uid; uid = (uid_t) NEXTCODE; SHORTCIRCUIT; PUSH ((uid == muid) ? 1 : 0); } break; case BC_LPORT: /* * Local port comparison. */ { u_int16_t hiport, loport; loport = (u_int16_t) NEXTCODE; hiport = (u_int16_t) NEXTCODE; SHORTCIRCUIT; PUSH (((mlport >= loport) && (mlport <= hiport)) ? 1 : 0); } break; case BC_RPORT: /* * Remote port comparison. */ { u_int16_t hiport, loport; loport = (u_int16_t) NEXTCODE; hiport = (u_int16_t) NEXTCODE; SHORTCIRCUIT; PUSH (((mrport >= loport) && (mrport <= hiport)) ? 1 : 0); } break; case BC_LADDR: /* * Local address comparison. */ { u_int32_t addr, mask; addr = (u_int32_t) NEXTCODE; mask = (u_int32_t) NEXTCODE; SHORTCIRCUIT; PUSH (((mladdr & mask) == addr) ? 1 : 0); } break; case BC_RADDR: /* * Remote address comparison. */ { u_int32_t addr, mask; addr = (u_int32_t) NEXTCODE; mask = (u_int32_t) NEXTCODE; SHORTCIRCUIT; PUSH (((mraddr & mask) == addr) ? 1 : 0); } break; case BC_EXE: /* * Executable filename comparison. */ { unsigned long estrid; const char *exe; estrid = (unsigned long) NEXTCODE; SHORTCIRCUIT; exe = st_retrieve (estrid); /* * This instruction is always true if the -p * option was not specified. */ if (mexe == NULL) { static int warned = 0; if (warned == 0) { logmsg ("warning: \"exe\" comparison used when executable names are not available; ignored"); warned = 1; } PUSH (1); break; } /* * Now compare using shell-style globbing. * * Note: Braces around statements because * PUSH is a macro. */ if (fnmatch (exe, mexe, FNM_PATHNAME) == 0) { PUSH (1); } else { PUSH (0); } } break; /* * Logical operations. */ case BC_OR: /* * Logical or. */ { bool_t a, b; a = POP; b = POP; PUSH (((a == 1) || (b == 1)) ? 1 : 0); } break; case BC_AND: /* * Logical and. */ { bool_t a, b; a = POP; b = POP; PUSH (((a == 1) && (b == 1)) ? 1 : 0); } break; case BC_NOT: /* * Logical not. */ { bool_t a; a = POP; PUSH ((a == 0) ? 1 : 0); } break; default: /* * Unhandled bytecode instruction, choke. */ assert (0); } } assert (stack_ptr == 1); return POP; } #undef NEXTCODE #undef PEEKCODE #undef POP #undef PEEK #undef PUSH #undef SHORTCIRCUIT /* * rule_parse () * * Parse and compile the specified rule. */ void rule_parse (const char *r) { extern int ruleparse (void); extern void rule_lexer_scan_string (const char *r); assert (r != NULL); rule_lexer_scan_string (r); if (ruleparse () != 0) abort (); } /* * rule_parse_file () * * Parse and compile the specified open file. */ void rule_parse_file (FILE *fp) { extern void rulerestart (FILE *); extern int ruleparse (void); rulerestart (fp); ruleparse (); } /* * add_code () * * Add a bytecode or piece of data to the code array, dynamically resizing the * array as necessary. */ static void add_code (bytecode_t c) { if ((code_length + 1) > code_size) { bytecode_t *p; code_size += CODE_SIZE_STEP; if ((p = realloc (code, sizeof (*p) * code_size)) == NULL) panic ("memory exhausted"); code = p; assert ((code_length + 1) <= code_size); } code[code_length++] = c; } /* * st_store () * * Store the specified string in the string table. * * Returns an integer that identifies the string and may be used with * st_retrieve () to retrieve the string. */ unsigned long st_store (const char *s) { unsigned long id; assert (s != NULL); if ((stringtab_length + 1) > stringtab_size) { char **p; stringtab_size += STRINGTAB_SIZE_STEP; if ((p = realloc (stringtab, sizeof (*p) * stringtab_size)) == NULL) panic ("memory exhausted"); stringtab = p; assert ((stringtab_length + 1) <= stringtab_size); } id = stringtab_length; if ((stringtab[id] = strdup (s)) == NULL) panic ("memory exhausted"); stringtab_length++; return id; } /* * st_retrieve () * * Retrieve a string using an identifier returned by st_store (). * * Returns a pointer to the string. */ static const char *st_retrieve (unsigned long id) { assert (id < stringtab_length); assert (stringtab != NULL); assert (stringtab[id] != NULL); return stringtab[id]; } tcpspy-1.7d.orig/rule.h0100644000175000017500000000450207424127102015013 0ustar spectraspectra/* * rule.h - Bytecode compiler and interpreter for rules * * This file is part of tcpspy, a TCP/IP connection monitor. * * Copyright (c) 2000, 2001, 2002 Tim J. Robbins. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $Id: rule.h,v 1.3 2001/01/05 14:04:41 fyre Stab $ */ #ifndef RULE_H #define RULE_H #include #include #include #include void rule_gen_user (uid_t uid); void rule_gen_lport (u_int16_t low, u_int16_t high); void rule_gen_rport (u_int16_t low, u_int16_t high); void rule_gen_laddr (u_int32_t addr, u_int32_t mask); void rule_gen_raddr (u_int32_t addr, u_int32_t mask); void rule_gen_exe (unsigned long estrid); void rule_gen_or (void); void rule_gen_and (void); void rule_gen_not (void); int rule_eval (uid_t muid, u_int32_t mladdr, u_int16_t mlport, u_int32_t mraddr, u_int16_t mrport, const char *mexe); void rule_parse (const char *r); void rule_parse_file (FILE *fp); unsigned long st_store (const char *s); #endif tcpspy-1.7d.orig/rule_grammar.y0100644000175000017500000000574007424127116016554 0ustar spectraspectra%{ /* * rule_grammar.y, rule_grammar.c - bison parser for rules * * This file is part of tcpspy, a TCP/IP connection monitor. * * Copyright (c) 2000, 2001, 2002 Tim J. Robbins. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $Id: rule_grammar.y,v 1.6 2001/01/05 14:04:59 fyre Stab $ */ #include #include #include #include #include "rcsid.h" #include "rule.h" RCSID("$Id: rule_grammar.y,v 1.6 2001/01/05 14:04:59 fyre Stab $"); int yyerror (); extern int yylex (); extern int firstrule, gotrule; %} %union { unsigned short boolean; uid_t user; struct { u_int16_t low, high; } port; struct { u_int32_t addr, mask; } addr; unsigned long exe; } %token LPAREN RPAREN %token USER %token USER_SPEC %token LPORT RPORT %token PORT_SPEC %token LADDR RADDR %token ADDR_SPEC %token EXE %token EXE_SPEC %left OR AND %right NOT %type test %% ruleset : rule ruleset { if (!firstrule) rule_gen_or (); gotrule = 1; firstrule = 0; } | /* empty */ { } ; rule : rule OR rule { rule_gen_or (); } | rule AND rule { rule_gen_and (); } | NOT rule { rule_gen_not (); } | LPAREN rule RPAREN { } | test { } ; test : USER USER_SPEC { rule_gen_user ($2); } | LPORT PORT_SPEC { rule_gen_lport ($2.low, $2.high); } | RPORT PORT_SPEC { rule_gen_rport ($2.low, $2.high); } | LADDR ADDR_SPEC { rule_gen_laddr ($2.addr, $2.mask); } | RADDR ADDR_SPEC { rule_gen_raddr ($2.addr, $2.mask); } | EXE EXE_SPEC { rule_gen_exe ($2); } ; %% int yyerror (char *s) { fprintf (stderr, "tcpspy: rule parser: %s\n", s); exit (EXIT_FAILURE); } tcpspy-1.7d.orig/rule_lexer.l0100644000175000017500000001220707424127116016224 0ustar spectraspectra%{ /* * rule_lexer.l, rule_lexer.c - lex lexer for rules * * This file is part of tcpspy, a TCP/IP connection monitor. * * Copyright (c) 2000, 2001, 2002 Tim J. Robbins. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $Id: rule_lexer.l,v 1.8 2001/01/05 14:05:26 fyre Stab $ */ #include #include #include #include #include #include #include #include #include #include #include "rcsid.h" #include "rule_grammar.h" #include "rule.h" RCSID("$Id: rule_lexer.l,v 1.8 2001/01/05 14:05:26 fyre Stab $"); static void rule_lexer_error (const char *msg); #define YY_FATAL_ERROR(msg) rule_lexer_error(msg) %} %option noyywrap %option nounput %option never-interactive %option case-insensitive %option warn %x WANT_USER WANT_PORT WANT_ADDR WANT_EXE DIGIT [0-9] NUMBER {DIGIT}+ QSTRING \"[^"]*\" IPADDR {NUMBER}\.{NUMBER}\.{NUMBER}\.{NUMBER} %% "(" return LPAREN; ")" return RPAREN; "or" return OR; "and" return AND; "not" return NOT; user { BEGIN (WANT_USER); return USER; } {NUMBER} { BEGIN (INITIAL); yytext[yyleng] = '\0'; rulelval.user = (uid_t) atoi (yytext); return USER_SPEC; } {QSTRING} { struct passwd *pw; BEGIN (INITIAL); yytext[yyleng-1] = '\0'; if ((pw = getpwnam (yytext + 1)) == NULL) YY_FATAL_ERROR ("unknown user"); rulelval.user = pw->pw_uid; return USER_SPEC; } lport { BEGIN (WANT_PORT); return LPORT; } rport { BEGIN (WANT_PORT); return RPORT; } ({NUMBER})?-?({NUMBER})? { const char *p = yytext; yytext[yyleng] = '\0'; BEGIN (INITIAL); rulelval.port.low = 0; while (isdigit (*p)) { rulelval.port.low *= 10; rulelval.port.low += (*p++) - '0'; } if (*p == '-') { p++; if (isdigit (*p)) { rulelval.port.high = 0; while (isdigit (*p)) { rulelval.port.high *= 10; rulelval.port.high += (*p++) - '0'; } } else rulelval.port.high = 65535; } else { rulelval.port.high = rulelval.port.low; } if (rulelval.port.high < rulelval.port.low) YY_FATAL_ERROR ("bad port range, high < low"); return PORT_SPEC; } {QSTRING} { struct servent *se; BEGIN (INITIAL); yytext[yyleng - 1] = '\0'; if ((se = getservbyname (yytext + 1, "tcp")) == NULL) YY_FATAL_ERROR ("unknown service"); rulelval.port.low = rulelval.port.high = (u_int16_t) ntohs (se->s_port); return PORT_SPEC; } laddr { BEGIN (WANT_ADDR); return LADDR; } raddr { BEGIN (WANT_ADDR); return RADDR; } {IPADDR}(\/{IPADDR})? { struct in_addr in; char *s; BEGIN (INITIAL); yytext[yyleng] = '\0'; if ((s = strchr (yytext, '/')) != NULL) { *s++ = '\0'; if (inet_aton (s, &in) == 0) YY_FATAL_ERROR ("bad net mask"); rulelval.addr.mask = in.s_addr; } else rulelval.addr.mask = 0xFFFFFFFF; if (inet_aton (yytext, &in) == 0) YY_FATAL_ERROR ("bad IP address"); rulelval.addr.addr = in.s_addr; return ADDR_SPEC; } exe { BEGIN (WANT_EXE); return EXE; } {QSTRING} { yytext[yyleng - 1] = '\0'; rulelval.exe = st_store (yytext + 1); return EXE_SPEC; } <*>#.*\n { /* eat comments */ } <*>[ \n\t] { /* whitespace is ignored */ } <*>. { return *yytext; } %% static void rule_lexer_error (const char *msg) { (void)yy_fatal_error; /* XXX Nasty hack to silence warning */ fprintf (stderr, "tcpspy: rule lexer: %s\n", msg); exit (EXIT_FAILURE); } /* * Hack: The prototype for yy_scan_string() is * YY_BUFFER_STATE yy_scan_string (const char *str); * ... but rule.c does not know what YY_BUFFER_STATE is. */ void rule_lexer_scan_string (const char *r) { yy_scan_string (r); } tcpspy-1.7d.orig/tcpspy.80100644000175000017500000001707207424127102015314 0ustar spectraspectra.\" This file is part of tcpspy, a TCP/IP connection monitor. .\" .\" Copyright (c) 2000, 2001, 2002 Tim J. Robbins. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. The name of the author may not be used to endorse or promote products .\" derived from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, .\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY .\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL .\" THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, .\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, .\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; .\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, .\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $Id: tcpspy.8,v 1.39 2001/05/20 11:52:12 tim Stab $ .TH TCPSPY 8 "May 2001" TJR "tcpspy 1.7" .SH NAME tcpspy \- TCP/IP Connection Monitor .SH SYNOPSIS .B tcpspy .RB [ "-dp" ] .RB [ "-e" .IR "rule" ]... .RB [ "-f" .IR "rulefile" ]... .RB [ "-F" .IR "facility" ] .RB [ "-I" .IR "interval" ] .RB [ "-U" .IR "user" ] .RB [ "-G" .IR "group" ] .SH DESCRIPTION .I tcpspy logs information about selected incoming and outgoing TCP/IP connections to syslog. The following information is logged: username, local address and port, remote address, port, and optionally the filename of the executable. At present, only the IPv4 protocol is supported. .PP .SS "Options" .TP .BI -e " 'rule'" Log only connections matching the specified rule. Rule syntax is outlined below. If this option is specified more than once, connections matching any of the specified rules are logged. You should quote the rule, as shown above. .TP .BI -f " rulefile" Read rules from .IR rulefile . Each rule is on a new line. The `#' character may be used to add comments; everything from this character to the end of the line is ignored. The .B -e and .B -f options may be used together. .TP .BI -F " facility" Log to syslog facility .I facility instead of the compile-time default setting. See the .BR syslog.conf (5) manual page for a list of facilities. .TP .BI -I " interval" Update the internal state every .I interval milliseconds, instead of the default of 1000 ms. Connections that last less than .I interval milliseconds may be missed, so you should experiment to find a value small enough that it catches most connections, but not so small that it causes tcpspy to use too much CPU time. .TP .BI -U " user" Switch to the specified user after startup. .I user may be a numeric user id or a user name from the system password file. .TP .BI -G " group" Switch to the specified group after startup. .I group may be a numeric group id or a group name from the system group file. If a username to switch to with the .B -U option is specified but .B -G is omitted, tcpspy will switch to that specified user's primary group. .TP .B -d Debugging mode; if this option is specified, tcpspy will not detach from the console after initialisation, and will log connections to standard output instead of syslog. .TP .B -p Log the filename of the executable that created/accepted the connection. You may require superuser privileges to obtain this information for processes you do not own (this is a kernel limitation). This option can greatly increase the amount of CPU time required to process each connection/disconnection. .PP .SS "Rule Syntax" A rule may be specified with the .B -e option to log information about connections matching this rule, overriding the default of logging all connections. .PP The following comparison operations are defined: .TP .BI user " uid" True if the local user initiating or accepting the connection has the .B effective user id .IR uid . .TP .BI user " \N'34'username\N'34'" Same as above, but using a username instead of a user id. .TP .BI lport " port" True if the local end of the connection has port number .IR port . .TP .BI lport " [low] - [high]" True if the local end of the connection has a port number greater than or equal to .I low and less than or equal to .IR high . If the form .I low- is used, high is assumed to be 65535. If the form .I -high is used, low is assumed to be 0. It is an error to omit both .IR low " and " high . .TP .BI lport " \N'34'service\N'34'" Same as above, but using a service name from .I /etc/services instead of a port number. .TP .B rport Same as .B lport but compares the port number of the remote end of the connection. .TP .BI laddr " n.n.n.n[/m.m.m.m]" Interpreted as a "net/mask" expression; true if "net" is equal to the bitwise AND of the local address of the connection and "mask". If no mask is specified, a default mask with all bits set (255.255.255.255) is used. .TP .B raddr Same as .B laddr but compares the remote address. .TP .BI exe " \N'34'pattern\N'34'" True if the full filename (including directory) of the executable that created/accepted the connection matches .IR pattern , a .BR glob (7)-style wildcard pattern. The pattern "" (an empty string) matches connections created/accepted by processes whose executable filename is unknown. If the .B -p option is not specified, a warning message will be printed, and the result of this comparison will always be true. .PP Expressions (including the comparisons listed above) may be joined together with the following logical operations: .TP .IB expr1 " or " expr2 True if either of .I expr1 or .I expr2 are true (logical OR). .TP .IB expr1 " and " expr2 True if both .I expr1 and .I expr2 are true (logical AND). .TP .BI not " expr" True if .I expr is false (logical NOT). .PP Rules are evaluated from left to right. Whitespace (space, tab and newline) characters are ignored between "words". Rules consisting of only whitespace match no connections, but do not cause an error. Parentheses, '(' and ')' may be placed around expressions to affect the order of evaluation. .PP The Examples section contains some sample rules which further demonstrate how they are constructed. .SH "EXIT STATUS" .TP 0 The daemon was successfully started .TP >0 An error occurred .SH SIGNALS .TP .I TERM Shut down at most .I interval milliseconds from now. .TP .I INT (Debugging mode only) Handled identically to .IR TERM . .PP All other signals retain their default behaviour, which is documented in .BR signal (7). .SH EXAMPLES .TP tcpspy -e 'user "joe" and rport "ssh"' Log connections made by user "joe" for the service "ssh". .TP tcpspy -e 'not raddr 10.0.0.0/255.0.0.0 and rport 25 and (user "bob" or user "joe")' Log connections made by users "bob" and "joe" to remote port 25 on machines not on a fictional "intranet". .TP tcpspy -e 'exe "/usr/bin/irc"' Log connections made by /usr/bin/irc (probably ircII). .SH BUGS Empty rule files cause .B tcpspy to log no connections instead of all connections. .SH AUTHOR Tim J. Robbins .SH SEE ALSO .BR glob (7), .BR proc (5), .BR services (5), .BR signal (7), .BR syslog (3), .BR syslog.conf (5) tcpspy-1.7d.orig/tcpspy.c0100644000175000017500000003651207424127116015374 0ustar spectraspectra/* * tcpspy.c - TCP/IP connection monitor. * * This file is part of tcpspy, a TCP/IP connection monitor. * * Copyright (c) 2000, 2001, 2002 Tim J. Robbins. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $Id: tcpspy.c,v 1.39.1.3 2001/07/02 11:55:36 tim Stab $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SYSLOG_NAMES #include #include #include #include #include #include #include "log.h" #include "rcsid.h" #include "rule.h" RCSID("$Id: tcpspy.c,v 1.39.1.3 2001/07/02 11:55:36 tim Stab $"); /* * Defaults for compile-time settings. Descriptions of these are in * the Makefile. */ #ifndef CONNTABLE_BUCKETS #define CONNTABLE_BUCKETS 5003 #endif #ifndef FACILITY #define FACILITY LOG_USER #endif int gotrule = 0; static int stopped = 0, showprocs = 0; static int facility = FACILITY; /* * This structure holds everything we need to know about a connection. We * use unsigned long instead of (for example) uid_t, ino_t to make hashing * easier. */ typedef struct conn { unsigned long lcl; unsigned long lclp; unsigned long rmt; unsigned long rmtp; unsigned long uid; unsigned long ino; char exe[PATH_MAX]; struct conn *next; } conn_t; typedef struct conntable { conn_t *buckets[CONNTABLE_BUCKETS]; } conntable_t; static int ct_init (conntable_t *ct); static int ct_hash (conn_t *c); static int ct_add (conntable_t *ct, conn_t *c); static int ct_find (conntable_t *ct, conn_t *c); static int ct_read (conntable_t *ct); static int ct_free (conntable_t *ct); static void huntinode (ino_t i, char *buf, size_t bufsize); static void logconn (conn_t *c, const char *action); static void compare (conntable_t *old, conntable_t *new); static void stopsig (int signal); /* * stopsig () * * Stop the program when certain signals are received. */ static void stopsig (int signo) { logmsg ("caught signal %d, shutting down", signo); stopped = 1; } /* * ct_init () * * Initialise a connection table (hashtable). */ static int ct_init (conntable_t *ct) { int i; assert (ct != NULL); for (i = 0; i < CONNTABLE_BUCKETS; i++) ct->buckets[i] = NULL; return 1; } /* * ct_hash () * * Simple hash function for connections. */ static int ct_hash (conn_t *c) { unsigned long h; assert (c != NULL); h = c->lcl ^ c->lclp ^ c->rmt ^ c->rmtp ^ c->uid ^ c->ino; return h % CONNTABLE_BUCKETS; } /* * ct_add () * * Add a connection to the connection table. */ static int ct_add (conntable_t *ct, conn_t *c) { conn_t *old, *newc; int bi; assert (ct != NULL); assert (c != NULL); newc = (conn_t *) malloc (sizeof (conn_t)); if (newc == NULL) panic ("memory exhausted"); memcpy (newc, c, sizeof (conn_t)); bi = ct_hash (c); old = ct->buckets[bi]; ct->buckets[bi] = newc; ct->buckets[bi]->next = old; return 1; } /* * ct_find () * * Find a connection in a table, return nonzero if found, zero otherwise. */ static int ct_find (conntable_t *ct, conn_t *c) { conn_t *bucket; assert (ct != NULL); assert (c != NULL); bucket = ct->buckets[ct_hash (c)]; while (bucket != NULL) { if ((c->lcl == bucket->lcl) && (c->lclp == bucket->lclp) && (c->rmt == bucket->rmt) && (c->rmtp == bucket->rmtp) && (c->uid == bucket->uid) && (c->ino == bucket->ino)) { return 1; } bucket = bucket->next; } return 0; } /* * ct_read () * * Read /proc/net/tcp and add all connections to the table if connections * of that type are being watched. */ static int ct_read (conntable_t *ct) { static FILE *fp = NULL; char buf[1024]; conn_t c; assert (ct != NULL); if (fp == NULL) { fp = fopen ("/proc/net/tcp", "r"); if (fp == NULL) panic ("/proc/net/tcp: %s", strerror (errno)); } rewind (fp); if (fgets (buf, sizeof (buf), fp) == NULL) panic ("/proc/net/tcp: missing header"); while (fgets (buf, sizeof (buf), fp) != NULL) { unsigned long st; if (sscanf (buf, "%*d: %lx:%lx %lx:%lx %lx %*x:%*x %*x:%*x %*x %lu %*d %lu", &c.lcl, &c.lclp, &c.rmt, &c.rmtp, &st, &c.uid, &c.ino) != 7) { logmsg ("/proc/net/tcp: warning: incomplete line"); continue; } if ((c.ino == 0) || (st != TCP_ESTABLISHED)) continue; if (showprocs != 0) huntinode ((ino_t) c.ino, c.exe, sizeof (c.exe)); if (ct_add (ct, &c) == 0) return 0; } return 1; } /* * ct_free () * * Free a connection table. */ static int ct_free (conntable_t *ct) { int i; assert (ct != NULL); for (i = 0; i < CONNTABLE_BUCKETS; i++) { conn_t *c0, *c1; c0 = ct->buckets[i]; while (c0 != NULL) { c1 = c0->next; free (c0); c0 = c1; } ct->buckets[i] = NULL; } return 1; } /* * huntinode () * * Find names processes using an inode and put them in a buffer. */ static void huntinode (ino_t i, char *buf, size_t bufsize) { DIR *procdir; struct dirent *procent; assert (buf != NULL); *buf = '\0'; if ((procdir = opendir ("/proc")) == NULL) panic ("/proc: %s", strerror (errno)); while ((procent = readdir (procdir)) != NULL) { char fdbuf[PATH_MAX]; DIR *fddir; struct dirent *fdent; /* * No test needed for "." and ".." since they don't begin * with digits. */ if (! isdigit (*procent->d_name)) continue; snprintf (fdbuf, sizeof (fdbuf), "/proc/%s/fd", procent->d_name); /* * We're don't always run as root, we may get EPERM here, * ignore it. */ if ((fddir = opendir (fdbuf)) == NULL) continue; while ((fdent = readdir (fddir)) != NULL) { int len; char lnkbuf[PATH_MAX], lnktgt[PATH_MAX]; char exebuf[PATH_MAX], exetgt[PATH_MAX]; ino_t this_ino; if (! isdigit (*fdent->d_name)) continue; snprintf (lnkbuf, sizeof (lnkbuf), "%s/%s", fdbuf, fdent->d_name); len = readlink (lnkbuf, lnktgt, sizeof (lnktgt) - 1); if (len < 0) continue; lnktgt[len] = '\0'; if (sscanf (lnktgt, "socket:[%lu]", &this_ino) != 1) continue; if (this_ino != i) continue; snprintf (exebuf, sizeof (exebuf), "/proc/%s/exe", procent->d_name); len = readlink (exebuf, exetgt, sizeof (exetgt) - 1); if (len < 0) continue; exetgt[len] = '\0'; strncpy (buf, exetgt, bufsize); buf[bufsize - 1] = '\0'; } closedir (fddir); } closedir (procdir); } /* * logconn () * * Log a connection/disconnection. */ static void logconn (conn_t *c, const char *action) { struct in_addr in; char laddr[16], raddr[16]; /* assume IPv4 nnn.nnn.nnn.nnn\0 */ char *n; struct passwd *pw; char uidbuf[32]; char *user; struct servent *se; char lport[64], rport[64]; assert (c != NULL); assert (action != NULL); if ((gotrule != 0) && (rule_eval (c->uid, c->lcl, c->lclp, c->rmt, c->rmtp, (showprocs != 0) ? c->exe : NULL) == 0)) return; in.s_addr = c->lcl; n = inet_ntoa (in); strncpy (laddr, n, sizeof (laddr)); laddr[sizeof (laddr) - 1] = '\0'; in.s_addr = c->rmt; n = inet_ntoa (in); strncpy (raddr, n, sizeof (raddr)); raddr[sizeof (raddr) - 1] = '\0'; snprintf (lport, sizeof (lport), "%lu", c->lclp); snprintf (rport, sizeof (rport), "%lu", c->rmtp); if ((se = getservbyport (htons (c->lclp), "tcp")) != NULL) { strncpy (lport, se->s_name, sizeof (lport)); lport[sizeof (lport) - 1] = '\0'; } if ((se = getservbyport (htons (c->rmtp), "tcp")) != NULL) { strncpy (rport, se->s_name, sizeof (rport)); rport[sizeof (rport) - 1] = '\0'; } if ((pw = getpwuid ((uid_t) c->uid)) == NULL) { snprintf (uidbuf, sizeof (uidbuf), "(uid %u)", (unsigned int)(uid_t)c->uid); user = uidbuf; } else { user = pw->pw_name; } if (showprocs != 0) logmsg ("%s: proc %.30s, user %s, local %s:%s, remote %s:%s", action, *c->exe != '\0' ? c->exe : "(unknown)", user, laddr, lport, raddr, rport); else logmsg ("%s: user %s, local %s:%s, remote %s:%s", action, user, laddr, lport, raddr, rport); } /* * compare () * * Compare the `old' and `new' tables, logging any differences. */ static void compare (conntable_t *old, conntable_t *new) { int i; assert (old != NULL); assert (new != NULL); for (i = 0; i < CONNTABLE_BUCKETS; i++) { conn_t *bucket; bucket = old->buckets[i]; while (bucket != NULL) { if (ct_find (new, bucket) == 0) logconn (bucket, "disconnect"); bucket = bucket->next; } } for (i = 0; i < CONNTABLE_BUCKETS; i++) { conn_t *bucket; bucket = new->buckets[i]; while (bucket != NULL) { if (ct_find (old, bucket) == 0) logconn (bucket, "connect"); bucket = bucket->next; } } } /* * getfacility () * * Convert a facility name to a integer facility value for syslog(). */ int getfacility (const char *s) { int i; assert (s != NULL); for (i = 0; i < LOG_NFACILITIES - 2; i++) { assert (facilitynames[i].c_name != NULL); if (strcmp (facilitynames[i].c_name, s) == 0) return facilitynames[i].c_val; } return -1; } static void usage (void) { fprintf (stderr, "usage: tcpspy [-dp] [-e rule]... [-f rulefile] [-I interval] " "[-U user]\n\t[-G group] [-F facility] [-I interval]\n"); exit (EXIT_FAILURE); } int firstrule = 1; int main (int argc, char *argv[]) { conntable_t old, new; unsigned long interval = 1000; int ch; uid_t dropuser = -1; gid_t dropgroup = -1, defgroup = -1; int debug = 0; log_set_syslog (); /* * Parse our arguments. */ opterr = 0; while ((ch = getopt (argc, argv, "dpe:I:U:G:u:w:i:f:F:")) != -1) { switch (ch) { case 'd': debug = 1; log_set_stdout (); break; case 'p': showprocs = 1; break; case 'e': rule_parse (optarg); gotrule = 1; if (firstrule == 0) /* * Join multiple rules together with * logical OR's. */ rule_gen_or (); firstrule = 0; /* Hide rule from `ps' */ memset (optarg, '\0', strlen (optarg)); break; case 'f': { FILE *fp; if ((fp = fopen (optarg, "r")) == NULL) { fprintf (stderr, "tcpspy: %s: %s\n", optarg, strerror (errno)); exit (EXIT_FAILURE); } rule_parse_file (fp); fclose (fp); } break; case 'I': interval = atoi (optarg); if (interval == 0) { fprintf (stderr, "tcpspy: bad interval\n"); exit (EXIT_FAILURE); } break; case 'U': { struct passwd *pw; if (isdigit (*optarg)) { dropuser = atoi (optarg); pw = getpwuid (atoi (optarg)); } else { if ((pw = getpwnam (optarg)) == NULL) { fprintf (stderr, "tcpspy: user `%s' unknown\n", optarg); exit (EXIT_FAILURE); } dropuser = pw->pw_uid; } /* * Use the gid from the password file entry if * possible, as a default. */ if (pw != NULL) defgroup = pw->pw_gid; else defgroup = (gid_t) -1; } break; case 'G': if (isdigit (*optarg)) dropgroup = atoi (optarg); else { struct group *gr; if ((gr = getgrnam (optarg)) == NULL) { fprintf (stderr, "tcpspy: group `%s' unknown\n", optarg); exit (EXIT_FAILURE); } dropgroup = gr->gr_gid; } break; case 'F': if ((facility = getfacility (optarg)) < 0) { fprintf (stderr, "tcpspy: bad facility name `%s'\n", optarg); exit (EXIT_FAILURE); } break; case 'u': case 'w': case 'i': fprintf (stderr, "tcpspy: -%c option is obsolete\n", ch); /* fall through to usage message */ default: usage(); } } argc -= optind; argv += optind; /* * Become an unprivileged user for safety purposes if requested. */ if ((dropgroup == (uid_t) -1) && (defgroup != (uid_t) -1)) dropgroup = defgroup; if (dropgroup != (gid_t) -1) { if (setgid (dropgroup) < 0) { fprintf (stderr, "tcpspy: setgid: %s\n", strerror (errno)); exit (EXIT_FAILURE); } } if (dropuser != (uid_t) -1) { if (setuid (dropuser) < 0) { fprintf (stderr, "tcpspy: setuid: %s\n", strerror (errno)); exit (EXIT_FAILURE); } } /* * Become a daemon by double-forking and detaching completely from * the terminal. */ if (debug == 0) { pid_t p; /* 1st fork */ p = fork(); if (p < 0) { fprintf (stderr, "tcpspy: fork: %s\n", strerror (errno)); exit (EXIT_FAILURE); } else if (p != 0) exit (0); /* 2nd fork */ p = fork(); if (p < 0) { fprintf (stderr, "tcpspy: fork: %s\n", strerror (errno)); exit (EXIT_FAILURE); } else if (p != 0) { fprintf (stderr, "tcpspy 1.7d started (pid %d)\n", (int) p); exit (EXIT_SUCCESS); } ioctl (STDIN_FILENO, TIOCNOTTY, NULL); close (STDIN_FILENO); close (STDOUT_FILENO); close (STDERR_FILENO); setpgid (0, 0); chdir ("/"); } else fprintf (stderr, "tcpspy 1.7d started (debug)\n"); signal (SIGTERM, stopsig); if (debug != 0) signal (SIGINT, stopsig); /* * Initialisation's done, start watching for connections. */ openlog ("tcpspy", LOG_PID, facility); if (debug == 0) /* * .. for the benefit of those reading the logs. Useless to * people running it in debug mode. */ logmsg ("tcpspy started, monitoring connections"); if (ct_init (&old) == 0) panic ("ct_init failed"); if (ct_read (&old) == 0) panic ("ct_read failed"); while (stopped == 0) { struct timeval tv1, tv2; static double elapsed = 0.0; static int slow_warn = 0; gettimeofday (&tv1, NULL); if (ct_init (&new) == 0) panic ("ct_init failed"); if (ct_read (&new) == 0) panic ("ct_read failed"); compare (&old, &new); if (ct_free (&old) == 0) panic ("ct_free failed"); memcpy (&old, &new, sizeof (conntable_t)); gettimeofday (&tv2, NULL); /* * If the time taken to poll the currently open connections is longer than * the time between checks, emit a warning message. */ elapsed += (double) ((tv2.tv_sec - tv1.tv_sec) * 1000000 + (tv2.tv_usec - tv1.tv_usec)); elapsed /= 2; if ((elapsed > (double)(interval * 1000)) && (slow_warn == 0)) { slow_warn = 1; logmsg ("warning: running slowly, suggest increasing interval with -I option"); } usleep (interval * 1000); } if (ct_free (&old) == 0) panic ("ct_free failed"); closelog (); return EXIT_SUCCESS; }