blob: 6a4ef635240e9765865796933e47b7bd2c62ca0c [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
8package pcap
9
10import (
11 "errors"
12 "fmt"
13 "io"
14 "net"
15 "os"
16 "reflect"
17 "runtime"
18 "strconv"
19 "sync"
20 "sync/atomic"
21 "syscall"
22 "time"
23 "unsafe"
24
25 "github.com/google/gopacket"
26 "github.com/google/gopacket/layers"
27)
28
29// ErrNotActive is returned if handle is not activated
30const ErrNotActive = pcapErrorNotActivated
31
32// MaxBpfInstructions is the maximum number of BPF instructions supported (BPF_MAXINSNS),
33// taken from Linux kernel: include/uapi/linux/bpf_common.h
34//
35// https://github.com/torvalds/linux/blob/master/include/uapi/linux/bpf_common.h
36const MaxBpfInstructions = 4096
37
38// 8 bytes per instruction, max 4096 instructions
39const bpfInstructionBufferSize = 8 * MaxBpfInstructions
40
41// Handle provides a connection to a pcap handle, allowing users to read packets
42// off the wire (Next), inject packets onto the wire (Inject), and
43// perform a number of other functions to affect and understand packet output.
44//
45// Handles are already pcap_activate'd
46type Handle struct {
47 // stop is set to a non-zero value by Handle.Close to signal to
48 // getNextBufPtrLocked to stop trying to read packets
49 // This must be the first entry to ensure alignment for sync.atomic
50 stop uint64
51 // cptr is the handle for the actual pcap C object.
52 cptr pcapTPtr
53 timeout time.Duration
54 device string
55 deviceIndex int
56 mu sync.Mutex
57 closeMu sync.Mutex
58 nanoSecsFactor int64
59
60 // Since pointers to these objects are passed into a C function, if
61 // they're declared locally then the Go compiler thinks they may have
62 // escaped into C-land, so it allocates them on the heap. This causes a
63 // huge memory hit, so to handle that we store them here instead.
64 pkthdr *pcapPkthdr
65 bufptr *uint8
66}
67
68// Stats contains statistics on how many packets were handled by a pcap handle,
69// and what was done with those packets.
70type Stats struct {
71 PacketsReceived int
72 PacketsDropped int
73 PacketsIfDropped int
74}
75
76// Interface describes a single network interface on a machine.
77type Interface struct {
78 Name string
79 Description string
80 Flags uint32
81 Addresses []InterfaceAddress
82}
83
84// Datalink describes the datalink
85type Datalink struct {
86 Name string
87 Description string
88}
89
90// InterfaceAddress describes an address associated with an Interface.
91// Currently, it's IPv4/6 specific.
92type InterfaceAddress struct {
93 IP net.IP
94 Netmask net.IPMask // Netmask may be nil if we were unable to retrieve it.
95 Broadaddr net.IP // Broadcast address for this IP may be nil
96 P2P net.IP // P2P destination address for this IP may be nil
97}
98
99// BPF is a compiled filter program, useful for offline packet matching.
100type BPF struct {
101 orig string
102 bpf pcapBpfProgram // takes a finalizer, not overriden by outsiders
103 hdr pcapPkthdr // allocate on the heap to enable optimizations
104}
105
106// BPFInstruction is a byte encoded structure holding a BPF instruction
107type BPFInstruction struct {
108 Code uint16
109 Jt uint8
110 Jf uint8
111 K uint32
112}
113
114// BlockForever causes it to block forever waiting for packets, when passed
115// into SetTimeout or OpenLive, while still returning incoming packets to userland relatively
116// quickly.
117const BlockForever = -time.Millisecond * 10
118
119func timeoutMillis(timeout time.Duration) int {
120 // Flip sign if necessary. See package docs on timeout for reasoning behind this.
121 if timeout < 0 {
122 timeout *= -1
123 }
124 // Round up
125 if timeout != 0 && timeout < time.Millisecond {
126 timeout = time.Millisecond
127 }
128 return int(timeout / time.Millisecond)
129}
130
131// OpenLive opens a device and returns a *Handle.
132// It takes as arguments the name of the device ("eth0"), the maximum size to
133// read for each packet (snaplen), whether to put the interface in promiscuous
134// mode, and a timeout. Warning: this function supports only microsecond timestamps.
135// For nanosecond resolution use an InactiveHandle.
136//
137// See the package documentation for important details regarding 'timeout'.
138func OpenLive(device string, snaplen int32, promisc bool, timeout time.Duration) (handle *Handle, _ error) {
139 var pro int
140 if promisc {
141 pro = 1
142 }
143
144 p, err := pcapOpenLive(device, int(snaplen), pro, timeoutMillis(timeout))
145 if err != nil {
146 return nil, err
147 }
148 p.timeout = timeout
149 p.device = device
150
151 ifc, err := net.InterfaceByName(device)
152 if err != nil {
153 // The device wasn't found in the OS, but could be "any"
154 // Set index to 0
155 p.deviceIndex = 0
156 } else {
157 p.deviceIndex = ifc.Index
158 }
159
160 p.nanoSecsFactor = 1000
161
162 // Only set the PCAP handle into non-blocking mode if we have a timeout
163 // greater than zero. If the user wants to block forever, we'll let libpcap
164 // handle that.
165 if p.timeout > 0 {
166 if err := p.setNonBlocking(); err != nil {
167 p.pcapClose()
168 return nil, err
169 }
170 }
171
172 return p, nil
173}
174
175// OpenOffline opens a file and returns its contents as a *Handle. Depending on libpcap support and
176// on the timestamp resolution used in the file, nanosecond or microsecond resolution is used
177// internally. All returned timestamps are scaled to nanosecond resolution. Resolution() can be used
178// to query the actual resolution used.
179func OpenOffline(file string) (handle *Handle, err error) {
180 handle, err = openOffline(file)
181 if err != nil {
182 return
183 }
184 if pcapGetTstampPrecision(handle.cptr) == pcapTstampPrecisionNano {
185 handle.nanoSecsFactor = 1
186 } else {
187 handle.nanoSecsFactor = 1000
188 }
189 return
190}
191
192// OpenOfflineFile returns contents of input file as a *Handle. Depending on libpcap support and
193// on the timestamp resolution used in the file, nanosecond or microsecond resolution is used
194// internally. All returned timestamps are scaled to nanosecond resolution. Resolution() can be used
195// to query the actual resolution used.
196func OpenOfflineFile(file *os.File) (handle *Handle, err error) {
197 handle, err = openOfflineFile(file)
198 if err != nil {
199 return
200 }
201 if pcapGetTstampPrecision(handle.cptr) == pcapTstampPrecisionNano {
202 handle.nanoSecsFactor = 1
203 } else {
204 handle.nanoSecsFactor = 1000
205 }
206 return
207}
208
209// NextError is the return code from a call to Next.
210type NextError int32
211
212// NextError implements the error interface.
213func (n NextError) Error() string {
214 switch n {
215 case NextErrorOk:
216 return "OK"
217 case NextErrorTimeoutExpired:
218 return "Timeout Expired"
219 case NextErrorReadError:
220 return "Read Error"
221 case NextErrorNoMorePackets:
222 return "No More Packets In File"
223 case NextErrorNotActivated:
224 return "Not Activated"
225 }
226 return strconv.Itoa(int(n))
227}
228
229// NextError values.
230const (
231 NextErrorOk NextError = 1
232 NextErrorTimeoutExpired NextError = 0
233 NextErrorReadError NextError = -1
234 // NextErrorNoMorePackets is returned when reading from a file (OpenOffline) and
235 // EOF is reached. When this happens, Next() returns io.EOF instead of this.
236 NextErrorNoMorePackets NextError = -2
237 NextErrorNotActivated NextError = -3
238)
239
240// ReadPacketData returns the next packet read from the pcap handle, along with an error
241// code associated with that packet. If the packet is read successfully, the
242// returned error is nil.
243func (p *Handle) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
244 p.mu.Lock()
245 err = p.getNextBufPtrLocked(&ci)
246 if err == nil {
247 data = make([]byte, ci.CaptureLength)
248 copy(data, (*(*[1 << 30]byte)(unsafe.Pointer(p.bufptr)))[:])
249 }
250 p.mu.Unlock()
251 if err == NextErrorTimeoutExpired {
252 runtime.Gosched()
253 }
254 return
255}
256
257type activateError int
258
259const (
260 aeNoError = activateError(0)
261 aeActivated = activateError(pcapErrorActivated)
262 aePromisc = activateError(pcapWarningPromisc)
263 aeNoSuchDevice = activateError(pcapErrorNoSuchDevice)
264 aeDenied = activateError(pcapErrorDenied)
265 aeNotUp = activateError(pcapErrorNotUp)
266 aeWarning = activateError(pcapWarning)
267)
268
269func (a activateError) Error() string {
270 switch a {
271 case aeNoError:
272 return "No Error"
273 case aeActivated:
274 return "Already Activated"
275 case aePromisc:
276 return "Cannot set as promisc"
277 case aeNoSuchDevice:
278 return "No Such Device"
279 case aeDenied:
280 return "Permission Denied"
281 case aeNotUp:
282 return "Interface Not Up"
283 case aeWarning:
284 return fmt.Sprintf("Warning: %v", activateErrMsg.Error())
285 default:
286 return fmt.Sprintf("unknown activated error: %d", a)
287 }
288}
289
290// getNextBufPtrLocked is shared code for ReadPacketData and
291// ZeroCopyReadPacketData.
292func (p *Handle) getNextBufPtrLocked(ci *gopacket.CaptureInfo) error {
293 if !p.isOpen() {
294 return io.EOF
295 }
296
297 // set after we have call waitForPacket for the first time
298 var waited bool
299
300 for atomic.LoadUint64(&p.stop) == 0 {
301 // try to read a packet if one is immediately available
302 result := p.pcapNextPacketEx()
303
304 switch result {
305 case NextErrorOk:
306 sec := p.pkthdr.getSec()
307 // convert micros to nanos
308 nanos := int64(p.pkthdr.getUsec()) * p.nanoSecsFactor
309
310 ci.Timestamp = time.Unix(sec, nanos)
311 ci.CaptureLength = p.pkthdr.getCaplen()
312 ci.Length = p.pkthdr.getLen()
313 ci.InterfaceIndex = p.deviceIndex
314
315 return nil
316 case NextErrorNoMorePackets:
317 // no more packets, return EOF rather than libpcap-specific error
318 return io.EOF
319 case NextErrorTimeoutExpired:
320 // we've already waited for a packet and we're supposed to time out
321 //
322 // we should never actually hit this if we were passed BlockForever
323 // since we should block on C.pcap_next_ex until there's a packet
324 // to read.
325 if waited && p.timeout > 0 {
326 return result
327 }
328
329 // wait for packet before trying again
330 p.waitForPacket()
331 waited = true
332 default:
333 return result
334 }
335 }
336
337 // stop must be set
338 return io.EOF
339}
340
341// ZeroCopyReadPacketData reads the next packet off the wire, and returns its data.
342// The slice returned by ZeroCopyReadPacketData points to bytes owned by the
343// the Handle. Each call to ZeroCopyReadPacketData invalidates any data previously
344// returned by ZeroCopyReadPacketData. Care must be taken not to keep pointers
345// to old bytes when using ZeroCopyReadPacketData... if you need to keep data past
346// the next time you call ZeroCopyReadPacketData, use ReadPacketData, which copies
347// the bytes into a new buffer for you.
348// data1, _, _ := handle.ZeroCopyReadPacketData()
349// // do everything you want with data1 here, copying bytes out of it if you'd like to keep them around.
350// data2, _, _ := handle.ZeroCopyReadPacketData() // invalidates bytes in data1
351func (p *Handle) ZeroCopyReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
352 p.mu.Lock()
353 err = p.getNextBufPtrLocked(&ci)
354 if err == nil {
355 slice := (*reflect.SliceHeader)(unsafe.Pointer(&data))
356 slice.Data = uintptr(unsafe.Pointer(p.bufptr))
357 slice.Len = ci.CaptureLength
358 slice.Cap = ci.CaptureLength
359 }
360 p.mu.Unlock()
361 if err == NextErrorTimeoutExpired {
362 runtime.Gosched()
363 }
364 return
365}
366
367// Close closes the underlying pcap handle.
368func (p *Handle) Close() {
369 p.closeMu.Lock()
370 defer p.closeMu.Unlock()
371
372 if !p.isOpen() {
373 return
374 }
375
376 atomic.StoreUint64(&p.stop, 1)
377
378 // wait for packet reader to stop
379 p.mu.Lock()
380 defer p.mu.Unlock()
381
382 p.pcapClose()
383}
384
385// Error returns the current error associated with a pcap handle (pcap_geterr).
386func (p *Handle) Error() error {
387 return p.pcapGeterr()
388}
389
390// Stats returns statistics on the underlying pcap handle.
391func (p *Handle) Stats() (stat *Stats, err error) {
392 return p.pcapStats()
393}
394
395// ListDataLinks obtains a list of all possible data link types supported for an interface.
396func (p *Handle) ListDataLinks() (datalinks []Datalink, err error) {
397 return p.pcapListDatalinks()
398}
399
400// compileBPFFilter always returns an allocated C.struct_bpf_program
401// It is the callers responsibility to free the memory again, e.g.
402//
403// C.pcap_freecode(&bpf)
404//
405func (p *Handle) compileBPFFilter(expr string) (pcapBpfProgram, error) {
406 var maskp = uint32(pcapNetmaskUnknown)
407
408 // Only do the lookup on network interfaces.
409 // No device indicates we're handling a pcap file.
410 if len(p.device) > 0 {
411 var err error
412 _, maskp, err = pcapLookupnet(p.device)
413 if err != nil {
414 // We can't lookup the network, but that could be because the interface
415 // doesn't have an IPv4.
416 maskp = uint32(pcapNetmaskUnknown)
417 }
418 }
419
420 return p.pcapCompile(expr, maskp)
421}
422
423// CompileBPFFilter compiles and returns a BPF filter with given a link type and capture length.
424func CompileBPFFilter(linkType layers.LinkType, captureLength int, expr string) ([]BPFInstruction, error) {
425 h, err := pcapOpenDead(linkType, captureLength)
426 if err != nil {
427 return nil, err
428 }
429 defer h.Close()
430 return h.CompileBPFFilter(expr)
431}
432
433// CompileBPFFilter compiles and returns a BPF filter for the pcap handle.
434func (p *Handle) CompileBPFFilter(expr string) ([]BPFInstruction, error) {
435 bpf, err := p.compileBPFFilter(expr)
436 defer bpf.free()
437 if err != nil {
438 return nil, err
439 }
440
441 return bpf.toBPFInstruction(), nil
442}
443
444// SetBPFFilter compiles and sets a BPF filter for the pcap handle.
445func (p *Handle) SetBPFFilter(expr string) (err error) {
446 bpf, err := p.compileBPFFilter(expr)
447 defer bpf.free()
448 if err != nil {
449 return err
450 }
451
452 return p.pcapSetfilter(bpf)
453}
454
455// SetBPFInstructionFilter may be used to apply a filter in BPF asm byte code format.
456//
457// Simplest way to generate BPF asm byte code is with tcpdump:
458// tcpdump -dd 'udp'
459//
460// The output may be used directly to add a filter, e.g.:
461// bpfInstructions := []pcap.BpfInstruction{
462// {0x28, 0, 0, 0x0000000c},
463// {0x15, 0, 9, 0x00000800},
464// {0x30, 0, 0, 0x00000017},
465// {0x15, 0, 7, 0x00000006},
466// {0x28, 0, 0, 0x00000014},
467// {0x45, 5, 0, 0x00001fff},
468// {0xb1, 0, 0, 0x0000000e},
469// {0x50, 0, 0, 0x0000001b},
470// {0x54, 0, 0, 0x00000012},
471// {0x15, 0, 1, 0x00000012},
472// {0x6, 0, 0, 0x0000ffff},
473// {0x6, 0, 0, 0x00000000},
474// }
475//
476// An other posibility is to write the bpf code in bpf asm.
477// Documentation: https://www.kernel.org/doc/Documentation/networking/filter.txt
478//
479// To compile the code use bpf_asm from
480// https://github.com/torvalds/linux/tree/master/tools/net
481//
482// The following command may be used to convert bpf_asm output to c/go struct, usable for SetBPFFilterByte:
483// bpf_asm -c tcp.bpf
484func (p *Handle) SetBPFInstructionFilter(bpfInstructions []BPFInstruction) (err error) {
485 bpf, err := bpfInstructionFilter(bpfInstructions)
486 if err != nil {
487 return err
488 }
489 defer bpf.free()
490
491 return p.pcapSetfilter(bpf)
492}
493
494func bpfInstructionFilter(bpfInstructions []BPFInstruction) (bpf pcapBpfProgram, err error) {
495 if len(bpfInstructions) < 1 {
496 return bpf, errors.New("bpfInstructions must not be empty")
497 }
498
499 if len(bpfInstructions) > MaxBpfInstructions {
500 return bpf, fmt.Errorf("bpfInstructions must not be larger than %d", MaxBpfInstructions)
501 }
502
503 return pcapBpfProgramFromInstructions(bpfInstructions), nil
504}
505
506// NewBPF compiles the given string into a new filter program.
507//
508// BPF filters need to be created from activated handles, because they need to
509// know the underlying link type to correctly compile their offsets.
510func (p *Handle) NewBPF(expr string) (*BPF, error) {
511 bpf := &BPF{orig: expr}
512
513 var err error
514 bpf.bpf, err = p.pcapCompile(expr, pcapNetmaskUnknown)
515 if err != nil {
516 return nil, err
517 }
518
519 runtime.SetFinalizer(bpf, destroyBPF)
520 return bpf, nil
521}
522
523// NewBPF allows to create a BPF without requiring an existing handle.
524// This allows to match packets obtained from a-non GoPacket capture source
525// to be matched.
526//
527// buf := make([]byte, MaxFrameSize)
528// bpfi, _ := pcap.NewBPF(layers.LinkTypeEthernet, MaxFrameSize, "icmp")
529// n, _ := someIO.Read(buf)
530// ci := gopacket.CaptureInfo{CaptureLength: n, Length: n}
531// if bpfi.Matches(ci, buf) {
532// doSomething()
533// }
534func NewBPF(linkType layers.LinkType, captureLength int, expr string) (*BPF, error) {
535 h, err := pcapOpenDead(linkType, captureLength)
536 if err != nil {
537 return nil, err
538 }
539 defer h.Close()
540 return h.NewBPF(expr)
541}
542
543// NewBPFInstructionFilter sets the given BPFInstructions as new filter program.
544//
545// More details see func SetBPFInstructionFilter
546//
547// BPF filters need to be created from activated handles, because they need to
548// know the underlying link type to correctly compile their offsets.
549func (p *Handle) NewBPFInstructionFilter(bpfInstructions []BPFInstruction) (*BPF, error) {
550 var err error
551 bpf := &BPF{orig: "BPF Instruction Filter"}
552
553 bpf.bpf, err = bpfInstructionFilter(bpfInstructions)
554 if err != nil {
555 return nil, err
556 }
557
558 runtime.SetFinalizer(bpf, destroyBPF)
559 return bpf, nil
560}
561func destroyBPF(bpf *BPF) {
562 bpf.bpf.free()
563}
564
565// String returns the original string this BPF filter was compiled from.
566func (b *BPF) String() string {
567 return b.orig
568}
569
570// Matches returns true if the given packet data matches this filter.
571func (b *BPF) Matches(ci gopacket.CaptureInfo, data []byte) bool {
572 return b.pcapOfflineFilter(ci, data)
573}
574
575// Version returns pcap_lib_version.
576func Version() string {
577 return pcapLibVersion()
578}
579
580// LinkType returns pcap_datalink, as a layers.LinkType.
581func (p *Handle) LinkType() layers.LinkType {
582 return p.pcapDatalink()
583}
584
585// SetLinkType calls pcap_set_datalink on the pcap handle.
586func (p *Handle) SetLinkType(dlt layers.LinkType) error {
587 return p.pcapSetDatalink(dlt)
588}
589
590// DatalinkValToName returns pcap_datalink_val_to_name as string
591func DatalinkValToName(dlt int) string {
592 return pcapDatalinkValToName(dlt)
593}
594
595// DatalinkValToDescription returns pcap_datalink_val_to_description as string
596func DatalinkValToDescription(dlt int) string {
597 return pcapDatalinkValToDescription(dlt)
598}
599
600// DatalinkNameToVal returns pcap_datalink_name_to_val as int
601func DatalinkNameToVal(name string) int {
602 return pcapDatalinkNameToVal(name)
603}
604
605// FindAllDevs attempts to enumerate all interfaces on the current machine.
606func FindAllDevs() (ifs []Interface, err error) {
607 alldevsp, err := pcapFindAllDevs()
608 if err != nil {
609 return nil, err
610 }
611 defer alldevsp.free()
612
613 for alldevsp.next() {
614 var iface Interface
615 iface.Name = alldevsp.name()
616 iface.Description = alldevsp.description()
617 iface.Addresses = findalladdresses(alldevsp.addresses())
618 iface.Flags = alldevsp.flags()
619 ifs = append(ifs, iface)
620 }
621 return
622}
623
624func findalladdresses(addresses pcapAddresses) (retval []InterfaceAddress) {
625 // TODO - make it support more than IPv4 and IPv6?
626 retval = make([]InterfaceAddress, 0, 1)
627 for addresses.next() {
628 // Strangely, it appears that in some cases, we get a pcap address back from
629 // pcap_findalldevs with a nil .addr. It appears that we can skip over
630 // these.
631 if addresses.addr() == nil {
632 continue
633 }
634 var a InterfaceAddress
635 var err error
636 if a.IP, err = sockaddrToIP(addresses.addr()); err != nil {
637 continue
638 }
639 // To be safe, we'll also check for netmask.
640 if addresses.netmask() == nil {
641 continue
642 }
643 if a.Netmask, err = sockaddrToIP(addresses.netmask()); err != nil {
644 // If we got an IP address but we can't get a netmask, just return the IP
645 // address.
646 a.Netmask = nil
647 }
648 if a.Broadaddr, err = sockaddrToIP(addresses.broadaddr()); err != nil {
649 a.Broadaddr = nil
650 }
651 if a.P2P, err = sockaddrToIP(addresses.dstaddr()); err != nil {
652 a.P2P = nil
653 }
654 retval = append(retval, a)
655 }
656 return
657}
658
659func sockaddrToIP(rsa *syscall.RawSockaddr) (IP []byte, err error) {
660 if rsa == nil {
661 err = errors.New("Value not set")
662 return
663 }
664 switch rsa.Family {
665 case syscall.AF_INET:
666 pp := (*syscall.RawSockaddrInet4)(unsafe.Pointer(rsa))
667 IP = make([]byte, 4)
668 for i := 0; i < len(IP); i++ {
669 IP[i] = pp.Addr[i]
670 }
671 return
672 case syscall.AF_INET6:
673 pp := (*syscall.RawSockaddrInet6)(unsafe.Pointer(rsa))
674 IP = make([]byte, 16)
675 for i := 0; i < len(IP); i++ {
676 IP[i] = pp.Addr[i]
677 }
678 return
679 }
680 err = errors.New("Unsupported address type")
681 return
682}
683
684// WritePacketData calls pcap_sendpacket, injecting the given data into the pcap handle.
685func (p *Handle) WritePacketData(data []byte) (err error) {
686 return p.pcapSendpacket(data)
687}
688
689// Direction is used by Handle.SetDirection.
690type Direction uint8
691
692// Direction values for Handle.SetDirection.
693const (
694 DirectionIn = Direction(pcapDIN)
695 DirectionOut = Direction(pcapDOUT)
696 DirectionInOut = Direction(pcapDINOUT)
697)
698
699// SetDirection sets the direction for which packets will be captured.
700func (p *Handle) SetDirection(direction Direction) error {
701 if direction != DirectionIn && direction != DirectionOut && direction != DirectionInOut {
702 return fmt.Errorf("Invalid direction: %v", direction)
703 }
704 return p.pcapSetdirection(direction)
705}
706
707// SnapLen returns the snapshot length
708func (p *Handle) SnapLen() int {
709 return p.pcapSnapshot()
710}
711
712// Resolution returns the timestamp resolution of acquired timestamps before scaling to NanosecondTimestampResolution.
713func (p *Handle) Resolution() gopacket.TimestampResolution {
714 if p.nanoSecsFactor == 1 {
715 return gopacket.TimestampResolutionMicrosecond
716 }
717 return gopacket.TimestampResolutionNanosecond
718}
719
720// TimestampSource tells PCAP which type of timestamp to use for packets.
721type TimestampSource int
722
723// String returns the timestamp type as a human-readable string.
724func (t TimestampSource) String() string {
725 return t.pcapTstampTypeValToName()
726}
727
728// TimestampSourceFromString translates a string into a timestamp type, case
729// insensitive.
730func TimestampSourceFromString(s string) (TimestampSource, error) {
731 return pcapTstampTypeNameToVal(s)
732}
733
734// InactiveHandle allows you to call pre-pcap_activate functions on your pcap
735// handle to set it up just the way you'd like.
736type InactiveHandle struct {
737 // cptr is the handle for the actual pcap C object.
738 cptr pcapTPtr
739 device string
740 deviceIndex int
741 timeout time.Duration
742}
743
744// holds the err messoge in case activation returned a Warning
745var activateErrMsg error
746
747// Error returns the current error associated with a pcap handle (pcap_geterr).
748func (p *InactiveHandle) Error() error {
749 return p.pcapGeterr()
750}
751
752// Activate activates the handle. The current InactiveHandle becomes invalid
753// and all future function calls on it will fail.
754func (p *InactiveHandle) Activate() (*Handle, error) {
755 // ignore error with set_tstamp_precision, since the actual precision is queried later anyway
756 pcapSetTstampPrecision(p.cptr, pcapTstampPrecisionNano)
757 handle, err := p.pcapActivate()
758 if err != aeNoError {
759 if err == aeWarning {
760 activateErrMsg = p.Error()
761 }
762 return nil, err
763 }
764 handle.timeout = p.timeout
765 if p.timeout > 0 {
766 if err := handle.setNonBlocking(); err != nil {
767 handle.pcapClose()
768 return nil, err
769 }
770 }
771 handle.device = p.device
772 handle.deviceIndex = p.deviceIndex
773 if pcapGetTstampPrecision(handle.cptr) == pcapTstampPrecisionNano {
774 handle.nanoSecsFactor = 1
775 } else {
776 handle.nanoSecsFactor = 1000
777 }
778 return handle, nil
779}
780
781// CleanUp cleans up any stuff left over from a successful or failed building
782// of a handle.
783func (p *InactiveHandle) CleanUp() {
784 p.pcapClose()
785}
786
787// NewInactiveHandle creates a new InactiveHandle, which wraps an un-activated PCAP handle.
788// Callers of NewInactiveHandle should immediately defer 'CleanUp', as in:
789// inactive := NewInactiveHandle("eth0")
790// defer inactive.CleanUp()
791func NewInactiveHandle(device string) (*InactiveHandle, error) {
792 // Try to get the interface index, but iy could be something like "any"
793 // in which case use 0, which doesn't exist in nature
794 deviceIndex := 0
795 ifc, err := net.InterfaceByName(device)
796 if err == nil {
797 deviceIndex = ifc.Index
798 }
799
800 // This copies a bunch of the pcap_open_live implementation from pcap.c:
801 handle, err := pcapCreate(device)
802 if err != nil {
803 return nil, err
804 }
805 handle.device = device
806 handle.deviceIndex = deviceIndex
807 return handle, nil
808}
809
810// SetSnapLen sets the snap length (max bytes per packet to capture).
811func (p *InactiveHandle) SetSnapLen(snaplen int) error {
812 return p.pcapSetSnaplen(snaplen)
813}
814
815// SetPromisc sets the handle to either be promiscuous (capture packets
816// unrelated to this host) or not.
817func (p *InactiveHandle) SetPromisc(promisc bool) error {
818 return p.pcapSetPromisc(promisc)
819}
820
821// SetTimeout sets the read timeout for the handle.
822//
823// See the package documentation for important details regarding 'timeout'.
824func (p *InactiveHandle) SetTimeout(timeout time.Duration) error {
825 err := p.pcapSetTimeout(timeout)
826 if err != nil {
827 return err
828 }
829 p.timeout = timeout
830 return nil
831}
832
833// SupportedTimestamps returns a list of supported timstamp types for this
834// handle.
835func (p *InactiveHandle) SupportedTimestamps() (out []TimestampSource) {
836 return p.pcapListTstampTypes()
837}
838
839// SetTimestampSource sets the type of timestamp generator PCAP uses when
840// attaching timestamps to packets.
841func (p *InactiveHandle) SetTimestampSource(t TimestampSource) error {
842 return p.pcapSetTstampType(t)
843}
844
845// CannotSetRFMon is returned by SetRFMon if the handle does not allow
846// setting RFMon because pcap_can_set_rfmon returns 0.
847var CannotSetRFMon = errors.New("Cannot set rfmon for this handle")
848
849// SetRFMon turns on radio monitoring mode, similar to promiscuous mode but for
850// wireless networks. If this mode is enabled, the interface will not need to
851// associate with an access point before it can receive traffic.
852func (p *InactiveHandle) SetRFMon(monitor bool) error {
853 return p.pcapSetRfmon(monitor)
854}
855
856// SetBufferSize sets the buffer size (in bytes) of the handle.
857func (p *InactiveHandle) SetBufferSize(bufferSize int) error {
858 return p.pcapSetBufferSize(bufferSize)
859}
860
861// SetImmediateMode sets (or unsets) the immediate mode of the
862// handle. In immediate mode, packets are delivered to the application
863// as soon as they arrive. In other words, this overrides SetTimeout.
864func (p *InactiveHandle) SetImmediateMode(mode bool) error {
865 return p.pcapSetImmediateMode(mode)
866}