--=====================_796427355==_ Content-Type: text/plain; charset="us-ascii" See below, it's pretty simple. >I'd love to get a copy... Can you please send it to me in text? (source) > >Thanks, > >-- >T. Jason Ucker 415.390.3720 >Sys Admin/jr Sys Engineer tju@sgi.com >SGI Direct > --=====================_796427355==_ Content-Type: text/plain; charset="us-ascii" /* * TcpAlert * Copyright (c) 1995 - Dana Nowell * * This code is provided AS-IS, no warranty of any type is granted * or implied (including fitness of use), USE AT YOUR OWN RISK. * * Redistribution and use in source forms, with and without * modification, are permitted provided that this entire comment * appears intact. * * Redistribution in binary form may occur without restriction. * Obviously, it would be nice if you gave credit where it is due. * * If you modify this code PLEASE add a comment after this one * describing your modifications, we should all leave footprints * for the next guy. (See the change log comment) * * * General design notes: * This code ASSUMES AN ANSI COMPILER! If your compiler is not ANSI, * the function prototypes and declarations will give you fits, sorry. * * This is NOT designed to be fast, small, and elegant. It IS designed * to be easy to read, easy to modify, and 'obviously' correct. * * Logging to syslog is accomplished via four functions LogDebug, * LogInfo, LogWarn, and LogError. This allows you a place to make simple * changes if you dislike my choices of log levels. Currently, LogInfo * and LogWarn use the same log level, LOG_WARNING. This is because * of some of the machines I use it on, they only log warnings and above. * You may want to change LogInfo to use LOG_NOTICE (I probably will in * the future). The LogDebug function is provided for debugging purposes. * It uses LOG_DEBUG as the logging level. These functions were provided * as function calls and not macros to allow people to customize at any * level, even to the point of not using syslog. * * Architecture: * Very simple. We create a socket, bind to a port and sit on an accept. * When the accept completes, we spin off a child to handle it and go * back to sitting on an accept. The child does all the real work in * function HandleConnection(). The basic info about the connection * is logged to syslog in function LogPartnerInfo(). * * Porting Notes: * This was coded for use on LINUX and compiled with gcc, if you port * it you need to look at the following areas. * Includes - your mileage my vary and your compiler may bitch * cleanchild - specifically the wait (may be wait3 or waitpid) * - signal call to reset signal (may not need it) * * This was coded for AF_INET sockets, if you want AF_ISO, AF_UNIX * or AF_CCITT you are on your own. The best I can say is you will * not be using a sockaddr_in structure and at a minimum all references * to it (and its elements) will need to be changed. I carry the size * of the socket structure around in socksize just for people like you. * * If you port it to a different platform and want to send me the changes, * I will incorporate them in new versions (assuming there are some). * */ /* * Change Log: * * 03/24/95 Dana Nowell Initial version * 03/27/95 Dana Nowell Ported to HP and SGI * * */ /* * defines for compile time code inclusion * * I put them here because I was too lazy to make a makefile, plus it * improves documentation (yeah, sure it does), you do whatever you want * */ /* * Which type of wait is used in function cleanchild. * check only one PLEASE * note WAIT3 and WAITPID are not implemented yet. * I have not ported to a box that requires them yet. */ #define WAIT_IS_WAIT 1 #define WAIT_IS_WAIT3 0 #define WAIT_IS_WAITPID 0 /* * causes cleanchild to reset the signal handler. To see if you * need this: set it to zero, run alert and 'tickle it' two or three * times. Check the log to ensure you actually did 'tickle it'. * Run ps and see if you have any zombies, if so set it to 1 and * try again. Most System V R4 systems should be 1. */ #define SIGNAL_RESET 1 /* * I have included a few lines of debugging info in the code. * set this to one to log them to syslog via LogDebug */ #define DEBUG_ME 0 /* * Set to 1 to use Bind/Named as the name resolver * Set to 0 to use only the local host file * Why anyone would ever set this to 0 is beyond me, but you can */ #define USE_NAMED 1 /* use resolver and not host file for lookup */ #include <stdio.h> #include <errno.h> #include <sys/types.h> #include <netdb.h> #include <arpa/inet.h> #include <netinet/in.h> #include <sys/socket.h> #include <signal.h> #include <syslog.h> #if USE_NAMED #include <arpa/nameser.h> #include <resolv.h> #endif /* * defines, typedefs, and structure defs used by the program */ #define DEFAULT_PORT 1099 /* mainly for testing */ #define MAX_NAME 100 #define MAX_LISTENS 5 #define MAX_SYSLOG_TEXT 200 #define LOGBUF_SIZE 100 /* various defines for exit states */ #define EXIT_SUCCESS 0 #define EXIT_FAILED_UNBLOCK 1 #define EXIT_FAILED_SOCKET 2 #define EXIT_FAILED_CMDLINE 3 #define EXIT_FAILED_INIT 4 #define EXIT_NO_WAY 99 /* * * I still do not like the definition of MAX_SYSLOG_BUFFER, * the magic 100 is annoying but it allows for the PID, port number, * NULL terminator, and the spacing in the sprintf format string in * function LogIt(). If you mess with the format string, be sure the * buffer is still big enough (I have been liberal in the allocation)! * */ #define MAX_SYSLOG_BUFFER (MAX_NAME + 100 + MAX_SYSLOG_TEXT) /* ANSI function prototypes */ void LogPartnerInfo( struct sockaddr_in *HostAddr ); int GetConnection( int size ); int OpenMySocket( void ); char *GetPartnerName( struct sockaddr_in *sap ); void cleanchild( int s ); void LogDebug( char *p ); void LogInfo( char *p ); void LogWarn( char *p ); void LogError( char *p ); void LogIt( int level, char *p ); int HandleConnection( int *NewSock ); int HandleAccept( int NewSock ); int UnblockTerminal( void ); int ParseCommandLine( int argc, char *argv[] ); int PostListen( int socket ); /* data elements */ /* this has more globals than I would like, but then it is a quick hack */ char copyright[] = "Sections of this program are copyright 1995 by Dana Nowell"; char version[] = "Version 1.0"; int MySocket = -1; /* fd describing socket */ struct sockaddr_in SockAddr; /* My side of the connection */ struct sockaddr_in RealHostAddr; /* His side of the connection */ char msgbuf[LOGBUF_SIZE+1]; /* buffer to format log messages */ int MyPid; int MyPort = DEFAULT_PORT; char MyName[MAX_NAME+1]; /*********************************************************************** * * Main - this is where it all starts * ***********************************************************************/ int main( int argc, char *argv[] ) { int NewSock; int socksize; printf( "%s, %s - Port Alarm Application\n%s\n\n", argv[0], version, copyright ); /* get PID for use in error messages */ MyPid = getpid(); /* * Handle command line junk, * copy to internal variables to avoid later buffer overrun, * after the copy we KNOW it will fit because we fixed the max length */ if ( ParseCommandLine( argc, argv ) ) { puts( "Failed to parse the command line properly" ); exit( EXIT_FAILED_CMDLINE ); } #if DEBUG_ME LogDebug( "In main after ParseCmdLine" ); #endif /* spin off a child and die to unblock the terminal/shell */ if ( UnblockTerminal() ) { exit(EXIT_FAILED_UNBLOCK); /* failed to unblock terminal */ } /* initialize any global data structures that need it */ if ( InitDataStructs() ) exit(EXIT_FAILED_INIT); /* write the startup message */ LogInfo( "Started Alert" ); /* setup child signal handler to avoid zombies */ (void) signal(SIGCHLD, cleanchild); /* ** Try to actually open the socket */ /* get a socket for the connection */ socksize = OpenMySocket(); if ( socksize < 0 ) /* if can not get socket, die */ exit(EXIT_FAILED_SOCKET); /* * loop forever, spinning off children to handle each connection */ while ( 1 ) { NewSock = GetConnection( socksize ); if ( NewSock < 0 ) continue; if ( HandleAccept( NewSock ) ) LogError( "Unable to handle the accept" ); (void) close( NewSock ); /* close the 'connection' socket */ NewSock = -1; } /* back to the forever while loop */ return EXIT_NO_WAY; /* just to make the compiler happy, not used */ } /*********************************************************************** * * InitDataStructs - return 0 on success 1 on failure * ***********************************************************************/ int InitDataStructs( void ) { int retval = 0; /* initialize the socket structure */ if (SockAddr.sin_family == 0) SockAddr.sin_family = AF_INET; if (SockAddr.sin_addr.s_addr == 0) SockAddr.sin_addr.s_addr = INADDR_ANY; if ( SockAddr.sin_port == 0 ) SockAddr.sin_port = htons(MyPort); #if 0 RealHostAddr.sin_family = AF_INET; RealHostAddr.sin_addr.s_addr = INADDR_ANY; #endif return retval; } /*********************************************************************** * * ParseCommandLine - return 0 on success 1 on failure * ***********************************************************************/ int ParseCommandLine( int argc, char *argv[] ) { char *p; int temp; int retval = 0; /* save off my name, size adjusted, for logging to syslogd */ p = argv[0]; temp = strlen( p ); if ( temp > MAX_NAME ) p[MAX_NAME] = '\0'; strcpy( MyName, p ); /* get port number if specified */ if ( argc > 1 ) MyPort = atoi( argv[1] ); return retval; } /*********************************************************************** * * UnblockTerminal - return 0 on success 1 on failure * ***********************************************************************/ int UnblockTerminal() { int pid; /* * spin off a child and die so we unblock the terminal */ pid = fork(); if ( pid < 0 ) { LogError( "Can not create child" ); return 1; } if ( pid != 0 ) /* if parent, die to unblock term, child continues on */ { exit(EXIT_SUCCESS); } /* now a new process (child process) so reset PID */ MyPid = getpid(); return 0; } /*********************************************************************** * * HandleAccept - where the accept is processed * returns 0 on success and 1 on failure * ***********************************************************************/ int HandleAccept( int NewSock ) { int retval = 0; int pid; /* ** Create a subprocess to process the request. */ #if DEBUG_ME sprintf( msgbuf, "Forking (fd = %d)\n", NewSock ); LogDebug( msgbuf ); #endif pid = fork(); if (pid == 0) /* Child process, log info and die */ { if ( HandleConnection( &NewSock ) ) LogError( "Failed to handle this connection completely" ); exit(EXIT_SUCCESS); /* child has done its job, die */ } if (pid < 0) /* fork failed */ { LogError( "Cannot fork" ); sleep(10); retval = 1; } return retval; } /*********************************************************************** * * HandleConnection - where the connection is actually processed * returns 0 on success and 1 on failure * ***********************************************************************/ int HandleConnection( int *NewSock ) { int retval = 0; /* clean up stuff left over from the parent */ (void) close( MySocket ); /* close to old 'listen' socket*/ MySocket = -1; (void) signal(SIGCHLD, SIG_DFL); /* reset the signal handler */ /* process the connection here */ LogPartnerInfo( &RealHostAddr ); /* log info about the connection */ /* add other things here later (IDENTD, FINGER, etc.) */ /* * NOTE, beware 'recursion wars'. If you include finger here * and then run this on your finger socket while the * 'other site' has done the same, it can get REAL interesting. */ /* clean up the new connect as we are done */ (void) close( *NewSock ); /* cleanup the 'connection' socket */ *NewSock = -1; return retval; } /*********************************************************************** * * LogPartnerInfo - logs info about HostAddr to syslog * ***********************************************************************/ void LogPartnerInfo( struct sockaddr_in *HostAddr ) { /* log the name of the host connecting to us */ sprintf( msgbuf, "Connected to %s", GetPartnerName( HostAddr ) ); LogWarn( msgbuf ); return; } /*********************************************************************** * * GetConnection - Posts accept and waits for connection * returns new socket for the connection * ***********************************************************************/ int GetConnection( int socksize ) { int NewSock; int size; while( 1 ) /* forever is a long time */ { do { errno = 0; size = socksize; NewSock = accept( MySocket, (struct sockaddr *) &RealHostAddr, &size ); } while ( NewSock < 0 && errno == EINTR ); if ( NewSock >= 0 ) /* got a live one */ break; sprintf( msgbuf, "Accept failure, %d", errno ); LogError( msgbuf ); sleep(10); } return NewSock; } /*********************************************************************** * * OpenMySocket * Opens socket, does bind and posts listen * returns size of socket on success and -1 on failure * ***********************************************************************/ int OpenMySocket() { int on = 1; int socksize; socksize = sizeof(SockAddr); if ( MySocket < 0 ) /* already open ??? */ { /* get the socket */ MySocket = socket(SockAddr.sin_family, SOCK_STREAM, 0); if (MySocket < 0) { /* probably something already running ??? */ sprintf( msgbuf, "Cannot create socket, errno %d", errno ); LogError( msgbuf ); return -1; } (void) setsockopt( MySocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on) ); (void) setsockopt( MySocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof(on) ); /* bind to the socket */ if ( bind( MySocket, (struct sockaddr *) &SockAddr, socksize ) < 0 ) { sprintf( msgbuf, "Cannot bind, errno %d", errno ); LogError( msgbuf ); socksize = -1; } } if ( PostListen( MySocket ) ) socksize = -1; /* if error shut it down */ if ( socksize < 0 && MySocket >= 0 ) { sprintf( msgbuf, "Error on socket %d, shutting it down", MySocket ); LogError( msgbuf ); (void) close( MySocket ); MySocket = -1; } return socksize; } /*********************************************************************** * * PostListen - post a listen on socket * returns 0 on success or 1 on failure * ***********************************************************************/ int PostListen( int socket ) { int retval = 0; if ( listen( socket, MAX_LISTENS ) < 0 ) { sprintf( msgbuf, "Cannot listen, errno %d", errno ); LogError( msgbuf ); retval = 1; } return retval; } /*********************************************************************** * * GetPartnerName - * returns pointer to buffer containing 'name' of sap * ***********************************************************************/ char *GetPartnerName( struct sockaddr_in *sap ) { static char NameBuf[ (3*MAX_NAME) ]; /* bigger than actually needed */ struct hostent *hostinfo; char *retval; char *quad = NULL; char temp[MAX_NAME+1]; int size; int family; NameBuf[0] = '\0'; /* safety first, no old data returned by mistake */ family = sap->sin_family; switch ( family ) { case AF_INET: quad = inet_ntoa( sap->sin_addr ); hostinfo = gethostbyaddr((char *) &sap->sin_addr, sizeof(sap->sin_addr), AF_INET); break; default: hostinfo = NULL; strcpy( NameBuf, "Unknown socket family" ); sprintf( msgbuf, "In GetPartnerName, bad family %d (%xH)", family, family ); LogError( msgbuf ); break; } /* if we have info, format a proper reply */ if ( hostinfo != NULL ) { /* make it fit, buffer overflow is a BAD thing */ size = strlen( hostinfo->h_name ); if ( size > MAX_NAME ) { memcpy( temp, hostinfo->h_name, MAX_NAME ); temp[ MAX_NAME ] = '\0'; strcpy( NameBuf, temp ); } else strcpy( NameBuf, hostinfo->h_name ); } /* if we have a quad format ID add it */ if ( quad != NULL ) { /* make it fit, buffer overflow is a BAD thing */ size = strlen( quad ); if ( size > MAX_NAME ) quad[ MAX_NAME ] = '\0'; strcat( NameBuf, " " ); strcat( NameBuf, quad ); } return NameBuf; } /*********************************************************************** * * cleanchild - called by sigchild signal handler to cleanup children * ***********************************************************************/ void cleanchild( int s ) { int status; #if DEBUG_ME LogDebug( "In cleanchild, just starting" ); #endif #if WAIT_IS_WAIT while( wait( &status ) > 0 ) /* catch sig child to avoid zombies */ { sleep(3); } #endif #if WAIT_IS_WAIT3 #endif #if WAIT_IS_WAITPID #endif #if DEBUG_ME LogDebug( "In cleanchild, all done" ); #endif #ifdef SIGNAL_RESET (void) signal(SIGCHLD, cleanchild); /* reset signal */ #endif } /*********************************************************************** * * LogDebug - writes text p to syslogd at DEBUG level * ***********************************************************************/ void LogDebug( char *p ) { LogIt( LOG_DEBUG, p ); } /*********************************************************************** * * LogInfo - writes text p to syslogd at WARNING level * ***********************************************************************/ void LogInfo( char *p ) { LogIt( LOG_WARNING, p ); } /*********************************************************************** * * LogWarn - writes text p to syslogd at WARNING level * ***********************************************************************/ void LogWarn( char *p ) { LogIt( LOG_WARNING, p ); } /*********************************************************************** * * LogError - writes text p to syslogd at ERROR level * ***********************************************************************/ void LogError( char *p ) { LogIt( LOG_ERR, p ); } /*********************************************************************** * * LogIt - writes text p to syslogd at the specified error level * ***********************************************************************/ void LogIt( int level, char *p ) { static char text[MAX_SYSLOG_BUFFER+1]; int size; /* make it fit, buffer overflow is a BAD thing */ size = strlen(p); if ( size > MAX_SYSLOG_TEXT ) p[MAX_SYSLOG_TEXT] = '\0'; /* format the actual syslog message and log it */ /* * WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! * * if you modify this format string, see the define for * MAX_SYSLOG_BUFFER. */ sprintf( text, "%s [%d] (port %d) - %s", MyName, MyPid, MyPort, p ); syslog( level, text ); } --=====================_796427355==_--