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