home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-11-23 | 74.7 KB | 2,734 lines |
- Newsgroups: comp.sources.misc
- From: vikas@jvnc.net (Vikas Aggarwal)
- Subject: v40i144: nocol - Network Monitoring System, Part14/26
- Message-ID: <1993Nov23.212634.21638@sparky.sterling.com>
- X-Md4-Signature: 9004fe9c9d9e5502cd084247d7e86f21
- Sender: kent@sparky.sterling.com (Kent Landfield)
- Organization: Sterling Software
- Date: Tue, 23 Nov 1993 21:26:34 GMT
- Approved: kent@sparky.sterling.com
-
- Submitted-by: vikas@jvnc.net (Vikas Aggarwal)
- Posting-number: Volume 40, Issue 144
- Archive-name: nocol/part14
- Environment: INET, UNIX
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # Contents: nocol-3.0/src/cmu-snmp/include/asn1.c
- # nocol-3.0/src/noclog/noclogd.c nocol-3.0/src/portmon/portmon.c
- # nocol-3.0/src/support/mping/brl-ping.c
- # Wrapped by kent@sparky on Tue Nov 9 22:22:19 1993
- PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 14 (of 26)."'
- if test -f 'nocol-3.0/src/cmu-snmp/include/asn1.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'nocol-3.0/src/cmu-snmp/include/asn1.c'\"
- else
- echo shar: Extracting \"'nocol-3.0/src/cmu-snmp/include/asn1.c'\" \(18366 characters\)
- sed "s/^X//" >'nocol-3.0/src/cmu-snmp/include/asn1.c' <<'END_OF_FILE'
- X/*
- X * Abstract Syntax Notation One, ASN.1
- X * As defined in ISO/IS 8824 and ISO/IS 8825
- X * This implements a subset of the above International Standards that
- X * is sufficient to implement SNMP.
- X *
- X * Encodes abstract data types into a machine independent stream of bytes.
- X *
- X */
- X/***********************************************************
- X Copyright 1988, 1989 by Carnegie Mellon University
- X
- X All Rights Reserved
- X
- XPermission to use, copy, modify, and distribute this software and its
- Xdocumentation for any purpose and without fee is hereby granted,
- Xprovided that the above copyright notice appear in all copies and that
- Xboth that copyright notice and this permission notice appear in
- Xsupporting documentation, and that the name of CMU not be
- Xused in advertising or publicity pertaining to distribution of the
- Xsoftware without specific, written prior permission.
- X
- XCMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
- XALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
- XCMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
- XANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
- XWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
- XARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- XSOFTWARE.
- X******************************************************************/
- X#ifdef KINETICS
- X#include "gw.h"
- X#endif
- X
- X#if (defined(unix) && !defined(KINETICS))
- X#include <sys/types.h>
- X#include <netinet/in.h>
- X#endif
- X
- X#include "asn1.h"
- X
- X#ifndef NULL
- X#define NULL 0
- X#endif
- X#define ERROR(x)
- X
- X/*
- X * asn_parse_int - pulls a long out of an ASN int type.
- X * On entry, datalength is input as the number of valid bytes following
- X * "data". On exit, it is returned as the number of valid bytes
- X * following the end of this object.
- X *
- X * Returns a pointer to the first byte past the end
- X * of this object (i.e. the start of the next object).
- X * Returns NULL on any error.
- X */
- Xu_char *
- Xasn_parse_int(data, datalength, type, intp, intsize)
- X register u_char *data; /* IN - pointer to start of object */
- X register int *datalength;/* IN/OUT - number of valid bytes left in buffer */
- X u_char *type; /* OUT - asn type of object */
- X long *intp; /* IN/OUT - pointer to start of output buffer */
- X int intsize; /* IN - size of output buffer */
- X{
- X/*
- X * ASN.1 integer ::= 0x02 asnlength byte {byte}*
- X */
- X register u_char *bufp = data;
- X u_long asn_length;
- X register long value = 0;
- X
- X if (intsize != sizeof (long)){
- X ERROR("not long");
- X return NULL;
- X }
- X *type = *bufp++;
- X bufp = asn_parse_length(bufp, &asn_length);
- X if (bufp == NULL){
- X ERROR("bad length");
- X return NULL;
- X }
- X if (asn_length + (bufp - data) > *datalength){
- X ERROR("overflow of message");
- X return NULL;
- X }
- X if (asn_length > intsize){
- X ERROR("I don't support such large integers");
- X return NULL;
- X }
- X *datalength -= (int)asn_length + (bufp - data);
- X if (*bufp & 0x80)
- X value = -1; /* integer is negative */
- X while(asn_length--)
- X value = (value << 8) | *bufp++;
- X *intp = value;
- X return bufp;
- X}
- X
- X
- X/*
- X * asn_build_int - builds an ASN object containing an integer.
- X * On entry, datalength is input as the number of valid bytes following
- X * "data". On exit, it is returned as the number of valid bytes
- X * following the end of this object.
- X *
- X * Returns a pointer to the first byte past the end
- X * of this object (i.e. the start of the next object).
- X * Returns NULL on any error.
- X */
- Xu_char *
- Xasn_build_int(data, datalength, type, intp, intsize)
- X register u_char *data; /* IN - pointer to start of output buffer */
- X register int *datalength;/* IN/OUT - number of valid bytes left in buffer */
- X u_char type; /* IN - asn type of object */
- X register long *intp; /* IN - pointer to start of long integer */
- X register int intsize; /* IN - size of *intp */
- X{
- X/*
- X * ASN.1 integer ::= 0x02 asnlength byte {byte}*
- X */
- X
- X register long integer;
- X register u_long mask;
- X
- X if (intsize != sizeof (long))
- X return NULL;
- X integer = *intp;
- X /*
- X * Truncate "unnecessary" bytes off of the most significant end of this 2's complement integer.
- X * There should be no sequence of 9 consecutive 1's or 0's at the most significant end of the
- X * integer.
- X */
- X mask = 0x1FF << ((8 * (sizeof(long) - 1)) - 1);
- X /* mask is 0xFF800000 on a big-endian machine */
- X while((((integer & mask) == 0) || ((integer & mask) == mask)) && intsize > 1){
- X intsize--;
- X integer <<= 8;
- X }
- X data = asn_build_header(data, datalength, type, intsize);
- X if (data == NULL)
- X return NULL;
- X if (*datalength < intsize)
- X return NULL;
- X *datalength -= intsize;
- X mask = 0xFF << (8 * (sizeof(long) - 1));
- X /* mask is 0xFF000000 on a big-endian machine */
- X while(intsize--){
- X *data++ = (u_char)((integer & mask) >> (8 * (sizeof(long) - 1)));
- X integer <<= 8;
- X }
- X return data;
- X}
- X
- X
- X/*
- X * asn_parse_string - pulls an octet string out of an ASN octet string type.
- X * On entry, datalength is input as the number of valid bytes following
- X * "data". On exit, it is returned as the number of valid bytes
- X * following the beginning of the next object.
- X *
- X * "string" is filled with the octet string.
- X *
- X * Returns a pointer to the first byte past the end
- X * of this object (i.e. the start of the next object).
- X * Returns NULL on any error.
- X */
- Xu_char *
- Xasn_parse_string(data, datalength, type, string, strlength)
- X u_char *data; /* IN - pointer to start of object */
- X register int *datalength; /* IN/OUT - number of valid bytes left in buffer */
- X u_char *type; /* OUT - asn type of object */
- X u_char *string; /* IN/OUT - pointer to start of output buffer */
- X register int *strlength; /* IN/OUT - size of output buffer */
- X{
- X/*
- X * ASN.1 octet string ::= primstring | cmpdstring
- X * primstring ::= 0x04 asnlength byte {byte}*
- X * cmpdstring ::= 0x24 asnlength string {string}*
- X * This doesn't yet support the compound string.
- X */
- X register u_char *bufp = data;
- X u_long asn_length;
- X
- X *type = *bufp++;
- X bufp = asn_parse_length(bufp, &asn_length);
- X if (bufp == NULL)
- X return NULL;
- X if (asn_length + (bufp - data) > *datalength){
- X ERROR("overflow of message");
- X return NULL;
- X }
- X if (asn_length > *strlength){
- X ERROR("I don't support such long strings");
- X return NULL;
- X }
- X bcopy((char *)bufp, (char *)string, (int)asn_length);
- X *strlength = (int)asn_length;
- X *datalength -= (int)asn_length + (bufp - data);
- X return bufp + asn_length;
- X}
- X
- X
- X/*
- X * asn_build_string - Builds an ASN octet string object containing the input string.
- X * On entry, datalength is input as the number of valid bytes following
- X * "data". On exit, it is returned as the number of valid bytes
- X * following the beginning of the next object.
- X *
- X * Returns a pointer to the first byte past the end
- X * of this object (i.e. the start of the next object).
- X * Returns NULL on any error.
- X */
- Xu_char *
- Xasn_build_string(data, datalength, type, string, strlength)
- X u_char *data; /* IN - pointer to start of object */
- X register int *datalength; /* IN/OUT - number of valid bytes left in buffer */
- X u_char type; /* IN - ASN type of string */
- X u_char *string; /* IN - pointer to start of input buffer */
- X register int strlength; /* IN - size of input buffer */
- X{
- X/*
- X * ASN.1 octet string ::= primstring | cmpdstring
- X * primstring ::= 0x04 asnlength byte {byte}*
- X * cmpdstring ::= 0x24 asnlength string {string}*
- X * This code will never send a compound string.
- X */
- X data = asn_build_header(data, datalength, type, strlength);
- X if (data == NULL)
- X return NULL;
- X if (*datalength < strlength)
- X return NULL;
- X bcopy((char *)string, (char *)data, strlength);
- X *datalength -= strlength;
- X return data + strlength;
- X}
- X
- X
- X/*
- X * asn_parse_header - interprets the ID and length of the current object.
- X * On entry, datalength is input as the number of valid bytes following
- X * "data". On exit, it is returned as the number of valid bytes
- X * in this object following the id and length.
- X *
- X * Returns a pointer to the first byte of the contents of this object.
- X * Returns NULL on any error.
- X */
- Xu_char *
- Xasn_parse_header(data, datalength, type)
- X u_char *data; /* IN - pointer to start of object */
- X int *datalength;/* IN/OUT - number of valid bytes left in buffer */
- X u_char *type; /* OUT - ASN type of object */
- X{
- X register u_char *bufp = data;
- X register header_len;
- X u_long asn_length;
- X
- X /* this only works on data types < 30, i.e. no extension octets */
- X if (IS_EXTENSION_ID(*bufp)){
- X ERROR("can't process ID >= 30");
- X return NULL;
- X }
- X *type = *bufp;
- X bufp = asn_parse_length(bufp + 1, &asn_length);
- X if (bufp == NULL)
- X return NULL;
- X header_len = bufp - data;
- X if (header_len + asn_length > *datalength){
- X ERROR("asn length too long");
- X return NULL;
- X }
- X *datalength = (int)asn_length;
- X return bufp;
- X}
- X
- X/*
- X * asn_build_header - builds an ASN header for an object with the ID and
- X * length specified.
- X * On entry, datalength is input as the number of valid bytes following
- X * "data". On exit, it is returned as the number of valid bytes
- X * in this object following the id and length.
- X *
- X * This only works on data types < 30, i.e. no extension octets.
- X * The maximum length is 0xFFFF;
- X *
- X * Returns a pointer to the first byte of the contents of this object.
- X * Returns NULL on any error.
- X */
- Xu_char *
- Xasn_build_header(data, datalength, type, length)
- X register u_char *data; /* IN - pointer to start of object */
- X int *datalength;/* IN/OUT - number of valid bytes left in buffer */
- X u_char type; /* IN - ASN type of object */
- X int length; /* IN - length of object */
- X{
- X if (*datalength < 1)
- X return NULL;
- X *data++ = type;
- X (*datalength)--;
- X return asn_build_length(data, datalength, length);
- X
- X}
- X
- X/*
- X * asn_parse_length - interprets the length of the current object.
- X * On exit, length contains the value of this length field.
- X *
- X * Returns a pointer to the first byte after this length
- X * field (aka: the start of the data field).
- X * Returns NULL on any error.
- X */
- Xu_char *
- Xasn_parse_length(data, length)
- X u_char *data; /* IN - pointer to start of length field */
- X u_long *length; /* OUT - value of length field */
- X{
- X register u_char lengthbyte = *data;
- X
- X if (lengthbyte & ASN_LONG_LEN){
- X lengthbyte &= ~ASN_LONG_LEN; /* turn MSb off */
- X if (lengthbyte == 0){
- X ERROR("We don't support indefinite lengths");
- X return NULL;
- X }
- X if (lengthbyte > sizeof(long)){
- X ERROR("we can't support data lengths that long");
- X return NULL;
- X }
- X bcopy((char *)data + 1, (char *)length, (int)lengthbyte);
- X *length = ntohl(*length);
- X *length >>= (8 * ((sizeof *length) - lengthbyte));
- X return data + lengthbyte + 1;
- X } else { /* short asnlength */
- X *length = (long)lengthbyte;
- X return data + 1;
- X }
- X}
- X
- Xu_char *
- Xasn_build_length(data, datalength, length)
- X register u_char *data; /* IN - pointer to start of object */
- X int *datalength;/* IN/OUT - number of valid bytes left in buffer */
- X register int length; /* IN - length of object */
- X{
- X u_char *start_data = data;
- X
- X /* no indefinite lengths sent */
- X if (length < 0x80){
- X *data++ = (u_char)length;
- X } else if (length <= 0xFF){
- X *data++ = (u_char)(0x01 | ASN_LONG_LEN);
- X *data++ = (u_char)length;
- X } else { /* 0xFF < length <= 0xFFFF */
- X *data++ = (u_char)(0x02 | ASN_LONG_LEN);
- X *data++ = (u_char)((length >> 8) & 0xFF);
- X *data++ = (u_char)(length & 0xFF);
- X }
- X if (*datalength < (data - start_data)){
- X ERROR("build_length");
- X return NULL;
- X }
- X *datalength -= (data - start_data);
- X return data;
- X
- X}
- X
- X/*
- X * asn_parse_objid - pulls an object indentifier out of an ASN object identifier type.
- X * On entry, datalength is input as the number of valid bytes following
- X * "data". On exit, it is returned as the number of valid bytes
- X * following the beginning of the next object.
- X *
- X * "objid" is filled with the object identifier.
- X *
- X * Returns a pointer to the first byte past the end
- X * of this object (i.e. the start of the next object).
- X * Returns NULL on any error.
- X */
- Xu_char *
- Xasn_parse_objid(data, datalength, type, objid, objidlength)
- X u_char *data; /* IN - pointer to start of object */
- X int *datalength; /* IN/OUT - number of valid bytes left in buffer */
- X u_char *type; /* OUT - ASN type of object */
- X oid *objid; /* IN/OUT - pointer to start of output buffer */
- X int *objidlength; /* IN/OUT - number of sub-id's in objid */
- X{
- X/*
- X * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
- X * subidentifier ::= {leadingbyte}* lastbyte
- X * leadingbyte ::= 1 7bitvalue
- X * lastbyte ::= 0 7bitvalue
- X */
- X register u_char *bufp = data;
- X register oid *oidp = objid + 1;
- X register u_long subidentifier;
- X register long length;
- X u_long asn_length;
- X
- X *type = *bufp++;
- X bufp = asn_parse_length(bufp, &asn_length);
- X if (bufp == NULL)
- X return NULL;
- X if (asn_length + (bufp - data) > *datalength){
- X ERROR("overflow of message");
- X return NULL;
- X }
- X *datalength -= (int)asn_length + (bufp - data);
- X
- X length = asn_length;
- X (*objidlength)--; /* account for expansion of first byte */
- X while (length > 0 && (*objidlength)-- > 0){
- X subidentifier = 0;
- X do { /* shift and add in low order 7 bits */
- X subidentifier = (subidentifier << 7) + (*(u_char *)bufp & ~ASN_BIT8);
- X length--;
- X } while (*(u_char *)bufp++ & ASN_BIT8); /* last byte has high bit clear */
- X if (subidentifier > (u_long)MAX_SUBID){
- X ERROR("subidentifier too long");
- X return NULL;
- X }
- X *oidp++ = (oid)subidentifier;
- X }
- X
- X /*
- X * The first two subidentifiers are encoded into the first component
- X * with the value (X * 40) + Y, where:
- X * X is the value of the first subidentifier.
- X * Y is the value of the second subidentifier.
- X */
- X subidentifier = (u_long)objid[1];
- X objid[1] = (u_char)(subidentifier % 40);
- X objid[0] = (u_char)((subidentifier - objid[1]) / 40);
- X
- X *objidlength = (int)(oidp - objid);
- X return bufp;
- X}
- X
- X/*
- X * asn_build_objid - Builds an ASN object identifier object containing the input string.
- X * On entry, datalength is input as the number of valid bytes following
- X * "data". On exit, it is returned as the number of valid bytes
- X * following the beginning of the next object.
- X *
- X * Returns a pointer to the first byte past the end
- X * of this object (i.e. the start of the next object).
- X * Returns NULL on any error.
- X */
- Xu_char *
- Xasn_build_objid(data, datalength, type, objid, objidlength)
- X register u_char *data; /* IN - pointer to start of object */
- X int *datalength; /* IN/OUT - number of valid bytes left in buffer */
- X u_char type; /* IN - ASN type of object */
- X oid *objid; /* IN - pointer to start of input buffer */
- X int objidlength; /* IN - number of sub-id's in objid */
- X{
- X/*
- X * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
- X * subidentifier ::= {leadingbyte}* lastbyte
- X * leadingbyte ::= 1 7bitvalue
- X * lastbyte ::= 0 7bitvalue
- X */
- X u_char buf[MAX_OID_LEN];
- X u_char *bp = buf;
- X oid objbuf[MAX_OID_LEN];
- X oid *op = objbuf;
- X register int asnlength;
- X register u_long subid, mask, testmask;
- X register int bits, testbits;
- X
- X bcopy((char *)objid, (char *)objbuf, objidlength * sizeof(oid));
- X /* transform size in bytes to size in subid's */
- X /* encode the first two components into the first subidentifier */
- X op[1] = op[1] + (op[0] * 40);
- X op++;
- X objidlength--;
- X
- X while(objidlength-- > 0){
- X subid = *op++;
- X mask = 0x7F; /* handle subid == 0 case */
- X bits = 0;
- X /* testmask *MUST* !!!! be of an unsigned type */
- X for(testmask = 0x7F, testbits = 0; testmask != 0; testmask <<= 7, testbits += 7){
- X if (subid & testmask){ /* if any bits set */
- X mask = testmask;
- X bits = testbits;
- X }
- X }
- X /* mask can't be zero here */
- X for(;mask != 0x7F; mask >>= 7, bits -= 7){
- X if (mask == 0x1E00000) /* fix a mask that got truncated above */
- X mask = 0xFE00000;
- X *bp++ = (u_char)(((subid & mask) >> bits) | ASN_BIT8);
- X }
- X *bp++ = (u_char)(subid & mask);
- X }
- X asnlength = bp - buf;
- X data = asn_build_header(data, datalength, type, asnlength);
- X if (data == NULL)
- X return NULL;
- X if (*datalength < asnlength)
- X return NULL;
- X bcopy((char *)buf, (char *)data, asnlength);
- X *datalength -= asnlength;
- X return data + asnlength;
- X}
- X
- X/*
- X * asn_parse_null - Interprets an ASN null type.
- X * On entry, datalength is input as the number of valid bytes following
- X * "data". On exit, it is returned as the number of valid bytes
- X * following the beginning of the next object.
- X *
- X * Returns a pointer to the first byte past the end
- X * of this object (i.e. the start of the next object).
- X * Returns NULL on any error.
- X */
- Xu_char *
- Xasn_parse_null(data, datalength, type)
- X u_char *data; /* IN - pointer to start of object */
- X int *datalength; /* IN/OUT - number of valid bytes left in buffer */
- X u_char *type; /* OUT - ASN type of object */
- X{
- X/*
- X * ASN.1 null ::= 0x05 0x00
- X */
- X register u_char *bufp = data;
- X u_long asn_length;
- X
- X *type = *bufp++;
- X bufp = asn_parse_length(bufp, &asn_length);
- X if (bufp == NULL)
- X return NULL;
- X if (asn_length != 0){
- X ERROR("Malformed NULL");
- X return NULL;
- X }
- X *datalength -= (bufp - data);
- X return bufp + asn_length;
- X}
- X
- X
- X/*
- X * asn_build_null - Builds an ASN null object.
- X * On entry, datalength is input as the number of valid bytes following
- X * "data". On exit, it is returned as the number of valid bytes
- X * following the beginning of the next object.
- X *
- X * Returns a pointer to the first byte past the end
- X * of this object (i.e. the start of the next object).
- X * Returns NULL on any error.
- X */
- Xu_char *
- Xasn_build_null(data, datalength, type)
- X u_char *data; /* IN - pointer to start of object */
- X int *datalength; /* IN/OUT - number of valid bytes left in buffer */
- X u_char type; /* IN - ASN type of object */
- X{
- X/*
- X * ASN.1 null ::= 0x05 0x00
- X */
- X return asn_build_header(data, datalength, type, 0);
- X}
- X
- END_OF_FILE
- if test 18366 -ne `wc -c <'nocol-3.0/src/cmu-snmp/include/asn1.c'`; then
- echo shar: \"'nocol-3.0/src/cmu-snmp/include/asn1.c'\" unpacked with wrong size!
- fi
- # end of 'nocol-3.0/src/cmu-snmp/include/asn1.c'
- fi
- if test -f 'nocol-3.0/src/noclog/noclogd.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'nocol-3.0/src/noclog/noclogd.c'\"
- else
- echo shar: Extracting \"'nocol-3.0/src/noclog/noclogd.c'\" \(18084 characters\)
- sed "s/^X//" >'nocol-3.0/src/noclog/noclogd.c' <<'END_OF_FILE'
- X/* $Header: /home/aggarwal/lsrc/nocol/src/noclog/RCS/noclogd.c,v 3.3 1993/10/30 03:47:19 aggarwal Exp $ */
- X
- X/* Copyright 1993 JvNCnet, Global Enterprise Services */
- X
- X/*
- X * AUTHOR
- X * David Wagner, wagner@jvnc.net
- X * Vikas Aggarwal, vikas@jvnc.net
- X */
- X
- X/*
- X * DESCRIPTION
- X * A logging daemon for the nocol monitor programs; not unlike
- X * syslogd, it selectively records EVENT structures sent over
- X * a socket by the nocol programs.
- X *
- X * The config file can also pipe the output to another program.
- X * Remember to use 'cat' since the EVENT strcuture will
- X * be piped to the executable and NOT sent over as command line
- X * argument.
- X */
- X
- X/*
- X * BUGS
- X * Can't handle too many connections in a short period of time:
- X * should be able to handle (say) 100 per second just fine, though.
- X */
- X
- X/*
- X * $Log: noclogd.c,v $
- X * Revision 3.3 1993/10/30 03:47:19 aggarwal
- X * Small problems in pointer passing in authenticate_host(). Also
- X * does a 'getsockopt()' to set the socket buffer size if possible.
- X * Cleaned up code for auto closing a stream on error.
- X *
- X * Revision 3.2 1993/10/02 05:31:06 aggarwal
- X * Moved the function to convert event to logstring into the nocol
- X * library.
- X *
- X * Revision 3.1 1993/09/22 20:24:36 aggarwal
- X * Deleted 'tag' from the print statement.
- X * Not used in the nocol struct yet.
- X *
- X * Revision 3.0 1993/09/21 18:40:42 aggarwal
- X * Deleted the code for the Unix socket. Tested, seems ready to go out.
- X *
- X * Revision 2.0 1993/09/18 21:41:38 aggarwal
- X * This version 2.0 tries to use STREAM unix sockets and DGRAM inet
- X * sockets (use of dgram unix sockets is not recommended due to
- X * buffering and data overflow problems).
- X *
- X * However, the nature of the client logging is of the un-connected
- X * type- since this didn't work in the stream connected environment,
- X * this idea is being shelved.
- X *
- X * Revision 1.16 1993/09/16 23:45:28 aggarwal
- X * Added macro to use 'pclose' instead of 'fclose' on receiving SIGHUP
- X *
- X * Revision 1.14 1993/09/14 21:32:36 aggarwal
- X * Changed 'read' to recvfrom() for UDP sockets.
- X * Also alarms for timeouts, and security for IP connections.
- X *
- X * Revision 1.6 1993/03/04 06:37:09 wagner
- X * SOCK_STREAM became SOCK_DGRAM. Started using select(). No more forking.
- X *
- X * Revision 1.3 1992/10/29 20:59:37 wagner
- X * Added ability to pipe log output to a pipe.
- X *
- X * Revision 1.2 1992/10/29 20:06:51 wagner
- X * Now reads a config file to determine where to log the EVENTs to.
- X *
- X * Revision 1.1 1992/10/29 18:23:02 wagner
- X * Initial revision
- X *
- X */
- X
- X#include "noclogd.h"
- X
- X#define READ_TIMEOUT 5 /* timeout for read() from sockets */
- X
- Xtypedef struct node_s {
- X char *sender; /* for comparing EVENT.sender */
- X char *path; /* Filename in char format */
- X FILE *stream; /* Opened stream */
- X int isapipe; /* True if output is a pipe */
- X int loglevel ; /* Log level for this stream */
- X struct node_s *next; /* Linked list */
- X} node;
- X
- Xstatic node *loglist=NULL;
- Xstatic int debugflag, mypid=0;
- Xstatic char *myname, *configfilename, *errfilename ;
- Xstatic int sighupflag=0, alarmflag=0 ;
- Xstatic unsigned long permithosts[50] ; /* list of hosts */
- X
- Xvoid sighuphandler(), alarm_intr();
- Xchar *event_to_logstr(); /* format event in string format */
- X
- Xint main(argc, argv)
- X int argc;
- X char **argv;
- X{
- X extern char *optarg;
- X extern int optind;
- X char *pidfilename= NULL;
- X int c ;
- X FILE *pidstream;
- X
- X /* For fatal(): currently no error condition */
- X myname = NULL;
- X mypid = 0;
- X errno = 0;
- X
- X /* Save the program name */
- X if ((myname = (char *)strrchr (argv[0], '/')) == NULL)
- X myname = argv[0] ; /* no path in program name */
- X else
- X myname++ ; /* skip leading '/' */
- X
- X
- X /* Parse the command line arguments; does no error checking */
- X debugflag = 0;
- X
- X while ((c = getopt(argc, argv, "de:f:p:")) != EOF)
- X switch(c)
- X {
- X case 'd':
- X debugflag++;
- X break;
- X case 'e':
- X errfilename = optarg ;
- X break ;
- X case 'f':
- X configfilename = optarg ;
- X break ;
- X case '?':
- X default:
- X fprintf(stderr, "%s: Unknown flag: %c\n", myname, optarg);
- X fprintf(stderr, "Usage: %s [-d] [-f <config file>] ", myname);
- X fprintf(stderr, "[-e <error filename>]\n");
- X exit (1);
- X }
- X
- X /* Set the default values. There is a reason for this madness */
- X if (errfilename == NULL)
- X NLOG_ERRORFILE( (errfilename = malloc(256)) );
- X if (configfilename == NULL)
- X NLOG_CONFIGFILE( (configfilename = malloc(256)) );
- X if (pidfilename == NULL)
- X NLOG_PIDFILE( (pidfilename = malloc(256)) );
- X
- X /* Set the umask so error files and PID files aren't world writeable*/
- X (void) umask(NLOG_UMASK);
- X
- X fprintf(stderr,"%s (info): LOGHOST is defined to be '%s'\n",
- X myname, NLOG_HOST);
- X fprintf(stderr,"Make sure logging daemon runs on this host\n\n");
- X
- X /* Become a daemon */
- X if (debugflag)
- X {
- X fprintf(stderr, "%s: DEBUG ON, server not daemon-izing\n",myname);
- X fprintf(stderr, " configf= '%s', errfile= '%s'\n\n",
- X configfilename, errfilename);
- X#ifndef DEBUG
- X fprintf(stderr,"%s: WARNING- program NOT compiled with DEBUG option\n",
- X myname);
- X#endif
- X }
- X else
- X daemon();
- X
- X /* Store away my current PID - this must be done after the daemon() call */
- X mypid = (int) getpid();
- X if ((pidstream=fopen(pidfilename, "w")) == NULL)
- X fatal("fopen() failed for PID file");
- X else
- X {
- X char myhostname[256];
- X gethostname(myhostname, sizeof(myhostname) -1) ;
- X myhostname[sizeof(myhostname) - 1] = '\0' ;
- X fprintf(pidstream, "%d\n%s\n", mypid, myhostname);
- X fclose(pidstream);
- X }
- X
- X /* Read the configuration file; good idea to do this after daemon() call */
- X openlogfiles();
- X
- X /* Set up the signal handler */
- X sighupflag = 0;
- X (void) signal(SIGHUP, sighuphandler);
- X
- X /* And do all the socket stuff - this never returns */
- X serve();
- X
- X /*NOTREACHED*/
- X}
- X
- X/*
- X * Opens a UDP logging socket, binds to it, and selects on it
- X * until some data appears. Then processes all data that comes
- X * in and logs it into the appropriate file. It never returns,
- X * but dies on error.
- X */
- Xserve()
- X{
- X int inetfd, nfds, sockbuffsize, optlen ;
- X struct sockaddr_in sin;
- X struct servent *sp;
- X fd_set readfds;
- X
- X /*
- X * Open the network logging socket
- X */
- X if ((inetfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
- X fatal("serve(): network socket() failed");
- X
- X optlen = 0;
- X getsockopt(inetfd, /* level */SOL_SOCKET, /* optname */SO_RCVBUF,
- X (char *)&sockbuffsize, &optlen);
- X#ifdef DEBUG
- X if (debugflag)
- X fprintf(stderr, "(debug) old inetfd RCVBUF size= %d\n", sockbuffsize);
- X#endif
- X if (sockbuffsize < 65534)
- X {
- X sockbuffsize = 65534 ;
- X setsockopt(inetfd, /* level */ SOL_SOCKET, /* optname */SO_RCVBUF,
- X (char *)&sockbuffsize, sizeof sockbuffsize );
- X }
- X if (debugflag)
- X {
- X optlen = 0 ;
- X getsockopt(inetfd, SOL_SOCKET, SO_RCVBUF, (char *)&sockbuffsize,
- X &optlen);
- X fprintf(stderr,
- X "(debug) inetfd RCVBUF size set to %d\n", sockbuffsize);
- X }
- X
- X bzero((char *) &sin, sizeof (sin)) ; /* important */
- X sin.sin_family = AF_INET;
- X /* Figure out what port number to use */
- X if ((sp=getservbyname(myname, "udp")) == NULL)
- X sp = getservbyname(NLOG_SERVICE, "udp");
- X if (sp == NULL)
- X sin.sin_port = htons(NLOG_PORT);
- X else
- X sin.sin_port = sp->s_port;
- X
- X /* And do the bind() */
- X if (bind(inetfd, (struct sockaddr *) &sin, sizeof(sin)) < 0)
- X fatal("serve(): couldn't bind to network socket");
- X
- X if(debugflag)
- X fprintf(stderr, " INET socket fd= %d\n", inetfd);
- X
- X /* Start waiting for log messages */
- X for (;;) {
- X if (sighupflag)
- X {
- X rereadconfig();
- X sighupflag = 0;
- X }
- X
- X /* We're gonna check this after the select, so clear it now... */
- X errno = 0;
- X
- X FD_ZERO(&readfds);
- X FD_SET(inetfd, &readfds);
- X nfds = select(FD_SETSIZE, &readfds, (fd_set *) NULL, (fd_set *) NULL,
- X (struct timeval *) NULL);
- X
- X /*
- X * The select should only return with nothing to read from
- X * if we got a SIGHUP...
- X */
- X if (errno == EINTR)
- X continue;
- X else if (nfds <= 0)
- X fatal("serve(): select() failed");
- X
- X if (FD_ISSET(inetfd, &readfds)) /* Inet dgram socket */
- X readevent(inetfd);
- X
- X }
- X /*NOTREACHED*/
- X}
- X
- X
- X/*
- X * Reads in one EVENT structure and logs it to the appropriate stream,
- X * based on the contents of loglist. Openlogfiles() must have been
- X * called first. Dies upon error.
- X */
- Xreadevent(fd)
- X int fd; /* socket file desc */
- X{
- X register char *r, *s;
- X int n, len ;
- X EVENT v;
- X char from[sizeof(v.sender)+1];
- X register node *p;
- X struct sockaddr_in frominet;
- X
- X len = sizeof (frominet);
- X
- X /* Try to read an EVENT structure in */
- X signal(SIGALRM, alarm_intr);
- X alarmflag = 0 ;
- X alarm(READ_TIMEOUT*10);
- X
- X n = recvfrom(fd, (char *)&v, sizeof(v), 0,
- X (struct sockaddr *)&frominet, &len );
- X if (n != sizeof(v))
- X {
- X if (alarmflag)
- X fprintf(stderr, "%s readevent: socket read timed out\n", myname);
- X else
- X fprintf(stderr,"%s readevent: socket read failed (incomplete)-- %s",
- X myname, sys_errlist[errno]);
- X
- X alarm(0); /* turn alarm off */
- X return(1) ; /* go back to waiting */
- X }
- X signal(SIGALRM, SIG_IGN); /* ignore alarm */
- X alarm(0) ;
- X
- X#ifdef DEBUG
- X if (debugflag)
- X fprintf(stderr, "Recvd packet, sender '%s', loglevel '%d'\n",
- X v.sender, v.loglevel);
- X#endif
- X
- X /*
- X * The rest of this should be fast, perhaps done in a forked child ?
- X */
- X if (! authenticate_host(&frominet))
- X return(1) ; /* illegal host */
- X
- X /* Make sure things aren't case sensitive */
- X for (r=v.sender, s=from; *r; )
- X *s++ = tolower(*r++);
- X *s = '\0';
- X
- X /*
- X * Check the linked list and log it to all applicable streams.
- X * For speed, check,,,
- X * log level first
- X * sender (takes longer since it is a string cmp)
- X * Log to all streams at priority EVENT.loglevel and higher.
- X */
- X for (p=loglist; p; p=p->next)
- X if ((int)v.loglevel <= p->loglevel)
- X if (strcmp(p->sender, "*") == 0 || strstr(from, p->sender))
- X {
- X /* Stream closed, try opening it.*/
- X if (!p->stream)
- X {
- X#ifdef DEBUG
- X if (debugflag)
- X fprintf(stderr, "Opening stream '%s'\n", p->path);
- X#endif
- X
- X if (p->isapipe)
- X p->stream = popen(p->path, "w");
- X else
- X p->stream = fopen(p->path, "a");
- X
- X if (! p->stream) /* if the stream could not be reopened */
- X {
- X fprintf(stderr, "%s: Could not open stream `%s'- ",
- X myname, p->path);
- X perror ("");
- X fflush(stderr);
- X continue ;
- X }
- X }
- X
- X
- X if (fprintf(p->stream, event_to_logstr(&v)) == EOF) /* error */
- X {
- X perror(p->path);
- X fflush(stderr) ;
- X p->isapipe ? fclose(p->stream) : pclose(p->stream);
- X p->stream = NULL ; /* try reopening next time */
- X continue ; /* Next for() */
- X }
- X
- X fflush(p->stream);
- X
- X if (p->isapipe) /* close and reopen every time ? */
- X {
- X pclose(p->stream);
- X p->stream = NULL; /* reset */
- X }
- X
- X
- X } /* end: if (stream closed, try reopening it) */
- X
- X} /* end readevent() */
- X
- X
- X/*+
- X * Authenticate hosts. Check to see if the sender has an IP address in
- X * the list from the config file. The argument is the socket file
- X * descriptor which *must* be of the INET type - not a Unix type.
- X *
- X * A = MASK & A
- X *
- X * Return 1 if OKAY, 0 if not
- X */
- Xauthenticate_host(peer)
- X struct sockaddr_in *peer ; /* typecast from sockaddr to sockaddr_in */
- X{
- X struct sockaddr_in s ;
- X int i ;
- X
- X if (peer == NULL)
- X return (0);
- X
- X for (i = 0; permithosts[i] != 0 ; ++i)
- X if (permithosts[i] == (unsigned long) peer->sin_addr.s_addr)
- X return(1) ;
- X
- X fprintf(stderr, "%s: Permission denied for host %s\n",
- X myname, inet_ntoa(peer->sin_addr));
- X
- X return (0);
- X}
- X
- X
- X/*+
- X * Allocates space for a new node, initializes it's fields, and
- X * inserts it into the beginning of loglist (since it is easier).
- X * Dies upon error.
- X */
- Xnode *insert(sender, path)
- X char *sender, *path;
- X{
- X node *new;
- X int i;
- X char *p;
- X
- X new = (node *) malloc(sizeof(node));
- X if (new == NULL)
- X fatal("insert(): out of memory");
- X bzero(new, sizeof(*new));
- X
- X new->next = loglist;
- X new->sender = (char *) malloc(strlen(sender)+1);
- X new->path = (char *) malloc(strlen(path)+1);
- X if (new->sender == NULL || new->path == NULL)
- X fatal("insert(): out of memory using malloc");
- X for (p=new->sender; *sender; sender++)
- X *p++ = tolower(*sender);
- X *p++ = '\0';
- X
- X if (*path == '|') /* pipe */
- X strcpy(new->path, path+1) , new->isapipe = 1 ;
- X else
- X strcpy(new->path, path);
- X
- X loglist = new; /* point to the new node */
- X return(new);
- X}
- X
- X/*
- X * Reads in a configuration file and opens the log files named there
- X * for output. Also writes to pipes instead of a log file if requested.
- X *
- X * PERMITHOSTS addr addr addr
- X * EVENT.sender min-log-severity Log-filename
- X * EVENT.sender min-log-severity |execute-filename
- X *
- X * Dies upon failure.
- X */
- Xopenlogfiles()
- X{
- X char line[1024], *progstr, *sevstr, *filestr, *p, *q;
- X FILE *config;
- X int level, linenum, i;
- X node *new;
- X
- X /* Sanity check */
- X if (loglist)
- X fatal("openlogfiles(): already a list of open files");
- X if ((config = fopen(configfilename, "r")) == NULL)
- X {
- X fprintf (stderr, "confile file '%s': ", configfilename);
- X fatal("openlogfiles(): couldn't fopen() ");
- X }
- X
- X
- X i = 0;
- X for (linenum=0; fgets(line, sizeof(line)-1, config) != NULL; linenum++)
- X {
- X
- X line[strlen(line)-1] = '\0'; /* Strip off '\n' at end of line */
- X
- X if ((p=strchr(line, '#')) != NULL) /* Get rid of comments */
- X *p = '\0';
- X
- X /* Parse the line into fields */
- X if (*line == NULL || (progstr=strtok(line, " \t")) == NULL)
- X continue;
- X else if (strncasecmp("PERMITHOST", line, strlen("PERMITHOST")) == 0)
- X {
- X while ((q = strtok(NULL, " \t")) != NULL)
- X {
- X permithosts[i++] = inet_addr(q);
- X if (debugflag)
- X fprintf(stderr, "Added %s to permithosts list\n", q);
- X } /* end while() */
- X continue ;
- X }
- X
- X else if ((sevstr=strtok(NULL, " \t")) == NULL) {
- X warning_int("config line %d: no severity string, ignoring...\n",
- X linenum);
- X continue;
- X } else if ((filestr=strtok(NULL, " \t")) == NULL) {
- X warning_int("config line %d: no logfile, ignoring...\n", linenum);
- X continue;
- X }
- X
- X /* Figure out what severity we're at */
- X level = -1;
- X switch(tolower(sevstr[0])) {
- X case 'c': case '1': level = E_CRITICAL; break;
- X case 'e': case '2': level = E_ERROR; break;
- X case 'w': case '3': level = E_WARNING; break;
- X case 'i': case '4': level = E_INFO; break;
- X }
- X if (level == -1) {
- X warning_int("config line %d: bad severity, ignoring...\n", linenum);
- X continue;
- X }
- X
- X /* Create and insert a new node into the linked list */
- X new = insert(progstr, filestr);
- X new->loglevel = level ;
- X }
- X
- X fclose(config); /* close config file */
- X permithosts[i] = 0 ; /* null the last one */
- X}
- X
- X/*
- X * Reread the configuration file. Called whenever SIGHUP is recieved.
- X */
- Xrereadconfig()
- X{
- X time_t locclock;
- X char *s;
- X register node *p, *q;
- X
- X locclock = time((time_t *)NULL);
- X s = (char *)ctime(&locclock);
- X *(strchr(s, '\n')) = '\0' ; /* get rid of the newline */
- X fprintf(stderr, "%s (%d) %s: Closing streams & Re-reading config file\n",
- X myname, mypid, s);
- X for (p = loglist; p; p=q)
- X {
- X q = p->next;
- X if (p->stream)
- X {
- X fflush(p->stream);
- X p->isapipe ? pclose(p->stream) : fclose(p->stream);
- X }
- X
- X if (p->sender != NULL)
- X free(p->sender);
- X if (p->path != NULL)
- X free(p->path);
- X free(p);
- X }
- X
- X loglist = NULL;
- X
- X openlogfiles();
- X}
- X
- X/*
- X * Become a daemon: go into the background, reset our process group,
- X * and clobber the current directory and stdin, stdout, stderr.
- X * Ideas for what needs to be done more or less stolen from BSD sources.
- X * Exits on failure, and complains vigorously!
- X */
- Xdaemon()
- X{
- X int retval, fd, errfd;
- X
- X if ((retval=fork()) < 0) /* Go into the background */
- X fatal("daemon(): fork() failed");
- X else if (retval)
- X exit(0);
- X
- X if ((int) setsid() < 0) /* Reset the process group */
- X fatal("daemon(): setsid() failed");
- X
- X if (chdir(ETCDIR) < 0) /* Clobber current directory */
- X if (chdir("/") < 0)
- X fatal("daemon(): chdir() failed");
- X
- X fd = open("/dev/null", O_RDWR, 0); /* Clobber stdin, stdout, .. */
- X errfd = open(errfilename, O_CREAT | O_APPEND | O_WRONLY, 0644);
- X if (fd < 0 || errfd < 0)
- X fatal("daemon(): open() failed for errorfile");
- X if (dup2(fd, 0) < 0 || dup2(errfd, 1) < 0)
- X fatal("daemon(): dup2() failed");
- X
- X /* Not much we can do if this dup2 fails - oh well, gotta ignore it */
- X (void) dup2(errfd, 2);
- X
- X if ((fd > 2 && close(fd) < 0) || (errfd > 2 && close(errfd) < 0))
- X fatal("daemon(): close() failed");
- X
- X signal(SIGALRM, SIG_IGN); /* ignore alarms until desired */
- X}
- X
- X/*
- X * Outputs an error message to stderr. Records the daemon's name and
- X * PID, if available. Prints out the error message corresponding to
- X * errno, if errno is set. Exits with return value 1.
- X */
- Xfatal(msg)
- X char *msg;
- X{
- X if (myname)
- X fprintf(stderr, "%s: ", myname);
- X if (mypid)
- X fprintf(stderr, "(%d) ", mypid);
- X if (errno)
- X perror(msg);
- X else
- X fprintf(stderr, "%s\n", msg);
- X
- X exit(1);
- X}
- X
- X
- X
- X/*
- X * Outputs a warning message to stderr. Records the daemon's name and
- X * PID, if available. Prints out the error message corresponding to
- X * errno, if errno is set. Does not exit.
- X *
- X * Assumes that 'format' is a valid fprintf format string that requires
- X * only one argument, the integer 'num'.
- X */
- Xwarning_int(format, num)
- X char *format;
- X int num;
- X{
- X if (myname)
- X fprintf(stderr, "%s: ", myname);
- X if (mypid)
- X fprintf(stderr, "(%d) ", mypid);
- X fprintf(stderr, format, num);
- X if (errno)
- X perror((char *) NULL);
- X else
- X fprintf(stderr, "\n");
- X}
- X
- X/*
- X * On receiving an alarm, simply set the flag and return
- X */
- Xvoid alarm_intr()
- X{
- X alarmflag = 1 ;
- X}
- X
- X/*
- X * Sets the sighupflag whenever we get a SIGHUP signal.
- X */
- Xvoid sighuphandler()
- X{
- X sighupflag = 1;
- X}
- X
- END_OF_FILE
- if test 18084 -ne `wc -c <'nocol-3.0/src/noclog/noclogd.c'`; then
- echo shar: \"'nocol-3.0/src/noclog/noclogd.c'\" unpacked with wrong size!
- fi
- # end of 'nocol-3.0/src/noclog/noclogd.c'
- fi
- if test -f 'nocol-3.0/src/portmon/portmon.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'nocol-3.0/src/portmon/portmon.c'\"
- else
- echo shar: Extracting \"'nocol-3.0/src/portmon/portmon.c'\" \(15152 characters\)
- sed "s/^X//" >'nocol-3.0/src/portmon/portmon.c' <<'END_OF_FILE'
- X/* $Header: /home/aggarwal/lsrc/nocol/src/portmon/RCS/portmon.c,v 1.2 1993/11/03 20:51:03 aggarwal Exp $ */
- X
- X/* Copyright 1993 JvNCnet, Global Enterprise Services */
- X
- X/*+ portmon
- X * FUNCTION:
- X * Monitor TCP ports and reponses for NOCOL. It can send a string
- X * and then parse the responses against a list. Each response can be
- X * assigned a severity.
- X *
- X * CAVEATS:
- X * 1) Uses 'strstr' and not a real regular expression. Case sensitive
- X *
- X * Vikas Aggarwal, -vikas@jvnc.net
- X */
- X
- X/*
- X * $Log: portmon.c,v $
- X * Revision 1.2 1993/11/03 20:51:03 aggarwal
- X * Added ifdef for h_addr (defined in netdb.h) in case its defined.
- X *
- X * Revision 1.1 1993/10/30 03:39:04 aggarwal
- X * Initial revision
- X *
- X */
- X
- X/* */
- X#ifndef lint
- X static char rcsid[] = "$Id: portmon.c,v 1.2 1993/11/03 20:51:03 aggarwal Exp $" ;
- X#endif
- X
- X#include "portmon.h"
- X
- Xstatic char *myname;
- Xstatic int debugflag, maxseverity, fdout, pollinterval ;
- Xstatic int gotalarm, sock ;
- Xstatic char *configfile ;
- Xstatic char *sender, *datafile ;
- X
- Xstatic void done(), usr1_handler(), alarm_handler();
- Xextern char *skip_spaces() ; /* in libnocol */
- X
- Xmain(ac, av)
- X int ac;
- X char **av;
- X{
- X extern char *optarg;
- X extern int optind;
- X int c ;
- X char *pf ; /* for pidfile in standalone */
- X
- X
- X if ((myname = (char *)strrchr (av[0], '/')) == NULL)
- X myname = av[0] ; /* no path in program name */
- X else
- X myname++ ; /* skip leading '/' */
- X
- X#ifdef SENDER
- X sender = SENDER ;
- X#else /* delete the directory name */
- X sender = myname ; /* no path in program name */
- X#endif
- X
- X /* the output data filename */
- X datafile = malloc (strlen(DATADIR)+ strlen(sender)+ strlen(OUTPUTEXT) +5);
- X sprintf(datafile, "%s/%s%s\0",
- X DATADIR, sender, OUTPUTEXT);
- X
- X configfile = CONFIGFILE ;
- X pollinterval = POLLINTERVAL ;
- X
- X while ((c = getopt(ac, av, "df:")) != EOF)
- X switch(c)
- X {
- X case 'd':
- X debugflag++;
- X break;
- X case 'f':
- X configfile = optarg ;
- X break ;
- X case '?':
- X default:
- X fprintf(stderr, "%s: Unknown flag: %c\n", myname, optarg);
- X fprintf(stderr, "Usage: %s [-d] [-f <config file>\n] ", myname);
- X exit (1);
- X }
- X
- X pf = malloc (strlen(myname) + strlen(ETCDIR) + 2) ;
- X sprintf(pf, "%s/%s\0", ETCDIR, myname) ;
- X if (standalone(pf) == -1) /* Kill prev running process */
- X {
- X fprintf(stderr, "%s: Error in standalone...exiting\n", myname);
- X exit (1);
- X }
- X else
- X free(pf) ; /* not needed anymore */
- X
- X if ( (fdout = open(datafile, O_RDWR | O_CREAT | O_TRUNC, 0664)) < 0)
- X {
- X fprintf(stderr, "(%s) ERROR in open datafile ", myname);
- X perror (datafile);
- X done();
- X }
- X
- X if (readconfig(fdout) == -1)
- X done();
- X
- X signal (SIGQUIT, done); /* Delete pid file while dying */
- X signal (SIGTERM, done);
- X signal (SIGINT, done);
- X signal (SIGHUP, done);
- X signal (SIGUSR1, usr1_handler); /* toggles debugging */
- X
- X redo:
- X lseek(fdout, (off_t)0, SEEK_SET); /* rewind file */
- X c = 0;
- X while (hostarray[c].hname)
- X {
- X int status ;
- X EVENT v;
- X
- X read(fdout, &v, sizeof v);
- X status = checkports(&(hostarray[c])) ;
- X if (status == -1)
- X fprintf (stderr, "%s: Error in checkports, skipping site %s\n",
- X myname, hostarray[c].hname);
- X else
- X {
- X update_event(&v, status, status, maxseverity) ;
- X lseek(fdout, -(off_t)sizeof(v), SEEK_CUR);
- X write(fdout, (char *)&v, sizeof(v));
- X }
- X ++c;
- X }
- X lseek(fdout, (off_t)0, SEEK_SET); /* rewind file */
- X
- X if (debugflag)
- X fprintf(stderr, "(debug) %s: sleeping for %d...zzz\n",
- X myname,pollinterval);
- X signal(SIGALRM, SIG_DFL); /* wake-up, in case blocked */
- X sleep (pollinterval);
- X goto redo ;
- X
- X} /* end: main() */
- X
- X
- X/*+
- X * FUNCTION:
- X * Checks the port for the structure _harray passed to it. Sets
- X * global maxseverity. Return value is the 'status' to be used in
- X * update_event().
- X */
- Xcheckports(h)
- X struct _harray *h;
- X{
- X int status;
- X char readbuf[BUFSIZ];
- X struct sockaddr_in sin;
- X
- X if (debugflag)
- X fprintf (stderr, "(debug) %s: Checking site '%s'/%d\n",
- X myname, h->hname, h->port);
- X
- X sock = socket(AF_INET, SOCK_STREAM, 0) ;
- X if (sock < 0)
- X {
- X perror("socket");
- X return (-1);
- X }
- X
- X bzero(&sin, sizeof(sin));
- X sin.sin_family = AF_INET;
- X
- X if (isdigit(*(h->ipaddr)) ) /* given an address, not a name */
- X sin.sin_addr.s_addr = inet_addr(h->ipaddr);
- X else
- X {
- X struct hostent *hp ;
- X if ((hp = gethostbyname(h->ipaddr)) == NULL)
- X {
- X perror(myname);
- X fprintf(stderr, "gethostbyname() failed for %s\n", h->ipaddr);
- X return(-1);
- X }
- X#ifdef h_addr /* in netdb.h */
- X sin.sin_addr.s_addr = inet_addr(hp->h_addr) ;
- X#else
- X sin.sin_addr.s_addr = inet_addr(hp->h_addr_list[0]) ;
- X#endif
- X }
- X
- X if (sin.sin_addr.s_addr == -1) /* error */
- X {
- X perror("inet_addr() failed");
- X return(-1); /* fatal error */
- X }
- X
- X
- X sin.sin_port = htons(h->port); /* port number to use */
- X
- X if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
- X {
- X if (debugflag)
- X perror("client: AF_INET connect() failed");
- X close(sock);
- X maxseverity = h->maxseverity;
- X return(0);
- X }
- X
- X if (h->send && *(h->send) != NULL) /* if something to send */
- X {
- X int n = timeout_read (readbuf, sizeof readbuf);
- X if (debugflag)
- X fprintf(stderr, " (debug) %s: ignoring connect string '%s'\n",
- X myname, readbuf );
- X
- X if (write(sock, h->send, strlen(h->send)) != strlen(h->send))
- X {
- X if (debugflag)
- X {
- X fprintf(stderr, "Sendstring error for '%s' port '%s'\n",
- X h->hname, h->port);
- X perror("write");
- X close (sock);
- X maxseverity = h->maxseverity;
- X return(0);
- X }
- X } /* end if (couldn't write) */
- X
- X write(sock, "\n", 1); /* send newline */
- X if (debugflag)
- X fprintf(stderr, " (debug) %s: sent string '%s' to %s...\n",
- X myname, h->send, h->hname) ;
- X
- X } /* end: if (something to send) */
- X
- X
- X if (h->responses[0].response) /* responses to check */
- X {
- X
- X if (timeout_read(readbuf, sizeof readbuf) <= 0)
- X {
- X if (debugflag)
- X fprintf(stderr, "readstring error for '%s' port '%d'",
- X h->hname, h->port);
- X if (gotalarm)
- X fprintf(stderr, "- timeout\n");
- X else
- X {
- X perror("read");
- X close (sock);
- X }
- X maxseverity = h->maxseverity;
- X return(0);
- X }
- X maxseverity = check_resp(readbuf, h->responses);
- X }
- X else
- X maxseverity = E_INFO ; /* Just had to check a 'connect' */
- X
- X if (maxseverity == -1) /* something failed, use default severity */
- X maxseverity = h->maxseverity ;
- X
- X close(sock);
- X if (debugflag)
- X fprintf(stderr, " (debug): returning severity %d\n", maxseverity) ;
- X if (maxseverity == E_INFO)
- X return(1);
- X else
- X return(0); /* status is down */
- X
- X} /* end: checkports() */
- X
- X/*+
- X * FUNCTION:
- X * Read from socket into buffer and put terminating NULL.
- X * Set alarm for timeout. Note that it is reading from 'global' sock
- X * descriptor (since the alarm closes it).
- X * Returns the number of bytes read.
- X *
- X */
- Xtimeout_read(buf, bufsiz)
- X char *buf;
- X int bufsiz ;
- X{
- X int n = 0, len = bufsiz ;
- X char *cp;
- X
- X cp = buf ;
- X
- X gotalarm = 0;
- X signal(SIGALRM, alarm_handler);
- X alarm(RTIMEOUT);
- X
- X /* read a LINE from global socket (until newline) */
- X while (len != 0 && (n = read (sock, cp, len)) > 0)
- X {
- X cp += (n - 1); /* increment pointer to last byte read */
- X len -= n;
- X if (*cp == '\n' || *cp == '\0')
- X break ;
- X else
- X cp++ ; /* increment past last byte read */
- X }
- X
- X signal (SIGALRM, SIG_IGN);
- X alarm (0); /* remember to unblock alarm */
- X
- X if (n <= 0)
- X len = -1 ; /* some error */
- X else
- X len = bufsiz - len ; /* Total number bytes read */
- X
- X if (debugflag)
- X fprintf(stderr, "(debug) timeout_read: Read %d bytes from socket\n",len);
- X
- X buf[len > 0 ? len:0] = '\0'; /* terminate with NULL */
- X
- X return (len); /* number bytes read else negative */
- X
- X} /* end: timeout_read() */
- X
- X
- X/*+
- X * FUNCTION:
- X * Check the list of responses
- X */
- Xcheck_resp(readstr, resarr)
- X char *readstr;
- X struct _response *resarr ;
- X{
- X
- X if (debugflag)
- X fprintf(stderr, " (debug) %s: Checking response '%s'\n", myname,readstr);
- X
- X while (resarr->response)
- X {
- X if (strstr(readstr, resarr->response) != NULL)
- X {
- X if (debugflag)
- X fprintf(stderr, " (debug) %s: Matched '%s'\n",
- X myname, resarr->response);
- X
- X return(resarr->severity);
- X }
- X
- X ++resarr ;
- X }
- X
- X if (debugflag)
- X fprintf (stderr, "%s: No response matched for site\n", myname);
- X
- X return(-1); /* No response matched given list */
- X} /* check_resp() */
- X
- X
- X/*+
- X * FUNCTION:
- X * Duplicate a string
- X */
- X
- Xchar *Strdup(s)
- X char *s ;
- X{
- X char *t ;
- X
- X t = malloc(strlen(s) + 1);
- X if (t != NULL)
- X (char *)strcpy(t, s);
- X
- X return (t);
- X}
- X
- X/*+
- X * FUNCTION:
- X * Read the config file.
- X * POLLINTERVAL ppp
- X * HOST <hostname> <address> <var> <port> <failseverity> "<send string>"
- X * <severity> "response1"
- X * <severity> "response2"
- X *
- X */
- X#define NEXTTOK (char *)skip_spaces(strtok(NULL, " \t"))
- X
- Xreadconfig(fdout)
- X int fdout ; /* output data filename */
- X{
- X int i = 0, j=0; /* array indexes */
- X int maxseverity ;
- X char *j1, *j2 ; /* temp string pointers */
- X FILE *cfd ;
- X EVENT v; /* Defined in NOCOL.H */
- X char record[MAXLINE] ;
- X struct tm *loctime ;
- X time_t locclock ; /* Careful, don't use 'long' */
- X
- X if ((cfd = fopen(configfile, "r")) == NULL)
- X {
- X fprintf(stderr, "%s error (init_sites) ", myname) ;
- X perror (configfile);
- X return (-1);
- X }
- X
- X /*
- X * Fill in the static data stuff
- X */
- X bzero ((char *)hostarray, sizeof(hostarray));
- X bzero (&v, sizeof(v)) ;
- X
- X locclock = time((time_t *)0);
- X loctime = localtime((long *)&locclock);
- X
- X v.mon = loctime->tm_mon + 1; v.day = loctime->tm_mday;
- X v.hour = loctime->tm_hour; v.min = loctime->tm_min;
- X
- X strncpy (v.sender, sender, sizeof(v.sender) - 1);
- X
- X strncpy (v.var.units, VARUNITS, sizeof (v.var.units) - 1);
- X v.var.threshold = 0 ;
- X
- X v.nocop = SETF_UPDOUN (0, n_UNKNOWN); /* Set all to UNKNOWN */
- X v.severity = E_INFO ;
- X
- X /*
- X * Now parse the config file
- X */
- X
- X while(fgetline(cfd,record,MAXLINE) > 0 ) /* keeps the \n */
- X {
- X static int skiphost;
- X int port ;
- X
- X record[strlen(record) -1] = '\0' ; /* chop off newline */
- X if (*record == '#' || *(skip_spaces(record)) == NULL)
- X continue ;
- X
- X if (strncasecmp(record, "POLLINTERVAL", strlen("POLLINTERVAL")) == 0)
- X {
- X strtok(record, " \t");
- X j1 = (char *)skip_spaces(strtok(NULL, "")) ;
- X if (j1 == NULL || *j1 == NULL || (pollinterval = atoi(j1)) <= 0)
- X fprintf(stderr, "%s: bad or missing pollinterval value\n",
- X myname);
- X
- X pollinterval = (pollinterval > 0 ? pollinterval : POLLINTERVAL);
- X if (debugflag)
- X fprintf (stderr, "(debug) %s: Pollinterval = %d\n",
- X myname, pollinterval);
- X
- X continue;
- X }
- X
- X
- X if (strncasecmp(record, "HOST", 4) != 0) /* Not HOST line */
- X {
- X if (skiphost)
- X continue ;
- X
- X j1 = strtok(record," \t") ; /* severity level */
- X j1 = (char *)skip_spaces(j1) ;
- X switch(tolower(*j1))
- X {
- X case 'c': case '1': maxseverity = E_CRITICAL; break;
- X case 'e': case '2': maxseverity = E_ERROR; break;
- X case 'w': case '3': maxseverity = E_WARNING; break;
- X case 'i': case '4': maxseverity = E_INFO; break;
- X default: maxseverity = E_CRITICAL; break ;
- X }
- X /* remember that the 'i' index has been incremented */
- X hostarray[i-1].responses[j].severity = maxseverity ;
- X j1 = (char *)skip_spaces(strtok(NULL, "")) ;
- X if (j1 == NULL)
- X {
- X fprintf(stderr, "%s: missing response line\n", myname);
- X continue;
- X }
- X hostarray[i-1].responses[j].response = (char *)Strdup(j1);
- X j++ ;
- X
- X continue ; /* next input line */
- X }
- X
- X /*
- X * Here if parsing a HOST line
- X */
- X j = 0; /* and reset the response array index */
- X
- X skiphost = 0; /* assume valid config */
- X strtok(record, " \t"); /* skip HOST keyword */
- X
- X strncpy(v.site.name, NEXTTOK, sizeof(v.site.name) - 1);
- X strncpy(v.site.addr, NEXTTOK, sizeof(v.site.addr) - 1);
- X if (inet_addr(v.site.addr) == -1) /* bad address */
- X {
- X fprintf(stderr,
- X "(%s): Error in addr '%s' for site '%s', ignoring\n",
- X myname, v.site.addr, v.site.name);
- X skiphost = 1;
- X continue ;
- X }
- X strncpy(v.var.name, NEXTTOK, sizeof(v.var.name) - 1);
- X
- X if ((port = atoi(NEXTTOK)) == 0)
- X {
- X fprintf(stderr,
- X "(%s): Error in port for site '%s', ignoring\n",
- X myname, v.site.name);
- X skiphost = 1;
- X continue ;
- X }
- X
- X j1 = NEXTTOK; /* severity level */
- X if (j1 == NULL)
- X j1 = "c";
- X switch(tolower(*j1))
- X {
- X case 'c': maxseverity = E_CRITICAL; break;
- X case 'e': maxseverity = E_ERROR; break;
- X case 'w': maxseverity = E_WARNING; break;
- X case 'i': maxseverity = E_INFO; break;
- X default: maxseverity = E_CRITICAL ; break ;
- X }
- X
- X if (debugflag)
- X fprintf (stderr, "Name: %s %s, VAR: %s, Port %d SEV: %d\n",
- X v.site.name,v.site.addr,v.var.name,
- X port,maxseverity);
- X
- X /* the rest of string is SEND */
- X j1 = (char *)skip_spaces(strtok(NULL, ""));
- X if (j1)
- X hostarray[i].send = (char *)Strdup(j1) ;
- X else
- X hostarray[i].send = NULL ; /* no SEND string */
- X
- X hostarray[i].port = port;
- X hostarray[i].maxseverity = maxseverity ;
- X hostarray[i].hname = (char *)Strdup(v.site.name);
- X hostarray[i].ipaddr = (char *)Strdup(v.site.addr);
- X bzero (hostarray[i].responses, sizeof (hostarray[i].responses));
- X
- X if (write (fdout, (char *)&v, sizeof(v)) != sizeof(v))
- X {
- X fprintf(stderr, "%s (write): %s\n", myname,sys_errlist[errno]);
- X done() ;
- X }
- X ++i; /* increment the index, in case */
- X
- X } /* end: while */
- X
- X fclose (cfd); /* Not needed any more */
- X return(1); /* All OK */
- X
- X} /* end: init_sites() */
- X
- X/*+
- X * FUNCTION:
- X * Toggle debugging on/off
- X */
- Xstatic void usr1_handler()
- X{
- X if (debugflag)
- X debugflag = 0;
- X else
- X debugflag = 1;
- X
- X if (debugflag)
- X fprintf (stderr, "(debug) %s: recvd USR1, enabling debugging\n", myname);
- X
- X}
- X
- X/*+
- X * FUNCTION:
- X * Handle timeouts for sockets. Since it doesn't interrupt system
- X * calls (like read() ), close the socket so that read fails.
- X */
- Xstatic void alarm_handler()
- X{
- X if (debugflag)
- X fprintf (stderr, "(debug) %s: recvd ALARM\n", myname);
- X gotalarm = 1;
- X close (sock);
- X}
- X
- X/*+
- X * FUNCTION:
- X *
- X */
- Xstatic void done()
- X{
- X char pidfile[MAXLINE] ;
- X
- X closeeventlog() ;
- X
- X fprintf (stderr, "%s: removing data, pid file.... ", myname);
- X sprintf (pidfile, "%s/%s.pid\0", ETCDIR, myname);
- X unlink (pidfile); /* remove the PID file */
- X unlink (datafile); /* delete the data file */
- X fprintf (stderr, "Done\n");
- X exit (1);
- X}
- X
- X
- END_OF_FILE
- if test 15152 -ne `wc -c <'nocol-3.0/src/portmon/portmon.c'`; then
- echo shar: \"'nocol-3.0/src/portmon/portmon.c'\" unpacked with wrong size!
- fi
- # end of 'nocol-3.0/src/portmon/portmon.c'
- fi
- if test -f 'nocol-3.0/src/support/mping/brl-ping.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'nocol-3.0/src/support/mping/brl-ping.c'\"
- else
- echo shar: Extracting \"'nocol-3.0/src/support/mping/brl-ping.c'\" \(18494 characters\)
- sed "s/^X//" >'nocol-3.0/src/support/mping/brl-ping.c' <<'END_OF_FILE'
- X/*
- X * P I N G . C
- X *
- X * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
- X * measure round-trip-delays and packet loss across network paths.
- X *
- X * Author -
- X * Mike Muuss
- X * U. S. Army Ballistic Research Laboratory
- X * December, 1983
- X * Modified at Uc Berkeley
- X * Record Route and verbose headers - Phil Dykstra, BRL, March 1988.
- X *
- X * 910504 Watt-Alan@Yale.Edu (Alan S. Watt)
- X *
- X * + Added verification of ICMP checksum on packet receipt, to check
- X * for data damage over links which don't provide a CRC.
- X *
- X * + Added -p<pattern> option to fill the packet with a specific
- X * bit pattern to check for data-dependent transmission loss.
- X *
- X * + Cleaned up several calls to inet_ntoa() which passed
- X * an unsigned long instead of a structure containing an unsigned
- X * long.
- X *
- X * Status -
- X * Public Domain. Distribution Unlimited.
- X *
- X * Bugs -
- X * More statistics could always be gathered.
- X * This program has to run SUID to ROOT to access the ICMP socket.
- X */
- X
- X#include <stdio.h>
- X#include <errno.h>
- X#include <sys/time.h>
- X
- X#include <sys/param.h>
- X#include <sys/socket.h>
- X#include <sys/file.h>
- X
- X#include <netinet/in_systm.h>
- X#include <netinet/in.h>
- X#include <netinet/ip.h>
- X#include <netinet/ip_icmp.h>
- X#include <netdb.h>
- X
- X#define MAXWAIT 10 /* max time to wait for response, sec. */
- X#define MAXPACKET 4096 /* max packet size */
- X#define VERBOSE 1 /* verbose flag */
- X#define QUIET 2 /* quiet flag */
- X#define FLOOD 4 /* floodping flag */
- X#define RROUTE 8 /* record route flag */
- X#define NROUTES 9 /* number of record route slots */
- X#ifndef MAXHOSTNAMELEN
- X#define MAXHOSTNAMELEN 64
- X#endif
- X
- Xu_char packet[MAXPACKET];
- Xint i, pingflags, options;
- Xextern int errno;
- X
- Xint s; /* Socket file descriptor */
- Xstruct hostent *hp; /* Pointer to host info */
- Xstruct timezone tz; /* leftover */
- X
- Xstruct sockaddr whereto;/* Who to ping */
- Xint datalen; /* How much data */
- X
- Xchar usage[] =
- X"Usage: ping [-dfnqrvR] host [packetsize [count [preload]]]\n";
- X
- Xchar *hostname;
- Xchar hnamebuf[MAXHOSTNAMELEN];
- X
- Xint npackets;
- Xint preload = 0; /* number of packets to "preload" */
- Xint ntransmitted = 0; /* sequence # for outbound packets = #sent */
- Xint ident;
- X
- Xint nreceived = 0; /* # of packets we got back */
- Xint timing = 0;
- Xint tmin = 999999999;
- Xint tmax = 0;
- Xint tsum = 0; /* sum of all times, for doing average */
- Xint finish(), catcher();
- Xchar *inet_ntoa();
- Xchar *pr_addr();
- X
- Xint numeric = 0; /* -n flag: numeric addresses only */
- Xchar rspace[3+4*NROUTES+1]; /* record route space */
- X
- Xint ncorrupted = 0; /* number of corrupted packets returned */
- Xint patternData = 0;
- Xint doPattern = 0;
- X
- X/*
- X * M A I N
- X */
- Xmain(argc, argv)
- Xchar *argv[];
- X{
- X struct sockaddr_in from;
- X char **av = argv;
- X struct sockaddr_in *to = (struct sockaddr_in *) &whereto;
- X int on = 1;
- X struct protoent *proto;
- X
- X argc--, av++;
- X while (argc > 0 && *av[0] == '-') {
- X while (*++av[0]) switch (*av[0]) {
- X case 'd':
- X options |= SO_DEBUG;
- X break;
- X case 'r':
- X options |= SO_DONTROUTE;
- X break;
- X case 'v':
- X pingflags |= VERBOSE;
- X break;
- X case 'q':
- X pingflags |= QUIET;
- X break;
- X case 'f':
- X pingflags |= FLOOD;
- X break;
- X case 'R':
- X pingflags |= RROUTE;
- X break;
- X case 'n':
- X numeric++;
- X break;
- X case 'p':
- X patternData = getPatternData(av[0]+1);
- X doPattern = 1;
- X goto nextArg;
- X }
- X nextArg:
- X argc--, av++;
- X }
- X if(argc < 1 || argc > 4) {
- X printf(usage);
- X exit(1);
- X }
- X
- X bzero((char *)&whereto, sizeof(struct sockaddr) );
- X to->sin_family = AF_INET;
- X to->sin_addr.s_addr = inet_addr(av[0]);
- X if(to->sin_addr.s_addr != (unsigned)-1) {
- X strcpy(hnamebuf, av[0]);
- X hostname = hnamebuf;
- X } else {
- X hp = gethostbyname(av[0]);
- X if (hp) {
- X to->sin_family = hp->h_addrtype;
- X bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
- X strncpy( hnamebuf, hp->h_name, sizeof(hnamebuf)-1 );
- X hostname = hnamebuf;
- X } else {
- X printf("%s: unknown host %s\n", argv[0], av[0]);
- X exit(1);
- X }
- X }
- X
- X if( argc >= 2 )
- X datalen = atoi( av[1] );
- X else
- X datalen = 64-8;
- X if (datalen > MAXPACKET) {
- X fprintf(stderr, "ping: packet size too large\n");
- X exit(1);
- X }
- X if (datalen >= sizeof(struct timeval)) /* can we time 'em? */
- X timing = 1;
- X
- X if (argc >= 3)
- X npackets = atoi(av[2]);
- X
- X if (argc == 4)
- X preload = atoi(av[3]);
- X
- X ident = getpid() & 0xFFFF;
- X
- X if ((proto = getprotobyname("icmp")) == NULL) {
- X fprintf(stderr, "icmp: unknown protocol\n");
- X exit(10);
- X }
- X if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
- X perror("ping: socket");
- X exit(5);
- X }
- X if (options & SO_DEBUG) {
- X setsockopt(s, SOL_SOCKET, SO_DEBUG, &on, sizeof(on));
- X }
- X if (options & SO_DONTROUTE) {
- X setsockopt(s, SOL_SOCKET, SO_DONTROUTE, &on, sizeof(on));
- X }
- X /* Record Route option */
- X if( pingflags & RROUTE ) {
- X#ifdef IP_OPTIONS
- X rspace[IPOPT_OPTVAL] = IPOPT_RR;
- X rspace[IPOPT_OLEN] = sizeof(rspace)-1;
- X rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
- X if( setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace, sizeof(rspace)) < 0 ) {
- X perror( "Record route" );
- X exit( 42 );
- X }
- X#else
- X fprintf( stderr, "ping: record route not available on this machine.\n" );
- X exit( 42 );
- X#endif IP_OPTIONS
- X }
- X
- X if(to->sin_family == AF_INET) {
- X printf("PING %s (%s): %d data bytes\n", hostname,
- X inet_ntoa(to->sin_addr), datalen);
- X } else {
- X printf("PING %s: %d data bytes\n", hostname, datalen );
- X }
- X setlinebuf( stdout );
- X
- X signal( SIGINT, finish );
- X signal(SIGALRM, catcher);
- X
- X /* fire off them quickies */
- X for(i=0; i < preload; i++)
- X pinger();
- X
- X if(!(pingflags & FLOOD))
- X catcher(); /* start things going */
- X
- X for (;;) {
- X int len = sizeof (packet);
- X int fromlen = sizeof (from);
- X int cc;
- X struct timeval timeout;
- X int fdmask = 1 << s;
- X
- X timeout.tv_sec = 0;
- X timeout.tv_usec = 10000;
- X
- X if(pingflags & FLOOD) {
- X pinger();
- X if( select(32, &fdmask, 0, 0, &timeout) == 0)
- X continue;
- X }
- X if ( (cc=recvfrom(s, packet, len, 0, &from, &fromlen)) < 0) {
- X if( errno == EINTR )
- X continue;
- X perror("ping: recvfrom");
- X continue;
- X }
- X pr_pack( packet, cc, &from );
- X if (npackets && nreceived >= npackets)
- X finish();
- X }
- X /*NOTREACHED*/
- X}
- X
- X/*
- X * C A T C H E R
- X *
- X * This routine causes another PING to be transmitted, and then
- X * schedules another SIGALRM for 1 second from now.
- X *
- X * Bug -
- X * Our sense of time will slowly skew (ie, packets will not be launched
- X * exactly at 1-second intervals). This does not affect the quality
- X * of the delay and loss statistics.
- X */
- Xcatcher()
- X{
- X int waittime;
- X
- X pinger();
- X if (npackets == 0 || ntransmitted < npackets)
- X alarm(1);
- X else {
- X if (nreceived) {
- X waittime = 2 * tmax / 1000;
- X if (waittime == 0)
- X waittime = 1;
- X } else
- X waittime = MAXWAIT;
- X signal(SIGALRM, finish);
- X alarm(waittime);
- X }
- X}
- X
- X/*
- X * P I N G E R
- X *
- X * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
- X * will be added on by the kernel. The ID field is our UNIX process ID,
- X * and the sequence number is an ascending integer. The first 8 bytes
- X * of the data portion are used to hold a UNIX "timeval" struct in VAX
- X * byte-order, to compute the round-trip time.
- X */
- Xpinger()
- X{
- X static u_char outpack[MAXPACKET];
- X register struct icmp *icp = (struct icmp *) outpack;
- X int i, cc;
- X register struct timeval *tp = (struct timeval *) &outpack[8];
- X register u_char *datap = &outpack[8+sizeof(struct timeval)];
- X
- X icp->icmp_type = ICMP_ECHO;
- X icp->icmp_code = 0;
- X icp->icmp_cksum = 0;
- X icp->icmp_seq = ntransmitted++;
- X icp->icmp_id = ident; /* ID */
- X
- X cc = datalen+8; /* skips ICMP portion */
- X
- X if (timing)
- X gettimeofday( tp, &tz );
- X
- X if (doPattern) {
- X for( i=8; i<datalen; i++) /* skip 8 for time */
- X *datap++ = patternData;
- X } else {
- X for( i=8; i<datalen; i++) /* skip 8 for time */
- X *datap++ = i;
- X }
- X
- X /* Compute ICMP checksum here */
- X icp->icmp_cksum = in_cksum( icp, cc );
- X
- X /* cc = sendto(s, msg, len, flags, to, tolen) */
- X i = sendto( s, outpack, cc, 0, &whereto, sizeof(struct sockaddr) );
- X
- X if( i < 0 || i != cc ) {
- X if( i<0 ) perror("sendto");
- X printf("ping: wrote %s %d chars, ret=%d\n",
- X hostname, cc, i );
- X fflush(stdout);
- X }
- X if(pingflags == FLOOD) {
- X putchar('.');
- X fflush(stdout);
- X }
- X}
- X
- X/*
- X * P R _ P A C K
- X *
- X * Print out the packet, if it came from us. This logic is necessary
- X * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
- X * which arrive ('tis only fair). This permits multiple copies of this
- X * program to be run without having intermingled output (or statistics!).
- X */
- Xpr_pack( buf, cc, from )
- Xchar *buf;
- Xint cc;
- Xstruct sockaddr_in *from;
- X{
- X struct ip *ip;
- X register struct icmp *icp;
- X register long *lp = (long *) packet;
- X register int i;
- X struct timeval tv;
- X struct timeval *tp;
- X int hlen, triptime;
- X
- X from->sin_addr.s_addr = ntohl( from->sin_addr.s_addr );
- X gettimeofday( &tv, &tz );
- X
- X /* Check the IP header */
- X ip = (struct ip *) buf;
- X hlen = ip->ip_hl << 2;
- X if( cc < hlen + ICMP_MINLEN ) {
- X if( pingflags & VERBOSE )
- X printf("packet too short (%d bytes) from %s\n", cc,
- X inet_ntoa(from->sin_addr));
- X return;
- X }
- X
- X /* Now the ICMP part */
- X cc -= hlen;
- X icp = (struct icmp *)(buf + hlen);
- X if( icp->icmp_type == ICMP_ECHOREPLY ) {
- X if( icp->icmp_id != ident )
- X return; /* 'Twas not our ECHO */
- X
- X nreceived++;
- X if (timing) {
- X tp = (struct timeval *)&icp->icmp_data[0];
- X tvsub( &tv, tp );
- X triptime = tv.tv_sec*1000+(tv.tv_usec/1000);
- X tsum += triptime;
- X if( triptime < tmin )
- X tmin = triptime;
- X if( triptime > tmax )
- X tmax = triptime;
- X }
- X
- X if( pingflags & QUIET )
- X return;
- X
- X if( pingflags & FLOOD ) {
- X putchar('\b');
- X fflush(stdout);
- X } else {
- X printf("%d bytes from %s: icmp_seq=%d", cc,
- X inet_ntoa(from->sin_addr), icp->icmp_seq );
- X if (corrupted (icp, cc)) {
- X printf (" (BAD)");
- X ncorrupted += 1;
- X }
- X if (timing)
- X printf(" time=%d ms\n", triptime );
- X else
- X putchar('\n');
- X }
- X } else {
- X /* We've got something other than an ECHOREPLY */
- X if( !(pingflags & VERBOSE) )
- X return;
- X
- X printf("%d bytes from %s: ",
- X cc, pr_addr(ntohl(from->sin_addr.s_addr)) );
- X pr_icmph( icp );
- X }
- X
- X /* Display any IP options */
- X /* XXX - we should eventually do this for all packets with options */
- X if( hlen > 20 && icp->icmp_type == ICMP_ECHOREPLY ) {
- X unsigned char *cp;
- X /*printf("%d byte IP header:\n", hlen);*/
- X cp = (unsigned char *)buf + sizeof(struct ip) + 3;
- X for( i = 0; i < NROUTES; i++ ) {
- X unsigned long l;
- X l = (*cp<<24) | (*(cp+1)<<16) | (*(cp+2)<<8) | *(cp+3);
- X /* give the nameserver a break! */
- X if( l == 0 ) {
- X /*printf("0.0.0.0\n"); Hope the zeros are not in the middle */
- X } else {
- X printf("\t%s\n", pr_addr(ntohl(l)) );
- X }
- X cp += 4;
- X }
- X }
- X}
- X
- X/* corrupted:
- X * verify data portion of packet is what we sent
- X */
- Xcorrupted (icp, len)
- Xregister struct icmp *icp;
- Xint len;
- X{
- X register i;
- X int cksum, oldcksum;
- X
- X
- X oldcksum = icp->icmp_cksum;
- X#ifndef FORCEBAD
- X icp->icmp_cksum = 0;
- X#endif
- X cksum = in_cksum( icp, len );
- X icp->icmp_cksum = oldcksum;
- X if (cksum != oldcksum)
- X return 1;
- X return 0;
- X}
- X
- X/* getPatternData: get a data pattern
- X *
- X * Handles decimal (default), octal (leading "0"), and
- X * hexidecimal (leading "0x", "0X") notations. If decimal,
- X * also accepts leading minus sign.
- X */
- X#include <ctype.h>
- X
- X#define DECORD(C) ((C) - '0')
- X#define UCXORD(C) ((C) - 'A' + 10)
- X#define LCXORD(C) ((C) - 'a' + 10)
- X
- XgetPatternData (str)
- Xchar* str;
- X{
- X int base = 10;
- X int digit;
- X unsigned int ret = 0;
- X int sign = 1;
- X
- X if (*str == '0') {
- X str++;
- X if (*str == 'x' || *str == 'X') {
- X str++; base = 16;
- X }
- X else
- X base = 8;
- X }
- X else if (*str == '-') {
- X str++; sign = -1;
- X }
- X
- X for ( ; *str != '\0'; str++) {
- X if (isdigit(*str))
- X digit = DECORD(*str);
- X else if (isxdigit(*str))
- X digit = isupper(*str) ? UCXORD(*str) : LCXORD(*str);
- X else
- X break;
- X
- X if (digit >= base)
- X break;
- X
- X ret = ret*base + digit;
- X }
- X return ret * sign;
- X}
- X
- X/*
- X * I N _ C K S U M
- X *
- X * Checksum routine for Internet Protocol family headers (C Version)
- X *
- X */
- Xin_cksum(addr, len)
- Xu_short *addr;
- Xint len;
- X{
- X register int nleft = len;
- X register u_short *w = addr;
- X register int sum = 0;
- X u_short answer = 0;
- X
- X /*
- X * Our algorithm is simple, using a 32 bit accumulator (sum),
- X * we add sequential 16 bit words to it, and at the end, fold
- X * back all the carry bits from the top 16 bits into the lower
- X * 16 bits.
- X */
- X while( nleft > 1 ) {
- X sum += *w++;
- X nleft -= 2;
- X }
- X
- X /* mop up an odd byte, if necessary */
- X if( nleft == 1 ) {
- X *(u_char *)(&answer) = *(u_char *)w ;
- X sum += answer;
- X }
- X
- X /*
- X * add back carry outs from top 16 bits to low 16 bits
- X */
- X sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
- X sum += (sum >> 16); /* add carry */
- X answer = ~sum; /* truncate to 16 bits */
- X return (answer);
- X}
- X
- X/*
- X * T V S U B
- X *
- X * Subtract 2 timeval structs: out = out - in.
- X *
- X * Out is assumed to be >= in.
- X */
- Xtvsub( out, in )
- Xregister struct timeval *out, *in;
- X{
- X if( (out->tv_usec -= in->tv_usec) < 0 ) {
- X out->tv_sec--;
- X out->tv_usec += 1000000;
- X }
- X out->tv_sec -= in->tv_sec;
- X}
- X
- X/*
- X * F I N I S H
- X *
- X * Print out statistics, and give up.
- X * Heavily buffered STDIO is used here, so that all the statistics
- X * will be written with 1 sys-write call. This is nice when more
- X * than one copy of the program is running on a terminal; it prevents
- X * the statistics output from becomming intermingled.
- X */
- Xfinish()
- X{
- X putchar('\n');
- X fflush(stdout);
- X printf("\n----%s PING Statistics----\n", hostname );
- X printf("%d packets transmitted, ", ntransmitted );
- X printf("%d packets received, ", nreceived );
- X if (ncorrupted > 0)
- X printf ("(%d corrupted) ", ncorrupted);
- X if (ntransmitted)
- X if( nreceived > ntransmitted)
- X printf("-- somebody's printing up packets!");
- X else
- X printf("%d%% packet loss",
- X (int) (((ntransmitted-nreceived)*100) /
- X ntransmitted));
- X printf("\n");
- X if (nreceived && timing)
- X printf("round-trip (ms) min/avg/max = %d/%d/%d\n",
- X tmin,
- X tsum / nreceived,
- X tmax );
- X fflush(stdout);
- X exit(0);
- X}
- X
- Xstatic char *ttab[] = {
- X "Echo Reply", /* ip + seq + udata */
- X "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */
- X "Source Quench", /* IP */
- X "Redirect", /* redirect type, gateway, + IP */
- X "Echo",
- X "Time Exceeded", /* transit, frag reassem + IP */
- X "Parameter Problem", /* pointer + IP */
- X "Timestamp", /* id + seq + three timestamps */
- X "Timestamp Reply", /* " */
- X "Info Request", /* id + sq */
- X "Info Reply" /* " */
- X};
- X
- X/*
- X * Print a descriptive string about an ICMP header.
- X */
- Xpr_icmph( icp )
- Xstruct icmp *icp;
- X{
- X switch( icp->icmp_type ) {
- X case ICMP_ECHOREPLY:
- X printf("Echo Reply\n");
- X /* XXX ID + Seq + Data */
- X break;
- X case ICMP_UNREACH:
- X switch( icp->icmp_code ) {
- X case ICMP_UNREACH_NET:
- X printf("Destination Net Unreachable\n");
- X break;
- X case ICMP_UNREACH_HOST:
- X printf("Destination Host Unreachable\n");
- X break;
- X case ICMP_UNREACH_PROTOCOL:
- X printf("Destination Protocol Unreachable\n");
- X break;
- X case ICMP_UNREACH_PORT:
- X printf("Destination Port Unreachable\n");
- X break;
- X case ICMP_UNREACH_NEEDFRAG:
- X printf("frag needed and DF set\n");
- X break;
- X case ICMP_UNREACH_SRCFAIL:
- X printf("Source Route Failed\n");
- X break;
- X default:
- X printf("Dest Unreachable, Bad Code: %d\n", icp->icmp_code );
- X break;
- X }
- X /* Print returned IP header information */
- X pr_retip( icp->icmp_data );
- X break;
- X case ICMP_SOURCEQUENCH:
- X printf("Source Quench\n");
- X pr_retip( icp->icmp_data );
- X break;
- X case ICMP_REDIRECT:
- X switch( icp->icmp_code ) {
- X case ICMP_REDIRECT_NET:
- X printf("Redirect Network");
- X break;
- X case ICMP_REDIRECT_HOST:
- X printf("Redirect Host");
- X break;
- X case ICMP_REDIRECT_TOSNET:
- X printf("Redirect Type of Service and Network");
- X break;
- X case ICMP_REDIRECT_TOSHOST:
- X printf("Redirect Type of Service and Host");
- X break;
- X default:
- X printf("Redirect, Bad Code: %d", icp->icmp_code );
- X break;
- X }
- X printf(" (New addr: 0x%08x)\n", icp->icmp_hun.ih_gwaddr );
- X pr_retip( icp->icmp_data );
- X break;
- X case ICMP_ECHO:
- X printf("Echo Request\n");
- X /* XXX ID + Seq + Data */
- X break;
- X case ICMP_TIMXCEED:
- X switch( icp->icmp_code ) {
- X case ICMP_TIMXCEED_INTRANS:
- X printf("Time to live exceeded\n");
- X break;
- X case ICMP_TIMXCEED_REASS:
- X printf("Frag reassembly time exceeded\n");
- X break;
- X default:
- X printf("Time exceeded, Bad Code: %d\n", icp->icmp_code );
- X break;
- X }
- X pr_retip( icp->icmp_data );
- X break;
- X case ICMP_PARAMPROB:
- X printf("Parameter problem: pointer = 0x%02x\n",
- X icp->icmp_hun.ih_pptr );
- X pr_retip( icp->icmp_data );
- X break;
- X case ICMP_TSTAMP:
- X printf("Timestamp\n");
- X /* XXX ID + Seq + 3 timestamps */
- X break;
- X case ICMP_TSTAMPREPLY:
- X printf("Timestamp Reply\n");
- X /* XXX ID + Seq + 3 timestamps */
- X break;
- X case ICMP_IREQ:
- X printf("Information Request\n");
- X /* XXX ID + Seq */
- X break;
- X case ICMP_IREQREPLY:
- X printf("Information Reply\n");
- X /* XXX ID + Seq */
- X break;
- X case ICMP_MASKREQ:
- X printf("Address Mask Request\n");
- X break;
- X case ICMP_MASKREPLY:
- X printf("Address Mask Reply\n");
- X break;
- X default:
- X printf("Bad ICMP type: %d\n", icp->icmp_type);
- X }
- X}
- X
- X/*
- X * Print an IP header with options.
- X */
- Xpr_iph( ip )
- Xstruct ip *ip;
- X{
- X int hlen;
- X unsigned char *cp;
- X
- X hlen = ip->ip_hl << 2;
- X cp = (unsigned char *)ip + 20; /* point to options */
- X
- X printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n");
- X printf(" %1x %1x %02x %04x %04x",
- X ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id );
- X printf(" %1x %04x", ((ip->ip_off)&0xe000)>>13, (ip->ip_off)&0x1fff );
- X printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum );
- X printf(" %08x %08x ",
- X ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr) );
- X /* dump and option bytes */
- X while( hlen-- > 20 ) {
- X printf( "%02x", *cp++ );
- X }
- X printf("\n");
- X}
- X
- X/*
- X * Return an ascii host address
- X * as a dotted quad and optionally with a hostname
- X */
- Xchar *
- Xpr_addr( l )
- Xunsigned long l;
- X{
- X struct hostent *hp;
- X static char buf[80];
- X
- X if( numeric || (hp = gethostbyaddr(&l, 4, AF_INET)) == NULL )
- X sprintf( buf, "%s", inet_ntoa(l) );
- X else
- X sprintf( buf, "%s (%s)", hp->h_name, inet_ntoa(l) );
- X
- X return( buf );
- X}
- X
- X/*
- X * Dump some info on a returned (via ICMP) IP packet.
- X */
- Xpr_retip( ip )
- Xstruct ip *ip;
- X{
- X int hlen;
- X unsigned char *cp;
- X
- X pr_iph( ip );
- X hlen = ip->ip_hl << 2;
- X cp = (unsigned char *)ip + hlen;
- X
- X if( ip->ip_p == 6 ) {
- X printf( "TCP: from port %d, to port %d (decimal)\n",
- X (*cp*256+*(cp+1)), (*(cp+2)*256+*(cp+3)) );
- X } else if( ip->ip_p == 17 ) {
- X printf( "UDP: from port %d, to port %d (decimal)\n",
- X (*cp*256+*(cp+1)), (*(cp+2)*256+*(cp+3)) );
- X }
- X}
- END_OF_FILE
- if test 18494 -ne `wc -c <'nocol-3.0/src/support/mping/brl-ping.c'`; then
- echo shar: \"'nocol-3.0/src/support/mping/brl-ping.c'\" unpacked with wrong size!
- fi
- # end of 'nocol-3.0/src/support/mping/brl-ping.c'
- fi
- echo shar: End of archive 14 \(of 26\).
- cp /dev/null ark14isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 26 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-