home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume40 / nocol / part14 < prev    next >
Encoding:
Text File  |  1993-11-23  |  74.7 KB  |  2,734 lines

  1. Newsgroups: comp.sources.misc
  2. From: vikas@jvnc.net (Vikas Aggarwal)
  3. Subject: v40i144:  nocol - Network Monitoring System, Part14/26
  4. Message-ID: <1993Nov23.212634.21638@sparky.sterling.com>
  5. X-Md4-Signature: 9004fe9c9d9e5502cd084247d7e86f21
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Tue, 23 Nov 1993 21:26:34 GMT
  9. Approved: kent@sparky.sterling.com
  10.  
  11. Submitted-by: vikas@jvnc.net (Vikas Aggarwal)
  12. Posting-number: Volume 40, Issue 144
  13. Archive-name: nocol/part14
  14. Environment: INET, UNIX
  15.  
  16. #! /bin/sh
  17. # This is a shell archive.  Remove anything before this line, then feed it
  18. # into a shell via "sh file" or similar.  To overwrite existing files,
  19. # type "sh file -c".
  20. # Contents:  nocol-3.0/src/cmu-snmp/include/asn1.c
  21. #   nocol-3.0/src/noclog/noclogd.c nocol-3.0/src/portmon/portmon.c
  22. #   nocol-3.0/src/support/mping/brl-ping.c
  23. # Wrapped by kent@sparky on Tue Nov  9 22:22:19 1993
  24. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
  25. echo If this archive is complete, you will see the following message:
  26. echo '          "shar: End of archive 14 (of 26)."'
  27. if test -f 'nocol-3.0/src/cmu-snmp/include/asn1.c' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'nocol-3.0/src/cmu-snmp/include/asn1.c'\"
  29. else
  30.   echo shar: Extracting \"'nocol-3.0/src/cmu-snmp/include/asn1.c'\" \(18366 characters\)
  31.   sed "s/^X//" >'nocol-3.0/src/cmu-snmp/include/asn1.c' <<'END_OF_FILE'
  32. X/*
  33. X * Abstract Syntax Notation One, ASN.1
  34. X * As defined in ISO/IS 8824 and ISO/IS 8825
  35. X * This implements a subset of the above International Standards that
  36. X * is sufficient to implement SNMP.
  37. X *
  38. X * Encodes abstract data types into a machine independent stream of bytes.
  39. X *
  40. X */
  41. X/***********************************************************
  42. X    Copyright 1988, 1989 by Carnegie Mellon University
  43. X
  44. X                      All Rights Reserved
  45. X
  46. XPermission to use, copy, modify, and distribute this software and its 
  47. Xdocumentation for any purpose and without fee is hereby granted, 
  48. Xprovided that the above copyright notice appear in all copies and that
  49. Xboth that copyright notice and this permission notice appear in 
  50. Xsupporting documentation, and that the name of CMU not be
  51. Xused in advertising or publicity pertaining to distribution of the
  52. Xsoftware without specific, written prior permission.  
  53. X
  54. XCMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  55. XALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  56. XCMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  57. XANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  58. XWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  59. XARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  60. XSOFTWARE.
  61. X******************************************************************/
  62. X#ifdef KINETICS
  63. X#include "gw.h"
  64. X#endif
  65. X
  66. X#if (defined(unix) && !defined(KINETICS))
  67. X#include <sys/types.h>
  68. X#include <netinet/in.h>
  69. X#endif
  70. X
  71. X#include "asn1.h"
  72. X
  73. X#ifndef NULL
  74. X#define NULL    0
  75. X#endif
  76. X#define    ERROR(x)
  77. X
  78. X/*
  79. X * asn_parse_int - pulls a long out of an ASN int type.
  80. X *  On entry, datalength is input as the number of valid bytes following
  81. X *   "data".  On exit, it is returned as the number of valid bytes
  82. X *   following the end of this object.
  83. X *
  84. X *  Returns a pointer to the first byte past the end
  85. X *   of this object (i.e. the start of the next object).
  86. X *  Returns NULL on any error.
  87. X */
  88. Xu_char *
  89. Xasn_parse_int(data, datalength, type, intp, intsize)
  90. X    register u_char        *data;    /* IN - pointer to start of object */
  91. X    register int        *datalength;/* IN/OUT - number of valid bytes left in buffer */
  92. X    u_char            *type;    /* OUT - asn type of object */
  93. X    long            *intp;    /* IN/OUT - pointer to start of output buffer */
  94. X    int                intsize;    /* IN - size of output buffer */
  95. X{
  96. X/*
  97. X * ASN.1 integer ::= 0x02 asnlength byte {byte}*
  98. X */
  99. X    register u_char *bufp = data;
  100. X    u_long        asn_length;
  101. X    register long   value = 0;
  102. X
  103. X    if (intsize != sizeof (long)){
  104. X    ERROR("not long");
  105. X    return NULL;
  106. X    }
  107. X    *type = *bufp++;
  108. X    bufp = asn_parse_length(bufp, &asn_length);
  109. X    if (bufp == NULL){
  110. X    ERROR("bad length");
  111. X    return NULL;
  112. X    }
  113. X    if (asn_length + (bufp - data) > *datalength){
  114. X    ERROR("overflow of message");
  115. X    return NULL;
  116. X    }
  117. X    if (asn_length > intsize){
  118. X    ERROR("I don't support such large integers");
  119. X    return NULL;
  120. X    }
  121. X    *datalength -= (int)asn_length + (bufp - data);
  122. X    if (*bufp & 0x80)
  123. X    value = -1; /* integer is negative */
  124. X    while(asn_length--)
  125. X    value = (value << 8) | *bufp++;
  126. X    *intp = value;
  127. X    return bufp;
  128. X}
  129. X
  130. X
  131. X/*
  132. X * asn_build_int - builds an ASN object containing an integer.
  133. X *  On entry, datalength is input as the number of valid bytes following
  134. X *   "data".  On exit, it is returned as the number of valid bytes
  135. X *   following the end of this object.
  136. X *
  137. X *  Returns a pointer to the first byte past the end
  138. X *   of this object (i.e. the start of the next object).
  139. X *  Returns NULL on any error.
  140. X */
  141. Xu_char *
  142. Xasn_build_int(data, datalength, type, intp, intsize)
  143. X    register u_char *data;    /* IN - pointer to start of output buffer */
  144. X    register int    *datalength;/* IN/OUT - number of valid bytes left in buffer */
  145. X    u_char        type;    /* IN - asn type of object */
  146. X    register long   *intp;    /* IN - pointer to start of long integer */
  147. X    register int    intsize;    /* IN - size of *intp */
  148. X{
  149. X/*
  150. X * ASN.1 integer ::= 0x02 asnlength byte {byte}*
  151. X */
  152. X
  153. X    register long integer;
  154. X    register u_long mask;
  155. X
  156. X    if (intsize != sizeof (long))
  157. X    return NULL;
  158. X    integer = *intp;
  159. X    /*
  160. X     * Truncate "unnecessary" bytes off of the most significant end of this 2's complement integer.
  161. X     * There should be no sequence of 9 consecutive 1's or 0's at the most significant end of the
  162. X     * integer.
  163. X     */
  164. X    mask = 0x1FF << ((8 * (sizeof(long) - 1)) - 1);
  165. X    /* mask is 0xFF800000 on a big-endian machine */
  166. X    while((((integer & mask) == 0) || ((integer & mask) == mask)) && intsize > 1){
  167. X    intsize--;
  168. X    integer <<= 8;
  169. X    }
  170. X    data = asn_build_header(data, datalength, type, intsize);
  171. X    if (data == NULL)
  172. X    return NULL;
  173. X    if (*datalength < intsize)
  174. X    return NULL;
  175. X    *datalength -= intsize;
  176. X    mask = 0xFF << (8 * (sizeof(long) - 1));
  177. X    /* mask is 0xFF000000 on a big-endian machine */
  178. X    while(intsize--){
  179. X    *data++ = (u_char)((integer & mask) >> (8 * (sizeof(long) - 1)));
  180. X    integer <<= 8;
  181. X    }
  182. X    return data;
  183. X}
  184. X
  185. X
  186. X/*
  187. X * asn_parse_string - pulls an octet string out of an ASN octet string type.
  188. X *  On entry, datalength is input as the number of valid bytes following
  189. X *   "data".  On exit, it is returned as the number of valid bytes
  190. X *   following the beginning of the next object.
  191. X *
  192. X *  "string" is filled with the octet string.
  193. X *
  194. X *  Returns a pointer to the first byte past the end
  195. X *   of this object (i.e. the start of the next object).
  196. X *  Returns NULL on any error.
  197. X */
  198. Xu_char *
  199. Xasn_parse_string(data, datalength, type, string, strlength)
  200. X    u_char        *data;        /* IN - pointer to start of object */
  201. X    register int    *datalength;    /* IN/OUT - number of valid bytes left in buffer */
  202. X    u_char        *type;        /* OUT - asn type of object */
  203. X    u_char        *string;        /* IN/OUT - pointer to start of output buffer */
  204. X    register int    *strlength;     /* IN/OUT - size of output buffer */
  205. X{
  206. X/*
  207. X * ASN.1 octet string ::= primstring | cmpdstring
  208. X * primstring ::= 0x04 asnlength byte {byte}*
  209. X * cmpdstring ::= 0x24 asnlength string {string}*
  210. X * This doesn't yet support the compound string.
  211. X */
  212. X    register u_char *bufp = data;
  213. X    u_long        asn_length;
  214. X
  215. X    *type = *bufp++;
  216. X    bufp = asn_parse_length(bufp, &asn_length);
  217. X    if (bufp == NULL)
  218. X    return NULL;
  219. X    if (asn_length + (bufp - data) > *datalength){
  220. X    ERROR("overflow of message");
  221. X    return NULL;
  222. X    }
  223. X    if (asn_length > *strlength){
  224. X    ERROR("I don't support such long strings");
  225. X    return NULL;
  226. X    }
  227. X    bcopy((char *)bufp, (char *)string, (int)asn_length);
  228. X    *strlength = (int)asn_length;
  229. X    *datalength -= (int)asn_length + (bufp - data);
  230. X    return bufp + asn_length;
  231. X}
  232. X
  233. X
  234. X/*
  235. X * asn_build_string - Builds an ASN octet string object containing the input string.
  236. X *  On entry, datalength is input as the number of valid bytes following
  237. X *   "data".  On exit, it is returned as the number of valid bytes
  238. X *   following the beginning of the next object.
  239. X *
  240. X *  Returns a pointer to the first byte past the end
  241. X *   of this object (i.e. the start of the next object).
  242. X *  Returns NULL on any error.
  243. X */
  244. Xu_char *
  245. Xasn_build_string(data, datalength, type, string, strlength)
  246. X    u_char        *data;        /* IN - pointer to start of object */
  247. X    register int    *datalength;    /* IN/OUT - number of valid bytes left in buffer */
  248. X    u_char        type;        /* IN - ASN type of string */
  249. X    u_char        *string;        /* IN - pointer to start of input buffer */
  250. X    register int    strlength;        /* IN - size of input buffer */
  251. X{
  252. X/*
  253. X * ASN.1 octet string ::= primstring | cmpdstring
  254. X * primstring ::= 0x04 asnlength byte {byte}*
  255. X * cmpdstring ::= 0x24 asnlength string {string}*
  256. X * This code will never send a compound string.
  257. X */
  258. X    data = asn_build_header(data, datalength, type, strlength);
  259. X    if (data == NULL)
  260. X    return NULL;
  261. X    if (*datalength < strlength)
  262. X    return NULL;
  263. X    bcopy((char *)string, (char *)data, strlength);
  264. X    *datalength -= strlength;
  265. X    return data + strlength;
  266. X}
  267. X
  268. X
  269. X/*
  270. X * asn_parse_header - interprets the ID and length of the current object.
  271. X *  On entry, datalength is input as the number of valid bytes following
  272. X *   "data".  On exit, it is returned as the number of valid bytes
  273. X *   in this object following the id and length.
  274. X *
  275. X *  Returns a pointer to the first byte of the contents of this object.
  276. X *  Returns NULL on any error.
  277. X */
  278. Xu_char *
  279. Xasn_parse_header(data, datalength, type)
  280. X    u_char        *data;    /* IN - pointer to start of object */
  281. X    int            *datalength;/* IN/OUT - number of valid bytes left in buffer */
  282. X    u_char        *type;    /* OUT - ASN type of object */
  283. X{
  284. X    register u_char *bufp = data;
  285. X    register        header_len;
  286. X    u_long        asn_length;
  287. X
  288. X    /* this only works on data types < 30, i.e. no extension octets */
  289. X    if (IS_EXTENSION_ID(*bufp)){
  290. X    ERROR("can't process ID >= 30");
  291. X    return NULL;
  292. X    }
  293. X    *type = *bufp;
  294. X    bufp = asn_parse_length(bufp + 1, &asn_length);
  295. X    if (bufp == NULL)
  296. X    return NULL;
  297. X    header_len = bufp - data;
  298. X    if (header_len + asn_length > *datalength){
  299. X    ERROR("asn length too long");
  300. X    return NULL;
  301. X    }
  302. X    *datalength = (int)asn_length;
  303. X    return bufp;
  304. X}
  305. X
  306. X/*
  307. X * asn_build_header - builds an ASN header for an object with the ID and
  308. X * length specified.
  309. X *  On entry, datalength is input as the number of valid bytes following
  310. X *   "data".  On exit, it is returned as the number of valid bytes
  311. X *   in this object following the id and length.
  312. X *
  313. X *  This only works on data types < 30, i.e. no extension octets.
  314. X *  The maximum length is 0xFFFF;
  315. X *
  316. X *  Returns a pointer to the first byte of the contents of this object.
  317. X *  Returns NULL on any error.
  318. X */
  319. Xu_char *
  320. Xasn_build_header(data, datalength, type, length)
  321. X    register u_char *data;    /* IN - pointer to start of object */
  322. X    int            *datalength;/* IN/OUT - number of valid bytes left in buffer */
  323. X    u_char        type;    /* IN - ASN type of object */
  324. X    int            length;    /* IN - length of object */
  325. X{
  326. X    if (*datalength < 1)
  327. X    return NULL;
  328. X    *data++ = type;
  329. X    (*datalength)--;
  330. X    return asn_build_length(data, datalength, length);
  331. X    
  332. X}
  333. X
  334. X/*
  335. X * asn_parse_length - interprets the length of the current object.
  336. X *  On exit, length contains the value of this length field.
  337. X *
  338. X *  Returns a pointer to the first byte after this length
  339. X *  field (aka: the start of the data field).
  340. X *  Returns NULL on any error.
  341. X */
  342. Xu_char *
  343. Xasn_parse_length(data, length)
  344. X    u_char  *data;    /* IN - pointer to start of length field */
  345. X    u_long  *length;    /* OUT - value of length field */
  346. X{
  347. X    register u_char lengthbyte = *data;
  348. X
  349. X    if (lengthbyte & ASN_LONG_LEN){
  350. X    lengthbyte &= ~ASN_LONG_LEN;    /* turn MSb off */
  351. X    if (lengthbyte == 0){
  352. X        ERROR("We don't support indefinite lengths");
  353. X        return NULL;
  354. X    }
  355. X    if (lengthbyte > sizeof(long)){
  356. X        ERROR("we can't support data lengths that long");
  357. X        return NULL;
  358. X    }
  359. X    bcopy((char *)data + 1, (char *)length, (int)lengthbyte);
  360. X    *length = ntohl(*length);
  361. X    *length >>= (8 * ((sizeof *length) - lengthbyte));
  362. X    return data + lengthbyte + 1;
  363. X    } else { /* short asnlength */
  364. X    *length = (long)lengthbyte;
  365. X    return data + 1;
  366. X    }
  367. X}
  368. X
  369. Xu_char *
  370. Xasn_build_length(data, datalength, length)
  371. X    register u_char *data;    /* IN - pointer to start of object */
  372. X    int            *datalength;/* IN/OUT - number of valid bytes left in buffer */
  373. X    register int    length;    /* IN - length of object */
  374. X{
  375. X    u_char    *start_data = data;
  376. X
  377. X    /* no indefinite lengths sent */
  378. X    if (length < 0x80){
  379. X    *data++ = (u_char)length;
  380. X    } else if (length <= 0xFF){
  381. X    *data++ = (u_char)(0x01 | ASN_LONG_LEN);
  382. X    *data++ = (u_char)length;
  383. X    } else { /* 0xFF < length <= 0xFFFF */
  384. X    *data++ = (u_char)(0x02 | ASN_LONG_LEN);
  385. X    *data++ = (u_char)((length >> 8) & 0xFF);
  386. X    *data++ = (u_char)(length & 0xFF);
  387. X    }
  388. X    if (*datalength < (data - start_data)){
  389. X    ERROR("build_length");
  390. X    return NULL;
  391. X    }
  392. X    *datalength -= (data - start_data);
  393. X    return data;
  394. X
  395. X}
  396. X
  397. X/*
  398. X * asn_parse_objid - pulls an object indentifier out of an ASN object identifier type.
  399. X *  On entry, datalength is input as the number of valid bytes following
  400. X *   "data".  On exit, it is returned as the number of valid bytes
  401. X *   following the beginning of the next object.
  402. X *
  403. X *  "objid" is filled with the object identifier.
  404. X *
  405. X *  Returns a pointer to the first byte past the end
  406. X *   of this object (i.e. the start of the next object).
  407. X *  Returns NULL on any error.
  408. X */
  409. Xu_char *
  410. Xasn_parse_objid(data, datalength, type, objid, objidlength)
  411. X    u_char        *data;        /* IN - pointer to start of object */
  412. X    int            *datalength;    /* IN/OUT - number of valid bytes left in buffer */
  413. X    u_char        *type;        /* OUT - ASN type of object */
  414. X    oid            *objid;        /* IN/OUT - pointer to start of output buffer */
  415. X    int            *objidlength;     /* IN/OUT - number of sub-id's in objid */
  416. X{
  417. X/*
  418. X * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
  419. X * subidentifier ::= {leadingbyte}* lastbyte
  420. X * leadingbyte ::= 1 7bitvalue
  421. X * lastbyte ::= 0 7bitvalue
  422. X */
  423. X    register u_char *bufp = data;
  424. X    register oid *oidp = objid + 1;
  425. X    register u_long subidentifier;
  426. X    register long   length;
  427. X    u_long        asn_length;
  428. X
  429. X    *type = *bufp++;
  430. X    bufp = asn_parse_length(bufp, &asn_length);
  431. X    if (bufp == NULL)
  432. X    return NULL;
  433. X    if (asn_length + (bufp - data) > *datalength){
  434. X    ERROR("overflow of message");
  435. X    return NULL;
  436. X    }
  437. X    *datalength -= (int)asn_length + (bufp - data);
  438. X
  439. X    length = asn_length;
  440. X    (*objidlength)--;    /* account for expansion of first byte */
  441. X    while (length > 0 && (*objidlength)-- > 0){
  442. X    subidentifier = 0;
  443. X    do {    /* shift and add in low order 7 bits */
  444. X        subidentifier = (subidentifier << 7) + (*(u_char *)bufp & ~ASN_BIT8);
  445. X        length--;
  446. X    } while (*(u_char *)bufp++ & ASN_BIT8);    /* last byte has high bit clear */
  447. X    if (subidentifier > (u_long)MAX_SUBID){
  448. X        ERROR("subidentifier too long");
  449. X        return NULL;
  450. X    }
  451. X    *oidp++ = (oid)subidentifier;
  452. X    }
  453. X
  454. X    /*
  455. X     * The first two subidentifiers are encoded into the first component
  456. X     * with the value (X * 40) + Y, where:
  457. X     *    X is the value of the first subidentifier.
  458. X     *  Y is the value of the second subidentifier.
  459. X     */
  460. X    subidentifier = (u_long)objid[1];
  461. X    objid[1] = (u_char)(subidentifier % 40);
  462. X    objid[0] = (u_char)((subidentifier - objid[1]) / 40);
  463. X
  464. X    *objidlength = (int)(oidp - objid);
  465. X    return bufp;
  466. X}
  467. X
  468. X/*
  469. X * asn_build_objid - Builds an ASN object identifier object containing the input string.
  470. X *  On entry, datalength is input as the number of valid bytes following
  471. X *   "data".  On exit, it is returned as the number of valid bytes
  472. X *   following the beginning of the next object.
  473. X *
  474. X *  Returns a pointer to the first byte past the end
  475. X *   of this object (i.e. the start of the next object).
  476. X *  Returns NULL on any error.
  477. X */
  478. Xu_char *
  479. Xasn_build_objid(data, datalength, type, objid, objidlength)
  480. X    register u_char *data;        /* IN - pointer to start of object */
  481. X    int            *datalength;    /* IN/OUT - number of valid bytes left in buffer */
  482. X    u_char        type;        /* IN - ASN type of object */
  483. X    oid            *objid;        /* IN - pointer to start of input buffer */
  484. X    int            objidlength;    /* IN - number of sub-id's in objid */
  485. X{
  486. X/*
  487. X * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
  488. X * subidentifier ::= {leadingbyte}* lastbyte
  489. X * leadingbyte ::= 1 7bitvalue
  490. X * lastbyte ::= 0 7bitvalue
  491. X */
  492. X    u_char buf[MAX_OID_LEN];
  493. X    u_char *bp = buf;
  494. X    oid    objbuf[MAX_OID_LEN];
  495. X    oid *op = objbuf;
  496. X    register int    asnlength;
  497. X    register u_long subid, mask, testmask;
  498. X    register int bits, testbits;
  499. X
  500. X    bcopy((char *)objid, (char *)objbuf, objidlength * sizeof(oid));
  501. X    /* transform size in bytes to size in subid's */
  502. X    /* encode the first two components into the first subidentifier */
  503. X    op[1] = op[1] + (op[0] * 40);
  504. X    op++;
  505. X    objidlength--;
  506. X
  507. X    while(objidlength-- > 0){
  508. X    subid = *op++;
  509. X    mask = 0x7F; /* handle subid == 0 case */
  510. X    bits = 0;
  511. X    /* testmask *MUST* !!!! be of an unsigned type */
  512. X    for(testmask = 0x7F, testbits = 0; testmask != 0; testmask <<= 7, testbits += 7){
  513. X        if (subid & testmask){    /* if any bits set */
  514. X        mask = testmask;
  515. X        bits = testbits;
  516. X        }
  517. X    }
  518. X    /* mask can't be zero here */
  519. X    for(;mask != 0x7F; mask >>= 7, bits -= 7){
  520. X        if (mask == 0x1E00000)  /* fix a mask that got truncated above */
  521. X        mask = 0xFE00000;
  522. X        *bp++ = (u_char)(((subid & mask) >> bits) | ASN_BIT8);
  523. X    }
  524. X    *bp++ = (u_char)(subid & mask);
  525. X    }
  526. X    asnlength = bp - buf;
  527. X    data = asn_build_header(data, datalength, type, asnlength);
  528. X    if (data == NULL)
  529. X    return NULL;
  530. X    if (*datalength < asnlength)
  531. X    return NULL;
  532. X    bcopy((char *)buf, (char *)data, asnlength);
  533. X    *datalength -= asnlength;
  534. X    return data + asnlength;
  535. X}
  536. X
  537. X/*
  538. X * asn_parse_null - Interprets an ASN null type.
  539. X *  On entry, datalength is input as the number of valid bytes following
  540. X *   "data".  On exit, it is returned as the number of valid bytes
  541. X *   following the beginning of the next object.
  542. X *
  543. X *  Returns a pointer to the first byte past the end
  544. X *   of this object (i.e. the start of the next object).
  545. X *  Returns NULL on any error.
  546. X */
  547. Xu_char *
  548. Xasn_parse_null(data, datalength, type)
  549. X    u_char        *data;        /* IN - pointer to start of object */
  550. X    int            *datalength;    /* IN/OUT - number of valid bytes left in buffer */
  551. X    u_char        *type;        /* OUT - ASN type of object */
  552. X{
  553. X/*
  554. X * ASN.1 null ::= 0x05 0x00
  555. X */
  556. X    register u_char   *bufp = data;
  557. X    u_long        asn_length;
  558. X
  559. X    *type = *bufp++;
  560. X    bufp = asn_parse_length(bufp, &asn_length);
  561. X    if (bufp == NULL)
  562. X    return NULL;
  563. X    if (asn_length != 0){
  564. X    ERROR("Malformed NULL");
  565. X    return NULL;
  566. X    }
  567. X    *datalength -= (bufp - data);
  568. X    return bufp + asn_length;
  569. X}
  570. X
  571. X
  572. X/*
  573. X * asn_build_null - Builds an ASN null object.
  574. X *  On entry, datalength is input as the number of valid bytes following
  575. X *   "data".  On exit, it is returned as the number of valid bytes
  576. X *   following the beginning of the next object.
  577. X *
  578. X *  Returns a pointer to the first byte past the end
  579. X *   of this object (i.e. the start of the next object).
  580. X *  Returns NULL on any error.
  581. X */
  582. Xu_char *
  583. Xasn_build_null(data, datalength, type)
  584. X    u_char        *data;        /* IN - pointer to start of object */
  585. X    int            *datalength;    /* IN/OUT - number of valid bytes left in buffer */
  586. X    u_char        type;        /* IN - ASN type of object */
  587. X{
  588. X/*
  589. X * ASN.1 null ::= 0x05 0x00
  590. X */
  591. X    return asn_build_header(data, datalength, type, 0);
  592. X}
  593. X
  594. END_OF_FILE
  595.   if test 18366 -ne `wc -c <'nocol-3.0/src/cmu-snmp/include/asn1.c'`; then
  596.     echo shar: \"'nocol-3.0/src/cmu-snmp/include/asn1.c'\" unpacked with wrong size!
  597.   fi
  598.   # end of 'nocol-3.0/src/cmu-snmp/include/asn1.c'
  599. fi
  600. if test -f 'nocol-3.0/src/noclog/noclogd.c' -a "${1}" != "-c" ; then 
  601.   echo shar: Will not clobber existing file \"'nocol-3.0/src/noclog/noclogd.c'\"
  602. else
  603.   echo shar: Extracting \"'nocol-3.0/src/noclog/noclogd.c'\" \(18084 characters\)
  604.   sed "s/^X//" >'nocol-3.0/src/noclog/noclogd.c' <<'END_OF_FILE'
  605. X/* $Header: /home/aggarwal/lsrc/nocol/src/noclog/RCS/noclogd.c,v 3.3 1993/10/30 03:47:19 aggarwal Exp $ */
  606. X
  607. X/* Copyright 1993 JvNCnet, Global Enterprise Services */
  608. X
  609. X/*
  610. X * AUTHOR
  611. X *    David Wagner, wagner@jvnc.net
  612. X *    Vikas Aggarwal, vikas@jvnc.net
  613. X */
  614. X
  615. X/*
  616. X * DESCRIPTION
  617. X *    A logging daemon for the nocol monitor programs; not unlike
  618. X *    syslogd, it selectively records EVENT structures sent over
  619. X *    a socket by the nocol programs.
  620. X *
  621. X *    The config file can also pipe the output to another program.
  622. X *    Remember to use 'cat' since the EVENT strcuture will
  623. X *    be piped to the executable and NOT sent over as command line
  624. X *    argument.
  625. X */
  626. X
  627. X/*
  628. X * BUGS
  629. X *    Can't handle too many connections in a short period of time:
  630. X *    should be able to handle (say) 100 per second just fine, though.
  631. X */
  632. X
  633. X/*
  634. X * $Log: noclogd.c,v $
  635. X * Revision 3.3  1993/10/30  03:47:19  aggarwal
  636. X * Small problems in pointer passing in authenticate_host(). Also
  637. X * does a 'getsockopt()' to set the socket buffer size if possible.
  638. X * Cleaned up code for auto closing a stream on error.
  639. X *
  640. X * Revision 3.2  1993/10/02  05:31:06  aggarwal
  641. X * Moved the function to convert event to logstring into the nocol
  642. X * library.
  643. X *
  644. X * Revision 3.1  1993/09/22  20:24:36  aggarwal
  645. X * Deleted 'tag' from the print statement.
  646. X * Not used in the nocol struct yet.
  647. X *
  648. X * Revision 3.0  1993/09/21  18:40:42  aggarwal
  649. X * Deleted the code for the Unix socket. Tested, seems ready to go out.
  650. X *
  651. X * Revision 2.0  1993/09/18  21:41:38  aggarwal
  652. X * This version 2.0 tries to use STREAM unix sockets and DGRAM inet
  653. X * sockets (use of dgram unix sockets is not recommended due to
  654. X * buffering and data overflow problems).
  655. X *
  656. X * However, the nature of the client logging is of the un-connected
  657. X * type- since this didn't work in the stream connected environment,
  658. X * this idea is being shelved.
  659. X *
  660. X * Revision 1.16  1993/09/16  23:45:28  aggarwal
  661. X * Added macro to use 'pclose' instead of 'fclose' on receiving SIGHUP
  662. X *
  663. X * Revision 1.14  1993/09/14  21:32:36  aggarwal
  664. X * Changed 'read' to recvfrom() for UDP sockets.
  665. X * Also alarms for timeouts, and security for IP connections.
  666. X *
  667. X * Revision 1.6  1993/03/04  06:37:09  wagner
  668. X * SOCK_STREAM became SOCK_DGRAM.  Started using select().  No more forking.
  669. X *
  670. X * Revision 1.3  1992/10/29  20:59:37  wagner
  671. X * Added ability to pipe log output to a pipe.
  672. X *
  673. X * Revision 1.2  1992/10/29  20:06:51  wagner
  674. X * Now reads a config file to determine where to log the EVENTs to.
  675. X *
  676. X * Revision 1.1  1992/10/29  18:23:02  wagner
  677. X * Initial revision
  678. X *
  679. X */
  680. X
  681. X#include "noclogd.h"
  682. X
  683. X#define READ_TIMEOUT    5        /* timeout for read() from sockets */
  684. X
  685. Xtypedef struct node_s {
  686. X    char        *sender;    /* for comparing EVENT.sender */
  687. X    char        *path;        /* Filename in char format */
  688. X    FILE        *stream;    /* Opened stream */
  689. X    int            isapipe;    /* True if output is a pipe */
  690. X    int            loglevel ;       /* Log level for this stream */
  691. X    struct node_s    *next;        /* Linked list */
  692. X} node;
  693. X
  694. Xstatic node    *loglist=NULL;
  695. Xstatic int    debugflag, mypid=0;
  696. Xstatic char    *myname, *configfilename, *errfilename ;
  697. Xstatic int    sighupflag=0, alarmflag=0 ;
  698. Xstatic unsigned long  permithosts[50] ;        /* list of hosts */
  699. X
  700. Xvoid    sighuphandler(), alarm_intr();
  701. Xchar   *event_to_logstr();        /* format event in string format */
  702. X
  703. Xint main(argc, argv)
  704. X    int argc;
  705. X    char **argv;
  706. X{
  707. X    extern char    *optarg;
  708. X    extern int    optind;
  709. X    char    *pidfilename= NULL;
  710. X    int        c ;
  711. X    FILE    *pidstream;
  712. X
  713. X    /* For fatal(): currently no error condition */
  714. X    myname = NULL;
  715. X    mypid = 0;
  716. X    errno = 0;
  717. X
  718. X    /* Save the program name */
  719. X    if ((myname = (char *)strrchr (argv[0], '/')) == NULL)
  720. X      myname = argv[0] ;             /* no path in program name */
  721. X    else
  722. X      myname++ ;                                /* skip leading '/' */
  723. X
  724. X
  725. X    /* Parse the command line arguments; does no error checking */
  726. X    debugflag = 0;
  727. X
  728. X    while ((c = getopt(argc, argv, "de:f:p:")) != EOF)
  729. X      switch(c)
  730. X      {
  731. X       case 'd':
  732. X      debugflag++;
  733. X      break;
  734. X       case 'e':
  735. X      errfilename = optarg ;
  736. X      break ;
  737. X       case 'f':
  738. X      configfilename = optarg ;
  739. X      break ;
  740. X       case '?':
  741. X       default:
  742. X      fprintf(stderr, "%s: Unknown flag: %c\n", myname, optarg);
  743. X      fprintf(stderr, "Usage: %s [-d] [-f <config file>] ", myname);
  744. X      fprintf(stderr, "[-e <error filename>]\n");
  745. X      exit (1);
  746. X      }
  747. X
  748. X    /* Set the default values. There is a reason for this madness */
  749. X    if (errfilename == NULL)
  750. X      NLOG_ERRORFILE( (errfilename = malloc(256)) );
  751. X    if (configfilename == NULL)
  752. X      NLOG_CONFIGFILE( (configfilename = malloc(256)) );
  753. X    if (pidfilename == NULL)
  754. X      NLOG_PIDFILE( (pidfilename = malloc(256)) );
  755. X             
  756. X    /* Set the umask so error files and PID files aren't world writeable*/
  757. X    (void) umask(NLOG_UMASK);
  758. X
  759. X    fprintf(stderr,"%s (info): LOGHOST is defined to be '%s'\n",
  760. X        myname, NLOG_HOST);
  761. X    fprintf(stderr,"Make sure logging daemon runs on this host\n\n");
  762. X
  763. X    /* Become a daemon */
  764. X    if (debugflag)
  765. X    {
  766. X    fprintf(stderr, "%s: DEBUG  ON, server not daemon-izing\n",myname);
  767. X    fprintf(stderr, "  configf= '%s', errfile= '%s'\n\n",
  768. X            configfilename, errfilename);
  769. X#ifndef DEBUG
  770. X    fprintf(stderr,"%s: WARNING- program NOT compiled with DEBUG option\n",
  771. X        myname);
  772. X#endif
  773. X    }
  774. X    else
  775. X      daemon();
  776. X
  777. X    /* Store away my current PID - this must be done after the daemon() call */
  778. X    mypid = (int) getpid();
  779. X    if ((pidstream=fopen(pidfilename, "w")) == NULL)
  780. X    fatal("fopen() failed for PID file");
  781. X    else
  782. X    {
  783. X    char myhostname[256];
  784. X    gethostname(myhostname, sizeof(myhostname) -1) ;
  785. X    myhostname[sizeof(myhostname) - 1] = '\0' ;
  786. X    fprintf(pidstream, "%d\n%s\n", mypid, myhostname);
  787. X    fclose(pidstream);
  788. X    }
  789. X
  790. X    /* Read the configuration file; good idea to do this after daemon() call */
  791. X    openlogfiles();
  792. X
  793. X    /* Set up the signal handler */
  794. X    sighupflag = 0;
  795. X    (void) signal(SIGHUP, sighuphandler);
  796. X
  797. X    /* And do all the socket stuff - this never returns */
  798. X    serve();
  799. X
  800. X    /*NOTREACHED*/
  801. X}
  802. X
  803. X/*
  804. X * Opens a UDP logging socket, binds to it, and selects on it
  805. X * until some data appears.  Then processes all data that comes
  806. X * in and logs it into the appropriate file.  It never returns,
  807. X * but dies on error.
  808. X */
  809. Xserve()
  810. X{
  811. X    int            inetfd, nfds,  sockbuffsize, optlen ;
  812. X    struct sockaddr_in    sin;
  813. X    struct servent    *sp;
  814. X    fd_set        readfds;
  815. X
  816. X    /*
  817. X     * Open the network logging socket
  818. X     */
  819. X    if ((inetfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
  820. X    fatal("serve(): network socket() failed");
  821. X
  822. X    optlen = 0;
  823. X    getsockopt(inetfd, /* level */SOL_SOCKET, /* optname */SO_RCVBUF, 
  824. X           (char *)&sockbuffsize, &optlen);
  825. X#ifdef DEBUG
  826. X    if (debugflag)
  827. X      fprintf(stderr, "(debug) old inetfd RCVBUF size= %d\n", sockbuffsize);
  828. X#endif
  829. X    if (sockbuffsize < 65534)
  830. X    {
  831. X    sockbuffsize = 65534 ;
  832. X    setsockopt(inetfd, /* level */ SOL_SOCKET, /* optname */SO_RCVBUF, 
  833. X           (char *)&sockbuffsize, sizeof sockbuffsize );
  834. X    }
  835. X    if (debugflag)
  836. X    {
  837. X    optlen = 0 ;
  838. X    getsockopt(inetfd, SOL_SOCKET, SO_RCVBUF, (char *)&sockbuffsize, 
  839. X           &optlen);
  840. X    fprintf(stderr, 
  841. X        "(debug) inetfd RCVBUF size set to %d\n", sockbuffsize);
  842. X    }
  843. X
  844. X    bzero((char *) &sin, sizeof (sin)) ;    /* important */
  845. X    sin.sin_family = AF_INET;
  846. X    /* Figure out what port number to use */
  847. X    if ((sp=getservbyname(myname, "udp")) == NULL)
  848. X    sp = getservbyname(NLOG_SERVICE, "udp");
  849. X    if (sp == NULL)
  850. X    sin.sin_port = htons(NLOG_PORT);
  851. X    else
  852. X    sin.sin_port = sp->s_port;
  853. X
  854. X    /* And do the bind() */
  855. X    if (bind(inetfd, (struct sockaddr *) &sin, sizeof(sin)) < 0)
  856. X    fatal("serve(): couldn't bind to network socket");
  857. X
  858. X    if(debugflag)
  859. X      fprintf(stderr, "  INET socket fd= %d\n", inetfd);
  860. X
  861. X    /* Start waiting for log messages */
  862. X    for (;;) {
  863. X    if (sighupflag)
  864. X    {
  865. X        rereadconfig();
  866. X        sighupflag = 0;
  867. X    }
  868. X
  869. X    /* We're gonna check this after the select, so clear it now... */
  870. X    errno = 0;
  871. X
  872. X    FD_ZERO(&readfds);
  873. X    FD_SET(inetfd, &readfds);
  874. X    nfds = select(FD_SETSIZE, &readfds, (fd_set *) NULL, (fd_set *) NULL,
  875. X            (struct timeval *) NULL);
  876. X
  877. X    /*
  878. X     * The select should only return with nothing to read from
  879. X     * if we got a SIGHUP...
  880. X     */
  881. X    if (errno == EINTR)
  882. X        continue;
  883. X    else if (nfds <= 0)
  884. X        fatal("serve(): select() failed");
  885. X
  886. X    if (FD_ISSET(inetfd, &readfds))        /* Inet dgram socket */
  887. X      readevent(inetfd);
  888. X
  889. X    }
  890. X    /*NOTREACHED*/
  891. X}
  892. X
  893. X
  894. X/*
  895. X * Reads in one EVENT structure and logs it to the appropriate stream,
  896. X * based on the contents of loglist.  Openlogfiles() must have been
  897. X * called first.  Dies upon error.
  898. X */
  899. Xreadevent(fd)
  900. X     int fd;            /* socket file desc */
  901. X{
  902. X    register char *r, *s;
  903. X    int        n, len ;
  904. X    EVENT    v;
  905. X    char    from[sizeof(v.sender)+1]; 
  906. X    register node    *p;
  907. X    struct sockaddr_in    frominet;
  908. X
  909. X    len = sizeof (frominet);
  910. X
  911. X    /* Try to read an EVENT structure in */
  912. X    signal(SIGALRM, alarm_intr);
  913. X    alarmflag = 0 ;
  914. X    alarm(READ_TIMEOUT*10);
  915. X
  916. X    n = recvfrom(fd, (char *)&v, sizeof(v), 0, 
  917. X         (struct sockaddr *)&frominet, &len );
  918. X    if (n != sizeof(v))
  919. X    {
  920. X    if (alarmflag)
  921. X      fprintf(stderr, "%s readevent: socket read timed out\n", myname);
  922. X    else
  923. X      fprintf(stderr,"%s readevent: socket read failed (incomplete)-- %s",
  924. X          myname, sys_errlist[errno]);
  925. X
  926. X    alarm(0);    /* turn alarm off */
  927. X    return(1) ;    /* go back to waiting */
  928. X    }
  929. X    signal(SIGALRM, SIG_IGN);        /* ignore alarm */
  930. X    alarm(0) ;
  931. X
  932. X#ifdef DEBUG
  933. X    if (debugflag)
  934. X      fprintf(stderr, "Recvd packet, sender '%s', loglevel '%d'\n",
  935. X          v.sender, v.loglevel);
  936. X#endif
  937. X
  938. X    /*
  939. X     * The rest of this should be fast, perhaps done in a forked child ?
  940. X     */
  941. X    if (! authenticate_host(&frominet))
  942. X      return(1) ;              /* illegal host */
  943. X
  944. X    /* Make sure things aren't case sensitive */
  945. X    for (r=v.sender, s=from; *r; )
  946. X    *s++ = tolower(*r++);
  947. X    *s = '\0';
  948. X
  949. X    /*
  950. X     * Check the linked list and log it to all applicable streams.
  951. X     * For speed, check,,,
  952. X     *         log level first
  953. X     *        sender (takes longer since it is a string cmp)
  954. X     * Log to all streams at priority EVENT.loglevel and higher.
  955. X     */
  956. X    for (p=loglist; p; p=p->next)
  957. X      if ((int)v.loglevel <= p->loglevel)
  958. X    if (strcmp(p->sender, "*") == 0 || strstr(from, p->sender))
  959. X    {
  960. X        /* Stream closed, try opening it.*/
  961. X        if (!p->stream)
  962. X        {
  963. X#ifdef DEBUG
  964. X        if (debugflag)
  965. X          fprintf(stderr, "Opening stream '%s'\n", p->path);
  966. X#endif
  967. X
  968. X        if (p->isapipe)
  969. X          p->stream = popen(p->path, "w");
  970. X        else
  971. X          p->stream = fopen(p->path, "a");
  972. X
  973. X        if (! p->stream)   /* if the stream could not be reopened  */
  974. X        {
  975. X            fprintf(stderr, "%s: Could not open stream `%s'- ",
  976. X                myname, p->path);
  977. X            perror ("");
  978. X            fflush(stderr);
  979. X            continue ;
  980. X        }
  981. X        }
  982. X
  983. X
  984. X        if (fprintf(p->stream, event_to_logstr(&v)) == EOF) /* error */
  985. X        {
  986. X        perror(p->path);
  987. X        fflush(stderr) ;
  988. X        p->isapipe ?  fclose(p->stream) : pclose(p->stream);
  989. X        p->stream = NULL ;    /* try reopening next time */
  990. X        continue ;        /* Next for() */
  991. X        }
  992. X        
  993. X        fflush(p->stream);
  994. X        
  995. X        if (p->isapipe)        /* close and reopen every time ? */
  996. X        {
  997. X        pclose(p->stream);
  998. X        p->stream = NULL;    /* reset */
  999. X        }
  1000. X        
  1001. X        
  1002. X    }    /*  end: if (stream closed, try reopening it) */
  1003. X
  1004. X}    /* end readevent() */
  1005. X
  1006. X
  1007. X/*+ 
  1008. X * Authenticate hosts. Check to see if the sender has an IP address in
  1009. X * the list from the config file. The argument is the socket file
  1010. X * descriptor which *must* be of the INET type - not a Unix type.
  1011. X *
  1012. X *    A = MASK & A
  1013. X *
  1014. X * Return 1 if OKAY, 0 if not
  1015. X */
  1016. Xauthenticate_host(peer)
  1017. X     struct sockaddr_in *peer ;    /* typecast from sockaddr to sockaddr_in  */
  1018. X{
  1019. X    struct sockaddr_in  s ;
  1020. X    int i ;
  1021. X
  1022. X    if (peer == NULL)
  1023. X      return (0);
  1024. X
  1025. X    for (i = 0; permithosts[i] != 0 ; ++i)
  1026. X      if (permithosts[i] == (unsigned long) peer->sin_addr.s_addr)
  1027. X    return(1) ;
  1028. X
  1029. X    fprintf(stderr, "%s: Permission denied for host %s\n", 
  1030. X        myname, inet_ntoa(peer->sin_addr));
  1031. X
  1032. X    return (0);
  1033. X}
  1034. X
  1035. X
  1036. X/*+
  1037. X * Allocates space for a new node, initializes it's fields, and
  1038. X * inserts it into the beginning of loglist (since it is easier).
  1039. X * Dies upon error.
  1040. X */
  1041. Xnode  *insert(sender, path)
  1042. X    char *sender, *path;
  1043. X{
  1044. X    node    *new;
  1045. X    int        i;
  1046. X    char    *p;
  1047. X
  1048. X    new = (node *) malloc(sizeof(node));
  1049. X    if (new == NULL)
  1050. X    fatal("insert(): out of memory");
  1051. X    bzero(new, sizeof(*new));
  1052. X
  1053. X    new->next = loglist;
  1054. X    new->sender = (char *) malloc(strlen(sender)+1);
  1055. X    new->path = (char *) malloc(strlen(path)+1);
  1056. X    if (new->sender == NULL  ||  new->path == NULL)
  1057. X      fatal("insert(): out of memory using malloc");
  1058. X    for (p=new->sender; *sender; sender++)
  1059. X    *p++ = tolower(*sender);
  1060. X    *p++ = '\0';
  1061. X
  1062. X    if (*path == '|')    /* pipe */
  1063. X      strcpy(new->path, path+1) , new->isapipe = 1 ;
  1064. X    else
  1065. X      strcpy(new->path, path);
  1066. X
  1067. X    loglist = new;    /* point to the new node */
  1068. X    return(new);
  1069. X}
  1070. X
  1071. X/*
  1072. X * Reads in a configuration file and opens the log files named there
  1073. X * for output.  Also writes to pipes instead of a log file if requested.
  1074. X *
  1075. X *        PERMITHOSTS   addr  addr  addr
  1076. X *        EVENT.sender  min-log-severity  Log-filename
  1077. X *        EVENT.sender  min-log-severity    |execute-filename
  1078. X *
  1079. X * Dies upon failure.
  1080. X */
  1081. Xopenlogfiles()
  1082. X{
  1083. X    char    line[1024], *progstr, *sevstr, *filestr, *p, *q;
  1084. X    FILE    *config;
  1085. X    int        level, linenum, i;
  1086. X    node    *new;
  1087. X
  1088. X    /* Sanity check */
  1089. X    if (loglist)
  1090. X    fatal("openlogfiles(): already a list of open files");
  1091. X    if ((config = fopen(configfilename, "r")) == NULL)
  1092. X    {
  1093. X    fprintf (stderr, "confile file '%s': ", configfilename);
  1094. X    fatal("openlogfiles(): couldn't fopen() ");
  1095. X    }
  1096. X
  1097. X
  1098. X    i = 0;
  1099. X    for (linenum=0; fgets(line, sizeof(line)-1, config) != NULL; linenum++)
  1100. X    {
  1101. X    
  1102. X    line[strlen(line)-1] = '\0';    /* Strip off '\n' at  end of line */
  1103. X
  1104. X    if ((p=strchr(line, '#')) != NULL)    /* Get rid of comments */
  1105. X        *p = '\0';
  1106. X
  1107. X    /* Parse the line into fields */
  1108. X    if (*line == NULL  ||  (progstr=strtok(line, " \t")) == NULL)
  1109. X        continue;
  1110. X    else if (strncasecmp("PERMITHOST", line, strlen("PERMITHOST")) == 0)
  1111. X    {
  1112. X        while ((q = strtok(NULL, " \t")) != NULL)
  1113. X        {
  1114. X        permithosts[i++] = inet_addr(q);
  1115. X        if (debugflag)
  1116. X          fprintf(stderr, "Added %s to permithosts list\n", q);
  1117. X        } /* end while() */
  1118. X        continue ;
  1119. X    }
  1120. X      
  1121. X    else if ((sevstr=strtok(NULL, " \t")) == NULL) {
  1122. X        warning_int("config line %d: no severity string, ignoring...\n",
  1123. X            linenum);
  1124. X        continue;
  1125. X    } else if ((filestr=strtok(NULL, " \t")) == NULL) {
  1126. X        warning_int("config line %d: no logfile, ignoring...\n", linenum);
  1127. X        continue;
  1128. X    }
  1129. X
  1130. X    /* Figure out what severity we're at */
  1131. X    level = -1;
  1132. X    switch(tolower(sevstr[0])) {
  1133. X        case 'c': case '1': level = E_CRITICAL; break;
  1134. X        case 'e': case '2': level = E_ERROR; break;
  1135. X        case 'w': case '3': level = E_WARNING; break;
  1136. X        case 'i': case '4': level = E_INFO; break;
  1137. X    }
  1138. X    if (level == -1) {
  1139. X        warning_int("config line %d: bad severity, ignoring...\n", linenum);
  1140. X        continue;
  1141. X    }
  1142. X
  1143. X    /* Create and insert a new node into the linked list */
  1144. X    new = insert(progstr, filestr);
  1145. X    new->loglevel  = level ;
  1146. X    }
  1147. X
  1148. X    fclose(config);        /* close config file */
  1149. X    permithosts[i] = 0 ;    /* null the last one */
  1150. X}
  1151. X
  1152. X/*
  1153. X * Reread the configuration file.  Called whenever SIGHUP is recieved.
  1154. X */
  1155. Xrereadconfig()
  1156. X{
  1157. X    time_t locclock;
  1158. X    char *s;
  1159. X    register node    *p, *q;
  1160. X
  1161. X    locclock = time((time_t *)NULL);
  1162. X    s = (char *)ctime(&locclock);
  1163. X    *(strchr(s, '\n')) = '\0' ;        /* get rid of the newline */
  1164. X    fprintf(stderr, "%s (%d) %s: Closing streams & Re-reading config file\n", 
  1165. X        myname, mypid, s);
  1166. X    for (p = loglist; p; p=q)
  1167. X    {
  1168. X    q = p->next;
  1169. X    if (p->stream)
  1170. X    {
  1171. X        fflush(p->stream);
  1172. X        p->isapipe ? pclose(p->stream) : fclose(p->stream);
  1173. X    }
  1174. X
  1175. X    if (p->sender != NULL)
  1176. X      free(p->sender);
  1177. X    if (p->path != NULL)
  1178. X      free(p->path);
  1179. X    free(p);
  1180. X    }
  1181. X
  1182. X    loglist = NULL;
  1183. X
  1184. X    openlogfiles();
  1185. X}
  1186. X
  1187. X/*
  1188. X * Become a daemon: go into the background, reset our process group,
  1189. X * and clobber the current directory and stdin, stdout, stderr.
  1190. X * Ideas for what needs to be done more or less stolen from BSD sources.
  1191. X * Exits on failure, and complains vigorously!
  1192. X */
  1193. Xdaemon()
  1194. X{
  1195. X    int        retval, fd, errfd;
  1196. X
  1197. X    if ((retval=fork()) < 0)            /* Go into the background */
  1198. X    fatal("daemon(): fork() failed");
  1199. X    else if (retval)
  1200. X    exit(0);
  1201. X
  1202. X    if ((int) setsid() < 0)            /* Reset the process group */
  1203. X    fatal("daemon(): setsid() failed");
  1204. X
  1205. X    if (chdir(ETCDIR) < 0)            /* Clobber current directory */
  1206. X      if (chdir("/") < 0)
  1207. X    fatal("daemon(): chdir() failed");
  1208. X
  1209. X    fd = open("/dev/null", O_RDWR, 0);        /* Clobber stdin, stdout, .. */
  1210. X    errfd = open(errfilename, O_CREAT | O_APPEND | O_WRONLY, 0644);
  1211. X    if (fd < 0 || errfd < 0)
  1212. X    fatal("daemon(): open() failed for errorfile");
  1213. X    if (dup2(fd, 0) < 0 || dup2(errfd, 1) < 0)
  1214. X    fatal("daemon(): dup2() failed");
  1215. X
  1216. X    /* Not much we can do if this dup2 fails - oh well, gotta ignore it */
  1217. X    (void) dup2(errfd, 2);
  1218. X
  1219. X    if ((fd > 2 && close(fd) < 0) || (errfd > 2 && close(errfd) < 0))
  1220. X    fatal("daemon(): close() failed");
  1221. X
  1222. X    signal(SIGALRM, SIG_IGN);        /* ignore alarms until desired */
  1223. X}
  1224. X
  1225. X/*
  1226. X * Outputs an error message to stderr.  Records the daemon's name and
  1227. X * PID, if available.  Prints out the error message corresponding to
  1228. X * errno, if errno is set.  Exits with return value 1.
  1229. X */
  1230. Xfatal(msg)
  1231. X    char *msg;
  1232. X{
  1233. X    if (myname)
  1234. X    fprintf(stderr, "%s: ", myname);
  1235. X    if (mypid)
  1236. X    fprintf(stderr, "(%d) ", mypid);
  1237. X    if (errno)
  1238. X    perror(msg);
  1239. X    else
  1240. X    fprintf(stderr, "%s\n", msg);
  1241. X
  1242. X    exit(1);
  1243. X}
  1244. X
  1245. X
  1246. X
  1247. X/*
  1248. X * Outputs a warning message to stderr.  Records the daemon's name and
  1249. X * PID, if available.  Prints out the error message corresponding to
  1250. X * errno, if errno is set.  Does not exit.
  1251. X *
  1252. X * Assumes that 'format' is a valid fprintf format string that requires
  1253. X * only one argument, the integer 'num'.
  1254. X */
  1255. Xwarning_int(format, num)
  1256. X    char *format;
  1257. X    int num;
  1258. X{
  1259. X    if (myname)
  1260. X    fprintf(stderr, "%s: ", myname);
  1261. X    if (mypid)
  1262. X    fprintf(stderr, "(%d) ", mypid);
  1263. X    fprintf(stderr, format, num);
  1264. X    if (errno)
  1265. X    perror((char *) NULL);
  1266. X    else
  1267. X    fprintf(stderr, "\n");
  1268. X}
  1269. X
  1270. X/*
  1271. X * On receiving an alarm, simply set the flag and return
  1272. X */
  1273. Xvoid alarm_intr()
  1274. X{
  1275. X    alarmflag = 1 ;
  1276. X}
  1277. X
  1278. X/*
  1279. X * Sets the sighupflag whenever we get a SIGHUP signal.
  1280. X */
  1281. Xvoid sighuphandler()
  1282. X{
  1283. X    sighupflag = 1;
  1284. X}
  1285. X
  1286. END_OF_FILE
  1287.   if test 18084 -ne `wc -c <'nocol-3.0/src/noclog/noclogd.c'`; then
  1288.     echo shar: \"'nocol-3.0/src/noclog/noclogd.c'\" unpacked with wrong size!
  1289.   fi
  1290.   # end of 'nocol-3.0/src/noclog/noclogd.c'
  1291. fi
  1292. if test -f 'nocol-3.0/src/portmon/portmon.c' -a "${1}" != "-c" ; then 
  1293.   echo shar: Will not clobber existing file \"'nocol-3.0/src/portmon/portmon.c'\"
  1294. else
  1295.   echo shar: Extracting \"'nocol-3.0/src/portmon/portmon.c'\" \(15152 characters\)
  1296.   sed "s/^X//" >'nocol-3.0/src/portmon/portmon.c' <<'END_OF_FILE'
  1297. X/* $Header: /home/aggarwal/lsrc/nocol/src/portmon/RCS/portmon.c,v 1.2 1993/11/03 20:51:03 aggarwal Exp $  */
  1298. X
  1299. X/* Copyright 1993 JvNCnet, Global Enterprise Services */
  1300. X
  1301. X/*+         portmon
  1302. X * FUNCTION:
  1303. X *     Monitor TCP ports and reponses for NOCOL. It can send a string
  1304. X * and then parse the responses against a list. Each response can be
  1305. X * assigned a severity.
  1306. X *
  1307. X * CAVEATS:
  1308. X *    1) Uses 'strstr' and not a real regular expression. Case sensitive
  1309. X *
  1310. X *      Vikas Aggarwal, -vikas@jvnc.net
  1311. X */
  1312. X
  1313. X/*
  1314. X * $Log: portmon.c,v $
  1315. X * Revision 1.2  1993/11/03  20:51:03  aggarwal
  1316. X * Added ifdef for h_addr (defined in netdb.h) in case its defined.
  1317. X *
  1318. X * Revision 1.1  1993/10/30  03:39:04  aggarwal
  1319. X * Initial revision
  1320. X *
  1321. X */
  1322. X
  1323. X/*   */
  1324. X#ifndef lint
  1325. X static char rcsid[] = "$Id: portmon.c,v 1.2 1993/11/03 20:51:03 aggarwal Exp $" ;
  1326. X#endif
  1327. X
  1328. X#include "portmon.h"
  1329. X
  1330. Xstatic char *myname;
  1331. Xstatic int debugflag, maxseverity, fdout, pollinterval ;
  1332. Xstatic int gotalarm, sock ;
  1333. Xstatic char *configfile ;
  1334. Xstatic char *sender, *datafile ;
  1335. X
  1336. Xstatic void done(),  usr1_handler(), alarm_handler();
  1337. Xextern char *skip_spaces() ;        /* in libnocol */
  1338. X
  1339. Xmain(ac, av)
  1340. X     int ac;
  1341. X     char **av;
  1342. X{
  1343. X    extern char *optarg;
  1344. X    extern int  optind;
  1345. X    int         c ;
  1346. X    char    *pf ;        /* for pidfile in standalone */
  1347. X
  1348. X
  1349. X    if ((myname = (char *)strrchr (av[0], '/')) == NULL)
  1350. X      myname = av[0] ;                        /* no path in program name */
  1351. X    else
  1352. X      myname++ ;                                /* skip leading '/' */
  1353. X
  1354. X#ifdef SENDER
  1355. X    sender = SENDER ;
  1356. X#else                                           /* delete the directory name */
  1357. X    sender = myname ;                         /* no path in program name */
  1358. X#endif
  1359. X
  1360. X    /* the output data filename */    
  1361. X    datafile = malloc (strlen(DATADIR)+ strlen(sender)+ strlen(OUTPUTEXT) +5);
  1362. X    sprintf(datafile,  "%s/%s%s\0",
  1363. X            DATADIR,  sender, OUTPUTEXT); 
  1364. X
  1365. X    configfile = CONFIGFILE ;
  1366. X    pollinterval = POLLINTERVAL ;
  1367. X
  1368. X    while ((c = getopt(ac, av, "df:")) != EOF)
  1369. X      switch(c)
  1370. X      {
  1371. X       case 'd':
  1372. X          debugflag++;
  1373. X          break;
  1374. X       case 'f':
  1375. X          configfile = optarg ;
  1376. X          break ;
  1377. X       case '?':
  1378. X       default:
  1379. X          fprintf(stderr, "%s: Unknown flag: %c\n", myname, optarg);
  1380. X          fprintf(stderr, "Usage: %s [-d] [-f <config file>\n] ", myname);
  1381. X          exit (1);
  1382. X      }
  1383. X
  1384. X    pf = malloc (strlen(myname) + strlen(ETCDIR) + 2) ;
  1385. X    sprintf(pf, "%s/%s\0", ETCDIR, myname) ;
  1386. X    if (standalone(pf) == -1)    /* Kill prev running process    */
  1387. X    {
  1388. X        fprintf(stderr, "%s: Error in standalone...exiting\n", myname);
  1389. X        exit (1);
  1390. X    }
  1391. X    else
  1392. X      free(pf) ;         /* not needed anymore */
  1393. X
  1394. X    if ( (fdout = open(datafile, O_RDWR | O_CREAT | O_TRUNC, 0664)) < 0)
  1395. X    {
  1396. X        fprintf(stderr, "(%s) ERROR in open datafile ", myname);
  1397. X        perror (datafile);
  1398. X    done();
  1399. X    }
  1400. X
  1401. X    if (readconfig(fdout) == -1)
  1402. X      done();
  1403. X
  1404. X    signal (SIGQUIT, done);             /* Delete pid file while dying  */
  1405. X    signal (SIGTERM, done);
  1406. X    signal (SIGINT, done);
  1407. X    signal (SIGHUP, done);
  1408. X    signal (SIGUSR1, usr1_handler);    /* toggles debugging */
  1409. X
  1410. X redo:
  1411. X    lseek(fdout, (off_t)0, SEEK_SET);    /* rewind file */
  1412. X    c = 0;
  1413. X    while (hostarray[c].hname)
  1414. X    {
  1415. X    int status ;
  1416. X    EVENT v;
  1417. X
  1418. X    read(fdout, &v, sizeof v);
  1419. X    status = checkports(&(hostarray[c])) ;
  1420. X    if (status == -1)
  1421. X      fprintf (stderr, "%s: Error in checkports, skipping site %s\n",
  1422. X           myname, hostarray[c].hname);
  1423. X    else
  1424. X    {
  1425. X        update_event(&v, status, status, maxseverity) ;
  1426. X        lseek(fdout, -(off_t)sizeof(v), SEEK_CUR);
  1427. X        write(fdout, (char *)&v, sizeof(v));
  1428. X    }
  1429. X    ++c;
  1430. X    }
  1431. X    lseek(fdout, (off_t)0, SEEK_SET);    /* rewind file */
  1432. X
  1433. X    if (debugflag)
  1434. X      fprintf(stderr, "(debug) %s: sleeping for %d...zzz\n", 
  1435. X          myname,pollinterval);
  1436. X    signal(SIGALRM, SIG_DFL);        /* wake-up, in case blocked */
  1437. X    sleep (pollinterval);
  1438. X    goto redo ;
  1439. X
  1440. X}    /* end:  main()  */
  1441. X
  1442. X
  1443. X/*+ 
  1444. X * FUNCTION:
  1445. X *     Checks the port for the structure _harray passed to it. Sets
  1446. X * global maxseverity. Return value is the 'status' to be used in
  1447. X * update_event().
  1448. X */
  1449. Xcheckports(h)
  1450. X     struct _harray  *h;
  1451. X{
  1452. X    int status;
  1453. X    char readbuf[BUFSIZ];
  1454. X    struct sockaddr_in sin;
  1455. X
  1456. X    if (debugflag)
  1457. X      fprintf (stderr, "(debug) %s: Checking site '%s'/%d\n",
  1458. X           myname, h->hname, h->port);
  1459. X
  1460. X    sock = socket(AF_INET, SOCK_STREAM, 0) ;
  1461. X    if (sock < 0)
  1462. X    {
  1463. X    perror("socket");
  1464. X    return (-1);
  1465. X    }
  1466. X
  1467. X    bzero(&sin, sizeof(sin));
  1468. X    sin.sin_family = AF_INET;
  1469. X
  1470. X    if (isdigit(*(h->ipaddr)) )     /* given an address, not a name */
  1471. X      sin.sin_addr.s_addr = inet_addr(h->ipaddr);
  1472. X    else
  1473. X    {
  1474. X        struct hostent  *hp ;
  1475. X        if ((hp = gethostbyname(h->ipaddr)) == NULL)
  1476. X        {
  1477. X            perror(myname);
  1478. X            fprintf(stderr, "gethostbyname() failed for %s\n", h->ipaddr);
  1479. X            return(-1);
  1480. X        }
  1481. X#ifdef h_addr    /* in netdb.h */
  1482. X        sin.sin_addr.s_addr = inet_addr(hp->h_addr) ;
  1483. X#else
  1484. X        sin.sin_addr.s_addr = inet_addr(hp->h_addr_list[0]) ;
  1485. X#endif
  1486. X    }
  1487. X
  1488. X    if (sin.sin_addr.s_addr == -1)      /* error */
  1489. X    {
  1490. X        perror("inet_addr() failed");
  1491. X    return(-1);            /* fatal error */
  1492. X    }
  1493. X
  1494. X
  1495. X    sin.sin_port = htons(h->port);        /* port number to use */
  1496. X    
  1497. X    if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
  1498. X    {
  1499. X        if (debugflag)
  1500. X      perror("client: AF_INET connect() failed");
  1501. X    close(sock);
  1502. X    maxseverity = h->maxseverity;
  1503. X        return(0);
  1504. X    }
  1505. X
  1506. X    if (h->send && *(h->send) != NULL)        /* if something to send */
  1507. X    {
  1508. X    int n = timeout_read (readbuf, sizeof readbuf);
  1509. X    if (debugflag)
  1510. X      fprintf(stderr, " (debug) %s: ignoring connect string '%s'\n",
  1511. X          myname, readbuf );
  1512. X
  1513. X    if (write(sock, h->send, strlen(h->send)) != strlen(h->send))
  1514. X    {
  1515. X        if (debugflag)
  1516. X        {
  1517. X        fprintf(stderr, "Sendstring error for '%s' port '%s'\n",
  1518. X            h->hname, h->port);
  1519. X        perror("write");
  1520. X        close (sock);
  1521. X        maxseverity = h->maxseverity;
  1522. X        return(0);
  1523. X        }
  1524. X    }    /* end if (couldn't write)  */
  1525. X
  1526. X    write(sock, "\n", 1);            /* send newline */
  1527. X    if (debugflag)
  1528. X      fprintf(stderr, " (debug) %s: sent string '%s' to %s...\n",
  1529. X          myname, h->send, h->hname) ;
  1530. X
  1531. X    }    /* end:  if (something to send) */
  1532. X
  1533. X
  1534. X    if (h->responses[0].response)    /* responses to check */
  1535. X    {
  1536. X
  1537. X    if (timeout_read(readbuf, sizeof readbuf) <= 0)
  1538. X    {
  1539. X        if (debugflag)
  1540. X          fprintf(stderr, "readstring error for '%s' port '%d'",
  1541. X              h->hname, h->port);
  1542. X        if (gotalarm)
  1543. X          fprintf(stderr, "- timeout\n");
  1544. X        else
  1545. X        {
  1546. X        perror("read");
  1547. X        close (sock);
  1548. X        }
  1549. X        maxseverity = h->maxseverity;
  1550. X        return(0);
  1551. X    }
  1552. X    maxseverity = check_resp(readbuf, h->responses);
  1553. X    }
  1554. X    else
  1555. X      maxseverity = E_INFO ;    /* Just had to check a 'connect' */
  1556. X
  1557. X    if (maxseverity == -1)    /* something failed, use default severity */
  1558. X      maxseverity = h->maxseverity ;
  1559. X
  1560. X    close(sock);
  1561. X    if (debugflag)
  1562. X      fprintf(stderr, " (debug): returning severity %d\n", maxseverity) ;
  1563. X    if (maxseverity == E_INFO)
  1564. X      return(1);
  1565. X    else
  1566. X      return(0);        /* status is down */
  1567. X
  1568. X}    /* end:  checkports()  */
  1569. X
  1570. X/*+ 
  1571. X * FUNCTION:
  1572. X *     Read from socket into buffer and put terminating NULL.
  1573. X * Set alarm for timeout. Note that it is reading from 'global' sock
  1574. X * descriptor (since the alarm closes it).
  1575. X * Returns the number of bytes read.
  1576. X *
  1577. X */
  1578. Xtimeout_read(buf, bufsiz)
  1579. X     char *buf;
  1580. X     int bufsiz ;
  1581. X{
  1582. X    int n = 0, len = bufsiz ;
  1583. X    char *cp;
  1584. X
  1585. X    cp = buf ; 
  1586. X
  1587. X    gotalarm = 0;
  1588. X    signal(SIGALRM, alarm_handler);
  1589. X    alarm(RTIMEOUT);
  1590. X
  1591. X    /* read a LINE from global socket (until newline) */
  1592. X    while (len != 0 && (n = read (sock, cp, len)) > 0)
  1593. X    {
  1594. X    cp += (n - 1);    /* increment pointer to last byte read */
  1595. X    len -= n;
  1596. X    if (*cp == '\n'  || *cp == '\0')
  1597. X      break ;
  1598. X    else
  1599. X      cp++ ;    /* increment past last byte read */
  1600. X    }
  1601. X
  1602. X    signal (SIGALRM, SIG_IGN);
  1603. X    alarm (0);                /* remember to unblock alarm */
  1604. X
  1605. X    if (n <= 0)
  1606. X      len = -1 ;            /* some error */
  1607. X    else
  1608. X      len = bufsiz - len ;        /* Total number bytes read */
  1609. X
  1610. X    if (debugflag)
  1611. X      fprintf(stderr, "(debug) timeout_read: Read %d bytes from socket\n",len);
  1612. X
  1613. X    buf[len > 0 ? len:0] = '\0';        /* terminate with NULL */
  1614. X
  1615. X    return (len);            /* number bytes read else negative */
  1616. X
  1617. X}    /* end:  timeout_read() */
  1618. X
  1619. X     
  1620. X/*+ 
  1621. X * FUNCTION:
  1622. X *     Check the list of responses
  1623. X */
  1624. Xcheck_resp(readstr, resarr)
  1625. X     char *readstr;
  1626. X     struct _response  *resarr ;
  1627. X{
  1628. X
  1629. X    if (debugflag)
  1630. X      fprintf(stderr, " (debug) %s: Checking response '%s'\n", myname,readstr);
  1631. X
  1632. X    while (resarr->response)
  1633. X    {
  1634. X    if (strstr(readstr, resarr->response) != NULL)
  1635. X    {
  1636. X        if (debugflag)
  1637. X          fprintf(stderr, " (debug) %s: Matched '%s'\n",
  1638. X              myname, resarr->response);
  1639. X
  1640. X        return(resarr->severity);
  1641. X    }
  1642. X
  1643. X    ++resarr ;
  1644. X    }
  1645. X
  1646. X    if (debugflag)
  1647. X      fprintf (stderr, "%s: No response matched for site\n", myname);
  1648. X
  1649. X    return(-1);        /* No response matched given list */
  1650. X}    /* check_resp()  */
  1651. X
  1652. X
  1653. X/*+ 
  1654. X * FUNCTION:
  1655. X *     Duplicate a string
  1656. X */
  1657. X
  1658. Xchar *Strdup(s)
  1659. X     char *s ;
  1660. X{
  1661. X    char *t ;
  1662. X
  1663. X    t = malloc(strlen(s) + 1);
  1664. X    if (t != NULL)
  1665. X      (char *)strcpy(t, s);
  1666. X
  1667. X    return (t);
  1668. X}
  1669. X
  1670. X/*+ 
  1671. X * FUNCTION:
  1672. X *     Read the config file.
  1673. X * POLLINTERVAL ppp
  1674. X * HOST  <hostname>  <address>  <var>  <port> <failseverity>  "<send string>"
  1675. X * <severity>    "response1"
  1676. X * <severity>   "response2"
  1677. X *
  1678. X */
  1679. X#define NEXTTOK  (char *)skip_spaces(strtok(NULL, " \t"))
  1680. X
  1681. Xreadconfig(fdout)
  1682. X     int fdout ;            /* output data filename */
  1683. X{
  1684. X    int i = 0, j=0;            /* array indexes */
  1685. X    int maxseverity ;
  1686. X    char *j1, *j2 ;            /* temp string pointers */
  1687. X    FILE *cfd ;
  1688. X    EVENT v;                            /* Defined in NOCOL.H */
  1689. X    char record[MAXLINE] ;
  1690. X    struct tm *loctime ;
  1691. X    time_t locclock ;                   /* Careful, don't use 'long'    */
  1692. X
  1693. X    if ((cfd = fopen(configfile, "r")) == NULL)
  1694. X    {
  1695. X        fprintf(stderr, "%s error (init_sites) ", myname) ;
  1696. X        perror (configfile);
  1697. X        return (-1);
  1698. X    }
  1699. X
  1700. X    /*
  1701. X     * Fill in the static data stuff
  1702. X     */
  1703. X    bzero ((char *)hostarray, sizeof(hostarray));
  1704. X    bzero (&v, sizeof(v)) ;
  1705. X
  1706. X    locclock = time((time_t *)0);
  1707. X    loctime = localtime((long *)&locclock);
  1708. X
  1709. X    v.mon = loctime->tm_mon + 1;        v.day = loctime->tm_mday;
  1710. X    v.hour = loctime->tm_hour;          v.min = loctime->tm_min;
  1711. X
  1712. X    strncpy (v.sender, sender, sizeof(v.sender) - 1);
  1713. X
  1714. X    strncpy (v.var.units, VARUNITS, sizeof (v.var.units) - 1);
  1715. X    v.var.threshold = 0 ;
  1716. X
  1717. X    v.nocop = SETF_UPDOUN (0, n_UNKNOWN); /* Set all to UNKNOWN   */
  1718. X    v.severity = E_INFO ;
  1719. X
  1720. X    /*
  1721. X     * Now parse the config file
  1722. X     */
  1723. X
  1724. X    while(fgetline(cfd,record,MAXLINE) > 0 )     /* keeps the \n */
  1725. X    {
  1726. X    static int skiphost;
  1727. X    int port ;
  1728. X
  1729. X    record[strlen(record) -1] = '\0' ;        /* chop off newline */
  1730. X    if (*record == '#' || *(skip_spaces(record)) == NULL)
  1731. X      continue ;
  1732. X
  1733. X    if (strncasecmp(record, "POLLINTERVAL", strlen("POLLINTERVAL")) == 0)
  1734. X    {
  1735. X        strtok(record, " \t");
  1736. X        j1 = (char *)skip_spaces(strtok(NULL, "")) ;
  1737. X        if (j1 == NULL || *j1 == NULL || (pollinterval = atoi(j1)) <= 0)
  1738. X        fprintf(stderr, "%s: bad or missing pollinterval value\n",
  1739. X            myname);
  1740. X
  1741. X        pollinterval = (pollinterval > 0 ? pollinterval : POLLINTERVAL);
  1742. X        if (debugflag)
  1743. X          fprintf (stderr, "(debug) %s: Pollinterval = %d\n", 
  1744. X               myname, pollinterval);
  1745. X
  1746. X        continue;
  1747. X    }
  1748. X
  1749. X
  1750. X    if (strncasecmp(record, "HOST", 4) != 0)    /* Not HOST line */
  1751. X    {
  1752. X        if (skiphost)
  1753. X          continue ;
  1754. X
  1755. X        j1 = strtok(record," \t") ;            /* severity level */
  1756. X        j1 = (char *)skip_spaces(j1) ;
  1757. X        switch(tolower(*j1))
  1758. X        {
  1759. X         case 'c': case '1': maxseverity = E_CRITICAL; break;
  1760. X         case 'e': case '2': maxseverity = E_ERROR;     break;
  1761. X         case 'w': case '3': maxseverity = E_WARNING; break;
  1762. X         case 'i': case '4': maxseverity = E_INFO;     break;
  1763. X         default:  maxseverity = E_CRITICAL; break ;
  1764. X        }
  1765. X        /* remember that the 'i' index has been incremented */
  1766. X        hostarray[i-1].responses[j].severity = maxseverity ;
  1767. X        j1 = (char *)skip_spaces(strtok(NULL, "")) ;
  1768. X        if (j1 == NULL)
  1769. X        {
  1770. X        fprintf(stderr, "%s: missing response line\n", myname);
  1771. X        continue;
  1772. X        }
  1773. X        hostarray[i-1].responses[j].response = (char *)Strdup(j1);
  1774. X        j++ ;
  1775. X
  1776. X        continue ;    /* next input line */
  1777. X    }
  1778. X
  1779. X    /*
  1780. X     * Here if parsing a HOST line
  1781. X     */
  1782. X    j = 0;            /* and reset the response array index */
  1783. X    
  1784. X    skiphost = 0;        /* assume valid config */
  1785. X    strtok(record, " \t");    /* skip HOST keyword */    
  1786. X        
  1787. X    strncpy(v.site.name, NEXTTOK, sizeof(v.site.name) - 1);
  1788. X    strncpy(v.site.addr, NEXTTOK, sizeof(v.site.addr) - 1);
  1789. X    if (inet_addr(v.site.addr) == -1)        /* bad address */
  1790. X    {
  1791. X        fprintf(stderr,
  1792. X            "(%s): Error in addr '%s' for site '%s', ignoring\n",
  1793. X            myname, v.site.addr, v.site.name);
  1794. X        skiphost = 1;
  1795. X        continue ;
  1796. X    }
  1797. X    strncpy(v.var.name, NEXTTOK, sizeof(v.var.name) - 1);
  1798. X    
  1799. X    if ((port = atoi(NEXTTOK)) == 0)
  1800. X    {
  1801. X        fprintf(stderr,
  1802. X            "(%s): Error in port for site '%s', ignoring\n",
  1803. X            myname, v.site.name);
  1804. X        skiphost = 1;
  1805. X        continue ;
  1806. X    }
  1807. X    
  1808. X    j1 = NEXTTOK;    /* severity level */
  1809. X    if (j1 == NULL)
  1810. X      j1 = "c";
  1811. X    switch(tolower(*j1))
  1812. X    {
  1813. X     case 'c': maxseverity = E_CRITICAL; break;
  1814. X     case 'e': maxseverity = E_ERROR; break;
  1815. X     case 'w': maxseverity = E_WARNING; break;
  1816. X     case 'i': maxseverity = E_INFO; break;
  1817. X     default:  maxseverity = E_CRITICAL ; break ;
  1818. X    }
  1819. X    
  1820. X    if (debugflag)
  1821. X      fprintf (stderr, "Name: %s %s, VAR: %s, Port %d SEV: %d\n",
  1822. X           v.site.name,v.site.addr,v.var.name, 
  1823. X           port,maxseverity);
  1824. X    
  1825. X    /* the rest of string is SEND */
  1826. X    j1 = (char *)skip_spaces(strtok(NULL, ""));  
  1827. X    if (j1)
  1828. X      hostarray[i].send = (char *)Strdup(j1) ;
  1829. X    else
  1830. X      hostarray[i].send = NULL ;        /* no SEND string */
  1831. X
  1832. X    hostarray[i].port = port;
  1833. X    hostarray[i].maxseverity = maxseverity ;
  1834. X    hostarray[i].hname = (char *)Strdup(v.site.name);
  1835. X    hostarray[i].ipaddr = (char *)Strdup(v.site.addr);
  1836. X    bzero (hostarray[i].responses, sizeof (hostarray[i].responses));
  1837. X    
  1838. X    if (write (fdout, (char *)&v, sizeof(v)) != sizeof(v))
  1839. X    {
  1840. X        fprintf(stderr, "%s (write): %s\n", myname,sys_errlist[errno]);
  1841. X        done() ;
  1842. X    }
  1843. X    ++i;            /* increment the index, in case */
  1844. X
  1845. X    }    /* end: while */
  1846. X
  1847. X    fclose (cfd);               /* Not needed any more */    
  1848. X    return(1);                          /* All OK  */
  1849. X
  1850. X}  /* end:  init_sites() */
  1851. X
  1852. X/*+ 
  1853. X * FUNCTION:
  1854. X *     Toggle debugging on/off
  1855. X */
  1856. Xstatic void usr1_handler()
  1857. X{
  1858. X    if (debugflag)
  1859. X      debugflag = 0;
  1860. X    else
  1861. X      debugflag = 1;
  1862. X
  1863. X    if (debugflag)
  1864. X      fprintf (stderr, "(debug) %s: recvd USR1, enabling debugging\n", myname);
  1865. X
  1866. X}    
  1867. X
  1868. X/*+ 
  1869. X * FUNCTION:
  1870. X *     Handle timeouts for sockets. Since it doesn't interrupt system
  1871. X *    calls (like read() ), close the socket so that read fails.
  1872. X */
  1873. Xstatic void alarm_handler()
  1874. X{
  1875. X    if (debugflag)
  1876. X      fprintf (stderr, "(debug) %s: recvd ALARM\n", myname);
  1877. X    gotalarm = 1;
  1878. X    close (sock);
  1879. X}
  1880. X
  1881. X/*+ 
  1882. X * FUNCTION:
  1883. X * 
  1884. X */
  1885. Xstatic void done()
  1886. X{
  1887. X    char pidfile[MAXLINE] ;
  1888. X
  1889. X    closeeventlog() ;
  1890. X
  1891. X    fprintf (stderr, "%s: removing data, pid file.... ", myname);
  1892. X    sprintf (pidfile, "%s/%s.pid\0", ETCDIR, myname);
  1893. X    unlink (pidfile);                           /* remove the PID file  */
  1894. X    unlink (datafile);                          /* delete the data file */
  1895. X    fprintf (stderr, "Done\n");
  1896. X    exit (1);
  1897. X}
  1898. X
  1899. X
  1900. END_OF_FILE
  1901.   if test 15152 -ne `wc -c <'nocol-3.0/src/portmon/portmon.c'`; then
  1902.     echo shar: \"'nocol-3.0/src/portmon/portmon.c'\" unpacked with wrong size!
  1903.   fi
  1904.   # end of 'nocol-3.0/src/portmon/portmon.c'
  1905. fi
  1906. if test -f 'nocol-3.0/src/support/mping/brl-ping.c' -a "${1}" != "-c" ; then 
  1907.   echo shar: Will not clobber existing file \"'nocol-3.0/src/support/mping/brl-ping.c'\"
  1908. else
  1909.   echo shar: Extracting \"'nocol-3.0/src/support/mping/brl-ping.c'\" \(18494 characters\)
  1910.   sed "s/^X//" >'nocol-3.0/src/support/mping/brl-ping.c' <<'END_OF_FILE'
  1911. X/*
  1912. X *            P I N G . C
  1913. X *
  1914. X * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
  1915. X * measure round-trip-delays and packet loss across network paths.
  1916. X *
  1917. X * Author -
  1918. X *    Mike Muuss
  1919. X *    U. S. Army Ballistic Research Laboratory
  1920. X *    December, 1983
  1921. X * Modified at Uc Berkeley
  1922. X * Record Route and verbose headers - Phil Dykstra, BRL, March 1988.
  1923. X *
  1924. X * 910504 Watt-Alan@Yale.Edu (Alan S. Watt)
  1925. X *
  1926. X * + Added verification of ICMP checksum on packet receipt, to check
  1927. X *   for data damage over links which don't provide a CRC.
  1928. X *
  1929. X * + Added -p<pattern> option to fill the packet with a specific
  1930. X *   bit pattern to check for data-dependent transmission loss.
  1931. X *
  1932. X * + Cleaned up several calls to inet_ntoa() which passed
  1933. X *   an unsigned long instead of a structure containing an unsigned
  1934. X *   long.
  1935. X *
  1936. X * Status -
  1937. X *    Public Domain.  Distribution Unlimited.
  1938. X *
  1939. X * Bugs -
  1940. X *    More statistics could always be gathered.
  1941. X *    This program has to run SUID to ROOT to access the ICMP socket.
  1942. X */
  1943. X
  1944. X#include <stdio.h>
  1945. X#include <errno.h>
  1946. X#include <sys/time.h>
  1947. X
  1948. X#include <sys/param.h>
  1949. X#include <sys/socket.h>
  1950. X#include <sys/file.h>
  1951. X
  1952. X#include <netinet/in_systm.h>
  1953. X#include <netinet/in.h>
  1954. X#include <netinet/ip.h>
  1955. X#include <netinet/ip_icmp.h>
  1956. X#include <netdb.h>
  1957. X
  1958. X#define    MAXWAIT        10    /* max time to wait for response, sec. */
  1959. X#define    MAXPACKET    4096    /* max packet size */
  1960. X#define VERBOSE        1    /* verbose flag */
  1961. X#define QUIET        2    /* quiet flag */
  1962. X#define FLOOD        4    /* floodping flag */
  1963. X#define    RROUTE        8    /* record route flag */
  1964. X#define    NROUTES        9    /* number of record route slots */
  1965. X#ifndef MAXHOSTNAMELEN
  1966. X#define MAXHOSTNAMELEN    64
  1967. X#endif
  1968. X
  1969. Xu_char    packet[MAXPACKET];
  1970. Xint    i, pingflags, options;
  1971. Xextern    int errno;
  1972. X
  1973. Xint s;            /* Socket file descriptor */
  1974. Xstruct hostent *hp;    /* Pointer to host info */
  1975. Xstruct timezone tz;    /* leftover */
  1976. X
  1977. Xstruct sockaddr whereto;/* Who to ping */
  1978. Xint datalen;        /* How much data */
  1979. X
  1980. Xchar usage[] =
  1981. X"Usage:  ping [-dfnqrvR] host [packetsize [count [preload]]]\n";
  1982. X
  1983. Xchar *hostname;
  1984. Xchar hnamebuf[MAXHOSTNAMELEN];
  1985. X
  1986. Xint npackets;
  1987. Xint preload = 0;        /* number of packets to "preload" */
  1988. Xint ntransmitted = 0;        /* sequence # for outbound packets = #sent */
  1989. Xint ident;
  1990. X
  1991. Xint nreceived = 0;        /* # of packets we got back */
  1992. Xint timing = 0;
  1993. Xint tmin = 999999999;
  1994. Xint tmax = 0;
  1995. Xint tsum = 0;            /* sum of all times, for doing average */
  1996. Xint finish(), catcher();
  1997. Xchar *inet_ntoa();
  1998. Xchar *pr_addr();
  1999. X
  2000. Xint numeric = 0;        /* -n flag: numeric addresses only */
  2001. Xchar rspace[3+4*NROUTES+1];    /* record route space */
  2002. X
  2003. Xint ncorrupted = 0;        /* number of corrupted packets returned */
  2004. Xint patternData = 0;
  2005. Xint doPattern = 0;
  2006. X
  2007. X/*
  2008. X *             M A I N
  2009. X */
  2010. Xmain(argc, argv)
  2011. Xchar *argv[];
  2012. X{
  2013. X    struct sockaddr_in from;
  2014. X    char **av = argv;
  2015. X    struct sockaddr_in *to = (struct sockaddr_in *) &whereto;
  2016. X    int on = 1;
  2017. X    struct protoent *proto;
  2018. X
  2019. X    argc--, av++;
  2020. X    while (argc > 0 && *av[0] == '-') {
  2021. X        while (*++av[0]) switch (*av[0]) {
  2022. X            case 'd':
  2023. X                options |= SO_DEBUG;
  2024. X                break;
  2025. X            case 'r':
  2026. X                options |= SO_DONTROUTE;
  2027. X                break;
  2028. X            case 'v':
  2029. X                pingflags |= VERBOSE;
  2030. X                break;
  2031. X            case 'q':
  2032. X                pingflags |= QUIET;
  2033. X                break;
  2034. X            case 'f':
  2035. X                pingflags |= FLOOD;
  2036. X                break;
  2037. X            case 'R':
  2038. X                pingflags |= RROUTE;
  2039. X                break;
  2040. X            case 'n':
  2041. X                numeric++;
  2042. X                break;
  2043. X            case 'p':
  2044. X                patternData = getPatternData(av[0]+1);
  2045. X                doPattern = 1;
  2046. X                goto nextArg;
  2047. X        }
  2048. X      nextArg:
  2049. X        argc--, av++;
  2050. X    }
  2051. X    if(argc < 1 || argc > 4)  {
  2052. X        printf(usage);
  2053. X        exit(1);
  2054. X    }
  2055. X
  2056. X    bzero((char *)&whereto, sizeof(struct sockaddr) );
  2057. X    to->sin_family = AF_INET;
  2058. X    to->sin_addr.s_addr = inet_addr(av[0]);
  2059. X    if(to->sin_addr.s_addr != (unsigned)-1) {
  2060. X        strcpy(hnamebuf, av[0]);
  2061. X        hostname = hnamebuf;
  2062. X    } else {
  2063. X        hp = gethostbyname(av[0]);
  2064. X        if (hp) {
  2065. X            to->sin_family = hp->h_addrtype;
  2066. X            bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
  2067. X            strncpy( hnamebuf, hp->h_name, sizeof(hnamebuf)-1 );
  2068. X            hostname = hnamebuf;
  2069. X        } else {
  2070. X            printf("%s: unknown host %s\n", argv[0], av[0]);
  2071. X            exit(1);
  2072. X        }
  2073. X    }
  2074. X
  2075. X    if( argc >= 2 )
  2076. X        datalen = atoi( av[1] );
  2077. X    else
  2078. X        datalen = 64-8;
  2079. X    if (datalen > MAXPACKET) {
  2080. X        fprintf(stderr, "ping: packet size too large\n");
  2081. X        exit(1);
  2082. X    }
  2083. X    if (datalen >= sizeof(struct timeval))    /* can we time 'em? */
  2084. X        timing = 1;
  2085. X
  2086. X    if (argc >= 3)
  2087. X        npackets = atoi(av[2]);
  2088. X
  2089. X    if (argc == 4)
  2090. X        preload = atoi(av[3]);
  2091. X
  2092. X    ident = getpid() & 0xFFFF;
  2093. X
  2094. X    if ((proto = getprotobyname("icmp")) == NULL) {
  2095. X        fprintf(stderr, "icmp: unknown protocol\n");
  2096. X        exit(10);
  2097. X    }
  2098. X    if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
  2099. X        perror("ping: socket");
  2100. X        exit(5);
  2101. X    }
  2102. X    if (options & SO_DEBUG) {
  2103. X        setsockopt(s, SOL_SOCKET, SO_DEBUG, &on, sizeof(on));
  2104. X    }
  2105. X    if (options & SO_DONTROUTE) {
  2106. X        setsockopt(s, SOL_SOCKET, SO_DONTROUTE, &on, sizeof(on));
  2107. X    }
  2108. X    /* Record Route option */
  2109. X    if( pingflags & RROUTE ) {
  2110. X#ifdef IP_OPTIONS
  2111. X        rspace[IPOPT_OPTVAL] = IPOPT_RR;
  2112. X        rspace[IPOPT_OLEN] = sizeof(rspace)-1;
  2113. X        rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
  2114. X        if( setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace, sizeof(rspace)) < 0 ) {
  2115. X            perror( "Record route" );
  2116. X            exit( 42 );
  2117. X        }
  2118. X#else
  2119. X        fprintf( stderr, "ping: record route not available on this machine.\n" );
  2120. X        exit( 42 );
  2121. X#endif IP_OPTIONS
  2122. X    }
  2123. X
  2124. X    if(to->sin_family == AF_INET) {
  2125. X        printf("PING %s (%s): %d data bytes\n", hostname,
  2126. X          inet_ntoa(to->sin_addr), datalen);
  2127. X    } else {
  2128. X        printf("PING %s: %d data bytes\n", hostname, datalen );
  2129. X    }
  2130. X    setlinebuf( stdout );
  2131. X
  2132. X    signal( SIGINT, finish );
  2133. X    signal(SIGALRM, catcher);
  2134. X
  2135. X    /* fire off them quickies */
  2136. X    for(i=0; i < preload; i++)
  2137. X        pinger();
  2138. X
  2139. X    if(!(pingflags & FLOOD))
  2140. X        catcher();    /* start things going */
  2141. X
  2142. X    for (;;) {
  2143. X        int len = sizeof (packet);
  2144. X        int fromlen = sizeof (from);
  2145. X        int cc;
  2146. X        struct timeval timeout;
  2147. X        int fdmask = 1 << s;
  2148. X
  2149. X        timeout.tv_sec = 0;
  2150. X        timeout.tv_usec = 10000;
  2151. X
  2152. X        if(pingflags & FLOOD) {
  2153. X            pinger();
  2154. X            if( select(32, &fdmask, 0, 0, &timeout) == 0)
  2155. X                continue;
  2156. X        }
  2157. X        if ( (cc=recvfrom(s, packet, len, 0, &from, &fromlen)) < 0) {
  2158. X            if( errno == EINTR )
  2159. X                continue;
  2160. X            perror("ping: recvfrom");
  2161. X            continue;
  2162. X        }
  2163. X        pr_pack( packet, cc, &from );
  2164. X        if (npackets && nreceived >= npackets)
  2165. X            finish();
  2166. X    }
  2167. X    /*NOTREACHED*/
  2168. X}
  2169. X
  2170. X/*
  2171. X *             C A T C H E R
  2172. X * 
  2173. X * This routine causes another PING to be transmitted, and then
  2174. X * schedules another SIGALRM for 1 second from now.
  2175. X * 
  2176. X * Bug -
  2177. X *     Our sense of time will slowly skew (ie, packets will not be launched
  2178. X *     exactly at 1-second intervals).  This does not affect the quality
  2179. X *    of the delay and loss statistics.
  2180. X */
  2181. Xcatcher()
  2182. X{
  2183. X    int waittime;
  2184. X
  2185. X    pinger();
  2186. X    if (npackets == 0 || ntransmitted < npackets)
  2187. X        alarm(1);
  2188. X    else {
  2189. X        if (nreceived) {
  2190. X            waittime = 2 * tmax / 1000;
  2191. X            if (waittime == 0)
  2192. X                waittime = 1;
  2193. X        } else
  2194. X            waittime = MAXWAIT;
  2195. X        signal(SIGALRM, finish);
  2196. X        alarm(waittime);
  2197. X    }
  2198. X}
  2199. X
  2200. X/*
  2201. X *             P I N G E R
  2202. X * 
  2203. X * Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
  2204. X * will be added on by the kernel.  The ID field is our UNIX process ID,
  2205. X * and the sequence number is an ascending integer.  The first 8 bytes
  2206. X * of the data portion are used to hold a UNIX "timeval" struct in VAX
  2207. X * byte-order, to compute the round-trip time.
  2208. X */
  2209. Xpinger()
  2210. X{
  2211. X    static u_char outpack[MAXPACKET];
  2212. X    register struct icmp *icp = (struct icmp *) outpack;
  2213. X    int i, cc;
  2214. X    register struct timeval *tp = (struct timeval *) &outpack[8];
  2215. X    register u_char *datap = &outpack[8+sizeof(struct timeval)];
  2216. X
  2217. X    icp->icmp_type = ICMP_ECHO;
  2218. X    icp->icmp_code = 0;
  2219. X    icp->icmp_cksum = 0;
  2220. X    icp->icmp_seq = ntransmitted++;
  2221. X    icp->icmp_id = ident;        /* ID */
  2222. X
  2223. X    cc = datalen+8;            /* skips ICMP portion */
  2224. X
  2225. X    if (timing)
  2226. X        gettimeofday( tp, &tz );
  2227. X
  2228. X    if (doPattern) {
  2229. X        for( i=8; i<datalen; i++)    /* skip 8 for time */
  2230. X            *datap++ = patternData;
  2231. X    } else {
  2232. X        for( i=8; i<datalen; i++)    /* skip 8 for time */
  2233. X            *datap++ = i;
  2234. X    }
  2235. X
  2236. X    /* Compute ICMP checksum here */
  2237. X    icp->icmp_cksum = in_cksum( icp, cc );
  2238. X
  2239. X    /* cc = sendto(s, msg, len, flags, to, tolen) */
  2240. X    i = sendto( s, outpack, cc, 0, &whereto, sizeof(struct sockaddr) );
  2241. X
  2242. X    if( i < 0 || i != cc )  {
  2243. X        if( i<0 )  perror("sendto");
  2244. X        printf("ping: wrote %s %d chars, ret=%d\n",
  2245. X            hostname, cc, i );
  2246. X        fflush(stdout);
  2247. X    }
  2248. X    if(pingflags == FLOOD) {
  2249. X        putchar('.');
  2250. X        fflush(stdout);
  2251. X    }
  2252. X}
  2253. X
  2254. X/*
  2255. X *            P R _ P A C K
  2256. X *
  2257. X * Print out the packet, if it came from us.  This logic is necessary
  2258. X * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
  2259. X * which arrive ('tis only fair).  This permits multiple copies of this
  2260. X * program to be run without having intermingled output (or statistics!).
  2261. X */
  2262. Xpr_pack( buf, cc, from )
  2263. Xchar *buf;
  2264. Xint cc;
  2265. Xstruct sockaddr_in *from;
  2266. X{
  2267. X    struct ip *ip;
  2268. X    register struct icmp *icp;
  2269. X    register long *lp = (long *) packet;
  2270. X    register int i;
  2271. X    struct timeval tv;
  2272. X    struct timeval *tp;
  2273. X    int hlen, triptime;
  2274. X
  2275. X    from->sin_addr.s_addr = ntohl( from->sin_addr.s_addr );
  2276. X    gettimeofday( &tv, &tz );
  2277. X
  2278. X    /* Check the IP header */
  2279. X    ip = (struct ip *) buf;
  2280. X    hlen = ip->ip_hl << 2;
  2281. X    if( cc < hlen + ICMP_MINLEN ) {
  2282. X        if( pingflags & VERBOSE )
  2283. X            printf("packet too short (%d bytes) from %s\n", cc,
  2284. X                inet_ntoa(from->sin_addr));
  2285. X        return;
  2286. X    }
  2287. X
  2288. X    /* Now the ICMP part */
  2289. X    cc -= hlen;
  2290. X    icp = (struct icmp *)(buf + hlen);
  2291. X    if( icp->icmp_type == ICMP_ECHOREPLY ) {
  2292. X        if( icp->icmp_id != ident )
  2293. X            return;            /* 'Twas not our ECHO */
  2294. X
  2295. X        nreceived++;
  2296. X        if (timing) {
  2297. X            tp = (struct timeval *)&icp->icmp_data[0];
  2298. X            tvsub( &tv, tp );
  2299. X            triptime = tv.tv_sec*1000+(tv.tv_usec/1000);
  2300. X            tsum += triptime;
  2301. X            if( triptime < tmin )
  2302. X                tmin = triptime;
  2303. X            if( triptime > tmax )
  2304. X                tmax = triptime;
  2305. X        }
  2306. X
  2307. X        if( pingflags & QUIET )
  2308. X            return;
  2309. X
  2310. X        if( pingflags & FLOOD ) {
  2311. X            putchar('\b');
  2312. X            fflush(stdout);
  2313. X        } else {
  2314. X            printf("%d bytes from %s: icmp_seq=%d", cc,
  2315. X              inet_ntoa(from->sin_addr), icp->icmp_seq );
  2316. X            if (corrupted (icp, cc)) {
  2317. X                printf (" (BAD)");
  2318. X                ncorrupted += 1;
  2319. X            }
  2320. X            if (timing)
  2321. X                printf(" time=%d ms\n", triptime );
  2322. X            else
  2323. X                putchar('\n');
  2324. X        }
  2325. X    } else {
  2326. X        /* We've got something other than an ECHOREPLY */
  2327. X        if( !(pingflags & VERBOSE) )
  2328. X            return;
  2329. X
  2330. X        printf("%d bytes from %s: ",
  2331. X          cc, pr_addr(ntohl(from->sin_addr.s_addr)) );
  2332. X        pr_icmph( icp );
  2333. X    }
  2334. X
  2335. X    /* Display any IP options */
  2336. X    /* XXX - we should eventually do this for all packets with options */
  2337. X    if( hlen > 20 && icp->icmp_type == ICMP_ECHOREPLY ) {
  2338. X        unsigned char *cp;
  2339. X        /*printf("%d byte IP header:\n", hlen);*/
  2340. X        cp = (unsigned char *)buf + sizeof(struct ip) + 3;
  2341. X        for( i = 0; i < NROUTES; i++ ) {
  2342. X            unsigned long l;
  2343. X            l = (*cp<<24) | (*(cp+1)<<16) | (*(cp+2)<<8) | *(cp+3);
  2344. X            /* give the nameserver a break! */
  2345. X            if( l == 0 ) {
  2346. X                /*printf("0.0.0.0\n"); Hope the zeros are not in the middle */
  2347. X            } else {
  2348. X                printf("\t%s\n", pr_addr(ntohl(l)) );
  2349. X            }
  2350. X            cp += 4;
  2351. X        }
  2352. X    }
  2353. X}
  2354. X
  2355. X/* corrupted:
  2356. X * verify data portion of packet is what we sent
  2357. X */
  2358. Xcorrupted (icp, len)
  2359. Xregister struct icmp *icp;
  2360. Xint len;
  2361. X{
  2362. X    register i;
  2363. X    int cksum, oldcksum;
  2364. X
  2365. X
  2366. X    oldcksum = icp->icmp_cksum;
  2367. X#ifndef FORCEBAD
  2368. X    icp->icmp_cksum = 0;
  2369. X#endif
  2370. X    cksum = in_cksum( icp, len );
  2371. X    icp->icmp_cksum = oldcksum;
  2372. X    if (cksum != oldcksum)
  2373. X        return 1;
  2374. X    return 0;
  2375. X}
  2376. X
  2377. X/* getPatternData: get a data pattern
  2378. X *
  2379. X * Handles decimal (default), octal (leading "0"), and
  2380. X * hexidecimal (leading "0x", "0X") notations.  If decimal,
  2381. X * also accepts leading minus sign.
  2382. X */
  2383. X#include <ctype.h>
  2384. X
  2385. X#define DECORD(C)    ((C) - '0')
  2386. X#define UCXORD(C)    ((C) - 'A' + 10)
  2387. X#define LCXORD(C)    ((C) - 'a' + 10)
  2388. X
  2389. XgetPatternData (str)
  2390. Xchar* str;
  2391. X{
  2392. X    int base = 10;
  2393. X    int digit;
  2394. X    unsigned int ret = 0;
  2395. X    int sign = 1;
  2396. X
  2397. X    if (*str == '0') {
  2398. X        str++;
  2399. X        if (*str == 'x' || *str == 'X') {
  2400. X            str++; base = 16;
  2401. X        }
  2402. X        else
  2403. X            base = 8;
  2404. X    }
  2405. X    else if (*str == '-') {
  2406. X        str++; sign = -1;
  2407. X    }
  2408. X
  2409. X    for ( ; *str != '\0'; str++) {
  2410. X        if (isdigit(*str))
  2411. X            digit = DECORD(*str);
  2412. X        else if (isxdigit(*str))
  2413. X            digit = isupper(*str) ? UCXORD(*str) : LCXORD(*str);
  2414. X        else
  2415. X            break;
  2416. X
  2417. X        if (digit >= base)
  2418. X            break;
  2419. X
  2420. X        ret = ret*base + digit;
  2421. X    }
  2422. X    return ret * sign;
  2423. X}
  2424. X
  2425. X/*
  2426. X *            I N _ C K S U M
  2427. X *
  2428. X * Checksum routine for Internet Protocol family headers (C Version)
  2429. X *
  2430. X */
  2431. Xin_cksum(addr, len)
  2432. Xu_short *addr;
  2433. Xint len;
  2434. X{
  2435. X    register int nleft = len;
  2436. X    register u_short *w = addr;
  2437. X    register int sum = 0;
  2438. X    u_short answer = 0;
  2439. X
  2440. X    /*
  2441. X     *  Our algorithm is simple, using a 32 bit accumulator (sum),
  2442. X     *  we add sequential 16 bit words to it, and at the end, fold
  2443. X     *  back all the carry bits from the top 16 bits into the lower
  2444. X     *  16 bits.
  2445. X     */
  2446. X    while( nleft > 1 )  {
  2447. X        sum += *w++;
  2448. X        nleft -= 2;
  2449. X    }
  2450. X
  2451. X    /* mop up an odd byte, if necessary */
  2452. X    if( nleft == 1 ) {
  2453. X        *(u_char *)(&answer) = *(u_char *)w ;
  2454. X        sum += answer;
  2455. X    }
  2456. X
  2457. X    /*
  2458. X     * add back carry outs from top 16 bits to low 16 bits
  2459. X     */
  2460. X    sum = (sum >> 16) + (sum & 0xffff);    /* add hi 16 to low 16 */
  2461. X    sum += (sum >> 16);            /* add carry */
  2462. X    answer = ~sum;                /* truncate to 16 bits */
  2463. X    return (answer);
  2464. X}
  2465. X
  2466. X/*
  2467. X *             T V S U B
  2468. X * 
  2469. X * Subtract 2 timeval structs:  out = out - in.
  2470. X * 
  2471. X * Out is assumed to be >= in.
  2472. X */
  2473. Xtvsub( out, in )
  2474. Xregister struct timeval *out, *in;
  2475. X{
  2476. X    if( (out->tv_usec -= in->tv_usec) < 0 )   {
  2477. X        out->tv_sec--;
  2478. X        out->tv_usec += 1000000;
  2479. X    }
  2480. X    out->tv_sec -= in->tv_sec;
  2481. X}
  2482. X
  2483. X/*
  2484. X *            F I N I S H
  2485. X *
  2486. X * Print out statistics, and give up.
  2487. X * Heavily buffered STDIO is used here, so that all the statistics
  2488. X * will be written with 1 sys-write call.  This is nice when more
  2489. X * than one copy of the program is running on a terminal;  it prevents
  2490. X * the statistics output from becomming intermingled.
  2491. X */
  2492. Xfinish()
  2493. X{
  2494. X    putchar('\n');
  2495. X    fflush(stdout);
  2496. X    printf("\n----%s PING Statistics----\n", hostname );
  2497. X    printf("%d packets transmitted, ", ntransmitted );
  2498. X    printf("%d packets received, ", nreceived );
  2499. X    if (ncorrupted > 0)
  2500. X        printf  ("(%d corrupted) ", ncorrupted);
  2501. X    if (ntransmitted)
  2502. X        if( nreceived > ntransmitted)
  2503. X            printf("-- somebody's printing up packets!");
  2504. X        else
  2505. X            printf("%d%% packet loss", 
  2506. X              (int) (((ntransmitted-nreceived)*100) /
  2507. X              ntransmitted));
  2508. X    printf("\n");
  2509. X    if (nreceived && timing)
  2510. X        printf("round-trip (ms)  min/avg/max = %d/%d/%d\n",
  2511. X        tmin,
  2512. X        tsum / nreceived,
  2513. X        tmax );
  2514. X    fflush(stdout);
  2515. X    exit(0);
  2516. X}
  2517. X
  2518. Xstatic char *ttab[] = {
  2519. X    "Echo Reply",        /* ip + seq + udata */
  2520. X    "Dest Unreachable",    /* net, host, proto, port, frag, sr + IP */
  2521. X    "Source Quench",    /* IP */
  2522. X    "Redirect",        /* redirect type, gateway, + IP  */
  2523. X    "Echo",
  2524. X    "Time Exceeded",    /* transit, frag reassem + IP */
  2525. X    "Parameter Problem",    /* pointer + IP */
  2526. X    "Timestamp",        /* id + seq + three timestamps */
  2527. X    "Timestamp Reply",    /* " */
  2528. X    "Info Request",        /* id + sq */
  2529. X    "Info Reply"        /* " */
  2530. X};
  2531. X
  2532. X/*
  2533. X *  Print a descriptive string about an ICMP header.
  2534. X */
  2535. Xpr_icmph( icp )
  2536. Xstruct icmp *icp;
  2537. X{
  2538. X    switch( icp->icmp_type ) {
  2539. X    case ICMP_ECHOREPLY:
  2540. X        printf("Echo Reply\n");
  2541. X        /* XXX ID + Seq + Data */
  2542. X        break;
  2543. X    case ICMP_UNREACH:
  2544. X        switch( icp->icmp_code ) {
  2545. X        case ICMP_UNREACH_NET:
  2546. X            printf("Destination Net Unreachable\n");
  2547. X            break;
  2548. X        case ICMP_UNREACH_HOST:
  2549. X            printf("Destination Host Unreachable\n");
  2550. X            break;
  2551. X        case ICMP_UNREACH_PROTOCOL:
  2552. X            printf("Destination Protocol Unreachable\n");
  2553. X            break;
  2554. X        case ICMP_UNREACH_PORT:
  2555. X            printf("Destination Port Unreachable\n");
  2556. X            break;
  2557. X        case ICMP_UNREACH_NEEDFRAG:
  2558. X            printf("frag needed and DF set\n");
  2559. X            break;
  2560. X        case ICMP_UNREACH_SRCFAIL:
  2561. X            printf("Source Route Failed\n");
  2562. X            break;
  2563. X        default:
  2564. X            printf("Dest Unreachable, Bad Code: %d\n", icp->icmp_code );
  2565. X            break;
  2566. X        }
  2567. X        /* Print returned IP header information */
  2568. X        pr_retip( icp->icmp_data );
  2569. X        break;
  2570. X    case ICMP_SOURCEQUENCH:
  2571. X        printf("Source Quench\n");
  2572. X        pr_retip( icp->icmp_data );
  2573. X        break;
  2574. X    case ICMP_REDIRECT:
  2575. X        switch( icp->icmp_code ) {
  2576. X        case ICMP_REDIRECT_NET:
  2577. X            printf("Redirect Network");
  2578. X            break;
  2579. X        case ICMP_REDIRECT_HOST:
  2580. X            printf("Redirect Host");
  2581. X            break;
  2582. X        case ICMP_REDIRECT_TOSNET:
  2583. X            printf("Redirect Type of Service and Network");
  2584. X            break;
  2585. X        case ICMP_REDIRECT_TOSHOST:
  2586. X            printf("Redirect Type of Service and Host");
  2587. X            break;
  2588. X        default:
  2589. X            printf("Redirect, Bad Code: %d", icp->icmp_code );
  2590. X            break;
  2591. X        }
  2592. X        printf(" (New addr: 0x%08x)\n", icp->icmp_hun.ih_gwaddr );
  2593. X        pr_retip( icp->icmp_data );
  2594. X        break;
  2595. X    case ICMP_ECHO:
  2596. X        printf("Echo Request\n");
  2597. X        /* XXX ID + Seq + Data */
  2598. X        break;
  2599. X    case ICMP_TIMXCEED:
  2600. X        switch( icp->icmp_code ) {
  2601. X        case ICMP_TIMXCEED_INTRANS:
  2602. X            printf("Time to live exceeded\n");
  2603. X            break;
  2604. X        case ICMP_TIMXCEED_REASS:
  2605. X            printf("Frag reassembly time exceeded\n");
  2606. X            break;
  2607. X        default:
  2608. X            printf("Time exceeded, Bad Code: %d\n", icp->icmp_code );
  2609. X            break;
  2610. X        }
  2611. X        pr_retip( icp->icmp_data );
  2612. X        break;
  2613. X    case ICMP_PARAMPROB:
  2614. X        printf("Parameter problem: pointer = 0x%02x\n",
  2615. X            icp->icmp_hun.ih_pptr );
  2616. X        pr_retip( icp->icmp_data );
  2617. X        break;
  2618. X    case ICMP_TSTAMP:
  2619. X        printf("Timestamp\n");
  2620. X        /* XXX ID + Seq + 3 timestamps */
  2621. X        break;
  2622. X    case ICMP_TSTAMPREPLY:
  2623. X        printf("Timestamp Reply\n");
  2624. X        /* XXX ID + Seq + 3 timestamps */
  2625. X        break;
  2626. X    case ICMP_IREQ:
  2627. X        printf("Information Request\n");
  2628. X        /* XXX ID + Seq */
  2629. X        break;
  2630. X    case ICMP_IREQREPLY:
  2631. X        printf("Information Reply\n");
  2632. X        /* XXX ID + Seq */
  2633. X        break;
  2634. X    case ICMP_MASKREQ:
  2635. X        printf("Address Mask Request\n");
  2636. X        break;
  2637. X    case ICMP_MASKREPLY:
  2638. X        printf("Address Mask Reply\n");
  2639. X        break;
  2640. X    default:
  2641. X        printf("Bad ICMP type: %d\n", icp->icmp_type);
  2642. X    }
  2643. X}
  2644. X
  2645. X/*
  2646. X *  Print an IP header with options.
  2647. X */
  2648. Xpr_iph( ip )
  2649. Xstruct ip *ip;
  2650. X{
  2651. X    int    hlen;
  2652. X    unsigned char *cp;
  2653. X
  2654. X    hlen = ip->ip_hl << 2;
  2655. X    cp = (unsigned char *)ip + 20;    /* point to options */
  2656. X
  2657. X    printf("Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst Data\n");
  2658. X    printf(" %1x  %1x  %02x %04x %04x",
  2659. X        ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id );
  2660. X    printf("   %1x %04x", ((ip->ip_off)&0xe000)>>13, (ip->ip_off)&0x1fff );
  2661. X    printf("  %02x  %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum );
  2662. X    printf(" %08x %08x ",
  2663. X        ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr) );
  2664. X    /* dump and option bytes */
  2665. X    while( hlen-- > 20 ) {
  2666. X        printf( "%02x", *cp++ );
  2667. X    }
  2668. X    printf("\n");
  2669. X}
  2670. X
  2671. X/*
  2672. X *  Return an ascii host address
  2673. X *  as a dotted quad and optionally with a hostname
  2674. X */
  2675. Xchar *
  2676. Xpr_addr( l )
  2677. Xunsigned long l;
  2678. X{
  2679. X    struct    hostent    *hp;
  2680. X    static    char    buf[80];
  2681. X
  2682. X    if( numeric || (hp = gethostbyaddr(&l, 4, AF_INET)) == NULL )
  2683. X        sprintf( buf, "%s", inet_ntoa(l) );
  2684. X    else
  2685. X        sprintf( buf, "%s (%s)", hp->h_name, inet_ntoa(l) );
  2686. X
  2687. X    return( buf );
  2688. X}
  2689. X
  2690. X/*
  2691. X *  Dump some info on a returned (via ICMP) IP packet.
  2692. X */
  2693. Xpr_retip( ip )
  2694. Xstruct ip *ip;
  2695. X{
  2696. X    int    hlen;
  2697. X    unsigned char    *cp;
  2698. X
  2699. X    pr_iph( ip );
  2700. X    hlen = ip->ip_hl << 2;
  2701. X    cp = (unsigned char *)ip + hlen;
  2702. X
  2703. X    if( ip->ip_p == 6 ) {
  2704. X        printf( "TCP: from port %d, to port %d (decimal)\n",
  2705. X            (*cp*256+*(cp+1)), (*(cp+2)*256+*(cp+3)) );
  2706. X    } else if( ip->ip_p == 17 ) {
  2707. X        printf( "UDP: from port %d, to port %d (decimal)\n",
  2708. X            (*cp*256+*(cp+1)), (*(cp+2)*256+*(cp+3)) );
  2709. X    }
  2710. X}
  2711. END_OF_FILE
  2712.   if test 18494 -ne `wc -c <'nocol-3.0/src/support/mping/brl-ping.c'`; then
  2713.     echo shar: \"'nocol-3.0/src/support/mping/brl-ping.c'\" unpacked with wrong size!
  2714.   fi
  2715.   # end of 'nocol-3.0/src/support/mping/brl-ping.c'
  2716. fi
  2717. echo shar: End of archive 14 \(of 26\).
  2718. cp /dev/null ark14isdone
  2719. MISSING=""
  2720. 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
  2721.     if test ! -f ark${I}isdone ; then
  2722.     MISSING="${MISSING} ${I}"
  2723.     fi
  2724. done
  2725. if test "${MISSING}" = "" ; then
  2726.     echo You have unpacked all 26 archives.
  2727.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2728. else
  2729.     echo You still must unpack the following archives:
  2730.     echo "        " ${MISSING}
  2731. fi
  2732. exit 0
  2733. exit 0 # Just in case...
  2734.