pcap-snoop.c revision 147894
117683Spst/* 239291Sfenner * Copyright (c) 1993, 1994, 1995, 1996, 1997 317683Spst * The Regents of the University of California. All rights reserved. 417683Spst * 517683Spst * Redistribution and use in source and binary forms, with or without 617683Spst * modification, are permitted provided that: (1) source code distributions 717683Spst * retain the above copyright notice and this paragraph in its entirety, (2) 817683Spst * distributions including binary code include the above copyright notice and 917683Spst * this paragraph in its entirety in the documentation or other materials 1017683Spst * provided with the distribution, and (3) all advertising materials mentioning 1117683Spst * features or use of this software display the following acknowledgement: 1217683Spst * ``This product includes software developed by the University of California, 1317683Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1417683Spst * the University nor the names of its contributors may be used to endorse 1517683Spst * or promote products derived from this software without specific prior 1617683Spst * written permission. 1717683Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1817683Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1917683Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2017683Spst */ 2117683Spst#ifndef lint 22127664Sbmsstatic const char rcsid[] _U_ = 23147894Ssam "@(#) $Header: /tcpdump/master/libpcap/pcap-snoop.c,v 1.54.2.1 2005/05/03 18:54:38 guy Exp $ (LBL)"; 2417683Spst#endif 2517683Spst 2675107Sfenner#ifdef HAVE_CONFIG_H 2775107Sfenner#include "config.h" 2875107Sfenner#endif 2975107Sfenner 3017683Spst#include <sys/param.h> 3117683Spst#include <sys/file.h> 3217683Spst#include <sys/ioctl.h> 3317683Spst#include <sys/socket.h> 3417683Spst#include <sys/time.h> 3517683Spst 3617683Spst#include <net/raw.h> 3717683Spst#include <net/if.h> 3817683Spst 3917683Spst#include <netinet/in.h> 4017683Spst#include <netinet/in_systm.h> 4117683Spst#include <netinet/ip.h> 4217683Spst#include <netinet/if_ether.h> 4317683Spst#include <netinet/ip_var.h> 4417683Spst#include <netinet/udp.h> 4517683Spst#include <netinet/udp_var.h> 4617683Spst#include <netinet/tcp.h> 4717683Spst#include <netinet/tcpip.h> 4817683Spst 4917683Spst#include <errno.h> 5017683Spst#include <stdio.h> 5117683Spst#include <stdlib.h> 5217683Spst#include <string.h> 5317683Spst#include <unistd.h> 5417683Spst 5517683Spst#include "pcap-int.h" 5617683Spst 5717683Spst#ifdef HAVE_OS_PROTO_H 5817683Spst#include "os-proto.h" 5917683Spst#endif 6017683Spst 61127664Sbmsstatic int 62127664Sbmspcap_read_snoop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 6317683Spst{ 6417683Spst int cc; 6517683Spst register struct snoopheader *sh; 66146768Ssam register u_int datalen; 67146768Ssam register u_int caplen; 6817683Spst register u_char *cp; 6917683Spst 7017683Spstagain: 71127664Sbms /* 72127664Sbms * Has "pcap_breakloop()" been called? 73127664Sbms */ 74127664Sbms if (p->break_loop) { 75127664Sbms /* 76127664Sbms * Yes - clear the flag that indicates that it 77127664Sbms * has, and return -2 to indicate that we were 78127664Sbms * told to break out of the loop. 79127664Sbms */ 80127664Sbms p->break_loop = 0; 81127664Sbms return (-2); 82127664Sbms } 8317683Spst cc = read(p->fd, (char *)p->buffer, p->bufsize); 8417683Spst if (cc < 0) { 8517683Spst /* Don't choke when we get ptraced */ 8617683Spst switch (errno) { 8717683Spst 8817683Spst case EINTR: 89127664Sbms goto again; 9017683Spst 9117683Spst case EWOULDBLOCK: 9217683Spst return (0); /* XXX */ 9317683Spst } 9475107Sfenner snprintf(p->errbuf, sizeof(p->errbuf), 9575107Sfenner "read: %s", pcap_strerror(errno)); 9617683Spst return (-1); 9717683Spst } 9817683Spst sh = (struct snoopheader *)p->buffer; 9917683Spst datalen = sh->snoop_packetlen; 100146768Ssam 101146768Ssam /* 102146768Ssam * XXX - Sigh, snoop_packetlen is a 16 bit quantity. If we 103146768Ssam * got a short length, but read a full sized snoop pakcet, 104146768Ssam * assume we overflowed and add back the 64K... 105146768Ssam */ 106146768Ssam if (cc == (p->snapshot + sizeof(struct snoopheader)) && 107146768Ssam (datalen < p->snapshot)) 108146768Ssam datalen += (64 * 1024); 109146768Ssam 11017683Spst caplen = (datalen < p->snapshot) ? datalen : p->snapshot; 11117683Spst cp = (u_char *)(sh + 1) + p->offset; /* XXX */ 11217683Spst 113127664Sbms /* 114127664Sbms * XXX unfortunately snoop loopback isn't exactly like 115127664Sbms * BSD's. The address family is encoded in the first 2 116127664Sbms * bytes rather than the first 4 bytes! Luckily the last 117127664Sbms * two snoop loopback bytes are zeroed. 118127664Sbms */ 119127664Sbms if (p->linktype == DLT_NULL && *((short *)(cp + 2)) == 0) { 120127664Sbms u_int *uip = (u_int *)cp; 121127664Sbms *uip >>= 16; 122127664Sbms } 123127664Sbms 12417683Spst if (p->fcode.bf_insns == NULL || 12517683Spst bpf_filter(p->fcode.bf_insns, cp, datalen, caplen)) { 12617683Spst struct pcap_pkthdr h; 12717683Spst ++p->md.stat.ps_recv; 128127664Sbms h.ts.tv_sec = sh->snoop_timestamp.tv_sec; 129127664Sbms h.ts.tv_usec = sh->snoop_timestamp.tv_usec; 13017683Spst h.len = datalen; 13117683Spst h.caplen = caplen; 13217683Spst (*callback)(user, &h, cp); 13317683Spst return (1); 13417683Spst } 13517683Spst return (0); 13617683Spst} 13717683Spst 138127664Sbmsstatic int 139146768Ssampcap_inject_snoop(pcap_t *p, const void *buf, size_t size) 140146768Ssam{ 141146768Ssam int ret; 142146768Ssam 143146768Ssam /* 144146768Ssam * XXX - libnet overwrites the source address with what I 145146768Ssam * presume is the interface's address; is that required? 146146768Ssam */ 147146768Ssam ret = write(p->fd, buf, size); 148146768Ssam if (ret == -1) { 149146768Ssam snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", 150146768Ssam pcap_strerror(errno)); 151146768Ssam return (-1); 152146768Ssam } 153146768Ssam return (ret); 154146768Ssam} 155146768Ssam 156146768Ssamstatic int 157127664Sbmspcap_stats_snoop(pcap_t *p, struct pcap_stat *ps) 15817683Spst{ 15917683Spst register struct rawstats *rs; 16017683Spst struct rawstats rawstats; 16117683Spst 16217683Spst rs = &rawstats; 16375107Sfenner memset(rs, 0, sizeof(*rs)); 16417683Spst if (ioctl(p->fd, SIOCRAWSTATS, (char *)rs) < 0) { 16575107Sfenner snprintf(p->errbuf, sizeof(p->errbuf), 16675107Sfenner "SIOCRAWSTATS: %s", pcap_strerror(errno)); 16717683Spst return (-1); 16817683Spst } 16917683Spst 17098530Sfenner /* 17198530Sfenner * "ifdrops" are those dropped by the network interface 17298530Sfenner * due to resource shortages or hardware errors. 17398530Sfenner * 17498530Sfenner * "sbdrops" are those dropped due to socket buffer limits. 17598530Sfenner * 17698530Sfenner * As filter is done in userland, "sbdrops" counts packets 17798530Sfenner * regardless of whether they would've passed the filter. 17898530Sfenner * 17998530Sfenner * XXX - does this count *all* Snoop or Drain sockets, 18098530Sfenner * rather than just this socket? If not, why does it have 18198530Sfenner * both Snoop and Drain statistics? 18298530Sfenner */ 18317683Spst p->md.stat.ps_drop = 18417683Spst rs->rs_snoop.ss_ifdrops + rs->rs_snoop.ss_sbdrops + 18517683Spst rs->rs_drain.ds_ifdrops + rs->rs_drain.ds_sbdrops; 18617683Spst 18798530Sfenner /* 18898530Sfenner * "ps_recv" counts only packets that passed the filter. 18998530Sfenner * As filtering is done in userland, this does not include 19098530Sfenner * packets dropped because we ran out of buffer space. 19198530Sfenner */ 19217683Spst *ps = p->md.stat; 19317683Spst return (0); 19417683Spst} 19517683Spst 19617683Spst/* XXX can't disable promiscuous */ 19717683Spstpcap_t * 198127664Sbmspcap_open_live(const char *device, int snaplen, int promisc, int to_ms, 199127664Sbms char *ebuf) 20017683Spst{ 20117683Spst int fd; 20217683Spst struct sockaddr_raw sr; 20317683Spst struct snoopfilter sf; 20417683Spst u_int v; 20575107Sfenner int ll_hdrlen; 20675107Sfenner int snooplen; 20717683Spst pcap_t *p; 20875107Sfenner struct ifreq ifr; 20917683Spst 21017683Spst p = (pcap_t *)malloc(sizeof(*p)); 21117683Spst if (p == NULL) { 21275107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", 21375107Sfenner pcap_strerror(errno)); 21417683Spst return (NULL); 21517683Spst } 21675107Sfenner memset(p, 0, sizeof(*p)); 21717683Spst fd = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP); 21817683Spst if (fd < 0) { 21975107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "snoop socket: %s", 22075107Sfenner pcap_strerror(errno)); 22117683Spst goto bad; 22217683Spst } 22317683Spst p->fd = fd; 22475107Sfenner memset(&sr, 0, sizeof(sr)); 22517683Spst sr.sr_family = AF_RAW; 22617683Spst (void)strncpy(sr.sr_ifname, device, sizeof(sr.sr_ifname)); 22717683Spst if (bind(fd, (struct sockaddr *)&sr, sizeof(sr))) { 22875107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "snoop bind: %s", 22975107Sfenner pcap_strerror(errno)); 23017683Spst goto bad; 23117683Spst } 23275107Sfenner memset(&sf, 0, sizeof(sf)); 23317683Spst if (ioctl(fd, SIOCADDSNOOP, &sf) < 0) { 23475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCADDSNOOP: %s", 23575107Sfenner pcap_strerror(errno)); 23617683Spst goto bad; 23717683Spst } 23817683Spst v = 64 * 1024; 23917683Spst (void)setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&v, sizeof(v)); 24017683Spst /* 24117683Spst * XXX hack - map device name to link layer type 24217683Spst */ 24339291Sfenner if (strncmp("et", device, 2) == 0 || /* Challenge 10 Mbit */ 24439291Sfenner strncmp("ec", device, 2) == 0 || /* Indigo/Indy 10 Mbit, 24539291Sfenner O2 10/100 */ 24639291Sfenner strncmp("ef", device, 2) == 0 || /* O200/2000 10/100 Mbit */ 247127664Sbms strncmp("eg", device, 2) == 0 || /* Octane/O2xxx/O3xxx Gigabit */ 24839291Sfenner strncmp("gfe", device, 3) == 0 || /* GIO 100 Mbit */ 24939291Sfenner strncmp("fxp", device, 3) == 0 || /* Challenge VME Enet */ 25039291Sfenner strncmp("ep", device, 2) == 0 || /* Challenge 8x10 Mbit EPLEX */ 25139291Sfenner strncmp("vfe", device, 3) == 0 || /* Challenge VME 100Mbit */ 25239291Sfenner strncmp("fa", device, 2) == 0 || 25375107Sfenner strncmp("qaa", device, 3) == 0 || 25498530Sfenner strncmp("cip", device, 3) == 0 || 25575107Sfenner strncmp("el", device, 2) == 0) { 25617683Spst p->linktype = DLT_EN10MB; 25717683Spst p->offset = RAW_HDRPAD(sizeof(struct ether_header)); 25875107Sfenner ll_hdrlen = sizeof(struct ether_header); 259146768Ssam /* 260146768Ssam * This is (presumably) a real Ethernet capture; give it a 261146768Ssam * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so 262146768Ssam * that an application can let you choose it, in case you're 263146768Ssam * capturing DOCSIS traffic that a Cisco Cable Modem 264146768Ssam * Termination System is putting out onto an Ethernet (it 265146768Ssam * doesn't put an Ethernet header onto the wire, it puts raw 266146768Ssam * DOCSIS frames out on the wire inside the low-level 267146768Ssam * Ethernet framing). 268146768Ssam * 269146768Ssam * XXX - are there any sorts of "fake Ethernet" that have 270146768Ssam * Ethernet link-layer headers but that *shouldn't offer 271146768Ssam * DLT_DOCSIS as a Cisco CMTS won't put traffic onto it 272146768Ssam * or get traffic bridged onto it? "el" is for ATM LANE 273146768Ssam * Ethernet devices, so that might be the case for them; 274146768Ssam * the same applies for "qaa" classical IP devices. If 275146768Ssam * "fa" devices are for FORE SPANS, that'd apply to them 276146768Ssam * as well; what are "cip" devices - some other ATM 277146768Ssam * Classical IP devices? 278146768Ssam */ 279146768Ssam p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); 280146768Ssam /* 281146768Ssam * If that fails, just leave the list empty. 282146768Ssam */ 283146768Ssam if (p->dlt_list != NULL) { 284146768Ssam p->dlt_list[0] = DLT_EN10MB; 285146768Ssam p->dlt_list[1] = DLT_DOCSIS; 286146768Ssam p->dlt_count = 2; 287146768Ssam } 28817683Spst } else if (strncmp("ipg", device, 3) == 0 || 28939291Sfenner strncmp("rns", device, 3) == 0 || /* O2/200/2000 FDDI */ 29017683Spst strncmp("xpi", device, 3) == 0) { 29117683Spst p->linktype = DLT_FDDI; 29217683Spst p->offset = 3; /* XXX yeah? */ 29375107Sfenner ll_hdrlen = 13; 29439291Sfenner } else if (strncmp("ppp", device, 3) == 0) { 29539291Sfenner p->linktype = DLT_RAW; 29675107Sfenner ll_hdrlen = 0; /* DLT_RAW meaning "no PPP header, just the IP packet"? */ 297127664Sbms } else if (strncmp("qfa", device, 3) == 0) { 298127664Sbms p->linktype = DLT_IP_OVER_FC; 299127664Sbms ll_hdrlen = 24; 300127664Sbms } else if (strncmp("pl", device, 2) == 0) { 301127664Sbms p->linktype = DLT_RAW; 302127664Sbms ll_hdrlen = 0; /* Cray UNICOS/mp pseudo link */ 30317683Spst } else if (strncmp("lo", device, 2) == 0) { 30417683Spst p->linktype = DLT_NULL; 305127664Sbms ll_hdrlen = 4; 30617683Spst } else { 30775107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 30875107Sfenner "snoop: unknown physical layer type"); 30917683Spst goto bad; 31017683Spst } 31175107Sfenner#ifdef SIOCGIFMTU 31275107Sfenner /* 31375107Sfenner * XXX - IRIX appears to give you an error if you try to set the 31475107Sfenner * capture length to be greater than the MTU, so let's try to get 31575107Sfenner * the MTU first and, if that succeeds, trim the snap length 31675107Sfenner * to be no greater than the MTU. 31775107Sfenner */ 31875107Sfenner (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); 31975107Sfenner if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) { 32075107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCGIFMTU: %s", 32175107Sfenner pcap_strerror(errno)); 32275107Sfenner goto bad; 32375107Sfenner } 32475107Sfenner /* 32575107Sfenner * OK, we got it. 32675107Sfenner * 32775107Sfenner * XXX - some versions of IRIX 6.5 define "ifr_mtu" and have an 32875107Sfenner * "ifru_metric" member of the "ifr_ifru" union in an "ifreq" 32975107Sfenner * structure, others don't. 33075107Sfenner * 33175107Sfenner * I've no idea what's going on, so, if "ifr_mtu" isn't defined, 33275107Sfenner * we define it as "ifr_metric", as using that field appears to 33375107Sfenner * work on the versions that lack "ifr_mtu" (and, on those that 33475107Sfenner * don't lack it, "ifru_metric" and "ifru_mtu" are both "int" 33575107Sfenner * members of the "ifr_ifru" union, which suggests that they 33675107Sfenner * may be interchangeable in this case). 33775107Sfenner */ 33875107Sfenner#ifndef ifr_mtu 33975107Sfenner#define ifr_mtu ifr_metric 34075107Sfenner#endif 341127664Sbms if (snaplen > ifr.ifr_mtu + ll_hdrlen) 342127664Sbms snaplen = ifr.ifr_mtu + ll_hdrlen; 34375107Sfenner#endif 34417683Spst 34575107Sfenner /* 34675107Sfenner * The argument to SIOCSNOOPLEN is the number of link-layer 34775107Sfenner * payload bytes to capture - it doesn't count link-layer 34875107Sfenner * header bytes. 34975107Sfenner */ 35075107Sfenner snooplen = snaplen - ll_hdrlen; 35175107Sfenner if (snooplen < 0) 35275107Sfenner snooplen = 0; 35375107Sfenner if (ioctl(fd, SIOCSNOOPLEN, &snooplen) < 0) { 35475107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCSNOOPLEN: %s", 35575107Sfenner pcap_strerror(errno)); 35675107Sfenner goto bad; 35775107Sfenner } 35875107Sfenner p->snapshot = snaplen; 35975107Sfenner v = 1; 36075107Sfenner if (ioctl(fd, SIOCSNOOPING, &v) < 0) { 36175107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCSNOOPING: %s", 36275107Sfenner pcap_strerror(errno)); 36375107Sfenner goto bad; 36475107Sfenner } 36575107Sfenner 36617683Spst p->bufsize = 4096; /* XXX */ 36717683Spst p->buffer = (u_char *)malloc(p->bufsize); 36817683Spst if (p->buffer == NULL) { 36975107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", 37075107Sfenner pcap_strerror(errno)); 37117683Spst goto bad; 37217683Spst } 37317683Spst 374127664Sbms /* 375127664Sbms * "p->fd" is a socket, so "select()" should work on it. 376127664Sbms */ 377127664Sbms p->selectable_fd = p->fd; 378127664Sbms 379127664Sbms p->read_op = pcap_read_snoop; 380146768Ssam p->inject_op = pcap_inject_snoop; 381127664Sbms p->setfilter_op = install_bpf_program; /* no kernel filtering */ 382147894Ssam p->setdirection_op = NULL; /* Not implemented. */ 383127664Sbms p->set_datalink_op = NULL; /* can't change data link type */ 384127664Sbms p->getnonblock_op = pcap_getnonblock_fd; 385127664Sbms p->setnonblock_op = pcap_setnonblock_fd; 386127664Sbms p->stats_op = pcap_stats_snoop; 387146768Ssam p->close_op = pcap_close_common; 388127664Sbms 38917683Spst return (p); 39017683Spst bad: 39117683Spst (void)close(fd); 392146768Ssam /* 393146768Ssam * Get rid of any link-layer type list we allocated. 394146768Ssam */ 395146768Ssam if (p->dlt_list != NULL) 396146768Ssam free(p->dlt_list); 39717683Spst free(p); 39817683Spst return (NULL); 39917683Spst} 40017683Spst 40117683Spstint 402127664Sbmspcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) 40317683Spst{ 40417683Spst return (0); 40517683Spst} 406