/nfswatch-4.99.11/pktfilter.c
C | 502 lines | 329 code | 50 blank | 123 comment | 47 complexity | 62d7b4476eb7ad0d49656fca33612a49 MD5 | raw file
- /*
- * $Id: pktfilter.c,v 1.12 2009/04/21 05:42:08 c4chris Exp $
- */
- #include "os.h"
- /*
- * pktfilter.c - filters to count the packets.
- *
- * David A. Curry Jeffrey C. Mogul
- * Purdue University Digital Equipment Corporation
- * Engineering Computer Network Western Research Laboratory
- * 1285 Electrical Engineering Building 250 University Avenue
- * West Lafayette, IN 47907-1285 Palo Alto, CA 94301
- * davy@ecn.purdue.edu mogul@decwrl.dec.com
- *
- */
- #include <sys/param.h>
- #include <sys/socket.h>
- #include <net/if.h>
- #if !defined(ultrix) && !defined(__osf__)
- #include <net/if_arp.h>
- #endif
- #include <netinet/in.h>
- #include <netinet/if_ether.h>
- #include <netinet/in_systm.h>
- #include <netinet/ip.h>
- #include <netinet/udp.h>
- #include <netinet/tcp.h>
- #ifndef LINUX
- #include <netinet/ip_var.h>
- #include <netinet/udp_var.h>
- #endif
- #include <netinet/ip_icmp.h>
- #include <errno.h>
- #include <stdio.h>
- #include <string.h>
- #include "nfswatch.h"
- #include "externs.h"
- #include "screen.h"
- #ifdef SUNOS4
- #define NND 1
- #include <sun/ndio.h>
- #endif
- #ifdef ultrix
- #include "ultrix.map.h"
- #include "ipports.h"
- #endif
- #ifdef __osf__
- /* or perhaps "#if defined(__osf__) && defined(__alpha)"? */
- #include "osf.map.h"
- #include "ipports.h"
- #endif
- #ifdef sgi
- #include <rpc/types.h>
- #include "sgi.map.h"
- #include "ipports.h"
- #endif
- #ifdef LINUX
- #define uh_sport source
- #define uh_dport dest
- #define uh_ulen len
- #define uh_sum check
- #define th_sport source
- #define th_dport dest
- #define th_off doff
- #endif
- /*
- * Ethernet broadcast address.
- */
- static struct ether_addr ether_broadcast = {
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
- };
- #ifndef SUNOS5
- static void pkt_dispatch(char *, int, u_short, struct timeval *);
- #endif
- static void ip_filter(struct ip *, ipaddrt, ipaddrt, struct timeval *);
- static void tcp_filter(struct tcphdr *, u_int, ipaddrt, ipaddrt,
- struct timeval *);
- static void udp_filter(struct udphdr *, ipaddrt, ipaddrt,
- struct timeval *);
- static void icmp_filter(void);
- /*
- * pkt_filter_ether - Parse Ethernet header,
- * pass rest of packet to pkt_dispatch()
- */
- void
- pkt_filter_ether(char *cp, u_int length, struct timeval *tstamp)
- {
- char packet[PACKETSIZE];
- register int bdcst;
- struct ether_header eheader;
- /*
- * Extract the ethernet header.
- */
- memcpy(&eheader, cp, sizeof(struct ether_header));
- memcpy(packet, cp + sizeof(struct ether_header),
- length - sizeof(struct ether_header));
- /*
- * See if it's a broadcast packet.
- */
- #if defined(ultrix) || defined(sgi) || defined(__osf__)
- bdcst = !bcmp((char *) eheader.ether_dhost, (char *) ðer_broadcast,
- sizeof(struct ether_addr));
- #else
- bdcst = !bcmp((char *) &eheader.ether_dhost, (char *) ðer_broadcast,
- sizeof(struct ether_addr));
- #endif
- /*
- * Figure out what kind of packet it is, and pass
- * it off to the appropriate filter.
- */
- pkt_dispatch(packet, bdcst, eheader.ether_type, tstamp);
- }
- #ifndef LLC_SNAP_LSAP
- #define LLC_UI 0x3
- #define LLC_SNAP_LSAP 0xaa
- #endif
- /*
- * pkt_filter_fddi - Parse FDDI and LLC headers,
- * pass rest of packet to pkt_dispatch()
- */
- void
- pkt_filter_fddi(char *cp, u_int length, struct timeval *tstamp)
- {
- char packet[PACKETSIZE];
- register int bdcst;
- struct fddi_header {
- u_char fddi_fc;
- u_char fddi_dhost[6];
- u_char fddi_shost[6];
- } fheader;
- struct llc_header {
- u_char llc_dsap;
- u_char llc_ssap;
- u_char llc_control;
- u_char llc_org_code[3];
- u_short llc_ether_type;
- } lheader;
- u_short etype;
- #define FDDI_LLC_LEN (sizeof(struct fddi_header) + sizeof(struct llc_header))
- if (length <= FDDI_LLC_LEN)
- return; /* runt */
- /*
- * Extract the FDDI and LLC headers.
- */
- (void) bcopy(cp, (char *) &fheader, sizeof(struct fddi_header));
- (void) bcopy(cp + sizeof(struct fddi_header), (char *) &lheader,
- sizeof(struct llc_header));
- (void) bcopy(cp + FDDI_LLC_LEN, (char *) packet,
- (int) (length - FDDI_LLC_LEN));
- /* Should check FDDI frame control ... */
- /*
- * See if it's a broadcast packet.
- */
- bdcst = !bcmp((char *) fheader.fddi_dhost, (char *) ðer_broadcast,
- sizeof(struct ether_addr));
- /*
- * Check LLC encapsulation type, extract Ethernet type if SNAP
- */
- if ((lheader.llc_dsap == LLC_SNAP_LSAP)
- && (lheader.llc_ssap == LLC_SNAP_LSAP)
- && (lheader.llc_control == LLC_UI)
- && (lheader.llc_org_code[0] == 0)
- && (lheader.llc_org_code[1] == 0)
- && (lheader.llc_org_code[2] == 0)) {
- etype = lheader.llc_ether_type;
- }
- else
- etype = 0;
- /*
- * Figure out what kind of packet it is, and pass
- * it off to the appropriate filter.
- */
- pkt_dispatch(packet, bdcst, etype, tstamp);
- }
- #ifdef USE_LINUX
- /*
- * A DLT_LINUX_SLL fake link-layer header.
- */
- #define SLL_HDR_LEN 16 /* total header length */
- #define SLL_ADDRLEN 8 /* length of address field */
- #define LINUX_SLL_HOST 0
- #define LINUX_SLL_BROADCAST 1
- #define LINUX_SLL_MULTICAST 2
- #define LINUX_SLL_OTHERHOST 3
- #define LINUX_SLL_OUTGOING 4
- struct sll_header {
- u_int16_t sll_pkttype; /* packet type */
- u_int16_t sll_hatype; /* link-layer address type */
- u_int16_t sll_halen; /* link-layer address length */
- u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */
- u_int16_t sll_protocol; /* protocol */
- };
- /*
- * pkt_filter_sll - Parse LINUX_SLL header,
- * pass rest of packet to pkt_dispatch()
- */
- void
- pkt_filter_sll(char *cp, u_int length, struct timeval *tstamp)
- {
- char packet[PACKETSIZE];
- register int bdcst;
- struct sll_header sheader;
- /*
- * Extract the SLL header.
- */
- memcpy(&sheader, cp, sizeof(struct sll_header));
- memcpy(packet, cp + sizeof(struct sll_header),
- length - sizeof(struct sll_header));
- /*
- * See if it's a broadcast packet.
- */
- bdcst = ntohs(sheader.sll_pkttype) == LINUX_SLL_BROADCAST;
- /*
- * Figure out what kind of packet it is, and pass
- * it off to the appropriate filter.
- */
- pkt_dispatch(packet, bdcst, sheader.sll_protocol, tstamp);
- }
- #endif /* USE_LINUX */
- /*
- * pkt_dispatch - count a packet, and pass it off to the appropriate filter.
- * Caller tells us the Ethernet type code and if the packet
- * was a broadcast.
- */
- #ifdef SUNOS5
- void
- #else
- static void
- #endif
- /* packet: address of IP or ARP header */
- /* bdcst: was packet a LAN broadcast? */
- /* etype: still in network byte-order */
- pkt_dispatch(char *packet, int bdcst,
- u_short etype, struct timeval *tstamp)
- {
- struct ip *ip;
- struct ether_arp *arp;
- int sender, target;
- register int want;
- /*
- * Count this packet in the network totals.
- */
- int_pkt_total++;
- pkt_total++;
- /*
- * See if it's a broadcast packet, and count it if it is.
- */
- if (bdcst) {
- pkt_counters[PKT_BROADCAST].pc_interval++;
- pkt_counters[PKT_BROADCAST].pc_total++;
- }
- /*
- * Figure out what kind of packet it is, and pass
- * it off to the appropriate filter.
- */
- switch (ntohs(etype)) {
- case ETHERTYPE_IP: /* IP packet */
- ip = (struct ip *) packet;
- want = want_packet(ip->ip_src.s_addr, ip->ip_dst.s_addr);
- /*
- * If we want this packet, count it in the host
- * totals and pass it off.
- */
- if (bdcst || want) {
- int_dst_pkt_total++;
- dst_pkt_total++;
- ip_filter(ip, ip->ip_src.s_addr,
- ip->ip_dst.s_addr, tstamp);
- }
- break;
- case ETHERTYPE_ARP: /* Address Resolution Protocol */
- arp = (struct ether_arp *) packet;
- sender = (arp->arp_spa[0] << 24) +
- (arp->arp_spa[1] << 16) +
- (arp->arp_spa[2] << 8) +
- arp->arp_spa[3];
- target = (arp->arp_tpa[0] << 24) +
- (arp->arp_tpa[1] << 16) +
- (arp->arp_tpa[2] << 8) +
- arp->arp_tpa[3];
- want = want_packet(sender, target);
- /*
- * If we want this packet, count it in the host
- * totals and then count it in the packet
- * type counters.
- */
- if (bdcst || want) {
- int_dst_pkt_total++;
- dst_pkt_total++;
- pkt_counters[PKT_ARP].pc_interval++;
- pkt_counters[PKT_ARP].pc_total++;
- }
- break;
- case ETHERTYPE_REVARP: /* Reverse Addr Resol Protocol */
- arp = (struct ether_arp *) packet;
- sender = (arp->arp_spa[0] << 24) +
- (arp->arp_spa[1] << 16) +
- (arp->arp_spa[2] << 8) +
- arp->arp_spa[3];
- target = (arp->arp_tpa[0] << 24) +
- (arp->arp_tpa[1] << 16) +
- (arp->arp_tpa[2] << 8) +
- arp->arp_tpa[3];
- want = want_packet(sender, target);
- /*
- * If we want this packet, count it in the host
- * totals and then count it in the packet
- * type counters.
- */
- if (bdcst || want) {
- int_dst_pkt_total++;
- dst_pkt_total++;
- pkt_counters[PKT_RARP].pc_interval++;
- pkt_counters[PKT_RARP].pc_total++;
- }
- break;
- #ifdef notdef
- case ETHERTYPE_PUP: /* Xerox PUP */
- #endif
- default: /* who knows... */
- int_dst_pkt_total++;
- dst_pkt_total++;
- pkt_counters[PKT_OTHER].pc_interval++;
- pkt_counters[PKT_OTHER].pc_total++;
- break;
- }
- }
- /*
- * ip_filter - strip off the IP header and pass off to the appropriate
- * filter.
- */
- static void
- ip_filter(struct ip *ip, ipaddrt src, ipaddrt dst,
- struct timeval *tstamp)
- {
- register int *data;
- register int datalength;
- data = (int *) ip;
- data += ip->ip_hl;
- datalength = ntohs(ip->ip_len) - (4 * ip->ip_hl);
- /*
- * Figure out what kind of IP packet this is, and
- * pass it off to the appropriate filter.
- */
- switch (ip->ip_p) {
- case IPPROTO_TCP: /* transmission control protocol*/
- tcp_filter((struct tcphdr *) data, datalength,
- src, dst, tstamp);
- break;
- case IPPROTO_UDP: /* user datagram protocol */
- udp_filter((struct udphdr *) data,
- src, dst, tstamp);
- break;
- case IPPROTO_ICMP: /* control message protocol */
- icmp_filter();
- break;
- #ifdef notdef
- case IPPROTO_IGMP: /* group message protocol */
- case IPPROTO_GGP: /* gateway-gateway protocol */
- case IPPROTO_EGP: /* exterior gateway protocol */
- case IPPROTO_PUP: /* Xerox pup protocol */
- case IPPROTO_IDP: /* XNS IDP */
- #endif
- default: /* who knows... */
- break;
- }
- }
- /* We should get this from the services database... */
- #define NFS_PORT 2049
- /*
- * tcp_filter - count TCP packets, pass RPC packets to the RPC filter.
- */
- static void
- tcp_filter(struct tcphdr *tcp, u_int length, ipaddrt src, ipaddrt dst,
- struct timeval *tstamp)
- {
- unsigned short source = ntohs(tcp->th_sport);
- unsigned short dest = ntohs(tcp->th_dport);
- unsigned int hdr_len = tcp->th_off * 4;
- /*
- * Count as a TCP packet.
- */
- pkt_counters[PKT_TCP].pc_interval++;
- pkt_counters[PKT_TCP].pc_total++;
- hdr_len += 4; /* For some reason... */
- if (length < hdr_len)
- return;
- if (source == NFS_PORT
- || dest == NFS_PORT) {
- rpc_filter((char *) tcp + hdr_len, length - hdr_len,
- src, dst, tstamp);
- return;
- }
- if (rpcPortCnt > 0) {
- unsigned int i;
- for (i = 0; i < rpcPortCnt; i++) {
- if (dest == rpcPort[i]) {
- rpc_filter((char *) tcp + hdr_len, length - hdr_len,
- src, dst, tstamp);
- return;
- }
- }
- }
- }
- /*
- * udp_filter - count UDP packets, pass RPC packets to the RPC filter.
- */
- static void
- udp_filter(struct udphdr *udp, ipaddrt src, ipaddrt dst,
- struct timeval *tstamp)
- {
- unsigned short source = ntohs(udp->uh_sport);
- unsigned short dest = ntohs(udp->uh_dport);
- /*
- * Count as a UDP packet.
- */
- pkt_counters[PKT_UDP].pc_interval++;
- pkt_counters[PKT_UDP].pc_total++;
- if (source == IPPORT_ROUTESERVER
- || dest == IPPORT_ROUTESERVER) {
- pkt_counters[PKT_ROUTING].pc_interval++;
- pkt_counters[PKT_ROUTING].pc_total++;
- return;
- }
- if (source == NFS_PORT
- || dest == NFS_PORT) {
- rpc_filter((char *) udp + sizeof(struct udphdr),
- ntohs(udp->uh_ulen) - sizeof(struct udphdr),
- src, dst, tstamp);
- return;
- }
- if (rpcPortCnt > 0) {
- unsigned int i;
- for (i = 0; i < rpcPortCnt; i++) {
- if (dest == rpcPort[i]) {
- rpc_filter((char *) udp + sizeof(struct udphdr),
- ntohs(udp->uh_ulen) - sizeof(struct udphdr),
- src, dst, tstamp);
- return;
- }
- }
- }
- }
- /*
- * icmp_filter - count ICMP packets.
- */
- static void
- icmp_filter(void)
- {
- pkt_counters[PKT_ICMP].pc_interval++;
- pkt_counters[PKT_ICMP].pc_total++;
- }