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_ = 23214518Srpaulo "@(#) $Header: /tcpdump/master/libpcap/pcap-snoop.c,v 1.59 2008-12-02 16:25:14 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 103240725Skevlo * got a short length, but read a full sized snoop packet, 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 */ 197190225Srpaulostatic int 198190225Srpaulopcap_activate_snoop(pcap_t *p) 19917683Spst{ 20017683Spst int fd; 20117683Spst struct sockaddr_raw sr; 20217683Spst struct snoopfilter sf; 20317683Spst u_int v; 20475107Sfenner int ll_hdrlen; 20575107Sfenner int snooplen; 20675107Sfenner struct ifreq ifr; 20717683Spst 20817683Spst fd = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP); 20917683Spst if (fd < 0) { 210190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snoop socket: %s", 21175107Sfenner pcap_strerror(errno)); 21217683Spst goto bad; 21317683Spst } 21417683Spst p->fd = fd; 21575107Sfenner memset(&sr, 0, sizeof(sr)); 21617683Spst sr.sr_family = AF_RAW; 217190225Srpaulo (void)strncpy(sr.sr_ifname, p->opt.source, sizeof(sr.sr_ifname)); 21817683Spst if (bind(fd, (struct sockaddr *)&sr, sizeof(sr))) { 219190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snoop bind: %s", 22075107Sfenner pcap_strerror(errno)); 22117683Spst goto bad; 22217683Spst } 22375107Sfenner memset(&sf, 0, sizeof(sf)); 22417683Spst if (ioctl(fd, SIOCADDSNOOP, &sf) < 0) { 225190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCADDSNOOP: %s", 22675107Sfenner pcap_strerror(errno)); 22717683Spst goto bad; 22817683Spst } 229214518Srpaulo if (p->opt.buffer_size != 0) 230214518Srpaulo v = p->opt.buffer_size; 231190225Srpaulo else 232190225Srpaulo v = 64 * 1024; /* default to 64K buffer size */ 23317683Spst (void)setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&v, sizeof(v)); 23417683Spst /* 23517683Spst * XXX hack - map device name to link layer type 23617683Spst */ 237190225Srpaulo if (strncmp("et", p->opt.source, 2) == 0 || /* Challenge 10 Mbit */ 238190225Srpaulo strncmp("ec", p->opt.source, 2) == 0 || /* Indigo/Indy 10 Mbit, 239190225Srpaulo O2 10/100 */ 240190225Srpaulo strncmp("ef", p->opt.source, 2) == 0 || /* O200/2000 10/100 Mbit */ 241190225Srpaulo strncmp("eg", p->opt.source, 2) == 0 || /* Octane/O2xxx/O3xxx Gigabit */ 242190225Srpaulo strncmp("gfe", p->opt.source, 3) == 0 || /* GIO 100 Mbit */ 243190225Srpaulo strncmp("fxp", p->opt.source, 3) == 0 || /* Challenge VME Enet */ 244190225Srpaulo strncmp("ep", p->opt.source, 2) == 0 || /* Challenge 8x10 Mbit EPLEX */ 245190225Srpaulo strncmp("vfe", p->opt.source, 3) == 0 || /* Challenge VME 100Mbit */ 246190225Srpaulo strncmp("fa", p->opt.source, 2) == 0 || 247190225Srpaulo strncmp("qaa", p->opt.source, 3) == 0 || 248190225Srpaulo strncmp("cip", p->opt.source, 3) == 0 || 249190225Srpaulo strncmp("el", p->opt.source, 2) == 0) { 25017683Spst p->linktype = DLT_EN10MB; 25117683Spst p->offset = RAW_HDRPAD(sizeof(struct ether_header)); 25275107Sfenner ll_hdrlen = sizeof(struct ether_header); 253146768Ssam /* 254146768Ssam * This is (presumably) a real Ethernet capture; give it a 255146768Ssam * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so 256146768Ssam * that an application can let you choose it, in case you're 257146768Ssam * capturing DOCSIS traffic that a Cisco Cable Modem 258146768Ssam * Termination System is putting out onto an Ethernet (it 259146768Ssam * doesn't put an Ethernet header onto the wire, it puts raw 260146768Ssam * DOCSIS frames out on the wire inside the low-level 261146768Ssam * Ethernet framing). 262146768Ssam * 263146768Ssam * XXX - are there any sorts of "fake Ethernet" that have 264146768Ssam * Ethernet link-layer headers but that *shouldn't offer 265146768Ssam * DLT_DOCSIS as a Cisco CMTS won't put traffic onto it 266146768Ssam * or get traffic bridged onto it? "el" is for ATM LANE 267146768Ssam * Ethernet devices, so that might be the case for them; 268146768Ssam * the same applies for "qaa" classical IP devices. If 269146768Ssam * "fa" devices are for FORE SPANS, that'd apply to them 270146768Ssam * as well; what are "cip" devices - some other ATM 271146768Ssam * Classical IP devices? 272146768Ssam */ 273146768Ssam p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); 274146768Ssam /* 275146768Ssam * If that fails, just leave the list empty. 276146768Ssam */ 277146768Ssam if (p->dlt_list != NULL) { 278146768Ssam p->dlt_list[0] = DLT_EN10MB; 279146768Ssam p->dlt_list[1] = DLT_DOCSIS; 280146768Ssam p->dlt_count = 2; 281146768Ssam } 282190225Srpaulo } else if (strncmp("ipg", p->opt.source, 3) == 0 || 283190225Srpaulo strncmp("rns", p->opt.source, 3) == 0 || /* O2/200/2000 FDDI */ 284190225Srpaulo strncmp("xpi", p->opt.source, 3) == 0) { 28517683Spst p->linktype = DLT_FDDI; 28617683Spst p->offset = 3; /* XXX yeah? */ 28775107Sfenner ll_hdrlen = 13; 288190225Srpaulo } else if (strncmp("ppp", p->opt.source, 3) == 0) { 28939291Sfenner p->linktype = DLT_RAW; 29075107Sfenner ll_hdrlen = 0; /* DLT_RAW meaning "no PPP header, just the IP packet"? */ 291190225Srpaulo } else if (strncmp("qfa", p->opt.source, 3) == 0) { 292127664Sbms p->linktype = DLT_IP_OVER_FC; 293127664Sbms ll_hdrlen = 24; 294190225Srpaulo } else if (strncmp("pl", p->opt.source, 2) == 0) { 295127664Sbms p->linktype = DLT_RAW; 296127664Sbms ll_hdrlen = 0; /* Cray UNICOS/mp pseudo link */ 297190225Srpaulo } else if (strncmp("lo", p->opt.source, 2) == 0) { 29817683Spst p->linktype = DLT_NULL; 299127664Sbms ll_hdrlen = 4; 30017683Spst } else { 301190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 30275107Sfenner "snoop: unknown physical layer type"); 30317683Spst goto bad; 30417683Spst } 305190225Srpaulo 306190225Srpaulo if (p->opt.rfmon) { 307190225Srpaulo /* 308190225Srpaulo * No monitor mode on Irix (no Wi-Fi devices on 309190225Srpaulo * hardware supported by Irix). 310190225Srpaulo */ 311190225Srpaulo return (PCAP_ERROR_RFMON_NOTSUP); 312190225Srpaulo } 313190225Srpaulo 31475107Sfenner#ifdef SIOCGIFMTU 31575107Sfenner /* 31675107Sfenner * XXX - IRIX appears to give you an error if you try to set the 31775107Sfenner * capture length to be greater than the MTU, so let's try to get 31875107Sfenner * the MTU first and, if that succeeds, trim the snap length 31975107Sfenner * to be no greater than the MTU. 32075107Sfenner */ 321190225Srpaulo (void)strncpy(ifr.ifr_name, p->opt.source, sizeof(ifr.ifr_name)); 32275107Sfenner if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) { 323190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFMTU: %s", 32475107Sfenner pcap_strerror(errno)); 32575107Sfenner goto bad; 32675107Sfenner } 32775107Sfenner /* 32875107Sfenner * OK, we got it. 32975107Sfenner * 33075107Sfenner * XXX - some versions of IRIX 6.5 define "ifr_mtu" and have an 33175107Sfenner * "ifru_metric" member of the "ifr_ifru" union in an "ifreq" 33275107Sfenner * structure, others don't. 33375107Sfenner * 33475107Sfenner * I've no idea what's going on, so, if "ifr_mtu" isn't defined, 33575107Sfenner * we define it as "ifr_metric", as using that field appears to 33675107Sfenner * work on the versions that lack "ifr_mtu" (and, on those that 33775107Sfenner * don't lack it, "ifru_metric" and "ifru_mtu" are both "int" 33875107Sfenner * members of the "ifr_ifru" union, which suggests that they 33975107Sfenner * may be interchangeable in this case). 34075107Sfenner */ 34175107Sfenner#ifndef ifr_mtu 34275107Sfenner#define ifr_mtu ifr_metric 34375107Sfenner#endif 344190225Srpaulo if (p->snapshot > ifr.ifr_mtu + ll_hdrlen) 345190225Srpaulo p->snapshot = ifr.ifr_mtu + ll_hdrlen; 34675107Sfenner#endif 34717683Spst 34875107Sfenner /* 34975107Sfenner * The argument to SIOCSNOOPLEN is the number of link-layer 35075107Sfenner * payload bytes to capture - it doesn't count link-layer 35175107Sfenner * header bytes. 35275107Sfenner */ 353190225Srpaulo snooplen = p->snapshot - ll_hdrlen; 35475107Sfenner if (snooplen < 0) 35575107Sfenner snooplen = 0; 35675107Sfenner if (ioctl(fd, SIOCSNOOPLEN, &snooplen) < 0) { 357190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCSNOOPLEN: %s", 35875107Sfenner pcap_strerror(errno)); 35975107Sfenner goto bad; 36075107Sfenner } 36175107Sfenner v = 1; 36275107Sfenner if (ioctl(fd, SIOCSNOOPING, &v) < 0) { 363190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCSNOOPING: %s", 36475107Sfenner pcap_strerror(errno)); 36575107Sfenner goto bad; 36675107Sfenner } 36775107Sfenner 36817683Spst p->bufsize = 4096; /* XXX */ 36917683Spst p->buffer = (u_char *)malloc(p->bufsize); 37017683Spst if (p->buffer == NULL) { 371190225Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", 37275107Sfenner pcap_strerror(errno)); 37317683Spst goto bad; 37417683Spst } 37517683Spst 376127664Sbms /* 377127664Sbms * "p->fd" is a socket, so "select()" should work on it. 378127664Sbms */ 379127664Sbms p->selectable_fd = p->fd; 380127664Sbms 381127664Sbms p->read_op = pcap_read_snoop; 382146768Ssam p->inject_op = pcap_inject_snoop; 383127664Sbms p->setfilter_op = install_bpf_program; /* no kernel filtering */ 384147894Ssam p->setdirection_op = NULL; /* Not implemented. */ 385127664Sbms p->set_datalink_op = NULL; /* can't change data link type */ 386127664Sbms p->getnonblock_op = pcap_getnonblock_fd; 387127664Sbms p->setnonblock_op = pcap_setnonblock_fd; 388127664Sbms p->stats_op = pcap_stats_snoop; 389127664Sbms 390190225Srpaulo return (0); 39117683Spst bad: 392214518Srpaulo pcap_cleanup_live_common(p); 393190225Srpaulo return (PCAP_ERROR); 39417683Spst} 39517683Spst 396190225Srpaulopcap_t * 397251129Sdelphijpcap_create_interface(const char *device, char *ebuf) 398190225Srpaulo{ 399190225Srpaulo pcap_t *p; 400190225Srpaulo 401190225Srpaulo p = pcap_create_common(device, ebuf); 402190225Srpaulo if (p == NULL) 403190225Srpaulo return (NULL); 404190225Srpaulo 405190225Srpaulo p->activate_op = pcap_activate_snoop; 406190225Srpaulo return (p); 407190225Srpaulo} 408190225Srpaulo 40917683Spstint 410127664Sbmspcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) 41117683Spst{ 41217683Spst return (0); 41317683Spst} 414