github.com/cilium/cilium@v1.16.2/pkg/hubble/recorder/pcap/pcap.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package pcap 5 6 import ( 7 "io" 8 "net" 9 10 "github.com/cilium/cilium/pkg/byteorder" 11 "github.com/cilium/cilium/pkg/time" 12 ) 13 14 // Datalink defines the type of the first layer of the captured packet 15 type Datalink uint32 16 17 var ( 18 Null Datalink = 0 19 Ethernet Datalink = 1 20 ) 21 22 const ( 23 MagicNumber = 0xa1b2c3d4 24 VersionMajor = 2 25 VersionMinor = 4 26 27 TimestampCorrection = 0 28 TimestampAccuracy = 0 29 30 DefaultSnapLen = 65535 31 ) 32 33 const ( 34 GlobalHeaderByteLen = 24 35 RecordHeaderByteLen = 16 36 ) 37 38 // Header contains the configurable parameters for the global pcap header 39 type Header struct { 40 // SnapshotLength is the maximum length of captured packets 41 SnapshotLength uint32 42 // Datalink is the type of header at the beginning of the packet 43 Datalink Datalink 44 } 45 46 // Bytes returns the byte representation of the global pcap header 47 func (h *Header) Bytes() []byte { 48 // https://wiki.wireshark.org/Development/LibpcapFileFormat#Global_Header 49 const ( 50 offsetMagicNumber = 0 51 offsetVersionMajor = 4 52 offsetVersionMinor = 6 53 offsetTimestampCorrection = 8 54 offsetTimestampAccuracy = 12 55 offsetSnapshotLength = 16 56 offsetDatalink = 20 57 ) 58 59 native := byteorder.Native 60 b := make([]byte, GlobalHeaderByteLen) 61 62 snapLen := h.SnapshotLength 63 if snapLen == 0 { 64 snapLen = DefaultSnapLen 65 } 66 67 native.PutUint32(b[offsetMagicNumber:], MagicNumber) 68 native.PutUint16(b[offsetVersionMajor:], VersionMajor) 69 native.PutUint16(b[offsetVersionMinor:], VersionMinor) 70 native.PutUint32(b[offsetTimestampCorrection:], TimestampCorrection) 71 native.PutUint32(b[offsetTimestampAccuracy:], TimestampAccuracy) 72 native.PutUint32(b[offsetSnapshotLength:], snapLen) 73 native.PutUint32(b[offsetDatalink:], uint32(h.Datalink)) 74 75 return b 76 } 77 78 // Record contains the configurable parameters for a record header 79 type Record struct { 80 // Timestamp is the time the packet was captured 81 Timestamp time.Time 82 // CaptureLength is the size of the captured packet 83 CaptureLength uint32 84 // OriginalLength is the size of the original packet 85 OriginalLength uint32 86 } 87 88 // Bytes returns the byte representation of the per-record pcap header 89 func (r *Record) Bytes() []byte { 90 // https://wiki.wireshark.org/Development/LibpcapFileFormat#Record_.28Packet.29_Header 91 const ( 92 offsetTimestampUnix = 0 93 offsetTimestampMicros = 4 94 offsetCaptureLength = 8 95 offsetOriginalLength = 12 96 ) 97 98 tsUnix := uint32(r.Timestamp.Unix()) 99 tsMicros := uint32(r.Timestamp.Nanosecond() / 1000) 100 101 native := byteorder.Native 102 b := make([]byte, RecordHeaderByteLen) 103 104 native.PutUint32(b[offsetTimestampUnix:], tsUnix) 105 native.PutUint32(b[offsetTimestampMicros:], tsMicros) 106 native.PutUint32(b[offsetCaptureLength:], r.CaptureLength) 107 native.PutUint32(b[offsetOriginalLength:], r.OriginalLength) 108 109 return b 110 } 111 112 // RecordWriter defines the interface for pcap writers 113 type RecordWriter interface { 114 // WriteHeader writes the global pcap header. This must be invoked before 115 // WriteRecord is called. 116 WriteHeader(header Header) error 117 // WriteRecord writes a pcap record to the underlying stream. 118 WriteRecord(record Record, packet []byte) error 119 io.Closer 120 } 121 122 var _ RecordWriter = (*Writer)(nil) 123 124 // Writer wraps a io.WriteCloser to implement RecordWriter 125 type Writer struct { 126 io.WriteCloser 127 } 128 129 // NewWriter wraps a io.WriteCloser 130 func NewWriter(w io.WriteCloser) *Writer { 131 return &Writer{ 132 WriteCloser: w, 133 } 134 } 135 136 // WriteHeader implements RecordWriter 137 func (w *Writer) WriteHeader(header Header) error { 138 _, err := w.Write(header.Bytes()) 139 return err 140 } 141 142 // WriteRecord implements RecordWriter 143 func (w *Writer) WriteRecord(record Record, packet []byte) error { 144 ioVec := net.Buffers{record.Bytes(), packet} 145 _, err := ioVec.WriteTo(w) 146 return err 147 }