1 /* $OpenBSD: pcap.c,v 1.10 2006/03/26 20:58:51 djm Exp $ */
2
3 /*
4 * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the Computer Systems
18 * Engineering Group at Lawrence Berkeley Laboratory.
19 * 4. Neither the name of the University nor of the Laboratory may be used
20 * to endorse or promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/types.h>
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <errno.h>
43 #include <fcntl.h>
44
45 #ifdef HAVE_OS_PROTO_H
46 #include "os-proto.h"
47 #endif
48
49 #include "pcap-int.h"
50
51 static const char pcap_version_string[] = "OpenBSD libpcap";
52
53 int
pcap_dispatch(pcap_t * p,int cnt,pcap_handler callback,u_char * user)54 pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
55 {
56
57 if (p->sf.rfile != NULL)
58 return (pcap_offline_read(p, cnt, callback, user));
59 return (pcap_read(p, cnt, callback, user));
60 }
61
62 int
pcap_loop(pcap_t * p,int cnt,pcap_handler callback,u_char * user)63 pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
64 {
65 register int n;
66
67 for (;;) {
68 if (p->sf.rfile != NULL)
69 n = pcap_offline_read(p, cnt, callback, user);
70 else {
71 /*
72 * XXX keep reading until we get something
73 * (or an error occurs)
74 */
75 do {
76 n = pcap_read(p, cnt, callback, user);
77 } while (n == 0);
78 }
79 if (n <= 0)
80 return (n);
81 if (cnt > 0) {
82 cnt -= n;
83 if (cnt <= 0)
84 return (0);
85 }
86 }
87 }
88
89 struct singleton {
90 struct pcap_pkthdr *hdr;
91 const u_char *pkt;
92 };
93
94
95 static void
pcap_oneshot(u_char * userData,const struct pcap_pkthdr * h,const u_char * pkt)96 pcap_oneshot(u_char *userData, const struct pcap_pkthdr *h, const u_char *pkt)
97 {
98 struct singleton *sp = (struct singleton *)userData;
99 *sp->hdr = *h;
100 sp->pkt = pkt;
101 }
102
103 const u_char *
pcap_next(pcap_t * p,struct pcap_pkthdr * h)104 pcap_next(pcap_t *p, struct pcap_pkthdr *h)
105 {
106 struct singleton s;
107
108 s.hdr = h;
109 if (pcap_dispatch(p, 1, pcap_oneshot, (u_char*)&s) <= 0)
110 return (0);
111 return (s.pkt);
112 }
113
114 struct pkt_for_fakecallback {
115 struct pcap_pkthdr *hdr;
116 const u_char **pkt;
117 };
118
119 static void
pcap_fakecallback(u_char * userData,const struct pcap_pkthdr * h,const u_char * pkt)120 pcap_fakecallback(u_char *userData, const struct pcap_pkthdr *h,
121 const u_char *pkt)
122 {
123 struct pkt_for_fakecallback *sp = (struct pkt_for_fakecallback *)userData;
124
125 *sp->hdr = *h;
126 *sp->pkt = pkt;
127 }
128
129 int
pcap_next_ex(pcap_t * p,struct pcap_pkthdr ** pkt_header,const u_char ** pkt_data)130 pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header,
131 const u_char **pkt_data)
132 {
133 struct pkt_for_fakecallback s;
134
135 s.hdr = &p->pcap_header;
136 s.pkt = pkt_data;
137
138 /* Saves a pointer to the packet headers */
139 *pkt_header= &p->pcap_header;
140
141 if (p->sf.rfile != NULL) {
142 int status;
143
144 /* We are on an offline capture */
145 status = pcap_offline_read(p, 1, pcap_fakecallback,
146 (u_char *)&s);
147
148 /*
149 * Return codes for pcap_offline_read() are:
150 * - 0: EOF
151 * - -1: error
152 * - >1: OK
153 * The first one ('0') conflicts with the return code of
154 * 0 from pcap_read() meaning "no packets arrived before
155 * the timeout expired", so we map it to -2 so you can
156 * distinguish between an EOF from a savefile and a
157 * "no packets arrived before the timeout expired, try
158 * again" from a live capture.
159 */
160 if (status == 0)
161 return (-2);
162 else
163 return (status);
164 }
165
166 /*
167 * Return codes for pcap_read() are:
168 * - 0: timeout
169 * - -1: error
170 * - -2: loop was broken out of with pcap_breakloop()
171 * - >1: OK
172 * The first one ('0') conflicts with the return code of 0 from
173 * pcap_offline_read() meaning "end of file".
174 */
175 return (pcap_read(p, 1, pcap_fakecallback, (u_char *)&s));
176 }
177
178 /*
179 * Force the loop in "pcap_read()" or "pcap_read_offline()" to terminate.
180 */
181 void
pcap_breakloop(pcap_t * p)182 pcap_breakloop(pcap_t *p)
183 {
184 p->break_loop = 1;
185 }
186
187 int
pcap_datalink(pcap_t * p)188 pcap_datalink(pcap_t *p)
189 {
190 return (p->linktype);
191 }
192
193 int
pcap_list_datalinks(pcap_t * p,int ** dlt_buffer)194 pcap_list_datalinks(pcap_t *p, int **dlt_buffer)
195 {
196 if (p->dlt_count == 0) {
197 /*
198 * We couldn't fetch the list of DLTs, which means
199 * this platform doesn't support changing the
200 * DLT for an interface. Return a list of DLTs
201 * containing only the DLT this device supports.
202 */
203 *dlt_buffer = (int*)malloc(sizeof(**dlt_buffer));
204 if (*dlt_buffer == NULL) {
205 (void)snprintf(p->errbuf, sizeof(p->errbuf),
206 "malloc: %s", pcap_strerror(errno));
207 return (-1);
208 }
209 **dlt_buffer = p->linktype;
210 return (1);
211 } else {
212 *dlt_buffer = (int*)malloc(sizeof(**dlt_buffer) * p->dlt_count);
213 if (*dlt_buffer == NULL) {
214 (void)snprintf(p->errbuf, sizeof(p->errbuf),
215 "malloc: %s", pcap_strerror(errno));
216 return (-1);
217 }
218 (void)memcpy(*dlt_buffer, p->dlt_list,
219 sizeof(**dlt_buffer) * p->dlt_count);
220 return (p->dlt_count);
221 }
222 }
223
224 struct dlt_choice {
225 const char *name;
226 const char *description;
227 int dlt;
228 };
229
230 static struct dlt_choice dlts[] = {
231 #define DLT_CHOICE(code, description) { #code, description, code }
232 DLT_CHOICE(DLT_NULL, "no link-layer encapsulation"),
233 DLT_CHOICE(DLT_EN10MB, "Ethernet (10Mb)"),
234 DLT_CHOICE(DLT_EN3MB, "Experimental Ethernet (3Mb)"),
235 DLT_CHOICE(DLT_AX25, "Amateur Radio AX.25"),
236 DLT_CHOICE(DLT_PRONET, "Proteon ProNET Token Ring"),
237 DLT_CHOICE(DLT_CHAOS, "Chaos"),
238 DLT_CHOICE(DLT_IEEE802, "IEEE 802 Networks"),
239 DLT_CHOICE(DLT_ARCNET, "ARCNET"),
240 DLT_CHOICE(DLT_SLIP, "Serial Line IP"),
241 DLT_CHOICE(DLT_PPP, "Point-to-point Protocol"),
242 DLT_CHOICE(DLT_FDDI, "FDDI"),
243 DLT_CHOICE(DLT_ATM_RFC1483, "LLC/SNAP encapsulated atm"),
244 DLT_CHOICE(DLT_LOOP, "loopback type (af header)"),
245 DLT_CHOICE(DLT_ENC, "IPSEC enc type (af header, spi, flags)"),
246 DLT_CHOICE(DLT_RAW, "raw IP"),
247 DLT_CHOICE(DLT_SLIP_BSDOS, "BSD/OS Serial Line IP"),
248 DLT_CHOICE(DLT_PPP_BSDOS, "BSD/OS Point-to-point Protocol"),
249 DLT_CHOICE(DLT_OLD_PFLOG, "Packet filter logging, old (XXX remove?)"),
250 DLT_CHOICE(DLT_PFSYNC, "Packet filter state syncing"),
251 DLT_CHOICE(DLT_PPP_ETHER, "PPP over Ethernet; session only w/o ether header"),
252 DLT_CHOICE(DLT_IEEE802_11, "IEEE 802.11 wireless"),
253 DLT_CHOICE(DLT_PFLOG, "Packet filter logging, by pcap people"),
254 DLT_CHOICE(DLT_IEEE802_11_RADIO, "IEEE 802.11 plus WLAN header"),
255 #undef DLT_CHOICE
256 { NULL, NULL, -1}
257 };
258
259 int
pcap_datalink_name_to_val(const char * name)260 pcap_datalink_name_to_val(const char *name)
261 {
262 int i;
263
264 for (i = 0; dlts[i].name != NULL; i++) {
265 /* Skip leading "DLT_" */
266 if (strcasecmp(dlts[i].name + 4, name) == 0)
267 return (dlts[i].dlt);
268 }
269 return (-1);
270 }
271
272 const char *
pcap_datalink_val_to_name(int dlt)273 pcap_datalink_val_to_name(int dlt)
274 {
275 int i;
276
277 for (i = 0; dlts[i].name != NULL; i++) {
278 if (dlts[i].dlt == dlt)
279 return (dlts[i].name + 4); /* Skip leading "DLT_" */
280 }
281 return (NULL);
282 }
283
284 const char *
pcap_datalink_val_to_description(int dlt)285 pcap_datalink_val_to_description(int dlt)
286 {
287 int i;
288
289 for (i = 0; dlts[i].name != NULL; i++) {
290 if (dlts[i].dlt == dlt)
291 return (dlts[i].description);
292 }
293 return (NULL);
294 }
295
296 int
pcap_snapshot(pcap_t * p)297 pcap_snapshot(pcap_t *p)
298 {
299 return (p->snapshot);
300 }
301
302 int
pcap_is_swapped(pcap_t * p)303 pcap_is_swapped(pcap_t *p)
304 {
305 return (p->sf.swapped);
306 }
307
308 int
pcap_major_version(pcap_t * p)309 pcap_major_version(pcap_t *p)
310 {
311 return (p->sf.version_major);
312 }
313
314 int
pcap_minor_version(pcap_t * p)315 pcap_minor_version(pcap_t *p)
316 {
317 return (p->sf.version_minor);
318 }
319
320 FILE *
pcap_file(pcap_t * p)321 pcap_file(pcap_t *p)
322 {
323 return (p->sf.rfile);
324 }
325
326 int
pcap_fileno(pcap_t * p)327 pcap_fileno(pcap_t *p)
328 {
329 return (p->fd);
330 }
331
332 void
pcap_perror(pcap_t * p,char * prefix)333 pcap_perror(pcap_t *p, char *prefix)
334 {
335 fprintf(stderr, "%s: %s\n", prefix, p->errbuf);
336 }
337
338 int
pcap_get_selectable_fd(pcap_t * p)339 pcap_get_selectable_fd(pcap_t *p)
340 {
341 return (p->fd);
342 }
343
344 char *
pcap_geterr(pcap_t * p)345 pcap_geterr(pcap_t *p)
346 {
347 return (p->errbuf);
348 }
349
350 int
pcap_getnonblock(pcap_t * p,char * errbuf)351 pcap_getnonblock(pcap_t *p, char *errbuf)
352 {
353 int fdflags;
354
355 fdflags = fcntl(p->fd, F_GETFL, 0);
356 if (fdflags == -1) {
357 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s",
358 pcap_strerror(errno));
359 return (-1);
360 }
361 if (fdflags & O_NONBLOCK)
362 return (1);
363 else
364 return (0);
365 }
366
367 int
pcap_setnonblock(pcap_t * p,int nonblock,char * errbuf)368 pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf)
369 {
370 int fdflags;
371
372 fdflags = fcntl(p->fd, F_GETFL, 0);
373 if (fdflags == -1) {
374 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s",
375 pcap_strerror(errno));
376 return (-1);
377 }
378 if (nonblock)
379 fdflags |= O_NONBLOCK;
380 else
381 fdflags &= ~O_NONBLOCK;
382 if (fcntl(p->fd, F_SETFL, fdflags) == -1) {
383 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_SETFL: %s",
384 pcap_strerror(errno));
385 return (-1);
386 }
387 return (0);
388 }
389
390 /*
391 * Not all systems have strerror().
392 */
393 char *
pcap_strerror(int errnum)394 pcap_strerror(int errnum)
395 {
396 #ifdef HAVE_STRERROR
397 return (strerror(errnum));
398 #else
399 extern int sys_nerr;
400 extern const char *const sys_errlist[];
401 static char ebuf[20];
402
403 if ((unsigned int)errnum < sys_nerr)
404 return ((char *)sys_errlist[errnum]);
405 (void)snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum);
406 return(ebuf);
407 #endif
408 }
409
410 pcap_t *
pcap_open_dead(int linktype,int snaplen)411 pcap_open_dead(int linktype, int snaplen)
412 {
413 pcap_t *p;
414
415 p = malloc(sizeof(*p));
416 if (p == NULL)
417 return NULL;
418 memset (p, 0, sizeof(*p));
419 p->snapshot = snaplen;
420 p->linktype = linktype;
421 p->fd = -1;
422 return p;
423 }
424
425 void
pcap_close(pcap_t * p)426 pcap_close(pcap_t *p)
427 {
428 /*XXX*/
429 if (p->fd >= 0)
430 close(p->fd);
431 if (p->sf.rfile != NULL) {
432 (void)fclose(p->sf.rfile);
433 if (p->sf.base != NULL)
434 free(p->sf.base);
435 } else if (p->buffer != NULL)
436 free(p->buffer);
437 #ifdef linux
438 if (p->md.device != NULL)
439 free(p->md.device);
440 #endif
441 pcap_freecode(&p->fcode);
442 if (p->dlt_list != NULL)
443 free(p->dlt_list);
444 free(p);
445 }
446
447 const char *
pcap_lib_version(void)448 pcap_lib_version(void)
449 {
450 return (pcap_version_string);
451 }
452
453