pcap-snoop.c revision 39291
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1993, 1994, 1995, 1996, 1997 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that: (1) source code distributions 71541Srgrimes * retain the above copyright notice and this paragraph in its entirety, (2) 81541Srgrimes * distributions including binary code include the above copyright notice and 91541Srgrimes * this paragraph in its entirety in the documentation or other materials 101541Srgrimes * provided with the distribution, and (3) all advertising materials mentioning 111541Srgrimes * features or use of this software display the following acknowledgement: 121541Srgrimes * ``This product includes software developed by the University of California, 131541Srgrimes * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 141541Srgrimes * the University nor the names of its contributors may be used to endorse 151541Srgrimes * or promote products derived from this software without specific prior 161541Srgrimes * written permission. 171541Srgrimes * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 181541Srgrimes * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 191541Srgrimes * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 201541Srgrimes */ 211541Srgrimes#ifndef lint 221541Srgrimesstatic const char rcsid[] = 231541Srgrimes "@(#) $Header: pcap-snoop.c,v 1.20 97/04/08 21:06:17 leres Exp $ (LBL)"; 241541Srgrimes#endif 251541Srgrimes 261541Srgrimes#include <sys/param.h> 271541Srgrimes#include <sys/file.h> 281541Srgrimes#include <sys/ioctl.h> 291541Srgrimes#include <sys/socket.h> 301541Srgrimes#include <sys/time.h> 311541Srgrimes 321541Srgrimes#include <net/raw.h> 331541Srgrimes#include <net/if.h> 341541Srgrimes 351541Srgrimes#include <netinet/in.h> 361541Srgrimes#include <netinet/in_systm.h> 371541Srgrimes#include <netinet/ip.h> 381541Srgrimes#include <netinet/if_ether.h> 391541Srgrimes#include <netinet/ip_var.h> 401541Srgrimes#include <netinet/udp.h> 411541Srgrimes#include <netinet/udp_var.h> 421541Srgrimes#include <netinet/tcp.h> 431541Srgrimes#include <netinet/tcpip.h> 441541Srgrimes 451541Srgrimes#include <errno.h> 461541Srgrimes#include <stdio.h> 471541Srgrimes#include <stdlib.h> 481541Srgrimes#include <string.h> 491541Srgrimes#include <unistd.h> 501541Srgrimes 511541Srgrimes#include "pcap-int.h" 521541Srgrimes 531541Srgrimes#include "gnuc.h" 541541Srgrimes#ifdef HAVE_OS_PROTO_H 551541Srgrimes#include "os-proto.h" 561541Srgrimes#endif 571541Srgrimes 581541Srgrimesint 591541Srgrimespcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 601541Srgrimes{ 611541Srgrimes int cc; 621541Srgrimes register struct snoopheader *sh; 63 register int datalen; 64 register int caplen; 65 register u_char *cp; 66 67again: 68 cc = read(p->fd, (char *)p->buffer, p->bufsize); 69 if (cc < 0) { 70 /* Don't choke when we get ptraced */ 71 switch (errno) { 72 73 case EINTR: 74 goto again; 75 76 case EWOULDBLOCK: 77 return (0); /* XXX */ 78 } 79 sprintf(p->errbuf, "read: %s", pcap_strerror(errno)); 80 return (-1); 81 } 82 sh = (struct snoopheader *)p->buffer; 83 datalen = sh->snoop_packetlen; 84 caplen = (datalen < p->snapshot) ? datalen : p->snapshot; 85 cp = (u_char *)(sh + 1) + p->offset; /* XXX */ 86 87 if (p->fcode.bf_insns == NULL || 88 bpf_filter(p->fcode.bf_insns, cp, datalen, caplen)) { 89 struct pcap_pkthdr h; 90 ++p->md.stat.ps_recv; 91 h.ts = sh->snoop_timestamp; 92 h.len = datalen; 93 h.caplen = caplen; 94 (*callback)(user, &h, cp); 95 return (1); 96 } 97 return (0); 98} 99 100int 101pcap_stats(pcap_t *p, struct pcap_stat *ps) 102{ 103 register struct rawstats *rs; 104 struct rawstats rawstats; 105 106 rs = &rawstats; 107 bzero((char *)rs, sizeof(*rs)); 108 if (ioctl(p->fd, SIOCRAWSTATS, (char *)rs) < 0) { 109 sprintf(p->errbuf, "SIOCRAWSTATS: %s", pcap_strerror(errno)); 110 return (-1); 111 } 112 113 p->md.stat.ps_drop = 114 rs->rs_snoop.ss_ifdrops + rs->rs_snoop.ss_sbdrops + 115 rs->rs_drain.ds_ifdrops + rs->rs_drain.ds_sbdrops; 116 117 *ps = p->md.stat; 118 return (0); 119} 120 121/* XXX can't disable promiscuous */ 122pcap_t * 123pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) 124{ 125 int fd; 126 struct sockaddr_raw sr; 127 struct snoopfilter sf; 128 u_int v; 129 pcap_t *p; 130 131 p = (pcap_t *)malloc(sizeof(*p)); 132 if (p == NULL) { 133 sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); 134 return (NULL); 135 } 136 bzero((char *)p, sizeof(*p)); 137 fd = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP); 138 if (fd < 0) { 139 sprintf(ebuf, "snoop socket: %s", pcap_strerror(errno)); 140 goto bad; 141 } 142 p->fd = fd; 143 bzero((char *)&sr, sizeof(sr)); 144 sr.sr_family = AF_RAW; 145 (void)strncpy(sr.sr_ifname, device, sizeof(sr.sr_ifname)); 146 if (bind(fd, (struct sockaddr *)&sr, sizeof(sr))) { 147 sprintf(ebuf, "snoop bind: %s", pcap_strerror(errno)); 148 goto bad; 149 } 150 bzero((char *)&sf, sizeof(sf)); 151 if (ioctl(fd, SIOCADDSNOOP, &sf) < 0) { 152 sprintf(ebuf, "SIOCADDSNOOP: %s", pcap_strerror(errno)); 153 goto bad; 154 } 155 v = 64 * 1024; 156 (void)setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&v, sizeof(v)); 157 if (ioctl(fd, SIOCSNOOPLEN, &snaplen) < 0) { 158 sprintf(ebuf, "SIOCSNOOPLEN: %s", pcap_strerror(errno)); 159 goto bad; 160 } 161 p->snapshot = snaplen; 162 v = 1; 163 if (ioctl(fd, SIOCSNOOPING, &v) < 0) { 164 sprintf(ebuf, "SIOCSNOOPING: %s", pcap_strerror(errno)); 165 goto bad; 166 } 167 /* 168 * XXX hack - map device name to link layer type 169 */ 170 if (strncmp("et", device, 2) == 0 || /* Challenge 10 Mbit */ 171 strncmp("ec", device, 2) == 0 || /* Indigo/Indy 10 Mbit, 172 O2 10/100 */ 173 strncmp("ef", device, 2) == 0 || /* O200/2000 10/100 Mbit */ 174 strncmp("gfe", device, 3) == 0 || /* GIO 100 Mbit */ 175 strncmp("fxp", device, 3) == 0 || /* Challenge VME Enet */ 176 strncmp("ep", device, 2) == 0 || /* Challenge 8x10 Mbit EPLEX */ 177 strncmp("vfe", device, 3) == 0 || /* Challenge VME 100Mbit */ 178 strncmp("fa", device, 2) == 0 || 179 strncmp("qaa", device, 3) == 0) { 180 p->linktype = DLT_EN10MB; 181 p->offset = RAW_HDRPAD(sizeof(struct ether_header)); 182 } else if (strncmp("ipg", device, 3) == 0 || 183 strncmp("rns", device, 3) == 0 || /* O2/200/2000 FDDI */ 184 strncmp("xpi", device, 3) == 0) { 185 p->linktype = DLT_FDDI; 186 p->offset = 3; /* XXX yeah? */ 187 } else if (strncmp("ppp", device, 3) == 0) { 188 p->linktype = DLT_RAW; 189 } else if (strncmp("lo", device, 2) == 0) { 190 p->linktype = DLT_NULL; 191 } else { 192 sprintf(ebuf, "snoop: unknown physical layer type"); 193 goto bad; 194 } 195 196 p->bufsize = 4096; /* XXX */ 197 p->buffer = (u_char *)malloc(p->bufsize); 198 if (p->buffer == NULL) { 199 sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); 200 goto bad; 201 } 202 203 return (p); 204 bad: 205 (void)close(fd); 206 free(p); 207 return (NULL); 208} 209 210int 211pcap_setfilter(pcap_t *p, struct bpf_program *fp) 212{ 213 214 p->fcode = *fp; 215 return (0); 216} 217