package pcap

import (
	"bytes"
	"testing"
	"time"
)

var testSimpleTcpPacket *Packet = &Packet{
	Data: []byte{
		0x00, 0x00, 0x0c, 0x9f, 0xf0, 0x20, 0xbc, 0x30, 0x5b, 0xe8, 0xd3, 0x49,
		0x08, 0x00, 0x45, 0x00, 0x01, 0xa4, 0x39, 0xdf, 0x40, 0x00, 0x40, 0x06,
		0x55, 0x5a, 0xac, 0x11, 0x51, 0x49, 0xad, 0xde, 0xfe, 0xe1, 0xc5, 0xf7,
		0x00, 0x50, 0xc5, 0x7e, 0x0e, 0x48, 0x49, 0x07, 0x42, 0x32, 0x80, 0x18,
		0x00, 0x73, 0xab, 0xb1, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x03, 0x77,
		0x37, 0x9c, 0x42, 0x77, 0x5e, 0x3a, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x20,
		0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f,
		0x73, 0x74, 0x3a, 0x20, 0x77, 0x77, 0x77, 0x2e, 0x66, 0x69, 0x73, 0x68,
		0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
		0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x6b, 0x65, 0x65, 0x70, 0x2d, 0x61,
		0x6c, 0x69, 0x76, 0x65, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41,
		0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c,
		0x61, 0x2f, 0x35, 0x2e, 0x30, 0x20, 0x28, 0x58, 0x31, 0x31, 0x3b, 0x20,
		0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x78, 0x38, 0x36, 0x5f, 0x36, 0x34,
		0x29, 0x20, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x57, 0x65, 0x62, 0x4b, 0x69,
		0x74, 0x2f, 0x35, 0x33, 0x35, 0x2e, 0x32, 0x20, 0x28, 0x4b, 0x48, 0x54,
		0x4d, 0x4c, 0x2c, 0x20, 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x47, 0x65, 0x63,
		0x6b, 0x6f, 0x29, 0x20, 0x43, 0x68, 0x72, 0x6f, 0x6d, 0x65, 0x2f, 0x31,
		0x35, 0x2e, 0x30, 0x2e, 0x38, 0x37, 0x34, 0x2e, 0x31, 0x32, 0x31, 0x20,
		0x53, 0x61, 0x66, 0x61, 0x72, 0x69, 0x2f, 0x35, 0x33, 0x35, 0x2e, 0x32,
		0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x74, 0x65,
		0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c,
		0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x68, 0x74, 0x6d,
		0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63,
		0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x6d, 0x6c, 0x3b, 0x71, 0x3d,
		0x30, 0x2e, 0x39, 0x2c, 0x2a, 0x2f, 0x2a, 0x3b, 0x71, 0x3d, 0x30, 0x2e,
		0x38, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, 0x6e,
		0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x67, 0x7a, 0x69, 0x70,
		0x2c, 0x64, 0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, 0x63,
		0x68, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c, 0x61,
		0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x65, 0x6e, 0x2d, 0x55,
		0x53, 0x2c, 0x65, 0x6e, 0x3b, 0x71, 0x3d, 0x30, 0x2e, 0x38, 0x0d, 0x0a,
		0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x43, 0x68, 0x61, 0x72, 0x73,
		0x65, 0x74, 0x3a, 0x20, 0x49, 0x53, 0x4f, 0x2d, 0x38, 0x38, 0x35, 0x39,
		0x2d, 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x3b, 0x71, 0x3d, 0x30,
		0x2e, 0x37, 0x2c, 0x2a, 0x3b, 0x71, 0x3d, 0x30, 0x2e, 0x33, 0x0d, 0x0a,
		0x0d, 0x0a,
	}}

func BenchmarkDecodeSimpleTcpPacket(b *testing.B) {
	for i := 0; i < b.N; i++ {
		testSimpleTcpPacket.Decode()
	}
}

func TestDecodeSimpleTcpPacket(t *testing.T) {
	p := testSimpleTcpPacket
	p.Decode()
	if p.DestMac != 0x00000c9ff020 {
		t.Error("Dest mac", p.DestMac)
	}
	if p.SrcMac != 0xbc305be8d349 {
		t.Error("Src mac", p.SrcMac)
	}
	if len(p.Headers) != 2 {
		t.Error("Incorrect number of headers", len(p.Headers))
		return
	}
	if ip, ipOk := p.Headers[0].(*Iphdr); ipOk {
		if ip.Version != 4 {
			t.Error("ip Version", ip.Version)
		}
		if ip.Ihl != 5 {
			t.Error("ip header length", ip.Ihl)
		}
		if ip.Tos != 0 {
			t.Error("ip TOS", ip.Tos)
		}
		if ip.Length != 420 {
			t.Error("ip Length", ip.Length)
		}
		if ip.Id != 14815 {
			t.Error("ip ID", ip.Id)
		}
		if ip.Flags != 0x02 {
			t.Error("ip Flags", ip.Flags)
		}
		if ip.FragOffset != 0 {
			t.Error("ip Fragoffset", ip.FragOffset)
		}
		if ip.Ttl != 64 {
			t.Error("ip TTL", ip.Ttl)
		}
		if ip.Protocol != 6 {
			t.Error("ip Protocol", ip.Protocol)
		}
		if ip.Checksum != 0x555A {
			t.Error("ip Checksum", ip.Checksum)
		}
		if !bytes.Equal(ip.SrcIp, []byte{172, 17, 81, 73}) {
			t.Error("ip Src", ip.SrcIp)
		}
		if !bytes.Equal(ip.DestIp, []byte{173, 222, 254, 225}) {
			t.Error("ip Dest", ip.DestIp)
		}
		if tcp, tcpOk := p.Headers[1].(*Tcphdr); tcpOk {
			if tcp.SrcPort != 50679 {
				t.Error("tcp srcport", tcp.SrcPort)
			}
			if tcp.DestPort != 80 {
				t.Error("tcp destport", tcp.DestPort)
			}
			if tcp.Seq != 0xc57e0e48 {
				t.Error("tcp seq", tcp.Seq)
			}
			if tcp.Ack != 0x49074232 {
				t.Error("tcp ack", tcp.Ack)
			}
			if tcp.DataOffset != 8 {
				t.Error("tcp dataoffset", tcp.DataOffset)
			}
			if tcp.Flags != 0x18 {
				t.Error("tcp flags", tcp.Flags)
			}
			if tcp.Window != 0x73 {
				t.Error("tcp window", tcp.Window)
			}
			if tcp.Checksum != 0xabb1 {
				t.Error("tcp checksum", tcp.Checksum)
			}
			if tcp.Urgent != 0 {
				t.Error("tcp urgent", tcp.Urgent)
			}
		} else {
			t.Error("Second header is not TCP header")
		}
	} else {
		t.Error("First header is not IP header")
	}
	if string(p.Payload) != "GET / HTTP/1.1\r\nHost: www.fish.com\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n\r\n" {
		t.Error("--- PAYLOAD STRING ---\n", string(p.Payload), "\n--- PAYLOAD BYTES ---\n", p.Payload)
	}
}

// Makes sure packet payload doesn't display the 6 trailing null of this packet
// as part of the payload.  They're actually the ethernet trailer.
func TestDecodeSmallTcpPacketHasEmptyPayload(t *testing.T) {
	p := &Packet{
		// This packet is only 54 bits (an empty TCP RST), thus 6 trailing null
		// bytes are added by the ethernet layer to make it the minimum packet size.
		Data: []byte{
			0xbc, 0x30, 0x5b, 0xe8, 0xd3, 0x49, 0xb8, 0xac, 0x6f, 0x92, 0xd5, 0xbf,
			0x08, 0x00, 0x45, 0x00, 0x00, 0x28, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06,
			0x3f, 0x9f, 0xac, 0x11, 0x51, 0xc5, 0xac, 0x11, 0x51, 0x49, 0x00, 0x63,
			0x9a, 0xef, 0x00, 0x00, 0x00, 0x00, 0x2e, 0xc1, 0x27, 0x83, 0x50, 0x14,
			0x00, 0x00, 0xc3, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		}}
	p.Decode()
	if p.Payload == nil {
		t.Error("Nil payload")
	}
	if len(p.Payload) != 0 {
		t.Error("Non-empty payload:", p.Payload)
	}
}

func TestDecodeVlanPacket(t *testing.T) {
	p := &Packet{
		Data: []byte{
			0x00, 0x10, 0xdb, 0xff, 0x10, 0x00, 0x00, 0x15, 0x2c, 0x9d, 0xcc, 0x00, 0x81, 0x00, 0x01, 0xf7,
			0x08, 0x00, 0x45, 0x00, 0x00, 0x28, 0x29, 0x8d, 0x40, 0x00, 0x7d, 0x06, 0x83, 0xa0, 0xac, 0x1b,
			0xca, 0x8e, 0x45, 0x16, 0x94, 0xe2, 0xd4, 0x0a, 0x00, 0x50, 0xdf, 0xab, 0x9c, 0xc6, 0xcd, 0x1e,
			0xe5, 0xd1, 0x50, 0x10, 0x01, 0x00, 0x5a, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		}}
	p.Decode()
	if p.Type != TYPE_VLAN {
		t.Error("Didn't detect vlan")
	}
	if len(p.Headers) != 3 {
		t.Error("Incorrect number of headers:", len(p.Headers))
		for i, h := range p.Headers {
			t.Errorf("Header %d: %#v", i, h)
		}
		t.FailNow()
	}
	if _, ok := p.Headers[0].(*Vlanhdr); !ok {
		t.Errorf("First header isn't vlan: %q", p.Headers[0])
	}
	if _, ok := p.Headers[1].(*Iphdr); !ok {
		t.Errorf("Second header isn't IP: %q", p.Headers[1])
	}
	if _, ok := p.Headers[2].(*Tcphdr); !ok {
		t.Errorf("Third header isn't TCP: %q", p.Headers[2])
	}
}

func TestDecodeFuzzFallout(t *testing.T) {
	testData := []struct {
		Data []byte
	}{
		{[]byte("000000000000\x81\x000")},
		{[]byte("000000000000\x81\x00000")},
		{[]byte("000000000000\x86\xdd0")},
		{[]byte("000000000000\b\x000")},
		{[]byte("000000000000\b\x060")},
		{[]byte{}},
		{[]byte("000000000000\b\x0600000000")},
		{[]byte("000000000000\x86\xdd000000\x01000000000000000000000000000000000")},
		{[]byte("000000000000\x81\x0000\b\x0600000000")},
		{[]byte("000000000000\b\x00n0000000000000000000")},
		{[]byte("000000000000\x86\xdd000000\x0100000000000000000000000000000000000")},
		{[]byte("000000000000\x81\x0000\b\x00g0000000000000000000")},
		//{[]byte()},
		{[]byte("000000000000\b\x00400000000\x110000000000")},
		{[]byte("0nMء\xfe\x13\x13\x81\x00gr\b\x00&x\xc9\xe5b'\x1e0\x00\x04\x00\x0020596224")},
		{[]byte("000000000000\x81\x0000\b\x00400000000\x110000000000")},
		{[]byte("000000000000\b\x00000000000\x0600\xff0000000")},
		{[]byte("000000000000\x86\xdd000000\x06000000000000000000000000000000000")},
		{[]byte("000000000000\x81\x0000\b\x00000000000\x0600b0000000")},
		{[]byte("000000000000\x81\x0000\b\x00400000000\x060000000000")},
		{[]byte("000000000000\x86\xdd000000\x11000000000000000000000000000000000")},
		{[]byte("000000000000\x86\xdd000000\x0600000000000000000000000000000000000000000000M")},
		{[]byte("000000000000\b\x00500000000\x0600000000000")},
		{[]byte("0nM\xd80\xfe\x13\x13\x81\x00gr\b\x00&x\xc9\xe5b'\x1e0\x00\x04\x00\x0020596224")},
	}

	for _, entry := range testData {
		pkt := &Packet{
			Time:   time.Now(),
			Caplen: uint32(len(entry.Data)),
			Len:    uint32(len(entry.Data)),
			Data:   entry.Data,
		}

		pkt.Decode()
		/*
			func() {
				defer func() {
					if err := recover(); err != nil {
						t.Fatalf("%d. %q failed: %v", idx, string(entry.Data), err)
					}
				}()
				pkt.Decode()
			}()
		*/
	}
}
