blob: 4d6a4fbe42f5a73713814596813866879ca6ae32 [file] [log] [blame]
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -07001// Copyright 2012 Google, Inc. All rights reserved.
2// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
3//
4// Use of this source code is governed by a BSD-style license
5// that can be found in the LICENSE file in the root of the source
6// tree.
7//
8// +build !windows
9
10package pcap
11
12import (
13 "errors"
14 "os"
15 "sync"
16 "syscall"
17 "time"
18 "unsafe"
19
20 "github.com/google/gopacket"
21
22 "github.com/google/gopacket/layers"
23)
24
25/*
26#cgo solaris LDFLAGS: -L /opt/local/lib -lpcap
27#cgo linux LDFLAGS: -lpcap
28#cgo dragonfly LDFLAGS: -lpcap
29#cgo freebsd LDFLAGS: -lpcap
30#cgo openbsd LDFLAGS: -lpcap
31#cgo netbsd LDFLAGS: -lpcap
32#cgo darwin LDFLAGS: -lpcap
33#include <stdlib.h>
34#include <pcap.h>
35#include <stdint.h>
36
37// Some old versions of pcap don't define this constant.
38#ifndef PCAP_NETMASK_UNKNOWN
39#define PCAP_NETMASK_UNKNOWN 0xffffffff
40#endif
41
42// libpcap doesn't actually export its version in a #define-guardable way,
43// so we have to use other defined things to differentiate versions.
44// We assume at least libpcap v1.1 at the moment.
45// See http://upstream-tracker.org/versions/libpcap.html
46
47#ifndef PCAP_ERROR_TSTAMP_PRECISION_NOTSUP // < v1.5
48#define PCAP_ERROR_TSTAMP_PRECISION_NOTSUP -12
49
50int pcap_set_immediate_mode(pcap_t *p, int mode) {
51 return PCAP_ERROR;
52}
53
54// libpcap version < v1.5 doesn't have timestamp precision (everything is microsecond)
55//
56// This means *_tstamp_* functions and macros are missing. Therefore, we emulate these
57// functions here and pretend the setting the precision works. This is actually the way
58// the pcap_open_offline_with_tstamp_precision works, because it doesn't return an error
59// if it was not possible to set the precision, which depends on support by the given file.
60// => The rest of the functions always pretend as if they could set nano precision and
61// verify the actual precision with pcap_get_tstamp_precision, which is emulated for <v1.5
62// to always return micro resolution.
63
64#define PCAP_TSTAMP_PRECISION_MICRO 0
65#define PCAP_TSTAMP_PRECISION_NANO 1
66
67pcap_t *pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision,
68 char *errbuf) {
69 return pcap_open_offline(fname, errbuf);
70}
71
72pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision,
73 char *errbuf) {
74 return pcap_fopen_offline(fp, errbuf);
75}
76
77int pcap_set_tstamp_precision(pcap_t *p, int tstamp_precision) {
78 if (tstamp_precision == PCAP_TSTAMP_PRECISION_MICRO)
79 return 0;
80 return PCAP_ERROR_TSTAMP_PRECISION_NOTSUP;
81}
82
83int pcap_get_tstamp_precision(pcap_t *p) {
84 return PCAP_TSTAMP_PRECISION_MICRO;
85}
86
87#ifndef PCAP_TSTAMP_HOST // < v1.2
88
89int pcap_set_tstamp_type(pcap_t* p, int t) { return -1; }
90int pcap_list_tstamp_types(pcap_t* p, int** t) { return 0; }
91void pcap_free_tstamp_types(int *tstamp_types) {}
92const char* pcap_tstamp_type_val_to_name(int t) {
93 return "pcap timestamp types not supported";
94}
95int pcap_tstamp_type_name_to_val(const char* t) {
96 return PCAP_ERROR;
97}
98
99#endif // < v1.2
100#endif // < v1.5
101
102#ifndef PCAP_ERROR_PROMISC_PERM_DENIED
103#define PCAP_ERROR_PROMISC_PERM_DENIED -11
104#endif
105
106// Windows, Macs, and Linux all use different time types. Joy.
107#ifdef __APPLE__
108#define gopacket_time_secs_t __darwin_time_t
109#define gopacket_time_usecs_t __darwin_suseconds_t
110#elif __ANDROID__
111#define gopacket_time_secs_t __kernel_time_t
112#define gopacket_time_usecs_t __kernel_suseconds_t
113#elif __GLIBC__
114#define gopacket_time_secs_t __time_t
115#define gopacket_time_usecs_t __suseconds_t
116#else // Some form of linux/bsd/etc...
117#include <sys/param.h>
118#ifdef __OpenBSD__
119#define gopacket_time_secs_t u_int32_t
120#define gopacket_time_usecs_t u_int32_t
121#else
122#define gopacket_time_secs_t time_t
123#define gopacket_time_usecs_t suseconds_t
124#endif
125#endif
126
127// The things we do to avoid pointers escaping to the heap...
128// According to https://github.com/the-tcpdump-group/libpcap/blob/1131a7c26c6f4d4772e4a2beeaf7212f4dea74ac/pcap.c#L398-L406 ,
129// the return value of pcap_next_ex could be greater than 1 for success.
130// Let's just make it 1 if it comes bigger than 1.
131int pcap_next_ex_escaping(pcap_t *p, uintptr_t pkt_hdr, uintptr_t pkt_data) {
132 int ex = pcap_next_ex(p, (struct pcap_pkthdr**)(pkt_hdr), (const u_char**)(pkt_data));
133 if (ex > 1) {
134 ex = 1;
135 }
136 return ex;
137}
138
139int pcap_offline_filter_escaping(struct bpf_program *fp, uintptr_t pkt_hdr, uintptr_t pkt) {
140 return pcap_offline_filter(fp, (struct pcap_pkthdr*)(pkt_hdr), (const u_char*)(pkt));
141}
142
143// pcap_wait returns when the next packet is available or the timeout expires.
144// Since it uses pcap_get_selectable_fd, it will not work in Windows.
145int pcap_wait(pcap_t *p, int usec) {
146 fd_set fds;
147 int fd;
148 struct timeval tv;
149
150 fd = pcap_get_selectable_fd(p);
151 if(fd < 0) {
152 return fd;
153 }
154
155 FD_ZERO(&fds);
156 FD_SET(fd, &fds);
157
158 tv.tv_sec = 0;
159 tv.tv_usec = usec;
160
161 if(usec != 0) {
162 return select(fd+1, &fds, NULL, NULL, &tv);
163 }
164
165 // block indefinitely if no timeout provided
166 return select(fd+1, &fds, NULL, NULL, NULL);
167}
168
169*/
170import "C"
171
172const errorBufferSize = C.PCAP_ERRBUF_SIZE
173
174const (
175 pcapErrorNotActivated = C.PCAP_ERROR_NOT_ACTIVATED
176 pcapErrorActivated = C.PCAP_ERROR_ACTIVATED
177 pcapWarningPromisc = C.PCAP_WARNING_PROMISC_NOTSUP
178 pcapErrorNoSuchDevice = C.PCAP_ERROR_NO_SUCH_DEVICE
179 pcapErrorDenied = C.PCAP_ERROR_PERM_DENIED
180 pcapErrorNotUp = C.PCAP_ERROR_IFACE_NOT_UP
181 pcapWarning = C.PCAP_WARNING
182 pcapDIN = C.PCAP_D_IN
183 pcapDOUT = C.PCAP_D_OUT
184 pcapDINOUT = C.PCAP_D_INOUT
185 pcapNetmaskUnknown = C.PCAP_NETMASK_UNKNOWN
186 pcapTstampPrecisionMicro = C.PCAP_TSTAMP_PRECISION_MICRO
187 pcapTstampPrecisionNano = C.PCAP_TSTAMP_PRECISION_NANO
188)
189
190type pcapPkthdr C.struct_pcap_pkthdr
191type pcapTPtr *C.struct_pcap
192type pcapBpfProgram C.struct_bpf_program
193
194func (h *pcapPkthdr) getSec() int64 {
195 return int64(h.ts.tv_sec)
196}
197
198func (h *pcapPkthdr) getUsec() int64 {
199 return int64(h.ts.tv_usec)
200}
201
202func (h *pcapPkthdr) getLen() int {
203 return int(h.len)
204}
205
206func (h *pcapPkthdr) getCaplen() int {
207 return int(h.caplen)
208}
209
210func pcapGetTstampPrecision(cptr pcapTPtr) int {
211 return int(C.pcap_get_tstamp_precision(cptr))
212}
213
214func pcapSetTstampPrecision(cptr pcapTPtr, precision int) error {
215 ret := C.pcap_set_tstamp_precision(cptr, C.int(precision))
216 if ret < 0 {
217 return errors.New(C.GoString(C.pcap_geterr(cptr)))
218 }
219 return nil
220}
221
222func statusError(status C.int) error {
223 return errors.New(C.GoString(C.pcap_statustostr(status)))
224}
225
226func pcapOpenLive(device string, snaplen int, pro int, timeout int) (*Handle, error) {
227 buf := (*C.char)(C.calloc(errorBufferSize, 1))
228 defer C.free(unsafe.Pointer(buf))
229
230 dev := C.CString(device)
231 defer C.free(unsafe.Pointer(dev))
232
233 cptr := C.pcap_open_live(dev, C.int(snaplen), C.int(pro), C.int(timeout), buf)
234 if cptr == nil {
235 return nil, errors.New(C.GoString(buf))
236 }
237 return &Handle{cptr: cptr}, nil
238}
239
240func openOffline(file string) (handle *Handle, err error) {
241 buf := (*C.char)(C.calloc(errorBufferSize, 1))
242 defer C.free(unsafe.Pointer(buf))
243 cf := C.CString(file)
244 defer C.free(unsafe.Pointer(cf))
245
246 cptr := C.pcap_open_offline_with_tstamp_precision(cf, C.PCAP_TSTAMP_PRECISION_NANO, buf)
247 if cptr == nil {
248 return nil, errors.New(C.GoString(buf))
249 }
250 return &Handle{cptr: cptr}, nil
251}
252
253func (p *Handle) pcapClose() {
254 if p.cptr != nil {
255 C.pcap_close(p.cptr)
256 }
257 p.cptr = nil
258}
259
260func (p *Handle) pcapGeterr() error {
261 return errors.New(C.GoString(C.pcap_geterr(p.cptr)))
262}
263
264func (p *Handle) pcapStats() (*Stats, error) {
265 var cstats C.struct_pcap_stat
266 if C.pcap_stats(p.cptr, &cstats) < 0 {
267 return nil, p.pcapGeterr()
268 }
269 return &Stats{
270 PacketsReceived: int(cstats.ps_recv),
271 PacketsDropped: int(cstats.ps_drop),
272 PacketsIfDropped: int(cstats.ps_ifdrop),
273 }, nil
274}
275
276// for libpcap < 1.8 pcap_compile is NOT thread-safe, so protect it.
277var pcapCompileMu sync.Mutex
278
279func (p *Handle) pcapCompile(expr string, maskp uint32) (pcapBpfProgram, error) {
280 var bpf pcapBpfProgram
281 cexpr := C.CString(expr)
282 defer C.free(unsafe.Pointer(cexpr))
283
284 pcapCompileMu.Lock()
285 defer pcapCompileMu.Unlock()
286 if C.pcap_compile(p.cptr, (*C.struct_bpf_program)(&bpf), cexpr, 1, C.bpf_u_int32(maskp)) < 0 {
287 return bpf, p.pcapGeterr()
288 }
289 return bpf, nil
290}
291
292func (p pcapBpfProgram) free() {
293 C.pcap_freecode((*C.struct_bpf_program)(&p))
294}
295
296func (p pcapBpfProgram) toBPFInstruction() []BPFInstruction {
297 bpfInsn := (*[bpfInstructionBufferSize]C.struct_bpf_insn)(unsafe.Pointer(p.bf_insns))[0:p.bf_len:p.bf_len]
298 bpfInstruction := make([]BPFInstruction, len(bpfInsn), len(bpfInsn))
299
300 for i, v := range bpfInsn {
301 bpfInstruction[i].Code = uint16(v.code)
302 bpfInstruction[i].Jt = uint8(v.jt)
303 bpfInstruction[i].Jf = uint8(v.jf)
304 bpfInstruction[i].K = uint32(v.k)
305 }
306 return bpfInstruction
307}
308
309func pcapBpfProgramFromInstructions(bpfInstructions []BPFInstruction) pcapBpfProgram {
310 var bpf pcapBpfProgram
311 bpf.bf_len = C.u_int(len(bpfInstructions))
312 cbpfInsns := C.calloc(C.size_t(len(bpfInstructions)), C.size_t(unsafe.Sizeof(bpfInstructions[0])))
313 gbpfInsns := (*[bpfInstructionBufferSize]C.struct_bpf_insn)(cbpfInsns)
314
315 for i, v := range bpfInstructions {
316 gbpfInsns[i].code = C.u_short(v.Code)
317 gbpfInsns[i].jt = C.u_char(v.Jt)
318 gbpfInsns[i].jf = C.u_char(v.Jf)
319 gbpfInsns[i].k = C.bpf_u_int32(v.K)
320 }
321
322 bpf.bf_insns = (*C.struct_bpf_insn)(cbpfInsns)
323 return bpf
324}
325
326func pcapLookupnet(device string) (netp, maskp uint32, err error) {
327 errorBuf := (*C.char)(C.calloc(errorBufferSize, 1))
328 defer C.free(unsafe.Pointer(errorBuf))
329 dev := C.CString(device)
330 defer C.free(unsafe.Pointer(dev))
331 if C.pcap_lookupnet(
332 dev,
333 (*C.bpf_u_int32)(unsafe.Pointer(&netp)),
334 (*C.bpf_u_int32)(unsafe.Pointer(&maskp)),
335 errorBuf,
336 ) < 0 {
337 return 0, 0, errors.New(C.GoString(errorBuf))
338 // We can't lookup the network, but that could be because the interface
339 // doesn't have an IPv4.
340 }
341 return
342}
343
344func (b *BPF) pcapOfflineFilter(ci gopacket.CaptureInfo, data []byte) bool {
345 hdr := (*C.struct_pcap_pkthdr)(&b.hdr)
346 hdr.ts.tv_sec = C.gopacket_time_secs_t(ci.Timestamp.Unix())
347 hdr.ts.tv_usec = C.gopacket_time_usecs_t(ci.Timestamp.Nanosecond() / 1000)
348 hdr.caplen = C.bpf_u_int32(len(data)) // Trust actual length over ci.Length.
349 hdr.len = C.bpf_u_int32(ci.Length)
350 dataptr := (*C.u_char)(unsafe.Pointer(&data[0]))
351 return C.pcap_offline_filter_escaping((*C.struct_bpf_program)(&b.bpf),
352 C.uintptr_t(uintptr(unsafe.Pointer(hdr))),
353 C.uintptr_t(uintptr(unsafe.Pointer(dataptr)))) != 0
354}
355
356func (p *Handle) pcapSetfilter(bpf pcapBpfProgram) error {
357 if C.pcap_setfilter(p.cptr, (*C.struct_bpf_program)(&bpf)) < 0 {
358 return p.pcapGeterr()
359 }
360 return nil
361}
362
363func (p *Handle) pcapListDatalinks() (datalinks []Datalink, err error) {
364 var dltbuf *C.int
365
366 n := int(C.pcap_list_datalinks(p.cptr, &dltbuf))
367 if n < 0 {
368 return nil, p.pcapGeterr()
369 }
370
371 defer C.pcap_free_datalinks(dltbuf)
372
373 datalinks = make([]Datalink, n)
374
375 dltArray := (*[1 << 28]C.int)(unsafe.Pointer(dltbuf))
376
377 for i := 0; i < n; i++ {
378 datalinks[i].Name = pcapDatalinkValToName(int((*dltArray)[i]))
379 datalinks[i].Description = pcapDatalinkValToDescription(int((*dltArray)[i]))
380 }
381
382 return datalinks, nil
383}
384
385func pcapOpenDead(linkType layers.LinkType, captureLength int) (*Handle, error) {
386 cptr := C.pcap_open_dead(C.int(linkType), C.int(captureLength))
387 if cptr == nil {
388 return nil, errors.New("error opening dead capture")
389 }
390
391 return &Handle{cptr: cptr}, nil
392}
393
394func (p *Handle) pcapNextPacketEx() NextError {
395 // This horrible magic allows us to pass a ptr-to-ptr to pcap_next_ex
396 // without causing that ptr-to-ptr to itself be allocated on the heap.
397 // Since Handle itself survives through the duration of the pcap_next_ex
398 // call, this should be perfectly safe for GC stuff, etc.
399
400 return NextError(C.pcap_next_ex_escaping(p.cptr, C.uintptr_t(uintptr(unsafe.Pointer(&p.pkthdr))), C.uintptr_t(uintptr(unsafe.Pointer(&p.bufptr)))))
401}
402
403func (p *Handle) pcapDatalink() layers.LinkType {
404 return layers.LinkType(C.pcap_datalink(p.cptr))
405}
406
407func (p *Handle) pcapSetDatalink(dlt layers.LinkType) error {
408 if C.pcap_set_datalink(p.cptr, C.int(dlt)) < 0 {
409 return p.pcapGeterr()
410 }
411 return nil
412}
413
414func pcapDatalinkValToName(dlt int) string {
415 return C.GoString(C.pcap_datalink_val_to_name(C.int(dlt)))
416}
417
418func pcapDatalinkValToDescription(dlt int) string {
419 return C.GoString(C.pcap_datalink_val_to_description(C.int(dlt)))
420}
421
422func pcapDatalinkNameToVal(name string) int {
423 cptr := C.CString(name)
424 defer C.free(unsafe.Pointer(cptr))
425 return int(C.pcap_datalink_name_to_val(cptr))
426}
427
428func pcapLibVersion() string {
429 return C.GoString(C.pcap_lib_version())
430}
431
432func (p *Handle) isOpen() bool {
433 return p.cptr != nil
434}
435
436type pcapDevices struct {
437 all, cur *C.pcap_if_t
438}
439
440func (p pcapDevices) free() {
441 C.pcap_freealldevs((*C.pcap_if_t)(p.all))
442}
443
444func (p *pcapDevices) next() bool {
445 if p.cur == nil {
446 p.cur = p.all
447 if p.cur == nil {
448 return false
449 }
450 return true
451 }
452 if p.cur.next == nil {
453 return false
454 }
455 p.cur = p.cur.next
456 return true
457}
458
459func (p pcapDevices) name() string {
460 return C.GoString(p.cur.name)
461}
462
463func (p pcapDevices) description() string {
464 return C.GoString(p.cur.description)
465}
466
467func (p pcapDevices) flags() uint32 {
468 return uint32(p.cur.flags)
469}
470
471type pcapAddresses struct {
472 all, cur *C.pcap_addr_t
473}
474
475func (p *pcapAddresses) next() bool {
476 if p.cur == nil {
477 p.cur = p.all
478 if p.cur == nil {
479 return false
480 }
481 return true
482 }
483 if p.cur.next == nil {
484 return false
485 }
486 p.cur = p.cur.next
487 return true
488}
489
490func (p pcapAddresses) addr() *syscall.RawSockaddr {
491 return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.addr))
492}
493
494func (p pcapAddresses) netmask() *syscall.RawSockaddr {
495 return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.netmask))
496}
497
498func (p pcapAddresses) broadaddr() *syscall.RawSockaddr {
499 return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.broadaddr))
500}
501
502func (p pcapAddresses) dstaddr() *syscall.RawSockaddr {
503 return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.dstaddr))
504}
505
506func (p pcapDevices) addresses() pcapAddresses {
507 return pcapAddresses{all: p.cur.addresses}
508}
509
510func pcapFindAllDevs() (pcapDevices, error) {
511 var buf *C.char
512 buf = (*C.char)(C.calloc(errorBufferSize, 1))
513 defer C.free(unsafe.Pointer(buf))
514 var alldevsp pcapDevices
515
516 if C.pcap_findalldevs((**C.pcap_if_t)(&alldevsp.all), buf) < 0 {
517 return pcapDevices{}, errors.New(C.GoString(buf))
518 }
519 return alldevsp, nil
520}
521
522func (p *Handle) pcapSendpacket(data []byte) error {
523 if C.pcap_sendpacket(p.cptr, (*C.u_char)(&data[0]), (C.int)(len(data))) < 0 {
524 return p.pcapGeterr()
525 }
526 return nil
527}
528
529func (p *Handle) pcapSetdirection(direction Direction) error {
530 if status := C.pcap_setdirection(p.cptr, (C.pcap_direction_t)(direction)); status < 0 {
531 return statusError(status)
532 }
533 return nil
534}
535
536func (p *Handle) pcapSnapshot() int {
537 return int(C.pcap_snapshot(p.cptr))
538}
539
540func (t TimestampSource) pcapTstampTypeValToName() string {
541 return C.GoString(C.pcap_tstamp_type_val_to_name(C.int(t)))
542}
543
544func pcapTstampTypeNameToVal(s string) (TimestampSource, error) {
545 cs := C.CString(s)
546 defer C.free(unsafe.Pointer(cs))
547 t := C.pcap_tstamp_type_name_to_val(cs)
548 if t < 0 {
549 return 0, statusError(t)
550 }
551 return TimestampSource(t), nil
552}
553
554func (p *InactiveHandle) pcapGeterr() error {
555 return errors.New(C.GoString(C.pcap_geterr(p.cptr)))
556}
557
558func (p *InactiveHandle) pcapActivate() (*Handle, activateError) {
559 ret := activateError(C.pcap_activate(p.cptr))
560 if ret != aeNoError {
561 return nil, ret
562 }
563 h := &Handle{
564 cptr: p.cptr,
565 }
566 p.cptr = nil
567 return h, ret
568}
569
570func (p *InactiveHandle) pcapClose() {
571 if p.cptr != nil {
572 C.pcap_close(p.cptr)
573 }
574}
575
576func pcapCreate(device string) (*InactiveHandle, error) {
577 buf := (*C.char)(C.calloc(errorBufferSize, 1))
578 defer C.free(unsafe.Pointer(buf))
579 dev := C.CString(device)
580 defer C.free(unsafe.Pointer(dev))
581
582 cptr := C.pcap_create(dev, buf)
583 if cptr == nil {
584 return nil, errors.New(C.GoString(buf))
585 }
586 return &InactiveHandle{cptr: cptr}, nil
587}
588
589func (p *InactiveHandle) pcapSetSnaplen(snaplen int) error {
590 if status := C.pcap_set_snaplen(p.cptr, C.int(snaplen)); status < 0 {
591 return statusError(status)
592 }
593 return nil
594}
595
596func (p *InactiveHandle) pcapSetPromisc(promisc bool) error {
597 var pro C.int
598 if promisc {
599 pro = 1
600 }
601 if status := C.pcap_set_promisc(p.cptr, pro); status < 0 {
602 return statusError(status)
603 }
604 return nil
605}
606
607func (p *InactiveHandle) pcapSetTimeout(timeout time.Duration) error {
608 if status := C.pcap_set_timeout(p.cptr, C.int(timeoutMillis(timeout))); status < 0 {
609 return statusError(status)
610 }
611 return nil
612}
613
614func (p *InactiveHandle) pcapListTstampTypes() (out []TimestampSource) {
615 var types *C.int
616 n := int(C.pcap_list_tstamp_types(p.cptr, &types))
617 if n < 0 {
618 return // public interface doesn't have error :(
619 }
620 defer C.pcap_free_tstamp_types(types)
621 typesArray := (*[1 << 28]C.int)(unsafe.Pointer(types))
622 for i := 0; i < n; i++ {
623 out = append(out, TimestampSource((*typesArray)[i]))
624 }
625 return
626}
627
628func (p *InactiveHandle) pcapSetTstampType(t TimestampSource) error {
629 if status := C.pcap_set_tstamp_type(p.cptr, C.int(t)); status < 0 {
630 return statusError(status)
631 }
632 return nil
633}
634
635func (p *InactiveHandle) pcapSetRfmon(monitor bool) error {
636 var mon C.int
637 if monitor {
638 mon = 1
639 }
640 switch canset := C.pcap_can_set_rfmon(p.cptr); canset {
641 case 0:
642 return CannotSetRFMon
643 case 1:
644 // success
645 default:
646 return statusError(canset)
647 }
648 if status := C.pcap_set_rfmon(p.cptr, mon); status != 0 {
649 return statusError(status)
650 }
651 return nil
652}
653
654func (p *InactiveHandle) pcapSetBufferSize(bufferSize int) error {
655 if status := C.pcap_set_buffer_size(p.cptr, C.int(bufferSize)); status < 0 {
656 return statusError(status)
657 }
658 return nil
659}
660
661func (p *InactiveHandle) pcapSetImmediateMode(mode bool) error {
662 var md C.int
663 if mode {
664 md = 1
665 }
666 if status := C.pcap_set_immediate_mode(p.cptr, md); status < 0 {
667 return statusError(status)
668 }
669 return nil
670}
671
672func (p *Handle) setNonBlocking() error {
673 buf := (*C.char)(C.calloc(errorBufferSize, 1))
674 defer C.free(unsafe.Pointer(buf))
675
676 // Change the device to non-blocking, we'll use pcap_wait to wait until the
677 // handle is ready to read.
678 if v := C.pcap_setnonblock(p.cptr, 1, buf); v < -1 {
679 return errors.New(C.GoString(buf))
680 }
681
682 return nil
683}
684
685// waitForPacket waits for a packet or for the timeout to expire.
686func (p *Handle) waitForPacket() {
687 // need to wait less than the read timeout according to pcap documentation.
688 // timeoutMillis rounds up to at least one millisecond so we can safely
689 // subtract up to a millisecond.
690 usec := timeoutMillis(p.timeout) * 1000
691 usec -= 100
692
693 C.pcap_wait(p.cptr, C.int(usec))
694}
695
696// openOfflineFile returns contents of input file as a *Handle.
697func openOfflineFile(file *os.File) (handle *Handle, err error) {
698 buf := (*C.char)(C.calloc(errorBufferSize, 1))
699 defer C.free(unsafe.Pointer(buf))
700 cmode := C.CString("rb")
701 defer C.free(unsafe.Pointer(cmode))
702 cf := C.fdopen(C.int(file.Fd()), cmode)
703
704 cptr := C.pcap_fopen_offline_with_tstamp_precision(cf, C.PCAP_TSTAMP_PRECISION_NANO, buf)
705 if cptr == nil {
706 return nil, errors.New(C.GoString(buf))
707 }
708 return &Handle{cptr: cptr}, nil
709}