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