mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00

Moves the vendor/ directory to cmd/vendor. Vendored binaries are built from cmd/, which is backed by symlinks pointing back to repo root.
207 lines
4.9 KiB
Go
207 lines
4.9 KiB
Go
package pcap
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
"time"
|
|
)
|
|
|
|
// FileHeader is the parsed header of a pcap file.
|
|
// http://wiki.wireshark.org/Development/LibpcapFileFormat
|
|
type FileHeader struct {
|
|
MagicNumber uint32
|
|
VersionMajor uint16
|
|
VersionMinor uint16
|
|
TimeZone int32
|
|
SigFigs uint32
|
|
SnapLen uint32
|
|
Network uint32
|
|
}
|
|
|
|
type PacketTime struct {
|
|
Sec int32
|
|
Usec int32
|
|
}
|
|
|
|
// Convert the PacketTime to a go Time struct.
|
|
func (p *PacketTime) Time() time.Time {
|
|
return time.Unix(int64(p.Sec), int64(p.Usec)*1000)
|
|
}
|
|
|
|
// Packet is a single packet parsed from a pcap file.
|
|
//
|
|
// Convenient access to IP, TCP, and UDP headers is provided after Decode()
|
|
// is called if the packet is of the appropriate type.
|
|
type Packet struct {
|
|
Time time.Time // packet send/receive time
|
|
Caplen uint32 // bytes stored in the file (caplen <= len)
|
|
Len uint32 // bytes sent/received
|
|
Data []byte // packet data
|
|
|
|
Type int // protocol type, see LINKTYPE_*
|
|
DestMac uint64
|
|
SrcMac uint64
|
|
|
|
Headers []interface{} // decoded headers, in order
|
|
Payload []byte // remaining non-header bytes
|
|
|
|
IP *Iphdr // IP header (for IP packets, after decoding)
|
|
TCP *Tcphdr // TCP header (for TCP packets, after decoding)
|
|
UDP *Udphdr // UDP header (for UDP packets after decoding)
|
|
}
|
|
|
|
// Reader parses pcap files.
|
|
type Reader struct {
|
|
flip bool
|
|
buf io.Reader
|
|
err error
|
|
fourBytes []byte
|
|
twoBytes []byte
|
|
sixteenBytes []byte
|
|
Header FileHeader
|
|
}
|
|
|
|
// NewReader reads pcap data from an io.Reader.
|
|
func NewReader(reader io.Reader) (*Reader, error) {
|
|
r := &Reader{
|
|
buf: reader,
|
|
fourBytes: make([]byte, 4),
|
|
twoBytes: make([]byte, 2),
|
|
sixteenBytes: make([]byte, 16),
|
|
}
|
|
switch magic := r.readUint32(); magic {
|
|
case 0xa1b2c3d4:
|
|
r.flip = false
|
|
case 0xd4c3b2a1:
|
|
r.flip = true
|
|
default:
|
|
return nil, fmt.Errorf("pcap: bad magic number: %0x", magic)
|
|
}
|
|
r.Header = FileHeader{
|
|
MagicNumber: 0xa1b2c3d4,
|
|
VersionMajor: r.readUint16(),
|
|
VersionMinor: r.readUint16(),
|
|
TimeZone: r.readInt32(),
|
|
SigFigs: r.readUint32(),
|
|
SnapLen: r.readUint32(),
|
|
Network: r.readUint32(),
|
|
}
|
|
return r, nil
|
|
}
|
|
|
|
// Next returns the next packet or nil if no more packets can be read.
|
|
func (r *Reader) Next() *Packet {
|
|
d := r.sixteenBytes
|
|
r.err = r.read(d)
|
|
if r.err != nil {
|
|
return nil
|
|
}
|
|
timeSec := asUint32(d[0:4], r.flip)
|
|
timeUsec := asUint32(d[4:8], r.flip)
|
|
capLen := asUint32(d[8:12], r.flip)
|
|
origLen := asUint32(d[12:16], r.flip)
|
|
|
|
data := make([]byte, capLen)
|
|
if r.err = r.read(data); r.err != nil {
|
|
return nil
|
|
}
|
|
return &Packet{
|
|
Time: time.Unix(int64(timeSec), int64(timeUsec)),
|
|
Caplen: capLen,
|
|
Len: origLen,
|
|
Data: data,
|
|
}
|
|
}
|
|
|
|
func (r *Reader) read(data []byte) error {
|
|
var err error
|
|
n, err := r.buf.Read(data)
|
|
for err == nil && n != len(data) {
|
|
var chunk int
|
|
chunk, err = r.buf.Read(data[n:])
|
|
n += chunk
|
|
}
|
|
if len(data) == n {
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (r *Reader) readUint32() uint32 {
|
|
data := r.fourBytes
|
|
if r.err = r.read(data); r.err != nil {
|
|
return 0
|
|
}
|
|
return asUint32(data, r.flip)
|
|
}
|
|
|
|
func (r *Reader) readInt32() int32 {
|
|
data := r.fourBytes
|
|
if r.err = r.read(data); r.err != nil {
|
|
return 0
|
|
}
|
|
return int32(asUint32(data, r.flip))
|
|
}
|
|
|
|
func (r *Reader) readUint16() uint16 {
|
|
data := r.twoBytes
|
|
if r.err = r.read(data); r.err != nil {
|
|
return 0
|
|
}
|
|
return asUint16(data, r.flip)
|
|
}
|
|
|
|
// Writer writes a pcap file.
|
|
type Writer struct {
|
|
writer io.Writer
|
|
buf []byte
|
|
}
|
|
|
|
// NewWriter creates a Writer that stores output in an io.Writer.
|
|
// The FileHeader is written immediately.
|
|
func NewWriter(writer io.Writer, header *FileHeader) (*Writer, error) {
|
|
w := &Writer{
|
|
writer: writer,
|
|
buf: make([]byte, 24),
|
|
}
|
|
binary.LittleEndian.PutUint32(w.buf, header.MagicNumber)
|
|
binary.LittleEndian.PutUint16(w.buf[4:], header.VersionMajor)
|
|
binary.LittleEndian.PutUint16(w.buf[6:], header.VersionMinor)
|
|
binary.LittleEndian.PutUint32(w.buf[8:], uint32(header.TimeZone))
|
|
binary.LittleEndian.PutUint32(w.buf[12:], header.SigFigs)
|
|
binary.LittleEndian.PutUint32(w.buf[16:], header.SnapLen)
|
|
binary.LittleEndian.PutUint32(w.buf[20:], header.Network)
|
|
if _, err := writer.Write(w.buf); err != nil {
|
|
return nil, err
|
|
}
|
|
return w, nil
|
|
}
|
|
|
|
// Writer writes a packet to the underlying writer.
|
|
func (w *Writer) Write(pkt *Packet) error {
|
|
binary.LittleEndian.PutUint32(w.buf, uint32(pkt.Time.Unix()))
|
|
binary.LittleEndian.PutUint32(w.buf[4:], uint32(pkt.Time.Nanosecond()))
|
|
binary.LittleEndian.PutUint32(w.buf[8:], uint32(pkt.Time.Unix()))
|
|
binary.LittleEndian.PutUint32(w.buf[12:], pkt.Len)
|
|
if _, err := w.writer.Write(w.buf[:16]); err != nil {
|
|
return err
|
|
}
|
|
_, err := w.writer.Write(pkt.Data)
|
|
return err
|
|
}
|
|
|
|
func asUint32(data []byte, flip bool) uint32 {
|
|
if flip {
|
|
return binary.BigEndian.Uint32(data)
|
|
}
|
|
return binary.LittleEndian.Uint32(data)
|
|
}
|
|
|
|
func asUint16(data []byte, flip bool) uint16 {
|
|
if flip {
|
|
return binary.BigEndian.Uint16(data)
|
|
}
|
|
return binary.LittleEndian.Uint16(data)
|
|
}
|