-
Notifications
You must be signed in to change notification settings - Fork 8
/
reader.go
66 lines (59 loc) · 2 KB
/
reader.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package pcapio
import (
"errors"
"fmt"
"io"
"github.com/brimdata/brimcap/recorder"
"github.com/brimdata/zed/pkg/nano"
"github.com/google/gopacket/layers"
"go.uber.org/multierr"
)
type BlockType int
const (
TypePacket BlockType = iota
TypeSection
TypeInterface
)
// Reader is an interface for reading data blocks from a pcap, either a legacy
// pcap or a next-gen pcap. The Read method returns blocks of data that are
// one of: a pcap file header (TypeSection), a pcap packet including the capture
// header (TypePacket), a pcap-ng section block (TypeSection), a pcap-ng
// interface block (TypeInterface), or a pcap-ng packet block (TypePacket).
// For TypePacket, the capture timestamp and the link-layer type of the packet
// is indicated in the Info return value.
type Reader interface {
Read() ([]byte, BlockType, error)
Packet([]byte) ([]byte, nano.Ts, layers.LinkType, error)
Offset() uint64
}
// NewReader returns a Reader by trying both pcap and pcap-ng formats.
func NewReader(r io.Reader) (Reader, error) {
return NewReaderWithWarnings(r, nil)
}
// NewReaderWithWarnings returns a Reader by trying both pcap and pcap-ng formats
// and arranges for warning messages to be sent over the given channel. Different
// pcap implementations can have out-of-spec peculiarities that can be tolerated
// so we send warnings and try to keep going.
func NewReaderWithWarnings(r io.Reader, warner Warner) (Reader, error) {
record := recorder.NewRecorder(r)
track := recorder.NewTrack(record)
_, err1 := NewPcapReader(track)
if err1 == nil {
return NewPcapReader(record)
}
track.Reset()
_, err2 := NewNgReader(track)
if err2 == nil {
r, err := NewNgReader(record)
r.SetWarningHandler(warner)
return r, err
}
var pcaperr, ngerr *ErrInvalidPcap
if errors.As(err1, &pcaperr) && errors.As(err2, &ngerr) {
err1 = fmt.Errorf("pcap: %w", pcaperr.err)
err2 = fmt.Errorf("pcapng: %w", ngerr.err)
err := multierr.Combine(err1, err2)
return nil, NewErrInvalidPcap(err)
}
return nil, multierr.Combine(err1, err2)
}