[
  {
    "path": ".travis.yml",
    "content": "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=on\n\nscript:\n - go build ./...\n - go test ./...\n"
  },
  {
    "path": "COPYING",
    "content": "Copyright (c) 2014, Alessandro Ghedini <alessandro@ghedini.me>\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "go.pkt\n======\n\n![Travis CI](https://secure.travis-ci.org/ghedo/go.pkt.png)\n\n**go.pkt** provides Go libraries for capturing, injecting, filtering, encoding and\ndecoding network packets.\n\n* [capture][capture]: provides the basic interface for packet capturing and\n  injection. Different implementations (\"pcap\", \"file\", ...) are provided as\n  subpackages.\n\n* [filter][filter]: provides an API for compiling and manipulating BPF filters.\n  A filter can be either compiled from tcpdump-like expressions, or created from\n  basic BPF instructions. Filters can then be either applied to packet sources\n  (see the capture package) or directly run against binary data.\n\n* [packet][packet]: provides the interfaces for implementing packet encoders\n  and decoders. Every supported protocol implements the Packet interface as a\n  submodule of this package (e.g. packet/ipv4, packet/tcp, ...).\n\n* [layers][layers]: provides utility functions for encoding and decoding\n  packets to/from binary data. Differently from the basic \"packet\" interface,\n  this can encode and decode complete \"stacks\" of packets, instead of\n  manipulating single ones.\n\n* [network][network]: provides utility functions for sending and receiving\n  packets over the network. Basically, it hides some of the complexity of using\n  the capture and layers packages together.\n\n* [routing][routing]: provides network routing information about the system. It\n  can either return all available routes or select a specific route depending on\n  a destination address.\n\n[capture]: http://godoc.org/github.com/ghedo/go.pkt/capture\n[filter]: http://godoc.org/github.com/ghedo/go.pkt/filter\n[packet]: http://godoc.org/github.com/ghedo/go.pkt/packet\n[layers]: http://godoc.org/github.com/ghedo/go.pkt/layers\n[network]: http://godoc.org/github.com/ghedo/go.pkt/network\n[routing]: http://godoc.org/github.com/ghedo/go.pkt/routing\n\n## Getting Started\n\n### Capturing\n\nPacket capturing is done using a packet \"source\" such as a network interface or\na dump file.\n\nIn the following example we create a \"pcap\" capture handle using the `eth0`\nnetwork interface, we activate it and then capture packets using the `Capture()`\nmethod.\n\n```go\nsrc, err := pcap.Open(\"eth0\")\nif err != nil {\n\tlog.Fatal(err)\n}\ndefer src.Close()\n\n// you may configure the source further, e.g. by activating\n// promiscuous mode.\n\nerr = src.Activate()\nif err != nil {\n\tlog.Fatal(err)\n}\n\nfor {\n\tbuf, err := src.Capture()\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tlog.Println(\"PACKET!!!\")\n\n\t// do something with the packet\n}\n```\n\n### Injection\n\nSimilarly to packet capturing, packet injection requires a capture handle.\n\nIn the following example we create a capture handle like before and then use\nthe `Inject()` method to send some data (we'll see later how to encode data in\nthe propert formats).\n\n```go\ndst, err := pcap.Open(\"eth0\")\nif err != nil {\n\tlog.Fatal(err)\n}\ndefer dst.Close()\n\n// you may configure the source further, e.g. by activating\n// promiscuous mode.\n\nerr = dst.Activate()\nif err != nil {\n\tlog.Fatal(err)\n}\n\nerr = dst.Inject([]byte(\"random data\"))\nif err != nil {\n\tlog.Fatal(err)\n}\n```\n\n### Filtering\n\nPacket filtering is done by creating a filter (e.g. by compiling it from an\nexpression) which can be either applied to a capture handle (by using the\n`ApplyFilter()` method) or used directly against a data buffer.\n\nIn the following example we create a filter by compiling a tcpdump-like\nexpression and then try to match some data against it.\n\n```go\n// Match UDP or TCP packets on top of Ethernet\nflt, err := filter.Compile(\"udp or tcp\", packet.Eth)\nif err != nil {\n\tlog.Fatal(err)\n}\n\nif flt.Match([]byte(\"random data\")) {\n\tlog.Println(\"MATCH!!!\")\n}\n```\n\n### Encoding\n\nEncoding packets is done by using the functions provided by the `layers`\npackage.\n\nIn the following example we create an ARP packet on top of an Ethernet packet\nand we encode them to binary data by using the `Pack()` method. Note that you'll\nneed to import the packages of the protocols used (`packet/eth` and `packet/arp`).\n\n```go\n// Create an Ethernet packet\neth_pkt := eth.Make()\neth_pkt.SrcAddr, _ = net.ParseMAC(\"4c:72:b9:54:e5:3d\")\neth_pkt.DstAddr, _ = net.ParseMAC(\"ff:ff:ff:ff:ff:ff\")\n\n// Create an ARP packet\narp_pkt := arp.Make()\narp_pkt.HWSrcAddr, _ = net.ParseMAC(\"4c:72:b9:54:e5:3d\")\narp_pkt.HWDstAddr, _ = net.ParseMAC(\"00:00:00:00:00:00\")\narp_pkt.ProtoSrcAddr = net.ParseIP(\"192.168.1.135\")\narp_pkt.ProtoDstAddr = net.ParseIP(\"192.168.1.254\")\n\nbuf, err := layers.Pack(eth_pkt, arp_pkt)\nif err != nil {\n\tlog.Fatal(err)\n}\n\n// do something with the packet\nlog.Println(buf)\n```\n\n### Decoding\n\nLike encoding, decoding is done by using the functions provided by the `layers`\npackage.\n\nThe following example uses the `UnpackAll()` function to decode a whole chain of\npackets (e.g. ethernet -> ipv4 -> udp).\n\n```go\n// Create the buf data\nbuf := []byte(\"random data\")\n\n// Assume Ethernet as datalink layer\npkt, err := layers.UnpackAll(buf, packet.Eth)\nif err != nil {\n\tlog.Fatal(err)\n}\n\nlog.Println(pkt)\n```\n\n### Network\n\nInstead of using the layers and capture packages together, the network package\ncan be used instead.\n\nThe following example creates an ARP request packet and uses `SendRecv()` to\nsend it and receive a suitable answer.\n\n```go\nc, err := pcap.Open(\"eth0\")\nif err != nil {\n\tlog.Fatal(err)\n}\ndefer c.Close()\n\nerr = c.Activate()\nif err != nil {\n\tlog.Fatal(err)\n}\n\n// Create an Ethernet packet\neth_pkt := eth.Make()\neth_pkt.SrcAddr, _ = net.ParseMAC(\"4c:72:b9:54:e5:3d\")\neth_pkt.DstAddr, _ = net.ParseMAC(\"ff:ff:ff:ff:ff:ff\")\n\n// Create an ARP packet\narp_pkt := arp.Make()\narp_pkt.HWSrcAddr, _ = net.ParseMAC(\"4c:72:b9:54:e5:3d\")\narp_pkt.HWDstAddr, _ = net.ParseMAC(\"00:00:00:00:00:00\")\narp_pkt.ProtoSrcAddr = net.ParseIP(\"192.168.1.135\")\narp_pkt.ProtoDstAddr = net.ParseIP(\"192.168.1.254\")\n\nrsp_pkt, err := network.SendRecv(c, 0, eth_pkt, arp_pkt)\nif err != nil {\n\tlog.Fatal(err)\n}\n\nlog.Println(rsp_pkt)\n```\n\n### Routing\n\nTODO\n\nFor more examples have a look at the [examples](examples/) directory in the\nsource repository.\n\n## Dependencies\n\n * `libpcap`\n\n## Copyright\n\nCopyright (C) 2014 Alessandro Ghedini <alessandro@ghedini.me>\n\nSee COPYING for the license.\n"
  },
  {
    "path": "capture/capture.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides the basic interface for packet capturing and injection. Different\n// implementations (\"pcap\", \"file\", ...) are provided as subpackages.\npackage capture\n\nimport \"github.com/ghedo/go.pkt/filter\"\nimport \"github.com/ghedo/go.pkt/packet\"\n\ntype Handle interface {\n    LinkType() packet.Type\n\n    SetMTU(mtu int) error\n    SetPromiscMode(promisc bool) error\n    SetMonitorMode(monitor bool) error\n\n    ApplyFilter(filter *filter.Filter) error\n\n    Activate() error\n\n    Capture() ([]byte, error)\n    Inject(buf []byte) error\n\n    Close()\n}\n"
  },
  {
    "path": "capture/file/capture.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides native packet capturing and injection on pcap dump files without\n// requiring the libpcap library.\npackage file\n\nimport \"bytes\"\nimport \"encoding/binary\"\nimport \"fmt\"\nimport \"io\"\nimport \"os\"\n\nimport \"github.com/ghedo/go.pkt/filter\"\nimport \"github.com/ghedo/go.pkt/packet\"\n\ntype Handle struct {\n    File  string\n    file   *os.File\n    out    *os.File\n    order  binary.ByteOrder\n    link   uint32\n    mtu    uint32\n    filter *filter.Filter\n}\n\nvar BigEndian    = []byte{0xa1, 0xb2, 0xc3, 0xd4}\nvar LittleEndian = []byte{0xd4, 0xc3, 0xb2, 0xa1}\n\n// Create a new capture handle from the given dump file. This will either open\n// the file if it exists, or create a new one.\nfunc Open(file_name string) (*Handle, error) {\n    handle := &Handle{ File: file_name }\n\n    open := open_file\n\n    if _, err := os.Stat(file_name); os.IsNotExist(err) {\n        open = create_file\n    }\n\n    file, err := open(file_name)\n    if err != nil {\n        return nil, err\n    }\n\n    handle.file = file\n\n    handle.file.Seek(0, 0)\n\n    magic := make([]byte, 4)\n    file.Read(magic)\n\n    switch {\n    case bytes.Equal(magic, BigEndian):\n        handle.order = binary.BigEndian\n\n    case bytes.Equal(magic, LittleEndian):\n        handle.order = binary.LittleEndian\n\n    default:\n        handle.file.Close()\n        return nil, fmt.Errorf(\"Invalid file\")\n    }\n\n    var ver_maj, ver_min uint16\n    var discard, mtu, link_type uint32\n\n    binary.Read(file, handle.order, &ver_maj)\n    binary.Read(file, handle.order, &ver_min)\n    binary.Read(file, handle.order, &discard)\n    binary.Read(file, handle.order, &discard)\n    binary.Read(file, handle.order, &mtu)\n    binary.Read(file, handle.order, &link_type)\n\n    handle.link = link_type\n    handle.mtu  = mtu\n\n    /*\n     * Use a different file handle for injecting packages so that we don't\n     * need to seek back and forth for capturing and injecting\n     */\n    handle.out, _ = open_file(file_name)\n    handle.out.Seek(0, 2)\n\n    return handle, nil\n}\n\nfunc create_file(file_name string) (*os.File, error) {\n    file, err := os.Create(file_name)\n    if err != nil {\n        return nil, fmt.Errorf(\"Could not create file: %s\", err)\n    }\n\n    file.Write(BigEndian) /* endiannes */\n\n    binary.Write(file, binary.BigEndian, uint16(2)) /* ver major */\n    binary.Write(file, binary.BigEndian, uint16(4)) /* ver minor */\n    binary.Write(file, binary.BigEndian, uint32(0))\n    binary.Write(file, binary.BigEndian, uint32(0))\n    binary.Write(file, binary.BigEndian, uint32(0x7fff)) /* MTU */\n    binary.Write(file, binary.BigEndian, uint32(1)) /* link type */\n\n    return file, nil\n}\n\nfunc open_file(file_name string) (*os.File, error) {\n    file, err := os.OpenFile(file_name, os.O_RDWR, 0644);\n    if err != nil {\n        return nil, fmt.Errorf(\"Could not open file: %s\", err)\n    }\n\n    return file, nil\n}\n\n// Return the link type of the capture handle (that is, the type of packets that\n// come out of the packet source).\nfunc (h *Handle) LinkType() packet.Type {\n    return packet.LinkType(h.link)\n}\n\n// Not supported.\nfunc (h *Handle) SetMTU(mtu int) error {\n    return fmt.Errorf(\"Unsupported\")\n}\n\n// Not supported.\nfunc (h *Handle) SetPromiscMode(promisc bool) error {\n    return fmt.Errorf(\"Unsupported\")\n}\n\n// Not supported.\nfunc (h *Handle) SetMonitorMode(monitor bool) error {\n    return fmt.Errorf(\"Unsupported\")\n}\n\n// Apply the given filter it to the packet source. Only packets that match this\n// filter will be captured.\nfunc (h *Handle) ApplyFilter(filter *filter.Filter) error {\n    if !filter.Validate() {\n        return fmt.Errorf(\"Invalid filter\")\n    }\n\n    h.filter = filter\n    return nil\n}\n\n// Activate the capture handle (this is not needed for the file capture handle,\n// but you may want to call it anyway in order to make switching to different\n// packet sources easier).\nfunc (h *Handle) Activate() error {\n    return nil\n}\n\n// Capture a single packet from the packet source. If no packet is available\n// (i.e. if the end of the dump file has been reached) it will return a nil\n// slice.\nfunc (h *Handle) Capture() ([]byte, error) {\n    var buf []byte\n    var sec, usec, caplen, wirelen uint32\n\n    for {\n        binary.Read(h.file, h.order, &sec)\n        binary.Read(h.file, h.order, &usec)\n        binary.Read(h.file, h.order, &caplen)\n        binary.Read(h.file, h.order, &wirelen)\n\n        if caplen == 0 {\n            return nil, nil\n        }\n\n        buf = make([]byte, int(caplen))\n\n        _, err := h.file.Read(buf)\n        if err == io.EOF {\n            return nil, nil\n        }\n\n        if err != nil  {\n            return nil, fmt.Errorf(\"Could not capture: %s\", err)\n        }\n\n        if h.filter != nil && !h.filter.Match(buf) {\n            continue\n        }\n\n        break\n    }\n\n    return buf, nil\n}\n\n// Inject a packet in the packet source. This will automatically append packets\n// at the end of the dump file, instead of truncating it.\nfunc (h *Handle) Inject(buf []byte) error {\n    var sec, usec, caplen, wirelen uint32\n\n    sec     = 0\n    usec    = 0\n    caplen  = uint32(len(buf))\n    wirelen = caplen\n\n    binary.Write(h.out, h.order, sec)\n    binary.Write(h.out, h.order, usec)\n    binary.Write(h.out, h.order, caplen)\n    binary.Write(h.out, h.order, wirelen)\n\n    n, err := h.out.Write(buf)\n    if err != nil || n < len(buf) {\n        return fmt.Errorf(\"Could not write packet: %s\", err)\n    }\n\n    return nil\n}\n\n// Close the packet source.\nfunc (h *Handle) Close() {\n    h.file.Close()\n    h.out.Close()\n}\n"
  },
  {
    "path": "capture/file/capture_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage file_test\n\nimport \"log\"\nimport \"testing\"\n\nimport \"github.com/ghedo/go.pkt/capture/file\"\nimport \"github.com/ghedo/go.pkt/filter\"\n\nfunc TestCapture(t *testing.T) {\n    src, err := file.Open(\"capture_test.pcap\")\n    if err != nil {\n        t.Fatalf(\"Error opening: %s\", err)\n    }\n    defer src.Close()\n\n    var count uint64\n    for {\n        buf, err := src.Capture()\n        if err != nil {\n            t.Fatalf(\"Error reading: %s\", err)\n        }\n\n        if buf == nil {\n            break\n        }\n\n        count++\n    }\n\n    if count != 16 {\n        t.Fatalf(\"Count mismatch: %d\", count)\n    }\n}\n\nfunc TestCaptureFilter(t *testing.T) {\n    src, err := file.Open(\"capture_test.pcap\")\n    if err != nil {\n        t.Fatalf(\"Error opening: %s\", err)\n    }\n    defer src.Close()\n\n    flt, err := filter.Compile(\"arp\", src.LinkType(), false)\n    if err != nil {\n        t.Fatalf(\"Error parsing filter: %s\", err)\n    }\n    defer flt.Cleanup()\n\n    err = src.ApplyFilter(flt)\n    if err != nil {\n        t.Fatalf(\"Error applying filter: %s\", err)\n    }\n\n    var count uint64\n    for {\n        buf, err := src.Capture()\n        if err != nil {\n            t.Fatalf(\"Error reading: %s %d\", err, count)\n        }\n\n        if buf == nil {\n            break\n        }\n\n        count++\n    }\n\n    if count != 2 {\n        t.Fatalf(\"Count mismatch: %d\", count)\n    }\n}\n\nfunc TestInject(t *testing.T) {\n    src, err := file.Open(\"capture_test.pcap\")\n    if err != nil {\n        t.Fatalf(\"Error opening: %s\", err)\n    }\n    defer src.Close()\n\n    dst, err := file.Open(\"inject_test.pcap\")\n    if err != nil {\n        t.Fatalf(\"Error opening: %s\", err)\n    }\n    defer dst.Close()\n\n    var count uint64\n    for {\n        buf, err := src.Capture()\n        if err != nil {\n            t.Fatalf(\"Error reading: %s\", err)\n        }\n\n        if buf == nil {\n            break\n        }\n\n        err = dst.Inject(buf)\n        if err != nil {\n            t.Fatalf(\"Error writing: %s\", err)\n        }\n\n        count++\n    }\n\n    if count != 16 {\n        t.Fatalf(\"Count mismatch: %d\", count)\n    }\n}\n\nfunc ExampleCapture() {\n    src, err := file.Open(\"/path/to/file/dump.pcap\")\n    if err != nil {\n        log.Fatal(err)\n    }\n    defer src.Close()\n\n    // you may configure the source further, e.g. by activating\n    // promiscuous mode.\n\n    err = src.Activate()\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    for {\n        buf, err := src.Capture()\n        if err != nil {\n            log.Fatal(err)\n        }\n\n        if buf == nil {\n            break\n        }\n\n        log.Println(\"PACKET!!!\")\n\n        // do something with the packet\n    }\n}\n\nfunc ExampleInject() {\n    dst, err := file.Open(\"/path/to/file/dump.pcap\")\n    if err != nil {\n        log.Fatal(err)\n    }\n    defer dst.Close()\n\n    // you may configure the source further, e.g. by activating\n    // promiscuous mode.\n\n    err = dst.Activate()\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    err = dst.Inject([]byte(\"random data\"))\n    if err != nil {\n        log.Fatal(err)\n    }\n}\n"
  },
  {
    "path": "capture/pcap/capture.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides packet capturing and injection on live network interfaces via\n// libpcap.\npackage pcap\n\n// #cgo LDFLAGS: -lpcap\n// #include <stdlib.h>\n// #include <pcap.h>\nimport \"C\"\n\nimport \"fmt\"\nimport \"unsafe\"\n\nimport \"github.com/ghedo/go.pkt/filter\"\nimport \"github.com/ghedo/go.pkt/packet\"\n\ntype Handle struct {\n    Device string\n    pcap   *C.pcap_t\n}\n\n// Create a new capture handle from the given network interface. Noe that this\n// may require root privileges.\nfunc Open(dev_name string) (*Handle, error) {\n    handle := &Handle{ Device: dev_name }\n\n    dev_str := C.CString(dev_name)\n    defer C.free(unsafe.Pointer(dev_str))\n\n    err_str := (*C.char)(C.calloc(256, 1))\n    defer C.free(unsafe.Pointer(err_str))\n\n    handle.pcap = C.pcap_create(dev_str, err_str)\n    if handle == nil {\n        return nil, fmt.Errorf(\n            \"Could not open device: %s\", C.GoString(err_str),\n        )\n    }\n\n    return handle, nil\n}\n\n// Return the link type of the capture handle (that is, the type of packets that\n// come out of the packet source).\nfunc (h *Handle) LinkType() packet.Type {\n    return packet.LinkType(uint32(C.pcap_datalink(h.pcap)))\n}\n\nfunc (h *Handle) SetMTU(mtu int) error {\n    err := C.pcap_set_snaplen(h.pcap, C.int(mtu))\n    if err < 0 {\n        return fmt.Errorf(\"Handle already active\")\n    }\n\n    return nil\n}\n\n// Enable/disable promiscuous mode.\nfunc (h *Handle) SetPromiscMode(promisc bool) error {\n    var promisc_int C.int\n\n    if promisc {\n        promisc_int = 1\n    } else {\n        promisc_int = 0\n    }\n\n    err := C.pcap_set_promisc(h.pcap, promisc_int)\n    if err < 0 {\n        return fmt.Errorf(\"Handle already active\")\n    }\n\n    return nil\n}\n\n// Enable/disable monitor mode. This is only relevant to RF-based packet sources\n// (e.g. a WiFi or Bluetooth network interface)\nfunc (h *Handle) SetMonitorMode(monitor bool) error {\n    var rfmon_int C.int\n\n    if monitor {\n        rfmon_int = 1\n    } else {\n        rfmon_int = 0\n    }\n\n    err := C.pcap_set_rfmon(h.pcap, rfmon_int)\n    if err < 0 {\n        return fmt.Errorf(\"Handle already active\")\n    }\n\n    return nil\n}\n\n// Apply the given filter it to the packet source. Only packets that match this\n// filter will be captured.\nfunc (h *Handle) ApplyFilter(filter *filter.Filter) error {\n    if !filter.Validate() {\n        return fmt.Errorf(\"Invalid filter\")\n    }\n\n    err_str := (*C.char)(C.calloc(256, 1))\n    defer C.free(unsafe.Pointer(err_str))\n\n    dev_str := C.CString(h.Device)\n    defer C.free(unsafe.Pointer(dev_str))\n\n    err := C.pcap_setfilter(h.pcap, (*C.struct_bpf_program)(filter.Program()))\n    if err < 0 {\n        return fmt.Errorf(\"Could not set filter: %s\", h.get_error())\n    }\n\n    return nil\n}\n\n// Activate the packet source. Note that after calling this method it will not\n// be possible to change the packet source configuration (MTU, promiscuous mode,\n// monitor mode, ...)\nfunc (h *Handle) Activate() error {\n    err := C.pcap_activate(h.pcap)\n    if err < 0 {\n        return fmt.Errorf(\"Could not activate: %s\", h.get_error())\n    }\n\n    return nil\n}\n\n// Capture a single packet from the packet source. This will block until a\n// packet is received.\nfunc (h *Handle) Capture() ([]byte, error) {\n    var buf *C.u_char\n    var pkt_hdr *C.struct_pcap_pkthdr\n\n    for {\n        err := C.pcap_next_ex(h.pcap, &pkt_hdr, &buf)\n        switch err {\n        case -2:\n            return nil, nil\n\n        case -1:\n            return nil, fmt.Errorf(\n                \"Could not read packet: %s\", h.get_error(),\n            )\n\n        case 0:\n            continue\n\n        case 1:\n            return C.GoBytes(unsafe.Pointer(buf),\n                             C.int(pkt_hdr.len)), nil\n        }\n    }\n\n    return nil, fmt.Errorf(\"WTF\")\n}\n\n// Inject a packet in the packet source.\nfunc (h *Handle) Inject(buf []byte) error {\n    cbuf := (*C.u_char)(&buf[0])\n    blen := C.int(len(buf))\n\n    err := C.pcap_sendpacket(h.pcap, cbuf, blen)\n    if err < 0 {\n        return fmt.Errorf(\"Could not inject packet: %s\", h.get_error())\n    }\n\n    return nil\n}\n\n// Close the packet source.\nfunc (h *Handle) Close() {\n    C.pcap_close(h.pcap)\n}\n\nfunc (h *Handle) get_error() error {\n    err_str := C.pcap_geterr(h.pcap)\n    return fmt.Errorf(C.GoString(err_str))\n}\n"
  },
  {
    "path": "capture/pcap/capture_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage pcap_test\n\nimport \"log\"\n\nimport \"github.com/ghedo/go.pkt/capture/pcap\"\n\nfunc ExampleCapture() {\n    src, err := pcap.Open(\"eth0\")\n    if err != nil {\n        log.Fatal(err)\n    }\n    defer src.Close()\n\n    // you may configure the source further, e.g. by activating\n    // promiscuous mode.\n\n    err = src.Activate()\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    for {\n        buf, err := src.Capture()\n        if err != nil {\n            log.Fatal(err)\n        }\n\n        log.Printf(\"PACKET!!! %v\", buf)\n\n        // do something with the packet\n    }\n}\n\nfunc ExampleInject() {\n    dst, err := pcap.Open(\"eth0\")\n    if err != nil {\n        log.Fatal(err)\n    }\n    defer dst.Close()\n\n    // you may configure the source further, e.g. by activating\n    // promiscuous mode.\n\n    err = dst.Activate()\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    err = dst.Inject([]byte(\"random data\"))\n    if err != nil {\n        log.Fatal(err)\n    }\n}\n"
  },
  {
    "path": "examples/arp/main.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage main\n\nimport \"log\"\nimport \"net\"\nimport \"time\"\n\nimport \"github.com/docopt/docopt-go\"\n\nimport \"github.com/ghedo/go.pkt/capture/pcap\"\nimport \"github.com/ghedo/go.pkt/packet/eth\"\nimport \"github.com/ghedo/go.pkt/packet/arp\"\n\nimport \"github.com/ghedo/go.pkt/network\"\nimport \"github.com/ghedo/go.pkt/routing\"\n\nfunc main() {\n    log.SetFlags(0)\n\n    usage := `Usage: arp <addr>\n\nResolve the given IP address using ARP.`\n\n    args, err := docopt.Parse(usage, nil, true, \"\", false)\n    if err != nil {\n        log.Fatalf(\"Invalid arguments: %s\", err)\n    }\n\n    addr    := args[\"<addr>\"].(string)\n    addr_ip := net.ParseIP(addr)\n    timeout := 5 * time.Second\n\n    route, err := routing.RouteTo(addr_ip)\n    if err != nil {\n        log.Fatalf(\"Error: %s\", err)\n    }\n\n    if route == nil {\n        log.Println(\"No route found\")\n    }\n\n    c, err := pcap.Open(route.Iface.Name)\n    if err != nil {\n        log.Fatalf(\"Error opening interface: %s\", err)\n    }\n    defer c.Close()\n\n    err = c.Activate()\n    if err != nil {\n        log.Fatalf(\"Error activating source: %s\", err)\n    }\n\n    eth_pkt := eth.Make()\n    eth_pkt.SrcAddr = route.Iface.HardwareAddr\n    eth_pkt.DstAddr, _ = net.ParseMAC(\"ff:ff:ff:ff:ff:ff\")\n\n    arp_pkt := arp.Make()\n    arp_pkt.HWSrcAddr = route.Iface.HardwareAddr\n    arp_pkt.HWDstAddr, _ = net.ParseMAC(\"00:00:00:00:00:00\")\n    arp_pkt.ProtoSrcAddr, _ = route.GetIfaceIPv4Addr()\n    arp_pkt.ProtoDstAddr = addr_ip\n\n    pkt, err := network.SendRecv(c, timeout, eth_pkt, arp_pkt)\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    log.Println(pkt.Payload().(*arp.Packet).HWSrcAddr)\n}\n"
  },
  {
    "path": "examples/bpf_asm/Makefile",
    "content": "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.y\n\nbpf_asm.nn.go: bpf_asm.l\n\tnex bpf_asm.l\n"
  },
  {
    "path": "examples/bpf_asm/bpf_asm.l",
    "content": "/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/ldxi/\t{ return OP_LDXI }\n/ldxb/\t{ return OP_LDXB }\n/st/\t{ return OP_ST }\n/stx/\t{ return OP_STX }\n/jmp/\t{ return OP_JMP }\n/ja/\t{ return OP_JMP }\n/jeq/\t{ return OP_JEQ }\n/jneq/\t{ return OP_JNEQ }\n/jne/\t{ return OP_JNEQ }\n/jlt/\t{ return OP_JLT }\n/jle/\t{ return OP_JLE }\n/jgt/\t{ return OP_JGT }\n/jge/\t{ return OP_JGE }\n/jset/\t{ return OP_JSET }\n/add/\t{ return OP_ADD }\n/sub/\t{ return OP_SUB }\n/mul/\t{ return OP_MUL }\n/div/\t{ return OP_DIV }\n/neg/\t{ return OP_NEG }\n/and/\t{ return OP_AND }\n/or/\t{ return OP_OR }\n/lsh/\t{ return OP_LSH }\n/rsh/\t{ return OP_RSH }\n/ret/\t{ return OP_RET }\n/tax/\t{ return OP_TAX }\n/txa/\t{ return OP_TXA }\n\n/#?len/\t\t{ return K_PKT_LEN }\n/#?proto/\t{ return K_PROTO }\n/#?type/\t{ return K_TYPE }\n/#?poff/\t{ return K_POFF }\n/#?ifidx/\t{ return K_IFIDX }\n/#?nla/\t\t{ return K_NLATTR }\n/#?nlan/\t{ return K_NLATTR_NEST }\n/#?mark/\t{ return K_MARK }\n/#?queue/\t{ return K_QUEUE }\n/#?hatype/\t{ return K_HATYPE }\n/#?rxhash/\t{ return K_RXHASH }\n/#?cpu/\t\t{ return K_CPU }\n/#?vlan_tci/\t{ return K_VLANT }\n/#?vlan_pr/\t{ return K_VLANP }\n\n/:/\t\t{ return ':' }\n/,/\t\t{ return ',' }\n/#/\t\t{ return '#' }\n/%/\t\t{ return '%' }\n/\\[/\t\t{ return '[' }\n/\\]/\t\t{ return ']' }\n/\\(/\t\t{ return '(' }\n/\\)/\t\t{ return ')' }\n/x/\t\t{ return 'x' }\n/a/\t\t{ return 'a' }\n/\\+/\t\t{ return '+' }\n/M/\t\t{ return 'M' }\n/\\*/\t\t{ return '*' }\n/&/\t\t{ return '&' }\n\n/([0][x][a-fA-F0-9]+)/ {\n\tstr := strings.TrimPrefix(yylex.Text(), \"0x\")\n\tnum, _ := strconv.ParseUint(str, 16, 32)\n\tlval.number = uint32(num)\n\treturn number\n}\n\n/([0][b][0-1]+)/ {\n\tstr := strings.TrimPrefix(yylex.Text(), \"0b\")\n\tnum, _ := strconv.ParseUint(str, 2, 32)\n\tlval.number = uint32(num)\n\treturn number\n}\n\n/(([0])|([-+]?[1-9][0-9]*))/ {\n\tnum, _ := strconv.ParseUint(yylex.Text(), 10, 32)\n\tlval.number = uint32(num)\n\treturn number\n}\n\n/([0][0-9]+)/ {\n\tstr := strings.TrimPrefix(yylex.Text(), \"0\")\n\tnum, _ := strconv.ParseUint(str, 8, 32)\n\tlval.number = uint32(num)\n\treturn number\n}\n\n/[a-zA-Z_][a-zA-Z0-9_]+/ \t{\n\tlval.label = yylex.Text()\n\treturn label\n}\n//\npackage main\n\nimport \"log\"\nimport \"strconv\"\nimport \"os\"\n\nimport \"github.com/docopt/docopt-go\"\n\nimport \"github.com/ghedo/go.pkt/filter\"\n\nvar bld *filter.Builder\n\nfunc main() {\n\tlog.SetFlags(0)\n\n\tusage := `Usage: bpf_asm <file>`\n\n\targs, err := docopt.Parse(usage, nil, true, \"\", false)\n\tif err != nil {\n\t\tlog.Fatalf(\"Invalid arguments: %s\", err)\n\t}\n\n\tfile, err := os.Open(args[\"<file>\"].(string))\n\tif err != nil {\n\t\tlog.Fatalf(\"Error opening file: %s\", err)\n\t}\n\n\tbld = filter.NewBuilder()\n\n\tlex := NewLexer(file)\n\tyyParse(lex)\n\n\tflt := bld.Build()\n\n\tif !flt.Validate() {\n\t\tlog.Fatalf(\"Invalid filter\")\n\t}\n\n\tlog.Println(flt)\n}\n"
  },
  {
    "path": "examples/bpf_asm/bpf_asm.y",
    "content": "%{\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%token OP_LDH\n%token OP_LD\n%token OP_LDI\n%token OP_LDX\n%token OP_LDXI\n%token OP_LDXB\n%token OP_ST\n%token OP_STX\n%token OP_JMP\n%token OP_JEQ\n%token OP_JNEQ\n%token OP_JLT\n%token OP_JLE\n%token OP_JGT\n%token OP_JGE\n%token OP_JSET\n%token OP_ADD\n%token OP_SUB\n%token OP_MUL\n%token OP_DIV\n%token OP_NEG\n%token OP_AND\n%token OP_OR\n%token OP_LSH\n%token OP_RSH\n%token OP_RET\n%token OP_TAX\n%token OP_TXA\n\n%token K_PKT_LEN\n%token K_PROTO\n%token K_TYPE\n%token K_POFF\n%token K_IFIDX\n%token K_NLATTR\n%token K_NLATTR_NEST\n%token K_MARK\n%token K_QUEUE\n%token K_HATYPE\n%token K_RXHASH\n%token K_CPU\n%token K_VLANT\n%token K_VLANP\n\n%token number\n%token label\n\n%token jtl\n%token jfl\n%token jkl\n\n%token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%'\n\n%type <label> label\n%type <number> number\n\n%%\n\nprog\n\t: line\n\t| prog line\n\t;\n\nline\n\t: instr\n\t| labelled_instr\n\t;\n\nlabelled_instr\n\t: labelled instr\n\t;\n\ninstr\n\t: ldb\n\t| ldh\n\t| ld\n\t| ldi\n\t| ldx\n\t| ldxi\n\t| st\n\t| stx\n\t| jmp\n\t| jeq\n\t| jneq\n\t| jlt\n\t| jle\n\t| jgt\n\t| jge\n\t| jset\n\t| add\n\t| sub\n\t| mul\n\t| div\n\t| neg\n\t| and\n\t| or\n\t| lsh\n\t| rsh\n\t| ret\n\t| tax\n\t| txa\n\t;\n\nlabelled\n\t: label ':' { bld.Label($1)\n\t}\n\t;\n\nldb\n\t: OP_LDB '[' 'x' '+' number ']' {\n\t\tbld.LD(filter.Byte, filter.IND, $5)\n\t}\n\t| OP_LDB '[' '%' 'x' '+' number ']' {\n\t\tbld.LD(filter.Byte, filter.IND, $6)\n\t}\n\t| OP_LDB '[' number ']' {\n\t\tbld.LD(filter.Byte, filter.ABS, $3)\n\t}\n\t;\n\nldh\n\t: OP_LDH '[' 'x' '+' number ']' {\n\t\tbld.LD(filter.Half, filter.IND, $5)\n\t}\n\t| OP_LDH '[' '%' 'x' '+' number ']' {\n\t\tbld.LD(filter.Half, filter.IND, $6)\n\t}\n\t| OP_LDH '[' number ']' {\n\t\tbld.LD(filter.Half, filter.ABS, $3)\n\t}\n\t;\n\nldi\n\t: OP_LDI '#' number {\n\t\tbld.LD(filter.Word, filter.IMM, $3)\n\t}\n\t| OP_LDI number {\n\t\tbld.LD(filter.Word, filter.IMM, $2)\n\t}\n\t;\n\nld\n\t: OP_LD '#' number {\n\t\tbld.LD(filter.Word, filter.IMM, $3)\n\t}\n\t| OP_LD K_PKT_LEN {\n\t\tbld.LD(filter.Word, filter.LEN, 0)\n\t}\n\t| OP_LD 'M' '[' number ']' {\n\t\tbld.LD(filter.Word, filter.MEM, $4)\n\t}\n\t| OP_LD '[' 'x' '+' number ']' {\n\t\tbld.LD(filter.Word, filter.IND, $5)\n\t}\n\t| OP_LD '[' '%' 'x' '+' number ']' {\n\t\tbld.LD(filter.Word, filter.IND, $6)\n\t}\n\t| OP_LD '[' number ']' {\n\t\tbld.LD(filter.Word, filter.ABS, $3)\n\t}\n\t;\n\nldxi\n\t: OP_LDXI '#' number {\n\t\tbld.LDX(filter.Word, filter.IMM, $3)\n\t}\n\t| OP_LDXI number {\n\t\tbld.LDX(filter.Word, filter.IMM, $2)\n\t}\n\t;\n\nldx\n\t: OP_LDX '#' number {\n\t\tbld.LDX(filter.Word, filter.IMM, $3)\n\t}\n\t| OP_LDX K_PKT_LEN {\n\t\tbld.LDX(filter.Word, filter.LEN, 0)\n\t}\n\t| OP_LDX 'M' '[' number ']' {\n\t\tbld.LDX(filter.Word, filter.MEM, $4)\n\t}\n\t| OP_LDXB number '*' '(' '[' number ']' '&' number ')' {\n\t\tif ($2 != 4 || $9 != 0xf) {\n\t\t\tyylex.Error(\"ldxb offset not supported!\")\n\t\t} else {\n\t\t\tbld.LDX(filter.Byte, filter.MSH, $6)\n\t\t}\n\t}\n\t| OP_LDX number '*' '(' '[' number ']' '&' number ')' {\n\t\tif ($2 != 4 || $9 != 0xf) {\n\t\t\tyylex.Error(\"ldxb offset not supported!\")\n\t\t} else {\n\t\t\tbld.LDX(filter.Byte, filter.MSH, $6)\n\t\t}\n\t}\n\t;\n\nst\n\t: OP_ST 'M' '[' number ']' {\n\t\tbld.ST($4)\n\t}\n\t;\n\nstx\n\t: OP_STX 'M' '[' number ']' {\n\t\tbld.STX($4)\n\t}\n\t;\n\njmp\n\t: OP_JMP label {\n\t\tbld.JA($2)\n\t}\n\t;\n\njeq\n\t: OP_JEQ '#' number ',' label ',' label {\n\t\tbld.JEQ(filter.Const, $5, $7, $3)\n\t}\n\t| OP_JEQ 'x' ',' label ',' label {\n\t\tbld.JEQ(filter.Index, $4, $6, 0)\n\t}\n\t| OP_JEQ '%' 'x' ',' label ',' label {\n\t\tbld.JEQ(filter.Index, $5, $7, 0)\n\t}\n\t| OP_JEQ '#' number ',' label {\n\t\tbld.JEQ(filter.Const, \"\", $5, $3)\n\t}\n\t| OP_JEQ 'x' ',' label {\n\t\tbld.JEQ(filter.Index, \"\", $4, 0)\n\t}\n\t| OP_JEQ '%' 'x' ',' label {\n\t\tbld.JEQ(filter.Index, \"\", $5, 0)\n\t}\n\t;\n\njneq\n\t: OP_JNEQ '#' number ',' label {\n\t\tbld.JEQ(filter.Const, \"\", $5, $3)\n\t}\n\t| OP_JNEQ 'x' ',' label {\n\t\tbld.JEQ(filter.Index, \"\", $4, 0)\n\t}\n\t| OP_JNEQ '%' 'x' ',' label {\n\t\tbld.JEQ(filter.Index, \"\", $5, 0)\n\t}\n\t;\n\njlt\n\t: OP_JLT '#' number ',' label {\n\t\tbld.JGE(filter.Const, \"\", $5, $3)\n\t}\n\t| OP_JLT 'x' ',' label {\n\t\tbld.JGE(filter.Index, \"\", $4, 0)\n\t}\n\t| OP_JLT '%' 'x' ',' label {\n\t\tbld.JGE(filter.Index, \"\", $5, 0)\n\t}\n\t;\n\njle\n\t: OP_JLE '#' number ',' label {\n\t\tbld.JGT(filter.Const, \"\", $5, $3)\n\t}\n\t| OP_JLE 'x' ',' label {\n\t\tbld.JGT(filter.Index, \"\", $4, 0)\n\t}\n\t| OP_JLE '%' 'x' ',' label {\n\t\tbld.JGT(filter.Index, \"\", $5, 0)\n\t}\n\t;\n\njgt\n\t: OP_JGT '#' number ',' label ',' label {\n\t\tbld.JGT(filter.Const, $5, $7, $3)\n\t}\n\t| OP_JGT 'x' ',' label ',' label {\n\t\tbld.JGT(filter.Index, $4, $6, 0)\n\t}\n\t| OP_JGT '%' 'x' ',' label ',' label {\n\t\tbld.JGT(filter.Index, $5, $7, 0)\n\t}\n\t| OP_JGT '#' number ',' label {\n\t\tbld.JGT(filter.Const, \"\", $5, $3)\n\t}\n\t| OP_JGT 'x' ',' label {\n\t\tbld.JGT(filter.Index, \"\", $4, 0)\n\t}\n\t| OP_JGT '%' 'x' ',' label {\n\t\tbld.JGT(filter.Index, \"\", $5, 0)\n\t}\n\t;\n\njge\n\t: OP_JGE '#' number ',' label ',' label {\n\t\tbld.JGE(filter.Const, $5, $7, $3)\n\t}\n\t| OP_JGE 'x' ',' label ',' label {\n\t\tbld.JGE(filter.Index, $4, $6, 0)\n\t}\n\t| OP_JGE '%' 'x' ',' label ',' label {\n\t\tbld.JGE(filter.Index, $5, $7, 0)\n\t}\n\t| OP_JGE '#' number ',' label {\n\t\tbld.JGE(filter.Const, \"\", $5, $3)\n\t}\n\t| OP_JGE 'x' ',' label {\n\t\tbld.JGE(filter.Index, \"\", $4, 0)\n\t}\n\t| OP_JGE '%' 'x' ',' label {\n\t\tbld.JGE(filter.Index, \"\", $5, 0)\n\t}\n\t;\n\njset\n\t: OP_JSET '#' number ',' label ',' label {\n\t\tbld.JSET(filter.Const, $5, $7, $3)\n\t}\n\t| OP_JSET 'x' ',' label ',' label {\n\t\tbld.JSET(filter.Index, $4, $6, 0)\n\t}\n\t| OP_JSET '%' 'x' ',' label ',' label {\n\t\tbld.JSET(filter.Index, $5, $7, 0)\n\t}\n\t| OP_JSET '#' number ',' label {\n\t\tbld.JSET(filter.Const, \"\", $5, $3)\n\t}\n\t| OP_JSET 'x' ',' label {\n\t\tbld.JSET(filter.Index, \"\", $4, 0)\n\t}\n\t| OP_JSET '%' 'x' ',' label {\n\t\tbld.JSET(filter.Index, \"\", $5, 0)\n\t}\n\t;\n\nadd\n\t: OP_ADD '#' number {\n\t\tbld.ADD(filter.Const, $3)\n\t}\n\t| OP_ADD 'x' {\n\t\tbld.ADD(filter.Index, 0)\n\t}\n\t| OP_ADD '%' 'x' {\n\t\tbld.ADD(filter.Index, 0)\n\t}\n\t;\n\nsub\n\t: OP_SUB '#' number {\n\t\tbld.SUB(filter.Const, $3)\n\t}\n\t| OP_SUB 'x' {\n\t\tbld.SUB(filter.Index, 0)\n\t}\n\t| OP_SUB '%' 'x' {\n\t\tbld.SUB(filter.Index, 0)\n\t}\n\t;\n\nmul\n\t: OP_MUL '#' number {\n\t\tbld.MUL(filter.Const, $3)\n\t}\n\t| OP_MUL 'x' {\n\t\tbld.MUL(filter.Index, 0)\n\t}\n\t| OP_MUL '%' 'x' {\n\t\tbld.MUL(filter.Index, 0)\n\t}\n\t;\n\ndiv\n\t: OP_DIV '#' number {\n\t\tbld.DIV(filter.Const, $3)\n\t}\n\t| OP_DIV 'x' {\n\t\tbld.DIV(filter.Index, 0)\n\t}\n\t| OP_DIV '%' 'x' {\n\t\tbld.DIV(filter.Index, 0)\n\t}\n\t;\n\nneg\n\t: OP_NEG {\n\t\tbld.NEG()\n\t}\n\t;\n\nand\n\t: OP_AND '#' number {\n\t\tbld.AND(filter.Const, $3)\n\t}\n\t| OP_AND 'x' {\n\t\tbld.AND(filter.Index, 0)\n\t}\n\t| OP_AND '%' 'x' {\n\t\tbld.AND(filter.Index, 0)\n\t}\n\t;\n\nor\n\t: OP_OR '#' number {\n\t\tbld.OR(filter.Const, $3)\n\t}\n\t| OP_OR 'x' {\n\t\tbld.OR(filter.Index, 0)\n\t}\n\t| OP_OR '%' 'x' {\n\t\tbld.OR(filter.Index, 0)\n\t}\n\t;\n\nlsh\n\t: OP_LSH '#' number {\n\t\tbld.LSH(filter.Const, $3)\n\t}\n\t| OP_LSH 'x' {\n\t\tbld.LSH(filter.Index, 0)\n\t}\n\t| OP_LSH '%' 'x' {\n\t\tbld.LSH(filter.Index, 0)\n\t}\n\t;\n\nrsh\n\t: OP_RSH '#' number {\n\t\tbld.RSH(filter.Const, $3)\n\t}\n\t| OP_RSH 'x' {\n\t\tbld.RSH(filter.Index, 0)\n\t}\n\t| OP_RSH '%' 'x' {\n\t\tbld.RSH(filter.Index, 0)\n\t}\n\t;\n\nret\n\t: OP_RET 'a' {\n\t\tbld.RET(filter.Acc, 0)\n\t}\n\t| OP_RET '%' 'a' {\n\t\tbld.RET(filter.Acc, 0)\n\t}\n\t| OP_RET 'x' {\n\t\tbld.RET(filter.Index, 0)\n\t}\n\t| OP_RET '%' 'x' {\n\t\tbld.RET(filter.Index, 0)\n\t}\n\t| OP_RET '#' number {\n\t\tbld.RET(filter.Const, $3)\n\t}\n\t;\n\ntax\n\t: OP_TAX {\n\t\tbld.TAX()\n\t}\n\t;\n\ntxa\n\t: OP_TXA {\n\t\tbld.TXA()\n\t}\n\t;\n\n%%\n"
  },
  {
    "path": "examples/dump/main.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage main\n\nimport \"log\"\nimport \"strconv\"\n\nimport \"github.com/docopt/docopt-go\"\n\nimport \"github.com/ghedo/go.pkt/capture\"\nimport \"github.com/ghedo/go.pkt/capture/pcap\"\nimport \"github.com/ghedo/go.pkt/capture/file\"\nimport \"github.com/ghedo/go.pkt/filter\"\nimport \"github.com/ghedo/go.pkt/layers\"\n\nfunc main() {\n    log.SetFlags(0)\n\n    usage := `Usage: dump [options] [<expression>]\n\nDump the traffic on the network (like tcpdump).\n\nOptions:\n  -c <count>  Exit after receiving count packets.\n  -i <iface>  Listen on interface.\n  -r <file>   Read packets from file.\n  -w <file>   Write the raw packets to file.`\n\n    args, err := docopt.Parse(usage, nil, true, \"\", false)\n    if err != nil {\n        log.Fatalf(\"Invalid arguments: %s\", err)\n    }\n\n    var count uint64\n\n    if args[\"-c\"] != nil {\n        count, err = strconv.ParseUint(args[\"-c\"].(string), 10, 64)\n        if err != nil {\n            log.Fatalf(\"Error parsing count: %s\", err)\n        }\n    }\n\n    var src capture.Handle\n\n    if args[\"-i\"] != nil {\n        src, err = pcap.Open(args[\"-i\"].(string))\n        if err != nil {\n            log.Fatalf(\"Error opening iface: %s\", err)\n        }\n    } else if args[\"-r\"] != nil {\n        src, err = file.Open(args[\"-r\"].(string))\n        if err != nil {\n            log.Fatalf(\"Error opening file: %s\", err)\n        }\n    } else {\n        log.Fatalf(\"Must select a source (either -i or -r)\")\n    }\n    defer src.Close()\n\n    var dst capture.Handle\n\n    if args[\"-w\"] != nil {\n        dst, err = file.Open(args[\"-w\"].(string))\n        if err != nil {\n            log.Fatalf(\"Error opening file: %s\", err)\n        }\n        defer dst.Close()\n    }\n\n    err = src.Activate()\n    if err != nil {\n        log.Fatalf(\"Error activating source: %s\", err)\n    }\n\n    if args[\"<expression>\"] != nil {\n        expr := args[\"<expression>\"].(string)\n\n        flt, err := filter.Compile(expr, src.LinkType(), false)\n        if err != nil {\n            log.Fatalf(\"Error parsing filter: %s\", err)\n        }\n        defer flt.Cleanup()\n\n        err = src.ApplyFilter(flt)\n        if err != nil {\n            log.Fatalf(\"Error appying filter: %s\", err)\n        }\n    }\n\n    var i uint64\n\n    for {\n        buf, err := src.Capture()\n        if err != nil {\n            log.Fatalf(\"Error: %s\", err)\n            break\n        }\n\n        if buf == nil {\n            break\n        }\n\n        i++\n\n        if dst == nil {\n            rcv_pkt, err := layers.UnpackAll(buf, src.LinkType())\n            if err != nil {\n                log.Printf(\"Error: %s\\n\", err)\n            }\n\n            log.Println(rcv_pkt)\n        } else {\n            dst.Inject(buf)\n        }\n\n        if count > 0 && i >= count {\n            break\n        }\n    }\n}\n"
  },
  {
    "path": "examples/ping/main.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage main\n\nimport \"log\"\nimport \"math/rand\"\nimport \"net\"\nimport \"time\"\n\nimport \"github.com/docopt/docopt-go\"\n\nimport \"github.com/ghedo/go.pkt/capture/pcap\"\n\nimport \"github.com/ghedo/go.pkt/packet/eth\"\nimport \"github.com/ghedo/go.pkt/packet/icmpv4\"\nimport \"github.com/ghedo/go.pkt/packet/ipv4\"\n\nimport \"github.com/ghedo/go.pkt/network\"\nimport \"github.com/ghedo/go.pkt/routing\"\n\nfunc main() {\n    log.SetFlags(0)\n\n    usage := `Usage: ping <addr>\n\nPing the given IP address.`\n\n    args, err := docopt.Parse(usage, nil, true, \"\", false)\n    if err != nil {\n        log.Fatalf(\"Invalid arguments: %s\", err)\n    }\n\n    addr    := args[\"<addr>\"].(string)\n    addr_ip := net.ParseIP(addr)\n    timeout := 5 * time.Second\n\n    route, err := routing.RouteTo(addr_ip)\n    if err != nil {\n        log.Fatalf(\"Error: %s\", err)\n    }\n\n    if route == nil {\n        log.Println(\"No route found\")\n    }\n\n    c, err := pcap.Open(route.Iface.Name)\n    if err != nil {\n        log.Fatalf(\"Error opening interface: %s\", err)\n    }\n    defer c.Close()\n\n    err = c.Activate()\n    if err != nil {\n        log.Fatalf(\"Error activating source: %s\", err)\n    }\n\n    eth_pkt := eth.Make()\n    eth_pkt.SrcAddr = route.Iface.HardwareAddr\n    eth_pkt.DstAddr, _ = network.NextHopMAC(c, timeout, route, addr_ip)\n\n    ipv4_pkt := ipv4.Make()\n    ipv4_pkt.SrcAddr, _ = route.GetIfaceIPv4Addr()\n    ipv4_pkt.DstAddr = addr_ip\n\n    icmp_pkt := icmpv4.Make()\n    icmp_pkt.Type = icmpv4.EchoRequest\n    icmp_pkt.Seq = 0\n    icmp_pkt.Id = uint16(rand.Intn(65535))\n\n    _, err = network.SendRecv(c, timeout, eth_pkt, ipv4_pkt, icmp_pkt)\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    log.Println(\"ping\")\n}\n"
  },
  {
    "path": "examples/route/main.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage main\n\nimport \"log\"\nimport \"net\"\n\nimport \"github.com/docopt/docopt-go\"\n\nimport \"github.com/ghedo/go.pkt/routing\"\n\nfunc main() {\n    log.SetFlags(0)\n\n    usage := `Usage: route [options] [<dest_addr>]\n\nFind the best route on the local routing table to the given destination IP\naddress (or dump all routes).\n\nOptions:\n  -a  Dump all routes.`\n\n    args, err := docopt.Parse(usage, nil, true, \"\", false)\n    if err != nil {\n        log.Fatalf(\"Invalid arguments: %s\", err)\n    }\n\n    if args[\"-a\"].(bool) {\n        routes, err := routing.Routes()\n        if err != err {\n            log.Fatalf(\"Error: %s\", err)\n        }\n\n        for _, r := range routes {\n            log.Println(r)\n        }\n\n        return\n    }\n\n    if args[\"<dest_addr>\"] == nil {\n        log.Fatalf(\"Must pass destination address\")\n    }\n\n    route, err := routing.RouteTo(net.ParseIP(args[\"<dest_addr>\"].(string)))\n    if err != nil {\n        log.Fatalf(\"Error: %s\", err)\n    }\n\n    if route != nil {\n        log.Println(route)\n    } else {\n        log.Println(\"No route found\")\n    }\n}\n"
  },
  {
    "path": "examples/syn_scan/main.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage main\n\nimport \"fmt\"\nimport \"log\"\nimport \"math\"\nimport \"math/rand\"\nimport \"net\"\nimport \"time\"\n\nimport \"github.com/docopt/docopt-go\"\n\nimport \"github.com/ghedo/go.pkt/capture/pcap\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/eth\"\nimport \"github.com/ghedo/go.pkt/packet/ipv4\"\nimport \"github.com/ghedo/go.pkt/packet/tcp\"\n\nimport \"github.com/ghedo/go.pkt/layers\"\nimport \"github.com/ghedo/go.pkt/network\"\nimport \"github.com/ghedo/go.pkt/routing\"\n\nfunc main() {\n    log.SetFlags(0)\n\n    usage := `Usage: syn_scan <addr>\n\nSimple TCP port scanner.`\n\n    args, err := docopt.Parse(usage, nil, true, \"\", false)\n    if err != nil {\n        log.Fatalf(\"Invalid arguments: %s\", err)\n    }\n\n    addr    := args[\"<addr>\"].(string)\n    addr_ip := net.ParseIP(addr)\n    timeout := 1 * time.Second\n\n    route, err := routing.RouteTo(addr_ip)\n    if err != nil {\n        log.Fatalf(\"Error: %s\", err)\n    }\n\n    if route == nil {\n        log.Println(\"No route found\")\n    }\n\n    c, err := pcap.Open(route.Iface.Name)\n    if err != nil {\n        log.Fatalf(\"Error opening interface: %s\", err)\n    }\n    defer c.Close()\n\n    err = c.Activate()\n    if err != nil {\n        log.Fatalf(\"Error activating source: %s\", err)\n    }\n\n    eth_pkt := eth.Make()\n    eth_pkt.SrcAddr = route.Iface.HardwareAddr\n    eth_pkt.DstAddr, _ = network.NextHopMAC(c, timeout, route, addr_ip)\n\n    ipv4_pkt := ipv4.Make()\n    ipv4_pkt.SrcAddr, _ = route.GetIfaceIPv4Addr()\n    ipv4_pkt.DstAddr = addr_ip\n\n    tcp_pkt := tcp.Make()\n    tcp_pkt.SrcPort = 49152\n    tcp_pkt.DstPort = 1\n    tcp_pkt.Flags   = tcp.Syn\n    tcp_pkt.Seq     = uint32(rand.Intn(math.MaxUint32))\n    tcp_pkt.WindowSize = 5840\n\n    for port := uint16(1); port < math.MaxUint16; port ++ {\n        tcp_pkt.DstPort = port\n\n        fmt.Printf(\"Scanning port %.5d: \", port)\n\n        pkt, err := network.SendRecv(c, timeout, eth_pkt, ipv4_pkt, tcp_pkt)\n        if err != nil {\n            fmt.Printf(\"%s\\n\", err)\n            continue\n        }\n\n        tcp_pkt := layers.FindLayer(pkt, packet.TCP).(*tcp.Packet)\n\n        if tcp_pkt.Flags & tcp.Rst == 0 {\n            fmt.Printf(\"OPEN\\n\")\n        } else if tcp_pkt.Flags & tcp.Syn == 0{\n            fmt.Printf(\"CLOSED\\n\")\n        }\n    }\n}\n"
  },
  {
    "path": "examples/tracereply/main.go",
    "content": "package main\n\nimport \"log\"\nimport \"net\"\nimport \"strconv\"\n\nimport \"github.com/docopt/docopt-go\"\n\nimport \"github.com/songgao/water\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/ipv6\"\nimport \"github.com/ghedo/go.pkt/packet/icmpv6\"\nimport \"github.com/ghedo/go.pkt/packet/tcp\"\nimport \"github.com/ghedo/go.pkt/packet/udp\"\nimport \"github.com/ghedo/go.pkt/layers\"\n\nfunc main() {\n    log.SetFlags(0)\n\n    usage := `Usage: tracereply <netif> <hops> <start_addr>\n\nReply to ICMPv6 traceroutes.`\n\n    args, err := docopt.Parse(usage, nil, true, \"\", false)\n    if err != nil {\n        log.Fatalf(\"Invalid arguments: %s\", err)\n    }\n\n    netif := args[\"<netif>\"].(string)\n    ip    := net.ParseIP(args[\"<start_addr>\"].(string))\n\n    hops, err := strconv.ParseUint(args[\"<hops>\"].(string), 10, 8)\n    if err != nil {\n        log.Fatalf(\"Error parsing hop paramenter: %s\", err)\n    }\n\n    config := water.Config{ DeviceType: water.TUN }\n    config.Name = netif\n\n    capture, err := water.New(config)\n    if err != nil {\n        log.Fatalf(\"Error creating capture interface: %s\", err)\n    }\n\n    for {\n        buf := make([]byte, 1500)\n\n        buf_len, err := capture.Read(buf)\n        if err != nil {\n            log.Fatalf(\"Error reading packet from interface: %s\", err)\n        }\n\n        buf = buf[:buf_len]\n\n        pkt, err := layers.UnpackAll(buf, packet.IPv6)\n        if err != nil {\n            log.Printf(\"Error unpacking packet: %s\", err)\n            continue;\n        }\n\n        ip_pkt := layers.FindLayer(pkt, packet.IPv6)\n        if ip_pkt == nil {\n            continue;\n        }\n\n        if ip_pkt.Payload() == nil {\n            continue\n        }\n\n        reply_ip_pkt := ipv6.Make()\n        reply_ip_pkt.DstAddr = ip_pkt.(*ipv6.Packet).SrcAddr\n\n        ttl := ip_pkt.(*ipv6.Packet).HopLimit\n\n        reply_pkts := []packet.Packet{ reply_ip_pkt }\n\n        switch {\n        case uint64(ttl) < hops:\n            []byte(ip)[len(ip) - 1] = ttl\n\n            reply_ip_pkt.SrcAddr = ip\n\n            reply_pkt := icmpv6.Make()\n\n            reply_pkt.Type = icmpv6.TimeExceeded\n            reply_pkt.Code = 0\n\n            reply_pkts = append(reply_pkts, reply_pkt, ip_pkt, ip_pkt.Payload())\n\n        case uint64(ttl) >= hops:\n            reply_ip_pkt.SrcAddr = ip_pkt.(*ipv6.Packet).DstAddr\n\n            switch ip_pkt.Payload().GetType() {\n            case packet.ICMPv6:\n                reply_pkt := icmpv6.Make()\n\n                reply_pkt.Type = icmpv6.EchoReply\n                reply_pkt.Code = 0\n                reply_pkt.Body = ip_pkt.Payload().(*icmpv6.Packet).Body\n\n                reply_pkts = append(reply_pkts, reply_pkt)\n\n            case packet.TCP:\n                reply_pkt := tcp.Make()\n\n                reply_pkt.SrcPort = ip_pkt.Payload().(*tcp.Packet).DstPort\n                reply_pkt.DstPort = ip_pkt.Payload().(*tcp.Packet).SrcPort\n                reply_pkt.Flags   = tcp.Rst\n\n                reply_pkts = append(reply_pkts, reply_pkt)\n\n            case packet.UDP:\n                reply_pkt := udp.Make()\n\n                reply_pkt.SrcPort = ip_pkt.Payload().(*udp.Packet).DstPort\n                reply_pkt.DstPort = ip_pkt.Payload().(*udp.Packet).SrcPort\n\n                reply_pkts = append(reply_pkts, reply_pkt,\n                                    ip_pkt.Payload().Payload())\n            }\n        }\n\n        reply_buf, err := layers.Pack(reply_pkts...)\n        if err != nil {\n            log.Printf(\"Error while packing: %s\\n\", err)\n            continue;\n        }\n\n        capture.Write(reply_buf)\n    }\n}\n"
  },
  {
    "path": "examples/traceroute/main.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage main\n\nimport \"log\"\nimport \"math\"\nimport \"math/rand\"\nimport \"net\"\nimport \"time\"\n\nimport \"github.com/docopt/docopt-go\"\n\nimport \"github.com/ghedo/go.pkt/capture/pcap\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/eth\"\nimport \"github.com/ghedo/go.pkt/packet/icmpv4\"\nimport \"github.com/ghedo/go.pkt/packet/ipv4\"\nimport \"github.com/ghedo/go.pkt/packet/raw\"\nimport \"github.com/ghedo/go.pkt/packet/tcp\"\nimport \"github.com/ghedo/go.pkt/packet/udp\"\n\nimport \"github.com/ghedo/go.pkt/layers\"\nimport \"github.com/ghedo/go.pkt/network\"\nimport \"github.com/ghedo/go.pkt/routing\"\n\nfunc main() {\n    log.SetFlags(0)\n\n    usage := `Usage: traceroute (--icmp | --udp | --tcp ) <addr>\n\nFind the route to the given IP address using ICMP, UDP or TCP packets.\n\nOptions:\n  --icmp  Use ICMP packets.\n  --udp   Use UDP packets.\n  --tcp   Use TCP packets.`\n\n    args, err := docopt.Parse(usage, nil, true, \"\", false)\n    if err != nil {\n        log.Fatalf(\"Invalid arguments: %s\", err)\n    }\n\n    addr    := args[\"<addr>\"].(string)\n    addr_ip := net.ParseIP(addr)\n    timeout := 5 * time.Second\n\n    route, err := routing.RouteTo(addr_ip)\n    if err != nil {\n        log.Fatalf(\"Error: %s\", err)\n    }\n\n    if route == nil {\n        log.Println(\"No route found\")\n    }\n\n    c, err := pcap.Open(route.Iface.Name)\n    if err != nil {\n        log.Fatalf(\"Error opening interface: %s\", err)\n    }\n    defer c.Close()\n\n    err = c.Activate()\n    if err != nil {\n        log.Fatalf(\"Error activating source: %s\", err)\n    }\n\n    eth_pkt := eth.Make()\n    eth_pkt.SrcAddr = route.Iface.HardwareAddr\n    eth_pkt.DstAddr, _ = network.NextHopMAC(c, timeout, route, addr_ip)\n\n    ipv4_pkt := ipv4.Make()\n    ipv4_pkt.SrcAddr, _ = route.GetIfaceIPv4Addr()\n    ipv4_pkt.DstAddr = addr_ip\n    ipv4_pkt.Id      = uint16(rand.Intn(math.MaxUint16))\n    ipv4_pkt.TTL     = 1\n\n    var payload_pkt packet.Packet\n\n    if args[\"--icmp\"].(bool) {\n        icmp_pkt := icmpv4.Make()\n        icmp_pkt.Type = icmpv4.EchoRequest\n        icmp_pkt.Id   = uint16(rand.Intn(math.MaxUint16))\n        icmp_pkt.Seq  = 1\n\n        payload_pkt = icmp_pkt\n    }\n\n    if args[\"--udp\"].(bool) {\n        udp_pkt := udp.Make()\n        udp_pkt.SrcPort = 49152\n        udp_pkt.DstPort = 33434\n\n        raw_pkt := raw.Make()\n        raw_pkt.Data = make([]byte, 40 - udp_pkt.GetLength())\n\n        for i := 0; i < len(raw_pkt.Data); i++ {\n            raw_pkt.Data[i] = byte(0x40 + (i & 0x3f))\n        }\n\n        udp_pkt.SetPayload(raw_pkt)\n\n        payload_pkt = udp_pkt\n    }\n\n    if args[\"--tcp\"].(bool) {\n        tcp_pkt := tcp.Make()\n        tcp_pkt.SrcPort = 49152\n        tcp_pkt.DstPort = 80\n        tcp_pkt.Flags   = tcp.Syn | tcp.ECE | tcp.Cwr\n        tcp_pkt.Seq     = uint32(rand.Intn(math.MaxUint32))\n        tcp_pkt.WindowSize = 5840\n\n        raw_pkt := raw.Make()\n        raw_pkt.Data = make([]byte, 40 - tcp_pkt.GetLength())\n\n        for i := 0; i < len(raw_pkt.Data); i++ {\n            raw_pkt.Data[i] = byte(0x40 + (i & 0x3f))\n        }\n\n        tcp_pkt.SetPayload(raw_pkt)\n\n        payload_pkt = tcp_pkt\n    }\n\n    for {\n        pkt, err := network.SendRecv(c, timeout, eth_pkt, ipv4_pkt, payload_pkt)\n        if err != nil {\n            log.Fatal(err)\n        }\n\n        ipv4_rsp := layers.FindLayer(pkt, packet.IPv4).(*ipv4.Packet)\n\n        log.Println(ipv4_rsp.SrcAddr)\n\n        if ipv4_rsp.SrcAddr.Equal(addr_ip) {\n            return\n        }\n\n        ipv4_pkt.TTL++\n        ipv4_pkt.Id++\n\n        if ipv4_pkt.TTL > 64 {\n            return\n        }\n    }\n}\n"
  },
  {
    "path": "filter/bpf_builder.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage filter\n\n// #include \"bpf_filter.h\"\nimport \"C\"\n\n// A Builder is used to compile a BPF filter from basic BPF instructions.\ntype Builder struct {\n    filter    *Filter\n    labels    map[string]int\n\n    jumps_k  map[int]string\n    jumps_jt map[int]string\n    jumps_jf map[int]string\n}\n\n// Allocate and initialize a new Builder.\nfunc NewBuilder() *Builder {\n    b := &Builder{}\n\n    b.filter   = &Filter{}\n    b.labels   = make(map[string]int)\n    b.jumps_k  = make(map[int]string)\n    b.jumps_jt = make(map[int]string)\n    b.jumps_jf = make(map[int]string)\n\n    return b\n}\n\n// Generate and return the Filter associated with the Builder.\nfunc (b *Builder) Build() *Filter {\n    prog := (*C.struct_bpf_program)(b.filter.Program())\n    flen := int(C.bpf_get_len(prog))\n\n    for i := 0; i < flen; i++ {\n        insn := C.bpf_get_insn(prog, C.int(i))\n\n        if lbl, ok := b.jumps_k[i]; ok {\n            addr := b.labels[lbl]\n            if addr != 0 {\n                insn.k = C.bpf_u_int32(addr - i - 1)\n            }\n        }\n\n        if lbl, ok := b.jumps_jt[i]; ok {\n            addr := b.labels[lbl]\n            if addr != 0 {\n                insn.jt = C.u_char(addr - i - 1)\n            }\n        }\n\n        if lbl, ok := b.jumps_jf[i]; ok {\n            addr := b.labels[lbl]\n            if addr != 0  {\n                insn.jf = C.u_char(addr - i - 1)\n            }\n        }\n    }\n\n    return b.filter\n}\n\n// Define a new label at the next instruction position. Labels are used in jump\n// instructions to identify the jump target.\nfunc (b *Builder) Label(name string) *Builder {\n    b.labels[name] = b.filter.Len()\n    return b\n}\n\n// Append an LD instruction to the filter, which loads a value of size s into\n// the accumulator. m represents the addressing mode of the source operand and\n// can be IMM (load a constant value), ABS (load packet data at the given fixed\n// offset), IND (load packet data at the given relative offset), LEN (load the\n// packet length or MEM (load a value from memory at the given offset).\nfunc (b *Builder) LD(s Size, m Mode, val uint32) *Builder {\n    code := Code(uint16(s) | uint16(m)) | LD\n    b.filter.append_insn(code, 0, 0, val)\n    return b\n}\n\n// Append a LDX (load index) instruction to the filter, which loads a value of\n// size s into the index register. m represents the addressing mode of the\n// source operand and can be IMM (load a constant value), LEN (load the packet\n// length, MEM (load a value from memory at the given offset) or MSH (load the\n// length of the IP header).\nfunc (b *Builder) LDX(s Size, m Mode, val uint32) *Builder {\n    code := Code(uint16(s) | uint16(m) | LDX)\n    b.filter.append_insn(code, 0, 0, val)\n    return b\n}\n\n// Append a ST (store) instruction to the filter, which stores the value of the\n// accumulator in memory at the given offset.\nfunc (b *Builder) ST(off uint32) *Builder {\n    b.filter.append_insn(ST, 0, 0, off)\n    return b\n}\n\n// Append a STX (store index) instruction to the filter, which stores the value\n// of the index register in memory at the given offset.\nfunc (b *Builder) STX(off uint32) *Builder {\n    b.filter.append_insn(STX, 0, 0, off)\n    return b\n}\n\n// Append an ADD instruction to the filter, which adds a value to the\n// accumulator. s represents the source operand type and can be either Const\n// (which adds the supplied value) or Index (which adds the index register\n// value).\nfunc (b *Builder) ADD(s Src, val uint32) *Builder {\n    code := Code(uint16(s) | uint16(0x00) | ALU)\n    b.filter.append_insn(code, 0, 0, val)\n    return b\n}\n\n// Append a SUB instruction to the filter, which subtracts a value from the\n// accumulator. s represents the source operand type and can be either Const\n// (which subtracts the supplied value) or Index (which subtracts the index\n// register value).\nfunc (b *Builder) SUB(s Src, val uint32) *Builder {\n    code := Code(uint16(s) | uint16(0x10) | ALU)\n    b.filter.append_insn(code, 0, 0, val)\n    return b\n}\n\n// Append a MUL instruction to the filter, which multiplies a value to the\n// accumulator. s represents the source operand type and can be either Const\n// (which multiplies the supplied value) or Index (which multiplies the index\n// register value).\nfunc (b *Builder) MUL(s Src, val uint32) *Builder {\n    code := Code(uint16(s) | uint16(0x20) | ALU)\n    b.filter.append_insn(code, 0, 0, val)\n    return b\n}\n\n// Append a DIV instruction to the filter, which divides the accumulator by a\n// value. s represents the source operand type and can be either Const (which\n// divides by the supplied value) or Index (which divides by the index register\n// value).\nfunc (b *Builder) DIV(s Src, val uint32) *Builder {\n    code := Code(uint16(s) | uint16(0x30) | ALU)\n    b.filter.append_insn(code, 0, 0, val)\n    return b\n}\n\n// Append an OR instruction to the filter, which performs the binary \"or\"\n// between the accumulator and a value. s represents the source operand type and\n// can be either Const (which uses the supplied value) or Index (which uses the\n// index register value).\nfunc (b *Builder) OR(s Src, val uint32) *Builder {\n    code := Code(uint16(s) | uint16(0x40) | ALU)\n    b.filter.append_insn(code, 0, 0, val)\n    return b\n}\n\n// Append an AND instruction to the filter, which performs the binary \"and\"\n// between the accumulator and a value. s represents the source operand type and\n// can be either Const (which uses the supplied value) or Index (which uses the\n// index register value).\nfunc (b *Builder) AND(s Src, val uint32) *Builder {\n    code := Code(uint16(s) | uint16(0x50) | ALU)\n    b.filter.append_insn(code, 0, 0, val)\n    return b\n}\n\n// Append an LSH instruction to the filter, which shifts to the left the\n// accumulator register by a value. s represents the source operand type and can\n// be either Const (which shifts by the supplied value) or Index (which shifts\n// by the index register value).\nfunc (b *Builder) LSH(s Src, val uint32) *Builder {\n    code := Code(uint16(s) | uint16(0x60) | ALU)\n    b.filter.append_insn(code, 0, 0, val)\n    return b\n}\n\n// Append an RSH instruction to the filter, which shifts to the right the\n// accumulator register by a value. s represents the source operand type and can\n// be either Const (which shifts by the supplied value) or Index (which shifts\n// by the index register value).\nfunc (b *Builder) RSH(s Src, val uint32) *Builder {\n    code := Code(uint16(s) | uint16(0x70) | ALU)\n    b.filter.append_insn(code, 0, 0, val)\n    return b\n}\n\n// Append a NEG instruction to the filter which negates the accumulator.\nfunc (b *Builder) NEG() *Builder {\n    code := Code(uint16(0x80) | ALU)\n    b.filter.append_insn(code, 0, 0, 0)\n    return b\n}\n\n// Append a MOD instruction to the filter, which computes the accumulator modulo a\n// value. s represents the source operand type and can be either Const (which\n// divides by the supplied value) or Index (which divides by the index register\n// value).\nfunc (b *Builder) MOD(s Src, val uint32) *Builder {\n    code := Code(uint16(s) | uint16(0x90) | ALU)\n    b.filter.append_insn(code, 0, 0, val)\n    return b\n}\n\n// Append an XOR instruction to the filter, which performs the binary \"xor\"\n// between the accumulator and a value. s represents the source operand type and\n// can be either Const (which uses the supplied value) or Index (which uses the\n// index register value).\nfunc (b *Builder) XOR(s Src, val uint32) *Builder {\n    code := Code(uint16(s) | uint16(0xa0) | ALU)\n    b.filter.append_insn(code, 0, 0, val)\n    return b\n}\n\n// Append a JA instruction to the filter, which performs a jump to the given\n// label.\nfunc (b *Builder) JA(j string) *Builder {\n    b.jumps_k[b.filter.Len()] = j\n\n    code := Code(uint16(0x00) | JMP)\n    b.filter.append_insn(code, 0, 0, 0)\n    return b\n}\n\n// Append a JEQ instruction to the filter, which performs a jump to the jt label\n// if the accumulator value equals cmp (if s is Const) or the index register (if\n// s is Index), otherwise jumps to jf.\nfunc (b *Builder) JEQ(s Src, jt, jf string, cmp uint32) *Builder {\n    b.jumps_jt[b.filter.Len()] = jt\n    b.jumps_jf[b.filter.Len()] = jf\n\n    code := Code(uint16(s) | uint16(0x10) | JMP)\n    b.filter.append_insn(code, 0, 0, cmp)\n    return b\n}\n\n// Append a JGT instruction to the filter, which performs a jump to the jt label\n// if the accumulator value is greater than cmp (if s is Const) or the index\n// register (if s is Index), otherwise jumps to jf.\nfunc (b *Builder) JGT(s Src, jt, jf string, cmp uint32) *Builder {\n    b.jumps_jt[b.filter.Len()] = jt\n    b.jumps_jf[b.filter.Len()] = jf\n\n    code := Code(uint16(s) | uint16(0x20) | JMP)\n    b.filter.append_insn(code, 0, 0, cmp)\n    return b\n}\n\n// Append a JGE instruction to the filter, which performs a jump to the jt label\n// if the accumulator value is greater than or equals cmp (if s is Const) or the\n// index register (if s is Index), otherwise jumps to jf.\nfunc (b *Builder) JGE(s Src, jt, jf string, cmp uint32) *Builder {\n    b.jumps_jt[b.filter.Len()] = jt\n    b.jumps_jf[b.filter.Len()] = jf\n\n    code := Code(uint16(s) | uint16(0x30) | JMP)\n    b.filter.append_insn(code, 0, 0, cmp)\n    return b\n}\n\n// Append a JSET instruction to the filter.\nfunc (b *Builder) JSET(s Src, jt, jf string, cmp uint32) *Builder {\n    b.jumps_jt[b.filter.Len()] = jt\n    b.jumps_jf[b.filter.Len()] = jf\n\n    code := Code(uint16(s) | uint16(0x40) | JMP)\n    b.filter.append_insn(code, 0, 0, cmp)\n    return b\n}\n\n// Append a RET instruction to the filter, which terminates the filter program\n// and specifies the amount of the packet to accept. s represents the source\n// operand type and can be either Const (which returns the supplied value) or\n// Acc (which returns the accumulator value).\nfunc (b *Builder) RET(s Src, bytes uint32) *Builder {\n    code := Code(uint16(s) | RET)\n    b.filter.append_insn(code, 0, 0, bytes)\n    return b\n}\n\n// Append a TAX instruction to the filter. TAX transfers the accumulator value\n// into the index register.\nfunc (b *Builder) TAX() *Builder {\n    code := Code(uint16(0x00) | MISC)\n    b.filter.append_insn(code, 0, 0, 0)\n    return b\n}\n\n// Append a TXA instruction to the filter. TXA transfers the index register\n// value into the accumulator.\nfunc (b *Builder) TXA() *Builder {\n    code := Code(uint16(0x80) | MISC)\n    b.filter.append_insn(code, 0, 0, 0)\n    return b\n}\n\n// Append a raw BPF instruction\nfunc (b *Builder) AppendInstruction(code Code, jt, jf uint8, k uint32) *Builder {\n    b.filter.append_insn(code, jt, jf, k)\n    return b\n}\n"
  },
  {
    "path": "filter/bpf_builder_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage filter_test\n\nimport \"log\"\nimport \"testing\"\n\nimport \"github.com/ghedo/go.pkt/filter\"\n\nfunc TestEmpty(t *testing.T) {\n    bld := filter.NewBuilder()\n\n    flt := bld.Build()\n    if flt.Len() != 0 {\n        t.Fatalf(\"Len mismatch: %d\", flt.Len())\n    }\n    flt.Cleanup()\n}\n\nvar test_arp = `{ 0x28,   0,   0, 0x0000000c },\n{ 0x15,   0,   1, 0x00000806 },\n{ 0x06,   0,   0, 0x00040000 },\n{ 0x06,   0,   0, 0x00000000 },`\n\nfunc TestARP(t *testing.T) {\n    arp := filter.NewBuilder().\n        LD(filter.Half, filter.ABS, 12).\n        JEQ(filter.Const, \"\", \"fail\", 0x806).\n        RET(filter.Const, 0x40000).\n        Label(\"fail\").\n        RET(filter.Const, 0x0).\n        Build()\n\n    if arp.String() != test_arp {\n        t.Fatalf(\"Program mismatch: %s\", arp.String())\n    }\n}\n\nfunc TestARPcBPF(t *testing.T) {\n    arp := filter.NewBuilder().\n    AppendInstruction(40, 0, 0, 12).\n    AppendInstruction(21, 0, 1, 2054).\n    AppendInstruction(6, 0, 0, 262144).\n    AppendInstruction(6, 0, 0, 0).\n    Build()\n\n    if arp.String() != test_arp {\n        t.Fatalf(\"Program mismatch: %s\", arp.String())\n    }\n}\n\nvar test_dns = `{ 0x00,   0,   0, 0x00000014 },\n{ 0xb1,   0,   0, 0x00000000 },\n{ 0x0c,   0,   0, 0x00000000 },\n{ 0x07,   0,   0, 0x00000000 },\n{ 0x40,   0,   0, 0x00000000 },\n{ 0x15,   0,   7, 0x07657861 },\n{ 0x40,   0,   0, 0x00000004 },\n{ 0x15,   0,   5, 0x6d706c65 },\n{ 0x40,   0,   0, 0x00000008 },\n{ 0x15,   0,   3, 0x03636f6d },\n{ 0x50,   0,   0, 0x0000000c },\n{ 0x15,   0,   1, 0x00000000 },\n{ 0x06,   0,   0, 0x00000001 },\n{ 0x06,   0,   0, 0x00000000 },`\n\nfunc TestDNS(t *testing.T) {\n    dns := filter.NewBuilder().\n        LD(filter.Word, filter.IMM, 20).\n        LDX(filter.Byte, filter.MSH, 0).\n        ADD(filter.Index, 0).\n        TAX().\n        Label(\"lb_0\").\n        LD(filter.Word, filter.IND, 0).\n        JEQ(filter.Const, \"\", \"lb_1\", 0x07657861).\n        LD(filter.Word, filter.IND, 4).\n        JEQ(filter.Const, \"\", \"lb_1\", 0x6d706c65).\n        LD(filter.Word, filter.IND, 8).\n        JEQ(filter.Const, \"\", \"lb_1\", 0x03636f6d).\n        LD(filter.Byte, filter.IND, 12).\n        JEQ(filter.Const, \"\", \"lb_1\", 0x00).\n        RET(filter.Const, 1).\n        Label(\"lb_1\").\n        RET(filter.Const, 0).\n        Build()\n\n\n    if dns.String() != test_dns {\n        t.Fatalf(\"Program mismatch: %s\", dns.String())\n    }\n}\n\nfunc TestALUOps(t *testing.T) {\n    flt := filter.NewBuilder().\n        LD(filter.Byte, filter.ABS, 0).\n        JEQ(filter.Const, \"\", \"fail\", 0x0f).\n        ADD(filter.Const, 1).\n        JEQ(filter.Const, \"\", \"fail\", 0x10).\n        SUB(filter.Const, 1).\n        JEQ(filter.Const, \"\", \"fail\", 0x0f).\n        MUL(filter.Const, 2).\n        JEQ(filter.Const, \"\", \"fail\", 0x1e).\n        DIV(filter.Const, 2).\n        JEQ(filter.Const, \"\", \"fail\", 0x0f).\n        OR(filter.Const, 0xf0).\n        JEQ(filter.Const, \"\", \"fail\", 0xff).\n        AND(filter.Const, 0x0f).\n        JEQ(filter.Const, \"\", \"fail\", 0x0f).\n        LSH(filter.Const, 4).\n        JEQ(filter.Const, \"\", \"fail\", 0xf0).\n        RSH(filter.Const, 4).\n        JEQ(filter.Const, \"\", \"fail\", 0x0f).\n        MOD(filter.Const, 0x0d).\n        JEQ(filter.Const, \"\", \"fail\", 0x02).\n        XOR(filter.Const, 0x03).\n        JEQ(filter.Const, \"\", \"fail\", 0x01).\n        RET(filter.Const, 0x40000).\n        Label(\"fail\").\n        RET(filter.Const, 0x0).\n        Build()\n\n    if !flt.Validate() {\n        t.Fatalf(\"Invalid filter: %s\", flt.String())\n    }\n\n    if !flt.Match([]byte{0x0f}) {\n        t.Fatal(\"Bad Math\")\n    }\n}\n\nfunc ExampleBuilder() {\n    // Build a filter to match ARP packets on top of Ethernet\n    flt := filter.NewBuilder().\n        LD(filter.Half, filter.ABS, 12).\n        JEQ(filter.Const, \"\", \"fail\", 0x806).\n        RET(filter.Const, 0x40000).\n        Label(\"fail\").\n        RET(filter.Const, 0x0).\n        Build()\n\n    if flt.Match([]byte(\"random data\")) {\n        log.Println(\"MATCH!!!\")\n    }\n}\n"
  },
  {
    "path": "filter/bpf_filter.c",
    "content": "/*-\n * Copyright (c) 1990, 1991, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * This code is derived from the Stanford/CMU enet packet filter,\n * (net/enet.c) distributed as part of 4.3BSD, and code contributed\n * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence\n * Berkeley Laboratory.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *      @(#)bpf_filter.c\t8.1 (Berkeley) 6/10/93\n */\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <strings.h>\n\n#include <sys/cdefs.h>\n#include <sys/param.h>\n\n#include <netinet/in.h>\n\n#ifndef __i386__\n#define BPF_ALIGN\n#endif\n\n#define EXTRACT_BYTE(p)\\\n\t((u_int8_t)\\\n\t\t((u_int8_t)*((u_char *)p)))\n\n#ifndef BPF_ALIGN\n#define EXTRACT_SHORT(p)\t((u_int16_t)ntohs(*(u_int16_t *)p))\n#define EXTRACT_LONG(p)\t\t(ntohl(*(u_int32_t *)p))\n#else\n#define EXTRACT_SHORT(p)\\\n\t((u_int16_t)\\\n\t\t((u_int16_t)*((u_char *)p+0)<<8|\\\n\t\t (u_int16_t)*((u_char *)p+1)<<0))\n#define EXTRACT_LONG(p)\\\n\t\t((u_int32_t)*((u_char *)p+0)<<24|\\\n\t\t (u_int32_t)*((u_char *)p+1)<<16|\\\n\t\t (u_int32_t)*((u_char *)p+2)<<8|\\\n\t\t (u_int32_t)*((u_char *)p+3)<<0)\n#endif\n\n#include \"bpf_filter.h\"\n\n/*\n * Execute the filter program starting at pc on the packet p\n * wirelen is the length of the original packet\n * buflen is the amount of data present\n */\nu_int\nbpf_filter(const struct bpf_insn *pc, char *p, u_int wirelen, u_int buflen)\n{\n\tu_int32_t A = 0, X = 0;\n\tu_int32_t k;\n\tu_int32_t mem[BPF_MEMWORDS];\n\n\tbzero(mem, sizeof(mem));\n\n\tif (pc == NULL)\n\t\t/*\n\t\t * No filter means accept all.\n\t\t */\n\t\treturn ((u_int)-1);\n\n\t--pc;\n\twhile (1) {\n\t\t++pc;\n\t\tswitch (pc->code) {\n\t\tdefault:\n\t\t\tabort();\n\n\t\tcase BPF_RET|BPF_K:\n\t\t\treturn ((u_int)pc->k);\n\n\t\tcase BPF_RET|BPF_A:\n\t\t\treturn ((u_int)A);\n\n\t\tcase BPF_LD|BPF_W|BPF_ABS:\n\t\t\tk = pc->k;\n\t\t\tif (k > buflen || sizeof(int32_t) > buflen - k) {\n\t\t\t\treturn (0);\n\t\t\t}\n#ifdef BPF_ALIGN\n\t\t\tif (((intptr_t)(p + k) & 3) != 0)\n\t\t\t\tA = EXTRACT_LONG(&p[k]);\n\t\t\telse\n#endif\n\t\t\t\tA = ntohl(*(int32_t *)(p + k));\n\t\t\tcontinue;\n\n\t\tcase BPF_LD|BPF_H|BPF_ABS:\n\t\t\tk = pc->k;\n\t\t\tif (k > buflen || sizeof(int16_t) > buflen - k) {\n\t\t\t\treturn (0);\n\t\t\t}\n\t\t\tA = EXTRACT_SHORT(&p[k]);\n\t\t\tcontinue;\n\n\t\tcase BPF_LD|BPF_B|BPF_ABS:\n\t\t\tk = pc->k;\n\t\t\tif (k >= buflen) {\n\t\t\t\treturn (0);\n\t\t\t}\n\t\t\tA = EXTRACT_BYTE(&p[k]);\n\t\t\tcontinue;\n\n\t\tcase BPF_LD|BPF_W|BPF_LEN:\n\t\t\tA = wirelen;\n\t\t\tcontinue;\n\n\t\tcase BPF_LDX|BPF_W|BPF_LEN:\n\t\t\tX = wirelen;\n\t\t\tcontinue;\n\n\t\tcase BPF_LD|BPF_W|BPF_IND:\n\t\t\tk = X + pc->k;\n\t\t\tif (pc->k > buflen || X > buflen - pc->k ||\n\t\t\t    sizeof(int32_t) > buflen - k) {\n\t\t\t\treturn (0);\n\t\t\t}\n#ifdef BPF_ALIGN\n\t\t\tif (((intptr_t)(p + k) & 3) != 0)\n\t\t\t\tA = EXTRACT_LONG(&p[k]);\n\t\t\telse\n#endif\n\t\t\t\tA = ntohl(*(int32_t *)(p + k));\n\t\t\tcontinue;\n\n\t\tcase BPF_LD|BPF_H|BPF_IND:\n\t\t\tk = X + pc->k;\n\t\t\tif (X > buflen || pc->k > buflen - X ||\n\t\t\t    sizeof(int16_t) > buflen - k) {\n\t\t\t\treturn (0);\n\t\t\t}\n\t\t\tA = EXTRACT_SHORT(&p[k]);\n\t\t\tcontinue;\n\n\t\tcase BPF_LD|BPF_B|BPF_IND:\n\t\t\tk = X + pc->k;\n\t\t\tif (pc->k >= buflen || X >= buflen - pc->k) {\n\t\t\t\treturn (0);\n\t\t\t}\n\t\t\tA = EXTRACT_BYTE(&p[k]);\n\t\t\tcontinue;\n\n\t\tcase BPF_LDX|BPF_MSH|BPF_B:\n\t\t\tk = pc->k;\n\t\t\tif (k >= buflen) {\n\t\t\t\treturn (0);\n\t\t\t}\n\t\t\tX = (p[pc->k] & 0xf) << 2;\n\t\t\tcontinue;\n\n\t\tcase BPF_LD|BPF_IMM:\n\t\t\tA = pc->k;\n\t\t\tcontinue;\n\n\t\tcase BPF_LDX|BPF_IMM:\n\t\t\tX = pc->k;\n\t\t\tcontinue;\n\n\t\tcase BPF_LD|BPF_MEM:\n\t\t\tA = mem[pc->k];\n\t\t\tcontinue;\n\n\t\tcase BPF_LDX|BPF_MEM:\n\t\t\tX = mem[pc->k];\n\t\t\tcontinue;\n\n\t\tcase BPF_ST:\n\t\t\tmem[pc->k] = A;\n\t\t\tcontinue;\n\n\t\tcase BPF_STX:\n\t\t\tmem[pc->k] = X;\n\t\t\tcontinue;\n\n\t\tcase BPF_JMP|BPF_JA:\n\t\t\tpc += pc->k;\n\t\t\tcontinue;\n\n\t\tcase BPF_JMP|BPF_JGT|BPF_K:\n\t\t\tpc += (A > pc->k) ? pc->jt : pc->jf;\n\t\t\tcontinue;\n\n\t\tcase BPF_JMP|BPF_JGE|BPF_K:\n\t\t\tpc += (A >= pc->k) ? pc->jt : pc->jf;\n\t\t\tcontinue;\n\n\t\tcase BPF_JMP|BPF_JEQ|BPF_K:\n\t\t\tpc += (A == pc->k) ? pc->jt : pc->jf;\n\t\t\tcontinue;\n\n\t\tcase BPF_JMP|BPF_JSET|BPF_K:\n\t\t\tpc += (A & pc->k) ? pc->jt : pc->jf;\n\t\t\tcontinue;\n\n\t\tcase BPF_JMP|BPF_JGT|BPF_X:\n\t\t\tpc += (A > X) ? pc->jt : pc->jf;\n\t\t\tcontinue;\n\n\t\tcase BPF_JMP|BPF_JGE|BPF_X:\n\t\t\tpc += (A >= X) ? pc->jt : pc->jf;\n\t\t\tcontinue;\n\n\t\tcase BPF_JMP|BPF_JEQ|BPF_X:\n\t\t\tpc += (A == X) ? pc->jt : pc->jf;\n\t\t\tcontinue;\n\n\t\tcase BPF_JMP|BPF_JSET|BPF_X:\n\t\t\tpc += (A & X) ? pc->jt : pc->jf;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_ADD|BPF_X:\n\t\t\tA += X;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_SUB|BPF_X:\n\t\t\tA -= X;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_MUL|BPF_X:\n\t\t\tA *= X;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_DIV|BPF_X:\n\t\t\tif (X == 0)\n\t\t\t\treturn (0);\n\t\t\tA /= X;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_MOD|BPF_X:\n\t\t\tif (X == 0)\n\t\t\t\treturn 0;\n\t\t\tA %= X;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_AND|BPF_X:\n\t\t\tA &= X;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_OR|BPF_X:\n\t\t\tA |= X;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_XOR|BPF_X:\n\t\t\tA ^= X;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_LSH|BPF_X:\n\t\t\tA <<= X;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_RSH|BPF_X:\n\t\t\tA >>= X;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_ADD|BPF_K:\n\t\t\tA += pc->k;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_SUB|BPF_K:\n\t\t\tA -= pc->k;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_MUL|BPF_K:\n\t\t\tA *= pc->k;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_DIV|BPF_K:\n\t\t\tA /= pc->k;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_MOD|BPF_K:\n\t\t\tA %= pc->k;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_AND|BPF_K:\n\t\t\tA &= pc->k;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_OR|BPF_K:\n\t\t\tA |= pc->k;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_XOR|BPF_K:\n\t\t\tA ^= pc->k;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_LSH|BPF_K:\n\t\t\tA <<= pc->k;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_RSH|BPF_K:\n\t\t\tA >>= pc->k;\n\t\t\tcontinue;\n\n\t\tcase BPF_ALU|BPF_NEG:\n\t\t\tA = -A;\n\t\t\tcontinue;\n\n\t\tcase BPF_MISC|BPF_TAX:\n\t\t\tX = A;\n\t\t\tcontinue;\n\n\t\tcase BPF_MISC|BPF_TXA:\n\t\t\tA = X;\n\t\t\tcontinue;\n\t\t}\n\t}\n}\n\nstatic const u_short\tbpf_code_map[] = {\n\t0x10ff,\t/* 0x00-0x0f: 1111111100001000 */\n\t0x3070,\t/* 0x10-0x1f: 0000111000001100 */\n\t0x3131,\t/* 0x20-0x2f: 1000110010001100 */\n\t0x3031,\t/* 0x30-0x3f: 1000110000001100 */\n\t0x3131,\t/* 0x40-0x4f: 1000110010001100 */\n\t0x1011,\t/* 0x50-0x5f: 1000100000001000 */\n\t0x1013,\t/* 0x60-0x6f: 1100100000001000 */\n\t0x1010,\t/* 0x70-0x7f: 0000100000001000 */\n\t0x0093,\t/* 0x80-0x8f: 1100100100000000 */\n\t0x1010,\t/* 0x90-0x9f: 0000100000001000 */\n\t0x1010,\t/* 0xa0-0xaf: 0000100000001000 */\n\t0x0002,\t/* 0xb0-0xbf: 0100000000000000 */\n\t0x0000,\t/* 0xc0-0xcf: 0000000000000000 */\n\t0x0000,\t/* 0xd0-0xdf: 0000000000000000 */\n\t0x0000,\t/* 0xe0-0xef: 0000000000000000 */\n\t0x0000\t/* 0xf0-0xff: 0000000000000000 */\n};\n\n#define\tBPF_VALIDATE_CODE(c)\t\\\n    ((c) <= 0xff && (bpf_code_map[(c) >> 4] & (1 << ((c) & 0xf))) != 0)\n\n/*\n * Return true if the 'fcode' is a valid filter program.\n * The constraints are that each jump be forward and to a valid\n * code.  The code must terminate with either an accept or reject.\n */\nint\nbpf_validate(const struct bpf_insn *f, int len)\n{\n\tregister int i;\n\tregister const struct bpf_insn *p;\n\n\t/* Do not accept negative length filter. */\n\tif (len < 0)\n\t\treturn (0);\n\n\t/* An empty filter means accept all. */\n\tif (len == 0)\n\t\treturn (1);\n\n\tfor (i = 0; i < len; ++i) {\n\t\tp = &f[i];\n\t\t/*\n\t\t * Check that the code is valid.\n\t\t */\n\t\tif (!BPF_VALIDATE_CODE(p->code))\n\t\t\treturn (0);\n\t\t/*\n\t\t * Check that that jumps are forward, and within\n\t\t * the code block.\n\t\t */\n\t\tif (BPF_CLASS(p->code) == BPF_JMP) {\n\t\t\tregister u_int offset;\n\n\t\t\tif (p->code == (BPF_JMP|BPF_JA))\n\t\t\t\toffset = p->k;\n\t\t\telse\n\t\t\t\toffset = p->jt > p->jf ? p->jt : p->jf;\n\t\t\tif (offset >= (u_int)(len - i) - 1)\n\t\t\t\treturn (0);\n\t\t\tcontinue;\n\t\t}\n\t\t/*\n\t\t * Check that memory operations use valid addresses.\n\t\t */\n\t\tif (p->code == BPF_ST || p->code == BPF_STX ||\n\t\t    p->code == (BPF_LD|BPF_MEM) ||\n\t\t    p->code == (BPF_LDX|BPF_MEM)) {\n\t\t\tif (p->k >= BPF_MEMWORDS)\n\t\t\t\treturn (0);\n\t\t\tcontinue;\n\t\t}\n\t\t/*\n\t\t * Check for constant division by 0.\n\t\t */\n\t\tif ((p->code == (BPF_ALU|BPF_DIV|BPF_K) ||\n\t\t    p->code == (BPF_ALU|BPF_MOD|BPF_K)) && p->k == 0)\n\t\t\treturn (0);\n\t}\n\treturn (BPF_CLASS(f[len - 1].code) == BPF_RET);\n}\n\nint\nbpf_append_insn(struct bpf_program *p, unsigned short code,\n                unsigned char jt, unsigned char jf, unsigned int k)\n{\n\tp->bf_insns = realloc(p->bf_insns, ++p->bf_len*sizeof(struct bpf_insn));\n\tif (p->bf_insns == NULL)\n\t\treturn -1;\n\n\tp->bf_insns[p->bf_len - 1].code = code;\n\tp->bf_insns[p->bf_len - 1].jt   = jt;\n\tp->bf_insns[p->bf_len - 1].jf   = jf;\n\tp->bf_insns[p->bf_len - 1].k    = k;\n\n\treturn 0;\n}\n\nint\nbpf_get_len(struct bpf_program *p)\n{\n\treturn p->bf_len;\n}\n\nstruct bpf_insn *\nbpf_get_insn(struct bpf_program *p, int i)\n{\n\tif (i > p->bf_len)\n\t\treturn NULL;\n\n\treturn &p->bf_insns[i];\n}\n"
  },
  {
    "path": "filter/bpf_filter.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides an API for compiling and manipulating BPF filters. A filter can be\n// either compiled from tcpdump-like expressions, or created from basic BPF\n// instructions. Filters can then be either applied to packet sources (see the\n// capture package) or directly run against binary data.\npackage filter\n\n// #include <stdlib.h>\n// #include \"bpf_filter.h\"\nimport \"C\"\n\nimport \"fmt\"\nimport \"strings\"\nimport \"syscall\"\nimport \"unsafe\"\n\ntype Filter struct {\n    program C.struct_bpf_program\n}\n\ntype Code uint16\n\nconst (\n    LD Code = syscall.BPF_LD\n    LDX     = syscall.BPF_LDX\n    ST      = syscall.BPF_ST\n    STX     = syscall.BPF_STX\n    ALU     = syscall.BPF_ALU\n    JMP     = syscall.BPF_JMP\n    RET     = syscall.BPF_RET\n    MISC    = syscall.BPF_MISC\n)\n\ntype Size uint16\n\nconst (\n    Word Size = syscall.BPF_W\n    Half      = syscall.BPF_H\n    Byte      = syscall.BPF_B\n)\n\ntype Mode uint16\n\nconst (\n    IMM Mode = syscall.BPF_IMM\n    ABS      = syscall.BPF_ABS\n    IND      = syscall.BPF_IND\n    MEM      = syscall.BPF_MEM\n    LEN      = syscall.BPF_LEN\n    MSH      = syscall.BPF_MSH\n)\n\ntype Src uint16\n\nconst (\n    Const Src = syscall.BPF_K\n    Index     = syscall.BPF_X\n    Acc       = syscall.BPF_A\n)\n\n// Try to match the given buffer against the filter.\nfunc (f *Filter) Match(buf []byte) bool {\n    cbuf := (*C.char)(unsafe.Pointer(&buf[0]))\n    blen := C.uint(len(buf))\n\n    if C.bpf_filter(f.program.bf_insns, cbuf, blen, blen) > 0 {\n        return true\n    }\n\n    return false\n}\n\n// Run filter on the given buffer and return its result.\nfunc (f *Filter) Filter(buf []byte) uint {\n    cbuf := (*C.char)(unsafe.Pointer(&buf[0]))\n    blen := C.uint(len(buf))\n\n    rc := C.bpf_filter(f.program.bf_insns, cbuf, blen, blen)\n    return uint(rc)\n}\n\n// Validate the filter. The constraints are that each jump be forward and to a\n// valid code. The code must terminate with either an accept or reject.\nfunc (f *Filter) Validate() bool {\n    if C.bpf_validate(f.program.bf_insns, C.int(f.program.bf_len)) > 0 {\n        return true\n    }\n\n    return false\n}\n\n// Deallocate the filter.\nfunc (f *Filter) Cleanup() {\n    f.program.bf_len = 0\n\n    if f.program.bf_insns != nil {\n        C.free(unsafe.Pointer(f.program.bf_insns))\n        f.program.bf_insns = nil\n    }\n}\n\n// Return the number of instructions in the filter.\nfunc (f *Filter) Len() int {\n    prog := (*C.struct_bpf_program)(f.Program())\n    flen := C.bpf_get_len(prog)\n    return int(flen)\n}\n\n// Return the compiled BPF program.\nfunc (f *Filter) Program() unsafe.Pointer {\n    return unsafe.Pointer(&f.program)\n}\n\nfunc (f *Filter) String() string {\n    var insns []string\n\n    prog := (*C.struct_bpf_program)(f.Program())\n    flen := C.bpf_get_len(prog)\n\n    for i := C.int(0); i < flen; i++ {\n        insn := C.bpf_get_insn(prog, i)\n\n        str := fmt.Sprintf(\n            \"{ 0x%.2x, %3d, %3d, 0x%.8x },\",\n            insn.code, insn.jt, insn.jf, insn.k,\n        )\n\n        insns = append(insns, str)\n    }\n\n    return strings.Join(insns, \"\\n\")\n}\n\nfunc (f *Filter) append_insn(code Code, jt, jf uint8, k uint32) {\n    prog := (*C.struct_bpf_program)(f.Program())\n    C.bpf_append_insn(\n        prog, C.ushort(code), C.uchar(jt), C.uchar(jf), C.uint(k),\n    )\n}\n"
  },
  {
    "path": "filter/bpf_filter.h",
    "content": "/*-\n * Copyright (c) 1990, 1991, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * This code is derived from the Stanford/CMU enet packet filter,\n * (net/enet.c) distributed as part of 4.3BSD, and code contributed\n * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence\n * Berkeley Laboratory.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *      @(#)bpf.h\t8.1 (Berkeley) 6/10/93\n *\t@(#)bpf.h\t1.34 (LBL)     6/16/96\n *\n * $FreeBSD$\n */\n\ntypedef unsigned int bpf_u_int32; /* cgo is stupid... */\ntypedef unsigned char u_char; /* oh, so stupid... */\n\nstruct bpf_program {\n\tunsigned int    bf_len; /* u_int */\n\tstruct bpf_insn *bf_insns;\n};\n\n/*\n * The instruction encodings.\n */\n/* instruction classes */\n#define BPF_CLASS(code) ((code) & 0x07)\n#define\t\tBPF_LD\t\t0x00\n#define\t\tBPF_LDX\t\t0x01\n#define\t\tBPF_ST\t\t0x02\n#define\t\tBPF_STX\t\t0x03\n#define\t\tBPF_ALU\t\t0x04\n#define\t\tBPF_JMP\t\t0x05\n#define\t\tBPF_RET\t\t0x06\n#define\t\tBPF_MISC\t0x07\n\n/* ld/ldx fields */\n#define BPF_SIZE(code)\t((code) & 0x18)\n#define\t\tBPF_W\t\t0x00\n#define\t\tBPF_H\t\t0x08\n#define\t\tBPF_B\t\t0x10\n#define BPF_MODE(code)\t((code) & 0xe0)\n#define\t\tBPF_IMM \t0x00\n#define\t\tBPF_ABS\t\t0x20\n#define\t\tBPF_IND\t\t0x40\n#define\t\tBPF_MEM\t\t0x60\n#define\t\tBPF_LEN\t\t0x80\n#define\t\tBPF_MSH\t\t0xa0\n\n/* alu/jmp fields */\n#define BPF_OP(code)\t((code) & 0xf0)\n#define\t\tBPF_ADD\t\t0x00\n#define\t\tBPF_SUB\t\t0x10\n#define\t\tBPF_MUL\t\t0x20\n#define\t\tBPF_DIV\t\t0x30\n#define\t\tBPF_OR\t\t0x40\n#define\t\tBPF_AND\t\t0x50\n#define\t\tBPF_LSH\t\t0x60\n#define\t\tBPF_RSH\t\t0x70\n#define\t\tBPF_NEG\t\t0x80\n#define\t\tBPF_MOD\t\t0x90\n#define\t\tBPF_XOR\t\t0xa0\n\n#define\t\tBPF_JA\t\t0x00\n#define\t\tBPF_JEQ\t\t0x10\n#define\t\tBPF_JGT\t\t0x20\n#define\t\tBPF_JGE\t\t0x30\n#define\t\tBPF_JSET\t0x40\n#define BPF_SRC(code)\t((code) & 0x08)\n#define\t\tBPF_K\t\t0x00\n#define\t\tBPF_X\t\t0x08\n\n/* ret - BPF_K and BPF_X also apply */\n#define BPF_RVAL(code)\t((code) & 0x18)\n#define\t\tBPF_A\t\t0x10\n\n/* misc */\n#define BPF_MISCOP(code) ((code) & 0xf8)\n#define\t\tBPF_TAX\t\t0x00\n#define\t\tBPF_TXA\t\t0x80\n\n/*\n * The instruction data structure.\n */\nstruct bpf_insn {\n\tunsigned short code; /* u_short   */\n\tunsigned char  jt;   /* u_char    */\n\tunsigned char  jf;   /* u_char    */\n\tunsigned int   k;    /* u_int32_t */\n};\n\n/*\n * Macros for insn array initializers.\n */\n#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }\n#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }\n\n/*\n * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST).\n */\n#define BPF_MEMWORDS 16\n\nunsigned int bpf_filter(const struct bpf_insn *pc, char *p,\n                        unsigned int wirelen, unsigned int buflen);\n\nint bpf_validate(const struct bpf_insn *f, int len);\n\nint bpf_append_insn(struct bpf_program *p, unsigned short code,\n                unsigned char jt, unsigned char jf, unsigned int k);\n\nint bpf_get_len(struct bpf_program *p);\n\nstruct bpf_insn *bpf_get_insn(struct bpf_program *p, int i);\n"
  },
  {
    "path": "filter/bpf_filter_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage filter_test\n\nimport \"log\"\nimport \"testing\"\n\nimport \"github.com/ghedo/go.pkt/filter\"\nimport \"github.com/ghedo/go.pkt/packet\"\n\nvar test_eth_arp = []byte{\n    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,\n    0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x4c, 0x72,\n    0xb9, 0x54, 0xe5, 0x3d, 0xc0, 0xa8, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0xc1, 0x1b, 0xd0, 0x25,\n}\n\nvar test_eth_vlan_arp = []byte{\n    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,\n    0x81, 0x00, 0x00, 0x87, 0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04,\n    0x00, 0x01, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d, 0xc0, 0xa8, 0x01, 0x87,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x1b, 0xd0, 0x25,\n}\n\nvar test_eth_ipv4_udp = []byte{\n    0x00, 0x21, 0x96, 0x6e, 0xf0, 0x70, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,\n    0x08, 0x00, 0x45, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,\n    0x27, 0x60, 0xc0, 0xa8, 0x01, 0x87, 0xc1, 0x1b, 0xd0, 0x25, 0xa2, 0x5a,\n    0x20, 0x92, 0x00, 0x08, 0xe9, 0x80,\n}\n\nvar test_eth_ipv4_tcp = []byte{\n    0x00, 0x21, 0x96, 0x6e, 0xf0, 0x70, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,\n    0x08, 0x00, 0x45, 0x00, 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06,\n    0x27, 0x5f, 0xc0, 0xa8, 0x01, 0x87, 0xc1, 0x1b, 0xd0, 0x25, 0xa2, 0x5a,\n    0x20, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02,\n    0x20, 0x00, 0x79, 0x85, 0x00, 0x00,\n}\n\nvar test_ipv4_tcp_single_byte = []byte{\n    0x45, 0x00, 0x00, 0x3c, 0xf4, 0x65, 0x40, 0x00, 0x36, 0x06, 0x07, 0xec,\n    0x6e, 0x34, 0x6d, 0x8c, 0x3d, 0x36, 0x2f, 0x74, 0x98, 0x64, 0x00, 0x50,\n    0xa4, 0x30, 0x06, 0xd1, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x39, 0x08,\n    0x90, 0x33, 0x00, 0x00, 0x02, 0x04, 0x05, 0xa0, 0x04, 0x02, 0x08, 0x0a,\n    0x00, 0x04, 0xf2, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x06,\n}\n\nfunc TestMatch(t *testing.T) {\n    arp, err := filter.Compile(\"arp\", packet.Eth, false)\n    if err != nil {\n        t.Fatalf(\"Error compiling arp\")\n    }\n\n    if !arp.Validate() {\n        t.Fatalf(\"Invalid filter ARP\\n%s\", arp)\n    }\n\n    udp, err := filter.Compile(\"udp\", packet.Eth, false)\n    if err != nil {\n        t.Fatalf(\"Error compiling udp\")\n    }\n\n    port, err := filter.Compile(\"port 8338\", packet.Eth, false)\n    if err != nil {\n        t.Fatalf(\"Error compiling port\")\n    }\n\n    single, err := filter.Compile(\"tcp[12] != 0xa0\", packet.IPv4, false)\n    if err != nil {\n        t.Fatalf(\"Error compiling single\")\n    }\n\n    if !arp.Match(test_eth_arp) {\n        t.Fatalf(\"ARP mismatch\")\n    }\n\n    if arp.Match(test_eth_ipv4_udp) {\n        t.Fatalf(\"ARP matched (but it shouldn't have)\")\n    }\n\n    if !udp.Match(test_eth_ipv4_udp) {\n        t.Fatalf(\"ARP mismatch\")\n    }\n\n    if udp.Match(test_eth_ipv4_tcp) {\n        t.Fatalf(\"UDP matched (but it shouldn't have)\")\n    }\n\n    if !port.Match(test_eth_ipv4_udp) {\n        t.Fatalf(\"UDP port mismatch\")\n    }\n\n    if !port.Match(test_eth_ipv4_tcp) {\n        t.Fatalf(\"TCP port mismatch\")\n    }\n\n    if port.Match(test_eth_vlan_arp) {\n        t.Fatalf(\"Port matched (but it shouldn't have)\")\n    }\n\n    if single.Match(test_ipv4_tcp_single_byte) {\n        t.Fatalf(\"Byte matched (but it shouldn't have)\")\n    }\n}\n\nfunc BenchmarkMatch(b *testing.B) {\n    test_filter, _ := filter.Compile(\"port 8338\", packet.Eth, false)\n\n    for n := 0; n < b.N; n++ {\n        test_filter.Match(test_eth_ipv4_tcp)\n    }\n}\n\nfunc ExampleFilter() {\n    // Match UDP or TCP packets on top of Ethernet\n    flt, err := filter.Compile(\"udp or tcp\", packet.Eth, false)\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    if flt.Match([]byte(\"random data\")) {\n        log.Println(\"MATCH!!!\")\n    }\n}\n"
  },
  {
    "path": "filter/pcap.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage filter\n\n// #cgo LDFLAGS: -lpcap\n// #include <stdlib.h>\n// #include <pcap.h>\nimport \"C\"\n\nimport \"fmt\"\nimport \"unsafe\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\n\n// Compile the given tcpdump-like expression to a BPF filter.\nfunc Compile(filter string, link_type packet.Type, optimize bool) (*Filter, error) {\n    var do_optimize int\n\n    if optimize {\n        do_optimize = 1\n    } else {\n        do_optimize = 0\n    }\n\n    f := &Filter{}\n\n    filter_str := C.CString(filter)\n    defer C.free(unsafe.Pointer(filter_str))\n\n    pcap_type := link_type.ToLinkType()\n\n    err := C.pcap_compile_nopcap(\n        C.int(0x7fff), C.int(pcap_type),\n        (*C.struct_bpf_program)(f.Program()),\n        filter_str, C.int(do_optimize), 0xffffffff,\n    )\n    if err < 0 {\n        return nil, fmt.Errorf(\"Could not compile filter\")\n    }\n\n    return f, nil\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/ghedo/go.pkt\n\nrequire (\n\tgithub.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815\n\tgithub.com/songgao/water v0.0.0-20180420064739-bf1a5d02778f\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=\ngithub.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=\ngithub.com/songgao/water v0.0.0-20180420064739-bf1a5d02778f h1:UExbpoG328zaxx4MhWPRZZpc527IdNUfQ1Z0uejVddc=\ngithub.com/songgao/water v0.0.0-20180420064739-bf1a5d02778f/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=\n"
  },
  {
    "path": "layers/layers.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides utility functions for encoding and decoding packets to/from binary\n// data. Differently from the basic \"packet\" interface, this can encode and\n// decode complete \"stacks\" of packets, instead of manipulating single ones.\npackage layers\n\nimport \"github.com/ghedo/go.pkt/packet\"\n\nimport \"github.com/ghedo/go.pkt/packet/arp\"\nimport \"github.com/ghedo/go.pkt/packet/eth\"\nimport \"github.com/ghedo/go.pkt/packet/icmpv4\"\nimport \"github.com/ghedo/go.pkt/packet/icmpv6\"\nimport \"github.com/ghedo/go.pkt/packet/ipv4\"\nimport \"github.com/ghedo/go.pkt/packet/ipv6\"\nimport \"github.com/ghedo/go.pkt/packet/llc\"\nimport \"github.com/ghedo/go.pkt/packet/radiotap\"\nimport \"github.com/ghedo/go.pkt/packet/raw\"\nimport \"github.com/ghedo/go.pkt/packet/sll\"\nimport \"github.com/ghedo/go.pkt/packet/snap\"\nimport \"github.com/ghedo/go.pkt/packet/tcp\"\nimport \"github.com/ghedo/go.pkt/packet/udp\"\nimport \"github.com/ghedo/go.pkt/packet/vlan\"\n\n// Compose packets into a chain and update their values (e.g. length, payload\n// protocol) accordingly.\nfunc Compose(pkts ...packet.Packet) (packet.Packet, error) {\n    next_pkt := packet.Packet(nil)\n\n    for i := len(pkts) - 1; i >= 0; i-- {\n        if next_pkt != nil {\n            err := pkts[i].SetPayload(next_pkt)\n            if err != nil {\n                return nil, err\n            }\n        }\n\n        next_pkt = pkts[i]\n    }\n\n    return pkts[0], nil\n}\n\n// Pack packets into their binary form. This will stack the packets before\n// encoding them (see the Compose() method) and also calculate the checksums.\nfunc Pack(pkts ...packet.Packet) ([]byte, error) {\n    var buf packet.Buffer\n\n    base_pkt, err := Compose(pkts...)\n    if err != nil {\n        return nil, err\n    }\n\n    tot_len := int(base_pkt.GetLength())\n\n    buf.Init(make([]byte, tot_len))\n\n    for i := len(pkts) - 1; i >= 0; i-- {\n        cur_pkt := pkts[i]\n        cur_len := int(cur_pkt.GetLength())\n\n        buf.SetOffset(tot_len - cur_len)\n        buf.NewLayer()\n\n        err := cur_pkt.Pack(&buf)\n        if err != nil {\n            return nil, err\n        }\n    }\n\n    buf.SetOffset(0)\n\n    return buf.Bytes(), nil\n}\n\n// Unpack the given byte slice into the packet list supplied. Note that this\n// will not check whether the packet types provided match the raw data. If the\n// packet types to be decoded are unknown, UnpackAll() should be used instead.\n//\n// Note that unpacking is done without copying the input slice, which means that\n// if the slice is modifed, it may affect the packets that where unpacked from\n// it. If you can't guarantee that the data slice won't change, you'll need to\n// copy it and pass the copy to Unpack().\nfunc Unpack(buf []byte, pkts ...packet.Packet) (packet.Packet, error) {\n    var b packet.Buffer\n    b.Init(buf)\n\n    prev_pkt := packet.Packet(nil)\n\n    for _, p := range pkts {\n        if b.Len() <= 0 {\n            break\n        }\n\n        b.NewLayer()\n\n        err := p.Unpack(&b)\n        if err != nil {\n            return nil, err\n        }\n\n        if prev_pkt != nil {\n            prev_pkt.SetPayload(p)\n        }\n\n        if p.GuessPayloadType() == packet.None {\n            break\n        }\n\n        prev_pkt = p\n    }\n\n    return pkts[0], nil\n}\n\n\n// Recursively unpack the given byte slice into a packet. The link_type argument\n// must specify the type of the first layer in the input data, successive layers\n// will be detected automatically.\n//\n// Note that unpacking is done without copying the input slice, which means that\n// if the slice is modifed, it may affect the packets that where unpacked from\n// it. If you can't guarantee that the data slice won't change, you'll need to\n// copy it and pass the copy to UnpackAll().\nfunc UnpackAll(buf []byte, link_type packet.Type) (packet.Packet, error) {\n    var b packet.Buffer\n    b.Init(buf)\n\n    first_pkt := packet.Packet(nil)\n    prev_pkt  := packet.Packet(nil)\n\n    for link_type != packet.None {\n        var p packet.Packet\n\n        if b.Len() <= 0 {\n            break\n        }\n\n        switch link_type {\n        case packet.ARP:      p = &arp.Packet{}\n        case packet.Eth:      p = &eth.Packet{}\n        case packet.ICMPv4:   p = &icmpv4.Packet{}\n        case packet.ICMPv6:   p = &icmpv6.Packet{}\n        case packet.IPv4:     p = &ipv4.Packet{}\n        case packet.IPv6:     p = &ipv6.Packet{}\n        case packet.LLC:      p = &llc.Packet{}\n        case packet.RadioTap: p = &radiotap.Packet{}\n        case packet.SLL:      p = &sll.Packet{}\n        case packet.SNAP:     p = &snap.Packet{}\n        case packet.TCP:      p = &tcp.Packet{}\n        case packet.UDP:      p = &udp.Packet{}\n        case packet.VLAN:     p = &vlan.Packet{}\n        default:              p = &raw.Packet{}\n        }\n\n        if p == nil {\n            break\n        }\n\n        b.NewLayer()\n\n        err := p.Unpack(&b)\n        if err != nil {\n            return nil, err\n        }\n\n        if prev_pkt != nil {\n            prev_pkt.SetPayload(p)\n        } else {\n            first_pkt = p\n        }\n\n        prev_pkt  = p\n        link_type = p.GuessPayloadType()\n    }\n\n    return first_pkt, nil\n}\n\n// Return the first layer of the given type in the packet. If no suitable layer\n// is found, return nil.\nfunc FindLayer(p packet.Packet, layer packet.Type) packet.Packet {\n    switch {\n    case p == nil:\n        return nil\n\n    case p.GetType() == layer:\n        return p\n\n    default:\n        return FindLayer(p.Payload(), layer)\n    }\n}\n"
  },
  {
    "path": "layers/layers_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage layers_test\n\nimport \"bytes\"\nimport \"log\"\nimport \"net\"\nimport \"testing\"\n\nimport \"github.com/ghedo/go.pkt/layers\"\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/arp\"\nimport \"github.com/ghedo/go.pkt/packet/eth\"\nimport \"github.com/ghedo/go.pkt/packet/ipv4\"\nimport \"github.com/ghedo/go.pkt/packet/raw\"\nimport \"github.com/ghedo/go.pkt/packet/udp\"\nimport \"github.com/ghedo/go.pkt/packet/tcp\"\nimport \"github.com/ghedo/go.pkt/packet/vlan\"\n\nvar hwsrc_str = \"4c:72:b9:54:e5:3d\"\nvar hwdst_str = \"00:21:96:6e:f0:70\"\n\nvar ipsrc_str = \"192.168.1.135\"\nvar ipdst_str = \"193.27.208.37\"\n\nvar test_eth_arp = []byte{\n    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,\n    0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x4c, 0x72,\n    0xb9, 0x54, 0xe5, 0x3d, 0xc0, 0xa8, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0xc1, 0x1b, 0xd0, 0x25,\n}\n\nfunc TestPackEthArp(t *testing.T) {\n    eth_pkt := eth.Make()\n    eth_pkt.SrcAddr, _ = net.ParseMAC(hwsrc_str)\n    eth_pkt.DstAddr, _ = net.ParseMAC(\"ff:ff:ff:ff:ff:ff\")\n\n    arp_pkt := arp.Make()\n    arp_pkt.HWSrcAddr, _ = net.ParseMAC(hwsrc_str)\n    arp_pkt.HWDstAddr, _ = net.ParseMAC(\"00:00:00:00:00:00\")\n    arp_pkt.ProtoSrcAddr = net.ParseIP(ipsrc_str)\n    arp_pkt.ProtoDstAddr = net.ParseIP(ipdst_str)\n\n    buf, err := layers.Pack(eth_pkt, arp_pkt)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_eth_arp, buf) {\n        t.Fatalf(\"Raw packet mismatch: %x\", buf)\n    }\n}\n\nfunc TestUnpackEthArp(t *testing.T) {\n    _, err := layers.Unpack(test_eth_arp, &eth.Packet{}, &arp.Packet{})\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n}\n\nfunc BenchmarkUnpackEthArp(bn *testing.B) {\n    var eth_pkt eth.Packet\n    var arp_pkt arp.Packet\n\n    for n := 0; n < bn.N; n++ {\n        layers.Unpack(test_eth_arp, &eth_pkt, &arp_pkt)\n    }\n}\n\nfunc TestUnpackAllEthArp(t *testing.T) {\n    pkt, err := layers.UnpackAll(test_eth_arp, packet.Eth)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if pkt.GetType() != packet.Eth {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.GetType())\n    }\n\n    if pkt.Payload().GetType() != packet.ARP {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.Payload().GetType())\n    }\n}\n\nfunc BenchmarkUnpackAllEthArp(bn *testing.B) {\n    for n := 0; n < bn.N; n++ {\n        layers.UnpackAll(test_eth_arp, packet.Eth)\n    }\n}\n\nvar test_eth_vlan_arp = []byte{\n    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,\n    0x81, 0x00, 0x00, 0x87, 0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04,\n    0x00, 0x01, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d, 0xc0, 0xa8, 0x01, 0x87,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x1b, 0xd0, 0x25,\n}\n\nfunc TestPackEthVLANArp(t *testing.T) {\n    eth_pkt := eth.Make()\n    eth_pkt.SrcAddr, _ = net.ParseMAC(hwsrc_str)\n    eth_pkt.DstAddr, _ = net.ParseMAC(\"ff:ff:ff:ff:ff:ff\")\n\n    vlan_pkt := vlan.Make()\n    vlan_pkt.VLAN = 135\n\n    arp_pkt := arp.Make()\n    arp_pkt.HWSrcAddr, _ = net.ParseMAC(hwsrc_str)\n    arp_pkt.HWDstAddr, _ = net.ParseMAC(\"00:00:00:00:00:00\")\n    arp_pkt.ProtoSrcAddr = net.ParseIP(ipsrc_str)\n    arp_pkt.ProtoDstAddr = net.ParseIP(ipdst_str)\n\n    buf, err := layers.Pack(eth_pkt, vlan_pkt, arp_pkt)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_eth_vlan_arp, buf) {\n        t.Fatalf(\"Raw packet mismatch: %x\", buf)\n    }\n}\n\nfunc TestUnpackEthVLANArp(t *testing.T) {\n    _, err := layers.Unpack(test_eth_arp, &eth.Packet{}, &vlan.Packet{}, &arp.Packet{})\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n}\n\nfunc BenchmarkUnpackEthVLANArp(bn *testing.B) {\n    var eth_pkt eth.Packet\n    var vlan_pkt vlan.Packet\n    var arp_pkt arp.Packet\n\n    for n := 0; n < bn.N; n++ {\n        layers.Unpack(test_eth_vlan_arp, &eth_pkt, &vlan_pkt, &arp_pkt)\n    }\n}\n\nfunc TestUnpackAllEthVLANArp(t *testing.T) {\n    pkt, err := layers.UnpackAll(test_eth_vlan_arp, packet.Eth)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if pkt.GetType() != packet.Eth {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.GetType())\n    }\n\n    pkt = pkt.Payload()\n    if pkt.GetType() != packet.VLAN {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.GetType())\n    }\n\n    pkt = pkt.Payload()\n    if pkt.GetType() != packet.ARP {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.GetType())\n    }\n}\n\nfunc BenchmarkUnpackAllEthVLANArp(bn *testing.B) {\n    for n := 0; n < bn.N; n++ {\n        layers.UnpackAll(test_eth_vlan_arp, packet.Eth)\n    }\n}\n\nvar test_eth_ipv4_udp = []byte{\n    0x00, 0x21, 0x96, 0x6e, 0xf0, 0x70, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,\n    0x08, 0x00, 0x45, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,\n    0x27, 0x60, 0xc0, 0xa8, 0x01, 0x87, 0xc1, 0x1b, 0xd0, 0x25, 0xa2, 0x5a,\n    0x20, 0x92, 0x00, 0x08, 0xe9, 0x80,\n}\n\nfunc TestPackEthIPv4UDP(t *testing.T) {\n    eth_pkt := eth.Make()\n    eth_pkt.SrcAddr, _ = net.ParseMAC(hwsrc_str)\n    eth_pkt.DstAddr, _ = net.ParseMAC(hwdst_str)\n\n    ip4_pkt := ipv4.Make()\n    ip4_pkt.SrcAddr = net.ParseIP(ipsrc_str)\n    ip4_pkt.DstAddr = net.ParseIP(ipdst_str)\n\n    udp_pkt := udp.Make()\n    udp_pkt.SrcPort = 41562\n    udp_pkt.DstPort = 8338\n\n    buf, err := layers.Pack(eth_pkt, ip4_pkt, udp_pkt)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_eth_ipv4_udp, buf) {\n        t.Fatalf(\"Raw packet mismatch: %x\", buf)\n    }\n}\n\nfunc TestUnpackEthUPv4UDP(t *testing.T) {\n    var eth_pkt eth.Packet\n    var ip4_pkt ipv4.Packet\n    var udp_pkt udp.Packet\n\n    _, err := layers.Unpack(test_eth_ipv4_udp, &eth_pkt, &ip4_pkt, &udp_pkt)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n}\n\nfunc BenchmarkUnpackEthUPv4UDP(bn *testing.B) {\n    var eth_pkt eth.Packet\n    var ip4_pkt ipv4.Packet\n    var udp_pkt udp.Packet\n\n    for n := 0; n < bn.N; n++ {\n        layers.Unpack(test_eth_ipv4_udp, &eth_pkt, &ip4_pkt, &udp_pkt)\n    }\n}\n\nfunc TestUnpackAllEthIPv4UDP(t *testing.T) {\n    pkt, err := layers.UnpackAll(test_eth_ipv4_udp, packet.Eth)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if pkt.GetType() != packet.Eth {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.GetType())\n    }\n\n    pkt = pkt.Payload()\n    if pkt.GetType() != packet.IPv4 {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.GetType())\n    }\n\n    pkt = pkt.Payload()\n    if pkt.GetType() != packet.UDP {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.GetType())\n    }\n}\n\nfunc BenchmarkUnpackAllEthIPv4UDP(bn *testing.B) {\n    for n := 0; n < bn.N; n++ {\n        layers.UnpackAll(test_eth_ipv4_udp, packet.Eth)\n    }\n}\n\nvar test_eth_ipv4_udp_raw = []byte{\n    0x00, 0x21, 0x96, 0x6e, 0xf0, 0x70, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,\n    0x08, 0x00, 0x45, 0x00, 0x00, 0x42, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,\n    0x27, 0x3a, 0xc0, 0xa8, 0x01, 0x87, 0xc1, 0x1b, 0xd0, 0x25, 0xa2, 0x5a,\n    0x20, 0x92, 0x00, 0x2e, 0x07, 0x03, 0x66, 0x64, 0x67, 0x20, 0x61, 0x67,\n    0x66, 0x68, 0x20, 0x6c, 0x64, 0x66, 0x68, 0x67, 0x6b, 0x20, 0x68, 0x66,\n    0x64, 0x6b, 0x67, 0x68, 0x20, 0x6b, 0x66, 0x6a, 0x64, 0x68, 0x73, 0x67,\n    0x20, 0x6b, 0x73, 0x68, 0x66, 0x64, 0x67, 0x6b,\n}\n\nfunc TestPackEthIPv4UDPRaw(t *testing.T) {\n    eth_pkt := eth.Make()\n    eth_pkt.SrcAddr, _ = net.ParseMAC(hwsrc_str)\n    eth_pkt.DstAddr, _ = net.ParseMAC(hwdst_str)\n\n    ip4_pkt := ipv4.Make()\n    ip4_pkt.SrcAddr = net.ParseIP(ipsrc_str)\n    ip4_pkt.DstAddr = net.ParseIP(ipdst_str)\n\n    udp_pkt := udp.Make()\n    udp_pkt.SrcPort = 41562\n    udp_pkt.DstPort = 8338\n\n    raw_pkt := raw.Make()\n    raw_pkt.Data = []byte(\"fdg agfh ldfhgk hfdkgh kfjdhsg kshfdgk\")\n\n    data, err := layers.Pack(eth_pkt, ip4_pkt, udp_pkt, raw_pkt)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if ip4_pkt.GetLength() != 66 {\n        t.Fatalf(\"IPv4 length mismatch: %d\", ip4_pkt.GetLength())\n    }\n\n    if udp_pkt.GetLength() != 46 {\n        t.Fatalf(\"UDP length mismatch: %d\", udp_pkt.GetLength())\n    }\n\n    if !bytes.Equal(test_eth_ipv4_udp_raw, data) {\n        t.Fatalf(\"Raw packet mismatch: %x\", data)\n    }\n}\n\nfunc TestUnpackEthUPv4UDPRaw(t *testing.T) {\n    var eth_pkt eth.Packet\n    var ip4_pkt ipv4.Packet\n    var udp_pkt udp.Packet\n    var raw_pkt raw.Packet\n\n    _, err := layers.Unpack(test_eth_ipv4_udp_raw,\n                            &eth_pkt, &ip4_pkt, &udp_pkt, &raw_pkt)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n}\n\nfunc BenchmarkUnpackEthUPv4UDPRaw(bn *testing.B) {\n    var eth_pkt eth.Packet\n    var ip4_pkt ipv4.Packet\n    var udp_pkt udp.Packet\n    var raw_pkt raw.Packet\n\n    for n := 0; n < bn.N; n++ {\n        layers.Unpack(test_eth_ipv4_udp_raw,\n                      &eth_pkt, &ip4_pkt, &udp_pkt, &raw_pkt)\n    }\n}\n\nfunc TestUnpackAllEthIPv4UDPRaw(t *testing.T) {\n    pkt, err := layers.UnpackAll(test_eth_ipv4_udp_raw, packet.Eth)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if pkt.GetType() != packet.Eth {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.GetType())\n    }\n\n    pkt = pkt.Payload()\n    if pkt.GetType() != packet.IPv4 {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.GetType())\n    }\n\n    pkt = pkt.Payload()\n    if pkt.GetType() != packet.UDP {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.GetType())\n    }\n\n    pkt = pkt.Payload()\n    if pkt.GetType() != packet.Raw {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.GetType())\n    }\n}\n\nfunc BenchmarkUnpackAllEthIPv4UDPRaw(bn *testing.B) {\n    for n := 0; n < bn.N; n++ {\n        layers.UnpackAll(test_eth_ipv4_udp_raw, packet.Eth)\n    }\n}\n\nvar test_eth_ipv4_tcp = []byte{\n    0x00, 0x21, 0x96, 0x6e, 0xf0, 0x70, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,\n    0x08, 0x00, 0x45, 0x00, 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06,\n    0x27, 0x5f, 0xc0, 0xa8, 0x01, 0x87, 0xc1, 0x1b, 0xd0, 0x25, 0xa2, 0x5a,\n    0x20, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02,\n    0x20, 0x00, 0x79, 0x85, 0x00, 0x00,\n}\n\nfunc TestPackEthIPv4TCP(t *testing.T) {\n    eth_pkt := eth.Make()\n    eth_pkt.SrcAddr, _ = net.ParseMAC(hwsrc_str)\n    eth_pkt.DstAddr, _ = net.ParseMAC(hwdst_str)\n\n    ip4_pkt := ipv4.Make()\n    ip4_pkt.SrcAddr = net.ParseIP(ipsrc_str)\n    ip4_pkt.DstAddr = net.ParseIP(ipdst_str)\n\n    tcp_pkt := tcp.Make()\n    tcp_pkt.SrcPort = 41562\n    tcp_pkt.DstPort = 8338\n    tcp_pkt.Flags   = tcp.Syn\n    tcp_pkt.WindowSize = 8192\n\n    buf, err := layers.Pack(eth_pkt, ip4_pkt, tcp_pkt)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_eth_ipv4_tcp, buf) {\n        t.Fatalf(\"Raw packet mismatch: %x\", buf)\n    }\n}\n\nfunc TestUnpackEthUPv4TCP(t *testing.T) {\n    var eth_pkt eth.Packet\n    var ip4_pkt ipv4.Packet\n    var tcp_pkt tcp.Packet\n\n    _, err := layers.Unpack(test_eth_ipv4_tcp, &eth_pkt, &ip4_pkt, &tcp_pkt)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n}\n\nfunc BenchmarkUnpackEthUPv4TCP(bn *testing.B) {\n    var eth_pkt eth.Packet\n    var ip4_pkt ipv4.Packet\n    var tcp_pkt tcp.Packet\n\n    for n := 0; n < bn.N; n++ {\n        layers.Unpack(test_eth_ipv4_tcp, &eth_pkt, &ip4_pkt, &tcp_pkt)\n    }\n}\n\nfunc TestUnpackAllEthIPv4TCP(t *testing.T) {\n    pkt, err := layers.UnpackAll(test_eth_ipv4_tcp, packet.Eth)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if pkt.GetType() != packet.Eth {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.GetType())\n    }\n\n    pkt = pkt.Payload()\n    if pkt.GetType() != packet.IPv4 {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.GetType())\n    }\n\n    pkt = pkt.Payload()\n    if pkt.GetType() != packet.TCP {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.GetType())\n    }\n}\n\nfunc BenchmarkUnpackAllEthIPv4TCP(bn *testing.B) {\n    for n := 0; n < bn.N; n++ {\n        layers.UnpackAll(test_eth_ipv4_tcp, packet.Eth)\n    }\n}\n\nvar test_eth_ipv4_tcp_raw = []byte{\n    0x00, 0x21, 0x96, 0x6e, 0xf0, 0x70, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,\n    0x08, 0x00, 0x45, 0x00, 0x00, 0x4e, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06,\n    0x27, 0x39, 0xc0, 0xa8, 0x01, 0x87, 0xc1, 0x1b, 0xd0, 0x25, 0xa2, 0x5a,\n    0x20, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02,\n    0x20, 0x00, 0x97, 0x2d, 0x00, 0x00, 0x66, 0x64, 0x67, 0x20, 0x61, 0x67,\n    0x66, 0x68, 0x20, 0x6c, 0x64, 0x66, 0x68, 0x67, 0x6b, 0x20, 0x68, 0x66,\n    0x64, 0x6b, 0x67, 0x68, 0x20, 0x6b, 0x66, 0x6a, 0x64, 0x68, 0x73, 0x67,\n    0x20, 0x6b, 0x73, 0x68, 0x66, 0x64, 0x67, 0x6b,\n}\n\nfunc TestPackEthIPv4TCPRaw(t *testing.T) {\n    eth_pkt := eth.Make()\n    eth_pkt.SrcAddr, _ = net.ParseMAC(hwsrc_str)\n    eth_pkt.DstAddr, _ = net.ParseMAC(hwdst_str)\n\n    ip4_pkt := ipv4.Make()\n    ip4_pkt.SrcAddr = net.ParseIP(ipsrc_str)\n    ip4_pkt.DstAddr = net.ParseIP(ipdst_str)\n\n    tcp_pkt := tcp.Make()\n    tcp_pkt.SrcPort = 41562\n    tcp_pkt.DstPort = 8338\n    tcp_pkt.Flags   = tcp.Syn\n    tcp_pkt.WindowSize = 8192\n\n    raw_pkt := raw.Make()\n    raw_pkt.Data = []byte(\"fdg agfh ldfhgk hfdkgh kfjdhsg kshfdgk\")\n\n    data, err := layers.Pack(eth_pkt, ip4_pkt, tcp_pkt, raw_pkt)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if ip4_pkt.GetLength() != 78 {\n        t.Fatalf(\"IPv4 length mismatch: %d\", ip4_pkt.GetLength())\n    }\n\n    if tcp_pkt.GetLength() != 58 {\n        t.Fatalf(\"TCP length mismatch: %d\", tcp_pkt.GetLength())\n    }\n\n    if !bytes.Equal(test_eth_ipv4_tcp_raw, data) {\n        t.Fatalf(\"Raw packet mismatch: %x\", data)\n    }\n}\n\nfunc TestUnpackEthUPv4TCPRaw(t *testing.T) {\n    var eth_pkt eth.Packet\n    var ip4_pkt ipv4.Packet\n    var tcp_pkt tcp.Packet\n    var raw_pkt raw.Packet\n\n    _, err := layers.Unpack(test_eth_ipv4_tcp_raw,\n                            &eth_pkt, &ip4_pkt, &tcp_pkt, &raw_pkt)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n}\n\nfunc BenchmarkUnpackEthUPv4TCPRaw(bn *testing.B) {\n    var eth_pkt eth.Packet\n    var ip4_pkt ipv4.Packet\n    var tcp_pkt tcp.Packet\n    var raw_pkt raw.Packet\n\n    for n := 0; n < bn.N; n++ {\n        layers.Unpack(test_eth_ipv4_tcp_raw,\n                      &eth_pkt, &ip4_pkt, &tcp_pkt, &raw_pkt)\n    }\n}\n\nfunc TestUnpackAllEthIPv4TCPRaw(t *testing.T) {\n    pkt, err := layers.UnpackAll(test_eth_ipv4_tcp_raw, packet.Eth)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if pkt.GetType() != packet.Eth {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.GetType())\n    }\n\n    pkt = pkt.Payload()\n    if pkt.GetType() != packet.IPv4 {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.GetType())\n    }\n\n    pkt = pkt.Payload()\n    if pkt.GetType() != packet.TCP {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.GetType())\n    }\n\n    pkt = pkt.Payload()\n    if pkt.GetType() != packet.Raw {\n        t.Fatalf(\"Packet type mismatch, %s\", pkt.GetType())\n    }\n}\n\nfunc BenchmarkUnpackAllEthIPv4TCPRaw(bn *testing.B) {\n    for n := 0; n < bn.N; n++ {\n        layers.UnpackAll(test_eth_ipv4_tcp_raw, packet.Eth)\n    }\n}\n\nfunc TestFindLayer(t *testing.T) {\n    pkt, err := layers.UnpackAll(test_eth_ipv4_tcp, packet.Eth)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    ipv4_pkt := layers.FindLayer(pkt, packet.IPv4)\n    if ipv4_pkt == nil || ipv4_pkt.GetType() != packet.IPv4 {\n        t.Fatalf(\"Not IPv4: %s\", ipv4_pkt)\n    }\n\n    tcp_pkt := layers.FindLayer(pkt, packet.TCP)\n    if tcp_pkt == nil || tcp_pkt.GetType() != packet.TCP {\n        t.Fatalf(\"Not TCP: %s\", tcp_pkt)\n    }\n\n    udp_pkt := layers.FindLayer(pkt, packet.UDP)\n    if udp_pkt != nil {\n        t.Fatalf(\"Not nil: %s\", udp_pkt)\n    }\n}\n\nfunc ExamplePack() {\n    // Create an Ethernet packet\n    eth_pkt := eth.Make()\n    eth_pkt.SrcAddr, _ = net.ParseMAC(\"4c:72:b9:54:e5:3d\")\n    eth_pkt.DstAddr, _ = net.ParseMAC(\"ff:ff:ff:ff:ff:ff\")\n\n    // Create an ARP packet\n    arp_pkt := arp.Make()\n    arp_pkt.HWSrcAddr, _ = net.ParseMAC(\"4c:72:b9:54:e5:3d\")\n    arp_pkt.HWDstAddr, _ = net.ParseMAC(\"00:00:00:00:00:00\")\n    arp_pkt.ProtoSrcAddr = net.ParseIP(\"192.168.1.135\")\n    arp_pkt.ProtoDstAddr = net.ParseIP(\"192.168.1.254\")\n\n    buf, err := layers.Pack(eth_pkt, arp_pkt)\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    // do something with the packet\n    log.Println(buf)\n}\n\nfunc ExampleUnpack() {\n    // Create the buf data\n    buf := []byte(\"random data\")\n\n    // Assume Ethernet as datalink layer\n    pkt, err := layers.UnpackAll(buf, packet.Eth)\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    log.Println(pkt)\n}\n"
  },
  {
    "path": "network/network.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides utility functions for sending and receiving packets over the\n// network. Basically, it hides some of the complexity of using the capture and\n// layers packages together.\npackage network\n\nimport \"fmt\"\nimport \"net\"\nimport \"time\"\n\nimport \"github.com/ghedo/go.pkt/capture\"\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/arp\"\nimport \"github.com/ghedo/go.pkt/packet/eth\"\nimport \"github.com/ghedo/go.pkt/layers\"\nimport \"github.com/ghedo/go.pkt/routing\"\n\n// Pack packets into their binary form and inject them in the given capture\n// handle.. This will stack the packets before encoding them and also calculate\n// the checksums.\nfunc Send(c capture.Handle, pkts ...packet.Packet) error {\n    if pkts[0].GetType() != c.LinkType() {\n        return fmt.Errorf(\"Expected packet type %s, got %s\",\n                          pkts[0].GetType(), c.LinkType())\n    }\n\n    buf, err := layers.Pack(pkts...)\n    if err != nil {\n        return fmt.Errorf(\"Could not pack: %s\", err)\n    }\n\n    err = c.Inject(buf)\n    if err != nil {\n        return fmt.Errorf(\"Could not inject: %s\", err)\n    }\n\n    return nil\n}\n\n// Capture a single packet from the given capture handle, unpack it and return\n// it. This will block until a packet is received.\nfunc Recv(c capture.Handle) (packet.Packet, error) {\n    buf, err := c.Capture()\n    if err != nil {\n        return nil, fmt.Errorf(\"Could not capture: %s\", err)\n    }\n\n    pkt, err := layers.UnpackAll(buf, c.LinkType())\n    if err != nil {\n        return nil, fmt.Errorf(\"Could not unpack: %s\", err)\n    }\n\n    return pkt, nil\n}\n\n// Like Send() and Recv() combined. This only returns a suitable answer for the\n// sent packets. If t is not zero, this will return if not answer is received\n// before t expires.\nfunc SendRecv(c capture.Handle, t time.Duration, pkts ...packet.Packet) (packet.Packet, error) {\n    err := Send(c, pkts...)\n    if err != nil {\n        return nil, err\n    }\n\n    now := time.Now()\n\n    for {\n        pkt, err := Recv(c)\n        if err != nil {\n            return nil, err\n        }\n\n        if pkt == nil {\n            return nil, nil\n        }\n\n        if pkt.Answers(pkts[0]) {\n            return pkt, nil\n        }\n\n        if int64(t) > 0 &&\n           int64(time.Since(now)) > int64(t.Nanoseconds()) {\n            return nil, fmt.Errorf(\"Timeout\")\n        }\n    }\n\n    return nil, fmt.Errorf(\"WTF\")\n}\n\n// Determine the next hop's MAX address to reach the given IP address and route\n// by doing an ARP resolution.\nfunc NextHopMAC(c capture.Handle, t time.Duration, r *routing.Route, addr net.IP) (net.HardwareAddr, error) {\n    eth_pkt := eth.Make()\n    eth_pkt.SrcAddr = r.Iface.HardwareAddr\n    eth_pkt.DstAddr, _ = net.ParseMAC(\"ff:ff:ff:ff:ff:ff\")\n\n    arp_pkt := arp.Make()\n    arp_pkt.HWSrcAddr = r.Iface.HardwareAddr\n    arp_pkt.HWDstAddr, _ = net.ParseMAC(\"00:00:00:00:00:00\")\n    arp_pkt.ProtoSrcAddr, _ = r.GetIfaceIPv4Addr()\n\n    if r.Default {\n        arp_pkt.ProtoDstAddr = r.Gateway\n    } else {\n        arp_pkt.ProtoDstAddr = addr\n    }\n\n    pkt, err := SendRecv(c, t, eth_pkt, arp_pkt)\n    if err != nil {\n        return nil, err\n    }\n\n    return pkt.Payload().(*arp.Packet).HWSrcAddr, nil\n}\n"
  },
  {
    "path": "packet/arp/pkt.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides encoding and decoding for ARP packets.\npackage arp\n\nimport \"net\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/eth\"\n\ntype Packet struct {\n    Operation     Operation        `string:\"op\"`\n\n    HWType        uint16\n    HWAddrLen     uint8            `string:\"hwlen\"`\n    HWSrcAddr     net.HardwareAddr `string:\"hwsrc\"`\n    HWDstAddr     net.HardwareAddr `string:\"hwdst\"`\n\n    ProtoType     eth.EtherType    `string:\"ptype\"`\n    ProtoAddrLen  uint8            `string:\"plen\"`\n    ProtoSrcAddr  net.IP           `string:\"psrc\"`\n    ProtoDstAddr  net.IP           `string:\"pdst\"`\n}\n\ntype Operation uint16\n\nconst (\n    Request Operation = 1\n    Reply             = 2\n)\n\nfunc Make() *Packet {\n    return &Packet {\n        Operation: Request,\n\n        HWType: 1,\n        HWAddrLen: 6,\n\n        ProtoType: eth.IPv4,\n        ProtoAddrLen: 4,\n    }\n}\n\nfunc (p *Packet) GetType() packet.Type {\n    return packet.ARP\n}\n\nfunc (p *Packet) GetLength() uint16 {\n    return 8 + uint16(p.HWAddrLen) * 2 + uint16(p.ProtoAddrLen) * 2\n}\n\nfunc (p *Packet) Equals(other packet.Packet) bool {\n    return packet.Compare(p, other)\n}\n\nfunc (p *Packet) Answers(other packet.Packet) bool {\n    if other == nil || other.GetType() != packet.ARP {\n        return false\n    }\n\n    if p.Operation == Reply && other.(*Packet).Operation == Request &&\n       p.ProtoSrcAddr.Equal(other.(*Packet).ProtoDstAddr) {\n        return true\n    }\n\n    return false\n}\n\nfunc (p *Packet) Pack(buf *packet.Buffer) error {\n    buf.WriteN(p.HWType)\n    buf.WriteN(p.ProtoType)\n\n    buf.WriteN(p.HWAddrLen)\n    buf.WriteN(p.ProtoAddrLen)\n\n    buf.WriteN(p.Operation)\n\n    buf.Write(p.HWSrcAddr[len(p.HWSrcAddr) - int(p.HWAddrLen):])\n    buf.Write(p.ProtoSrcAddr[len(p.ProtoSrcAddr) - int(p.ProtoAddrLen):])\n\n    buf.Write(p.HWDstAddr[len(p.HWDstAddr) - int(p.HWAddrLen):])\n    buf.Write(p.ProtoDstAddr[len(p.ProtoDstAddr) - int(p.ProtoAddrLen):])\n\n    return nil\n}\n\nfunc (p *Packet) Unpack(buf *packet.Buffer) error {\n    buf.ReadN(&p.HWType)\n    buf.ReadN(&p.ProtoType)\n\n    buf.ReadN(&p.HWAddrLen)\n    buf.ReadN(&p.ProtoAddrLen)\n\n    buf.ReadN(&p.Operation)\n\n    p.HWSrcAddr = net.HardwareAddr(buf.Next(int(p.HWAddrLen)))\n    p.ProtoSrcAddr = net.IP(buf.Next(int(p.ProtoAddrLen)))\n\n    p.HWDstAddr = net.HardwareAddr(buf.Next(int(p.HWAddrLen)))\n    p.ProtoDstAddr = net.IP(buf.Next(int(p.ProtoAddrLen)))\n\n    return nil\n}\n\nfunc (p *Packet) Payload() packet.Packet {\n    return nil\n}\n\nfunc (p *Packet) GuessPayloadType() packet.Type {\n    return packet.None\n}\n\nfunc (p *Packet) SetPayload(pl packet.Packet) error {\n    return nil\n}\n\nfunc (p *Packet) InitChecksum(csum uint32) {\n}\n\nfunc (p *Packet) String() string {\n    return packet.Stringify(p)\n}\n\nfunc (o Operation) String() string {\n    switch o {\n    case Request:\n        return \"request\"\n\n    case Reply:\n        return \"reply\"\n\n    default:\n        return \"invalid\"\n    }\n}\n"
  },
  {
    "path": "packet/arp/pkt_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage arp_test\n\nimport \"bytes\"\nimport \"net\"\nimport \"testing\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/arp\"\nimport \"github.com/ghedo/go.pkt/packet/eth\"\n\nvar test_simple = []byte{\n    0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x4C, 0x72, 0xB9, 0x54,\n    0xE5, 0x3D, 0xC0, 0xA8, 0x01, 0x87, 0x1F, 0x92, 0x2B, 0x56, 0xED, 0x77,\n    0x1C, 0x3C, 0x09, 0xBF,\n}\n\nvar hwsrc_str = \"4c:72:b9:54:e5:3d\"\nvar hwdst_str = \"1f:92:2b:56:ed:77\"\nvar ipsrc_str = \"192.168.1.135\"\nvar ipdst_str = \"28.60.9.191\"\n\nfunc MakeTestSimple() *arp.Packet {\n    hwsrc, _ := net.ParseMAC(hwsrc_str)\n    hwdst, _ := net.ParseMAC(hwdst_str)\n    ipsrc := net.ParseIP(ipsrc_str)\n    ipdst := net.ParseIP(ipdst_str)\n\n    return &arp.Packet{\n        Operation: arp.Request,\n\n        HWType: 1,\n        HWAddrLen: 6,\n        HWSrcAddr: hwsrc,\n        HWDstAddr: hwdst,\n\n        ProtoType:    eth.IPv4,\n        ProtoAddrLen: 4,\n        ProtoSrcAddr: ipsrc,\n        ProtoDstAddr: ipdst,\n    }\n}\n\nfunc TestPack(t *testing.T) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    err := p.Pack(&b)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_simple, b.Buffer()) {\n        t.Fatalf(\"Raw packet mismatch: %x\", b.Buffer())\n    }\n}\n\nfunc BenchmarkPack(bn *testing.B) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    for n := 0; n < bn.N; n++ {\n        p.Pack(&b)\n    }\n}\n\nfunc TestUnpack(t *testing.T) {\n    var p arp.Packet\n\n    cmp := MakeTestSimple()\n\n    var b packet.Buffer\n    b.Init(test_simple)\n\n    err := p.Unpack(&b)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if !p.Equals(cmp) {\n        t.Fatalf(\"Packet mismatch:\\n%s\\n%s\", &p, cmp)\n    }\n}\n\nfunc BenchmarkUnpack(bn *testing.B) {\n    var p arp.Packet\n    var b packet.Buffer\n\n    for n := 0; n < bn.N; n++ {\n        b.Init(test_simple)\n        p.Unpack(&b)\n    }\n}\n"
  },
  {
    "path": "packet/buffer.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage packet\n\nimport \"encoding/binary\"\n\n// A Buffer is a variable-sized buffer of bytes with Read and Write methods.\n// It's based on the bytes.Buffer code provided by the standard library, but\n// implements additional convenience methods.\n//\n// This is used internally to provide packet encoding and decoding, and should\n// not be used directly.\ntype Buffer struct {\n    buf       []byte\n    off       int\n    layer_off int\n}\n\n// Initialize the buffer with the given slice.\nfunc (b *Buffer) Init(buf []byte) {\n    b.buf = buf\n    b.off = 0\n    b.layer_off = 0\n}\n\n// Return the unread portion of the buffer as slice.\nfunc (b *Buffer) Bytes() []byte {\n    return b.buf[b.off:]\n}\n\n// Return the whole buffer as slice.\nfunc (b *Buffer) Buffer() []byte {\n    return b.buf\n}\n\n// Return the number of bytes of the unread portion of the buffer.\nfunc (b *Buffer) Len() int {\n    return len(b.buf) - b.off\n}\n\n// Manually set the buffer offset to off.\nfunc (b *Buffer) SetOffset(off int) {\n    b.off = off\n}\n\n// Point the layer starting offset to the current buffer offset.\nfunc (b *Buffer) NewLayer() {\n    b.layer_off = len(b.buf) - b.Len()\n}\n\n// Return the buffer of the current layer as slice.\nfunc (b *Buffer) LayerBytes() []byte {\n    return b.buf[b.layer_off:]\n}\n\n// Return the length of the current decoded layer.\nfunc (b *Buffer) LayerLen() int {\n    return b.off - b.layer_off\n}\n\n// Append the contents of p to the buffer.\nfunc (b *Buffer) Write(p []byte) (n int, err error) {\n    n = copy(b.buf[b.off:], p)\n    b.off += n\n    return\n}\n\n// Append the value of data to the buffer in network byter order.\nfunc (b *Buffer) WriteN(data interface{}) error {\n    return binary.Write(b, binary.BigEndian, data)\n}\n\n// Append the value of data to the buffer in little endian byter order.\nfunc (b *Buffer) WriteL(data interface{}) error {\n    return binary.Write(b, binary.LittleEndian, data)\n}\n\n// Write data in network byte order to the specified offset relative to the\n// start of the current layer.\nfunc (b *Buffer) PutUint16N(off int, data uint16) {\n    binary.BigEndian.PutUint16(b.buf[b.layer_off + off:], data)\n}\n\n// Read the next len(p) bytes from the buffer or until the buffer is drained.\nfunc (b *Buffer) Read(p []byte) (n int, err error) {\n    n = copy(p, b.buf[b.off:])\n    b.off += n\n    return\n}\n\n// Read structured data from the buffer in network byte order.\nfunc (p *Buffer) ReadN(data interface{}) error {\n    return binary.Read(p, binary.BigEndian, data)\n}\n\n// Read structured data from the buffer in little endian byte order.\nfunc (p *Buffer) ReadL(data interface{}) error {\n    return binary.Read(p, binary.LittleEndian, data)\n}\n\n// Read aligned structured data from the buffer in little endian byte order.\nfunc (p *Buffer) ReadLAligned(data interface{}, width uintptr) error {\n    p.off = ((((p.off) + ((int(width)) - 1)) & (^((int(width)) - 1))) - p.off)\n\n    return binary.Read(p, binary.LittleEndian, data)\n}\n\n// Return a slice containing the next n bytes from the buffer, advancing the\n// buffer as if the bytes had been returned by Read\nfunc (b *Buffer) Next(n int) []byte {\n    m := b.Len()\n    if n > m {\n        n = m\n    }\n    data := b.buf[b.off : b.off+n]\n    b.off += n\n    return data\n}\n"
  },
  {
    "path": "packet/eth/pkt.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides encoding and decoding for Ethernet (both EthernetII and 802.3)\n// packets.\npackage eth\n\nimport \"fmt\"\nimport \"net\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\n\ntype Packet struct {\n    DstAddr     net.HardwareAddr `string:\"dst\"`\n    SrcAddr     net.HardwareAddr `string:\"src\"`\n    Type        EtherType\n    Length      uint16           `cmp:\"skip\"`\n    pkt_payload packet.Packet    `cmp:\"skip\" string:\"skip\"`\n}\n\ntype EtherType uint16\n\nconst (\n    None EtherType = 0x0000\n    ARP            = 0x0806\n    IPv4           = 0x0800\n    IPv6           = 0x86dd\n    LLC            = 0x0001  /* pseudo ethertype */\n    LLDP           = 0x088cc\n    QinQ           = 0x88a8\n    TRILL          = 0x22f3\n    VLAN           = 0x8100\n    WoL            = 0x0842\n)\n\nfunc Make() *Packet {\n    return &Packet{\n        DstAddr: make([]byte, 6),\n        SrcAddr: make([]byte, 6),\n        Length:  14,\n    }\n}\n\nfunc (p *Packet) Equals(other packet.Packet) bool {\n    return packet.Compare(p, other)\n}\n\nfunc (p *Packet) Answers(other packet.Packet) bool {\n    if other == nil || other.GetType() != packet.Eth {\n        return false\n    }\n\n    if p.Type != other.(*Packet).Type {\n        return false\n    }\n\n    if p.Payload() != nil {\n        return p.Payload().Answers(other.Payload())\n    }\n\n    return true\n}\n\nfunc (p *Packet) GetType() packet.Type {\n    return packet.Eth\n}\n\nfunc (p *Packet) GetLength() uint16 {\n    if p.pkt_payload != nil {\n        return p.pkt_payload.GetLength() + 14\n    }\n\n    return 14\n}\n\nfunc (p *Packet) Pack(buf *packet.Buffer) error {\n    buf.Write(p.DstAddr)\n    buf.Write(p.SrcAddr)\n\n    if p.Type != LLC {\n        buf.WriteN(p.Type)\n    } else {\n        buf.WriteN(p.Length)\n    }\n\n    return nil\n}\n\nfunc (p *Packet) Unpack(buf *packet.Buffer) error {\n    p.DstAddr = net.HardwareAddr(buf.Next(6))\n    p.SrcAddr = net.HardwareAddr(buf.Next(6))\n\n    buf.ReadN(&p.Type)\n\n    if p.Type < 0x0600 {\n        p.Length = uint16(p.Type)\n        p.Type   = LLC\n    }\n\n    return nil\n}\n\nfunc (p *Packet) Payload() packet.Packet {\n    return p.pkt_payload\n}\n\nfunc (p *Packet) GuessPayloadType() packet.Type {\n    return EtherTypeToType(p.Type)\n}\n\nfunc (p *Packet) SetPayload(pl packet.Packet) error {\n    p.pkt_payload = pl\n    p.Type        = TypeToEtherType(pl.GetType())\n\n    if p.Type < 0x0600 {\n        p.Length = p.GetLength()\n    }\n\n    return nil\n}\n\nfunc (p *Packet) InitChecksum(csum uint32) {\n}\n\nfunc (p *Packet) String() string {\n    return packet.Stringify(p)\n}\n\nvar ethertype_to_type_map = map[EtherType]packet.Type{\n    None:  packet.None,\n    ARP:   packet.ARP,\n    IPv4:  packet.IPv4,\n    IPv6:  packet.IPv6,\n    LLC:   packet.LLC,\n    LLDP:  packet.LLDP,\n    VLAN:  packet.VLAN,\n    QinQ:  packet.VLAN,\n    TRILL: packet.TRILL,\n    WoL:   packet.WoL,\n}\n\n// Create a new Type from the given EtherType.\nfunc EtherTypeToType(ethertype EtherType) packet.Type {\n    for e, t := range ethertype_to_type_map {\n        if e == ethertype {\n            return t\n        }\n    }\n\n    return packet.Raw\n}\n\n// Convert the Type to the corresponding EtherType.\nfunc TypeToEtherType(pkttype packet.Type) EtherType {\n    /* Hack to avoid non-determinism due to map iteration ordering */\n    if pkttype == packet.VLAN {\n        return VLAN\n    }\n\n    for e, t := range ethertype_to_type_map {\n        if t == pkttype {\n            return e\n        }\n    }\n\n    return None\n}\n\nfunc (t EtherType) String() string {\n    switch t {\n    case ARP:   return \"ARP\"\n    case IPv4:  return \"IPv4\"\n    case IPv6:  return \"IPv6\"\n    case LLC:   return \"LLC\"\n    case LLDP:  return \"LLDP\"\n    case None:  return \"None\"\n    case QinQ:  return \"QinQ\"\n    case TRILL: return \"TRILL\"\n    case VLAN:  return \"VLAN\"\n    case WoL:   return \"WoL\"\n    default:    return fmt.Sprintf(\"0x%x\", uint16(t))\n    }\n}\n"
  },
  {
    "path": "packet/eth/pkt_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage eth_test\n\nimport \"bytes\"\nimport \"net\"\nimport \"testing\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/eth\"\n\nvar hwsrc_str = \"4c:72:b9:54:e5:3d\"\nvar hwdst_str = \"1f:92:2b:56:ed:77\"\n\nvar test_simple = []byte{\n    0x1f, 0x92, 0x2b, 0x56, 0xed, 0x77, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,\n    0x08, 0x00,\n}\n\nfunc MakeTestSimple() *eth.Packet {\n    hwsrc, _ := net.ParseMAC(hwsrc_str)\n    hwdst, _ := net.ParseMAC(hwdst_str)\n\n    return &eth.Packet{\n        SrcAddr: hwsrc,\n        DstAddr: hwdst,\n        Type:    eth.IPv4,\n    }\n}\n\nfunc TestPack(t *testing.T) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    err := p.Pack(&b)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_simple, b.Buffer()) {\n        t.Fatalf(\"Raw packet mismatch: %x\", b.Buffer())\n    }\n}\n\nfunc BenchmarkPack(bn *testing.B) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    for n := 0; n < bn.N; n++ {\n        p.Pack(&b)\n    }\n}\n\nfunc TestUnpack(t *testing.T) {\n    var p eth.Packet\n\n    cmp := MakeTestSimple()\n\n    var b packet.Buffer\n    b.Init(test_simple)\n\n    err := p.Unpack(&b)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if !p.Equals(cmp) {\n        t.Fatalf(\"Packet mismatch:\\n%s\\n%s\", &p, cmp)\n    }\n}\n\nfunc BenchmarkUnpack(bn *testing.B) {\n    var p eth.Packet\n    var b packet.Buffer\n\n    for n := 0; n < bn.N; n++ {\n        b.Init(test_simple)\n        p.Unpack(&b)\n    }\n}\n"
  },
  {
    "path": "packet/icmpv4/pkt.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides encoding and decoding for ICMPv4 packets.\npackage icmpv4\n\nimport \"fmt\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/ipv4\"\n\ntype Packet struct {\n    Type        Type\n    Code        Code\n    Checksum    uint16        `string:\"sum\"`\n    Id          uint16\n    Seq         uint16\n    pkt_payload packet.Packet `cmp:\"skip\" string:\"skip\"`\n}\n\ntype Type uint8\ntype Code uint8\n\nconst (\n    EchoReply Type = iota\n    Reserved1\n    Reserved2\n    DstUnreachable\n    SrcQuench\n    RedirectMsg\n    Reserved3\n    Reserved4\n    EchoRequest\n    RouterAdv\n    RouterSol\n    TimeExceeded\n    ParamProblem\n    Timestamp\n    TimestampReply\n    InfoRequest\n    InfoReply\n    AddrMaskRequest\n    AddrMaskReply\n)\n\nfunc Make() *Packet {\n    return &Packet{\n        Type: EchoRequest,\n    }\n}\n\nfunc (p *Packet) GetType() packet.Type {\n    return packet.ICMPv4\n}\n\nfunc (p *Packet) GetLength() uint16 {\n    if p.pkt_payload != nil {\n        return p.pkt_payload.GetLength() + 8\n    }\n\n    return 8\n}\n\nfunc (p *Packet) Equals(other packet.Packet) bool {\n    return packet.Compare(p, other)\n}\n\nfunc (p *Packet) Answers(other packet.Packet) bool {\n    if other == nil || other.GetType() != packet.ICMPv4 {\n        return false\n    }\n\n    if (other.(*Packet).Type == EchoRequest && p.Type == EchoReply) ||\n       (other.(*Packet).Type == Timestamp && p.Type == TimestampReply) ||\n       (other.(*Packet).Type == InfoRequest && p.Type == InfoReply) ||\n       (other.(*Packet).Type == AddrMaskRequest && p.Type == AddrMaskReply) {\n        return (other.(*Packet).Seq == p.Seq) &&\n               (other.(*Packet).Id == p.Id)\n    }\n\n    return false\n}\n\nfunc (p *Packet) Pack(buf *packet.Buffer) error {\n    buf.WriteN(byte(p.Type))\n    buf.WriteN(byte(p.Code))\n    buf.WriteN(uint16(0x0000))\n    buf.WriteN(p.Id)\n    buf.WriteN(p.Seq)\n\n    p.Checksum = ipv4.CalculateChecksum(buf.LayerBytes(), 0)\n    buf.PutUint16N(2, p.Checksum)\n\n    return nil\n}\n\nfunc (p *Packet) Unpack(buf *packet.Buffer) error {\n    buf.ReadN(&p.Type)\n    buf.ReadN(&p.Code)\n    buf.ReadN(&p.Checksum)\n    buf.ReadN(&p.Id)\n    buf.ReadN(&p.Seq)\n\n    /* TODO: data */\n\n    return nil\n}\n\nfunc (p *Packet) Payload() packet.Packet {\n    return p.pkt_payload\n}\n\nfunc (p *Packet) GuessPayloadType() packet.Type {\n    switch p.Type {\n    case DstUnreachable, SrcQuench, RedirectMsg, TimeExceeded, ParamProblem:\n        return packet.IPv4\n    }\n\n    return packet.None\n}\n\nfunc (p *Packet) SetPayload(pl packet.Packet) error {\n    switch p.Type {\n    case DstUnreachable, SrcQuench, RedirectMsg, TimeExceeded, ParamProblem:\n        p.pkt_payload = pl\n    }\n\n    return nil\n}\n\nfunc (p *Packet) InitChecksum(csum uint32) {\n}\n\nfunc (p *Packet) String() string {\n    return packet.Stringify(p)\n}\n\nfunc (t Type) String() string {\n    switch t {\n    case EchoReply:         return \"echo-reply\"\n    case DstUnreachable:    return \"dst-unreach\"\n    case SrcQuench:         return \"src-quench\"\n    case RedirectMsg:       return \"redirect\"\n    case EchoRequest:       return \"echo-request\"\n    case RouterAdv:         return \"router-adv\"\n    case RouterSol:         return \"router-sol\"\n    case TimeExceeded:      return \"time-exceeded\"\n    case ParamProblem:      return \"param-problem\"\n    case Timestamp:         return \"timestamp-request\"\n    case TimestampReply:    return \"timestamp-reply\"\n    case InfoRequest:       return \"info-request\"\n    case InfoReply:         return \"info-reply\"\n    case AddrMaskRequest:   return \"addr-mask-request\"\n    case AddrMaskReply:     return \"addr-mask-reply\"\n    default:                return \"unknown\"\n    }\n}\n\nfunc (c Code) String() string {\n    if c != 0 {\n        return fmt.Sprintf(\"%x\", uint8(c))\n    }\n\n    return \"\"\n}\n"
  },
  {
    "path": "packet/icmpv4/pkt_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage icmpv4_test\n\nimport \"bytes\"\nimport \"testing\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/icmpv4\"\n\nvar test_simple = []byte{\n    0x08, 0x00, 0xf7, 0xd2, 0x00, 0x0f, 0x00, 0x1e,\n}\n\nfunc MakeTestSimple() *icmpv4.Packet {\n    return &icmpv4.Packet{\n        Type: icmpv4.EchoRequest,\n        Code: 0,\n        Id: 15,\n        Seq: 30,\n    }\n}\n\nfunc TestPack(t *testing.T) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    err := p.Pack(&b)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_simple, b.Buffer()) {\n        t.Fatalf(\"Raw packet mismatch: %x\", b.Buffer())\n    }\n}\n\nfunc BenchmarkPack(bn *testing.B) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    for n := 0; n < bn.N; n++ {\n        p.Pack(&b)\n    }\n}\n\nfunc TestUnpack(t *testing.T) {\n    var p icmpv4.Packet\n\n    cmp := MakeTestSimple()\n    cmp.Checksum = 0xf7d2\n\n    var b packet.Buffer\n    b.Init(test_simple)\n\n    err := p.Unpack(&b)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if !p.Equals(cmp) {\n        t.Fatalf(\"Packet mismatch:\\n%s\\n%s\", &p, cmp)\n    }\n}\n\nfunc BenchmarkUnpack(bn *testing.B) {\n    var p icmpv4.Packet\n    var b packet.Buffer\n\n    for n := 0; n < bn.N; n++ {\n        b.Init(test_simple)\n        p.Unpack(&b)\n    }\n}\n"
  },
  {
    "path": "packet/icmpv6/pkt.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides encoding and decoding for ICMPv6 packets.\npackage icmpv6\n\nimport \"fmt\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/ipv4\"\n\ntype Packet struct {\n    Type      Type\n    Code      Code\n    Checksum  uint16 `string:\"sum\"`\n    csum_seed uint32 `cmp:\"skip\" string:\"skip\"`\n    Body      uint32 `cmp:\"skip\" string:\"skip\"`\n    pkt_payload packet.Packet `cmp:\"skip\" string:\"skip\"`\n}\n\ntype Type uint8\ntype Code uint8\n\nconst (\n    DstUnreachable Type = 1\n    PacketTooBig        = 2\n    TimeExceeded        = 3\n    ParamProblem        = 4\n    Private1            = 100\n    Private2            = 101\n    Reserved1           = 127\n    EchoRequest         = 128\n    EchoReply           = 129\n    /* TODO: more types */\n)\n\nfunc Make() *Packet {\n    return &Packet{\n        Type: EchoRequest,\n    }\n}\n\nfunc (p *Packet) GetType() packet.Type {\n    return packet.ICMPv6\n}\n\nfunc (p *Packet) GetLength() uint16 {\n    if p.pkt_payload != nil {\n        return p.pkt_payload.GetLength() + 8\n    }\n\n    return 8\n}\n\nfunc (p *Packet) Equals(other packet.Packet) bool {\n    return packet.Compare(p, other)\n}\n\nfunc (p *Packet) Answers(other packet.Packet) bool {\n    if other == nil || other.GetType() != packet.ICMPv6 {\n        return false\n    }\n\n    if other.(*Packet).Type == EchoRequest && p.Type == EchoReply {\n        return true\n    }\n\n    return false\n}\n\nfunc (p *Packet) Pack(buf *packet.Buffer) error {\n    buf.WriteN(byte(p.Type))\n    buf.WriteN(byte(p.Code))\n    buf.WriteN(uint16(0x00))\n    buf.WriteN(p.Body)\n\n    if p.csum_seed != 0 {\n        p.Checksum = ipv4.CalculateChecksum(buf.LayerBytes(), p.csum_seed)\n        buf.PutUint16N(2, p.Checksum)\n    }\n\n    return nil\n}\n\nfunc (p *Packet) Unpack(buf *packet.Buffer) error {\n    buf.ReadN(&p.Type)\n    buf.ReadN(&p.Code)\n    buf.ReadN(&p.Checksum)\n\n    /* TODO: data */\n    buf.ReadN(&p.Body)\n\n    return nil\n}\n\nfunc (p *Packet) Payload() packet.Packet {\n    return p.pkt_payload\n}\n\nfunc (p *Packet) GuessPayloadType() packet.Type {\n    switch p.Type {\n    case DstUnreachable, PacketTooBig, TimeExceeded, ParamProblem:\n        return packet.IPv6\n    }\n\n    return packet.None\n}\n\nfunc (p *Packet) SetPayload(pl packet.Packet) error {\n    switch p.Type {\n    case DstUnreachable, PacketTooBig, TimeExceeded, ParamProblem:\n        p.pkt_payload = pl\n    }\n\n    return nil\n}\n\nfunc (p *Packet) InitChecksum(csum uint32) {\n    p.csum_seed = csum\n}\n\nfunc (p *Packet) String() string {\n    return packet.Stringify(p)\n}\n\nfunc (t Type) String() string {\n    switch t {\n    case DstUnreachable:    return \"dst-unreach\"\n    case PacketTooBig:      return \"too-big\"\n    case TimeExceeded:      return \"timeout\"\n    case ParamProblem:      return \"param-problem\"\n    case EchoRequest:       return \"echo-request\"\n    case EchoReply:         return \"echo-reply\"\n    default:                return \"unknown\"\n    }\n}\n\nfunc (c Code) String() string {\n    if c != 0 {\n        return fmt.Sprintf(\"%x\", uint8(c))\n    }\n\n    return \"\"\n}\n"
  },
  {
    "path": "packet/icmpv6/pkt_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage icmpv6_test\n\nimport \"bytes\"\nimport \"net\"\nimport \"testing\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/icmpv6\"\nimport \"github.com/ghedo/go.pkt/packet/ipv6\"\n\nvar test_simple = []byte{\n    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n}\n\nfunc MakeTestSimple() *icmpv6.Packet {\n    return &icmpv6.Packet{\n        Type: icmpv6.EchoRequest,\n    }\n}\n\nfunc TestPack(t *testing.T) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    err := p.Pack(&b)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_simple, b.Buffer()) {\n        t.Fatalf(\"Raw packet mismatch: %x\", b.Buffer())\n    }\n}\n\nfunc BenchmarkPack(bn *testing.B) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    for n := 0; n < bn.N; n++ {\n        p.Pack(&b)\n    }\n}\n\nfunc TestUnpack(t *testing.T) {\n    var p icmpv6.Packet\n\n    cmp := MakeTestSimple()\n\n    var b packet.Buffer\n    b.Init(test_simple)\n\n    err := p.Unpack(&b)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if !p.Equals(cmp) {\n        t.Fatalf(\"Packet mismatch:\\n%s\\n%s\", &p, cmp)\n    }\n}\n\nfunc BenchmarkUnpack(bn *testing.B) {\n    var p icmpv6.Packet\n    var b packet.Buffer\n\n    for n := 0; n < bn.N; n++ {\n        b.Init(test_simple)\n        p.Unpack(&b)\n    }\n}\n\nvar test_with_ipv6 = []byte{\n    0x80, 0x00, 0x5b, 0xed, 0x00, 0x00, 0x00, 0x00,\n}\n\nvar ipsrc_str = \"fe80::4e72:b9ff:fe54:e53d\"\nvar ipdst_str = \"2001:4860:4860::8888\"\n\nfunc TestPackWithIPv6(t *testing.T) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_with_ipv6)))\n\n    ip6 := ipv6.Make()\n    ip6.SrcAddr = net.ParseIP(ipsrc_str)\n    ip6.DstAddr = net.ParseIP(ipdst_str)\n\n    icmp6 := MakeTestSimple()\n\n    ip6.SetPayload(icmp6)\n\n    err := icmp6.Pack(&b)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_with_ipv6, b.Buffer()) {\n        t.Fatalf(\"Raw packet mismatch: %x\", b.Buffer())\n    }\n}\n\nfunc TestUnpackWithIPv6(t *testing.T) {\n    var p icmpv6.Packet\n\n    cmp := MakeTestSimple()\n    cmp.Checksum = 0x5bed\n\n    var b packet.Buffer\n    b.Init(test_with_ipv6)\n\n    err := p.Unpack(&b)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if !p.Equals(cmp) {\n        t.Fatalf(\"Packet mismatch:\\n%s\\n%s\", &p, cmp)\n    }\n}\n"
  },
  {
    "path": "packet/ipv4/pkt.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides encoding and decoding for IPv4 packets.\npackage ipv4\n\nimport \"fmt\"\nimport \"net\"\nimport \"strings\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\n\ntype Packet struct {\n    Version     uint8\n    IHL         uint8\n    TOS         uint8         `cmp:\"skip\"`\n    Length      uint16        `cmp:\"skip\"`\n    Id          uint16\n    Flags       Flags\n    FragOff     uint16\n    TTL         uint8         `cmp:\"skip\"`\n    Protocol    Protocol      `string:\"proto\"`\n    Checksum    uint16        `cmp:\"skip\" string:\"sum\"`\n    SrcAddr     net.IP        `string:\"src\"`\n    DstAddr     net.IP        `string:\"dst\"`\n    pkt_payload packet.Packet `cmp:\"skip\" string:\"skip\"`\n}\n\ntype Flags uint8\n\nconst (\n    Evil     Flags = 1 << 2 /* RFC3514 */\n    DontFragment   = 1 << 1\n    MoreFragments  = 1 << 0\n)\n\ntype Protocol uint8\n\nconst (\n    None Protocol = 0x00\n    GRE           = 0x2F\n    ICMPv4        = 0x01\n    ICMPv6        = 0x3A\n    IGMP          = 0x02\n    IPSecAH       = 0x33\n    IPSecESP      = 0x32\n    IPv6          = 0x29\n    ISIS          = 0x7C\n    L2TP          = 0x73\n    OSPF          = 0x59\n    SCTP          = 0x84\n    TCP           = 0x06\n    UDP           = 0x11\n    UDPLite       = 0x88\n)\n\nfunc Make() *Packet {\n    return &Packet{\n        Version: 4,\n        IHL: 5,\n        Length: 20,\n        TTL: 64,\n        Id: 1,\n    }\n}\n\nfunc (p *Packet) GetType() packet.Type {\n    return packet.IPv4\n}\n\nfunc (p *Packet) GetLength() uint16 {\n    if p.pkt_payload != nil {\n        return p.pkt_payload.GetLength() + 20\n    }\n\n    return 20\n}\n\nfunc (p *Packet) Equals(other packet.Packet) bool {\n    return packet.Compare(p, other)\n}\n\nfunc (p *Packet) Answers(other packet.Packet) bool {\n    if other == nil || other.GetType() != packet.IPv4 {\n        return false\n    }\n\n    if p.Payload() != nil &&\n       p.Payload().GetType() == packet.ICMPv4 &&\n       p.Payload().Payload() != nil {\n        return p.Payload().Payload().Equals(other)\n    }\n\n    if !p.SrcAddr.Equal(other.(*Packet).DstAddr) ||\n        p.Protocol != other.(*Packet).Protocol {\n        return false\n    }\n\n    if p.Payload() != nil {\n        return p.Payload().Answers(other.Payload())\n    }\n\n    return true\n}\n\nfunc (p *Packet) Pack(buf *packet.Buffer) error {\n    buf.WriteN((p.Version << 4) | p.IHL)\n    buf.WriteN(p.TOS)\n    buf.WriteN(p.Length)\n    buf.WriteN(p.Id)\n    buf.WriteN((uint16(p.Flags) << 13) | p.FragOff)\n    buf.WriteN(p.TTL)\n    buf.WriteN(p.Protocol)\n    buf.WriteN(uint16(0x00))\n    buf.Write(p.SrcAddr.To4())\n    buf.Write(p.DstAddr.To4())\n\n    p.checksum(buf.LayerBytes()[:20])\n    buf.PutUint16N(10, p.Checksum)\n\n    return nil\n}\n\nfunc (p *Packet) checksum(raw_bytes []byte) {\n    var csum uint32\n\n    for i := 0; i < len(raw_bytes) - 1; i += 2 {\n        csum += uint32(raw_bytes[i]) << 8\n        csum += uint32(raw_bytes[i + 1])\n    }\n\n    p.Checksum = ^uint16((csum >> 16) + csum)\n}\n\nfunc (p *Packet) pseudo_checksum() uint32 {\n    var csum uint32\n\n    csum += (uint32(p.SrcAddr.To4()[0]) + uint32(p.SrcAddr.To4()[2])) << 8\n    csum +=  uint32(p.SrcAddr.To4()[1]) + uint32(p.SrcAddr.To4()[3])\n    csum += (uint32(p.DstAddr.To4()[0]) + uint32(p.DstAddr.To4()[2])) << 8\n    csum +=  uint32(p.DstAddr.To4()[1]) + uint32(p.DstAddr.To4()[3])\n    csum +=  uint32(p.Protocol)\n    csum +=  uint32(p.pkt_payload.GetLength())\n\n    return csum\n}\n\nfunc (p *Packet) Unpack(buf *packet.Buffer) error {\n    var versihl uint8\n    buf.ReadN(&versihl)\n\n    p.Version  = versihl >> 4\n    p.IHL      = versihl & 0x0F\n\n    buf.ReadN(&p.TOS)\n    buf.ReadN(&p.Length)\n    buf.ReadN(&p.Id)\n\n    var flagsfrag uint16\n    buf.ReadN(&flagsfrag)\n    p.Flags   = Flags(flagsfrag >> 13)\n    p.FragOff = flagsfrag & 0x1FFF\n\n    buf.ReadN(&p.TTL)\n\n    buf.ReadN(&p.Protocol)\n\n    buf.ReadN(&p.Checksum)\n\n    p.SrcAddr = net.IP(buf.Next(4))\n    p.DstAddr = net.IP(buf.Next(4))\n\n    /* TODO: Options */\n\n    return nil\n}\n\nfunc (p *Packet) Payload() packet.Packet {\n    return p.pkt_payload\n}\n\nfunc (p *Packet) GuessPayloadType() packet.Type {\n    return ProtocolToType(p.Protocol)\n}\n\nfunc (p *Packet) SetPayload(pl packet.Packet) error {\n    p.pkt_payload = pl\n    p.Protocol    = TypeToProtocol(pl.GetType())\n    p.Length      = p.GetLength()\n\n    pl.InitChecksum(p.pseudo_checksum())\n\n    return nil\n}\n\nfunc (p *Packet) InitChecksum(csum uint32) {\n}\n\nfunc (p *Packet) String() string {\n    return packet.Stringify(p)\n}\n\nfunc (f Flags) String() string {\n    var flags []string\n\n    if f & Evil != 0  {\n        flags = append(flags, \"evil\")\n    }\n\n    if f & DontFragment != 0 {\n        flags = append(flags, \"dont-fragment\")\n    }\n\n    if f & MoreFragments != 0 {\n        flags = append(flags, \"more-fragments\")\n    }\n\n    return strings.Join(flags, \"|\")\n}\n\nfunc CalculateChecksum(raw_bytes []byte, csum uint32) uint16 {\n    length := len(raw_bytes) - 1\n\n    for i := 0; i < length; i += 2 {\n        csum += uint32(raw_bytes[i]) << 8\n        csum += uint32(raw_bytes[i + 1])\n    }\n\n    csum = (csum >> 16) + (csum & 0xffff)\n\n    return ^uint16(csum + (csum >> 16))\n}\n\nvar ipv4proto_to_type_map = map[Protocol]packet.Type{\n    None:     packet.None,\n    GRE:      packet.GRE,\n    ICMPv4:   packet.ICMPv4,\n    ICMPv6:   packet.ICMPv6,\n    IGMP:     packet.IGMP,\n    IPSecAH:  packet.IPSec,\n    IPSecESP: packet.IPSec,\n    IPv6:     packet.IPv6,\n    UDP:      packet.UDP,\n    ISIS:     packet.ISIS,\n    L2TP:     packet.L2TP,\n    OSPF:     packet.OSPF,\n    SCTP:     packet.SCTP,\n    UDPLite:  packet.UDPLite,\n    TCP:      packet.TCP,\n}\n\n// Create a new Type from the given IP protocol ID.\nfunc ProtocolToType(proto Protocol) packet.Type {\n    for p, t := range ipv4proto_to_type_map {\n        if p == proto {\n            return t\n        }\n    }\n\n    return packet.Raw\n}\n\n// Convert the Type to the corresponding IP protocol ID.\nfunc TypeToProtocol(pkttype packet.Type) Protocol {\n    for p, t := range ipv4proto_to_type_map {\n        if t == pkttype {\n            return p\n        }\n    }\n\n    return None\n}\n\nfunc (p Protocol) String() string {\n    switch p {\n    case GRE:      return \"GRE\"\n    case ICMPv4:   return \"ICMPv4\"\n    case ICMPv6:   return \"ICMPv6\"\n    case IGMP:     return \"IGMP\"\n    case IPSecAH:  return \"IPSecAH\"\n    case IPSecESP: return \"IPSecESP\"\n    case IPv6:     return \"IPv6\"\n    case UDP:      return \"UDP\"\n    case ISIS:     return \"ISIS\"\n    case L2TP:     return \"L2TP\"\n    case OSPF:     return \"OSPF\"\n    case SCTP:     return \"SCTP\"\n    case UDPLite:  return \"UDPLite\"\n    case TCP:      return \"TCP\"\n    default:       return fmt.Sprintf(\"0x%x\", uint16(p))\n    }\n}\n"
  },
  {
    "path": "packet/ipv4/pkt_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage ipv4_test\n\nimport \"bytes\"\nimport \"net\"\nimport \"testing\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/ipv4\"\n\nvar test_simple = []byte{\n    0x45, 0x03, 0x00, 0x14, 0x00, 0x0f, 0x40, 0x00, 0x64, 0x06, 0x48, 0x97,\n    0xc0, 0xa8, 0x01, 0x87, 0x08, 0x08, 0x04, 0x04,\n}\n\nvar ipsrc_str = \"192.168.1.135\"\nvar ipdst_str = \"8.8.4.4\"\n\nfunc MakeTestSimple() *ipv4.Packet {\n    return &ipv4.Packet{\n        Version: 4,\n        IHL: 5,\n        Length: 20,\n        TOS: 3,\n        Id: 15,\n        TTL: 100,\n        Flags: ipv4.DontFragment,\n        Protocol: ipv4.TCP,\n        SrcAddr: net.ParseIP(ipsrc_str),\n        DstAddr: net.ParseIP(ipdst_str),\n    }\n}\n\nfunc TestPack(t *testing.T) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    err := p.Pack(&b)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_simple, b.Buffer()) {\n        t.Fatalf(\"Raw packet mismatch: %x\", b.Buffer())\n    }\n}\n\nfunc BenchmarkPack(bn *testing.B) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    for n := 0; n < bn.N; n++ {\n        p.Pack(&b)\n    }\n}\n\nfunc TestUnpack(t *testing.T) {\n    var p ipv4.Packet\n\n    cmp := MakeTestSimple()\n    cmp.Checksum = 0x4897\n\n    var b packet.Buffer\n    b.Init(test_simple)\n\n    err := p.Unpack(&b)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if !p.Equals(cmp) {\n        t.Fatalf(\"Packet mismatch:\\n%s\\n%s\", &p, cmp)\n    }\n}\n\nfunc BenchmarkUnpack(bn *testing.B) {\n    var p ipv4.Packet\n    var b packet.Buffer\n\n    for n := 0; n < bn.N; n++ {\n        b.Init(test_simple)\n        p.Unpack(&b)\n    }\n}\n"
  },
  {
    "path": "packet/ipv6/pkt.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides encoding and decoding for IPv6 packets.\npackage ipv6\n\nimport \"encoding/binary\"\nimport \"net\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/ipv4\"\n\ntype Packet struct {\n    Version     uint8\n    Class       uint8\n    Label       uint32\n    Length      uint16        `string:\"len\"`\n    NextHdr     ipv4.Protocol `string:\"next\"`\n    HopLimit    uint8         `cmp:\"skip\" string:\"hop\"`\n    SrcAddr     net.IP        `string:\"src\"`\n    DstAddr     net.IP        `string:\"dst\"`\n    pkt_payload packet.Packet `cmp:\"skip\" string:\"skip\"`\n}\n\ntype Flags uint8\n\nfunc Make() *Packet {\n    return &Packet{\n        Version: 6,\n        HopLimit: 64,\n    }\n}\n\nfunc (p *Packet) GetType() packet.Type {\n    return packet.IPv6\n}\n\nfunc (p *Packet) GetLength() uint16 {\n    if p.pkt_payload != nil {\n        return p.pkt_payload.GetLength() + 40\n    }\n\n    return 40\n}\n\nfunc (p *Packet) Equals(other packet.Packet) bool {\n    return packet.Compare(p, other)\n}\n\nfunc (p *Packet) Answers(other packet.Packet) bool {\n    if other == nil || other.GetType() != packet.IPv6 {\n        return false\n    }\n\n    /* TODO: check link-local broadcast addresses */\n    if !p.DstAddr.Equal(other.(*Packet).SrcAddr) {\n        return false\n    }\n\n    /* TODO: check ICMPv6 errors */\n\n    if p.Payload() != nil {\n        return p.Payload().Answers(other.Payload())\n    }\n\n    return true\n}\n\nfunc (p *Packet) Pack(buf *packet.Buffer) error {\n    buf.WriteN(uint8(p.Version << 4 | (p.Class >> 4)))\n    buf.WriteN(p.Class << 4 | uint8(p.Label >> 16))\n    buf.WriteN(uint16(p.Label))\n\n    buf.WriteN(p.Length)\n    buf.WriteN(p.NextHdr)\n    buf.WriteN(p.HopLimit)\n\n    buf.Write(p.SrcAddr.To16())\n    buf.Write(p.DstAddr.To16())\n\n    return nil\n}\n\nfunc (p *Packet) pseudo_checksum() uint32 {\n    var csum uint32\n\n    for i := 0; i < 16; i += 2 {\n        csum += uint32(p.SrcAddr.To16()[i]) << 8\n        csum += uint32(p.SrcAddr.To16()[i + 1])\n        csum += uint32(p.DstAddr.To16()[i]) << 8\n        csum += uint32(p.DstAddr.To16()[i + 1])\n    }\n\n    csum += uint32(p.Length)\n    csum += uint32(p.NextHdr)\n\n    return csum\n}\n\nfunc (p *Packet) Unpack(buf *packet.Buffer) error {\n    var versclass uint8\n    buf.ReadN(&versclass)\n\n    p.Version = versclass >> 4\n\n    p.Class =\n     uint8((binary.BigEndian.Uint16(buf.LayerBytes()[0:2]) >> 4) & 0x00FF)\n\n    p.Label =\n     binary.BigEndian.Uint32(buf.LayerBytes()[0:4]) & 0x000FFFFF\n\n    buf.Next(3)\n\n    buf.ReadN(&p.Length)\n    buf.ReadN(&p.NextHdr)\n    buf.ReadN(&p.HopLimit)\n\n    p.SrcAddr = net.IP(buf.Next(16))\n    p.DstAddr = net.IP(buf.Next(16))\n\n    /* TODO: Options */\n\n    return nil\n}\n\nfunc (p *Packet) Payload() packet.Packet {\n    return p.pkt_payload\n}\n\nfunc (p *Packet) GuessPayloadType() packet.Type {\n    return ipv4.ProtocolToType(p.NextHdr)\n}\n\nfunc (p *Packet) SetPayload(pl packet.Packet) error {\n    p.pkt_payload = pl\n    p.NextHdr     = ipv4.TypeToProtocol(pl.GetType())\n    p.Length      = pl.GetLength()\n\n    pl.InitChecksum(p.pseudo_checksum())\n\n    return nil\n}\n\nfunc (p *Packet) InitChecksum(csum uint32) {\n}\n\nfunc (p *Packet) String() string {\n    return packet.Stringify(p)\n}\n"
  },
  {
    "path": "packet/ipv6/pkt_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage ipv6_test\n\nimport \"bytes\"\nimport \"net\"\nimport \"testing\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/ipv4\"\nimport \"github.com/ghedo/go.pkt/packet/ipv6\"\n\nvar test_simple = []byte{\n    0x63, 0x0d, 0x5b, 0x0a, 0x00, 0x08, 0x11, 0x40, 0xfe, 0x80, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x4e, 0x72, 0xb9, 0xff, 0xfe, 0x54, 0xe5, 0x3d,\n    0x07, 0x9a, 0x19, 0xb9, 0x11, 0x15, 0xed, 0x67, 0x99, 0xf5, 0xf0, 0x7a,\n    0x66, 0x87, 0x5b, 0x0f,\n}\n\nvar ipsrc_str = \"fe80::4e72:b9ff:fe54:e53d\"\nvar ipdst_str = \"79a:19b9:1115:ed67:99f5:f07a:6687:5b0f\"\n\nfunc MakeTestSimple() *ipv6.Packet {\n    return &ipv6.Packet{\n        Version: 6,\n        Class: 48,\n        Label: 875274,\n        Length: 8,\n        NextHdr: ipv4.UDP,\n        HopLimit: 64,\n        SrcAddr: net.ParseIP(ipsrc_str),\n        DstAddr: net.ParseIP(ipdst_str),\n    }\n}\n\nfunc TestPack(t *testing.T) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    err := p.Pack(&b)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_simple, b.Buffer()) {\n        t.Fatalf(\"Raw packet mismatch: %x\", b.Buffer())\n    }\n}\n\nfunc BenchmarkPack(bn *testing.B) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    for n := 0; n < bn.N; n++ {\n        p.Pack(&b)\n    }\n}\n\nfunc TestUnpack(t *testing.T) {\n    var p ipv6.Packet\n\n    cmp := MakeTestSimple()\n\n    var b packet.Buffer\n    b.Init(test_simple)\n\n    err := p.Unpack(&b)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if !p.Equals(cmp) {\n        t.Fatalf(\"Packet mismatch:\\n%s\\n%s\", &p, cmp)\n    }\n}\n\nfunc BenchmarkUnpack(bn *testing.B) {\n    var p ipv6.Packet\n    var b packet.Buffer\n\n    for n := 0; n < bn.N; n++ {\n        b.Init(test_simple)\n        p.Unpack(&b)\n    }\n}\n"
  },
  {
    "path": "packet/llc/pkt.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides encoding and decoding for LLC (802.2 Logical Link Control) packets.\npackage llc\n\nimport \"github.com/ghedo/go.pkt/packet\"\n\ntype Packet struct {\n    DSAP        uint8\n    SSAP        uint8\n    Control     uint16        `string:\"ctrl\"`\n\n    pkt_payload packet.Packet `string:\"skip\"`\n}\n\nfunc Make() *Packet {\n    return &Packet{ }\n}\n\nfunc (p *Packet) GetType() packet.Type {\n    return packet.LLC\n}\n\nfunc (p *Packet) GetLength() uint16 {\n    if p.pkt_payload != nil {\n        return p.pkt_payload.GetLength() + 2\n    }\n\n    return 2\n}\n\nfunc (p *Packet) Equals(other packet.Packet) bool {\n    return packet.Compare(p, other)\n}\n\nfunc (p *Packet) Answers(other packet.Packet) bool {\n    return false\n}\n\nfunc (p *Packet) Pack(buf *packet.Buffer) error {\n    buf.WriteN(p.DSAP)\n    buf.WriteN(p.SSAP)\n\n    if p.Control & 0x1 == 0 || p.Control & 0x3 == 0x1 {\n        buf.WriteN(p.Control)\n    } else {\n        buf.WriteN(uint8(p.Control))\n    }\n\n    return nil\n}\n\nfunc (p *Packet) Unpack(buf *packet.Buffer) error {\n    buf.ReadN(&p.DSAP)\n    buf.ReadN(&p.SSAP)\n\n    if buf.Bytes()[:1][0] & 0x1 == 0 ||\n       buf.Bytes()[:1][0] & 0x3 == 0x1 {\n        buf.ReadN(&p.Control)\n    } else {\n        var ctrl uint8\n        buf.ReadN(&ctrl)\n        p.Control = uint16(ctrl)\n    }\n\n    return nil\n}\n\nfunc (p *Packet) Payload() packet.Packet {\n    return p.pkt_payload\n}\n\nfunc (p *Packet) GuessPayloadType() packet.Type {\n    if p.DSAP == 0xaa && p.SSAP == 0xaa {\n        return packet.SNAP\n    }\n\n    return packet.None\n}\n\nfunc (p *Packet) SetPayload(pl packet.Packet) error {\n    p.pkt_payload = pl\n\n    return nil\n}\n\nfunc (p *Packet) InitChecksum(csum uint32) {\n}\n\nfunc (p *Packet) String() string {\n    return packet.Stringify(p)\n}\n"
  },
  {
    "path": "packet/llc/pkt_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage llc_test\n\nimport \"bytes\"\nimport \"testing\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/llc\"\n\nvar test_simple = []byte{\n    0x4e, 0x5e, 0x0b,\n}\n\nfunc MakeTestSimple() *llc.Packet {\n    return &llc.Packet{\n        DSAP: 0x4e,\n        SSAP: 0x5e,\n        Control: 0xa | 0x1,\n    }\n}\n\nfunc TestPack(t *testing.T) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    err := p.Pack(&b)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_simple, b.Buffer()) {\n        t.Fatalf(\"Raw packet mismatch: %x\", b.Buffer())\n    }\n}\n\nfunc BenchmarkPack(bn *testing.B) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    for n := 0; n < bn.N; n++ {\n        p.Pack(&b)\n    }\n}\n\nfunc TestUnpack(t *testing.T) {\n    var p llc.Packet\n\n    cmp := MakeTestSimple()\n\n    var b packet.Buffer\n    b.Init(test_simple)\n\n    err := p.Unpack(&b)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if !p.Equals(cmp) {\n        t.Fatalf(\"Packet mismatch:\\n%s\\n%s\", &p, cmp)\n    }\n}\n\nfunc BenchmarkUnpack(bn *testing.B) {\n    var p llc.Packet\n    var b packet.Buffer\n\n    for n := 0; n < bn.N; n++ {\n        b.Init(test_simple)\n        p.Unpack(&b)\n    }\n}\n"
  },
  {
    "path": "packet/packet.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides the interfaces for implementing packet encoders and decoders. Every\n// supported protocol implements the Packet interface as a submodule of this\n// package (e.g. packet/ipv4, packet/tcp, ...).\npackage packet\n\nimport \"fmt\"\nimport \"reflect\"\nimport \"strconv\"\nimport \"strings\"\n\n// Type represents the protocol of a packet.\ntype Type uint16\n\nconst (\n    None Type = iota\n    ARP\n    Bluetooth /* TODO */\n    Eth\n    GRE       /* TODO */\n    ICMPv4\n    ICMPv6\n    IGMP      /* TODO */\n    IPSec     /* TODO */\n    IPv4\n    IPv6\n    ISIS      /* TODO */\n    L2TP      /* TODO */\n    LLC\n    LLDP      /* TODO */\n    OSPF      /* TODO */\n    RadioTap  /* TODO */\n    Raw\n    SCTP      /* TODO */\n    SLL\n    SNAP\n    TCP\n    TRILL     /* TODO */\n    UDP\n    UDPLite   /* TODO */\n    VLAN\n    WiFi      /* TODO */\n    WoL       /* TODO */\n)\n\n// Packet is the interface used internally to implement packet encoding and\n// decoding independently of the packet wire format.\ntype Packet interface {\n    /* Return the type of the packet */\n    GetType() Type\n\n    /* Return the length of the packet including the payload if present */\n    GetLength() uint16\n\n    /* Check if the packet matches another packet */\n    Equals(other Packet) bool\n\n    /* Check if the packet is an answer to another packet */\n    Answers(other Packet) bool\n\n    /* Encode the packet and write it to the given buffer */\n    Pack(out *Buffer) error\n\n    /* Decode the packet from the given buffer */\n    Unpack(in *Buffer) error\n\n    /* Return the payload of the packet or nil */\n    Payload() Packet\n\n    /* Initialize the payload of the packet */\n    SetPayload(payload Packet) error\n\n    /* Try to guess the type of the payload */\n    GuessPayloadType() Type\n\n    /* Initialize the checksum of the packet with the given seed */\n    InitChecksum(seed uint32)\n\n    String() string\n}\n\nvar pcap_link_type_to_type_map = [][2]uint32{\n    {   1, uint32(Eth)      },\n    { 113, uint32(SLL)      },\n    { 127, uint32(RadioTap) },\n    { 228, uint32(IPv4)     },\n    { 229, uint32(IPv6)     },\n}\n\n// Create a new type from the given PCAP link type.\nfunc LinkType(link_type uint32) Type {\n    for _, t := range pcap_link_type_to_type_map {\n        if t[0] == link_type {\n            return Type(t[1])\n        }\n    }\n\n    return None\n}\n\n// Convert the Type to the corresponding PCAP link type.\nfunc (pkttype Type) ToLinkType() uint32 {\n    for _, t := range pcap_link_type_to_type_map {\n        if t[1] == uint32(pkttype) {\n            return t[0]\n        }\n    }\n\n    return 0x00\n}\n\nfunc (t Type) String() string {\n    switch t {\n    case ARP:       return \"ARP\"\n    case Bluetooth: return \"Bluetooth\"\n    case Eth:       return \"Ethernet\"\n    case GRE:       return \"GRE\"\n    case ICMPv4:    return \"ICMPv4\"\n    case ICMPv6:    return \"ICMPv6\"\n    case IGMP:      return \"IGMP\"\n    case IPSec:     return \"IPSec\"\n    case IPv4:      return \"IPv4\"\n    case IPv6:      return \"IPv6\"\n    case ISIS:      return \"IS-IS\"\n    case L2TP:      return \"L2TP\"\n    case LLC:       return \"LLC\"\n    case LLDP:      return \"LLDP\"\n    case None:      return \"None\"\n    case OSPF:      return \"OSPF\"\n    case RadioTap:  return \"RadioTap\"\n    case SCTP:      return \"SCTP\"\n    case SNAP:      return \"SNAP\"\n    case SLL:       return \"SLL\"\n    case TCP:       return \"TCP\"\n    case TRILL:     return \"TRILL\"\n    case UDPLite:   return \"UDP Lite\"\n    case UDP:       return \"UDP\"\n    case VLAN:      return \"VLAN\"\n    case WiFi:      return \"WiFi\"\n    case WoL:       return \"WoL\"\n    /* case Raw: */\n    default:        return \"Data\"\n    }\n}\n\nfunc Compare(a, b Packet) bool {\n    if a == nil || b == nil {\n        return a == b\n    }\n\n    if a.GetType() != b.GetType() {\n        return false\n    }\n\n    aval := reflect.ValueOf(a).Elem()\n    bval := reflect.ValueOf(b).Elem()\n\n    for i := 0; i < aval.NumField(); i++ {\n        ftype := aval.Type().Field(i)\n\n        if ftype.Tag.Get(\"cmp\") == \"skip\" {\n            continue\n        }\n\n        if !compare_value(aval.Field(i), bval.Field(i)) {\n            fmt.Println(aval.Type().Field(i).Name)\n            return false\n        }\n    }\n\n    return true\n}\n\nfunc compare_value(a, b reflect.Value) bool {\n    if a.Type() != b.Type() {\n        return false\n    }\n\n    m := a.MethodByName(\"Equal\")\n    if m.IsValid() {\n        res := m.Call([]reflect.Value{b})\n        return res[0].Bool()\n    }\n\n    switch a.Kind() {\n    case reflect.Bool:\n        return a.Bool() == b.Bool()\n\n    case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n        return a.Uint() == b.Uint()\n\n    case reflect.Array:\n        for i := 0; i < a.Len(); i++ {\n            if !compare_value(a.Index(i), b.Index(i)) {\n                return false\n            }\n        }\n\n        return true\n\n    case reflect.Slice:\n        if a.IsNil() != b.IsNil() {\n            return false\n        }\n\n        if a.Len() != b.Len() {\n            return false\n        }\n\n        if a.Pointer() == b.Pointer() {\n            return true\n        }\n\n        for i := 0; i < a.Len(); i++ {\n            if !compare_value(a.Index(i), b.Index(i)) {\n                return false\n            }\n        }\n\n        return true\n\n    case reflect.Interface:\n        return true\n\n    default:\n        return false\n    }\n}\n\nfunc Stringify(p Packet) string {\n    value := reflect.ValueOf(p).Elem()\n    name  := strings.ToLower(p.GetType().String())\n\n    var fields []string\n    for i := 0; i < value.NumField(); i++ {\n        field := value.Field(i)\n        ftype := value.Type().Field(i)\n\n        key := strings.ToLower(ftype.Name)\n\n        if ftype.Tag.Get(\"string\") != \"\" {\n            key = ftype.Tag.Get(\"string\")\n        }\n\n        if key == \"skip\" {\n            continue\n        }\n\n        val := stringify_value(key, field)\n        if val != \"\" {\n            fields = append(fields, fmt.Sprintf(\"%s=%s\", key, val))\n        }\n    }\n\n    s := fmt.Sprintf(\"%s(%s)\", name, strings.Join(fields, \", \"))\n\n    if p.Payload() != nil {\n        s = strings.Join([]string{s, p.Payload().String()}, \" | \")\n    }\n\n    return s\n}\n\nfunc stringify_value(key string, val reflect.Value) string {\n    var s string\n    var m reflect.Value\n\n    if !val.IsValid() {\n        goto end\n    }\n\n    switch val.Kind() {\n    case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n        if val.Uint() > 0 {\n            if key == \"sum\" || key == \"type\" {\n                s = \"0x\" + strconv.FormatUint(val.Uint(), 16)\n            } else {\n                s = strconv.FormatUint(val.Uint(), 10)\n            }\n        }\n\n    case reflect.Interface, reflect.Slice, reflect.Struct:\n        if val.IsNil() {\n            goto end\n        }\n\n    case reflect.Bool:\n        if val.Bool() {\n            s = \"true\"\n        }\n    }\n\n    m = val.MethodByName(\"String\")\n    if m.IsValid() {\n        res := m.Call([]reflect.Value{})\n        s = res[0].String()\n    }\n\nend:\n    return s\n}\n"
  },
  {
    "path": "packet/radiotap/pkt.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides encoding and decoding for RadioTap packets.\npackage radiotap\n\nimport \"fmt\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\n\ntype Packet struct {\n    Version         uint8\n    Length          uint16\n    Present         Present\n    Data            []byte        `cmp:\"skip\" string:\"skip\"`\n    pkt_payload     packet.Packet `cmp:\"skip\" string:\"skip\"`\n}\n\ntype Present uint32\n\nconst (\n    TSFT Present = 1 << iota\n    Flags\n    Rate\n    Channel\n    FHSS\n    DbmAntSignal\n    DbmAntNoise\n    LockQuality\n    TXAttenuation\n    DbTXAttenuation\n    DbmTXPower\n    Antenna\n    DbAntSignal\n    DbAntNoise\n    EXT\n)\n\nfunc Make() *Packet {\n    return &Packet{\n    }\n}\n\nfunc (p *Packet) GetType() packet.Type {\n    return packet.RadioTap\n}\n\nfunc (p *Packet) GetLength() uint16 {\n    if p.pkt_payload != nil {\n        return p.pkt_payload.GetLength() + 8 + uint16(len(p.Data))\n    }\n\n    return 8 + uint16(len(p.Data))\n}\n\nfunc (p *Packet) Equals(other packet.Packet) bool {\n    return packet.Compare(p, other)\n}\n\nfunc (p *Packet) Answers(other packet.Packet) bool {\n    return false\n}\n\nfunc (p *Packet) Pack(buf *packet.Buffer) error {\n    buf.WriteL(p.Version)\n    buf.WriteL(uint8(0x00))\n    buf.WriteL(p.Length)\n    buf.WriteL(p.Present)\n\n    /* TODO: actually decode fields */\n    buf.Write(p.Data)\n\n    return nil\n}\n\nfunc (p *Packet) Unpack(buf *packet.Buffer) error {\n    buf.ReadN(&p.Version)\n\n    var pad uint8\n    buf.ReadL(&pad)\n\n    buf.ReadL(&p.Length)\n    buf.ReadL(&p.Present)\n\n    /* TODO: actually decode fields */\n    p.Data = buf.Next(int(p.Length) - 8)\n\n    return nil\n}\n\nfunc (p *Packet) Payload() packet.Packet {\n    return p.pkt_payload\n}\n\nfunc (p *Packet) GuessPayloadType() packet.Type {\n    return packet.WiFi\n}\n\nfunc (p *Packet) SetPayload(pl packet.Packet) error {\n    p.pkt_payload = pl\n    p.Length      = p.GetLength()\n\n    return nil\n}\n\nfunc (p *Packet) InitChecksum(csum uint32) {\n}\n\nfunc (p *Packet) String() string {\n    return packet.Stringify(p)\n}\n\nfunc (p Present) String() string {\n    return fmt.Sprintf(\"0x%x\", uint32(p))\n}\n"
  },
  {
    "path": "packet/radiotap/pkt_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage radiotap_test\n\nimport \"bytes\"\nimport \"testing\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/radiotap\"\n\nvar test_simple = []byte{\n    0x00, 0x00, 0x20, 0x00, 0x67, 0x08, 0x04, 0x00, 0x54, 0xc6, 0xb8, 0x24,\n    0x00, 0x00, 0x00, 0x00, 0x22, 0x0c, 0xda, 0xa0, 0x02, 0x00, 0x00, 0x00,\n    0x40, 0x01, 0x00, 0x00, 0x3c, 0x14, 0x24, 0x11,\n}\n\nfunc MakeTestSimple() *radiotap.Packet {\n    return &radiotap.Packet{\n        Version: 0,\n        Length: 32,\n        Present: 264295,\n        Data: []byte{0x54, 0xc6, 0xb8, 0x24, 0x00, 0x00, 0x00, 0x00,\n                     0x22, 0x0c, 0xda, 0xa0, 0x02, 0x00, 0x00, 0x00,\n                     0x40, 0x01, 0x00, 0x00, 0x3c, 0x14, 0x24, 0x11,\n        },\n    }\n}\n\nfunc TestPack(t *testing.T) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    err := p.Pack(&b)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_simple, b.Buffer()) {\n        t.Fatalf(\"Raw packet mismatch: %x\", b.Buffer())\n    }\n}\n\nfunc BenchmarkPack(bn *testing.B) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    for n := 0; n < bn.N; n++ {\n        p.Pack(&b)\n    }\n}\n\nfunc TestUnpack(t *testing.T) {\n    var p radiotap.Packet\n\n    cmp := MakeTestSimple()\n\n    var b packet.Buffer\n    b.Init(test_simple)\n\n    err := p.Unpack(&b)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if !p.Equals(cmp) {\n        t.Fatalf(\"Packet mismatch:\\n%s\\n%s\", &p, cmp)\n    }\n}\n\nfunc BenchmarkUnpack(bn *testing.B) {\n    var p radiotap.Packet\n    var b packet.Buffer\n\n    for n := 0; n < bn.N; n++ {\n        b.Init(test_simple)\n        p.Unpack(&b)\n    }\n}\n"
  },
  {
    "path": "packet/raw/pkt.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides encoding and decoding for raw data packets.\npackage raw\n\nimport \"fmt\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\n\ntype Packet struct {\n    Data   []byte `string:\"skip\"`\n}\n\nfunc Make() *Packet {\n    return &Packet{ }\n}\n\nfunc (p *Packet) GetType() packet.Type {\n    return packet.Raw\n}\n\nfunc (p *Packet) GetLength() uint16 {\n    return uint16(len(p.Data))\n}\n\nfunc (p *Packet) Equals(other packet.Packet) bool {\n    return packet.Compare(p, other)\n}\n\nfunc (p *Packet) Answers(other packet.Packet) bool {\n    return false\n}\n\nfunc (p *Packet) Pack(buf *packet.Buffer) error {\n    buf.Write(p.Data)\n\n    return nil\n}\n\nfunc (p *Packet) Unpack(buf *packet.Buffer) error {\n    p.Data   = buf.Next(buf.Len())\n\n    return nil\n}\n\nfunc (p *Packet) Payload() packet.Packet {\n    return nil\n}\n\nfunc (p *Packet) GuessPayloadType() packet.Type {\n    return packet.None\n}\n\nfunc (p *Packet) SetPayload(pl packet.Packet) error {\n    return nil\n}\n\nfunc (p *Packet) InitChecksum(csum uint32) {\n}\n\nfunc (p *Packet) String() string {\n    return fmt.Sprintf(\"data(len=%d)\", len(p.Data))\n}\n"
  },
  {
    "path": "packet/raw/pkt_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage raw_test\n\nimport \"bytes\"\nimport \"testing\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/raw\"\n\nvar test_simple = []byte{\n    0x61, 0x73, 0x64, 0x61, 0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,\n    0x73, 0x64, 0x20, 0x61, 0x73,\n}\n\nfunc MakeTestSimple() *raw.Packet {\n    return &raw.Packet{\n        Data: []byte(\"asdasd asd asd as\"),\n    }\n}\n\nfunc TestPack(t *testing.T) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    err := p.Pack(&b)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_simple, b.Buffer()) {\n        t.Fatalf(\"Raw packet mismatch: %x\", b.Buffer())\n    }\n}\n\nfunc BenchmarkPack(bn *testing.B) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    for n := 0; n < bn.N; n++ {\n        p.Pack(&b)\n    }\n}\n\nfunc TestUnpack(t *testing.T) {\n    var p raw.Packet\n\n    cmp := MakeTestSimple()\n\n    var b packet.Buffer\n    b.Init(test_simple)\n\n    err := p.Unpack(&b)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if !p.Equals(cmp) {\n        t.Fatalf(\"Packet mismatch:\\n%s\\n%s\", &p, cmp)\n    }\n}\n\nfunc BenchmarkUnpack(bn *testing.B) {\n    var p raw.Packet\n    var b packet.Buffer\n\n    for n := 0; n < bn.N; n++ {\n        b.Init(test_simple)\n        p.Unpack(&b)\n    }\n}\n"
  },
  {
    "path": "packet/sll/pkt.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides encoding and decoding for SLL (Linux cooked mode) packets.\npackage sll\n\nimport \"net\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/eth\"\n\ntype Packet struct {\n    Type        Type\n    AddrType    uint16           `string:\"atype\"`\n    AddrLen     uint16           `string:\"alen\"`\n    SrcAddr     net.HardwareAddr `string:\"src\"`\n    EtherType   eth.EtherType\n    pkt_payload packet.Packet    `cmp:\"skip\" string:\"skip\"`\n}\n\ntype Type uint16\n\nconst (\n    Host      Type = 0\n    Broadcast Type = 1\n    Multicast Type = 2\n    OtherHost Type = 3\n    Outgoing  Type = 4\n)\n\nfunc Make() *Packet {\n    return &Packet{\n        Type: Host,\n        AddrType: 2,\n        AddrLen: 6,\n    }\n}\n\nfunc (p *Packet) GetType() packet.Type {\n    return packet.SLL\n}\n\nfunc (p *Packet) GetLength() uint16 {\n    if p.pkt_payload != nil {\n        return p.pkt_payload.GetLength() + 16\n    }\n\n    return p.AddrLen + 16\n}\n\nfunc (p *Packet) Equals(other packet.Packet) bool {\n    return packet.Compare(p, other)\n}\n\nfunc (p *Packet) Answers(other packet.Packet) bool {\n    return false\n}\n\nfunc (p *Packet) Pack(buf *packet.Buffer) error {\n    buf.WriteN(p.Type)\n    buf.WriteN(p.AddrType)\n    buf.WriteN(p.AddrLen)\n    buf.WriteN(p.SrcAddr)\n\n    for i := 0; i < 8 - int(p.AddrLen); i++ {\n        buf.WriteN(uint8(0x00))\n    }\n\n    buf.WriteN(p.EtherType)\n\n    return nil\n}\n\nfunc (p *Packet) Unpack(buf *packet.Buffer) error {\n    buf.ReadN(&p.Type)\n    buf.ReadN(&p.AddrType)\n    buf.ReadN(&p.AddrLen)\n\n    p.SrcAddr = net.HardwareAddr(buf.Next(int(p.AddrLen)))\n    buf.Next(8 - int(p.AddrLen))\n\n    buf.ReadN(&p.EtherType)\n\n    return nil\n}\n\nfunc (p *Packet) Payload() packet.Packet {\n    return p.pkt_payload\n}\n\nfunc (p *Packet) GuessPayloadType() packet.Type {\n    return eth.EtherTypeToType(p.EtherType)\n}\n\nfunc (p *Packet) SetPayload(pl packet.Packet) error {\n    p.pkt_payload = pl\n    p.EtherType   = eth.TypeToEtherType(pl.GetType())\n\n    return nil\n}\n\nfunc (p *Packet) InitChecksum(csum uint32) {\n}\n\nfunc (p *Packet) String() string {\n    return packet.Stringify(p)\n}\n\nfunc (t Type) String() string {\n    switch t {\n    case Host:      return \"host\"\n    case Broadcast: return \"broadcast\"\n    case Multicast: return \"multicast\"\n    case OtherHost: return \"other\"\n    case Outgoing:  return \"outgoing\"\n    default:        return \"unknown\"\n    }\n}\n"
  },
  {
    "path": "packet/sll/pkt_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage sll_test\n\nimport \"bytes\"\nimport \"net\"\nimport \"testing\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/eth\"\nimport \"github.com/ghedo/go.pkt/packet/sll\"\n\nvar hwsrc_str = \"4c:72:b9:54:e5:3d\"\n\nvar test_simple = []byte{\n    0x00, 0x04, 0x00, 0x01, 0x00, 0x06, 0x4c, 0x72, 0xb9, 0x54, 0xe5, 0x3d,\n    0x00, 0x00, 0x08, 0x00,\n}\n\nfunc MakeTestSimple() *sll.Packet {\n    hwsrc, _ := net.ParseMAC(hwsrc_str)\n\n    return &sll.Packet{\n        Type: sll.Outgoing,\n        AddrType: 1,\n        AddrLen: 6,\n        SrcAddr: hwsrc,\n        EtherType: eth.IPv4,\n    }\n}\n\nfunc TestPack(t *testing.T) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    err := p.Pack(&b)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_simple, b.Buffer()) {\n        t.Fatalf(\"Raw packet mismatch: %x\", b.Buffer())\n    }\n}\n\nfunc BenchmarkPack(bn *testing.B) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    for n := 0; n < bn.N; n++ {\n        p.Pack(&b)\n    }\n}\n\nfunc TestUnpack(t *testing.T) {\n    var p sll.Packet\n\n    cmp := MakeTestSimple()\n\n    var b packet.Buffer\n    b.Init(test_simple)\n\n    err := p.Unpack(&b)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if !p.Equals(cmp) {\n        t.Fatalf(\"Packet mismatch:\\n%s\\n%s\", &p, cmp)\n    }\n}\n\nfunc BenchmarkUnpack(bn *testing.B) {\n    var p sll.Packet\n    var b packet.Buffer\n\n    for n := 0; n < bn.N; n++ {\n        b.Init(test_simple)\n        p.Unpack(&b)\n    }\n}\n"
  },
  {
    "path": "packet/snap/pkt.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides encoding and decoding for SNAP packets.\npackage snap\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/eth\"\n\ntype Packet struct {\n    OUI         [3]byte\n    Type        eth.EtherType\n\n    pkt_payload packet.Packet `cmp:\"skip\" string:\"skip\"`\n}\n\nfunc Make() *Packet {\n    return &Packet{ }\n}\n\nfunc (p *Packet) GetType() packet.Type {\n    return packet.SNAP\n}\n\nfunc (p *Packet) GetLength() uint16 {\n    if p.pkt_payload != nil {\n        return p.pkt_payload.GetLength() + 5\n    }\n\n    return 5\n}\n\nfunc (p *Packet) Equals(other packet.Packet) bool {\n    return packet.Compare(p, other)\n}\n\nfunc (p *Packet) Answers(other packet.Packet) bool {\n    return false\n}\n\nfunc (p *Packet) Pack(buf *packet.Buffer) error {\n    buf.WriteN(p.OUI)\n    buf.WriteN(p.Type)\n\n    return nil\n}\n\nfunc (p *Packet) Unpack(buf *packet.Buffer) error {\n    buf.ReadN(&p.OUI)\n    buf.ReadN(&p.Type)\n\n    return nil\n}\n\nfunc (p *Packet) Payload() packet.Packet {\n    return p.pkt_payload\n}\n\nfunc (p *Packet) GuessPayloadType() packet.Type {\n    if p.OUI[0] == 0x00 && p.OUI[1] == 0x00 && p.OUI[2] == 0x00 {\n        return eth.EtherTypeToType(p.Type)\n    } else {\n        return packet.Raw\n    }\n}\n\nfunc (p *Packet) SetPayload(pl packet.Packet) error {\n    p.pkt_payload = pl\n    p.Type        = eth.TypeToEtherType(pl.GetType())\n\n    return nil\n}\n\nfunc (p *Packet) InitChecksum(csum uint32) {\n}\n\nfunc (p *Packet) String() string {\n    return packet.Stringify(p)\n}\n"
  },
  {
    "path": "packet/snap/pkt_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage snap_test\n\nimport \"bytes\"\nimport \"testing\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/eth\"\nimport \"github.com/ghedo/go.pkt/packet/snap\"\n\nvar test_simple = []byte{\n    0x00, 0x00, 0x00, 0x08, 0x00,\n}\n\nfunc MakeTestSimple() *snap.Packet {\n    return &snap.Packet{\n        Type: eth.IPv4,\n    }\n}\n\nfunc TestPack(t *testing.T) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    err := p.Pack(&b)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_simple, b.Buffer()) {\n        t.Fatalf(\"Raw packet mismatch: %x\", b.Buffer())\n    }\n}\n\nfunc BenchmarkPack(bn *testing.B) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    for n := 0; n < bn.N; n++ {\n        p.Pack(&b)\n    }\n}\n\nfunc TestUnpack(t *testing.T) {\n    var p snap.Packet\n\n    cmp := MakeTestSimple()\n\n    var b packet.Buffer\n    b.Init(test_simple)\n\n    err := p.Unpack(&b)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if !p.Equals(cmp) {\n        t.Fatalf(\"Packet mismatch:\\n%s\\n%s\", &p, cmp)\n    }\n}\n\nfunc BenchmarkUnpack(bn *testing.B) {\n    var p snap.Packet\n    var b packet.Buffer\n\n    for n := 0; n < bn.N; n++ {\n        b.Init(test_simple)\n        p.Unpack(&b)\n    }\n}\n"
  },
  {
    "path": "packet/tcp/pkt.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides encoding and decoding for TCP packets.\npackage tcp\n\nimport \"strings\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/ipv4\"\n\ntype Packet struct {\n    SrcPort     uint16        `string:\"sport\"`\n    DstPort     uint16        `string:\"dport\"`\n    Seq         uint32\n    Ack         uint32\n    DataOff     uint8         `string:\"off\"`\n    Flags       Flags\n    WindowSize  uint16        `string:\"win\"`\n    Checksum    uint16        `string:\"sum\"`\n    Urgent      uint16        `string:\"urg\"`\n    Options     []Option      `cmp:\"skip\" string:\"skip\"`\n    csum_seed   uint32        `cmp:\"skip\" string:\"skip\"`\n    pkt_payload packet.Packet `cmp:\"skip\" string:\"skip\"`\n}\n\ntype Flags uint16\n\nconst (\n    Syn Flags = 1<<1\n    Fin       = 1<<2\n    Rst       = 1<<3\n    PSH       = 1<<4\n    Ack       = 1<<5\n    Urg       = 1<<6\n    ECE       = 1<<7\n    Cwr       = 1<<8\n    NS        = 1<<9\n)\n\ntype Option struct {\n    Type OptType\n    Len  uint8\n    Data []byte\n}\n\ntype OptType uint8\n\nconst (\n    End OptType = 0x00\n    Nop         = 0x01\n    MSS         = 0x02\n    WindowScale = 0x03\n    SAckOk      = 0x04\n    SAck        = 0x05\n    Timestamp   = 0x08\n)\n\nfunc Make() *Packet {\n    return &Packet{\n        Flags: Syn,\n        DataOff: 5,\n        WindowSize: 5840,\n    }\n}\n\nfunc (p *Packet) GetType() packet.Type {\n    return packet.TCP\n}\n\nfunc (p *Packet) GetLength() uint16 {\n    if p.pkt_payload != nil {\n        return p.pkt_payload.GetLength() + uint16(p.DataOff) * 4\n    }\n\n    return uint16(p.DataOff) * 4\n}\n\nfunc (p *Packet) Equals(other packet.Packet) bool {\n    return packet.Compare(p, other)\n}\n\nfunc (p *Packet) Answers(other packet.Packet) bool {\n    if other == nil || other.GetType() != packet.TCP {\n        return false\n    }\n\n    if p.SrcPort != other.(*Packet).DstPort ||\n       p.DstPort != other.(*Packet).SrcPort {\n        return false\n    }\n\n    return true\n}\n\nfunc (p *Packet) Pack(buf *packet.Buffer) error {\n    buf.WriteN(p.SrcPort)\n    buf.WriteN(p.DstPort)\n    buf.WriteN(p.Seq)\n    buf.WriteN(p.Ack)\n\n    flags := uint16(p.DataOff) << 12\n\n    if p.Flags & Fin != 0 {\n        flags |= 0x0001\n    }\n\n    if p.Flags & Syn != 0 {\n        flags |= 0x0002\n    }\n\n    if p.Flags & Rst != 0 {\n        flags |= 0x0004\n    }\n\n    if p.Flags & PSH != 0 {\n        flags |= 0x0008\n    }\n\n    if p.Flags & Ack != 0 {\n        flags |= 0x0010\n    }\n\n    if p.Flags & Urg != 0 {\n        flags |= 0x0020\n    }\n\n    if p.Flags & ECE != 0 {\n        flags |= 0x0040\n    }\n\n    if p.Flags & Cwr != 0 {\n        flags |= 0x0080\n    }\n\n    if p.Flags & NS != 0 {\n        flags |= 0x0100\n    }\n\n    buf.WriteN(flags)\n\n    buf.WriteN(p.WindowSize)\n    buf.WriteN(uint16(0x0000))\n    buf.WriteN(p.Urgent)\n\n    for _, opt := range p.Options {\n        buf.WriteN(opt.Type)\n        buf.WriteN(opt.Len)\n        buf.WriteN(opt.Data)\n    }\n\n    if p.csum_seed != 0 {\n        p.Checksum =\n          ipv4.CalculateChecksum(buf.LayerBytes(), p.csum_seed)\n    }\n\n    buf.PutUint16N(16, p.Checksum)\n\n    /* add padding */\n    for buf.LayerLen() < int(p.DataOff) * 4 {\n        buf.WriteN(uint8(0x00))\n    }\n\n    return nil\n}\n\nfunc (p *Packet) Unpack(buf *packet.Buffer) error {\n    buf.ReadN(&p.SrcPort)\n    buf.ReadN(&p.DstPort)\n    buf.ReadN(&p.Seq)\n    buf.ReadN(&p.Ack)\n\n    var offns uint8\n    buf.ReadN(&offns)\n\n    p.DataOff = offns >> 4\n\n    if offns & 0x01 != 0 {\n        p.Flags |= NS\n    }\n\n    var flags uint8\n    buf.ReadN(&flags)\n\n    if flags & 0x01 != 0 {\n        p.Flags |= Fin\n    }\n\n    if flags & 0x02 != 0 {\n        p.Flags |= Syn\n    }\n\n    if flags & 0x04 != 0 {\n        p.Flags |= Rst\n    }\n\n    if flags & 0x08 != 0 {\n        p.Flags |= PSH\n    }\n\n    if flags & 0x10 != 0 {\n        p.Flags |= Ack\n    }\n\n    if flags & 0x20 != 0 {\n        p.Flags |= Urg\n    }\n\n    if flags & 0x40 != 0 {\n        p.Flags |= ECE\n    }\n\n    if flags & 0x80 != 0 {\n        p.Flags |= Cwr\n    }\n\n    buf.ReadN(&p.WindowSize)\n    buf.ReadN(&p.Checksum)\n    buf.ReadN(&p.Urgent)\n\noptions:\n    for buf.LayerLen() < int(p.DataOff) * 4 {\n        var opt_type OptType\n        buf.ReadN(&opt_type)\n\n        switch opt_type {\n        case End: /* end of options */\n            break options\n\n        case Nop: /* padding */\n            continue\n\n        default:\n            opt := Option{ Type: opt_type }\n\n            buf.ReadN(&opt.Len)\n            opt.Data = buf.Next(int(opt.Len) - 2)\n\n            p.Options = append(p.Options, opt)\n        }\n    }\n\n    /* remove padding */\n    if buf.LayerLen() < int(p.DataOff) * 4 {\n        buf.Next(int(p.DataOff) * 4 - buf.LayerLen())\n    }\n\n    return nil\n}\n\nfunc (p *Packet) Payload() packet.Packet {\n    return p.pkt_payload\n}\n\nfunc (p *Packet) GuessPayloadType() packet.Type {\n    return packet.Raw\n}\n\nfunc (p *Packet) SetPayload(pl packet.Packet) error {\n    p.pkt_payload = pl\n\n    return nil\n}\n\nfunc (p *Packet) InitChecksum(csum uint32) {\n    p.csum_seed = csum\n}\n\nfunc (p *Packet) String() string {\n    return packet.Stringify(p)\n}\n\nfunc (f Flags) String() string {\n    var flags []string\n\n    if f & Fin != 0 {\n        flags = append(flags, \"fin\")\n    }\n\n    if f & Syn != 0 {\n        flags = append(flags, \"syn\")\n    }\n\n    if f & Rst != 0 {\n        flags = append(flags, \"rst\")\n    }\n\n    if f & PSH != 0 {\n        flags = append(flags, \"psh\")\n    }\n\n    if f & Ack != 0 {\n        flags = append(flags, \"ack\")\n    }\n\n    if f & Urg != 0 {\n        flags = append(flags, \"urg\")\n    }\n\n    if f & ECE != 0 {\n        flags = append(flags, \"ece\")\n    }\n\n    if f & Cwr != 0 {\n        flags = append(flags, \"cwr\")\n    }\n\n    if f & NS != 0 {\n        flags = append(flags, \"ns\")\n    }\n\n    return strings.Join(flags, \"|\")\n}\n"
  },
  {
    "path": "packet/tcp/pkt_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage tcp_test\n\nimport \"bytes\"\nimport \"net\"\nimport \"testing\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/ipv4\"\nimport \"github.com/ghedo/go.pkt/packet/tcp\"\n\nvar test_simple = []byte{\n    0x00, 0x14, 0x00, 0x50, 0x00, 0x00, 0x15, 0x18, 0x00, 0x00, 0x01, 0xb0,\n    0x50, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x28,\n}\n\nfunc MakeTestSimple() *tcp.Packet {\n    return &tcp.Packet{\n        SrcPort: 20,\n        DstPort: 80,\n        Seq: 5400,\n        Ack: 432,\n        DataOff: 5,\n        Flags: tcp.Syn,\n        WindowSize: 8192,\n        Urgent: 40,\n    }\n}\n\nfunc TestPack(t *testing.T) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    err := p.Pack(&b)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_simple, b.Buffer()) {\n        t.Fatalf(\"Raw packet mismatch: %x\", b.Buffer())\n    }\n}\n\nfunc BenchmarkPack(bn *testing.B) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    for n := 0; n < bn.N; n++ {\n        p.Pack(&b)\n    }\n}\n\nfunc TestUnpack(t *testing.T) {\n    var p tcp.Packet\n\n    cmp := MakeTestSimple()\n\n    var b packet.Buffer\n    b.Init(test_simple)\n\n    err := p.Unpack(&b)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if !p.Equals(cmp) {\n        t.Fatalf(\"Packet mismatch:\\n%s\\n%s\", &p, cmp)\n    }\n}\n\nfunc BenchmarkUnpack(bn *testing.B) {\n    var p tcp.Packet\n    var b packet.Buffer\n\n    for n := 0; n < bn.N; n++ {\n        b.Init(test_simple)\n        p.Unpack(&b)\n    }\n}\n\nvar test_with_ipv4 = []byte{\n    0x00, 0x14, 0x00, 0x50, 0x00, 0x00, 0x15, 0x18, 0x00, 0x00, 0x01, 0xb0,\n    0x50, 0x02, 0x20, 0x00, 0xa6, 0x4f, 0x00, 0x28,\n}\n\nvar ipsrc_str = \"192.168.1.135\"\nvar ipdst_str = \"8.8.8.8\"\n\nfunc TestPackWithIPv4(t *testing.T) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_with_ipv4)))\n\n    ip4 := ipv4.Make()\n    ip4.SrcAddr = net.ParseIP(ipsrc_str)\n    ip4.DstAddr = net.ParseIP(ipdst_str)\n\n    tcp := MakeTestSimple()\n\n    ip4.SetPayload(tcp)\n\n    err := tcp.Pack(&b)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_with_ipv4, b.Buffer()) {\n        t.Fatalf(\"Raw packet mismatch: %x\", b.Buffer())\n    }\n}\n\nfunc TestUnpackWithIPv4(t *testing.T) {\n    var p tcp.Packet\n\n    cmp := MakeTestSimple()\n    cmp.Checksum = 0xa64f\n\n    var b packet.Buffer\n    b.Init(test_with_ipv4)\n\n    err := p.Unpack(&b)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if !p.Equals(cmp) {\n        t.Fatalf(\"Packet mismatch:\\n%s\\n%s\", &p, cmp)\n    }\n}\n\nvar test_options = []byte{\n    0x00, 0x14, 0x00, 0x50, 0x00, 0x00, 0x15, 0x18, 0x00, 0x00, 0x01, 0xb0,\n    0xa0, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x28, 0x02, 0x04, 0x05, 0x78,\n    0x04, 0x02, 0x08, 0x0a, 0x61, 0x25, 0xe5, 0xb2, 0x00, 0x13, 0x15, 0x66,\n    0x03, 0x03, 0x0a, 0x00,\n}\n\nfunc TestPackOptions(t *testing.T) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_options)))\n\n    p := MakeTestSimple()\n\n    p.DataOff = 10\n\n    p.Options = append(p.Options,\n        tcp.Option{\n            Type: tcp.MSS,\n            Len:  4,\n            Data: []byte{0x05, 0x78},\n        },\n    )\n\n    p.Options = append(p.Options,\n        tcp.Option{\n            Type: tcp.SAckOk,\n            Len:  2,\n        },\n    )\n\n    p.Options = append(p.Options,\n        tcp.Option{\n            Type: tcp.Timestamp,\n            Len:  10,\n            Data: []byte{0x61, 0x25, 0xE5, 0xB2, 0x00, 0x13, 0x15, 0x66},\n        },\n    )\n\n    p.Options = append(p.Options,\n        tcp.Option{\n            Type: tcp.WindowScale,\n            Len:  3,\n            Data: []byte{0x0A},\n        },\n    )\n\n    p.Options = append(p.Options,\n        tcp.Option{\n            Type: tcp.End,\n        },\n    )\n\n    err := p.Pack(&b)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_options, b.Buffer()) {\n        t.Fatalf(\"Raw packet mismatch: %x\", b.Buffer())\n    }\n}\n\nfunc TestUnpackOptions(t *testing.T) {\n    var p tcp.Packet\n\n    var b packet.Buffer\n    b.Init(test_options)\n\n    err := p.Unpack(&b)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if len(p.Options) != 4 {\n        t.Fatalf(\"Options number mismatch: %d\", len(p.Options))\n    }\n\n    if p.Options[0].Type != tcp.MSS {\n        t.Fatalf(\"Option MSS mismatch: %x\", p.Options[0].Data)\n    }\n\n    if p.Options[1].Type != tcp.SAckOk {\n        t.Fatalf(\"Option SAckOk mismatch: %x\", p.Options[1].Data)\n    }\n\n    if p.Options[2].Type != tcp.Timestamp {\n        t.Fatalf(\"Option Timestamp mismatch: %x\", p.Options[2].Data)\n    }\n\n    if p.Options[3].Type != tcp.WindowScale {\n        t.Fatalf(\"Option WindowScale mismatch: %x\", p.Options[3].Data)\n    }\n}\n"
  },
  {
    "path": "packet/udp/pkt.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides encoding and decoding for UDP packets.\npackage udp\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/ipv4\"\n\ntype Packet struct {\n    SrcPort     uint16        `string:\"sport\"`\n    DstPort     uint16        `string:\"dport\"`\n    Length      uint16        `string:\"len\"`\n    Checksum    uint16        `string:\"sum\"`\n    csum_seed   uint32        `cmp:\"skip\" string:\"skip\"`\n    pkt_payload packet.Packet `cmp:\"skip\" string:\"skip\"`\n}\n\nfunc Make() *Packet {\n    return &Packet{\n        Length: 8,\n    }\n}\n\nfunc (p *Packet) GetType() packet.Type {\n    return packet.UDP\n}\n\nfunc (p *Packet) GetLength() uint16 {\n    if p.pkt_payload != nil {\n        return p.pkt_payload.GetLength() + 8\n    }\n\n    return 8\n}\n\nfunc (p *Packet) Equals(other packet.Packet) bool {\n    return packet.Compare(p, other)\n}\n\nfunc (p *Packet) Answers(other packet.Packet) bool {\n    if other == nil || other.GetType() != packet.TCP {\n        return false\n    }\n\n    if p.SrcPort != other.(*Packet).DstPort ||\n       p.DstPort != other.(*Packet).SrcPort {\n        return false\n    }\n\n    return true\n}\n\nfunc (p *Packet) Pack(buf *packet.Buffer) error {\n    buf.WriteN(p.SrcPort)\n    buf.WriteN(p.DstPort)\n    buf.WriteN(p.Length)\n\n    if p.csum_seed != 0 {\n        p.Checksum =\n          ipv4.CalculateChecksum(buf.LayerBytes(), p.csum_seed)\n    }\n\n    buf.WriteN(p.Checksum)\n\n    return nil\n}\n\nfunc (p *Packet) Unpack(buf *packet.Buffer) error {\n    buf.ReadN(&p.SrcPort)\n    buf.ReadN(&p.DstPort)\n    buf.ReadN(&p.Length)\n    buf.ReadN(&p.Checksum)\n\n    return nil\n}\n\nfunc (p *Packet) Payload() packet.Packet {\n    return p.pkt_payload\n}\n\nfunc (p *Packet) GuessPayloadType() packet.Type {\n    return packet.Raw\n}\n\nfunc (p *Packet) SetPayload(pl packet.Packet) error {\n    p.pkt_payload = pl\n    p.Length      = p.GetLength()\n\n    return nil\n}\n\nfunc (p *Packet) InitChecksum(csum uint32) {\n    p.csum_seed = csum\n}\n\nfunc (p *Packet) String() string {\n    return packet.Stringify(p)\n}\n"
  },
  {
    "path": "packet/udp/pkt_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage udp_test\n\nimport \"bytes\"\nimport \"net\"\nimport \"testing\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/ipv4\"\nimport \"github.com/ghedo/go.pkt/packet/udp\"\n\nvar test_simple = []byte{\n    0xcb, 0xa6, 0x00, 0x50, 0x00, 0x12, 0x00, 0x00,\n}\n\nfunc MakeTestSimple() *udp.Packet {\n    return &udp.Packet{\n        SrcPort: 52134,\n        DstPort: 80,\n        Length: 18,\n    }\n}\n\nfunc TestPack(t *testing.T) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    err := p.Pack(&b)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_simple, b.Buffer()) {\n        t.Fatalf(\"Raw packet mismatch: %x\", b.Buffer())\n    }\n}\n\nfunc BenchmarkPack(bn *testing.B) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    for n := 0; n < bn.N; n++ {\n        p.Pack(&b)\n    }\n}\n\nfunc TestUnpack(t *testing.T) {\n    var p udp.Packet\n\n    cmp := MakeTestSimple()\n\n    var b packet.Buffer\n    b.Init(test_simple)\n\n    err := p.Unpack(&b)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if !p.Equals(cmp) {\n        t.Fatalf(\"Packet mismatch:\\n%s\\n%s\", &p, cmp)\n    }\n}\n\nfunc BenchmarkUnpack(bn *testing.B) {\n    var p udp.Packet\n    var b packet.Buffer\n\n    for n := 0; n < bn.N; n++ {\n        b.Init(test_simple)\n        p.Unpack(&b)\n    }\n}\n\nvar test_with_ipv4 = []byte{\n    0xcb, 0xa6, 0x00, 0x50, 0x00, 0x12, 0x61, 0x9e,\n}\n\nvar ipsrc_str = \"192.168.1.135\"\nvar ipdst_str = \"8.8.8.8\"\n\nfunc TestPackWithIPv4(t *testing.T) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_with_ipv4)))\n\n    ip4 := ipv4.Make()\n    ip4.SrcAddr = net.ParseIP(ipsrc_str)\n    ip4.DstAddr = net.ParseIP(ipdst_str)\n\n    udp := &udp.Packet{\n        SrcPort: 52134,\n        DstPort: 80,\n        Length: 18,\n    }\n\n    ip4.SetPayload(udp)\n\n    err := udp.Pack(&b)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_with_ipv4, b.Buffer()) {\n        t.Fatalf(\"Raw packet mismatch: %x\", b.Buffer())\n    }\n}\n\nfunc TestUnpackWithIPv4(t *testing.T) {\n    var p udp.Packet\n\n    cmp := MakeTestSimple()\n    cmp.Checksum = 0x619e\n\n    var b packet.Buffer\n    b.Init(test_with_ipv4)\n\n    err := p.Unpack(&b)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if !p.Equals(cmp) {\n        t.Fatalf(\"Packet mismatch:\\n%s\\n%s\", &p, cmp)\n    }\n}\n"
  },
  {
    "path": "packet/vlan/pkt.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides encoding and decoding for VLAN packets.\npackage vlan\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/eth\"\n\ntype Packet struct {\n    Priority     uint8         `string:\"prio\"`\n    DropEligible bool          `string:\"drop\"`\n    VLAN         uint16\n    Type         eth.EtherType\n    pkt_payload  packet.Packet `cmp:\"skip\" string:\"skip\"`\n}\n\nfunc Make() *Packet {\n    return &Packet{ }\n}\n\nfunc (p *Packet) GetType() packet.Type {\n    return packet.VLAN\n}\n\nfunc (p *Packet) GetLength() uint16 {\n    if p.pkt_payload != nil {\n        return p.pkt_payload.GetLength() + 4\n    }\n\n    return 4\n}\n\nfunc (p *Packet) Equals(other packet.Packet) bool {\n    return packet.Compare(p, other)\n}\n\nfunc (p *Packet) Answers(other packet.Packet) bool {\n    if other == nil {\n        return false\n    }\n\n    if  other.GetType() == packet.VLAN &&\n        p.VLAN != other.(*Packet).VLAN {\n        return false\n    }\n\n    if p.Payload() != nil {\n        return p.Payload().Answers(other.Payload())\n    }\n\n    return true\n}\n\nfunc (p *Packet) Pack(buf *packet.Buffer) error {\n    tci := uint16(p.Priority) << 13 | p.VLAN\n    if p.DropEligible {\n        tci |= 0x10\n    }\n\n    buf.WriteN(tci)\n    buf.WriteN(p.Type)\n\n    return nil\n}\n\nfunc (p *Packet) Unpack(buf *packet.Buffer) error {\n    var tci uint16\n    buf.ReadN(&tci)\n\n    p.Priority     = (uint8(tci >> 8) & 0xE0) >> 5\n    p.DropEligible = uint8(tci) & 0x10 != 0\n    p.VLAN         = tci & 0x0FFF\n\n    buf.ReadN(&p.Type)\n\n    return nil\n}\n\nfunc (p *Packet) Payload() packet.Packet {\n    return p.pkt_payload\n}\n\nfunc (p *Packet) GuessPayloadType() packet.Type {\n    return eth.EtherTypeToType(p.Type)\n}\n\nfunc (p *Packet) SetPayload(pl packet.Packet) error {\n    p.pkt_payload = pl\n    p.Type        = eth.TypeToEtherType(pl.GetType())\n\n    return nil\n}\n\nfunc (p *Packet) InitChecksum(csum uint32) {\n}\n\nfunc (p *Packet) String() string {\n    return packet.Stringify(p)\n}\n"
  },
  {
    "path": "packet/vlan/pkt_test.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage vlan_test\n\nimport \"bytes\"\nimport \"testing\"\n\nimport \"github.com/ghedo/go.pkt/packet\"\nimport \"github.com/ghedo/go.pkt/packet/eth\"\nimport \"github.com/ghedo/go.pkt/packet/vlan\"\n\nvar test_simple = []byte{\n    0x64, 0x00, 0x08, 0x00,\n}\n\nfunc MakeTestSimple() *vlan.Packet {\n    return &vlan.Packet{\n        Priority: 3,\n        VLAN:     1024,\n        Type:     eth.IPv4,\n    }\n}\n\nfunc TestPack(t *testing.T) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    err := p.Pack(&b)\n    if err != nil {\n        t.Fatalf(\"Error packing: %s\", err)\n    }\n\n    if !bytes.Equal(test_simple, b.Buffer()) {\n        t.Fatalf(\"Raw packet mismatch: %x\", b.Buffer())\n    }\n}\n\nfunc BenchmarkPack(bn *testing.B) {\n    var b packet.Buffer\n    b.Init(make([]byte, len(test_simple)))\n\n    p := MakeTestSimple()\n\n    for n := 0; n < bn.N; n++ {\n        p.Pack(&b)\n    }\n}\n\nfunc TestUnpack(t *testing.T) {\n    var p vlan.Packet\n\n    cmp := MakeTestSimple()\n\n    var b packet.Buffer\n    b.Init(test_simple)\n\n    err := p.Unpack(&b)\n    if err != nil {\n        t.Fatalf(\"Error unpacking: %s\", err)\n    }\n\n    if !p.Equals(cmp) {\n        t.Fatalf(\"Packet mismatch:\\n%s\\n%s\", &p, cmp)\n    }\n}\n\nfunc BenchmarkUnpack(bn *testing.B) {\n    var p vlan.Packet\n    var b packet.Buffer\n\n    for n := 0; n < bn.N; n++ {\n        b.Init(test_simple)\n        p.Unpack(&b)\n    }\n}\n"
  },
  {
    "path": "routing/routing.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Provides network routing information about the system. It can either return\n// all available routes or select a specific route depending on a destination\n// address.\npackage routing\n\nimport \"fmt\"\nimport \"net\"\nimport \"sort\"\nimport \"strings\"\n\ntype Route struct {\n    Default bool\n    SrcNet  *net.IPNet\n    DstNet  *net.IPNet\n    Gateway net.IP\n    Iface   *net.Interface\n}\n\ntype route_slice []*Route\n\nfunc (r route_slice) Len() int {\n    return len(r)\n}\n\nfunc (r route_slice) Swap(i, j int) {\n    r[i], r[j] = r[j], r[i]\n}\n\nfunc (r route_slice) Less(i, j int) bool {\n    a := r[i]\n    b := r[j]\n\n    if a.Default {\n        return true\n    }\n\n    if b.Default {\n        return false\n    }\n\n    a_len, _ := a.DstNet.Mask.Size()\n    b_len, _ := b.DstNet.Mask.Size()\n    if a_len < b_len {\n        return false\n    }\n\n    return true\n}\n\n// Return the route that matches the given destination address.\nfunc RouteTo(dst net.IP) (*Route, error) {\n    var def *Route\n\n    routes, err := Routes()\n    if err != nil {\n        return nil, fmt.Errorf(\"Could not get routes: %s\", err)\n    }\n\n    sort.Sort(route_slice(routes))\n\n    for _, r := range routes {\n        if r.Default &&\n           r.Iface != nil &&\n           r.Iface.Flags & net.FlagLoopback == 0 {\n            def = r\n            continue\n        }\n\n        if r.DstNet != nil &&\n           r.DstNet.Contains(dst) {\n            return r, nil\n        }\n    }\n\n    return def, nil\n}\n\n// Return the default IPv4 address of a network interface.\nfunc (r *Route) GetIfaceIPv4Addr() (net.IP, error) {\n    iface := r.Iface\n\n    addrs, err := iface.Addrs();\n    if err != nil {\n        return nil, err\n    }\n\n    for _, a := range addrs {\n        if ipnet, ok := a.(*net.IPNet); ok {\n            if ip4 := ipnet.IP.To4(); ip4 != nil {\n                return ip4, nil\n            }\n        }\n    }\n\n    return nil, fmt.Errorf(\"No address found\")\n}\n\n// Return the default IPv6 address of a network interface.\nfunc (r *Route) GetIfaceIPv6Addr() (net.IP, error) {\n    iface := r.Iface\n\n    addrs, err := iface.Addrs();\n    if err != nil {\n        return nil, err\n    }\n\n    for _, a := range addrs {\n        if ipnet, ok := a.(*net.IPNet); ok {\n            if ip6 := ipnet.IP.To16(); ip6 != nil {\n                return ip6, nil\n            }\n        }\n    }\n\n    return nil, fmt.Errorf(\"No address found\")\n}\n\nfunc (r *Route) String() string {\n    var parts []string\n\n    if r.Default {\n        parts = append(parts, \"default\")\n    } else if r.DstNet != nil {\n        parts = append(parts, r.DstNet.String())\n    }\n\n    if r.SrcNet != nil {\n        src := fmt.Sprintf(\"from %s\", r.DstNet.String())\n        parts = append(parts, src)\n    }\n\n    if r.Gateway != nil {\n        gateway := fmt.Sprintf(\"via %s\", r.Gateway.String())\n        parts = append(parts, gateway)\n    }\n\n    if r.Iface != nil {\n        iface := fmt.Sprintf(\"dev %s\", r.Iface.Name)\n        parts = append(parts, iface)\n    }\n\n    return strings.Join(parts, \" \")\n}\n"
  },
  {
    "path": "routing/routing_linux.go",
    "content": "/*\n * Network packet analysis framework.\n *\n * Copyright (c) 2014, Alessandro Ghedini\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n * IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\npackage routing\n\nimport \"fmt\"\nimport \"net\"\nimport \"syscall\"\nimport \"unsafe\"\n\ntype rtmsg struct {\n\tfamily  uint8\n\tdst_len uint8\n\tsrc_len uint8\n\ttos     uint8\n\ttable   uint8\n\tproto   uint8\n\tscope   uint8\n\trtype   uint8\n\tflags   uint32\n}\n\n// List all available routes on the system.\nfunc Routes() ([]*Route, error) {\n\tvar routes []*Route\n\n\trib, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_UNSPEC)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"Could not retrieve RIB: %s\", err)\n\t}\n\n\tmsgs, err := syscall.ParseNetlinkMessage(rib)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"Could not parse messages: %s\", err)\n\t}\n\n\tfor _, m := range msgs {\n\t\tif m.Header.Type == syscall.NLMSG_DONE {\n\t\t\tbreak\n\t\t}\n\n\t\tif m.Header.Type != syscall.RTM_NEWROUTE {\n\t\t\tcontinue\n\t\t}\n\n\t\troute := &Route{ Default: true }\n\n\t\trtmsg := (*rtmsg)(unsafe.Pointer(&m.Data[0]))\n\n\t\tattrs, err := syscall.ParseNetlinkRouteAttr(&m)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"Could not parse attr: %s\", err)\n\t\t}\n\n\t\tfor _, a := range attrs {\n\t\t\tswitch a.Attr.Type {\n\t\t\tcase syscall.RTA_SRC:\n\t\t\t\troute.SrcNet = &net.IPNet{\n\t\t\t\t\tIP:   net.IP(a.Value),\n\t\t\t\t\tMask: net.CIDRMask(\n\t\t\t\t\t\tint(rtmsg.src_len),\n\t\t\t\t\t\tlen(a.Value) * 8,\n\t\t\t\t\t),\n\t\t\t\t}\n\n\t\t\tcase syscall.RTA_DST:\n\t\t\t\troute.DstNet = &net.IPNet{\n\t\t\t\t\tIP:   net.IP(a.Value),\n\t\t\t\t\tMask: net.CIDRMask(\n\t\t\t\t\t\tint(rtmsg.dst_len),\n\t\t\t\t\t\tlen(a.Value) * 8,\n\t\t\t\t\t),\n\t\t\t\t}\n\n\t\t\t\troute.Default = false\n\n\t\t\tcase syscall.RTA_GATEWAY:\n\t\t\t\troute.Gateway = net.IP(a.Value)\n\n\t\t\tcase syscall.RTA_OIF:\n\t\t\t\toif := *(*uint32)(unsafe.Pointer(&a.Value[0]))\n\t\t\t\tiface, err := net.InterfaceByIndex(int(oif))\n\t\t\t\tif err != nil {\n\t\t\t\t}\n\n\t\t\t\troute.Iface = iface\n\n\t\t\tcase syscall.RTA_PRIORITY:\n\t\t\t}\n\t\t}\n\n\t\troutes = append(routes, route)\n\t}\n\n\treturn routes, nil\n}\n"
  }
]