5 kx /*
5 kx * Show ICMP packets incoming (and detect bombs)
5 kx * modified from ping
5 kx * 1994/1995 - Laurent Demailly - <dl@hplyot.obspm.fr>
5 kx */
5 kx
5 kx /* note : the original bsd code was *very* buggy !!!
5 kx it should be ok, now */
5 kx
5 kx /*
5 kx * Print out the packet, if it came from us. This logic is necessary
5 kx * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
5 kx * which arrive ('tis only fair). This permits multiple copies of this
5 kx * program to be run without having intermingled output (or statistics!).
5 kx */
5 kx
5 kx #include <string.h>
5 kx #include <stddef.h> /* offsetof */
5 kx #include "defs.h"
5 kx
5 kx #ifndef ANSI_OFFSETOF
5 kx #ifndef offsetof
5 kx # define offsetof(t,m) (int)((&((t *)0L)->m))
5 kx #endif
5 kx #endif
5 kx
5 kx char to_hex(a)
5 kx int a;
5 kx {
5 kx return ((char)(a <= 9 ? a + '0' : (a -10) + 'A'));
5 kx }
5 kx
5 kx int pr_pack(buf, cc, from)
5 kx char *buf; /* ptr to start of IP header */
5 kx int cc; /* total size of received packet */
5 kx struct sockaddr_in *from; /* address of sender */
5 kx {
5 kx int iphdrlen,doipdecoding=1;
5 kx struct ip *ip; /* ptr to IP header */
5 kx register struct icmp *icp; /* ptr to ICMP header */
5 kx struct tcphdr *tp; /* ptr to TCP header */
5 kx time_t t;
5 kx char *pr_type(),*pr_subtype(),*strtime;
5 kx struct hostent *hostent=NULL;
5 kx struct servent *servent=NULL;
5 kx static char prbuf[1024]; /* provide enough room for even the longest hosts*/
5 kx
5 kx /*
5 kx * We have to look at the IP header, to get its length.
5 kx * We also verify that what follows the IP header contains at
5 kx * least an ICMP header (8 bytes minimum).
5 kx */
5 kx ip = (struct ip *) buf;
5 kx iphdrlen = ip->ip_hl << 2; /* convert # 16-bit words to #bytes */
5 kx if (cc < iphdrlen + ICMP_MINLEN) {
5 kx sprintf(prbuf,"packet too short (%d bytes) from %s", cc,
5 kx inet_ntoa(from->sin_addr));
5 kx if (syslogdoutput) {
5 kx syslog(LOG_WARNING,"%s",prbuf);
5 kx } else {
5 kx puts(prbuf);
5 kx fflush(stdout);
5 kx }
5 kx return -1;
5 kx }
5 kx cc -= iphdrlen;
5 kx
5 kx icp = (struct icmp *)(buf + iphdrlen);
5 kx switch (icp->icmp_type)
5 kx {
5 kx case ICMP_ECHO :
5 kx case ICMP_ECHOREPLY :
5 kx doipdecoding=0;
5 kx if (verbose<2) break;
5 kx case ICMP_SOURCEQUENCH :
5 kx case ICMP_TIMXCEED :
5 kx case ICMP_REDIRECT :
5 kx if (!verbose) break;
5 kx default :
5 kx if (!nonamequery) {
5 kx hostent=gethostbyaddr((char*)&(from->sin_addr.s_addr),
5 kx sizeof (struct in_addr),
5 kx AF_INET);
5 kx }
5 kx if (!syslogdoutput) {
5 kx t=time((time_t *)NULL); strtime=(char *)ctime(&t);
5 kx strtime+=4; /* skip day name */
5 kx strtime[15]=0; /* keep MMM DD HH:MM:SS */
5 kx printf("%s ",strtime);
5 kx }
5 kx sprintf(prbuf,hostent?"ICMP_%s%s < %s [%s]":"ICMP_%s%s < %s",
5 kx pr_type(icp->icmp_type),
5 kx icp->icmp_type==ICMP_UNREACH?pr_subtype(icp->icmp_code):"",
5 kx inet_ntoa(from->sin_addr),
5 kx hostent?hostent->h_name:NULL
5 kx );
5 kx if ( doipdecoding &&
5 kx ( cc >= offsetof(struct icmp,icmp_ip.ip_src)+sizeof(icp->icmp_ip.ip_dst) ) )
5 kx {
5 kx if (showsrcip)
5 kx { /* icp->icmp_ip.ip_src.s_addr == local host, show it
5 kx only if requested (might be usefull for host with several
5 kx interfaces */
5 kx if (!nonamequery) {
5 kx hostent=gethostbyaddr((char*)&(icp->icmp_ip.ip_src.s_addr),
5 kx sizeof (struct in_addr),
5 kx AF_INET);
5 kx }
5 kx sprintf(prbuf+strlen(prbuf),hostent?" - %s [%s]":" - %s",
5 kx inet_ntoa(icp->icmp_ip.ip_src),
5 kx hostent?hostent->h_name:NULL);
5 kx }
5 kx if (cc>=offsetof(struct icmp,icmp_ip.ip_dst)+sizeof(icp->icmp_ip.ip_dst))
5 kx {
5 kx if (!nonamequery) {
5 kx hostent=gethostbyaddr((char*)&(icp->icmp_ip.ip_dst.s_addr),
5 kx sizeof (struct in_addr),
5 kx AF_INET);
5 kx }
5 kx sprintf(prbuf+strlen(prbuf),hostent?" > %s [%s]":" > %s",
5 kx inet_ntoa(icp->icmp_ip.ip_dst),
5 kx hostent?hostent->h_name:NULL);
5 kx tp = (struct tcphdr *)((char *)&(icp->icmp_dun)+sizeof(struct ip)) ;
5 kx #if defined(__GLIBC__) && (__GLIBC__ >= 2)
5 kx if (cc>=offsetof(struct icmp,icmp_dun)+sizeof(struct ip)+offsetof(struct tcphdr,seq)+sizeof(tp->seq))
5 kx {
5 kx if (noportquery) {
5 kx sprintf(prbuf+strlen(prbuf)," sp=%d dp=%d seq=0x%8.8x",
5 kx ntohs(tp->source),ntohs(tp->dest),
5 kx ntohl(tp->seq));
5 kx } else {
5 kx if ((servent=getservbyport(ntohs(tp->source),NULL)))
5 kx sprintf(prbuf+strlen(prbuf)," sp=%d [%s]",
5 kx ntohs(tp->source),servent->s_name);
5 kx else
5 kx sprintf(prbuf+strlen(prbuf)," sp=%d",tp->source);
5 kx if ((servent=getservbyport(ntohs(tp->dest),NULL)))
5 kx sprintf(prbuf+strlen(prbuf)," dp=%d [%s] seq=0x%8.8x",
5 kx ntohs(tp->dest),servent->s_name,
5 kx ntohl(tp->seq));
5 kx else
5 kx sprintf(prbuf+strlen(prbuf)," dp=%d seq=0x%8.8x",
5 kx ntohs(tp->dest),ntohl(tp->seq));
5 kx }
5 kx }
5 kx #else
5 kx if (cc>=offsetof(struct icmp,icmp_dun)+sizeof(struct ip)+offsetof(struct tcphdr,th_seq)+sizeof(tp->th_seq))
5 kx {
5 kx if (noportquery) {
5 kx sprintf(prbuf+strlen(prbuf)," sp=%d dp=%d seq=0x%8.8x",
5 kx ntohs(tp->th_sport),ntohs(tp->th_dport),
5 kx ntohl(tp->th_seq));
5 kx } else {
5 kx if ((servent=getservbyport(ntohs(tp->th_sport),NULL)))
5 kx sprintf(prbuf+strlen(prbuf)," sp=%d [%s]",
5 kx ntohs(tp->th_sport),servent->s_name);
5 kx else
5 kx sprintf(prbuf+strlen(prbuf)," sp=%d",tp->th_sport);
5 kx if ((servent=getservbyport(ntohs(tp->th_dport),NULL)))
5 kx sprintf(prbuf+strlen(prbuf)," dp=%d [%s] seq=0x%8.8x",
5 kx ntohs(tp->th_dport),servent->s_name,
5 kx ntohl(tp->th_seq));
5 kx else
5 kx sprintf(prbuf+strlen(prbuf)," dp=%d seq=0x%8.8x",
5 kx ntohs(tp->th_dport),ntohl(tp->th_seq));
5 kx }
5 kx }
5 kx #endif
5 kx }
5 kx }
5 kx sprintf(prbuf+strlen(prbuf)," sz=%d(+%d)",cc,iphdrlen);
5 kx if (syslogdoutput) {
5 kx syslog(LOG_NOTICE,"%s",prbuf);
5 kx } else {
5 kx puts(prbuf);
5 kx fflush(stdout);
5 kx if (verbose>2) { /* hexa dump adapted from a file dump by dl (me!) */
5 kx /* certainly not the smartest around, but it works !*/
5 kx static char h[] = " ";
5 kx static char a[] = " ";
5 kx int i,j,b,n, flagNEof;
5 kx unsigned char *pbuf=(unsigned char *)buf;
5 kx
5 kx n = 0;
5 kx flagNEof = 1;
5 kx while (flagNEof) {
5 kx i = j = 0;
5 kx while (i < 16 && (flagNEof = cc--)) {
5 kx b= (int)(*(pbuf++));
5 kx h[j++] = to_hex(b >> 4);
5 kx h[j++] = to_hex(b & 0x0F);
5 kx j += i % 2 + ((i == 7) << 1);
5 kx a[i++] = (b > 31 && b < 127) ? b : '.';
5 kx }
5 kx if (i==0) break;
5 kx while (i < 16) {
5 kx h[j++] = ' ';
5 kx h[j++] = ' ';
5 kx j += i % 2 + ((i == 7) << 1);
5 kx a[i++] = ' ';
5 kx }
5 kx printf("%04X : %s %s\n", n, h, a);
5 kx n += 16;
5 kx }
5 kx }
5 kx }
5 kx }
5 kx return 0;
5 kx }
5 kx
5 kx /*
5 kx * Convert an ICMP "type" field to a printable string.
5 kx * This is called for ICMP packets that are received that are not
5 kx * ICMP_ECHOREPLY packets.
5 kx */
5 kx
5 kx char *
5 kx pr_type(t)
5 kx register int t;
5 kx {
5 kx static char *ttab[] = {
5 kx "Echo_Reply",
5 kx "1",
5 kx "2",
5 kx "Dest_Unreachable",
5 kx "Source_Quench",
5 kx "Redirect",
5 kx "6",
5 kx "7",
5 kx "Echo",
5 kx "RouterAdvert",
5 kx "Router_Solicit",
5 kx "Time_Exceeded",
5 kx "Parameter_Problem",
5 kx "Timestamp",
5 kx "Timestamp_Reply",
5 kx "Info_Request",
5 kx "Info_Reply",
5 kx "Mask_Request",
5 kx "Mask_Reply"
5 kx };
5 kx
5 kx if (t < 0 || t > 18) {
5 kx static char buf[80];
5 kx sprintf(buf,"OUT_OF_RANGE(%d)",t);
5 kx return(buf);
5 kx }
5 kx return(ttab[t]);
5 kx }
5 kx
5 kx /*
5 kx * Convert an ICMP UNREACH sub-"type" field to a printable string.
5 kx */
5 kx
5 kx char *
5 kx pr_subtype(t)
5 kx register int t;
5 kx {
5 kx static char *ttab[] = {
5 kx "Net",
5 kx "Host",
5 kx "Protocol",
5 kx "Port",
5 kx "Frag",
5 kx "Source",
5 kx "DestNet",
5 kx "DestHost",
5 kx "Isolated",
5 kx "AuthNet",
5 kx "AuthHost",
5 kx "NetSvc",
5 kx "HostSvc",
5 kx "Filtered",
5 kx "PrecdViolation",
5 kx "PrecdCut"
5 kx };
5 kx static char buf[80];
5 kx
5 kx if (t < 0 || t > 15) {
5 kx sprintf(buf,"[OUT_OF_RANGE(%d)]",t);
5 kx } else {
5 kx sprintf(buf,"[%s]",ttab[t]);
5 kx }
5 kx return(buf);
5 kx }
5 kx