home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / ICMPCMD.C < prev    next >
C/C++ Source or Header  |  1994-06-27  |  11KB  |  434 lines

  1. /* ICMP-related user commands
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. /* Mods by PA0GRI */
  5. #include "global.h"
  6. #include "icmp.h"
  7. #include "ip.h"
  8. #include "mbuf.h"
  9. #include "netuser.h"
  10. #include "internet.h"
  11. #include "timer.h"
  12. #include "socket.h"
  13. #include "proc.h"
  14. #include "session.h"
  15. #include "cmdparse.h"
  16. #include "commands.h"
  17.   
  18. static int doicmpec __ARGS((int argc, char *argv[],void *p));
  19. static int doicmpstat __ARGS((int argc, char *argv[],void *p));
  20. static int doicmptr __ARGS((int argc, char *argv[],void *p));
  21. static int doicmpquench __ARGS((int argc, char *argv[],void *p));
  22. static int doicmptimeexceed __ARGS((int argc, char *argv[],void *p));
  23. static void pingtx __ARGS((int s,void *ping1,void *p));
  24. static void pinghdr __ARGS((struct session *sp,struct ping *ping));
  25.   
  26. static struct cmds DFAR Icmpcmds[] = {
  27.     "echo",         doicmpec,       0, 0, NULLCHAR,
  28.     "quench",       doicmpquench, 0, 0, NULLCHAR,
  29.     "status",       doicmpstat,     0, 0, NULLCHAR,
  30.     "timeexceed",   doicmptimeexceed,0,0, NULLCHAR,
  31.     "trace",        doicmptr,       0, 0, NULLCHAR,
  32.     NULLCHAR
  33. };
  34.   
  35. int Icmp_trace;
  36. int Icmp_SQ = 1;
  37. static int Icmp_echo = 1;
  38.   
  39. int
  40. doicmp(argc,argv,p)
  41. int argc;
  42. char *argv[];
  43. void *p;
  44. {
  45.     return subcmd(Icmpcmds,argc,argv,p);
  46. }
  47.   
  48. static int
  49. doicmpstat(argc,argv,p)
  50. int argc;
  51. char *argv[];
  52. void *p;
  53. {
  54.     register int i;
  55.     int lim;
  56.   
  57.     /* Note that the ICMP variables are shown in column order, because
  58.      * that lines up the In and Out variables on the same line
  59.      */
  60.     lim = NUMICMPMIB/2;
  61.     for(i=1;i<=lim;i++){
  62.         tprintf("(%2u)%-20s%10lu",i,Icmp_mib[i].name,
  63.         Icmp_mib[i].value.integer);
  64.         tprintf("     (%2u)%-20s%10lu\n",i+lim,Icmp_mib[i+lim].name,
  65.         Icmp_mib[i+lim].value.integer);
  66.     }
  67.     return 0;
  68. }
  69.   
  70. static int
  71. doicmptr(argc,argv,p)
  72. int argc;
  73. char *argv[];
  74. void *p;
  75. {
  76.     if(argc < 2) {
  77.         tprintf("ICMP Tracing is %d\n",Icmp_trace) ;
  78.         return 0 ;
  79.     }
  80.   
  81.     switch(argv[1][0]) {
  82.         case '0':
  83.         case '1':
  84.         case '2': Icmp_trace=atoi(argv[1]);
  85.             break;
  86.         default:
  87.             tputs("Trace modes are: 0|1|2\n") ;
  88.             return -1 ;
  89.     }
  90.   
  91.     return 0 ;
  92. }
  93.   
  94. static int
  95. doicmpec(argc,argv,p)
  96. int argc;
  97. char *argv[];
  98. void *p;
  99. {
  100.     return setbool(&Icmp_echo,"ICMP echo response accept",argc,argv);
  101. }
  102.   
  103. static int
  104. doicmpquench(argc,argv,p)
  105. int argc;
  106. char *argv[];
  107. void *p;
  108. {
  109.     return setbool(&Icmp_SQ,"Mem Low Source Quench",argc,argv);
  110. }
  111.   
  112. int Icmp_timeexceed = 1;
  113. static int
  114. doicmptimeexceed(argc,argv,p)
  115. int argc;
  116. char *argv[];
  117. void *p;
  118. {
  119.     return setbool(&Icmp_timeexceed,"Ttl time exceed reply",argc,argv);
  120. }
  121.   
  122. /* Send ICMP Echo Request packets */
  123. int
  124. doping(argc,argv,p)
  125. int argc;
  126. char *argv[];
  127. void *p;
  128. {
  129.     struct proc *pinger = NULLPROC; /* Transmit process */
  130.     struct sockaddr_in from;
  131.     struct icmp icmp;
  132.     struct mbuf *bp;
  133.     int32 timestamp,rtt,abserr;
  134.     int s,fromlen;
  135.     struct ping ping;
  136.     struct session *sp;
  137.   
  138.     memset((char *)&ping,0,sizeof(ping));
  139.     if(argc > 3) {
  140.         /* Make sure this is a 'one-shot- ping
  141.          * if not coming from the console - WG7J
  142.          */
  143.         if(Curproc->input != Command->input)
  144.             return 0;
  145.         ping.interval = atol(argv[3]);
  146.     }
  147.   
  148.     if(argc > 2)
  149.         ping.len = atoi(argv[2]);
  150.   
  151.     /* Optionally ping a range of IP addresses */
  152.     if(argc > 4)
  153.         ping.incflag = 1;
  154.   
  155.     if(ping.interval)
  156.         /* Multi shot ping. Allocate a session descriptor */
  157.         if((sp = ping.sp = newsession(argv[1],PING,0)) == NULLSESSION){
  158.             tputs(TooManySessions);
  159.             return 1;
  160.         }
  161.   
  162.     tprintf("Resolving %s... ",argv[1]);
  163.     usflush(Current->output);
  164.   
  165.     if((ping.target = resolve(argv[1])) == 0){
  166.         tprintf(Badhost,argv[1]);
  167.         if(ping.interval) {
  168.             keywait(NULLCHAR,1);
  169.             freesession(sp);
  170.         }
  171.         return 1;
  172.     }
  173.     if((s = socket(AF_INET,SOCK_RAW,ICMP_PTCL)) == -1){
  174.         tputs(Nosock);
  175.         if(ping.interval) {
  176.             keywait(NULLCHAR,1);
  177.             freesession(sp);
  178.         }
  179.         return 1;
  180.     }
  181.   
  182.     tprintf(" pinging [%s]\n",inet_ntoa(ping.target));
  183.     usflush(Current->output);
  184.   
  185.     if(ping.interval == 0) {
  186.         /* One shot ping; let echo_proc hook handle response.
  187.          * An ID of MAXINT16 will not be confused with a legal socket
  188.          * number, which is used to identify repeated pings
  189.          */
  190.         pingem(s,ping.target,0,MAXINT16,ping.len);
  191.         close_s(s);
  192.         return 0;
  193.     }
  194.   
  195.     sp->s = s;
  196.   
  197.     /* start the continuous pinger process */
  198.     pinger = newproc("pingtx",300,pingtx,s,&ping,NULL,0);
  199.   
  200.     /* Now collect the replies */
  201.     pinghdr(sp,&ping);
  202.     for(;;){
  203.         fromlen = sizeof(from);
  204.         if(recv_mbuf(s,&bp,0,(char *)&from,&fromlen) == -1)
  205.             break;
  206.         ntohicmp(&icmp,&bp);
  207.         if(icmp.type != ICMP_ECHO_REPLY || icmp.args.echo.id != s){
  208.             /* Ignore other people's responses */
  209.             free_p(bp);
  210.             continue;
  211.         }
  212.         /* Get stamp */
  213.         if(pullup(&bp,(char *)×tamp,sizeof(timestamp))
  214.         != sizeof(timestamp)){
  215.             /* The timestamp is missing! */
  216.             free_p(bp);     /* Probably not necessary */
  217.             continue;
  218.         }
  219.         free_p(bp);
  220.   
  221.         ping.responses++;
  222.   
  223.         /* Compute round trip time, update smoothed estimates */
  224.         rtt = msclock() - timestamp;
  225.         abserr = (rtt > ping.srtt) ? (rtt-ping.srtt) : (ping.srtt-rtt);
  226.   
  227.         if(ping.responses == 1){
  228.             /* First response, base entire SRTT on it */
  229.             ping.srtt = rtt;
  230.             ping.mdev = 0;
  231.         } else {
  232.             ping.srtt = (7*ping.srtt + rtt + 4) >> 3;
  233.             ping.mdev = (3*ping.mdev + abserr + 2) >> 2;
  234.         }
  235.         if((ping.responses % 20) == 0)
  236.             pinghdr(sp,&ping);
  237.         tprintf("%10lu%10lu%5lu%10lu%10lu%10lu\n",
  238.         ping.sent,ping.responses,
  239.         (ping.responses*100 + ping.sent/2)/ping.sent,
  240.         rtt,ping.srtt,ping.mdev);
  241.     }
  242.     if(pinger != NULLPROC)
  243.         killproc(pinger);
  244.     freesession(sp);
  245.     return 0;
  246. }
  247.   
  248. static void
  249. pinghdr(sp,ping)
  250. struct session *sp;
  251. struct ping *ping;
  252. {
  253.     tprintf("Pinging %s (%s); data %d interval %lu ms:\n",
  254.     sp->name,inet_ntoa(ping->target),ping->len,ping->interval);
  255.     tputs("      sent      rcvd    %       rtt   avg rtt      mdev\n");
  256. }
  257.   
  258. void
  259. echo_proc(source,dest,icmp,bp)
  260. int32 source;
  261. int32 dest;
  262. struct icmp *icmp;
  263. struct mbuf *bp;
  264. {
  265.     int32 timestamp,rtt;
  266.   
  267.     if(Icmp_echo && icmp->args.echo.id == MAXINT16
  268.         && pullup(&bp,(char *)×tamp,sizeof(timestamp))
  269.     == sizeof(timestamp)){
  270.         /* Compute round trip time */
  271.         rtt = msclock() - timestamp;
  272.         tprintf("%s: rtt %lu\n",inet_ntoa(source),rtt);
  273.     }
  274.     free_p(bp);
  275. }
  276. /* Ping transmit process. Runs until killed */
  277. static void
  278. pingtx(s,ping1,p)
  279. int s;          /* Socket to use */
  280. void *ping1;
  281. void *p;
  282. {
  283.     struct ping *ping;
  284.   
  285.     ping = (struct ping *)ping1;
  286.     ping->sent = 0;
  287.     if(ping->incflag){
  288.         for(;;){
  289.             pingem(s,ping->target++,0,MAXINT16,ping->len);
  290.             ping->sent++;
  291.             pause(ping->interval);
  292.         }
  293.     } else {
  294.         for(;;){
  295.             pingem(s,ping->target,(int16)ping->sent++,(int16)s,ping->len);
  296.             pause(ping->interval);
  297.         }
  298.     }
  299. }
  300.   
  301.   
  302. /* Send ICMP Echo Request packet */
  303. int
  304. pingem(s,target,seq,id,len)
  305. int s;          /* Raw socket on which to send ping */
  306. int32 target;   /* Site to be pinged */
  307. int16 seq;      /* ICMP Echo Request sequence number */
  308. int16 id;       /* ICMP Echo Request ID */
  309. int16 len;      /* Length of optional data field */
  310. {
  311.     struct mbuf *data;
  312.     struct mbuf *bp;
  313.     struct icmp icmp;
  314.     struct sockaddr_in to;
  315.     int32 clock;
  316.   
  317.     clock = msclock();
  318.     data = ambufw((int16)(len+sizeof(clock)));
  319.     data->cnt = len+sizeof(clock);
  320.     /* Set optional data field, if any, to all 55's */
  321.     if(len != 0)
  322.         memset(data->data+sizeof(clock),0x55,len);
  323.   
  324.     /* Insert timestamp and build ICMP header */
  325.     memcpy(data->data,(char *)&clock,sizeof(clock));
  326.     icmpOutEchos++;
  327.     icmpOutMsgs++;
  328.     icmp.type = ICMP_ECHO;
  329.     icmp.code = 0;
  330.     icmp.args.echo.seq = seq;
  331.     icmp.args.echo.id = id;
  332.     if((bp = htonicmp(&icmp,data)) == NULLBUF){
  333.         free_p(data);
  334.         return 0;
  335.     }
  336.     to.sin_family = AF_INET;
  337.     to.sin_addr.s_addr = target;
  338.     send_mbuf(s,bp,0,(char *)&to,sizeof(to));
  339.     return 0;
  340. }
  341.   
  342. #if defined GATECMDS
  343. /* Send ICMP Echo Request and wait for response
  344.    For mailbox command 'p <hostid> [length]'
  345.    WA3DSP 12/93
  346.    Modified by WG7J to add a timeout value in seconds, 2/12/94
  347. */
  348. int
  349. dombping(argc,argv,p)
  350. int argc;
  351. char *argv[];
  352. void *p;
  353. {
  354.     struct sockaddr_in from;
  355.     struct icmp icmp;
  356.     struct mbuf *bp;
  357.     struct route *rp;
  358.     int32 timestamp,rtt;
  359.     int s,fromlen,rval;
  360.     int32 target;
  361.     int16 len = 0;
  362.     long timeout;
  363.   
  364.     tprintf("Resolving %s...",argv[1]);
  365.     usflush(Curproc->output);
  366.   
  367.     if((target = resolve(argv[1])) == 0){
  368.         tprintf(Badhost,argv[1]);
  369.         return 0;
  370.     }
  371.     if((rp=rt_lookup(target)) == NULL && !ismyaddr(target)) {
  372.         tprintf("No route to %s\n",argv[1]);
  373.         return 0;
  374.     }
  375.     if((s = socket(AF_INET,SOCK_RAW,ICMP_PTCL)) == -1){
  376.         tputs(Nosock);
  377.         return 1;
  378.     }
  379.   
  380.     tprintf(" pinging [%s]\n",inet_ntoa(target));
  381.     usflush(Curproc->output);
  382.   
  383.     if(argc > 2)
  384.         /* Set a maximum value for the data, so no-one can
  385.          * wedge us by send a large data ping - WG7J
  386.          */
  387.         len = min(atoi(argv[2]),512);
  388.     if(argc > 3)
  389.         timeout = atol(argv[3]) * 1000L;
  390.     else
  391.         timeout = 30000L;
  392.   
  393.     pingem(s,target,0,(int16)s,len);
  394.   
  395.     for(;;){
  396.         fromlen = sizeof(from);
  397.         alarm(timeout);
  398.         rval=recv_mbuf(s,&bp,0,(char *)&from,&fromlen);
  399.         alarm(0L);
  400.         if (rval == -1 || errno == EALARM) {
  401.             tprintf("Timeout - No response\n\n");
  402.             close_s(s);
  403.             return 0;
  404.         }
  405.         ntohicmp(&icmp,&bp);
  406.         if(icmp.type != ICMP_ECHO_REPLY || icmp.args.echo.id != s){
  407.             /* Ignore other people's responses */
  408.             free_p(bp);
  409.             continue;
  410.         }
  411.         /* Get stamp */
  412.         if(pullup(&bp,(char *)×tamp,sizeof(timestamp))
  413.         != sizeof(timestamp)){
  414.             /* The timestamp is missing! */
  415.             free_p(bp);     /* Probably not necessary */
  416.             tprintf("Response Received - missing timestamp\n\n");
  417.             close_s(s);
  418.             return 0;
  419.         } else {
  420.             break;
  421.         }
  422.     }
  423.     close_s(s);
  424.     free_p(bp);
  425.   
  426.     /* Compute round trip time, update smoothed estimates */
  427.     rtt = msclock() - timestamp;
  428.     tprintf("[%s]  rtt %ld ms\n\n",inet_ntoa(target),rtt);
  429.     return 0;
  430. }
  431.   
  432. #endif  /* GATECMDS */
  433.   
  434.