158 lines
4.6 KiB
Go
158 lines
4.6 KiB
Go
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)
|
|
}
|
|
}
|