home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / TRACE.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  15KB  |  551 lines

  1. /* Packet tracing - top level and generic routines, including hex/ascii
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Mods by G1EMM
  5.  *
  6.  * Tracing to session taken from WNOS3, by Johan. K. Reinalda, WG7J
  7.  */
  8. #include <ctype.h>
  9. #include <time.h>
  10. #include "global.h"
  11. #ifdef TRACE
  12. #ifdef ANSIPROTO
  13. #include <stdarg.h>
  14. #endif
  15. #include "mbuf.h"
  16. #include "iface.h"
  17. #include "pktdrvr.h"
  18. #include "commands.h"
  19. #include "session.h"
  20. #include "trace.h"
  21. #include "cmdparse.h"
  22.   
  23. #ifdef MONITOR
  24. static void plain_dump __ARGS((FILE *fp, struct mbuf **bpp));
  25. #endif
  26. static void ascii_dump __ARGS((FILE *fp,struct mbuf **bpp));
  27. static void ctohex __ARGS((char *buf,int16 c));
  28. static void fmtline __ARGS((FILE *fp,int16 addr,char *buf,int16 len));
  29. static void hex_dump __ARGS((FILE *fp,struct mbuf **bpp));
  30. static void showtrace __ARGS((struct iface *ifp));
  31. extern struct session *Current;
  32. extern struct session *Command;
  33. #ifdef MULTITASK
  34. extern int Nokeys;
  35. #endif
  36.   
  37. extern int Tracesession;
  38. extern struct session *Trace;
  39.   
  40. #ifdef MONITOR
  41. int Trace_compact_header = 0;
  42. static char *kissname __ARGS((struct iface *ifp,struct mbuf *bp,int type));
  43.   
  44. #include "slip.h"
  45.   
  46. static char *
  47. kissname(ifp, bp, type)
  48. struct iface *ifp;
  49. struct mbuf *bp;
  50. int type;
  51. {
  52.     int port;
  53.   
  54.     if (ifp->type != CL_AX25 || type != CL_KISS)
  55.         return ifp->name;
  56.     port = (bp->data[0] & 0xF0) >> 4;
  57.     if (Slip[ifp->xdev].kiss[port] == NULLIF)
  58.         return ifp->name;
  59.     return Slip[ifp->xdev].kiss[port]->name;
  60. }
  61.   
  62. #endif
  63.   
  64. int
  65. dostrace(argc,argv,p)
  66. int argc;
  67. char *argv[];
  68. void *p;
  69. {
  70.     if(Trace == NULLSESSION)
  71.         argc = 0; /* No session setup, so don't allow turning it on ! */
  72.     return setbool(&Tracesession,"Trace to session",argc,argv);
  73. }
  74.   
  75. /* Redefined here so that programs calling dump in the library won't pull
  76.  * in the rest of the package
  77.  */
  78.   
  79. static char nospace[] = "No space!!\n";
  80.   
  81. struct tracecmd Tracecmd[] = {
  82.     "input",        IF_TRACE_IN,    IF_TRACE_IN,
  83.     "-input",       0,              IF_TRACE_IN,
  84.     "output",       IF_TRACE_OUT,   IF_TRACE_OUT,
  85.     "-output",      0,              IF_TRACE_OUT,
  86.     "broadcast",    0,              IF_TRACE_NOBC,
  87.     "-broadcast",   IF_TRACE_NOBC,  IF_TRACE_NOBC,
  88.     "raw",          IF_TRACE_RAW,   IF_TRACE_RAW,
  89.     "-raw",         0,              IF_TRACE_RAW,
  90.     "ascii",        IF_TRACE_ASCII, IF_TRACE_ASCII|IF_TRACE_HEX,
  91.     "-ascii",       0,              IF_TRACE_ASCII|IF_TRACE_HEX,
  92.     "hex",          IF_TRACE_HEX,   IF_TRACE_ASCII|IF_TRACE_HEX,
  93.     "-hex",         IF_TRACE_ASCII, IF_TRACE_ASCII|IF_TRACE_HEX,
  94. #ifdef MONITOR
  95. /* borrow a meaningless combination for the new trace type */
  96. #define IF_TRACE_PLAIN (IF_TRACE_ASCII|IF_TRACE_HEX)
  97.     "monitor",  IF_TRACE_PLAIN, IF_TRACE_ASCII|IF_TRACE_HEX,
  98.     "-monitor", IF_TRACE_ASCII, IF_TRACE_ASCII|IF_TRACE_HEX,
  99. #endif
  100.     "off",          0,              0xffff,
  101.     NULLCHAR,       0,              0
  102. };
  103.   
  104. void
  105. dump(ifp,direction,type,bp)
  106. register struct iface *ifp;
  107. int direction;
  108. unsigned type;
  109. struct mbuf *bp;
  110. {
  111.     struct mbuf *tbp;
  112.     void (*func) __ARGS((FILE *,struct mbuf **,int));
  113.     int16 size;
  114.     time_t timer;
  115.     char *cp;
  116.   
  117.     if(ifp == NULL || (ifp->trace & direction) == 0)
  118.         return; /* Nothing to trace */
  119.   
  120. #ifndef LINUX
  121.     /* N.B. Linux version can keep the trace at all times. */
  122.     if(Tracesession) {
  123.     /* Disable trace if this is not Trace-sessions,
  124.      * or when shelled out, and not tracing to file */
  125. #ifdef MULTITASK
  126.         if((Current != Trace || Nokeys) && (ifp->trfp == stdout))
  127. #else
  128.             if((Current != Trace) && (ifp->trfp == stdout))
  129. #endif /* MULTITASK */
  130.                 return; /* Nothing to trace */
  131.     } else {
  132.     /* Disable trace on non-command sessions or when shelled out */
  133. #ifdef MULTITASK
  134.         if((Current != Command || Nokeys) && (ifp->trfp == stdout))
  135. #else
  136.             if((Current != Command) && (ifp->trfp == stdout))
  137. #endif
  138.                 return; /* Nothing to trace */
  139.     }
  140. #endif
  141.   
  142.     time(&timer);
  143.     cp = ctime(&timer);
  144.     cp[24] = '\0';
  145.   
  146.     switch(direction){
  147.         case IF_TRACE_IN:
  148.             if((ifp->trace & IF_TRACE_NOBC)
  149.                 && (Tracef[type].addrtest != NULLFP)
  150.                 && (*Tracef[type].addrtest)(ifp,bp) == 0)
  151.                 return;         /* broadcasts are suppressed */
  152. #ifdef MONITOR
  153.             if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
  154.                 fprintf(ifp->trfp, "(%s) ", kissname(ifp, bp, type));
  155.             else
  156. #endif
  157.                 fprintf(ifp->trfp,"\n%s - %s recv:\n",cp,ifp->name);
  158.             break;
  159.         case IF_TRACE_OUT:
  160. #ifdef MONITOR
  161.             if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
  162.                 fprintf(ifp->trfp, "(%s) ", kissname(ifp, bp, type));
  163.             else
  164. #endif
  165.                 fprintf(ifp->trfp,"\n%s - %s sent:\n",cp,ifp->name);
  166.             break;
  167.     }
  168.     if(bp == NULLBUF || (size = len_p(bp)) == 0){
  169.         fprintf(ifp->trfp,"empty packet!!\n");
  170.         return;
  171.     }
  172.   
  173.     if(type < NCLASS)
  174.         func = Tracef[type].tracef;
  175.     else
  176.         func = NULLVFP;
  177.   
  178.     dup_p(&tbp,bp,0,size);
  179.     if(tbp == NULLBUF){
  180.         fprintf(ifp->trfp,nospace);
  181.         return;
  182.     }
  183. #ifdef MONITOR
  184.     Trace_compact_header = ((ifp->trace&IF_TRACE_PLAIN) == IF_TRACE_PLAIN);
  185. #endif
  186.     if(func != NULLVFP)
  187.         (*func)(ifp->trfp,&tbp,1);
  188. #ifdef MONITOR
  189.     if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
  190.         plain_dump(ifp->trfp, &tbp);
  191.     else
  192. #endif
  193.         if(ifp->trace & IF_TRACE_ASCII){
  194.         /* Dump only data portion of packet in ascii */
  195.             ascii_dump(ifp->trfp,&tbp);
  196.         } else if(ifp->trace & IF_TRACE_HEX){
  197.         /* Dump entire packet in hex/ascii */
  198.             free_p(tbp);
  199.             dup_p(&tbp,bp,0,len_p(bp));
  200.             if(tbp != NULLBUF)
  201.                 hex_dump(ifp->trfp,&tbp);
  202.             else
  203.                 fprintf(ifp->trfp,nospace);
  204.         }
  205.     free_p(tbp);
  206. }
  207.   
  208. /* Dump packet bytes, no interpretation */
  209. void
  210. raw_dump(ifp,direction,bp)
  211. struct iface *ifp;
  212. int direction;
  213. struct mbuf *bp;
  214. {
  215.     struct mbuf *tbp;
  216.   
  217.     /* Dump entire packet in hex/ascii */
  218.     fprintf(ifp->trfp,"\n******* raw packet dump (%s %s)\n",
  219.     ((direction & IF_TRACE_OUT) ? "send" : "recv"),ifp->name);
  220.     dup_p(&tbp,bp,0,len_p(bp));
  221.     if(tbp != NULLBUF)
  222.         hex_dump(ifp->trfp,&tbp);
  223.     else
  224.         fprintf(ifp->trfp,nospace);
  225.     fprintf(ifp->trfp,"*******\n");
  226.     free_p(tbp);
  227.     return;
  228. }
  229.   
  230. /* Dump an mbuf in hex */
  231. static void
  232. hex_dump(fp,bpp)
  233. FILE *fp;
  234. register struct mbuf **bpp;
  235. {
  236.     int16 n;
  237.     int16 address;
  238.     char buf[16];
  239.   
  240.     if(bpp == NULLBUFP || *bpp == NULLBUF)
  241.         return;
  242.   
  243.     address = 0;
  244.     while((n = pullup(bpp,buf,sizeof(buf))) != 0){
  245.         fmtline(fp,address,buf,n);
  246.         address += n;
  247.     }
  248. }
  249. /* Dump an mbuf in ascii */
  250. static void
  251. ascii_dump(fp,bpp)
  252. FILE *fp;
  253. register struct mbuf **bpp;
  254. {
  255.     int c;
  256.     register int16 tot;
  257.   
  258.     if(bpp == NULLBUFP || *bpp == NULLBUF)
  259.         return;
  260.   
  261.     tot = 0;
  262.     while((c = PULLCHAR(bpp)) != -1){
  263.         if((tot % 64) == 0)
  264.             fprintf(fp,"%04x  ",tot);
  265.         fprintf(fp,"%c",(isprint(uchar(c)) ? c : '.'));
  266.         if((++tot % 64) == 0)
  267.             fprintf(fp,"\n");
  268.     }
  269.     if((tot % 64) != 0)
  270.         fprintf(fp,"\n");
  271. }
  272. /* Print a buffer up to 16 bytes long in formatted hex with ascii
  273.  * translation, e.g.,
  274.  * 0000: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f  0123456789:;<=>?
  275.  */
  276. static void
  277. fmtline(fp,addr,buf,len)
  278. FILE *fp;
  279. int16 addr;
  280. char *buf;
  281. int16 len;
  282. {
  283.     char line[80];
  284.     register char *aptr,*cptr;
  285.     register char c;
  286.   
  287.     memset(line,' ',sizeof(line));
  288.     ctohex(line,(int16)hibyte(addr));
  289.     ctohex(line+2,(int16)lobyte(addr));
  290.     aptr = &line[6];
  291.     cptr = &line[55];
  292.     while(len-- != 0){
  293.         c = *buf++;
  294.         ctohex(aptr,(int16)uchar(c));
  295.         aptr += 3;
  296.         c &= 0x7f;
  297.         *cptr++ = isprint(uchar(c)) ? c : '.';
  298.     }
  299.     *cptr++ = '\n';
  300.     fprintf(fp,"%.*s",(unsigned)(cptr-line),line);
  301. }
  302. /* Convert byte to two ascii-hex characters */
  303. static void
  304. ctohex(buf,c)
  305. register char *buf;
  306. register int16 c;
  307. {
  308.     static char hex[] = "0123456789abcdef";
  309.   
  310.     *buf++ = hex[hinibble(c)];
  311.     *buf = hex[lonibble(c)];
  312. }
  313.   
  314. #ifdef MONITOR
  315. /* Dump an mbuf in ascii with newlines but no others. */
  316. /* Actually, we do limited VT100 parsing, since that seems popular here */
  317. static void
  318. plain_dump(fp,bpp)
  319. FILE *fp;
  320. register struct mbuf **bpp;
  321. {
  322.     struct mbuf *tmp;
  323.     int c, esc, nl;
  324.   
  325.     if (bpp == NULLBUFP || *bpp == NULLBUF)
  326.         return;
  327.   
  328.     /* check for lots of non-ASCII, non-VT100 and ascii_dump instead? */
  329.     dup_p(&tmp, *bpp, 0, len_p(*bpp));
  330.     nl = 0;
  331.     while ((c = PULLCHAR(&tmp)) != -1)
  332.     {
  333.         /*
  334.          * Printable characters are okay, as are \n \t \r \b \f \a \E
  335.          * Nulls and other control characters are verboten, as are meta
  336.          * controls.  Meta-printables are accepted, since they may be
  337.          * intended as PC graphics (but don't expect them to dump right
  338.          * from here because I don't decode them.  Maybe someday).
  339.          */
  340.         if (c < 8 || (c > 13 && c < 26) || (c > 27 && c < 32) ||
  341.             (c > 126 && c < 174) || c > 223)
  342.             nl = 1;
  343.     }
  344.     if (nl)
  345.     {
  346.         ascii_dump(fp, bpp);
  347.         return;
  348.     }
  349.     esc = 0;
  350.     nl = 1;
  351.     while ((c = PULLCHAR(bpp)) != -1)
  352.     {
  353.         if (c == 0x1B)
  354.             esc = !esc;
  355.         else if (esc == 1 && c == '[')
  356.             esc = 2;
  357.         else if (esc == 1)
  358.             esc = 0;
  359.         else if (esc == 2 && c != ';' && !isdigit(c))
  360.         {
  361.           /* handle some common cases? */
  362.             esc = 0;
  363.         }
  364.         else if (esc == 0 && c == '\r')
  365.         {
  366.             fprintf(fp, "\n");
  367.             nl = 1;
  368.         }
  369.       /* safe programming: not everyone *always* agrees on isprint */
  370.         else if (esc == 0 && c != '\n' && (isprint(c) || c == '\t'))
  371.         {
  372.             fprintf(fp, "%c", c);
  373.             nl = 0;
  374.         }
  375.     }
  376.     if (!nl)
  377.         fprintf(fp, "\n");
  378. }
  379. #endif
  380.   
  381.   
  382. /* Modify or displace interface trace flags */
  383. int
  384. dotrace(argc,argv,p)
  385. int argc;
  386. char *argv[];
  387. void *p;
  388. {
  389.     struct iface *ifp;
  390.     struct tracecmd *tp;
  391.   
  392.     if(argc < 2){
  393.         for(ifp = Ifaces; ifp != NULLIF; ifp = ifp->next)
  394.             showtrace(ifp);
  395.         return 0;
  396.     }
  397.     if((ifp = if_lookup(argv[1])) == NULLIF){
  398.         tprintf(Badinterface,argv[1]);
  399.         return 1;
  400.     }
  401.     if(ifp->port){
  402.         tputs("No trace on this interface - use master.\n");
  403.         return 1;
  404.     }
  405.     if(argc == 2){
  406.         showtrace(ifp);
  407.         return 0;
  408.     }
  409.     /* MODIFY THIS TO HANDLE MULTIPLE OPTIONS */
  410.     if(argc >= 3){
  411.         for(tp = Tracecmd;tp->name != NULLCHAR;tp++)
  412.             if(strncmp(tp->name,argv[2],strlen(argv[2])) == 0)
  413.                 break;
  414.         if(tp->name != NULLCHAR)
  415.             ifp->trace = (ifp->trace & ~tp->mask) | tp->val;
  416.         else
  417.             ifp->trace = htoi(argv[2]);
  418.     }
  419.     /* Always default to stdout unless trace file is given */
  420.     if(ifp->trfp != NULLFILE && ifp->trfp != stdout)
  421.         fclose(ifp->trfp);
  422.     ifp->trfp = stdout;
  423.     if(ifp->trfile != NULLCHAR)
  424.         free(ifp->trfile);
  425.     ifp->trfile = NULLCHAR;
  426.   
  427.     if(argc >= 4){
  428.         if((ifp->trfp = fopen(argv[3],APPEND_TEXT)) == NULLFILE){
  429.             tprintf("Can't write to %s\n",argv[3]);
  430.             ifp->trfp = stdout;
  431.         } else {
  432.             ifp->trfile = strdup(argv[3]);
  433.         }
  434.     }
  435.     showtrace(ifp);
  436.     return 0;
  437. }
  438. /* Display the trace flags for a particular interface */
  439. static void
  440. showtrace(ifp)
  441. register struct iface *ifp;
  442. {
  443.     if(ifp == NULLIF)
  444.         return;
  445.     tprintf("%s:",ifp->name);
  446.     if(ifp->port){
  447.         tputs(" trace on master interface only.\n");
  448.         return;
  449.     }
  450.     if(ifp->trace & (IF_TRACE_IN | IF_TRACE_OUT | IF_TRACE_RAW)){
  451.         if(ifp->trace & IF_TRACE_IN)
  452.             tputs(" input");
  453.         if(ifp->trace & IF_TRACE_OUT)
  454.             tputs(" output");
  455.   
  456.         if(ifp->trace & IF_TRACE_NOBC)
  457.             tputs(" - no broadcasts");
  458.   
  459. #ifdef MONITOR
  460.         if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
  461.             tprintf(" (Monitoring)");
  462.         else
  463. #endif
  464.             if(ifp->trace & IF_TRACE_HEX)
  465.                 tputs(" (Hex/ASCII dump)");
  466.             else if(ifp->trace & IF_TRACE_ASCII)
  467.                 tputs(" (ASCII dump)");
  468.             else
  469.                 tputs(" (headers only)");
  470.   
  471.         if(ifp->trace & IF_TRACE_RAW)
  472.             tputs(" Raw output");
  473.   
  474.         if(ifp->trfile != NULLCHAR)
  475.             tprintf(" trace file: %s",ifp->trfile);
  476.         tputc('\n');
  477.     } else
  478.         tputs(" tracing off\n");
  479. }
  480.   
  481. /* shut down all trace files */
  482. void
  483. shuttrace()
  484. {
  485.     struct iface *ifp;
  486.   
  487.     for(ifp = Ifaces; ifp != NULLIF; ifp = ifp->next){
  488.         if(ifp->trfp != NULLFILE && ifp->trfp != stdout)
  489.             fclose(ifp->trfp);
  490.         if(ifp->trfile != NULLCHAR)
  491.             free(ifp->trfile);
  492.         ifp->trfile = NULLCHAR;
  493.         ifp->trfp = NULLFILE;
  494.     }
  495. }
  496.   
  497. #ifdef PPP
  498. /* Log messages of the form
  499.  * Tue Jan 31 00:00:00 1987 44.64.0.7:1003 open FTP
  500.  */
  501. #if     defined(ANSIPROTO)
  502. void
  503. trace_log(struct iface *ifp,char *fmt, ...)
  504. {
  505.     va_list ap;
  506.     char *cp;
  507.     long t;
  508.   
  509.     if(ifp->trfp == NULLFILE)
  510.         return;
  511.   
  512.     time(&t);
  513.     cp = ctime(&t);
  514.     rip(cp);
  515.     fprintf(ifp->trfp,"%s",cp);
  516.   
  517.     fprintf(ifp->trfp," - ");
  518.     va_start(ap,fmt);
  519.     vfprintf(ifp->trfp,fmt,ap);
  520.     va_end(ap);
  521.     fprintf(ifp->trfp,"\n");
  522. }
  523. #else
  524. /*VARARGS2*/
  525. void
  526. trace_log(ifp,fmt,arg1,arg2,arg3,arg4,arg5)
  527. struct iface *ifp;
  528. char *fmt;
  529. int arg1,arg2,arg3,arg4,arg5;
  530. {
  531.     char *cp;
  532.     long t;
  533.   
  534.     if(ifp->trfp == NULLFILE)
  535.         return;
  536.   
  537.     time(&t);
  538.     cp = ctime(&t);
  539.     rip(cp);
  540.     fprintf(ifp->trfp,"%s",cp);
  541.   
  542.     fprintf(ifp->trfp," - ");
  543.     fprintf(ifp->trfp,fmt,arg1,arg2,arg3,arg4,arg5);
  544.     fprintf(ifp->trfp,"\n");
  545. }
  546. #endif
  547. #endif /* PPP */
  548.   
  549. #endif /*TRACE*/
  550.   
  551.