Skip to content

Commit

Permalink
Lots more readability courtesy of nigeltao.
Browse files Browse the repository at this point in the history
  • Loading branch information
gconnell committed Dec 5, 2012
1 parent 46ac4b0 commit 7510004
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 138 deletions.
2 changes: 2 additions & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ AUTHORS AND MAINTAINERS:
MAIN DEVELOPERS:
Graeme Connell <gconnell@google.com, gsconnell@gmail.com>

CONTRIBUTORS:
Nigel Tao <nigeltao@google.com>

-----------------------------------------------
FORKED FROM github.com/akrennmair/gopcap
Expand Down
6 changes: 3 additions & 3 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,18 @@ type DecodeFailure struct {
err error
}

// Returns the entire payload which failed to be decoded.
// Payload returns the entire payload which failed to be decoded.
func (d *DecodeFailure) Payload() []byte { return d.data }

// Returns the error encountered during decoding.
// Error eturns the error encountered during decoding.
func (d *DecodeFailure) Error() error { return d.err }

// LayerType returns LayerTypeDecodeFailure
func (d *DecodeFailure) LayerType() LayerType { return LayerTypeDecodeFailure }

// decodeUnknown "decodes" unsupported data types by returning an error.
// This decoder will thus always return a DecodeFailure layer.
var decodeUnknown decoderFunc = func(data []byte) (out DecodeResult, err error) {
func decodeUnknown(data []byte) (out DecodeResult, err error) {
err = errors.New("Link type not currently supported")
return
}
Expand Down
65 changes: 34 additions & 31 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func TestFlowMapKey(t *testing.T) {
_ = map[Flow]bool{}
_ = map[Endpoint]bool{}
_ = map[[2]Flow]bool{}
if NewEndpointFromUDPPort(53) != NewEndpointFromUDPPort(53) {
if NewUDPPortEndpoint(53) != NewUDPPortEndpoint(53) {
t.Error("Endpoint equality seems to be broken")
}
}
Expand Down Expand Up @@ -276,36 +276,39 @@ func generateRandomSlice() (b []byte) {
return b
}

// securityTestRandomInput creates new packets with a decoder by feeding it
// random input. We're looking for actual program crashes caused by this
// parsing... proper error detection (ErrorLayer() being set) is fine/expected.
func securityTestRandomInput(d Decoder, t *testing.T) {
for i := 0; i < 1000; i++ {
NewPacket(generateRandomSlice(), d, Default)
}
}

func TestDecoderSecurity(t *testing.T) {
seed := time.Now().UnixNano()
fmt.Println("If you see a crash here, it's serious business. Report it!")
fmt.Println("Send this number with any crash reports:", seed)
rand.Seed(seed)
t.Log("ARP")
securityTestRandomInput(decoderFunc(decodeARP), t)
t.Log("Dot1Q")
securityTestRandomInput(decoderFunc(decodeDot1Q), t)
t.Log("Ethernet")
securityTestRandomInput(decoderFunc(decodeEthernet), t)
t.Log("ICMP")
securityTestRandomInput(decoderFunc(decodeICMP), t)
t.Log("IPv4")
securityTestRandomInput(decoderFunc(decodeIPv4), t)
t.Log("IPv6")
securityTestRandomInput(decoderFunc(decodeIPv6), t)
t.Log("PPP")
securityTestRandomInput(decoderFunc(decodePPP), t)
t.Log("TCP")
securityTestRandomInput(decoderFunc(decodeTCP), t)
t.Log("UDP")
securityTestRandomInput(decoderFunc(decodeUDP), t)
fmt.Printf("If you see a crash here, it's serious business. Report it!\n"+
"Send this number with any crash reports: %v\n", seed)
r := rand.New(rand.NewSource(seed))

testCases := []struct {
s string
d decoderFunc
}{
{"ARP", decodeARP},
{"Dot1Q", decodeDot1Q},
{"Ethernet", decodeEthernet},
{"ICMP", decodeICMP},
{"IPv4", decodeIPv4},
{"IPv6", decodeIPv6},
{"PPP", decodePPP},
{"TCP", decodeTCP},
{"UDP", decodeUDP},
}
for _, tc := range testCases {
// Fuzz-test the decoder tc.d by feeding it random inputs.
// We're fine with errors occurring here... what we're looking
// for is actual program crashes, which Shouldn't Happen (tm) due
// to golang slice range checking... but we're paranoid.
t.Logf("Testing %s", tc.s)
for i := 0; i < 1000; i++ {
b := make([]byte, 0, 256)
for r.Int()%100 != 0 {
b = append(b, byte(r.Int()))
}
NewPacket(b, tc.d, Default)
}
}
fmt.Println("No crash to see here... continuing with testing")
}
19 changes: 9 additions & 10 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@
// doSomethingWithPacket(p)
// }
//
// The fastest method of decoding is to use both Lazy and NoCopy. These flags
// are both bits, so you can pass (gopacket.Lazy | gopacket.NoCopy) in as the
// decode method to achieve the fastest creation of packets.
// The fastest method of decoding is to use both Lazy and NoCopy, but note from
// the many caveats above that for some implementations they may be dangerous
// either or both may be dangerous.
//
// Pointers To Known Layers
//
Expand Down Expand Up @@ -151,8 +151,9 @@
// src, dst := netFlow.Endpoints()
// reverseFlow := gopacket.NewFlow(dst, src)
//
// Both Endpoint and Flow objects can be used as map keys, and the euqality operator can
// compare them, so you can easily group together all packets based on endpoint criteria:
// Both Endpoint and Flow objects can be used as map keys, and the equality
// operator can compare them, so you can easily group together all packets
// based on endpoint criteria:
//
// flows := map[gopacket.Endpoint]chan gopacket.Packet
// packet := gopacket.NewPacket(myPacketData, gopacket.LinkTypeEthernet, gopacket.Lazy)
Expand All @@ -168,11 +169,9 @@
// }
// }
// // Find all packets coming from UDP port 1000 to UDP port 500
// interestingFlow := gopacket.ewFlow(gopacket.ewEndpointFromUDPPort(1000), gopacket.ewEndpointFromUDPPort(500))
// if udp := packet.Layer(gopacket.LayerTypeUDP); udp != nil {
// if udp.TransportFlow() == interestingFlow {
// fmt.Println("Found that flow I was looking for!")
// }
// interestingFlow := gopacket.NewFlow(gopacket.NewUDPPortEndpoint(1000), gopacket.NewUDPPortEndpoint(500))
// if t := packet.NetworkLayer(); t != nil && t.TransportFlow() == interestingFlow {
// fmt.Println("Found that UDP flow I was looking for!")
// }
//
// Implementing Your Own Decoder
Expand Down
35 changes: 16 additions & 19 deletions flows.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// Copyright (c) 2012 Google, Inc. All rights reserved.
// Copyright (c) 2009-2012 Andreas Krennmair. All rights reserved.

package gopacket

Expand All @@ -21,28 +20,26 @@ type Endpoint struct {
// LayerType returns the layer type associated with this endpoint.
func (e Endpoint) LayerType() LayerType { return e.typ }

// Raw returns the raw bytes of this endpoint. These aren't human-readable most of the time, but they are fast.
// Raw returns the raw bytes of this endpoint. These aren't human-readable most of the time, but they are faster than calling String.
func (e Endpoint) Raw() []byte { return []byte(e.raw) }

// String returns the endpoint as a human-readable string.
func (a Endpoint) String() string {
switch a.typ {
case LayerTypeIPv4:
fallthrough
case LayerTypeIPv6:
case LayerTypeIPv4, LayerTypeIPv6:
return net.IP([]byte(a.raw)).String()
case LayerTypeEthernet:
return net.HardwareAddr([]byte(a.raw)).String()
case LayerTypeTCP:
case LayerTypeTCP, LayerTypeUDP:
return strconv.Itoa(int(binary.BigEndian.Uint16([]byte(a.raw))))
case LayerTypePPP:
return "point"
}
return "endpoint"
}

// NewEndpointFromIP creates a new IPv4 or IPv6 endpoint from a net.IP address.
func NewEndpointFromIP(a net.IP) (_ Endpoint, err error) {
// NewIPEndpoint creates a new IPv4 or IPv6 endpoint from a net.IP address.
func NewIPEndpoint(a net.IP) (_ Endpoint, err error) {
if len(a) == 4 {
return Endpoint{LayerTypeIPv4, string(a)}, nil
} else if len(a) == 16 {
Expand All @@ -52,28 +49,28 @@ func NewEndpointFromIP(a net.IP) (_ Endpoint, err error) {
return
}

// NewEndpointFromHardwareAddr creates a new Ethernet endpoint from a net.HardwareAddr address.
func NewEndpointFromHardwareAddr(a net.HardwareAddr) (_ Endpoint, err error) {
// NewMACEndpoint creates a new Ethernet endpoint from a net.HardwareAddr address.
func NewMACEndpoint(a net.HardwareAddr) (_ Endpoint, err error) {
if len(a) == 6 {
return Endpoint{LayerTypeEthernet, string(a)}, nil
}
err = fmt.Errorf("Invalid MAC byte string has size %d", len(a))
return
}

// NewEndpointFromTCPPort creates a new TCP endpoint.
func NewEndpointFromTCPPort(a uint16) Endpoint {
return Endpoint{LayerTypeTCP, string([]byte{byte(a >> 8), byte(a & 0xff)})}
// NewTCPPortEndpoint creates a new TCP endpoint.
func NewTCPPortEndpoint(a uint16) Endpoint {
return Endpoint{LayerTypeTCP, string([]byte{byte(a >> 8), byte(a)})}
}

// NewEndpointFromTCPPort creates a new UDP endpoint.
func NewEndpointFromUDPPort(a uint16) Endpoint {
return Endpoint{LayerTypeUDP, string([]byte{byte(a >> 8), byte(a & 0xff)})}
// NewUDPPortEndpoint creates a new UDP endpoint.
func NewUDPPortEndpoint(a uint16) Endpoint {
return Endpoint{LayerTypeUDP, string([]byte{byte(a >> 8), byte(a)})}
}

// PPPEndpoint is an "endpoint" for PPP flows. Since PPP is "point to point", we have a single endpoint "point"
// that we use in all cases for PPP.
var PPPEndpoint Endpoint = Endpoint{typ: LayerTypePPP}
var PPPEndpoint = Endpoint{typ: LayerTypePPP}

// Flow represents the direction of traffic for a packet layer, as a source and destination Endpoint.
// Flows are usable as map keys.
Expand Down Expand Up @@ -103,7 +100,7 @@ func (f Flow) LayerType() LayerType {
return f.typ
}

// Endpoints returns the two Endpoint objects for this flow.
// Endpoints returns the two Endpoints for this flow.
func (f Flow) Endpoints() (src, dst Endpoint) {
return Endpoint{f.typ, f.src}, Endpoint{f.typ, f.dst}
}
Expand All @@ -121,4 +118,4 @@ func (f Flow) Dst() (dst Endpoint) {
}

// PPPFlow is a "flow" for PPP. Since PPP is "point to point", we have a single constant flow "point"->"point".
var PPPFlow Flow = Flow{typ: LayerTypePPP}
var PPPFlow = Flow{typ: LayerTypePPP}
70 changes: 70 additions & 0 deletions gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) 2012 Google, Inc. All rights reserved.

// +build ignore

// Package gopacket_mac_fetcher is a binary that pulls the list of known MAC
// prefixes from IEEE and writes them out to a go file which is compiled
// into gopacket. It should be run as follows:
//
// go run gen.go | gofmt > valid_mac_prefixes.go
package main

import (
"bufio"
"encoding/hex"
"flag"
"io"
"fmt"
"net/http"
"os"
"regexp"
"time"
)

const header = `// Copyright (c) 2012 Google, Inc. All rights reserved.
package gopacket
// Created by gopacket_mac_fetcher, don't edit manually
// Generated at %s
// Fetched from %q
// ValidMACPrefixMap maps a valid MAC address prefix to the name of the
// organization that owns the rights to use it. We map it to a hidden
// variable so it won't show up in godoc, since it's a very large map.
var ValidMACPrefixMap = validMACPrefixMap
var validMACPrefixMap = map[[3]byte]string{
`

var url = flag.String("url", "http://standards.ieee.org/develop/regauth/oui/oui.txt", "URL to fetch MACs from")

func main() {
fmt.Fprintf(os.Stderr, "Fetching MACs from %q\n", *url)
resp, err := http.Get(*url)
if err != nil {
panic(err)
}
defer resp.Body.Close()
buffered := bufio.NewReader(resp.Body)
finder := regexp.MustCompile(`^([0-9A-F]{6})\s+\(base 16\)\s+(.*)`)
fmt.Fprintln(os.Stderr, "Starting write to standard output")
fmt.Printf(header, time.Now(), *url);
for {
line, err := buffered.ReadString('\n')
if err == io.EOF {
break
} else if err != nil {
panic(err)
}
if matches := finder.FindStringSubmatch(line); matches != nil {
bytes := make([]byte, 3)
hex.Decode(bytes, []byte(matches[1]))
company := matches[2]
if company == "" {
company = "PRIVATE"
}
fmt.Printf("\t[3]byte{%d, %d, %d}: %q,\n", bytes[0], bytes[1], bytes[2], company)
}
}
fmt.Println("}")
}
74 changes: 0 additions & 74 deletions gopacket_mac_fetcher/mac_fetcher.go

This file was deleted.

2 changes: 1 addition & 1 deletion packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

// Packet is the primary object used by gopacket. Packets are created by a
// Decoder's Decode call. A packet is made up of a set of Data(), which
// Decoder's Decode call. A packet is made up of a set of Data, which
// is broken into a number of Layers as it is decoded.
type Packet interface {
// Data returns all data associated with this packet
Expand Down

0 comments on commit 7510004

Please sign in to comment.