Skip to content

Commit

Permalink
Enums array conversion.
Browse files Browse the repository at this point in the history
Handle enum decoding and String() with an array of EnumMetadata, so
users can override individual protocol handling.
  • Loading branch information
gconnell committed Dec 30, 2012
1 parent af09ebd commit e30988b
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 125 deletions.
24 changes: 15 additions & 9 deletions gc
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,21 @@ fi
go fmt ./...
gofmt -w gen.go
go build gen.go
go test ./...
pushd pcap
gofmt -w benchmark.go
go build benchmark.go
popd
pushd pfring
gofmt -w simple.go
go build simple.go
popd
go test
if [ -f /usr/include/pcap.h ]; then
pushd pcap
go test
gofmt -w benchmark.go
go build benchmark.go
popd
fi
if [ -f /usr/include/pfring.h ]; then
pushd pfring
go test
gofmt -w simple.go
go build simple.go
popd
fi

# Run our initial commit
git commit "$@"
Expand Down
273 changes: 157 additions & 116 deletions layers/enums.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,28 @@
package layers

import (
"errors"
"fmt"
"github.com/gconnell/gopacket"
)

// EnumMetadata keeps track of a set of metadata for each enumeration value
// for protocol enumerations.
type EnumMetadata struct {
// DecodeWith is the decoder to use to decode this protocol's data.
DecodeWith gopacket.Decoder
// Name is the name of the enumeration value.
Name string
}

// errorFunc returns a decoder that spits out a specific error message.
func errorFunc(msg string) gopacket.Decoder {
var e = errors.New(msg)
return gopacket.DecodeFunc(func([]byte, gopacket.PacketBuilder) error {
return e
})
}

// EthernetType is an enumeration of ethernet type values, and acts as a decoder
// for any type it supports.
type EthernetType uint16
Expand All @@ -29,30 +47,6 @@ const (
EthernetTypeEthernetCTP EthernetType = 0x9000
)

func (e EthernetType) Decode(data []byte, p gopacket.PacketBuilder) error {
switch e {
case EthernetTypeLLC:
return decodeLLC(data, p)
case EthernetTypeIPv4:
return decodeIPv4(data, p)
case EthernetTypeIPv6:
return decodeIPv6(data, p)
case EthernetTypeARP:
return decodeARP(data, p)
case EthernetTypeDot1Q:
return decodeDot1Q(data, p)
case EthernetTypePPPoEDiscovery, EthernetTypePPPoESession:
return decodePPPoE(data, p)
case EthernetTypeEthernetCTP:
return decodeEthernetCTP(data, p)
case EthernetTypeCiscoDiscovery:
return decodeCiscoDiscovery(data, p)
case EthernetTypeMPLSUnicast, EthernetTypeMPLSMulticast:
return decodeMPLS(data, p)
}
return fmt.Errorf("Unsupported ethernet type %v", e)
}

// IPProtocol is an enumeration of IP protocol values, and acts as a decoder
// for any type it supports.
type IPProtocol uint8
Expand All @@ -77,49 +71,9 @@ const (
IPProtocolMPLSInIP IPProtocol = 137
)

func (ip IPProtocol) Decode(data []byte, p gopacket.PacketBuilder) error {
switch ip {
case IPProtocolTCP:
return decodeTCP(data, p)
case IPProtocolUDP:
return decodeUDP(data, p)
case IPProtocolICMP:
return decodeICMP(data, p)
case IPProtocolSCTP:
return decodeSCTP(data, p)
case IPProtocolIPv6:
return decodeIPv6(data, p)
case IPProtocolIPIP:
return decodeIPv4(data, p)
case IPProtocolEtherIP:
return decodeEtherIP(data, p)
case IPProtocolRUDP:
return decodeRUDP(data, p)
case IPProtocolGRE:
return decodeGRE(data, p)
case IPProtocolIPv6HopByHop:
return decodeIPv6HopByHop(data, p)
case IPProtocolIPv6Routing:
return decodeIPv6Routing(data, p)
case IPProtocolIPv6Fragment:
return decodeIPv6Fragment(data, p)
case IPProtocolAH:
return decodeIPSecAH(data, p)
case IPProtocolESP:
return decodeIPSecESP(data, p)
case IPProtocolUDPLite:
return decodeUDPLite(data, p)
case IPProtocolMPLSInIP:
return decodeMPLS(data, p)
case IPProtocolNoNextHeader:
return fmt.Errorf("NoNextHeader found with %d bytes remaining to decode", len(data))
}
return fmt.Errorf("Unsupported IP protocol %v", ip)
}

// LinkType is an enumeration of link types, and acts as a decoder for any
// link type it supports.
type LinkType int
type LinkType uint8

const (
// According to pcap-linktype(7).
Expand Down Expand Up @@ -150,18 +104,8 @@ const (
LinkTypeLinuxLAPD LinkType = 177
)

func (l LinkType) Decode(data []byte, p gopacket.PacketBuilder) error {
switch l {
case LinkTypeEthernet:
return decodeEthernet(data, p)
case LinkTypePPP:
return decodePPP(data, p)
}
return fmt.Errorf("Unsupported link-layer type %v", l)
}

// PPPoECode is the PPPoE code enum, taken from http://tools.ietf.org/html/rfc2516
type PPPoECode int
type PPPoECode uint8

const (
PPPoECodePADI PPPoECode = 0x09
Expand All @@ -172,15 +116,6 @@ const (
PPPoECodeSession PPPoECode = 0x00
)

// Decode decodes a PPPoE payload, based on the PPPoECode.
func (pc PPPoECode) Decode(data []byte, p gopacket.PacketBuilder) error {
switch pc {
case PPPoECodeSession:
return decodePPP(data, p)
}
return fmt.Errorf("Cannot currently handle PPPoE error code %v", pc)
}

// PPPType is an enumeration of PPP type values, and acts as a decoder for any
// type it supports.
type PPPType uint16
Expand All @@ -190,16 +125,6 @@ const (
PPPTypeIPv6 PPPType = 0x0057
)

func (pt PPPType) Decode(data []byte, p gopacket.PacketBuilder) error {
switch pt {
case PPPTypeIPv4:
return decodeIPv4(data, p)
case PPPTypeIPv6:
return decodeIPv6(data, p)
}
return fmt.Errorf("Unsupported PPP type %v", pt)
}

// SCTPChunkType is an enumeration of chunk types inside SCTP packets.
type SCTPChunkType uint8

Expand All @@ -219,26 +144,142 @@ const (
SCTPChunkTypeShutdownComplete SCTPChunkType = 14
)

func (s SCTPChunkType) Decode(data []byte, p gopacket.PacketBuilder) error {
switch s {
case SCTPChunkTypeData:
return decodeSCTPData(data, p)
case SCTPChunkTypeInit, SCTPChunkTypeInitAck:
return decodeSCTPInit(data, p)
case SCTPChunkTypeSack:
return decodeSCTPSack(data, p)
case SCTPChunkTypeHeartbeat, SCTPChunkTypeHeartbeatAck:
return decodeSCTPHeartbeat(data, p)
case SCTPChunkTypeAbort, SCTPChunkTypeError:
return decodeSCTPError(data, p)
case SCTPChunkTypeShutdown:
return decodeSCTPShutdown(data, p)
case SCTPChunkTypeShutdownAck:
return decodeSCTPShutdownAck(data, p)
case SCTPChunkTypeCookieEcho:
return decodeSCTPCookieEcho(data, p)
case SCTPChunkTypeCookieAck, SCTPChunkTypeShutdownComplete:
return decodeSCTPEmptyLayer(data, p)
var (
// Each of the following arrays contains mappings of how to handle enum
// values for various enum types in gopacket/layers.
//
// So, EthernetTypeMetadata[2] contains information on how to handle EthernetType
// 2, including which name to give it and which decoder to use to decode
// packet data of that type. These arrays are filled by default with all of the
// protocols gopacket/layers knows how to handle, but users of the library can
// add new decoders or override existing ones. For example, if you write a better
// TCP decoder, you can override IPProtocolMetadata[IPProtocolTCP].DecodeWith
// with your new decoder, and all gopacket/layers decoding will use your new
// decoder whenever they encounter that IPProtocol.
EthernetTypeMetadata [65536]EnumMetadata
IPProtocolMetadata [265]EnumMetadata
SCTPChunkTypeMetadata [265]EnumMetadata
PPPTypeMetadata [65536]EnumMetadata
PPPoECodeMetadata [256]EnumMetadata
LinkTypeMetadata [256]EnumMetadata
)

func (a EthernetType) Decode(data []byte, p gopacket.PacketBuilder) error {
return EthernetTypeMetadata[a].DecodeWith.Decode(data, p)
}
func (a EthernetType) String() string {
return EthernetTypeMetadata[a].Name
}
func (a IPProtocol) Decode(data []byte, p gopacket.PacketBuilder) error {
return IPProtocolMetadata[a].DecodeWith.Decode(data, p)
}
func (a IPProtocol) String() string {
return IPProtocolMetadata[a].Name
}
func (a SCTPChunkType) Decode(data []byte, p gopacket.PacketBuilder) error {
return SCTPChunkTypeMetadata[a].DecodeWith.Decode(data, p)
}
func (a SCTPChunkType) String() string {
return SCTPChunkTypeMetadata[a].Name
}
func (a PPPType) Decode(data []byte, p gopacket.PacketBuilder) error {
return PPPTypeMetadata[a].DecodeWith.Decode(data, p)
}
func (a PPPType) String() string {
return PPPTypeMetadata[a].Name
}
func (a LinkType) Decode(data []byte, p gopacket.PacketBuilder) error {
return LinkTypeMetadata[a].DecodeWith.Decode(data, p)
}
func (a LinkType) String() string {
return LinkTypeMetadata[a].Name
}
func (a PPPoECode) Decode(data []byte, p gopacket.PacketBuilder) error {
return PPPoECodeMetadata[a].DecodeWith.Decode(data, p)
}
func (a PPPoECode) String() string {
return PPPoECodeMetadata[a].Name
}

func init() {
for i := 0; i < 65536; i++ {
EthernetTypeMetadata[i] = EnumMetadata{
DecodeWith: errorFunc(fmt.Sprintf("Unable to decode ethernet type %d", i)),
Name: fmt.Sprintf("UnknownEthernetType(%d)", i),
}
PPPTypeMetadata[i] = EnumMetadata{
DecodeWith: errorFunc(fmt.Sprintf("Unable to decode PPP type %d", i)),
Name: fmt.Sprintf("UnknownPPPType(%d)", i),
}
}
return fmt.Errorf("Unable to decode SCTP chunk type %v", s)
for i := 0; i < 256; i++ {
IPProtocolMetadata[i] = EnumMetadata{
DecodeWith: errorFunc(fmt.Sprintf("Unable to decode IP protocol %d", i)),
Name: fmt.Sprintf("UnknownIPProtocol(%d)", i),
}
SCTPChunkTypeMetadata[i] = EnumMetadata{
DecodeWith: errorFunc(fmt.Sprintf("Unable to decode SCTP chunk type %d", i)),
Name: fmt.Sprintf("UnknownSCTPChunkType(%d)", i),
}
PPPoECodeMetadata[i] = EnumMetadata{
DecodeWith: errorFunc(fmt.Sprintf("Unable to decode PPPoE code %d", i)),
Name: fmt.Sprintf("UnknownPPPoECode(%d)", i),
}
LinkTypeMetadata[i] = EnumMetadata{
DecodeWith: errorFunc(fmt.Sprintf("Unable to decode link type %d", i)),
Name: fmt.Sprintf("UnknownLinkType(%d)", i),
}
}

EthernetTypeMetadata[EthernetTypeLLC] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeLLC), Name: "LLC"}
EthernetTypeMetadata[EthernetTypeIPv4] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4), Name: "IPv4"}
EthernetTypeMetadata[EthernetTypeIPv6] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6), Name: "IPv6"}
EthernetTypeMetadata[EthernetTypeARP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeARP), Name: "ARP"}
EthernetTypeMetadata[EthernetTypeDot1Q] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot1Q), Name: "Dot1Q"}
EthernetTypeMetadata[EthernetTypePPPoEDiscovery] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodePPPoE), Name: "PPPoEDiscovery"}
EthernetTypeMetadata[EthernetTypePPPoESession] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodePPPoE), Name: "PPPoESession"}
EthernetTypeMetadata[EthernetTypeEthernetCTP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeEthernetCTP), Name: "EthernetCTP"}
EthernetTypeMetadata[EthernetTypeCiscoDiscovery] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeCiscoDiscovery), Name: "CiscoDiscovery"}
EthernetTypeMetadata[EthernetTypeMPLSUnicast] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeMPLS), Name: "MPLSUnicast"}
EthernetTypeMetadata[EthernetTypeMPLSMulticast] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeMPLS), Name: "MPLSMulticast"}

IPProtocolMetadata[IPProtocolTCP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeTCP), Name: "TCP"}
IPProtocolMetadata[IPProtocolUDP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeUDP), Name: "UDP"}
IPProtocolMetadata[IPProtocolICMP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeICMP), Name: "ICMP"}
IPProtocolMetadata[IPProtocolSCTP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTP), Name: "SCTP"}
IPProtocolMetadata[IPProtocolIPv6] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6), Name: "IPv6"}
IPProtocolMetadata[IPProtocolIPIP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4), Name: "IPv4"}
IPProtocolMetadata[IPProtocolEtherIP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeEtherIP), Name: "EtherIP"}
IPProtocolMetadata[IPProtocolRUDP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeRUDP), Name: "RUDP"}
IPProtocolMetadata[IPProtocolGRE] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeGRE), Name: "GRE"}
IPProtocolMetadata[IPProtocolIPv6HopByHop] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6HopByHop), Name: "IPv6HopByHop"}
IPProtocolMetadata[IPProtocolIPv6Routing] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6Routing), Name: "IPv6Routing"}
IPProtocolMetadata[IPProtocolIPv6Fragment] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6Fragment), Name: "IPv6Fragment"}
IPProtocolMetadata[IPProtocolAH] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPSecAH), Name: "IPSecAH"}
IPProtocolMetadata[IPProtocolESP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPSecESP), Name: "IPSecESP"}
IPProtocolMetadata[IPProtocolUDPLite] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeUDPLite), Name: "UDPLite"}
IPProtocolMetadata[IPProtocolMPLSInIP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeMPLS), Name: "MPLS"}
IPProtocolMetadata[IPProtocolNoNextHeader] = EnumMetadata{DecodeWith: errorFunc("NoNextHeader with non-zero byte payload"), Name: "NoNextHeader"}

SCTPChunkTypeMetadata[SCTPChunkTypeData] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPData), Name: "Data"}
SCTPChunkTypeMetadata[SCTPChunkTypeInit] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPInit), Name: "Init"}
SCTPChunkTypeMetadata[SCTPChunkTypeInitAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPInit), Name: "InitAck"}
SCTPChunkTypeMetadata[SCTPChunkTypeSack] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPSack), Name: "Sack"}
SCTPChunkTypeMetadata[SCTPChunkTypeHeartbeat] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPHeartbeat), Name: "Heartbeat"}
SCTPChunkTypeMetadata[SCTPChunkTypeHeartbeatAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPHeartbeat), Name: "HeartbeatAck"}
SCTPChunkTypeMetadata[SCTPChunkTypeAbort] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPError), Name: "Abort"}
SCTPChunkTypeMetadata[SCTPChunkTypeError] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPError), Name: "Error"}
SCTPChunkTypeMetadata[SCTPChunkTypeShutdown] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPShutdown), Name: "Shutdown"}
SCTPChunkTypeMetadata[SCTPChunkTypeShutdownAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPShutdownAck), Name: "ShutdownAck"}
SCTPChunkTypeMetadata[SCTPChunkTypeCookieEcho] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPCookieEcho), Name: "CookieEcho"}
SCTPChunkTypeMetadata[SCTPChunkTypeCookieAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPEmptyLayer), Name: "CookieAck"}
SCTPChunkTypeMetadata[SCTPChunkTypeShutdownComplete] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPEmptyLayer), Name: "ShutdownComplete"}

PPPTypeMetadata[PPPTypeIPv4] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4), Name: "IPv4"}
PPPTypeMetadata[PPPTypeIPv6] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6), Name: "IPv6"}

PPPoECodeMetadata[PPPoECodeSession] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodePPP), Name: "PPP"}

LinkTypeMetadata[LinkTypeEthernet] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeEthernet), Name: "Ethernet"}
LinkTypeMetadata[LinkTypePPP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodePPP), Name: "PPP"}
}

0 comments on commit e30988b

Please sign in to comment.