]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libpcap/pcap-snoop.c
This commit was generated by cvs2svn to compensate for changes in r95415,
[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.30 2000/10/28 00:01:30 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         p->md.stat.ps_drop =
119             rs->rs_snoop.ss_ifdrops + rs->rs_snoop.ss_sbdrops +
120             rs->rs_drain.ds_ifdrops + rs->rs_drain.ds_sbdrops;
121
122         *ps = p->md.stat;
123         return (0);
124 }
125
126 /* XXX can't disable promiscuous */
127 pcap_t *
128 pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
129 {
130         int fd;
131         struct sockaddr_raw sr;
132         struct snoopfilter sf;
133         u_int v;
134         int ll_hdrlen;
135         int snooplen;
136         pcap_t *p;
137         struct ifreq ifr;
138
139         p = (pcap_t *)malloc(sizeof(*p));
140         if (p == NULL) {
141                 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
142                     pcap_strerror(errno));
143                 return (NULL);
144         }
145         memset(p, 0, sizeof(*p));
146         fd = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP);
147         if (fd < 0) {
148                 snprintf(ebuf, PCAP_ERRBUF_SIZE, "snoop socket: %s",
149                     pcap_strerror(errno));
150                 goto bad;
151         }
152         p->fd = fd;
153         memset(&sr, 0, sizeof(sr));
154         sr.sr_family = AF_RAW;
155         (void)strncpy(sr.sr_ifname, device, sizeof(sr.sr_ifname));
156         if (bind(fd, (struct sockaddr *)&sr, sizeof(sr))) {
157                 snprintf(ebuf, PCAP_ERRBUF_SIZE, "snoop bind: %s",
158                     pcap_strerror(errno));
159                 goto bad;
160         }
161         memset(&sf, 0, sizeof(sf));
162         if (ioctl(fd, SIOCADDSNOOP, &sf) < 0) {
163                 snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCADDSNOOP: %s",
164                     pcap_strerror(errno));
165                 goto bad;
166         }
167         v = 64 * 1024;
168         (void)setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&v, sizeof(v));
169         /*
170          * XXX hack - map device name to link layer type
171          */
172         if (strncmp("et", device, 2) == 0 ||    /* Challenge 10 Mbit */
173             strncmp("ec", device, 2) == 0 ||    /* Indigo/Indy 10 Mbit,
174                                                    O2 10/100 */
175             strncmp("ef", device, 2) == 0 ||    /* O200/2000 10/100 Mbit */
176             strncmp("gfe", device, 3) == 0 ||   /* GIO 100 Mbit */
177             strncmp("fxp", device, 3) == 0 ||   /* Challenge VME Enet */
178             strncmp("ep", device, 2) == 0 ||    /* Challenge 8x10 Mbit EPLEX */
179             strncmp("vfe", device, 3) == 0 ||   /* Challenge VME 100Mbit */
180             strncmp("fa", device, 2) == 0 ||
181             strncmp("qaa", device, 3) == 0 ||
182             strncmp("el", device, 2) == 0) {
183                 p->linktype = DLT_EN10MB;
184                 p->offset = RAW_HDRPAD(sizeof(struct ether_header));
185                 ll_hdrlen = sizeof(struct ether_header);
186         } else if (strncmp("ipg", device, 3) == 0 ||
187                    strncmp("rns", device, 3) == 0 ||    /* O2/200/2000 FDDI */
188                    strncmp("xpi", device, 3) == 0) {
189                 p->linktype = DLT_FDDI;
190                 p->offset = 3;                          /* XXX yeah? */
191                 ll_hdrlen = 13;
192         } else if (strncmp("ppp", device, 3) == 0) {
193                 p->linktype = DLT_RAW;
194                 ll_hdrlen = 0;  /* DLT_RAW meaning "no PPP header, just the IP packet"? */
195         } else if (strncmp("lo", device, 2) == 0) {
196                 p->linktype = DLT_NULL;
197                 ll_hdrlen = 4;  /* is this just like BSD's loopback device? */
198         } else {
199                 snprintf(ebuf, PCAP_ERRBUF_SIZE,
200                     "snoop: unknown physical layer type");
201                 goto bad;
202         }
203 #ifdef SIOCGIFMTU
204         /*
205          * XXX - IRIX appears to give you an error if you try to set the
206          * capture length to be greater than the MTU, so let's try to get
207          * the MTU first and, if that succeeds, trim the snap length
208          * to be no greater than the MTU.
209          */
210         (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
211         if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) {
212                 snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCGIFMTU: %s",
213                     pcap_strerror(errno));
214                 goto bad;
215         }
216         /*
217          * OK, we got it.
218          *
219          * XXX - some versions of IRIX 6.5 define "ifr_mtu" and have an
220          * "ifru_metric" member of the "ifr_ifru" union in an "ifreq"
221          * structure, others don't.
222          *
223          * I've no idea what's going on, so, if "ifr_mtu" isn't defined,
224          * we define it as "ifr_metric", as using that field appears to
225          * work on the versions that lack "ifr_mtu" (and, on those that
226          * don't lack it, "ifru_metric" and "ifru_mtu" are both "int"
227          * members of the "ifr_ifru" union, which suggests that they
228          * may be interchangeable in this case).
229          */
230 #ifndef ifr_mtu
231 #define ifr_mtu ifr_metric
232 #endif
233         if (snaplen > ifr.ifr_mtu)
234                 snaplen = ifr.ifr_mtu;
235 #endif
236
237         /*
238          * The argument to SIOCSNOOPLEN is the number of link-layer
239          * payload bytes to capture - it doesn't count link-layer
240          * header bytes.
241          */
242         snooplen = snaplen - ll_hdrlen;
243         if (snooplen < 0)
244                 snooplen = 0;
245         if (ioctl(fd, SIOCSNOOPLEN, &snooplen) < 0) {
246                 snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCSNOOPLEN: %s",
247                     pcap_strerror(errno));
248                 goto bad;
249         }
250         p->snapshot = snaplen;
251         v = 1;
252         if (ioctl(fd, SIOCSNOOPING, &v) < 0) {
253                 snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCSNOOPING: %s",
254                     pcap_strerror(errno));
255                 goto bad;
256         }
257
258         p->bufsize = 4096;                              /* XXX */
259         p->buffer = (u_char *)malloc(p->bufsize);
260         if (p->buffer == NULL) {
261                 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
262                     pcap_strerror(errno));
263                 goto bad;
264         }
265
266         return (p);
267  bad:
268         (void)close(fd);
269         free(p);
270         return (NULL);
271 }
272
273 int
274 pcap_setfilter(pcap_t *p, struct bpf_program *fp)
275 {
276
277         if (install_bpf_program(p, fp) < 0)
278                 return (-1);
279         return (0);
280 }