]> The Tcpdump Group git mirrors - libpcap/blob - pcap-linux.c
do not use sprintf(). always use snprintf().
[libpcap] / pcap-linux.c
1 /*
2 * Copyright (c) 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-linux.c,v 1.16 2000-04-27 09:11:13 itojun Exp $ (LBL)";
24 #endif
25
26 #include <sys/param.h>
27 #include <sys/ioctl.h>
28 #include <sys/socket.h>
29 #include <sys/time.h>
30
31 #include <net/if.h>
32 #ifdef HAVE_NET_IF_ARP_H
33 #include <net/if_arp.h>
34 #else
35 #include <linux/if_arp.h>
36 #endif
37 #include <linux/if_ether.h>
38
39 #include <netinet/in.h>
40
41 #include <errno.h>
42 #include <malloc.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 static struct ifreq saved_ifr;
49
50 #include "pcap-int.h"
51
52 #include "gnuc.h"
53 #ifdef HAVE_OS_PROTO_H
54 #include "os-proto.h"
55 #endif
56
57 void linux_restore_ifr(void);
58
59 int
60 pcap_stats(pcap_t *p, struct pcap_stat *ps)
61 {
62
63 *ps = p->md.stat;
64 return (0);
65 }
66
67 int
68 pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
69 {
70 register int cc;
71 register int bufsize;
72 register int caplen;
73 register u_char *bp;
74 struct sockaddr from;
75 int fromlen;
76
77 bp = p->buffer + p->offset;
78 bufsize = p->bufsize;
79 if (p->md.pad > 0) {
80 memset(bp, 0, p->md.pad);
81 bp += p->md.pad;
82 bufsize -= p->md.pad;
83 }
84
85 again:
86 do {
87 fromlen = sizeof(from);
88 cc = recvfrom(p->fd, bp, bufsize, 0, &from, &fromlen);
89 if (cc < 0) {
90 /* Don't choke when we get ptraced */
91 switch (errno) {
92
93 case EINTR:
94 goto again;
95
96 case EWOULDBLOCK:
97 return (0); /* XXX */
98 }
99 snprintf(p->errbuf, sizeof(p->errbuf),
100 "read: %s", pcap_strerror(errno));
101 return (-1);
102 }
103 } while (strcmp(p->md.device, from.sa_data));
104
105 /* If we need have leading zero bytes, adjust count */
106 cc += p->md.pad;
107 bp = p->buffer + p->offset;
108
109 /* If we need to step over leading junk, adjust count and pointer */
110 cc -= p->md.skip;
111 bp += p->md.skip;
112
113 /* Captured length can't exceed our read buffer size */
114 caplen = cc;
115 if (caplen > bufsize)
116 caplen = bufsize;
117
118 /* Captured length can't exceed the snapshot length */
119 if (caplen > p->snapshot)
120 caplen = p->snapshot;
121
122 if (p->fcode.bf_insns == NULL ||
123 bpf_filter(p->fcode.bf_insns, bp, cc, caplen)) {
124 struct pcap_pkthdr h;
125
126 ++p->md.stat.ps_recv;
127 /* Get timestamp */
128 if (ioctl(p->fd, SIOCGSTAMP, &h.ts) < 0) {
129 snprintf(p->errbuf, sizeof(p->errbuf), "SIOCGSTAMP: %s",
130 pcap_strerror(errno));
131 return (-1);
132 }
133 h.len = cc;
134 h.caplen = caplen;
135 (*callback)(user, &h, bp);
136 return (1);
137 }
138 return (0);
139 }
140
141 pcap_t *
142 pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
143 {
144 register int fd, broadcast;
145 register pcap_t *p;
146 struct ifreq ifr;
147 struct sockaddr sa;
148
149 p = (pcap_t *)malloc(sizeof(*p));
150 if (p == NULL) {
151 snprint(ebuf, PCAP_ERRBUFF_SIZE, PCAP_ERRBUFF_SIZE,
152 "malloc: %s", pcap_strerror(errno));
153 return (NULL);
154 }
155 memset(p, 0, sizeof(*p));
156 fd = -1;
157
158 fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL));
159 if (fd < 0) {
160 snprint(ebuf, PCAP_ERRBUFF_SIZE, "socket: %s",
161 pcap_strerror(errno));
162 goto bad;
163 }
164 p->fd = fd;
165
166 /* Bind to the interface name */
167 memset(&sa, 0, sizeof(sa));
168 sa.sa_family = AF_INET;
169 (void)strncpy(sa.sa_data, device, sizeof(sa.sa_data));
170 if (bind(p->fd, &sa, sizeof(sa))) {
171 snprint(ebuf, PCAP_ERRBUFF_SIZE, "bind: %s: %s", device,
172 pcap_strerror(errno));
173 goto bad;
174 }
175
176 memset(&ifr, 0, sizeof(ifr));
177 strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
178 if (ioctl(p->fd, SIOCGIFHWADDR, &ifr) < 0 ) {
179 snprint(ebuf, PCAP_ERRBUFF_SIZE, "SIOCGIFHWADDR: %s",
180 pcap_strerror(errno));
181 goto bad;
182 }
183 broadcast = 0;
184 switch (ifr.ifr_hwaddr.sa_family) {
185
186 case ARPHRD_ETHER:
187 case ARPHRD_METRICOM:
188 p->linktype = DLT_EN10MB;
189 p->offset = 2;
190 ++broadcast;
191 break;
192
193 case ARPHRD_EETHER:
194 p->linktype = DLT_EN3MB;
195 ++broadcast;
196 break;
197
198 case ARPHRD_AX25:
199 p->linktype = DLT_AX25;
200 ++broadcast;
201 break;
202
203 case ARPHRD_PRONET:
204 p->linktype = DLT_PRONET;
205 break;
206
207 case ARPHRD_CHAOS:
208 p->linktype = DLT_CHAOS;
209 break;
210
211 case ARPHRD_IEEE802:
212 p->linktype = DLT_IEEE802;
213 ++broadcast;
214 break;
215
216 case ARPHRD_ARCNET:
217 p->linktype = DLT_ARCNET;
218 ++broadcast;
219 break;
220
221 case ARPHRD_SLIP:
222 case ARPHRD_CSLIP:
223 case ARPHRD_SLIP6:
224 case ARPHRD_CSLIP6:
225 case ARPHRD_PPP:
226 p->linktype = DLT_RAW;
227 break;
228
229 case ARPHRD_LOOPBACK:
230 p->linktype = DLT_NULL;
231 p->md.pad = 2;
232 p->md.skip = 12;
233 break;
234
235 #ifdef ARPHRD_FDDI
236 /* Not all versions of the kernel has this define */
237 case ARPHRD_FDDI:
238 p->linktype = DLT_FDDI;
239 ++broadcast;
240 break;
241 #endif
242
243 #ifdef notdef
244 case ARPHRD_LOCALTLK:
245 case ARPHRD_NETROM:
246 case ARPHRD_APPLETLK:
247 case ARPHRD_DLCI:
248 case ARPHRD_RSRVD:
249 case ARPHRD_ADAPT:
250 case ARPHRD_TUNNEL:
251 case ARPHRD_TUNNEL6:
252 case ARPHRD_FRAD:
253 case ARPHRD_SKIP:
254 /* XXX currently do not know what to do with these... */
255 abort();
256 #endif
257
258 default:
259 snprint(ebuf, PCAP_ERRBUFF_SIZE,
260 "unknown physical layer type 0x%x",
261 ifr.ifr_hwaddr.sa_family);
262 goto bad;
263 }
264
265 /* Base the buffer size on the interface MTU */
266 memset(&ifr, 0, sizeof(ifr));
267 strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
268 if (ioctl(p->fd, SIOCGIFMTU, &ifr) < 0 ) {
269 snprint(ebuf, PCAP_ERRBUFF_SIZE, "SIOCGIFMTU: %s",
270 pcap_strerror(errno));
271 goto bad;
272 }
273
274 /* Leave room for link header (which is never large under linux...) */
275 p->bufsize = ifr.ifr_mtu + 64;
276
277 p->buffer = (u_char *)malloc(p->bufsize + p->offset);
278 if (p->buffer == NULL) {
279 snprint(ebuf, PCAP_ERRBUFF_SIZE, "malloc: %s",
280 pcap_strerror(errno));
281 goto bad;
282 }
283
284 /* XXX */
285 if (promisc && broadcast) {
286 memset(&ifr, 0, sizeof(ifr));
287 strcpy(ifr.ifr_name, device);
288 if (ioctl(p->fd, SIOCGIFFLAGS, &ifr) < 0 ) {
289 snprint(ebuf, PCAP_ERRBUFF_SIZE, "SIOCGIFFLAGS: %s",
290 pcap_strerror(errno));
291 goto bad;
292 }
293 saved_ifr = ifr;
294 ifr.ifr_flags |= IFF_PROMISC;
295 if (ioctl(p->fd, SIOCSIFFLAGS, &ifr) < 0 ) {
296 snprint(ebuf, PCAP_ERRBUFF_SIZE, "SIOCSIFFLAGS: %s",
297 pcap_strerror(errno));
298 goto bad;
299 }
300 ifr.ifr_flags &= ~IFF_PROMISC;
301 atexit(linux_restore_ifr);
302 }
303
304 p->md.device = strdup(device);
305 if (p->md.device == NULL) {
306 snprint(ebuf, PCAP_ERRBUFF_SIZE, "malloc: %s",
307 pcap_strerror(errno));
308 goto bad;
309 }
310 p->snapshot = snaplen;
311
312 return (p);
313 bad:
314 if (fd >= 0)
315 (void)close(fd);
316 if (p->buffer != NULL)
317 free(p->buffer);
318 if (p->md.device != NULL)
319 free(p->md.device);
320 free(p);
321 return (NULL);
322 }
323
324 int
325 pcap_setfilter(pcap_t *p, struct bpf_program *fp)
326 {
327
328 p->fcode = *fp;
329 return (0);
330 }
331
332 void
333 linux_restore_ifr(void)
334 {
335 register int fd;
336
337 fd = socket(PF_INET, SOCK_PACKET, htons(0x0003));
338 if (fd < 0)
339 fprintf(stderr, "linux socket: %s", pcap_strerror(errno));
340 else if (ioctl(fd, SIOCSIFFLAGS, &saved_ifr) < 0)
341 fprintf(stderr, "linux SIOCSIFFLAGS: %s", pcap_strerror(errno));
342 }