refactor http packet capture

This commit is contained in:
soypat
2025-06-03 23:48:51 -03:00
parent 2d71907241
commit 7c5b427b14
4 changed files with 58 additions and 17 deletions
+1 -1
View File
@@ -110,7 +110,7 @@ func doHTTP(conn *internet.TCPConn, hdr *httpraw.Header) error {
return nil // No data yet.
}
fmt.Println("state is established; check request and send response")
_, err := hdr.ReadFromLimited(conn, hdr.Free())
_, err := hdr.ReadFromLimited(conn, hdr.BufferFree())
if err != nil {
return err
}
+16 -6
View File
@@ -119,7 +119,7 @@ func (h *Header) ReadFromLimited(r io.Reader, maxBytesToRead int) (int, error) {
} else if h.flags.hasAny(flagMangledBuffer) {
return 0, errMangledBuffer
}
free := h.Free()
free := h.BufferFree()
if free < maxBytesToRead {
if h.flags.hasAny(flagNoBufferGrow) {
return 0, errSmallBuffer
@@ -145,7 +145,7 @@ func (h *Header) ReadFromBytes(b []byte) (int, error) {
if len(b) == 0 {
return 0, errSmallBuffer
}
free := h.Free()
free := h.BufferFree()
if free < len(b) {
if h.flags.hasAny(flagNoBufferGrow) {
return 0, errSmallBuffer
@@ -156,13 +156,23 @@ func (h *Header) ReadFromBytes(b []byte) (int, error) {
return len(b), nil
}
// Free returns amount of bytes free in underlying buffer.
func (h *Header) Free() int {
// BufferParsed returns the amount of bytes parsed during a call to Parse* methods.
// If the Parse* method completed without error then BufferParsed returns the header's length including the final "\r\n\r\n" text.
// BufferParsed returns 0 if the buffer is invalid/mangled or if no header data has been parsed succesfully.
func (h *Header) BufferParsed() int {
if h.flags.hasAny(flagMangledBuffer | flagOOMReached) {
return 0
}
return h.hbuf.off
}
// BufferFree returns amount of bytes free in underlying buffer.
func (h *Header) BufferFree() int {
return h.hbuf.free()
}
// Capacity returns the total capacity of the underlying buffer.
func (h *Header) Capacity() int {
// BufferCapacity returns the total capacity of the underlying buffer.
func (h *Header) BufferCapacity() int {
return cap(h.hbuf.buf)
}
+25 -9
View File
@@ -181,7 +181,7 @@ func (pc *PacketBreakdown) CaptureTCP(dst []Frame, pkt []byte, bitOffset int) ([
}
func (pc *PacketBreakdown) CaptureHTTP(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
const protocol = "HTTP"
const httpProtocol = "HTTP"
if bitOffset%8 != 0 {
return nil, errors.New("HTTP must be parsed at byte boundary")
}
@@ -190,16 +190,32 @@ func (pc *PacketBreakdown) CaptureHTTP(dst []Frame, pkt []byte, bitOffset int) (
httpData := pkt[bitOffset/8:]
pc.hdr.Reset(httpData)
err := pc.hdr.Parse(asResponse)
if err == nil {
dst = append(dst, remainingFrameInfo(protocol, FieldClassText, bitOffset, len(pkt)))
return dst, nil
if err != nil {
pc.hdr.Reset(httpData)
err = pc.hdr.Parse(asRequest) // try as request.
}
pc.hdr.Reset(httpData)
err = pc.hdr.Parse(asRequest)
if err == nil {
dst = append(dst, remainingFrameInfo(protocol, FieldClassText, bitOffset, len(pkt)))
return dst, nil
if err != nil {
return dst, err
}
hdrLen := pc.hdr.BufferParsed()
body, _ := pc.hdr.Body()
dst = append(dst, Frame{
Protocol: httpProtocol,
PacketBitOffset: bitOffset,
Fields: []FrameField{
{
Name: "HTTP Header",
Class: FieldClassText,
FrameBitOffset: 0,
BitLength: hdrLen * octet,
},
{
Class: FieldClassPayload,
FrameBitOffset: hdrLen * octet,
BitLength: len(body) * octet,
},
},
})
return dst, err
}
+16 -1
View File
@@ -15,6 +15,7 @@ import (
func TestCap(t *testing.T) {
const mtu = 1500
const httpBody = "{200,ok}"
var buf [mtu]byte
var gen ltesto.PacketGen
rng := rand.New(rand.NewSource(1))
@@ -29,6 +30,8 @@ func TestCap(t *testing.T) {
var hdr httpraw.Header
hdr.SetStatus("200", "OK")
hdr.Set("Cookie", "ABC=123")
pkt, _ = hdr.AppendResponse(pkt)
pkt = append(pkt, httpBody...)
var pbreak PacketBreakdown
frames, err := pbreak.CaptureEthernet(nil, pkt, 0)
if err != nil {
@@ -55,11 +58,19 @@ func TestCap(t *testing.T) {
}
return math.MaxUint64
}
getClassData := func(frame Frame, class FieldClass) []byte {
idx, err := frame.FieldByClass(class)
if err != nil {
return nil
}
v, _ := frame.AppendField(nil, idx, pkt)
return v
}
efrm, _ := ethernet.NewFrame(pkt)
pefrm := frames[0]
pifrm := frames[1]
ptfrm := frames[2]
// phfrm := frames[3]
phfrm := frames[3]
gotEproto := ethernet.Type(getClass(pefrm, FieldClassProto))
if gotEproto != efrm.EtherTypeOrSize() {
t.Errorf("want %s ethernet type, got %s", efrm.EtherTypeOrSize().String(), gotEproto.String())
@@ -95,4 +106,8 @@ func TestCap(t *testing.T) {
if gotHeaderLen != uint64(wantHeaderLen) {
t.Errorf("want %d TCP header length, got %d", wantHeaderLen, gotHeaderLen)
}
gotBody := getClassData(phfrm, FieldClassPayload)
if string(gotBody) != httpBody {
t.Errorf("want %q HTTP body, got %q", httpBody, gotBody)
}
}