print-ip.c revision 39300
117680Spst/* 239300Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 317680Spst * The Regents of the University of California. All rights reserved. 417680Spst * 517680Spst * Redistribution and use in source and binary forms, with or without 617680Spst * modification, are permitted provided that: (1) source code distributions 717680Spst * retain the above copyright notice and this paragraph in its entirety, (2) 817680Spst * distributions including binary code include the above copyright notice and 917680Spst * this paragraph in its entirety in the documentation or other materials 1017680Spst * provided with the distribution, and (3) all advertising materials mentioning 1117680Spst * features or use of this software display the following acknowledgement: 1217680Spst * ``This product includes software developed by the University of California, 1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1417680Spst * the University nor the names of its contributors may be used to endorse 1517680Spst * or promote products derived from this software without specific prior 1617680Spst * written permission. 1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2017680Spst */ 2117680Spst 2217680Spst#ifndef lint 2326183Sfennerstatic const char rcsid[] = 2439300Sfenner "@(#) $Header: print-ip.c,v 1.66 97/05/28 12:51:43 leres Exp $ (LBL)"; 2517680Spst#endif 2617680Spst 2717680Spst#include <sys/param.h> 2817680Spst#include <sys/time.h> 2917680Spst#include <sys/socket.h> 3017680Spst 3117680Spst#include <netinet/in.h> 3217680Spst#include <netinet/in_systm.h> 3317680Spst#include <netinet/ip.h> 3417680Spst#include <netinet/ip_var.h> 3517680Spst#include <netinet/udp.h> 3617680Spst#include <netinet/udp_var.h> 3717680Spst#include <netinet/tcp.h> 3817680Spst#include <netinet/tcpip.h> 3917680Spst 4039300Sfenner#ifdef HAVE_MALLOC_H 4139300Sfenner#include <malloc.h> 4239300Sfenner#endif 4317680Spst#include <stdio.h> 4417680Spst#include <stdlib.h> 4517680Spst#include <string.h> 4617680Spst#include <unistd.h> 4717680Spst 4817680Spst#include "addrtoname.h" 4917680Spst#include "interface.h" 5017680Spst#include "extract.h" /* must come after interface.h */ 5117680Spst 5217680Spst/* Compatibility */ 5317680Spst#ifndef IPPROTO_ND 5417680Spst#define IPPROTO_ND 77 5517680Spst#endif 5617680Spst 5717680Spst#ifndef IN_CLASSD 5817680Spst#define IN_CLASSD(i) (((int32_t)(i) & 0xf0000000) == 0xe0000000) 5917680Spst#endif 6017680Spst 6117680Spst/* (following from ipmulti/mrouted/prune.h) */ 6217680Spst 6317680Spst/* 6417680Spst * The packet format for a traceroute request. 6517680Spst */ 6617680Spststruct tr_query { 6717680Spst u_int tr_src; /* traceroute source */ 6817680Spst u_int tr_dst; /* traceroute destination */ 6917680Spst u_int tr_raddr; /* traceroute response address */ 7026183Sfenner#ifdef WORDS_BIGENDIAN 7117680Spst struct { 7226183Sfenner u_int ttl : 8; /* traceroute response ttl */ 7326183Sfenner u_int qid : 24; /* traceroute query id */ 7417680Spst } q; 7517680Spst#else 7617680Spst struct { 7726183Sfenner u_int qid : 24; /* traceroute query id */ 7826183Sfenner u_int ttl : 8; /* traceroute response ttl */ 7917680Spst } q; 8026183Sfenner#endif 8117680Spst}; 8217680Spst 8317680Spst#define tr_rttl q.ttl 8417680Spst#define tr_qid q.qid 8517680Spst 8617680Spst/* 8717680Spst * Traceroute response format. A traceroute response has a tr_query at the 8817680Spst * beginning, followed by one tr_resp for each hop taken. 8917680Spst */ 9017680Spststruct tr_resp { 9117680Spst u_int tr_qarr; /* query arrival time */ 9217680Spst u_int tr_inaddr; /* incoming interface address */ 9317680Spst u_int tr_outaddr; /* outgoing interface address */ 9417680Spst u_int tr_rmtaddr; /* parent address in source tree */ 9517680Spst u_int tr_vifin; /* input packet count on interface */ 9617680Spst u_int tr_vifout; /* output packet count on interface */ 9717680Spst u_int tr_pktcnt; /* total incoming packets for src-grp */ 9817680Spst u_char tr_rproto; /* routing proto deployed on router */ 9917680Spst u_char tr_fttl; /* ttl required to forward on outvif */ 10017680Spst u_char tr_smask; /* subnet mask for src addr */ 10117680Spst u_char tr_rflags; /* forwarding error codes */ 10217680Spst}; 10317680Spst 10417680Spst/* defs within mtrace */ 10517680Spst#define TR_QUERY 1 10617680Spst#define TR_RESP 2 10717680Spst 10817680Spst/* fields for tr_rflags (forwarding error codes) */ 10917680Spst#define TR_NO_ERR 0 11017680Spst#define TR_WRONG_IF 1 11117680Spst#define TR_PRUNED 2 11217680Spst#define TR_OPRUNED 3 11317680Spst#define TR_SCOPED 4 11417680Spst#define TR_NO_RTE 5 11517680Spst#define TR_NO_FWD 7 11617680Spst#define TR_NO_SPACE 0x81 11717680Spst#define TR_OLD_ROUTER 0x82 11817680Spst 11917680Spst/* fields for tr_rproto (routing protocol) */ 12017680Spst#define TR_PROTO_DVMRP 1 12117680Spst#define TR_PROTO_MOSPF 2 12217680Spst#define TR_PROTO_PIM 3 12317680Spst#define TR_PROTO_CBT 4 12417680Spst 12517680Spststatic void print_mtrace(register const u_char *bp, register u_int len) 12617680Spst{ 12726183Sfenner register struct tr_query *tr = (struct tr_query *)(bp + 8); 12817680Spst 12917680Spst printf("mtrace %d: %s to %s reply-to %s", tr->tr_qid, 13017680Spst ipaddr_string(&tr->tr_src), ipaddr_string(&tr->tr_dst), 13117680Spst ipaddr_string(&tr->tr_raddr)); 13217680Spst if (IN_CLASSD(ntohl(tr->tr_raddr))) 13317680Spst printf(" with-ttl %d", tr->tr_rttl); 13417680Spst} 13517680Spst 13617680Spststatic void print_mresp(register const u_char *bp, register u_int len) 13717680Spst{ 13826183Sfenner register struct tr_query *tr = (struct tr_query *)(bp + 8); 13917680Spst 14017680Spst printf("mresp %d: %s to %s reply-to %s", tr->tr_qid, 14117680Spst ipaddr_string(&tr->tr_src), ipaddr_string(&tr->tr_dst), 14217680Spst ipaddr_string(&tr->tr_raddr)); 14317680Spst if (IN_CLASSD(ntohl(tr->tr_raddr))) 14417680Spst printf(" with-ttl %d", tr->tr_rttl); 14517680Spst} 14617680Spst 14717680Spststatic void 14817680Spstigmp_print(register const u_char *bp, register u_int len, 14917680Spst register const u_char *bp2) 15017680Spst{ 15117680Spst register const struct ip *ip; 15217680Spst 15317680Spst ip = (const struct ip *)bp2; 15417680Spst (void)printf("%s > %s: ", 15517680Spst ipaddr_string(&ip->ip_src), 15617680Spst ipaddr_string(&ip->ip_dst)); 15717680Spst 15817680Spst TCHECK2(bp[0], 8); 15917680Spst switch (bp[0]) { 16017680Spst case 0x11: 16117691Spst (void)printf("igmp %s query", bp[1] ? "v2" : "v1"); 16217691Spst if (bp[1] && bp[1] != 100) 16317691Spst (void)printf(" [intvl %d]", bp[1]); 16417680Spst if (*(int *)&bp[4]) 16517680Spst (void)printf(" [gaddr %s]", ipaddr_string(&bp[4])); 16617680Spst if (len != 8) 16717680Spst (void)printf(" [len %d]", len); 16817680Spst break; 16917680Spst case 0x12: 17017691Spst case 0x16: 17117691Spst (void)printf("igmp %s report %s", 17219954Sfenner (bp[0] & 0x0f) == 6 ? "v2" : "v1", 17317691Spst ipaddr_string(&bp[4])); 17417680Spst if (len != 8) 17517680Spst (void)printf(" [len %d]", len); 17617691Spst if (bp[1]) 17717691Spst (void)printf(" [b1=0x%x]", bp[1]); 17817680Spst break; 17917680Spst case 0x17: 18017680Spst (void)printf("igmp leave %s", ipaddr_string(&bp[4])); 18119954Sfenner if (len != 8) 18219954Sfenner (void)printf(" [len %d]", len); 18319954Sfenner if (bp[1]) 18419954Sfenner (void)printf(" [b1=0x%x]", bp[1]); 18517680Spst break; 18617680Spst case 0x13: 18717680Spst (void)printf("igmp dvmrp"); 18817680Spst if (len < 8) 18917680Spst (void)printf(" [len %d]", len); 19017680Spst else 19117680Spst dvmrp_print(bp, len); 19217680Spst break; 19317680Spst case 0x14: 19417680Spst (void)printf("igmp pim"); 19517680Spst pim_print(bp, len); 19617680Spst break; 19717680Spst case 0x1e: 19817680Spst print_mresp(bp, len); 19917680Spst break; 20017680Spst case 0x1f: 20117680Spst print_mtrace(bp, len); 20217680Spst break; 20317680Spst default: 20417680Spst (void)printf("igmp-%d", bp[0] & 0xf); 20517691Spst if (bp[1]) 20617691Spst (void)printf(" [b1=0x%02x]", bp[1]); 20717680Spst break; 20817680Spst } 20917680Spst 21017680Spst TCHECK2(bp[0], len); 21117680Spst if (vflag) { 21217680Spst /* Check the IGMP checksum */ 21317680Spst u_int32_t sum = 0; 21417680Spst int count; 21526183Sfenner const u_short *sp = (u_short *)bp; 21617680Spst 21717680Spst for (count = len / 2; --count >= 0; ) 21817680Spst sum += *sp++; 21917680Spst if (len & 1) 22026183Sfenner sum += ntohs(*(u_char *) sp << 8); 22117680Spst while (sum >> 16) 22217680Spst sum = (sum & 0xffff) + (sum >> 16); 22317680Spst sum = 0xffff & ~sum; 22417680Spst if (sum != 0) 22517680Spst printf(" bad igmp cksum %x!", EXTRACT_16BITS(&bp[2])); 22617680Spst } 22717680Spst return; 22817680Spsttrunc: 22917680Spst fputs("[|igmp]", stdout); 23017680Spst} 23117680Spst 23217680Spst/* 23317680Spst * print the recorded route in an IP RR, LSRR or SSRR option. 23417680Spst */ 23517680Spststatic void 23617680Spstip_printroute(const char *type, register const u_char *cp, u_int length) 23717680Spst{ 23817680Spst register u_int ptr = cp[2] - 1; 23917680Spst register u_int len; 24017680Spst 24117680Spst printf(" %s{", type); 24217680Spst if ((length + 1) & 3) 24317680Spst printf(" [bad length %d]", length); 24417680Spst if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1) 24517680Spst printf(" [bad ptr %d]", cp[2]); 24617680Spst 24717680Spst type = ""; 24817680Spst for (len = 3; len < length; len += 4) { 24917680Spst if (ptr == len) 25017680Spst type = "#"; 25117680Spst printf("%s%s", type, ipaddr_string(&cp[len])); 25217680Spst type = " "; 25317680Spst } 25417680Spst printf("%s}", ptr == len? "#" : ""); 25517680Spst} 25617680Spst 25717680Spst/* 25817680Spst * print IP options. 25917680Spst */ 26017680Spststatic void 26117680Spstip_optprint(register const u_char *cp, u_int length) 26217680Spst{ 26317680Spst register u_int len; 26417680Spst 26517680Spst for (; length > 0; cp += len, length -= len) { 26617680Spst int tt = *cp; 26717680Spst 26817680Spst len = (tt == IPOPT_NOP || tt == IPOPT_EOL) ? 1 : cp[1]; 26917680Spst if (len <= 0) { 27017680Spst printf("[|ip op len %d]", len); 27117680Spst return; 27217680Spst } 27317680Spst if (&cp[1] >= snapend || cp + len > snapend) { 27417680Spst printf("[|ip]"); 27517680Spst return; 27617680Spst } 27717680Spst switch (tt) { 27817680Spst 27917680Spst case IPOPT_EOL: 28017680Spst printf(" EOL"); 28117680Spst if (length > 1) 28217680Spst printf("-%d", length - 1); 28317680Spst return; 28417680Spst 28517680Spst case IPOPT_NOP: 28617680Spst printf(" NOP"); 28717680Spst break; 28817680Spst 28917680Spst case IPOPT_TS: 29017680Spst printf(" TS{%d}", len); 29117680Spst break; 29217680Spst 29317680Spst case IPOPT_SECURITY: 29417680Spst printf(" SECURITY{%d}", len); 29517680Spst break; 29617680Spst 29717680Spst case IPOPT_RR: 29817680Spst printf(" RR{%d}=", len); 29917680Spst ip_printroute("RR", cp, len); 30017680Spst break; 30117680Spst 30217680Spst case IPOPT_SSRR: 30317680Spst ip_printroute("SSRR", cp, len); 30417680Spst break; 30517680Spst 30617680Spst case IPOPT_LSRR: 30717680Spst ip_printroute("LSRR", cp, len); 30817680Spst break; 30917680Spst 31017691Spst case IPOPT_RA: 31117691Spst printf(" RA{%d}", len); 31217691Spst if (cp[2] != 0 || cp[3] != 0) 31317691Spst printf(" [b23=0x04%x]", cp[2] << 8 | cp[3]); 31417691Spst break; 31517691Spst 31617680Spst default: 31717680Spst printf(" IPOPT-%d{%d}", cp[0], len); 31817680Spst break; 31917680Spst } 32017680Spst } 32117680Spst} 32217680Spst 32317680Spst/* 32417680Spst * compute an IP header checksum. 32517680Spst * don't modifiy the packet. 32617680Spst */ 32717680Spststatic int 32817680Spstin_cksum(const struct ip *ip) 32917680Spst{ 33017680Spst register const u_short *sp = (u_short *)ip; 33117680Spst register u_int32_t sum = 0; 33217680Spst register int count; 33317680Spst 33417680Spst /* 33517680Spst * No need for endian conversions. 33617680Spst */ 33717680Spst for (count = ip->ip_hl * 2; --count >= 0; ) 33817680Spst sum += *sp++; 33917680Spst while (sum > 0xffff) 34017680Spst sum = (sum & 0xffff) + (sum >> 16); 34117680Spst sum = ~sum & 0xffff; 34217680Spst 34317680Spst return (sum); 34417680Spst} 34517680Spst 34617680Spst/* 34717680Spst * print an IP datagram. 34817680Spst */ 34917680Spstvoid 35017680Spstip_print(register const u_char *bp, register u_int length) 35117680Spst{ 35217680Spst register const struct ip *ip; 35317680Spst register u_int hlen, len, off; 35417680Spst register const u_char *cp; 35517680Spst 35617680Spst ip = (const struct ip *)bp; 35717680Spst#ifdef LBL_ALIGN 35817680Spst /* 35917680Spst * If the IP header is not aligned, copy into abuf. 36017680Spst * This will never happen with BPF. It does happen raw packet 36117680Spst * dumps from -r. 36217680Spst */ 36317680Spst if ((long)ip & 3) { 36417680Spst static u_char *abuf = NULL; 36517680Spst static int didwarn = 0; 36617680Spst 36717680Spst if (abuf == NULL) { 36817680Spst abuf = (u_char *)malloc(snaplen); 36917680Spst if (abuf == NULL) 37017680Spst error("ip_print: malloc"); 37117680Spst } 37217680Spst memcpy((char *)abuf, (char *)ip, min(length, snaplen)); 37317680Spst snapend += abuf - (u_char *)ip; 37417680Spst packetp = abuf; 37517680Spst ip = (struct ip *)abuf; 37617680Spst /* We really want libpcap to give us aligned packets */ 37717680Spst if (!didwarn) { 37817680Spst warning("compensating for unaligned libpcap packets"); 37917680Spst ++didwarn; 38017680Spst } 38117680Spst } 38217680Spst#endif 38317680Spst if ((u_char *)(ip + 1) > snapend) { 38417680Spst printf("[|ip]"); 38517680Spst return; 38617680Spst } 38717680Spst if (length < sizeof (struct ip)) { 38817680Spst (void)printf("truncated-ip %d", length); 38917680Spst return; 39017680Spst } 39117680Spst hlen = ip->ip_hl * 4; 39217680Spst 39317680Spst len = ntohs(ip->ip_len); 39417680Spst if (length < len) 39517680Spst (void)printf("truncated-ip - %d bytes missing!", 39617680Spst len - length); 39717680Spst len -= hlen; 39817680Spst 39917680Spst /* 40017680Spst * If this is fragment zero, hand it to the next higher 40117680Spst * level protocol. 40217680Spst */ 40317680Spst off = ntohs(ip->ip_off); 40417680Spst if ((off & 0x1fff) == 0) { 40517680Spst cp = (const u_char *)ip + hlen; 40617680Spst switch (ip->ip_p) { 40717680Spst 40817680Spst case IPPROTO_TCP: 40917680Spst tcp_print(cp, len, (const u_char *)ip); 41017680Spst break; 41117680Spst 41217680Spst case IPPROTO_UDP: 41317680Spst udp_print(cp, len, (const u_char *)ip); 41417680Spst break; 41517680Spst 41617680Spst case IPPROTO_ICMP: 41717680Spst icmp_print(cp, (const u_char *)ip); 41817680Spst break; 41917680Spst 42017680Spst#ifndef IPPROTO_IGRP 42117680Spst#define IPPROTO_IGRP 9 42217680Spst#endif 42317680Spst case IPPROTO_IGRP: 42417680Spst igrp_print(cp, len, (const u_char *)ip); 42517680Spst break; 42617680Spst 42717680Spst case IPPROTO_ND: 42817680Spst (void)printf("%s > %s:", ipaddr_string(&ip->ip_src), 42917680Spst ipaddr_string(&ip->ip_dst)); 43017680Spst (void)printf(" nd %d", len); 43117680Spst break; 43217680Spst 43317680Spst case IPPROTO_EGP: 43417680Spst egp_print(cp, len, (const u_char *)ip); 43517680Spst break; 43617680Spst 43717680Spst#ifndef IPPROTO_OSPF 43817680Spst#define IPPROTO_OSPF 89 43917680Spst#endif 44017680Spst case IPPROTO_OSPF: 44117680Spst ospf_print(cp, len, (const u_char *)ip); 44217680Spst break; 44317680Spst 44417680Spst#ifndef IPPROTO_IGMP 44517680Spst#define IPPROTO_IGMP 2 44617680Spst#endif 44717680Spst case IPPROTO_IGMP: 44817680Spst igmp_print(cp, len, (const u_char *)ip); 44917680Spst break; 45017680Spst 45139300Sfenner case 4: 45239300Sfenner /* DVMRP multicast tunnel (ip-in-ip encapsulation) */ 45317680Spst if (vflag) 45417680Spst (void)printf("%s > %s: ", 45517680Spst ipaddr_string(&ip->ip_src), 45617680Spst ipaddr_string(&ip->ip_dst)); 45717680Spst ip_print(cp, len); 45817680Spst if (! vflag) { 45939300Sfenner printf(" (ipip)"); 46017680Spst return; 46117680Spst } 46217680Spst break; 46317680Spst 46426183Sfenner#ifndef IPPROTO_GRE 46526183Sfenner#define IPPROTO_GRE 47 46626183Sfenner#endif 46726183Sfenner case IPPROTO_GRE: 46826183Sfenner if (vflag) 46926183Sfenner (void)printf("gre %s > %s: ", 47026183Sfenner ipaddr_string(&ip->ip_src), 47126183Sfenner ipaddr_string(&ip->ip_dst)); 47226183Sfenner /* do it */ 47326183Sfenner gre_print(cp, len); 47426183Sfenner if (! vflag) { 47526183Sfenner printf(" (gre encap)"); 47626183Sfenner return; 47726183Sfenner } 47826183Sfenner break; 47926183Sfenner 48017680Spst default: 48117680Spst (void)printf("%s > %s:", ipaddr_string(&ip->ip_src), 48217680Spst ipaddr_string(&ip->ip_dst)); 48317680Spst (void)printf(" ip-proto-%d %d", ip->ip_p, len); 48417680Spst break; 48517680Spst } 48617680Spst } 48717680Spst /* 48817680Spst * for fragmented datagrams, print id:size@offset. On all 48917680Spst * but the last stick a "+". For unfragmented datagrams, note 49017680Spst * the don't fragment flag. 49117680Spst */ 49217680Spst if (off & 0x3fff) { 49317680Spst /* 49417680Spst * if this isn't the first frag, we're missing the 49517680Spst * next level protocol header. print the ip addr. 49617680Spst */ 49717680Spst if (off & 0x1fff) 49817680Spst (void)printf("%s > %s:", ipaddr_string(&ip->ip_src), 49917680Spst ipaddr_string(&ip->ip_dst)); 50017680Spst (void)printf(" (frag %d:%d@%d%s)", ntohs(ip->ip_id), len, 50117680Spst (off & 0x1fff) * 8, 50217680Spst (off & IP_MF)? "+" : ""); 50317680Spst } else if (off & IP_DF) 50417680Spst (void)printf(" (DF)"); 50517680Spst 50617680Spst if (ip->ip_tos) 50717680Spst (void)printf(" [tos 0x%x]", (int)ip->ip_tos); 50817680Spst if (ip->ip_ttl <= 1) 50917680Spst (void)printf(" [ttl %d]", (int)ip->ip_ttl); 51017680Spst 51117680Spst if (vflag) { 51217680Spst int sum; 51317680Spst char *sep = ""; 51417680Spst 51517680Spst printf(" ("); 51617680Spst if (ip->ip_ttl > 1) { 51717680Spst (void)printf("%sttl %d", sep, (int)ip->ip_ttl); 51817680Spst sep = ", "; 51917680Spst } 52017680Spst if ((off & 0x3fff) == 0) { 52117680Spst (void)printf("%sid %d", sep, (int)ntohs(ip->ip_id)); 52217680Spst sep = ", "; 52317680Spst } 52417680Spst if ((u_char *)ip + hlen <= snapend) { 52517680Spst sum = in_cksum(ip); 52617680Spst if (sum != 0) { 52717680Spst (void)printf("%sbad cksum %x!", sep, 52817680Spst ntohs(ip->ip_sum)); 52917680Spst sep = ", "; 53017680Spst } 53117680Spst } 53217680Spst if ((hlen -= sizeof(struct ip)) > 0) { 53317680Spst (void)printf("%soptlen=%d", sep, hlen); 53417680Spst ip_optprint((u_char *)(ip + 1), hlen); 53517680Spst } 53617680Spst printf(")"); 53717680Spst } 53817680Spst} 539