769 lines
19 KiB
C
769 lines
19 KiB
C
/*
|
|
* This module prints out IP/TCP/UDP packets in a verbose form
|
|
*
|
|
* @(#)ipprint.c 1.1 94/10/31
|
|
*
|
|
* Copyright (c) 1988 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <net/if.h>
|
|
#include <netinet/in_systm.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/ip.h>
|
|
#include <netinet/tcp.h>
|
|
#include <netinet/udp.h>
|
|
#include <netinet/ip_icmp.h>
|
|
#include <netinet/if_ether.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
# define NND 1
|
|
#include "ndio.h"
|
|
|
|
#include <protocols/routed.h>
|
|
#include <arpa/tftp.h>
|
|
|
|
# define IP_OFFSET 0x1FFF /* masked off DF and MF flags */
|
|
# ifndef IPPPORT_DOMAIN
|
|
# define IPPORT_DOMAIN 53 /* domain name server port */
|
|
# endif
|
|
|
|
extern char *malloc();
|
|
extern char *sprintf();
|
|
extern char *inet_ntoa();
|
|
|
|
extern char *getname();
|
|
extern char *getportname();
|
|
|
|
char *prototable[]; /* IP protocol numbers to names */
|
|
|
|
|
|
extern int symflag[]; /* verbose printout needed */
|
|
extern int rpcflag[]; /* RPC printout needed */
|
|
|
|
char *icmptype(); /* forward declarations */
|
|
|
|
ipprint(index, name, ip, length)
|
|
int index;
|
|
char *name;
|
|
struct ip *ip;
|
|
int length;
|
|
{
|
|
int *data;
|
|
unsigned char *opt;
|
|
int datalength, optlength, curlength;
|
|
|
|
data = (int *)ip;
|
|
data += ip->ip_hl;
|
|
datalength = ntohs(ip->ip_len) - ip->ip_hl*4;
|
|
if (!symflag[index] && !rpcflag[index]) {
|
|
shortipprint( index, ip, length, (struct udphdr *)data );
|
|
return;
|
|
}
|
|
if (ip->ip_off & IP_OFFSET)
|
|
{
|
|
switch (ip->ip_p)
|
|
{
|
|
case IPPROTO_TCP: display(index,"TCP"); break;
|
|
case IPPROTO_UDP: display(index,"UDP"); break;
|
|
case IPPROTO_ND: display(index,"ND"); break;
|
|
case IPPROTO_ICMP: display(index,"ICMP"); break;
|
|
case IPPROTO_HELLO: display(index,"Hello"); break;
|
|
default: display(index,"%s protocol %d", name, ip->ip_p);
|
|
break;
|
|
}
|
|
display(index," fragment offset=%d, length=%d ",
|
|
(ip->ip_off & IP_OFFSET) * 8, datalength);
|
|
display(index," from %s ", getname(ip->ip_src) );
|
|
display(index,"to %s", getname(ip->ip_dst) );
|
|
}
|
|
else switch (ip->ip_p)
|
|
{
|
|
case IPPROTO_TCP:
|
|
tcpprint(index, (struct tcphdr *)data, datalength,
|
|
ip->ip_src, ip->ip_dst);
|
|
break;
|
|
|
|
case IPPROTO_UDP:
|
|
udpprint(index, (struct udphdr *)data, datalength,
|
|
ip->ip_src, ip->ip_dst);
|
|
break;
|
|
|
|
case IPPROTO_ND:
|
|
ndprint(index, (char *)data, datalength, ip->ip_src, ip->ip_dst);
|
|
break;
|
|
|
|
case IPPROTO_ICMP:
|
|
icmpprint(index, (struct icmp *)data, datalength,
|
|
ip->ip_src, ip->ip_dst);
|
|
break;
|
|
|
|
case IPPROTO_HELLO:
|
|
helloprint(index, (char *)data, datalength,
|
|
ip->ip_src, ip->ip_dst);
|
|
break;
|
|
|
|
default:
|
|
display(index,"Unknown IP protocol %d", ip->ip_p);
|
|
display(index," from %s ", getname(ip->ip_src) );
|
|
display(index,"to %s", getname(ip->ip_dst) );
|
|
break;
|
|
}
|
|
if (ip->ip_off & IP_MF)
|
|
display(index, " (more fragments)");
|
|
opt = (unsigned char *)ip;
|
|
opt += sizeof(struct ip);
|
|
optlength = ip->ip_hl*4 - sizeof(struct ip);
|
|
if (optlength > 0)
|
|
display(index, "\n ip options:");
|
|
while (optlength > 0) {
|
|
/*
|
|
* Decode IP options.
|
|
*/
|
|
curlength = opt[1];
|
|
switch (*opt) {
|
|
case IPOPT_EOL:
|
|
return;
|
|
|
|
case IPOPT_NOP:
|
|
opt++;
|
|
optlength--;
|
|
continue;
|
|
|
|
case IPOPT_RR:
|
|
display(index," <record route> ");
|
|
ip_rrprint(index, opt, curlength);
|
|
break;
|
|
|
|
case IPOPT_TS:
|
|
display(index," <time stamp>");
|
|
break;
|
|
|
|
case IPOPT_SECURITY:
|
|
display(index," <security>");
|
|
break;
|
|
|
|
case IPOPT_LSRR:
|
|
display(index," <loose source route> ");
|
|
ip_rrprint(index, opt, curlength);
|
|
break;
|
|
|
|
case IPOPT_SATID:
|
|
display(index," <stream id>");
|
|
break;
|
|
|
|
case IPOPT_SSRR:
|
|
display(index," <strict source route> ");
|
|
ip_rrprint(index, opt, curlength);
|
|
break;
|
|
|
|
default:
|
|
display(index," <option %d, len %d>", *opt, curlength);
|
|
break;
|
|
}
|
|
/*
|
|
* Following most options comes a length field
|
|
*/
|
|
opt += curlength;
|
|
optlength -= curlength;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Print out a recorded route option.
|
|
*/
|
|
ip_rrprint(index, opt, length)
|
|
int index;
|
|
unsigned char *opt;
|
|
int length;
|
|
{
|
|
int pointer;
|
|
struct in_addr addr;
|
|
|
|
opt += IPOPT_OFFSET;
|
|
length -= IPOPT_OFFSET;
|
|
|
|
pointer = *opt++;
|
|
pointer -= IPOPT_MINOFF;
|
|
length--;
|
|
|
|
while (length > 0) {
|
|
bcopy((char *)opt, (char *)&addr, sizeof(addr));
|
|
if (addr.s_addr == INADDR_ANY)
|
|
display(index, "-");
|
|
else
|
|
display(index, "%s", getname(addr) );
|
|
if (pointer == 0)
|
|
display(index, "(Current)");
|
|
opt += sizeof(addr);
|
|
length -= sizeof(addr);
|
|
pointer -= sizeof(addr);
|
|
if (length >0)
|
|
display(index, ", ");
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* short printout version (one-line) for Internet Packets
|
|
*/
|
|
shortipprint(index, ip, length, udp)
|
|
int index;
|
|
struct ip *ip;
|
|
int length;
|
|
struct udphdr *udp;
|
|
{
|
|
int proto, frag;
|
|
struct in_addr src, dst;
|
|
char fchar;
|
|
|
|
proto = ip->ip_p;
|
|
frag = ip->ip_off & 0x1fff;
|
|
fchar = (frag ? '*' : ' ');
|
|
dst = ip->ip_dst;
|
|
src = ip->ip_src;
|
|
if (prototable[proto])
|
|
display(index,"%c%4d %4s ", fchar, length, prototable[proto]);
|
|
else
|
|
display(index,"%c%4d %02d ", fchar, length, proto);
|
|
if (frag)
|
|
return;
|
|
|
|
display(index,"%15.15s ", getname(src));
|
|
display(index,"%15.15s ", getname(dst));
|
|
if (proto == IPPROTO_TCP || proto == IPPROTO_UDP) {
|
|
display(index,"%10.10s ", getportname(udp->uh_sport, proto));
|
|
display(index,"%10.10s", getportname(udp->uh_dport, proto));
|
|
}
|
|
else if (proto == IPPROTO_ICMP) {
|
|
display(index," %s", icmptype((struct icmp *)udp));
|
|
}
|
|
}
|
|
|
|
|
|
tcpprint(index, tcp, length, src, dst)
|
|
int index;
|
|
register struct tcphdr *tcp; /* points to tcp */
|
|
int length; /* in bytes of entire TCP */
|
|
struct in_addr src, dst; /* Internet addresses */
|
|
{
|
|
/*
|
|
* Print the given TCP segment
|
|
*/
|
|
int optlen;
|
|
unsigned char *opt;
|
|
|
|
display(index,"TCP from %s.%s ",
|
|
getname(src),
|
|
getportname(tcp->th_sport,IPPROTO_TCP) );
|
|
display(index,"to %s.%s ",
|
|
getname(dst),
|
|
getportname(tcp->th_dport,IPPROTO_TCP) );
|
|
display(index,"seq %X, ", ntohl(tcp->th_seq));
|
|
if (tcp->th_flags & TH_ACK)
|
|
display(index,"ack %X, ", ntohl(tcp->th_ack));
|
|
if (tcp->th_flags & TH_SYN)
|
|
display(index,"SYN, ");
|
|
if (tcp->th_flags & TH_RST)
|
|
display(index,"RESET, ");
|
|
if (tcp->th_flags & TH_FIN)
|
|
display(index,"FIN, ");
|
|
display(index," window %d, ", ntohs(tcp->th_win));
|
|
optlen = tcp->th_off*4 - sizeof(struct tcphdr);
|
|
opt = (unsigned char *)tcp;
|
|
opt += sizeof(struct tcphdr);
|
|
while (optlen > 0) {
|
|
/*
|
|
* decode the TCP options. Right now the only one is MSS,
|
|
* although Bob might want me to add SACK at some point.
|
|
*/
|
|
int mss, curlen;
|
|
switch (*opt) {
|
|
case TCPOPT_EOL:
|
|
optlen = 0;
|
|
break;
|
|
case TCPOPT_NOP:
|
|
optlen--;
|
|
opt++;
|
|
break;
|
|
case TCPOPT_MAXSEG:
|
|
curlen = opt[1];
|
|
mss = opt[2]*256 + opt[3];
|
|
optlen -= curlen;
|
|
opt += curlen;
|
|
display(index,"<mss %d> ", mss);
|
|
break;
|
|
default:
|
|
display(index,"<%d> ", *opt++);
|
|
optlen--;
|
|
}
|
|
}
|
|
length -= tcp->th_off*4;
|
|
if (length <= 0)
|
|
return;
|
|
|
|
display(index,"%d bytes data", length);
|
|
if (rpcflag[index] != 0)
|
|
rpcprint(index, opt, length);
|
|
}
|
|
|
|
|
|
udpprint(index, udp, length, src, dst)
|
|
int index;
|
|
struct udphdr *udp;
|
|
struct in_addr src, dst;
|
|
{
|
|
int ulen = ntohs(udp->uh_ulen);
|
|
|
|
display(index,"UDP from %s.%s ",
|
|
getname(src),
|
|
getportname(udp->uh_sport,IPPROTO_UDP) );
|
|
display(index,"to %s.%s ",
|
|
getname(dst),
|
|
getportname(udp->uh_dport,IPPROTO_UDP) );
|
|
display(index," %d bytes", ulen );
|
|
if (length < ulen)
|
|
display(index," (only %d bytes long)", length);
|
|
if (!rpcflag[index]) return;
|
|
if (udp->uh_sport == htons(IPPORT_ROUTESERVER) ||
|
|
udp->uh_dport == htons(IPPORT_ROUTESERVER))
|
|
routeprint(index,
|
|
(struct rip *)((char *)udp + sizeof(struct udphdr)),
|
|
udp->uh_ulen - sizeof(struct udphdr) );
|
|
else if (udp->uh_sport == htons(IPPORT_TFTP) ||
|
|
udp->uh_dport == htons(IPPORT_TFTP))
|
|
tftpprint(index,
|
|
(struct tftphdr *)((char *)udp + sizeof(struct udphdr)),
|
|
udp->uh_ulen - sizeof(struct udphdr) );
|
|
else if (udp->uh_sport == htons(IPPORT_DOMAIN) ||
|
|
udp->uh_dport == htons(IPPORT_DOMAIN))
|
|
domainprint(index,
|
|
((char *)udp + sizeof(struct udphdr)),
|
|
udp->uh_ulen - sizeof(struct udphdr) );
|
|
else rpcprint(index, (char *)udp + sizeof(struct udphdr),
|
|
ulen - sizeof(struct udphdr) );
|
|
}
|
|
|
|
/*
|
|
* Return a TFTP error code string, given number
|
|
*/
|
|
char *tftperror(code)
|
|
unsigned short code;
|
|
{
|
|
static char buf[128];
|
|
|
|
switch (code) {
|
|
case EUNDEF: return("not defined");
|
|
case ENOTFOUND: return("file not found");
|
|
case EACCESS: return("access violation");
|
|
case ENOSPACE: return("disk full or allocation exceeded");
|
|
case EBADOP: return("illegal TFTP operation");
|
|
case EBADID: return("unknown transfer ID");
|
|
case EEXISTS: return("file already exists");
|
|
case ENOUSER: return("no such user");
|
|
}
|
|
(void) sprintf(buf,"%d",code);
|
|
return(buf);
|
|
}
|
|
|
|
/*
|
|
* Print a Trivial File Transfer (TFTP) packet
|
|
*/
|
|
tftpprint(index, p, length)
|
|
int index;
|
|
struct tftphdr *p;
|
|
int length;
|
|
{
|
|
display(index," TFTP ");
|
|
switch (ntohs(p->th_opcode)) {
|
|
case RRQ:
|
|
display(index,"Read");
|
|
break;
|
|
case WRQ:
|
|
display(index,"Write");
|
|
break;
|
|
case DATA:
|
|
display(index,"Data block %d", ntohs(p->th_block));
|
|
break;
|
|
case ACK:
|
|
display(index,"Ack block %d", ntohs(p->th_block));
|
|
break;
|
|
case ERROR:
|
|
display(index,"Error %s", tftperror(ntohs(p->th_code)) );
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Print a Routing Information Protocol (RIP) packet
|
|
*/
|
|
routeprint(index, p, length)
|
|
int index;
|
|
struct rip *p;
|
|
int length;
|
|
{
|
|
register struct netinfo *n;
|
|
struct sockaddr_in *sin;
|
|
int i;
|
|
char *name;
|
|
|
|
switch (p->rip_cmd) {
|
|
case RIPCMD_REQUEST: display(index," Route Request "); break;
|
|
case RIPCMD_RESPONSE: display(index," Route Response "); break;
|
|
case RIPCMD_TRACEON: display(index," Route Trace On "); break;
|
|
case RIPCMD_TRACEOFF: display(index," Route Trace Off "); break;
|
|
case RIPCMD_POLL: display(index," Route Poll "); break;
|
|
case RIPCMD_POLLENTRY: display(index," Route Poll Entry "); break;
|
|
default: return; /* probably not a RIP packet */
|
|
}
|
|
switch (p->rip_cmd) {
|
|
case RIPCMD_POLLENTRY:
|
|
if (length > 4 + sizeof(struct netinfo)) {
|
|
register struct entryinfo *ep;
|
|
|
|
ep = (struct entryinfo *)(p->rip_tracefile);
|
|
display(index,"Reply\n ");
|
|
sin = (struct sockaddr_in *)&ep->rtu_dst;
|
|
name = getname(sin->sin_addr);
|
|
display(index,"Dst %s(%s), ", name, inet_ntoa(sin->sin_addr));
|
|
sin = (struct sockaddr_in *)&ep->rtu_router;
|
|
name = getname(sin->sin_addr);
|
|
display(index,"via %s(%s), ", name, inet_ntoa(sin->sin_addr));
|
|
display(index,"metric %d, ifp %s",
|
|
ep->rtu_metric, ep->int_name);
|
|
break;
|
|
}
|
|
|
|
case RIPCMD_REQUEST:
|
|
case RIPCMD_RESPONSE:
|
|
case RIPCMD_POLL:
|
|
/*
|
|
* skip header; rest are sockaddr/metric pairs, except
|
|
* in the case of POLLENTRY replies.
|
|
*/
|
|
length -= 4;
|
|
for (n=p->rip_nets;length >= sizeof(struct netinfo); n++) {
|
|
if (p->rip_vers > 0) {
|
|
n->rip_dst.sa_family =
|
|
ntohs(n->rip_dst.sa_family);
|
|
n->rip_metric = ntohl((u_long)n->rip_metric);
|
|
}
|
|
display(index,"\n\t");
|
|
sin = (struct sockaddr_in *)&n->rip_dst;
|
|
if (sin->sin_port) {
|
|
display(index,"**port %d** ",
|
|
htons(sin->sin_port) & 0xFFFF);
|
|
}
|
|
for (i=6;i<13;i++)
|
|
if (n->rip_dst.sa_data[i]) {
|
|
display(index,"sockaddr[%d] = %d", i,
|
|
n->rip_dst.sa_data[i] & 0xFF);
|
|
}
|
|
if (sin->sin_addr.s_addr==htonl(INADDR_ANY))
|
|
name = "default";
|
|
else name = getname(sin->sin_addr);
|
|
display(index," %s(%s), metric %d", name,
|
|
inet_ntoa(sin->sin_addr), n->rip_metric);
|
|
length -= sizeof(struct netinfo);
|
|
}
|
|
return;
|
|
|
|
case RIPCMD_TRACEON:
|
|
case RIPCMD_TRACEOFF:
|
|
display(index,"\n Trace file name = %s", p->rip_tracefile);
|
|
return;
|
|
}
|
|
}
|
|
|
|
ndprint(index, data, length, src, dst)
|
|
int index;
|
|
char *data;
|
|
struct in_addr src, dst;
|
|
{
|
|
register struct ndpack *nd;
|
|
|
|
nd = (struct ndpack *)(data - sizeof(struct ip));
|
|
display(index,"ND from %s ", getname(src) );
|
|
display(index,"to %s ", getname(dst) );
|
|
switch (nd->np_op & NDOPCODE) {
|
|
case NDOPREAD: display(index,"Read"); break;
|
|
case NDOPWRITE: display(index,"Write"); break;
|
|
case NDOPERROR: display(index,"Error"); break;
|
|
}
|
|
display(index," device %d blk %d count %d length %d",
|
|
nd->np_min, htonl(nd->np_blkno), htonl(nd->np_bcount), length );
|
|
if (nd->np_op & NDOPDONE) display(index, " Done");
|
|
}
|
|
|
|
|
|
icmpprint(index, icp, length, src, dst)
|
|
int index;
|
|
register struct icmp *icp; /* points to icmp packet */
|
|
int length; /* in bytes of entire icmp*/
|
|
struct in_addr src, dst; /* Internet addresses */
|
|
{
|
|
/*
|
|
* Print the given ICMP message
|
|
*/
|
|
display(index,"ICMP from %s ", getname(src) );
|
|
display(index,"to %s ", getname(dst) );
|
|
display(index,"%s ", icmptype(icp));
|
|
switch (icp->icmp_type)
|
|
{
|
|
case ICMP_ECHO:
|
|
case ICMP_ECHOREPLY:
|
|
display(index, "%d data bytes", length);
|
|
break;
|
|
|
|
case ICMP_UNREACH:
|
|
switch (icp->icmp_code)
|
|
{
|
|
case ICMP_UNREACH_NET: display(index,"bad net"); break;
|
|
case ICMP_UNREACH_HOST: display(index,"bad host"); break;
|
|
case ICMP_UNREACH_PROTOCOL: display(index,"bad protocol"); break;
|
|
case ICMP_UNREACH_PORT: display(index,"bad port"); break;
|
|
case ICMP_UNREACH_NEEDFRAG: display(index,"needed to fragment");
|
|
break;
|
|
case ICMP_UNREACH_SRCFAIL: display(index,"src route failed");
|
|
break;
|
|
default: display(index,"subcode %d", icp->icmp_code);
|
|
}
|
|
case ICMP_TIMXCEED:
|
|
case ICMP_SOURCEQUENCH:
|
|
display(index,"\n bad packet: ");
|
|
if (length > 28)
|
|
ipprint(index, 0, (struct ip *)icp->icmp_data, 28);
|
|
break;
|
|
|
|
case ICMP_REDIRECT:
|
|
switch (icp->icmp_code)
|
|
{
|
|
case ICMP_REDIRECT_NET:
|
|
display(index,"for network");
|
|
break;
|
|
case ICMP_REDIRECT_HOST:
|
|
display(index,"for host");
|
|
break;
|
|
case ICMP_REDIRECT_TOSNET:
|
|
display(index,"for tos and net");
|
|
break;
|
|
case ICMP_REDIRECT_TOSHOST:
|
|
display(index,"for tos and host");
|
|
break;
|
|
default:
|
|
display(index,"subcode %d", icp->icmp_code);
|
|
}
|
|
display(index," to %s", getname(icp->icmp_gwaddr));
|
|
display(index,"\n bad packet: ");
|
|
if (length > 28)
|
|
ipprint(index, 0, (struct ip *)icp->icmp_data, 28);
|
|
break;
|
|
|
|
case ICMP_MASKREPLY:
|
|
display(index, getname(icp->icmp_mask));
|
|
break;
|
|
|
|
default:
|
|
if (icp->icmp_code)
|
|
display(index,"subcode %d", icp->icmp_code);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Print the given Ethernet address
|
|
*/
|
|
char *printether(p)
|
|
struct ether_addr *p;
|
|
{
|
|
static char buf[256];
|
|
|
|
if (isbroadcast(p))
|
|
return("broadcast");
|
|
|
|
sprintf(buf, "%x:%x:%x:%x:%x:%x",
|
|
p->ether_addr_octet[0],
|
|
p->ether_addr_octet[1],
|
|
p->ether_addr_octet[2],
|
|
p->ether_addr_octet[3],
|
|
p->ether_addr_octet[4],
|
|
p->ether_addr_octet[5]);
|
|
return(buf);
|
|
}
|
|
|
|
arpprint(index, name, arp, length)
|
|
int index;
|
|
char *name;
|
|
struct ether_arp *arp;
|
|
int length;
|
|
{
|
|
struct in_addr ip;
|
|
|
|
if (!symflag[index]) {
|
|
shortarpprint( index, name, arp, length);
|
|
return;
|
|
}
|
|
|
|
switch (ntohs(arp->arp_pro)) {
|
|
case ETHERTYPE_IP: display(index,"ip"); break;
|
|
case ETHERTYPE_TRAIL: display(index,"trailer"); break;
|
|
case ETHERTYPE_TRAIL+1: display(index,"trailer(1)"); break;
|
|
case ETHERTYPE_TRAIL+2: display(index,"trailer(2)"); break;
|
|
case ETHERTYPE_TRAIL+3: display(index,"trailer(3)"); break;
|
|
case ETHERTYPE_TRAIL+4: display(index,"trailer(4)"); break;
|
|
case ETHERTYPE_TRAIL+5: display(index,"trailer(5)"); break;
|
|
case ETHERTYPE_TRAIL+6: display(index,"trailer(6)"); break;
|
|
case ETHERTYPE_TRAIL+7: display(index,"trailer(7)"); break;
|
|
default: display(index,"protocol %d", ntohs(arp->arp_pro));
|
|
}
|
|
display(index," %s ", name);
|
|
switch (ntohs(arp->arp_op)) {
|
|
case ARPOP_REQUEST: display(index,"request"); break;
|
|
case ARPOP_REPLY: display(index,"reply"); break;
|
|
case REVARP_REQUEST: display(index,"rev request"); break;
|
|
case REVARP_REPLY: display(index,"rev reply"); break;
|
|
default: display(index,"op %d", ntohs(arp->arp_op));
|
|
}
|
|
display(index," from ");
|
|
/*
|
|
* Allow this to be compiled on 3.x systems as well as 4.x systems
|
|
*/
|
|
#ifdef arp_spa
|
|
# undef arp_spa
|
|
# undef arp_sha
|
|
# undef arp_tpa
|
|
# undef arp_tha
|
|
# define arp_spa arp_xspa
|
|
# define arp_sha arp_xsha
|
|
# define arp_tpa arp_xtpa
|
|
# define arp_tha arp_xtha
|
|
#endif arp_spa
|
|
|
|
bcopy((char *)arp->arp_spa, (char *)&ip, sizeof(ip));
|
|
if (ip.s_addr != htonl(INADDR_ANY))
|
|
display(index,"%s", getname(ip));
|
|
if (isknown(&arp->arp_sha))
|
|
display(index,"(%s)", printether(&arp->arp_sha));
|
|
bcopy((char *)arp->arp_tpa, (char *)&ip, sizeof(ip));
|
|
display(index," for ");
|
|
if (ip.s_addr != htonl(INADDR_ANY))
|
|
display(index,"%s", getname(ip));
|
|
if (isknown(&arp->arp_tha))
|
|
display(index,"(%s)", printether(&arp->arp_tha));
|
|
}
|
|
|
|
/*
|
|
* Return TRUE if the Ethernet address is known
|
|
*/
|
|
isknown(a)
|
|
struct ether_addr *a;
|
|
{
|
|
register u_char *p = a->ether_addr_octet;
|
|
int i;
|
|
|
|
for (i=0; i<6; i++)
|
|
if (*p++) return(1);
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* one-line version of the ARP printout routine
|
|
*/
|
|
shortarpprint(index, name, arp, length)
|
|
int index;
|
|
char *name;
|
|
struct ether_arp *arp;
|
|
int length;
|
|
{
|
|
struct in_addr src, dst;
|
|
|
|
display(index,"%5d %4s ", length, name);
|
|
|
|
bcopy((char *)arp->arp_spa, (char *)&src, sizeof(src));
|
|
bcopy((char *)arp->arp_tpa, (char *)&dst, sizeof(dst));
|
|
|
|
display(index,"%15.15s ", getname(src));
|
|
display(index,"%15.15s ", getname(dst));
|
|
}
|
|
|
|
|
|
struct hellohdr {
|
|
u_short h_cksum;
|
|
u_short h_date;
|
|
u_long h_time;
|
|
u_short h_tstp;
|
|
};
|
|
|
|
struct m_hdr {
|
|
u_char m_count ;
|
|
u_char m_type ;
|
|
};
|
|
|
|
struct type0pair {
|
|
u_short d0_delay;
|
|
u_short d0_offset;
|
|
};
|
|
|
|
|
|
struct type1pair {
|
|
struct in_addr d1_dst;
|
|
u_short d1_delay ;
|
|
short d1_offset ;
|
|
};
|
|
|
|
|
|
/*
|
|
* The "HELLO" routing information protocol
|
|
*/
|
|
helloprint(index, data, length, src, dst)
|
|
int index;
|
|
int length;
|
|
u_char *data;
|
|
struct in_addr src, dst;
|
|
{
|
|
struct hellohdr *h = (struct hellohdr *)data;
|
|
struct m_hdr *mh;
|
|
struct type1pair *t1p;
|
|
u_short delay;
|
|
int i;
|
|
|
|
length -= sizeof(struct hellohdr);
|
|
data += sizeof(struct hellohdr);
|
|
|
|
display(index,"Hello from %s ", getname(src) );
|
|
display(index,"to %s length %d",getname(dst), length );
|
|
if (!rpcflag[index]) return;
|
|
|
|
display(index,"\n");
|
|
while (length > 0) {
|
|
mh = (struct m_hdr *)data;
|
|
length -= sizeof(struct m_hdr);
|
|
data += sizeof(struct m_hdr);
|
|
switch (mh->m_type) {
|
|
case 0:
|
|
length -= sizeof(struct type0pair);
|
|
data += sizeof(struct type0pair);
|
|
display(index," Type %d\n", mh->m_type);
|
|
break;
|
|
case 1:
|
|
for (i = 0; i < mh->m_count && length > 0; i++) {
|
|
t1p = (struct type1pair *)data;
|
|
bcopy( &t1p->d1_dst, &dst,
|
|
sizeof(struct in_addr));
|
|
delay = ntohs(t1p->d1_delay) & 0x7fff;
|
|
display(index, " %s delay %d offset %d\n",
|
|
getname(dst), delay, ntohs(t1p->d1_offset));
|
|
length -= sizeof(struct type1pair);
|
|
data += sizeof(struct type1pair);
|
|
}
|
|
break;
|
|
default:
|
|
display(index," Type %d\n", mh->m_type);
|
|
break;
|
|
}
|
|
}
|
|
}
|