Add hex2pcap
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"pcap-web-tools/internal/pcap"
|
||||
)
|
||||
|
||||
func TestBuildPacketConcatenatesWithoutFix(t *testing.T) {
|
||||
res, err := buildPacket(hex2pcapForm{L2: "aa bb", L3: "cc", L7: "dd:ee"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(res.Packet, []byte{0xaa, 0xbb, 0xcc, 0xdd, 0xee}) {
|
||||
t.Errorf("packet %x", res.Packet)
|
||||
}
|
||||
if res.LinkType != pcap.LinkTypeEthernet || res.Fixed {
|
||||
t.Errorf("link type %d fixed %v", res.LinkType, res.Fixed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildPacketLinkType(t *testing.T) {
|
||||
tests := []struct {
|
||||
form hex2pcapForm
|
||||
want uint32
|
||||
}{
|
||||
{hex2pcapForm{L3: "45"}, pcap.LinkTypeRaw},
|
||||
{hex2pcapForm{L2: "00", L3: "45"}, pcap.LinkTypeEthernet},
|
||||
{hex2pcapForm{L7: "00"}, pcap.LinkTypeEthernet},
|
||||
{hex2pcapForm{L3: "45", LinkType: "113"}, pcap.LinkTypeLinuxSLL},
|
||||
{hex2pcapForm{L7: "00", LinkType: "custom", CustomLinkType: "228"}, 228},
|
||||
{hex2pcapForm{L7: "00", LinkType: "custom", CustomLinkType: "0x93"}, 147},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
res, err := buildPacket(tt.form)
|
||||
if err != nil {
|
||||
t.Errorf("%+v: %v", tt.form, err)
|
||||
continue
|
||||
}
|
||||
if res.LinkType != tt.want {
|
||||
t.Errorf("%+v: link type %d, want %d", tt.form, res.LinkType, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildPacketFixWholeFrameInPayload(t *testing.T) {
|
||||
// Full Ethernet + IPv4 + ICMP frame pasted into the payload field only.
|
||||
res, err := buildPacket(hex2pcapForm{
|
||||
L7: "00112233445566778899aabb0800 45000000000100004001 0000 c0a8000108080808 0800 0000 abcd0001",
|
||||
Fix: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res.IPOffset != 14 {
|
||||
t.Errorf("IP offset %d, want 14", res.IPOffset)
|
||||
}
|
||||
if got := binary.BigEndian.Uint16(res.Packet[14+2:]); got != 28 {
|
||||
t.Errorf("IPv4 total length %d, want 28", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildPacketFixUsesLayer3Boundary(t *testing.T) {
|
||||
// IPv4 with a 4 byte option and TCP with 12 bytes of options in layer 3:
|
||||
// the TCP data offset is set from where the layer 3 field ends.
|
||||
res, err := buildPacket(hex2pcapForm{
|
||||
L3: "46000000123440004006 0000 0a0000010a000002 94040000 c350005000000001000000000018ffff00000000 0101080a0000000100000000",
|
||||
L7: "474554202f",
|
||||
Fix: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := res.Packet[24+12] >> 4; got != 8 {
|
||||
t.Errorf("TCP data offset %d, want 8", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildPacketErrors(t *testing.T) {
|
||||
for name, f := range map[string]hex2pcapForm{
|
||||
"empty": {},
|
||||
"bad hex": {L3: "4g"},
|
||||
"fix non-IP": {L7: "ffffffffffff 66778899aabb 0806 0001", Fix: true},
|
||||
"bad custom": {L7: "00", LinkType: "custom", CustomLinkType: "x"},
|
||||
"fix not IP hdr": {L3: "00", Fix: true},
|
||||
} {
|
||||
if _, err := buildPacket(f); err == nil {
|
||||
t.Errorf("%s: expected error", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPcapFilename(t *testing.T) {
|
||||
for in, want := range map[string]string{
|
||||
"": "packet.pcap",
|
||||
" ": "packet.pcap",
|
||||
"dns query": "dns_query.pcap",
|
||||
"x.pcap": "x.pcap",
|
||||
"../etc/passwd": ".._etc_passwd.pcap",
|
||||
`a"b`: "a_b.pcap",
|
||||
} {
|
||||
if got := pcapFilename(in); got != want {
|
||||
t.Errorf("pcapFilename(%q) = %q, want %q", in, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandlers(t *testing.T) {
|
||||
srv, err := New()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, path := range []string{"/", "/hex2pcap", "/hex2pcap?example", "/static/style.css"} {
|
||||
rec := httptest.NewRecorder()
|
||||
srv.ServeHTTP(rec, httptest.NewRequest("GET", path, nil))
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Errorf("GET %s: %d", path, rec.Code)
|
||||
}
|
||||
}
|
||||
|
||||
post := func(v url.Values) *httptest.ResponseRecorder {
|
||||
req := httptest.NewRequest("POST", "/hex2pcap", strings.NewReader(v.Encode()))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
rec := httptest.NewRecorder()
|
||||
srv.ServeHTTP(rec, req)
|
||||
return rec
|
||||
}
|
||||
|
||||
rec := post(url.Values{"l3": {"4500"}, "l7": {"aabb"}, "action": {"download"}, "filename": {"test"}})
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("download: %d %s", rec.Code, rec.Body)
|
||||
}
|
||||
if cd := rec.Header().Get("Content-Disposition"); cd != `attachment; filename="test.pcap"` {
|
||||
t.Errorf("Content-Disposition %q", cd)
|
||||
}
|
||||
body := rec.Body.Bytes()
|
||||
if len(body) != 24+16+4 || binary.LittleEndian.Uint32(body[20:]) != pcap.LinkTypeRaw {
|
||||
t.Errorf("pcap body %x", body)
|
||||
}
|
||||
|
||||
rec = post(url.Values{"l3": {"4500"}, "action": {"preview"}})
|
||||
if rec.Code != http.StatusOK || !strings.Contains(rec.Body.String(), "Hex dump") {
|
||||
t.Errorf("preview: %d", rec.Code)
|
||||
}
|
||||
|
||||
rec = post(url.Values{"l3": {"zz"}, "action": {"download"}})
|
||||
if rec.Code != http.StatusBadRequest || !strings.Contains(rec.Body.String(), "invalid character") {
|
||||
t.Errorf("bad hex: %d", rec.Code)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user