Full Code of ghedo/go.pkt for AI

master c97f47ad982f cached
63 files
261.3 KB
77.4k tokens
622 symbols
1 requests
Download .txt
Showing preview only (278K chars total). Download the full file or copy to clipboard to get everything.
Repository: ghedo/go.pkt
Branch: master
Commit: c97f47ad982f
Files: 63
Total size: 261.3 KB

Directory structure:
gitextract_y_3guso3/

├── .travis.yml
├── COPYING
├── README.md
├── capture/
│   ├── capture.go
│   ├── file/
│   │   ├── capture.go
│   │   ├── capture_test.go
│   │   └── capture_test.pcap
│   └── pcap/
│       ├── capture.go
│       └── capture_test.go
├── examples/
│   ├── arp/
│   │   └── main.go
│   ├── bpf_asm/
│   │   ├── Makefile
│   │   ├── bpf_asm.l
│   │   └── bpf_asm.y
│   ├── dump/
│   │   └── main.go
│   ├── ping/
│   │   └── main.go
│   ├── route/
│   │   └── main.go
│   ├── syn_scan/
│   │   └── main.go
│   ├── tracereply/
│   │   └── main.go
│   └── traceroute/
│       └── main.go
├── filter/
│   ├── bpf_builder.go
│   ├── bpf_builder_test.go
│   ├── bpf_filter.c
│   ├── bpf_filter.go
│   ├── bpf_filter.h
│   ├── bpf_filter_test.go
│   └── pcap.go
├── go.mod
├── go.sum
├── layers/
│   ├── layers.go
│   └── layers_test.go
├── network/
│   └── network.go
├── packet/
│   ├── arp/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── buffer.go
│   ├── eth/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── icmpv4/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── icmpv6/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── ipv4/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── ipv6/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── llc/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── packet.go
│   ├── radiotap/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── raw/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── sll/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── snap/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── tcp/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── udp/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   └── vlan/
│       ├── pkt.go
│       └── pkt_test.go
└── routing/
    ├── routing.go
    └── routing_linux.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .travis.yml
================================================
language: go

sudo: false

addons:
 apt:
   packages:
    - libpcap0.8-dev

go:
 - "1.11"
 - "tip"

env:
 - GO111MODULE=on

script:
 - go build ./...
 - go test ./...


================================================
FILE: COPYING
================================================
Copyright (c) 2014, Alessandro Ghedini <alessandro@ghedini.me>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: README.md
================================================
go.pkt
======

![Travis CI](https://secure.travis-ci.org/ghedo/go.pkt.png)

**go.pkt** provides Go libraries for capturing, injecting, filtering, encoding and
decoding network packets.

* [capture][capture]: provides the basic interface for packet capturing and
  injection. Different implementations ("pcap", "file", ...) are provided as
  subpackages.

* [filter][filter]: provides an API for compiling and manipulating BPF filters.
  A filter can be either compiled from tcpdump-like expressions, or created from
  basic BPF instructions. Filters can then be either applied to packet sources
  (see the capture package) or directly run against binary data.

* [packet][packet]: provides the interfaces for implementing packet encoders
  and decoders. Every supported protocol implements the Packet interface as a
  submodule of this package (e.g. packet/ipv4, packet/tcp, ...).

* [layers][layers]: provides utility functions for encoding and decoding
  packets to/from binary data. Differently from the basic "packet" interface,
  this can encode and decode complete "stacks" of packets, instead of
  manipulating single ones.

* [network][network]: provides utility functions for sending and receiving
  packets over the network. Basically, it hides some of the complexity of using
  the capture and layers packages together.

* [routing][routing]: provides network routing information about the system. It
  can either return all available routes or select a specific route depending on
  a destination address.

[capture]: http://godoc.org/github.com/ghedo/go.pkt/capture
[filter]: http://godoc.org/github.com/ghedo/go.pkt/filter
[packet]: http://godoc.org/github.com/ghedo/go.pkt/packet
[layers]: http://godoc.org/github.com/ghedo/go.pkt/layers
[network]: http://godoc.org/github.com/ghedo/go.pkt/network
[routing]: http://godoc.org/github.com/ghedo/go.pkt/routing

## Getting Started

### Capturing

Packet capturing is done using a packet "source" such as a network interface or
a dump file.

In the following example we create a "pcap" capture handle using the `eth0`
network interface, we activate it and then capture packets using the `Capture()`
method.

```go
src, err := pcap.Open("eth0")
if err != nil {
	log.Fatal(err)
}
defer src.Close()

// you may configure the source further, e.g. by activating
// promiscuous mode.

err = src.Activate()
if err != nil {
	log.Fatal(err)
}

for {
	buf, err := src.Capture()
	if err != nil {
		log.Fatal(err)
	}

	log.Println("PACKET!!!")

	// do something with the packet
}
```

### Injection

Similarly to packet capturing, packet injection requires a capture handle.

In the following example we create a capture handle like before and then use
the `Inject()` method to send some data (we'll see later how to encode data in
the propert formats).

```go
dst, err := pcap.Open("eth0")
if err != nil {
	log.Fatal(err)
}
defer dst.Close()

// you may configure the source further, e.g. by activating
// promiscuous mode.

err = dst.Activate()
if err != nil {
	log.Fatal(err)
}

err = dst.Inject([]byte("random data"))
if err != nil {
	log.Fatal(err)
}
```

### Filtering

Packet filtering is done by creating a filter (e.g. by compiling it from an
expression) which can be either applied to a capture handle (by using the
`ApplyFilter()` method) or used directly against a data buffer.

In the following example we create a filter by compiling a tcpdump-like
expression and then try to match some data against it.

```go
// Match UDP or TCP packets on top of Ethernet
flt, err := filter.Compile("udp or tcp", packet.Eth)
if err != nil {
	log.Fatal(err)
}

if flt.Match([]byte("random data")) {
	log.Println("MATCH!!!")
}
```

### Encoding

Encoding packets is done by using the functions provided by the `layers`
package.

In the following example we create an ARP packet on top of an Ethernet packet
and we encode them to binary data by using the `Pack()` method. Note that you'll
need to import the packages of the protocols used (`packet/eth` and `packet/arp`).

```go
// Create an Ethernet packet
eth_pkt := eth.Make()
eth_pkt.SrcAddr, _ = net.ParseMAC("4c:72:b9:54:e5:3d")
eth_pkt.DstAddr, _ = net.ParseMAC("ff:ff:ff:ff:ff:ff")

// Create an ARP packet
arp_pkt := arp.Make()
arp_pkt.HWSrcAddr, _ = net.ParseMAC("4c:72:b9:54:e5:3d")
arp_pkt.HWDstAddr, _ = net.ParseMAC("00:00:00:00:00:00")
arp_pkt.ProtoSrcAddr = net.ParseIP("192.168.1.135")
arp_pkt.ProtoDstAddr = net.ParseIP("192.168.1.254")

buf, err := layers.Pack(eth_pkt, arp_pkt)
if err != nil {
	log.Fatal(err)
}

// do something with the packet
log.Println(buf)
```

### Decoding

Like encoding, decoding is done by using the functions provided by the `layers`
package.

The following example uses the `UnpackAll()` function to decode a whole chain of
packets (e.g. ethernet -> ipv4 -> udp).

```go
// Create the buf data
buf := []byte("random data")

// Assume Ethernet as datalink layer
pkt, err := layers.UnpackAll(buf, packet.Eth)
if err != nil {
	log.Fatal(err)
}

log.Println(pkt)
```

### Network

Instead of using the layers and capture packages together, the network package
can be used instead.

The following example creates an ARP request packet and uses `SendRecv()` to
send it and receive a suitable answer.

```go
c, err := pcap.Open("eth0")
if err != nil {
	log.Fatal(err)
}
defer c.Close()

err = c.Activate()
if err != nil {
	log.Fatal(err)
}

// Create an Ethernet packet
eth_pkt := eth.Make()
eth_pkt.SrcAddr, _ = net.ParseMAC("4c:72:b9:54:e5:3d")
eth_pkt.DstAddr, _ = net.ParseMAC("ff:ff:ff:ff:ff:ff")

// Create an ARP packet
arp_pkt := arp.Make()
arp_pkt.HWSrcAddr, _ = net.ParseMAC("4c:72:b9:54:e5:3d")
arp_pkt.HWDstAddr, _ = net.ParseMAC("00:00:00:00:00:00")
arp_pkt.ProtoSrcAddr = net.ParseIP("192.168.1.135")
arp_pkt.ProtoDstAddr = net.ParseIP("192.168.1.254")

rsp_pkt, err := network.SendRecv(c, 0, eth_pkt, arp_pkt)
if err != nil {
	log.Fatal(err)
}

log.Println(rsp_pkt)
```

### Routing

TODO

For more examples have a look at the [examples](examples/) directory in the
source repository.

## Dependencies

 * `libpcap`

## Copyright

Copyright (C) 2014 Alessandro Ghedini <alessandro@ghedini.me>

See COPYING for the license.


================================================
FILE: capture/capture.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Provides the basic interface for packet capturing and injection. Different
// implementations ("pcap", "file", ...) are provided as subpackages.
package capture

import "github.com/ghedo/go.pkt/filter"
import "github.com/ghedo/go.pkt/packet"

type Handle interface {
    LinkType() packet.Type

    SetMTU(mtu int) error
    SetPromiscMode(promisc bool) error
    SetMonitorMode(monitor bool) error

    ApplyFilter(filter *filter.Filter) error

    Activate() error

    Capture() ([]byte, error)
    Inject(buf []byte) error

    Close()
}


================================================
FILE: capture/file/capture.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Provides native packet capturing and injection on pcap dump files without
// requiring the libpcap library.
package file

import "bytes"
import "encoding/binary"
import "fmt"
import "io"
import "os"

import "github.com/ghedo/go.pkt/filter"
import "github.com/ghedo/go.pkt/packet"

type Handle struct {
    File  string
    file   *os.File
    out    *os.File
    order  binary.ByteOrder
    link   uint32
    mtu    uint32
    filter *filter.Filter
}

var BigEndian    = []byte{0xa1, 0xb2, 0xc3, 0xd4}
var LittleEndian = []byte{0xd4, 0xc3, 0xb2, 0xa1}

// Create a new capture handle from the given dump file. This will either open
// the file if it exists, or create a new one.
func Open(file_name string) (*Handle, error) {
    handle := &Handle{ File: file_name }

    open := open_file

    if _, err := os.Stat(file_name); os.IsNotExist(err) {
        open = create_file
    }

    file, err := open(file_name)
    if err != nil {
        return nil, err
    }

    handle.file = file

    handle.file.Seek(0, 0)

    magic := make([]byte, 4)
    file.Read(magic)

    switch {
    case bytes.Equal(magic, BigEndian):
        handle.order = binary.BigEndian

    case bytes.Equal(magic, LittleEndian):
        handle.order = binary.LittleEndian

    default:
        handle.file.Close()
        return nil, fmt.Errorf("Invalid file")
    }

    var ver_maj, ver_min uint16
    var discard, mtu, link_type uint32

    binary.Read(file, handle.order, &ver_maj)
    binary.Read(file, handle.order, &ver_min)
    binary.Read(file, handle.order, &discard)
    binary.Read(file, handle.order, &discard)
    binary.Read(file, handle.order, &mtu)
    binary.Read(file, handle.order, &link_type)

    handle.link = link_type
    handle.mtu  = mtu

    /*
     * Use a different file handle for injecting packages so that we don't
     * need to seek back and forth for capturing and injecting
     */
    handle.out, _ = open_file(file_name)
    handle.out.Seek(0, 2)

    return handle, nil
}

func create_file(file_name string) (*os.File, error) {
    file, err := os.Create(file_name)
    if err != nil {
        return nil, fmt.Errorf("Could not create file: %s", err)
    }

    file.Write(BigEndian) /* endiannes */

    binary.Write(file, binary.BigEndian, uint16(2)) /* ver major */
    binary.Write(file, binary.BigEndian, uint16(4)) /* ver minor */
    binary.Write(file, binary.BigEndian, uint32(0))
    binary.Write(file, binary.BigEndian, uint32(0))
    binary.Write(file, binary.BigEndian, uint32(0x7fff)) /* MTU */
    binary.Write(file, binary.BigEndian, uint32(1)) /* link type */

    return file, nil
}

func open_file(file_name string) (*os.File, error) {
    file, err := os.OpenFile(file_name, os.O_RDWR, 0644);
    if err != nil {
        return nil, fmt.Errorf("Could not open file: %s", err)
    }

    return file, nil
}

// Return the link type of the capture handle (that is, the type of packets that
// come out of the packet source).
func (h *Handle) LinkType() packet.Type {
    return packet.LinkType(h.link)
}

// Not supported.
func (h *Handle) SetMTU(mtu int) error {
    return fmt.Errorf("Unsupported")
}

// Not supported.
func (h *Handle) SetPromiscMode(promisc bool) error {
    return fmt.Errorf("Unsupported")
}

// Not supported.
func (h *Handle) SetMonitorMode(monitor bool) error {
    return fmt.Errorf("Unsupported")
}

// Apply the given filter it to the packet source. Only packets that match this
// filter will be captured.
func (h *Handle) ApplyFilter(filter *filter.Filter) error {
    if !filter.Validate() {
        return fmt.Errorf("Invalid filter")
    }

    h.filter = filter
    return nil
}

// Activate the capture handle (this is not needed for the file capture handle,
// but you may want to call it anyway in order to make switching to different
// packet sources easier).
func (h *Handle) Activate() error {
    return nil
}

// Capture a single packet from the packet source. If no packet is available
// (i.e. if the end of the dump file has been reached) it will return a nil
// slice.
func (h *Handle) Capture() ([]byte, error) {
    var buf []byte
    var sec, usec, caplen, wirelen uint32

    for {
        binary.Read(h.file, h.order, &sec)
        binary.Read(h.file, h.order, &usec)
        binary.Read(h.file, h.order, &caplen)
        binary.Read(h.file, h.order, &wirelen)

        if caplen == 0 {
            return nil, nil
        }

        buf = make([]byte, int(caplen))

        _, err := h.file.Read(buf)
        if err == io.EOF {
            return nil, nil
        }

        if err != nil  {
            return nil, fmt.Errorf("Could not capture: %s", err)
        }

        if h.filter != nil && !h.filter.Match(buf) {
            continue
        }

        break
    }

    return buf, nil
}

// Inject a packet in the packet source. This will automatically append packets
// at the end of the dump file, instead of truncating it.
func (h *Handle) Inject(buf []byte) error {
    var sec, usec, caplen, wirelen uint32

    sec     = 0
    usec    = 0
    caplen  = uint32(len(buf))
    wirelen = caplen

    binary.Write(h.out, h.order, sec)
    binary.Write(h.out, h.order, usec)
    binary.Write(h.out, h.order, caplen)
    binary.Write(h.out, h.order, wirelen)

    n, err := h.out.Write(buf)
    if err != nil || n < len(buf) {
        return fmt.Errorf("Could not write packet: %s", err)
    }

    return nil
}

// Close the packet source.
func (h *Handle) Close() {
    h.file.Close()
    h.out.Close()
}


================================================
FILE: capture/file/capture_test.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package file_test

import "log"
import "testing"

import "github.com/ghedo/go.pkt/capture/file"
import "github.com/ghedo/go.pkt/filter"

func TestCapture(t *testing.T) {
    src, err := file.Open("capture_test.pcap")
    if err != nil {
        t.Fatalf("Error opening: %s", err)
    }
    defer src.Close()

    var count uint64
    for {
        buf, err := src.Capture()
        if err != nil {
            t.Fatalf("Error reading: %s", err)
        }

        if buf == nil {
            break
        }

        count++
    }

    if count != 16 {
        t.Fatalf("Count mismatch: %d", count)
    }
}

func TestCaptureFilter(t *testing.T) {
    src, err := file.Open("capture_test.pcap")
    if err != nil {
        t.Fatalf("Error opening: %s", err)
    }
    defer src.Close()

    flt, err := filter.Compile("arp", src.LinkType(), false)
    if err != nil {
        t.Fatalf("Error parsing filter: %s", err)
    }
    defer flt.Cleanup()

    err = src.ApplyFilter(flt)
    if err != nil {
        t.Fatalf("Error applying filter: %s", err)
    }

    var count uint64
    for {
        buf, err := src.Capture()
        if err != nil {
            t.Fatalf("Error reading: %s %d", err, count)
        }

        if buf == nil {
            break
        }

        count++
    }

    if count != 2 {
        t.Fatalf("Count mismatch: %d", count)
    }
}

func TestInject(t *testing.T) {
    src, err := file.Open("capture_test.pcap")
    if err != nil {
        t.Fatalf("Error opening: %s", err)
    }
    defer src.Close()

    dst, err := file.Open("inject_test.pcap")
    if err != nil {
        t.Fatalf("Error opening: %s", err)
    }
    defer dst.Close()

    var count uint64
    for {
        buf, err := src.Capture()
        if err != nil {
            t.Fatalf("Error reading: %s", err)
        }

        if buf == nil {
            break
        }

        err = dst.Inject(buf)
        if err != nil {
            t.Fatalf("Error writing: %s", err)
        }

        count++
    }

    if count != 16 {
        t.Fatalf("Count mismatch: %d", count)
    }
}

func ExampleCapture() {
    src, err := file.Open("/path/to/file/dump.pcap")
    if err != nil {
        log.Fatal(err)
    }
    defer src.Close()

    // you may configure the source further, e.g. by activating
    // promiscuous mode.

    err = src.Activate()
    if err != nil {
        log.Fatal(err)
    }

    for {
        buf, err := src.Capture()
        if err != nil {
            log.Fatal(err)
        }

        if buf == nil {
            break
        }

        log.Println("PACKET!!!")

        // do something with the packet
    }
}

func ExampleInject() {
    dst, err := file.Open("/path/to/file/dump.pcap")
    if err != nil {
        log.Fatal(err)
    }
    defer dst.Close()

    // you may configure the source further, e.g. by activating
    // promiscuous mode.

    err = dst.Activate()
    if err != nil {
        log.Fatal(err)
    }

    err = dst.Inject([]byte("random data"))
    if err != nil {
        log.Fatal(err)
    }
}


================================================
FILE: capture/pcap/capture.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Provides packet capturing and injection on live network interfaces via
// libpcap.
package pcap

// #cgo LDFLAGS: -lpcap
// #include <stdlib.h>
// #include <pcap.h>
import "C"

import "fmt"
import "unsafe"

import "github.com/ghedo/go.pkt/filter"
import "github.com/ghedo/go.pkt/packet"

type Handle struct {
    Device string
    pcap   *C.pcap_t
}

// Create a new capture handle from the given network interface. Noe that this
// may require root privileges.
func Open(dev_name string) (*Handle, error) {
    handle := &Handle{ Device: dev_name }

    dev_str := C.CString(dev_name)
    defer C.free(unsafe.Pointer(dev_str))

    err_str := (*C.char)(C.calloc(256, 1))
    defer C.free(unsafe.Pointer(err_str))

    handle.pcap = C.pcap_create(dev_str, err_str)
    if handle == nil {
        return nil, fmt.Errorf(
            "Could not open device: %s", C.GoString(err_str),
        )
    }

    return handle, nil
}

// Return the link type of the capture handle (that is, the type of packets that
// come out of the packet source).
func (h *Handle) LinkType() packet.Type {
    return packet.LinkType(uint32(C.pcap_datalink(h.pcap)))
}

func (h *Handle) SetMTU(mtu int) error {
    err := C.pcap_set_snaplen(h.pcap, C.int(mtu))
    if err < 0 {
        return fmt.Errorf("Handle already active")
    }

    return nil
}

// Enable/disable promiscuous mode.
func (h *Handle) SetPromiscMode(promisc bool) error {
    var promisc_int C.int

    if promisc {
        promisc_int = 1
    } else {
        promisc_int = 0
    }

    err := C.pcap_set_promisc(h.pcap, promisc_int)
    if err < 0 {
        return fmt.Errorf("Handle already active")
    }

    return nil
}

// Enable/disable monitor mode. This is only relevant to RF-based packet sources
// (e.g. a WiFi or Bluetooth network interface)
func (h *Handle) SetMonitorMode(monitor bool) error {
    var rfmon_int C.int

    if monitor {
        rfmon_int = 1
    } else {
        rfmon_int = 0
    }

    err := C.pcap_set_rfmon(h.pcap, rfmon_int)
    if err < 0 {
        return fmt.Errorf("Handle already active")
    }

    return nil
}

// Apply the given filter it to the packet source. Only packets that match this
// filter will be captured.
func (h *Handle) ApplyFilter(filter *filter.Filter) error {
    if !filter.Validate() {
        return fmt.Errorf("Invalid filter")
    }

    err_str := (*C.char)(C.calloc(256, 1))
    defer C.free(unsafe.Pointer(err_str))

    dev_str := C.CString(h.Device)
    defer C.free(unsafe.Pointer(dev_str))

    err := C.pcap_setfilter(h.pcap, (*C.struct_bpf_program)(filter.Program()))
    if err < 0 {
        return fmt.Errorf("Could not set filter: %s", h.get_error())
    }

    return nil
}

// Activate the packet source. Note that after calling this method it will not
// be possible to change the packet source configuration (MTU, promiscuous mode,
// monitor mode, ...)
func (h *Handle) Activate() error {
    err := C.pcap_activate(h.pcap)
    if err < 0 {
        return fmt.Errorf("Could not activate: %s", h.get_error())
    }

    return nil
}

// Capture a single packet from the packet source. This will block until a
// packet is received.
func (h *Handle) Capture() ([]byte, error) {
    var buf *C.u_char
    var pkt_hdr *C.struct_pcap_pkthdr

    for {
        err := C.pcap_next_ex(h.pcap, &pkt_hdr, &buf)
        switch err {
        case -2:
            return nil, nil

        case -1:
            return nil, fmt.Errorf(
                "Could not read packet: %s", h.get_error(),
            )

        case 0:
            continue

        case 1:
            return C.GoBytes(unsafe.Pointer(buf),
                             C.int(pkt_hdr.len)), nil
        }
    }

    return nil, fmt.Errorf("WTF")
}

// Inject a packet in the packet source.
func (h *Handle) Inject(buf []byte) error {
    cbuf := (*C.u_char)(&buf[0])
    blen := C.int(len(buf))

    err := C.pcap_sendpacket(h.pcap, cbuf, blen)
    if err < 0 {
        return fmt.Errorf("Could not inject packet: %s", h.get_error())
    }

    return nil
}

// Close the packet source.
func (h *Handle) Close() {
    C.pcap_close(h.pcap)
}

func (h *Handle) get_error() error {
    err_str := C.pcap_geterr(h.pcap)
    return fmt.Errorf(C.GoString(err_str))
}


================================================
FILE: capture/pcap/capture_test.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package pcap_test

import "log"

import "github.com/ghedo/go.pkt/capture/pcap"

func ExampleCapture() {
    src, err := pcap.Open("eth0")
    if err != nil {
        log.Fatal(err)
    }
    defer src.Close()

    // you may configure the source further, e.g. by activating
    // promiscuous mode.

    err = src.Activate()
    if err != nil {
        log.Fatal(err)
    }

    for {
        buf, err := src.Capture()
        if err != nil {
            log.Fatal(err)
        }

        log.Printf("PACKET!!! %v", buf)

        // do something with the packet
    }
}

func ExampleInject() {
    dst, err := pcap.Open("eth0")
    if err != nil {
        log.Fatal(err)
    }
    defer dst.Close()

    // you may configure the source further, e.g. by activating
    // promiscuous mode.

    err = dst.Activate()
    if err != nil {
        log.Fatal(err)
    }

    err = dst.Inject([]byte("random data"))
    if err != nil {
        log.Fatal(err)
    }
}


================================================
FILE: examples/arp/main.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import "log"
import "net"
import "time"

import "github.com/docopt/docopt-go"

import "github.com/ghedo/go.pkt/capture/pcap"
import "github.com/ghedo/go.pkt/packet/eth"
import "github.com/ghedo/go.pkt/packet/arp"

import "github.com/ghedo/go.pkt/network"
import "github.com/ghedo/go.pkt/routing"

func main() {
    log.SetFlags(0)

    usage := `Usage: arp <addr>

Resolve the given IP address using ARP.`

    args, err := docopt.Parse(usage, nil, true, "", false)
    if err != nil {
        log.Fatalf("Invalid arguments: %s", err)
    }

    addr    := args["<addr>"].(string)
    addr_ip := net.ParseIP(addr)
    timeout := 5 * time.Second

    route, err := routing.RouteTo(addr_ip)
    if err != nil {
        log.Fatalf("Error: %s", err)
    }

    if route == nil {
        log.Println("No route found")
    }

    c, err := pcap.Open(route.Iface.Name)
    if err != nil {
        log.Fatalf("Error opening interface: %s", err)
    }
    defer c.Close()

    err = c.Activate()
    if err != nil {
        log.Fatalf("Error activating source: %s", err)
    }

    eth_pkt := eth.Make()
    eth_pkt.SrcAddr = route.Iface.HardwareAddr
    eth_pkt.DstAddr, _ = net.ParseMAC("ff:ff:ff:ff:ff:ff")

    arp_pkt := arp.Make()
    arp_pkt.HWSrcAddr = route.Iface.HardwareAddr
    arp_pkt.HWDstAddr, _ = net.ParseMAC("00:00:00:00:00:00")
    arp_pkt.ProtoSrcAddr, _ = route.GetIfaceIPv4Addr()
    arp_pkt.ProtoDstAddr = addr_ip

    pkt, err := network.SendRecv(c, timeout, eth_pkt, arp_pkt)
    if err != nil {
        log.Fatal(err)
    }

    log.Println(pkt.Payload().(*arp.Packet).HWSrcAddr)
}


================================================
FILE: examples/bpf_asm/Makefile
================================================
all: bpf_asm

bpf_asm: bpf_asm.nn.go y.go
	go build -o bpf_asm bpf_asm.nn.go y.go

y.go: bpf_asm.y
	go tool yacc bpf_asm.y

bpf_asm.nn.go: bpf_asm.l
	nex bpf_asm.l


================================================
FILE: examples/bpf_asm/bpf_asm.l
================================================
/ldb/	{ return OP_LDB }
/ldh/	{ return OP_LDH }
/ld/	{ return OP_LD }
/ldi/	{ return OP_LDI }
/ldx/	{ return OP_LDX }
/ldxi/	{ return OP_LDXI }
/ldxb/	{ return OP_LDXB }
/st/	{ return OP_ST }
/stx/	{ return OP_STX }
/jmp/	{ return OP_JMP }
/ja/	{ return OP_JMP }
/jeq/	{ return OP_JEQ }
/jneq/	{ return OP_JNEQ }
/jne/	{ return OP_JNEQ }
/jlt/	{ return OP_JLT }
/jle/	{ return OP_JLE }
/jgt/	{ return OP_JGT }
/jge/	{ return OP_JGE }
/jset/	{ return OP_JSET }
/add/	{ return OP_ADD }
/sub/	{ return OP_SUB }
/mul/	{ return OP_MUL }
/div/	{ return OP_DIV }
/neg/	{ return OP_NEG }
/and/	{ return OP_AND }
/or/	{ return OP_OR }
/lsh/	{ return OP_LSH }
/rsh/	{ return OP_RSH }
/ret/	{ return OP_RET }
/tax/	{ return OP_TAX }
/txa/	{ return OP_TXA }

/#?len/		{ return K_PKT_LEN }
/#?proto/	{ return K_PROTO }
/#?type/	{ return K_TYPE }
/#?poff/	{ return K_POFF }
/#?ifidx/	{ return K_IFIDX }
/#?nla/		{ return K_NLATTR }
/#?nlan/	{ return K_NLATTR_NEST }
/#?mark/	{ return K_MARK }
/#?queue/	{ return K_QUEUE }
/#?hatype/	{ return K_HATYPE }
/#?rxhash/	{ return K_RXHASH }
/#?cpu/		{ return K_CPU }
/#?vlan_tci/	{ return K_VLANT }
/#?vlan_pr/	{ return K_VLANP }

/:/		{ return ':' }
/,/		{ return ',' }
/#/		{ return '#' }
/%/		{ return '%' }
/\[/		{ return '[' }
/\]/		{ return ']' }
/\(/		{ return '(' }
/\)/		{ return ')' }
/x/		{ return 'x' }
/a/		{ return 'a' }
/\+/		{ return '+' }
/M/		{ return 'M' }
/\*/		{ return '*' }
/&/		{ return '&' }

/([0][x][a-fA-F0-9]+)/ {
	str := strings.TrimPrefix(yylex.Text(), "0x")
	num, _ := strconv.ParseUint(str, 16, 32)
	lval.number = uint32(num)
	return number
}

/([0][b][0-1]+)/ {
	str := strings.TrimPrefix(yylex.Text(), "0b")
	num, _ := strconv.ParseUint(str, 2, 32)
	lval.number = uint32(num)
	return number
}

/(([0])|([-+]?[1-9][0-9]*))/ {
	num, _ := strconv.ParseUint(yylex.Text(), 10, 32)
	lval.number = uint32(num)
	return number
}

/([0][0-9]+)/ {
	str := strings.TrimPrefix(yylex.Text(), "0")
	num, _ := strconv.ParseUint(str, 8, 32)
	lval.number = uint32(num)
	return number
}

/[a-zA-Z_][a-zA-Z0-9_]+/ 	{
	lval.label = yylex.Text()
	return label
}
//
package main

import "log"
import "strconv"
import "os"

import "github.com/docopt/docopt-go"

import "github.com/ghedo/go.pkt/filter"

var bld *filter.Builder

func main() {
	log.SetFlags(0)

	usage := `Usage: bpf_asm <file>`

	args, err := docopt.Parse(usage, nil, true, "", false)
	if err != nil {
		log.Fatalf("Invalid arguments: %s", err)
	}

	file, err := os.Open(args["<file>"].(string))
	if err != nil {
		log.Fatalf("Error opening file: %s", err)
	}

	bld = filter.NewBuilder()

	lex := NewLexer(file)
	yyParse(lex)

	flt := bld.Build()

	if !flt.Validate() {
		log.Fatalf("Invalid filter")
	}

	log.Println(flt)
}


================================================
FILE: examples/bpf_asm/bpf_asm.y
================================================
%{
package main

import "github.com/ghedo/go.pkt/filter"
%}

%union {
	label  string
	number uint32
}

%token OP_LDB
%token OP_LDH
%token OP_LD
%token OP_LDI
%token OP_LDX
%token OP_LDXI
%token OP_LDXB
%token OP_ST
%token OP_STX
%token OP_JMP
%token OP_JEQ
%token OP_JNEQ
%token OP_JLT
%token OP_JLE
%token OP_JGT
%token OP_JGE
%token OP_JSET
%token OP_ADD
%token OP_SUB
%token OP_MUL
%token OP_DIV
%token OP_NEG
%token OP_AND
%token OP_OR
%token OP_LSH
%token OP_RSH
%token OP_RET
%token OP_TAX
%token OP_TXA

%token K_PKT_LEN
%token K_PROTO
%token K_TYPE
%token K_POFF
%token K_IFIDX
%token K_NLATTR
%token K_NLATTR_NEST
%token K_MARK
%token K_QUEUE
%token K_HATYPE
%token K_RXHASH
%token K_CPU
%token K_VLANT
%token K_VLANP

%token number
%token label

%token jtl
%token jfl
%token jkl

%token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%'

%type <label> label
%type <number> number

%%

prog
	: line
	| prog line
	;

line
	: instr
	| labelled_instr
	;

labelled_instr
	: labelled instr
	;

instr
	: ldb
	| ldh
	| ld
	| ldi
	| ldx
	| ldxi
	| st
	| stx
	| jmp
	| jeq
	| jneq
	| jlt
	| jle
	| jgt
	| jge
	| jset
	| add
	| sub
	| mul
	| div
	| neg
	| and
	| or
	| lsh
	| rsh
	| ret
	| tax
	| txa
	;

labelled
	: label ':' { bld.Label($1)
	}
	;

ldb
	: OP_LDB '[' 'x' '+' number ']' {
		bld.LD(filter.Byte, filter.IND, $5)
	}
	| OP_LDB '[' '%' 'x' '+' number ']' {
		bld.LD(filter.Byte, filter.IND, $6)
	}
	| OP_LDB '[' number ']' {
		bld.LD(filter.Byte, filter.ABS, $3)
	}
	;

ldh
	: OP_LDH '[' 'x' '+' number ']' {
		bld.LD(filter.Half, filter.IND, $5)
	}
	| OP_LDH '[' '%' 'x' '+' number ']' {
		bld.LD(filter.Half, filter.IND, $6)
	}
	| OP_LDH '[' number ']' {
		bld.LD(filter.Half, filter.ABS, $3)
	}
	;

ldi
	: OP_LDI '#' number {
		bld.LD(filter.Word, filter.IMM, $3)
	}
	| OP_LDI number {
		bld.LD(filter.Word, filter.IMM, $2)
	}
	;

ld
	: OP_LD '#' number {
		bld.LD(filter.Word, filter.IMM, $3)
	}
	| OP_LD K_PKT_LEN {
		bld.LD(filter.Word, filter.LEN, 0)
	}
	| OP_LD 'M' '[' number ']' {
		bld.LD(filter.Word, filter.MEM, $4)
	}
	| OP_LD '[' 'x' '+' number ']' {
		bld.LD(filter.Word, filter.IND, $5)
	}
	| OP_LD '[' '%' 'x' '+' number ']' {
		bld.LD(filter.Word, filter.IND, $6)
	}
	| OP_LD '[' number ']' {
		bld.LD(filter.Word, filter.ABS, $3)
	}
	;

ldxi
	: OP_LDXI '#' number {
		bld.LDX(filter.Word, filter.IMM, $3)
	}
	| OP_LDXI number {
		bld.LDX(filter.Word, filter.IMM, $2)
	}
	;

ldx
	: OP_LDX '#' number {
		bld.LDX(filter.Word, filter.IMM, $3)
	}
	| OP_LDX K_PKT_LEN {
		bld.LDX(filter.Word, filter.LEN, 0)
	}
	| OP_LDX 'M' '[' number ']' {
		bld.LDX(filter.Word, filter.MEM, $4)
	}
	| OP_LDXB number '*' '(' '[' number ']' '&' number ')' {
		if ($2 != 4 || $9 != 0xf) {
			yylex.Error("ldxb offset not supported!")
		} else {
			bld.LDX(filter.Byte, filter.MSH, $6)
		}
	}
	| OP_LDX number '*' '(' '[' number ']' '&' number ')' {
		if ($2 != 4 || $9 != 0xf) {
			yylex.Error("ldxb offset not supported!")
		} else {
			bld.LDX(filter.Byte, filter.MSH, $6)
		}
	}
	;

st
	: OP_ST 'M' '[' number ']' {
		bld.ST($4)
	}
	;

stx
	: OP_STX 'M' '[' number ']' {
		bld.STX($4)
	}
	;

jmp
	: OP_JMP label {
		bld.JA($2)
	}
	;

jeq
	: OP_JEQ '#' number ',' label ',' label {
		bld.JEQ(filter.Const, $5, $7, $3)
	}
	| OP_JEQ 'x' ',' label ',' label {
		bld.JEQ(filter.Index, $4, $6, 0)
	}
	| OP_JEQ '%' 'x' ',' label ',' label {
		bld.JEQ(filter.Index, $5, $7, 0)
	}
	| OP_JEQ '#' number ',' label {
		bld.JEQ(filter.Const, "", $5, $3)
	}
	| OP_JEQ 'x' ',' label {
		bld.JEQ(filter.Index, "", $4, 0)
	}
	| OP_JEQ '%' 'x' ',' label {
		bld.JEQ(filter.Index, "", $5, 0)
	}
	;

jneq
	: OP_JNEQ '#' number ',' label {
		bld.JEQ(filter.Const, "", $5, $3)
	}
	| OP_JNEQ 'x' ',' label {
		bld.JEQ(filter.Index, "", $4, 0)
	}
	| OP_JNEQ '%' 'x' ',' label {
		bld.JEQ(filter.Index, "", $5, 0)
	}
	;

jlt
	: OP_JLT '#' number ',' label {
		bld.JGE(filter.Const, "", $5, $3)
	}
	| OP_JLT 'x' ',' label {
		bld.JGE(filter.Index, "", $4, 0)
	}
	| OP_JLT '%' 'x' ',' label {
		bld.JGE(filter.Index, "", $5, 0)
	}
	;

jle
	: OP_JLE '#' number ',' label {
		bld.JGT(filter.Const, "", $5, $3)
	}
	| OP_JLE 'x' ',' label {
		bld.JGT(filter.Index, "", $4, 0)
	}
	| OP_JLE '%' 'x' ',' label {
		bld.JGT(filter.Index, "", $5, 0)
	}
	;

jgt
	: OP_JGT '#' number ',' label ',' label {
		bld.JGT(filter.Const, $5, $7, $3)
	}
	| OP_JGT 'x' ',' label ',' label {
		bld.JGT(filter.Index, $4, $6, 0)
	}
	| OP_JGT '%' 'x' ',' label ',' label {
		bld.JGT(filter.Index, $5, $7, 0)
	}
	| OP_JGT '#' number ',' label {
		bld.JGT(filter.Const, "", $5, $3)
	}
	| OP_JGT 'x' ',' label {
		bld.JGT(filter.Index, "", $4, 0)
	}
	| OP_JGT '%' 'x' ',' label {
		bld.JGT(filter.Index, "", $5, 0)
	}
	;

jge
	: OP_JGE '#' number ',' label ',' label {
		bld.JGE(filter.Const, $5, $7, $3)
	}
	| OP_JGE 'x' ',' label ',' label {
		bld.JGE(filter.Index, $4, $6, 0)
	}
	| OP_JGE '%' 'x' ',' label ',' label {
		bld.JGE(filter.Index, $5, $7, 0)
	}
	| OP_JGE '#' number ',' label {
		bld.JGE(filter.Const, "", $5, $3)
	}
	| OP_JGE 'x' ',' label {
		bld.JGE(filter.Index, "", $4, 0)
	}
	| OP_JGE '%' 'x' ',' label {
		bld.JGE(filter.Index, "", $5, 0)
	}
	;

jset
	: OP_JSET '#' number ',' label ',' label {
		bld.JSET(filter.Const, $5, $7, $3)
	}
	| OP_JSET 'x' ',' label ',' label {
		bld.JSET(filter.Index, $4, $6, 0)
	}
	| OP_JSET '%' 'x' ',' label ',' label {
		bld.JSET(filter.Index, $5, $7, 0)
	}
	| OP_JSET '#' number ',' label {
		bld.JSET(filter.Const, "", $5, $3)
	}
	| OP_JSET 'x' ',' label {
		bld.JSET(filter.Index, "", $4, 0)
	}
	| OP_JSET '%' 'x' ',' label {
		bld.JSET(filter.Index, "", $5, 0)
	}
	;

add
	: OP_ADD '#' number {
		bld.ADD(filter.Const, $3)
	}
	| OP_ADD 'x' {
		bld.ADD(filter.Index, 0)
	}
	| OP_ADD '%' 'x' {
		bld.ADD(filter.Index, 0)
	}
	;

sub
	: OP_SUB '#' number {
		bld.SUB(filter.Const, $3)
	}
	| OP_SUB 'x' {
		bld.SUB(filter.Index, 0)
	}
	| OP_SUB '%' 'x' {
		bld.SUB(filter.Index, 0)
	}
	;

mul
	: OP_MUL '#' number {
		bld.MUL(filter.Const, $3)
	}
	| OP_MUL 'x' {
		bld.MUL(filter.Index, 0)
	}
	| OP_MUL '%' 'x' {
		bld.MUL(filter.Index, 0)
	}
	;

div
	: OP_DIV '#' number {
		bld.DIV(filter.Const, $3)
	}
	| OP_DIV 'x' {
		bld.DIV(filter.Index, 0)
	}
	| OP_DIV '%' 'x' {
		bld.DIV(filter.Index, 0)
	}
	;

neg
	: OP_NEG {
		bld.NEG()
	}
	;

and
	: OP_AND '#' number {
		bld.AND(filter.Const, $3)
	}
	| OP_AND 'x' {
		bld.AND(filter.Index, 0)
	}
	| OP_AND '%' 'x' {
		bld.AND(filter.Index, 0)
	}
	;

or
	: OP_OR '#' number {
		bld.OR(filter.Const, $3)
	}
	| OP_OR 'x' {
		bld.OR(filter.Index, 0)
	}
	| OP_OR '%' 'x' {
		bld.OR(filter.Index, 0)
	}
	;

lsh
	: OP_LSH '#' number {
		bld.LSH(filter.Const, $3)
	}
	| OP_LSH 'x' {
		bld.LSH(filter.Index, 0)
	}
	| OP_LSH '%' 'x' {
		bld.LSH(filter.Index, 0)
	}
	;

rsh
	: OP_RSH '#' number {
		bld.RSH(filter.Const, $3)
	}
	| OP_RSH 'x' {
		bld.RSH(filter.Index, 0)
	}
	| OP_RSH '%' 'x' {
		bld.RSH(filter.Index, 0)
	}
	;

ret
	: OP_RET 'a' {
		bld.RET(filter.Acc, 0)
	}
	| OP_RET '%' 'a' {
		bld.RET(filter.Acc, 0)
	}
	| OP_RET 'x' {
		bld.RET(filter.Index, 0)
	}
	| OP_RET '%' 'x' {
		bld.RET(filter.Index, 0)
	}
	| OP_RET '#' number {
		bld.RET(filter.Const, $3)
	}
	;

tax
	: OP_TAX {
		bld.TAX()
	}
	;

txa
	: OP_TXA {
		bld.TXA()
	}
	;

%%


================================================
FILE: examples/dump/main.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import "log"
import "strconv"

import "github.com/docopt/docopt-go"

import "github.com/ghedo/go.pkt/capture"
import "github.com/ghedo/go.pkt/capture/pcap"
import "github.com/ghedo/go.pkt/capture/file"
import "github.com/ghedo/go.pkt/filter"
import "github.com/ghedo/go.pkt/layers"

func main() {
    log.SetFlags(0)

    usage := `Usage: dump [options] [<expression>]

Dump the traffic on the network (like tcpdump).

Options:
  -c <count>  Exit after receiving count packets.
  -i <iface>  Listen on interface.
  -r <file>   Read packets from file.
  -w <file>   Write the raw packets to file.`

    args, err := docopt.Parse(usage, nil, true, "", false)
    if err != nil {
        log.Fatalf("Invalid arguments: %s", err)
    }

    var count uint64

    if args["-c"] != nil {
        count, err = strconv.ParseUint(args["-c"].(string), 10, 64)
        if err != nil {
            log.Fatalf("Error parsing count: %s", err)
        }
    }

    var src capture.Handle

    if args["-i"] != nil {
        src, err = pcap.Open(args["-i"].(string))
        if err != nil {
            log.Fatalf("Error opening iface: %s", err)
        }
    } else if args["-r"] != nil {
        src, err = file.Open(args["-r"].(string))
        if err != nil {
            log.Fatalf("Error opening file: %s", err)
        }
    } else {
        log.Fatalf("Must select a source (either -i or -r)")
    }
    defer src.Close()

    var dst capture.Handle

    if args["-w"] != nil {
        dst, err = file.Open(args["-w"].(string))
        if err != nil {
            log.Fatalf("Error opening file: %s", err)
        }
        defer dst.Close()
    }

    err = src.Activate()
    if err != nil {
        log.Fatalf("Error activating source: %s", err)
    }

    if args["<expression>"] != nil {
        expr := args["<expression>"].(string)

        flt, err := filter.Compile(expr, src.LinkType(), false)
        if err != nil {
            log.Fatalf("Error parsing filter: %s", err)
        }
        defer flt.Cleanup()

        err = src.ApplyFilter(flt)
        if err != nil {
            log.Fatalf("Error appying filter: %s", err)
        }
    }

    var i uint64

    for {
        buf, err := src.Capture()
        if err != nil {
            log.Fatalf("Error: %s", err)
            break
        }

        if buf == nil {
            break
        }

        i++

        if dst == nil {
            rcv_pkt, err := layers.UnpackAll(buf, src.LinkType())
            if err != nil {
                log.Printf("Error: %s\n", err)
            }

            log.Println(rcv_pkt)
        } else {
            dst.Inject(buf)
        }

        if count > 0 && i >= count {
            break
        }
    }
}


================================================
FILE: examples/ping/main.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import "log"
import "math/rand"
import "net"
import "time"

import "github.com/docopt/docopt-go"

import "github.com/ghedo/go.pkt/capture/pcap"

import "github.com/ghedo/go.pkt/packet/eth"
import "github.com/ghedo/go.pkt/packet/icmpv4"
import "github.com/ghedo/go.pkt/packet/ipv4"

import "github.com/ghedo/go.pkt/network"
import "github.com/ghedo/go.pkt/routing"

func main() {
    log.SetFlags(0)

    usage := `Usage: ping <addr>

Ping the given IP address.`

    args, err := docopt.Parse(usage, nil, true, "", false)
    if err != nil {
        log.Fatalf("Invalid arguments: %s", err)
    }

    addr    := args["<addr>"].(string)
    addr_ip := net.ParseIP(addr)
    timeout := 5 * time.Second

    route, err := routing.RouteTo(addr_ip)
    if err != nil {
        log.Fatalf("Error: %s", err)
    }

    if route == nil {
        log.Println("No route found")
    }

    c, err := pcap.Open(route.Iface.Name)
    if err != nil {
        log.Fatalf("Error opening interface: %s", err)
    }
    defer c.Close()

    err = c.Activate()
    if err != nil {
        log.Fatalf("Error activating source: %s", err)
    }

    eth_pkt := eth.Make()
    eth_pkt.SrcAddr = route.Iface.HardwareAddr
    eth_pkt.DstAddr, _ = network.NextHopMAC(c, timeout, route, addr_ip)

    ipv4_pkt := ipv4.Make()
    ipv4_pkt.SrcAddr, _ = route.GetIfaceIPv4Addr()
    ipv4_pkt.DstAddr = addr_ip

    icmp_pkt := icmpv4.Make()
    icmp_pkt.Type = icmpv4.EchoRequest
    icmp_pkt.Seq = 0
    icmp_pkt.Id = uint16(rand.Intn(65535))

    _, err = network.SendRecv(c, timeout, eth_pkt, ipv4_pkt, icmp_pkt)
    if err != nil {
        log.Fatal(err)
    }

    log.Println("ping")
}


================================================
FILE: examples/route/main.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import "log"
import "net"

import "github.com/docopt/docopt-go"

import "github.com/ghedo/go.pkt/routing"

func main() {
    log.SetFlags(0)

    usage := `Usage: route [options] [<dest_addr>]

Find the best route on the local routing table to the given destination IP
address (or dump all routes).

Options:
  -a  Dump all routes.`

    args, err := docopt.Parse(usage, nil, true, "", false)
    if err != nil {
        log.Fatalf("Invalid arguments: %s", err)
    }

    if args["-a"].(bool) {
        routes, err := routing.Routes()
        if err != err {
            log.Fatalf("Error: %s", err)
        }

        for _, r := range routes {
            log.Println(r)
        }

        return
    }

    if args["<dest_addr>"] == nil {
        log.Fatalf("Must pass destination address")
    }

    route, err := routing.RouteTo(net.ParseIP(args["<dest_addr>"].(string)))
    if err != nil {
        log.Fatalf("Error: %s", err)
    }

    if route != nil {
        log.Println(route)
    } else {
        log.Println("No route found")
    }
}


================================================
FILE: examples/syn_scan/main.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import "fmt"
import "log"
import "math"
import "math/rand"
import "net"
import "time"

import "github.com/docopt/docopt-go"

import "github.com/ghedo/go.pkt/capture/pcap"

import "github.com/ghedo/go.pkt/packet"
import "github.com/ghedo/go.pkt/packet/eth"
import "github.com/ghedo/go.pkt/packet/ipv4"
import "github.com/ghedo/go.pkt/packet/tcp"

import "github.com/ghedo/go.pkt/layers"
import "github.com/ghedo/go.pkt/network"
import "github.com/ghedo/go.pkt/routing"

func main() {
    log.SetFlags(0)

    usage := `Usage: syn_scan <addr>

Simple TCP port scanner.`

    args, err := docopt.Parse(usage, nil, true, "", false)
    if err != nil {
        log.Fatalf("Invalid arguments: %s", err)
    }

    addr    := args["<addr>"].(string)
    addr_ip := net.ParseIP(addr)
    timeout := 1 * time.Second

    route, err := routing.RouteTo(addr_ip)
    if err != nil {
        log.Fatalf("Error: %s", err)
    }

    if route == nil {
        log.Println("No route found")
    }

    c, err := pcap.Open(route.Iface.Name)
    if err != nil {
        log.Fatalf("Error opening interface: %s", err)
    }
    defer c.Close()

    err = c.Activate()
    if err != nil {
        log.Fatalf("Error activating source: %s", err)
    }

    eth_pkt := eth.Make()
    eth_pkt.SrcAddr = route.Iface.HardwareAddr
    eth_pkt.DstAddr, _ = network.NextHopMAC(c, timeout, route, addr_ip)

    ipv4_pkt := ipv4.Make()
    ipv4_pkt.SrcAddr, _ = route.GetIfaceIPv4Addr()
    ipv4_pkt.DstAddr = addr_ip

    tcp_pkt := tcp.Make()
    tcp_pkt.SrcPort = 49152
    tcp_pkt.DstPort = 1
    tcp_pkt.Flags   = tcp.Syn
    tcp_pkt.Seq     = uint32(rand.Intn(math.MaxUint32))
    tcp_pkt.WindowSize = 5840

    for port := uint16(1); port < math.MaxUint16; port ++ {
        tcp_pkt.DstPort = port

        fmt.Printf("Scanning port %.5d: ", port)

        pkt, err := network.SendRecv(c, timeout, eth_pkt, ipv4_pkt, tcp_pkt)
        if err != nil {
            fmt.Printf("%s\n", err)
            continue
        }

        tcp_pkt := layers.FindLayer(pkt, packet.TCP).(*tcp.Packet)

        if tcp_pkt.Flags & tcp.Rst == 0 {
            fmt.Printf("OPEN\n")
        } else if tcp_pkt.Flags & tcp.Syn == 0{
            fmt.Printf("CLOSED\n")
        }
    }
}


================================================
FILE: examples/tracereply/main.go
================================================
package main

import "log"
import "net"
import "strconv"

import "github.com/docopt/docopt-go"

import "github.com/songgao/water"

import "github.com/ghedo/go.pkt/packet"
import "github.com/ghedo/go.pkt/packet/ipv6"
import "github.com/ghedo/go.pkt/packet/icmpv6"
import "github.com/ghedo/go.pkt/packet/tcp"
import "github.com/ghedo/go.pkt/packet/udp"
import "github.com/ghedo/go.pkt/layers"

func main() {
    log.SetFlags(0)

    usage := `Usage: tracereply <netif> <hops> <start_addr>

Reply to ICMPv6 traceroutes.`

    args, err := docopt.Parse(usage, nil, true, "", false)
    if err != nil {
        log.Fatalf("Invalid arguments: %s", err)
    }

    netif := args["<netif>"].(string)
    ip    := net.ParseIP(args["<start_addr>"].(string))

    hops, err := strconv.ParseUint(args["<hops>"].(string), 10, 8)
    if err != nil {
        log.Fatalf("Error parsing hop paramenter: %s", err)
    }

    config := water.Config{ DeviceType: water.TUN }
    config.Name = netif

    capture, err := water.New(config)
    if err != nil {
        log.Fatalf("Error creating capture interface: %s", err)
    }

    for {
        buf := make([]byte, 1500)

        buf_len, err := capture.Read(buf)
        if err != nil {
            log.Fatalf("Error reading packet from interface: %s", err)
        }

        buf = buf[:buf_len]

        pkt, err := layers.UnpackAll(buf, packet.IPv6)
        if err != nil {
            log.Printf("Error unpacking packet: %s", err)
            continue;
        }

        ip_pkt := layers.FindLayer(pkt, packet.IPv6)
        if ip_pkt == nil {
            continue;
        }

        if ip_pkt.Payload() == nil {
            continue
        }

        reply_ip_pkt := ipv6.Make()
        reply_ip_pkt.DstAddr = ip_pkt.(*ipv6.Packet).SrcAddr

        ttl := ip_pkt.(*ipv6.Packet).HopLimit

        reply_pkts := []packet.Packet{ reply_ip_pkt }

        switch {
        case uint64(ttl) < hops:
            []byte(ip)[len(ip) - 1] = ttl

            reply_ip_pkt.SrcAddr = ip

            reply_pkt := icmpv6.Make()

            reply_pkt.Type = icmpv6.TimeExceeded
            reply_pkt.Code = 0

            reply_pkts = append(reply_pkts, reply_pkt, ip_pkt, ip_pkt.Payload())

        case uint64(ttl) >= hops:
            reply_ip_pkt.SrcAddr = ip_pkt.(*ipv6.Packet).DstAddr

            switch ip_pkt.Payload().GetType() {
            case packet.ICMPv6:
                reply_pkt := icmpv6.Make()

                reply_pkt.Type = icmpv6.EchoReply
                reply_pkt.Code = 0
                reply_pkt.Body = ip_pkt.Payload().(*icmpv6.Packet).Body

                reply_pkts = append(reply_pkts, reply_pkt)

            case packet.TCP:
                reply_pkt := tcp.Make()

                reply_pkt.SrcPort = ip_pkt.Payload().(*tcp.Packet).DstPort
                reply_pkt.DstPort = ip_pkt.Payload().(*tcp.Packet).SrcPort
                reply_pkt.Flags   = tcp.Rst

                reply_pkts = append(reply_pkts, reply_pkt)

            case packet.UDP:
                reply_pkt := udp.Make()

                reply_pkt.SrcPort = ip_pkt.Payload().(*udp.Packet).DstPort
                reply_pkt.DstPort = ip_pkt.Payload().(*udp.Packet).SrcPort

                reply_pkts = append(reply_pkts, reply_pkt,
                                    ip_pkt.Payload().Payload())
            }
        }

        reply_buf, err := layers.Pack(reply_pkts...)
        if err != nil {
            log.Printf("Error while packing: %s\n", err)
            continue;
        }

        capture.Write(reply_buf)
    }
}


================================================
FILE: examples/traceroute/main.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import "log"
import "math"
import "math/rand"
import "net"
import "time"

import "github.com/docopt/docopt-go"

import "github.com/ghedo/go.pkt/capture/pcap"

import "github.com/ghedo/go.pkt/packet"
import "github.com/ghedo/go.pkt/packet/eth"
import "github.com/ghedo/go.pkt/packet/icmpv4"
import "github.com/ghedo/go.pkt/packet/ipv4"
import "github.com/ghedo/go.pkt/packet/raw"
import "github.com/ghedo/go.pkt/packet/tcp"
import "github.com/ghedo/go.pkt/packet/udp"

import "github.com/ghedo/go.pkt/layers"
import "github.com/ghedo/go.pkt/network"
import "github.com/ghedo/go.pkt/routing"

func main() {
    log.SetFlags(0)

    usage := `Usage: traceroute (--icmp | --udp | --tcp ) <addr>

Find the route to the given IP address using ICMP, UDP or TCP packets.

Options:
  --icmp  Use ICMP packets.
  --udp   Use UDP packets.
  --tcp   Use TCP packets.`

    args, err := docopt.Parse(usage, nil, true, "", false)
    if err != nil {
        log.Fatalf("Invalid arguments: %s", err)
    }

    addr    := args["<addr>"].(string)
    addr_ip := net.ParseIP(addr)
    timeout := 5 * time.Second

    route, err := routing.RouteTo(addr_ip)
    if err != nil {
        log.Fatalf("Error: %s", err)
    }

    if route == nil {
        log.Println("No route found")
    }

    c, err := pcap.Open(route.Iface.Name)
    if err != nil {
        log.Fatalf("Error opening interface: %s", err)
    }
    defer c.Close()

    err = c.Activate()
    if err != nil {
        log.Fatalf("Error activating source: %s", err)
    }

    eth_pkt := eth.Make()
    eth_pkt.SrcAddr = route.Iface.HardwareAddr
    eth_pkt.DstAddr, _ = network.NextHopMAC(c, timeout, route, addr_ip)

    ipv4_pkt := ipv4.Make()
    ipv4_pkt.SrcAddr, _ = route.GetIfaceIPv4Addr()
    ipv4_pkt.DstAddr = addr_ip
    ipv4_pkt.Id      = uint16(rand.Intn(math.MaxUint16))
    ipv4_pkt.TTL     = 1

    var payload_pkt packet.Packet

    if args["--icmp"].(bool) {
        icmp_pkt := icmpv4.Make()
        icmp_pkt.Type = icmpv4.EchoRequest
        icmp_pkt.Id   = uint16(rand.Intn(math.MaxUint16))
        icmp_pkt.Seq  = 1

        payload_pkt = icmp_pkt
    }

    if args["--udp"].(bool) {
        udp_pkt := udp.Make()
        udp_pkt.SrcPort = 49152
        udp_pkt.DstPort = 33434

        raw_pkt := raw.Make()
        raw_pkt.Data = make([]byte, 40 - udp_pkt.GetLength())

        for i := 0; i < len(raw_pkt.Data); i++ {
            raw_pkt.Data[i] = byte(0x40 + (i & 0x3f))
        }

        udp_pkt.SetPayload(raw_pkt)

        payload_pkt = udp_pkt
    }

    if args["--tcp"].(bool) {
        tcp_pkt := tcp.Make()
        tcp_pkt.SrcPort = 49152
        tcp_pkt.DstPort = 80
        tcp_pkt.Flags   = tcp.Syn | tcp.ECE | tcp.Cwr
        tcp_pkt.Seq     = uint32(rand.Intn(math.MaxUint32))
        tcp_pkt.WindowSize = 5840

        raw_pkt := raw.Make()
        raw_pkt.Data = make([]byte, 40 - tcp_pkt.GetLength())

        for i := 0; i < len(raw_pkt.Data); i++ {
            raw_pkt.Data[i] = byte(0x40 + (i & 0x3f))
        }

        tcp_pkt.SetPayload(raw_pkt)

        payload_pkt = tcp_pkt
    }

    for {
        pkt, err := network.SendRecv(c, timeout, eth_pkt, ipv4_pkt, payload_pkt)
        if err != nil {
            log.Fatal(err)
        }

        ipv4_rsp := layers.FindLayer(pkt, packet.IPv4).(*ipv4.Packet)

        log.Println(ipv4_rsp.SrcAddr)

        if ipv4_rsp.SrcAddr.Equal(addr_ip) {
            return
        }

        ipv4_pkt.TTL++
        ipv4_pkt.Id++

        if ipv4_pkt.TTL > 64 {
            return
        }
    }
}


================================================
FILE: filter/bpf_builder.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package filter

// #include "bpf_filter.h"
import "C"

// A Builder is used to compile a BPF filter from basic BPF instructions.
type Builder struct {
    filter    *Filter
    labels    map[string]int

    jumps_k  map[int]string
    jumps_jt map[int]string
    jumps_jf map[int]string
}

// Allocate and initialize a new Builder.
func NewBuilder() *Builder {
    b := &Builder{}

    b.filter   = &Filter{}
    b.labels   = make(map[string]int)
    b.jumps_k  = make(map[int]string)
    b.jumps_jt = make(map[int]string)
    b.jumps_jf = make(map[int]string)

    return b
}

// Generate and return the Filter associated with the Builder.
func (b *Builder) Build() *Filter {
    prog := (*C.struct_bpf_program)(b.filter.Program())
    flen := int(C.bpf_get_len(prog))

    for i := 0; i < flen; i++ {
        insn := C.bpf_get_insn(prog, C.int(i))

        if lbl, ok := b.jumps_k[i]; ok {
            addr := b.labels[lbl]
            if addr != 0 {
                insn.k = C.bpf_u_int32(addr - i - 1)
            }
        }

        if lbl, ok := b.jumps_jt[i]; ok {
            addr := b.labels[lbl]
            if addr != 0 {
                insn.jt = C.u_char(addr - i - 1)
            }
        }

        if lbl, ok := b.jumps_jf[i]; ok {
            addr := b.labels[lbl]
            if addr != 0  {
                insn.jf = C.u_char(addr - i - 1)
            }
        }
    }

    return b.filter
}

// Define a new label at the next instruction position. Labels are used in jump
// instructions to identify the jump target.
func (b *Builder) Label(name string) *Builder {
    b.labels[name] = b.filter.Len()
    return b
}

// Append an LD instruction to the filter, which loads a value of size s into
// the accumulator. m represents the addressing mode of the source operand and
// can be IMM (load a constant value), ABS (load packet data at the given fixed
// offset), IND (load packet data at the given relative offset), LEN (load the
// packet length or MEM (load a value from memory at the given offset).
func (b *Builder) LD(s Size, m Mode, val uint32) *Builder {
    code := Code(uint16(s) | uint16(m)) | LD
    b.filter.append_insn(code, 0, 0, val)
    return b
}

// Append a LDX (load index) instruction to the filter, which loads a value of
// size s into the index register. m represents the addressing mode of the
// source operand and can be IMM (load a constant value), LEN (load the packet
// length, MEM (load a value from memory at the given offset) or MSH (load the
// length of the IP header).
func (b *Builder) LDX(s Size, m Mode, val uint32) *Builder {
    code := Code(uint16(s) | uint16(m) | LDX)
    b.filter.append_insn(code, 0, 0, val)
    return b
}

// Append a ST (store) instruction to the filter, which stores the value of the
// accumulator in memory at the given offset.
func (b *Builder) ST(off uint32) *Builder {
    b.filter.append_insn(ST, 0, 0, off)
    return b
}

// Append a STX (store index) instruction to the filter, which stores the value
// of the index register in memory at the given offset.
func (b *Builder) STX(off uint32) *Builder {
    b.filter.append_insn(STX, 0, 0, off)
    return b
}

// Append an ADD instruction to the filter, which adds a value to the
// accumulator. s represents the source operand type and can be either Const
// (which adds the supplied value) or Index (which adds the index register
// value).
func (b *Builder) ADD(s Src, val uint32) *Builder {
    code := Code(uint16(s) | uint16(0x00) | ALU)
    b.filter.append_insn(code, 0, 0, val)
    return b
}

// Append a SUB instruction to the filter, which subtracts a value from the
// accumulator. s represents the source operand type and can be either Const
// (which subtracts the supplied value) or Index (which subtracts the index
// register value).
func (b *Builder) SUB(s Src, val uint32) *Builder {
    code := Code(uint16(s) | uint16(0x10) | ALU)
    b.filter.append_insn(code, 0, 0, val)
    return b
}

// Append a MUL instruction to the filter, which multiplies a value to the
// accumulator. s represents the source operand type and can be either Const
// (which multiplies the supplied value) or Index (which multiplies the index
// register value).
func (b *Builder) MUL(s Src, val uint32) *Builder {
    code := Code(uint16(s) | uint16(0x20) | ALU)
    b.filter.append_insn(code, 0, 0, val)
    return b
}

// Append a DIV instruction to the filter, which divides the accumulator by a
// value. s represents the source operand type and can be either Const (which
// divides by the supplied value) or Index (which divides by the index register
// value).
func (b *Builder) DIV(s Src, val uint32) *Builder {
    code := Code(uint16(s) | uint16(0x30) | ALU)
    b.filter.append_insn(code, 0, 0, val)
    return b
}

// Append an OR instruction to the filter, which performs the binary "or"
// between the accumulator and a value. s represents the source operand type and
// can be either Const (which uses the supplied value) or Index (which uses the
// index register value).
func (b *Builder) OR(s Src, val uint32) *Builder {
    code := Code(uint16(s) | uint16(0x40) | ALU)
    b.filter.append_insn(code, 0, 0, val)
    return b
}

// Append an AND instruction to the filter, which performs the binary "and"
// between the accumulator and a value. s represents the source operand type and
// can be either Const (which uses the supplied value) or Index (which uses the
// index register value).
func (b *Builder) AND(s Src, val uint32) *Builder {
    code := Code(uint16(s) | uint16(0x50) | ALU)
    b.filter.append_insn(code, 0, 0, val)
    return b
}

// Append an LSH instruction to the filter, which shifts to the left the
// accumulator register by a value. s represents the source operand type and can
// be either Const (which shifts by the supplied value) or Index (which shifts
// by the index register value).
func (b *Builder) LSH(s Src, val uint32) *Builder {
    code := Code(uint16(s) | uint16(0x60) | ALU)
    b.filter.append_insn(code, 0, 0, val)
    return b
}

// Append an RSH instruction to the filter, which shifts to the right the
// accumulator register by a value. s represents the source operand type and can
// be either Const (which shifts by the supplied value) or Index (which shifts
// by the index register value).
func (b *Builder) RSH(s Src, val uint32) *Builder {
    code := Code(uint16(s) | uint16(0x70) | ALU)
    b.filter.append_insn(code, 0, 0, val)
    return b
}

// Append a NEG instruction to the filter which negates the accumulator.
func (b *Builder) NEG() *Builder {
    code := Code(uint16(0x80) | ALU)
    b.filter.append_insn(code, 0, 0, 0)
    return b
}

// Append a MOD instruction to the filter, which computes the accumulator modulo a
// value. s represents the source operand type and can be either Const (which
// divides by the supplied value) or Index (which divides by the index register
// value).
func (b *Builder) MOD(s Src, val uint32) *Builder {
    code := Code(uint16(s) | uint16(0x90) | ALU)
    b.filter.append_insn(code, 0, 0, val)
    return b
}

// Append an XOR instruction to the filter, which performs the binary "xor"
// between the accumulator and a value. s represents the source operand type and
// can be either Const (which uses the supplied value) or Index (which uses the
// index register value).
func (b *Builder) XOR(s Src, val uint32) *Builder {
    code := Code(uint16(s) | uint16(0xa0) | ALU)
    b.filter.append_insn(code, 0, 0, val)
    return b
}

// Append a JA instruction to the filter, which performs a jump to the given
// label.
func (b *Builder) JA(j string) *Builder {
    b.jumps_k[b.filter.Len()] = j

    code := Code(uint16(0x00) | JMP)
    b.filter.append_insn(code, 0, 0, 0)
    return b
}

// Append a JEQ instruction to the filter, which performs a jump to the jt label
// if the accumulator value equals cmp (if s is Const) or the index register (if
// s is Index), otherwise jumps to jf.
func (b *Builder) JEQ(s Src, jt, jf string, cmp uint32) *Builder {
    b.jumps_jt[b.filter.Len()] = jt
    b.jumps_jf[b.filter.Len()] = jf

    code := Code(uint16(s) | uint16(0x10) | JMP)
    b.filter.append_insn(code, 0, 0, cmp)
    return b
}

// Append a JGT instruction to the filter, which performs a jump to the jt label
// if the accumulator value is greater than cmp (if s is Const) or the index
// register (if s is Index), otherwise jumps to jf.
func (b *Builder) JGT(s Src, jt, jf string, cmp uint32) *Builder {
    b.jumps_jt[b.filter.Len()] = jt
    b.jumps_jf[b.filter.Len()] = jf

    code := Code(uint16(s) | uint16(0x20) | JMP)
    b.filter.append_insn(code, 0, 0, cmp)
    return b
}

// Append a JGE instruction to the filter, which performs a jump to the jt label
// if the accumulator value is greater than or equals cmp (if s is Const) or the
// index register (if s is Index), otherwise jumps to jf.
func (b *Builder) JGE(s Src, jt, jf string, cmp uint32) *Builder {
    b.jumps_jt[b.filter.Len()] = jt
    b.jumps_jf[b.filter.Len()] = jf

    code := Code(uint16(s) | uint16(0x30) | JMP)
    b.filter.append_insn(code, 0, 0, cmp)
    return b
}

// Append a JSET instruction to the filter.
func (b *Builder) JSET(s Src, jt, jf string, cmp uint32) *Builder {
    b.jumps_jt[b.filter.Len()] = jt
    b.jumps_jf[b.filter.Len()] = jf

    code := Code(uint16(s) | uint16(0x40) | JMP)
    b.filter.append_insn(code, 0, 0, cmp)
    return b
}

// Append a RET instruction to the filter, which terminates the filter program
// and specifies the amount of the packet to accept. s represents the source
// operand type and can be either Const (which returns the supplied value) or
// Acc (which returns the accumulator value).
func (b *Builder) RET(s Src, bytes uint32) *Builder {
    code := Code(uint16(s) | RET)
    b.filter.append_insn(code, 0, 0, bytes)
    return b
}

// Append a TAX instruction to the filter. TAX transfers the accumulator value
// into the index register.
func (b *Builder) TAX() *Builder {
    code := Code(uint16(0x00) | MISC)
    b.filter.append_insn(code, 0, 0, 0)
    return b
}

// Append a TXA instruction to the filter. TXA transfers the index register
// value into the accumulator.
func (b *Builder) TXA() *Builder {
    code := Code(uint16(0x80) | MISC)
    b.filter.append_insn(code, 0, 0, 0)
    return b
}

// Append a raw BPF instruction
func (b *Builder) AppendInstruction(code Code, jt, jf uint8, k uint32) *Builder {
    b.filter.append_insn(code, jt, jf, k)
    return b
}


================================================
FILE: filter/bpf_builder_test.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package filter_test

import "log"
import "testing"

import "github.com/ghedo/go.pkt/filter"

func TestEmpty(t *testing.T) {
    bld := filter.NewBuilder()

    flt := bld.Build()
    if flt.Len() != 0 {
        t.Fatalf("Len mismatch: %d", flt.Len())
    }
    flt.Cleanup()
}

var test_arp = `{ 0x28,   0,   0, 0x0000000c },
{ 0x15,   0,   1, 0x00000806 },
{ 0x06,   0,   0, 0x00040000 },
{ 0x06,   0,   0, 0x00000000 },`

func TestARP(t *testing.T) {
    arp := filter.NewBuilder().
        LD(filter.Half, filter.ABS, 12).
        JEQ(filter.Const, "", "fail", 0x806).
        RET(filter.Const, 0x40000).
        Label("fail").
        RET(filter.Const, 0x0).
        Build()

    if arp.String() != test_arp {
        t.Fatalf("Program mismatch: %s", arp.String())
    }
}

func TestARPcBPF(t *testing.T) {
    arp := filter.NewBuilder().
    AppendInstruction(40, 0, 0, 12).
    AppendInstruction(21, 0, 1, 2054).
    AppendInstruction(6, 0, 0, 262144).
    AppendInstruction(6, 0, 0, 0).
    Build()

    if arp.String() != test_arp {
        t.Fatalf("Program mismatch: %s", arp.String())
    }
}

var test_dns = `{ 0x00,   0,   0, 0x00000014 },
{ 0xb1,   0,   0, 0x00000000 },
{ 0x0c,   0,   0, 0x00000000 },
{ 0x07,   0,   0, 0x00000000 },
{ 0x40,   0,   0, 0x00000000 },
{ 0x15,   0,   7, 0x07657861 },
{ 0x40,   0,   0, 0x00000004 },
{ 0x15,   0,   5, 0x6d706c65 },
{ 0x40,   0,   0, 0x00000008 },
{ 0x15,   0,   3, 0x03636f6d },
{ 0x50,   0,   0, 0x0000000c },
{ 0x15,   0,   1, 0x00000000 },
{ 0x06,   0,   0, 0x00000001 },
{ 0x06,   0,   0, 0x00000000 },`

func TestDNS(t *testing.T) {
    dns := filter.NewBuilder().
        LD(filter.Word, filter.IMM, 20).
        LDX(filter.Byte, filter.MSH, 0).
        ADD(filter.Index, 0).
        TAX().
        Label("lb_0").
        LD(filter.Word, filter.IND, 0).
        JEQ(filter.Const, "", "lb_1", 0x07657861).
        LD(filter.Word, filter.IND, 4).
        JEQ(filter.Const, "", "lb_1", 0x6d706c65).
        LD(filter.Word, filter.IND, 8).
        JEQ(filter.Const, "", "lb_1", 0x03636f6d).
        LD(filter.Byte, filter.IND, 12).
        JEQ(filter.Const, "", "lb_1", 0x00).
        RET(filter.Const, 1).
        Label("lb_1").
        RET(filter.Const, 0).
        Build()


    if dns.String() != test_dns {
        t.Fatalf("Program mismatch: %s", dns.String())
    }
}

func TestALUOps(t *testing.T) {
    flt := filter.NewBuilder().
        LD(filter.Byte, filter.ABS, 0).
        JEQ(filter.Const, "", "fail", 0x0f).
        ADD(filter.Const, 1).
        JEQ(filter.Const, "", "fail", 0x10).
        SUB(filter.Const, 1).
        JEQ(filter.Const, "", "fail", 0x0f).
        MUL(filter.Const, 2).
        JEQ(filter.Const, "", "fail", 0x1e).
        DIV(filter.Const, 2).
        JEQ(filter.Const, "", "fail", 0x0f).
        OR(filter.Const, 0xf0).
        JEQ(filter.Const, "", "fail", 0xff).
        AND(filter.Const, 0x0f).
        JEQ(filter.Const, "", "fail", 0x0f).
        LSH(filter.Const, 4).
        JEQ(filter.Const, "", "fail", 0xf0).
        RSH(filter.Const, 4).
        JEQ(filter.Const, "", "fail", 0x0f).
        MOD(filter.Const, 0x0d).
        JEQ(filter.Const, "", "fail", 0x02).
        XOR(filter.Const, 0x03).
        JEQ(filter.Const, "", "fail", 0x01).
        RET(filter.Const, 0x40000).
        Label("fail").
        RET(filter.Const, 0x0).
        Build()

    if !flt.Validate() {
        t.Fatalf("Invalid filter: %s", flt.String())
    }

    if !flt.Match([]byte{0x0f}) {
        t.Fatal("Bad Math")
    }
}

func ExampleBuilder() {
    // Build a filter to match ARP packets on top of Ethernet
    flt := filter.NewBuilder().
        LD(filter.Half, filter.ABS, 12).
        JEQ(filter.Const, "", "fail", 0x806).
        RET(filter.Const, 0x40000).
        Label("fail").
        RET(filter.Const, 0x0).
        Build()

    if flt.Match([]byte("random data")) {
        log.Println("MATCH!!!")
    }
}


================================================
FILE: filter/bpf_filter.c
================================================
/*-
 * Copyright (c) 1990, 1991, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from the Stanford/CMU enet packet filter,
 * (net/enet.c) distributed as part of 4.3BSD, and code contributed
 * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
 * Berkeley Laboratory.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *      @(#)bpf_filter.c	8.1 (Berkeley) 6/10/93
 */

#include <stdint.h>
#include <stdlib.h>
#include <strings.h>

#include <sys/cdefs.h>
#include <sys/param.h>

#include <netinet/in.h>

#ifndef __i386__
#define BPF_ALIGN
#endif

#define EXTRACT_BYTE(p)\
	((u_int8_t)\
		((u_int8_t)*((u_char *)p)))

#ifndef BPF_ALIGN
#define EXTRACT_SHORT(p)	((u_int16_t)ntohs(*(u_int16_t *)p))
#define EXTRACT_LONG(p)		(ntohl(*(u_int32_t *)p))
#else
#define EXTRACT_SHORT(p)\
	((u_int16_t)\
		((u_int16_t)*((u_char *)p+0)<<8|\
		 (u_int16_t)*((u_char *)p+1)<<0))
#define EXTRACT_LONG(p)\
		((u_int32_t)*((u_char *)p+0)<<24|\
		 (u_int32_t)*((u_char *)p+1)<<16|\
		 (u_int32_t)*((u_char *)p+2)<<8|\
		 (u_int32_t)*((u_char *)p+3)<<0)
#endif

#include "bpf_filter.h"

/*
 * Execute the filter program starting at pc on the packet p
 * wirelen is the length of the original packet
 * buflen is the amount of data present
 */
u_int
bpf_filter(const struct bpf_insn *pc, char *p, u_int wirelen, u_int buflen)
{
	u_int32_t A = 0, X = 0;
	u_int32_t k;
	u_int32_t mem[BPF_MEMWORDS];

	bzero(mem, sizeof(mem));

	if (pc == NULL)
		/*
		 * No filter means accept all.
		 */
		return ((u_int)-1);

	--pc;
	while (1) {
		++pc;
		switch (pc->code) {
		default:
			abort();

		case BPF_RET|BPF_K:
			return ((u_int)pc->k);

		case BPF_RET|BPF_A:
			return ((u_int)A);

		case BPF_LD|BPF_W|BPF_ABS:
			k = pc->k;
			if (k > buflen || sizeof(int32_t) > buflen - k) {
				return (0);
			}
#ifdef BPF_ALIGN
			if (((intptr_t)(p + k) & 3) != 0)
				A = EXTRACT_LONG(&p[k]);
			else
#endif
				A = ntohl(*(int32_t *)(p + k));
			continue;

		case BPF_LD|BPF_H|BPF_ABS:
			k = pc->k;
			if (k > buflen || sizeof(int16_t) > buflen - k) {
				return (0);
			}
			A = EXTRACT_SHORT(&p[k]);
			continue;

		case BPF_LD|BPF_B|BPF_ABS:
			k = pc->k;
			if (k >= buflen) {
				return (0);
			}
			A = EXTRACT_BYTE(&p[k]);
			continue;

		case BPF_LD|BPF_W|BPF_LEN:
			A = wirelen;
			continue;

		case BPF_LDX|BPF_W|BPF_LEN:
			X = wirelen;
			continue;

		case BPF_LD|BPF_W|BPF_IND:
			k = X + pc->k;
			if (pc->k > buflen || X > buflen - pc->k ||
			    sizeof(int32_t) > buflen - k) {
				return (0);
			}
#ifdef BPF_ALIGN
			if (((intptr_t)(p + k) & 3) != 0)
				A = EXTRACT_LONG(&p[k]);
			else
#endif
				A = ntohl(*(int32_t *)(p + k));
			continue;

		case BPF_LD|BPF_H|BPF_IND:
			k = X + pc->k;
			if (X > buflen || pc->k > buflen - X ||
			    sizeof(int16_t) > buflen - k) {
				return (0);
			}
			A = EXTRACT_SHORT(&p[k]);
			continue;

		case BPF_LD|BPF_B|BPF_IND:
			k = X + pc->k;
			if (pc->k >= buflen || X >= buflen - pc->k) {
				return (0);
			}
			A = EXTRACT_BYTE(&p[k]);
			continue;

		case BPF_LDX|BPF_MSH|BPF_B:
			k = pc->k;
			if (k >= buflen) {
				return (0);
			}
			X = (p[pc->k] & 0xf) << 2;
			continue;

		case BPF_LD|BPF_IMM:
			A = pc->k;
			continue;

		case BPF_LDX|BPF_IMM:
			X = pc->k;
			continue;

		case BPF_LD|BPF_MEM:
			A = mem[pc->k];
			continue;

		case BPF_LDX|BPF_MEM:
			X = mem[pc->k];
			continue;

		case BPF_ST:
			mem[pc->k] = A;
			continue;

		case BPF_STX:
			mem[pc->k] = X;
			continue;

		case BPF_JMP|BPF_JA:
			pc += pc->k;
			continue;

		case BPF_JMP|BPF_JGT|BPF_K:
			pc += (A > pc->k) ? pc->jt : pc->jf;
			continue;

		case BPF_JMP|BPF_JGE|BPF_K:
			pc += (A >= pc->k) ? pc->jt : pc->jf;
			continue;

		case BPF_JMP|BPF_JEQ|BPF_K:
			pc += (A == pc->k) ? pc->jt : pc->jf;
			continue;

		case BPF_JMP|BPF_JSET|BPF_K:
			pc += (A & pc->k) ? pc->jt : pc->jf;
			continue;

		case BPF_JMP|BPF_JGT|BPF_X:
			pc += (A > X) ? pc->jt : pc->jf;
			continue;

		case BPF_JMP|BPF_JGE|BPF_X:
			pc += (A >= X) ? pc->jt : pc->jf;
			continue;

		case BPF_JMP|BPF_JEQ|BPF_X:
			pc += (A == X) ? pc->jt : pc->jf;
			continue;

		case BPF_JMP|BPF_JSET|BPF_X:
			pc += (A & X) ? pc->jt : pc->jf;
			continue;

		case BPF_ALU|BPF_ADD|BPF_X:
			A += X;
			continue;

		case BPF_ALU|BPF_SUB|BPF_X:
			A -= X;
			continue;

		case BPF_ALU|BPF_MUL|BPF_X:
			A *= X;
			continue;

		case BPF_ALU|BPF_DIV|BPF_X:
			if (X == 0)
				return (0);
			A /= X;
			continue;

		case BPF_ALU|BPF_MOD|BPF_X:
			if (X == 0)
				return 0;
			A %= X;
			continue;

		case BPF_ALU|BPF_AND|BPF_X:
			A &= X;
			continue;

		case BPF_ALU|BPF_OR|BPF_X:
			A |= X;
			continue;

		case BPF_ALU|BPF_XOR|BPF_X:
			A ^= X;
			continue;

		case BPF_ALU|BPF_LSH|BPF_X:
			A <<= X;
			continue;

		case BPF_ALU|BPF_RSH|BPF_X:
			A >>= X;
			continue;

		case BPF_ALU|BPF_ADD|BPF_K:
			A += pc->k;
			continue;

		case BPF_ALU|BPF_SUB|BPF_K:
			A -= pc->k;
			continue;

		case BPF_ALU|BPF_MUL|BPF_K:
			A *= pc->k;
			continue;

		case BPF_ALU|BPF_DIV|BPF_K:
			A /= pc->k;
			continue;

		case BPF_ALU|BPF_MOD|BPF_K:
			A %= pc->k;
			continue;

		case BPF_ALU|BPF_AND|BPF_K:
			A &= pc->k;
			continue;

		case BPF_ALU|BPF_OR|BPF_K:
			A |= pc->k;
			continue;

		case BPF_ALU|BPF_XOR|BPF_K:
			A ^= pc->k;
			continue;

		case BPF_ALU|BPF_LSH|BPF_K:
			A <<= pc->k;
			continue;

		case BPF_ALU|BPF_RSH|BPF_K:
			A >>= pc->k;
			continue;

		case BPF_ALU|BPF_NEG:
			A = -A;
			continue;

		case BPF_MISC|BPF_TAX:
			X = A;
			continue;

		case BPF_MISC|BPF_TXA:
			A = X;
			continue;
		}
	}
}

static const u_short	bpf_code_map[] = {
	0x10ff,	/* 0x00-0x0f: 1111111100001000 */
	0x3070,	/* 0x10-0x1f: 0000111000001100 */
	0x3131,	/* 0x20-0x2f: 1000110010001100 */
	0x3031,	/* 0x30-0x3f: 1000110000001100 */
	0x3131,	/* 0x40-0x4f: 1000110010001100 */
	0x1011,	/* 0x50-0x5f: 1000100000001000 */
	0x1013,	/* 0x60-0x6f: 1100100000001000 */
	0x1010,	/* 0x70-0x7f: 0000100000001000 */
	0x0093,	/* 0x80-0x8f: 1100100100000000 */
	0x1010,	/* 0x90-0x9f: 0000100000001000 */
	0x1010,	/* 0xa0-0xaf: 0000100000001000 */
	0x0002,	/* 0xb0-0xbf: 0100000000000000 */
	0x0000,	/* 0xc0-0xcf: 0000000000000000 */
	0x0000,	/* 0xd0-0xdf: 0000000000000000 */
	0x0000,	/* 0xe0-0xef: 0000000000000000 */
	0x0000	/* 0xf0-0xff: 0000000000000000 */
};

#define	BPF_VALIDATE_CODE(c)	\
    ((c) <= 0xff && (bpf_code_map[(c) >> 4] & (1 << ((c) & 0xf))) != 0)

/*
 * Return true if the 'fcode' is a valid filter program.
 * The constraints are that each jump be forward and to a valid
 * code.  The code must terminate with either an accept or reject.
 */
int
bpf_validate(const struct bpf_insn *f, int len)
{
	register int i;
	register const struct bpf_insn *p;

	/* Do not accept negative length filter. */
	if (len < 0)
		return (0);

	/* An empty filter means accept all. */
	if (len == 0)
		return (1);

	for (i = 0; i < len; ++i) {
		p = &f[i];
		/*
		 * Check that the code is valid.
		 */
		if (!BPF_VALIDATE_CODE(p->code))
			return (0);
		/*
		 * Check that that jumps are forward, and within
		 * the code block.
		 */
		if (BPF_CLASS(p->code) == BPF_JMP) {
			register u_int offset;

			if (p->code == (BPF_JMP|BPF_JA))
				offset = p->k;
			else
				offset = p->jt > p->jf ? p->jt : p->jf;
			if (offset >= (u_int)(len - i) - 1)
				return (0);
			continue;
		}
		/*
		 * Check that memory operations use valid addresses.
		 */
		if (p->code == BPF_ST || p->code == BPF_STX ||
		    p->code == (BPF_LD|BPF_MEM) ||
		    p->code == (BPF_LDX|BPF_MEM)) {
			if (p->k >= BPF_MEMWORDS)
				return (0);
			continue;
		}
		/*
		 * Check for constant division by 0.
		 */
		if ((p->code == (BPF_ALU|BPF_DIV|BPF_K) ||
		    p->code == (BPF_ALU|BPF_MOD|BPF_K)) && p->k == 0)
			return (0);
	}
	return (BPF_CLASS(f[len - 1].code) == BPF_RET);
}

int
bpf_append_insn(struct bpf_program *p, unsigned short code,
                unsigned char jt, unsigned char jf, unsigned int k)
{
	p->bf_insns = realloc(p->bf_insns, ++p->bf_len*sizeof(struct bpf_insn));
	if (p->bf_insns == NULL)
		return -1;

	p->bf_insns[p->bf_len - 1].code = code;
	p->bf_insns[p->bf_len - 1].jt   = jt;
	p->bf_insns[p->bf_len - 1].jf   = jf;
	p->bf_insns[p->bf_len - 1].k    = k;

	return 0;
}

int
bpf_get_len(struct bpf_program *p)
{
	return p->bf_len;
}

struct bpf_insn *
bpf_get_insn(struct bpf_program *p, int i)
{
	if (i > p->bf_len)
		return NULL;

	return &p->bf_insns[i];
}


================================================
FILE: filter/bpf_filter.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Provides an API for compiling and manipulating BPF filters. A filter can be
// either compiled from tcpdump-like expressions, or created from basic BPF
// instructions. Filters can then be either applied to packet sources (see the
// capture package) or directly run against binary data.
package filter

// #include <stdlib.h>
// #include "bpf_filter.h"
import "C"

import "fmt"
import "strings"
import "syscall"
import "unsafe"

type Filter struct {
    program C.struct_bpf_program
}

type Code uint16

const (
    LD Code = syscall.BPF_LD
    LDX     = syscall.BPF_LDX
    ST      = syscall.BPF_ST
    STX     = syscall.BPF_STX
    ALU     = syscall.BPF_ALU
    JMP     = syscall.BPF_JMP
    RET     = syscall.BPF_RET
    MISC    = syscall.BPF_MISC
)

type Size uint16

const (
    Word Size = syscall.BPF_W
    Half      = syscall.BPF_H
    Byte      = syscall.BPF_B
)

type Mode uint16

const (
    IMM Mode = syscall.BPF_IMM
    ABS      = syscall.BPF_ABS
    IND      = syscall.BPF_IND
    MEM      = syscall.BPF_MEM
    LEN      = syscall.BPF_LEN
    MSH      = syscall.BPF_MSH
)

type Src uint16

const (
    Const Src = syscall.BPF_K
    Index     = syscall.BPF_X
    Acc       = syscall.BPF_A
)

// Try to match the given buffer against the filter.
func (f *Filter) Match(buf []byte) bool {
    cbuf := (*C.char)(unsafe.Pointer(&buf[0]))
    blen := C.uint(len(buf))

    if C.bpf_filter(f.program.bf_insns, cbuf, blen, blen) > 0 {
        return true
    }

    return false
}

// Run filter on the given buffer and return its result.
func (f *Filter) Filter(buf []byte) uint {
    cbuf := (*C.char)(unsafe.Pointer(&buf[0]))
    blen := C.uint(len(buf))

    rc := C.bpf_filter(f.program.bf_insns, cbuf, blen, blen)
    return uint(rc)
}

// Validate the filter. The constraints are that each jump be forward and to a
// valid code. The code must terminate with either an accept or reject.
func (f *Filter) Validate() bool {
    if C.bpf_validate(f.program.bf_insns, C.int(f.program.bf_len)) > 0 {
        return true
    }

    return false
}

// Deallocate the filter.
func (f *Filter) Cleanup() {
    f.program.bf_len = 0

    if f.program.bf_insns != nil {
        C.free(unsafe.Pointer(f.program.bf_insns))
        f.program.bf_insns = nil
    }
}

// Return the number of instructions in the filter.
func (f *Filter) Len() int {
    prog := (*C.struct_bpf_program)(f.Program())
    flen := C.bpf_get_len(prog)
    return int(flen)
}

// Return the compiled BPF program.
func (f *Filter) Program() unsafe.Pointer {
    return unsafe.Pointer(&f.program)
}

func (f *Filter) String() string {
    var insns []string

    prog := (*C.struct_bpf_program)(f.Program())
    flen := C.bpf_get_len(prog)

    for i := C.int(0); i < flen; i++ {
        insn := C.bpf_get_insn(prog, i)

        str := fmt.Sprintf(
            "{ 0x%.2x, %3d, %3d, 0x%.8x },",
            insn.code, insn.jt, insn.jf, insn.k,
        )

        insns = append(insns, str)
    }

    return strings.Join(insns, "\n")
}

func (f *Filter) append_insn(code Code, jt, jf uint8, k uint32) {
    prog := (*C.struct_bpf_program)(f.Program())
    C.bpf_append_insn(
        prog, C.ushort(code), C.uchar(jt), C.uchar(jf), C.uint(k),
    )
}


================================================
FILE: filter/bpf_filter.h
================================================
/*-
 * Copyright (c) 1990, 1991, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from the Stanford/CMU enet packet filter,
 * (net/enet.c) distributed as part of 4.3BSD, and code contributed
 * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
 * Berkeley Laboratory.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *      @(#)bpf.h	8.1 (Berkeley) 6/10/93
 *	@(#)bpf.h	1.34 (LBL)     6/16/96
 *
 * $FreeBSD$
 */

typedef unsigned int bpf_u_int32; /* cgo is stupid... */
typedef unsigned char u_char; /* oh, so stupid... */

struct bpf_program {
	unsigned int    bf_len; /* u_int */
	struct bpf_insn *bf_insns;
};

/*
 * The instruction encodings.
 */
/* instruction classes */
#define BPF_CLASS(code) ((code) & 0x07)
#define		BPF_LD		0x00
#define		BPF_LDX		0x01
#define		BPF_ST		0x02
#define		BPF_STX		0x03
#define		BPF_ALU		0x04
#define		BPF_JMP		0x05
#define		BPF_RET		0x06
#define		BPF_MISC	0x07

/* ld/ldx fields */
#define BPF_SIZE(code)	((code) & 0x18)
#define		BPF_W		0x00
#define		BPF_H		0x08
#define		BPF_B		0x10
#define BPF_MODE(code)	((code) & 0xe0)
#define		BPF_IMM 	0x00
#define		BPF_ABS		0x20
#define		BPF_IND		0x40
#define		BPF_MEM		0x60
#define		BPF_LEN		0x80
#define		BPF_MSH		0xa0

/* alu/jmp fields */
#define BPF_OP(code)	((code) & 0xf0)
#define		BPF_ADD		0x00
#define		BPF_SUB		0x10
#define		BPF_MUL		0x20
#define		BPF_DIV		0x30
#define		BPF_OR		0x40
#define		BPF_AND		0x50
#define		BPF_LSH		0x60
#define		BPF_RSH		0x70
#define		BPF_NEG		0x80
#define		BPF_MOD		0x90
#define		BPF_XOR		0xa0

#define		BPF_JA		0x00
#define		BPF_JEQ		0x10
#define		BPF_JGT		0x20
#define		BPF_JGE		0x30
#define		BPF_JSET	0x40
#define BPF_SRC(code)	((code) & 0x08)
#define		BPF_K		0x00
#define		BPF_X		0x08

/* ret - BPF_K and BPF_X also apply */
#define BPF_RVAL(code)	((code) & 0x18)
#define		BPF_A		0x10

/* misc */
#define BPF_MISCOP(code) ((code) & 0xf8)
#define		BPF_TAX		0x00
#define		BPF_TXA		0x80

/*
 * The instruction data structure.
 */
struct bpf_insn {
	unsigned short code; /* u_short   */
	unsigned char  jt;   /* u_char    */
	unsigned char  jf;   /* u_char    */
	unsigned int   k;    /* u_int32_t */
};

/*
 * Macros for insn array initializers.
 */
#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }

/*
 * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST).
 */
#define BPF_MEMWORDS 16

unsigned int bpf_filter(const struct bpf_insn *pc, char *p,
                        unsigned int wirelen, unsigned int buflen);

int bpf_validate(const struct bpf_insn *f, int len);

int bpf_append_insn(struct bpf_program *p, unsigned short code,
                unsigned char jt, unsigned char jf, unsigned int k);

int bpf_get_len(struct bpf_program *p);

struct bpf_insn *bpf_get_insn(struct bpf_program *p, int i);


================================================
FILE: filter/bpf_filter_test.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package filter_test

import "log"
import "testing"

import "github.com/ghedo/go.pkt/filter"
import "github.com/ghedo/go.pkt/packet"

var test_eth_arp = []byte{
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,
    0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x4c, 0x72,
    0xb9, 0x54, 0xe5, 0x3d, 0xc0, 0xa8, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0xc1, 0x1b, 0xd0, 0x25,
}

var test_eth_vlan_arp = []byte{
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,
    0x81, 0x00, 0x00, 0x87, 0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04,
    0x00, 0x01, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d, 0xc0, 0xa8, 0x01, 0x87,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x1b, 0xd0, 0x25,
}

var test_eth_ipv4_udp = []byte{
    0x00, 0x21, 0x96, 0x6e, 0xf0, 0x70, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,
    0x08, 0x00, 0x45, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
    0x27, 0x60, 0xc0, 0xa8, 0x01, 0x87, 0xc1, 0x1b, 0xd0, 0x25, 0xa2, 0x5a,
    0x20, 0x92, 0x00, 0x08, 0xe9, 0x80,
}

var test_eth_ipv4_tcp = []byte{
    0x00, 0x21, 0x96, 0x6e, 0xf0, 0x70, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,
    0x08, 0x00, 0x45, 0x00, 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06,
    0x27, 0x5f, 0xc0, 0xa8, 0x01, 0x87, 0xc1, 0x1b, 0xd0, 0x25, 0xa2, 0x5a,
    0x20, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02,
    0x20, 0x00, 0x79, 0x85, 0x00, 0x00,
}

var test_ipv4_tcp_single_byte = []byte{
    0x45, 0x00, 0x00, 0x3c, 0xf4, 0x65, 0x40, 0x00, 0x36, 0x06, 0x07, 0xec,
    0x6e, 0x34, 0x6d, 0x8c, 0x3d, 0x36, 0x2f, 0x74, 0x98, 0x64, 0x00, 0x50,
    0xa4, 0x30, 0x06, 0xd1, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x39, 0x08,
    0x90, 0x33, 0x00, 0x00, 0x02, 0x04, 0x05, 0xa0, 0x04, 0x02, 0x08, 0x0a,
    0x00, 0x04, 0xf2, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x06,
}

func TestMatch(t *testing.T) {
    arp, err := filter.Compile("arp", packet.Eth, false)
    if err != nil {
        t.Fatalf("Error compiling arp")
    }

    if !arp.Validate() {
        t.Fatalf("Invalid filter ARP\n%s", arp)
    }

    udp, err := filter.Compile("udp", packet.Eth, false)
    if err != nil {
        t.Fatalf("Error compiling udp")
    }

    port, err := filter.Compile("port 8338", packet.Eth, false)
    if err != nil {
        t.Fatalf("Error compiling port")
    }

    single, err := filter.Compile("tcp[12] != 0xa0", packet.IPv4, false)
    if err != nil {
        t.Fatalf("Error compiling single")
    }

    if !arp.Match(test_eth_arp) {
        t.Fatalf("ARP mismatch")
    }

    if arp.Match(test_eth_ipv4_udp) {
        t.Fatalf("ARP matched (but it shouldn't have)")
    }

    if !udp.Match(test_eth_ipv4_udp) {
        t.Fatalf("ARP mismatch")
    }

    if udp.Match(test_eth_ipv4_tcp) {
        t.Fatalf("UDP matched (but it shouldn't have)")
    }

    if !port.Match(test_eth_ipv4_udp) {
        t.Fatalf("UDP port mismatch")
    }

    if !port.Match(test_eth_ipv4_tcp) {
        t.Fatalf("TCP port mismatch")
    }

    if port.Match(test_eth_vlan_arp) {
        t.Fatalf("Port matched (but it shouldn't have)")
    }

    if single.Match(test_ipv4_tcp_single_byte) {
        t.Fatalf("Byte matched (but it shouldn't have)")
    }
}

func BenchmarkMatch(b *testing.B) {
    test_filter, _ := filter.Compile("port 8338", packet.Eth, false)

    for n := 0; n < b.N; n++ {
        test_filter.Match(test_eth_ipv4_tcp)
    }
}

func ExampleFilter() {
    // Match UDP or TCP packets on top of Ethernet
    flt, err := filter.Compile("udp or tcp", packet.Eth, false)
    if err != nil {
        log.Fatal(err)
    }

    if flt.Match([]byte("random data")) {
        log.Println("MATCH!!!")
    }
}


================================================
FILE: filter/pcap.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package filter

// #cgo LDFLAGS: -lpcap
// #include <stdlib.h>
// #include <pcap.h>
import "C"

import "fmt"
import "unsafe"

import "github.com/ghedo/go.pkt/packet"

// Compile the given tcpdump-like expression to a BPF filter.
func Compile(filter string, link_type packet.Type, optimize bool) (*Filter, error) {
    var do_optimize int

    if optimize {
        do_optimize = 1
    } else {
        do_optimize = 0
    }

    f := &Filter{}

    filter_str := C.CString(filter)
    defer C.free(unsafe.Pointer(filter_str))

    pcap_type := link_type.ToLinkType()

    err := C.pcap_compile_nopcap(
        C.int(0x7fff), C.int(pcap_type),
        (*C.struct_bpf_program)(f.Program()),
        filter_str, C.int(do_optimize), 0xffffffff,
    )
    if err < 0 {
        return nil, fmt.Errorf("Could not compile filter")
    }

    return f, nil
}


================================================
FILE: go.mod
================================================
module github.com/ghedo/go.pkt

require (
	github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
	github.com/songgao/water v0.0.0-20180420064739-bf1a5d02778f
)


================================================
FILE: go.sum
================================================
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/songgao/water v0.0.0-20180420064739-bf1a5d02778f h1:UExbpoG328zaxx4MhWPRZZpc527IdNUfQ1Z0uejVddc=
github.com/songgao/water v0.0.0-20180420064739-bf1a5d02778f/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=


================================================
FILE: layers/layers.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Provides utility functions for encoding and decoding packets to/from binary
// data. Differently from the basic "packet" interface, this can encode and
// decode complete "stacks" of packets, instead of manipulating single ones.
package layers

import "github.com/ghedo/go.pkt/packet"

import "github.com/ghedo/go.pkt/packet/arp"
import "github.com/ghedo/go.pkt/packet/eth"
import "github.com/ghedo/go.pkt/packet/icmpv4"
import "github.com/ghedo/go.pkt/packet/icmpv6"
import "github.com/ghedo/go.pkt/packet/ipv4"
import "github.com/ghedo/go.pkt/packet/ipv6"
import "github.com/ghedo/go.pkt/packet/llc"
import "github.com/ghedo/go.pkt/packet/radiotap"
import "github.com/ghedo/go.pkt/packet/raw"
import "github.com/ghedo/go.pkt/packet/sll"
import "github.com/ghedo/go.pkt/packet/snap"
import "github.com/ghedo/go.pkt/packet/tcp"
import "github.com/ghedo/go.pkt/packet/udp"
import "github.com/ghedo/go.pkt/packet/vlan"

// Compose packets into a chain and update their values (e.g. length, payload
// protocol) accordingly.
func Compose(pkts ...packet.Packet) (packet.Packet, error) {
    next_pkt := packet.Packet(nil)

    for i := len(pkts) - 1; i >= 0; i-- {
        if next_pkt != nil {
            err := pkts[i].SetPayload(next_pkt)
            if err != nil {
                return nil, err
            }
        }

        next_pkt = pkts[i]
    }

    return pkts[0], nil
}

// Pack packets into their binary form. This will stack the packets before
// encoding them (see the Compose() method) and also calculate the checksums.
func Pack(pkts ...packet.Packet) ([]byte, error) {
    var buf packet.Buffer

    base_pkt, err := Compose(pkts...)
    if err != nil {
        return nil, err
    }

    tot_len := int(base_pkt.GetLength())

    buf.Init(make([]byte, tot_len))

    for i := len(pkts) - 1; i >= 0; i-- {
        cur_pkt := pkts[i]
        cur_len := int(cur_pkt.GetLength())

        buf.SetOffset(tot_len - cur_len)
        buf.NewLayer()

        err := cur_pkt.Pack(&buf)
        if err != nil {
            return nil, err
        }
    }

    buf.SetOffset(0)

    return buf.Bytes(), nil
}

// Unpack the given byte slice into the packet list supplied. Note that this
// will not check whether the packet types provided match the raw data. If the
// packet types to be decoded are unknown, UnpackAll() should be used instead.
//
// Note that unpacking is done without copying the input slice, which means that
// if the slice is modifed, it may affect the packets that where unpacked from
// it. If you can't guarantee that the data slice won't change, you'll need to
// copy it and pass the copy to Unpack().
func Unpack(buf []byte, pkts ...packet.Packet) (packet.Packet, error) {
    var b packet.Buffer
    b.Init(buf)

    prev_pkt := packet.Packet(nil)

    for _, p := range pkts {
        if b.Len() <= 0 {
            break
        }

        b.NewLayer()

        err := p.Unpack(&b)
        if err != nil {
            return nil, err
        }

        if prev_pkt != nil {
            prev_pkt.SetPayload(p)
        }

        if p.GuessPayloadType() == packet.None {
            break
        }

        prev_pkt = p
    }

    return pkts[0], nil
}


// Recursively unpack the given byte slice into a packet. The link_type argument
// must specify the type of the first layer in the input data, successive layers
// will be detected automatically.
//
// Note that unpacking is done without copying the input slice, which means that
// if the slice is modifed, it may affect the packets that where unpacked from
// it. If you can't guarantee that the data slice won't change, you'll need to
// copy it and pass the copy to UnpackAll().
func UnpackAll(buf []byte, link_type packet.Type) (packet.Packet, error) {
    var b packet.Buffer
    b.Init(buf)

    first_pkt := packet.Packet(nil)
    prev_pkt  := packet.Packet(nil)

    for link_type != packet.None {
        var p packet.Packet

        if b.Len() <= 0 {
            break
        }

        switch link_type {
        case packet.ARP:      p = &arp.Packet{}
        case packet.Eth:      p = &eth.Packet{}
        case packet.ICMPv4:   p = &icmpv4.Packet{}
        case packet.ICMPv6:   p = &icmpv6.Packet{}
        case packet.IPv4:     p = &ipv4.Packet{}
        case packet.IPv6:     p = &ipv6.Packet{}
        case packet.LLC:      p = &llc.Packet{}
        case packet.RadioTap: p = &radiotap.Packet{}
        case packet.SLL:      p = &sll.Packet{}
        case packet.SNAP:     p = &snap.Packet{}
        case packet.TCP:      p = &tcp.Packet{}
        case packet.UDP:      p = &udp.Packet{}
        case packet.VLAN:     p = &vlan.Packet{}
        default:              p = &raw.Packet{}
        }

        if p == nil {
            break
        }

        b.NewLayer()

        err := p.Unpack(&b)
        if err != nil {
            return nil, err
        }

        if prev_pkt != nil {
            prev_pkt.SetPayload(p)
        } else {
            first_pkt = p
        }

        prev_pkt  = p
        link_type = p.GuessPayloadType()
    }

    return first_pkt, nil
}

// Return the first layer of the given type in the packet. If no suitable layer
// is found, return nil.
func FindLayer(p packet.Packet, layer packet.Type) packet.Packet {
    switch {
    case p == nil:
        return nil

    case p.GetType() == layer:
        return p

    default:
        return FindLayer(p.Payload(), layer)
    }
}


================================================
FILE: layers/layers_test.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package layers_test

import "bytes"
import "log"
import "net"
import "testing"

import "github.com/ghedo/go.pkt/layers"
import "github.com/ghedo/go.pkt/packet"
import "github.com/ghedo/go.pkt/packet/arp"
import "github.com/ghedo/go.pkt/packet/eth"
import "github.com/ghedo/go.pkt/packet/ipv4"
import "github.com/ghedo/go.pkt/packet/raw"
import "github.com/ghedo/go.pkt/packet/udp"
import "github.com/ghedo/go.pkt/packet/tcp"
import "github.com/ghedo/go.pkt/packet/vlan"

var hwsrc_str = "4c:72:b9:54:e5:3d"
var hwdst_str = "00:21:96:6e:f0:70"

var ipsrc_str = "192.168.1.135"
var ipdst_str = "193.27.208.37"

var test_eth_arp = []byte{
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,
    0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x4c, 0x72,
    0xb9, 0x54, 0xe5, 0x3d, 0xc0, 0xa8, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0xc1, 0x1b, 0xd0, 0x25,
}

func TestPackEthArp(t *testing.T) {
    eth_pkt := eth.Make()
    eth_pkt.SrcAddr, _ = net.ParseMAC(hwsrc_str)
    eth_pkt.DstAddr, _ = net.ParseMAC("ff:ff:ff:ff:ff:ff")

    arp_pkt := arp.Make()
    arp_pkt.HWSrcAddr, _ = net.ParseMAC(hwsrc_str)
    arp_pkt.HWDstAddr, _ = net.ParseMAC("00:00:00:00:00:00")
    arp_pkt.ProtoSrcAddr = net.ParseIP(ipsrc_str)
    arp_pkt.ProtoDstAddr = net.ParseIP(ipdst_str)

    buf, err := layers.Pack(eth_pkt, arp_pkt)
    if err != nil {
        t.Fatalf("Error packing: %s", err)
    }

    if !bytes.Equal(test_eth_arp, buf) {
        t.Fatalf("Raw packet mismatch: %x", buf)
    }
}

func TestUnpackEthArp(t *testing.T) {
    _, err := layers.Unpack(test_eth_arp, &eth.Packet{}, &arp.Packet{})
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }
}

func BenchmarkUnpackEthArp(bn *testing.B) {
    var eth_pkt eth.Packet
    var arp_pkt arp.Packet

    for n := 0; n < bn.N; n++ {
        layers.Unpack(test_eth_arp, &eth_pkt, &arp_pkt)
    }
}

func TestUnpackAllEthArp(t *testing.T) {
    pkt, err := layers.UnpackAll(test_eth_arp, packet.Eth)
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }

    if pkt.GetType() != packet.Eth {
        t.Fatalf("Packet type mismatch, %s", pkt.GetType())
    }

    if pkt.Payload().GetType() != packet.ARP {
        t.Fatalf("Packet type mismatch, %s", pkt.Payload().GetType())
    }
}

func BenchmarkUnpackAllEthArp(bn *testing.B) {
    for n := 0; n < bn.N; n++ {
        layers.UnpackAll(test_eth_arp, packet.Eth)
    }
}

var test_eth_vlan_arp = []byte{
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,
    0x81, 0x00, 0x00, 0x87, 0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04,
    0x00, 0x01, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d, 0xc0, 0xa8, 0x01, 0x87,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x1b, 0xd0, 0x25,
}

func TestPackEthVLANArp(t *testing.T) {
    eth_pkt := eth.Make()
    eth_pkt.SrcAddr, _ = net.ParseMAC(hwsrc_str)
    eth_pkt.DstAddr, _ = net.ParseMAC("ff:ff:ff:ff:ff:ff")

    vlan_pkt := vlan.Make()
    vlan_pkt.VLAN = 135

    arp_pkt := arp.Make()
    arp_pkt.HWSrcAddr, _ = net.ParseMAC(hwsrc_str)
    arp_pkt.HWDstAddr, _ = net.ParseMAC("00:00:00:00:00:00")
    arp_pkt.ProtoSrcAddr = net.ParseIP(ipsrc_str)
    arp_pkt.ProtoDstAddr = net.ParseIP(ipdst_str)

    buf, err := layers.Pack(eth_pkt, vlan_pkt, arp_pkt)
    if err != nil {
        t.Fatalf("Error packing: %s", err)
    }

    if !bytes.Equal(test_eth_vlan_arp, buf) {
        t.Fatalf("Raw packet mismatch: %x", buf)
    }
}

func TestUnpackEthVLANArp(t *testing.T) {
    _, err := layers.Unpack(test_eth_arp, &eth.Packet{}, &vlan.Packet{}, &arp.Packet{})
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }
}

func BenchmarkUnpackEthVLANArp(bn *testing.B) {
    var eth_pkt eth.Packet
    var vlan_pkt vlan.Packet
    var arp_pkt arp.Packet

    for n := 0; n < bn.N; n++ {
        layers.Unpack(test_eth_vlan_arp, &eth_pkt, &vlan_pkt, &arp_pkt)
    }
}

func TestUnpackAllEthVLANArp(t *testing.T) {
    pkt, err := layers.UnpackAll(test_eth_vlan_arp, packet.Eth)
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }

    if pkt.GetType() != packet.Eth {
        t.Fatalf("Packet type mismatch, %s", pkt.GetType())
    }

    pkt = pkt.Payload()
    if pkt.GetType() != packet.VLAN {
        t.Fatalf("Packet type mismatch, %s", pkt.GetType())
    }

    pkt = pkt.Payload()
    if pkt.GetType() != packet.ARP {
        t.Fatalf("Packet type mismatch, %s", pkt.GetType())
    }
}

func BenchmarkUnpackAllEthVLANArp(bn *testing.B) {
    for n := 0; n < bn.N; n++ {
        layers.UnpackAll(test_eth_vlan_arp, packet.Eth)
    }
}

var test_eth_ipv4_udp = []byte{
    0x00, 0x21, 0x96, 0x6e, 0xf0, 0x70, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,
    0x08, 0x00, 0x45, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
    0x27, 0x60, 0xc0, 0xa8, 0x01, 0x87, 0xc1, 0x1b, 0xd0, 0x25, 0xa2, 0x5a,
    0x20, 0x92, 0x00, 0x08, 0xe9, 0x80,
}

func TestPackEthIPv4UDP(t *testing.T) {
    eth_pkt := eth.Make()
    eth_pkt.SrcAddr, _ = net.ParseMAC(hwsrc_str)
    eth_pkt.DstAddr, _ = net.ParseMAC(hwdst_str)

    ip4_pkt := ipv4.Make()
    ip4_pkt.SrcAddr = net.ParseIP(ipsrc_str)
    ip4_pkt.DstAddr = net.ParseIP(ipdst_str)

    udp_pkt := udp.Make()
    udp_pkt.SrcPort = 41562
    udp_pkt.DstPort = 8338

    buf, err := layers.Pack(eth_pkt, ip4_pkt, udp_pkt)
    if err != nil {
        t.Fatalf("Error packing: %s", err)
    }

    if !bytes.Equal(test_eth_ipv4_udp, buf) {
        t.Fatalf("Raw packet mismatch: %x", buf)
    }
}

func TestUnpackEthUPv4UDP(t *testing.T) {
    var eth_pkt eth.Packet
    var ip4_pkt ipv4.Packet
    var udp_pkt udp.Packet

    _, err := layers.Unpack(test_eth_ipv4_udp, &eth_pkt, &ip4_pkt, &udp_pkt)
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }
}

func BenchmarkUnpackEthUPv4UDP(bn *testing.B) {
    var eth_pkt eth.Packet
    var ip4_pkt ipv4.Packet
    var udp_pkt udp.Packet

    for n := 0; n < bn.N; n++ {
        layers.Unpack(test_eth_ipv4_udp, &eth_pkt, &ip4_pkt, &udp_pkt)
    }
}

func TestUnpackAllEthIPv4UDP(t *testing.T) {
    pkt, err := layers.UnpackAll(test_eth_ipv4_udp, packet.Eth)
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }

    if pkt.GetType() != packet.Eth {
        t.Fatalf("Packet type mismatch, %s", pkt.GetType())
    }

    pkt = pkt.Payload()
    if pkt.GetType() != packet.IPv4 {
        t.Fatalf("Packet type mismatch, %s", pkt.GetType())
    }

    pkt = pkt.Payload()
    if pkt.GetType() != packet.UDP {
        t.Fatalf("Packet type mismatch, %s", pkt.GetType())
    }
}

func BenchmarkUnpackAllEthIPv4UDP(bn *testing.B) {
    for n := 0; n < bn.N; n++ {
        layers.UnpackAll(test_eth_ipv4_udp, packet.Eth)
    }
}

var test_eth_ipv4_udp_raw = []byte{
    0x00, 0x21, 0x96, 0x6e, 0xf0, 0x70, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,
    0x08, 0x00, 0x45, 0x00, 0x00, 0x42, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
    0x27, 0x3a, 0xc0, 0xa8, 0x01, 0x87, 0xc1, 0x1b, 0xd0, 0x25, 0xa2, 0x5a,
    0x20, 0x92, 0x00, 0x2e, 0x07, 0x03, 0x66, 0x64, 0x67, 0x20, 0x61, 0x67,
    0x66, 0x68, 0x20, 0x6c, 0x64, 0x66, 0x68, 0x67, 0x6b, 0x20, 0x68, 0x66,
    0x64, 0x6b, 0x67, 0x68, 0x20, 0x6b, 0x66, 0x6a, 0x64, 0x68, 0x73, 0x67,
    0x20, 0x6b, 0x73, 0x68, 0x66, 0x64, 0x67, 0x6b,
}

func TestPackEthIPv4UDPRaw(t *testing.T) {
    eth_pkt := eth.Make()
    eth_pkt.SrcAddr, _ = net.ParseMAC(hwsrc_str)
    eth_pkt.DstAddr, _ = net.ParseMAC(hwdst_str)

    ip4_pkt := ipv4.Make()
    ip4_pkt.SrcAddr = net.ParseIP(ipsrc_str)
    ip4_pkt.DstAddr = net.ParseIP(ipdst_str)

    udp_pkt := udp.Make()
    udp_pkt.SrcPort = 41562
    udp_pkt.DstPort = 8338

    raw_pkt := raw.Make()
    raw_pkt.Data = []byte("fdg agfh ldfhgk hfdkgh kfjdhsg kshfdgk")

    data, err := layers.Pack(eth_pkt, ip4_pkt, udp_pkt, raw_pkt)
    if err != nil {
        t.Fatalf("Error packing: %s", err)
    }

    if ip4_pkt.GetLength() != 66 {
        t.Fatalf("IPv4 length mismatch: %d", ip4_pkt.GetLength())
    }

    if udp_pkt.GetLength() != 46 {
        t.Fatalf("UDP length mismatch: %d", udp_pkt.GetLength())
    }

    if !bytes.Equal(test_eth_ipv4_udp_raw, data) {
        t.Fatalf("Raw packet mismatch: %x", data)
    }
}

func TestUnpackEthUPv4UDPRaw(t *testing.T) {
    var eth_pkt eth.Packet
    var ip4_pkt ipv4.Packet
    var udp_pkt udp.Packet
    var raw_pkt raw.Packet

    _, err := layers.Unpack(test_eth_ipv4_udp_raw,
                            &eth_pkt, &ip4_pkt, &udp_pkt, &raw_pkt)
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }
}

func BenchmarkUnpackEthUPv4UDPRaw(bn *testing.B) {
    var eth_pkt eth.Packet
    var ip4_pkt ipv4.Packet
    var udp_pkt udp.Packet
    var raw_pkt raw.Packet

    for n := 0; n < bn.N; n++ {
        layers.Unpack(test_eth_ipv4_udp_raw,
                      &eth_pkt, &ip4_pkt, &udp_pkt, &raw_pkt)
    }
}

func TestUnpackAllEthIPv4UDPRaw(t *testing.T) {
    pkt, err := layers.UnpackAll(test_eth_ipv4_udp_raw, packet.Eth)
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }

    if pkt.GetType() != packet.Eth {
        t.Fatalf("Packet type mismatch, %s", pkt.GetType())
    }

    pkt = pkt.Payload()
    if pkt.GetType() != packet.IPv4 {
        t.Fatalf("Packet type mismatch, %s", pkt.GetType())
    }

    pkt = pkt.Payload()
    if pkt.GetType() != packet.UDP {
        t.Fatalf("Packet type mismatch, %s", pkt.GetType())
    }

    pkt = pkt.Payload()
    if pkt.GetType() != packet.Raw {
        t.Fatalf("Packet type mismatch, %s", pkt.GetType())
    }
}

func BenchmarkUnpackAllEthIPv4UDPRaw(bn *testing.B) {
    for n := 0; n < bn.N; n++ {
        layers.UnpackAll(test_eth_ipv4_udp_raw, packet.Eth)
    }
}

var test_eth_ipv4_tcp = []byte{
    0x00, 0x21, 0x96, 0x6e, 0xf0, 0x70, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,
    0x08, 0x00, 0x45, 0x00, 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06,
    0x27, 0x5f, 0xc0, 0xa8, 0x01, 0x87, 0xc1, 0x1b, 0xd0, 0x25, 0xa2, 0x5a,
    0x20, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02,
    0x20, 0x00, 0x79, 0x85, 0x00, 0x00,
}

func TestPackEthIPv4TCP(t *testing.T) {
    eth_pkt := eth.Make()
    eth_pkt.SrcAddr, _ = net.ParseMAC(hwsrc_str)
    eth_pkt.DstAddr, _ = net.ParseMAC(hwdst_str)

    ip4_pkt := ipv4.Make()
    ip4_pkt.SrcAddr = net.ParseIP(ipsrc_str)
    ip4_pkt.DstAddr = net.ParseIP(ipdst_str)

    tcp_pkt := tcp.Make()
    tcp_pkt.SrcPort = 41562
    tcp_pkt.DstPort = 8338
    tcp_pkt.Flags   = tcp.Syn
    tcp_pkt.WindowSize = 8192

    buf, err := layers.Pack(eth_pkt, ip4_pkt, tcp_pkt)
    if err != nil {
        t.Fatalf("Error packing: %s", err)
    }

    if !bytes.Equal(test_eth_ipv4_tcp, buf) {
        t.Fatalf("Raw packet mismatch: %x", buf)
    }
}

func TestUnpackEthUPv4TCP(t *testing.T) {
    var eth_pkt eth.Packet
    var ip4_pkt ipv4.Packet
    var tcp_pkt tcp.Packet

    _, err := layers.Unpack(test_eth_ipv4_tcp, &eth_pkt, &ip4_pkt, &tcp_pkt)
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }
}

func BenchmarkUnpackEthUPv4TCP(bn *testing.B) {
    var eth_pkt eth.Packet
    var ip4_pkt ipv4.Packet
    var tcp_pkt tcp.Packet

    for n := 0; n < bn.N; n++ {
        layers.Unpack(test_eth_ipv4_tcp, &eth_pkt, &ip4_pkt, &tcp_pkt)
    }
}

func TestUnpackAllEthIPv4TCP(t *testing.T) {
    pkt, err := layers.UnpackAll(test_eth_ipv4_tcp, packet.Eth)
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }

    if pkt.GetType() != packet.Eth {
        t.Fatalf("Packet type mismatch, %s", pkt.GetType())
    }

    pkt = pkt.Payload()
    if pkt.GetType() != packet.IPv4 {
        t.Fatalf("Packet type mismatch, %s", pkt.GetType())
    }

    pkt = pkt.Payload()
    if pkt.GetType() != packet.TCP {
        t.Fatalf("Packet type mismatch, %s", pkt.GetType())
    }
}

func BenchmarkUnpackAllEthIPv4TCP(bn *testing.B) {
    for n := 0; n < bn.N; n++ {
        layers.UnpackAll(test_eth_ipv4_tcp, packet.Eth)
    }
}

var test_eth_ipv4_tcp_raw = []byte{
    0x00, 0x21, 0x96, 0x6e, 0xf0, 0x70, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,
    0x08, 0x00, 0x45, 0x00, 0x00, 0x4e, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06,
    0x27, 0x39, 0xc0, 0xa8, 0x01, 0x87, 0xc1, 0x1b, 0xd0, 0x25, 0xa2, 0x5a,
    0x20, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02,
    0x20, 0x00, 0x97, 0x2d, 0x00, 0x00, 0x66, 0x64, 0x67, 0x20, 0x61, 0x67,
    0x66, 0x68, 0x20, 0x6c, 0x64, 0x66, 0x68, 0x67, 0x6b, 0x20, 0x68, 0x66,
    0x64, 0x6b, 0x67, 0x68, 0x20, 0x6b, 0x66, 0x6a, 0x64, 0x68, 0x73, 0x67,
    0x20, 0x6b, 0x73, 0x68, 0x66, 0x64, 0x67, 0x6b,
}

func TestPackEthIPv4TCPRaw(t *testing.T) {
    eth_pkt := eth.Make()
    eth_pkt.SrcAddr, _ = net.ParseMAC(hwsrc_str)
    eth_pkt.DstAddr, _ = net.ParseMAC(hwdst_str)

    ip4_pkt := ipv4.Make()
    ip4_pkt.SrcAddr = net.ParseIP(ipsrc_str)
    ip4_pkt.DstAddr = net.ParseIP(ipdst_str)

    tcp_pkt := tcp.Make()
    tcp_pkt.SrcPort = 41562
    tcp_pkt.DstPort = 8338
    tcp_pkt.Flags   = tcp.Syn
    tcp_pkt.WindowSize = 8192

    raw_pkt := raw.Make()
    raw_pkt.Data = []byte("fdg agfh ldfhgk hfdkgh kfjdhsg kshfdgk")

    data, err := layers.Pack(eth_pkt, ip4_pkt, tcp_pkt, raw_pkt)
    if err != nil {
        t.Fatalf("Error packing: %s", err)
    }

    if ip4_pkt.GetLength() != 78 {
        t.Fatalf("IPv4 length mismatch: %d", ip4_pkt.GetLength())
    }

    if tcp_pkt.GetLength() != 58 {
        t.Fatalf("TCP length mismatch: %d", tcp_pkt.GetLength())
    }

    if !bytes.Equal(test_eth_ipv4_tcp_raw, data) {
        t.Fatalf("Raw packet mismatch: %x", data)
    }
}

func TestUnpackEthUPv4TCPRaw(t *testing.T) {
    var eth_pkt eth.Packet
    var ip4_pkt ipv4.Packet
    var tcp_pkt tcp.Packet
    var raw_pkt raw.Packet

    _, err := layers.Unpack(test_eth_ipv4_tcp_raw,
                            &eth_pkt, &ip4_pkt, &tcp_pkt, &raw_pkt)
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }
}

func BenchmarkUnpackEthUPv4TCPRaw(bn *testing.B) {
    var eth_pkt eth.Packet
    var ip4_pkt ipv4.Packet
    var tcp_pkt tcp.Packet
    var raw_pkt raw.Packet

    for n := 0; n < bn.N; n++ {
        layers.Unpack(test_eth_ipv4_tcp_raw,
                      &eth_pkt, &ip4_pkt, &tcp_pkt, &raw_pkt)
    }
}

func TestUnpackAllEthIPv4TCPRaw(t *testing.T) {
    pkt, err := layers.UnpackAll(test_eth_ipv4_tcp_raw, packet.Eth)
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }

    if pkt.GetType() != packet.Eth {
        t.Fatalf("Packet type mismatch, %s", pkt.GetType())
    }

    pkt = pkt.Payload()
    if pkt.GetType() != packet.IPv4 {
        t.Fatalf("Packet type mismatch, %s", pkt.GetType())
    }

    pkt = pkt.Payload()
    if pkt.GetType() != packet.TCP {
        t.Fatalf("Packet type mismatch, %s", pkt.GetType())
    }

    pkt = pkt.Payload()
    if pkt.GetType() != packet.Raw {
        t.Fatalf("Packet type mismatch, %s", pkt.GetType())
    }
}

func BenchmarkUnpackAllEthIPv4TCPRaw(bn *testing.B) {
    for n := 0; n < bn.N; n++ {
        layers.UnpackAll(test_eth_ipv4_tcp_raw, packet.Eth)
    }
}

func TestFindLayer(t *testing.T) {
    pkt, err := layers.UnpackAll(test_eth_ipv4_tcp, packet.Eth)
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }

    ipv4_pkt := layers.FindLayer(pkt, packet.IPv4)
    if ipv4_pkt == nil || ipv4_pkt.GetType() != packet.IPv4 {
        t.Fatalf("Not IPv4: %s", ipv4_pkt)
    }

    tcp_pkt := layers.FindLayer(pkt, packet.TCP)
    if tcp_pkt == nil || tcp_pkt.GetType() != packet.TCP {
        t.Fatalf("Not TCP: %s", tcp_pkt)
    }

    udp_pkt := layers.FindLayer(pkt, packet.UDP)
    if udp_pkt != nil {
        t.Fatalf("Not nil: %s", udp_pkt)
    }
}

func ExamplePack() {
    // Create an Ethernet packet
    eth_pkt := eth.Make()
    eth_pkt.SrcAddr, _ = net.ParseMAC("4c:72:b9:54:e5:3d")
    eth_pkt.DstAddr, _ = net.ParseMAC("ff:ff:ff:ff:ff:ff")

    // Create an ARP packet
    arp_pkt := arp.Make()
    arp_pkt.HWSrcAddr, _ = net.ParseMAC("4c:72:b9:54:e5:3d")
    arp_pkt.HWDstAddr, _ = net.ParseMAC("00:00:00:00:00:00")
    arp_pkt.ProtoSrcAddr = net.ParseIP("192.168.1.135")
    arp_pkt.ProtoDstAddr = net.ParseIP("192.168.1.254")

    buf, err := layers.Pack(eth_pkt, arp_pkt)
    if err != nil {
        log.Fatal(err)
    }

    // do something with the packet
    log.Println(buf)
}

func ExampleUnpack() {
    // Create the buf data
    buf := []byte("random data")

    // Assume Ethernet as datalink layer
    pkt, err := layers.UnpackAll(buf, packet.Eth)
    if err != nil {
        log.Fatal(err)
    }

    log.Println(pkt)
}


================================================
FILE: network/network.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Provides utility functions for sending and receiving packets over the
// network. Basically, it hides some of the complexity of using the capture and
// layers packages together.
package network

import "fmt"
import "net"
import "time"

import "github.com/ghedo/go.pkt/capture"
import "github.com/ghedo/go.pkt/packet"
import "github.com/ghedo/go.pkt/packet/arp"
import "github.com/ghedo/go.pkt/packet/eth"
import "github.com/ghedo/go.pkt/layers"
import "github.com/ghedo/go.pkt/routing"

// Pack packets into their binary form and inject them in the given capture
// handle.. This will stack the packets before encoding them and also calculate
// the checksums.
func Send(c capture.Handle, pkts ...packet.Packet) error {
    if pkts[0].GetType() != c.LinkType() {
        return fmt.Errorf("Expected packet type %s, got %s",
                          pkts[0].GetType(), c.LinkType())
    }

    buf, err := layers.Pack(pkts...)
    if err != nil {
        return fmt.Errorf("Could not pack: %s", err)
    }

    err = c.Inject(buf)
    if err != nil {
        return fmt.Errorf("Could not inject: %s", err)
    }

    return nil
}

// Capture a single packet from the given capture handle, unpack it and return
// it. This will block until a packet is received.
func Recv(c capture.Handle) (packet.Packet, error) {
    buf, err := c.Capture()
    if err != nil {
        return nil, fmt.Errorf("Could not capture: %s", err)
    }

    pkt, err := layers.UnpackAll(buf, c.LinkType())
    if err != nil {
        return nil, fmt.Errorf("Could not unpack: %s", err)
    }

    return pkt, nil
}

// Like Send() and Recv() combined. This only returns a suitable answer for the
// sent packets. If t is not zero, this will return if not answer is received
// before t expires.
func SendRecv(c capture.Handle, t time.Duration, pkts ...packet.Packet) (packet.Packet, error) {
    err := Send(c, pkts...)
    if err != nil {
        return nil, err
    }

    now := time.Now()

    for {
        pkt, err := Recv(c)
        if err != nil {
            return nil, err
        }

        if pkt == nil {
            return nil, nil
        }

        if pkt.Answers(pkts[0]) {
            return pkt, nil
        }

        if int64(t) > 0 &&
           int64(time.Since(now)) > int64(t.Nanoseconds()) {
            return nil, fmt.Errorf("Timeout")
        }
    }

    return nil, fmt.Errorf("WTF")
}

// Determine the next hop's MAX address to reach the given IP address and route
// by doing an ARP resolution.
func NextHopMAC(c capture.Handle, t time.Duration, r *routing.Route, addr net.IP) (net.HardwareAddr, error) {
    eth_pkt := eth.Make()
    eth_pkt.SrcAddr = r.Iface.HardwareAddr
    eth_pkt.DstAddr, _ = net.ParseMAC("ff:ff:ff:ff:ff:ff")

    arp_pkt := arp.Make()
    arp_pkt.HWSrcAddr = r.Iface.HardwareAddr
    arp_pkt.HWDstAddr, _ = net.ParseMAC("00:00:00:00:00:00")
    arp_pkt.ProtoSrcAddr, _ = r.GetIfaceIPv4Addr()

    if r.Default {
        arp_pkt.ProtoDstAddr = r.Gateway
    } else {
        arp_pkt.ProtoDstAddr = addr
    }

    pkt, err := SendRecv(c, t, eth_pkt, arp_pkt)
    if err != nil {
        return nil, err
    }

    return pkt.Payload().(*arp.Packet).HWSrcAddr, nil
}


================================================
FILE: packet/arp/pkt.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Provides encoding and decoding for ARP packets.
package arp

import "net"

import "github.com/ghedo/go.pkt/packet"
import "github.com/ghedo/go.pkt/packet/eth"

type Packet struct {
    Operation     Operation        `string:"op"`

    HWType        uint16
    HWAddrLen     uint8            `string:"hwlen"`
    HWSrcAddr     net.HardwareAddr `string:"hwsrc"`
    HWDstAddr     net.HardwareAddr `string:"hwdst"`

    ProtoType     eth.EtherType    `string:"ptype"`
    ProtoAddrLen  uint8            `string:"plen"`
    ProtoSrcAddr  net.IP           `string:"psrc"`
    ProtoDstAddr  net.IP           `string:"pdst"`
}

type Operation uint16

const (
    Request Operation = 1
    Reply             = 2
)

func Make() *Packet {
    return &Packet {
        Operation: Request,

        HWType: 1,
        HWAddrLen: 6,

        ProtoType: eth.IPv4,
        ProtoAddrLen: 4,
    }
}

func (p *Packet) GetType() packet.Type {
    return packet.ARP
}

func (p *Packet) GetLength() uint16 {
    return 8 + uint16(p.HWAddrLen) * 2 + uint16(p.ProtoAddrLen) * 2
}

func (p *Packet) Equals(other packet.Packet) bool {
    return packet.Compare(p, other)
}

func (p *Packet) Answers(other packet.Packet) bool {
    if other == nil || other.GetType() != packet.ARP {
        return false
    }

    if p.Operation == Reply && other.(*Packet).Operation == Request &&
       p.ProtoSrcAddr.Equal(other.(*Packet).ProtoDstAddr) {
        return true
    }

    return false
}

func (p *Packet) Pack(buf *packet.Buffer) error {
    buf.WriteN(p.HWType)
    buf.WriteN(p.ProtoType)

    buf.WriteN(p.HWAddrLen)
    buf.WriteN(p.ProtoAddrLen)

    buf.WriteN(p.Operation)

    buf.Write(p.HWSrcAddr[len(p.HWSrcAddr) - int(p.HWAddrLen):])
    buf.Write(p.ProtoSrcAddr[len(p.ProtoSrcAddr) - int(p.ProtoAddrLen):])

    buf.Write(p.HWDstAddr[len(p.HWDstAddr) - int(p.HWAddrLen):])
    buf.Write(p.ProtoDstAddr[len(p.ProtoDstAddr) - int(p.ProtoAddrLen):])

    return nil
}

func (p *Packet) Unpack(buf *packet.Buffer) error {
    buf.ReadN(&p.HWType)
    buf.ReadN(&p.ProtoType)

    buf.ReadN(&p.HWAddrLen)
    buf.ReadN(&p.ProtoAddrLen)

    buf.ReadN(&p.Operation)

    p.HWSrcAddr = net.HardwareAddr(buf.Next(int(p.HWAddrLen)))
    p.ProtoSrcAddr = net.IP(buf.Next(int(p.ProtoAddrLen)))

    p.HWDstAddr = net.HardwareAddr(buf.Next(int(p.HWAddrLen)))
    p.ProtoDstAddr = net.IP(buf.Next(int(p.ProtoAddrLen)))

    return nil
}

func (p *Packet) Payload() packet.Packet {
    return nil
}

func (p *Packet) GuessPayloadType() packet.Type {
    return packet.None
}

func (p *Packet) SetPayload(pl packet.Packet) error {
    return nil
}

func (p *Packet) InitChecksum(csum uint32) {
}

func (p *Packet) String() string {
    return packet.Stringify(p)
}

func (o Operation) String() string {
    switch o {
    case Request:
        return "request"

    case Reply:
        return "reply"

    default:
        return "invalid"
    }
}


================================================
FILE: packet/arp/pkt_test.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package arp_test

import "bytes"
import "net"
import "testing"

import "github.com/ghedo/go.pkt/packet"
import "github.com/ghedo/go.pkt/packet/arp"
import "github.com/ghedo/go.pkt/packet/eth"

var test_simple = []byte{
    0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x4C, 0x72, 0xB9, 0x54,
    0xE5, 0x3D, 0xC0, 0xA8, 0x01, 0x87, 0x1F, 0x92, 0x2B, 0x56, 0xED, 0x77,
    0x1C, 0x3C, 0x09, 0xBF,
}

var hwsrc_str = "4c:72:b9:54:e5:3d"
var hwdst_str = "1f:92:2b:56:ed:77"
var ipsrc_str = "192.168.1.135"
var ipdst_str = "28.60.9.191"

func MakeTestSimple() *arp.Packet {
    hwsrc, _ := net.ParseMAC(hwsrc_str)
    hwdst, _ := net.ParseMAC(hwdst_str)
    ipsrc := net.ParseIP(ipsrc_str)
    ipdst := net.ParseIP(ipdst_str)

    return &arp.Packet{
        Operation: arp.Request,

        HWType: 1,
        HWAddrLen: 6,
        HWSrcAddr: hwsrc,
        HWDstAddr: hwdst,

        ProtoType:    eth.IPv4,
        ProtoAddrLen: 4,
        ProtoSrcAddr: ipsrc,
        ProtoDstAddr: ipdst,
    }
}

func TestPack(t *testing.T) {
    var b packet.Buffer
    b.Init(make([]byte, len(test_simple)))

    p := MakeTestSimple()

    err := p.Pack(&b)
    if err != nil {
        t.Fatalf("Error packing: %s", err)
    }

    if !bytes.Equal(test_simple, b.Buffer()) {
        t.Fatalf("Raw packet mismatch: %x", b.Buffer())
    }
}

func BenchmarkPack(bn *testing.B) {
    var b packet.Buffer
    b.Init(make([]byte, len(test_simple)))

    p := MakeTestSimple()

    for n := 0; n < bn.N; n++ {
        p.Pack(&b)
    }
}

func TestUnpack(t *testing.T) {
    var p arp.Packet

    cmp := MakeTestSimple()

    var b packet.Buffer
    b.Init(test_simple)

    err := p.Unpack(&b)
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }

    if !p.Equals(cmp) {
        t.Fatalf("Packet mismatch:\n%s\n%s", &p, cmp)
    }
}

func BenchmarkUnpack(bn *testing.B) {
    var p arp.Packet
    var b packet.Buffer

    for n := 0; n < bn.N; n++ {
        b.Init(test_simple)
        p.Unpack(&b)
    }
}


================================================
FILE: packet/buffer.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package packet

import "encoding/binary"

// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
// It's based on the bytes.Buffer code provided by the standard library, but
// implements additional convenience methods.
//
// This is used internally to provide packet encoding and decoding, and should
// not be used directly.
type Buffer struct {
    buf       []byte
    off       int
    layer_off int
}

// Initialize the buffer with the given slice.
func (b *Buffer) Init(buf []byte) {
    b.buf = buf
    b.off = 0
    b.layer_off = 0
}

// Return the unread portion of the buffer as slice.
func (b *Buffer) Bytes() []byte {
    return b.buf[b.off:]
}

// Return the whole buffer as slice.
func (b *Buffer) Buffer() []byte {
    return b.buf
}

// Return the number of bytes of the unread portion of the buffer.
func (b *Buffer) Len() int {
    return len(b.buf) - b.off
}

// Manually set the buffer offset to off.
func (b *Buffer) SetOffset(off int) {
    b.off = off
}

// Point the layer starting offset to the current buffer offset.
func (b *Buffer) NewLayer() {
    b.layer_off = len(b.buf) - b.Len()
}

// Return the buffer of the current layer as slice.
func (b *Buffer) LayerBytes() []byte {
    return b.buf[b.layer_off:]
}

// Return the length of the current decoded layer.
func (b *Buffer) LayerLen() int {
    return b.off - b.layer_off
}

// Append the contents of p to the buffer.
func (b *Buffer) Write(p []byte) (n int, err error) {
    n = copy(b.buf[b.off:], p)
    b.off += n
    return
}

// Append the value of data to the buffer in network byter order.
func (b *Buffer) WriteN(data interface{}) error {
    return binary.Write(b, binary.BigEndian, data)
}

// Append the value of data to the buffer in little endian byter order.
func (b *Buffer) WriteL(data interface{}) error {
    return binary.Write(b, binary.LittleEndian, data)
}

// Write data in network byte order to the specified offset relative to the
// start of the current layer.
func (b *Buffer) PutUint16N(off int, data uint16) {
    binary.BigEndian.PutUint16(b.buf[b.layer_off + off:], data)
}

// Read the next len(p) bytes from the buffer or until the buffer is drained.
func (b *Buffer) Read(p []byte) (n int, err error) {
    n = copy(p, b.buf[b.off:])
    b.off += n
    return
}

// Read structured data from the buffer in network byte order.
func (p *Buffer) ReadN(data interface{}) error {
    return binary.Read(p, binary.BigEndian, data)
}

// Read structured data from the buffer in little endian byte order.
func (p *Buffer) ReadL(data interface{}) error {
    return binary.Read(p, binary.LittleEndian, data)
}

// Read aligned structured data from the buffer in little endian byte order.
func (p *Buffer) ReadLAligned(data interface{}, width uintptr) error {
    p.off = ((((p.off) + ((int(width)) - 1)) & (^((int(width)) - 1))) - p.off)

    return binary.Read(p, binary.LittleEndian, data)
}

// Return a slice containing the next n bytes from the buffer, advancing the
// buffer as if the bytes had been returned by Read
func (b *Buffer) Next(n int) []byte {
    m := b.Len()
    if n > m {
        n = m
    }
    data := b.buf[b.off : b.off+n]
    b.off += n
    return data
}


================================================
FILE: packet/eth/pkt.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Provides encoding and decoding for Ethernet (both EthernetII and 802.3)
// packets.
package eth

import "fmt"
import "net"

import "github.com/ghedo/go.pkt/packet"

type Packet struct {
    DstAddr     net.HardwareAddr `string:"dst"`
    SrcAddr     net.HardwareAddr `string:"src"`
    Type        EtherType
    Length      uint16           `cmp:"skip"`
    pkt_payload packet.Packet    `cmp:"skip" string:"skip"`
}

type EtherType uint16

const (
    None EtherType = 0x0000
    ARP            = 0x0806
    IPv4           = 0x0800
    IPv6           = 0x86dd
    LLC            = 0x0001  /* pseudo ethertype */
    LLDP           = 0x088cc
    QinQ           = 0x88a8
    TRILL          = 0x22f3
    VLAN           = 0x8100
    WoL            = 0x0842
)

func Make() *Packet {
    return &Packet{
        DstAddr: make([]byte, 6),
        SrcAddr: make([]byte, 6),
        Length:  14,
    }
}

func (p *Packet) Equals(other packet.Packet) bool {
    return packet.Compare(p, other)
}

func (p *Packet) Answers(other packet.Packet) bool {
    if other == nil || other.GetType() != packet.Eth {
        return false
    }

    if p.Type != other.(*Packet).Type {
        return false
    }

    if p.Payload() != nil {
        return p.Payload().Answers(other.Payload())
    }

    return true
}

func (p *Packet) GetType() packet.Type {
    return packet.Eth
}

func (p *Packet) GetLength() uint16 {
    if p.pkt_payload != nil {
        return p.pkt_payload.GetLength() + 14
    }

    return 14
}

func (p *Packet) Pack(buf *packet.Buffer) error {
    buf.Write(p.DstAddr)
    buf.Write(p.SrcAddr)

    if p.Type != LLC {
        buf.WriteN(p.Type)
    } else {
        buf.WriteN(p.Length)
    }

    return nil
}

func (p *Packet) Unpack(buf *packet.Buffer) error {
    p.DstAddr = net.HardwareAddr(buf.Next(6))
    p.SrcAddr = net.HardwareAddr(buf.Next(6))

    buf.ReadN(&p.Type)

    if p.Type < 0x0600 {
        p.Length = uint16(p.Type)
        p.Type   = LLC
    }

    return nil
}

func (p *Packet) Payload() packet.Packet {
    return p.pkt_payload
}

func (p *Packet) GuessPayloadType() packet.Type {
    return EtherTypeToType(p.Type)
}

func (p *Packet) SetPayload(pl packet.Packet) error {
    p.pkt_payload = pl
    p.Type        = TypeToEtherType(pl.GetType())

    if p.Type < 0x0600 {
        p.Length = p.GetLength()
    }

    return nil
}

func (p *Packet) InitChecksum(csum uint32) {
}

func (p *Packet) String() string {
    return packet.Stringify(p)
}

var ethertype_to_type_map = map[EtherType]packet.Type{
    None:  packet.None,
    ARP:   packet.ARP,
    IPv4:  packet.IPv4,
    IPv6:  packet.IPv6,
    LLC:   packet.LLC,
    LLDP:  packet.LLDP,
    VLAN:  packet.VLAN,
    QinQ:  packet.VLAN,
    TRILL: packet.TRILL,
    WoL:   packet.WoL,
}

// Create a new Type from the given EtherType.
func EtherTypeToType(ethertype EtherType) packet.Type {
    for e, t := range ethertype_to_type_map {
        if e == ethertype {
            return t
        }
    }

    return packet.Raw
}

// Convert the Type to the corresponding EtherType.
func TypeToEtherType(pkttype packet.Type) EtherType {
    /* Hack to avoid non-determinism due to map iteration ordering */
    if pkttype == packet.VLAN {
        return VLAN
    }

    for e, t := range ethertype_to_type_map {
        if t == pkttype {
            return e
        }
    }

    return None
}

func (t EtherType) String() string {
    switch t {
    case ARP:   return "ARP"
    case IPv4:  return "IPv4"
    case IPv6:  return "IPv6"
    case LLC:   return "LLC"
    case LLDP:  return "LLDP"
    case None:  return "None"
    case QinQ:  return "QinQ"
    case TRILL: return "TRILL"
    case VLAN:  return "VLAN"
    case WoL:   return "WoL"
    default:    return fmt.Sprintf("0x%x", uint16(t))
    }
}


================================================
FILE: packet/eth/pkt_test.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package eth_test

import "bytes"
import "net"
import "testing"

import "github.com/ghedo/go.pkt/packet"
import "github.com/ghedo/go.pkt/packet/eth"

var hwsrc_str = "4c:72:b9:54:e5:3d"
var hwdst_str = "1f:92:2b:56:ed:77"

var test_simple = []byte{
    0x1f, 0x92, 0x2b, 0x56, 0xed, 0x77, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,
    0x08, 0x00,
}

func MakeTestSimple() *eth.Packet {
    hwsrc, _ := net.ParseMAC(hwsrc_str)
    hwdst, _ := net.ParseMAC(hwdst_str)

    return &eth.Packet{
        SrcAddr: hwsrc,
        DstAddr: hwdst,
        Type:    eth.IPv4,
    }
}

func TestPack(t *testing.T) {
    var b packet.Buffer
    b.Init(make([]byte, len(test_simple)))

    p := MakeTestSimple()

    err := p.Pack(&b)
    if err != nil {
        t.Fatalf("Error packing: %s", err)
    }

    if !bytes.Equal(test_simple, b.Buffer()) {
        t.Fatalf("Raw packet mismatch: %x", b.Buffer())
    }
}

func BenchmarkPack(bn *testing.B) {
    var b packet.Buffer
    b.Init(make([]byte, len(test_simple)))

    p := MakeTestSimple()

    for n := 0; n < bn.N; n++ {
        p.Pack(&b)
    }
}

func TestUnpack(t *testing.T) {
    var p eth.Packet

    cmp := MakeTestSimple()

    var b packet.Buffer
    b.Init(test_simple)

    err := p.Unpack(&b)
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }

    if !p.Equals(cmp) {
        t.Fatalf("Packet mismatch:\n%s\n%s", &p, cmp)
    }
}

func BenchmarkUnpack(bn *testing.B) {
    var p eth.Packet
    var b packet.Buffer

    for n := 0; n < bn.N; n++ {
        b.Init(test_simple)
        p.Unpack(&b)
    }
}


================================================
FILE: packet/icmpv4/pkt.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Provides encoding and decoding for ICMPv4 packets.
package icmpv4

import "fmt"

import "github.com/ghedo/go.pkt/packet"
import "github.com/ghedo/go.pkt/packet/ipv4"

type Packet struct {
    Type        Type
    Code        Code
    Checksum    uint16        `string:"sum"`
    Id          uint16
    Seq         uint16
    pkt_payload packet.Packet `cmp:"skip" string:"skip"`
}

type Type uint8
type Code uint8

const (
    EchoReply Type = iota
    Reserved1
    Reserved2
    DstUnreachable
    SrcQuench
    RedirectMsg
    Reserved3
    Reserved4
    EchoRequest
    RouterAdv
    RouterSol
    TimeExceeded
    ParamProblem
    Timestamp
    TimestampReply
    InfoRequest
    InfoReply
    AddrMaskRequest
    AddrMaskReply
)

func Make() *Packet {
    return &Packet{
        Type: EchoRequest,
    }
}

func (p *Packet) GetType() packet.Type {
    return packet.ICMPv4
}

func (p *Packet) GetLength() uint16 {
    if p.pkt_payload != nil {
        return p.pkt_payload.GetLength() + 8
    }

    return 8
}

func (p *Packet) Equals(other packet.Packet) bool {
    return packet.Compare(p, other)
}

func (p *Packet) Answers(other packet.Packet) bool {
    if other == nil || other.GetType() != packet.ICMPv4 {
        return false
    }

    if (other.(*Packet).Type == EchoRequest && p.Type == EchoReply) ||
       (other.(*Packet).Type == Timestamp && p.Type == TimestampReply) ||
       (other.(*Packet).Type == InfoRequest && p.Type == InfoReply) ||
       (other.(*Packet).Type == AddrMaskRequest && p.Type == AddrMaskReply) {
        return (other.(*Packet).Seq == p.Seq) &&
               (other.(*Packet).Id == p.Id)
    }

    return false
}

func (p *Packet) Pack(buf *packet.Buffer) error {
    buf.WriteN(byte(p.Type))
    buf.WriteN(byte(p.Code))
    buf.WriteN(uint16(0x0000))
    buf.WriteN(p.Id)
    buf.WriteN(p.Seq)

    p.Checksum = ipv4.CalculateChecksum(buf.LayerBytes(), 0)
    buf.PutUint16N(2, p.Checksum)

    return nil
}

func (p *Packet) Unpack(buf *packet.Buffer) error {
    buf.ReadN(&p.Type)
    buf.ReadN(&p.Code)
    buf.ReadN(&p.Checksum)
    buf.ReadN(&p.Id)
    buf.ReadN(&p.Seq)

    /* TODO: data */

    return nil
}

func (p *Packet) Payload() packet.Packet {
    return p.pkt_payload
}

func (p *Packet) GuessPayloadType() packet.Type {
    switch p.Type {
    case DstUnreachable, SrcQuench, RedirectMsg, TimeExceeded, ParamProblem:
        return packet.IPv4
    }

    return packet.None
}

func (p *Packet) SetPayload(pl packet.Packet) error {
    switch p.Type {
    case DstUnreachable, SrcQuench, RedirectMsg, TimeExceeded, ParamProblem:
        p.pkt_payload = pl
    }

    return nil
}

func (p *Packet) InitChecksum(csum uint32) {
}

func (p *Packet) String() string {
    return packet.Stringify(p)
}

func (t Type) String() string {
    switch t {
    case EchoReply:         return "echo-reply"
    case DstUnreachable:    return "dst-unreach"
    case SrcQuench:         return "src-quench"
    case RedirectMsg:       return "redirect"
    case EchoRequest:       return "echo-request"
    case RouterAdv:         return "router-adv"
    case RouterSol:         return "router-sol"
    case TimeExceeded:      return "time-exceeded"
    case ParamProblem:      return "param-problem"
    case Timestamp:         return "timestamp-request"
    case TimestampReply:    return "timestamp-reply"
    case InfoRequest:       return "info-request"
    case InfoReply:         return "info-reply"
    case AddrMaskRequest:   return "addr-mask-request"
    case AddrMaskReply:     return "addr-mask-reply"
    default:                return "unknown"
    }
}

func (c Code) String() string {
    if c != 0 {
        return fmt.Sprintf("%x", uint8(c))
    }

    return ""
}


================================================
FILE: packet/icmpv4/pkt_test.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package icmpv4_test

import "bytes"
import "testing"

import "github.com/ghedo/go.pkt/packet"
import "github.com/ghedo/go.pkt/packet/icmpv4"

var test_simple = []byte{
    0x08, 0x00, 0xf7, 0xd2, 0x00, 0x0f, 0x00, 0x1e,
}

func MakeTestSimple() *icmpv4.Packet {
    return &icmpv4.Packet{
        Type: icmpv4.EchoRequest,
        Code: 0,
        Id: 15,
        Seq: 30,
    }
}

func TestPack(t *testing.T) {
    var b packet.Buffer
    b.Init(make([]byte, len(test_simple)))

    p := MakeTestSimple()

    err := p.Pack(&b)
    if err != nil {
        t.Fatalf("Error packing: %s", err)
    }

    if !bytes.Equal(test_simple, b.Buffer()) {
        t.Fatalf("Raw packet mismatch: %x", b.Buffer())
    }
}

func BenchmarkPack(bn *testing.B) {
    var b packet.Buffer
    b.Init(make([]byte, len(test_simple)))

    p := MakeTestSimple()

    for n := 0; n < bn.N; n++ {
        p.Pack(&b)
    }
}

func TestUnpack(t *testing.T) {
    var p icmpv4.Packet

    cmp := MakeTestSimple()
    cmp.Checksum = 0xf7d2

    var b packet.Buffer
    b.Init(test_simple)

    err := p.Unpack(&b)
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }

    if !p.Equals(cmp) {
        t.Fatalf("Packet mismatch:\n%s\n%s", &p, cmp)
    }
}

func BenchmarkUnpack(bn *testing.B) {
    var p icmpv4.Packet
    var b packet.Buffer

    for n := 0; n < bn.N; n++ {
        b.Init(test_simple)
        p.Unpack(&b)
    }
}


================================================
FILE: packet/icmpv6/pkt.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Provides encoding and decoding for ICMPv6 packets.
package icmpv6

import "fmt"

import "github.com/ghedo/go.pkt/packet"
import "github.com/ghedo/go.pkt/packet/ipv4"

type Packet struct {
    Type      Type
    Code      Code
    Checksum  uint16 `string:"sum"`
    csum_seed uint32 `cmp:"skip" string:"skip"`
    Body      uint32 `cmp:"skip" string:"skip"`
    pkt_payload packet.Packet `cmp:"skip" string:"skip"`
}

type Type uint8
type Code uint8

const (
    DstUnreachable Type = 1
    PacketTooBig        = 2
    TimeExceeded        = 3
    ParamProblem        = 4
    Private1            = 100
    Private2            = 101
    Reserved1           = 127
    EchoRequest         = 128
    EchoReply           = 129
    /* TODO: more types */
)

func Make() *Packet {
    return &Packet{
        Type: EchoRequest,
    }
}

func (p *Packet) GetType() packet.Type {
    return packet.ICMPv6
}

func (p *Packet) GetLength() uint16 {
    if p.pkt_payload != nil {
        return p.pkt_payload.GetLength() + 8
    }

    return 8
}

func (p *Packet) Equals(other packet.Packet) bool {
    return packet.Compare(p, other)
}

func (p *Packet) Answers(other packet.Packet) bool {
    if other == nil || other.GetType() != packet.ICMPv6 {
        return false
    }

    if other.(*Packet).Type == EchoRequest && p.Type == EchoReply {
        return true
    }

    return false
}

func (p *Packet) Pack(buf *packet.Buffer) error {
    buf.WriteN(byte(p.Type))
    buf.WriteN(byte(p.Code))
    buf.WriteN(uint16(0x00))
    buf.WriteN(p.Body)

    if p.csum_seed != 0 {
        p.Checksum = ipv4.CalculateChecksum(buf.LayerBytes(), p.csum_seed)
        buf.PutUint16N(2, p.Checksum)
    }

    return nil
}

func (p *Packet) Unpack(buf *packet.Buffer) error {
    buf.ReadN(&p.Type)
    buf.ReadN(&p.Code)
    buf.ReadN(&p.Checksum)

    /* TODO: data */
    buf.ReadN(&p.Body)

    return nil
}

func (p *Packet) Payload() packet.Packet {
    return p.pkt_payload
}

func (p *Packet) GuessPayloadType() packet.Type {
    switch p.Type {
    case DstUnreachable, PacketTooBig, TimeExceeded, ParamProblem:
        return packet.IPv6
    }

    return packet.None
}

func (p *Packet) SetPayload(pl packet.Packet) error {
    switch p.Type {
    case DstUnreachable, PacketTooBig, TimeExceeded, ParamProblem:
        p.pkt_payload = pl
    }

    return nil
}

func (p *Packet) InitChecksum(csum uint32) {
    p.csum_seed = csum
}

func (p *Packet) String() string {
    return packet.Stringify(p)
}

func (t Type) String() string {
    switch t {
    case DstUnreachable:    return "dst-unreach"
    case PacketTooBig:      return "too-big"
    case TimeExceeded:      return "timeout"
    case ParamProblem:      return "param-problem"
    case EchoRequest:       return "echo-request"
    case EchoReply:         return "echo-reply"
    default:                return "unknown"
    }
}

func (c Code) String() string {
    if c != 0 {
        return fmt.Sprintf("%x", uint8(c))
    }

    return ""
}


================================================
FILE: packet/icmpv6/pkt_test.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package icmpv6_test

import "bytes"
import "net"
import "testing"

import "github.com/ghedo/go.pkt/packet"
import "github.com/ghedo/go.pkt/packet/icmpv6"
import "github.com/ghedo/go.pkt/packet/ipv6"

var test_simple = []byte{
    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}

func MakeTestSimple() *icmpv6.Packet {
    return &icmpv6.Packet{
        Type: icmpv6.EchoRequest,
    }
}

func TestPack(t *testing.T) {
    var b packet.Buffer
    b.Init(make([]byte, len(test_simple)))

    p := MakeTestSimple()

    err := p.Pack(&b)
    if err != nil {
        t.Fatalf("Error packing: %s", err)
    }

    if !bytes.Equal(test_simple, b.Buffer()) {
        t.Fatalf("Raw packet mismatch: %x", b.Buffer())
    }
}

func BenchmarkPack(bn *testing.B) {
    var b packet.Buffer
    b.Init(make([]byte, len(test_simple)))

    p := MakeTestSimple()

    for n := 0; n < bn.N; n++ {
        p.Pack(&b)
    }
}

func TestUnpack(t *testing.T) {
    var p icmpv6.Packet

    cmp := MakeTestSimple()

    var b packet.Buffer
    b.Init(test_simple)

    err := p.Unpack(&b)
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }

    if !p.Equals(cmp) {
        t.Fatalf("Packet mismatch:\n%s\n%s", &p, cmp)
    }
}

func BenchmarkUnpack(bn *testing.B) {
    var p icmpv6.Packet
    var b packet.Buffer

    for n := 0; n < bn.N; n++ {
        b.Init(test_simple)
        p.Unpack(&b)
    }
}

var test_with_ipv6 = []byte{
    0x80, 0x00, 0x5b, 0xed, 0x00, 0x00, 0x00, 0x00,
}

var ipsrc_str = "fe80::4e72:b9ff:fe54:e53d"
var ipdst_str = "2001:4860:4860::8888"

func TestPackWithIPv6(t *testing.T) {
    var b packet.Buffer
    b.Init(make([]byte, len(test_with_ipv6)))

    ip6 := ipv6.Make()
    ip6.SrcAddr = net.ParseIP(ipsrc_str)
    ip6.DstAddr = net.ParseIP(ipdst_str)

    icmp6 := MakeTestSimple()

    ip6.SetPayload(icmp6)

    err := icmp6.Pack(&b)
    if err != nil {
        t.Fatalf("Error packing: %s", err)
    }

    if !bytes.Equal(test_with_ipv6, b.Buffer()) {
        t.Fatalf("Raw packet mismatch: %x", b.Buffer())
    }
}

func TestUnpackWithIPv6(t *testing.T) {
    var p icmpv6.Packet

    cmp := MakeTestSimple()
    cmp.Checksum = 0x5bed

    var b packet.Buffer
    b.Init(test_with_ipv6)

    err := p.Unpack(&b)
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }

    if !p.Equals(cmp) {
        t.Fatalf("Packet mismatch:\n%s\n%s", &p, cmp)
    }
}


================================================
FILE: packet/ipv4/pkt.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Provides encoding and decoding for IPv4 packets.
package ipv4

import "fmt"
import "net"
import "strings"

import "github.com/ghedo/go.pkt/packet"

type Packet struct {
    Version     uint8
    IHL         uint8
    TOS         uint8         `cmp:"skip"`
    Length      uint16        `cmp:"skip"`
    Id          uint16
    Flags       Flags
    FragOff     uint16
    TTL         uint8         `cmp:"skip"`
    Protocol    Protocol      `string:"proto"`
    Checksum    uint16        `cmp:"skip" string:"sum"`
    SrcAddr     net.IP        `string:"src"`
    DstAddr     net.IP        `string:"dst"`
    pkt_payload packet.Packet `cmp:"skip" string:"skip"`
}

type Flags uint8

const (
    Evil     Flags = 1 << 2 /* RFC3514 */
    DontFragment   = 1 << 1
    MoreFragments  = 1 << 0
)

type Protocol uint8

const (
    None Protocol = 0x00
    GRE           = 0x2F
    ICMPv4        = 0x01
    ICMPv6        = 0x3A
    IGMP          = 0x02
    IPSecAH       = 0x33
    IPSecESP      = 0x32
    IPv6          = 0x29
    ISIS          = 0x7C
    L2TP          = 0x73
    OSPF          = 0x59
    SCTP          = 0x84
    TCP           = 0x06
    UDP           = 0x11
    UDPLite       = 0x88
)

func Make() *Packet {
    return &Packet{
        Version: 4,
        IHL: 5,
        Length: 20,
        TTL: 64,
        Id: 1,
    }
}

func (p *Packet) GetType() packet.Type {
    return packet.IPv4
}

func (p *Packet) GetLength() uint16 {
    if p.pkt_payload != nil {
        return p.pkt_payload.GetLength() + 20
    }

    return 20
}

func (p *Packet) Equals(other packet.Packet) bool {
    return packet.Compare(p, other)
}

func (p *Packet) Answers(other packet.Packet) bool {
    if other == nil || other.GetType() != packet.IPv4 {
        return false
    }

    if p.Payload() != nil &&
       p.Payload().GetType() == packet.ICMPv4 &&
       p.Payload().Payload() != nil {
        return p.Payload().Payload().Equals(other)
    }

    if !p.SrcAddr.Equal(other.(*Packet).DstAddr) ||
        p.Protocol != other.(*Packet).Protocol {
        return false
    }

    if p.Payload() != nil {
        return p.Payload().Answers(other.Payload())
    }

    return true
}

func (p *Packet) Pack(buf *packet.Buffer) error {
    buf.WriteN((p.Version << 4) | p.IHL)
    buf.WriteN(p.TOS)
    buf.WriteN(p.Length)
    buf.WriteN(p.Id)
    buf.WriteN((uint16(p.Flags) << 13) | p.FragOff)
    buf.WriteN(p.TTL)
    buf.WriteN(p.Protocol)
    buf.WriteN(uint16(0x00))
    buf.Write(p.SrcAddr.To4())
    buf.Write(p.DstAddr.To4())

    p.checksum(buf.LayerBytes()[:20])
    buf.PutUint16N(10, p.Checksum)

    return nil
}

func (p *Packet) checksum(raw_bytes []byte) {
    var csum uint32

    for i := 0; i < len(raw_bytes) - 1; i += 2 {
        csum += uint32(raw_bytes[i]) << 8
        csum += uint32(raw_bytes[i + 1])
    }

    p.Checksum = ^uint16((csum >> 16) + csum)
}

func (p *Packet) pseudo_checksum() uint32 {
    var csum uint32

    csum += (uint32(p.SrcAddr.To4()[0]) + uint32(p.SrcAddr.To4()[2])) << 8
    csum +=  uint32(p.SrcAddr.To4()[1]) + uint32(p.SrcAddr.To4()[3])
    csum += (uint32(p.DstAddr.To4()[0]) + uint32(p.DstAddr.To4()[2])) << 8
    csum +=  uint32(p.DstAddr.To4()[1]) + uint32(p.DstAddr.To4()[3])
    csum +=  uint32(p.Protocol)
    csum +=  uint32(p.pkt_payload.GetLength())

    return csum
}

func (p *Packet) Unpack(buf *packet.Buffer) error {
    var versihl uint8
    buf.ReadN(&versihl)

    p.Version  = versihl >> 4
    p.IHL      = versihl & 0x0F

    buf.ReadN(&p.TOS)
    buf.ReadN(&p.Length)
    buf.ReadN(&p.Id)

    var flagsfrag uint16
    buf.ReadN(&flagsfrag)
    p.Flags   = Flags(flagsfrag >> 13)
    p.FragOff = flagsfrag & 0x1FFF

    buf.ReadN(&p.TTL)

    buf.ReadN(&p.Protocol)

    buf.ReadN(&p.Checksum)

    p.SrcAddr = net.IP(buf.Next(4))
    p.DstAddr = net.IP(buf.Next(4))

    /* TODO: Options */

    return nil
}

func (p *Packet) Payload() packet.Packet {
    return p.pkt_payload
}

func (p *Packet) GuessPayloadType() packet.Type {
    return ProtocolToType(p.Protocol)
}

func (p *Packet) SetPayload(pl packet.Packet) error {
    p.pkt_payload = pl
    p.Protocol    = TypeToProtocol(pl.GetType())
    p.Length      = p.GetLength()

    pl.InitChecksum(p.pseudo_checksum())

    return nil
}

func (p *Packet) InitChecksum(csum uint32) {
}

func (p *Packet) String() string {
    return packet.Stringify(p)
}

func (f Flags) String() string {
    var flags []string

    if f & Evil != 0  {
        flags = append(flags, "evil")
    }

    if f & DontFragment != 0 {
        flags = append(flags, "dont-fragment")
    }

    if f & MoreFragments != 0 {
        flags = append(flags, "more-fragments")
    }

    return strings.Join(flags, "|")
}

func CalculateChecksum(raw_bytes []byte, csum uint32) uint16 {
    length := len(raw_bytes) - 1

    for i := 0; i < length; i += 2 {
        csum += uint32(raw_bytes[i]) << 8
        csum += uint32(raw_bytes[i + 1])
    }

    csum = (csum >> 16) + (csum & 0xffff)

    return ^uint16(csum + (csum >> 16))
}

var ipv4proto_to_type_map = map[Protocol]packet.Type{
    None:     packet.None,
    GRE:      packet.GRE,
    ICMPv4:   packet.ICMPv4,
    ICMPv6:   packet.ICMPv6,
    IGMP:     packet.IGMP,
    IPSecAH:  packet.IPSec,
    IPSecESP: packet.IPSec,
    IPv6:     packet.IPv6,
    UDP:      packet.UDP,
    ISIS:     packet.ISIS,
    L2TP:     packet.L2TP,
    OSPF:     packet.OSPF,
    SCTP:     packet.SCTP,
    UDPLite:  packet.UDPLite,
    TCP:      packet.TCP,
}

// Create a new Type from the given IP protocol ID.
func ProtocolToType(proto Protocol) packet.Type {
    for p, t := range ipv4proto_to_type_map {
        if p == proto {
            return t
        }
    }

    return packet.Raw
}

// Convert the Type to the corresponding IP protocol ID.
func TypeToProtocol(pkttype packet.Type) Protocol {
    for p, t := range ipv4proto_to_type_map {
        if t == pkttype {
            return p
        }
    }

    return None
}

func (p Protocol) String() string {
    switch p {
    case GRE:      return "GRE"
    case ICMPv4:   return "ICMPv4"
    case ICMPv6:   return "ICMPv6"
    case IGMP:     return "IGMP"
    case IPSecAH:  return "IPSecAH"
    case IPSecESP: return "IPSecESP"
    case IPv6:     return "IPv6"
    case UDP:      return "UDP"
    case ISIS:     return "ISIS"
    case L2TP:     return "L2TP"
    case OSPF:     return "OSPF"
    case SCTP:     return "SCTP"
    case UDPLite:  return "UDPLite"
    case TCP:      return "TCP"
    default:       return fmt.Sprintf("0x%x", uint16(p))
    }
}


================================================
FILE: packet/ipv4/pkt_test.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package ipv4_test

import "bytes"
import "net"
import "testing"

import "github.com/ghedo/go.pkt/packet"
import "github.com/ghedo/go.pkt/packet/ipv4"

var test_simple = []byte{
    0x45, 0x03, 0x00, 0x14, 0x00, 0x0f, 0x40, 0x00, 0x64, 0x06, 0x48, 0x97,
    0xc0, 0xa8, 0x01, 0x87, 0x08, 0x08, 0x04, 0x04,
}

var ipsrc_str = "192.168.1.135"
var ipdst_str = "8.8.4.4"

func MakeTestSimple() *ipv4.Packet {
    return &ipv4.Packet{
        Version: 4,
        IHL: 5,
        Length: 20,
        TOS: 3,
        Id: 15,
        TTL: 100,
        Flags: ipv4.DontFragment,
        Protocol: ipv4.TCP,
        SrcAddr: net.ParseIP(ipsrc_str),
        DstAddr: net.ParseIP(ipdst_str),
    }
}

func TestPack(t *testing.T) {
    var b packet.Buffer
    b.Init(make([]byte, len(test_simple)))

    p := MakeTestSimple()

    err := p.Pack(&b)
    if err != nil {
        t.Fatalf("Error packing: %s", err)
    }

    if !bytes.Equal(test_simple, b.Buffer()) {
        t.Fatalf("Raw packet mismatch: %x", b.Buffer())
    }
}

func BenchmarkPack(bn *testing.B) {
    var b packet.Buffer
    b.Init(make([]byte, len(test_simple)))

    p := MakeTestSimple()

    for n := 0; n < bn.N; n++ {
        p.Pack(&b)
    }
}

func TestUnpack(t *testing.T) {
    var p ipv4.Packet

    cmp := MakeTestSimple()
    cmp.Checksum = 0x4897

    var b packet.Buffer
    b.Init(test_simple)

    err := p.Unpack(&b)
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }

    if !p.Equals(cmp) {
        t.Fatalf("Packet mismatch:\n%s\n%s", &p, cmp)
    }
}

func BenchmarkUnpack(bn *testing.B) {
    var p ipv4.Packet
    var b packet.Buffer

    for n := 0; n < bn.N; n++ {
        b.Init(test_simple)
        p.Unpack(&b)
    }
}


================================================
FILE: packet/ipv6/pkt.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Provides encoding and decoding for IPv6 packets.
package ipv6

import "encoding/binary"
import "net"

import "github.com/ghedo/go.pkt/packet"
import "github.com/ghedo/go.pkt/packet/ipv4"

type Packet struct {
    Version     uint8
    Class       uint8
    Label       uint32
    Length      uint16        `string:"len"`
    NextHdr     ipv4.Protocol `string:"next"`
    HopLimit    uint8         `cmp:"skip" string:"hop"`
    SrcAddr     net.IP        `string:"src"`
    DstAddr     net.IP        `string:"dst"`
    pkt_payload packet.Packet `cmp:"skip" string:"skip"`
}

type Flags uint8

func Make() *Packet {
    return &Packet{
        Version: 6,
        HopLimit: 64,
    }
}

func (p *Packet) GetType() packet.Type {
    return packet.IPv6
}

func (p *Packet) GetLength() uint16 {
    if p.pkt_payload != nil {
        return p.pkt_payload.GetLength() + 40
    }

    return 40
}

func (p *Packet) Equals(other packet.Packet) bool {
    return packet.Compare(p, other)
}

func (p *Packet) Answers(other packet.Packet) bool {
    if other == nil || other.GetType() != packet.IPv6 {
        return false
    }

    /* TODO: check link-local broadcast addresses */
    if !p.DstAddr.Equal(other.(*Packet).SrcAddr) {
        return false
    }

    /* TODO: check ICMPv6 errors */

    if p.Payload() != nil {
        return p.Payload().Answers(other.Payload())
    }

    return true
}

func (p *Packet) Pack(buf *packet.Buffer) error {
    buf.WriteN(uint8(p.Version << 4 | (p.Class >> 4)))
    buf.WriteN(p.Class << 4 | uint8(p.Label >> 16))
    buf.WriteN(uint16(p.Label))

    buf.WriteN(p.Length)
    buf.WriteN(p.NextHdr)
    buf.WriteN(p.HopLimit)

    buf.Write(p.SrcAddr.To16())
    buf.Write(p.DstAddr.To16())

    return nil
}

func (p *Packet) pseudo_checksum() uint32 {
    var csum uint32

    for i := 0; i < 16; i += 2 {
        csum += uint32(p.SrcAddr.To16()[i]) << 8
        csum += uint32(p.SrcAddr.To16()[i + 1])
        csum += uint32(p.DstAddr.To16()[i]) << 8
        csum += uint32(p.DstAddr.To16()[i + 1])
    }

    csum += uint32(p.Length)
    csum += uint32(p.NextHdr)

    return csum
}

func (p *Packet) Unpack(buf *packet.Buffer) error {
    var versclass uint8
    buf.ReadN(&versclass)

    p.Version = versclass >> 4

    p.Class =
     uint8((binary.BigEndian.Uint16(buf.LayerBytes()[0:2]) >> 4) & 0x00FF)

    p.Label =
     binary.BigEndian.Uint32(buf.LayerBytes()[0:4]) & 0x000FFFFF

    buf.Next(3)

    buf.ReadN(&p.Length)
    buf.ReadN(&p.NextHdr)
    buf.ReadN(&p.HopLimit)

    p.SrcAddr = net.IP(buf.Next(16))
    p.DstAddr = net.IP(buf.Next(16))

    /* TODO: Options */

    return nil
}

func (p *Packet) Payload() packet.Packet {
    return p.pkt_payload
}

func (p *Packet) GuessPayloadType() packet.Type {
    return ipv4.ProtocolToType(p.NextHdr)
}

func (p *Packet) SetPayload(pl packet.Packet) error {
    p.pkt_payload = pl
    p.NextHdr     = ipv4.TypeToProtocol(pl.GetType())
    p.Length      = pl.GetLength()

    pl.InitChecksum(p.pseudo_checksum())

    return nil
}

func (p *Packet) InitChecksum(csum uint32) {
}

func (p *Packet) String() string {
    return packet.Stringify(p)
}


================================================
FILE: packet/ipv6/pkt_test.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package ipv6_test

import "bytes"
import "net"
import "testing"

import "github.com/ghedo/go.pkt/packet"
import "github.com/ghedo/go.pkt/packet/ipv4"
import "github.com/ghedo/go.pkt/packet/ipv6"

var test_simple = []byte{
    0x63, 0x0d, 0x5b, 0x0a, 0x00, 0x08, 0x11, 0x40, 0xfe, 0x80, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x4e, 0x72, 0xb9, 0xff, 0xfe, 0x54, 0xe5, 0x3d,
    0x07, 0x9a, 0x19, 0xb9, 0x11, 0x15, 0xed, 0x67, 0x99, 0xf5, 0xf0, 0x7a,
    0x66, 0x87, 0x5b, 0x0f,
}

var ipsrc_str = "fe80::4e72:b9ff:fe54:e53d"
var ipdst_str = "79a:19b9:1115:ed67:99f5:f07a:6687:5b0f"

func MakeTestSimple() *ipv6.Packet {
    return &ipv6.Packet{
        Version: 6,
        Class: 48,
        Label: 875274,
        Length: 8,
        NextHdr: ipv4.UDP,
        HopLimit: 64,
        SrcAddr: net.ParseIP(ipsrc_str),
        DstAddr: net.ParseIP(ipdst_str),
    }
}

func TestPack(t *testing.T) {
    var b packet.Buffer
    b.Init(make([]byte, len(test_simple)))

    p := MakeTestSimple()

    err := p.Pack(&b)
    if err != nil {
        t.Fatalf("Error packing: %s", err)
    }

    if !bytes.Equal(test_simple, b.Buffer()) {
        t.Fatalf("Raw packet mismatch: %x", b.Buffer())
    }
}

func BenchmarkPack(bn *testing.B) {
    var b packet.Buffer
    b.Init(make([]byte, len(test_simple)))

    p := MakeTestSimple()

    for n := 0; n < bn.N; n++ {
        p.Pack(&b)
    }
}

func TestUnpack(t *testing.T) {
    var p ipv6.Packet

    cmp := MakeTestSimple()

    var b packet.Buffer
    b.Init(test_simple)

    err := p.Unpack(&b)
    if err != nil {
        t.Fatalf("Error unpacking: %s", err)
    }

    if !p.Equals(cmp) {
        t.Fatalf("Packet mismatch:\n%s\n%s", &p, cmp)
    }
}

func BenchmarkUnpack(bn *testing.B) {
    var p ipv6.Packet
    var b packet.Buffer

    for n := 0; n < bn.N; n++ {
        b.Init(test_simple)
        p.Unpack(&b)
    }
}


================================================
FILE: packet/llc/pkt.go
================================================
/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the foll
Download .txt
gitextract_y_3guso3/

├── .travis.yml
├── COPYING
├── README.md
├── capture/
│   ├── capture.go
│   ├── file/
│   │   ├── capture.go
│   │   ├── capture_test.go
│   │   └── capture_test.pcap
│   └── pcap/
│       ├── capture.go
│       └── capture_test.go
├── examples/
│   ├── arp/
│   │   └── main.go
│   ├── bpf_asm/
│   │   ├── Makefile
│   │   ├── bpf_asm.l
│   │   └── bpf_asm.y
│   ├── dump/
│   │   └── main.go
│   ├── ping/
│   │   └── main.go
│   ├── route/
│   │   └── main.go
│   ├── syn_scan/
│   │   └── main.go
│   ├── tracereply/
│   │   └── main.go
│   └── traceroute/
│       └── main.go
├── filter/
│   ├── bpf_builder.go
│   ├── bpf_builder_test.go
│   ├── bpf_filter.c
│   ├── bpf_filter.go
│   ├── bpf_filter.h
│   ├── bpf_filter_test.go
│   └── pcap.go
├── go.mod
├── go.sum
├── layers/
│   ├── layers.go
│   └── layers_test.go
├── network/
│   └── network.go
├── packet/
│   ├── arp/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── buffer.go
│   ├── eth/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── icmpv4/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── icmpv6/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── ipv4/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── ipv6/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── llc/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── packet.go
│   ├── radiotap/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── raw/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── sll/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── snap/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── tcp/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   ├── udp/
│   │   ├── pkt.go
│   │   └── pkt_test.go
│   └── vlan/
│       ├── pkt.go
│       └── pkt_test.go
└── routing/
    ├── routing.go
    └── routing_linux.go
Download .txt
SYMBOL INDEX (622 symbols across 54 files)

FILE: capture/capture.go
  type Handle (line 38) | type Handle interface

FILE: capture/file/capture.go
  type Handle (line 44) | type Handle struct
    method LinkType (line 144) | func (h *Handle) LinkType() packet.Type {
    method SetMTU (line 149) | func (h *Handle) SetMTU(mtu int) error {
    method SetPromiscMode (line 154) | func (h *Handle) SetPromiscMode(promisc bool) error {
    method SetMonitorMode (line 159) | func (h *Handle) SetMonitorMode(monitor bool) error {
    method ApplyFilter (line 165) | func (h *Handle) ApplyFilter(filter *filter.Filter) error {
    method Activate (line 177) | func (h *Handle) Activate() error {
    method Capture (line 184) | func (h *Handle) Capture() ([]byte, error) {
    method Inject (line 221) | func (h *Handle) Inject(buf []byte) error {
    method Close (line 243) | func (h *Handle) Close() {
  function Open (line 59) | func Open(file_name string) (*Handle, error) {
  function create_file (line 115) | func create_file(file_name string) (*os.File, error) {
  function open_file (line 133) | func open_file(file_name string) (*os.File, error) {

FILE: capture/file/capture_test.go
  function TestCapture (line 39) | func TestCapture(t *testing.T) {
  function TestCaptureFilter (line 65) | func TestCaptureFilter(t *testing.T) {
  function TestInject (line 102) | func TestInject(t *testing.T) {
  function ExampleCapture (line 139) | func ExampleCapture() {
  function ExampleInject (line 170) | func ExampleInject() {

FILE: capture/pcap/capture.go
  type Handle (line 46) | type Handle struct
    method LinkType (line 74) | func (h *Handle) LinkType() packet.Type {
    method SetMTU (line 78) | func (h *Handle) SetMTU(mtu int) error {
    method SetPromiscMode (line 88) | func (h *Handle) SetPromiscMode(promisc bool) error {
    method SetMonitorMode (line 107) | func (h *Handle) SetMonitorMode(monitor bool) error {
    method ApplyFilter (line 126) | func (h *Handle) ApplyFilter(filter *filter.Filter) error {
    method Activate (line 148) | func (h *Handle) Activate() error {
    method Capture (line 159) | func (h *Handle) Capture() ([]byte, error) {
    method Inject (line 187) | func (h *Handle) Inject(buf []byte) error {
    method Close (line 200) | func (h *Handle) Close() {
    method get_error (line 204) | func (h *Handle) get_error() error {
  function Open (line 53) | func Open(dev_name string) (*Handle, error) {

FILE: capture/pcap/capture_test.go
  function ExampleCapture (line 37) | func ExampleCapture() {
  function ExampleInject (line 64) | func ExampleInject() {

FILE: examples/arp/main.go
  function main (line 46) | func main() {

FILE: examples/dump/main.go
  function main (line 44) | func main() {

FILE: examples/ping/main.go
  function main (line 49) | func main() {

FILE: examples/route/main.go
  function main (line 40) | func main() {

FILE: examples/syn_scan/main.go
  function main (line 53) | func main() {

FILE: examples/tracereply/main.go
  function main (line 18) | func main() {

FILE: examples/traceroute/main.go
  function main (line 55) | func main() {

FILE: filter/bpf_builder.go
  type Builder (line 37) | type Builder struct
    method Build (line 60) | func (b *Builder) Build() *Filter {
    method Label (line 94) | func (b *Builder) Label(name string) *Builder {
    method LD (line 104) | func (b *Builder) LD(s Size, m Mode, val uint32) *Builder {
    method LDX (line 115) | func (b *Builder) LDX(s Size, m Mode, val uint32) *Builder {
    method ST (line 123) | func (b *Builder) ST(off uint32) *Builder {
    method STX (line 130) | func (b *Builder) STX(off uint32) *Builder {
    method ADD (line 139) | func (b *Builder) ADD(s Src, val uint32) *Builder {
    method SUB (line 149) | func (b *Builder) SUB(s Src, val uint32) *Builder {
    method MUL (line 159) | func (b *Builder) MUL(s Src, val uint32) *Builder {
    method DIV (line 169) | func (b *Builder) DIV(s Src, val uint32) *Builder {
    method OR (line 179) | func (b *Builder) OR(s Src, val uint32) *Builder {
    method AND (line 189) | func (b *Builder) AND(s Src, val uint32) *Builder {
    method LSH (line 199) | func (b *Builder) LSH(s Src, val uint32) *Builder {
    method RSH (line 209) | func (b *Builder) RSH(s Src, val uint32) *Builder {
    method NEG (line 216) | func (b *Builder) NEG() *Builder {
    method MOD (line 226) | func (b *Builder) MOD(s Src, val uint32) *Builder {
    method XOR (line 236) | func (b *Builder) XOR(s Src, val uint32) *Builder {
    method JA (line 244) | func (b *Builder) JA(j string) *Builder {
    method JEQ (line 255) | func (b *Builder) JEQ(s Src, jt, jf string, cmp uint32) *Builder {
    method JGT (line 267) | func (b *Builder) JGT(s Src, jt, jf string, cmp uint32) *Builder {
    method JGE (line 279) | func (b *Builder) JGE(s Src, jt, jf string, cmp uint32) *Builder {
    method JSET (line 289) | func (b *Builder) JSET(s Src, jt, jf string, cmp uint32) *Builder {
    method RET (line 302) | func (b *Builder) RET(s Src, bytes uint32) *Builder {
    method TAX (line 310) | func (b *Builder) TAX() *Builder {
    method TXA (line 318) | func (b *Builder) TXA() *Builder {
    method AppendInstruction (line 325) | func (b *Builder) AppendInstruction(code Code, jt, jf uint8, k uint32)...
  function NewBuilder (line 47) | func NewBuilder() *Builder {

FILE: filter/bpf_builder_test.go
  function TestEmpty (line 38) | func TestEmpty(t *testing.T) {
  function TestARP (line 53) | func TestARP(t *testing.T) {
  function TestARPcBPF (line 67) | func TestARPcBPF(t *testing.T) {
  function TestDNS (line 95) | func TestDNS(t *testing.T) {
  function TestALUOps (line 121) | func TestALUOps(t *testing.T) {
  function ExampleBuilder (line 159) | func ExampleBuilder() {

FILE: filter/bpf_filter.c
  function u_int (line 76) | u_int
  function bpf_validate (line 366) | int
  function bpf_append_insn (line 422) | int
  function bpf_get_len (line 438) | int
  type bpf_insn (line 444) | struct bpf_insn
  type bpf_program (line 445) | struct bpf_program

FILE: filter/bpf_filter.go
  type Filter (line 46) | type Filter struct
    method Match (line 91) | func (f *Filter) Match(buf []byte) bool {
    method Filter (line 103) | func (f *Filter) Filter(buf []byte) uint {
    method Validate (line 113) | func (f *Filter) Validate() bool {
    method Cleanup (line 122) | func (f *Filter) Cleanup() {
    method Len (line 132) | func (f *Filter) Len() int {
    method Program (line 139) | func (f *Filter) Program() unsafe.Pointer {
    method String (line 143) | func (f *Filter) String() string {
    method append_insn (line 163) | func (f *Filter) append_insn(code Code, jt, jf uint8, k uint32) {
  type Code (line 50) | type Code
  constant LD (line 53) | LD Code = syscall.BPF_LD
  constant LDX (line 54) | LDX     = syscall.BPF_LDX
  constant ST (line 55) | ST      = syscall.BPF_ST
  constant STX (line 56) | STX     = syscall.BPF_STX
  constant ALU (line 57) | ALU     = syscall.BPF_ALU
  constant JMP (line 58) | JMP     = syscall.BPF_JMP
  constant RET (line 59) | RET     = syscall.BPF_RET
  constant MISC (line 60) | MISC    = syscall.BPF_MISC
  type Size (line 63) | type Size
  constant Word (line 66) | Word Size = syscall.BPF_W
  constant Half (line 67) | Half      = syscall.BPF_H
  constant Byte (line 68) | Byte      = syscall.BPF_B
  type Mode (line 71) | type Mode
  constant IMM (line 74) | IMM Mode = syscall.BPF_IMM
  constant ABS (line 75) | ABS      = syscall.BPF_ABS
  constant IND (line 76) | IND      = syscall.BPF_IND
  constant MEM (line 77) | MEM      = syscall.BPF_MEM
  constant LEN (line 78) | LEN      = syscall.BPF_LEN
  constant MSH (line 79) | MSH      = syscall.BPF_MSH
  type Src (line 82) | type Src
  constant Const (line 85) | Const Src = syscall.BPF_K
  constant Index (line 86) | Index     = syscall.BPF_X
  constant Acc (line 87) | Acc       = syscall.BPF_A

FILE: filter/bpf_filter.h
  type bpf_u_int32 (line 40) | typedef unsigned int bpf_u_int32;
  type u_char (line 41) | typedef unsigned char u_char;
  type bpf_program (line 43) | struct bpf_program {
  type bpf_insn (line 110) | struct bpf_insn {
  type bpf_insn (line 128) | struct bpf_insn
  type bpf_insn (line 131) | struct bpf_insn
  type bpf_program (line 133) | struct bpf_program
  type bpf_program (line 136) | struct bpf_program
  type bpf_insn (line 138) | struct bpf_insn
  type bpf_program (line 138) | struct bpf_program

FILE: filter/bpf_filter_test.go
  function TestMatch (line 76) | func TestMatch(t *testing.T) {
  function BenchmarkMatch (line 134) | func BenchmarkMatch(b *testing.B) {
  function ExampleFilter (line 142) | func ExampleFilter() {

FILE: filter/pcap.go
  function Compile (line 44) | func Compile(filter string, link_type packet.Type, optimize bool) (*Filt...

FILE: layers/layers.go
  function Compose (line 55) | func Compose(pkts ...packet.Packet) (packet.Packet, error) {
  function Pack (line 74) | func Pack(pkts ...packet.Packet) ([]byte, error) {
  function Unpack (line 112) | func Unpack(buf []byte, pkts ...packet.Packet) (packet.Packet, error) {
  function UnpackAll (line 153) | func UnpackAll(buf []byte, link_type packet.Type) (packet.Packet, error) {
  function FindLayer (line 210) | func FindLayer(p packet.Packet, layer packet.Type) packet.Packet {

FILE: layers/layers_test.go
  function TestPackEthArp (line 61) | func TestPackEthArp(t *testing.T) {
  function TestUnpackEthArp (line 82) | func TestUnpackEthArp(t *testing.T) {
  function BenchmarkUnpackEthArp (line 89) | func BenchmarkUnpackEthArp(bn *testing.B) {
  function TestUnpackAllEthArp (line 98) | func TestUnpackAllEthArp(t *testing.T) {
  function BenchmarkUnpackAllEthArp (line 113) | func BenchmarkUnpackAllEthArp(bn *testing.B) {
  function TestPackEthVLANArp (line 126) | func TestPackEthVLANArp(t *testing.T) {
  function TestUnpackEthVLANArp (line 150) | func TestUnpackEthVLANArp(t *testing.T) {
  function BenchmarkUnpackEthVLANArp (line 157) | func BenchmarkUnpackEthVLANArp(bn *testing.B) {
  function TestUnpackAllEthVLANArp (line 167) | func TestUnpackAllEthVLANArp(t *testing.T) {
  function BenchmarkUnpackAllEthVLANArp (line 188) | func BenchmarkUnpackAllEthVLANArp(bn *testing.B) {
  function TestPackEthIPv4UDP (line 201) | func TestPackEthIPv4UDP(t *testing.T) {
  function TestUnpackEthUPv4UDP (line 224) | func TestUnpackEthUPv4UDP(t *testing.T) {
  function BenchmarkUnpackEthUPv4UDP (line 235) | func BenchmarkUnpackEthUPv4UDP(bn *testing.B) {
  function TestUnpackAllEthIPv4UDP (line 245) | func TestUnpackAllEthIPv4UDP(t *testing.T) {
  function BenchmarkUnpackAllEthIPv4UDP (line 266) | func BenchmarkUnpackAllEthIPv4UDP(bn *testing.B) {
  function TestPackEthIPv4UDPRaw (line 282) | func TestPackEthIPv4UDPRaw(t *testing.T) {
  function TestUnpackEthUPv4UDPRaw (line 316) | func TestUnpackEthUPv4UDPRaw(t *testing.T) {
  function BenchmarkUnpackEthUPv4UDPRaw (line 329) | func BenchmarkUnpackEthUPv4UDPRaw(bn *testing.B) {
  function TestUnpackAllEthIPv4UDPRaw (line 341) | func TestUnpackAllEthIPv4UDPRaw(t *testing.T) {
  function BenchmarkUnpackAllEthIPv4UDPRaw (line 367) | func BenchmarkUnpackAllEthIPv4UDPRaw(bn *testing.B) {
  function TestPackEthIPv4TCP (line 381) | func TestPackEthIPv4TCP(t *testing.T) {
  function TestUnpackEthUPv4TCP (line 406) | func TestUnpackEthUPv4TCP(t *testing.T) {
  function BenchmarkUnpackEthUPv4TCP (line 417) | func BenchmarkUnpackEthUPv4TCP(bn *testing.B) {
  function TestUnpackAllEthIPv4TCP (line 427) | func TestUnpackAllEthIPv4TCP(t *testing.T) {
  function BenchmarkUnpackAllEthIPv4TCP (line 448) | func BenchmarkUnpackAllEthIPv4TCP(bn *testing.B) {
  function TestPackEthIPv4TCPRaw (line 465) | func TestPackEthIPv4TCPRaw(t *testing.T) {
  function TestUnpackEthUPv4TCPRaw (line 501) | func TestUnpackEthUPv4TCPRaw(t *testing.T) {
  function BenchmarkUnpackEthUPv4TCPRaw (line 514) | func BenchmarkUnpackEthUPv4TCPRaw(bn *testing.B) {
  function TestUnpackAllEthIPv4TCPRaw (line 526) | func TestUnpackAllEthIPv4TCPRaw(t *testing.T) {
  function BenchmarkUnpackAllEthIPv4TCPRaw (line 552) | func BenchmarkUnpackAllEthIPv4TCPRaw(bn *testing.B) {
  function TestFindLayer (line 558) | func TestFindLayer(t *testing.T) {
  function ExamplePack (line 580) | func ExamplePack() {
  function ExampleUnpack (line 602) | func ExampleUnpack() {

FILE: network/network.go
  function Send (line 50) | func Send(c capture.Handle, pkts ...packet.Packet) error {
  function Recv (line 71) | func Recv(c capture.Handle) (packet.Packet, error) {
  function SendRecv (line 88) | func SendRecv(c capture.Handle, t time.Duration, pkts ...packet.Packet) ...
  function NextHopMAC (line 121) | func NextHopMAC(c capture.Handle, t time.Duration, r *routing.Route, add...

FILE: packet/arp/pkt.go
  type Packet (line 39) | type Packet struct
    method GetType (line 72) | func (p *Packet) GetType() packet.Type {
    method GetLength (line 76) | func (p *Packet) GetLength() uint16 {
    method Equals (line 80) | func (p *Packet) Equals(other packet.Packet) bool {
    method Answers (line 84) | func (p *Packet) Answers(other packet.Packet) bool {
    method Pack (line 97) | func (p *Packet) Pack(buf *packet.Buffer) error {
    method Unpack (line 115) | func (p *Packet) Unpack(buf *packet.Buffer) error {
    method Payload (line 133) | func (p *Packet) Payload() packet.Packet {
    method GuessPayloadType (line 137) | func (p *Packet) GuessPayloadType() packet.Type {
    method SetPayload (line 141) | func (p *Packet) SetPayload(pl packet.Packet) error {
    method InitChecksum (line 145) | func (p *Packet) InitChecksum(csum uint32) {
    method String (line 148) | func (p *Packet) String() string {
  type Operation (line 53) | type Operation
    method String (line 152) | func (o Operation) String() string {
  constant Request (line 56) | Request Operation = 1
  constant Reply (line 57) | Reply             = 2
  function Make (line 60) | func Make() *Packet {

FILE: packet/arp/pkt_test.go
  function MakeTestSimple (line 52) | func MakeTestSimple() *arp.Packet {
  function TestPack (line 73) | func TestPack(t *testing.T) {
  function BenchmarkPack (line 89) | func BenchmarkPack(bn *testing.B) {
  function TestUnpack (line 100) | func TestUnpack(t *testing.T) {
  function BenchmarkUnpack (line 118) | func BenchmarkUnpack(bn *testing.B) {

FILE: packet/buffer.go
  type Buffer (line 41) | type Buffer struct
    method Init (line 48) | func (b *Buffer) Init(buf []byte) {
    method Bytes (line 55) | func (b *Buffer) Bytes() []byte {
    method Buffer (line 60) | func (b *Buffer) Buffer() []byte {
    method Len (line 65) | func (b *Buffer) Len() int {
    method SetOffset (line 70) | func (b *Buffer) SetOffset(off int) {
    method NewLayer (line 75) | func (b *Buffer) NewLayer() {
    method LayerBytes (line 80) | func (b *Buffer) LayerBytes() []byte {
    method LayerLen (line 85) | func (b *Buffer) LayerLen() int {
    method Write (line 90) | func (b *Buffer) Write(p []byte) (n int, err error) {
    method WriteN (line 97) | func (b *Buffer) WriteN(data interface{}) error {
    method WriteL (line 102) | func (b *Buffer) WriteL(data interface{}) error {
    method PutUint16N (line 108) | func (b *Buffer) PutUint16N(off int, data uint16) {
    method Read (line 113) | func (b *Buffer) Read(p []byte) (n int, err error) {
    method ReadN (line 120) | func (p *Buffer) ReadN(data interface{}) error {
    method ReadL (line 125) | func (p *Buffer) ReadL(data interface{}) error {
    method ReadLAligned (line 130) | func (p *Buffer) ReadLAligned(data interface{}, width uintptr) error {
    method Next (line 138) | func (b *Buffer) Next(n int) []byte {

FILE: packet/eth/pkt.go
  type Packet (line 40) | type Packet struct
    method Equals (line 71) | func (p *Packet) Equals(other packet.Packet) bool {
    method Answers (line 75) | func (p *Packet) Answers(other packet.Packet) bool {
    method GetType (line 91) | func (p *Packet) GetType() packet.Type {
    method GetLength (line 95) | func (p *Packet) GetLength() uint16 {
    method Pack (line 103) | func (p *Packet) Pack(buf *packet.Buffer) error {
    method Unpack (line 116) | func (p *Packet) Unpack(buf *packet.Buffer) error {
    method Payload (line 130) | func (p *Packet) Payload() packet.Packet {
    method GuessPayloadType (line 134) | func (p *Packet) GuessPayloadType() packet.Type {
    method SetPayload (line 138) | func (p *Packet) SetPayload(pl packet.Packet) error {
    method InitChecksum (line 149) | func (p *Packet) InitChecksum(csum uint32) {
    method String (line 152) | func (p *Packet) String() string {
  type EtherType (line 48) | type EtherType
    method String (line 196) | func (t EtherType) String() string {
  constant None (line 51) | None EtherType = 0x0000
  constant ARP (line 52) | ARP            = 0x0806
  constant IPv4 (line 53) | IPv4           = 0x0800
  constant IPv6 (line 54) | IPv6           = 0x86dd
  constant LLC (line 55) | LLC            = 0x0001
  constant LLDP (line 56) | LLDP           = 0x088cc
  constant QinQ (line 57) | QinQ           = 0x88a8
  constant TRILL (line 58) | TRILL          = 0x22f3
  constant VLAN (line 59) | VLAN           = 0x8100
  constant WoL (line 60) | WoL            = 0x0842
  function Make (line 63) | func Make() *Packet {
  function EtherTypeToType (line 170) | func EtherTypeToType(ethertype EtherType) packet.Type {
  function TypeToEtherType (line 181) | func TypeToEtherType(pkttype packet.Type) EtherType {

FILE: packet/eth/pkt_test.go
  function MakeTestSimple (line 48) | func MakeTestSimple() *eth.Packet {
  function TestPack (line 59) | func TestPack(t *testing.T) {
  function BenchmarkPack (line 75) | func BenchmarkPack(bn *testing.B) {
  function TestUnpack (line 86) | func TestUnpack(t *testing.T) {
  function BenchmarkUnpack (line 104) | func BenchmarkUnpack(bn *testing.B) {

FILE: packet/icmpv4/pkt.go
  type Packet (line 39) | type Packet struct
    method GetType (line 79) | func (p *Packet) GetType() packet.Type {
    method GetLength (line 83) | func (p *Packet) GetLength() uint16 {
    method Equals (line 91) | func (p *Packet) Equals(other packet.Packet) bool {
    method Answers (line 95) | func (p *Packet) Answers(other packet.Packet) bool {
    method Pack (line 111) | func (p *Packet) Pack(buf *packet.Buffer) error {
    method Unpack (line 124) | func (p *Packet) Unpack(buf *packet.Buffer) error {
    method Payload (line 136) | func (p *Packet) Payload() packet.Packet {
    method GuessPayloadType (line 140) | func (p *Packet) GuessPayloadType() packet.Type {
    method SetPayload (line 149) | func (p *Packet) SetPayload(pl packet.Packet) error {
    method InitChecksum (line 158) | func (p *Packet) InitChecksum(csum uint32) {
    method String (line 161) | func (p *Packet) String() string {
  type Type (line 48) | type Type
    method String (line 165) | func (t Type) String() string {
  type Code (line 49) | type Code
    method String (line 186) | func (c Code) String() string {
  constant EchoReply (line 52) | EchoReply Type = iota
  constant Reserved1 (line 53) | Reserved1
  constant Reserved2 (line 54) | Reserved2
  constant DstUnreachable (line 55) | DstUnreachable
  constant SrcQuench (line 56) | SrcQuench
  constant RedirectMsg (line 57) | RedirectMsg
  constant Reserved3 (line 58) | Reserved3
  constant Reserved4 (line 59) | Reserved4
  constant EchoRequest (line 60) | EchoRequest
  constant RouterAdv (line 61) | RouterAdv
  constant RouterSol (line 62) | RouterSol
  constant TimeExceeded (line 63) | TimeExceeded
  constant ParamProblem (line 64) | ParamProblem
  constant Timestamp (line 65) | Timestamp
  constant TimestampReply (line 66) | TimestampReply
  constant InfoRequest (line 67) | InfoRequest
  constant InfoReply (line 68) | InfoReply
  constant AddrMaskRequest (line 69) | AddrMaskRequest
  constant AddrMaskReply (line 70) | AddrMaskReply
  function Make (line 73) | func Make() *Packet {

FILE: packet/icmpv4/pkt_test.go
  function MakeTestSimple (line 43) | func MakeTestSimple() *icmpv4.Packet {
  function TestPack (line 52) | func TestPack(t *testing.T) {
  function BenchmarkPack (line 68) | func BenchmarkPack(bn *testing.B) {
  function TestUnpack (line 79) | func TestUnpack(t *testing.T) {
  function BenchmarkUnpack (line 98) | func BenchmarkUnpack(bn *testing.B) {

FILE: packet/icmpv6/pkt.go
  type Packet (line 39) | type Packet struct
    method GetType (line 70) | func (p *Packet) GetType() packet.Type {
    method GetLength (line 74) | func (p *Packet) GetLength() uint16 {
    method Equals (line 82) | func (p *Packet) Equals(other packet.Packet) bool {
    method Answers (line 86) | func (p *Packet) Answers(other packet.Packet) bool {
    method Pack (line 98) | func (p *Packet) Pack(buf *packet.Buffer) error {
    method Unpack (line 112) | func (p *Packet) Unpack(buf *packet.Buffer) error {
    method Payload (line 123) | func (p *Packet) Payload() packet.Packet {
    method GuessPayloadType (line 127) | func (p *Packet) GuessPayloadType() packet.Type {
    method SetPayload (line 136) | func (p *Packet) SetPayload(pl packet.Packet) error {
    method InitChecksum (line 145) | func (p *Packet) InitChecksum(csum uint32) {
    method String (line 149) | func (p *Packet) String() string {
  type Type (line 48) | type Type
    method String (line 153) | func (t Type) String() string {
  type Code (line 49) | type Code
    method String (line 165) | func (c Code) String() string {
  constant DstUnreachable (line 52) | DstUnreachable Type = 1
  constant PacketTooBig (line 53) | PacketTooBig        = 2
  constant TimeExceeded (line 54) | TimeExceeded        = 3
  constant ParamProblem (line 55) | ParamProblem        = 4
  constant Private1 (line 56) | Private1            = 100
  constant Private2 (line 57) | Private2            = 101
  constant Reserved1 (line 58) | Reserved1           = 127
  constant EchoRequest (line 59) | EchoRequest         = 128
  constant EchoReply (line 60) | EchoReply           = 129
  function Make (line 64) | func Make() *Packet {

FILE: packet/icmpv6/pkt_test.go
  function MakeTestSimple (line 45) | func MakeTestSimple() *icmpv6.Packet {
  function TestPack (line 51) | func TestPack(t *testing.T) {
  function BenchmarkPack (line 67) | func BenchmarkPack(bn *testing.B) {
  function TestUnpack (line 78) | func TestUnpack(t *testing.T) {
  function BenchmarkUnpack (line 96) | func BenchmarkUnpack(bn *testing.B) {
  function TestPackWithIPv6 (line 113) | func TestPackWithIPv6(t *testing.T) {
  function TestUnpackWithIPv6 (line 135) | func TestUnpackWithIPv6(t *testing.T) {

FILE: packet/ipv4/pkt.go
  type Packet (line 40) | type Packet struct
    method GetType (line 94) | func (p *Packet) GetType() packet.Type {
    method GetLength (line 98) | func (p *Packet) GetLength() uint16 {
    method Equals (line 106) | func (p *Packet) Equals(other packet.Packet) bool {
    method Answers (line 110) | func (p *Packet) Answers(other packet.Packet) bool {
    method Pack (line 133) | func (p *Packet) Pack(buf *packet.Buffer) error {
    method checksum (line 151) | func (p *Packet) checksum(raw_bytes []byte) {
    method pseudo_checksum (line 162) | func (p *Packet) pseudo_checksum() uint32 {
    method Unpack (line 175) | func (p *Packet) Unpack(buf *packet.Buffer) error {
    method Payload (line 205) | func (p *Packet) Payload() packet.Packet {
    method GuessPayloadType (line 209) | func (p *Packet) GuessPayloadType() packet.Type {
    method SetPayload (line 213) | func (p *Packet) SetPayload(pl packet.Packet) error {
    method InitChecksum (line 223) | func (p *Packet) InitChecksum(csum uint32) {
    method String (line 226) | func (p *Packet) String() string {
  type Flags (line 56) | type Flags
    method String (line 230) | func (f Flags) String() string {
  constant Evil (line 59) | Evil     Flags = 1 << 2
  constant DontFragment (line 60) | DontFragment   = 1 << 1
  constant MoreFragments (line 61) | MoreFragments  = 1 << 0
  type Protocol (line 64) | type Protocol
    method String (line 301) | func (p Protocol) String() string {
  constant None (line 67) | None Protocol = 0x00
  constant GRE (line 68) | GRE           = 0x2F
  constant ICMPv4 (line 69) | ICMPv4        = 0x01
  constant ICMPv6 (line 70) | ICMPv6        = 0x3A
  constant IGMP (line 71) | IGMP          = 0x02
  constant IPSecAH (line 72) | IPSecAH       = 0x33
  constant IPSecESP (line 73) | IPSecESP      = 0x32
  constant IPv6 (line 74) | IPv6          = 0x29
  constant ISIS (line 75) | ISIS          = 0x7C
  constant L2TP (line 76) | L2TP          = 0x73
  constant OSPF (line 77) | OSPF          = 0x59
  constant SCTP (line 78) | SCTP          = 0x84
  constant TCP (line 79) | TCP           = 0x06
  constant UDP (line 80) | UDP           = 0x11
  constant UDPLite (line 81) | UDPLite       = 0x88
  function Make (line 84) | func Make() *Packet {
  function CalculateChecksum (line 248) | func CalculateChecksum(raw_bytes []byte, csum uint32) uint16 {
  function ProtocolToType (line 280) | func ProtocolToType(proto Protocol) packet.Type {
  function TypeToProtocol (line 291) | func TypeToProtocol(pkttype packet.Type) Protocol {

FILE: packet/ipv4/pkt_test.go
  function MakeTestSimple (line 48) | func MakeTestSimple() *ipv4.Packet {
  function TestPack (line 63) | func TestPack(t *testing.T) {
  function BenchmarkPack (line 79) | func BenchmarkPack(bn *testing.B) {
  function TestUnpack (line 90) | func TestUnpack(t *testing.T) {
  function BenchmarkUnpack (line 109) | func BenchmarkUnpack(bn *testing.B) {

FILE: packet/ipv6/pkt.go
  type Packet (line 40) | type Packet struct
    method GetType (line 61) | func (p *Packet) GetType() packet.Type {
    method GetLength (line 65) | func (p *Packet) GetLength() uint16 {
    method Equals (line 73) | func (p *Packet) Equals(other packet.Packet) bool {
    method Answers (line 77) | func (p *Packet) Answers(other packet.Packet) bool {
    method Pack (line 96) | func (p *Packet) Pack(buf *packet.Buffer) error {
    method pseudo_checksum (line 111) | func (p *Packet) pseudo_checksum() uint32 {
    method Unpack (line 127) | func (p *Packet) Unpack(buf *packet.Buffer) error {
    method Payload (line 153) | func (p *Packet) Payload() packet.Packet {
    method GuessPayloadType (line 157) | func (p *Packet) GuessPayloadType() packet.Type {
    method SetPayload (line 161) | func (p *Packet) SetPayload(pl packet.Packet) error {
    method InitChecksum (line 171) | func (p *Packet) InitChecksum(csum uint32) {
    method String (line 174) | func (p *Packet) String() string {
  type Flags (line 52) | type Flags
  function Make (line 54) | func Make() *Packet {

FILE: packet/ipv6/pkt_test.go
  function MakeTestSimple (line 51) | func MakeTestSimple() *ipv6.Packet {
  function TestPack (line 64) | func TestPack(t *testing.T) {
  function BenchmarkPack (line 80) | func BenchmarkPack(bn *testing.B) {
  function TestUnpack (line 91) | func TestUnpack(t *testing.T) {
  function BenchmarkUnpack (line 109) | func BenchmarkUnpack(bn *testing.B) {

FILE: packet/llc/pkt.go
  type Packet (line 36) | type Packet struct
    method GetType (line 48) | func (p *Packet) GetType() packet.Type {
    method GetLength (line 52) | func (p *Packet) GetLength() uint16 {
    method Equals (line 60) | func (p *Packet) Equals(other packet.Packet) bool {
    method Answers (line 64) | func (p *Packet) Answers(other packet.Packet) bool {
    method Pack (line 68) | func (p *Packet) Pack(buf *packet.Buffer) error {
    method Unpack (line 81) | func (p *Packet) Unpack(buf *packet.Buffer) error {
    method Payload (line 97) | func (p *Packet) Payload() packet.Packet {
    method GuessPayloadType (line 101) | func (p *Packet) GuessPayloadType() packet.Type {
    method SetPayload (line 109) | func (p *Packet) SetPayload(pl packet.Packet) error {
    method InitChecksum (line 115) | func (p *Packet) InitChecksum(csum uint32) {
    method String (line 118) | func (p *Packet) String() string {
  function Make (line 44) | func Make() *Packet {

FILE: packet/llc/pkt_test.go
  function MakeTestSimple (line 43) | func MakeTestSimple() *llc.Packet {
  function TestPack (line 51) | func TestPack(t *testing.T) {
  function BenchmarkPack (line 67) | func BenchmarkPack(bn *testing.B) {
  function TestUnpack (line 78) | func TestUnpack(t *testing.T) {
  function BenchmarkUnpack (line 96) | func BenchmarkUnpack(bn *testing.B) {

FILE: packet/packet.go
  type Type (line 42) | type Type
    method ToLinkType (line 131) | func (pkttype Type) ToLinkType() uint32 {
    method String (line 141) | func (t Type) String() string {
  constant None (line 45) | None Type = iota
  constant ARP (line 46) | ARP
  constant Bluetooth (line 47) | Bluetooth
  constant Eth (line 48) | Eth
  constant GRE (line 49) | GRE
  constant ICMPv4 (line 50) | ICMPv4
  constant ICMPv6 (line 51) | ICMPv6
  constant IGMP (line 52) | IGMP
  constant IPSec (line 53) | IPSec
  constant IPv4 (line 54) | IPv4
  constant IPv6 (line 55) | IPv6
  constant ISIS (line 56) | ISIS
  constant L2TP (line 57) | L2TP
  constant LLC (line 58) | LLC
  constant LLDP (line 59) | LLDP
  constant OSPF (line 60) | OSPF
  constant RadioTap (line 61) | RadioTap
  constant Raw (line 62) | Raw
  constant SCTP (line 63) | SCTP
  constant SLL (line 64) | SLL
  constant SNAP (line 65) | SNAP
  constant TCP (line 66) | TCP
  constant TRILL (line 67) | TRILL
  constant UDP (line 68) | UDP
  constant UDPLite (line 69) | UDPLite
  constant VLAN (line 70) | VLAN
  constant WiFi (line 71) | WiFi
  constant WoL (line 72) | WoL
  type Packet (line 77) | type Packet interface
  function LinkType (line 120) | func LinkType(link_type uint32) Type {
  function Compare (line 175) | func Compare(a, b Packet) bool {
  function compare_value (line 203) | func compare_value(a, b reflect.Value) bool {
  function Stringify (line 259) | func Stringify(p Packet) string {
  function stringify_value (line 293) | func stringify_value(key string, val reflect.Value) string {

FILE: packet/radiotap/pkt.go
  type Packet (line 38) | type Packet struct
    method GetType (line 71) | func (p *Packet) GetType() packet.Type {
    method GetLength (line 75) | func (p *Packet) GetLength() uint16 {
    method Equals (line 83) | func (p *Packet) Equals(other packet.Packet) bool {
    method Answers (line 87) | func (p *Packet) Answers(other packet.Packet) bool {
    method Pack (line 91) | func (p *Packet) Pack(buf *packet.Buffer) error {
    method Unpack (line 103) | func (p *Packet) Unpack(buf *packet.Buffer) error {
    method Payload (line 118) | func (p *Packet) Payload() packet.Packet {
    method GuessPayloadType (line 122) | func (p *Packet) GuessPayloadType() packet.Type {
    method SetPayload (line 126) | func (p *Packet) SetPayload(pl packet.Packet) error {
    method InitChecksum (line 133) | func (p *Packet) InitChecksum(csum uint32) {
    method String (line 136) | func (p *Packet) String() string {
  type Present (line 46) | type Present
    method String (line 140) | func (p Present) String() string {
  constant TSFT (line 49) | TSFT Present = 1 << iota
  constant Flags (line 50) | Flags
  constant Rate (line 51) | Rate
  constant Channel (line 52) | Channel
  constant FHSS (line 53) | FHSS
  constant DbmAntSignal (line 54) | DbmAntSignal
  constant DbmAntNoise (line 55) | DbmAntNoise
  constant LockQuality (line 56) | LockQuality
  constant TXAttenuation (line 57) | TXAttenuation
  constant DbTXAttenuation (line 58) | DbTXAttenuation
  constant DbmTXPower (line 59) | DbmTXPower
  constant Antenna (line 60) | Antenna
  constant DbAntSignal (line 61) | DbAntSignal
  constant DbAntNoise (line 62) | DbAntNoise
  constant EXT (line 63) | EXT
  function Make (line 66) | func Make() *Packet {

FILE: packet/radiotap/pkt_test.go
  function MakeTestSimple (line 45) | func MakeTestSimple() *radiotap.Packet {
  function TestPack (line 57) | func TestPack(t *testing.T) {
  function BenchmarkPack (line 73) | func BenchmarkPack(bn *testing.B) {
  function TestUnpack (line 84) | func TestUnpack(t *testing.T) {
  function BenchmarkUnpack (line 102) | func BenchmarkUnpack(bn *testing.B) {

FILE: packet/raw/pkt.go
  type Packet (line 38) | type Packet struct
    method GetType (line 46) | func (p *Packet) GetType() packet.Type {
    method GetLength (line 50) | func (p *Packet) GetLength() uint16 {
    method Equals (line 54) | func (p *Packet) Equals(other packet.Packet) bool {
    method Answers (line 58) | func (p *Packet) Answers(other packet.Packet) bool {
    method Pack (line 62) | func (p *Packet) Pack(buf *packet.Buffer) error {
    method Unpack (line 68) | func (p *Packet) Unpack(buf *packet.Buffer) error {
    method Payload (line 74) | func (p *Packet) Payload() packet.Packet {
    method GuessPayloadType (line 78) | func (p *Packet) GuessPayloadType() packet.Type {
    method SetPayload (line 82) | func (p *Packet) SetPayload(pl packet.Packet) error {
    method InitChecksum (line 86) | func (p *Packet) InitChecksum(csum uint32) {
    method String (line 89) | func (p *Packet) String() string {
  function Make (line 42) | func Make() *Packet {

FILE: packet/raw/pkt_test.go
  function MakeTestSimple (line 44) | func MakeTestSimple() *raw.Packet {
  function TestPack (line 50) | func TestPack(t *testing.T) {
  function BenchmarkPack (line 66) | func BenchmarkPack(bn *testing.B) {
  function TestUnpack (line 77) | func TestUnpack(t *testing.T) {
  function BenchmarkUnpack (line 95) | func BenchmarkUnpack(bn *testing.B) {

FILE: packet/sll/pkt.go
  type Packet (line 39) | type Packet struct
    method GetType (line 66) | func (p *Packet) GetType() packet.Type {
    method GetLength (line 70) | func (p *Packet) GetLength() uint16 {
    method Equals (line 78) | func (p *Packet) Equals(other packet.Packet) bool {
    method Answers (line 82) | func (p *Packet) Answers(other packet.Packet) bool {
    method Pack (line 86) | func (p *Packet) Pack(buf *packet.Buffer) error {
    method Unpack (line 101) | func (p *Packet) Unpack(buf *packet.Buffer) error {
    method Payload (line 114) | func (p *Packet) Payload() packet.Packet {
    method GuessPayloadType (line 118) | func (p *Packet) GuessPayloadType() packet.Type {
    method SetPayload (line 122) | func (p *Packet) SetPayload(pl packet.Packet) error {
    method InitChecksum (line 129) | func (p *Packet) InitChecksum(csum uint32) {
    method String (line 132) | func (p *Packet) String() string {
  type Type (line 48) | type Type
    method String (line 136) | func (t Type) String() string {
  constant Host (line 51) | Host      Type = 0
  constant Broadcast (line 52) | Broadcast Type = 1
  constant Multicast (line 53) | Multicast Type = 2
  constant OtherHost (line 54) | OtherHost Type = 3
  constant Outgoing (line 55) | Outgoing  Type = 4
  function Make (line 58) | func Make() *Packet {

FILE: packet/sll/pkt_test.go
  function MakeTestSimple (line 48) | func MakeTestSimple() *sll.Packet {
  function TestPack (line 60) | func TestPack(t *testing.T) {
  function BenchmarkPack (line 76) | func BenchmarkPack(bn *testing.B) {
  function TestUnpack (line 87) | func TestUnpack(t *testing.T) {
  function BenchmarkUnpack (line 105) | func BenchmarkUnpack(bn *testing.B) {

FILE: packet/snap/pkt.go
  type Packet (line 37) | type Packet struct
    method GetType (line 48) | func (p *Packet) GetType() packet.Type {
    method GetLength (line 52) | func (p *Packet) GetLength() uint16 {
    method Equals (line 60) | func (p *Packet) Equals(other packet.Packet) bool {
    method Answers (line 64) | func (p *Packet) Answers(other packet.Packet) bool {
    method Pack (line 68) | func (p *Packet) Pack(buf *packet.Buffer) error {
    method Unpack (line 75) | func (p *Packet) Unpack(buf *packet.Buffer) error {
    method Payload (line 82) | func (p *Packet) Payload() packet.Packet {
    method GuessPayloadType (line 86) | func (p *Packet) GuessPayloadType() packet.Type {
    method SetPayload (line 94) | func (p *Packet) SetPayload(pl packet.Packet) error {
    method InitChecksum (line 101) | func (p *Packet) InitChecksum(csum uint32) {
    method String (line 104) | func (p *Packet) String() string {
  function Make (line 44) | func Make() *Packet {

FILE: packet/snap/pkt_test.go
  function MakeTestSimple (line 44) | func MakeTestSimple() *snap.Packet {
  function TestPack (line 50) | func TestPack(t *testing.T) {
  function BenchmarkPack (line 66) | func BenchmarkPack(bn *testing.B) {
  function TestUnpack (line 77) | func TestUnpack(t *testing.T) {
  function BenchmarkUnpack (line 95) | func BenchmarkUnpack(bn *testing.B) {

FILE: packet/tcp/pkt.go
  type Packet (line 39) | type Packet struct
    method GetType (line 94) | func (p *Packet) GetType() packet.Type {
    method GetLength (line 98) | func (p *Packet) GetLength() uint16 {
    method Equals (line 106) | func (p *Packet) Equals(other packet.Packet) bool {
    method Answers (line 110) | func (p *Packet) Answers(other packet.Packet) bool {
    method Pack (line 123) | func (p *Packet) Pack(buf *packet.Buffer) error {
    method Unpack (line 194) | func (p *Packet) Unpack(buf *packet.Buffer) error {
    method Payload (line 278) | func (p *Packet) Payload() packet.Packet {
    method GuessPayloadType (line 282) | func (p *Packet) GuessPayloadType() packet.Type {
    method SetPayload (line 286) | func (p *Packet) SetPayload(pl packet.Packet) error {
    method InitChecksum (line 292) | func (p *Packet) InitChecksum(csum uint32) {
    method String (line 296) | func (p *Packet) String() string {
  type Flags (line 54) | type Flags
    method String (line 300) | func (f Flags) String() string {
  constant Syn (line 57) | Syn Flags = 1<<1
  constant Fin (line 58) | Fin       = 1<<2
  constant Rst (line 59) | Rst       = 1<<3
  constant PSH (line 60) | PSH       = 1<<4
  constant Ack (line 61) | Ack       = 1<<5
  constant Urg (line 62) | Urg       = 1<<6
  constant ECE (line 63) | ECE       = 1<<7
  constant Cwr (line 64) | Cwr       = 1<<8
  constant NS (line 65) | NS        = 1<<9
  type Option (line 68) | type Option struct
  type OptType (line 74) | type OptType
  constant End (line 77) | End OptType = 0x00
  constant Nop (line 78) | Nop         = 0x01
  constant MSS (line 79) | MSS         = 0x02
  constant WindowScale (line 80) | WindowScale = 0x03
  constant SAckOk (line 81) | SAckOk      = 0x04
  constant SAck (line 82) | SAck        = 0x05
  constant Timestamp (line 83) | Timestamp   = 0x08
  function Make (line 86) | func Make() *Packet {

FILE: packet/tcp/pkt_test.go
  function MakeTestSimple (line 46) | func MakeTestSimple() *tcp.Packet {
  function TestPack (line 59) | func TestPack(t *testing.T) {
  function BenchmarkPack (line 75) | func BenchmarkPack(bn *testing.B) {
  function TestUnpack (line 86) | func TestUnpack(t *testing.T) {
  function BenchmarkUnpack (line 104) | func BenchmarkUnpack(bn *testing.B) {
  function TestPackWithIPv4 (line 122) | func TestPackWithIPv4(t *testing.T) {
  function TestUnpackWithIPv4 (line 144) | func TestUnpackWithIPv4(t *testing.T) {
  function TestPackOptions (line 170) | func TestPackOptions(t *testing.T) {
  function TestUnpackOptions (line 225) | func TestUnpackOptions(t *testing.T) {

FILE: packet/udp/pkt.go
  type Packet (line 37) | type Packet struct
    method GetType (line 52) | func (p *Packet) GetType() packet.Type {
    method GetLength (line 56) | func (p *Packet) GetLength() uint16 {
    method Equals (line 64) | func (p *Packet) Equals(other packet.Packet) bool {
    method Answers (line 68) | func (p *Packet) Answers(other packet.Packet) bool {
    method Pack (line 81) | func (p *Packet) Pack(buf *packet.Buffer) error {
    method Unpack (line 96) | func (p *Packet) Unpack(buf *packet.Buffer) error {
    method Payload (line 105) | func (p *Packet) Payload() packet.Packet {
    method GuessPayloadType (line 109) | func (p *Packet) GuessPayloadType() packet.Type {
    method SetPayload (line 113) | func (p *Packet) SetPayload(pl packet.Packet) error {
    method InitChecksum (line 120) | func (p *Packet) InitChecksum(csum uint32) {
    method String (line 124) | func (p *Packet) String() string {
  function Make (line 46) | func Make() *Packet {

FILE: packet/udp/pkt_test.go
  function MakeTestSimple (line 45) | func MakeTestSimple() *udp.Packet {
  function TestPack (line 53) | func TestPack(t *testing.T) {
  function BenchmarkPack (line 69) | func BenchmarkPack(bn *testing.B) {
  function TestUnpack (line 80) | func TestUnpack(t *testing.T) {
  function BenchmarkUnpack (line 98) | func BenchmarkUnpack(bn *testing.B) {
  function TestPackWithIPv4 (line 115) | func TestPackWithIPv4(t *testing.T) {
  function TestUnpackWithIPv4 (line 141) | func TestUnpackWithIPv4(t *testing.T) {

FILE: packet/vlan/pkt.go
  type Packet (line 37) | type Packet struct
    method GetType (line 49) | func (p *Packet) GetType() packet.Type {
    method GetLength (line 53) | func (p *Packet) GetLength() uint16 {
    method Equals (line 61) | func (p *Packet) Equals(other packet.Packet) bool {
    method Answers (line 65) | func (p *Packet) Answers(other packet.Packet) bool {
    method Pack (line 82) | func (p *Packet) Pack(buf *packet.Buffer) error {
    method Unpack (line 94) | func (p *Packet) Unpack(buf *packet.Buffer) error {
    method Payload (line 107) | func (p *Packet) Payload() packet.Packet {
    method GuessPayloadType (line 111) | func (p *Packet) GuessPayloadType() packet.Type {
    method SetPayload (line 115) | func (p *Packet) SetPayload(pl packet.Packet) error {
    method InitChecksum (line 122) | func (p *Packet) InitChecksum(csum uint32) {
    method String (line 125) | func (p *Packet) String() string {
  function Make (line 45) | func Make() *Packet {

FILE: packet/vlan/pkt_test.go
  function MakeTestSimple (line 44) | func MakeTestSimple() *vlan.Packet {
  function TestPack (line 52) | func TestPack(t *testing.T) {
  function BenchmarkPack (line 68) | func BenchmarkPack(bn *testing.B) {
  function TestUnpack (line 79) | func TestUnpack(t *testing.T) {
  function BenchmarkUnpack (line 97) | func BenchmarkUnpack(bn *testing.B) {

FILE: routing/routing.go
  type Route (line 41) | type Route struct
    method GetIfaceIPv4Addr (line 109) | func (r *Route) GetIfaceIPv4Addr() (net.IP, error) {
    method GetIfaceIPv6Addr (line 129) | func (r *Route) GetIfaceIPv6Addr() (net.IP, error) {
    method String (line 148) | func (r *Route) String() string {
  type route_slice (line 49) | type route_slice
    method Len (line 51) | func (r route_slice) Len() int {
    method Swap (line 55) | func (r route_slice) Swap(i, j int) {
    method Less (line 59) | func (r route_slice) Less(i, j int) bool {
  function RouteTo (line 81) | func RouteTo(dst net.IP) (*Route, error) {

FILE: routing/routing_linux.go
  type rtmsg (line 38) | type rtmsg struct
  function Routes (line 51) | func Routes() ([]*Route, error) {
Condensed preview — 63 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (284K chars).
[
  {
    "path": ".travis.yml",
    "chars": 167,
    "preview": "language: go\n\nsudo: false\n\naddons:\n apt:\n   packages:\n    - libpcap0.8-dev\n\ngo:\n - \"1.11\"\n - \"tip\"\n\nenv:\n - GO111MODULE="
  },
  {
    "path": "COPYING",
    "chars": 1327,
    "preview": "Copyright (c) 2014, Alessandro Ghedini <alessandro@ghedini.me>\nAll rights reserved.\n\nRedistribution and use in source an"
  },
  {
    "path": "README.md",
    "chars": 6175,
    "preview": "go.pkt\n======\n\n![Travis CI](https://secure.travis-ci.org/ghedo/go.pkt.png)\n\n**go.pkt** provides Go libraries for capturi"
  },
  {
    "path": "capture/capture.go",
    "chars": 1986,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "capture/file/capture.go",
    "chars": 6948,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "capture/file/capture_test.go",
    "chars": 4490,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "capture/pcap/capture.go",
    "chars": 5699,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "capture/pcap/capture_test.go",
    "chars": 2401,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "examples/arp/main.go",
    "chars": 3054,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "examples/bpf_asm/Makefile",
    "chars": 164,
    "preview": "all: bpf_asm\n\nbpf_asm: bpf_asm.nn.go y.go\n\tgo build -o bpf_asm bpf_asm.nn.go y.go\n\ny.go: bpf_asm.y\n\tgo tool yacc bpf_asm"
  },
  {
    "path": "examples/bpf_asm/bpf_asm.l",
    "chars": 2731,
    "preview": "/ldb/\t{ return OP_LDB }\n/ldh/\t{ return OP_LDH }\n/ld/\t{ return OP_LD }\n/ldi/\t{ return OP_LDI }\n/ldx/\t{ return OP_LDX }\n/l"
  },
  {
    "path": "examples/bpf_asm/bpf_asm.y",
    "chars": 7204,
    "preview": "%{\npackage main\n\nimport \"github.com/ghedo/go.pkt/filter\"\n%}\n\n%union {\n\tlabel  string\n\tnumber uint32\n}\n\n%token OP_LDB\n%to"
  },
  {
    "path": "examples/dump/main.go",
    "chars": 4166,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "examples/ping/main.go",
    "chars": 3118,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "examples/route/main.go",
    "chars": 2506,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "examples/syn_scan/main.go",
    "chars": 3693,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "examples/tracereply/main.go",
    "chars": 3562,
    "preview": "package main\n\nimport \"log\"\nimport \"net\"\nimport \"strconv\"\n\nimport \"github.com/docopt/docopt-go\"\n\nimport \"github.com/songg"
  },
  {
    "path": "examples/traceroute/main.go",
    "chars": 4988,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "filter/bpf_builder.go",
    "chars": 11935,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "filter/bpf_builder_test.go",
    "chars": 5350,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "filter/bpf_filter.c",
    "chars": 9842,
    "preview": "/*-\n * Copyright (c) 1990, 1991, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * This c"
  },
  {
    "path": "filter/bpf_filter.go",
    "chars": 4666,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "filter/bpf_filter.h",
    "chars": 4319,
    "preview": "/*-\n * Copyright (c) 1990, 1991, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * This c"
  },
  {
    "path": "filter/bpf_filter_test.go",
    "chars": 5142,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "filter/pcap.go",
    "chars": 2291,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "go.mod",
    "chars": 169,
    "preview": "module github.com/ghedo/go.pkt\n\nrequire (\n\tgithub.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815\n\tgithub.com/so"
  },
  {
    "path": "go.sum",
    "chars": 452,
    "preview": "github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=\ngithub.co"
  },
  {
    "path": "layers/layers.go",
    "chars": 6873,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "layers/layers_test.go",
    "chars": 17974,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "network/network.go",
    "chars": 4646,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/arp/pkt.go",
    "chars": 4366,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/arp/pkt_test.go",
    "chars": 3450,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/buffer.go",
    "chars": 4656,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/eth/pkt.go",
    "chars": 5238,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/eth/pkt_test.go",
    "chars": 3017,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/icmpv4/pkt.go",
    "chars": 5178,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/icmpv4/pkt_test.go",
    "chars": 2863,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/icmpv6/pkt.go",
    "chars": 4441,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/icmpv6/pkt_test.go",
    "chars": 3852,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/ipv4/pkt.go",
    "chars": 8002,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/ipv4/pkt_test.go",
    "chars": 3165,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/ipv6/pkt.go",
    "chars": 4594,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/ipv6/pkt_test.go",
    "chars": 3317,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/llc/pkt.go",
    "chars": 3171,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/llc/pkt_test.go",
    "chars": 2773,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/packet.go",
    "chars": 8357,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/radiotap/pkt.go",
    "chars": 3495,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/radiotap/pkt_test.go",
    "chars": 3200,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/raw/pkt.go",
    "chars": 2515,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/raw/pkt_test.go",
    "chars": 2836,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/sll/pkt.go",
    "chars": 3808,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/sll/pkt_test.go",
    "chars": 3044,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/snap/pkt.go",
    "chars": 2916,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/snap/pkt_test.go",
    "chars": 2791,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/tcp/pkt.go",
    "chars": 7131,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/tcp/pkt_test.go",
    "chars": 6247,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/udp/pkt.go",
    "chars": 3434,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/udp/pkt_test.go",
    "chars": 3898,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/vlan/pkt.go",
    "chars": 3385,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "packet/vlan/pkt_test.go",
    "chars": 2834,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "routing/routing.go",
    "chars": 4414,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  },
  {
    "path": "routing/routing_linux.go",
    "chars": 3192,
    "preview": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redi"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the ghedo/go.pkt GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 63 files (261.3 KB), approximately 77.4k tokens, and a symbol index with 622 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!