diff options
author | Rodney W. Grimes <rgrimes@FreeBSD.org> | 1993-06-12 14:49:13 +0000 |
---|---|---|
committer | Rodney W. Grimes <rgrimes@FreeBSD.org> | 1993-06-12 14:49:13 +0000 |
commit | 9002c02abc587664acb357c6879d8ca08664dd0b (patch) | |
tree | 515fc124b039c993c5762b23524842c4aebcaa06 /usr.sbin/tcpdump | |
download | src-9002c02abc587664acb357c6879d8ca08664dd0b.tar.gz src-9002c02abc587664acb357c6879d8ca08664dd0b.zip |
Initial import, 0.1 + pk 0.2.4-B1
Notes
Notes:
svn path=/cvs2svn/branches/tcpdump/; revision=2
Diffstat (limited to 'usr.sbin/tcpdump')
62 files changed, 17461 insertions, 0 deletions
diff --git a/usr.sbin/tcpdump/Makefile b/usr.sbin/tcpdump/Makefile new file mode 100644 index 000000000000..0a1f2533744b --- /dev/null +++ b/usr.sbin/tcpdump/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 0.1 (RGrimes) 4/4/93 + +SUBDIR= tcpdump tcpslice + +.include <bsd.subdir.mk> diff --git a/usr.sbin/tcpdump/Makefile.inc b/usr.sbin/tcpdump/Makefile.inc new file mode 100644 index 000000000000..948999506171 --- /dev/null +++ b/usr.sbin/tcpdump/Makefile.inc @@ -0,0 +1,3 @@ +# @(#)Makefile.inc 5.1 (Berkeley) 5/11/90 + +BINDIR?= /usr/local/bin diff --git a/usr.sbin/tcpdump/tcpdump/Makefile b/usr.sbin/tcpdump/tcpdump/Makefile new file mode 100644 index 000000000000..fee95540b94b --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/Makefile @@ -0,0 +1,24 @@ +# @(#)Makefile 0.1 (RWGrimes) 3/24/93 + +PROG= tcpdump +CFLAGS+=-DCSLIP -I. +MAN1= tcpdump.0 +SRCS= version.c addrtoname.c bpf_dump.c bpf_filter.c bpf_image.c etherent.c \ + gencode.c inet.c md.c nametoaddr.c optimize.c os.c pcap.c \ + print-arp.c print-atalk.c print-bootp.c print-domain.c \ + print-egp.c print-ether.c print-fddi.c print-icmp.c print-ip.c \ + print-nfs.c print-ntp.c print-null.c print-ospf.c print-ppp.c \ + print-rip.c print-sl.c print-snmp.c print-sunrpc.c print-tcp.c \ + print-tftp.c print-udp.c savefile.c tcpdump.c tcpgram.c \ + tcplex.c util.c +.PATH: /sys/net +CLEANFILES+= tcpgram.c tcplex.c y.tab.h y.tab.c version.c version.h + +version.c version.h: VERSION + rm -f version.c ; \ + sed 's/.*/char version[] = "&";/' $(.CURDIR)/VERSION > version.c + set `sed 's/\([0-9]*\)\.\([0-9]*\).*/\1 \2/' $(.CURDIR)/VERSION` ; \ + { echo '#define VERSION_MAJOR' $$1 ; \ + echo '#define VERSION_MINOR' $$2 ; } > version.h + +.include <bsd.prog.mk> diff --git a/usr.sbin/tcpdump/tcpdump/VERSION b/usr.sbin/tcpdump/tcpdump/VERSION new file mode 100644 index 000000000000..c043eea7767e --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/VERSION @@ -0,0 +1 @@ +2.2.1 diff --git a/usr.sbin/tcpdump/tcpdump/addrtoname.c b/usr.sbin/tcpdump/tcpdump/addrtoname.c new file mode 100644 index 000000000000..5c7086518a56 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/addrtoname.c @@ -0,0 +1,478 @@ +/* + * Copyright (c) 1988, 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Internet, ethernet, port, and protocol string to address + * and address to string conversion routines + */ +#ifndef lint +static char rcsid[] = + "@(#) $Header: addrtoname.c,v 1.14 92/05/25 14:29:07 mccanne Exp $ (LBL)"; +#endif + +#include <stdio.h> +#include <strings.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <arpa/inet.h> +#include <signal.h> + +#include "interface.h" +#include "addrtoname.h" +#include "nametoaddr.h" +#include "etherent.h" + +/* + * hash tables for whatever-to-name translations + */ + +#define HASHNAMESIZE 4096 + +struct hnamemem { + u_long addr; + char *name; + struct hnamemem *nxt; +}; + +struct hnamemem hnametable[HASHNAMESIZE]; +struct hnamemem tporttable[HASHNAMESIZE]; +struct hnamemem uporttable[HASHNAMESIZE]; +struct hnamemem eprototable[HASHNAMESIZE]; + +struct enamemem { + u_short e_addr0; + u_short e_addr1; + u_short e_addr2; + char *e_name; + struct enamemem *e_nxt; +}; + +struct enamemem enametable[HASHNAMESIZE]; + + +/* + * A faster replacement for inet_ntoa(). + */ +char * +intoa(addr) + u_long addr; +{ + register char *cp; + register u_int byte; + register int n; + static char buf[sizeof(".xxx.xxx.xxx.xxx")]; + + NTOHL(addr); + cp = &buf[sizeof buf]; + *--cp = '\0'; + + n = 4; + do { + byte = addr & 0xff; + *--cp = byte % 10 + '0'; + byte /= 10; + if (byte > 0) { + *--cp = byte % 10 + '0'; + byte /= 10; + if (byte > 0) + *--cp = byte + '0'; + } + *--cp = '.'; + addr >>= 8; + } while (--n > 0); + + return cp + 1; +} + +static u_long f_netmask; +static u_long f_localnet; +static u_long netmask; + +/* + * "getname" is written in this atrocious way to make sure we don't + * wait forever while trying to get hostnames from yp. + */ +#include <setjmp.h> + +jmp_buf getname_env; + +static void +nohostname() +{ + longjmp(getname_env, 1); +} + +/* + * Return a name for the IP address pointed to by ap. This address + * is assumed to be in network byte order. + */ +char * +getname(ap) + u_char *ap; +{ + register struct hnamemem *p; + register struct hostent *hp; + register char *cp; + u_long addr; + +#ifndef TCPDUMP_ALIGN + addr = *(u_long *)ap; +#else + /* + * Deal with alignment. + */ + switch ((int)ap & 3) { + + case 0: + addr = *(u_long *)ap; + break; + + case 2: +#if BYTE_ORDER == LITTLE_ENDIAN + addr = ((u_long)*(u_short *)(ap + 2) << 16) | + (u_long)*(u_short *)ap; +#else + addr = ((u_long)*(u_short *)ap << 16) | + (u_long)*(u_short *)(ap + 2); +#endif + break; + + default: +#if BYTE_ORDER == LITTLE_ENDIAN + addr = ((u_long)ap[0] << 24) | + ((u_long)ap[1] << 16) | + ((u_long)ap[2] << 8) | + (u_long)ap[3]; +#else + addr = ((u_long)ap[3] << 24) | + ((u_long)ap[2] << 16) | + ((u_long)ap[1] << 8) | + (u_long)ap[0]; +#endif + break; + } +#endif + p = &hnametable[addr & (HASHNAMESIZE-1)]; + for (; p->nxt; p = p->nxt) { + if (p->addr == addr) + return (p->name); + } + p->addr = addr; + p->nxt = (struct hnamemem *)calloc(1, sizeof (*p)); + + /* + * Only print names when: + * (1) -n was not given. + * (2) Address is foreign and -f was given. If -f was not + * present, f_netmask and f_local are 0 and the second + * test will succeed. + * (3) The host portion is not 0 (i.e., a network address). + * (4) The host portion is not broadcast. + */ + if (!nflag && (addr & f_netmask) == f_localnet + && (addr &~ netmask) != 0 && (addr | netmask) != 0xffffffff) { + if (!setjmp(getname_env)) { + (void)signal(SIGALRM, nohostname); + (void)alarm(20); + hp = gethostbyaddr((char *)&addr, 4, AF_INET); + (void)alarm(0); + if (hp) { + char *index(); + char *dotp; + u_int len = strlen(hp->h_name) + 1; + p->name = (char *)malloc(len); + (void)strcpy(p->name, hp->h_name); + if (Nflag) { + /* Remove domain qualifications */ + dotp = index(p->name, '.'); + if (dotp) + *dotp = 0; + } + return (p->name); + } + } + } + cp = intoa(addr); + p->name = (char *)malloc((unsigned)(strlen(cp) + 1)); + (void)strcpy(p->name, cp); + return (p->name); +} + +static char hex[] = "0123456789abcdef"; + + +/* Find the hash node that corresponds the ether address 'ep'. */ + +static inline struct enamemem * +lookup_emem(ep) + u_char *ep; +{ + register u_int i, j, k; + struct enamemem *tp; + + k = (ep[0] << 8) | ep[1]; + j = (ep[2] << 8) | ep[3]; + i = (ep[4] << 8) | ep[5]; + + tp = &enametable[(i ^ j) & (HASHNAMESIZE-1)]; + while (tp->e_nxt) + if (tp->e_addr0 == i && + tp->e_addr1 == j && + tp->e_addr2 == k) + return tp; + else + tp = tp->e_nxt; + tp->e_addr0 = i; + tp->e_addr1 = j; + tp->e_addr2 = k; + tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp)); + + return tp; +} + +char * +etheraddr_string(ep) + register u_char *ep; +{ + register u_int i, j; + register char *cp; + register struct enamemem *tp; + + tp = lookup_emem(ep); + if (tp->e_name) + return tp->e_name; + +#ifdef ETHER_SERVICE + if (!nflag) { + cp = ETHER_ntohost(ep); + if (cp) { + tp->e_name = cp; + return cp; + } + } +#endif + tp->e_name = cp = (char *)malloc(sizeof("00:00:00:00:00:00")); + + if (j = *ep >> 4) + *cp++ = hex[j]; + *cp++ = hex[*ep++ & 0xf]; + for (i = 5; (int)--i >= 0;) { + *cp++ = ':'; + if (j = *ep >> 4) + *cp++ = hex[j]; + *cp++ = hex[*ep++ & 0xf]; + } + *cp = '\0'; + return (tp->e_name); +} + +char * +etherproto_string(port) + u_short port; +{ + register char *cp; + register struct hnamemem *tp; + register u_long i = port; + + for (tp = &eprototable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) + if (tp->addr == i) + return (tp->name); + + tp->name = cp = (char *)malloc(sizeof("0000")); + tp->addr = i; + tp->nxt = (struct hnamemem *)calloc(1, sizeof (*tp)); + + NTOHS(port); + *cp++ = hex[port >> 12 & 0xf]; + *cp++ = hex[port >> 8 & 0xf]; + *cp++ = hex[port >> 4 & 0xf]; + *cp++ = hex[port & 0xf]; + *cp++ = '\0'; + return (tp->name); +} + +char * +tcpport_string(port) + u_short port; +{ + register struct hnamemem *tp; + register int i = port; + + for (tp = &tporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) + if (tp->addr == i) + return (tp->name); + + tp->name = (char *)malloc(sizeof("00000")); + tp->addr = i; + tp->nxt = (struct hnamemem *)calloc(1, sizeof (*tp)); + + (void)sprintf(tp->name, "%d", i); + return (tp->name); +} + +char * +udpport_string(port) + register u_short port; +{ + register struct hnamemem *tp; + register int i = port; + + for (tp = &uporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) + if (tp->addr == i) + return (tp->name); + + tp->name = (char *)malloc(sizeof("00000")); + tp->addr = i; + tp->nxt = (struct hnamemem *)calloc(1, sizeof(*tp)); + + (void)sprintf(tp->name, "%d", i); + + return (tp->name); +} + +static void +init_servarray() +{ + struct servent *sv; + register struct hnamemem *table; + register int i; + + while (sv = getservent()) { + NTOHS(sv->s_port); + i = sv->s_port & (HASHNAMESIZE-1); + if (strcmp(sv->s_proto, "tcp") == 0) + table = &tporttable[i]; + else if (strcmp(sv->s_proto, "udp") == 0) + table = &uporttable[i]; + else + continue; + + while (table->name) + table = table->nxt; + if (nflag) { + char buf[32]; + + (void)sprintf(buf, "%d", sv->s_port); + table->name = (char *)malloc((unsigned)strlen(buf)+1); + (void)strcpy(table->name, buf); + } else { + table->name = + (char *)malloc((unsigned)strlen(sv->s_name)+1); + (void)strcpy(table->name, sv->s_name); + } + table->addr = sv->s_port; + table->nxt = (struct hnamemem *)calloc(1, sizeof(*table)); + } + endservent(); +} + +#include "etherproto.h" + +/* Static data base of ether protocol types. */ +struct eproto eproto_db[] = { + { "pup", ETHERTYPE_PUP }, + { "xns", ETHERTYPE_NS }, + { "ip", ETHERTYPE_IP }, + { "arp", ETHERTYPE_ARP }, + { "rarp", ETHERTYPE_REVARP }, + { "sprite", ETHERTYPE_SPRITE }, + { "mopdl", ETHERTYPE_MOPDL }, + { "moprc", ETHERTYPE_MOPRC }, + { "decnet", ETHERTYPE_DN }, + { "lat", ETHERTYPE_LAT }, + { "lanbridge", ETHERTYPE_LANBRIDGE }, + { "vexp", ETHERTYPE_VEXP }, + { "vprod", ETHERTYPE_VPROD }, + { "atalk", ETHERTYPE_ATALK }, + { "atalkarp", ETHERTYPE_AARP }, + { "loopback", ETHERTYPE_LOOPBACK }, + { (char *)0, 0 } +}; + +static void +init_eprotoarray() +{ + register int i; + register struct hnamemem *table; + + for (i = 0; eproto_db[i].s; i++) { + int j = ntohs(eproto_db[i].p) & (HASHNAMESIZE-1); + table = &eprototable[j]; + while (table->name) + table = table->nxt; + table->name = eproto_db[i].s; + table->addr = ntohs(eproto_db[i].p); + table->nxt = (struct hnamemem *)calloc(1, sizeof(*table)); + } +} + +static void +init_etherarray() +{ +#ifndef ETHER_SERVICE + FILE *fp; + struct etherent *ep; + struct enamemem *tp; + + fp = fopen(ETHERS_FILE, "r"); + if (fp == 0) + /* No data base; will have to settle for + numeric addresses. */ + return; + + while (ep = next_etherent(fp)) { + tp = lookup_emem(ep->addr); + tp->e_name = (char *)malloc((unsigned)strlen(ep->name)+1); + strcpy(tp->e_name, ep->name); + } +#endif +} + +/* + * Initialize the address to name translation machinery. We map all + * non-local IP addresses to numeric addresses if fflag is true (i.e., + * to prevent blocking on the nameserver). localnet is the IP address + * of the local network. mask is its subnet mask. + */ +void +init_addrtoname(fflag, localnet, mask) + int fflag; + u_long localnet; + u_long mask; +{ + netmask = mask; + if (fflag) { + f_localnet = localnet; + f_netmask = mask; + } + if (nflag) + /* + * Simplest way to suppress names. + */ + return; + + init_etherarray(); + init_servarray(); + init_eprotoarray(); +} diff --git a/usr.sbin/tcpdump/tcpdump/addrtoname.h b/usr.sbin/tcpdump/tcpdump/addrtoname.h new file mode 100644 index 000000000000..6dc6979895c9 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/addrtoname.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1988, 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#) $Header: addrtoname.h,v 1.5 92/03/17 13:41:37 mccanne Exp $ (LBL) + */ + +/* Name to address translation routines. */ + +extern char *etheraddr_string(); +extern char *etherproto_string(); +extern char *tcpport_string(); +extern char *udpport_string(); +extern char *getname(); +extern char *intoa(); + +extern void init_addrtoname(); +extern void no_foreign_names(); + +#define ipaddr_string(p) getname((u_char *)(p)) diff --git a/usr.sbin/tcpdump/tcpdump/appletalk.h b/usr.sbin/tcpdump/tcpdump/appletalk.h new file mode 100644 index 000000000000..90c8c806330f --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/appletalk.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * AppleTalk protocol formats (courtesy Bill Croft of Stanford/SUMEX). + * + * @(#) $Header: appletalk.h,v 1.6 90/10/03 22:14:26 leres Exp $ (LBL) + */ + +/* Datagram Delivery Protocol */ + +struct atDDP { + u_short length; + u_short checksum; + u_short dstNet; + u_short srcNet; + u_char dstNode; + u_char srcNode; + u_char dstSkt; + u_char srcSkt; + u_char type; +}; + +struct atShortDDP { + u_short length; + u_char dstSkt; + u_char srcSkt; + u_char type; +}; + +#define ddpMaxWKS 0x7F +#define ddpMaxData 586 +#define ddpLengthMask 0x3FF +#define ddpHopShift 10 +#define ddpSize 13 /* size of DDP header (avoid struct padding) */ +#define ddpSSize 5 +#define ddpWKS 128 /* boundary of DDP well known sockets */ +#define ddpRTMP 1 /* RTMP type */ +#define ddpRTMPrequest 5 /* RTMP request type */ +#define ddpNBP 2 /* NBP type */ +#define ddpATP 3 /* ATP type */ +#define ddpECHO 4 /* ECHO type */ +#define ddpIP 22 /* IP type */ +#define ddpARP 23 /* ARP type */ +#define ddpKLAP 0x4b /* Kinetics KLAP type */ + + +/* AppleTalk Transaction Protocol */ + +struct atATP { + u_char control; + u_char bitmap; + u_short transID; + long userData; +}; + +#define atpReqCode 0x40 +#define atpRspCode 0x80 +#define atpRelCode 0xC0 +#define atpXO 0x20 +#define atpEOM 0x10 +#define atpSTS 0x08 +#define atpFlagMask 0x3F +#define atpControlMask 0xF8 +#define atpMaxNum 8 +#define atpMaxData 578 + + +/* AppleTalk Echo Protocol */ + +struct atEcho { + u_char echoFunction; + u_char *echoData; +}; + +#define echoSkt 4 /* the echoer socket */ +#define echoSize 1 /* size of echo header */ +#define echoRequest 1 /* echo request */ +#define echoReply 2 /* echo request */ + + +/* Name Binding Protocol */ + +struct atNBP { + u_char control; + u_char id; +}; + +struct atNBPtuple { + u_short net; + u_char node; + u_char skt; + u_char enumerator; +}; + +#define nbpBrRq 0x10 +#define nbpLkUp 0x20 +#define nbpLkUpReply 0x30 + +#define nbpNIS 2 +#define nbpTupleMax 15 + +#define nbpHeaderSize 2 +#define nbpTupleSize 5; + + +/* Routing Table Maint. Protocol */ + +#define rtmpSkt 1 /* number of RTMP socket */ +#define rtmpSize 4 /* minimum size */ +#define rtmpTupleSize 3 + + +/* Zone Information Protocol */ + +struct zipHeader { + u_char command; + u_char netcount; +}; + +#define zipHeaderSize 2 +#define zipQuery 1 +#define zipReply 2 +#define zipTakedown 3 +#define zipBringup 4 +#define ddpZIP 6 +#define zipSkt 6 +#define GetMyZone 7 +#define GetZoneList 8 + +/* + * UDP port range used for ddp-in-udp encapsulation is 16512-16639 + * for client sockets (128-255) and 200-327 for server sockets + * (0-127). We also try to recognize the pre-April 88 server + * socket range of 768-895. + */ +#define atalk_port(p) \ + (((unsigned)((p) - 16512) < 128) || \ + ((unsigned)((p) - 200) < 128) || \ + ((unsigned)((p) - 768) < 128)) diff --git a/usr.sbin/tcpdump/tcpdump/bootp.h b/usr.sbin/tcpdump/tcpdump/bootp.h new file mode 100644 index 000000000000..ab474cf4d638 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/bootp.h @@ -0,0 +1,103 @@ +/* @(#) $Header: bootp.h,v 1.2 90/05/29 21:29:16 leres Exp $ (LBL) */ +/* + * Bootstrap Protocol (BOOTP). RFC951 and RFC1048. + * + * This file specifies the "implementation-independent" BOOTP protocol + * information which is common to both client and server. + * + * Copyright 1988 by Carnegie Mellon. + * + * Permission to use, copy, modify, and distribute this program for any + * purpose and without fee is hereby granted, provided that this copyright + * and permission notice appear on all copies and supporting documentation, + * the name of Carnegie Mellon not be used in advertising or publicity + * pertaining to distribution of the program without specific prior + * permission, and notice be given in supporting documentation that copying + * and distribution is by permission of Carnegie Mellon and Stanford + * University. Carnegie Mellon makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + + +struct bootp { + unsigned char bp_op; /* packet opcode type */ + unsigned char bp_htype; /* hardware addr type */ + unsigned char bp_hlen; /* hardware addr length */ + unsigned char bp_hops; /* gateway hops */ + unsigned long bp_xid; /* transaction ID */ + unsigned short bp_secs; /* seconds since boot began */ + unsigned short bp_unused; + struct in_addr bp_ciaddr; /* client IP address */ + struct in_addr bp_yiaddr; /* 'your' IP address */ + struct in_addr bp_siaddr; /* server IP address */ + struct in_addr bp_giaddr; /* gateway IP address */ + unsigned char bp_chaddr[16]; /* client hardware address */ + unsigned char bp_sname[64]; /* server host name */ + unsigned char bp_file[128]; /* boot file name */ + unsigned char bp_vend[64]; /* vendor-specific area */ +}; + +/* + * UDP port numbers, server and client. + */ +#define IPPORT_BOOTPS 67 +#define IPPORT_BOOTPC 68 + +#define BOOTREPLY 2 +#define BOOTREQUEST 1 + + +/* + * Vendor magic cookie (v_magic) for CMU + */ +#define VM_CMU "CMU" + +/* + * Vendor magic cookie (v_magic) for RFC1048 + */ +#define VM_RFC1048 { 99, 130, 83, 99 } + + + +/* + * RFC1048 tag values used to specify what information is being supplied in + * the vendor field of the packet. + */ + +#define TAG_PAD ((unsigned char) 0) +#define TAG_SUBNET_MASK ((unsigned char) 1) +#define TAG_TIME_OFFSET ((unsigned char) 2) +#define TAG_GATEWAY ((unsigned char) 3) +#define TAG_TIME_SERVER ((unsigned char) 4) +#define TAG_NAME_SERVER ((unsigned char) 5) +#define TAG_DOMAIN_SERVER ((unsigned char) 6) +#define TAG_LOG_SERVER ((unsigned char) 7) +#define TAG_COOKIE_SERVER ((unsigned char) 8) +#define TAG_LPR_SERVER ((unsigned char) 9) +#define TAG_IMPRESS_SERVER ((unsigned char) 10) +#define TAG_RLP_SERVER ((unsigned char) 11) +#define TAG_HOSTNAME ((unsigned char) 12) +#define TAG_BOOTSIZE ((unsigned char) 13) +#define TAG_END ((unsigned char) 255) + + + +/* + * "vendor" data permitted for CMU bootp clients. + */ + +struct cmu_vend { + unsigned char v_magic[4]; /* magic number */ + unsigned long v_flags; /* flags/opcodes, etc. */ + struct in_addr v_smask; /* Subnet mask */ + struct in_addr v_dgate; /* Default gateway */ + struct in_addr v_dns1, v_dns2; /* Domain name servers */ + struct in_addr v_ins1, v_ins2; /* IEN-116 name servers */ + struct in_addr v_ts1, v_ts2; /* Time servers */ + unsigned char v_unused[25]; /* currently unused */ +}; + + +/* v_flags values */ +#define VF_SMASK 1 /* Subnet mask field contains valid data */ diff --git a/usr.sbin/tcpdump/tcpdump/bpf_dump.c b/usr.sbin/tcpdump/tcpdump/bpf_dump.c new file mode 100644 index 000000000000..fab9596d2f44 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/bpf_dump.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#ifndef lint +static char rcsid[] = + "@(#) $Header: bpf_dump.c,v 1.1 92/01/29 13:25:30 mccanne Exp $ (LBL)"; +#endif + +#include <sys/types.h> +#include <sys/time.h> +#include <net/bpf.h> + +void +bpf_dump(p, option) + struct bpf_program *p; + int option; +{ + struct bpf_insn *insn; + int i; + int n = p->bf_len; + + insn = p->bf_insns; + if (option > 2) { + printf("%d\n", n); + for (i = 0; i < n; ++insn, ++i) { + printf("%lu %lu %lu %lu\n", insn->code, + insn->jt, insn->jf, insn->k); + } + return ; + } + if (option > 1) { + for (i = 0; i < n; ++insn, ++i) + printf("{ 0x%x, %d, %d, 0x%08x },\n", + insn->code, insn->jt, insn->jf, insn->k); + return; + } + for (i = 0; i < n; ++insn, ++i) { +#ifdef BDEBUG + extern int bids[]; + printf(bids[i] > 0 ? "[%02d]" : " -- ", bids[i] - 1); +#endif + puts(bpf_image(insn, i)); + } +} diff --git a/usr.sbin/tcpdump/tcpdump/bpf_image.c b/usr.sbin/tcpdump/tcpdump/bpf_image.c new file mode 100644 index 000000000000..d36eab252f7c --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/bpf_image.c @@ -0,0 +1,282 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#) $Header: bpf_image.c,v 1.10 92/01/26 21:01:16 mccanne Exp $ (LBL)"; +#endif + +#include <stdio.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/time.h> +#include <net/bpf.h> + +char * +bpf_image(p, n) + struct bpf_insn *p; + int n; +{ + int v; + char *fmt, *op; + static char image[256]; + char operand[64]; + + v = p->k; + switch (p->code) { + + default: + op = "unimp"; + fmt = "0x%x"; + v = p->code; + break; + + case BPF_RET|BPF_K: + op = "ret"; + fmt = "#%d"; + break; + + case BPF_RET|BPF_A: + op = "ret"; + fmt = ""; + break; + + case BPF_LD|BPF_W|BPF_ABS: + op = "ld"; + fmt = "[%d]"; + break; + + case BPF_LD|BPF_H|BPF_ABS: + op = "ldh"; + fmt = "[%d]"; + break; + + case BPF_LD|BPF_B|BPF_ABS: + op = "ldb"; + fmt = "[%d]"; + break; + + case BPF_LD|BPF_W|BPF_LEN: + op = "ld"; + fmt = "#pktlen"; + break; + + case BPF_LD|BPF_W|BPF_IND: + op = "ld"; + fmt = "[x + %d]"; + break; + + case BPF_LD|BPF_H|BPF_IND: + op = "ldh"; + fmt = "[x + %d]"; + break; + + case BPF_LD|BPF_B|BPF_IND: + op = "ldb"; + fmt = "[x + %d]"; + break; + + case BPF_LD|BPF_IMM: + op = "ld"; + fmt = "#0x%x"; + break; + + case BPF_LDX|BPF_IMM: + op = "ldx"; + fmt = "#0x%x"; + break; + + case BPF_LDX|BPF_MSH|BPF_B: + op = "ldxb"; + fmt = "4*([%d]&0xf)"; + break; + + case BPF_LD|BPF_MEM: + op = "ld"; + fmt = "M[%d]"; + break; + + case BPF_LDX|BPF_MEM: + op = "ldx"; + fmt = "M[%d]"; + break; + + case BPF_ST: + op = "st"; + fmt = "M[%d]"; + break; + + case BPF_STX: + op = "stx"; + fmt = "M[%d]"; + break; + + case BPF_JMP|BPF_JA: + op = "ja"; + fmt = "%d"; + v = n + p->k; + break; + + case BPF_JMP|BPF_JGT|BPF_K: + op = "jgt"; + fmt = "#0x%x"; + break; + + case BPF_JMP|BPF_JGE|BPF_K: + op = "jge"; + fmt = "#0x%x"; + break; + + case BPF_JMP|BPF_JEQ|BPF_K: + op = "jeq"; + fmt = "#0x%x"; + break; + + case BPF_JMP|BPF_JSET|BPF_K: + op = "jset"; + fmt = "#0x%x"; + break; + + case BPF_JMP|BPF_JGT|BPF_X: + op = "jgt"; + fmt = "x"; + break; + + case BPF_JMP|BPF_JGE|BPF_X: + op = "jge"; + fmt = "x"; + break; + + case BPF_JMP|BPF_JEQ|BPF_X: + op = "jeq"; + fmt = "x"; + break; + + case BPF_JMP|BPF_JSET|BPF_X: + op = "jset"; + fmt = "x"; + break; + + case BPF_ALU|BPF_ADD|BPF_X: + op = "add"; + fmt = "x"; + break; + + case BPF_ALU|BPF_SUB|BPF_X: + op = "sub"; + fmt = "x"; + break; + + case BPF_ALU|BPF_MUL|BPF_X: + op = "mul"; + fmt = "x"; + break; + + case BPF_ALU|BPF_DIV|BPF_X: + op = "div"; + fmt = "x"; + break; + + case BPF_ALU|BPF_AND|BPF_X: + op = "and"; + fmt = "x"; + break; + + case BPF_ALU|BPF_OR|BPF_X: + op = "or"; + fmt = "x"; + break; + + case BPF_ALU|BPF_LSH|BPF_X: + op = "lsh"; + fmt = "x"; + break; + + case BPF_ALU|BPF_RSH|BPF_X: + op = "rsh"; + fmt = "x"; + break; + + case BPF_ALU|BPF_ADD|BPF_K: + op = "add"; + fmt = "#%d"; + break; + + case BPF_ALU|BPF_SUB|BPF_K: + op = "sub"; + fmt = "#%d"; + break; + + case BPF_ALU|BPF_MUL|BPF_K: + op = "mul"; + fmt = "#%d"; + break; + + case BPF_ALU|BPF_DIV|BPF_K: + op = "div"; + fmt = "#%d"; + break; + + case BPF_ALU|BPF_AND|BPF_K: + op = "and"; + fmt = "#%d"; + break; + + case BPF_ALU|BPF_OR|BPF_K: + op = "or"; + fmt = "#%d"; + break; + + case BPF_ALU|BPF_LSH|BPF_K: + op = "lsh"; + fmt = "#%d"; + break; + + case BPF_ALU|BPF_RSH|BPF_K: + op = "rsh"; + fmt = "#%d"; + break; + + case BPF_ALU|BPF_NEG: + op = "neg"; + fmt = ""; + break; + + case BPF_MISC|BPF_TAX: + op = "tax"; + fmt = ""; + break; + + case BPF_MISC|BPF_TXA: + op = "txa"; + fmt = ""; + break; + } + (void)sprintf(operand, fmt, v); + (void)sprintf(image, + (BPF_CLASS(p->code) == BPF_JMP && + BPF_OP(p->code) != BPF_JA) ? + "(%03d) %-8s %-16s jt %d\tjf %d" + : "(%03d) %-8s %s", + n, op, operand, n + 1 + p->jt, n + 1 + p->jf); + return image; +} diff --git a/usr.sbin/tcpdump/tcpdump/etherent.c b/usr.sbin/tcpdump/tcpdump/etherent.c new file mode 100644 index 000000000000..9d7ee8009600 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/etherent.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#ifndef lint +static char rcsid[] = + "@(#) $Header: etherent.c,v 1.2 90/09/20 23:16:06 mccanne Exp $ (LBL)"; +#endif + +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> +#include "interface.h" + +#ifndef ETHER_SERVICE + +#include "etherent.h" + +/* Hex digit to integer. */ +static inline int +xdtoi(c) +{ + if (isdigit(c)) + return c - '0'; + else if (islower(c)) + return c - 'a' + 10; + else + return c - 'A' + 10; +} + +static inline int +skip_space(f) + FILE *f; +{ + int c; + + do { + c = getc(f); + } while (isspace(c) && c != '\n'); + + return c; +} + +static inline int +skip_line(f) + FILE *f; +{ + int c; + + do + c = getc(f); + while (c != '\n' && c != EOF); + + return c; +} + +struct etherent * +next_etherent(fp) + FILE *fp; +{ + register int c, d, i; + char *bp; + static struct etherent e; + static int nline = 1; + top: + while (nline) { + /* Find addr */ + c = skip_space(fp); + if (c == '\n') + continue; + /* If this is a comment, or first thing on line + cannot be etehrnet address, skip the line. */ + else if (!isxdigit(c)) + c = skip_line(fp); + else { + /* must be the start of an address */ + for (i = 0; i < 6; i += 1) { + d = xdtoi(c); + c = getc(fp); + if (c != ':') { + d <<= 4; + d |= xdtoi(c); + c = getc(fp); + } + e.addr[i] = d; + if (c != ':') + break; + c = getc(fp); + } + nline = 0; + } + if (c == EOF) + return 0; + } + + /* If we started a new line, 'c' holds the char past the ether addr, + which we assume is white space. If we are continuning a line, + 'c' is garbage. In either case, we can throw it away. */ + + c = skip_space(fp); + if (c == '\n') { + nline = 1; + goto top; + } + else if (c == '#') { + (void)skip_line(fp); + nline = 1; + goto top; + } + else if (c == EOF) + return 0; + + /* Must be a name. */ + bp = e.name; + /* Use 'd' to prevent buffer overflow. */ + d = sizeof(e.name) - 1; + do { + *bp++ = c; + c = getc(fp); + } while (!isspace(c) && c != EOF && --d > 0); + *bp = '\0'; + if (c == '\n') + nline = 1; + + return &e; +} + +#endif diff --git a/usr.sbin/tcpdump/tcpdump/etherent.h b/usr.sbin/tcpdump/tcpdump/etherent.h new file mode 100644 index 000000000000..83ebaabb8647 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/etherent.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#) $Header: etherent.h,v 1.2 90/09/20 23:16:17 mccanne Exp $ (LBL) + */ + +/* File name of ethernet address data base. */ + +#define ETHERS_FILE "/etc/ethers" + +struct etherent { + u_char addr[6]; + char name[122]; +}; + +struct etherent *next_etherent(); + diff --git a/usr.sbin/tcpdump/tcpdump/etherproto.h b/usr.sbin/tcpdump/tcpdump/etherproto.h new file mode 100644 index 000000000000..5c0e245cee72 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/etherproto.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#) $Header: etherproto.h,v 1.7 90/10/10 15:04:04 mccanne Exp $ (LBL) + */ + +/* Map between Ethernet protocol types and names */ + +/* Add other Ethernet packet types here */ +#ifndef ETHERTYPE_SPRITE +#define ETHERTYPE_SPRITE 0x0500 +#endif +#ifndef ETHERTYPE_MOPDL +#define ETHERTYPE_MOPDL 0x6001 +#endif +#ifndef ETHERTYPE_MOPRC +#define ETHERTYPE_MOPRC 0x6002 +#endif +#ifndef ETHERTYPE_DN +#define ETHERTYPE_DN 0x6003 +#endif +#ifndef ETHERTYPE_LAT +#define ETHERTYPE_LAT 0x6004 +#endif +#ifndef ETHERTYPE_LANBRIDGE +#define ETHERTYPE_LANBRIDGE 0x8038 +#endif +#ifndef ETHERTYPE_VEXP +#define ETHERTYPE_VEXP 0x805b +#endif +#ifndef ETHERTYPE_VPROD +#define ETHERTYPE_VPROD 0x805c +#endif +#ifndef ETHERTYPE_LOOPBACK +#define ETHERTYPE_LOOPBACK 0x9000 +#endif + +#ifndef ETHERTYPE_ATALK +#define ETHERTYPE_ATALK 0x809b /* XXX */ +#endif +#ifndef ETHERTYPE_AARP +#define ETHERTYPE_AARP 0x80f3 +#endif +#ifndef ETHERTYPE_NS +#define ETHERTYPE_NS 0x0600 +#endif + +struct eproto { + char *s; + u_short p; +}; + +extern struct eproto eproto_db[]; diff --git a/usr.sbin/tcpdump/tcpdump/extract.h b/usr.sbin/tcpdump/tcpdump/extract.h new file mode 100644 index 000000000000..bd45c59b3e9e --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/extract.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#) $Header: extract.h,v 1.4 92/05/25 14:28:36 mccanne Exp $ (LBL) + */ + +#ifdef TCPDUMP_ALIGN +#if BYTEORDER == LITTLE_ENDIAN +#define EXTRACT_SHORT(p)\ + ((u_short)\ + ((u_short)*((u_char *)p+1)<<8|\ + (u_short)*((u_char *)p+0)<<0)) +#define EXTRACT_LONG(p)\ + ((u_long)*((u_char *)p+3)<<24|\ + (u_long)*((u_char *)p+2)<<16|\ + (u_long)*((u_char *)p+1)<<8|\ + (u_long)*((u_char *)p+0)<<0) +#else +#define EXTRACT_SHORT(p)\ + ((u_short)\ + ((u_short)*((u_char *)p+0)<<8|\ + (u_short)*((u_char *)p+1)<<0)) +#define EXTRACT_LONG(p)\ + ((u_long)*((u_char *)p+0)<<24|\ + (u_long)*((u_char *)p+1)<<16|\ + (u_long)*((u_char *)p+2)<<8|\ + (u_long)*((u_char *)p+3)<<0) +#endif +#else +#define EXTRACT_SHORT(p) ((u_short)ntohs(*(u_short *)p)) +#define EXTRACT_LONG(p) (ntohl(*(u_long *)p)) +#endif diff --git a/usr.sbin/tcpdump/tcpdump/gencode.c b/usr.sbin/tcpdump/tcpdump/gencode.c new file mode 100644 index 000000000000..8cb48ea05483 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/gencode.c @@ -0,0 +1,1384 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#ifndef lint +static char rcsid[] = + "@(#) $Header: gencode.c,v 1.33 92/05/22 16:38:39 mccanne Exp $ (LBL)"; +#endif + +#ifdef __STDC__ +#include <stdlib.h> +#endif +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <sys/time.h> +#include <net/bpf.h> + +#include "interface.h" +#include "gencode.h" +#include "nametoaddr.h" +#include "extract.h" + +#define JMP(c) ((c)|BPF_JMP|BPF_K) + +extern struct bpf_insn *icode_to_fcode(); +extern u_long net_mask(); +static void init_linktype(); + +static int alloc_reg(); +static void free_reg(); + +static struct block *root; + +/* + * We divy out chunks of memory rather than call malloc each time so + * we don't have to worry about leaking memory. It's probably + * not a big deal if all this memory was wasted but it this ever + * goes into a library that would probably not be a good idea. + */ +#define NCHUNKS 16 +#define CHUNK0SIZE 1024 +struct chunk { + u_int n_left; + void *m; +}; + +static struct chunk chunks[NCHUNKS]; +static int cur_chunk; + +static void * +newchunk(n) + u_int n; +{ + struct chunk *cp; + int k, size; + + /* XXX Round up to nearest long. */ + n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1); + + cp = &chunks[cur_chunk]; + if (n > cp->n_left) { + ++cp, k = ++cur_chunk; + if (k >= NCHUNKS) + error("out of memory"); + size = CHUNK0SIZE << k; + cp->m = (void *)malloc(size); + bzero((char *)cp->m, size); + cp->n_left = size; + if (n > size) + error("out of memory"); + } + cp->n_left -= n; + return (void *)((char *)cp->m + cp->n_left); +} + +static void +freechunks() +{ + int i; + + for (i = 0; i < NCHUNKS; ++i) + if (chunks[i].m) + free(chunks[i].m); +} + +static inline struct block * +new_block(code) + int code; +{ + struct block *p; + + p = (struct block *)newchunk(sizeof(*p)); + p->s.code = code; + p->head = p; + + return p; +} + +static inline struct slist * +new_stmt(code) + int code; +{ + struct slist *p; + + p = (struct slist *)newchunk(sizeof(*p)); + p->s.code = code; + + return p; +} + +static struct block * +gen_retblk(v) + int v; +{ + struct block *b = new_block(BPF_RET|BPF_K); + + b->s.k = v; + return b; +} + +static inline void +syntax() +{ + error("syntax error in filter expression"); +} + +static u_long netmask; + +struct bpf_program * +parse(buf, Oflag, linktype, mask) + char *buf; + int Oflag; + int linktype; + u_long mask; +{ + extern int n_errors; + static struct bpf_program F; + struct bpf_insn *p; + int len; + + netmask = mask; + + F.bf_insns = 0; + F.bf_len = 0; + + lex_init(buf ? buf : ""); + init_linktype(linktype); + yyparse(); + + if (n_errors) + syntax(); + + if (root == 0) + root = gen_retblk(snaplen); + + if (Oflag) { + optimize(&root); + if (root == 0 || + (root->s.code == (BPF_RET|BPF_K) && root->s.k == 0)) + error("expression rejects all packets"); + } + p = icode_to_fcode(root, &len); + F.bf_insns = p; + F.bf_len = len; + + freechunks(); + return &F; +} + +/* + * Backpatch the blocks in 'list' to 'target'. The 'sense' field indicates + * which of the jt and jf fields has been resolved and which is a pointer + * back to another unresolved block (or nil). At least one of the fields + * in each block is already resolved. + */ +static void +backpatch(list, target) + struct block *list, *target; +{ + struct block *next; + + while (list) { + if (!list->sense) { + next = JT(list); + JT(list) = target; + } else { + next = JF(list); + JF(list) = target; + } + list = next; + } +} + +/* + * Merge the lists in b0 and b1, using the 'sense' field to indicate + * which of jt and jf is the link. + */ +static void +merge(b0, b1) + struct block *b0, *b1; +{ + register struct block **p = &b0; + + /* Find end of list. */ + while (*p) + p = !((*p)->sense) ? &JT(*p) : &JF(*p); + + /* Concatenate the lists. */ + *p = b1; +} + +void +finish_parse(p) + struct block *p; +{ + backpatch(p, gen_retblk(snaplen)); + p->sense = !p->sense; + backpatch(p, gen_retblk(0)); + root = p->head; +} + +void +gen_and(b0, b1) + struct block *b0, *b1; +{ + backpatch(b0, b1->head); + b0->sense = !b0->sense; + b1->sense = !b1->sense; + merge(b1, b0); + b1->sense = !b1->sense; + b1->head = b0->head; +} + +void +gen_or(b0, b1) + struct block *b0, *b1; +{ + b0->sense = !b0->sense; + backpatch(b0, b1->head); + b0->sense = !b0->sense; + merge(b1, b0); + b1->head = b0->head; +} + +void +gen_not(b) + struct block *b; +{ + b->sense = !b->sense; +} + +static struct block * +gen_cmp(offset, size, v) + u_int offset, size; + long v; +{ + struct slist *s; + struct block *b; + + s = new_stmt(BPF_LD|BPF_ABS|size); + s->s.k = offset; + + b = new_block(JMP(BPF_JEQ)); + b->stmts = s; + b->s.k = v; + + return b; +} + +struct block * +gen_mcmp(offset, size, v, mask) + u_int offset, size; + long v; + u_long mask; +{ + struct block *b = gen_cmp(offset, size, v); + struct slist *s; + + if (mask != 0xffffffff) { + s = new_stmt(BPF_ALU|BPF_AND|BPF_K); + s->s.k = mask; + b->stmts->next = s; + } + return b; +} + +struct block * +gen_bcmp(offset, size, v) + u_int offset; + u_int size; + u_char *v; +{ + struct block *b, *tmp; + int k; + + b = 0; + while (size >= 4) { + k = size - 4; + tmp = gen_cmp(offset + k, BPF_W, EXTRACT_LONG(&v[k])); + if (b != 0) + gen_and(b, tmp); + b = tmp; + size -= 4; + } + while (size >= 2) { + k = size - 2; + tmp = gen_cmp(offset + k, BPF_H, (long)EXTRACT_SHORT(&v[k])); + if (b != 0) + gen_and(b, tmp); + b = tmp; + size -= 2; + } + if (size > 0) { + tmp = gen_cmp(offset, BPF_B, (long)v[0]); + if (b != 0) + gen_and(b, tmp); + b = tmp; + } + return b; +} + +/* + * Various code contructs need to know the layout of the data link + * layer. These variables give the necessary offsets. off_linktype + * is set to -1 for no encapsulation, in which case, IP is assumed. + */ +static u_int off_linktype; +static u_int off_nl; +static int linktype; + +static void +init_linktype(type) + int type; +{ + linktype = type; + + switch (type) { + + case DLT_EN10MB: + off_linktype = 12; + off_nl = 14; + return; + + case DLT_SLIP: + /* + * SLIP doesn't have a link level type. The 16 byte + * header is hacked into our SLIP driver. + */ + off_linktype = -1; + off_nl = 16; + return; + + case DLT_NULL: + off_linktype = -1; + off_nl = 0; + return; + + case DLT_PPP: + off_linktype = 2; + off_nl = 4; + return; + + case DLT_FDDI: + off_linktype = 19; + off_nl = 21; + return; + + case DLT_IEEE802: + off_linktype = 20; + off_nl = 22; + return; + } + error("unknown data link type 0x%x", linktype); + /* NOTREACHED */ +} + +static struct block * +gen_uncond(rsense) + int rsense; +{ + struct block *b; + struct slist *s; + + s = new_stmt(BPF_LD|BPF_IMM); + s->s.k = !rsense; + b = new_block(JMP(BPF_JEQ)); + b->stmts = s; + + return b; +} + +static inline struct block * +gen_true() +{ + return gen_uncond(1); +} + +static inline struct block * +gen_false() +{ + return gen_uncond(0); +} + +struct block * +gen_linktype(proto) + int proto; +{ + switch (linktype) { + case DLT_SLIP: + if (proto == ETHERTYPE_IP) + return gen_true(); + else + return gen_false(); + + case DLT_PPP: + if (proto == ETHERTYPE_IP) + proto = 0x0021; /* XXX - need ppp.h defs */ + break; + } + return gen_cmp(off_linktype, BPF_H, (long)proto); +} + +static struct block * +gen_hostop(addr, mask, dir, proto, src_off, dst_off) + u_long addr; + u_long mask; + int dir, proto; + u_int src_off, dst_off; +{ + struct block *b0, *b1; + u_int offset; + + switch (dir) { + + case Q_SRC: + offset = src_off; + break; + + case Q_DST: + offset = dst_off; + break; + + case Q_AND: + b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off); + b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off); + gen_and(b0, b1); + return b1; + + case Q_OR: + case Q_DEFAULT: + b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off); + b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off); + gen_or(b0, b1); + return b1; + + default: + abort(); + } + b0 = gen_linktype(proto); + b1 = gen_mcmp(offset, BPF_W, (long)addr, mask); + gen_and(b0, b1); + return b1; +} + +static struct block * +gen_ehostop(eaddr, dir) + u_char *eaddr; + int dir; +{ + struct block *b0, *b1; + + switch (dir) { + case Q_SRC: + return gen_bcmp(6, 6, eaddr); + + case Q_DST: + return gen_bcmp(0, 6, eaddr); + + case Q_AND: + b0 = gen_ehostop(eaddr, Q_SRC); + b1 = gen_ehostop(eaddr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_ehostop(eaddr, Q_SRC); + b1 = gen_ehostop(eaddr, Q_DST); + gen_or(b0, b1); + return b1; + } + abort(); + /* NOTREACHED */ +} + +static struct block * +gen_host(addr, mask, proto, dir) + u_long addr; + u_long mask; + int proto; + int dir; +{ + struct block *b0, *b1; + + switch (proto) { + + case Q_DEFAULT: + b0 = gen_host(addr, mask, Q_IP, dir); + b1 = gen_host(addr, mask, Q_ARP, dir); + gen_or(b0, b1); + b0 = gen_host(addr, mask, Q_RARP, dir); + gen_or(b1, b0); + return b0; + + case Q_IP: + return gen_hostop(addr, mask, dir, ETHERTYPE_IP, + off_nl + 12, off_nl + 16); + + case Q_RARP: + return gen_hostop(addr, mask, dir, ETHERTYPE_REVARP, + off_nl + 14, off_nl + 24); + + case Q_ARP: + return gen_hostop(addr, mask, dir, ETHERTYPE_ARP, + off_nl + 14, off_nl + 24); + + case Q_TCP: + error("'tcp' modifier applied to host"); + + case Q_UDP: + error("'udp' modifier applied to host"); + + case Q_ICMP: + error("'icmp' modifier applied to host"); + } + abort(); + /* NOTREACHED */ +} + +static struct block * +gen_gateway(eaddr, alist, proto, dir) + u_char *eaddr; + u_long **alist; + int proto; + int dir; +{ + struct block *b0, *b1, *tmp; + + if (dir != 0) + error("direction applied to 'gateway'"); + + switch (proto) { + case Q_DEFAULT: + case Q_IP: + case Q_ARP: + case Q_RARP: + b0 = gen_ehostop(eaddr, Q_OR); + b1 = gen_host(**alist++, 0xffffffffL, proto, Q_OR); + while (*alist) { + tmp = gen_host(**alist++, 0xffffffffL, proto, Q_OR); + gen_or(b1, tmp); + b1 = tmp; + } + gen_not(b1); + gen_and(b0, b1); + return b1; + } + error("illegal modifier of 'gateway'"); + /* NOTREACHED */ +} + +struct block * +gen_proto_abbrev(proto) + int proto; +{ + struct block *b0, *b1; + + switch (proto) { + + case Q_TCP: + b0 = gen_linktype(ETHERTYPE_IP); + b1 = gen_cmp(off_nl + 9, BPF_B, (long)IPPROTO_TCP); + gen_and(b0, b1); + break; + + case Q_UDP: + b0 = gen_linktype(ETHERTYPE_IP); + b1 = gen_cmp(off_nl + 9, BPF_B, (long)IPPROTO_UDP); + gen_and(b0, b1); + break; + + case Q_ICMP: + b0 = gen_linktype(ETHERTYPE_IP); + b1 = gen_cmp(off_nl + 9, BPF_B, (long)IPPROTO_ICMP); + gen_and(b0, b1); + break; + + case Q_IP: + b1 = gen_linktype(ETHERTYPE_IP); + break; + + case Q_ARP: + b1 = gen_linktype(ETHERTYPE_ARP); + break; + + case Q_RARP: + b1 = gen_linktype(ETHERTYPE_REVARP); + break; + + case Q_LINK: + error("link layer applied in wrong context"); + + default: + abort(); + } + return b1; +} + +static struct block * +gen_ipfrag() +{ + struct slist *s; + struct block *b; + + /* not ip frag */ + s = new_stmt(BPF_LD|BPF_H|BPF_ABS); + s->s.k = off_nl + 6; + b = new_block(JMP(BPF_JSET)); + b->s.k = 0x1fff; + b->stmts = s; + gen_not(b); + + return b; +} + +static struct block * +gen_portatom(off, v) + int off; + long v; +{ + struct slist *s; + struct block *b; + + s = new_stmt(BPF_LDX|BPF_MSH|BPF_B); + s->s.k = off_nl; + + s->next = new_stmt(BPF_LD|BPF_IND|BPF_H); + s->next->s.k = off_nl + off; + + b = new_block(JMP(BPF_JEQ)); + b->stmts = s; + b->s.k = v; + + return b; +} + +struct block * +gen_portop(port, proto, dir) + int port; + int proto; + int dir; +{ + struct block *b0, *b1, *tmp; + + /* ip proto 'proto' */ + tmp = gen_cmp(off_nl + 9, BPF_B, (long)proto); + b0 = gen_ipfrag(); + gen_and(tmp, b0); + + switch (dir) { + case Q_SRC: + b1 = gen_portatom(0, (long)port); + break; + + case Q_DST: + b1 = gen_portatom(2, (long)port); + break; + + case Q_OR: + case Q_DEFAULT: + tmp = gen_portatom(0, (long)port); + b1 = gen_portatom(2, (long)port); + gen_or(tmp, b1); + break; + + case Q_AND: + tmp = gen_portatom(0, (long)port); + b1 = gen_portatom(2, (long)port); + gen_and(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + + return b1; +} + +static struct block * +gen_port(port, ip_proto, dir) + int port; + int ip_proto; + int dir; +{ + struct block *b0, *b1, *tmp; + + /* ether proto ip */ + b0 = gen_linktype(ETHERTYPE_IP); + + switch (ip_proto) { + case IPPROTO_UDP: + case IPPROTO_TCP: + b1 = gen_portop(port, ip_proto, dir); + break; + + case PROTO_UNDEF: + tmp = gen_portop(port, IPPROTO_TCP, dir); + b1 = gen_portop(port, IPPROTO_UDP, dir); + gen_or(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + return b1; +} + +int +lookup_proto(name, proto) + char *name; + int proto; +{ + int v; + + switch (proto) { + case Q_DEFAULT: + case Q_IP: + v = s_nametoproto(name); + if (v == PROTO_UNDEF) + error("unknown ip proto '%s'", name); + break; + + case Q_LINK: + /* XXX should look up h/w protocol type based on linktype */ + v = s_nametoeproto(name); + if (v == PROTO_UNDEF) + error("unknown ether proto '%s'", name); + break; + + default: + v = PROTO_UNDEF; + break; + } + return v; +} + +struct block * +gen_proto(v, proto, dir) + int v; + int proto; + int dir; +{ + struct block *b0, *b1; + + if (dir != Q_DEFAULT) + error("direction applied to 'proto'"); + + switch (proto) { + case Q_DEFAULT: + case Q_IP: + b0 = gen_linktype(ETHERTYPE_IP); + b1 = gen_cmp(off_nl + 9, BPF_B, (long)v); + gen_and(b0, b1); + return b1; + + case Q_ARP: + error("arp does not encapsulate another protocol"); + /* NOTREACHED */ + + case Q_RARP: + error("rarp does not encapsulate another protocol"); + /* NOTREACHED */ + + case Q_LINK: + return gen_linktype(v); + + case Q_UDP: + error("'udp proto' is bogus"); + + case Q_TCP: + error("'tcp proto' is bogus"); + + case Q_ICMP: + error("'icmp proto' is bogus"); + } + abort(); + /* NOTREACHED */ +} + +struct block * +gen_scode(name, q) + char *name; + struct qual q; +{ + int proto = q.proto; + int dir = q.dir; + u_char *eaddr; + u_long mask, addr, **alist; + struct block *b, *tmp; + int port, real_proto; + + switch (q.addr) { + + case Q_NET: + addr = s_nametonetaddr(name); + if (addr == 0) + error("unknown network '%s'", name); + mask = net_mask(&addr); + return gen_host(addr, mask, proto, dir); + + case Q_DEFAULT: + case Q_HOST: + if (proto == Q_LINK) { + /* XXX Should lookup hw addr based on link layer */ + eaddr = ETHER_hostton(name); + if (eaddr == 0) + error("unknown ether host '%s'", name); + return gen_ehostop(eaddr, dir); + + } else { + alist = s_nametoaddr(name); + if (alist == 0 || *alist == 0) + error("uknown host '%s'", name); + b = gen_host(**alist++, 0xffffffffL, proto, dir); + while (*alist) { + tmp = gen_host(**alist++, 0xffffffffL, + proto, dir); + gen_or(b, tmp); + b = tmp; + } + return b; + } + + case Q_PORT: + if (proto != Q_DEFAULT && proto != Q_UDP && proto != Q_TCP) + error("illegal qualifier of 'port'"); + if (s_nametoport(name, &port, &real_proto) == 0) + error("unknown port '%s'", name); + if (proto == Q_UDP) { + if (real_proto == IPPROTO_TCP) + error("port '%s' is tcp", name); + else + /* override PROTO_UNDEF */ + real_proto = IPPROTO_UDP; + } + if (proto == Q_TCP) { + if (real_proto == IPPROTO_UDP) + error("port '%s' is udp", name); + else + /* override PROTO_UNDEF */ + real_proto = IPPROTO_TCP; + } + return gen_port(port, real_proto, dir); + + case Q_GATEWAY: + eaddr = ETHER_hostton(name); + if (eaddr == 0) + error("unknown ether host: %s", name); + + alist = s_nametoaddr(name); + if (alist == 0 || *alist == 0) + error("uknown host '%s'", name); + return gen_gateway(eaddr, alist, proto, dir); + + case Q_PROTO: + real_proto = lookup_proto(name, proto); + if (real_proto >= 0) + return gen_proto(real_proto, proto, dir); + else + error("unknown protocol: %s", name); + + case Q_UNDEF: + syntax(); + /* NOTREACHED */ + } + abort(); + /* NOTREACHED */ +} + +struct block * +gen_ncode(v, q) + u_long v; + struct qual q; +{ + u_long mask; + int proto = q.proto; + int dir = q.dir; + + switch (q.addr) { + + case Q_DEFAULT: + case Q_HOST: + case Q_NET: + mask = net_mask(&v); + return gen_host(v, mask, proto, dir); + + case Q_PORT: + if (proto == Q_UDP) + proto = IPPROTO_UDP; + else if (proto == Q_TCP) + proto = IPPROTO_TCP; + else if (proto == Q_DEFAULT) + proto = PROTO_UNDEF; + else + error("illegal qualifier of 'port'"); + + return gen_port((int)v, proto, dir); + + case Q_GATEWAY: + error("'gateway' requires a name"); + /* NOTREACHED */ + + case Q_PROTO: + return gen_proto((int)v, proto, dir); + + case Q_UNDEF: + syntax(); + /* NOTREACHED */ + } + abort(); + /* NOTREACHED */ +} + +struct block * +gen_ecode(eaddr, q) + u_char *eaddr; + struct qual q; +{ + if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) + return gen_ehostop(eaddr, (int)q.dir); + else + error("ethernet address used in non-ether expression"); + /* NOTREACHED */ +} + +void +sappend(s0, s1) + struct slist *s0, *s1; +{ + /* + * This is definitely not the best way to do this, but the + * lists will rarely get long. + */ + while (s0->next) + s0 = s0->next; + s0->next = s1; +} + +struct slist * +xfer_to_x(a) + struct arth *a; +{ + struct slist *s; + + s = new_stmt(BPF_LDX|BPF_MEM); + s->s.k = a->regno; + return s; +} + +struct slist * +xfer_to_a(a) + struct arth *a; +{ + struct slist *s; + + s = new_stmt(BPF_LD|BPF_MEM); + s->s.k = a->regno; + return s; +} + +struct arth * +gen_load(proto, index, size) + int proto; + struct arth *index; + int size; +{ + struct slist *s, *tmp; + struct block *b; + int regno = alloc_reg(); + + free_reg(index->regno); + switch (size) { + + default: + error("data size must be 1, 2, or 4"); + + case 1: + size = BPF_B; + break; + + case 2: + size = BPF_H; + break; + + case 4: + size = BPF_W; + break; + } + switch (proto) { + default: + error("unsupported index operation"); + + case Q_LINK: + s = xfer_to_x(index); + tmp = new_stmt(BPF_LD|BPF_IND|size); + sappend(s, tmp); + sappend(index->s, s); + break; + + case Q_IP: + case Q_ARP: + case Q_RARP: + /* XXX Note that we assume a fixed link link header here. */ + s = xfer_to_x(index); + tmp = new_stmt(BPF_LD|BPF_IND|size); + tmp->s.k = off_nl; + sappend(s, tmp); + sappend(index->s, s); + + b = gen_proto_abbrev(proto); + if (index->b) + gen_and(index->b, b); + index->b = b; + break; + + case Q_TCP: + case Q_UDP: + case Q_ICMP: + s = new_stmt(BPF_LDX|BPF_MSH|BPF_B); + s->s.k = off_nl; + sappend(s, xfer_to_a(index)); + sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X)); + sappend(s, new_stmt(BPF_MISC|BPF_TAX)); + sappend(s, tmp = new_stmt(BPF_LD|BPF_IND|size)); + tmp->s.k = off_nl; + sappend(index->s, s); + + gen_and(gen_proto_abbrev(proto), b = gen_ipfrag()); + if (index->b) + gen_and(index->b, b); + index->b = b; + break; + } + index->regno = regno; + s = new_stmt(BPF_ST); + s->s.k = regno; + sappend(index->s, s); + + return index; +} + +struct block * +gen_relation(code, a0, a1, reversed) + int code; + struct arth *a0, *a1; + int reversed; +{ + struct slist *s0, *s1, *s2; + struct block *b, *tmp; + + s0 = xfer_to_x(a1); + s1 = xfer_to_a(a0); + s2 = new_stmt(BPF_ALU|BPF_SUB|BPF_X); + b = new_block(JMP(code)); + if (reversed) + gen_not(b); + + sappend(s1, s2); + sappend(s0, s1); + sappend(a1->s, s0); + sappend(a0->s, a1->s); + + b->stmts = a0->s; + + free_reg(a0->regno); + free_reg(a1->regno); + + /* 'and' together protocol checks */ + if (a0->b) { + if (a1->b) { + gen_and(a0->b, tmp = a1->b); + } + else + tmp = a0->b; + } else + tmp = a1->b; + + if (tmp) + gen_and(tmp, b); + + return b; +} + +struct arth * +gen_loadlen() +{ + int regno = alloc_reg(); + struct arth *a = (struct arth *)newchunk(sizeof(*a)); + struct slist *s; + + s = new_stmt(BPF_LD|BPF_LEN); + s->next = new_stmt(BPF_ST); + s->next->s.k = regno; + a->s = s; + a->regno = regno; + + return a; +} + +struct arth * +gen_loadi(val) + int val; +{ + struct arth *a; + struct slist *s; + int reg; + + a = (struct arth *)newchunk(sizeof(*a)); + + reg = alloc_reg(); + + s = new_stmt(BPF_LD|BPF_IMM); + s->s.k = val; + s->next = new_stmt(BPF_ST); + s->next->s.k = reg; + a->s = s; + a->regno = reg; + + return a; +} + +struct arth * +gen_neg(a) + struct arth *a; +{ + struct slist *s; + + s = xfer_to_a(a); + sappend(a->s, s); + s = new_stmt(BPF_ALU|BPF_NEG); + s->s.k = 0; + sappend(a->s, s); + s = new_stmt(BPF_ST); + s->s.k = a->regno; + sappend(a->s, s); + + return a; +} + +struct arth * +gen_arth(code, a0, a1) + int code; + struct arth *a0, *a1; +{ + struct slist *s0, *s1, *s2; + + s0 = xfer_to_x(a1); + s1 = xfer_to_a(a0); + s2 = new_stmt(BPF_ALU|BPF_X|code); + + sappend(s1, s2); + sappend(s0, s1); + sappend(a1->s, s0); + sappend(a0->s, a1->s); + + free_reg(a1->regno); + + s0 = new_stmt(BPF_ST); + a0->regno = s0->s.k = alloc_reg(); + sappend(a0->s, s0); + + return a0; +} + +/* + * Here we handle simple allocation of the scratch registers. + * If too many registers are alloc'd, the allocator punts. + */ +static int regused[BPF_MEMWORDS]; +static int curreg; + +/* + * Return the next free register. + */ +static int +alloc_reg() +{ + int n = BPF_MEMWORDS; + + while (--n >= 0) { + if (regused[curreg]) + curreg = (curreg + 1) % BPF_MEMWORDS; + else { + regused[curreg] = 1; + return curreg; + } + } + error("too many registers needed to evaluate expression"); + /* NOTREACHED */ +} + +/* + * Return a register to the table so it can + * be used later. + */ +static void +free_reg(n) + int n; +{ + regused[n] = 0; +} + +static struct block * +gen_len(jmp, n) + int jmp; + int n; +{ + struct slist *s; + struct block *b; + + s = new_stmt(BPF_LD|BPF_LEN); + s->next = new_stmt(BPF_SUB|BPF_IMM); + s->next->s.k = n; + b = new_block(JMP(jmp)); + b->stmts = s; + + return b; +} + +struct block * +gen_greater(n) + int n; +{ + return gen_len(BPF_JGE, n); +} + +struct block * +gen_less(n) + int n; +{ + struct block *b; + + b = gen_len(BPF_JGT, n); + gen_not(b); + + return b; +} + +struct block * +gen_byteop(op, idx, val) + int op; + int idx; + int val; +{ + struct block *b; + struct slist *s; + + switch (op) { + default: + abort(); + + case '=': + return gen_cmp((u_int)idx, BPF_B, (long)val); + + case '<': + b = gen_cmp((u_int)idx, BPF_B, (long)val); + b->s.code = JMP(BPF_JGE); + gen_not(b); + return b; + + case '>': + b = gen_cmp((u_int)idx, BPF_B, (long)val); + b->s.code = JMP(BPF_JGT); + return b; + + case '|': + s = new_stmt(BPF_ALU|BPF_AND|BPF_K); + break; + + case '&': + s = new_stmt(BPF_ALU|BPF_AND|BPF_K); + break; + } + s->s.k = val; + b = new_block(JMP(BPF_JEQ)); + b->stmts = s; + gen_not(b); + + return b; +} + +struct block * +gen_broadcast(proto) + int proto; +{ + u_long hostmask; + struct block *b0, *b1, *b2; + static u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + switch (proto) { + + case Q_DEFAULT: + case Q_LINK: + if (linktype == DLT_EN10MB) + return gen_ehostop(ebroadcast, Q_DST); + error("not a broadcast link"); + break; + + case Q_IP: + b0 = gen_linktype(ETHERTYPE_IP); + hostmask = ~netmask; + b1 = gen_mcmp(off_nl + 16, BPF_W, (long)0, hostmask); + b2 = gen_mcmp(off_nl + 16, BPF_W, + (long)(~0 & hostmask), hostmask); + gen_or(b1, b2); + gen_and(b0, b2); + return b2; + } + error("only ether/ip broadcast filters supported"); +} + +struct block * +gen_multicast(proto) + int proto; +{ + register struct block *b0, *b1, *b2; + register struct slist *s; + + switch (proto) { + + case Q_DEFAULT: + case Q_LINK: + if (linktype != DLT_EN10MB) + break; + + /* ether[0] & 1 != 0 */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = 0; + b0 = new_block(JMP(BPF_JSET)); + b0->s.k = 1; + b0->stmts = s; + return b0; + + case Q_IP: + b0 = gen_linktype(ETHERTYPE_IP); + b1 = gen_cmp(off_nl + 16, BPF_B, (long)224); + b1->s.code = JMP(BPF_JGE); + gen_and(b0, b1); + return b1; + } + error("only ether/ip multicast filters supported"); +} diff --git a/usr.sbin/tcpdump/tcpdump/gencode.h b/usr.sbin/tcpdump/tcpdump/gencode.h new file mode 100644 index 000000000000..b8f342d6b629 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/gencode.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#) $Header: gencode.h,v 1.14 92/02/14 15:18:55 mccanne Exp $ (LBL) + */ + +/* + * filter.h must be included before this file. + */ + +/* Address qualifers. */ + +#define Q_HOST 1 +#define Q_NET 2 +#define Q_PORT 3 +#define Q_GATEWAY 4 +#define Q_PROTO 5 + +/* Protocol qualifiers. */ + +#define Q_LINK 1 +#define Q_IP 2 +#define Q_ARP 3 +#define Q_RARP 4 +#define Q_TCP 5 +#define Q_UDP 6 +#define Q_ICMP 7 + +/* Directional qualifers. */ + +#define Q_SRC 1 +#define Q_DST 2 +#define Q_OR 3 +#define Q_AND 4 + +#define Q_DEFAULT 0 +#define Q_UNDEF 255 + +struct stmt { + int code; + long k; +}; + +struct slist { + struct stmt s; + struct slist *next; +}; + +/* + * A bit vector to represent definition sets. We assume TOT_REGISTERS + * is smaller than 8*sizeof(atomset). + */ +typedef u_long atomset; +#define ATOMMASK(n) (1 << (n)) +#define ATOMELEM(d, n) (d & ATOMMASK(n)) + +/* + * An unbounded set. + */ +typedef u_long *uset; + +/* + * Total number of atomic entities, including accumulator (A) and index (X). + * We treat all these guys similarly during flow analysis. + */ +#define N_ATOMS (BPF_MEMWORDS+2) + +struct edge { + int id; + int code; + uset edom; + struct block *succ; + struct block *pred; + struct edge *next; /* link list of incoming edges for a node */ +}; + +struct block { + int id; + struct slist *stmts; /* side effect stmts */ + struct stmt s; /* branch stmt */ + int mark; + int level; + int offset; + int sense; + struct edge et; + struct edge ef; + struct block *head; + struct block *link; /* link field used by optimizer */ + uset dom; + uset closure; + struct edge *in_edges; + atomset def, kill; + atomset in_use; + atomset out_use; + long oval; + long val[N_ATOMS]; +}; + +struct arth { + struct block *b; /* protocol checks */ + struct slist *s; /* stmt list */ + int regno; /* virtual register number of result */ +}; + +extern struct arth *gen_loadi(); +extern struct arth *gen_load(); +extern struct arth *gen_loadlen(); +extern struct arth *gen_neg(); +extern struct arth *gen_arth(); + +extern void gen_and(); +extern void gen_or(); +extern void gen_not(); + +extern struct block *gen_scode(); +extern struct block *gen_ecode(); +extern struct block *gen_ncode(); +extern struct block *gen_proto_abbrev(); +extern struct block *gen_relation(); +extern struct block *gen_less(); +extern struct block *gen_greater(); +extern struct block *gen_byteop(); +extern struct block *gen_broadcast(); +extern struct block *gen_multicast(); + +extern void optimize(); + +extern void finish_parse(); + +struct qual { + unsigned char addr; + unsigned char proto; + unsigned char dir; + unsigned char pad; +}; + +/* XXX */ +#define JT(b) ((b)->et.succ) +#define JF(b) ((b)->ef.succ) diff --git a/usr.sbin/tcpdump/tcpdump/inet.c b/usr.sbin/tcpdump/tcpdump/inet.c new file mode 100644 index 000000000000..550129e1af55 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/inet.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#)$Header: inet.c,v 1.12 92/01/29 12:46:18 mccanne Exp $ (LBL)"; +#endif + +#include <stdio.h> +#include <ctype.h> +#include <strings.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/ioctl.h> + +#include <net/if.h> +#include <netinet/in.h> + +#include "interface.h" + +/* Not all systems have IFF_LOOPBACK */ +#ifdef IFF_LOOPBACK +#define ISLOOPBACK(p) ((p)->ifr_flags & IFF_LOOPBACK) +#else +#define ISLOOPBACK(p) (strcmp((p)->ifr_name, "lo0") == 0) +#endif + +/* + * Return the name of a network interface attached to the system, or 0 + * if none can be found. The interface must be configured up; the + * lowest unit number is preferred; loopback is ignored. + */ +char * +lookup_device() +{ + struct ifreq ibuf[16], *ifrp, *ifend, *mp; + struct ifconf ifc; + int fd; + int minunit, n; + char *cp; + static char device[sizeof(ifrp->ifr_name)]; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + perror("tcpdump: socket"); + exit(1); + } + ifc.ifc_len = sizeof ibuf; + ifc.ifc_buf = (caddr_t)ibuf; + + if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 || + ifc.ifc_len < sizeof(struct ifreq)) { + perror("tcpdump: SIOCGIFCONF: "); + exit(1); + } + ifrp = ibuf; + ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len); + + mp = 0; + minunit = 666; + while (ifrp < ifend) { + struct ifreq ifr; + /* + * Need a template to preserve address info that is + * used below to locate the next entry. (Otherwise, + * SIOCGIFFLAGS stomps over it because the requests + * are returned in a union.) + */ + bcopy(ifrp->ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { + fprintf(stderr, "tcpdump: SIOCGIFFLAGS: "); + perror(ifrp->ifr_name); + exit(1); + } + if ((ifr.ifr_flags & IFF_UP) && !ISLOOPBACK(&ifr)) { + for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp) + ; + n = atoi(cp); + if (n < minunit) { + minunit = n; + mp = ifrp; + } + } +#if BSD >= 199006 + n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); + if (n < sizeof(*ifrp)) + ++ifrp; + else + ifrp = (struct ifreq *)((char *)ifrp + n); +#else + ++ifrp; +#endif + } + close(fd); + if (mp == 0) + return (0); + + (void)strcpy(device, mp->ifr_name); + return (device); +} + +/* + * Get the netmask of an IP address. This routine is used if + * SIOCGIFNETMASK doesn't work. + */ +static u_long +ipaddrtonetmask(addr) + u_long addr; +{ + if (IN_CLASSA(addr)) + return (IN_CLASSA_NET); + if (IN_CLASSB(addr)) + return (IN_CLASSB_NET); + if (IN_CLASSC(addr)) + return (IN_CLASSC_NET); + error("unknown IP address class: %08X", addr); + /* NOTREACHED */ +} + +void +lookup_net(device, netp, maskp) + char *device; + u_long *netp; + u_long *maskp; +{ + int fd; + struct ifreq ifr; + struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; + + /* Use data gram socket to get IP address. */ + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("tcpdump: socket"); + exit(1); + } + (void)strncpy(ifr.ifr_name, device, sizeof ifr.ifr_name); + if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) { + /* + * This will fail if an IP address hasn't been assigned. + */ + *netp = 0; + *maskp = 0; + return; + } + *netp = sin->sin_addr.s_addr; + if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) + *maskp = 0; + else + *maskp = sin->sin_addr.s_addr; + if (*maskp == 0) + *maskp = ipaddrtonetmask(*netp); + *netp &= *maskp; + (void)close(fd); +} diff --git a/usr.sbin/tcpdump/tcpdump/interface.h b/usr.sbin/tcpdump/tcpdump/interface.h new file mode 100644 index 000000000000..dfccba6e6730 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/interface.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#) $Header: interface.h,v 1.46 92/06/02 17:57:22 mccanne Exp $ (LBL) + */ + +#ifdef __GNUC__ +#define inline __inline +#else +#define inline +#endif + +#include "os.h" /* operating system stuff */ +#include "md.h" /* machine dependent stuff */ + +#ifndef __STDC__ +extern char *malloc(); +extern char *calloc(); +#endif + +extern int dflag; /* print filter code */ +extern int eflag; /* print ethernet header */ +extern int nflag; /* leave addresses as numbers */ +extern int Nflag; /* remove domains from printed host names */ +extern int qflag; /* quick (shorter) output */ +extern int Sflag; /* print raw TCP sequence numbers */ +extern int tflag; /* print packet arrival time */ +extern int vflag; /* verbose */ +extern int xflag; /* print packet in hex */ + +extern char *program_name; /* used to generate self-identifying messages */ + +extern int snaplen; +/* global pointers to beginning and end of current packet (during printing) */ +extern unsigned char *packetp; +extern unsigned char *snapend; + +extern long thiszone; /* gmt to local correction */ + +extern void ts_print(); +extern int clock_sigfigs(); + +extern char *lookup_device(); + +extern void error(); +extern void warning(); + +extern char *read_infile(); +extern char *copy_argv(); + +extern void usage(); +extern void show_code(); +extern void init_addrtoname(); + +/* The printer routines. */ + +extern void ether_if_print(); +extern void arp_print(); +extern void ip_print(); +extern void tcp_print(); +extern void udp_print(); +extern void icmp_print(); +extern void default_print(); + +extern void ntp_print(); +extern void nfsreq_print(); +extern void nfsreply_print(); +extern void ns_print(); +extern void ddp_print(); +extern void rip_print(); +extern void tftp_print(); +extern void bootp_print(); +extern void snmp_print(); +extern void sl_if_print(); +extern void ppp_if_print(); +extern void fddi_if_print(); +extern void null_if_print(); +extern void egp_print(); + +#define min(a,b) ((a)>(b)?(b):(a)) +#define max(a,b) ((b)>(a)?(b):(a)) + +/* + * The default snapshot length. This value allows most printers to print + * useful information while keeping the amount of unwanted data down. + * In particular, it allows for an ethernet header, tcp/ip header, and + * 14 bytes of data (assuming no ip options). + */ +#define DEFAULT_SNAPLEN 68 + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 +#define LITTLE_ENDIAN 1234 +#endif diff --git a/usr.sbin/tcpdump/tcpdump/md.c b/usr.sbin/tcpdump/tcpdump/md.c new file mode 100644 index 000000000000..6bb04b72cade --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/md.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#) $Header: md-vax.c,v 1.3 90/10/03 14:14:33 mccanne Locked $ (LBL)"; +#endif + +/* Vaxen appear to have clocks accurate to 1 us, + but packetfilter is timestamping to 10 ms. */ + +int +clock_sigfigs() +{ + return 2; +} + diff --git a/usr.sbin/tcpdump/tcpdump/md.h b/usr.sbin/tcpdump/tcpdump/md.h new file mode 100644 index 000000000000..f83d81fcf0e0 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/md.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#) $Header: md-vax.h,v 1.2 90/09/21 02:23:16 mccanne Exp $ (LBL) + */ + +#ifndef BYTE_ORDER +#define BYTE_ORDER LITTLE_ENDIAN +#endif + +/* These should be fixed to be real macros, for speed */ + +#ifndef NTOHL +#define NTOHL(x) (x) = ntohl(x) +#define NTOHS(x) (x) = ntohs(x) +#define HTONL(x) (x) = htonl(x) +#define HTONS(x) (x) = htons(x) +#endif + +#ifndef vax +/* Some Ultrix header files may need this */ +#define vax 1 +#endif vax diff --git a/usr.sbin/tcpdump/tcpdump/mib.h b/usr.sbin/tcpdump/tcpdump/mib.h new file mode 100644 index 000000000000..a81897ce8b2a --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/mib.h @@ -0,0 +1,1256 @@ +/* + * This file was generated by tcpdump/makemib on Wed Sep 26 12:12:31 EDT 1990 + * You probably don't want to edit this by hand! + * + * struct mib somename = { desc, oid-octet, type, child-pointer, next-pointer +}; + */ + +/* parse problem: new name "mib" for mgmt.mib(1) ignored */ +/* parse problem: no parent for 0.nullSpecific(0) */ +struct obj +_proteon_obj = { + "proteon", 1, 0, + NULL, NULL +}, +_ibm_obj = { + "ibm", 2, 0, + NULL, &_proteon_obj +}, +_cmu_obj = { + "cmu", 3, 0, + NULL, &_ibm_obj +}, +_unix_obj = { + "unix", 4, 0, + NULL, &_cmu_obj +}, +_acc_obj = { + "acc", 5, 0, + NULL, &_unix_obj +}, +_twg_obj = { + "twg", 6, 0, + NULL, &_acc_obj +}, +_cayman_obj = { + "cayman", 7, 0, + NULL, &_twg_obj +}, +_nysernet_obj = { + "nysernet", 8, 0, + NULL, &_cayman_obj +}, +_cisco_obj = { + "cisco", 9, 0, + NULL, &_nysernet_obj +}, +_nsc_obj = { + "nsc", 10, 0, + NULL, &_cisco_obj +}, +_hp_obj = { + "hp", 11, 0, + NULL, &_nsc_obj +}, +_epilogue_obj = { + "epilogue", 12, 0, + NULL, &_hp_obj +}, +_utennessee_obj = { + "utennessee", 13, 0, + NULL, &_epilogue_obj +}, +_bbn_obj = { + "bbn", 14, 0, + NULL, &_utennessee_obj +}, +_xylogics_obj = { + "xylogics", 15, 0, + NULL, &_bbn_obj +}, +_unisys_obj = { + "unisys", 16, 0, + NULL, &_xylogics_obj +}, +_canstar_obj = { + "canstar", 17, 0, + NULL, &_unisys_obj +}, +_wellfleet_obj = { + "wellfleet", 18, 0, + NULL, &_canstar_obj +}, +_trw_obj = { + "trw", 19, 0, + NULL, &_wellfleet_obj +}, +_mit_obj = { + "mit", 20, 0, + NULL, &_trw_obj +}, +_eon_obj = { + "eon", 21, 0, + NULL, &_mit_obj +}, +_spartacus_obj = { + "spartacus", 22, 0, + NULL, &_eon_obj +}, +_excelan_obj = { + "excelan", 23, 0, + NULL, &_spartacus_obj +}, +_spider_obj = { + "spider", 24, 0, + NULL, &_excelan_obj +}, +_nsfnet_obj = { + "nsfnet", 25, 0, + NULL, &_spider_obj +}, +_sytek_obj = { + "sytek", 26, 0, + NULL, &_nsfnet_obj +}, +_intergraph_obj = { + "intergraph", 27, 0, + NULL, &_sytek_obj +}, +_interlan_obj = { + "interlan", 28, 0, + NULL, &_intergraph_obj +}, +_vitalink_obj = { + "vitalink", 29, 0, + NULL, &_interlan_obj +}, +_ulana_obj = { + "ulana", 30, 0, + NULL, &_vitalink_obj +}, +_nswc_obj = { + "nswc", 31, 0, + NULL, &_ulana_obj +}, +_santacruzoperation_obj = { + "santacruzoperation", 32, 0, + NULL, &_nswc_obj +}, +_xyplex_obj = { + "xyplex", 33, 0, + NULL, &_santacruzoperation_obj +}, +_cray_obj = { + "cray", 34, 0, + NULL, &_xyplex_obj +}, +_bellnorthernresearch_obj = { + "bellnorthernresearch", 35, 0, + NULL, &_cray_obj +}, +_dec_obj = { + "dec", 36, 0, + NULL, &_bellnorthernresearch_obj +}, +_touch_obj = { + "touch", 37, 0, + NULL, &_dec_obj +}, +_networkresearchcorp_obj = { + "networkresearchcorp", 38, 0, + NULL, &_touch_obj +}, +_baylor_obj = { + "baylor", 39, 0, + NULL, &_networkresearchcorp_obj +}, +_nmfeccllnl_obj = { + "nmfeccllnl", 40, 0, + NULL, &_baylor_obj +}, +_sri_obj = { + "sri", 41, 0, + NULL, &_nmfeccllnl_obj +}, +_sun_obj = { + "sun", 42, 0, + NULL, &_sri_obj +}, +_3com_obj = { + "3com", 43, 0, + NULL, &_sun_obj +}, +_cmc_obj = { + "cmc", 44, 0, + NULL, &_3com_obj +}, +_synoptics_obj = { + "synoptics", 45, 0, + NULL, &_cmc_obj +}, +_cheyenne_obj = { + "cheyenne", 46, 0, + NULL, &_synoptics_obj +}, +_prime_obj = { + "prime", 47, 0, + NULL, &_cheyenne_obj +}, +_mcnc_obj = { + "mcnc", 48, 0, + NULL, &_prime_obj +}, +_chipcom_obj = { + "chipcom", 49, 0, + NULL, &_mcnc_obj +}, +_opticaldatasystems_obj = { + "opticaldatasystems", 50, 0, + NULL, &_chipcom_obj +}, +_gated_obj = { + "gated", 51, 0, + NULL, &_opticaldatasystems_obj +}, +_cabletron_obj = { + "cabletron", 52, 0, + NULL, &_gated_obj +}, +_apollo_obj = { + "apollo", 53, 0, + NULL, &_cabletron_obj +}, +_desktalksystems_obj = { + "desktalksystems", 54, 0, + NULL, &_apollo_obj +}, +_ssds_obj = { + "ssds", 55, 0, + NULL, &_desktalksystems_obj +}, +_castlerock_obj = { + "castlerock", 56, 0, + NULL, &_ssds_obj +}, +_mips_obj = { + "mips", 57, 0, + NULL, &_castlerock_obj +}, +_tgv_obj = { + "tgv", 58, 0, + NULL, &_mips_obj +}, +_silicongraphics_obj = { + "silicongraphics", 59, 0, + NULL, &_tgv_obj +}, +_ubc_obj = { + "ubc", 60, 0, + NULL, &_silicongraphics_obj +}, +_merit_obj = { + "merit", 61, 0, + NULL, &_ubc_obj +}, +_fibercom_obj = { + "fibercom", 62, 0, + NULL, &_merit_obj +}, +_apple_obj = { + "apple", 63, 0, + NULL, &_fibercom_obj +}, +_gandalf_obj = { + "gandalf", 64, 0, + NULL, &_apple_obj +}, +_dartmouth_obj = { + "dartmouth", 65, 0, + NULL, &_gandalf_obj +}, +_davidsystems_obj = { + "davidsystems", 66, 0, + NULL, &_dartmouth_obj +}, +_reuter_obj = { + "reuter", 67, 0, + NULL, &_davidsystems_obj +}, +_cornell_obj = { + "cornell", 68, 0, + NULL, &_reuter_obj +}, +_tmac_obj = { + "tmac", 69, 0, + NULL, &_cornell_obj +}, +_locus_obj = { + "locus", 70, 0, + NULL, &_tmac_obj +}, +_nasa_obj = { + "nasa", 71, 0, + NULL, &_locus_obj +}, +_retix_obj = { + "retix", 72, 0, + NULL, &_nasa_obj +}, +_boeing_obj = { + "boeing", 73, 0, + NULL, &_retix_obj +}, +_att_obj = { + "att", 74, 0, + NULL, &_boeing_obj +}, +_ungermannbass_obj = { + "ungermannbass", 75, 0, + NULL, &_att_obj +}, +_digitalanalysis_obj = { + "digitalanalysis", 76, 0, + NULL, &_ungermannbass_obj +}, +_hplanman_obj = { + "hplanman", 77, 0, + NULL, &_digitalanalysis_obj +}, +_netlabs_obj = { + "netlabs", 78, 0, + NULL, &_hplanman_obj +}, +_icl_obj = { + "icl", 79, 0, + NULL, &_netlabs_obj +}, +_auspex_obj = { + "auspex", 80, 0, + NULL, &_icl_obj +}, +_lannet_obj = { + "lannet", 81, 0, + NULL, &_auspex_obj +}, +_ncd_obj = { + "ncd", 82, 0, + NULL, &_lannet_obj +}, +_raycom_obj = { + "raycom", 83, 0, + NULL, &_ncd_obj +}, +_pirellifocom_obj = { + "pirellifocom", 84, 0, + NULL, &_raycom_obj +}, +_datability_obj = { + "datability", 85, 0, + NULL, &_pirellifocom_obj +}, +_networkappltech_obj = { + "networkappltech", 86, 0, + NULL, &_datability_obj +}, +_link_obj = { + "link", 87, 0, + NULL, &_networkappltech_obj +}, +_nyu_obj = { + "nyu", 88, 0, + NULL, &_link_obj +}, +_rnd_obj = { + "rnd", 89, 0, + NULL, &_nyu_obj +}, +_intercon_obj = { + "intercon", 90, 0, + NULL, &_rnd_obj +}, +_learningtree_obj = { + "learningtree", 91, 0, + NULL, &_intercon_obj +}, +_webstercomputer_obj = { + "webstercomputer", 92, 0, + NULL, &_learningtree_obj +}, +_frontier_obj = { + "frontier", 93, 0, + NULL, &_webstercomputer_obj +}, +_nokia_obj = { + "nokia", 94, 0, + NULL, &_frontier_obj +}, +_allenbradley_obj = { + "allenbradley", 95, 0, + NULL, &_nokia_obj +}, +_cern_obj = { + "cern", 96, 0, + NULL, &_allenbradley_obj +}, +_sigma_obj = { + "sigma", 97, 0, + NULL, &_cern_obj +}, +_emergingtech_obj = { + "emergingtech", 98, 0, + NULL, &_sigma_obj +}, +_snmpresearch_obj = { + "snmpresearch", 99, 0, + NULL, &_emergingtech_obj +}, +_ohiostate_obj = { + "ohiostate", 100, 0, + NULL, &_snmpresearch_obj +}, +_ultra_obj = { + "ultra", 101, 0, + NULL, &_ohiostate_obj +}, +_ccur_obj = { + "ccur", 136, 0, + NULL, &_ultra_obj +}, +_enterprises_obj = { + "enterprises", 1, 0, + &_ccur_obj, NULL +}, +_snmpInPkts_obj = { + "snmpInPkts", 1, 0, + NULL, NULL +}, +_snmpOutPkts_obj = { + "snmpOutPkts", 2, 0, + NULL, &_snmpInPkts_obj +}, +_snmpInBadVersions_obj = { + "snmpInBadVersions", 3, 0, + NULL, &_snmpOutPkts_obj +}, +_snmpInBadCommunityNames_obj = { + "snmpInBadCommunityNames", 4, 0, + NULL, &_snmpInBadVersions_obj +}, +_snmpInBadCommunityUses_obj = { + "snmpInBadCommunityUses", 5, 0, + NULL, &_snmpInBadCommunityNames_obj +}, +_snmpInASNParseErrs_obj = { + "snmpInASNParseErrs", 6, 0, + NULL, &_snmpInBadCommunityUses_obj +}, +_snmpInBadTypes_obj = { + "snmpInBadTypes", 7, 0, + NULL, &_snmpInASNParseErrs_obj +}, +_snmpInTooBigs_obj = { + "snmpInTooBigs", 8, 0, + NULL, &_snmpInBadTypes_obj +}, +_snmpInNoSuchNames_obj = { + "snmpInNoSuchNames", 9, 0, + NULL, &_snmpInTooBigs_obj +}, +_snmpInBadValues_obj = { + "snmpInBadValues", 10, 0, + NULL, &_snmpInNoSuchNames_obj +}, +_snmpInReadOnlys_obj = { + "snmpInReadOnlys", 11, 0, + NULL, &_snmpInBadValues_obj +}, +_snmpInGenErrs_obj = { + "snmpInGenErrs", 12, 0, + NULL, &_snmpInReadOnlys_obj +}, +_snmpInTotalReqVars_obj = { + "snmpInTotalReqVars", 13, 0, + NULL, &_snmpInGenErrs_obj +}, +_snmpInTotalSetVars_obj = { + "snmpInTotalSetVars", 14, 0, + NULL, &_snmpInTotalReqVars_obj +}, +_snmpInGetRequests_obj = { + "snmpInGetRequests", 15, 0, + NULL, &_snmpInTotalSetVars_obj +}, +_snmpInGetNexts_obj = { + "snmpInGetNexts", 16, 0, + NULL, &_snmpInGetRequests_obj +}, +_snmpInSetRequests_obj = { + "snmpInSetRequests", 17, 0, + NULL, &_snmpInGetNexts_obj +}, +_snmpInGetResponses_obj = { + "snmpInGetResponses", 18, 0, + NULL, &_snmpInSetRequests_obj +}, +_snmpInTraps_obj = { + "snmpInTraps", 19, 0, + NULL, &_snmpInGetResponses_obj +}, +_snmpOutTooBigs_obj = { + "snmpOutTooBigs", 20, 0, + NULL, &_snmpInTraps_obj +}, +_snmpOutNoSuchNames_obj = { + "snmpOutNoSuchNames", 21, 0, + NULL, &_snmpOutTooBigs_obj +}, +_snmpOutBadValues_obj = { + "snmpOutBadValues", 22, 0, + NULL, &_snmpOutNoSuchNames_obj +}, +_snmpOutReadOnlys_obj = { + "snmpOutReadOnlys", 23, 0, + NULL, &_snmpOutBadValues_obj +}, +_snmpOutGenErrs_obj = { + "snmpOutGenErrs", 24, 0, + NULL, &_snmpOutReadOnlys_obj +}, +_snmpOutGetRequests_obj = { + "snmpOutGetRequests", 25, 0, + NULL, &_snmpOutGenErrs_obj +}, +_snmpOutGetNexts_obj = { + "snmpOutGetNexts", 26, 0, + NULL, &_snmpOutGetRequests_obj +}, +_snmpOutSetRequests_obj = { + "snmpOutSetRequests", 27, 0, + NULL, &_snmpOutGetNexts_obj +}, +_snmpOutGetResponses_obj = { + "snmpOutGetResponses", 28, 0, + NULL, &_snmpOutSetRequests_obj +}, +_snmpOutTraps_obj = { + "snmpOutTraps", 29, 0, + NULL, &_snmpOutGetResponses_obj +}, +_snmpEnableAuthTraps_obj = { + "snmpEnableAuthTraps", 30, 0, + NULL, &_snmpOutTraps_obj +}, +_egpNeighState_obj = { + "egpNeighState", 1, 0, + NULL, NULL +}, +_egpNeighAddr_obj = { + "egpNeighAddr", 2, 0, + NULL, &_egpNeighState_obj +}, +_egpNeighAs_obj = { + "egpNeighAs", 3, 0, + NULL, &_egpNeighAddr_obj +}, +_egpNeighInMsgs_obj = { + "egpNeighInMsgs", 4, 0, + NULL, &_egpNeighAs_obj +}, +_egpNeighInErrs_obj = { + "egpNeighInErrs", 5, 0, + NULL, &_egpNeighInMsgs_obj +}, +_egpNeighOutMsgs_obj = { + "egpNeighOutMsgs", 6, 0, + NULL, &_egpNeighInErrs_obj +}, +_egpNeighOutErrs_obj = { + "egpNeighOutErrs", 7, 0, + NULL, &_egpNeighOutMsgs_obj +}, +_egpNeighInErrMsgs_obj = { + "egpNeighInErrMsgs", 8, 0, + NULL, &_egpNeighOutErrs_obj +}, +_egpNeighOutErrMsgs_obj = { + "egpNeighOutErrMsgs", 9, 0, + NULL, &_egpNeighInErrMsgs_obj +}, +_egpNeighStateUps_obj = { + "egpNeighStateUps", 10, 0, + NULL, &_egpNeighOutErrMsgs_obj +}, +_egpNeighStateDowns_obj = { + "egpNeighStateDowns", 11, 0, + NULL, &_egpNeighStateUps_obj +}, +_egpNeighIntervalHello_obj = { + "egpNeighIntervalHello", 12, 0, + NULL, &_egpNeighStateDowns_obj +}, +_egpNeighIntervalPoll_obj = { + "egpNeighIntervalPoll", 13, 0, + NULL, &_egpNeighIntervalHello_obj +}, +_egpNeighMode_obj = { + "egpNeighMode", 14, 0, + NULL, &_egpNeighIntervalPoll_obj +}, +_egpNeighEventTrigger_obj = { + "egpNeighEventTrigger", 15, 0, + NULL, &_egpNeighMode_obj +}, +_egpNeighEntry_obj = { + "egpNeighEntry", 1, 0, + &_egpNeighEventTrigger_obj, NULL +}, +_egpInMsgs_obj = { + "egpInMsgs", 1, 0, + NULL, NULL +}, +_egpInErrors_obj = { + "egpInErrors", 2, 0, + NULL, &_egpInMsgs_obj +}, +_egpOutMsgs_obj = { + "egpOutMsgs", 3, 0, + NULL, &_egpInErrors_obj +}, +_egpOutErrors_obj = { + "egpOutErrors", 4, 0, + NULL, &_egpOutMsgs_obj +}, +_egpNeighTable_obj = { + "egpNeighTable", 5, 0, + &_egpNeighEntry_obj, &_egpOutErrors_obj +}, +_egpAs_obj = { + "egpAs", 6, 0, + NULL, &_egpNeighTable_obj +}, +_udpLocalAddress_obj = { + "udpLocalAddress", 1, 0, + NULL, NULL +}, +_udpLocalPort_obj = { + "udpLocalPort", 2, 0, + NULL, &_udpLocalAddress_obj +}, +_udpEntry_obj = { + "udpEntry", 1, 0, + &_udpLocalPort_obj, NULL +}, +_udpInDatagrams_obj = { + "udpInDatagrams", 1, 0, + NULL, NULL +}, +_udpNoPorts_obj = { + "udpNoPorts", 2, 0, + NULL, &_udpInDatagrams_obj +}, +_udpInErrors_obj = { + "udpInErrors", 3, 0, + NULL, &_udpNoPorts_obj +}, +_udpOutDatagrams_obj = { + "udpOutDatagrams", 4, 0, + NULL, &_udpInErrors_obj +}, +_udpTable_obj = { + "udpTable", 5, 0, + &_udpEntry_obj, &_udpOutDatagrams_obj +}, +_tcpConnState_obj = { + "tcpConnState", 1, 0, + NULL, NULL +}, +_tcpConnLocalAddress_obj = { + "tcpConnLocalAddress", 2, 0, + NULL, &_tcpConnState_obj +}, +_tcpConnLocalPort_obj = { + "tcpConnLocalPort", 3, 0, + NULL, &_tcpConnLocalAddress_obj +}, +_tcpConnRemAddress_obj = { + "tcpConnRemAddress", 4, 0, + NULL, &_tcpConnLocalPort_obj +}, +_tcpConnRemPort_obj = { + "tcpConnRemPort", 5, 0, + NULL, &_tcpConnRemAddress_obj +}, +_tcpConnEntry_obj = { + "tcpConnEntry", 1, 0, + &_tcpConnRemPort_obj, NULL +}, +_tcpRtoAlgorithm_obj = { + "tcpRtoAlgorithm", 1, 0, + NULL, NULL +}, +_tcpRtoMin_obj = { + "tcpRtoMin", 2, 0, + NULL, &_tcpRtoAlgorithm_obj +}, +_tcpRtoMax_obj = { + "tcpRtoMax", 3, 0, + NULL, &_tcpRtoMin_obj +}, +_tcpMaxConn_obj = { + "tcpMaxConn", 4, 0, + NULL, &_tcpRtoMax_obj +}, +_tcpActiveOpens_obj = { + "tcpActiveOpens", 5, 0, + NULL, &_tcpMaxConn_obj +}, +_tcpPassiveOpens_obj = { + "tcpPassiveOpens", 6, 0, + NULL, &_tcpActiveOpens_obj +}, +_tcpAttemptFails_obj = { + "tcpAttemptFails", 7, 0, + NULL, &_tcpPassiveOpens_obj +}, +_tcpEstabResets_obj = { + "tcpEstabResets", 8, 0, + NULL, &_tcpAttemptFails_obj +}, +_tcpCurrEstab_obj = { + "tcpCurrEstab", 9, 0, + NULL, &_tcpEstabResets_obj +}, +_tcpInSegs_obj = { + "tcpInSegs", 10, 0, + NULL, &_tcpCurrEstab_obj +}, +_tcpOutSegs_obj = { + "tcpOutSegs", 11, 0, + NULL, &_tcpInSegs_obj +}, +_tcpRetransSegs_obj = { + "tcpRetransSegs", 12, 0, + NULL, &_tcpOutSegs_obj +}, +_tcpConnTable_obj = { + "tcpConnTable", 13, 0, + &_tcpConnEntry_obj, &_tcpRetransSegs_obj +}, +_tcpInErrs_obj = { + "tcpInErrs", 14, 0, + NULL, &_tcpConnTable_obj +}, +_tcpOutRsts_obj = { + "tcpOutRsts", 15, 0, + NULL, &_tcpInErrs_obj +}, +_icmpInMsgs_obj = { + "icmpInMsgs", 1, 0, + NULL, NULL +}, +_icmpInErrors_obj = { + "icmpInErrors", 2, 0, + NULL, &_icmpInMsgs_obj +}, +_icmpInDestUnreachs_obj = { + "icmpInDestUnreachs", 3, 0, + NULL, &_icmpInErrors_obj +}, +_icmpInTimeExcds_obj = { + "icmpInTimeExcds", 4, 0, + NULL, &_icmpInDestUnreachs_obj +}, +_icmpInParmProbs_obj = { + "icmpInParmProbs", 5, 0, + NULL, &_icmpInTimeExcds_obj +}, +_icmpInSrcQuenchs_obj = { + "icmpInSrcQuenchs", 6, 0, + NULL, &_icmpInParmProbs_obj +}, +_icmpInRedirects_obj = { + "icmpInRedirects", 7, 0, + NULL, &_icmpInSrcQuenchs_obj +}, +_icmpInEchos_obj = { + "icmpInEchos", 8, 0, + NULL, &_icmpInRedirects_obj +}, +_icmpInEchoReps_obj = { + "icmpInEchoReps", 9, 0, + NULL, &_icmpInEchos_obj +}, +_icmpInTimestamps_obj = { + "icmpInTimestamps", 10, 0, + NULL, &_icmpInEchoReps_obj +}, +_icmpInTimestampReps_obj = { + "icmpInTimestampReps", 11, 0, + NULL, &_icmpInTimestamps_obj +}, +_icmpInAddrMasks_obj = { + "icmpInAddrMasks", 12, 0, + NULL, &_icmpInTimestampReps_obj +}, +_icmpInAddrMaskReps_obj = { + "icmpInAddrMaskReps", 13, 0, + NULL, &_icmpInAddrMasks_obj +}, +_icmpOutMsgs_obj = { + "icmpOutMsgs", 14, 0, + NULL, &_icmpInAddrMaskReps_obj +}, +_icmpOutErrors_obj = { + "icmpOutErrors", 15, 0, + NULL, &_icmpOutMsgs_obj +}, +_icmpOutDestUnreachs_obj = { + "icmpOutDestUnreachs", 16, 0, + NULL, &_icmpOutErrors_obj +}, +_icmpOutTimeExcds_obj = { + "icmpOutTimeExcds", 17, 0, + NULL, &_icmpOutDestUnreachs_obj +}, +_icmpOutParmProbs_obj = { + "icmpOutParmProbs", 18, 0, + NULL, &_icmpOutTimeExcds_obj +}, +_icmpOutSrcQuenchs_obj = { + "icmpOutSrcQuenchs", 19, 0, + NULL, &_icmpOutParmProbs_obj +}, +_icmpOutRedirects_obj = { + "icmpOutRedirects", 20, 0, + NULL, &_icmpOutSrcQuenchs_obj +}, +_icmpOutEchos_obj = { + "icmpOutEchos", 21, 0, + NULL, &_icmpOutRedirects_obj +}, +_icmpOutEchoReps_obj = { + "icmpOutEchoReps", 22, 0, + NULL, &_icmpOutEchos_obj +}, +_icmpOutTimestamps_obj = { + "icmpOutTimestamps", 23, 0, + NULL, &_icmpOutEchoReps_obj +}, +_icmpOutTimestampReps_obj = { + "icmpOutTimestampReps", 24, 0, + NULL, &_icmpOutTimestamps_obj +}, +_icmpOutAddrMasks_obj = { + "icmpOutAddrMasks", 25, 0, + NULL, &_icmpOutTimestampReps_obj +}, +_icmpOutAddrMaskReps_obj = { + "icmpOutAddrMaskReps", 26, 0, + NULL, &_icmpOutAddrMasks_obj +}, +_ipNetToMediaIfIndex_obj = { + "ipNetToMediaIfIndex", 1, 0, + NULL, NULL +}, +_ipNetToMediaPhysAddress_obj = { + "ipNetToMediaPhysAddress", 2, 0, + NULL, &_ipNetToMediaIfIndex_obj +}, +_ipNetToMediaNetAddress_obj = { + "ipNetToMediaNetAddress", 3, 0, + NULL, &_ipNetToMediaPhysAddress_obj +}, +_ipNetToMediaType_obj = { + "ipNetToMediaType", 4, 0, + NULL, &_ipNetToMediaNetAddress_obj +}, +_ipNetToMediaEntry_obj = { + "ipNetToMediaEntry", 1, 0, + &_ipNetToMediaType_obj, NULL +}, +_ipRouteDest_obj = { + "ipRouteDest", 1, 0, + NULL, NULL +}, +_ipRouteIfIndex_obj = { + "ipRouteIfIndex", 2, 0, + NULL, &_ipRouteDest_obj +}, +_ipRouteMetric1_obj = { + "ipRouteMetric1", 3, 0, + NULL, &_ipRouteIfIndex_obj +}, +_ipRouteMetric2_obj = { + "ipRouteMetric2", 4, 0, + NULL, &_ipRouteMetric1_obj +}, +_ipRouteMetric3_obj = { + "ipRouteMetric3", 5, 0, + NULL, &_ipRouteMetric2_obj +}, +_ipRouteMetric4_obj = { + "ipRouteMetric4", 6, 0, + NULL, &_ipRouteMetric3_obj +}, +_ipRouteNextHop_obj = { + "ipRouteNextHop", 7, 0, + NULL, &_ipRouteMetric4_obj +}, +_ipRouteType_obj = { + "ipRouteType", 8, 0, + NULL, &_ipRouteNextHop_obj +}, +_ipRouteProto_obj = { + "ipRouteProto", 9, 0, + NULL, &_ipRouteType_obj +}, +_ipRouteAge_obj = { + "ipRouteAge", 10, 0, + NULL, &_ipRouteProto_obj +}, +_ipRouteMask_obj = { + "ipRouteMask", 11, 0, + NULL, &_ipRouteAge_obj +}, +_ipRouteEntry_obj = { + "ipRouteEntry", 1, 0, + &_ipRouteMask_obj, NULL +}, +_ipAdEntAddr_obj = { + "ipAdEntAddr", 1, 0, + NULL, NULL +}, +_ipAdEntIfIndex_obj = { + "ipAdEntIfIndex", 2, 0, + NULL, &_ipAdEntAddr_obj +}, +_ipAdEntNetMask_obj = { + "ipAdEntNetMask", 3, 0, + NULL, &_ipAdEntIfIndex_obj +}, +_ipAdEntBcastAddr_obj = { + "ipAdEntBcastAddr", 4, 0, + NULL, &_ipAdEntNetMask_obj +}, +_ipAdEntReasmMaxSize_obj = { + "ipAdEntReasmMaxSize", 5, 0, + NULL, &_ipAdEntBcastAddr_obj +}, +_ipAddrEntry_obj = { + "ipAddrEntry", 1, 0, + &_ipAdEntReasmMaxSize_obj, NULL +}, +_ipForwarding_obj = { + "ipForwarding", 1, 0, + NULL, NULL +}, +_ipDefaultTTL_obj = { + "ipDefaultTTL", 2, 0, + NULL, &_ipForwarding_obj +}, +_ipInReceives_obj = { + "ipInReceives", 3, 0, + NULL, &_ipDefaultTTL_obj +}, +_ipInHdrErrors_obj = { + "ipInHdrErrors", 4, 0, + NULL, &_ipInReceives_obj +}, +_ipInAddrErrors_obj = { + "ipInAddrErrors", 5, 0, + NULL, &_ipInHdrErrors_obj +}, +_ipForwDatagrams_obj = { + "ipForwDatagrams", 6, 0, + NULL, &_ipInAddrErrors_obj +}, +_ipInUnknownProtos_obj = { + "ipInUnknownProtos", 7, 0, + NULL, &_ipForwDatagrams_obj +}, +_ipInDiscards_obj = { + "ipInDiscards", 8, 0, + NULL, &_ipInUnknownProtos_obj +}, +_ipInDelivers_obj = { + "ipInDelivers", 9, 0, + NULL, &_ipInDiscards_obj +}, +_ipOutRequests_obj = { + "ipOutRequests", 10, 0, + NULL, &_ipInDelivers_obj +}, +_ipOutDiscards_obj = { + "ipOutDiscards", 11, 0, + NULL, &_ipOutRequests_obj +}, +_ipOutNoRoutes_obj = { + "ipOutNoRoutes", 12, 0, + NULL, &_ipOutDiscards_obj +}, +_ipReasmTimeout_obj = { + "ipReasmTimeout", 13, 0, + NULL, &_ipOutNoRoutes_obj +}, +_ipReasmReqds_obj = { + "ipReasmReqds", 14, 0, + NULL, &_ipReasmTimeout_obj +}, +_ipReasmOKs_obj = { + "ipReasmOKs", 15, 0, + NULL, &_ipReasmReqds_obj +}, +_ipReasmFails_obj = { + "ipReasmFails", 16, 0, + NULL, &_ipReasmOKs_obj +}, +_ipFragOKs_obj = { + "ipFragOKs", 17, 0, + NULL, &_ipReasmFails_obj +}, +_ipFragFails_obj = { + "ipFragFails", 18, 0, + NULL, &_ipFragOKs_obj +}, +_ipFragCreates_obj = { + "ipFragCreates", 19, 0, + NULL, &_ipFragFails_obj +}, +_ipAddrTable_obj = { + "ipAddrTable", 20, 0, + &_ipAddrEntry_obj, &_ipFragCreates_obj +}, +_ipRoutingTable_obj = { + "ipRoutingTable", 21, 0, + &_ipRouteEntry_obj, &_ipAddrTable_obj +}, +_ipNetToMediaTable_obj = { + "ipNetToMediaTable", 22, 0, + &_ipNetToMediaEntry_obj, &_ipRoutingTable_obj +}, +_atIfIndex_obj = { + "atIfIndex", 1, 0, + NULL, NULL +}, +_atPhysAddress_obj = { + "atPhysAddress", 2, 0, + NULL, &_atIfIndex_obj +}, +_atNetAddress_obj = { + "atNetAddress", 3, 0, + NULL, &_atPhysAddress_obj +}, +_atEntry_obj = { + "atEntry", 1, 0, + &_atNetAddress_obj, NULL +}, +_atTable_obj = { + "atTable", 1, 0, + &_atEntry_obj, NULL +}, +_ifIndex_obj = { + "ifIndex", 1, 0, + NULL, NULL +}, +_ifDescr_obj = { + "ifDescr", 2, 0, + NULL, &_ifIndex_obj +}, +_ifType_obj = { + "ifType", 3, 0, + NULL, &_ifDescr_obj +}, +_ifMtu_obj = { + "ifMtu", 4, 0, + NULL, &_ifType_obj +}, +_ifSpeed_obj = { + "ifSpeed", 5, 0, + NULL, &_ifMtu_obj +}, +_ifPhysAddress_obj = { + "ifPhysAddress", 6, 0, + NULL, &_ifSpeed_obj +}, +_ifAdminStatus_obj = { + "ifAdminStatus", 7, 0, + NULL, &_ifPhysAddress_obj +}, +_ifOperStatus_obj = { + "ifOperStatus", 8, 0, + NULL, &_ifAdminStatus_obj +}, +_ifLastChange_obj = { + "ifLastChange", 9, 0, + NULL, &_ifOperStatus_obj +}, +_ifInOctets_obj = { + "ifInOctets", 10, 0, + NULL, &_ifLastChange_obj +}, +_ifInUcastPkts_obj = { + "ifInUcastPkts", 11, 0, + NULL, &_ifInOctets_obj +}, +_ifInNUcastPkts_obj = { + "ifInNUcastPkts", 12, 0, + NULL, &_ifInUcastPkts_obj +}, +_ifInDiscards_obj = { + "ifInDiscards", 13, 0, + NULL, &_ifInNUcastPkts_obj +}, +_ifInErrors_obj = { + "ifInErrors", 14, 0, + NULL, &_ifInDiscards_obj +}, +_ifInUnknownProtos_obj = { + "ifInUnknownProtos", 15, 0, + NULL, &_ifInErrors_obj +}, +_ifOutOctets_obj = { + "ifOutOctets", 16, 0, + NULL, &_ifInUnknownProtos_obj +}, +_ifOutUcastPkts_obj = { + "ifOutUcastPkts", 17, 0, + NULL, &_ifOutOctets_obj +}, +_ifOutNUcastPkts_obj = { + "ifOutNUcastPkts", 18, 0, + NULL, &_ifOutUcastPkts_obj +}, +_ifOutDiscards_obj = { + "ifOutDiscards", 19, 0, + NULL, &_ifOutNUcastPkts_obj +}, +_ifOutErrors_obj = { + "ifOutErrors", 20, 0, + NULL, &_ifOutDiscards_obj +}, +_ifOutQLen_obj = { + "ifOutQLen", 21, 0, + NULL, &_ifOutErrors_obj +}, +_ifSpecific_obj = { + "ifSpecific", 22, 0, + NULL, &_ifOutQLen_obj +}, +_ifEntry_obj = { + "ifEntry", 1, 0, + &_ifSpecific_obj, NULL +}, +_ifNumber_obj = { + "ifNumber", 1, 0, + NULL, NULL +}, +_ifTable_obj = { + "ifTable", 2, 0, + &_ifEntry_obj, &_ifNumber_obj +}, +_sysDescr_obj = { + "sysDescr", 1, 0, + NULL, NULL +}, +_sysObjectID_obj = { + "sysObjectID", 2, 0, + NULL, &_sysDescr_obj +}, +_sysUpTime_obj = { + "sysUpTime", 3, 0, + NULL, &_sysObjectID_obj +}, +_sysContact_obj = { + "sysContact", 4, 0, + NULL, &_sysUpTime_obj +}, +_sysName_obj = { + "sysName", 5, 0, + NULL, &_sysContact_obj +}, +_sysLocation_obj = { + "sysLocation", 6, 0, + NULL, &_sysName_obj +}, +_sysServices_obj = { + "sysServices", 7, 0, + NULL, &_sysLocation_obj +}, +_system_obj = { + "system", 1, 0, + &_sysServices_obj, NULL +}, +_interfaces_obj = { + "interfaces", 2, 0, + &_ifTable_obj, &_system_obj +}, +_at_obj = { + "at", 3, 0, + &_atTable_obj, &_interfaces_obj +}, +_ip_obj = { + "ip", 4, 0, + &_ipNetToMediaTable_obj, &_at_obj +}, +_icmp_obj = { + "icmp", 5, 0, + &_icmpOutAddrMaskReps_obj, &_ip_obj +}, +_tcp_obj = { + "tcp", 6, 0, + &_tcpOutRsts_obj, &_icmp_obj +}, +_udp_obj = { + "udp", 7, 0, + &_udpTable_obj, &_tcp_obj +}, +_egp_obj = { + "egp", 8, 0, + &_egpAs_obj, &_udp_obj +}, +_transmission_obj = { + "transmission", 10, 0, + NULL, &_egp_obj +}, +_snmp_obj = { + "snmp", 11, 0, + &_snmpEnableAuthTraps_obj, &_transmission_obj +}, +_mib_obj = { + "mib", 1, 0, + &_snmp_obj, NULL +}, +_directory_obj = { + "directory", 1, 0, + NULL, NULL +}, +_mgmt_obj = { + "mgmt", 2, 0, + &_mib_obj, &_directory_obj +}, +_experimental_obj = { + "experimental", 3, 0, + NULL, &_mgmt_obj +}, +_private_obj = { + "private", 4, 0, + &_enterprises_obj, &_experimental_obj +}, +_internet_obj = { + "internet", 1, 0, + &_private_obj, NULL +}, +_dod_obj = { + "dod", 6, 0, + &_internet_obj, NULL +}, +_org_obj = { + "org", 3, 0, + &_dod_obj, NULL +}, +_iso_obj = { + "iso", 1, 0, + &_org_obj, NULL +}, +*mibroot = &_iso_obj; diff --git a/usr.sbin/tcpdump/tcpdump/nametoaddr.c b/usr.sbin/tcpdump/tcpdump/nametoaddr.c new file mode 100644 index 000000000000..6f2330f141c1 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/nametoaddr.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Name to id translation routines used by the scanner. + * These functions are not time critical. + */ + +#ifndef lint +static char rcsid[] = + "@(#) $Header: nametoaddr.c,v 1.9 91/02/04 16:56:46 mccanne Exp $ (LBL)"; +#endif + +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <errno.h> +#include <arpa/inet.h> + +#ifdef ultrix +#include <sys/time.h> +#include <rpc/types.h> +#include <nfs/nfs.h> +#endif + +#include "interface.h" +#include "etherent.h" +#include "nametoaddr.h" + +/* + * Convert host name to internet address. + * Return 0 upon failure. + */ +u_long ** +s_nametoaddr(name) + char *name; +{ +#ifndef h_addr + static u_long *hlist[2]; +#endif + u_long **p; + struct hostent *hp; + + if (hp = gethostbyname(name)) { +#ifndef h_addr + hlist[0] = (u_long *)hp->h_addr; + NTOHL(hp->h_addr); + return hlist; +#else + for (p = (u_long **)hp->h_addr_list; *p; ++p) + NTOHL(**p); + return (u_long **)hp->h_addr_list; +#endif + } + else + return 0; +} + +/* + * Convert net name to internet address. + * Return 0 upon failure. + */ +u_long +s_nametonetaddr(name) + char *name; +{ + struct netent *np; + + if (np = getnetbyname(name)) + return np->n_net; + else + return 0; +} + +/* + * Convert a port name to its port and protocol numbers. + * We assume only TCP or UDP. + * Return 0 upon failure. + */ +s_nametoport(name, port, proto) + char *name; + int *port; + int *proto; +{ + struct servent *sp; + char *other; + + sp = getservbyname(name, (char *)0); + if (sp != 0) { + NTOHS(sp->s_port); + *port = sp->s_port; + *proto = s_nametoproto(sp->s_proto); + /* + * We need to check /etc/services for ambiguous entries. + * If we find the ambiguous entry, and it has the + * same port number, change the proto to PROTO_UNDEF + * so both TCP and UDP will be checked. + */ + if (*proto == IPPROTO_TCP) + other = "udp"; + else + other = "tcp"; + + sp = getservbyname(name, other); + if (sp != 0) { + NTOHS(sp->s_port); + if (*port != sp->s_port) + /* Can't handle ambigous names that refer + to different port numbers. */ + warning("ambiguous port %s in /etc/services", + name); + *proto = PROTO_UNDEF; + } + return 1; + } +#ifdef ultrix + /* Special hack in case NFS isn't in /etc/services */ + if (strcmp(name, "nfs") == 0) { + *port = NFS_PORT; + *proto = PROTO_UNDEF; + return 1; + } +#endif + return 0; +} + +int +s_nametoproto(str) + char *str; +{ + struct protoent *p; + + p = getprotobyname(str); + if (p != 0) + return p->p_proto; + else + return PROTO_UNDEF; +} + +#include "etherproto.h" + +int +s_nametoeproto(s) + char *s; +{ + struct eproto *p = eproto_db; + + while (p->s != 0) { + if (strcmp(p->s, s) == 0) + return p->p; + p += 1; + } + return PROTO_UNDEF; +} + +/* Hex digit to integer. */ +static inline int +xdtoi(c) +{ + if (isdigit(c)) + return c - '0'; + else if (islower(c)) + return c - 'a' + 10; + else + return c - 'A' + 10; +} + +u_long +atoin(s) + char *s; +{ + u_long addr = 0; + u_int n; + + while (1) { + n = 0; + while (*s && *s != '.') + n = n * 10 + *s++ - '0'; + addr <<= 8; + addr |= n & 0xff; + if (*s == '\0') + return addr; + ++s; + } + /* NOTREACHED */ +} + + +/* + * Convert 's' which has the form "xx:xx:xx:xx:xx:xx" into a new + * ethernet address. Assumes 's' is well formed. + */ +u_char * +ETHER_aton(s) + char *s; +{ + register u_char *ep, *e; + register u_int d; + + e = ep = (u_char *)malloc(6); + + while (*s) { + if (*s == ':') + s += 1; + d = xdtoi(*s++); + if (isxdigit(*s)) { + d <<= 4; + d |= xdtoi(*s++); + } + *ep++ = d; + } + + return e; +} + +#ifndef ETHER_SERVICE +u_char * +ETHER_hostton(name) + char *name; +{ + struct etherent *ep; + FILE *fp; + u_char *ap; + + fp = fopen(ETHERS_FILE, "r"); + if (fp != 0) { + while (ep = next_etherent(fp)) { + if (strcmp(ep->name, name) == 0) { + ap = (u_char *)malloc(6); + bcopy(ep->addr, ap, 6); + return ap; + } + } + } + return (u_char *)0; +} +#endif diff --git a/usr.sbin/tcpdump/tcpdump/nametoaddr.h b/usr.sbin/tcpdump/tcpdump/nametoaddr.h new file mode 100644 index 000000000000..23da3f2580f7 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/nametoaddr.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#) $Header: nametoaddr.h,v 1.6 90/09/24 12:50:41 mccanne Exp $ (LBL) + * + * Address to name translation routines. + */ + +extern u_long **s_nametoaddr(); +extern u_long s_nametonetaddr(); + +extern int s_nametoport(); +extern int s_nametoproto(); +extern int s_nametoeproto(); + +extern u_char *ETHER_hostton(); +extern u_char *ETHER_aton(); + +/* + * If a protocol is unknown, PROTO_UNDEF is returned. + * Also, s_nametoport() returns the protocol along with the port number. + * If there are ambiguous entried in /etc/services (i.e. domain + * can be either tcp or udp) PROTO_UNDEF is returned. + */ +#define PROTO_UNDEF -1 + diff --git a/usr.sbin/tcpdump/tcpdump/ntp.h b/usr.sbin/tcpdump/tcpdump/ntp.h new file mode 100644 index 000000000000..493686d95c48 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/ntp.h @@ -0,0 +1,117 @@ +/* $Header: ntp.h,v 1.1 90/08/07 11:08:27 mogul Exp $ */ + +/* + * Based on ntp.h from the U of MD implementation + * This file is based on Version 2 of the NTP spec (RFC1119). + */ + +/* + * Definitions for the masses + */ +#define JAN_1970 2208988800 /* 1970 - 1900 in seconds */ + +/* + * Structure definitions for NTP fixed point values + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Integer Part | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Fraction Part | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Integer Part | Fraction Part | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ +struct l_fixedpt { + u_long int_part; + u_long fraction; +}; + +struct s_fixedpt { + u_short int_part; + u_short fraction; +}; + +/* ================= Table 3.3. Packet Variables ================= */ +/* + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |LI | VN | Mode| Stratum | Poll | Precision | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Synchronizing Distance | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Synchronizing Dispersion | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reference Clock Identifier | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | Reference Timestamp (64 bits) | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | Originate Timestamp (64 bits) | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | Receive Timestamp (64 bits) | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | Transmit Timestamp (64 bits) | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ +struct ntpdata { + u_char status; /* status of local clock and leap info */ + u_char stratum; /* Stratum level */ + u_char ppoll; /* poll value */ + int precision:8; + struct s_fixedpt distance; + struct s_fixedpt dispersion; + u_long refid; + struct l_fixedpt reftime; + struct l_fixedpt org; + struct l_fixedpt rec; + struct l_fixedpt xmt; +}; +/* + * Leap Second Codes (high order two bits) + */ +#define NO_WARNING 0x00 /* no warning */ +#define PLUS_SEC 0x40 /* add a second (61 seconds) */ +#define MINUS_SEC 0x80 /* minus a second (59 seconds) */ +#define ALARM 0xc0 /* alarm condition (clock unsynchronized) */ + +/* + * Clock Status Bits that Encode Version + */ +#define NTPVERSION_1 0x08 +#define VERSIONMASK 0x38 +#define LEAPMASK 0xc0 +#define MODEMASK 0x07 + +/* + * Code values + */ +#define MODE_UNSPEC 0 /* unspecified */ +#define MODE_SYM_ACT 1 /* symmetric active */ +#define MODE_SYM_PAS 2 /* symmetric passive */ +#define MODE_CLIENT 3 /* client */ +#define MODE_SERVER 4 /* server */ +#define MODE_BROADCAST 5 /* broadcast */ +#define MODE_RES1 6 /* reserved */ +#define MODE_RES2 7 /* reserved */ + +/* + * Stratum Definitions + */ +#define UNSPECIFIED 0 +#define PRIM_REF 1 /* radio clock */ +#define INFO_QUERY 62 /* **** THIS implementation dependent **** */ +#define INFO_REPLY 63 /* **** THIS implementation dependent **** */ diff --git a/usr.sbin/tcpdump/tcpdump/optimize.c b/usr.sbin/tcpdump/tcpdump/optimize.c new file mode 100644 index 000000000000..50640112fb05 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/optimize.c @@ -0,0 +1,1871 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Optimization module for tcpdump intermediate representation. + */ +#ifndef lint +static char rcsid[] = + "@(#) $Header: optimize.c,v 1.35 91/07/18 09:27:55 mccanne Exp $ (LBL)"; +#endif + +#include <stdio.h> +#include <sys/types.h> + +#include <sys/time.h> +#include <net/bpf.h> + +#include "interface.h" +#include "gencode.h" + +#define A_ATOM BPF_MEMWORDS +#define X_ATOM (BPF_MEMWORDS+1) + +#define NOP -1 + +/* + * This define is used to represent *both* the accumulator and + * x register in use-def computations. + * Currently, the use-def code assumes only one definition per instruction. + */ +#define AX_ATOM N_ATOMS + +/* + * A flag to indicate that further optimization is needed. + * Iterative passes are continued until a given pass yields no + * branch movement. + */ +static int done; + +/* + * A block is marked if only if its mark equals the current mark. + * Rather than traverse the code array, marking each item, 'cur_mark' is + * incremented. This automatically makes each element unmarked. + */ +static int cur_mark; +#define isMarked(p) ((p)->mark == cur_mark) +#define unMarkAll() cur_mark += 1 +#define Mark(p) ((p)->mark = cur_mark) + +static void opt_init(); +static void opt_cleanup(); + +static void make_marks(); +static void mark_code(); + +static void intern_blocks(); + +static int eq_slist(); + +static int n_blocks; +struct block **blocks; +static int n_edges; +struct edge **edges; + +/* + * A bit vector set representation of the dominators. + * We round up the set size to the next power of two. + */ +static int nodewords; +static int edgewords; +struct block **levels; +u_long *space; +#define BITS_PER_WORD (8*sizeof(u_long)) +/* + * True if a is in uset {p} + */ +#define SET_MEMBER(p, a) \ +((p)[(unsigned)(a) / BITS_PER_WORD] & (1 << ((unsigned)(a) % BITS_PER_WORD))) + +/* + * Add 'a' to uset p. + */ +#define SET_INSERT(p, a) \ +(p)[(unsigned)(a) / BITS_PER_WORD] |= (1 << ((unsigned)(a) % BITS_PER_WORD)) + +/* + * Delete 'a' from uset p. + */ +#define SET_DELETE(p, a) \ +(p)[(unsigned)(a) / BITS_PER_WORD] &= ~(1 << ((unsigned)(a) % BITS_PER_WORD)) + +/* + * a := a intersect b + */ +#define SET_INTERSECT(a, b, n)\ +{\ + register u_long *_x = a, *_y = b;\ + register int _n = n;\ + while (--_n >= 0) *_x++ &= *_y++;\ +} + +/* + * a := a - b + */ +#define SET_SUBTRACT(a, b, n)\ +{\ + register u_long *_x = a, *_y = b;\ + register int _n = n;\ + while (--_n >= 0) *_x++ &=~ *_y++;\ +} + +/* + * a := a union b + */ +#define SET_UNION(a, b, n)\ +{\ + register u_long *_x = a, *_y = b;\ + register int _n = n;\ + while (--_n >= 0) *_x++ |= *_y++;\ +} + +static uset all_dom_sets; +static uset all_closure_sets; +static uset all_edge_sets; + +#ifndef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif + +static void +find_levels_r(b) + struct block *b; +{ + int level; + + if (isMarked(b)) + return; + + Mark(b); + b->link = 0; + + if (JT(b)) { + find_levels_r(JT(b)); + find_levels_r(JF(b)); + level = MAX(JT(b)->level, JF(b)->level) + 1; + } else + level = 0; + b->level = level; + b->link = levels[level]; + levels[level] = b; +} + +/* + * Level graph. The levels go from 0 at the leaves to + * N_LEVELS at the root. The levels[] array points to the + * first node of the level list, whose elements are linked + * with the 'link' field of the struct block. + */ +static void +find_levels(root) + struct block *root; +{ + bzero((char *)levels, n_blocks * sizeof(*levels)); + unMarkAll(); + find_levels_r(root); +} + +/* + * Find dominator relationships. + * Assumes graph has been leveled. + */ +static void +find_dom(root) + struct block *root; +{ + int i; + struct block *b; + u_long *x; + + /* + * Initialize sets to contain all nodes. + */ + x = all_dom_sets; + i = n_blocks * nodewords; + while (--i >= 0) + *x++ = ~0; + /* Root starts off empty. */ + for (i = nodewords; --i >= 0;) + root->dom[i] = 0; + + /* root->level is the highest level no found. */ + for (i = root->level; i >= 0; --i) { + for (b = levels[i]; b; b = b->link) { + SET_INSERT(b->dom, b->id); + if (JT(b) == 0) + continue; + SET_INTERSECT(JT(b)->dom, b->dom, nodewords); + SET_INTERSECT(JF(b)->dom, b->dom, nodewords); + } + } +} + +static void +propedom(ep) + struct edge *ep; +{ + SET_INSERT(ep->edom, ep->id); + if (ep->succ) { + SET_INTERSECT(ep->succ->et.edom, ep->edom, edgewords); + SET_INTERSECT(ep->succ->ef.edom, ep->edom, edgewords); + } +} + +/* + * Compute edge dominators. + * Assumes graph has been leveled and predecessors estabished. + */ +static void +find_edom(root) + struct block *root; +{ + int i; + uset x; + struct block *b; + + x = all_edge_sets; + for (i = n_edges * edgewords; --i >= 0; ) + x[i] = ~0; + + /* root->level is the highest level no found. */ + bzero(root->et.edom, edgewords * sizeof(*(uset)0)); + bzero(root->ef.edom, edgewords * sizeof(*(uset)0)); + for (i = root->level; i >= 0; --i) { + for (b = levels[i]; b != 0; b = b->link) { + propedom(&b->et); + propedom(&b->ef); + } + } +} + +/* + * Find the backwards transitive closure of the flow graph. These sets + * are backwards in the sense that we find the set of nodes that reach + * a given node, not the set of nodes that can be reached by a node. + * + * Assumes graph has been leveled. + */ +static void +find_closure(root) + struct block *root; +{ + int i; + struct block *b; + + /* + * Initialize sets to contain no nodes. + */ + bzero((char *)all_closure_sets, + n_blocks * nodewords * sizeof(*all_closure_sets)); + + /* root->level is the highest level no found. */ + for (i = root->level; i >= 0; --i) { + for (b = levels[i]; b; b = b->link) { + SET_INSERT(b->closure, b->id); + if (JT(b) == 0) + continue; + SET_UNION(JT(b)->closure, b->closure, nodewords); + SET_UNION(JF(b)->closure, b->closure, nodewords); + } + } +} + +/* + * Return the register number that is used by s. If A and X are both + * used, return AX_ATOM. If no register is used, return -1. + * + * The implementation should probably change to an array access. + */ +static int +atomuse(s) + struct stmt *s; +{ + register int c = s->code; + + if (c == NOP) + return -1; + + switch (BPF_CLASS(c)) { + + case BPF_RET: + return (BPF_RVAL(c) == BPF_A) ? A_ATOM : + (BPF_RVAL(c) == BPF_X) ? X_ATOM : -1; + + case BPF_LD: + case BPF_LDX: + return (BPF_MODE(c) == BPF_IND) ? X_ATOM : + (BPF_MODE(c) == BPF_MEM) ? s->k : -1; + + case BPF_ST: + return A_ATOM; + + case BPF_STX: + return X_ATOM; + + case BPF_JMP: + case BPF_ALU: + if (BPF_SRC(c) == BPF_X) + return AX_ATOM; + return A_ATOM; + + case BPF_MISC: + return BPF_MISCOP(c) == BPF_TXA ? X_ATOM : A_ATOM; + } + abort(); + /* NOTREACHED */ +} + +/* + * Return the register number that is defined by 's'. We assume that + * a single stmt cannot define more than one register. If no register + * is defined, return -1. + * + * The implementation should probably change to an array access. + */ +static int +atomdef(s) + struct stmt *s; +{ + if (s->code == NOP) + return -1; + + switch (BPF_CLASS(s->code)) { + + case BPF_LD: + case BPF_ALU: + return A_ATOM; + + case BPF_LDX: + return X_ATOM; + + case BPF_ST: + case BPF_STX: + return s->k; + + case BPF_MISC: + return BPF_MISCOP(s->code) == BPF_TAX ? X_ATOM : A_ATOM; + } + return -1; +} + +static void +compute_local_ud(b) + struct block *b; +{ + struct slist *s; + atomset def = 0, use = 0, kill = 0; + int atom; + + for (s = b->stmts; s; s = s->next) { + if (s->s.code == NOP) + continue; + atom = atomuse(&s->s); + if (atom >= 0) { + if (atom == AX_ATOM) { + if (!ATOMELEM(def, X_ATOM)) + use |= ATOMMASK(X_ATOM); + if (!ATOMELEM(def, A_ATOM)) + use |= ATOMMASK(A_ATOM); + } + else if (atom < N_ATOMS) { + if (!ATOMELEM(def, atom)) + use |= ATOMMASK(atom); + } + else + abort(); + } + atom = atomdef(&s->s); + if (atom >= 0) { + if (!ATOMELEM(atom, use)) + kill |= ATOMMASK(atom); + def |= ATOMMASK(atom); + } + } + if (!ATOMELEM(def, A_ATOM) && BPF_CLASS(b->s.code) == BPF_JMP) + use |= ATOMMASK(A_ATOM); + + b->def = def; + b->kill = kill; + b->in_use = use; +} + +/* + * Assume graph is already leveled. + */ +static void +find_ud(root) + struct block *root; +{ + int i, maxlevel; + struct block *p; + + /* + * root->level is the highest level no found; + * count down from there. + */ + maxlevel = root->level; + for (i = maxlevel; i >= 0; --i) + for (p = levels[i]; p; p = p->link) { + compute_local_ud(p); + p->out_use = 0; + } + + for (i = 1; i <= maxlevel; ++i) { + for (p = levels[i]; p; p = p->link) { + p->out_use |= JT(p)->in_use | JF(p)->in_use; + p->in_use |= p->out_use &~ p->kill; + } + } +} + +/* + * These data structures are used in a Cocke and Shwarz style + * value numbering scheme. Since the flowgraph is acyclic, + * exit values can be propagated from a node's predecessors + * provided it is uniquely defined. + */ +struct valnode { + int code; + long v0, v1; + long val; + struct valnode *next; +}; + +#define MODULUS 213 +static struct valnode *hashtbl[MODULUS]; +static int curval; +static int maxval; + +/* Integer constants mapped with the load immediate opcode. */ +#define K(i) F(BPF_LD|BPF_IMM|BPF_W, i, 0L) + +struct vmapinfo { + int is_const; + long const_val; +}; + +struct vmapinfo *vmap; +struct valnode *vnode_base; +struct valnode *next_vnode; + +static void +init_val() +{ + curval = 0; + next_vnode = vnode_base; + bzero((char *)vmap, maxval * sizeof(*vmap)); + bzero((char *)hashtbl, sizeof hashtbl); +} + +/* Because we really don't have an IR, this stuff is a little messy. */ +static long +F(code, v0, v1) + int code; + long v0, v1; +{ + u_int hash; + int val; + struct valnode *p; + + hash = (u_int)code ^ (v0 << 4) ^ (v1 << 8); + hash %= MODULUS; + + for (p = hashtbl[hash]; p; p = p->next) + if (p->code == code && p->v0 == v0 && p->v1 == v1) + return p->val; + + val = ++curval; + if (BPF_MODE(code) == BPF_IMM && + (BPF_CLASS(code) == BPF_LD || BPF_CLASS(code) == BPF_LDX)) { + vmap[val].const_val = v0; + vmap[val].is_const = 1; + } + p = next_vnode++; + p->val = val; + p->code = code; + p->v0 = v0; + p->v1 = v1; + p->next = hashtbl[hash]; + hashtbl[hash] = p; + + return val; +} + +static inline void +vstore(s, valp, newval, alter) + struct stmt *s; + long *valp; + long newval; + int alter; +{ + if (alter && *valp == newval) + s->code = NOP; + else + *valp = newval; +} + +static void +fold_op(s, v0, v1) + struct stmt *s; + long v0, v1; +{ + long a, b; + + a = vmap[v0].const_val; + b = vmap[v1].const_val; + + switch (BPF_OP(s->code)) { + case BPF_ADD: + a += b; + break; + + case BPF_SUB: + a -= b; + break; + + case BPF_MUL: + a *= b; + break; + + case BPF_DIV: + if (b == 0) + error("division by zero"); + a /= b; + break; + + case BPF_AND: + a &= b; + break; + + case BPF_OR: + a |= b; + break; + + case BPF_LSH: + a <<= b; + break; + + case BPF_RSH: + a >>= b; + break; + + case BPF_NEG: + a = -a; + break; + + default: + abort(); + } + s->k = a; + s->code = BPF_LD|BPF_IMM; + done = 0; +} + +static inline struct slist * +this_op(s) + struct slist *s; +{ + while (s != 0 && s->s.code == NOP) + s = s->next; + return s; +} + +static void +opt_not(b) + struct block *b; +{ + struct block *tmp = JT(b); + + JT(b) = JF(b); + JF(b) = tmp; +} + +static void +opt_peep(b) + struct block *b; +{ + struct slist *s; + struct slist *next, *last; + int val; + long v; + + s = b->stmts; + if (s == 0) + return; + + last = s; + while (1) { + s = this_op(s); + if (s == 0) + break; + next = this_op(s->next); + if (next == 0) + break; + last = next; + + /* + * st M[k] --> st M[k] + * ldx M[k] tax + */ + if (s->s.code == BPF_ST && + next->s.code == (BPF_LDX|BPF_MEM) && + s->s.k == next->s.k) { + done = 0; + next->s.code = BPF_MISC|BPF_TAX; + } + /* + * ld #k --> ldx #k + * tax txa + */ + if (s->s.code == (BPF_LD|BPF_IMM) && + next->s.code == (BPF_MISC|BPF_TAX)) { + s->s.code = BPF_LDX|BPF_IMM; + next->s.code = BPF_MISC|BPF_TXA; + done = 0; + } + /* + * This is an ugly special case, but it happens + * when you say tcp[k] or udp[k] where k is a constant. + */ + if (s->s.code == (BPF_LD|BPF_IMM)) { + struct slist *add, *tax, *ild; + + /* + * Check that X isn't used on exit from this + * block (which the optimizer might cause). + * We know the code generator won't generate + * any local dependencies. + */ + if (ATOMELEM(b->out_use, X_ATOM)) + break; + + if (next->s.code != (BPF_LDX|BPF_MSH|BPF_B)) + add = next; + else + add = this_op(next->next); + if (add == 0 || add->s.code != (BPF_ALU|BPF_ADD|BPF_X)) + break; + + tax = this_op(add->next); + if (tax == 0 || tax->s.code != (BPF_MISC|BPF_TAX)) + break; + + ild = this_op(tax->next); + if (ild == 0 || BPF_CLASS(ild->s.code) != BPF_LD || + BPF_MODE(ild->s.code) != BPF_IND) + break; + /* + * XXX We need to check that X is not + * subsequently used. We know we can eliminate the + * accumulator modifications since it is defined + * by the last stmt of this sequence. + * + * We want to turn this sequence: + * + * (004) ldi #0x2 {s} + * (005) ldxms [14] {next} -- optional + * (006) addx {add} + * (007) tax {tax} + * (008) ild [x+0] {ild} + * + * into this sequence: + * + * (004) nop + * (005) ldxms [14] + * (006) nop + * (007) nop + * (008) ild [x+2] + * + */ + ild->s.k += s->s.k; + s->s.code = NOP; + add->s.code = NOP; + tax->s.code = NOP; + done = 0; + } + s = next; + } + /* + * If we have a subtract to do a comparsion, and the X register + * is a known constant, we can merge this value into the + * comparison. + */ + if (last->s.code == (BPF_ALU|BPF_SUB|BPF_X) && + !ATOMELEM(b->out_use, A_ATOM)) { + val = b->val[X_ATOM]; + if (vmap[val].is_const) { + b->s.k += vmap[val].const_val; + last->s.code = NOP; + done = 0; + } else if (b->s.k == 0) { + /* + * sub x -> nop + * j #0 j x + */ + last->s.code = NOP; + b->s.code = BPF_CLASS(b->s.code) | BPF_OP(b->s.code) | + BPF_X; + done = 0; + } + } + /* + * Likewise, a constant subtract can be simplified. + */ + else if (last->s.code == (BPF_ALU|BPF_SUB|BPF_K) && + !ATOMELEM(b->out_use, A_ATOM)) { + b->s.k += last->s.k; + last->s.code = NOP; + done = 0; + } + /* + * and #k nop + * jeq #0 -> jset #k + */ + if (last->s.code == (BPF_ALU|BPF_AND|BPF_K) && + !ATOMELEM(b->out_use, A_ATOM) && b->s.k == 0) { + b->s.k = last->s.k; + b->s.code = BPF_JMP|BPF_K|BPF_JSET; + last->s.code = NOP; + done = 0; + opt_not(b); + } + /* + * If the accumulator is a known constant, we can compute the + * comparison result. + */ + val = b->val[A_ATOM]; + if (vmap[val].is_const && BPF_SRC(b->s.code) == BPF_K) { + v = vmap[val].const_val; + switch (BPF_OP(b->s.code)) { + + case BPF_JEQ: + v = v == b->s.k; + break; + + case BPF_JGT: + v = v > b->s.k; + break; + + case BPF_JGE: + v = v >= b->s.k; + break; + + case BPF_JSET: + v &= b->s.k; + break; + + default: + abort(); + } + if (JF(b) != JT(b)) + done = 0; + if (v) + JF(b) = JT(b); + else + JT(b) = JF(b); + } +} + +/* + * Compute the symbolic value of expression of 's', and update + * anything it defines in the value table 'val'. If 'alter' is true, + * do various optimizations. This code would be cleaner if symblic + * evaluation and code transformations weren't folded together. + */ +static void +opt_stmt(s, val, alter) + struct stmt *s; + long val[]; + int alter; +{ + int op; + long v; + + switch (s->code) { + + case BPF_LD|BPF_ABS|BPF_W: + case BPF_LD|BPF_ABS|BPF_H: + case BPF_LD|BPF_ABS|BPF_B: + v = F(s->code, s->k, 0L); + vstore(s, &val[A_ATOM], v, alter); + break; + + case BPF_LD|BPF_IND|BPF_W: + case BPF_LD|BPF_IND|BPF_H: + case BPF_LD|BPF_IND|BPF_B: + v = val[X_ATOM]; + if (alter && vmap[v].is_const) { + s->code = BPF_LD|BPF_ABS|BPF_SIZE(s->code); + s->k += vmap[v].const_val; + v = F(s->code, s->k, 0L); + done = 0; + } + else + v = F(s->code, s->k, v); + vstore(s, &val[A_ATOM], v, alter); + break; + + case BPF_LD|BPF_LEN: + v = F(s->code, 0L, 0L); + vstore(s, &val[A_ATOM], v, alter); + break; + + case BPF_LD|BPF_IMM: + v = K(s->k); + vstore(s, &val[A_ATOM], v, alter); + break; + + case BPF_LDX|BPF_IMM: + v = K(s->k); + vstore(s, &val[X_ATOM], v, alter); + break; + + case BPF_LDX|BPF_MSH|BPF_B: + v = F(s->code, s->k, 0L); + vstore(s, &val[X_ATOM], v, alter); + break; + + case BPF_ALU|BPF_NEG: + if (alter && vmap[val[A_ATOM]].is_const) { + s->code = BPF_LD|BPF_IMM; + s->k = -vmap[val[A_ATOM]].const_val; + val[A_ATOM] = K(s->k); + } + else + val[A_ATOM] = F(s->code, val[A_ATOM], 0L); + break; + + case BPF_ALU|BPF_ADD|BPF_K: + case BPF_ALU|BPF_SUB|BPF_K: + case BPF_ALU|BPF_MUL|BPF_K: + case BPF_ALU|BPF_DIV|BPF_K: + case BPF_ALU|BPF_AND|BPF_K: + case BPF_ALU|BPF_OR|BPF_K: + case BPF_ALU|BPF_LSH|BPF_K: + case BPF_ALU|BPF_RSH|BPF_K: + op = BPF_OP(s->code); + if (alter) { + if (s->k == 0) { + if (op == BPF_ADD || op == BPF_SUB || + op == BPF_LSH || op == BPF_RSH || + op == BPF_OR) { + s->code = NOP; + break; + } + if (op == BPF_MUL || op == BPF_AND) { + s->code = BPF_LD|BPF_IMM; + val[A_ATOM] = K(s->k); + break; + } + } + if (vmap[val[A_ATOM]].is_const) { + fold_op(s, val[A_ATOM], K(s->k)); + val[A_ATOM] = K(s->k); + break; + } + } + val[A_ATOM] = F(s->code, val[A_ATOM], K(s->k)); + break; + + case BPF_ALU|BPF_ADD|BPF_X: + case BPF_ALU|BPF_SUB|BPF_X: + case BPF_ALU|BPF_MUL|BPF_X: + case BPF_ALU|BPF_DIV|BPF_X: + case BPF_ALU|BPF_AND|BPF_X: + case BPF_ALU|BPF_OR|BPF_X: + case BPF_ALU|BPF_LSH|BPF_X: + case BPF_ALU|BPF_RSH|BPF_X: + op = BPF_OP(s->code); + if (alter && vmap[val[X_ATOM]].is_const) { + if (vmap[val[A_ATOM]].is_const) { + fold_op(s, val[A_ATOM], val[X_ATOM]); + val[A_ATOM] = K(s->k); + } + else { + s->code = BPF_ALU|BPF_K|op; + s->k = vmap[val[X_ATOM]].const_val; + done = 0; + val[A_ATOM] = + F(s->code, val[A_ATOM], K(s->k)); + } + break; + } + /* + * Check if we're doing something to an accumulator + * that is 0, and simplify. This may not seem like + * much of a simplification but it could open up further + * optimizations. + * XXX We could also check for mul by 1, and -1, etc. + */ + if (alter && vmap[val[A_ATOM]].is_const + && vmap[val[A_ATOM]].const_val == 0) { + if (op == BPF_ADD || op == BPF_OR || + op == BPF_LSH || op == BPF_RSH || op == BPF_SUB) { + s->code = BPF_MISC|BPF_TXA; + vstore(s, &val[A_ATOM], val[X_ATOM], alter); + break; + } + else if (op == BPF_MUL || op == BPF_DIV || + op == BPF_AND) { + s->code = BPF_LD|BPF_IMM; + s->k = 0; + vstore(s, &val[A_ATOM], K(s->k), alter); + break; + } + else if (op == BPF_NEG) { + s->code = NOP; + break; + } + } + val[A_ATOM] = F(s->code, val[A_ATOM], val[X_ATOM]); + break; + + case BPF_MISC|BPF_TXA: + vstore(s, &val[A_ATOM], val[X_ATOM], alter); + break; + + case BPF_LD|BPF_MEM: + v = val[s->k]; + if (alter && vmap[v].is_const) { + s->code = BPF_LD|BPF_IMM; + s->k = vmap[v].const_val; + done = 0; + } + vstore(s, &val[A_ATOM], v, alter); + break; + + case BPF_MISC|BPF_TAX: + vstore(s, &val[X_ATOM], val[A_ATOM], alter); + break; + + case BPF_LDX|BPF_MEM: + v = val[s->k]; + if (alter && vmap[v].is_const) { + s->code = BPF_LDX|BPF_IMM; + s->k = vmap[v].const_val; + done = 0; + } + vstore(s, &val[X_ATOM], v, alter); + break; + + case BPF_ST: + vstore(s, &val[s->k], val[A_ATOM], alter); + break; + + case BPF_STX: + vstore(s, &val[s->k], val[X_ATOM], alter); + break; + } +} + +static void +deadstmt(s, last) + register struct stmt *s; + register struct stmt *last[]; +{ + register int atom; + + atom = atomuse(s); + if (atom >= 0) { + if (atom == AX_ATOM) { + last[X_ATOM] = 0; + last[A_ATOM] = 0; + } + else + last[atom] = 0; + } + atom = atomdef(s); + if (atom >= 0) { + if (last[atom]) { + done = 0; + last[atom]->code = NOP; + } + last[atom] = s; + } +} + +static void +opt_deadstores(b) + register struct block *b; +{ + register struct slist *s; + register int atom; + struct stmt *last[N_ATOMS]; + + bzero((char *)last, sizeof last); + + for (s = b->stmts; s != 0; s = s->next) + deadstmt(&s->s, last); + deadstmt(&b->s, last); + + for (atom = 0; atom < N_ATOMS; ++atom) + if (last[atom] && !ATOMELEM(b->out_use, atom)) { + last[atom]->code = NOP; + done = 0; + } +} + +static void +opt_blk(b, do_stmts) + struct block *b; +{ + struct slist *s; + struct edge *p; + int i; + long aval; + + /* + * Initialize the atom values. + * If we have no predecessors, everything is undefined. + * Otherwise, we inherent our values from our predecessors. + * If any register has an ambiguous value (i.e. control paths are + * merging) give it the undefined value of 0. + */ + p = b->in_edges; + if (p == 0) + bzero((char *)b->val, sizeof(b->val)); + else { + bcopy((char *)p->pred->val, (char *)b->val, sizeof(b->val)); + while (p = p->next) { + for (i = 0; i < N_ATOMS; ++i) + if (b->val[i] != p->pred->val[i]) + b->val[i] = 0; + } + } + aval = b->val[A_ATOM]; + for (s = b->stmts; s; s = s->next) + opt_stmt(&s->s, b->val, do_stmts); + + /* + * This is a special case: if we don't use anything from this + * block, and we load the accumulator with value that is + * already there, eliminate all the statements. + */ + if (do_stmts && b->out_use == 0 && aval != 0 && + b->val[A_ATOM] == aval) + b->stmts = 0; + else { + opt_peep(b); + opt_deadstores(b); + } + /* + * Set up values for branch optimizer. + */ + if (BPF_SRC(b->s.code) == BPF_K) + b->oval = K(b->s.k); + else + b->oval = b->val[X_ATOM]; + b->et.code = b->s.code; + b->ef.code = -b->s.code; +} + +/* + * Return true if any register that is used on exit from 'succ', has + * an exit value that is different from the corresponding exit value + * from 'b'. + */ +static int +use_conflict(b, succ) + struct block *b, *succ; +{ + int atom; + atomset use = succ->out_use; + + if (use == 0) + return 0; + + for (atom = 0; atom < N_ATOMS; ++atom) + if (ATOMELEM(use, atom)) + if (b->val[atom] != succ->val[atom]) + return 1; + return 0; +} + +struct block * +fold_edge(child, ep) + struct block *child; + struct edge *ep; +{ + int sense; + int aval0, aval1, oval0, oval1; + int code = ep->code; + + if (code < 0) { + code = -code; + sense = 0; + } else + sense = 1; + + if (child->s.code != code) + return 0; + + aval0 = child->val[A_ATOM]; + oval0 = child->oval; + aval1 = ep->pred->val[A_ATOM]; + oval1 = ep->pred->oval; + + if (aval0 != aval1) + return 0; + + if (oval0 == oval1) + /* + * The operands are identical, so the + * result is true if a true branch was + * taken to get here, otherwise false. + */ + return sense ? JT(child) : JF(child); + + if (sense && code == (BPF_JMP|BPF_JEQ|BPF_K)) + /* + * At this point, we only know the comparison if we + * came down the true branch, and it was an equility + * comparison with a constant. We rely on the fact that + * distinct constants have distinct value numbers. + */ + return JF(child); + + return 0; +} + +static void +opt_j(ep) + struct edge *ep; +{ + register int i, k; + register struct block *target; + + if (JT(ep->succ) == 0) + return; + + if (JT(ep->succ) == JF(ep->succ)) { + /* + * Common branch targets can be eliminated, provided + * there is no data dependency. + */ + if (!use_conflict(ep->pred, ep->succ->et.succ)) { + done = 0; + ep->succ = JT(ep->succ); + } + } + /* + * For each edge dominator that matches the successor of this + * edge, promote the edge succesor to the its grandchild. + * + * XXX We violate the set abstraction here in favor a reasonbly + * efficient loop. + */ + top: + for (i = 0; i < edgewords; ++i) { + register u_long x = ep->edom[i]; + + while (x != 0) { + k = ffs(x) - 1; + x &=~ 1 << k; + k += i * BITS_PER_WORD; + + target = fold_edge(ep->succ, edges[k]); + /* + * Check that there is no data dependency between + * nodes that will be violated if we move the edge. + */ + if (target != 0 && !use_conflict(ep->pred, target)) { + done = 0; + ep->succ = target; + if (JT(target) != 0) + /* + * Start over unless we hit a leaf. + */ + goto top; + return; + } + } + } +} + + +static void +or_pullup(b) + struct block *b; +{ + int val, at_top; + struct block *pull; + struct block **diffp, **samep; + struct edge *ep; + + ep = b->in_edges; + if (ep == 0) + return; + + /* + * Make sure each predecessor loads the same value. + * XXX why? + */ + val = ep->pred->val[A_ATOM]; + for (ep = ep->next; ep != 0; ep = ep->next) + if (val != ep->pred->val[A_ATOM]) + return; + + if (JT(b->in_edges->pred) == b) + diffp = &JT(b->in_edges->pred); + else + diffp = &JF(b->in_edges->pred); + + at_top = 1; + while (1) { + if (*diffp == 0) + return; + + if (JT(*diffp) != JT(b)) + return; + + if (!SET_MEMBER((*diffp)->dom, b->id)) + return; + + if ((*diffp)->val[A_ATOM] != val) + break; + + diffp = &JF(*diffp); + at_top = 0; + } + samep = &JF(*diffp); + while (1) { + if (*samep == 0) + return; + + if (JT(*samep) != JT(b)) + return; + + if (!SET_MEMBER((*samep)->dom, b->id)) + return; + + if ((*samep)->val[A_ATOM] == val) + break; + + /* XXX Need to check that there are no data dependencies + between dp0 and dp1. Currently, the code generator + will not produce such dependencies. */ + samep = &JF(*samep); + } +#ifdef notdef + /* XXX This doesn't cover everything. */ + for (i = 0; i < N_ATOMS; ++i) + if ((*samep)->val[i] != pred->val[i]) + return; +#endif + /* Pull up the node. */ + pull = *samep; + *samep = JF(pull); + JF(pull) = *diffp; + + /* + * At the top of the chain, each predecessor needs to point at the + * pulled up node. Inside the chain, there is only one predecessor + * to worry about. + */ + if (at_top) { + for (ep = b->in_edges; ep != 0; ep = ep->next) { + if (JT(ep->pred) == b) + JT(ep->pred) = pull; + else + JF(ep->pred) = pull; + } + } + else + *diffp = pull; + + done = 0; +} + +static void +and_pullup(b) + struct block *b; +{ + int val, at_top; + struct block *pull; + struct block **diffp, **samep; + struct edge *ep; + + ep = b->in_edges; + if (ep == 0) + return; + + /* + * Make sure each predecessor loads the same value. + */ + val = ep->pred->val[A_ATOM]; + for (ep = ep->next; ep != 0; ep = ep->next) + if (val != ep->pred->val[A_ATOM]) + return; + + if (JT(b->in_edges->pred) == b) + diffp = &JT(b->in_edges->pred); + else + diffp = &JF(b->in_edges->pred); + + at_top = 1; + while (1) { + if (*diffp == 0) + return; + + if (JF(*diffp) != JF(b)) + return; + + if (!SET_MEMBER((*diffp)->dom, b->id)) + return; + + if ((*diffp)->val[A_ATOM] != val) + break; + + diffp = &JT(*diffp); + at_top = 0; + } + samep = &JT(*diffp); + while (1) { + if (*samep == 0) + return; + + if (JF(*samep) != JF(b)) + return; + + if (!SET_MEMBER((*samep)->dom, b->id)) + return; + + if ((*samep)->val[A_ATOM] == val) + break; + + /* XXX Need to check that there are no data dependencies + between diffp and samep. Currently, the code generator + will not produce such dependencies. */ + samep = &JT(*samep); + } +#ifdef notdef + /* XXX This doesn't cover everything. */ + for (i = 0; i < N_ATOMS; ++i) + if ((*samep)->val[i] != pred->val[i]) + return; +#endif + /* Pull up the node. */ + pull = *samep; + *samep = JT(pull); + JT(pull) = *diffp; + + /* + * At the top of the chain, each predecessor needs to point at the + * pulled up node. Inside the chain, there is only one predecessor + * to worry about. + */ + if (at_top) { + for (ep = b->in_edges; ep != 0; ep = ep->next) { + if (JT(ep->pred) == b) + JT(ep->pred) = pull; + else + JF(ep->pred) = pull; + } + } + else + *diffp = pull; + + done = 0; +} + +static void +opt_blks(root, do_stmts) + struct block *root; +{ + int i, maxlevel; + struct block *p; + + init_val(); + maxlevel = root->level; + for (i = maxlevel; i >= 0; --i) + for (p = levels[i]; p; p = p->link) + opt_blk(p, do_stmts); + + if (do_stmts) + /* + * No point trying to move branches; it can't possibly + * make a difference at this point. + */ + return; + + for (i = 1; i <= maxlevel; ++i) { + for (p = levels[i]; p; p = p->link) { + opt_j(&p->et); + opt_j(&p->ef); + } + } + for (i = 1; i <= maxlevel; ++i) { + for (p = levels[i]; p; p = p->link) { + or_pullup(p); + and_pullup(p); + } + } +} + +static inline void +link_inedge(parent, child) + struct edge *parent; + struct block *child; +{ + parent->next = child->in_edges; + child->in_edges = parent; +} + +static void +find_inedges(root) + struct block *root; +{ + int i; + struct block *b; + struct edge *ep; + + for (i = 0; i < n_blocks; ++i) + blocks[i]->in_edges = 0; + + /* + * Traverse the graph, adding each edge to the predecessor + * list of its sucessors. Skip the leaves (i.e. level 0). + */ + for (i = root->level; i > 0; --i) { + for (b = levels[i]; b != 0; b = b->link) { + link_inedge(&b->et, JT(b)); + link_inedge(&b->ef, JF(b)); + } + } +} + +static void +opt_root(b) + struct block **b; +{ + struct slist *tmp, *s; + + s = (*b)->stmts; + (*b)->stmts = 0; + while (BPF_CLASS((*b)->s.code) == BPF_JMP && JT(*b) == JF(*b)) + *b = JT(*b); + + tmp = (*b)->stmts; + if (tmp != 0) + sappend(s, tmp); + (*b)->stmts = s; +} + +static void +opt_loop(root, do_stmts) + struct block *root; + int do_stmts; +{ + int passes = 0; +#ifdef BDEBUG + if (dflag > 1) + opt_dump(root); +#endif + do { + done = 1; + find_levels(root); + find_dom(root); + find_closure(root); + find_inedges(root); + find_ud(root); + find_edom(root); + opt_blks(root, do_stmts); +#ifdef BDEBUG + if (dflag > 1) + opt_dump(root); +#endif + } while (!done); +} + +/* + * Optimize the filter code in its dag representation. + */ +void +optimize(rootp) + struct block **rootp; +{ + struct block *root; + + root = *rootp; + + opt_init(root); + opt_loop(root, 0); + opt_loop(root, 1); + intern_blocks(root); + opt_root(rootp); + opt_cleanup(); +} + +static void +make_marks(p) + struct block *p; +{ + if (!isMarked(p)) { + Mark(p); + if (BPF_CLASS(p->s.code) != BPF_RET) { + make_marks(JT(p)); + make_marks(JF(p)); + } + } +} + +/* + * Mark code array such that isMarked(i) is true + * only for nodes that are alive. + */ +static void +mark_code(p) + struct block *p; +{ + cur_mark += 1; + make_marks(p); +} + +/* + * True iff the two stmt lists load the same value from the packet into + * the accumulator. + */ +static int +eq_slist(x, y) + struct slist *x, *y; +{ + while (1) { + while (x && x->s.code == NOP) + x = x->next; + while (y && y->s.code == NOP) + y = y->next; + if (x == 0) + return y == 0; + if (y == 0) + return x == 0; + if (x->s.code != y->s.code || x->s.k != y->s.k) + return 0; + x = x->next; + y = y->next; + } +} + +static inline int +eq_blk(b0, b1) + struct block *b0, *b1; +{ + if (b0->s.code == b1->s.code && + b0->s.k == b1->s.k && + b0->et.succ == b1->et.succ && + b0->ef.succ == b1->ef.succ) + return eq_slist(b0->stmts, b1->stmts); + return 0; +} + +static void +intern_blocks(root) + struct block *root; +{ + struct block *p; + int i, j; + int done; + top: + done = 1; + for (i = 0; i < n_blocks; ++i) + blocks[i]->link = 0; + + mark_code(root); + + for (i = n_blocks - 1; --i >= 0; ) { + if (!isMarked(blocks[i])) + continue; + for (j = i + 1; j < n_blocks; ++j) { + if (!isMarked(blocks[j])) + continue; + if (eq_blk(blocks[i], blocks[j])) { + blocks[i]->link = blocks[j]->link ? + blocks[j]->link : blocks[j]; + break; + } + } + } + for (i = 0; i < n_blocks; ++i) { + p = blocks[i]; + if (JT(p) == 0) + continue; + if (JT(p)->link) { + done = 0; + JT(p) = JT(p)->link; + } + if (JF(p)->link) { + done = 0; + JF(p) = JF(p)->link; + } + } + if (!done) + goto top; +} + +static void +opt_cleanup() +{ + free((void *)vnode_base); + free((void *)vmap); + free((void *)edges); + free((void *)space); + free((void *)levels); + free((void *)blocks); +} + +/* + * Return the number of stmts in 's'. + */ +static int +slength(s) + struct slist *s; +{ + int n = 0; + + for (; s; s = s->next) + if (s->s.code != NOP) + ++n; + return n; +} + +/* + * Return the number of nodes reachable by 'p'. + * All nodes should be initially unmarked. + */ +static int +count_blocks(p) + struct block *p; +{ + if (p == 0 || isMarked(p)) + return 0; + Mark(p); + return count_blocks(JT(p)) + count_blocks(JF(p)) + 1; +} + +/* + * Do a depth first search on the flow graph, numbering the + * the basic blocks, and entering them into the 'blocks' array.` + */ +static void +number_blks_r(p) + struct block *p; +{ + int n; + + if (p == 0 || isMarked(p)) + return; + + Mark(p); + n = n_blocks++; + p->id = n; + blocks[n] = p; + + number_blks_r(JT(p)); + number_blks_r(JF(p)); +} + +/* + * Return the number of stmts in the flowgraph reachable by 'p'. + * The nodes should be unmarked before calling. + */ +static int +count_stmts(p) + struct block *p; +{ + int n; + + if (p == 0 || isMarked(p)) + return 0; + Mark(p); + n = count_stmts(JT(p)) + count_stmts(JF(p)); + return slength(p->stmts) + n + 1; +} + +/* + * Allocate memory. All allocation is done before optimization + * is begun. A linear bound on the size of all data structures is computed + * from the total number of blocks and/or statements. + */ +static void +opt_init(root) + struct block *root; +{ + u_long *p; + int i, n, max_stmts; + + /* + * First, count the blocks, so we can malloc an array to map + * block number to block. Then, put the blocks into the array. + */ + unMarkAll(); + n = count_blocks(root); + blocks = (struct block **)malloc(n * sizeof(*blocks)); + unMarkAll(); + n_blocks = 0; + number_blks_r(root); + + n_edges = 2 * n_blocks; + edges = (struct edge **)malloc(n_edges * sizeof(*edges)); + + /* + * The number of levels is bounded by the number of nodes. + */ + levels = (struct block **)malloc(n_blocks * sizeof(*levels)); + + edgewords = n_edges / (8 * sizeof(u_long)) + 1; + nodewords = n_blocks / (8 * sizeof(u_long)) + 1; + + /* XXX */ + space = (u_long *)malloc(2 * n_blocks * nodewords * sizeof(*space) + + n_edges * edgewords * sizeof(*space)); + p = space; + all_dom_sets = p; + for (i = 0; i < n; ++i) { + blocks[i]->dom = p; + p += nodewords; + } + all_closure_sets = p; + for (i = 0; i < n; ++i) { + blocks[i]->closure = p; + p += nodewords; + } + all_edge_sets = p; + for (i = 0; i < n; ++i) { + register struct block *b = blocks[i]; + + b->et.edom = p; + p += edgewords; + b->ef.edom = p; + p += edgewords; + b->et.id = i; + edges[i] = &b->et; + b->ef.id = n_blocks + i; + edges[n_blocks + i] = &b->ef; + b->et.pred = b; + b->ef.pred = b; + } + max_stmts = 0; + for (i = 0; i < n; ++i) + max_stmts += slength(blocks[i]->stmts) + 1; + /* + * We allocate at most 3 value numbers per statement, + * so this is an upper bound on the number of valnodes + * we'll need. + */ + maxval = 3 * max_stmts; + vmap = (struct vmapinfo *)malloc(maxval * sizeof(*vmap)); + vnode_base = (struct valnode *)malloc(maxval * sizeof(*vmap)); +} + +/* + * Some pointers used to convert the basic block form of the code, + * into the array form that BPF requires. 'fstart' will point to + * the malloc'd array while 'ftail' is used during the recursive traversal. + */ +static struct bpf_insn *fstart; +static struct bpf_insn *ftail; + +#ifdef BDEBUG +int bids[1000]; +#endif + +static void +convert_code_r(p) + struct block *p; +{ + struct bpf_insn *dst; + struct slist *src; + int slen; + u_int off; + + if (p == 0 || isMarked(p)) + return; + Mark(p); + + convert_code_r(JF(p)); + convert_code_r(JT(p)); + + slen = slength(p->stmts); + dst = ftail -= slen + 1; + + p->offset = dst - fstart; + + for (src = p->stmts; src; src = src->next) { + if (src->s.code == NOP) + continue; + dst->code = (u_short)src->s.code; + dst->k = src->s.k; + ++dst; + } +#ifdef BDEBUG + bids[dst - fstart] = p->id + 1; +#endif + dst->code = (u_short)p->s.code; + dst->k = p->s.k; + if (JT(p)) { + off = JT(p)->offset - (p->offset + slen) - 1; + if (off >= 256) + error("long jumps not supported"); + dst->jt = off; + off = JF(p)->offset - (p->offset + slen) - 1; + if (off >= 256) + error("long jumps not supported"); + dst->jf = off; + } +} + + +/* + * Convert flowgraph intermediate representation to the + * BPF array representation. Set *lenp to the number of instructions. + */ +struct bpf_insn * +icode_to_fcode(root, lenp) + struct block *root; + int *lenp; +{ + int n; + struct bpf_insn *fp; + + unMarkAll(); + n = *lenp = count_stmts(root); + + fp = (struct bpf_insn *)malloc(sizeof(*fp) * n); + bzero((char *)fp, sizeof(*fp) * n); + fstart = fp; + ftail = fp + n; + + unMarkAll(); + convert_code_r(root); + + return fp; +} + +#ifdef BDEBUG +opt_dump(root) + struct block *root; +{ + struct bpf_program f; + + bzero(bids, sizeof bids); + f.bf_insns = icode_to_fcode(root, &f.bf_len); + bpf_dump(&f, 1); + putchar('\n'); + free((char *)f.bf_insns); +} +#endif diff --git a/usr.sbin/tcpdump/tcpdump/os.c b/usr.sbin/tcpdump/tcpdump/os.c new file mode 100644 index 000000000000..856fb5a2bc66 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/os.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#) $Header: os-bsd.c,v 1.2 90/09/21 02:12:17 mccanne Exp $ (LBL)"; +#endif + diff --git a/usr.sbin/tcpdump/tcpdump/os.h b/usr.sbin/tcpdump/tcpdump/os.h new file mode 100644 index 000000000000..e0d01cf9484a --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/os.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#) $Header: os-bsd.h,v 1.15 91/05/05 23:59:11 mccanne Exp $ (LBL) + */ + +#include <sys/param.h> + +#ifndef BSD +#define BSD +#endif + +#define SHA(ap) ((ap)->arp_sha) +#define SPA(ap) ((ap)->arp_spa) +#define THA(ap) ((ap)->arp_tha) +#define TPA(ap) ((ap)->arp_tpa) + +#define EDST(ep) ((ep)->ether_dhost) +#define ESRC(ep) ((ep)->ether_shost) + +#ifndef ETHERTYPE_REVARP +#define ETHERTYPE_REVARP 0x8035 +#endif + +#ifndef IPPROTO_ND +/* From <netinet/in.h> on a Sun somewhere. */ +#define IPPROTO_ND 77 +#endif + +#ifndef REVARP_REQUEST +#define REVARP_REQUEST 3 +#endif +#ifndef REVARP_REPLY +#define REVARP_REPLY 4 +#endif + +/* newish RIP commands */ +#ifndef RIPCMD_POLL +#define RIPCMD_POLL 5 +#endif +#ifndef RIPCMD_POLLENTRY +#define RIPCMD_POLLENTRY 6 +#endif + +/* + * Map BSD names to SunOS names. + */ +#if BSD >= 199006 +#define RFS_NULL NFSPROC_NULL +#define RFS_GETATTR NFSPROC_GETATTR +#define RFS_SETATTR NFSPROC_SETATTR +#define RFS_ROOT NFSPROC_ROOT +#define RFS_LOOKUP NFSPROC_LOOKUP +#define RFS_READLINK NFSPROC_READLINK +#define RFS_READ NFSPROC_READ +#define RFS_WRITECACHE NFSPROC_WRITECACHE +#define RFS_WRITE NFSPROC_WRITE +#define RFS_CREATE NFSPROC_CREATE +#define RFS_REMOVE NFSPROC_REMOVE +#define RFS_RENAME NFSPROC_RENAME +#define RFS_LINK NFSPROC_LINK +#define RFS_SYMLINK NFSPROC_SYMLINK +#define RFS_MKDIR NFSPROC_MKDIR +#define RFS_RMDIR NFSPROC_RMDIR +#define RFS_READDIR NFSPROC_READDIR +#define RFS_STATFS NFSPROC_STATFS +#define RFS_NPROC NFSPROC_NPROC +#endif diff --git a/usr.sbin/tcpdump/tcpdump/ospf.h b/usr.sbin/tcpdump/tcpdump/ospf.h new file mode 100644 index 000000000000..e3a3a6d65d3e --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/ospf.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * OSPF support contributed by Jeffrey Honig (jch@mitchell.cit.cornell.edu) + */ +#define OSPF_TYPE_UMD 0 /* UMd's special monitoring packets */ +#define OSPF_TYPE_HELLO 1 /* Hello */ +#define OSPF_TYPE_DB 2 /* Database Description */ +#define OSPF_TYPE_LSR 3 /* Link State Request */ +#define OSPF_TYPE_LSU 4 /* Link State Update */ +#define OSPF_TYPE_LSA 5 /* Link State Ack */ +#define OSPF_TYPE_MAX 6 + +/* Options *_options */ +#define OSPF_OPTION_T 0x01 /* T bit: TOS support */ +#define OSPF_OPTION_E 0x02 /* E bit: External routes advertised */ +#define OSPF_OPTION_MC 0x04 /* MC bit: Multicast capable */ + +/* ospf_authtype */ +#define OSPF_AUTH_NONE 0 /* No auth-data */ +#define OSPF_AUTH_SIMPLE 1 /* Simple password */ + +/* db_flags */ +#define OSPF_DB_INIT 0x04 /* */ +#define OSPF_DB_MORE 0x02 +#define OSPF_DB_MASTER 0x01 + +/* ls_type */ +#define LS_TYPE_ROUTER 1 /* router link */ +#define LS_TYPE_NETWORK 2 /* network link */ +#define LS_TYPE_SUM_IP 3 /* summary link */ +#define LS_TYPE_SUM_ABR 4 /* summary area link */ +#define LS_TYPE_ASE 5 /* ASE */ +#define LS_TYPE_GROUP 6 /* Group membership (multicast */ + /* extensions 23 July 1991) */ +#define LS_TYPE_MAX 7 + +/************************************************* + * + * is the above a bug in the documentation? + * + *************************************************/ + + +/* rla_link.link_type */ +#define RLA_TYPE_ROUTER 1 /* point-to-point to another router */ +#define RLA_TYPE_TRANSIT 2 /* connection to transit network */ +#define RLA_TYPE_STUB 3 /* connection to stub network */ +#define RLA_TYPE_VIRTUAL 4 /* virtual link */ + +/* rla_flags */ +#define RLA_FLAG_B 0x01 +#define RLA_FLAG_E 0x02 +#define RLA_FLAG_W1 0x04 +#define RLA_FLAG_W2 0x08 + +/* sla_tosmetric breakdown */ +#define SLA_MASK_TOS 0x7f000000 +#define SLA_MASK_METRIC 0x00ffffff +#define SLA_SHIFT_TOS 24 + +/* asla_tosmetric breakdown */ +#define ASLA_FLAG_EXTERNAL 0x80000000 +#define ASLA_MASK_TOS 0x7f000000 +#define ASLA_SHIFT_TOS 24 +#define ASLA_MASK_METRIC 0x00ffffff + +/* multicast vertex type */ +#define MCLA_VERTEX_ROUTER 1 +#define MCLA_VERTEX_NETWORK 2 + +/* link state advertisement header */ +struct lsa_hdr { + u_short ls_age; + u_char ls_options; + u_char ls_type; + struct in_addr ls_stateid; + struct in_addr ls_router; + u_long ls_seq; + u_short ls_chksum; + u_short ls_length; +} ; + +/* link state advertisement */ +struct lsa { + struct lsa_hdr ls_hdr; + + /* Link state types */ + union { + /* Router links advertisements */ + struct { + u_char rla_flags; + u_char rla_zero[1]; + u_short rla_count; + struct rlalink { + struct in_addr link_id; + struct in_addr link_data; + u_char link_type; + u_char link_toscount; + u_short link_tos0metric; + } rla_link[1]; /* may repeat */ + } un_rla; + + /* Network links advertisements */ + struct { + struct in_addr nla_mask; + struct in_addr nla_router[1]; /* may repeat */ + } un_nla; + + /* Summary links advertisements */ + struct { + struct in_addr sla_mask; + u_long sla_tosmetric[1]; /* may repeat */ + } un_sla; + + /* AS external links advertisements */ + struct { + struct in_addr asla_mask; + struct aslametric { + u_long asla_tosmetric; + struct in_addr asla_forward; + struct in_addr asla_tag; + } asla_metric[1]; /* may repeat */ + } un_asla; + + /* Multicast group membership */ + struct mcla { + u_long mcla_vtype; + struct in_addr mcla_vid; + } un_mcla[1]; + } lsa_un; +} ; + + +/* + * TOS metric struct (will be 0 or more in router links update) + */ +struct tos_metric { + u_char tos_type; + u_char tos_zero; + u_short tos_metric; +} ; + +#define OSPF_AUTH_SIZE 8 + +/* + * the main header + */ +struct ospfhdr { + u_char ospf_version; + u_char ospf_type; + u_short ospf_len; + struct in_addr ospf_routerid; + struct in_addr ospf_areaid; + u_short ospf_chksum; + u_short ospf_authtype; + u_char ospf_authdata[OSPF_AUTH_SIZE]; + union { + + /* Hello packet */ + struct { + struct in_addr hello_mask; + u_short hello_helloint; + u_char hello_options; + u_char hello_priority; + u_long hello_deadint; + struct in_addr hello_dr; + struct in_addr hello_bdr; + struct in_addr hello_neighbor[1]; /* may repeat */ + } un_hello; + + /* Database Description packet */ + struct { + u_char db_zero[2]; + u_char db_options; + u_char db_flags; + u_long db_seq; + struct lsa_hdr db_lshdr[1]; /* may repeat */ + } un_db; + + /* Link State Request */ + struct lsr { + u_long ls_type; + struct in_addr ls_stateid; + struct in_addr ls_router; + } un_lsr[1]; /* may repeat */ + + /* Link State Update */ + struct { + u_long lsu_count; + struct lsa lsu_lsa[1]; /* may repeat */ + } un_lsu; + + /* Link State Acknowledment */ + struct { + struct lsa_hdr lsa_lshdr[1]; /* may repeat */ + } un_lsa ; + } ospf_un ; +} ; + +#define ospf_hello ospf_un.un_hello +#define ospf_db ospf_un.un_db +#define ospf_lsr ospf_un.un_lsr +#define ospf_lsu ospf_un.un_lsu +#define ospf_lsa ospf_un.un_lsa + diff --git a/usr.sbin/tcpdump/tcpdump/pcap.c b/usr.sbin/tcpdump/tcpdump/pcap.c new file mode 100644 index 000000000000..04c96953766b --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/pcap.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#ifndef lint +static char rcsid[] = + "@(#)$Header: pcap-bpf.c,v 1.29 92/06/02 17:57:29 mccanne Exp $ (LBL)"; +#endif + +#include <stdio.h> +#include <netdb.h> +#include <ctype.h> +#include <signal.h> +#include <errno.h> +#include <sys/param.h> /* optionally get BSD define */ +#include <sys/time.h> +#include <sys/timeb.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <net/bpf.h> +#include <net/if.h> +#include <string.h> + +#include "interface.h" + +extern int errno; + +static void +bpf_stats(fd) + int fd; +{ + struct bpf_stat s; + + if (ioctl(fd, BIOCGSTATS, &s) < 0) + return; + + (void)fflush(stdout); + (void)fprintf(stderr, "%d packets received by filter\n", s.bs_recv); + (void)fprintf(stderr, "%d packets dropped by kernel\n", s.bs_drop); +} + +void +readloop(cnt, if_fd, fp, printit) + int cnt; + int if_fd; + struct bpf_program *fp; + void (*printit)(); +{ + u_char *buf; + u_int bufsize; + int cc; + + if (ioctl(if_fd, BIOCGBLEN, (caddr_t)&bufsize) < 0) { + perror("tcpdump: BIOCGBLEN"); + exit(1); + } + buf = (u_char *)malloc(bufsize); + + if (ioctl(if_fd, BIOCSETF, (caddr_t)fp) < 0) { + perror("tcpdump: BIOCSETF"); + exit(1); + } + while (1) { + register u_char *bp, *ep; + + if ((cc = read(if_fd, (char *)buf, (int)bufsize)) < 0) { + /* Don't choke when we get ptraced */ + if (errno == EINTR) + continue; +#if defined(sun) && !defined(BSD) + /* + * Due to a SunOS bug, after 2^31 bytes, the kernel + * file offset overflows and read fails with EINVAL. + * The lseek() to 0 will fix things. + */ + if (errno == EINVAL && + (long)(tell(if_fd) + bufsize) < 0) { + (void)lseek(if_fd, 0, 0); + continue; + } +#endif + perror("tcpdump: read"); + exit(1); + } + /* + * Loop through each packet. + */ +#define bhp ((struct bpf_hdr *)bp) + bp = buf; + ep = bp + cc; + while (bp < ep) { + register int caplen, hdrlen; + if (cnt >= 0 && --cnt < 0) + goto out; + (*printit)(bp + (hdrlen = bhp->bh_hdrlen), + &bhp->bh_tstamp, bhp->bh_datalen, + caplen = bhp->bh_caplen); + bp += BPF_WORDALIGN(caplen + hdrlen); + } +#undef bhp + } + out: + wrapup(if_fd); +} + +wrapup(fd) + int fd; +{ + bpf_stats(fd); + close(fd); +} + +static inline int +bpf_open() +{ + int fd; + int n = 0; + char device[sizeof "/dev/bpf000"]; + + /* + * Go through all the minors and find one that isn't in use. + */ + do { + (void)sprintf(device, "/dev/bpf%d", n++); + fd = open(device, O_RDONLY); + } while (fd < 0 && errno == EBUSY); + + if (fd < 0) { + (void) fprintf(stderr, "tcpdump: "); + perror(device); + exit(-1); + } + return fd; +} + +int +initdevice(device, pflag, linktype) + char *device; + int pflag; + int *linktype; +{ + struct timeval timeout; + int if_fd; + struct ifreq ifr; + struct bpf_version bv; + + if_fd = bpf_open(); + + if (ioctl(if_fd, BIOCVERSION, (caddr_t)&bv) < 0) + warning("kernel bpf interpreter may be out of date"); + else if (bv.bv_major != BPF_MAJOR_VERSION || + bv.bv_minor < BPF_MINOR_VERSION) + error("requires bpf language %d.%d or higher; kernel is %d.%d", + BPF_MAJOR_VERSION, BPF_MINOR_VERSION, + bv.bv_major, bv.bv_minor); + + (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + if (ioctl(if_fd, BIOCSETIF, (caddr_t)&ifr) < 0) { + (void) fprintf(stderr, "tcpdump: BIOCSETIF: "); + perror(device); + exit(-1); + } + /* Get the data link layer type. */ + if (ioctl(if_fd, BIOCGDLT, (caddr_t)linktype) < 0) { + perror("tcpdump: BIOCGDLT"); + exit(-1); + } + /* set timeout */ + timeout.tv_sec = 1; + timeout.tv_usec = 0; + if (ioctl(if_fd, BIOCSRTIMEOUT, (caddr_t)&timeout) < 0) { + perror("tcpdump: BIOCSRTIMEOUT"); + exit(-1); + } + /* set promiscuous mode if requested, but only for broadcast nets */ + if (pflag == 0) { + switch (*linktype) { + + case DLT_SLIP: + case DLT_PPP: + case DLT_NULL: + break; + + default: + if (ioctl(if_fd, BIOCPROMISC, (void *)0) < 0) { + perror("tcpdump: BIOCPROMISC"); + exit(-1); + } + } + } + return(if_fd); +} diff --git a/usr.sbin/tcpdump/tcpdump/print-arp.c b/usr.sbin/tcpdump/tcpdump/print-arp.c new file mode 100644 index 000000000000..3f0671a4ba58 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-arp.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#) $Header: print-arp.c,v 1.16 91/04/19 10:45:56 mccanne Exp $ (LBL)"; +#endif + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include "interface.h" +#include "addrtoname.h" + +void +arp_print(ap, length, caplen) + register struct ether_arp *ap; + int length; + int caplen; +{ + if ((u_char *)(ap + 1) > snapend) { + printf("[|arp]"); + return; + } + if (length < sizeof(struct ether_arp)) { + (void)printf("truncated-arp"); + default_print((u_short *)ap, length); + return; + } + + NTOHS(ap->arp_hrd); + NTOHS(ap->arp_pro); + NTOHS(ap->arp_op); + + if (ap->arp_hrd != ARPHRD_ETHER + || (ap->arp_pro != ETHERTYPE_IP + && ap->arp_pro != ETHERTYPE_TRAIL) + || ap->arp_hln != sizeof(SHA(ap)) + || ap->arp_pln != sizeof(SPA(ap))) { + (void)printf("arp-req #%d for proto #%d (%d) hardware %d (%d)", + ap->arp_op, ap->arp_pro, ap->arp_pln, + ap->arp_hrd, ap->arp_hln); + return; + } + if (ap->arp_pro == ETHERTYPE_TRAIL) + (void)printf("trailer"); + switch (ap->arp_op) { + + case ARPOP_REQUEST: + (void)printf("arp who-has %s tell %s", + ipaddr_string(TPA(ap)), + ipaddr_string(SPA(ap))); + break; + + case ARPOP_REPLY: + (void)printf("arp reply %s is-at %s", + ipaddr_string(SPA(ap)), + etheraddr_string(SHA(ap))); + break; + + case REVARP_REQUEST: + (void)printf("rarp who-is %s tell %s", + etheraddr_string(THA(ap)), + etheraddr_string(SHA(ap))); + break; + + case REVARP_REPLY: + (void)printf("rarp reply %s at %s", + etheraddr_string(THA(ap)), + ipaddr_string(TPA(ap))); + break; + + default: + (void)printf("arp-%d", ap->arp_op); + default_print((u_short *)ap, caplen); + break; + } +} diff --git a/usr.sbin/tcpdump/tcpdump/print-atalk.c b/usr.sbin/tcpdump/tcpdump/print-atalk.c new file mode 100644 index 000000000000..203585ef5a8b --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-atalk.c @@ -0,0 +1,478 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Format and print AppleTalk packets. + */ +#ifndef lint +static char rcsid[] = + "@(#)$Header: print-atalk.c,v 1.22 92/03/26 14:15:34 mccanne Exp $ (LBL)"; +#endif + +#ifdef __STDC__ +#include <stdlib.h> +#endif +#include <stdio.h> + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> + +#include "interface.h" +#include "addrtoname.h" +#include "appletalk.h" +#include <strings.h> +#include "extract.h" + +static char *ataddr_string(); +static struct atNBPtuple *nbp_tuple_print(); +static struct atNBPtuple *nbp_name_print(); +static void atp_print(); +static void nbp_print(); +static void atp_bitmap_print(); + +/* + * Print AppleTalk Datagram Delivery Protocol packets. + */ +void +ddp_print(dp, length) + register struct atDDP *dp; + int length; +{ + if (length < ddpSize) { + (void)printf(" truncated-ddp %d", length); + return; + } + (void)printf("%s.%d > %s.%d:", + ataddr_string(EXTRACT_SHORT(&dp->srcNet), dp->srcNode), + dp->srcSkt, + ataddr_string(EXTRACT_SHORT(&dp->dstNet), dp->dstNode), + dp->dstSkt); + + /* 'type' is the last field of 'dp' so we need the whole thing. + If we cannot determine the type, bail out. (This last byte + happens to be *one* byte past the end of tcpdump's minimum + snapshot length.) */ + if ((u_char *)(dp + 1) > snapend) { + printf(" [|atalk]"); + return; + } + + length -= ddpSize; + switch (dp->type) { + + case ddpRTMP: + (void)printf(" at-rtmp %d", length); + break; + case ddpRTMPrequest: + (void)printf(" at-rtmpReq %d", length); + break; + case ddpNBP: + nbp_print((struct atNBP *)((u_char *)dp + ddpSize), + length, dp); + break; + case ddpATP: + atp_print((struct atATP *)((u_char *)dp + ddpSize), length); + break; + case ddpECHO: + (void)printf(" at-echo %d", length); + break; + case ddpIP: + (void)printf(" at-IP %d", length); + break; + case ddpARP: + (void)printf(" at-ARP %d", length); + break; + case ddpKLAP: + (void)printf(" at-KLAP %d", length); + break; + default: + (void)printf(" at-#%d %d", length); + break; + } +} + +static void +atp_print(ap, length) + register struct atATP *ap; + int length; +{ + char c; + long data; + + if ((u_char *)(ap + 1) > snapend) { + /* Just bail if we don't have the whole chunk. */ + printf(" [|atalk]"); + return; + } + length -= sizeof(*ap); + switch (ap->control & 0xc0) { + + case atpReqCode: + (void)printf(" atp-req%s %d", + ap->control & atpXO? " " : "*", + EXTRACT_SHORT(&ap->transID)); + + atp_bitmap_print(ap->bitmap); + + if (length != 0) + (void)printf(" [len=%d]", length); + + switch (ap->control & (atpEOM|atpSTS)) { + case atpEOM: + (void)printf(" [EOM]"); + break; + case atpSTS: + (void)printf(" [STS]"); + break; + case atpEOM|atpSTS: + (void)printf(" [EOM,STS]"); + break; + } + break; + + case atpRspCode: + (void)printf(" atp-resp%s%d:%d (%d)", + ap->control & atpEOM? "*" : " ", + EXTRACT_SHORT(&ap->transID), ap->bitmap, length); + switch (ap->control & (atpXO|atpSTS)) { + case atpXO: + (void)printf(" [XO]"); + break; + case atpSTS: + (void)printf(" [STS]"); + break; + case atpXO|atpSTS: + (void)printf(" [XO,STS]"); + break; + } + break; + + case atpRelCode: + (void)printf(" atp-rel %d", EXTRACT_SHORT(&ap->transID)); + + atp_bitmap_print(ap->bitmap); + + /* length should be zero */ + if (length) + (void)printf(" [len=%d]", length); + + /* there shouldn't be any control flags */ + if (ap->control & (atpXO|atpEOM|atpSTS)) { + c = '['; + if (ap->control & atpXO) { + (void)printf("%cXO", c); + c = ','; + } + if (ap->control & atpEOM) { + (void)printf("%cEOM", c); + c = ','; + } + if (ap->control & atpSTS) { + (void)printf("%cSTS", c); + c = ','; + } + (void)printf("]"); + } + break; + + default: + (void)printf(" atp-0x%x %d (%d)", ap->control, + EXTRACT_SHORT(&ap->transID), length); + break; + } + data = EXTRACT_LONG(&ap->userData); + if (data != 0) + (void)printf(" 0x%x", data); +} + +static void +atp_bitmap_print(bm) + register u_char bm; +{ + register char c; + register int i; + + /* + * The '& 0xff' below is needed for compilers that want to sign + * extend a u_char, which is the case with the Ultrix compiler. + * (gcc is smart enough to eliminate it, at least on the Sparc). + */ + if ((bm + 1) & (bm & 0xff)) { + c = '<'; + for (i = 0; bm; ++i) { + if (bm & 1) { + (void)printf("%c%d", c, i); + c = ','; + } + bm >>= 1; + } + (void)printf(">"); + } else { + for (i = 0; bm; ++i) + bm >>= 1; + if (i > 1) + (void)printf("<0-%d>", i - 1); + else + (void)printf("<0>"); + } +} + +static void +nbp_print(np, length, dp) + register struct atNBP *np; + int length; + register struct atDDP *dp; +{ + register struct atNBPtuple *tp = + (struct atNBPtuple *)((u_char *)np + nbpHeaderSize); + int i = length; + u_char *ep; + + length -= nbpHeaderSize; + if (length < 8) { + /* must be room for at least one tuple */ + (void)printf(" truncated-nbp %d", length + nbpHeaderSize); + return; + } + /* ep points to end of available data */ + ep = snapend; + if ((u_char *)tp > ep) { + printf(" [|atalk]"); + return; + } + switch (i = np->control & 0xf0) { + + case nbpBrRq: + case nbpLkUp: + (void)printf(i == nbpLkUp? " nbp-lkup %d:":" nbp-brRq %d:", + np->id); + if ((u_char *)(tp + 1) > ep) { + printf(" [|atalk]"); + return; + } + (void)nbp_name_print(tp, ep); + /* + * look for anomalies: the spec says there can only + * be one tuple, the address must match the source + * address and the enumerator should be zero. + */ + if ((np->control & 0xf) != 1) + (void)printf(" [ntup=%d]", np->control & 0xf); + if (tp->enumerator) + (void)printf(" [enum=%d]", tp->enumerator); + if (EXTRACT_SHORT(&tp->net) != EXTRACT_SHORT(&dp->srcNet) || + tp->node != dp->srcNode || tp->skt != dp->srcSkt) + (void)printf(" [addr=%s.%d]", + ataddr_string(EXTRACT_SHORT(&tp->net), + tp->node), + tp->skt); + break; + + case nbpLkUpReply: + (void)printf(" nbp-reply %d:", np->id); + + /* print each of the tuples in the reply */ + for (i = np->control & 0xf; --i >= 0 && tp; ) + tp = nbp_tuple_print(tp, ep, dp); + break; + + default: + (void)printf(" nbp-0x%x %d (%d)", np->control, np->id, + length); + break; + } +} + +/* print a counted string */ +static char * +print_cstring(cp, ep) + register char *cp; + register u_char *ep; +{ + register int length; + + if (cp >= (char *)ep) { + (void)printf("[|atalk]"); + return (0); + } + length = *cp++; + + /* Spec says string can be at most 32 bytes long */ + if (length < 0 || length > 32) { + (void)printf("[len=%d]", length); + return (0); + } + while (--length >= 0) { + if (cp >= (char *)ep) { + (void)printf("[|atalk]"); + return (0); + } + putchar(*cp++); + } + return (cp); +} + +static struct atNBPtuple * +nbp_tuple_print(tp, ep, dp) + register struct atNBPtuple *tp; + register u_char *ep; + register struct atDDP *dp; +{ + register struct atNBPtuple *tpn; + + if ((u_char *)(tp + 1) > ep) { + printf(" [|atalk]"); + return 0; + } + tpn = nbp_name_print(tp, ep); + + /* if the enumerator isn't 1, print it */ + if (tp->enumerator != 1) + (void)printf("(%d)", tp->enumerator); + + /* if the socket doesn't match the src socket, print it */ + if (tp->skt != dp->srcSkt) + (void)printf(" %d", tp->skt); + + /* if the address doesn't match the src address, it's an anomaly */ + if (EXTRACT_SHORT(&tp->net) != EXTRACT_SHORT(&dp->srcNet) || + tp->node != dp->srcNode) + (void)printf(" [addr=%s]", + ataddr_string(EXTRACT_SHORT(&tp->net), tp->node)); + + return (tpn); +} + +static struct atNBPtuple * +nbp_name_print(tp, ep) + struct atNBPtuple *tp; + register u_char *ep; +{ + register char *cp = (char *)tp + nbpTupleSize; + + putchar(' '); + + /* Object */ + putchar('"'); + if (cp = print_cstring(cp, ep)) { + /* Type */ + putchar(':'); + if (cp = print_cstring(cp, ep)) { + /* Zone */ + putchar('@'); + if (cp = print_cstring(cp, ep)) + putchar('"'); + } + } + return ((struct atNBPtuple *)cp); +} + + +#define HASHNAMESIZE 4096 + +struct hnamemem { + int addr; + char *name; + struct hnamemem *nxt; +}; + +static struct hnamemem hnametable[HASHNAMESIZE]; + +static char * +ataddr_string(atnet, athost) + u_short atnet; + u_char athost; +{ + register struct hnamemem *tp, *tp2; + register int i = (atnet << 8) | athost; + char nambuf[256]; + static int first = 1; + FILE *fp; + + /* + * if this is the first call, see if there's an AppleTalk + * number to name map file. + */ + if (first && (first = 0, !nflag) + && (fp = fopen("/etc/atalk.names", "r"))) { + char line[256]; + int i1, i2, i3; + + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '\n' || line[0] == 0 || line[0] == '#') + continue; + if (sscanf(line, "%d.%d.%d %s", &i1, &i2, &i3, + nambuf) == 4) + /* got a hostname. */ + i3 |= ((i1 << 8) | i2) << 8; + else if (sscanf(line, "%d.%d %s", &i1, &i2, + nambuf) == 3) + /* got a net name */ + i3 = (((i1 << 8) | i2) << 8) | 255; + else + continue; + + for (tp = &hnametable[i3 & (HASHNAMESIZE-1)]; + tp->nxt; tp = tp->nxt) + ; + tp->addr = i3; + tp->nxt = (struct hnamemem *)calloc(1, sizeof(*tp)); + i3 = strlen(nambuf) + 1; + tp->name = strcpy(malloc((unsigned) i3), nambuf); + } + fclose(fp); + } + + for (tp = &hnametable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) + if (tp->addr == i) + return (tp->name); + + /* didn't have the node name -- see if we've got the net name */ + i |= 255; + for (tp2 = &hnametable[i & (HASHNAMESIZE-1)]; tp2->nxt; tp2 = tp2->nxt) + if (tp2->addr == i) { + tp->addr = (atnet << 8) | athost; + tp->nxt = (struct hnamemem *)calloc(1, sizeof(*tp)); + (void)sprintf(nambuf, "%s.%d", tp2->name, athost); + i = strlen(nambuf) + 1; + tp->name = strcpy(malloc((unsigned) i), nambuf); + return (tp->name); + } + + tp->addr = (atnet << 8) | athost; + tp->nxt = (struct hnamemem *)calloc(1, sizeof(*tp)); + if (athost != 255) + (void)sprintf(nambuf, "%d.%d.%d", + atnet >> 8, atnet & 0xff, athost); + else + (void)sprintf(nambuf, "%d.%d", atnet >> 8, atnet & 0xff); + i = strlen(nambuf) + 1; + tp->name = strcpy(malloc((unsigned) i), nambuf); + + return (tp->name); +} diff --git a/usr.sbin/tcpdump/tcpdump/print-bootp.c b/usr.sbin/tcpdump/tcpdump/print-bootp.c new file mode 100644 index 000000000000..0641d825ff4f --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-bootp.c @@ -0,0 +1,263 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Format and print bootp packets. + */ +#ifndef lint +static char rcsid[] = + "@(#) $Header: print-bootp.c,v 1.17 91/11/14 22:21:34 leres Exp $ (LBL)"; +#endif + +#include <stdio.h> + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <strings.h> +#include <ctype.h> + +#include "interface.h" +#include "addrtoname.h" +#include "bootp.h" + +void rfc1048_print(); +void cmu_print(); + +/* + * Print bootp requests + */ +void +bootp_print(bp, length, sport, dport) + register struct bootp *bp; + int length; + u_short sport, dport; +{ + static char tstr[] = " [|bootp]"; + static unsigned char vm_cmu[4] = VM_CMU; + static unsigned char vm_rfc1048[4] = VM_RFC1048; + u_char *ep; + +#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc + + /* Note funny sized packets */ + if (length != sizeof(struct bootp)) + (void)printf(" [len=%d]", length); + + /* 'ep' points to the end of avaible data. */ + ep = (u_char *)snapend; + + switch (bp->bp_op) { + + case BOOTREQUEST: + /* Usually, a request goes from a client to a server */ + if (sport != IPPORT_BOOTPC || dport != IPPORT_BOOTPS) + printf(" (request)"); + break; + + case BOOTREPLY: + /* Usually, a reply goes from a server to a client */ + if (sport != IPPORT_BOOTPS || dport != IPPORT_BOOTPC) + printf(" (reply)"); + break; + + default: + printf(" bootp-#%d", bp->bp_op); + } + + NTOHL(bp->bp_xid); + NTOHS(bp->bp_secs); + + /* The usual hardware address type is 1 (10Mb Ethernet) */ + if (bp->bp_htype != 1) + printf(" htype-#%d", bp->bp_htype); + + /* The usual length for 10Mb Ethernet address is 6 bytes */ + if (bp->bp_htype != 1 || bp->bp_hlen != 6) + printf(" hlen:%d", bp->bp_hlen); + + /* Only print interesting fields */ + if (bp->bp_hops) + printf(" hops:%d", bp->bp_hops); + if (bp->bp_xid) + printf(" xid:0x%x", bp->bp_xid); + if (bp->bp_secs) + printf(" secs:%d", bp->bp_secs); + + /* Client's ip address */ + TCHECK(bp->bp_ciaddr, sizeof(bp->bp_ciaddr)); + if (bp->bp_ciaddr.s_addr) + printf(" C:%s", ipaddr_string(&bp->bp_ciaddr)); + + /* 'your' ip address (bootp client) */ + TCHECK(bp->bp_yiaddr, sizeof(bp->bp_yiaddr)); + if (bp->bp_yiaddr.s_addr) + printf(" Y:%s", ipaddr_string(&bp->bp_yiaddr)); + + /* Server's ip address */ + TCHECK(bp->bp_siaddr, sizeof(bp->bp_siaddr)); + if (bp->bp_siaddr.s_addr) + printf(" S:%s", ipaddr_string(&bp->bp_siaddr)); + + /* Gateway's ip address */ + TCHECK(bp->bp_giaddr, sizeof(bp->bp_giaddr)); + if (bp->bp_giaddr.s_addr) + printf(" G:%s", ipaddr_string(&bp->bp_giaddr)); + + /* Client's Ethernet address */ + if (bp->bp_htype == 1 && bp->bp_hlen == 6) { + register struct ether_header *eh; + register char *e; + + TCHECK(bp->bp_chaddr[0], 6); + eh = (struct ether_header *)packetp; + if (bp->bp_op == BOOTREQUEST) + e = (char *)ESRC(eh); + else if (bp->bp_op == BOOTREPLY) + e = (char *)EDST(eh); + else + e = 0; + if (e == 0 || bcmp((char *)bp->bp_chaddr, e, 6) != 0) + printf(" ether %s", etheraddr_string(bp->bp_chaddr)); + } + + TCHECK(bp->bp_sname[0], sizeof(bp->bp_sname)); + if (*bp->bp_sname) { + printf(" sname "); + if (printfn(bp->bp_sname, ep)) { + fputs(tstr + 1, stdout); + return; + } + } + TCHECK(bp->bp_file[0], sizeof(bp->bp_file)); + if (*bp->bp_file) { + printf(" file "); + if (printfn(bp->bp_file, ep)) { + fputs(tstr + 1, stdout); + return; + } + } + + /* Don't try to decode the vendor buffer unless we're verbose */ + if (vflag <= 0) + return; + + TCHECK(bp->bp_vend[0], sizeof(bp->bp_vend)); + printf(" vend"); + if (bcmp(bp->bp_vend, vm_rfc1048, sizeof(u_long)) == 0) + rfc1048_print(bp->bp_vend, sizeof(bp->bp_vend)); + else if (bcmp(bp->bp_vend, vm_cmu, sizeof(u_long)) == 0) + cmu_print(bp->bp_vend, sizeof(bp->bp_vend)); + else { + u_long ul; + + bcopy((char *)bp->bp_vend, (char *)&ul, sizeof(ul)); + printf("-#0x%x", ul); + } + + return; +trunc: + fputs(tstr, stdout); +#undef TCHECK +} + +void +rfc1048_print(bp, length) + register u_char *bp; + int length; +{ + u_char tag; + u_char *ep; + register int i; + u_long ul; + + printf("-rfc1048"); + + /* Step over magic cookie */ + bp += sizeof(long); + + /* Setup end pointer */ + ep = bp + length; + + while (bp < ep) { + tag = *bp++; + i = *bp++; + switch (tag) { + + case TAG_PAD: + /* no-op */ + break; + + case TAG_SUBNET_MASK: + ul = 0; + bcopy((char *)bp, (char *)&ul, i); + printf(" SM:%s", ipaddr_string(&ul)); + break; + + case TAG_TIME_SERVER: + ul = 0; + bcopy((char *)bp, (char *)&ul, i); + printf(" TS:%s", ipaddr_string(&ul)); + break; + + case TAG_GATEWAY: + ul = 0; + bcopy((char *)bp, (char *)&ul, i); + printf(" G:%s", ipaddr_string(&ul)); + break; + + case TAG_TIME_OFFSET: + case TAG_NAME_SERVER: + case TAG_DOMAIN_SERVER: + case TAG_LOG_SERVER: + case TAG_COOKIE_SERVER: + case TAG_LPR_SERVER: + case TAG_IMPRESS_SERVER: + case TAG_RLP_SERVER: + case TAG_HOSTNAME: + case TAG_BOOTSIZE: + printf(" tag-#%d", tag); + if (i == sizeof(long)) { + bcopy((char *)bp, (char *)&ul, sizeof(long)); + printf(":0x%x", ul); + } else + printf(":?"); + break; + + case TAG_END: + return; + + default: + printf("[tag-#%d]", tag); + return; + } + } +} + +void +cmu_print(bp, length) + register u_char *bp; + int length; +{ + /* XXX not really implemented */ + printf("-cmu [...]"); +} diff --git a/usr.sbin/tcpdump/tcpdump/print-domain.c b/usr.sbin/tcpdump/tcpdump/print-domain.c new file mode 100644 index 000000000000..04cf5aa47ea6 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-domain.c @@ -0,0 +1,287 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#) $Header: print-domain.c,v 1.16 92/05/25 14:28:59 mccanne Exp $ (LBL)"; +#endif + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> +#include <arpa/nameser.h> + +#include "interface.h" +#include "addrtoname.h" + +static char *ns_ops[] = { + "", " inv_q", " stat", " op3", " op4", " op5", " op6", " op7", + " op8", " updataA", " updateD", " updateDA", + " updateM", " updateMA", " zoneInit", " zoneRef", +}; + +static char *ns_resp[] = { + "", " FormErr", " ServFail", " NXDomain", + " NotImp", " Refused", " Resp6", " Resp7", + " Resp8", " Resp9", " Resp10", " Resp11", + " Resp12", " Resp13", " Resp14", " NoChange", +}; + + +/* skip over a domain name */ +static u_char * +ns_nskip(cp) + register u_char *cp; +{ + register u_char i; + + if (((i = *cp++) & 0xc0) == 0xc0) + return (cp + 1); + while (i) { + cp += i; + i = *cp++; + } + return (cp); +} + +/* print a domain name */ +static void +ns_nprint(cp, bp, ep) + register u_char *cp; + register u_char *bp; + register u_char *ep; +{ + register u_int i; + + putchar(' '); + if (i = *cp++) + while (i && cp < ep) { + if ((i & 0xc0) == 0xc0) { + cp = bp + (((i << 8) | *cp) & 0x3fff); + i = *cp++; + continue; + } + do { + putchar(*cp++); + } while (--i); + putchar('.'); + i = *cp++; + } + else + putchar('.'); +} + + +/* print a query */ +static void +ns_qprint(cp, bp, ep) + register u_char *cp; + register u_char *bp; + register u_char *ep; +{ + u_char *np = cp; + register u_int i; + + cp = ns_nskip(cp); + + if (cp + 4 > ep) + return; + + /* print the qtype and qclass (if it's not IN) */ + i = *cp++ << 8; + switch (i |= *cp++) { + case T_A: printf(" A"); break; + case T_NS: printf(" NS"); break; + case T_MD: printf(" MD"); break; + case T_MF: printf(" MF"); break; + case T_CNAME: printf(" CNAME"); break; + case T_SOA: printf(" SOA"); break; + case T_MB: printf(" MB"); break; + case T_MG: printf(" MG"); break; + case T_MR: printf(" MR"); break; + case T_NULL: printf(" NULL"); break; + case T_WKS: printf(" WKS"); break; + case T_PTR: printf(" PTR"); break; + case T_HINFO: printf(" HINFO"); break; + case T_MINFO: printf(" MINFO"); break; + case T_MX: printf(" MX"); break; + case T_UINFO: printf(" UINFO"); break; + case T_UID: printf(" UID"); break; + case T_GID: printf(" GID"); break; +#ifdef T_UNSPEC + case T_UNSPEC: printf(" UNSPEC"); break; +#endif + case T_AXFR: printf(" AXFR"); break; + case T_MAILB: printf(" MAILB"); break; + case T_MAILA: printf(" MAILA"); break; + case T_ANY: printf(" ANY"); break; + default: printf(" Type%d", i); break; + } + i = *cp++ << 8; + if ((i |= *cp++) != C_IN) + if (i == C_ANY) + printf("(c_any)"); + else + printf("(Class %d)", i); + + putchar('?'); + ns_nprint(np, bp, ep); +} + + +/* print a reply */ +static void +ns_rprint(cp, bp, ep) + register u_char *cp; + register u_char *bp; + register u_char *ep; +{ + register u_int i; + u_short typ; + + cp = ns_nskip(cp); + + if (cp + 10 > ep) + return; + + /* print the type/qtype and class (if it's not IN) */ + typ = *cp++ << 8; + typ |= *cp++; + i = *cp++ << 8; + if ((i |= *cp++) != C_IN) + if (i == C_ANY) + printf("(c_any)"); + else + printf("(Class %d)", i); + + /* ignore ttl & len */ + cp += 6; + switch (typ) { + case T_A: printf(" A %s", ipaddr_string(cp)); break; + case T_NS: printf(" NS"); ns_nprint(cp, bp, ep); break; + case T_MD: printf(" MD"); break; + case T_MF: printf(" MF"); break; + case T_CNAME: printf(" CNAME"); ns_nprint(cp, bp, ep); break; + case T_SOA: printf(" SOA"); break; + case T_MB: printf(" MB"); break; + case T_MG: printf(" MG"); break; + case T_MR: printf(" MR"); break; + case T_NULL: printf(" NULL"); break; + case T_WKS: printf(" WKS"); break; + case T_PTR: printf(" PTR"); ns_nprint(cp, bp, ep); break; + case T_HINFO: printf(" HINFO"); break; + case T_MINFO: printf(" MINFO"); break; + case T_MX: printf(" MX"); ns_nprint(cp+2, bp, ep); +#ifndef TCPDUMP_ALIGN + printf(" %d", *(short *)cp); +#else + { + u_short x = *cp | cp[1] << 8; + printf(" %d", ntohs(x)); + } +#endif + break; + case T_UINFO: printf(" UINFO"); break; + case T_UID: printf(" UID"); break; + case T_GID: printf(" GID"); break; +#ifdef T_UNSPEC + case T_UNSPEC: printf(" UNSPEC"); break; +#endif + case T_AXFR: printf(" AXFR"); break; + case T_MAILB: printf(" MAILB"); break; + case T_MAILA: printf(" MAILA"); break; + case T_ANY: printf(" ANY"); break; + default: printf(" Type%d", typ); break; + } +} + +void +ns_print(np, length) + register HEADER *np; + int length; +{ + u_char *ep = (u_char *)snapend; + + /* get the byte-order right */ + NTOHS(np->id); + NTOHS(np->qdcount); + NTOHS(np->ancount); + NTOHS(np->nscount); + NTOHS(np->arcount); + + if (np->qr) { + /* this is a response */ + printf(" %d%s%s%s%s%s", + np->id, + ns_ops[np->opcode], + ns_resp[np->rcode], + np->aa? "*" : "", + np->ra? "" : "-", + np->tc? "|" : ""); + if (np->qdcount != 1) + printf(" [%dq]", np->qdcount); + printf(" %d/%d/%d", np->ancount, np->nscount, np->arcount); + if (np->ancount) + ns_rprint(ns_nskip((u_char *)(np + 1)) + 4, + (u_char *)np, ep); + } + else { + /* this is a request */ + printf(" %d%s%s", + np->id, + ns_ops[np->opcode], + np->rd? "+" : ""); + + /* any weirdness? */ + if (*(((u_short *)np)+1) & htons(0x6ff)) + printf(" [b2&3=0x%x]", ntohs(*(((u_short *)np)+1))); + + if (np->opcode == IQUERY) { + if (np->qdcount) + printf(" [%dq]", np->qdcount); + if (np->ancount != 1) + printf(" [%da]", np->ancount); + } + else { + if (np->ancount) + printf(" [%da]", np->ancount); + if (np->qdcount != 1) + printf(" [%dq]", np->qdcount); + } + if (np->nscount) + printf(" [%dn]", np->nscount); + if (np->arcount) + printf(" [%dau]", np->arcount); + + ns_qprint((u_char *)(np + 1), (u_char *)np, ep); + } + printf(" (%d)", length); +} diff --git a/usr.sbin/tcpdump/tcpdump/print-egp.c b/usr.sbin/tcpdump/tcpdump/print-egp.c new file mode 100644 index 000000000000..a88a68364525 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-egp.c @@ -0,0 +1,347 @@ +/* + * Copyright (c) 1991 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Lawrence Berkeley Laboratory, + * Berkeley, CA. The name of the University may not be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Initial contribution from Jeff Honig (jch@MITCHELL.CIT.CORNELL.EDU). + */ +#include <stdio.h> +#include <sys/param.h> +#include <sys/uio.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netdb.h> + +#include "interface.h" +#include "addrtoname.h" + +struct egp_packet { + u_char egp_version; +#define EGP_VERSION 2 + u_char egp_type; +#define EGPT_ACQUIRE 3 +#define EGPT_REACH 5 +#define EGPT_POLL 2 +#define EGPT_UPDATE 1 +#define EGPT_ERROR 8 + u_char egp_code; +#define EGPC_REQUEST 0 +#define EGPC_CONFIRM 1 +#define EGPC_REFUSE 2 +#define EGPC_CEASE 3 +#define EGPC_CEASEACK 4 +#define EGPC_HELLO 0 +#define EGPC_HEARDU 1 + u_char egp_status; +#define EGPS_UNSPEC 0 +#define EGPS_ACTIVE 1 +#define EGPS_PASSIVE 2 +#define EGPS_NORES 3 +#define EGPS_ADMIN 4 +#define EGPS_GODOWN 5 +#define EGPS_PARAM 6 +#define EGPS_PROTO 7 +#define EGPS_INDET 0 +#define EGPS_UP 1 +#define EGPS_DOWN 2 +#define EGPS_UNSOL 0x80 + u_short egp_checksum; + u_short egp_as; + u_short egp_sequence; + union { + u_short egpu_hello; + u_char egpu_gws[2]; + u_short egpu_reason; +#define EGPR_UNSPEC 0 +#define EGPR_BADHEAD 1 +#define EGPR_BADDATA 2 +#define EGPR_NOREACH 3 +#define EGPR_XSPOLL 4 +#define EGPR_NORESP 5 +#define EGPR_UVERSION 6 + } egp_handg; +#define egp_hello egp_handg.egpu_hello +#define egp_intgw egp_handg.egpu_gws[0] +#define egp_extgw egp_handg.egpu_gws[1] +#define egp_reason egp_handg.egpu_reason + union { + u_short egpu_poll; + u_long egpu_sourcenet; + } egp_pands; +#define egp_poll egp_pands.egpu_poll +#define egp_sourcenet egp_pands.egpu_sourcenet +}; + +char *egp_acquire_codes[] = { + "request", + "confirm", + "refuse", + "cease", + "cease_ack" +}; + +char *egp_acquire_status[] = { + "unspecified", + "active_mode", + "passive_mode", + "insufficient_resources", + "administratively_prohibited", + "going_down", + "parameter_violation", + "protocol_violation" +}; + +char *egp_reach_codes[] = { + "hello", + "i-h-u" +}; + +char *egp_status_updown[] = { + "indeterminate", + "up", + "down" +}; + +char *egp_reasons[] = { + "unspecified", + "bad_EGP_header_format", + "bad_EGP_data_field_format", + "reachability_info_unavailable", + "excessive_polling_rate", + "no_response", + "unsupported_version" +}; + +static void +egpnrprint(egp, length) + register struct egp_packet *egp; + register int length; +{ + register u_char *cp, *ep; +#define TCHECK(n) if (cp > ep - n) goto trunc + register u_long addr; + register u_long net; + register int netlen; + int gateways, distances, networks; + int t_gateways; + char *comma; + + addr = egp->egp_sourcenet; + if (IN_CLASSA(addr)) { + net = addr & IN_CLASSA_NET; + netlen = 1; + } else if (IN_CLASSB(addr)) { + net = addr & IN_CLASSB_NET; + netlen = 2; + } else if (IN_CLASSC(addr)) { + net = addr & IN_CLASSC_NET; + netlen = 3; + } else { + net = 0; + netlen = 0; + } + cp = (u_char *)(egp + 1); + ep = snapend; + + t_gateways = egp->egp_intgw + egp->egp_extgw; + for (gateways = 0; gateways < t_gateways; ++gateways) { + /* Pickup host part of gateway address */ + addr = 0; + TCHECK(4 - netlen); + switch (netlen) { + + case 1: + addr = *cp++; + /* fall through */ + case 2: + addr = (addr << 8) | *cp++; + /* fall through */ + case 3: + addr = (addr << 8) | *cp++; + } + addr |= net; + TCHECK(1); + distances = *cp++; + printf(" %s %s ", + gateways < egp->egp_intgw ? "int" : "ext", + intoa(addr)); + + comma = ""; + putchar('('); + while (--distances >= 0) { + TCHECK(2); + printf("%sd%d:", comma, (int)*cp++); + comma = ", "; + networks = *cp++; + while (--networks >= 0) { + /* Pickup network number */ + TCHECK(1); + addr = (u_long)*cp++ << 24; + if (IN_CLASSB(addr)) { + TCHECK(1); + addr |= (u_long)*cp++ << 16; + } else if (!IN_CLASSA(addr)) { + TCHECK(2); + addr |= (u_long)*cp++ << 16; + addr |= (u_long)*cp++ << 8; + } + printf(" %s", intoa(addr)); + } + } + putchar(')'); + } + return; +trunc: + fputs("[|]", stdout); +} + +void +egp_print(egp, length, ip) + register struct egp_packet *egp; + register int length; + register struct ip *ip; +{ + register int status; + register int code; + register int type; + + (void)printf("%s > %s: egp: ", + ipaddr_string(&ip->ip_src), + ipaddr_string(&ip->ip_dst)); + + if (egp->egp_version != EGP_VERSION) { + printf("[version %d]", egp->egp_version); + return; + } + printf("as:%d seq:%d", ntohs(egp->egp_as), ntohs(egp->egp_sequence)); + + type = egp->egp_type; + code = egp->egp_code; + status = egp->egp_status; + + switch (type) { + case EGPT_ACQUIRE: + printf(" acquire"); + switch (code) { + case EGPC_REQUEST: + case EGPC_CONFIRM: + printf(" %s", egp_acquire_codes[code]); + switch (status) { + case EGPS_UNSPEC: + case EGPS_ACTIVE: + case EGPS_PASSIVE: + printf(" %s", egp_acquire_status[status]); + break; + + default: + printf(" [status %d]", status); + break; + } + printf(" hello:%d poll:%d", + ntohs(egp->egp_hello), + ntohs(egp->egp_poll)); + break; + + case EGPC_REFUSE: + case EGPC_CEASE: + case EGPC_CEASEACK: + printf(" %s", egp_acquire_codes[code]); + switch (status ) { + case EGPS_UNSPEC: + case EGPS_NORES: + case EGPS_ADMIN: + case EGPS_GODOWN: + case EGPS_PARAM: + case EGPS_PROTO: + printf(" %s", egp_acquire_status[status]); + break; + + default: + printf("[status %d], status"); + break; + } + break; + + default: + printf("[code %d]", code); + break; + } + break; + + case EGPT_REACH: + switch (code) { + + case EGPC_HELLO: + case EGPC_HEARDU: + printf(" %s", egp_reach_codes[code]); + if (status <= EGPS_DOWN) + printf(" state:%s", egp_status_updown[status]); + else + printf(" [status %d], status"); + break; + + default: + printf("[reach code %d], code"); + break; + } + break; + + case EGPT_POLL: + printf(" poll"); + if (egp->egp_status <= EGPS_DOWN) + printf(" state:%s", egp_status_updown[status]); + else + printf(" [status %d]", status); + printf(" net:%s", intoa(egp->egp_sourcenet)); + break; + + case EGPT_UPDATE: + printf(" update"); + if (status & EGPS_UNSOL) { + status &= ~EGPS_UNSOL; + printf(" unsolicitied"); + } + if (status <= EGPS_DOWN) + printf(" state:%s", egp_status_updown[status]); + else + printf(" [status %d]", status); + printf(" %s int %d ext %d", + intoa(egp->egp_sourcenet), + egp->egp_intgw, + egp->egp_extgw); + if (vflag) + egpnrprint(egp, length); + break; + + case EGPT_ERROR: + printf(" error"); + if (status <= EGPS_DOWN) + printf(" state:%s", egp_status_updown[status]); + else + printf(" [status]", status); + + if (ntohs(egp->egp_reason) <= EGPR_UVERSION) + printf(" %s", egp_reasons[ntohs(egp->egp_reason)]); + else + printf(" [reason]", ntohs(egp->egp_reason)); + break; + + default: + printf("[type %d]", type); + break; + } +} diff --git a/usr.sbin/tcpdump/tcpdump/print-ether.c b/usr.sbin/tcpdump/tcpdump/print-ether.c new file mode 100644 index 000000000000..2d01c17ce17c --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-ether.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#ifndef lint +static char rcsid[] = + "@(#) $Header: print-ether.c,v 1.22 91/10/07 20:18:28 leres Exp $ (LBL)"; +#endif + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> + +#include "interface.h" +#include "addrtoname.h" + +u_char *packetp; +u_char *snapend; + +static inline void +ether_print(ep, length) + register struct ether_header *ep; + int length; +{ + if (qflag) + (void)printf("%s %s %d: ", + etheraddr_string(ESRC(ep)), + etheraddr_string(EDST(ep)), + length); + else + (void)printf("%s %s %s %d: ", + etheraddr_string(ESRC(ep)), + etheraddr_string(EDST(ep)), + etherproto_string(ep->ether_type), + length); +} + +/* + * This is the top level routine of the printer. 'p' is the points + * to the ether header of the packet, 'tvp' is the timestamp, + * 'length' is the length of the packet off the wire, and 'caplen' + * is the number of bytes actually captured. + */ +void +ether_if_print(p, tvp, length, caplen) + u_char *p; + struct timeval *tvp; + int length; + int caplen; +{ + struct ether_header *ep; + register int i; + + ts_print(tvp); + + if (caplen < sizeof(struct ether_header)) { + printf("[|ether]"); + goto out; + } + + if (eflag) + ether_print((struct ether_header *)p, length); + + /* + * Some printers want to get back at the ethernet addresses, + * and/or check that they're not walking off the end of the packet. + * Rather than pass them all the way down, we set these globals. + */ + packetp = p; + snapend = p + caplen; + + length -= sizeof(struct ether_header); + ep = (struct ether_header *)p; + p += sizeof(struct ether_header); + switch (ntohs(ep->ether_type)) { + + case ETHERTYPE_IP: + ip_print((struct ip *)p, length); + break; + + case ETHERTYPE_ARP: + case ETHERTYPE_REVARP: + arp_print((struct ether_arp *)p, length, caplen - sizeof(*ep)); + break; + + default: + if (!eflag) + ether_print(ep, length); + if (!xflag && !qflag) + default_print((u_short *)p, caplen - sizeof(*ep)); + break; + } + if (xflag) + default_print((u_short *)p, caplen - sizeof(*ep)); + out: + putchar('\n'); +} diff --git a/usr.sbin/tcpdump/tcpdump/print-fddi.c b/usr.sbin/tcpdump/tcpdump/print-fddi.c new file mode 100644 index 000000000000..77831126088e --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-fddi.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#)$Header: print-fddi.c,v 1.4 92/02/03 16:04:02 van Exp $ (LBL)"; +#endif + +#ifdef FDDI +#include <stdio.h> +#include <netdb.h> +#include <ctype.h> +#include <signal.h> +#include <errno.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/timeb.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/mbuf.h> +#include <sys/ioctl.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> + +#include <net/bpf.h> + +#include "interface.h" +#include "addrtoname.h" + +/* + * NOTE: This is a very preliminary hack for FDDI support. + * There are all sorts of wired in constants & nothing (yet) + * to print SMT packets as anything other than hex dumps. + * Most of the necessary changes are waiting on my redoing + * the "header" that a kernel fddi driver supplies to bpf: I + * want it to look like one byte of 'direction' (0 or 1 + * depending on whether the packet was inbound or outbound), + * two bytes of system/driver dependent data (anything an + * implementor thinks would be useful to filter on and/or + * save per-packet, then the real 21-byte FDDI header. + * Steve McCanne & I have also talked about adding the + * 'direction' byte to all bpf headers (e.g., in the two + * bytes of padding on an ethernet header). It's not clear + * we could do this in a backwards compatible way & we hate + * the idea of an incompatible bpf change. Discussions are + * proceeding. + * + * Also, to really support FDDI (and better support 802.2 + * over ethernet) we really need to re-think the rather simple + * minded assumptions about fixed length & fixed format link + * level headers made in gencode.c. One day... + * + * - vj + */ + +/* XXX This goes somewhere else. */ +#define FDDI_HDRLEN 21 + +static u_char fddi_bit_swap[] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +}; + +static inline void +fddi_print(p, length) + u_char *p; + int length; +{ + u_char fsrc[6], fdst[6]; + register char *srcname, *dstname; + register int i; + + /* + * bit-swap the fddi addresses (isn't the IEEE standards + * process wonderful!) then convert them to names. + */ + + for (i = 0; i < sizeof(fdst); ++i) + fdst[i] = fddi_bit_swap[p[i+1]]; + for (i = 0; i < sizeof(fsrc); ++i) + fsrc[i] = fddi_bit_swap[p[i+7]]; + dstname = etheraddr_string(fdst); + srcname = etheraddr_string(fsrc); + + if (vflag) + printf("%s %s %02x %02x %02x %02x %02x%02x%02x %s %d: ", + dstname, srcname, + p[0], + p[13], p[14], p[15], + p[16], p[17], p[18], + etherproto_string((p[19] << 8) | p[20]), + length); + else if (qflag) + printf("%s %s %d: ", dstname, srcname, length); + else + printf("%s %s %02x %s %d: ", + dstname, srcname, + p[0], + etherproto_string((p[19] << 8) | p[20]), + length); +} + +void +fddi_if_print(p, tvp, length, caplen) + u_char *p; + struct timeval *tvp; + int length; + int caplen; +{ + struct ip *ip; + u_short type; + + ts_print(tvp); + + if (caplen < FDDI_HDRLEN) { + printf("[|fddi]"); + goto out; + } + + /* + * Some printers want to get back at the link level addresses, + * and/or check that they're not walking off the end of the packet. + * Rather than pass them all the way down, we set these globals. + */ + packetp = (u_char *)p; + snapend = (u_char *)p + caplen; + + /* + * If the frame is not an LLC frame or is not an LLC/UI frame + * or doesn't have SNAP as a dest NSAP, use the default printer. + * (XXX - should interpret SMT packets here.) + */ + if ((p[0] & 0xf8) != 0x50) + /* not LLC frame -- use default printer */ + type = 0; + else if ((p[15] &~ 0x10) != 0x03) + /* not UI frame -- use default printer */ + type = 0; + else if (p[13] != 170) + /* DSAP not SNAP -- use default printer */ + type = 0; + else + type = (p[19] << 8) | p[20]; + if (eflag) + fddi_print(p, length); + + length -= FDDI_HDRLEN; + p += FDDI_HDRLEN; + + switch (ntohs(type)) { + + case ETHERTYPE_IP: + ip_print((struct ip *)p, length); + break; + + case ETHERTYPE_ARP: + case ETHERTYPE_REVARP: + arp_print((struct ether_arp *)p, length, caplen - FDDI_HDRLEN); + break; + + default: + if (!eflag) + fddi_print(p, length); + if (!xflag && !qflag) + default_print((u_short *)p, caplen - FDDI_HDRLEN); + break; + } + if (xflag) + default_print((u_short *)p, caplen - sizeof(FDDI_HDRLEN)); +out: + putchar('\n'); +} +#else +#include <stdio.h> +void +fddi_if_print() +{ + void error(); + + error("not configured for fddi"); + /* NOTREACHED */ +} +#endif diff --git a/usr.sbin/tcpdump/tcpdump/print-icmp.c b/usr.sbin/tcpdump/tcpdump/print-icmp.c new file mode 100644 index 000000000000..928d8664517d --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-icmp.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#) $Header: print-icmp.c,v 1.11 91/03/27 17:42:58 leres Exp $ (LBL)"; +#endif + +#include <stdio.h> + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> + +#include <netinet/ip_icmp.h> + +#include "interface.h" +#include "addrtoname.h" + +void +icmp_print(dp, ip) + register struct icmp *dp; + register struct ip *ip; +{ + char buf[256]; + register char *str = buf; + register struct ip *oip; + register struct udphdr *ouh; + register int hlen; + u_char *ep; + +#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc + + /* 'ep' points to the end of avaible data. */ + ep = (u_char *)snapend; + + (void)printf("%s > %s: ", + ipaddr_string(&ip->ip_src), + ipaddr_string(&ip->ip_dst)); + strcpy(str, "[?]"); + + TCHECK(dp->icmp_code, sizeof(dp->icmp_code)); + switch (dp->icmp_type) { + case ICMP_ECHOREPLY: + str = "echo reply"; + break; + case ICMP_UNREACH: + TCHECK(dp->icmp_ip.ip_dst, sizeof(dp->icmp_ip.ip_dst)); + switch (dp->icmp_code) { + case ICMP_UNREACH_NET: + (void)sprintf(buf, "net %s unreachable", + ipaddr_string(&dp->icmp_ip.ip_dst)); + break; + case ICMP_UNREACH_HOST: + (void)sprintf(buf, "host %s unreachable", + ipaddr_string(&dp->icmp_ip.ip_dst)); + break; + case ICMP_UNREACH_PROTOCOL: + TCHECK(dp->icmp_ip.ip_p, sizeof(dp->icmp_ip.ip_p)); + (void)sprintf(buf, "%s protocol %d unreachable", + ipaddr_string(&dp->icmp_ip.ip_dst), + dp->icmp_ip.ip_p); + break; + case ICMP_UNREACH_PORT: + TCHECK(dp->icmp_ip.ip_p, sizeof(dp->icmp_ip.ip_p)); + oip = &dp->icmp_ip; + hlen = oip->ip_hl * 4; + ouh = (struct udphdr *)(((u_char *)oip) + hlen); + NTOHS(ouh->uh_dport); + switch (oip->ip_p) { + case IPPROTO_TCP: + (void)sprintf(buf, + "%s tcp port %s unreachable", + ipaddr_string(&oip->ip_dst), + tcpport_string(ouh->uh_dport)); + break; + case IPPROTO_UDP: + (void)sprintf(buf, + "%s udp port %s unreachable", + ipaddr_string(&oip->ip_dst), + udpport_string(ouh->uh_dport)); + break; + default: + (void)sprintf(buf, + "%s protocol %d port %d unreachable", + ipaddr_string(&oip->ip_dst), + oip->ip_p, ouh->uh_dport); + break; + } + break; + case ICMP_UNREACH_NEEDFRAG: + (void)sprintf(buf, "%s unreachable - need to frag", + ipaddr_string(&dp->icmp_ip.ip_dst)); + break; + case ICMP_UNREACH_SRCFAIL: + (void)sprintf(buf, + "%s unreachable - source route failed", + ipaddr_string(&dp->icmp_ip.ip_dst)); + break; + } + break; + case ICMP_SOURCEQUENCH: + str = "source quench"; + break; + case ICMP_REDIRECT: + TCHECK(dp->icmp_ip.ip_dst, sizeof(dp->icmp_ip.ip_dst)); + switch (dp->icmp_code) { + case ICMP_REDIRECT_NET: + (void)sprintf(buf, "redirect %s to net %s", + ipaddr_string(&dp->icmp_ip.ip_dst), + ipaddr_string(&dp->icmp_gwaddr)); + break; + case ICMP_REDIRECT_HOST: + (void)sprintf(buf, "redirect %s to host %s", + ipaddr_string(&dp->icmp_ip.ip_dst), + ipaddr_string(&dp->icmp_gwaddr)); + break; + case ICMP_REDIRECT_TOSNET: + (void)sprintf(buf, "redirect-tos %s to net %s", + ipaddr_string(&dp->icmp_ip.ip_dst), + ipaddr_string(&dp->icmp_gwaddr)); + break; + case ICMP_REDIRECT_TOSHOST: + (void)sprintf(buf, "redirect-tos %s to host %s", + ipaddr_string(&dp->icmp_ip.ip_dst), + ipaddr_string(&dp->icmp_gwaddr)); + break; + } + break; + case ICMP_ECHO: + str = "echo request"; + break; + case ICMP_TIMXCEED: + TCHECK(dp->icmp_ip.ip_dst, sizeof(dp->icmp_ip.ip_dst)); + switch (dp->icmp_code) { + case ICMP_TIMXCEED_INTRANS: + str = "time exceeded in-transit"; + break; + case ICMP_TIMXCEED_REASS: + str = "ip reassembly time exceeded"; + break; + } + break; + case ICMP_PARAMPROB: + if (dp->icmp_code) + (void)sprintf(buf, "parameter problem - code %d", + dp->icmp_code); + else { + TCHECK(dp->icmp_pptr, sizeof(dp->icmp_pptr)); + (void)sprintf(buf, "parameter problem - octet %d", + dp->icmp_pptr); + } + break; + case ICMP_TSTAMP: + str = "time stamp request"; + break; + case ICMP_TSTAMPREPLY: + str = "time stamp reply"; + break; + case ICMP_IREQ: + str = "information request"; + break; + case ICMP_IREQREPLY: + str = "information reply"; + break; + case ICMP_MASKREQ: + str = "address mask request"; + break; + case ICMP_MASKREPLY: + TCHECK(dp->icmp_mask, sizeof(dp->icmp_mask)); + (void)sprintf(buf, "address mask is 0x%08x", dp->icmp_mask); + break; + } + (void)printf("icmp: %s", str); + return; +trunc: + fputs("[|icmp]", stdout); +#undef TCHECK +} diff --git a/usr.sbin/tcpdump/tcpdump/print-ip.c b/usr.sbin/tcpdump/tcpdump/print-ip.c new file mode 100644 index 000000000000..8716a016d14a --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-ip.c @@ -0,0 +1,313 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#) $Header: print-ip.c,v 1.28 92/05/25 14:29:02 mccanne Exp $ (LBL)"; +#endif + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> + +#include "interface.h" +#include "addrtoname.h" + +void +igmp_print(cp, len, ip) + register u_char *cp; + register int len; + register struct ip *ip; +{ + register u_char *ep = (u_char *)snapend; + + (void)printf("%s > %s: ", + ipaddr_string(&ip->ip_src), + ipaddr_string(&ip->ip_dst)); + + if (cp + 7 > ep) { + (void)printf("[|igmp]"); + return; + } + switch (cp[0] & 0xf) { + case 1: + (void)printf("igmp query"); + if (*(int *)&cp[4]) + (void)printf(" [gaddr %s]", ipaddr_string(&cp[4])); + if (len != 8) + (void)printf(" [len %d]", len); + break; + case 2: + (void)printf("igmp report %s", ipaddr_string(&cp[4])); + if (len != 8) + (void)printf(" [len %d]", len); + break; + case 3: + (void)printf("igmp dvmrp", ipaddr_string(&cp[4])); + if (len < 8) + (void)printf(" [len %d]", len); + break; + default: + (void)printf("igmp-%d", cp[0] & 0xf); + break; + } + if ((cp[0] >> 4) != 1) + (void)printf(" [v%d]", cp[0] >> 4); + if (cp[1]) + (void)printf(" [b1=0x%x]", cp[1]); +} + +/* + * print the recorded route in an IP RR, LSRR or SSRR option. + */ +static void +ip_printroute(type, cp, length) + char *type; + register u_char *cp; + int length; +{ + int ptr = cp[2] - 1; + int len; + + printf(" %s{", type); + if ((length + 1) & 3) + printf(" [bad length %d]", length); + if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1) + printf(" [bad ptr %d]", cp[2]); + + type = ""; + for (len = 3; len < length; len += 4) { + if (ptr == len) + type = "#"; +#ifdef TCPDUMP_ALIGN + { + struct in_addr addr; + bcopy((char *)&cp[len], (char *)&addr, sizeof(addr)); + printf("%s%s", type, ipaddr_string(&addr)); + } +#else + printf("%s%s", type, ipaddr_string(&cp[len])); +#endif + type = " "; + } + printf("%s}", ptr == len? "#" : ""); +} + +/* + * print IP options. + */ +static void +ip_optprint(cp, length) + register u_char *cp; + int length; +{ + int len; + + for (; length > 0; cp += len, length -= len) { + int tt = *cp; + + len = (tt == IPOPT_NOP || tt == IPOPT_EOL) ? 1 : cp[1]; + if (&cp[1] >= snapend || cp + len > snapend) { + printf("[|ip]"); + return; + } + switch (tt) { + + case IPOPT_EOL: + printf(" EOL"); + if (length > 1) + printf("-%d", length - 1); + return; + + case IPOPT_NOP: + printf(" NOP"); + break; + + case IPOPT_TS: + printf(" TS{%d}", len); + break; + + case IPOPT_SECURITY: + printf(" SECURITY{%d}", len); + break; + + case IPOPT_RR: + printf(" RR{%d}=", len); + ip_printroute("RR", cp, len); + break; + + case IPOPT_SSRR: + ip_printroute("SSRR", cp, len); + break; + + case IPOPT_LSRR: + ip_printroute("LSRR", cp, len); + break; + + default: + printf(" IPOPT-%d{%d}", cp[0], len); + break; + } + } +} + +/* + * print an IP datagram. + */ +void +ip_print(ip, length) + register struct ip *ip; + register int length; +{ + register int hlen; + register int len; + register unsigned char *cp; + +#ifdef TCPDUMP_ALIGN + static u_char *abuf; + /* + * The IP header is not word aligned, so copy into abuf. + * This will never happen with BPF. It does happen raw packet + * dumps from -r. + */ + if ((int)ip & (sizeof(long)-1)) { + if (abuf == 0) + abuf = (u_char *)malloc(snaplen); + bcopy((char *)ip, (char *)abuf, min(length, snaplen)); + snapend += abuf - (u_char *)ip; + packetp = abuf; + ip = (struct ip *)abuf; + } +#endif + if ((u_char *)(ip + 1) > snapend) { + printf("[|ip]"); + return; + } + if (length < sizeof (struct ip)) { + (void)printf("truncated-ip %d", length); + return; + } + hlen = ip->ip_hl * 4; + + NTOHS(ip->ip_len); + NTOHS(ip->ip_off); + NTOHS(ip->ip_id); + + len = ip->ip_len - hlen; + if (length < ip->ip_len) + (void)printf("truncated-ip - %d bytes missing!", + ip->ip_len - length); + + /* + * If this is fragment zero, hand it to the next higher + * level protocol. + */ + if ((ip->ip_off & 0x1fff) == 0) { + cp = (unsigned char *)ip + hlen; + switch (ip->ip_p) { + + case IPPROTO_TCP: + tcp_print((struct tcphdr *)cp, len, ip); + break; + case IPPROTO_UDP: + udp_print((struct udphdr *)cp, len, ip); + break; + case IPPROTO_ICMP: + icmp_print((struct icmp *)cp, ip); + break; + case IPPROTO_ND: + (void)printf("%s > %s:", ipaddr_string(&ip->ip_src), + ipaddr_string(&ip->ip_dst)); + (void)printf(" nd %d", len); + break; + case IPPROTO_EGP: + egp_print((struct egp_packet *)cp, len, ip); + break; +#ifndef IPPROTO_OSPF +#define IPPROTO_OSPF 89 +#endif + case IPPROTO_OSPF: + ospf_print((struct ospfhdr *)cp, len, ip); + break; +#ifndef IPPROTO_IGMP +#define IPPROTO_IGMP 2 +#endif + case IPPROTO_IGMP: + igmp_print(cp, len, ip); + break; + default: + (void)printf("%s > %s:", ipaddr_string(&ip->ip_src), + ipaddr_string(&ip->ip_dst)); + (void)printf(" ip-proto-%d %d", ip->ip_p, len); + break; + } + } + /* + * for fragmented datagrams, print id:size@offset. On all + * but the last stick a "+". For unfragmented datagrams, note + * the don't fragment flag. + */ + if (ip->ip_off & 0x3fff) { + /* + * if this isn't the first frag, we're missing the + * next level protocol header. print the ip addr. + */ + if (ip->ip_off & 0x1fff) + (void)printf("%s > %s:", ipaddr_string(&ip->ip_src), + ipaddr_string(&ip->ip_dst)); + (void)printf(" (frag %d:%d@%d%s)", ip->ip_id, len, + (ip->ip_off & 0x1fff) * 8, + (ip->ip_off & IP_MF)? "+" : ""); + } else if (ip->ip_off & IP_DF) + (void)printf(" (DF)"); + + if (ip->ip_tos) + (void)printf(" [tos 0x%x]", (int)ip->ip_tos); + if (ip->ip_ttl <= 1) + (void)printf(" [ttl %d]", (int)ip->ip_ttl); + + if (vflag) { + char *sep = ""; + + printf(" ("); + if (ip->ip_ttl > 1) { + (void)printf("%sttl %d", sep, (int)ip->ip_ttl); + sep = ", "; + } + if ((ip->ip_off & 0x3fff) == 0) { + (void)printf("%sid %d", sep, (int)ip->ip_id); + sep = ", "; + } + if ((hlen -= sizeof(struct ip)) > 0) { + (void)printf("%soptlen=%d", sep, hlen); + ip_optprint((u_char *)(ip + 1), hlen); + } + printf(")"); + } +} diff --git a/usr.sbin/tcpdump/tcpdump/print-nfs.c b/usr.sbin/tcpdump/tcpdump/print-nfs.c new file mode 100644 index 000000000000..8b3169771184 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-nfs.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 1990, 1991, 1992 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#) $Header: print-nfs.c,v 1.24 92/01/31 12:27:46 mccanne Exp $ (LBL)"; +#endif + +#include <stdio.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> + +#include <sys/time.h> +#include <errno.h> +#include <rpc/types.h> +#include <rpc/auth.h> +#include <rpc/auth_unix.h> +#include <rpc/svc.h> +#include <rpc/xdr.h> +#include <rpc/rpc_msg.h> + +#include <ctype.h> + +#include "interface.h" +/* These must come after interface.h for BSD. */ +#if BSD >= 199006 +#include <sys/ucred.h> +#include <nfs/nfsv2.h> +#endif +#include <nfs/nfs.h> + +#include "addrtoname.h" +#include "extract.h" + +static void nfs_printfh(); +static void nfs_printfn(); + +#if BYTE_ORDER == LITTLE_ENDIAN +/* + * Byte swap an array of n words. + * Assume input is word-aligned. + * Check that buffer is bounded by "snapend". + */ +static void +bswap(bp, n) + register u_long *bp; + register u_int n; +{ + register int nwords = ((char *)snapend - (char *)bp) / sizeof(*bp); + + if (nwords > n) + nwords = n; + for (; --nwords >= 0; ++bp) + *bp = ntohl(*bp); +} +#endif + +void +nfsreply_print(rp, length, ip) + register struct rpc_msg *rp; + int length; + register struct ip *ip; +{ +#if BYTE_ORDER == LITTLE_ENDIAN + bswap((u_long *)rp, sizeof(*rp) / sizeof(u_long)); +#endif + if (!nflag) + (void)printf("%s.nfs > %s.%x: reply %s %d", + ipaddr_string(&ip->ip_src), + ipaddr_string(&ip->ip_dst), + rp->rm_xid, + rp->rm_reply.rp_stat == MSG_ACCEPTED? "ok":"ERR", + length); + else + (void)printf("%s.%x > %s.%x: reply %s %d", + ipaddr_string(&ip->ip_src), + NFS_PORT, + ipaddr_string(&ip->ip_dst), + rp->rm_xid, + rp->rm_reply.rp_stat == MSG_ACCEPTED? "ok":"ERR", + length); +} + +/* + * Return a pointer to the first file handle in the packet. + * If the packet was truncated, return 0. + */ +static u_long * +parsereq(rp, length) + register struct rpc_msg *rp; + register int length; +{ + register u_long *dp = (u_long *)&rp->rm_call.cb_cred; + register u_long *ep = (u_long *)snapend; + + /* + * find the start of the req data (if we captured it) + * note that dp[1] was already byte swapped by bswap() + */ + if (dp < ep && dp[1] < length) { + dp += (dp[1] + (2*sizeof(u_long) + 3)) / sizeof(u_long); + if ((dp < ep) && (dp[1] < length)) { + dp += (dp[1] + (2*sizeof(u_long) + 3)) / + sizeof(u_long); + if (dp < ep) + return (dp); + } + } + return (0); +} + +/* + * Print out an NFS file handle and return a pointer to following word. + * If packet was truncated, return 0. + */ +static u_long * +parsefh(dp) + register u_long *dp; +{ + if (dp + 8 <= (u_long *)snapend) { + nfs_printfh(dp); + return (dp + 8); + } + return (0); +} + +/* + * Print out a file name and return pointer to longword past it. + * If packet was truncated, return 0. + */ +static u_long * +parsefn(dp) + register u_long *dp; +{ + register int len; + register u_char *cp; + + /* Bail if we don't have the string length */ + if ((u_char *)dp > snapend - sizeof(*dp)) + return(0); + + /* Fetch string length; convert to host order */ + len = *dp++; + NTOHL(len); + + cp = (u_char *)dp; + /* Update long pointer (NFS filenames are padded to long) */ + dp += ((len + 3) & ~3) / sizeof(*dp); + if ((u_char *)dp > snapend) + return (0); + nfs_printfn(cp, len); + + return (dp); +} + +/* + * Print out file handle and file name. + * Return pointer to longword past file name. + * If packet was truncated (or there was some other error), return 0. + */ +static u_long * +parsefhn(dp) + register u_long *dp; +{ + dp = parsefh(dp); + if (dp == 0) + return (0); + putchar(' '); + return (parsefn(dp)); +} + +void +nfsreq_print(rp, length, ip) + register struct rpc_msg *rp; + int length; + register struct ip *ip; +{ + register u_long *dp; + register u_char *ep = snapend; +#define TCHECK(p, l) if ((u_char *)(p) > ep - l) break + +#if BYTE_ORDER == LITTLE_ENDIAN + bswap((u_long *)rp, sizeof(*rp) / sizeof(u_long)); +#endif + + if (!nflag) + (void)printf("%s.%x > %s.nfs: %d", + ipaddr_string(&ip->ip_src), + rp->rm_xid, + ipaddr_string(&ip->ip_dst), + length); + else + (void)printf("%s.%x > %s.%x: %d", + ipaddr_string(&ip->ip_src), + rp->rm_xid, + ipaddr_string(&ip->ip_dst), + NFS_PORT, + length); + + switch (rp->rm_call.cb_proc) { +#ifdef NFSPROC_NOOP + case NFSPROC_NOOP: + printf(" nop"); + return; +#else +#define NFSPROC_NOOP -1 +#endif + case RFS_NULL: + printf(" null"); + return; + + case RFS_GETATTR: + printf(" getattr"); + if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0) + return; + break; + + case RFS_SETATTR: + printf(" setattr"); + if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0) + return; + break; + +#if RFS_ROOT != NFSPROC_NOOP + case RFS_ROOT: + printf(" root"); + break; +#endif + case RFS_LOOKUP: + printf(" lookup"); + if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0) + return; + break; + + case RFS_READLINK: + printf(" readlink"); + if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0) + return; + break; + + case RFS_READ: + printf(" read"); + if ((dp = parsereq(rp, length)) != 0 && + (dp = parsefh(dp)) != 0) { + TCHECK(dp, 3 * sizeof(*dp)); + printf(" %lu (%lu) bytes @ %lu", + ntohl(dp[1]), ntohl(dp[2]), ntohl(dp[0])); + return; + } + break; + +#if RFS_WRITECACHE != NFSPROC_NOOP + case RFS_WRITECACHE: + printf(" writecache"); + if ((dp = parsereq(rp, length)) != 0 && + (dp = parsefh(dp)) != 0) { + TCHECK(dp, 4 * sizeof(*dp)); + printf(" %lu (%lu) bytes @ %lu (%lu)", + ntohl(dp[3]), ntohl(dp[2]), + ntohl(dp[1]), ntohl(dp[0])); + return; + } + break; +#endif + case RFS_WRITE: + printf(" write"); + if ((dp = parsereq(rp, length)) != 0 && + (dp = parsefh(dp)) != 0) { + TCHECK(dp, 4 * sizeof(*dp)); + printf(" %lu (%lu) bytes @ %lu (%lu)", + ntohl(dp[3]), ntohl(dp[2]), + ntohl(dp[1]), ntohl(dp[0])); + return; + } + break; + + case RFS_CREATE: + printf(" create"); + if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0) + return; + break; + + case RFS_REMOVE: + printf(" remove"); + if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0) + return; + break; + + case RFS_RENAME: + printf(" rename"); + if ((dp = parsereq(rp, length)) != 0 && + (dp = parsefhn(dp)) != 0) { + fputs(" ->", stdout); + if (parsefhn(dp) != 0) + return; + } + break; + + case RFS_LINK: + printf(" link"); + if ((dp = parsereq(rp, length)) != 0 && + (dp = parsefh(dp)) != 0) { + fputs(" ->", stdout); + if (parsefhn(dp) != 0) + return; + } + break; + + case RFS_SYMLINK: + printf(" symlink"); + if ((dp = parsereq(rp, length)) != 0 && + (dp = parsefhn(dp)) != 0) { + fputs(" -> ", stdout); + if (parsefn(dp) != 0) + return; + } + break; + + case RFS_MKDIR: + printf(" mkdir"); + if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0) + return; + break; + + case RFS_RMDIR: + printf(" rmdir"); + if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0) + return; + break; + + case RFS_READDIR: + printf(" readdir"); + if ((dp = parsereq(rp, length)) != 0 && + (dp = parsefh(dp)) != 0) { + TCHECK(dp, 2 * sizeof(*dp)); + printf(" %lu bytes @ %lu", ntohl(dp[1]), ntohl(dp[0])); + return; + } + break; + + case RFS_STATFS: + printf(" statfs"); + if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0) + return; + break; + + default: + printf(" proc-%lu", rp->rm_call.cb_proc); + return; + } + fputs(" [|nfs]", stdout); +#undef TCHECK +} + +/* + * Print out an NFS file handle. + * We assume packet was not truncated before the end of the + * file handle pointed to by dp. + */ +static void +nfs_printfh(dp) + register u_long *dp; +{ + /* + * take a wild guess at the structure of file handles. + * On sun 3s, there are 2 longs of fsid, a short + * len == 8, a long of inode & a long of generation number. + * On sun 4s, the len == 10 & there are 2 bytes of + * padding immediately following it. + */ + if (dp[2] == 0xa0000) { + if (dp[1]) + (void) printf(" fh %ld.%ld.%lu", dp[0], dp[1], dp[3]); + else + (void) printf(" fh %ld.%ld", dp[0], dp[3]); + } else if ((dp[2] >> 16) == 8) + /* + * 'dp' is longword aligned, so we must use the extract + * macros below for dp+10 which cannot possibly be aligned. + */ + if (dp[1]) + (void) printf(" fh %ld.%ld.%lu", dp[0], dp[1], + EXTRACT_LONG((u_char *)dp + 10)); + else + (void) printf(" fh %ld.%ld", dp[0], + EXTRACT_LONG((u_char *)dp + 10)); + /* On Ultrix pre-4.0, three longs: fsid, fno, fgen and then zeros */ + else if (dp[3] == 0) { + (void)printf(" fh %d,%d/%ld.%ld", major(dp[0]), minor(dp[0]), + dp[1], dp[2]); + } + /* + * On Ultrix 4.0, + * five longs: fsid, fno, fgen, eno, egen and then zeros + */ + else if (dp[5] == 0) { + (void)printf(" fh %d,%d/%ld.%ld", major(dp[0]), minor(dp[0]), + dp[1], dp[2]); + if (vflag) { + /* print additional info */ + (void)printf("[%ld.%ld]", dp[3], dp[4]); + } + } + else + (void) printf(" fh %lu.%lu.%lu.%lu", + dp[0], dp[1], dp[2], dp[3]); +} + +/* + * Print out an NFS filename. + * Assumes that len bytes from cp are present in packet. + */ +static void +nfs_printfn(cp, len) + register u_char *cp; + register int len; +{ + register char c; + + /* Sanity */ + if (len >= 64) { + fputs("[\">]", stdout); + return; + } + /* Print out the filename */ + putchar('"'); + while (--len >= 0) { + c = toascii(*cp++); + if (!isascii(c)) { + c = toascii(c); + putchar('M'); + putchar('-'); + } + if (!isprint(c)) { + c ^= 0x40; /* DEL to ?, others to alpha */ + putchar('^'); + } + putchar(c); + } + putchar('"'); +} diff --git a/usr.sbin/tcpdump/tcpdump/print-ntp.c b/usr.sbin/tcpdump/tcpdump/print-ntp.c new file mode 100644 index 000000000000..86f6ba76c1f2 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-ntp.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Format and print ntp packets. + * By Jeffrey Mogul/DECWRL + * loosely based on print-bootp.c + */ + +#ifndef lint +static char rcsid[] = + "@(#) $Header: print-ntp.c,v 1.7 92/01/04 01:45:16 leres Exp $ (LBL)"; +#endif + +#include <stdio.h> + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <strings.h> +#include <ctype.h> + +#include "interface.h" +#include "addrtoname.h" +#include "ntp.h" + +/* + * Print ntp requests + */ +void +ntp_print(bp, length) + register struct ntpdata *bp; + int length; +{ + u_char *ep; + int mode, version, leapind; + static char rclock[5]; + +#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc + + /* Note funny sized packets */ + if (length != sizeof(struct ntpdata)) + (void)printf(" [len=%d]", length); + + /* 'ep' points to the end of avaible data. */ + ep = (u_char *)snapend; + + TCHECK(bp->status, sizeof(bp->status)); + + version = (bp->status & VERSIONMASK) >> 3; + printf(" v%d", version); + + leapind = bp->status & LEAPMASK; + switch (leapind) { + + case NO_WARNING: + break; + + case PLUS_SEC: + fputs(" +1s", stdout); + break; + + case MINUS_SEC: + fputs(" -1s", stdout); + break; + } + + mode = bp->status & MODEMASK; + switch (mode) { + + case MODE_UNSPEC: /* unspecified */ + fputs(" unspec", stdout); + break; + + case MODE_SYM_ACT: /* symmetric active */ + fputs(" sym_act", stdout); + break; + + case MODE_SYM_PAS: /* symmetric passive */ + fputs(" sym_pas", stdout); + break; + + case MODE_CLIENT: /* client */ + fputs(" client", stdout); + break; + + case MODE_SERVER: /* server */ + fputs(" server", stdout); + break; + + case MODE_BROADCAST: /* broadcast */ + fputs(" bcast", stdout); + break; + + case MODE_RES1: /* reserved */ + fputs(" res1", stdout); + break; + + case MODE_RES2: /* reserved */ + fputs(" res2", stdout); + break; + + } + + TCHECK(bp->stratum, sizeof(bp->stratum)); + printf(" strat %d", bp->stratum); + + TCHECK(bp->ppoll, sizeof(bp->ppoll)); + printf(" poll %d", bp->ppoll); + + /* Can't TCHECK bp->precision bitfield so bp->distance + 0 instead */ + TCHECK(bp->distance, 0); + printf(" prec %d", bp->precision); + + if (!vflag) + return; + + TCHECK(bp->distance, sizeof(bp->distance)); + fputs(" dist ", stdout); + p_sfix(&bp->distance); + + TCHECK(bp->dispersion, sizeof(bp->dispersion)); + fputs(" disp ", stdout); + p_sfix(&bp->dispersion); + + TCHECK(bp->refid, sizeof(bp->refid)); + fputs(" ref ", stdout); + /* Interpretation depends on stratum */ + switch (bp->stratum) { + + case UNSPECIFIED: + case PRIM_REF: + strncpy(rclock, (char *)&(bp->refid), 4); + rclock[4] = '\0'; + fputs(rclock, stdout); + break; + + case INFO_QUERY: + printf("%s INFO_QUERY", ipaddr_string(&(bp->refid))); + /* this doesn't have more content */ + return; + + case INFO_REPLY: + printf("%s INFO_REPLY", ipaddr_string(&(bp->refid))); + /* this is too complex to be worth printing */ + return; + + default: + printf("%s", ipaddr_string(&(bp->refid))); + break; + } + + TCHECK(bp->reftime, sizeof(bp->reftime)); + putchar('@'); + p_ntp_time(&(bp->reftime)); + + TCHECK(bp->org, sizeof(bp->org)); + fputs(" orig ", stdout); + p_ntp_time(&(bp->org)); + + TCHECK(bp->rec, sizeof(bp->rec)); + fputs(" rec ", stdout); + p_ntp_delta(&(bp->org), &(bp->rec)); + + TCHECK(bp->xmt, sizeof(bp->xmt)); + fputs(" xmt ", stdout); + p_ntp_delta(&(bp->org), &(bp->xmt)); + + return; + +trunc: + fputs(" [|ntp]", stdout); +#undef TCHECK +} + +p_sfix(sfp) + register struct s_fixedpt *sfp; +{ + register int i; + register int f; + register float ff; + + i = ntohs(sfp->int_part); + f = ntohs(sfp->fraction); + ff = f / 65536.0; /* shift radix point by 16 bits */ + f = ff * 1000000.0; /* Treat fraction as parts per million */ + printf("%d.%06d", i, f); +} + +#define FMAXINT (4294967296.0) /* floating point rep. of MAXINT */ + +p_ntp_time(lfp) + register struct l_fixedpt *lfp; +{ + register long i; + register unsigned long uf; + register unsigned long f; + register float ff; + + i = ntohl(lfp->int_part); + uf = ntohl(lfp->fraction); + ff = uf; + if (ff < 0.0) /* some compilers are buggy */ + ff += FMAXINT; + ff = ff / FMAXINT; /* shift radix point by 32 bits */ + f = ff * 1000000000.0; /* treat fraction as parts per billion */ + printf("%lu.%09d", i, f); +} + +/* Prints time difference between *lfp and *olfp */ +p_ntp_delta(olfp, lfp) + register struct l_fixedpt *olfp; + register struct l_fixedpt *lfp; +{ + register long i; + register unsigned long uf; + register unsigned long ouf; + register unsigned long f; + register float ff; + int signbit; + + i = ntohl(lfp->int_part) - ntohl(olfp->int_part); + + uf = ntohl(lfp->fraction); + ouf = ntohl(olfp->fraction); + + if (i > 0) { /* new is definitely greater than old */ + signbit = 0; + f = uf - ouf; + if (ouf > uf) /* must borrow from high-order bits */ + i -= 1; + } else if (i < 0) { /* new is definitely less than old */ + signbit = 1; + f = ouf - uf; + if (uf > ouf) /* must carry into the high-order bits */ + i += 1; + i = -i; + } else { /* int_part is zero */ + if (uf > ouf) { + signbit = 0; + f = uf - ouf; + } else { + signbit = 1; + f = ouf - uf; + } + } + + ff = f; + if (ff < 0.0) /* some compilers are buggy */ + ff += FMAXINT; + ff = ff / FMAXINT; /* shift radix point by 32 bits */ + f = ff * 1000000000.0; /* treat fraction as parts per billion */ + if (signbit) + putchar('-'); + else + putchar('+'); + printf("%d.%09d", i, f); +} diff --git a/usr.sbin/tcpdump/tcpdump/print-null.c b/usr.sbin/tcpdump/tcpdump/print-null.c new file mode 100644 index 000000000000..b1860685b84d --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-null.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#)$Header: print-null.c,v 1.3 91/10/07 20:19:11 leres Exp $ (LBL)"; +#endif + +#include <stdio.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/time.h> +#include <sys/timeb.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/mbuf.h> +#include <sys/ioctl.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> + +#include <net/bpf.h> + +#include "interface.h" +#include "addrtoname.h" + +#define NULL_HDRLEN 4 + +static void +null_print(p, ip, length) + u_char *p; + struct ip *ip; + int length; +{ + u_int family; + + bcopy(p, &family, sizeof(family)); + + if (nflag) { + /* XXX just dump the header */ + return; + } + switch (family) { + + case AF_INET: + printf("ip: "); + break; + + case AF_NS: + printf("ns: "); + break; + + default: + printf("AF %d: ", family); + break; + } +} + +void +null_if_print(p, tvp, length, caplen) + u_char *p; + struct timeval *tvp; + int length; + int caplen; +{ + struct ip *ip; + + ts_print(tvp); + + /* + * Some printers want to get back at the link level addresses, + * and/or check that they're not walking off the end of the packet. + * Rather than pass them all the way down, we set these globals. + */ + packetp = (u_char *)p; + snapend = (u_char *)p + caplen; + + length -= NULL_HDRLEN; + + ip = (struct ip *)(p + NULL_HDRLEN); + + if (eflag) + null_print(p, ip, length); + + ip_print(ip, length); + + if (xflag) + default_print((u_short *)ip, caplen - NULL_HDRLEN); + putchar('\n'); +} + diff --git a/usr.sbin/tcpdump/tcpdump/print-ospf.c b/usr.sbin/tcpdump/tcpdump/print-ospf.c new file mode 100644 index 000000000000..90daf9447a05 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-ospf.c @@ -0,0 +1,586 @@ +/* + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * OSPF support contributed by Jeffrey Honig (jch@mitchell.cit.cornell.edu) + */ +#ifndef lint +static char rcsid[] = + "@(#) $Header: print-ospf.c,v 1.1 92/01/29 12:44:17 mccanne Exp $ (LBL)"; +#endif + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> + +#include <errno.h> +#include <ctype.h> + +#include "ospf.h" +#include "interface.h" +#include "addrtoname.h" + +#ifndef __GNUC__ +#define inline +#endif + +#if !defined(__STDC__) && !defined(const) +#define const +#endif /* !defined(__STDC__) && !defined(const) */ + +struct bits { + u_long bit; + const char *str; +}; + +static const struct bits ospf_option_bits[] = { + OSPF_OPTION_T, "T", + OSPF_OPTION_E, "E", + OSPF_OPTION_MC, "MC", + 0, (char *) 0 +}; + +static const struct bits ospf_rla_flag_bits[] = { + RLA_FLAG_B, "B", + RLA_FLAG_E, "E", + RLA_FLAG_W1, "W1", + RLA_FLAG_W2, "W2", + 0, (char *) 0 +}; + +static const char *ospf_types[OSPF_TYPE_MAX] = { + (char *) 0, + "hello", + "dd", + "ls_req", + "ls_upd", + "ls_ack" +}; + +static inline void +ospf_print_seqage(seq, us) +register u_long seq; +register time_t us; +{ + register time_t sec = us % 60; + register time_t mins = (us / 60) % 60; + register time_t hour = us/3600; + + printf(" S %X age ", + seq); + if (hour) { + printf("%d:%02d:%02d", + hour, + mins, + sec); + } else if (mins) { + printf("%d:%02d", + mins, + sec); + } else { + printf("%d", + sec); + } +} + + +static inline void +ospf_print_bits(bp, options) +register struct bits *bp; +register u_char options; +{ + char sep = ' '; + + do { + if (options & bp->bit) { + printf("%c%s", + sep, + bp->str); + sep = '/'; + } + } while ((++bp)->bit) ; +} + + +#define LS_PRINT(lsp, type) switch (type) { \ + case LS_TYPE_ROUTER: \ + printf(" rtr %s ", ipaddr_string(&lsp->ls_router)); break; \ + case LS_TYPE_NETWORK: \ + printf(" net dr %s if %s", ipaddr_string(&lsp->ls_router), ipaddr_string(&lsp->ls_stateid)); break; \ + case LS_TYPE_SUM_IP: \ + printf(" sum %s abr %s", ipaddr_string(&lsp->ls_stateid), ipaddr_string(&lsp->ls_router)); break; \ + case LS_TYPE_SUM_ABR: \ + printf(" abr %s rtr %s", ipaddr_string(&lsp->ls_router), ipaddr_string(&lsp->ls_stateid)); break; \ + case LS_TYPE_ASE: \ + printf(" ase %s asbr %s", ipaddr_string(&lsp->ls_stateid), ipaddr_string(&lsp->ls_router)); break; \ + case LS_TYPE_GROUP: \ + printf(" group %s rtr %s", ipaddr_string(&lsp->ls_stateid), ipaddr_string(&lsp->ls_router)); break; \ + } + +static int +ospf_print_lshdr(lshp, end) +register struct lsa_hdr *lshp; +caddr_t end; +{ + if ((caddr_t) (lshp + 1) > end) { + return 1; + } + + printf(" {"); + + if (!lshp->ls_type || lshp->ls_type >= LS_TYPE_MAX) { + printf(" ??LS type %d?? }", + lshp->ls_type); + return 1; + } + + ospf_print_bits(ospf_option_bits, lshp->ls_options); + ospf_print_seqage(ntohl(lshp->ls_seq), + ntohs(lshp->ls_age)); + + LS_PRINT(lshp, lshp->ls_type); + + return 0; +} + + +/* + * Print a single link state advertisement. If truncated return 1, else 0. + */ + +static int +ospf_print_lsa(lsap, end) +register struct lsa *lsap; +caddr_t end; +{ + register caddr_t ls_end; + struct rlalink *rlp; + struct tos_metric *tosp; + struct in_addr *ap; + struct aslametric *almp; + struct mcla *mcp; + u_long *lp; + int j, k; + + if (ospf_print_lshdr(&lsap->ls_hdr, end)) { + return 1; + } + + ls_end = (caddr_t) lsap + ntohs(lsap->ls_hdr.ls_length); + + if (ls_end > end) { + printf(" }"); + return 1; + } + + switch (lsap->ls_hdr.ls_type) { + case LS_TYPE_ROUTER: + ospf_print_bits(ospf_rla_flag_bits, lsap->lsa_un.un_rla.rla_flags); + + j = ntohs(lsap->lsa_un.un_rla.rla_count); + rlp = lsap->lsa_un.un_rla.rla_link; + while (j--) { + struct rlalink *rln = (struct rlalink *) ((caddr_t) (rlp + 1) + ((rlp->link_toscount) * sizeof (struct tos_metric))); + + if ((caddr_t) rln > ls_end) { + break; + } + printf(" {"); + + switch (rlp->link_type) { + case RLA_TYPE_VIRTUAL: + printf(" virt"); + /* Fall through */ + + case RLA_TYPE_ROUTER: + printf(" nbrid %s if %s", + ipaddr_string(&rlp->link_id), + ipaddr_string(&rlp->link_data)); + break; + + case RLA_TYPE_TRANSIT: + printf(" dr %s if %s", + ipaddr_string(&rlp->link_id), + ipaddr_string(&rlp->link_data)); + break; + + case RLA_TYPE_STUB: + printf(" net %s mask %s", + ipaddr_string(&rlp->link_id), + ipaddr_string(&rlp->link_data)); + break; + + default: + printf(" ??RouterLinksType %d?? }", + rlp->link_type); + return 0; + } + printf(" tos 0 metric %d", + ntohs(rlp->link_tos0metric)); + tosp = (struct tos_metric *) ((sizeof rlp->link_tos0metric) + (caddr_t) rlp); + for (k = 0; k < rlp->link_toscount; k++, tosp++) { + printf(" tos %d metric %d", + ntohs(tosp->tos_type), + ntohs(tosp->tos_metric)); + } + printf(" }"); + rlp = rln; + } + break; + + case LS_TYPE_NETWORK: + printf(" mask %s rtrs", + ipaddr_string(&lsap->lsa_un.un_nla.nla_mask)); + for (ap = lsap->lsa_un.un_nla.nla_router; + (caddr_t) (ap + 1) <= ls_end; + ap++) { + printf(" %s", + ipaddr_string(ap)); + } + break; + + case LS_TYPE_SUM_IP: + printf(" mask %s", + ipaddr_string(&lsap->lsa_un.un_sla.sla_mask)); + /* Fall through */ + + case LS_TYPE_SUM_ABR: + + for (lp = lsap->lsa_un.un_sla.sla_tosmetric; + (caddr_t) (lp + 1) <= ls_end; + lp++) { + u_long ul = ntohl(*lp); + + printf(" tos %d metric %d", + (ul & SLA_MASK_TOS) >> SLA_SHIFT_TOS, + ul & SLA_MASK_METRIC); + } + break; + + case LS_TYPE_ASE: + printf(" mask %s", + ipaddr_string(&lsap->lsa_un.un_asla.asla_mask)); + + for (almp = lsap->lsa_un.un_asla.asla_metric; + (caddr_t) (almp + 1) <= ls_end; + almp++) { + u_long ul = ntohl(almp->asla_tosmetric); + + printf(" type %d tos %d metric %d", + (ul & ASLA_FLAG_EXTERNAL) ? 2 : 1, + (ul & ASLA_MASK_TOS) >> ASLA_SHIFT_TOS, + (ul & ASLA_MASK_METRIC)); + if (almp->asla_forward.s_addr) { + printf(" forward %s", + ipaddr_string(&almp->asla_forward)); + } + if (almp->asla_tag.s_addr) { + printf(" tag %s", + ipaddr_string(&almp->asla_tag)); + } + } + break; + + case LS_TYPE_GROUP: + /* Multicast extensions as of 23 July 1991 */ + for (mcp = lsap->lsa_un.un_mcla; + (caddr_t) (mcp + 1) <= ls_end; + mcp++) { + switch (ntohl(mcp->mcla_vtype)) { + case MCLA_VERTEX_ROUTER: + printf(" rtr rtrid %s", + ipaddr_string(&mcp->mcla_vid)); + break; + + case MCLA_VERTEX_NETWORK: + printf(" net dr %s", + ipaddr_string(&mcp->mcla_vid)); + break; + + default: + printf(" ??VertexType %d??", + ntohl(mcp->mcla_vtype)); + break; + } + } + } + + printf(" }"); + return 0; +} + + +void +ospf_print(dat, length, ip) +u_char *dat; +int length; +struct ip *ip; +{ + register struct ospfhdr *op = (struct ospfhdr *) dat; + register caddr_t end = (caddr_t)snapend; + register struct lsa *lsap; + register struct lsa_hdr *lshp; + char sep; + int i, j; + struct in_addr *ap; + struct lsr *lsrp; + + /* Print the source and destination address */ + (void) printf(" %s > %s:", + ipaddr_string(&ip->ip_src), + ipaddr_string(&ip->ip_dst)); + + if ((caddr_t) (&op->ospf_len + 1) > end) { + goto trunc_test; + } + + /* If the type is valid translate it, or just print the type */ + /* value. If it's not valid, say so and return */ + if (op->ospf_type || op->ospf_type < OSPF_TYPE_MAX) { + printf(" OSPFv%d-%s %d:", + op->ospf_version, + ospf_types[op->ospf_type], + length); + } else { + printf(" ospf-v%d-??type %d?? %d:", + op->ospf_version, + op->ospf_type, + length); + return; + } + + if (length != ntohs(op->ospf_len)) { + printf(" ??len %d??", + ntohs(op->ospf_len)); + goto trunc_test; + } + + if ((caddr_t) (&op->ospf_routerid + 1) > end) { + goto trunc_test; + } + + /* Print the routerid if it is not the same as the source */ + if (ip->ip_src.s_addr != op->ospf_routerid.s_addr) { + printf(" rtrid %s", + ipaddr_string(&op->ospf_routerid)); + } + + if ((caddr_t) (&op->ospf_areaid + 1) > end) { + goto trunc_test; + } + + if (op->ospf_areaid.s_addr) { + printf(" area %s", + ipaddr_string(&op->ospf_areaid)); + } else { + printf(" backbone"); + } + + if ((caddr_t) (op->ospf_authdata + OSPF_AUTH_SIZE) > end) { + goto trunc_test; + } + + if (vflag) { + /* Print authentication data (should we really do this?) */ + switch (ntohs(op->ospf_authtype)) { + case OSPF_AUTH_NONE: + break; + + case OSPF_AUTH_SIMPLE: + printf(" auth "); + j = 0; + for (i = 0; i < sizeof (op->ospf_authdata); i++) { + if (!isprint(op->ospf_authdata[i])) { + j = 1; + break; + } + } + if (j) { + /* Print the auth-data as a string of octets */ + printf("%s.%s", + ipaddr_string((struct in_addr *) op->ospf_authdata), + ipaddr_string((struct in_addr *) &op->ospf_authdata[sizeof (struct in_addr)])); + } else { + /* Print the auth-data as a text string */ + printf("'%.8s'", + op->ospf_authdata); + } + break; + + default: + printf(" ??authtype-%d??", + ntohs(op->ospf_authtype)); + return; + } + } + + + /* Do rest according to version. */ + switch (op->ospf_version) { + case 2: + /* ospf version 2 */ + switch (op->ospf_type) { + case OSPF_TYPE_UMD: /* Rob Coltun's special monitoring packets; do nothing */ + break; + + case OSPF_TYPE_HELLO: + if ((caddr_t) (&op->ospf_hello.hello_deadint + 1) > end) { + break; + } + if (vflag) { + ospf_print_bits(ospf_option_bits, op->ospf_hello.hello_options); + printf(" mask %s int %d pri %d dead %d", + ipaddr_string(&op->ospf_hello.hello_mask), + ntohs(op->ospf_hello.hello_helloint), + op->ospf_hello.hello_priority, + ntohl(op->ospf_hello.hello_deadint)); + } + + if ((caddr_t) (&op->ospf_hello.hello_dr + 1) > end) { + break; + } + if (op->ospf_hello.hello_dr.s_addr) { + printf(" dr %s", + ipaddr_string(&op->ospf_hello.hello_dr)); + } + + if ((caddr_t) (&op->ospf_hello.hello_bdr + 1) > end) { + break; + } + if (op->ospf_hello.hello_bdr.s_addr) { + printf(" bdr %s", + ipaddr_string(&op->ospf_hello.hello_bdr)); + } + + if (vflag) { + if ((caddr_t) (op->ospf_hello.hello_neighbor + 1) > end) { + break; + } + printf(" nbrs"); + for (ap = op->ospf_hello.hello_neighbor; + (caddr_t) (ap + 1) <= end; + ap++) { + printf(" %s", + ipaddr_string(ap)); + } + } + break; /* HELLO */ + + case OSPF_TYPE_DB: + if ((caddr_t) (&op->ospf_db.db_seq + 1) > end) { + break; + } + ospf_print_bits(ospf_option_bits, op->ospf_db.db_options); + sep = ' '; + if (op->ospf_db.db_flags & OSPF_DB_INIT) { + printf("%cI", + sep); + sep = '/'; + } + if (op->ospf_db.db_flags & OSPF_DB_MORE) { + printf("%cM", + sep); + sep = '/'; + } + if (op->ospf_db.db_flags & OSPF_DB_MASTER) { + printf("%cMS", + sep); + sep = '/'; + } + printf(" S %X", + ntohl(op->ospf_db.db_seq)); + + if (vflag) { + /* Print all the LS adv's */ + lshp = op->ospf_db.db_lshdr; + + while (!ospf_print_lshdr(lshp, end)) { + printf(" }"); + lshp++; + } + } + break; + + case OSPF_TYPE_LSR: + if (vflag) { + for (lsrp = op->ospf_lsr; (caddr_t) (lsrp+1) <= end; lsrp++) { + long type; + + if ((caddr_t) (lsrp + 1) > end) { + break; + } + + printf(" {"); + if (!(type = lsrp->ls_type) || type >= LS_TYPE_MAX) { + printf(" ??LinkStateType %d }", + type); + printf(" }"); + break; + } + + LS_PRINT(lsrp, type); + printf(" }"); + } + } + break; + + case OSPF_TYPE_LSU: + if (vflag) { + lsap = op->ospf_lsu.lsu_lsa; + i = ntohl(op->ospf_lsu.lsu_count); + + while (i-- && + !ospf_print_lsa(lsap, end)) { + lsap = (struct lsa *) ((caddr_t) lsap + ntohs(lsap->ls_hdr.ls_length)); + } + } + break; + + + case OSPF_TYPE_LSA: + if (vflag) { + lshp = op->ospf_lsa.lsa_lshdr; + + while (!ospf_print_lshdr(lshp, end)) { + printf(" }"); + lshp++; + } + break; + } + } /* end switch on v2 packet type */ + break; + + default: + printf(" ospf [version %d]", + op->ospf_version); + break; + } /* end switch on version */ + + trunc_test: + if ((snapend - dat) < length) { + printf(" [|]"); + } + + return; /* from ospf_print */ +} + + diff --git a/usr.sbin/tcpdump/tcpdump/print-ppp.c b/usr.sbin/tcpdump/tcpdump/print-ppp.c new file mode 100644 index 000000000000..c83cc7d41dfd --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-ppp.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#)$Header: print-ppp.c,v 1.7 91/10/07 20:18:33 leres Exp $ (LBL)"; +#endif + +#ifdef PPP +#include <stdio.h> +#include <netdb.h> +#include <ctype.h> +#include <signal.h> +#include <errno.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/timeb.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/mbuf.h> +#include <sys/ioctl.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> + +#include <net/bpf.h> + +#include "interface.h" +#include "addrtoname.h" + +/* XXX This goes somewhere else. */ +#define PPP_HDRLEN 4 + +void +ppp_if_print(p, tvp, length, caplen) + u_char *p; + struct timeval *tvp; + int length; + int caplen; +{ + struct ip *ip; + + ts_print(tvp); + + if (caplen < PPP_HDRLEN) { + printf("[|ppp]"); + goto out; + } + + /* + * Some printers want to get back at the link level addresses, + * and/or check that they're not walking off the end of the packet. + * Rather than pass them all the way down, we set these globals. + */ + packetp = (u_char *)p; + snapend = (u_char *)p + caplen; + + if (eflag) + printf("%c %4d %02x %04x: ", p[0] ? 'O' : 'I', length, + p[1], ntohs(*(u_short *)&p[2])); + + length -= PPP_HDRLEN; + ip = (struct ip *)(p + PPP_HDRLEN); + ip_print(ip, length); + + if (xflag) + default_print((u_short *)ip, caplen - PPP_HDRLEN); +out: + putchar('\n'); +} +#else +#include <stdio.h> +void +ppp_if_print() +{ + void error(); + + error("not configured for ppp"); + /* NOTREACHED */ +} +#endif diff --git a/usr.sbin/tcpdump/tcpdump/print-rip.c b/usr.sbin/tcpdump/tcpdump/print-rip.c new file mode 100644 index 000000000000..d123fe9a48bb --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-rip.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#) $Header: print-rip.c,v 1.12 91/04/19 10:46:46 mccanne Exp $ (LBL)"; +#endif + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <protocols/routed.h> + +#include <errno.h> + +#include "interface.h" +#include "addrtoname.h" + +static void +rip_entry_print(ni) + register struct netinfo *ni; +{ + if (ntohs(ni->rip_dst.sa_family) != AF_INET) { + register int i; + + printf(" [family %d:", ntohs(ni->rip_dst.sa_family)); + for (i = 0; i < 14; i += 2) + printf(" %02x%02x", ni->rip_dst.sa_data[i], + ni->rip_dst.sa_data[i+1]); + printf("]"); + } else { + register struct sockaddr_in *sin = + (struct sockaddr_in *)&ni->rip_dst; + printf(" %s", ipaddr_string(&sin->sin_addr)); + if (sin->sin_port) + printf(" [port %d]", sin->sin_port); + } + printf("(%d)", ntohl(ni->rip_metric)); +} + +void +rip_print(dat, length) + u_char *dat; + int length; +{ + register struct rip *rp = (struct rip *)dat; + register struct netinfo *ni; + register int amt = (u_char *)snapend - dat; + register int i = min(length, amt) - + (sizeof(struct rip) - sizeof(struct netinfo)); + int j; + int trunc; + + if (i < 0) + return; + + switch (rp->rip_cmd) { + + case RIPCMD_REQUEST: + printf(" rip-req %d", length); + break; + case RIPCMD_RESPONSE: + j = length / sizeof(*ni); + if (j * sizeof(*ni) != length - 4) + printf(" rip-resp %d[%d]:", j, length); + else + printf(" rip-resp %d:", j); + trunc = ((i / sizeof(*ni)) * sizeof(*ni) != i); + for (ni = rp->rip_nets; (i -= sizeof(*ni)) >= 0; ++ni) + rip_entry_print(ni); + if (trunc) + printf("[|rip]"); + break; + case RIPCMD_TRACEON: + printf(" rip-traceon %d: \"%s\"", length, rp->rip_tracefile); + break; + case RIPCMD_TRACEOFF: + printf(" rip-traceoff %d", length); + break; + case RIPCMD_POLL: + printf(" rip-poll %d", length); + break; + case RIPCMD_POLLENTRY: + printf(" rip-pollentry %d", length); + break; + default: + printf(" rip-%d ?? %d", rp->rip_cmd, length); + break; + } + if (rp->rip_vers != RIPVERSION) + printf(" [vers %d]", rp->rip_vers); +} diff --git a/usr.sbin/tcpdump/tcpdump/print-sl.c b/usr.sbin/tcpdump/tcpdump/print-sl.c new file mode 100644 index 000000000000..2c89b42d4322 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-sl.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#)$Header: print-sl.c,v 1.17 91/10/07 20:18:35 leres Exp $ (LBL)"; +#endif + +#ifdef CSLIP +#include <stdio.h> +#include <netdb.h> +#include <ctype.h> +#include <signal.h> +#include <errno.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/timeb.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/mbuf.h> +#include <sys/ioctl.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> + +#include <net/slcompress.h> +#include <net/slip.h> +#include <net/bpf.h> + +#include "interface.h" +#include "addrtoname.h" + +static int lastlen[2][256]; +static int lastconn = 255; + +static void compressed_sl_print(); + +void +sl_if_print(p, tvp, length, caplen) + u_char *p; + struct timeval *tvp; + int length; + int caplen; +{ + struct ip *ip; + + ts_print(tvp); + + if (caplen < SLIP_HDRLEN) { + printf("[|slip]"); + goto out; + } + /* + * Some printers want to get back at the link level addresses, + * and/or check that they're not walking off the end of the packet. + * Rather than pass them all the way down, we set these globals. + */ + packetp = (u_char *)p; + snapend = (u_char *)p + caplen; + + length -= SLIP_HDRLEN; + + ip = (struct ip *)(p + SLIP_HDRLEN); + + if (eflag) + sliplink_print(p, ip, length); + + ip_print(ip, length); + + if (xflag) + default_print((u_short *)ip, caplen - SLIP_HDRLEN); + out: + putchar('\n'); +} + +sliplink_print(p, ip, length) + u_char *p; + struct ip *ip; + int length; +{ + int dir; + int hlen; + + dir = p[SLX_DIR]; + putchar(dir == SLIPDIR_IN ? 'I' : 'O'); + putchar(' '); + + if (nflag) { + /* XXX just dump the header */ + int i; + + for (i = 0; i < 15; ++i) + printf("%02x.", p[SLX_CHDR + i]); + printf("%02x: ", p[SLX_CHDR + 15]); + return; + } + switch (p[SLX_CHDR] & 0xf0) { + + case TYPE_IP: + printf("ip %d: ", length + SLIP_HDRLEN); + break; + + case TYPE_UNCOMPRESSED_TCP: + /* + * The connection id is stode in the IP protcol field. + */ + lastconn = ip->ip_p; + hlen = ip->ip_hl; + hlen += ((struct tcphdr *)&((int *)ip)[hlen])->th_off; + lastlen[dir][lastconn] = length - (hlen << 2); + printf("utcp %d: ", lastconn); + break; + + default: + if (p[SLX_CHDR] & TYPE_COMPRESSED_TCP) { + compressed_sl_print(&p[SLX_CHDR], ip, length, dir); + printf(": "); + } else + printf("slip-%d!: ", p[SLX_CHDR]); + } +} + +static u_char * +print_sl_change(str, cp) + char *str; + register u_char *cp; +{ + register u_int i; + + if ((i = *cp++) == 0) { + i = (cp[0] << 8) | cp[1]; + cp += 2; + } + printf(" %s%d", str, i); + return (cp); +} + +static u_char * +print_sl_winchange(cp) + register u_char *cp; +{ + register short i; + + if ((i = *cp++) == 0) { + i = (cp[0] << 8) | cp[1]; + cp += 2; + } + if (i >= 0) + printf(" W+%d", i); + else + printf(" W%d", i); + return (cp); +} + +static void +compressed_sl_print(chdr, ip, length, dir) + u_char *chdr; + int length; + struct ip *ip; + int dir; +{ + register u_char *cp = chdr; + register u_int flags; + int hlen; + + flags = *cp++; + if (flags & NEW_C) { + lastconn = *cp++; + printf("ctcp %d", lastconn); + } else + printf("ctcp *"); + + /* skip tcp checksum */ + cp += 2; + + switch (flags & SPECIALS_MASK) { + case SPECIAL_I: + printf(" *SA+%d", lastlen[dir][lastconn]); + break; + + case SPECIAL_D: + printf(" *S+%d", lastlen[dir][lastconn]); + break; + + default: + if (flags & NEW_U) + cp = print_sl_change("U=", cp); + if (flags & NEW_W) + cp = print_sl_winchange(cp); + if (flags & NEW_A) + cp = print_sl_change("A+", cp); + if (flags & NEW_S) + cp = print_sl_change("S+", cp); + break; + } + if (flags & NEW_I) + cp = print_sl_change("I+", cp); + + /* + * 'hlen' is the length of the uncompressed TCP/IP header (in longs). + * 'cp - chdr' is the length of the compressed header. + * 'length - hlen' is the amount of data in the packet. + */ + hlen = ip->ip_hl; + hlen += ((struct tcphdr *)&((long *)ip)[hlen])->th_off; + lastlen[dir][lastconn] = length - (hlen << 2); + printf(" %d (%d)", lastlen[dir][lastconn], cp - chdr); +} +#else +#include <stdio.h> +void +sl_if_print() +{ + void error(); + + error("not configured for slip"); + /* NOTREACHED */ +} +#endif diff --git a/usr.sbin/tcpdump/tcpdump/print-snmp.c b/usr.sbin/tcpdump/tcpdump/print-snmp.c new file mode 100644 index 000000000000..d1996c07a292 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-snmp.c @@ -0,0 +1,1043 @@ +/* + * Copyright (c) 1990, by John Robert LoVerso. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by John Robert LoVerso. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * This implementaion has been influenced by the CMU SNMP release, + * by Steve Waldbusser. However, this shares no code with that system. + * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_. + * Earlier forms of this implemention were derived and/or inspired by an + * awk script originally written by C. Philip Wood of LANL (but later + * heavily modified by John Robert LoVerso). The copyright notice for + * that work is preserved below, even though it may not rightly apply + * to this file. + * + * This started out as a very simple program, but the incremental decoding + * (into the BE structure) complicated things. + * + # Los Alamos National Laboratory + # + # Copyright, 1990. The Regents of the University of California. + # This software was produced under a U.S. Government contract + # (W-7405-ENG-36) by Los Alamos National Laboratory, which is + # operated by the University of California for the U.S. Department + # of Energy. The U.S. Government is licensed to use, reproduce, + # and distribute this software. Permission is granted to the + # public to copy and use this software without charge, provided + # that this Notice and any statement of authorship are reproduced + # on all copies. Neither the Government nor the University makes + # any warranty, express or implied, or assumes any liability or + # responsibility for the use of this software. + # @(#)snmp.awk.x 1.1 (LANL) 1/15/90 + */ +#ifndef lint +static char rcsid[] = + "@(#) $Id: print-snmp.c,v 3.10 91/01/17 01:18:13 loverso Exp Locker: loverso $ (jlv)"; +#endif + +#include <sys/param.h> +#include <sys/types.h> +#include <stdio.h> +#include <ctype.h> + +#include "interface.h" +#include "addrtoname.h" + +/* + * Universal ASN.1 types + * (we only care about the tag values for those allowed in the Internet SMI) + */ +char *Universal[] = { + "U-0", + "Boolean", + "Integer", +#define INTEGER 2 + "Bitstring", + "String", +#define STRING 4 + "Null", +#define ASN_NULL 5 + "ObjID", +#define OBJECTID 6 + "ObjectDes", + "U-8","U-9","U-10","U-11", /* 8-11 */ + "U-12","U-13","U-14","U-15", /* 12-15 */ + "Sequence", +#define SEQUENCE 16 + "Set" +}; + +/* + * Application-wide ASN.1 types from the Internet SMI and their tags + */ +char *Application[] = { + "IpAddress", +#define IPADDR 0 + "Counter", +#define COUNTER 1 + "Gauge", +#define GAUGE 2 + "TimeTicks", +#define TIMETICKS 3 + "Opaque" +}; + +/* + * Context-specific ASN.1 types for the SNMP PDUs and their tags + */ +char *Context[] = { + "GetRequest", +#define GETREQ 0 + "GetNextRequest", +#define GETNEXTREQ 1 + "GetResponse", +#define GETRESP 2 + "SetRequest", +#define SETREQ 3 + "Trap" +#define TRAP 4 +}; + +/* + * Private ASN.1 types + * The Internet SMI does not specify any + */ +char *Private[] = { + "P-0" +}; + +/* + * error-status values for any SNMP PDU + */ +char *ErrorStatus[] = { + "noError", + "tooBig", + "noSuchName", + "badValue", + "readOnly", + "genErr" +}; +#define DECODE_ErrorStatus(e) \ + ( e >= 0 && e <= sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \ + ? ErrorStatus[e] : (sprintf(errbuf, "err=%d", e), errbuf)) + +/* + * generic-trap values in the SNMP Trap-PDU + */ +char *GenericTrap[] = { + "coldStart", + "warmStart", + "linkDown", + "linkUp", + "authenticationFailure", + "egpNeighborLoss", + "enterpriseSpecific" +#define GT_ENTERPRISE 7 +}; +#define DECODE_GenericTrap(t) \ + ( t >= 0 && t <= sizeof(GenericTrap)/sizeof(GenericTrap[0]) \ + ? GenericTrap[t] : (sprintf(buf, "gt=%d", t), buf)) + +/* + * ASN.1 type class table + * Ties together the preceding Universal, Application, Context, and Private + * type definitions. + */ +#define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */ +struct { + char *name; + char **Id; + int numIDs; +} Class[] = { + defineCLASS(Universal), +#define UNIVERSAL 0 + defineCLASS(Application), +#define APPLICATION 1 + defineCLASS(Context), +#define CONTEXT 2 + defineCLASS(Private), +#define PRIVATE 3 +}; + +/* + * defined forms for ASN.1 types + */ +char *Form[] = { + "Primitive", +#define PRIMITIVE 0 + "Constructed", +#define CONSTRUCTED 1 +}; + +/* + * A structure for the OID tree for the compiled-in MIB. + * This is stored as a general-order tree. + */ +struct obj { + char *desc; /* name of object */ + u_char oid; /* sub-id following parent */ + u_char type; /* object type (unused) */ + struct obj *child, *next; /* child and next sibling pointers */ +} *objp = NULL; + +/* + * Include the compiled in SNMP MIB. "mib.h" is produced by feeding + * RFC-1156 format files into "makemib". "mib.h" MUST define at least + * a value for `mibroot'. + * + * In particluar, this is gross, as this is including initialized structures, + * and by right shouldn't be an "include" file. + */ +#include "mib.h" + +/* + * This defines a list of OIDs which will be abreviated on output. + * Currently, this includes the prefixes for the Internet MIB, the + * private enterprises tree, and the experimental tree. + */ +struct obj_abrev { + char *prefix; /* prefix for this abrev */ + struct obj *node; /* pointer into object table */ + char *oid; /* ASN.1 encoded OID */ +} obj_abrev_list[] = { +#ifndef NO_ABREV_MIB + /* .iso.org.dod.internet.mgmt.mib */ + { "", &_mib_obj, "\53\6\1\2\1" }, +#endif +#ifndef NO_ABREV_ENTER + /* .iso.org.dod.internet.private.enterprises */ + { "E:", &_enterprises_obj, "\53\6\1\4\1" }, +#endif +#ifndef NO_ABREV_EXPERI + /* .iso.org.dod.internet.experimental */ + { "X:", &_experimental_obj, "\53\6\1\3" }, +#endif + { 0,0,0 } +}; + +/* + * This is used in the OID print routine to walk down the object tree + * rooted at `mibroot'. + */ +#define OBJ_PRINT(o, suppressdot) \ +{ \ + if (objp) { \ + do { \ + if ((o) == objp->oid) \ + break; \ + } while (objp = objp->next); \ + } \ + if (objp) { \ + printf(suppressdot?"%s":".%s", objp->desc); \ + objp = objp->child; \ + } else \ + printf(suppressdot?"%u":".%u", (o)); \ +} + +/* + * This is the definition for the Any-Data-Type storage used purely for + * temporary internal representation while decoding an ASN.1 data stream. + */ +struct be { + unsigned long asnlen; + union { + caddr_t raw; + long integer; + unsigned long uns; + unsigned char *str; + } data; + unsigned char form, class, id; /* tag info */ + u_char type; +#define BE_ANY 255 +#define BE_NONE 0 +#define BE_NULL 1 +#define BE_OCTET 2 +#define BE_OID 3 +#define BE_INT 4 +#define BE_UNS 5 +#define BE_STR 6 +#define BE_SEQ 7 +#define BE_INETADDR 8 +#define BE_PDU 9 +}; + +/* + * Defaults for SNMP PDU components + */ +#define DEF_COMMUNITY "public" +#define DEF_VERSION 0 + +/* + * constants for ASN.1 decoding + */ +#define OIDMUX 40 +#define ASNLEN_INETADDR 4 +#define ASN_SHIFT7 7 +#define ASN_SHIFT8 8 +#define ASN_BIT8 0x80 +#define ASN_LONGLEN 0x80 + +#define ASN_ID_BITS 0x1f +#define ASN_FORM_BITS 0x20 +#define ASN_FORM_SHIFT 5 +#define ASN_CLASS_BITS 0xc0 +#define ASN_CLASS_SHIFT 6 + +#define ASN_ID_EXT 0x1f /* extension ID in tag field */ + +/* + * truncated==1 means the packet was complete, but we don't have all of + * it to decode. + */ +static int truncated; +#define ifNotTruncated if (truncated) fputs("[|snmp]", stdout); else + +/* + * This decodes the next ASN.1 object in the stream pointed to by "p" + * (and of real-length "len") and stores the intermediate data in the + * provided BE object. + * + * This returns -l if it fails (i.e., the ASN.1 stream is not valid). + * O/w, this returns the number of bytes parsed from "p". + */ +int +asn1_parse(p, len, elem) + register u_char *p; + int len; + struct be *elem; +{ + unsigned char form, class, id; + int indent=0, i, hdr; + char *classstr; + + elem->asnlen = 0; + elem->type = BE_ANY; + if (len < 1) { + ifNotTruncated puts("[nothing to parse], stdout"); + return -1; + } + + /* + * it would be nice to use a bit field, but you can't depend on them. + * +---+---+---+---+---+---+---+---+ + * + class |frm| id | + * +---+---+---+---+---+---+---+---+ + * 7 6 5 4 3 2 1 0 + */ + id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */ +#ifdef notdef + form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */ + class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */ + form &= 0x1; /* bit 5 -> bit 0, range 0-1 */ +#else + form = (*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT; + class = (*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT; +#endif + elem->form = form; + elem->class = class; + elem->id = id; + if (vflag) + printf("|%.2x", *p); + p++; len--; hdr = 1; + /* extended tag field */ + if (id == ASN_ID_EXT) { + for (id = 0; *p & ASN_BIT8 && len > 0; len--, hdr++, p++) { + if (vflag) + printf("|%.2x", *p); + id += *p & ~ASN_BIT8; + } + if (len == 0 && *p & ASN_BIT8) { + ifNotTruncated fputs("[Xtagfield?]", stdout); + return -1; + } + } + if (len < 1) { + ifNotTruncated fputs("[no asnlen]", stdout); + return -1; + } + elem->asnlen = *p; + if (vflag) + printf("|%.2x", *p); + p++; len--; hdr++; + if (elem->asnlen & ASN_BIT8) { + int noct = elem->asnlen % ASN_BIT8; + elem->asnlen = 0; + if (len < noct) { + ifNotTruncated printf("[asnlen? %d<%d]", len, noct); + return -1; + } + for (; noct-- > 0; len--, hdr++) { + if (vflag) + printf("|%.2x", *p); + elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++; + } + } + if (len < elem->asnlen) { + if (!truncated) { + printf("[len%d<asnlen%u]", len, elem->asnlen); + return -1; + } + /* maybe should check at least 4? */ + elem->asnlen = len; + } + if (form >= sizeof(Form)/sizeof(Form[0])) { + ifNotTruncated printf("[form?%d]", form); + return -1; + } + if (class >= sizeof(Class)/sizeof(Class[0])) { + ifNotTruncated printf("[class?%c/%d]", *Form[form], class); + return -1; + } + if (id >= Class[class].numIDs) { + ifNotTruncated printf("[id?%c/%s/%d]", *Form[form], + Class[class].name, id); + return -1; + } + + switch (form) { + case PRIMITIVE: + switch (class) { + case UNIVERSAL: + switch (id) { + case STRING: + elem->type = BE_STR; + elem->data.str = p; + break; + + case INTEGER: { + register long data; + elem->type = BE_INT; + data = 0; + + if (*p & ASN_BIT8) /* negative */ + data = -1; + for (i = elem->asnlen; i-- > 0; p++) + data = (data << ASN_SHIFT8) | *p; + elem->data.integer = data; + break; + } + + case OBJECTID: + elem->type = BE_OID; + elem->data.raw = (caddr_t)p; + break; + + case ASN_NULL: + elem->type = BE_NULL; + elem->data.raw = NULL; + break; + + default: + elem->type = BE_OCTET; + elem->data.raw = (caddr_t)p; + printf("[P/U/%s]", + Class[class].Id[id]); + break; + } + break; + + case APPLICATION: + switch (id) { + case IPADDR: + elem->type = BE_INETADDR; + elem->data.raw = (caddr_t)p; + break; + + case COUNTER: + case GAUGE: + case TIMETICKS: { + register unsigned long data; + elem->type = BE_UNS; + data = 0; + for (i = elem->asnlen; i-- > 0; p++) + data = (data << 8) + *p; + elem->data.uns = data; + break; + } + + default: + elem->type = BE_OCTET; + elem->data.raw = (caddr_t)p; + printf("[P/A/%s]", + Class[class].Id[id]); + break; + } + break; + + default: + elem->type = BE_OCTET; + elem->data.raw = (caddr_t)p; + printf("[P/%s/%s]", + Class[class].name, Class[class].Id[id]); + break; + } + break; + + case CONSTRUCTED: + switch (class) { + case UNIVERSAL: + switch (id) { + case SEQUENCE: + elem->type = BE_SEQ; + elem->data.raw = (caddr_t)p; + break; + + default: + elem->type = BE_OCTET; + elem->data.raw = (caddr_t)p; + printf("C/U/%s", Class[class].Id[id]); + break; + } + break; + + case CONTEXT: + elem->type = BE_PDU; + elem->data.raw = (caddr_t)p; + break; + + default: + elem->type = BE_OCTET; + elem->data.raw = (caddr_t)p; + printf("C/%s/%s", + Class[class].name, Class[class].Id[id]); + break; + } + break; + } + p += elem->asnlen; + len -= elem->asnlen; + return elem->asnlen + hdr; +} + +/* + * Display the ASN.1 object represented by the BE object. + * This used to be an integral part of asn1_parse() before the intermediate + * BE form was added. + */ +void +asn1_print(elem) + struct be *elem; +{ + u_char *p = (u_char *)elem->data.raw; + u_long asnlen = elem->asnlen; + int i; + + switch (elem->type) { + + case BE_OCTET: + for (i = asnlen; i-- > 0; p++); + printf("_%.2x", *p); + break; + + case BE_NULL: + break; + + case BE_OID: { + int o = 0, first = -1, i = asnlen; + + if (!nflag && asnlen > 2) { + struct obj_abrev *a = &obj_abrev_list[0]; + for (; a->node; a++) { + if (!memcmp(a->oid, p, strlen(a->oid))) { + objp = a->node->child; + i -= strlen(a->oid); + p += strlen(a->oid); + fputs(a->prefix, stdout); + first = 1; + break; + } + } + } + for (; i-- > 0; p++) { + o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8); + if (*p & ASN_LONGLEN) + continue; + + /* + * first subitem encodes two items with 1st*OIDMUX+2nd + */ + if (first < 0) { + if (!nflag) + objp = mibroot; + first = 0; + OBJ_PRINT(o/OIDMUX, first); + o %= OIDMUX; + } + OBJ_PRINT(o, first); + if (--first < 0) + first = 0; + o = 0; + } + break; + } + + case BE_INT: + printf("%ld", elem->data.integer); + break; + + case BE_UNS: + printf("%ld", elem->data.uns); + break; + + case BE_STR: { + register int printable = 1, first = 1; + u_char *p = elem->data.str; + for (i = asnlen; printable && i-- > 0; p++) + printable = isprint(*p) || isspace(*p); + p = elem->data.str; + if (printable) + (void)printfn(p, p+asnlen); + else + for (i = asnlen; i-- > 0; p++) { + printf(first ? "%.2x" : "_%.2x", *p); + first = 0; + } + break; + } + + case BE_SEQ: + printf("Seq(%d)", elem->asnlen); + break; + + case BE_INETADDR: { + char sep; + if (asnlen != ASNLEN_INETADDR) + printf("[inetaddr len!=%d]", ASNLEN_INETADDR); + sep='['; + for (i = asnlen; i-- > 0; p++) { + printf("%c%u", sep, *p); + sep='.'; + } + putchar(']'); + break; + } + + case BE_PDU: + printf("%s(%d)", + Class[CONTEXT].Id[elem->id], elem->asnlen); + break; + + case BE_ANY: + fputs("[BE_ANY!?]", stdout); + break; + + default: + fputs("[be!?]", stdout); + break; + } +} + +#ifdef notdef +/* + * This is a brute force ASN.1 printer: recurses to dump an entire structure. + * This will work for any ASN.1 stream, not just an SNMP PDU. + * + * By adding newlines and spaces at the correct places, this would print in + * Rose-Normal-Form. + * + * This is not currently used. + */ +void +asn1_decode(p, length) + u_char *p; + int length; +{ + struct be elem; + int i = 0; + + while (i >= 0 && length > 0) { + i = asn1_parse(p, length, &elem); + if (i >= 0) { + fputs(" ", stdout); + asn1_print(&elem); + if (elem.type == BE_SEQ || elem.type == BE_PDU) { + fputs(" {", stdout); + asn1_decode(elem.data.raw, elem.asnlen); + fputs(" }", stdout); + } + length -= i; + p += i; + } + } +} +#endif + +/* + * General SNMP header + * SEQUENCE { + * version INTEGER {version-1(0)}, + * community OCTET STRING, + * data ANY -- PDUs + * } + * PDUs for all but Trap: (see rfc1157 from page 15 on) + * SEQUENCE { + * request-id INTEGER, + * error-status INTEGER, + * error-index INTEGER, + * varbindlist SEQUENCE OF + * SEQUENCE { + * name ObjectName, + * value ObjectValue + * } + * } + * PDU for Trap: + * SEQUENCE { + * enterprise OBJECT IDENTIFIER, + * agent-addr NetworkAddress, + * generic-trap INTEGER, + * specific-trap INTEGER, + * time-stamp TimeTicks, + * varbindlist SEQUENCE OF + * SEQUENCE { + * name ObjectName, + * value ObjectValue + * } + * } + */ + +/* + * Decode SNMP varBind + */ +void +varbind_print (pduid, np, length, error) + u_char pduid, *np; + int length, error; +{ + struct be elem; + int count = 0, index; + + /* Sequence of varBind */ + if ((count = asn1_parse(np, length, &elem)) < 0) + return; + if (elem.type != BE_SEQ) { + fputs("[!SEQ of varbind]", stdout); + asn1_print(&elem); + return; + } + if (count < length) + printf("[%d extra after SEQ of varbind]", length - count); + /* descend */ + length = elem.asnlen; + np = (u_char *)elem.data.raw; + + for (index = 1; length > 0; index++) { + u_char *vbend; + int vblength; + + if (!error || index == error) + fputs(" ", stdout); + + /* Sequence */ + if ((count = asn1_parse(np, length, &elem)) < 0) + return; + if (elem.type != BE_SEQ) { + fputs("[!varbind]", stdout); + asn1_print(&elem); + return; + } + vbend = np + count; + vblength = length - count; + /* descend */ + length = elem.asnlen; + np = (u_char *)elem.data.raw; + + /* objName (OID) */ + if ((count = asn1_parse(np, length, &elem)) < 0) + return; + if (elem.type != BE_OID) { + fputs("[objName!=OID]", stdout); + asn1_print(&elem); + return; + } + if (!error || index == error) + asn1_print(&elem); + length -= count; + np += count; + + if (pduid != GETREQ && pduid != GETNEXTREQ && !error) + fputs("=", stdout); + + /* objVal (ANY) */ + if ((count = asn1_parse(np, length, &elem)) < 0) + return; + if (pduid == GETREQ || pduid == GETNEXTREQ) { + if (elem.type != BE_NULL) { + fputs("[objVal!=NULL]", stdout); + asn1_print(&elem); + } + } else + if (error && index == error && elem.type != BE_NULL) + fputs("[err objVal!=NULL]", stdout); + if (!error || index == error) + asn1_print(&elem); + + length = vblength; + np = vbend; + } +} + +/* + * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, and SetRequest + */ +void +snmppdu_print (pduid, np, length) + u_char pduid, *np; + int length; +{ + struct be elem; + int count = 0, error; + + /* reqId (Integer) */ + if ((count = asn1_parse(np, length, &elem)) < 0) + return; + if (elem.type != BE_INT) { + fputs("[reqId!=INT]", stdout); + asn1_print(&elem); + return; + } + /* ignore the reqId */ + length -= count; + np += count; + + /* errorStatus (Integer) */ + if ((count = asn1_parse(np, length, &elem)) < 0) + return; + if (elem.type != BE_INT) { + fputs("[errorStatus!=INT]", stdout); + asn1_print(&elem); + return; + } + error = 0; + if ((pduid == GETREQ || pduid == GETNEXTREQ) + && elem.data.integer != 0) { + char errbuf[10]; + printf("[errorStatus(%s)!=0]", + DECODE_ErrorStatus(elem.data.integer)); + } else if (elem.data.integer != 0) { + char errbuf[10]; + printf(" %s", DECODE_ErrorStatus(elem.data.integer)); + error = elem.data.integer; + } + length -= count; + np += count; + + /* errorIndex (Integer) */ + if ((count = asn1_parse(np, length, &elem)) < 0) + return; + if (elem.type != BE_INT) { + fputs("[errorIndex!=INT]", stdout); + asn1_print(&elem); + return; + } + if ((pduid == GETREQ || pduid == GETNEXTREQ) + && elem.data.integer != 0) + printf("[errorIndex(%d)!=0]", elem.data.integer); + else if (elem.data.integer != 0) { + if (!error) + printf("[errorIndex(%d) w/o errorStatus]", + elem.data.integer); + else { + printf("@%d", elem.data.integer); + error = elem.data.integer; + } + } else if (error) { + fputs("[errorIndex==0]", stdout); + error = 0; + } + length -= count; + np += count; + + varbind_print(pduid, np, length, error); + return; +} + +/* + * Decode SNMP Trap PDU + */ +void +trap_print (np, length) + u_char *np; + int length; +{ + struct be elem; + int count = 0, generic; + + putchar(' '); + + /* enterprise (oid) */ + if ((count = asn1_parse(np, length, &elem)) < 0) + return; + if (elem.type != BE_OID) { + fputs("[enterprise!=OID]", stdout); + asn1_print(&elem); + return; + } + asn1_print(&elem); + length -= count; + np += count; + + putchar(' '); + + /* agent-addr (inetaddr) */ + if ((count = asn1_parse(np, length, &elem)) < 0) + return; + if (elem.type != BE_INETADDR) { + fputs("[agent-addr!=INETADDR]", stdout); + asn1_print(&elem); + return; + } + asn1_print(&elem); + length -= count; + np += count; + + /* generic-trap (Integer) */ + if ((count = asn1_parse(np, length, &elem)) < 0) + return; + if (elem.type != BE_INT) { + fputs("[generic-trap!=INT]", stdout); + asn1_print(&elem); + return; + } + generic = elem.data.integer; + { + char buf[10]; + printf(" %s", DECODE_GenericTrap(generic)); + } + length -= count; + np += count; + + /* specific-trap (Integer) */ + if ((count = asn1_parse(np, length, &elem)) < 0) + return; + if (elem.type != BE_INT) { + fputs("[specific-trap!=INT]", stdout); + asn1_print(&elem); + return; + } + if (generic != GT_ENTERPRISE) { + if (elem.data.integer != 0) + printf("[specific-trap(%d)!=0]", elem.data.integer); + } else + printf(" s=%d", elem.data.integer); + length -= count; + np += count; + + putchar(' '); + + /* time-stamp (TimeTicks) */ + if ((count = asn1_parse(np, length, &elem)) < 0) + return; + if (elem.type != BE_UNS) { /* XXX */ + fputs("[time-stamp!=TIMETICKS]", stdout); + asn1_print(&elem); + return; + } + asn1_print(&elem); + length -= count; + np += count; + + varbind_print (TRAP, np, length, 0); + return; +} + +/* + * Decode SNMP header and pass on to PDU printing routines + */ +void +snmp_print (np, length) + u_char *np; + int length; +{ + struct be elem, pdu; + int count = 0; + + truncated = 0; + + /* truncated packet? */ + if (np + length > snapend) { + truncated = 1; + length = snapend - np; + } + + putchar(' '); + + /* initial Sequence */ + if ((count = asn1_parse(np, length, &elem)) < 0) + return; + if (elem.type != BE_SEQ) { + fputs("[!init SEQ]", stdout); + asn1_print(&elem); + return; + } + if (count < length) + printf("[%d extra after iSEQ]", length - count); + /* descend */ + length = elem.asnlen; + np = (u_char *)elem.data.raw; + /* Version (Integer) */ + if ((count = asn1_parse(np, length, &elem)) < 0) + return; + if (elem.type != BE_INT) { + fputs("[version!=INT]", stdout); + asn1_print(&elem); + return; + } + /* only handle version==0 */ + if (elem.data.integer != DEF_VERSION) { + printf("[version(%d)!=0]", elem.data.integer); + return; + } + length -= count; + np += count; + + /* Community (String) */ + if ((count = asn1_parse(np, length, &elem)) < 0) + return; + if (elem.type != BE_STR) { + fputs("[comm!=STR]", stdout); + asn1_print(&elem); + return; + } + /* default community */ + if (strncmp(elem.data.str, DEF_COMMUNITY, sizeof(DEF_COMMUNITY)-1)) + /* ! "public" */ + printf("C=%.*s ", elem.asnlen, elem.data.str); + length -= count; + np += count; + + /* PDU (Context) */ + if ((count = asn1_parse(np, length, &pdu)) < 0) + return; + if (pdu.type != BE_PDU) { + fputs("[no PDU]", stdout); + return; + } + if (count < length) + printf("[%d extra after PDU]", length - count); + asn1_print(&pdu); + /* descend into PDU */ + length = pdu.asnlen; + np = (u_char *)pdu.data.raw; + + switch (pdu.id) { + case TRAP: + trap_print(np, length); + break; + case GETREQ: + case GETNEXTREQ: + case GETRESP: + case SETREQ: + snmppdu_print(pdu.id, np, length); + break; + } + return; +} diff --git a/usr.sbin/tcpdump/tcpdump/print-sunrpc.c b/usr.sbin/tcpdump/tcpdump/print-sunrpc.c new file mode 100644 index 000000000000..ad28e93b46c0 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-sunrpc.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 1992 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#) $Header: print-sunrpc.c,v 1.1 92/06/02 11:36:37 mccanne Exp $ (LBL)"; +#endif + +#include <stdio.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> + +#include <sys/time.h> +#include <errno.h> +#include <rpc/types.h> +#include <rpc/auth.h> +#include <rpc/auth_unix.h> +#include <rpc/svc.h> +#include <rpc/xdr.h> +#include <rpc/rpc_msg.h> + +#include <rpc/pmap_prot.h> + +#include <ctype.h> + +#include "interface.h" + +#include "addrtoname.h" +#include "extract.h" + +#if BYTE_ORDER == LITTLE_ENDIAN +/* + * Byte swap an array of n words. + * Assume input is word-aligned. + * Check that buffer is bounded by "snapend". + */ +static void +bswap(bp, n) + register u_long *bp; + register u_int n; +{ + register int nwords = ((char *)snapend - (char *)bp) / sizeof(*bp); + + if (nwords > n) + nwords = n; + for (; --nwords >= 0; ++bp) + *bp = ntohl(*bp); +} +#endif + +void +sunrpcrequest_print(rp, length, ip) + register struct rpc_msg *rp; + int length; + register struct ip *ip; +{ + register u_long *dp; + register u_char *ep = snapend; +#define TCHECK(p, l) if ((u_char *)(p) > ep - l) break + +#if BYTE_ORDER == LITTLE_ENDIAN + bswap((u_long *)rp, sizeof(*rp) / sizeof(u_long)); +#endif + + if (!nflag) + (void)printf("%s.%x > %s.sunrpc: %d", + ipaddr_string(&ip->ip_src), + rp->rm_xid, + ipaddr_string(&ip->ip_dst), + length); + else + (void)printf("%s.%x > %s.%x: %d", + ipaddr_string(&ip->ip_src), + rp->rm_xid, + ipaddr_string(&ip->ip_dst), + PMAPPORT, + length); + + switch (rp->rm_call.cb_proc) { + + case PMAPPROC_NULL: + printf(" null"); + break; + + case PMAPPROC_SET: + printf(" set"); + break; + + case PMAPPROC_UNSET: + printf(" unset"); + break; + + case PMAPPROC_GETPORT: + printf(" getport"); + break; + + case PMAPPROC_DUMP: + printf(" dump"); + break; + + case PMAPPROC_CALLIT: + printf(" callit"); + break; + + default: + printf(" proc #%d", rp->rm_call.cb_proc); + } + printf(" prog #%d", rp->rm_call.cb_prog); + putchar('\n'); +} + diff --git a/usr.sbin/tcpdump/tcpdump/print-tcp.c b/usr.sbin/tcpdump/tcpdump/print-tcp.c new file mode 100644 index 000000000000..9974b3c0d027 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-tcp.c @@ -0,0 +1,287 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#) $Header: print-tcp.c,v 1.18 92/05/25 14:29:04 mccanne Exp $ (LBL)"; +#endif + +#include <sys/param.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> + +#ifdef X10 +#include <X/X.h> +#include <X/Xproto.h> +#endif + +#include "interface.h" +#include "addrtoname.h" + +#ifndef TCPOPT_WSCALE +#define TCPOPT_WSCALE 3 /* window scale factor (rfc1072) */ +#endif +#ifndef TCPOPT_SACKOK +#define TCPOPT_SACKOK 4 /* selective ack ok (rfc1072) */ +#endif +#ifndef TCPOPT_SACK +#define TCPOPT_SACK 5 /* selective ack (rfc1072) */ +#endif +#ifndef TCPOPT_ECHO +#define TCPOPT_ECHO 6 /* echo (rfc1072) */ +#endif +#ifndef TCPOPT_ECHOREPLY +#define TCPOPT_ECHOREPLY 7 /* echo (rfc1072) */ +#endif + +struct tha { + struct in_addr src; + struct in_addr dst; + u_int port; +}; + +struct tcp_seq_hash { + struct tcp_seq_hash *nxt; + struct tha addr; + tcp_seq seq; + tcp_seq ack; +}; + +#define TSEQ_HASHSIZE 919 + +static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE]; + + +void +tcp_print(tp, length, ip) + register struct tcphdr *tp; + register int length; + register struct ip *ip; +{ + register u_char flags; + register int hlen; + + if ((u_char *)(tp + 1) > snapend) { + printf("[|tcp]"); + return; + } + if (length < sizeof(struct tcphdr)) { + (void)printf("truncated-tcp %d", length); + return; + } + + NTOHS(tp->th_sport); + NTOHS(tp->th_dport); + NTOHL(tp->th_seq); + NTOHL(tp->th_ack); + NTOHS(tp->th_win); + NTOHS(tp->th_urp); + + (void)printf("%s.%s > %s.%s: ", + ipaddr_string(&ip->ip_src), tcpport_string(tp->th_sport), + ipaddr_string(&ip->ip_dst), tcpport_string(tp->th_dport)); + + if (!qflag) { +#ifdef X10 + register int be; + + if ((be = (tp->th_sport == X_TCP_BI_PORT || + tp->th_dport == X_TCP_BI_PORT)) || + tp->th_sport == X_TCP_LI_PORT || + tp->th_dport == X_TCP_LI_PORT) { + register XReq *xp = (XReq *)(tp + 1); + + x10_print(xp, length - sizeof(struct tcphdr), be); + return; + } +#endif + } + + if (qflag) { + (void)printf("tcp %d", length - tp->th_off * 4); + return; + } + if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) { + if (flags & TH_SYN) + putchar('S'); + if (flags & TH_FIN) + putchar('F'); + if (flags & TH_RST) + putchar('R'); + if (flags & TH_PUSH) + putchar('P'); + } else + putchar('.'); + + if (!Sflag && (flags & TH_ACK)) { + register struct tcp_seq_hash *th; + register int rev; + struct tha tha; + /* + * Find (or record) the initial sequence numbers for + * this conversation. (we pick an arbitrary + * collating order so there's only one entry for + * both directions). + */ + if (tp->th_sport < tp->th_dport || + (tp->th_sport == tp->th_dport && + ip->ip_src.s_addr < ip->ip_dst.s_addr)) { + tha.src = ip->ip_src, tha.dst = ip->ip_dst; + tha.port = tp->th_sport << 16 | tp->th_dport; + rev = 0; + } else { + tha.src = ip->ip_dst, tha.dst = ip->ip_src; + tha.port = tp->th_dport << 16 | tp->th_sport; + rev = 1; + } + + for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; + th->nxt; th = th->nxt) + if (!bcmp((char *)&tha, (char *)&th->addr, + sizeof(th->addr))) + break; + + if (!th->nxt || flags & TH_SYN) { + /* didn't find it or new conversation */ + if (!th->nxt) + th->nxt = (struct tcp_seq_hash *) + calloc(1, sizeof (*th)); + th->addr = tha; + if (rev) + th->ack = tp->th_seq, th->seq = tp->th_ack - 1; + else + th->seq = tp->th_seq, th->ack = tp->th_ack - 1; + } else { + if (rev) + tp->th_seq -= th->ack, tp->th_ack -= th->seq; + else + tp->th_seq -= th->seq, tp->th_ack -= th->ack; + } + } + hlen = tp->th_off * 4; + length -= hlen; + if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) + (void)printf(" %lu:%lu(%d)", tp->th_seq, tp->th_seq + length, + length); + if (flags & TH_ACK) + (void)printf(" ack %lu", tp->th_ack); + + (void)printf(" win %d", tp->th_win); + + if (flags & TH_URG) + (void)printf(" urg %d", tp->th_urp); + /* + * Handle any options. + */ + if ((hlen -= sizeof(struct tcphdr)) > 0) { + register u_char *cp = (u_char *)tp + sizeof(struct tcphdr); + int i; + char ch = '<'; + + putchar(' '); + while (--hlen >= 0) { + putchar(ch); + switch (*cp++) { + case TCPOPT_MAXSEG: + { + u_short mss; +#ifdef TCPDUMP_ALIGN + bcopy((char *)cp + 1, (char *)&mss, + sizeof(mss)); +#else + mss = *(u_short *)(cp + 1); +#endif + (void)printf("mss %d", ntohs(mss)); + if (*cp != 4) + (void)printf("[len %d]", *cp); + cp += 3; + hlen -= 3; + break; + } + case TCPOPT_EOL: + (void)printf("eol"); + break; + case TCPOPT_NOP: + (void)printf("nop"); + break; + case TCPOPT_WSCALE: + (void)printf("wscale %d", cp[1]); + if (*cp != 3) + (void)printf("[len %d]", *cp); + cp += 2; + hlen -= 2; + break; + case TCPOPT_SACKOK: + (void)printf("sackOK"); + if (*cp != 2) + (void)printf("[len %d]", *cp); + cp += 1; + hlen -= 1; + break; + case TCPOPT_ECHO: + { + u_long v; +#ifdef TCPDUMP_ALIGN + bcopy((char *)cp + 1, (char *)&v, + sizeof(v)); +#else + v = *(u_long *)(cp + 1); +#endif + (void)printf("echo %lu", v); + if (*cp != 6) + (void)printf("[len %d]", *cp); + cp += 5; + hlen -= 5; + break; + } + case TCPOPT_ECHOREPLY: + { + u_long v; +#ifdef TCPDUMP_ALIGN + bcopy((char *)cp + 1, (char *)&v, + sizeof(v)); +#else + v = *(u_long *)(cp + 1); +#endif + (void)printf("echoreply %lu", v); + if (*cp != 6) + (void)printf("[len %d]", *cp); + cp += 5; + hlen -= 5; + break; + } + default: + (void)printf("opt-%d:", cp[-1]); + for (i = *cp++ - 2, hlen -= i + 1; i > 0; --i) + (void)printf("%02x", *cp++); + break; + } + ch = ','; + } + putchar('>'); + } +} + diff --git a/usr.sbin/tcpdump/tcpdump/print-tftp.c b/usr.sbin/tcpdump/tcpdump/print-tftp.c new file mode 100644 index 000000000000..3f8f079a6106 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-tftp.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Format and print trivial file transfer protocol packets. + */ +#ifndef lint +static char rcsid[] = + "@(#) $Header: print-tftp.c,v 1.13 91/04/19 10:46:57 mccanne Exp $ (LBL)"; +#endif + +#include <stdio.h> +#include <sys/param.h> +#include <sys/types.h> +#include <arpa/tftp.h> + +#include "interface.h" +#include <strings.h> +#include <ctype.h> + +struct int2str { + int code; + char *str; +}; + +/* op code to string mapping */ +static struct int2str op2str[] = { + RRQ, "RRQ", /* read request */ + WRQ, "WRQ", /* write request */ + DATA, "DATA", /* data packet */ + ACK, "ACK", /* acknowledgement */ + ERROR, "ERROR", /* error code */ + 0, 0 +}; + +/* error code to string mapping */ +static struct int2str err2str[] = { + EUNDEF, "EUNDEF", /* not defined */ + ENOTFOUND, "ENOTFOUND", /* file not found */ + EACCESS, "EACCESS", /* access violation */ + ENOSPACE, "ENOSPACE", /* disk full or allocation exceeded *? + EBADOP, "EBADOP", /* illegal TFTP operation */ + EBADID, "EBADID", /* unknown transfer ID */ + EEXISTS, "EEXISTS", /* file already exists */ + ENOUSER, "ENOUSER", /* no such user */ + 0, 0 +}; + +/* + * Print trivial file transfer program requests + */ +void +tftp_print(tp, length) + register struct tftphdr *tp; + int length; +{ + register struct int2str *ts; + register u_char *ep; +#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc + static char tstr[] = " [|tftp]"; + + /* 'ep' points to the end of avaible data. */ + ep = (u_char *)snapend; + + /* Print length */ + printf(" %d", length); + + /* Print tftp request type */ + TCHECK(tp->th_opcode, sizeof(tp->th_opcode)); + NTOHS(tp->th_opcode); + putchar(' '); + for (ts = op2str; ts->str; ++ts) + if (ts->code == tp->th_opcode) { + fputs(ts->str, stdout); + break; + } + if (ts->str == 0) { + /* Bail if bogus opcode */ + printf("tftp-#%d", tp->th_opcode); + return; + } + + switch (tp->th_opcode) { + + case RRQ: + case WRQ: + putchar(' '); + if (printfn((u_char *)tp->th_stuff, ep)) { + fputs(&tstr[1], stdout); + return; + } + break; + + case DATA: + TCHECK(tp->th_block, sizeof(tp->th_block)); + NTOHS(tp->th_block); + printf(" block %d", tp->th_block); + break; + + case ACK: + break; + + case ERROR: + /* Print error code string */ + TCHECK(tp->th_code, sizeof(tp->th_code)); + NTOHS(tp->th_code); + putchar(' '); + for (ts = err2str; ts->str; ++ts) + if (ts->code == tp->th_code) { + fputs(ts->str, stdout); + break; + } + if (ts->str == 0) + printf("tftp-err-#%d", tp->th_code); + + /* Print error message string */ + putchar(' '); + if (printfn((u_char *)tp->th_data, ep)) { + fputs(&tstr[1], stdout); + return; + } + break; + + default: + /* We shouldn't get here */ + printf("(unknown #%d)", tp->th_opcode); + break; + } + return; +trunc: + fputs(tstr, stdout); +#undef TCHECK +} diff --git a/usr.sbin/tcpdump/tcpdump/print-udp.c b/usr.sbin/tcpdump/tcpdump/print-udp.c new file mode 100644 index 000000000000..cd5180890219 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-udp.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#) $Header: print-udp.c,v 1.26 92/05/22 19:43:17 leres Exp $ (LBL)"; +#endif + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> + +#include <arpa/nameser.h> +#include <arpa/tftp.h> +#include <errno.h> +#include <sys/time.h> +#include <rpc/types.h> +#include <rpc/auth.h> +#include <rpc/auth_unix.h> +#include <rpc/svc.h> +#include <rpc/xdr.h> +#include <rpc/rpc_msg.h> + +#include "interface.h" +/* These must come after interface.h for BSD. */ +#if BSD >= 199006 +#include <sys/ucred.h> +#include <nfs/nfsv2.h> +#endif +#include <nfs/nfs.h> + +#include "addrtoname.h" +#include "appletalk.h" + +#include "bootp.h" + +/* XXX probably should use getservbyname() and cache answers */ +#define TFTP_PORT 69 /*XXX*/ +#define SUNRPC_PORT 111 /*XXX*/ +#define SNMP_PORT 161 /*XXX*/ +#define NTP_PORT 123 /*XXX*/ +#define SNMPTRAP_PORT 162 /*XXX*/ +#define RIP_PORT 520 /*XXX*/ + +void +udp_print(up, length, ip) + register struct udphdr *up; + int length; + register struct ip *ip; +{ + register u_char *cp = (u_char *)(up + 1); + + if (cp > snapend) { + printf("[|udp]"); + return; + } + if (length < sizeof(struct udphdr)) { + (void)printf(" truncated-udp %d", length); + return; + } + length -= sizeof(struct udphdr); + + NTOHS(up->uh_sport); + NTOHS(up->uh_dport); + NTOHS(up->uh_ulen); + + if (! qflag) { + register struct rpc_msg *rp; + enum msg_type direction; + + rp = (struct rpc_msg *)(up + 1); + direction = (enum msg_type)ntohl(rp->rm_direction); + if (up->uh_dport == NFS_PORT && direction == CALL) { + nfsreq_print(rp, length, ip); + return; + } + else if (up->uh_sport == NFS_PORT && direction == REPLY) { + nfsreply_print(rp, length, ip); + return; + } +#ifdef notdef + else if (up->uh_dport == SUNRPC_PORT && direction == CALL) { + sunrpcrequest_print(rp, length, ip); + return; + } +#endif + else if (cp[2] == 2 && (atalk_port(up->uh_sport) || + atalk_port(up->uh_dport))) { + ddp_print((struct atDDP *)(&cp[3]), length - 3); + return; + } + } + (void)printf("%s.%s > %s.%s:", + ipaddr_string(&ip->ip_src), udpport_string(up->uh_sport), + ipaddr_string(&ip->ip_dst), udpport_string(up->uh_dport)); + + if (!qflag) { +#define ISPORT(p) (up->uh_dport == (p) || up->uh_sport == (p)) + if (ISPORT(NAMESERVER_PORT)) + ns_print((HEADER *)(up + 1), length); + else if (ISPORT(TFTP_PORT)) + tftp_print((struct tftphdr *)(up + 1), length); + else if (ISPORT(IPPORT_BOOTPC) || ISPORT(IPPORT_BOOTPS)) + bootp_print((struct bootp *)(up + 1), length, + up->uh_sport, up->uh_dport); + else if (up->uh_dport == RIP_PORT) + rip_print((u_char *)(up + 1), length); + else if (ISPORT(SNMP_PORT) || ISPORT(SNMPTRAP_PORT)) + snmp_print((u_char *)(up + 1), length); + else if (ISPORT(NTP_PORT)) + ntp_print((struct ntpdata *)(up + 1), length); + else + (void)printf(" udp %d", up->uh_ulen - sizeof(*up)); +#undef ISPORT + } else + (void)printf(" udp %d", up->uh_ulen - sizeof(*up)); +} diff --git a/usr.sbin/tcpdump/tcpdump/savefile.c b/usr.sbin/tcpdump/tcpdump/savefile.c new file mode 100644 index 000000000000..79bb9e8afc68 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/savefile.c @@ -0,0 +1,303 @@ +/* + * Copyright (c) 1990,1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#ifndef lint +static char rcsid[] = + "@(#)$Header: savefile.c,v 1.27 92/01/26 21:29:26 mccanne Exp $ (LBL)"; +#endif + +/* + * savefile.c - supports offline use of tcpdump + * Extraction/creation by Jeffrey Mogul, DECWRL + * Modified by Steve McCanne, LBL. + * + * Used to save the received packet headers, after filtering, to + * a file, and then read them later. + * The first record in the file contains saved values for the machine + * dependent values so we can print the dump file on any architecture. + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/time.h> +#include <net/bpf.h> + +#include "version.h" +#include "savefile.h" + +#define TCPDUMP_MAGIC 0xa1b2c3d4 + +/* + * The first record in the file contains saved values for some + * of the flags used in the printout phases of tcpdump. + * Many fields here are longs so compilers won't insert unwanted + * padding; these files need to be interchangeable across architectures. + */ +struct file_header { + u_long magic; + u_short version_major; + u_short version_minor; + long thiszone; /* gmt to local correction */ + u_long sigfigs; /* accuracy of timestamps */ + u_long snaplen; /* max length saved portion of each pkt */ + u_long linktype; +}; + +int sf_swapped; + +FILE *sf_readfile; +FILE *sf_writefile; + +static int +sf_write_header(fp, linktype, thiszone, snaplen, precision) + FILE *fp; + int linktype; + int thiszone; + int snaplen; + int precision; +{ + struct file_header hdr; + + hdr.magic = TCPDUMP_MAGIC; + hdr.version_major = VERSION_MAJOR; + hdr.version_minor = VERSION_MINOR; + + hdr.thiszone = thiszone; + hdr.snaplen = snaplen; + hdr.sigfigs = precision; + hdr.linktype = linktype; + + if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) + return -1; + + return 0; +} + +static void +swap_hdr(hp) + struct file_header *hp; +{ + hp->version_major = SWAPSHORT(hp->version_major); + hp->version_minor = SWAPSHORT(hp->version_minor); + hp->thiszone = SWAPLONG(hp->thiszone); + hp->sigfigs = SWAPLONG(hp->sigfigs); + hp->snaplen = SWAPLONG(hp->snaplen); + hp->linktype = SWAPLONG(hp->linktype); +} + +int +sf_read_init(fname, linktypep, thiszonep, snaplenp, precision) + char *fname; + int *linktypep, *thiszonep, *snaplenp, *precision; +{ + register FILE *fp; + struct file_header hdr; + + if (fname[0] == '-' && fname[1] == '\0') + fp = stdin; + else { + fp = fopen(fname, "r"); + if (fp == 0) { + (void) fprintf(stderr, "tcpdump: fopen: "); + perror(fname); + exit(1); + } + } + if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) { + (void) fprintf(stderr, "tcpdump: fread: "); + perror(fname); + exit(1); + } + if (hdr.magic != TCPDUMP_MAGIC) { + if (SWAPLONG(hdr.magic) != TCPDUMP_MAGIC) + return SFERR_BADF; + sf_swapped = 1; + swap_hdr(&hdr); + } + if (hdr.version_major < VERSION_MAJOR) + return SFERR_BADVERSION; + + *thiszonep = hdr.thiszone; + *snaplenp = hdr.snaplen; + *linktypep = hdr.linktype; + *precision = hdr.sigfigs; + + sf_readfile = fp; + + return 0; +} + +/* + * Print out packets stored in the file initilized by sf_read_init(). + * If cnt >= 0, return after 'cnt' packets, otherwise continue until eof. + */ +int +sf_read(filtp, cnt, snaplen, printit) + struct bpf_program *filtp; + int cnt, snaplen; + void (*printit)(); +{ + struct packet_header h; + u_char *buf; + struct bpf_insn *fcode = filtp->bf_insns; + int status = 0; + + buf = (u_char *)malloc(snaplen); + + while (status == 0) { + status = sf_next_packet(&h, buf, snaplen); + + if (status) + break; + /* + * XXX It's possible (and likely) for us to screw up the + * network layer alignment when we pass down packets from + * this point (ip_print deals by copying the ip header + * to an aligned buffer). There doesn't seem to be a + * clean way to fix this. We could compute an offset + * from the link type (which would have to be passed in), + * but that only works for fixed size headers. + */ + if (bpf_filter(fcode, buf, h.len, h.caplen)) { + if (cnt >= 0 && --cnt < 0) + break; + (*printit)(buf, &h.ts, h.len, h.caplen); + } + } + + if (status == SFERR_EOF) + /* treat EOF's as okay status */ + status = 0; + + free((char *)buf); + return status; +} + +/* + * Read sf_readfile and return the next packet. Return the header in hdr + * and the contents in buf. Return 0 on success, SFERR_EOF if there were + * no more packets, and SFERR_TRUNC if a partial packet was encountered. + */ +int +sf_next_packet(hdr, buf, buflen) + struct packet_header *hdr; + u_char *buf; + int buflen; +{ + FILE *fp = sf_readfile; + + /* read the stamp */ + if (fread((char *)hdr, sizeof(struct packet_header), 1, fp) != 1) { + /* probably an EOF, though could be a truncated packet */ + return SFERR_EOF; + } + + if (sf_swapped) { + /* these were written in opposite byte order */ + hdr->caplen = SWAPLONG(hdr->caplen); + hdr->len = SWAPLONG(hdr->len); + hdr->ts.tv_sec = SWAPLONG(hdr->ts.tv_sec); + hdr->ts.tv_usec = SWAPLONG(hdr->ts.tv_usec); + } + + if (hdr->caplen > buflen) + return SFERR_BADF; + + /* read the packet itself */ + + if (fread((char *)buf, hdr->caplen, 1, fp) != 1) + return SFERR_TRUNC; + + return 0; +} + +/* + * Initialize so that sf_write() will output to the file named 'fname'. + */ +void +sf_write_init(fname, linktype, thiszone, snaplen, precision) + char *fname; + int linktype; + int thiszone; + int snaplen; + int precision; +{ + if (fname[0] == '-' && fname[1] == '\0') + sf_writefile = stdout; + else { + sf_writefile = fopen(fname, "w"); + if (sf_writefile == 0) { + (void) fprintf(stderr, "tcpdump: fopen: "); + perror(fname); + exit(1); + } + } + (void)sf_write_header(sf_writefile, + linktype, thiszone, snaplen, precision); +} + +/* + * Output a packet to the intialized dump file. + */ +void +sf_write(sp, tvp, length, caplen) + u_char *sp; + struct timeval *tvp; + int length; + int caplen; +{ + struct packet_header h; + + h.ts.tv_sec = tvp->tv_sec; + h.ts.tv_usec = tvp->tv_usec; + h.len = length; + h.caplen = caplen; + + (void)fwrite((char *)&h, sizeof h, 1, sf_writefile); + (void)fwrite((char *)sp, caplen, 1, sf_writefile); +} + +void +sf_err(code) + int code; +{ + switch (code) { + case SFERR_BADVERSION: + error("archaic file format"); + /* NOTREACHED */ + + case SFERR_BADF: + error("bad dump file format"); + /* NOTREACHED */ + + case SFERR_TRUNC: + error("truncated dump file"); + /* NOTREACHED */ + + case SFERR_EOF: + error("EOF reading dump file"); + /* NOTREACHED */ + + default: + error("unknown dump file error code in sf_err()"); + /* NOTREACHED */ + } + abort(); +} diff --git a/usr.sbin/tcpdump/tcpdump/savefile.h b/usr.sbin/tcpdump/tcpdump/savefile.h new file mode 100644 index 000000000000..a5082f9fb276 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/savefile.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Header: savefile.h,v 1.10 90/12/17 13:48:58 mccanne Exp $ + * + * Header for offline storage info. + * Extraction/creation by Jeffrey Mogul, DECWRL. + * + * Used to save the received packet headers, after filtering, to + * a file, and then read them later. + */ + +/* + * Each packet in the dump file is prepended with this generic header. + * This gets around the problem of different headers for different + * packet interfaces. + */ +struct packet_header { + struct timeval ts; /* time stamp */ + u_long len; /* length this packet (off wire) */ + u_long caplen; /* length of portion present */ +}; + +/* true if the contents of the savefile being read are byte-swapped */ +extern int sf_swapped; + +/* macros for when sf_swapped is true: */ +/* + * We use the "receiver-makes-right" approach to byte order, + * because time is at a premium when we are writing the file. + * In other words, the file_header and packet_header records + * are written in host byte order. + * Note that the packets are always written in network byte order. + * + * ntoh[ls] aren't sufficient because we might need to swap on a big-endian + * machine (if the file was written in little-end order). + */ +#define SWAPLONG(y) \ +((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff)) +#define SWAPSHORT(y) \ + ( (((y)&0xff)<<8) | (((y)&0xff00)>>8) ) + + +extern FILE *sf_readfile; /* dump file being read from */ +extern FILE *sf_writefile; /* dump file being written to */ + +int sf_read_init(); +int sf_read(); +int sf_next_packet(); +void sf_write_init(); +void sf_write(); +void sf_err(); + +#define SFERR_TRUNC 1 +#define SFERR_BADVERSION 2 +#define SFERR_BADF 3 +#define SFERR_EOF 4 /* not really an error, just a status */ + diff --git a/usr.sbin/tcpdump/tcpdump/tcpdump.1 b/usr.sbin/tcpdump/tcpdump/tcpdump.1 new file mode 100644 index 000000000000..2406319e0ffc --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/tcpdump.1 @@ -0,0 +1,1067 @@ +.\" @(#) $Header: tcpdump.1,v 1.40 92/01/29 16:56:02 mccanne Exp $ (LBL) +.\" +.\" Copyright (c) 1988, 1989, 1990, 1991, 1992 +.\" The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH TCPDUMP 1 "4 Jan 1992" +.SH NAME +tcpdump \- dump traffic on a network +.SH SYNOPSIS +.na +.B tcpdump +[ +.B \-deflnNOpqStvx +] [ +.B \-c +.I count +] [ +.B \-F +.I file +] +.br +.ti +8 +[ +.B \-i +.I interface +] [ +.B \-r +.I file +] +[ +.B \-s +.I snaplen +] +.br +.ti +8 +[ +.B \-w +.I file +] +.I expression +.br +.ad +.SH DESCRIPTION +.LP +\fITcpdump\fP prints out the headers of packets on a network interface +that match the boolean \fIexpression\fP. +.B Under SunOS: +You must be root to invoke \fItcpdump\fP or it must be installed +setuid to root. +.B Under Ultrix: +Any user can invoke \fItcpdump\fP once the super-user has enabled +promiscuous-mode operation using +.IR pfconfig (8). +.B Under BSD: +Access is controlled by the permissions on +.I /dev/bpf0, +etc. +.SH OPTIONS +.TP +.B \-c +Exit after receiving \fIcount\fP packets. +.TP +.B \-d +Dump the compiled packet-matching code to standard output and stop. +.TP +.B \-e +Print the link-level header on each dump line. +.TP +.B \-f +Print `foreign' internet addresses numerically rather than symbolically +(this option is intended to get around serious brain damage in +Sun's yp server \(em usually it hangs forever translating non-local +internet numbers). +.TP +.B \-F +Use \fIfile\fP as input for the filter expression. +An additional expression given on the command line is ignored. +.TP +.B \-i +Listen on \fIinterface\fP. +If unspecified, \fItcpdump\fP searches the system interface list for the +lowest numbered, configured up interface (excluding loopback). +Ties are broken by choosing the earliest match. +.TP +.B \-l +Make stdout line buffered. Useful if you want to see the data +while capturing it. E.g., +.br +``tcpdump\ \ \-l\ \ |\ \ tee dat'' or +``tcpdump\ \ \-l \ \ > dat\ \ &\ \ tail\ \ \-f\ \ dat''. +.TP +.B \-n +Don't convert addresses (i.e., host addresses, port numbers, etc.) to names. +.TP +.B \-N +Don't print domain name qualification of host names. E.g., +if you give this flag then \fItcpdump\fP will print ``nic'' +instead of ``nic.ddn.mil''. +.TP +.B \-O +Do not run the packet-matching code optimizer. This is useful only +if you suspect a bug in the optimizer. +.TP +.B \-p +\fIDon't\fP put the interface +into promiscuous mode. Note that the interface might be in promiscuous +for some other reason; hence, `-p' cannot be used as an abbreviation for +`ether host {localhost} or broadcast'. +.TP +.B \-q +Quick (quiet?) output. Print less protocol information so output +lines are shorter. +.TP +.B \-r +Read packets from \fIfile\fR (which was created with the -w option). +Standard input is used if \fIfile\fR is ``-''. +.TP +.B \-s +Snarf \fIsnaplen\fP bytes of data from each packet rather than the +default of 68 (with NIT, the minimum is actually 96). +68 bytes is adequate for IP, ICMP, TCP +and UDP but may truncate protocol information from name server and NFS +packets (see below). Packets truncated because of a limited snapshot +are indicated in the output with ``[|\fIproto\fP]'', where \fIproto\fP +is the name of the protocol level at which the truncation has occured. +Note that taking larger snapshots both increases +the amount of time it takes to process packets and, effectively, +decreases the amount of packet buffering. This may cause packets to be +lost. You should limit \fIsnaplen\fP to the smallest number that will +capture the protocol information you're interested in. +.TP +.B \-S +Print absolute, rather than relative, TCP sequence numbers. +.TP +.B \-t +\fIDon't\fP print a timestamp on each dump line. +.TP +.B \-tt +Print an unformatted timestamp on each dump line. +.TP +.B \-v +(Slightly more) verbose output. For example, the time to live +and type of service information in an IP packet is printed. +.TP +.B \-w +Write the raw packets to \fIfile\fR rather than parsing and printing +them out. They can later be printed with the \-r option. +Standard output is used if \fIfile\fR is ``-''. +.TP +.B \-x +Print each packet (minus its link level header) in hex. +The smaller of the entire packet or +.I snaplen +bytes will be printed. +.IP "\fI expression\fP" +.RS +selects which packets will be dumped. If no \fIexpression\fP +is given, all packets on the net will be dumped. Otherwise, +only packets for which \fIexpression\fP is `true' will be dumped. +.LP +The \fIexpression\fP consists of one or more +.I primitives. +Primitives usually consist of an +.I id +(name or number) preceded by one or more qualifiers. There are three +different kinds of qualifier: +.IP \fItype\fP +qualifiers say what kind of thing the id name or number refers to. +Possible types are +.BR host , +.B net +and +.BR port . +E.g., `host foo', `net 128.3', `port 20'. If there is no type +qualifier, +.B host +is assumed. +.IP \fIdir\fP +qualifiers specify a particular tranfer direction to and/or from +.I id. +Possible directions are +.BR src , +.BR dst , +.B "src or dst" +and +.BR "src and dst" . +E.g., `src foo', `dst net 128.3', `src or dst port ftp-data'. If +there is no dir qualifier, +.B "src or dst" +is assumed. +.IP \fIproto\fP +qualifiers restrict the match to a particular protocol. Possible +protos are: +.BR ether , +.BR ip , +.BR arp , +.BR rarp , +.B tcp +and +.BR udp . +E.g., `ether src foo', `arp net 128.3', `tcp port 21'. If there is +no proto qualifier, all protocols consistent with the type are +assumed. E.g., `src foo' means `(ip or arp or rarp) src foo' +(except the latter is not legal syntax), `net bar' means `(ip or +arp or rarp) net bar' and `port 53' means `(tcp or udp) port 53'. +.LP +In addition to the above, there are some special `primitive' keywords +that don't follow the pattern: +.BR gateway , +.BR broadcast , +.BR less , +.B greater +and arithmetic expressions. All of these are described below. +.LP +More complex filter expressions are built up by using the words +.BR and , +.B or +and +.B not +to combine primitives. E.g., `host foo and not port ftp and not port ftp-data'. +To save typing, identical qualifier lists can be omitted. E.g., +`tcp dst port ftp or ftp-data or domain' is exactly the same as +`tcp dst port ftp or tcp dst port ftp-data or tcp dst port domain'. +.LP +Allowable primitives are: +.IP "\fBdst host \fIhost\fR" +True if the IP destination field of the packet is \fIhost\fP, +which may be either an address or a name. +.IP "\fBsrc host \fIhost\fR" +True if the IP source field of the packet is \fIhost\fP. +.IP "\fBhost \fIhost\fP +True if either the IP source or destination of the packet is \fIhost\fP. +Any of the above host expressions can be prepended with the keywords, +\fBip\fP, \fBarp\fP, or \fBrarp\fP as in: +.in +.5i +.nf +\fBip host \fIhost\fR +.fi +.in -.5i +which is equivalent to: +.in +.5i +.nf +\fBether proto \fI\\ip\fB and host \fIhost\fR +.fi +.in -.5i +If \fIhost\fR is a name with multiple IP addresses, each address will +be checked for a match. +.IP "\fBether dst \fIehost\fP +True if the ethernet destination address is \fIehost\fP. \fIEhost\fP +may be either a name from /etc/ethers or a number (see +.IR ethers (3N) +for numeric format). +.IP "\fBether src \fIehost\fP +True if the ethernet source address is \fIehost\fP. +.IP "\fBether host \fIehost\fP +True if either the ethernet source or destination address is \fIehost\fP. +.IP "\fBgateway\fP \fIhost\fP +True if the packet used \fIhost\fP as a gateway. I.e., the ethernet +source or destination address was \fIhost\fP but neither the IP source +nor the IP destination was \fIhost\fP. \fIHost\fP must be a name and +must be found in both /etc/hosts and /etc/ethers. (An equivalent +expression is +.in +.5i +.nf +\fBether host \fIehost \fBand not host \fIhost\fR +.fi +.in -.5i +which can be used with either names or numbers for \fIhost / ehost\fP.) +.IP "\fBdst net \fInet\fR" +True if the IP destination address of the packet has a network +number of \fInet\fP, which may be either an address or a name. +.IP "\fBsrc net \fInet\fR" +True if the IP source address of the packet has a network +number of \fInet\fP. +.IP "\fBnet \fInet\fR" +True if either the IP source or destination address of the packet has a network +number of \fInet\fP. +.IP "\fBdst port \fIport\fR" +True if the packet is ip/tcp or ip/udp and has a +destination port value of \fIport\fP. +The \fIport\fP can be a number or a name used in /etc/services (see +.IR tcp (4P) +and +.IR udp (4P)). +If a name is used, both the port +number and protocol are checked. If a number or ambiguous name is used, +only the port number is checked (e.g., \fBdst port 513\fR will print both +tcp/login traffic and udp/who traffic, and \fBport domain\fR will print +both tcp/domain and udp/domain traffic). +.IP "\fBsrc port \fIport\fR" +True if the packet has a source port value of \fIport\fP. +.IP "\fBport \fIport\fR" +True if either the source or destination port of the packet is \fIport\fP. +Any of the above port expressions can be prepended with the keywords, +\fBtcp\fP or \fBudp\fP, as in: +.in +.5i +.nf +\fBtcp src port \fIport\fR +.fi +.in -.5i +which matches only tcp packets. +.IP "\fBless \fIlength\fR" +True if the packet has a length less than or equal to \fIlength\fP. +This is equivalent to: +.in +.5i +.nf +\fBlen <= \fIlength\fP. +.fi +.in -.5i +.IP "\fBgreater \fIlength\fR" +True if the packet has a length greater than or equal to \fIlength\fP. +This is equivalent to: +.in +.5i +.nf +\fBlen >= \fIlength\fP. +.fi +.in -.5i +.IP "\fBip proto \fIprotocol\fR" +True if the packet is an ip packet (see +.IR ip (4P)) +of protocol type \fIprotocol\fP. +\fIProtocol\fP can be a number or one of the names +\fIicmp\fP, \fIudp\fP, \fInd\fP, or \fItcp\fP. +Note that the identifiers \fItcp\fP, \fIudp\fP, and \fIicmp\fP are also +keywords and must be escaped via backslash (\\), which is \\\\ in the C-shell. +.IP "\fBether broadcast\fR" +True if the packet is an ethernet broadcast packet. The \fIether\fP +keyword is optional. +.IP "\fBip broadcast\fR" +True if the packet is an IP broadcast packet. It checks for both +the all-zeroes and all-ones broadcast conventions, and looks up +the local subnet mask. +.IP "\fBether multicast\fR" +True if the packet is an ethernet multicast packet. The \fIether\fP +keyword is optional. +This is shorthand for `\fBether[0] & 1 != 0\fP'. +.IP "\fBip multicast\fR" +True if the packet is an IP multicast packet. +.IP "\fBether proto \fIprotocol\fR" +True if the packet is of ether type \fIprotocol\fR. +\fIProtocol\fP can be a number or a name like +\fIip\fP, \fIarp\fP, or \fIrarp\fP. +Note these identifiers are also keywords +and must be escaped via backslash (\\). +.IP "\fBip\fR, \fBarp\fR, \fBrarp\fR" +Abbreviations for: +.in +.5i +.nf +\fBether proto \fIp\fR +.fi +.in -.5i +where \fIp\fR is one of the above protocols. +.IP "\fBtcp\fR, \fBudp\fR, \fBicmp\fR" +Abbreviations for: +.in +.5i +.nf +\fBip proto \fIp\fR +.fi +.in -.5i +where \fIp\fR is one of the above protocols. +.IP "\fIexpr relop expr\fR" +True if the relation holds, where \fIrelop\fR is one of >, <, >=, <=, =, !=, +and \fIexpr\fR is an arithmetic expression composed of integer constants +(expressed in standard C syntax), the normal binary operators +[+, -, *, /, &, |], a length operator, and special packet data accessors. +To access +data inside the packet, use the following syntax: +.in +.5i +.nf +\fIproto\fB [ \fIexpr\fB : \fIsize\fB ]\fR +.fi +.in -.5i +\fIProto\fR is one of \fBether, ip, arp, rarp, tcp, udp, \fRor \fBicmp\fR, and +indicates the protocol layer for the index operation. +The byte offset, relative to the indicated protocol layer, is +given by \fIexpr\fR. +\fISize\fR is optional and indicates the number of bytes in the +field of interest; it can be either one, two, or four, and defaults to one. +The length operator, indicated by the keyword \fBlen\fP, gives the +length of the packet. + +For example, `\fBether[0] & 1 != 0\fP' catches all multicast traffic. +The expression `\fBip[0] & 0xf != 5\fP' +catches all IP packets with options. The expression +`\fBip[2:2] & 0x1fff = 0\fP' +catches only unfragmented datagrams and frag zero of fragmented datagrams. +This check is implicitly applied to the \fBtcp\fP and \fBudp\fP +index opertations. +For instance, \fBtcp[0]\fP always means the first +byte of the TCP \fIheader\fP, and never means the first byte of an +intervening fragment. +.LP +Primitives may be combined using: +.IP +A parenthesized group of primitives and operators +(parentheses are special to the Shell and must be escaped). +.IP +Negation (`\fB!\fP' or `\fBnot\fP'). +.IP +Concatenation (`\fBand\fP'). +.IP +Alternation (`\fBor\fP'). +.LP +Negation has highest precedence. +Alternation and concatenation have equal precedence and associate +left to right. Note that explicit \fBand\fR tokens, not juxtaposition, +are now required for concatenation. +.LP +If an identifier is given without a keyword, the most recent keyword +is assumed. +For example, +.in +.5i +.nf +\fBnot host vs and ace\fR +.fi +.in -.5i +is short for +.in +.5i +.nf +\fBnot host vs and host ace\fR +.fi +.in -.5i +which should not be confused with +.in +.5i +.nf +\fBnot ( host vs or ace )\fR +.fi +.in -.5i +.LP +Expression arguments can be passed to tcpdump as either a single argument +or as multiple arguments, whichever is more convenient. +Generally, if the expression contains Shell metacharacters, it is +easier to pass it as a single, quoted argument. +Multiple arguments are concatenated with spaces before being parsed. +.SH EXAMPLES +.LP +To print all packets arriving at or departing from \fIsundown\fP: +.RS +.nf +\fBtcpdump host sundown\fP +.fi +.RE +.LP +To print traffic between \fIhelios\fR and either \fIhot\fR or \fIace\fR: +.RS +.nf +\fBtcpdump host helios and \\( hot or ace \\)\fP +.fi +.RE +.LP +To print all IP packets between \fIace\fR and any host except \fIhelios\fR: +.RS +.nf +\fBtcpdump ip host ace and not helios\fP +.fi +.RE +.LP +To print all traffic between local hosts and hosts at Berkeley: +.RS +.nf +.B +tcpdump net ucb-ether +.fi +.RE +.LP +To print all ftp traffic through internet gateway \fIsnup\fP: +(note that the expression is quoted to prevent the shell from +(mis-)interpreting the parentheses): +.RS +.nf +.B +tcpdump 'gateway snup and (port ftp or ftp-data)' +.fi +.RE +.LP +To print traffic neither sourced from nor destined for local hosts +(if you gateway to one other net, this stuff should never make it +onto your local net). +.RS +.nf +.B +tcpdump ip and not net \fIlocalnet\fP +.fi +.RE +.LP +To print the start and end packets (the SYN and FIN packets) of each +TCP conversation that involves a non-local host. +.RS +.nf +.B +tcpdump 'tcp[13] & 3 != 0 and not src and dst net \fIlocalnet\fP' +.fi +.RE +.LP +To print IP packets longer than 576 bytes sent through gateway \fIsnup\fP: +.RS +.nf +.B +tcpdump 'gateway snup and ip[2:2] > 576' +.fi +.RE +.LP +To print IP broadcast or multicast packets that were +.I not +sent via ethernet broadcast or multicast: +.RS +.nf +.B +tcpdump 'ether[0] & 1 = 0 and ip[16] >= 224' +.fi +.RE +.LP +To print all ICMP packets that are not echo requests/replies (i.e., not +ping packets): +.RS +.nf +.B +tcpdump 'icmp[0] != 8 and icmp[0] != 0" +.fi +.RE +.SH OUTPUT FORMAT +.LP +The output of \fItcpdump\fP is protocol dependent. The following +gives a brief description and examples of most of the formats. +.de HD +.sp 1.5 +.B +.. +.HD +Link Level Headers +.LP +If the '-e' option is given, the link level header is printed out. +On ethernets, the source and destination addresses, protocol, +and packet length are printed. +.LP +\fI(N.B.: The following description assumes familiarity with +the SLIP compression algorithm described in RFC-1144.)\fP +.LP +On SLIP links, a direction indicator (``I'' for inbound, ``O'' for outbound), +packet type, and compression information are printed out. +The packet type is printed first. +The three types are \fIip\fP, \fIutcp\fP, and \fIctcp\fP. +No further link information is printed for \fIip\fR packets. +For TCP packets, the connection identifier is printed following the type. +If the packet is compressed, its encoded header is printed out. +The special cases are printed out as +\fB*S+\fIn\fR and \fB*SA+\fIn\fR, where \fIn\fR is the amount by which +the sequence number (or sequence number and ack) has changed. +If it is not a special case, +zero or more changes are printed. +A change is indicated by U (urgent pointer), W (window), A (ack), +S (sequence number), and I (packet ID), followed by a delta (+n or -n), +or a new value (=n). +Finally, the amount of data in the packet and compressed header length +are printed. +.LP +For example, the following line shows an outbound compressed TCP packet, +with an implicit connection identifier; the ack has changed by 6, +the sequence number by 49, and the packet ID by 6; there are 3 bytes of +data and 6 bytes of compressed header: +.RS +.nf +\fBO ctcp * A+6 S+49 I+6 3 (6)\fP +.fi +.RE +.HD +ARP/RARP Packets +.LP +Arp/rarp output shows the type of request and its arguments. The +format is intended to be self explanatory. +Here is a short sample taken from the start of an `rlogin' from +host \fIrtsg\fP to host \fIcsam\fP: +.RS +.nf +.sp .5 +\f(CWarp who-has csam tell rtsg +arp reply csam is-at CSAM\fP +.sp .5 +.fi +.RE +The first line says that rtsg sent an arp packet asking +for the ethernet address of internet host csam. Csam +replies with its ethernet address (in this example, ethernet addresses +are in caps and internet addresses in lower case). +.LP +This would look less redundant if we had done \fBtcpdump \-n\fP: +.RS +.nf +.sp .5 +\f(CWarp who-has 128.3.254.6 tell 128.3.254.68 +arp reply 128.3.254.6 is-at 02:07:01:00:01:c4\fP +.fi +.RE +.LP +If we had done \fBtcpdump \-e\fP, the fact that the first packet is +broadcast and the second is point-to-point would be visible: +.RS +.nf +.sp .5 +\f(CWRTSG Broadcast 0806 64: arp who-has csam tell rtsg +CSAM RTSG 0806 64: arp reply csam is-at CSAM\fP +.sp .5 +.fi +.RE +For the first packet this says the ethernet source address is RTSG, the +destination is the broadcast address, the type field +contained hex 0806 (type ETHER_ARP) and the total length was 64 bytes. +.HD +TCP Packets +.LP +\fI(N.B.:The following description assumes familiarity with +the TCP protocol described in RFC-793. If you are not familiar +with the protocol, neither this description nor tcpdump will +be of much use to you.)\fP +.LP +The general format of a tcp protocol line is: +.RS +.nf +.sp .5 +\fIsrc > dst: flags data-seqno ack window urgent options\fP +.sp .5 +.fi +.RE +\fISrc\fP and \fIdst\fP are the source and destination IP +addresses and ports. \fIFlags\fP are some combination of S (SYN), +F (FIN), P (PUSH) or R (RST) or a single `.' (no flags). +\fIData-seqno\fP describes the portion of sequence space covered +by the data in this packet (see example below). +\fIAck\fP is sequence number of the next data expected the other +direction on this connection. +\fIWindow\fP is the number of bytes of receive buffer space available +the other direction on this connection. +\fIUrg\fP indicates there is `urgent' data in the packet. +\fIOptions\fP are tcp options enclosed in angle brackets (e.g., <mss 1024>). +.LP +\fISrc, dst\fP and \fIflags\fP are always present. The other fields +depend on the contents of the packet's tcp protocol header and +are output only if appropriate. +.LP +Here is the opening portion of an rlogin from host \fIrtsg\fP to +host \fIcsam\fP. +.RS +.nf +.sp .5 +\s-2\f(CWrtsg.1023 > csam.login: S 768512:768512(0) win 4096 <mss 1024> +csam.login > rtsg.1023: S 947648:947648(0) ack 768513 win 4096 <mss 1024> +rtsg.1023 > csam.login: . ack 1 win 4096 +rtsg.1023 > csam.login: P 1:2(1) ack 1 win 4096 +csam.login > rtsg.1023: . ack 2 win 4096 +rtsg.1023 > csam.login: P 2:21(19) ack 1 win 4096 +csam.login > rtsg.1023: P 1:2(1) ack 21 win 4077 +csam.login > rtsg.1023: P 2:3(1) ack 21 win 4077 urg 1 +csam.login > rtsg.1023: P 3:4(1) ack 21 win 4077 urg 1\fP\s+2 +.sp .5 +.fi +.RE +The first line says that tcp port 1023 on rtsg sent a packet +to port \fIlogin\fP +on csam. The \fBS\fP indicates that the \fISYN\fP flag was set. +The packet sequence number was 768512 and it contained no data. +(The notation is `first:last(nbytes)' which means `sequence +numbers \fIfirst\fP +up to but not including \fIlast\fP which is \fInbytes\fP bytes of user data'.) +There was no piggy-backed ack, the available receive window was 4096 +bytes and there was a max-segment-size option requesting an mss of +1024 bytes. +.LP +Csam replies with a similar packet except it includes a piggy-backed +ack for rtsg's SYN. Rtsg then acks csam's SYN. The `.' means no +flags were set. +The packet contained no data so there is no data sequence number. +Note that the ack sequence +number is a small integer (1). The first time \fBtcpdump\fP sees a +tcp `conversation', it prints the sequence number from the packet. +On subsequent packets of the conversation, the difference between +the current packet's sequence number and this initial sequence number +is printed. This means that sequence numbers after the +first can be interpreted +as relative byte positions in the conversation's data stream (with the +first data byte each direction being `1'). `-S' will override this +feature, causing the original sequence numbers to be output. +.LP +On the 6th line, rtsg sends csam 19 bytes of data (bytes 2 through 20 +in the rtsg \(-> csam side of the conversation). +The PUSH flag is set in the packet. +On the 7th line, csam says it's received data sent by rtsg up to +but not including byte 21. Most of this data is apparently sitting in the +socket buffer since csam's receive window has gotten 19 bytes smaller. +Csam also sends one byte of data to rtsg in this packet. +On the 8th and 9th lines, +csam sends two bytes of urgent, pushed data to rtsg. +.HD +.B +UDP Packets +.LP +UDP format is illustrated by this rwho packet: +.RS +.nf +.sp .5 +\f(CWactinide.who > broadcast.who: udp 84\fP +.sp .5 +.fi +.RE +This says that port \fIwho\fP on host \fIactinide\fP sent a udp +datagram to port \fIwho\fP on host \fIbroadcast\fP, the Internet +broadcast address. The packet contained 84 bytes of user data. +.LP +Some UDP services are recognized (from the source or destination +port number) and the higher level protocol information printed. +In particular, Domain Name service requests (RFC-1034/1035) and Sun +RPC calls (RFC-1050) to NFS. +.HD +UDP Name Server Requests +.LP +\fI(N.B.:The following description assumes familiarity with +the Domain Service protocol described in RFC-1035. If you are not familiar +with the protocol, the following description will appear to be written +in greek.)\fP +.LP +Name server requests are formatted as +.RS +.nf +.sp .5 +\fIsrc > dst: id op? flags qtype qclass name (len)\fP +.sp .5 +\f(CWh2opolo.1538 > helios.domain: 3+ A? ucbvax.berkeley.edu. (37)\fP +.sp .5 +.fi +.RE +Host \fIh2opolo\fP asked the domain server on \fIhelios\fP for an +address record (qtype=A) associated with the name \fIucbvax.berkeley.edu.\fP +The query id was `3'. The `+' indicates the \fIrecursion desired\fP flag +was set. The query length was 37 bytes, not including the UDP and +IP protocol headers. The query operation was the normal one, \fIQuery\fP, +so the op field was omitted. If the op had been anything else, it would +have been printed between the `3' and the `+'. +Similarly, the qclass was the normal one, +\fIC_IN\fP, and omitted. Any other qclass would have been printed +immediately after the `A'. +.LP +A few anomalies are checked and may result in extra fields enclosed in +square brackets: If a query contains an answer, name server or +authority section, +.IR ancount , +.IR nscount , +or +.I arcount +are printed as `[\fIn\fPa]', `[\fIn\fPn]' or `[\fIn\fPau]' where \fIn\fP +is the appropriate count. +If any of the response bits are set (AA, RA or rcode) or any of the +`must be zero' bits are set in bytes two and three, `[b2&3=\fIx\fP]' +is printed, where \fIx\fP is the hex value of header bytes two and three. +.HD +UDP Name Server Responses +.LP +Name server responses are formatted as +.RS +.nf +.sp .5 +\fIsrc > dst: id op rcode flags a/n/au type class data (len)\fP +.sp .5 +\f(CWhelios.domain > h2opolo.1538: 3 3/3/7 A 128.32.137.3 (273) +helios.domain > h2opolo.1537: 2 NXDomain* 0/1/0 (97)\fP +.sp .5 +.fi +.RE +In the first example, \fIhelios\fP responds to query id 3 from \fIh2opolo\fP +with 3 answer records, 3 name server records and 7 authority records. +The first answer record is type A (address) and its data is internet +address 128.32.137.3. The total size of the response was 273 bytes, +excluding UDP and IP headers. The op (Query) and response code +(NoError) were omitted, as was the class (C_IN) of the A record. +.LP +In the second example, \fIhelios\fP responds to query 2 with a +response code of non-existent domain (NXDomain) with no answers, +one name server and no authority records. The `*' indicates that +the \fIauthoritative answer\fP bit was set. Since there were no +answers, no type, class or data were printed. +.LP +Other flag characters that might appear are `\-' (recursion available, +RA, \fInot\fP set) and `|' (truncated message, TC, set). If the +`question' section doesn't contain exactly one entry, `[\fIn\fPq]' +is printed. +.LP +Note that name server requests and responses tend to be large and the +default \fIsnaplen\fP of 96 bytes may not capture enough of the packet +to print. Use the \fB\-s\fP flag to increase the snaplen if you +need to seriously investigate name server traffic. `\fB\-s 128\fP' +has worked well for me. + +.HD +NFS Requests +.LP +Sun NFS (Network File System) requests and replies are printed as: +.RS +.nf +.sp .5 +\fIsrc.xid > dst.nfs: len op args\fP +\fIsrc.nfs > dst.xid: reply stat len\fP +.sp .5 +\f(CWvs.e2766 > helios.nfs: 136 readdir fh 6.5197 8192 bytes @ 0 +helios.nfs > vs.e2766: reply ok 384 +vs.e2767 > helios.nfs: 136 lookup fh 6.5197 `RCS'\fP +.sp .5 +.fi +.RE +In the first line, host \fIvs\fP sends a transaction with id \fIe2766\fP +to \fIhelios\fP (note that the number following the src host is a +transaction id, \fInot\fP the source port). The request was 136 bytes, +excluding the UDP and IP headers. The operation was a \fIreaddir\fP +(read directory) on file handle (\fIfh\fP) 6.5197. 8192 bytes are +read, starting at offset 0. \fIHelios\fP replies `ok' with 384 +bytes of data. (The design of Sun's RPC protocol makes it difficult to +interpret replies. I don't bother.) +.LP +In the third line, \fIvs\fP asks \fIhelios\fP to lookup the name +`\fIRCS\fP' in directory file 6.5197. Note that the data printed +depends on the operation type. The format is intended to be self +explanatory (at least, to me) if read in conjunction with +an NFS protocol spec. +.LP +Note that NFS requests are very large and the above won't be printed +unless \fIsnaplen\fP is increased. I use `\fB\-s 192\fP' to watch +NFS traffic. + +.HD +KIP Appletalk (DDP in UDP) +.LP +Appletalk DDP packets encapsulated in UDP datagrams are de-encapsulated +and dumped as DDP packets (i.e., all the UDP header information is +discarded). The file +.I /etc/atalk.names +is used to translate appletalk net and node numbers to names. +Lines in this file have the form +.RS +.nf +.sp .5 +\fInumber name\fP + +\f(CW1.254 ether +16.1 icsd-net +1.254.110 ace\fP +.sp .5 +.fi +.RE +The first two lines give the names of appletalk networks. The third +line gives the name of a particular host (a host is distinguished +from a net by the 3rd octet in the number \- +a net number \fImust\fP have two octets and a host number \fImust\fP +have three octets.) The number and name should be separated by +whitespace (blanks or tabs). +The +.I /etc/atalk.names +file may contain blank lines or comment lines (lines starting with +a `#'). +.LP +Appletalk addresses are printed in the form +.RS +.nf +.sp .5 +\fInet.host.port\fP + +\f(CW144.1.209.2 > icsd-net.112.220 +office.2 > icsd-net.112.220 +jssmag.149.235 > icsd-net.2\fP +.sp .5 +.fi +.RE +(If the +.I /etc/atalk.names +doesn't exist or doesn't contain an entry for some appletalk +host/net number, addresses are printed in numeric form.) +In the first example, NBP (DDP port 2) on net 144.1 node 209 +is sending to whatever is listening on port 220 of net icsd node 112. +The second line is the same except the full name of the source node +is known (`office'). The third line is a send from port 235 on +net jssmag node 149 to broadcast on the icsd-net NBP port (note that +the broadcast address (255) is indicated by a net name with no host +number \- for this reason it's a good idea to keep node names and +net names distinct in /etc/atalk.names). +.LP +NBP (name binding protocol) and ATP (Appletalk transaction protocol) +packets have their contents interpreted. Other protocols just dump +the protocol name (or number if no name is registered for the +protocol) and packet size. + +\fBNBP packets\fP are formatted like the following examples: +.RS +.nf +.sp .5 +\s-2\f(CWicsd-net.112.220 > jssmag.2: nbp-lkup 190: "=:LaserWriter@*" +jssmag.209.2 > icsd-net.112.220: nbp-reply 190: "RM1140:LaserWriter@*" 250 +techpit.2 > icsd-net.112.220: nbp-reply 190: "techpit:LaserWriter@*" 186\fP\s+2 +.sp .5 +.fi +.RE +The first line is a name lookup request for laserwriters sent by net icsd host +112 and broadcast on net jssmag. The nbp id for the lookup is 190. +The second line shows a reply for this request (note that it has the +same id) from host jssmag.209 saying that it has a laserwriter +resource named "RM1140" registered on port 250. The third line is +another reply to the same request saying host techpit has laserwriter +"techpit" registered on port 186. + +\fBATP packet\fP formatting is demonstrated by the following example: +.RS +.nf +.sp .5 +\s-2\f(CWjssmag.209.165 > helios.132: atp-req 12266<0-7> 0xae030001 +helios.132 > jssmag.209.165: atp-resp 12266:0 (512) 0xae040000 +helios.132 > jssmag.209.165: atp-resp 12266:1 (512) 0xae040000 +helios.132 > jssmag.209.165: atp-resp 12266:2 (512) 0xae040000 +helios.132 > jssmag.209.165: atp-resp 12266:3 (512) 0xae040000 +helios.132 > jssmag.209.165: atp-resp 12266:4 (512) 0xae040000 +helios.132 > jssmag.209.165: atp-resp 12266:5 (512) 0xae040000 +helios.132 > jssmag.209.165: atp-resp 12266:6 (512) 0xae040000 +helios.132 > jssmag.209.165: atp-resp*12266:7 (512) 0xae040000 +jssmag.209.165 > helios.132: atp-req 12266<3,5> 0xae030001 +helios.132 > jssmag.209.165: atp-resp 12266:3 (512) 0xae040000 +helios.132 > jssmag.209.165: atp-resp 12266:5 (512) 0xae040000 +jssmag.209.165 > helios.132: atp-rel 12266<0-7> 0xae030001 +jssmag.209.133 > helios.132: atp-req* 12267<0-7> 0xae030002\fP\s+2 +.sp .5 +.fi +.RE +Jssmag.209 initiates transaction id 12266 with host helios by requesting +up to 8 packets (the `<0-7>'). The hex number at the end of the line +is the value of the `userdata' field in the request. +.LP +Helios responds with 8 512-byte packets. The `:digit' following the +transaction id gives the packet sequence number in the transaction +and the number in parens is the amount of data in the packet, +excluding the atp header. The `*' on packet 7 indicates that the +EOM bit was set. +.LP +Jssmag.209 then requests that packets 3 & 5 be retransmitted. Helios +resends them then jssmag.209 releases the transaction. Finally, +jssmag.209 initiates the next request. The `*' on the request +indicates that XO (`exactly once') was \fInot\fP set. + +.HD +IP Fragmentation +.LP +Fragmented Internet datagrams are printed as +.RS +.nf +.sp .5 +\fB(frag \fIid\fB:\fIsize\fB@\fIoffset\fB+)\fR +\fB(frag \fIid\fB:\fIsize\fB@\fIoffset\fB)\fR +.sp .5 +.fi +.RE +(The first form indicates there are more fragments. The second +indicates this is the last fragment.) +.LP +\fIId\fP is the fragment id. \fISize\fP is the fragment +size (in bytes) excluding the IP header. \fIOffset\fP is this +fragment's offset (in bytes) in the original datagram. +.LP +The fragment information is output for each fragment. The first +fragment contains the higher level protocol header and the frag +info is printed after the protocol info. Fragments +after the first contain no higher level protocol header and the +frag info is printed after the source and destination addresses. +For example, here is part of an ftp from arizona.edu to lbl-rtsg.arpa +over a CSNET connection that doesn't appear to handle 576 byte datagrams: +.RS +.nf +.sp .5 +\s-2\f(CWarizona.ftp-data > rtsg.1170: . 1024:1332(308) ack 1 win 4096 (frag 595a:328@0+) +arizona > rtsg: (frag 595a:204@328) +rtsg.1170 > arizona.ftp-data: . ack 1536 win 2560\fP\s+2 +.sp .5 +.fi +.RE +There are a couple of things to note here: First, addresses in the +2nd line don't include port numbers. This is because the TCP +protocol information is all in the first fragment and we have no idea +what the port or sequence numbers are when we print the later fragments. +Second, the tcp sequence information in the first line is printed as if there +were 308 bytes of user data when, in fact, there are 512 bytes (308 in +the first frag and 204 in the second). If you are looking for holes +in the sequence space or trying to match up acks +with packets, this can fool you. +.LP +A packet with the IP \fIdon't fragment\fP flag is marked with a +trailing \fB(DF)\fP. +.HD +Timestamps +.LP +By default, all output lines are preceded by a timestamp. The timestamp +is the current clock time in the form +.RS +.nf +\fIhh:mm:ss.frac\fP +.fi +.RE +and is as accurate as the kernel's clock (e.g., \(+-10ms on a Sun-3). +The timestamp reflects the time the kernel first saw the packet. No attempt +is made to account for the time lag between when the +ethernet interface removed the packet from the wire and when the kernel +serviced the `new packet' interrupt (of course, +with Sun's lousy clock resolution this time lag is negligible.) +.SH "SEE ALSO" +traffic(1C), nit(4P), bpf(4) +.SH AUTHORS +Van Jacobson (van@helios.ee.lbl.gov), +Craig Leres (leres@helios.ee.lbl.gov) and +Steven McCanne (mccanne@helios.ee.lbl.gov), all of +Lawrence Berkeley Laboratory, University of California, Berkeley, CA. +.SH BUGS +The clock resolution on most Suns is pathetic (20ms). +If you want to use the timestamp to generate some of the important +performance distributions (like packet interarrival time) it's best +to watch something that generates packets slowly (like an Arpanet +gateway or a MicroVax running VMS). +.LP +NIT doesn't let you watch your own outbound traffic, BPF will. +We recommend that you use the latter. +.LP +\fItcpdump\fP for Ultrix requires Ultrix version 4.0 or later; the kernel +has to have been built with the \fIpacketfilter\fP pseudo-device driver +(see +.IR packetfilter (4)). +As of this writing, Ultrix does not let you +watch either your own outbound or inbound traffic. +.LP +Under SunOS 4.1, the packet capture code (or Streams NIT) is not what +you'd call efficient. Don't plan on doing much with your Sun while +you're monitoring a busy network. +.LP +On Sun systems prior to release 3.2, NIT is very buggy. +If run on an old system, tcpdump may crash the machine. +.LP +Some attempt should be made to reassemble IP fragments or, at least +to compute the right length for the higher level protocol. +.LP +Name server inverse queries are not dumped correctly: The (empty) +question section is printed rather than real query in the answer +section. Some believe that inverse queries are themselves a bug and +prefer to fix the program generating them rather than tcpdump. +.LP +Apple Ethertalk DDP packets could be dumped as easily as KIP DDP +packets but aren't. +Even if we were inclined to do anything to promote the use of +Ethertalk (we aren't), LBL doesn't allow Ethertalk on any of its +networks so we'd would have no way of testing this code. +.LP +A packet trace that crosses a daylight savings time change will give +skewed time stamps (the time change is ignored). diff --git a/usr.sbin/tcpdump/tcpdump/tcpdump.c b/usr.sbin/tcpdump/tcpdump/tcpdump.c new file mode 100644 index 000000000000..9a0ccc4bbd63 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/tcpdump.c @@ -0,0 +1,347 @@ +/* + * Copyright (c) 1987-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#ifndef lint +char copyright[] = + "@(#) Copyright (c) 1987-1990 The Regents of the University of California.\nAll rights reserved.\n"; +static char rcsid[] = + "@(#)$Header: tcpdump.c,v 1.68 92/06/02 17:57:41 mccanne Exp $ (LBL)"; +#endif + +/* + * tcpdump - monitor tcp/ip traffic on an ethernet. + * + * First written in 1987 by Van Jacobson, Lawrence Berkeley Laboratory. + * Mercilessly hacked and occasionally improved since then via the + * combined efforts of Van, Steve McCanne and Craig Leres of LBL. + */ + +#include <stdio.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/timeb.h> +#include <netinet/in.h> + +#include <net/bpf.h> + +#include "interface.h" +#include "savefile.h" +#include "addrtoname.h" + +int fflag; /* don't translate "foreign" IP address */ +int nflag; /* leave addresses as numbers */ +int Nflag; /* remove domains from printed host names */ +int pflag; /* don't go promiscuous */ +int qflag; /* quick (shorter) output */ +int tflag = 1; /* print packet arrival time */ +int eflag; /* print ethernet header */ +int vflag; /* verbose */ +int xflag; /* print packet in hex */ +int Oflag = 1; /* run filter code optimizer */ +int Sflag; /* print raw TCP sequence numbers */ + +int dflag; /* print filter code */ + +char *program_name; + +long thiszone; /* gmt to local correction */ + +static void cleanup(); + +/* Length of saved portion of packet. */ +int snaplen = DEFAULT_SNAPLEN; + +static int if_fd = -1; + +struct printer { + void (*f)(); + int type; +}; + +static struct printer printers[] = { + { ether_if_print, DLT_EN10MB }, + { sl_if_print, DLT_SLIP }, + { ppp_if_print, DLT_PPP }, + { fddi_if_print, DLT_FDDI }, + { null_if_print, DLT_NULL }, + { 0, 0 }, +}; + +void +(*lookup_printer(type))() + int type; +{ + struct printer *p; + + for (p = printers; p->f; ++p) + if (type == p->type) + return p->f; + + error("unknown data link type 0x%x", type); + /* NOTREACHED */ +} + +void +main(argc, argv) + int argc; + char **argv; +{ + struct bpf_program *parse(); + void bpf_dump(); + + int cnt = -1, i; + struct timeb zt; + struct bpf_program *fcode; + int op; + void (*printit)(); + char *infile = 0; + char *cmdbuf; + int linktype; + int err; + u_long localnet; + u_long netmask; + + char *RFileName = 0; /* -r argument */ + char *WFileName = 0; /* -w argument */ + + char *device = 0; + + int precision = clock_sigfigs(); + + extern char *optarg; + extern int optind, opterr; + + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "c:defF:i:lnNOpqr:s:Stvw:xY")) != EOF) + switch (op) { + case 'c': + cnt = atoi(optarg); + break; + + case 'd': + ++dflag; + break; + + case 'e': + ++eflag; + break; + + case 'f': + ++fflag; + break; + + case 'F': + infile = optarg; + break; + + case 'i': + device = optarg; + break; + + case 'l': + setlinebuf(stdout); + break; + + case 'n': + ++nflag; + break; + + case 'N': + ++Nflag; + break; + + case 'O': + Oflag = 0; + break; + + case 'p': + ++pflag; + break; + + case 'q': + ++qflag; + break; + + case 'r': + RFileName = optarg; + break; + + case 's': + snaplen = atoi(optarg); + break; + + case 'S': + ++Sflag; + break; + + case 't': + --tflag; + break; + + case 'v': + ++vflag; + break; + + case 'w': + WFileName = optarg; + break; +#ifdef YYDEBUG + case 'Y': + { + extern int yydebug; + yydebug = 1; + } + break; +#endif + case 'x': + ++xflag; + break; + + default: + usage(); + /* NOTREACHED */ + } + + if (tflag > 0) { + struct timeval now; + struct timezone tz; + + if (gettimeofday(&now, &tz) < 0) { + perror("tcpdump: gettimeofday"); + exit(1); + } + thiszone = tz.tz_minuteswest * -60; + if (localtime((time_t *)&now.tv_sec)->tm_isdst) + thiszone += 3600; + } + + if (RFileName) { + /* + * We don't need network access, so set it back to the user id. + * Also, this prevents the user from reading anyone's + * trace file. + */ + setuid(getuid()); + + err = sf_read_init(RFileName, &linktype, &thiszone, &snaplen, + &precision); + if (err) + sf_err(err); + localnet = 0; + netmask = 0; + if (fflag != 0) + error("-f and -r options are incompatible"); + } else { + if (device == 0) { + device = lookup_device(); + if (device == 0) + error("can't find any interfaces"); + } + if_fd = initdevice(device, pflag, &linktype); + lookup_net(device, &localnet, &netmask); + /* + * Let user own process after socket has been opened. + */ + setuid(getuid()); + } + + if (infile) + cmdbuf = read_infile(infile); + else + cmdbuf = copy_argv(&argv[optind]); + + fcode = parse(cmdbuf, Oflag, linktype, netmask); + if (dflag) { + bpf_dump(fcode, dflag); + exit(0); + } + init_addrtoname(fflag, localnet, netmask); + + (void)signal(SIGTERM, cleanup); + (void)signal(SIGINT, cleanup); + (void)signal(SIGHUP, cleanup); + + printit = lookup_printer(linktype); + + if (WFileName) { + sf_write_init(WFileName, linktype, thiszone, snaplen, + precision); + printit = sf_write; + } + if (RFileName) { + err = sf_read(fcode, cnt, snaplen, printit); + if (err) + sf_err(err); + } else { + fprintf(stderr, "%s: listening on %s\n", program_name, device); + fflush(stderr); + readloop(cnt, if_fd, fcode, printit); + } + exit(0); +} + +/* make a clean exit on interrupts */ +static void +cleanup() +{ + if (if_fd >= 0) { + putc('\n', stderr); + wrapup(if_fd); + } + exit(0); +} + +void +default_print(sp, length) + register u_short *sp; + register int length; +{ + register u_int i; + register int nshorts; + + nshorts = (unsigned) length / sizeof(u_short); + i = 0; + while (--nshorts >= 0) { + if ((i++ % 8) == 0) + (void)printf("\n\t\t\t"); + (void)printf(" %04x", ntohs(*sp++)); + } + if (length & 1) { + if ((i % 8) == 0) + (void)printf("\n\t\t\t"); + (void)printf(" %02x", *(u_char *)sp); + } +} + +void +usage() +{ + extern char version[]; + + (void)fprintf(stderr, "Version %s\n", version); + (void)fprintf(stderr, +"Usage: tcpdump [-deflnOpqtvx] [-c count] [-i interface]\n"); + (void)fprintf(stderr, +"\t\t[-r filename] [-w filename] [expr]\n"); + exit(-1); +} diff --git a/usr.sbin/tcpdump/tcpdump/tcpgram.y b/usr.sbin/tcpdump/tcpdump/tcpgram.y new file mode 100644 index 000000000000..da235d0b1068 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/tcpgram.y @@ -0,0 +1,232 @@ +%{ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Grammar for tcpdump. + */ +#ifndef lint +static char rcsid[] = + "@(#) $Header: tcpgram.y,v 1.29 92/03/17 13:45:08 mccanne Exp $ (LBL)"; +#endif + +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include "interface.h" + +#include <sys/time.h> +#include <net/bpf.h> + +#include "gencode.h" + +#define QSET(q, p, d, a) (q).proto = (p),\ + (q).dir = (d),\ + (q).addr = (a) + +int n_errors = 0; + +static struct qual qerr = { Q_UNDEF, Q_UNDEF, Q_UNDEF, Q_UNDEF }; + +static void +yyerror() +{ + ++n_errors; +} + +%} + +%union { + int i; + u_long h; + u_char *e; + char *s; + struct stmt *stmt; + struct arth *a; + struct { + struct qual q; + struct block *b; + } blk; + struct block *rblk; +} + +%type <blk> expr id nid pid term rterm qid +%type <blk> head +%type <i> pqual dqual aqual ndaqual +%type <a> arth narth +%type <i> byteop pname pnum relop irelop +%type <blk> and or paren not null prog +%type <rblk> other + +%token DST SRC HOST GATEWAY +%token NET PORT LESS GREATER PROTO BYTE +%token ARP RARP IP TCP UDP ICMP +%token TK_BROADCAST TK_MULTICAST +%token NUM +%token LINK +%token GEQ LEQ NEQ +%token ID EID HID +%token LSH RSH +%token LEN + +%type <s> ID +%type <e> EID +%type <h> HID +%type <i> NUM + +%left OR AND +%nonassoc '!' +%left '|' +%left '&' +%left LSH RSH +%left '+' '-' +%left '*' '/' +%nonassoc UMINUS +%% +prog: null expr +{ + finish_parse($2.b); +} + | null + ; +null: /* null */ { $$.q = qerr; } + ; +expr: term + | expr and term { gen_and($1.b, $3.b); $$ = $3; } + | expr and id { gen_and($1.b, $3.b); $$ = $3; } + | expr or term { gen_or($1.b, $3.b); $$ = $3; } + | expr or id { gen_or($1.b, $3.b); $$ = $3; } + ; +and: AND { $$ = $<blk>0; } + ; +or: OR { $$ = $<blk>0; } + ; +id: nid + | pnum { $$.b = gen_ncode((u_long)$1, + $$.q = $<blk>0.q); } + | paren pid ')' { $$ = $2; } + ; +nid: ID { $$.b = gen_scode($1, $$.q = $<blk>0.q); } + | HID { $$.b = gen_ncode($1, $$.q = $<blk>0.q); } + | EID { $$.b = gen_ecode($1, $$.q = $<blk>0.q); } + | not id { gen_not($2.b); $$ = $2; } + ; +not: '!' { $$ = $<blk>0; } + ; +paren: '(' { $$ = $<blk>0; } + ; +pid: nid + | qid and id { gen_and($1.b, $3.b); $$ = $3; } + | qid or id { gen_or($1.b, $3.b); $$ = $3; } + ; +qid: pnum { $$.b = gen_ncode((u_long)$1, + $$.q = $<blk>0.q); } + | pid + ; +term: rterm + | not term { gen_not($2.b); $$ = $2; } + ; +head: pqual dqual aqual { QSET($$.q, $1, $2, $3); } + | pqual dqual { QSET($$.q, $1, $2, Q_DEFAULT); } + | pqual aqual { QSET($$.q, $1, Q_DEFAULT, $2); } + | pqual PROTO { QSET($$.q, $1, Q_DEFAULT, Q_PROTO); } + | pqual ndaqual { QSET($$.q, $1, Q_DEFAULT, $2); } + ; +rterm: head id { $$ = $2; } + | paren expr ')' { $$.b = $2.b; $$.q = $1.q; } + | pname { $$.b = gen_proto_abbrev($1); $$.q = qerr; } + | arth relop arth { $$.b = gen_relation($2, $1, $3, 0); + $$.q = qerr; } + | arth irelop arth { $$.b = gen_relation($2, $1, $3, 1); + $$.q = qerr; } + | other { $$.b = $1; $$.q = qerr; } + ; +/* protocol level qualifiers */ +pqual: pname + | { $$ = Q_DEFAULT; } + ; +/* 'direction' qualifiers */ +dqual: SRC { $$ = Q_SRC; } + | DST { $$ = Q_DST; } + | SRC OR DST { $$ = Q_OR; } + | DST OR SRC { $$ = Q_OR; } + | SRC AND DST { $$ = Q_AND; } + | DST AND SRC { $$ = Q_AND; } + ; +/* address type qualifiers */ +aqual: HOST { $$ = Q_HOST; } + | NET { $$ = Q_NET; } + | PORT { $$ = Q_PORT; } + ; +/* non-directional address type qualifiers */ +ndaqual: GATEWAY { $$ = Q_GATEWAY; } + ; +pname: LINK { $$ = Q_LINK; } + | IP { $$ = Q_IP; } + | ARP { $$ = Q_ARP; } + | RARP { $$ = Q_RARP; } + | TCP { $$ = Q_TCP; } + | UDP { $$ = Q_UDP; } + | ICMP { $$ = Q_ICMP; } + ; +other: pqual TK_BROADCAST { $$ = gen_broadcast($1); } + | pqual TK_MULTICAST { $$ = gen_multicast($1); } + | LESS NUM { $$ = gen_less($2); } + | GREATER NUM { $$ = gen_greater($2); } + | BYTE NUM byteop NUM { $$ = gen_byteop($3, $2, $4); } + ; +relop: '>' { $$ = BPF_JGT; } + | GEQ { $$ = BPF_JGE; } + | '=' { $$ = BPF_JEQ; } + ; +irelop: LEQ { $$ = BPF_JGT; } + | '<' { $$ = BPF_JGE; } + | NEQ { $$ = BPF_JEQ; } + ; +arth: pnum { $$ = gen_loadi($1); } + | narth + ; +narth: pname '[' arth ']' { $$ = gen_load($1, $3, 1); } + | pname '[' arth ':' NUM ']' { $$ = gen_load($1, $3, $5); } + | arth '+' arth { $$ = gen_arth(BPF_ADD, $1, $3); } + | arth '-' arth { $$ = gen_arth(BPF_SUB, $1, $3); } + | arth '*' arth { $$ = gen_arth(BPF_MUL, $1, $3); } + | arth '/' arth { $$ = gen_arth(BPF_DIV, $1, $3); } + | arth '&' arth { $$ = gen_arth(BPF_AND, $1, $3); } + | arth '|' arth { $$ = gen_arth(BPF_OR, $1, $3); } + | arth LSH arth { $$ = gen_arth(BPF_LSH, $1, $3); } + | arth RSH arth { $$ = gen_arth(BPF_RSH, $1, $3); } + | '-' arth %prec UMINUS { $$ = gen_neg($2); } + | paren narth ')' { $$ = $2; } + | LEN { $$ = gen_loadlen(); } + ; +byteop: '&' { $$ = '&'; } + | '|' { $$ = '|'; } + | '<' { $$ = '<'; } + | '>' { $$ = '>'; } + | '=' { $$ = '='; } + ; +pnum: NUM + | paren pnum ')' { $$ = $2; } + ; +%% diff --git a/usr.sbin/tcpdump/tcpdump/tcplex.l b/usr.sbin/tcpdump/tcpdump/tcplex.l new file mode 100644 index 000000000000..840590addcd3 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/tcplex.l @@ -0,0 +1,146 @@ +%{ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#) $Header: tcplex.l,v 1.26 92/02/14 15:16:35 mccanne Exp $ (LBL)"; +#endif + +/* + * Compiling with gcc under SunOS will cause problems unless we have this + * cruft here. The flex skeleton includes stddef.h which defines these types + * (under gcc). They will conflict with Sun's definitions in sys/types.h. + */ +#define size_t xxxsize_t +#define ptrdiff_t xxxptrdiff_t +#define wchar_t xxxwchar_t +#include <sys/types.h> +#undef size_t +#undef ptrdiff_t +#undef wchar_t + +#include "nametoaddr.h" + +/* + * We need bpf since enum bpf_code is in YYSTYPE. + */ +#include <sys/time.h> +#include <net/bpf.h> + +#include "gencode.h" +#include "y.tab.h" /* "tokdefs.h" */ + +#ifdef FLEX_SCANNER +#undef YY_INPUT +#define YY_INPUT(buf, result, max)\ + {\ + char *src = in_buffer;\ + int i;\ +\ + if (*src == 0)\ + result = YY_NULL;\ + else {\ + for (i = 0; *src && i < max; ++i)\ + buf[i] = *src++;\ + in_buffer += i;\ + result = i;\ + }\ + } +#else +#undef getc +#define getc(fp) (*in_buffer == 0 ? EOF : *in_buffer++) +#endif + +extern YYSTYPE yylval; +static char *in_buffer; + +%} + +N ([0-9]+|(0X|0x)[0-9A-Fa-f]+) +B ([0-9A-Fa-f][0-9A-Fa-f]?) + +%a 3000 + +%% +dst return DST; +src return SRC; + +link|ether|ppp|slip return LINK; +arp return ARP; +rarp return RARP; +ip return IP; +tcp return TCP; +udp return UDP; +icmp return ICMP; + +host return HOST; +net return NET; +port return PORT; +proto return PROTO; + +gateway return GATEWAY; + +less return LESS; +greater return GREATER; +byte return BYTE; +broadcast return TK_BROADCAST; +multicast return TK_MULTICAST; + +and return AND; +or return OR; +not return '!'; + +len return LEN; + +[ \n\t] ; +[+\-*/:\[\]!<>()&|=] return yytext[0]; +">=" return GEQ; +"<=" return LEQ; +"!=" return NEQ; +"==" return '='; +"<<" return LSH; +">>" return RSH; +{N} { yylval.i = stoi(yytext); return NUM; } +({N}\.{N})|({N}\.{N}\.{N})|({N}\.{N}\.{N}\.{N}) { + yylval.h = atoin(yytext); return HID; +} +{B}:{B}:{B}:{B}:{B}:{B} { yylval.e = ETHER_aton(yytext); return EID; } +{B}:+({B}:+)+ { error("bogus ethernet address %s", yytext); } +[A-Za-z][-_.A-Za-z0-9]* { yylval.s = yytext; return ID; } +"\\"[^ !()\n\t]+ { yylval.s = yytext + 1; return ID; } +[^ \[\]\t\n\-_.A-Za-z0-9!<>()&|=]+ { error("illegal token: %s\n", yytext); } +. { error("illegal char '%c'", *yytext); } +%% +void +lex_init(buf) + char *buf; +{ + in_buffer = buf; +} +#ifndef FLEX_SCANNER +int +yywrap() +/* so we don't need -ll */ +{ + return 1; +} +#endif diff --git a/usr.sbin/tcpdump/tcpdump/util.c b/usr.sbin/tcpdump/tcpdump/util.c new file mode 100644 index 000000000000..ec58c3f56cb1 --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/util.c @@ -0,0 +1,278 @@ +/* + * Copyright (c) 1988-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char rcsid[] = + "@(#) $Header: util.c,v 1.12 91/10/28 22:09:31 mccanne Exp $ (LBL)"; +#endif + +#include <stdio.h> +#ifdef __STDC__ +#include <stdlib.h> +#endif +#include <sys/types.h> +#include <sys/time.h> +#include <ctype.h> +#include <varargs.h> +#include <sys/file.h> +#include <sys/stat.h> + +#include "interface.h" + +/* Hex digit to integer. */ +static inline int +xdtoi(c) +{ + if (isdigit(c)) + return c - '0'; + else if (islower(c)) + return c - 'a' + 10; + else + return c - 'A' + 10; +} + +/* + * Convert string to integer. Just like atoi(), but checks for + * preceding 0x or 0 and uses hex or octal instead of decimal. + */ +int +stoi(s) + char *s; +{ + int base = 10; + int n = 0; + + if (*s == '0') { + if (s[1] == 'x' || s[1] == 'X') { + s += 2; + base = 16; + } + else { + base = 8; + s += 1; + } + } + while (*s) + n = n * base + xdtoi(*s++); + + return n; +} + +/* + * Print out a filename (or other ascii string). + * Return true if truncated. + */ +int +printfn(s, ep) + register u_char *s, *ep; +{ + register u_char c; + + putchar('"'); + while (c = *s++) { + if (s > ep) { + putchar('"'); + return(1); + } + if (!isascii(c)) { + c = toascii(c); + putchar('M'); + putchar('-'); + } + if (!isprint(c)) { + c ^= 0x40; /* DEL to ?, others to alpha */ + putchar('^'); + } + putchar(c); + } + putchar('"'); + return(0); +} + +/* + * Print the timestamp + */ +void +ts_print(tvp) + register struct timeval *tvp; +{ + register int i; + + if (tflag > 0) { + /* Default */ + i = (tvp->tv_sec + thiszone) % 86400; + (void)printf("%02d:%02d:%02d.%06d ", + i / 3600, (i % 3600) / 60, i % 60, tvp->tv_usec); + } else if (tflag < 0) { + /* Unix timeval style */ + (void)printf("%d.%06d ", tvp->tv_sec, tvp->tv_usec); + } +} + +#ifdef NOVFPRINTF +/* + * Stock 4.3 doesn't have vfprintf. + * This routine is due to Chris Torek. + */ +vfprintf(f, fmt, args) + FILE *f; + char *fmt; + va_list args; +{ + int ret; + + if ((f->_flag & _IOWRT) == 0) { + if (f->_flag & _IORW) + f->_flag |= _IOWRT; + else + return EOF; + } + ret = _doprnt(fmt, args, f); + return ferror(f) ? EOF : ret; +} +#endif + +static char * +stripdir(s) + register char *s; +{ + register char *cp; + char *rindex(); + + cp = rindex(s, '/'); + return (cp != 0) ? cp + 1 : s; +} + +/* VARARGS */ +void +error(va_alist) + va_dcl +{ + register char *cp; + va_list ap; + + (void)fprintf(stderr, "%s: ", stripdir(program_name)); + + va_start(ap); + cp = va_arg(ap, char *); + (void)vfprintf(stderr, cp, ap); + va_end(ap); + if (*cp) { + cp += strlen(cp); + if (cp[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +void +warning(va_alist) + va_dcl +{ + register char *cp; + va_list ap; + + (void)fprintf(stderr, "%s: warning: ", stripdir(program_name)); + + va_start(ap); + cp = va_arg(ap, char *); + (void)vfprintf(stderr, cp, ap); + va_end(ap); + if (*cp) { + cp += strlen(cp); + if (cp[-1] != '\n') + (void)fputc('\n', stderr); + } +} + + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +char * +copy_argv(argv) + register char **argv; +{ + register char **p; + register int len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = malloc(len); + + p = argv; + dst = buf; + while (src = *p++) { + while (*dst++ = *src++) + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} + +char * +read_infile(fname) + char *fname; +{ + struct stat buf; + int fd; + char *p; + + fd = open(fname, O_RDONLY); + if (fd < 0) + error("can't open '%s'", fname); + + if (fstat(fd, &buf) < 0) + error("can't state '%s'", fname); + + p = malloc((unsigned)buf.st_size); + if (read(fd, p, (int)buf.st_size) != buf.st_size) + error("problem reading '%s'", fname); + + return p; +} + +/* + * Left justify 'addr' and return its resulting network mask. + */ +u_long +net_mask(addr) + u_long *addr; +{ + register u_long m = 0xffffffff; + + if (*addr) + while ((*addr & 0xff000000) == 0) + *addr <<= 8, m <<= 8; + + return m; +} diff --git a/usr.sbin/tcpdump/tcpslice/Makefile b/usr.sbin/tcpdump/tcpslice/Makefile new file mode 100644 index 000000000000..d1cd63b19ff4 --- /dev/null +++ b/usr.sbin/tcpdump/tcpslice/Makefile @@ -0,0 +1,18 @@ +# @(#)Makefile 0.1 (RWGrimes) 3/24/93 + +PROG= tcpslice +CFLAGS+=-DCSLIP -I. -I$(.CURDIR)/../tcpdump +MAN1= tcpslice.0 +SRCS= version.c tcpslice.c gwtm2secs.c search.c \ + savefile.c bpf_filter.c md.c util.c +.PATH: ${.CURDIR}/../tcpdump /sys/net +CLEANFILES+= version.c version.h + +version.c version.h: $(.CURDIR)/../tcpdump/VERSION + rm -f version.c ; \ + sed 's/.*/char version[] = "&";/' $(.CURDIR)/../tcpdump/VERSION > version.c + set `sed 's/\([0-9]*\)\.\([0-9]*\).*/\1 \2/' $(.CURDIR)/../tcpdump/VERSION` ; \ + { echo '#define VERSION_MAJOR' $$1 ; \ + echo '#define VERSION_MINOR' $$2 ; } > version.h + +.include <bsd.prog.mk> diff --git a/usr.sbin/tcpdump/tcpslice/gwtm2secs.c b/usr.sbin/tcpdump/tcpslice/gwtm2secs.c new file mode 100644 index 000000000000..aeb377fd932d --- /dev/null +++ b/usr.sbin/tcpdump/tcpslice/gwtm2secs.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#ifndef lint +static char rcsid[] = + "@(#)$Header: gwtm2secs.c,v 1.1 92/06/02 11:35:19 mccanne Exp $ (LBL)"; +#endif + +/* + * gwtm2secs.c - convert "tm" structs for Greenwich time to Unix timestamp + */ + +#include <stdio.h> +#include <sys/types.h> +#include <time.h> + +static int days_in_month[] = + /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +#define IS_LEAP_YEAR(year) \ + (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) + +time_t gwtm2secs( tm ) +struct tm *tm; + { + int i, days, year; + + year = tm->tm_year; + + /* Allow for year being specified with either 2 digits or 4 digits. + * 2-digit years are either 19xx or 20xx - a simple heuristic + * distinguishes them, since we can't represent any time < 1970. + */ + if ( year < 100 ) + if ( year >= 70 ) + year += 1900; + else + year += 2000; + + days = 0; + for ( i = 1970; i < year; ++i ) + { + days += 365; + if ( IS_LEAP_YEAR(i) ) + ++days; + } + + for ( i = 0; i < tm->tm_mon; ++i ) + days += days_in_month[i]; + + if ( IS_LEAP_YEAR(year) && tm->tm_mon > 1 ) /* 1 is February */ + ++days; + + days += tm->tm_mday - 1; /* -1 since days are numbered starting at 1 */ + + return days * 86400 + tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec; + } diff --git a/usr.sbin/tcpdump/tcpslice/search.c b/usr.sbin/tcpdump/tcpslice/search.c new file mode 100644 index 000000000000..8bea0d2fabf1 --- /dev/null +++ b/usr.sbin/tcpdump/tcpslice/search.c @@ -0,0 +1,563 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#ifndef lint +static char rcsid[] = + "@(#)$Header: search.c,v 1.3 92/05/01 15:14:45 vern Exp $ (LBL)"; +#endif + +/* + * search.c - supports fast searching through tcpdump files for timestamps + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/time.h> + +#include "interface.h" +#include "savefile.h" + + +/* Maximum number of seconds that we can conceive of a dump file spanning. */ +#define MAX_REASONABLE_FILE_SPAN (3600*24*366) /* one year */ + +/* Maximum packet length we ever expect to see. */ +#define MAX_REASONABLE_PACKET_LENGTH 65535 + +/* Size of a packet header in bytes; easier than typing the sizeof() all + * the time ... + */ +#define PACKET_HDR_LEN (sizeof( struct packet_header )) + +/* The maximum size of a packet, including its header. */ +#define MAX_PACKET_SIZE (PACKET_HDR_LEN + snaplen) + +/* Number of contiguous bytes from a dumpfile in which there's guaranteed + * to be enough information to find a "definite" header if one exists + * therein. This takes 3 full packets - the first to be just misaligned + * (one byte short of a full packet), missing its timestamp; the second + * to have the legitimate timestamp; and the third to provide confirmation + * that the second is legit, making it a "definite" header. We could + * scrimp a bit here since not the entire third packet is required, but + * it doesn't seem worth it + */ +#define MAX_BYTES_FOR_DEFINITE_HEADER (3 * MAX_PACKET_SIZE) + +/* Maximum number of seconds that might reasonably separate two headers. */ +#define MAX_REASONABLE_HDR_SEPARATION (3600 * 24 * 7) /* one week */ + +/* When searching a file for a packet, if we think we're within this many + * bytes of the packet we just search linearly. Since linear searches are + * probably much faster than random ones (random ones require searching for + * the beginning of the packet, which may be unaligned in memory), we make + * this value pretty hefty. + */ +#define STRAIGHT_SCAN_THRESHOLD (100 * MAX_PACKET_SIZE) + +/* Extracts a long integer from a possibly unaligned buffer containing + * unsigned characters. + */ +#define EXTRACT_LONG(buf) (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]) + + +/* Given a header and an acceptable first and last time stamp, returns non-zero + * if the header looks reasonable and zero otherwise. + */ +static int reasonable_header( hdr, first_time, last_time ) +struct packet_header *hdr; +long first_time, last_time; + { + if ( last_time == 0 ) + last_time = first_time + MAX_REASONABLE_FILE_SPAN; + + return hdr->ts.tv_sec >= first_time && + hdr->ts.tv_sec <= last_time && + hdr->len > 0 && + hdr->len <= MAX_REASONABLE_PACKET_LENGTH && + hdr->caplen > 0 && + hdr->caplen <= MAX_REASONABLE_PACKET_LENGTH; + } + + +/* Given a buffer, extracts a (properly aligned) packet header from it. */ + +static void extract_header( buf, hdr ) +u_char *buf; +struct packet_header *hdr; + { + hdr->ts.tv_sec = EXTRACT_LONG(buf); + buf += sizeof( long ); + hdr->ts.tv_usec = EXTRACT_LONG(buf); + buf += sizeof( long ); + hdr->len = EXTRACT_LONG(buf); + buf += sizeof( long ); + hdr->caplen = EXTRACT_LONG(buf); + + if ( sf_swapped ) + { + hdr->ts.tv_sec = SWAPLONG(hdr->ts.tv_sec); + hdr->ts.tv_usec = SWAPLONG(hdr->ts.tv_usec); + hdr->len = SWAPLONG(hdr->len); + hdr->caplen = SWAPLONG(hdr->caplen); + } + } + + +/* Search a buffer to locate the first header within it. Return values + * are HEADER_NONE, HEADER_CLASH, HEADER_PERHAPS, and HEADER_DEFINITELY. + * The first indicates that no evidence of a header was found; the second + * that two or more possible headers were found, neither more convincing + * than the other(s); the third that exactly one "possible" header was + * found; and the fourth that exactly one "definite" header was found. + * + * Headers are detected by looking for positions in the buffer which have + * reasonable timestamps and lengths. If there is enough room in the buffer + * for another header to follow a candidate header, a check is made for + * that following header. If it is present then the header is *definite* + * (unless another "perhaps" or "definite" header is found); if not, then + * the header is discarded. If there is not enough room in the buffer for + * another header then the candidate is *perhaps* (unless another header + * is subsequently found). A "tie" between a "definite" header and a + * "perhaps" header is resolved in favor of the definite header. Any + * other tie leads to HEADER_CLASH. + * + * The buffer position of the header is returned in hdrpos_addr and + * for convenience the corresponding header in return_hdr. + * + * first_time is the earliest possible acceptable timestamp in the + * header. last_time, if non-zero, is the last such timestamp. If + * zero, then up to MAX_REASONABLE_FILE_SPAN seconds after first_time + * is acceptable. + */ + +#define HEADER_NONE 0 +#define HEADER_CLASH 1 +#define HEADER_PERHAPS 2 +#define HEADER_DEFINITELY 3 + +static int find_header( buf, buf_len, first_time, last_time, + hdrpos_addr, return_hdr ) +u_char *buf; +unsigned buf_len; +long first_time, last_time; +u_char **hdrpos_addr; +struct packet_header *return_hdr; + { + u_char *bufptr, *bufend, *last_pos_to_try; + struct packet_header hdr, hdr2; + int status = HEADER_NONE; + int saw_PERHAPS_clash = 0; + + /* Initially, try each buffer position to see whether it looks like + * a valid packet header. We may later restrict the positions we look + * at to avoid seeing a sequence of legitimate headers as conflicting + * with one another. + */ + bufend = buf + buf_len; + last_pos_to_try = bufend - PACKET_HDR_LEN; + + for ( bufptr = buf; bufptr < last_pos_to_try; ++bufptr ) + { + extract_header( bufptr, &hdr ); + + if ( reasonable_header( &hdr, first_time, last_time ) ) + { + u_char *next_header = bufptr + PACKET_HDR_LEN + hdr.caplen; + + if ( next_header + PACKET_HDR_LEN < bufend ) + { /* check for another good header */ + extract_header( next_header, &hdr2 ); + + if ( reasonable_header( &hdr2, hdr.ts.tv_sec, + hdr.ts.tv_sec + MAX_REASONABLE_HDR_SEPARATION ) ) + { /* a confirmed header */ + switch ( status ) + { + case HEADER_NONE: + case HEADER_PERHAPS: + status = HEADER_DEFINITELY; + *hdrpos_addr = bufptr; + *return_hdr = hdr; + + /* Make sure we don't demote this "definite" + * to a "clash" if we stumble across its + * successor. + */ + last_pos_to_try = next_header - PACKET_HDR_LEN; + break; + + case HEADER_DEFINITELY: + return HEADER_CLASH; + + default: + error( "bad status in find_header()" ); + } + } + + /* ... else the header is bogus - we've verified that it's + * not followed by a reasonable header. + */ + } + + else + { /* can't check for another good header */ + switch ( status ) + { + case HEADER_NONE: + status = HEADER_PERHAPS; + *hdrpos_addr = bufptr; + *return_hdr = hdr; + break; + + case HEADER_PERHAPS: + /* We don't immediately turn this into a + * clash because perhaps we'll later see a + * "definite" which will save us ... + */ + saw_PERHAPS_clash = 1; + break; + + case HEADER_DEFINITELY: + /* Keep the definite in preference to this one. */ + break; + + default: + error( "bad status in find_header()" ); + } + } + } + } + + if ( status == HEADER_PERHAPS && saw_PERHAPS_clash ) + status = HEADER_CLASH; + + return status; + } + + +/* Positions the sf_readfile stream such that the next sf_read() will + * read the final full packet in the file. Returns non-zero if + * successful, zero if unsuccessful. If successful, returns the + * timestamp of the last packet in last_timestamp. + * + * Note that this routine is a special case of sf_find_packet(). In + * order to use sf_find_packet(), one first must use this routine in + * order to give sf_find_packet() an upper bound on the timestamps + * present in the dump file. + */ +int sf_find_end( first_timestamp, last_timestamp ) +struct timeval *first_timestamp; +struct timeval *last_timestamp; + { + long first_time = first_timestamp->tv_sec; + unsigned num_bytes; + u_char *buf, *bufpos, *bufend; + u_char *hdrpos; + struct packet_header hdr, successor_hdr; + int status; + + /* Allow enough room for at least two full (untruncated) packets, + * perhaps followed by a truncated packet, so we have a shot at + * finding a "definite" header and following its chain to the + * end of the file. + */ + num_bytes = MAX_BYTES_FOR_DEFINITE_HEADER; + if ( fseek( sf_readfile, (long) -num_bytes, 2 ) < 0 ) + return 0; + + buf = (u_char *)malloc((unsigned) num_bytes); + if ( ! buf ) + return 0; + + status = 0; + bufpos = buf; + bufend = buf + num_bytes; + + if ( fread( (char *) bufpos, num_bytes, 1, sf_readfile ) != 1 ) + goto done; + + if ( find_header( bufpos, num_bytes, first_time, 0L, &hdrpos, &hdr ) != + HEADER_DEFINITELY ) + goto done; + + /* Okay, we have a definite header in our hands. Follow its + * chain till we find the last valid packet in the file ... + */ + for ( ; ; ) + { + /* move to the next header position */ + bufpos = hdrpos + PACKET_HDR_LEN + hdr.caplen; + + /* bufpos now points to a candidate packet, which if valid + * should replace the current packet pointed to by hdrpos as + * the last valid packet ... + */ + if ( bufpos >= bufend - PACKET_HDR_LEN ) + /* not enough room for another header */ + break; + + extract_header( bufpos, &successor_hdr ); + + first_time = hdr.ts.tv_sec; + if ( ! reasonable_header( &successor_hdr, first_time, 0L ) ) + /* this bodes ill - it means bufpos is perhaps a + * bogus packet header after all ... + */ + break; + + /* Note that the following test is for whether the next + * packet starts at a position > bufend, *not* for a + * position >= bufend. If this is the last packet in the + * file and there isn't a subsequent partial packet, then + * we expect the first buffer position beyond this packet + * to be just beyond the end of the buffer, i.e., at bufend + * itself. + */ + if ( bufpos + PACKET_HDR_LEN + successor_hdr.caplen > bufend ) + /* the packet is truncated */ + break; + + /* Accept this packet as fully legit. */ + hdrpos = bufpos; + hdr = successor_hdr; + } + + /* Success! Last valid packet is at hdrpos. */ + *last_timestamp = hdr.ts; + status = 1; + + /* Seek so that the next read will start at last valid packet. */ + if ( fseek( sf_readfile, (long) -(bufend - hdrpos), 2 ) < 0 ) + error( "final fseek() failed in sf_find_end()" ); + + done: + free( (char *) buf ); + + return status; + } + + +/* Takes two timeval's and returns the difference, tv2 - tv1, as a double. */ + +static double timeval_diff( tv1, tv2 ) +struct timeval *tv1, *tv2; + { + double result = (tv2->tv_sec - tv1->tv_sec); + result += (tv2->tv_usec - tv1->tv_usec) / 1000000.0; + + return result; + } + + +/* Returns true if timestamp t1 is chronologically less than timestamp t2. */ + +int sf_timestamp_less_than( t1, t2 ) +struct timeval *t1, *t2; + { + return t1->tv_sec < t2->tv_sec || + (t1->tv_sec == t2->tv_sec && + t1->tv_usec < t2->tv_usec); + } + + +/* Given two timestamps on either side of desired_time and their positions, + * returns the interpolated position of the desired_time packet. Returns a + * negative value if the desired_time is outside the given range. + */ + +static +long interpolated_position( min_time, min_pos, max_time, max_pos, desired_time ) +struct timeval *min_time, *max_time, *desired_time; +long min_pos, max_pos; + { + double full_span = timeval_diff( max_time, min_time ); + double desired_span = timeval_diff( desired_time, min_time ); + long full_span_pos = max_pos - min_pos; + double fractional_offset = desired_span / full_span; + + if ( fractional_offset < 0.0 || fractional_offset > 1.0 ) + return -1; + + return min_pos + (long) (fractional_offset * (double) full_span_pos); + } + + +/* Reads packets linearly until one with a time >= the given desired time + * is found; positions the dump file so that the next read will start + * at the given packet. Returns non-zero on success, 0 if an EOF was + * first encountered. + */ + +static int read_up_to( desired_time ) +struct timeval *desired_time; + { + int status = 1; + struct packet_header hdr; + u_char *buf; + long pos; + + buf = (u_char *) malloc( (unsigned) snaplen ); + + for ( ; ; ) + { + struct timeval *timestamp; + + pos = ftell( sf_readfile ); + status = sf_next_packet( &hdr, buf, snaplen ); + + if ( status ) + { + if ( status == SFERR_EOF ) + { + status = 0; + break; + } + + error( "bad status %d in read_up_to()", status ); + } + + timestamp = &hdr.ts; + + if ( ! sf_timestamp_less_than( timestamp, desired_time ) ) + break; + } + + if ( fseek( sf_readfile, pos, 0 ) < 0 ) + error( "fseek() failed in read_up_to()" ); + + free( (char *) buf ); + + return status; + } + + +/* Positions the sf_readfile stream so that the next sf_read() will + * return the first packet with a time greater than or equal to + * desired_time. desired_time must be greater than min_time and less + * than max_time, which should correspond to actual packets in the + * file. min_pos is the file position (byte offset) corresponding to + * the min_time packet and max_pos is the same for the max_time packet. + * + * Returns non-zero on success, 0 if the given position is beyond max_pos. + * + * NOTE: when calling this routine, the sf_readfile stream *must* be + * already aligned so that the next call to sf_next_packet() will yield + * a valid packet. + */ + +int sf_find_packet( min_time, min_pos, max_time, max_pos, desired_time ) +struct timeval *min_time, *max_time; +long min_pos, max_pos; +struct timeval *desired_time; + { + int status = 1; + struct timeval min_time_copy, max_time_copy; + unsigned num_bytes = MAX_BYTES_FOR_DEFINITE_HEADER; + int num_bytes_read; + long desired_pos, present_pos; + u_char *buf, *hdrpos; + struct packet_header hdr; + + buf = (u_char *) malloc( num_bytes ); + if ( ! buf ) + error( "malloc() failured in sf_find_packet()" ); + + min_time_copy = *min_time; + min_time = &min_time_copy; + + max_time_copy = *max_time; + max_time = &max_time_copy; + + for ( ; ; ) /* loop until positioned correctly */ + { + desired_pos = + interpolated_position( min_time, min_pos, + max_time, max_pos, + desired_time ); + + if ( desired_pos < 0 ) + { + status = 0; + break; + } + + present_pos = ftell( sf_readfile ); + + if ( present_pos <= desired_pos && + desired_pos - present_pos < STRAIGHT_SCAN_THRESHOLD ) + { /* we're close enough to just blindly read ahead */ + status = read_up_to( desired_time ); + break; + } + + /* Undershoot the target a little bit - it's much easier to + * then scan straight forward than to try to read backwards ... + */ + desired_pos -= STRAIGHT_SCAN_THRESHOLD / 2; + if ( desired_pos < min_pos ) + desired_pos = min_pos; + + if ( fseek( sf_readfile, desired_pos, 0 ) < 0 ) + error( "fseek() failed in sf_find_packet()" ); + + num_bytes_read = + fread( (char *) buf, 1, num_bytes, sf_readfile ); + + if ( num_bytes_read == 0 ) + /* This shouldn't ever happen because we try to + * undershoot, unless the dump file has only a + * couple packets in it ... + */ + error( "fread() failed in sf_find_packet()" ); + + if ( find_header( buf, num_bytes, min_time->tv_sec, + max_time->tv_sec, &hdrpos, &hdr ) != + HEADER_DEFINITELY ) + error( "can't find header at position %ld in dump file", + desired_pos ); + + /* Correct desired_pos to reflect beginning of packet. */ + desired_pos += (hdrpos - buf); + + /* Seek to the beginning of the header. */ + if ( fseek( sf_readfile, desired_pos, 0 ) < 0 ) + error( "fseek() failed in sf_find_packet()" ); + + if ( sf_timestamp_less_than( &hdr.ts, desired_time ) ) + { /* too early in the file */ + *min_time = hdr.ts; + min_pos = desired_pos; + } + + else if ( sf_timestamp_less_than( desired_time, &hdr.ts ) ) + { /* too late in the file */ + *max_time = hdr.ts; + max_pos = desired_pos; + } + + else + /* got it! */ + break; + } + + free( (char *) buf ); + + return status; + } diff --git a/usr.sbin/tcpdump/tcpslice/tcpslice.1 b/usr.sbin/tcpdump/tcpslice/tcpslice.1 new file mode 100644 index 000000000000..b130f2c22a7e --- /dev/null +++ b/usr.sbin/tcpdump/tcpslice/tcpslice.1 @@ -0,0 +1,260 @@ +.\" @(#) $Header: tcpslice.1,v 1.2 91/10/16 11:42:46 vern Exp $ (LBL) +.\" +.\" Copyright (c) 1988-1990 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH TCPSLICE 1 "14 Oct 1991" +.SH NAME +tcpslice \- extract pieces of and/or glue together tcpdump files +.SH SYNOPSIS +.na +.B tcpslice +[ +.B \-dRrt +] [ +.B \-w +.I file +] +.br +.ti +9 +[ +.I start-time +[ +.I end-time +] ] +.I file ... +.br +.ad +.SH DESCRIPTION +.LP +.I Tcpslice +is a program for extracting portions of packet-trace files generated using +\fItcpdump(l)\fP's +.B \-w +flag. +It can also be used to glue together several such files, as discussed +below. +.LP +The basic operation of +.I tcpslice +is to copy to +.I stdout +all packets from its input file(s) whose timestamps fall +within a given range. The starting and ending times of the range +may be specified on the command line. All ranges are inclusive. +The starting time defaults +to the time of the first packet in the first input file; we call +this the +.I first time. +The ending time defaults to ten years after the starting time. +Thus, the command +.I tcpslice trace-file +simply copies +.I trace-file +to \fIstdout\fP (assuming the file does not include more than +ten years' worth of data). +.LP +There are a number of ways to specify times. The first is using +Unix timestamps of the form +.I sssssssss.uuuuuu +(this is the format specified by \fItcpdump\fP's +.B \-tt +flag). +For example, +.B 654321098.7654 +specifies 38 seconds and 765,400 microseconds +after 8:51PM PDT, Sept. 25, 1990. +.LP +All examples in this manual are given +for PDT times, but when displaying times and interpreting times symbolically +as discussed below, +.I tcpslice +uses the local timezone, regardless of the timezone in which the \fItcpdump\fP +file was generated. The daylight-savings setting used is that which is +appropriate for the local timezone at the date in question. For example, +times associated with summer months will usually include daylight-savings +effects, and those with winter months will not. +.LP +Times may also be specified relative +to either the +.I first time +(when specifying a starting time) +or the starting time (when specifying an ending time) +by preceding a numeric value in seconds with a `+'. +For example, a starting time of +.B +200 +indicates 200 seconds after the +.I first time, +and the two arguments +.B +200 +300 +indicate from 200 seconds after the +.I first time +through 500 seconds after the +.I first time. +.LP +Times may also be specified in terms of years (y), months (m), days (d), +hours (h), minutes (m), seconds (s), and microseconds(u). For example, +the Unix timestamp 654321098.7654 discussed above could also be expressed +as +.B 90y9m25d20h51m38s765400u. +.LP +When specifying times using this style, fields that are omitted default +as follows. If the omitted field is a unit +.I greater +than that of the first specified field, then its value defaults to +the corresponding value taken from either +.I first time +(if the starting time is being specified) or the starting time +(if the ending time is being specified). +If the omitted field is a unit +.I less +than that of the first specified field, then it defaults to zero. +For example, suppose that the input file has a +.I first time +of the Unix timestamp mentioned above, i.e., 38 seconds and 765,400 microseconds +after 8:51PM PDT, Sept. 25, 1990. To specify 9:36PM PDT (exactly) on the +same date we could use +.B 21h36m. +To specify a range from 9:36PM PDT through 1:54AM PDT the next day we +could use +.B 21h36m 26d1h54m. +.LP +Relative times can also be specified when using the +.I ymdhmsu +format. Omitted fields then default to 0 if the unit of the field is +.I greater +than that of the first specified field, and to the corresponding value +taken from either the +.I first time +or the starting time if the omitted field's unit is +.I less +than that of the first specified field. Given a +.I first time +of the Unix timestamp mentioned above, +.B 22h +1h10m +specifies a range from 10:00PM PDT on that date through 11:10PM PDT, and +.B +1h +1h10m +specifies a range from 38.7654 seconds after 9:51PM PDT through 38.7654 +seconds after 11:01PM PDT. The first hour of the file could be extracted +using +.B +0 +1h. +.LP +Note that with the +.I ymdhmsu +format there is an ambiguity between using +.I m +for `month' or for `minute'. The ambiguity is resolved as follows: if an +.I m +field is followed by a +.I d +field then it is interpreted as specifying months; otherwise it +specifies minutes. +.LP +If more than one input file is specified then +.I tcpslice +first copies packets lying in the given range from the first file; it +then increases the starting time of the range to lie just beyond the +timestamp of the last packet in the first file, repeats the process +with the second file, and so on. Thus files with interleaved packets +are +.I not +merged. For a given file, only packets that are newer than any in the +preceding files will be considered. This mechanism avoids any possibility +of a packet occurring more than once in the output. +.SH OPTIONS +.LP +If any of +.B \-R, +.B \-r +or +.B \-t +are specified then +.I tcpslice +reports the timestamps of the first and last packets in each input file +and exits. Only one of these three options may be specified. +.TP +.B \-d +Dump the start and end times specified by the given range and +exit. This option is useful for checking that the given range actually +specifies the times you think it does. If one of +.B \-R, +.B \-r +or +.B \-t +has been specified then the times are dumped in the corresponding +format; otherwise, raw format (\fB \-R\fP) is used. +.TP +.B \-R +Dump the timestamps of the first and last packets in each input file +as raw timestamps (i.e., in the form \fI sssssssss.uuuuuu\fP). +.TP +.B \-r +Same as +.B \-R +except the timestamps are dumped in human-readable format, similar +to that used by \fI date(1)\fP. +.TP +.B \-t +Same as +.B \-R +except the timestamps are dumped in +.I tcpslice +format, i.e., in the +.I ymdhmsu +format discussed above. +.TP +.B \-w +Direct the output to \fIfile\fR rather than \fIstdout\fP. +.SH "SEE ALSO" +tcpdump(l) +.SH AUTHOR +Vern Paxson (vern@ee.lbl.gov), of +Lawrence Berkeley Laboratory, University of California, Berkeley, CA. +.SH BUGS +An input filename that beings with a digit or a `+' can be confused +with a start/end time. Such filenames can be specified with a +leading `./'; for example, specify the file `04Jul76.trace' as +`./04Jul76.trace'. +.LP +.I tcpslice +cannot read its input from \fIstdin\fP, since it uses random-access +to rummage through its input files. +.LP +.I tcpslice +refuses to write to its output if it is a terminal +(as indicated by \fIisatty(3)\fP). This is not a bug but a feature, +to prevent it from spraying binary data to the user's terminal. +Note that this means you must either redirect \fIstdout\fP or specify an +output file via \fB\-w\fP. +.LP +.I tcpslice +will not work properly on \fItcpdump\fP files spanning more than one year; +with files containing portions of packets whose original length was +more than 65,535 bytes; nor with files containing fewer than three packets. +Such files result in +the error message: `couldn't find final packet in file'. These problems +are due to the interpolation scheme used by +.I tcpslice +to greatly speed up its processing when dealing with large trace files. +Note that +.I tcpslice +can efficiently extract slices from the middle of trace files of any +size, and can also work with truncated trace files (i.e., the final packet +in the file is only partially present, typically due to \fItcpdump\fP +being ungracefully killed). diff --git a/usr.sbin/tcpdump/tcpslice/tcpslice.c b/usr.sbin/tcpdump/tcpslice/tcpslice.c new file mode 100644 index 000000000000..b5b6eeafb527 --- /dev/null +++ b/usr.sbin/tcpdump/tcpslice/tcpslice.c @@ -0,0 +1,645 @@ +/* + * Copyright (c) 1987-1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#ifndef lint +char copyright[] = + "@(#) Copyright (c) 1987-1990 The Regents of the University of California.\nAll rights reserved.\n"; +static char rcsid[] = + "@(#)$Header: tcpslice.c,v 1.10 92/06/02 17:57:44 mccanne Exp $ (LBL)"; +#endif + +/* + * tcpslice - extract pieces of and/or glue together tcpdump files + */ + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/timeb.h> +#include <netinet/in.h> +#include <varargs.h> + +#include "savefile.h" +#include "version.h" + + +int tflag = 0; /* global that util routines are sensitive to */ + +char *program_name; + +long thiszone; /* gmt to local correction in trace file */ + +/* Length of saved portion of packet. */ +int snaplen; + +/* Length of saved portion of data past link level protocol. */ +int snapdlen; + +/* Precision of clock used to generate trace file. */ +int precision; + +static int linkinfo; + +/* Style in which to print timestamps; RAW is "secs.usecs"; READABLE is + * ala the Unix "date" tool; and PARSEABLE is tcpslice's custom format, + * designed to be easy to parse. The default is RAW. + */ +enum stamp_styles { TIMESTAMP_RAW, TIMESTAMP_READABLE, TIMESTAMP_PARSEABLE }; +enum stamp_styles timestamp_style = TIMESTAMP_RAW; + + +time_t gwtm2secs( /* struct tm *tmp */ ); + + +long local_time_zone( /* timestamp */ ); +struct timeval parse_time(/* time_string, base_time*/); +void fill_tm(/* time_string, is_delta, t, usecs_addr */); +void get_file_range( /* filename, first_time, last_time */ ); +struct timeval first_packet_time(/* filename */); +void extract_slice(/* filename, start_time, stop_time */); +char *timestamp_to_string( /* timestamp */ ); +void dump_times(/* filename */); +void usage(); + + +int +main(argc, argv) + int argc; + char **argv; +{ + int op; + int dump_flag = 0; + int report_times = 0; + char *start_time_string = 0; + char *stop_time_string = 0; + char *write_file_name = "-"; /* default is stdout */ + struct timeval first_time, start_time, stop_time; + + extern char *optarg; + extern int optind, opterr; + + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "dRrtw:")) != EOF) + switch (op) { + + case 'd': + dump_flag = 1; + break; + + case 'R': + ++report_times; + timestamp_style = TIMESTAMP_RAW; + break; + + case 'r': + ++report_times; + timestamp_style = TIMESTAMP_READABLE; + break; + + case 't': + ++report_times; + timestamp_style = TIMESTAMP_PARSEABLE; + break; + + case 'w': + write_file_name = optarg; + break; + + default: + usage(); + /* NOTREACHED */ + } + + if ( report_times > 1 ) + error( "only one of -R, -r, or -t can be specified" ); + + + if (optind < argc) + /* See if the next argument looks like a possible + * start time, and if so assume it is one. + */ + if (isdigit(argv[optind][0]) || argv[optind][0] == '+') + start_time_string = argv[optind++]; + + if (optind < argc) + if (isdigit(argv[optind][0]) || argv[optind][0] == '+') + stop_time_string = argv[optind++]; + + + if (optind >= argc) + error("at least one input file must be given"); + + + first_time = first_packet_time(argv[optind]); + fclose( sf_readfile ); + + + if (start_time_string) + start_time = parse_time(start_time_string, first_time); + else + start_time = first_time; + + if (stop_time_string) + stop_time = parse_time(stop_time_string, start_time); + + else + { + stop_time = start_time; + stop_time.tv_sec += 86400*3660; /* + 10 years; "forever" */ + } + + + if (report_times) { + for (; optind < argc; ++optind) + dump_times(argv[optind]); + } + + if (dump_flag) { + printf( "start\t%s\nstop\t%s\n", + timestamp_to_string( &start_time ), + timestamp_to_string( &stop_time ) ); + } + + if (! report_times && ! dump_flag) { + if ( ! strcmp( write_file_name, "-" ) && + isatty( fileno(stdout) ) ) + error("stdout is a terminal; redirect or use -w"); + + sf_write_init(write_file_name, linkinfo, thiszone, snaplen, + precision); + + for (; optind < argc; ++optind) + extract_slice(argv[optind], &start_time, &stop_time); + + fclose( sf_writefile ); + } + + return 0; +} + + +/* Returns non-zero if a string matches the format for a timestamp, + * 0 otherwise. + */ +int is_timestamp( str ) +char *str; + { + while ( isdigit(*str) || *str == '.' ) + ++str; + + return *str == '\0'; + } + + +/* Return the correction in seconds for the local time zone with respect + * to Greenwich time. + */ +long local_time_zone(timestamp) +long timestamp; +{ + struct timeval now; + struct timezone tz; + long localzone; + + if (gettimeofday(&now, &tz) < 0) { + perror("tcpslice: gettimeofday"); + exit(1); + } + localzone = tz.tz_minuteswest * -60; + + if (localtime((time_t *) ×tamp)->tm_isdst) + localzone += 3600; + + return localzone; +} + +/* Given a string specifying a time (or a time offset) and a "base time" + * from which to compute offsets and fill in defaults, returns a timeval + * containing the specified time. + */ + +struct timeval +parse_time(time_string, base_time) + char *time_string; + struct timeval base_time; +{ + struct tm *bt = localtime((time_t *) &base_time.tv_sec); + struct tm t; + struct timeval result; + time_t usecs = 0; + int is_delta = (time_string[0] == '+'); + + if ( is_delta ) + ++time_string; /* skip over '+' sign */ + + if ( is_timestamp( time_string ) ) + { /* interpret as a raw timestamp or timestamp offset */ + char *time_ptr; + + result.tv_sec = atoi( time_string ); + time_ptr = strchr( time_string, '.' ); + + if ( time_ptr ) + { /* microseconds are specified, too */ + int num_digits = strlen( time_ptr + 1 ); + result.tv_usec = atoi( time_ptr + 1 ); + + /* turn 123.456 into 123 seconds plus 456000 usec */ + while ( num_digits++ < 6 ) + result.tv_usec *= 10; + } + + else + result.tv_usec = 0; + + if ( is_delta ) + { + result.tv_sec += base_time.tv_sec; + result.tv_usec += base_time.tv_usec; + + if ( result.tv_usec > 1000000 ) + { + result.tv_usec -= 1000000; + ++result.tv_sec; + } + } + + return result; + } + + if (is_delta) { + t = *bt; + usecs = base_time.tv_usec; + } else { + /* Zero struct (easy way around lack of tm_gmtoff/tm_zone + * under older systems) */ + bzero((char *)&t, sizeof(t)); + + /* Set values to "not set" flag so we can later identify + * and default them. + */ + t.tm_sec = t.tm_min = t.tm_hour = t.tm_mday = t.tm_mon = + t.tm_year = -1; + } + + fill_tm(time_string, is_delta, &t, &usecs); + + /* Now until we reach a field that was specified, fill in the + * missing fields from the base time. + */ +#define CHECK_FIELD(field_name) \ + if (t.field_name < 0) \ + t.field_name = bt->field_name; \ + else \ + break + + do { /* bogus do-while loop so "break" in CHECK_FIELD will work */ + CHECK_FIELD(tm_year); + CHECK_FIELD(tm_mon); + CHECK_FIELD(tm_mday); + CHECK_FIELD(tm_hour); + CHECK_FIELD(tm_min); + CHECK_FIELD(tm_sec); + } while ( 0 ); + + /* Set remaining unspecified fields to 0. */ +#define ZERO_FIELD_IF_NOT_SET(field_name,zero_val) \ + if (t.field_name < 0) \ + t.field_name = zero_val + + if (! is_delta) { + ZERO_FIELD_IF_NOT_SET(tm_year,90); /* should never happen */ + ZERO_FIELD_IF_NOT_SET(tm_mon,0); + ZERO_FIELD_IF_NOT_SET(tm_mday,1); + ZERO_FIELD_IF_NOT_SET(tm_hour,0); + ZERO_FIELD_IF_NOT_SET(tm_min,0); + ZERO_FIELD_IF_NOT_SET(tm_sec,0); + } + + result.tv_sec = gwtm2secs(&t); + result.tv_sec -= local_time_zone(result.tv_sec); + result.tv_usec = usecs; + + return result; +} + + +/* Fill in (or add to, if is_delta is true) the time values in the + * tm struct "t" as specified by the time specified in the string + * "time_string". "usecs_addr" is updated with the specified number + * of microseconds, if any. + */ +void +fill_tm(time_string, is_delta, t, usecs_addr) + char *time_string; + int is_delta; /* if true, add times in instead of replacing */ + struct tm *t; /* tm struct to be filled from time_string */ + time_t *usecs_addr; +{ + char *t_start, *t_stop, format_ch; + int val; + +#define SET_VAL(lhs,rhs) \ + if (is_delta) \ + lhs += rhs; \ + else \ + lhs = rhs + + /* Loop through the time string parsing one specification at + * a time. Each specification has the form <number><letter> + * where <number> indicates the amount of time and <letter> + * the units. + */ + for (t_stop = t_start = time_string; *t_start; t_start = ++t_stop) { + if (! isdigit(*t_start)) + error("bad date format %s, problem starting at %s", + time_string, t_start); + + while (isdigit(*t_stop)) + ++t_stop; + if (! t_stop) + error("bad date format %s, problem starting at %s", + time_string, t_start); + + val = atoi(t_start); + + format_ch = *t_stop; + if ( isupper( format_ch ) ) + format_ch = tolower( format_ch ); + + switch (format_ch) { + case 'y': + if ( val > 1900 ) + val -= 1900; + SET_VAL(t->tm_year, val); + break; + + case 'm': + if (strchr(t_stop+1, 'D') || + strchr(t_stop+1, 'd')) + /* it's months */ + SET_VAL(t->tm_mon, val - 1); + else /* it's minutes */ + SET_VAL(t->tm_min, val); + break; + + case 'd': + SET_VAL(t->tm_mday, val); + break; + + case 'h': + SET_VAL(t->tm_hour, val); + break; + + case 's': + SET_VAL(t->tm_sec, val); + break; + + case 'u': + SET_VAL(*usecs_addr, val); + break; + + default: + error( + "bad date format %s, problem starting at %s", + time_string, t_start); + } + } +} + + +/* Return in first_time and last_time the timestamps of the first and + * last packets in the given file. + */ +void +get_file_range( filename, first_time, last_time ) + char filename[]; + struct timeval *first_time; + struct timeval *last_time; +{ + *first_time = first_packet_time( filename ); + + if ( ! sf_find_end( first_time, last_time ) ) + error( "couldn't find final packet in file %s", filename ); +} + + +/* Returns the timestamp of the first packet in the given tcpdump save + * file, which as a side-effect is initialized for further save-file + * reading. + */ + +struct timeval +first_packet_time(filename) + char filename[]; +{ + struct packet_header hdr; + u_char *buf; + + if (sf_read_init(filename, &linkinfo, &thiszone, &snaplen, &precision)) + error( "bad tcpdump file %s", filename ); + + buf = (u_char *)malloc((unsigned)snaplen); + + if (sf_next_packet(&hdr, buf, snaplen)) + error( "bad status reading first packet in %s", filename ); + + free((char *)buf); + + return hdr.ts; +} + + +/* Extract from the given file all packets with timestamps between + * the two time values given (inclusive). These packets are written + * to the save file output set up by a previous call to sf_write_init(). + * Upon return, start_time is adjusted to reflect a time just after + * that of the last packet written to the output. + */ + +void +extract_slice(filename, start_time, stop_time) + char filename[]; + struct timeval *start_time; + struct timeval *stop_time; +{ + long start_pos, stop_pos; + struct timeval file_start_time, file_stop_time; + int status; + struct packet_header hdr; + u_char *buf; + + + if (sf_read_init(filename, &linkinfo, &thiszone, &snaplen, &precision)) + error( "bad tcpdump file %s", filename ); + + buf = (u_char *)malloc((unsigned)snaplen); + + start_pos = ftell( sf_readfile ); + + + if ( (status = sf_next_packet( &hdr, buf, snaplen )) ) + error( "bad status %d reading packet in %s", + status, filename ); + + file_start_time = hdr.ts; + + + if ( ! sf_find_end( &file_start_time, &file_stop_time ) ) + error( "problems finding end packet of file %s", + filename ); + + stop_pos = ftell( sf_readfile ); + + + /* sf_find_packet() requires that the time it's passed as its last + * argument be in the range [min_time, max_time], so we enforce + * that constraint here. + */ + if ( sf_timestamp_less_than( start_time, &file_start_time ) ) + *start_time = file_start_time; + + if ( sf_timestamp_less_than( &file_stop_time, start_time ) ) + return; /* there aren't any packets of interest in the file */ + + + sf_find_packet( &file_start_time, start_pos, + &file_stop_time, stop_pos, + start_time ); + + for ( ; ; ) + { + struct timeval *timestamp; + status = sf_next_packet( &hdr, buf, snaplen ); + + if ( status ) + { + if ( status != SFERR_EOF ) + error( "bad status %d reading packet in %s", + status, filename ); + break; + } + + timestamp = &hdr.ts; + + if ( ! sf_timestamp_less_than( timestamp, start_time ) ) + { /* packet is recent enough */ + if ( sf_timestamp_less_than( stop_time, timestamp ) ) + /* We've gone beyond the end of the region + * of interest ... We're done with this file. + */ + break; + + sf_write( buf, timestamp, (int) hdr.len, + (int) hdr.caplen ); + *start_time = *timestamp; + + /* We know that each packet is guaranteed to have + * a unique timestamp, so we push forward the + * allowed minimum time to weed out duplicate + * packets. + */ + ++start_time->tv_usec; + } + } + + fclose( sf_readfile ); + free( (char *) buf ); +} + + +/* Translates a timestamp to the time format specified by the user. + * Returns a pointer to the translation residing in a static buffer. + * There are two such buffers, which are alternated on subseqeuent + * calls, so two calls may be made to this routine without worrying + * about the results of the first call being overwritten by the + * results of the second. + */ + +char * +timestamp_to_string(timestamp) + struct timeval *timestamp; +{ + struct tm *t; +#define NUM_BUFFERS 2 + static char buffers[NUM_BUFFERS][128]; + static int buffer_to_use = 0; + char *buf; + + buf = buffers[buffer_to_use]; + buffer_to_use = (buffer_to_use + 1) % NUM_BUFFERS; + + switch ( timestamp_style ) + { + case TIMESTAMP_RAW: + sprintf( buf, "%d.%d", timestamp->tv_sec, timestamp->tv_usec ); + break; + + case TIMESTAMP_READABLE: + t = localtime((time_t *) ×tamp->tv_sec); + strcpy( buf, asctime( t ) ); + buf[24] = '\0'; /* nuke final newline */ + break; + + case TIMESTAMP_PARSEABLE: + t = localtime((time_t *) ×tamp->tv_sec); + sprintf( buf, "%02dy%02dm%02dd%02dh%02dm%02ds%06du", + t->tm_year, t->tm_mon + 1, t->tm_mday, t->tm_hour, + t->tm_min, t->tm_sec, timestamp->tv_usec ); + break; + + } + + return buf; +} + + +/* Given a tcpdump save filename, reports on the times of the first + * and last packets in the file. + */ + +void +dump_times(filename) + char filename[]; +{ + struct timeval first_time, last_time; + + get_file_range( filename, &first_time, &last_time ); + + printf( "%s\t%s\t%s\n", + filename, + timestamp_to_string( &first_time ), + timestamp_to_string( &last_time ) ); +} + +void +usage() +{ + (void)fprintf(stderr, "tcpslice for tcpdump version %d.%d\n", + VERSION_MAJOR, VERSION_MINOR); + (void)fprintf(stderr, +"Usage: tcpslice [-dRrt] [-w file] [start-time [end-time]] file ... \n"); + + exit(-1); +} |