]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libpcap/pcap-snoop.c
This commit was generated by cvs2svn to compensate for changes in r121330,
[FreeBSD/FreeBSD.git] / contrib / libpcap / pcap-snoop.c
1 /*
2  * Copyright (c) 1993, 1994, 1995, 1996, 1997
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the University of California,
13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21 #ifndef lint
22 static const char rcsid[] =
23     "@(#) $Header: /tcpdump/master/libpcap/pcap-snoop.c,v 1.33 2001/12/10 07:14:21 guy Exp $ (LBL)";
24 #endif
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <sys/param.h>
31 #include <sys/file.h>
32 #include <sys/ioctl.h>
33 #include <sys/socket.h>
34 #include <sys/time.h>
35
36 #include <net/raw.h>
37 #include <net/if.h>
38
39 #include <netinet/in.h>
40 #include <netinet/in_systm.h>
41 #include <netinet/ip.h>
42 #include <netinet/if_ether.h>
43 #include <netinet/ip_var.h>
44 #include <netinet/udp.h>
45 #include <netinet/udp_var.h>
46 #include <netinet/tcp.h>
47 #include <netinet/tcpip.h>
48
49 #include <errno.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54
55 #include "pcap-int.h"
56
57 #ifdef HAVE_OS_PROTO_H
58 #include "os-proto.h"
59 #endif
60
61 int
62 pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
63 {
64         int cc;
65         register struct snoopheader *sh;
66         register int datalen;
67         register int caplen;
68         register u_char *cp;
69
70 again:
71         cc = read(p->fd, (char *)p->buffer, p->bufsize);
72         if (cc < 0) {
73                 /* Don't choke when we get ptraced */
74                 switch (errno) {
75
76                 case EINTR:
77                                 goto again;
78
79                 case EWOULDBLOCK:
80                         return (0);                     /* XXX */
81                 }
82                 snprintf(p->errbuf, sizeof(p->errbuf),
83                     "read: %s", pcap_strerror(errno));
84                 return (-1);
85         }
86         sh = (struct snoopheader *)p->buffer;
87         datalen = sh->snoop_packetlen;
88         caplen = (datalen < p->snapshot) ? datalen : p->snapshot;
89         cp = (u_char *)(sh + 1) + p->offset;            /* XXX */
90
91         if (p->fcode.bf_insns == NULL ||
92             bpf_filter(p->fcode.bf_insns, cp, datalen, caplen)) {
93                 struct pcap_pkthdr h;
94                 ++p->md.stat.ps_recv;
95                 h.ts = sh->snoop_timestamp;
96                 h.len = datalen;
97                 h.caplen = caplen;
98                 (*callback)(user, &h, cp);
99                 return (1);
100         }
101         return (0);
102 }
103
104 int
105 pcap_stats(pcap_t *p, struct pcap_stat *ps)
106 {
107         register struct rawstats *rs;
108         struct rawstats rawstats;
109
110         rs = &rawstats;
111         memset(rs, 0, sizeof(*rs));
112         if (ioctl(p->fd, SIOCRAWSTATS, (char *)rs) < 0) {
113                 snprintf(p->errbuf, sizeof(p->errbuf),
114                     "SIOCRAWSTATS: %s", pcap_strerror(errno));
115                 return (-1);
116         }
117
118         /*
119          * "ifdrops" are those dropped by the network interface
120          * due to resource shortages or hardware errors.
121          *
122          * "sbdrops" are those dropped due to socket buffer limits.
123          *
124          * As filter is done in userland, "sbdrops" counts packets
125          * regardless of whether they would've passed the filter.
126          *
127          * XXX - does this count *all* Snoop or Drain sockets,
128          * rather than just this socket?  If not, why does it have
129          * both Snoop and Drain statistics?
130          */
131         p->md.stat.ps_drop =
132             rs->rs_snoop.ss_ifdrops + rs->rs_snoop.ss_sbdrops +
133             rs->rs_drain.ds_ifdrops + rs->rs_drain.ds_sbdrops;
134
135         /*
136          * "ps_recv" counts only packets that passed the filter.
137          * As filtering is done in userland, this does not include
138          * packets dropped because we ran out of buffer space.
139          */
140         *ps = p->md.stat;
141         return (0);
142 }
143
144 /* XXX can't disable promiscuous */
145 pcap_t *
146 pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
147 {
148         int fd;
149         struct sockaddr_raw sr;
150         struct snoopfilter sf;
151         u_int v;
152         int ll_hdrlen;
153         int snooplen;
154         pcap_t *p;
155         struct ifreq ifr;
156
157         p = (pcap_t *)malloc(sizeof(*p));
158         if (p == NULL) {
159                 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
160                     pcap_strerror(errno));
161                 return (NULL);
162         }
163         memset(p, 0, sizeof(*p));
164         fd = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP);
165         if (fd < 0) {
166                 snprintf(ebuf, PCAP_ERRBUF_SIZE, "snoop socket: %s",
167                     pcap_strerror(errno));
168                 goto bad;
169         }
170         p->fd = fd;
171         memset(&sr, 0, sizeof(sr));
172         sr.sr_family = AF_RAW;
173         (void)strncpy(sr.sr_ifname, device, sizeof(sr.sr_ifname));
174         if (bind(fd, (struct sockaddr *)&sr, sizeof(sr))) {
175                 snprintf(ebuf, PCAP_ERRBUF_SIZE, "snoop bind: %s",
176                     pcap_strerror(errno));
177                 goto bad;
178         }
179         memset(&sf, 0, sizeof(sf));
180         if (ioctl(fd, SIOCADDSNOOP, &sf) < 0) {
181                 snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCADDSNOOP: %s",
182                     pcap_strerror(errno));
183                 goto bad;
184         }
185         v = 64 * 1024;
186         (void)setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&v, sizeof(v));
187         /*
188          * XXX hack - map device name to link layer type
189          */
190         if (strncmp("et", device, 2) == 0 ||    /* Challenge 10 Mbit */
191             strncmp("ec", device, 2) == 0 ||    /* Indigo/Indy 10 Mbit,
192                                                    O2 10/100 */
193             strncmp("ef", device, 2) == 0 ||    /* O200/2000 10/100 Mbit */
194             strncmp("gfe", device, 3) == 0 ||   /* GIO 100 Mbit */
195             strncmp("fxp", device, 3) == 0 ||   /* Challenge VME Enet */
196             strncmp("ep", device, 2) == 0 ||    /* Challenge 8x10 Mbit EPLEX */
197             strncmp("vfe", device, 3) == 0 ||   /* Challenge VME 100Mbit */
198             strncmp("fa", device, 2) == 0 ||
199             strncmp("qaa", device, 3) == 0 ||
200             strncmp("cip", device, 3) == 0 ||
201             strncmp("el", device, 2) == 0) {
202                 p->linktype = DLT_EN10MB;
203                 p->offset = RAW_HDRPAD(sizeof(struct ether_header));
204                 ll_hdrlen = sizeof(struct ether_header);
205         } else if (strncmp("ipg", device, 3) == 0 ||
206                    strncmp("rns", device, 3) == 0 ||    /* O2/200/2000 FDDI */
207                    strncmp("xpi", device, 3) == 0) {
208                 p->linktype = DLT_FDDI;
209                 p->offset = 3;                          /* XXX yeah? */
210                 ll_hdrlen = 13;
211         } else if (strncmp("ppp", device, 3) == 0) {
212                 p->linktype = DLT_RAW;
213                 ll_hdrlen = 0;  /* DLT_RAW meaning "no PPP header, just the IP packet"? */
214         } else if (strncmp("lo", device, 2) == 0) {
215                 p->linktype = DLT_NULL;
216                 ll_hdrlen = 4;  /* is this just like BSD's loopback device? */
217         } else {
218                 snprintf(ebuf, PCAP_ERRBUF_SIZE,
219                     "snoop: unknown physical layer type");
220                 goto bad;
221         }
222 #ifdef SIOCGIFMTU
223         /*
224          * XXX - IRIX appears to give you an error if you try to set the
225          * capture length to be greater than the MTU, so let's try to get
226          * the MTU first and, if that succeeds, trim the snap length
227          * to be no greater than the MTU.
228          */
229         (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
230         if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) {
231                 snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCGIFMTU: %s",
232                     pcap_strerror(errno));
233                 goto bad;
234         }
235         /*
236          * OK, we got it.
237          *
238          * XXX - some versions of IRIX 6.5 define "ifr_mtu" and have an
239          * "ifru_metric" member of the "ifr_ifru" union in an "ifreq"
240          * structure, others don't.
241          *
242          * I've no idea what's going on, so, if "ifr_mtu" isn't defined,
243          * we define it as "ifr_metric", as using that field appears to
244          * work on the versions that lack "ifr_mtu" (and, on those that
245          * don't lack it, "ifru_metric" and "ifru_mtu" are both "int"
246          * members of the "ifr_ifru" union, which suggests that they
247          * may be interchangeable in this case).
248          */
249 #ifndef ifr_mtu
250 #define ifr_mtu ifr_metric
251 #endif
252         if (snaplen > ifr.ifr_mtu)
253                 snaplen = ifr.ifr_mtu;
254 #endif
255
256         /*
257          * The argument to SIOCSNOOPLEN is the number of link-layer
258          * payload bytes to capture - it doesn't count link-layer
259          * header bytes.
260          */
261         snooplen = snaplen - ll_hdrlen;
262         if (snooplen < 0)
263                 snooplen = 0;
264         if (ioctl(fd, SIOCSNOOPLEN, &snooplen) < 0) {
265                 snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCSNOOPLEN: %s",
266                     pcap_strerror(errno));
267                 goto bad;
268         }
269         p->snapshot = snaplen;
270         v = 1;
271         if (ioctl(fd, SIOCSNOOPING, &v) < 0) {
272                 snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCSNOOPING: %s",
273                     pcap_strerror(errno));
274                 goto bad;
275         }
276
277         p->bufsize = 4096;                              /* XXX */
278         p->buffer = (u_char *)malloc(p->bufsize);
279         if (p->buffer == NULL) {
280                 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
281                     pcap_strerror(errno));
282                 goto bad;
283         }
284
285         return (p);
286  bad:
287         (void)close(fd);
288         free(p);
289         return (NULL);
290 }
291
292 int
293 pcap_setfilter(pcap_t *p, struct bpf_program *fp)
294 {
295
296         if (install_bpf_program(p, fp) < 0)
297                 return (-1);
298         return (0);
299 }