74 lines
1.8 KiB
Go
74 lines
1.8 KiB
Go
package pcap
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
)
|
|
|
|
// SplitLimit bounds each output file of Split. Zero means no limit.
|
|
type SplitLimit struct {
|
|
Packets int // maximum packets per file
|
|
Bytes int64 // maximum file size, including the file and record headers
|
|
}
|
|
|
|
// SplitStats summarizes a Split.
|
|
type SplitStats struct {
|
|
Packets int // packets copied
|
|
Parts int // files created
|
|
Truncated bool // the input ended with an incomplete packet record, which was dropped
|
|
}
|
|
|
|
// Split copies the pcap file read from r into consecutive parts, each starting
|
|
// with the input's file header and holding whole packet records, so that no
|
|
// part exceeds the limit. A packet that is bigger than the size limit on its
|
|
// own goes into a part by itself. create is called to open part 1, 2, ...
|
|
func Split(r io.Reader, limit SplitLimit, create func(part int) (io.Writer, error)) (SplitStats, error) {
|
|
var st SplitStats
|
|
pr, err := NewReader(r)
|
|
if err != nil {
|
|
return st, err
|
|
}
|
|
|
|
var (
|
|
w io.Writer
|
|
nPackets int
|
|
nBytes int64
|
|
)
|
|
for {
|
|
rec, err := pr.Next()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if errors.Is(err, ErrTruncated) {
|
|
st.Truncated = true
|
|
break
|
|
}
|
|
if err != nil {
|
|
return st, err
|
|
}
|
|
|
|
full := limit.Packets > 0 && nPackets >= limit.Packets ||
|
|
limit.Bytes > 0 && nPackets > 0 && nBytes+int64(len(rec)) > limit.Bytes
|
|
if w == nil || full {
|
|
st.Parts++
|
|
if w, err = create(st.Parts); err != nil {
|
|
return st, err
|
|
}
|
|
if _, err := w.Write(pr.Header()); err != nil {
|
|
return st, err
|
|
}
|
|
nPackets, nBytes = 0, int64(len(pr.Header()))
|
|
}
|
|
if _, err := w.Write(rec); err != nil {
|
|
return st, err
|
|
}
|
|
nPackets++
|
|
nBytes += int64(len(rec))
|
|
st.Packets++
|
|
}
|
|
if st.Packets == 0 {
|
|
return st, errors.New("the pcap file contains no packets")
|
|
}
|
|
return st, nil
|
|
}
|