// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package gopacket
import (
"fmt"
)
// Layer represents a single decoded packet layer (using either the
// OSI or TCP/IP definition of a layer). When decoding, a packet's data is
// broken up into a number of layers. The caller may call LayerType() to
// figure out which type of layer they've received from the packet. Optionally,
// they may then use a type assertion to get the actual layer type for deep
// inspection of the data.
type Layer interface {
// LayerType is the gopacket type for this layer.
LayerType() LayerType
// LayerContents returns the set of bytes that make up this layer.
LayerContents() []byte
// LayerPayload returns the set of bytes contained within this layer, not
// including the layer itself.
LayerPayload() []byte
}
// Payload is a Layer containing the payload of a packet. The definition of
// what constitutes the payload of a packet depends on previous layers; for
// TCP and UDP, we stop decoding above layer 4 and return the remaining
// bytes as a Payload. Payload is an ApplicationLayer.
type Payload []byte
// LayerType returns LayerTypePayload
func (p Payload) LayerType() LayerType { return LayerTypePayload }
// LayerContents returns the bytes making up this layer.
func (p Payload) LayerContents() []byte { return []byte(p) }
// LayerPayload returns the payload within this layer.
func (p Payload) LayerPayload() []byte { return nil }
// Payload returns this layer as bytes.
func (p Payload) Payload() []byte { return []byte(p) }
// String implements fmt.Stringer.
func (p Payload) String() string { return fmt.Sprintf("%d byte(s)", len(p)) }
// GoString implements fmt.GoStringer.
func (p Payload) GoString() string { return LongBytesGoString([]byte(p)) }
// CanDecode implements DecodingLayer.
func (p Payload) CanDecode() LayerClass { return LayerTypePayload }
// NextLayerType implements DecodingLayer.
func (p Payload) NextLayerType() LayerType { return LayerTypeZero }
// DecodeFromBytes implements DecodingLayer.
func (p *Payload) DecodeFromBytes(data []byte, df DecodeFeedback) error {
*p = Payload(data)
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (p Payload) SerializeTo(b SerializeBuffer, opts SerializeOptions) error {
bytes, err := b.PrependBytes(len(p))
if err != nil {
return err
}
copy(bytes, p)
return nil
}
// decodePayload decodes data by returning it all in a Payload layer.
func decodePayload(data []byte, p PacketBuilder) error {
payload := &Payload{}
if err := payload.DecodeFromBytes(data, p); err != nil {
return err
}
p.AddLayer(payload)
p.SetApplicationLayer(payload)
return nil
}
// Fragment is a Layer containing a fragment of a larger frame, used by layers
// like IPv4 and IPv6 that allow for fragmentation of their payloads.
type Fragment []byte
// LayerType returns LayerTypeFragment
func (p *Fragment) LayerType() LayerType { return LayerTypeFragment }
// LayerContents implements Layer.
func (p *Fragment) LayerContents() []byte { return []byte(*p) }
// LayerPayload implements Layer.
func (p *Fragment) LayerPayload() []byte { return nil }
// Payload returns this layer as a byte slice.
func (p *Fragment) Payload() []byte { return []byte(*p) }
// String implements fmt.Stringer.
func (p *Fragment) String() string { return fmt.Sprintf("%d byte(s)", len(*p)) }
// CanDecode implements DecodingLayer.
func (p *Fragment) CanDecode() LayerClass { return LayerTypeFragment }
// NextLayerType implements DecodingLayer.
func (p *Fragment) NextLayerType() LayerType { return LayerTypeZero }
// DecodeFromBytes implements DecodingLayer.
func (p *Fragment) DecodeFromBytes(data []byte, df DecodeFeedback) error {
*p = Fragment(data)
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (p *Fragment) SerializeTo(b SerializeBuffer, opts SerializeOptions) error {
bytes, err := b.PrependBytes(len(*p))
if err != nil {
return err
}
copy(bytes, *p)
return nil
}
// decodeFragment decodes data by returning it all in a Fragment layer.
func decodeFragment(data []byte, p PacketBuilder) error {
payload := &Fragment{}
if err := payload.DecodeFromBytes(data, p); err != nil {
return err
}
p.AddLayer(payload)
p.SetApplicationLayer(payload)
return nil
}
// These layers correspond to Internet Protocol Suite (TCP/IP) layers, and their
// corresponding OSI layers, as best as possible.
// LinkLayer is the packet layer corresponding to TCP/IP layer 1 (OSI layer 2)
type LinkLayer interface {
Layer
LinkFlow() Flow
}
// NetworkLayer is the packet layer corresponding to TCP/IP layer 2 (OSI
// layer 3)
type NetworkLayer interface {
Layer
NetworkFlow() Flow
}
// TransportLayer is the packet layer corresponding to the TCP/IP layer 3 (OSI
// layer 4)
type TransportLayer interface {
Layer
TransportFlow() Flow
}
// ApplicationLayer is the packet layer corresponding to the TCP/IP layer 4 (OSI
// layer 7), also known as the packet payload.
type ApplicationLayer interface {
Layer
Payload() []byte
}
// ErrorLayer is a packet layer created when decoding of the packet has failed.
// Its payload is all the bytes that we were unable to decode, and the returned
// error details why the decoding failed.
type ErrorLayer interface {
Layer
Error() error
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
// Package bytediff provides a simple diff utility for looking at differences in byte
// slices. It's slow, clunky, and not particularly good by any measure, but
// it does provide very useful visualizations for diffs between small byte
// slices.
//
// Our diff algorithm uses a dynamic programming implementation of longest common
// substring to find matching parts of slices, then recursively calls itself on
// the prefix/suffix of that matching part for each packet. This is a Bad Idea
// (tm) for normal (especially large) input, but for packets where large portions
// repeat frequently and we expect minor changes between results, it's actually
// quite useful.
package bytediff
import (
"bytes"
"fmt"
)
// OutputFormat tells a Differences.String call how to format the set of
// differences into a human-readable string. Its internals are currently
// unexported because we may want to change them drastically in the future. For
// the moment, please just use one of the provided OutputFormats that comes with
// this library.
type OutputFormat struct {
start, finish, add, remove, change, reset string
}
var (
// BashOutput uses bash escape sequences to color output.
BashOutput = &OutputFormat{
reset: "\033[0m",
remove: "\033[32m",
add: "\033[31m",
change: "\033[33m",
}
// HTMLOutput uses a <pre> to wrap output, and <span>s to color it.
// HTMLOutput is pretty experimental, so use at your own risk ;)
HTMLOutput = &OutputFormat{
start: "<pre>",
finish: "</pre>",
reset: "</span>",
remove: "<span style='color:red'>",
add: "<span style='color:green'>",
change: "<span style='color:yellow'>",
}
)
// longestCommonSubstring uses a O(MN) dynamic programming approach to find the
// longest common substring in a set of slices. It returns the index in each
// slice at which the substring begins, plus the length of the commonality.
func longestCommonSubstring(strA, strB []byte) (indexA, indexB, length int) {
lenA, lenB := len(strA), len(strB)
if lenA == 0 || lenB == 0 {
return 0, 0, 0
}
arr := make([][]int, lenA)
for i := 0; i < lenA; i++ {
arr[i] = make([]int, lenB)
}
var maxLength int
var maxA, maxB int
for a := 0; a < lenA; a++ {
for b := 0; b < lenB; b++ {
if strA[a] == strB[b] {
length := 1
if a > 0 && b > 0 {
length = arr[a-1][b-1] + 1
}
arr[a][b] = length
if length > maxLength {
maxLength = length
maxA = a
maxB = b
}
}
}
}
a, b := maxA, maxB
for a >= 0 && b >= 0 && strA[a] == strB[b] {
indexA = a
indexB = b
a--
b--
length++
}
return
}
// Difference represents a single part of the data being diffed, containing
// information about both the original and new values.
// From and To are the sets of bytes in the original and the new byte slice.
// !Replace implies From == To (no change)
// len(To) == 0 implies From is being deleted
// len(From) == 0 implies To is being inserted
// else implies From is being replaced by To
type Difference struct {
Replace bool
From, To []byte
}
// color returns the bash color for a given difference.
func (c *OutputFormat) color(d Difference) string {
switch {
case !d.Replace:
return ""
case len(d.From) == 0:
return c.remove
case len(d.To) == 0:
return c.add
default:
return c.change
}
}
// Diff diffs strA and strB, returning a list of differences which
// can be used to construct either the original or new string.
//
// Diff is optimized for comparing VERY SHORT slices. It's meant for comparing
// things like packets off the wire, not large files or the like.
// As such, its runtime can be catastrophic if large inputs are passed in.
// You've been warned.
func Diff(strA, strB []byte) Differences {
if len(strA) == 0 && len(strB) == 0 {
return nil
}
ia, ib, l := longestCommonSubstring(strA, strB)
if l == 0 {
return Differences{
Difference{true, strA, strB},
}
}
beforeA, match, afterA := strA[:ia], strA[ia:ia+l], strA[ia+l:]
beforeB, afterB := strB[:ib], strB[ib+l:]
var diffs Differences
diffs = append(diffs, Diff(beforeA, beforeB)...)
diffs = append(diffs, Difference{false, match, match})
diffs = append(diffs, Diff(afterA, afterB)...)
return diffs
}
// Differences is a set of differences for a given diff'd pair of byte slices.
type Differences []Difference
// String outputs a previously diff'd set of strings, showing differences
// between them, highlighted by colors.
//
// The output format of this function is NOT guaranteed consistent, and may be
// changed at any time by the library authors. It's meant solely for human
// consumption.
func (c *OutputFormat) String(diffs Differences) string {
var buf bytes.Buffer
count := 0
fmt.Fprintf(&buf, "%s", c.start)
fmt.Fprintf(&buf, "00000000 ")
for i := 0; i < len(diffs); i++ {
diff := diffs[i]
color := c.color(diff)
reset := ""
if color != "" {
reset = c.reset
}
fmt.Fprint(&buf, color)
for _, b := range diff.From {
fmt.Fprintf(&buf, " %02x", b)
count++
switch count % 16 {
case 0:
fmt.Fprintf(&buf, "%v\n%08x%v ", reset, count, color)
case 8:
fmt.Fprintf(&buf, " ")
}
}
fmt.Fprint(&buf, reset)
}
fmt.Fprintf(&buf, "\n\n00000000 ")
count = 0
for i := 0; i < len(diffs); i++ {
diff := diffs[i]
str := diff.From
if diff.Replace {
str = diff.To
}
color := c.color(diff)
reset := ""
if color != "" {
reset = c.reset
}
fmt.Fprint(&buf, color)
for _, b := range str {
fmt.Fprintf(&buf, " %02x", b)
count++
switch count % 16 {
case 0:
fmt.Fprintf(&buf, "%v\n%08x%v ", reset, count, color)
case 8:
fmt.Fprintf(&buf, " ")
}
}
fmt.Fprint(&buf, reset)
}
fmt.Fprint(&buf, "\n")
fmt.Fprintf(&buf, "%s", c.finish)
return buf.String()
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package gopacket
import (
"errors"
)
// DecodeFeedback is used by DecodingLayer layers to provide decoding metadata.
type DecodeFeedback interface {
// SetTruncated should be called if during decoding you notice that a packet
// is shorter than internal layer variables (HeaderLength, or the like) say it
// should be. It sets packet.Metadata().Truncated.
SetTruncated()
}
type nilDecodeFeedback struct{}
func (nilDecodeFeedback) SetTruncated() {}
// NilDecodeFeedback implements DecodeFeedback by doing nothing.
var NilDecodeFeedback DecodeFeedback = nilDecodeFeedback{}
// PacketBuilder is used by layer decoders to store the layers they've decoded,
// and to defer future decoding via NextDecoder.
// Typically, the pattern for use is:
// func (m *myDecoder) Decode(data []byte, p PacketBuilder) error {
// if myLayer, err := myDecodingLogic(data); err != nil {
// return err
// } else {
// p.AddLayer(myLayer)
// }
// // maybe do this, if myLayer is a LinkLayer
// p.SetLinkLayer(myLayer)
// return p.NextDecoder(nextDecoder)
// }
type PacketBuilder interface {
DecodeFeedback
// AddLayer should be called by a decoder immediately upon successful
// decoding of a layer.
AddLayer(l Layer)
// The following functions set the various specific layers in the final
// packet. Note that if many layers call SetX, the first call is kept and all
// other calls are ignored.
SetLinkLayer(LinkLayer)
SetNetworkLayer(NetworkLayer)
SetTransportLayer(TransportLayer)
SetApplicationLayer(ApplicationLayer)
SetErrorLayer(ErrorLayer)
// NextDecoder should be called by a decoder when they're done decoding a
// packet layer but not done with decoding the entire packet. The next
// decoder will be called to decode the last AddLayer's LayerPayload.
// Because of this, NextDecoder must only be called once all other
// PacketBuilder calls have been made. Set*Layer and AddLayer calls after
// NextDecoder calls will behave incorrectly.
NextDecoder(next Decoder) error
// DumpPacketData is used solely for decoding. If you come across an error
// you need to diagnose while processing a packet, call this and your packet's
// data will be dumped to stderr so you can create a test. This should never
// be called from a production decoder.
DumpPacketData()
// DecodeOptions returns the decode options
DecodeOptions() *DecodeOptions
}
// Decoder is an interface for logic to decode a packet layer. Users may
// implement a Decoder to handle their own strange packet types, or may use one
// of the many decoders available in the 'layers' subpackage to decode things
// for them.
type Decoder interface {
// Decode decodes the bytes of a packet, sending decoded values and other
// information to PacketBuilder, and returning an error if unsuccessful. See
// the PacketBuilder documentation for more details.
Decode([]byte, PacketBuilder) error
}
// DecodeFunc wraps a function to make it a Decoder.
type DecodeFunc func([]byte, PacketBuilder) error
// Decode implements Decoder by calling itself.
func (d DecodeFunc) Decode(data []byte, p PacketBuilder) error {
// function, call thyself.
return d(data, p)
}
// DecodePayload is a Decoder that returns a Payload layer containing all
// remaining bytes.
var DecodePayload Decoder = DecodeFunc(decodePayload)
// DecodeUnknown is a Decoder that returns an Unknown layer containing all
// remaining bytes, useful if you run up against a layer that you're unable to
// decode yet. This layer is considered an ErrorLayer.
var DecodeUnknown Decoder = DecodeFunc(decodeUnknown)
// DecodeFragment is a Decoder that returns a Fragment layer containing all
// remaining bytes.
var DecodeFragment Decoder = DecodeFunc(decodeFragment)
// LayerTypeZero is an invalid layer type, but can be used to determine whether
// layer type has actually been set correctly.
var LayerTypeZero = RegisterLayerType(0, LayerTypeMetadata{Name: "Unknown", Decoder: DecodeUnknown})
// LayerTypeDecodeFailure is the layer type for the default error layer.
var LayerTypeDecodeFailure = RegisterLayerType(1, LayerTypeMetadata{Name: "DecodeFailure", Decoder: DecodeUnknown})
// LayerTypePayload is the layer type for a payload that we don't try to decode
// but treat as a success, IE: an application-level payload.
var LayerTypePayload = RegisterLayerType(2, LayerTypeMetadata{Name: "Payload", Decoder: DecodePayload})
// LayerTypeFragment is the layer type for a fragment of a layer transported
// by an underlying layer that supports fragmentation.
var LayerTypeFragment = RegisterLayerType(3, LayerTypeMetadata{Name: "Fragment", Decoder: DecodeFragment})
// DecodeFailure is a packet layer created if decoding of the packet data failed
// for some reason. It implements ErrorLayer. LayerContents will be the entire
// set of bytes that failed to parse, and Error will return the reason parsing
// failed.
type DecodeFailure struct {
data []byte
err error
stack []byte
}
// Error returns the error encountered during decoding.
func (d *DecodeFailure) Error() error { return d.err }
// LayerContents implements Layer.
func (d *DecodeFailure) LayerContents() []byte { return d.data }
// LayerPayload implements Layer.
func (d *DecodeFailure) LayerPayload() []byte { return nil }
// String implements fmt.Stringer.
func (d *DecodeFailure) String() string {
return "Packet decoding error: " + d.Error().Error()
}
// Dump implements Dumper.
func (d *DecodeFailure) Dump() (s string) {
if d.stack != nil {
s = string(d.stack)
}
return
}
// 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.
func decodeUnknown(data []byte, p PacketBuilder) error {
return errors.New("Layer type not currently supported")
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package gopacket
import (
"bytes"
"fmt"
"strconv"
)
// MaxEndpointSize determines the maximum size in bytes of an endpoint address.
//
// Endpoints/Flows have a problem: They need to be hashable. Therefore, they
// can't use a byte slice. The two obvious choices are to use a string or a
// byte array. Strings work great, but string creation requires memory
// allocation, which can be slow. Arrays work great, but have a fixed size. We
// originally used the former, now we've switched to the latter. Use of a fixed
// byte-array doubles the speed of constructing a flow (due to not needing to
// allocate). This is a huge increase... too much for us to pass up.
//
// The end result of this, though, is that an endpoint/flow can't be created
// using more than MaxEndpointSize bytes per address.
const MaxEndpointSize = 16
// Endpoint is the set of bytes used to address packets at various layers.
// See LinkLayer, NetworkLayer, and TransportLayer specifications.
// Endpoints are usable as map keys.
type Endpoint struct {
typ EndpointType
len int
raw [MaxEndpointSize]byte
}
// EndpointType returns the endpoint type associated with this endpoint.
func (a Endpoint) EndpointType() EndpointType { return a.typ }
// 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 (a Endpoint) Raw() []byte { return a.raw[:a.len] }
// LessThan provides a stable ordering for all endpoints. It sorts first based
// on the EndpointType of an endpoint, then based on the raw bytes of that
// endpoint.
//
// For some endpoints, the actual comparison may not make sense, however this
// ordering does provide useful information for most Endpoint types.
// Ordering is based first on endpoint type, then on raw endpoint bytes.
// Endpoint bytes are sorted lexicographically.
func (a Endpoint) LessThan(b Endpoint) bool {
return a.typ < b.typ || (a.typ == b.typ && bytes.Compare(a.raw[:a.len], b.raw[:b.len]) < 0)
}
// fnvHash is used by our FastHash functions, and implements the FNV hash
// created by Glenn Fowler, Landon Curt Noll, and Phong Vo.
// See http://isthe.com/chongo/tech/comp/fnv/.
func fnvHash(s []byte) (h uint64) {
h = fnvBasis
for i := 0; i < len(s); i++ {
h ^= uint64(s[i])
h *= fnvPrime
}
return
}
const fnvBasis = 14695981039346656037
const fnvPrime = 1099511628211
// FastHash provides a quick hashing function for an endpoint, useful if you'd
// like to split up endpoints by modulos or other load-balancing techniques.
// It uses a variant of Fowler-Noll-Vo hashing.
//
// The output of FastHash is not guaranteed to remain the same through future
// code revisions, so should not be used to key values in persistent storage.
func (a Endpoint) FastHash() (h uint64) {
h = fnvHash(a.raw[:a.len])
h ^= uint64(a.typ)
h *= fnvPrime
return
}
// NewEndpoint creates a new Endpoint object.
//
// The size of raw must be less than MaxEndpointSize, otherwise this function
// will panic.
func NewEndpoint(typ EndpointType, raw []byte) (e Endpoint) {
e.len = len(raw)
if e.len > MaxEndpointSize {
panic("raw byte length greater than MaxEndpointSize")
}
e.typ = typ
copy(e.raw[:], raw)
return
}
// EndpointTypeMetadata is used to register a new endpoint type.
type EndpointTypeMetadata struct {
// Name is the string returned by an EndpointType's String function.
Name string
// Formatter is called from an Endpoint's String function to format the raw
// bytes in an Endpoint into a human-readable string.
Formatter func([]byte) string
}
// EndpointType is the type of a gopacket Endpoint. This type determines how
// the bytes stored in the endpoint should be interpreted.
type EndpointType int64
var endpointTypes = map[EndpointType]EndpointTypeMetadata{}
// RegisterEndpointType creates a new EndpointType and registers it globally.
// It MUST be passed a unique number, or it will panic. Numbers 0-999 are
// reserved for gopacket's use.
func RegisterEndpointType(num int, meta EndpointTypeMetadata) EndpointType {
t := EndpointType(num)
if _, ok := endpointTypes[t]; ok {
panic("Endpoint type number already in use")
}
endpointTypes[t] = meta
return t
}
func (e EndpointType) String() string {
if t, ok := endpointTypes[e]; ok {
return t.Name
}
return strconv.Itoa(int(e))
}
func (a Endpoint) String() string {
if t, ok := endpointTypes[a.typ]; ok && t.Formatter != nil {
return t.Formatter(a.raw[:a.len])
}
return fmt.Sprintf("%v:%v", a.typ, a.raw)
}
// Flow represents the direction of traffic for a packet layer, as a source and destination Endpoint.
// Flows are usable as map keys.
type Flow struct {
typ EndpointType
slen, dlen int
src, dst [MaxEndpointSize]byte
}
// FlowFromEndpoints creates a new flow by pasting together two endpoints.
// The endpoints must have the same EndpointType, or this function will return
// an error.
func FlowFromEndpoints(src, dst Endpoint) (_ Flow, err error) {
if src.typ != dst.typ {
err = fmt.Errorf("Mismatched endpoint types: %v->%v", src.typ, dst.typ)
return
}
return Flow{src.typ, src.len, dst.len, src.raw, dst.raw}, nil
}
// FastHash provides a quick hashing function for a flow, useful if you'd
// like to split up flows by modulos or other load-balancing techniques.
// It uses a variant of Fowler-Noll-Vo hashing, and is guaranteed to collide
// with its reverse flow. IE: the flow A->B will have the same hash as the flow
// B->A.
//
// The output of FastHash is not guaranteed to remain the same through future
// code revisions, so should not be used to key values in persistent storage.
func (f Flow) FastHash() (h uint64) {
// This combination must be commutative. We don't use ^, since that would
// give the same hash for all A->A flows.
h = fnvHash(f.src[:f.slen]) + fnvHash(f.dst[:f.dlen])
h ^= uint64(f.typ)
h *= fnvPrime
return
}
// String returns a human-readable representation of this flow, in the form
// "Src->Dst"
func (f Flow) String() string {
s, d := f.Endpoints()
return fmt.Sprintf("%v->%v", s, d)
}
// EndpointType returns the EndpointType for this Flow.
func (f Flow) EndpointType() EndpointType {
return f.typ
}
// Endpoints returns the two Endpoints for this flow.
func (f Flow) Endpoints() (src, dst Endpoint) {
return Endpoint{f.typ, f.slen, f.src}, Endpoint{f.typ, f.dlen, f.dst}
}
// Src returns the source Endpoint for this flow.
func (f Flow) Src() (src Endpoint) {
src, _ = f.Endpoints()
return
}
// Dst returns the destination Endpoint for this flow.
func (f Flow) Dst() (dst Endpoint) {
_, dst = f.Endpoints()
return
}
// Reverse returns a new flow with endpoints reversed.
func (f Flow) Reverse() Flow {
return Flow{f.typ, f.dlen, f.slen, f.dst, f.src}
}
// NewFlow creates a new flow.
//
// src and dst must have length <= MaxEndpointSize, otherwise NewFlow will
// panic.
func NewFlow(t EndpointType, src, dst []byte) (f Flow) {
f.slen = len(src)
f.dlen = len(dst)
if f.slen > MaxEndpointSize || f.dlen > MaxEndpointSize {
panic("flow raw byte length greater than MaxEndpointSize")
}
f.typ = t
copy(f.src[:], src)
copy(f.dst[:], dst)
return
}
// EndpointInvalid is an endpoint type used for invalid endpoints, IE endpoints
// that are specified incorrectly during creation.
var EndpointInvalid = RegisterEndpointType(0, EndpointTypeMetadata{Name: "invalid", Formatter: func(b []byte) string {
return fmt.Sprintf("%v", b)
}})
// InvalidEndpoint is a singleton Endpoint of type EndpointInvalid.
var InvalidEndpoint = NewEndpoint(EndpointInvalid, nil)
// InvalidFlow is a singleton Flow of type EndpointInvalid.
var InvalidFlow = NewFlow(EndpointInvalid, nil, nil)
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package gopacket
// LayerClass is a set of LayerTypes, used for grabbing one of a number of
// different types from a packet.
type LayerClass interface {
// Contains returns true if the given layer type should be considered part
// of this layer class.
Contains(LayerType) bool
// LayerTypes returns the set of all layer types in this layer class.
// Note that this may not be a fast operation on all LayerClass
// implementations.
LayerTypes() []LayerType
}
// Contains implements LayerClass.
func (l LayerType) Contains(a LayerType) bool {
return l == a
}
// LayerTypes implements LayerClass.
func (l LayerType) LayerTypes() []LayerType {
return []LayerType{l}
}
// LayerClassSlice implements a LayerClass with a slice.
type LayerClassSlice []bool
// Contains returns true if the given layer type should be considered part
// of this layer class.
func (s LayerClassSlice) Contains(t LayerType) bool {
return int(t) < len(s) && s[t]
}
// LayerTypes returns all layer types in this LayerClassSlice.
// Because of LayerClassSlice's implementation, this could be quite slow.
func (s LayerClassSlice) LayerTypes() (all []LayerType) {
for i := 0; i < len(s); i++ {
if s[i] {
all = append(all, LayerType(i))
}
}
return
}
// NewLayerClassSlice creates a new LayerClassSlice by creating a slice of
// size max(types) and setting slice[t] to true for each type t. Note, if
// you implement your own LayerType and give it a high value, this WILL create
// a very large slice.
func NewLayerClassSlice(types []LayerType) LayerClassSlice {
var max LayerType
for _, typ := range types {
if typ > max {
max = typ
}
}
t := make([]bool, int(max+1))
for _, typ := range types {
t[typ] = true
}
return t
}
// LayerClassMap implements a LayerClass with a map.
type LayerClassMap map[LayerType]bool
// Contains returns true if the given layer type should be considered part
// of this layer class.
func (m LayerClassMap) Contains(t LayerType) bool {
return m[t]
}
// LayerTypes returns all layer types in this LayerClassMap.
func (m LayerClassMap) LayerTypes() (all []LayerType) {
for t := range m {
all = append(all, t)
}
return
}
// NewLayerClassMap creates a LayerClassMap and sets map[t] to true for each
// type in types.
func NewLayerClassMap(types []LayerType) LayerClassMap {
m := LayerClassMap{}
for _, typ := range types {
m[typ] = true
}
return m
}
// NewLayerClass creates a LayerClass, attempting to be smart about which type
// it creates based on which types are passed in.
func NewLayerClass(types []LayerType) LayerClass {
for _, typ := range types {
if typ > maxLayerType {
// NewLayerClassSlice could create a very large object, so instead create
// a map.
return NewLayerClassMap(types)
}
}
return NewLayerClassSlice(types)
}
// Copyright 2025 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"errors"
"github.com/google/gopacket"
)
// AGUEVar0 represents a packet encoded with Generic UDP Encapsulation.
// It should sit "under" a UDP layer with dest port 666.
//
// For more information about the meaning of the fields, see
// https://tools.ietf.org/html/draft-ietf-intarea-gue-04#section-3.1
type AGUEVar0 struct {
Version uint8
C bool
Protocol IPProtocol
Flags uint16
Extensions []byte
Data []byte
}
// LayerType returns this pseudo-header's type as defined in layertypes.go
func (l AGUEVar0) LayerType() gopacket.LayerType {
return LayerTypeAGUEVar0
}
// LayerContents returns a byte array containing our serialized header.
func (l AGUEVar0) LayerContents() []byte {
b := make([]byte, 4, 4+len(l.Extensions))
hlen := uint8(len(l.Extensions))
b[0] = l.Version<<6 | hlen
if l.C {
b[0] |= 0x20
}
b[0] |= hlen
b[1] = byte(l.Protocol)
b[2] = byte(l.Flags >> 8)
b[3] = byte(l.Flags & 0xff)
b = append(b, l.Extensions...)
return b
}
// LayerPayload returns an IPv4 or IPv6 packet in serialized form.
func (l AGUEVar0) LayerPayload() []byte {
return l.Data
}
// SerializeTo writes our header into SerializeBuffer.
func (l AGUEVar0) SerializeTo(buf gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
b := l.LayerContents()
writeTo, err := buf.PrependBytes(len(b))
if err != nil {
return err
}
copy(writeTo, b)
return nil
}
// CanDecode returns the type of layer we can decode.
func (l AGUEVar0) CanDecode() gopacket.LayerClass {
return LayerTypeAGUEVar0
}
// DecodeFromBytes extracts our header data from a serialized packet.
func (l *AGUEVar0) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
l.Version = data[0] >> 6
l.C = data[0]&0x20 != 0
l.Protocol = IPProtocol(data[1])
l.Flags = (uint16(data[2]) << 8) | uint16(data[3])
hlen := data[0] & 0x1f
l.Extensions = data[4 : 4+hlen]
l.Data = data[4+hlen:]
return nil
}
// NextLayerType returns the next layer type, e.g. LayerTypeIPv4
func (l AGUEVar0) NextLayerType() gopacket.LayerType {
return l.Protocol.LayerType()
}
// decodeAGUE decodes AGUEVar0 or AGUEVar1, depending on the first data byte.
// If AGUEVar1, it refers the packet to AGUEVar1 for decoding.
// Else it adds AGUEVar0 layer info to the packet object, recursively decodes
// remaining layers, and returns the next-layer type (IPv4 or IPv6).
func decodeAGUE(data []byte, p gopacket.PacketBuilder) error {
if len(data) == 0 {
return errors.New("decodeAGUE() failed, no data")
}
if data[0]>>6 == 1 {
return decodeAGUEVar1(data, p)
}
l := AGUEVar0{}
if err := l.DecodeFromBytes(data, gopacket.NilDecodeFeedback); err != nil {
return err
}
p.AddLayer(l)
return p.NextDecoder(l.NextLayerType())
}
// Copyright 2025 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"errors"
"github.com/google/gopacket"
)
// An AGUEVar1 header is mostly imaginary, having a length of 0 in its serialized form.
// IPProtocol value is either IPProtocolIPv4 or IPProtocolIPv6, depending on the encapped
// IP header contained in Data, which must begin with the high-order bits 01.
type AGUEVar1 struct {
Protocol IPProtocol
Data []byte
}
// LayerType returns this pseudo-header's type as defined in layertypes.go
func (l AGUEVar1) LayerType() gopacket.LayerType {
return LayerTypeAGUEVar1
}
// LayerContents returns an empty byte array, because this header has no length.
func (l AGUEVar1) LayerContents() []byte {
b := make([]byte, 0, 0)
return b
}
// LayerPayload returns an IPv4 or IPv6 packet in serialized form.
func (l AGUEVar1) LayerPayload() []byte {
return l.Data
}
// SerializeTo writes our imaginary header into SerializeBuffer. This amount to a noop.
func (l AGUEVar1) SerializeTo(buf gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
return nil
}
// CanDecode returns the type of layer we can decode.
func (l AGUEVar1) CanDecode() gopacket.LayerClass {
return LayerTypeAGUEVar1
}
// DecodeFromBytes extracts our pseudo-header data from a serialized packet.
// There's only one thing, the next header type, which is either IPv4 or IPv6.
// They are crafted to keep their own header type in the first nibble.
// So we peek into the IP header to get the next-layer protocol type.
func (l *AGUEVar1) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 1 {
return errors.New("DecodeFromBytes() failed, no data")
}
ipVersion := data[0] >> 4
if ipVersion == 4 {
l.Protocol = IPProtocolIPv4
} else if ipVersion == 6 {
l.Protocol = IPProtocolIPv6
} else {
return errors.New("DecodeFromBytes() failed, unknown IP version")
}
l.Data = data
return nil
}
// NextLayerType returns the next layer type, e.g. LayerTypeIPv4
func (l AGUEVar1) NextLayerType() gopacket.LayerType {
return l.Protocol.LayerType()
}
// decodeAGUEVar1 decodes packet data to figure out the next-layer IP type,
// then adds AGUEVar1 layer info to the packet object, recursively decodes
// remaining layers, and returns the next-layer type.
func decodeAGUEVar1(data []byte, p gopacket.PacketBuilder) error {
l := AGUEVar1{}
if err := l.DecodeFromBytes(data, gopacket.NilDecodeFeedback); err != nil {
return err
}
p.AddLayer(l)
return p.NextDecoder(l.NextLayerType())
}
// Copyright 2025 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
// This file implements the Andromeda PSP header, a specialized version of the PSP header.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"github.com/google/gopacket"
)
// APSP represents a packet encrypted with the Andromeda Paddywhack Security Protocol.
// It should sit "under" a UDP layer with dest port 1000.
// For more information about the meaning of the fields,
// see go/andromeda-psp-format
// This is a remix and extension of the basic PSP header, see go/psp-format
// Field order and packing don't really matter, because we serialize explicitly,
// in SerializeTo()
type APSP struct {
BaseLayer
NextHeader uint8
HdrExtLen uint8
CryptOffset uint8 // lower 6 bits are offset, 2 high bits are reserved
SDVersVirt uint8 // see go/andromeda-psp-format for bitfield breakdown
SecParamIdx uint32
InitVector uint64
SecTokenV2 uint32
VirtKey uint32
SrcEndpointID uint64
DstEndpointID uint64
}
// ApspLen is the sum of the header fields above, by length
const ApspLen = 40
// CanDecode returns the type of layer we can decode.
func (l APSP) CanDecode() gopacket.LayerClass {
return LayerTypeAPSP
}
// DecodeFromBytes extracts our header data from a serialized packet.
func (l *APSP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < ApspLen {
df.SetTruncated()
return fmt.Errorf("invalid APSP header. Length %d less than %d", len(data), ApspLen)
}
l.NextHeader = data[0]
l.HdrExtLen = data[1]
l.CryptOffset = data[2]
l.SDVersVirt = data[3]
l.SecParamIdx = binary.BigEndian.Uint32(data[4:8])
l.InitVector = binary.BigEndian.Uint64(data[8:16])
l.SecTokenV2 = binary.BigEndian.Uint32(data[16:20])
l.VirtKey = binary.BigEndian.Uint32(data[20:24])
l.SrcEndpointID = binary.BigEndian.Uint64(data[24:32])
l.DstEndpointID = binary.BigEndian.Uint64(data[32:40])
l.BaseLayer = BaseLayer{Contents: data[:ApspLen]}
l.Payload = data[ApspLen:]
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (l APSP) SerializeTo(buf gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
b := l.LayerContents()
writeTo, err := buf.PrependBytes(len(b))
if err != nil {
return err
}
copy(writeTo, b)
return nil
}
// LayerContents returns a byte array containing our serialized header.
func (l APSP) LayerContents() []byte {
bytes := make([]byte, ApspLen)
bytes[0] = l.NextHeader
bytes[1] = l.HdrExtLen
bytes[2] = l.CryptOffset
bytes[3] = l.SDVersVirt
binary.BigEndian.PutUint32(bytes[4:], l.SecParamIdx)
binary.BigEndian.PutUint64(bytes[8:], l.InitVector)
binary.BigEndian.PutUint32(bytes[16:], l.SecTokenV2)
binary.BigEndian.PutUint32(bytes[20:], l.VirtKey)
binary.BigEndian.PutUint64(bytes[24:], l.SrcEndpointID)
binary.BigEndian.PutUint64(bytes[32:], l.DstEndpointID)
return bytes
}
// LayerPayload returns an IPv4 or IPv6 packet in serialized form.
func (l APSP) LayerPayload() []byte {
return l.Payload
}
// NextLayerType returns the next layer type, either IPv4 or IPv6.
func (l APSP) NextLayerType() gopacket.LayerType {
// TODO: check for IPv6
return LayerTypeIPv4
}
// LayerType returns LayerTypeAPSP.
func (l APSP) LayerType() gopacket.LayerType {
return LayerTypeAPSP
}
func decodeAPSP(data []byte, p gopacket.PacketBuilder) error {
if len(data) == 0 {
return errors.New("decodeAPSP() failed, no data")
}
l := APSP{}
if err := l.DecodeFromBytes(data, gopacket.NilDecodeFeedback); err != nil {
return err
}
p.AddLayer(l)
return p.NextDecoder(l.NextLayerType())
}
// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"github.com/google/gopacket"
)
// Potential values for ARP.Operation.
const (
ARPRequest = 1
ARPReply = 2
)
// ARP is a ARP packet header.
type ARP struct {
BaseLayer
AddrType LinkType
Protocol EthernetType
HwAddressSize uint8
ProtAddressSize uint8
Operation uint16
SourceHwAddress []byte
SourceProtAddress []byte
DstHwAddress []byte
DstProtAddress []byte
}
// LayerType returns LayerTypeARP
func (arp *ARP) LayerType() gopacket.LayerType { return LayerTypeARP }
// DecodeFromBytes decodes the given bytes into this layer.
func (arp *ARP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 8 {
df.SetTruncated()
return fmt.Errorf("ARP length %d too short", len(data))
}
arp.AddrType = LinkType(binary.BigEndian.Uint16(data[0:2]))
arp.Protocol = EthernetType(binary.BigEndian.Uint16(data[2:4]))
arp.HwAddressSize = data[4]
arp.ProtAddressSize = data[5]
arp.Operation = binary.BigEndian.Uint16(data[6:8])
arpLength := 8 + 2*arp.HwAddressSize + 2*arp.ProtAddressSize
if len(data) < int(arpLength) {
df.SetTruncated()
return fmt.Errorf("ARP length %d too short, %d expected", len(data), arpLength)
}
arp.SourceHwAddress = data[8 : 8+arp.HwAddressSize]
arp.SourceProtAddress = data[8+arp.HwAddressSize : 8+arp.HwAddressSize+arp.ProtAddressSize]
arp.DstHwAddress = data[8+arp.HwAddressSize+arp.ProtAddressSize : 8+2*arp.HwAddressSize+arp.ProtAddressSize]
arp.DstProtAddress = data[8+2*arp.HwAddressSize+arp.ProtAddressSize : 8+2*arp.HwAddressSize+2*arp.ProtAddressSize]
arp.Contents = data[:arpLength]
arp.Payload = data[arpLength:]
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (arp *ARP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
size := 8 + len(arp.SourceHwAddress) + len(arp.SourceProtAddress) + len(arp.DstHwAddress) + len(arp.DstProtAddress)
bytes, err := b.PrependBytes(size)
if err != nil {
return err
}
if opts.FixLengths {
if len(arp.SourceHwAddress) != len(arp.DstHwAddress) {
return errors.New("mismatched hardware address sizes")
}
arp.HwAddressSize = uint8(len(arp.SourceHwAddress))
if len(arp.SourceProtAddress) != len(arp.DstProtAddress) {
return errors.New("mismatched prot address sizes")
}
arp.ProtAddressSize = uint8(len(arp.SourceProtAddress))
}
binary.BigEndian.PutUint16(bytes, uint16(arp.AddrType))
binary.BigEndian.PutUint16(bytes[2:], uint16(arp.Protocol))
bytes[4] = arp.HwAddressSize
bytes[5] = arp.ProtAddressSize
binary.BigEndian.PutUint16(bytes[6:], arp.Operation)
start := 8
for _, addr := range [][]byte{
arp.SourceHwAddress,
arp.SourceProtAddress,
arp.DstHwAddress,
arp.DstProtAddress,
} {
copy(bytes[start:], addr)
start += len(addr)
}
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (arp *ARP) CanDecode() gopacket.LayerClass {
return LayerTypeARP
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (arp *ARP) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
func decodeARP(data []byte, p gopacket.PacketBuilder) error {
arp := &ARP{}
return decodingLayerDecoder(arp, data, p)
}
// Copyright 2019 The GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file in the root of the source tree.
package layers
// This file implements the ASF RMCP payload specified in section 3.2.2.3 of
// https://www.dmtf.org/sites/default/files/standards/documents/DSP0136.pdf
import (
"encoding/binary"
"fmt"
"github.com/google/gopacket"
)
const (
// ASFRMCPEnterprise is the IANA-assigned Enterprise Number of the ASF-RMCP.
ASFRMCPEnterprise uint32 = 4542
)
// ASFDataIdentifier encapsulates fields used to uniquely identify the format of
// the data block.
//
// While the enterprise number is almost always 4542 (ASF-RMCP), we support
// registering layers using structs of this type as a key in case any users are
// using OEM-extensions.
type ASFDataIdentifier struct {
// Enterprise is the IANA Enterprise Number associated with the entity that
// defines the message type. A list can be found at
// https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers.
// This can be thought of as the namespace for the message type.
Enterprise uint32
// Type is the message type, defined by the entity associated with the
// enterprise above. No pressure, but in the context of EN 4542, 1 byte is
// the difference between sending a ping and telling a machine to do an
// unconditional power down (0x80 and 0x12 respectively).
Type uint8
}
// LayerType returns the payload layer type corresponding to an ASF message
// type.
func (a ASFDataIdentifier) LayerType() gopacket.LayerType {
if lt := asfDataLayerTypes[a]; lt != 0 {
return lt
}
// some layer types don't have a payload, e.g. ASF-RMCP Presence Ping.
return gopacket.LayerTypePayload
}
// RegisterASFLayerType allows specifying that the data block of ASF packets
// with a given enterprise number and type should be processed by a given layer
// type. This overrides any existing registrations, including defaults.
func RegisterASFLayerType(a ASFDataIdentifier, l gopacket.LayerType) {
asfDataLayerTypes[a] = l
}
var (
// ASFDataIdentifierPresencePong is the message type of the response to a
// Presence Ping message. It indicates the sender is ASF-RMCP-aware.
ASFDataIdentifierPresencePong = ASFDataIdentifier{
Enterprise: ASFRMCPEnterprise,
Type: 0x40,
}
// ASFDataIdentifierPresencePing is a message type sent to a managed client
// to solicit a Presence Pong response. Clients may ignore this if the RMCP
// version is unsupported. Sending this message with a sequence number <255
// is the recommended way of finding out whether an implementation sends
// RMCP ACKs (e.g. iDRAC does, Super Micro does not).
//
// Systems implementing IPMI must respond to this ping to conform to the
// spec, so it is a good substitute for an ICMP ping.
ASFDataIdentifierPresencePing = ASFDataIdentifier{
Enterprise: ASFRMCPEnterprise,
Type: 0x80,
}
// asfDataLayerTypes is used to find the next layer for a given ASF header.
asfDataLayerTypes = map[ASFDataIdentifier]gopacket.LayerType{
ASFDataIdentifierPresencePong: LayerTypeASFPresencePong,
}
)
// ASF defines ASF's generic RMCP message Data block format. See section
// 3.2.2.3.
type ASF struct {
BaseLayer
ASFDataIdentifier
// Tag is used to match request/response pairs. The tag of a response is set
// to that of the message it is responding to. If a message is
// unidirectional, i.e. not part of a request/response pair, this is set to
// 255.
Tag uint8
// 1 byte reserved, set to 0x00.
// Length is the length of this layer's payload in bytes.
Length uint8
}
// LayerType returns LayerTypeASF. It partially satisfies Layer and
// SerializableLayer.
func (*ASF) LayerType() gopacket.LayerType {
return LayerTypeASF
}
// CanDecode returns LayerTypeASF. It partially satisfies DecodingLayer.
func (a *ASF) CanDecode() gopacket.LayerClass {
return a.LayerType()
}
// DecodeFromBytes makes the layer represent the provided bytes. It partially
// satisfies DecodingLayer.
func (a *ASF) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 8 {
df.SetTruncated()
return fmt.Errorf("invalid ASF data header, length %v less than 8",
len(data))
}
a.BaseLayer.Contents = data[:8]
a.BaseLayer.Payload = data[8:]
a.Enterprise = binary.BigEndian.Uint32(data[:4])
a.Type = uint8(data[4])
a.Tag = uint8(data[5])
// 1 byte reserved
a.Length = uint8(data[7])
return nil
}
// NextLayerType returns the layer type corresponding to the message type of
// this ASF data layer. This partially satisfies DecodingLayer.
func (a *ASF) NextLayerType() gopacket.LayerType {
return a.ASFDataIdentifier.LayerType()
}
// SerializeTo writes the serialized fom of this layer into the SerializeBuffer,
// partially satisfying SerializableLayer.
func (a *ASF) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
payload := b.Bytes()
bytes, err := b.PrependBytes(8)
if err != nil {
return err
}
binary.BigEndian.PutUint32(bytes[:4], a.Enterprise)
bytes[4] = uint8(a.Type)
bytes[5] = a.Tag
bytes[6] = 0x00
if opts.FixLengths {
a.Length = uint8(len(payload))
}
bytes[7] = a.Length
return nil
}
// decodeASF decodes the byte slice into an RMCP-ASF data struct.
func decodeASF(data []byte, p gopacket.PacketBuilder) error {
return decodingLayerDecoder(&ASF{}, data, p)
}
// Copyright 2019 The GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file in the root of the source tree.
package layers
// This file implements the RMCP ASF Presence Pong message, specified in section
// 3.2.4.3 of
// https://www.dmtf.org/sites/default/files/standards/documents/DSP0136.pdf. It
// also contains non-competing elements from IPMI v2.0, specified in section
// 13.2.4 of
// https://www.intel.com/content/dam/www/public/us/en/documents/specification-updates/ipmi-intelligent-platform-mgt-interface-spec-2nd-gen-v2-0-spec-update.pdf.
import (
"encoding/binary"
"fmt"
"github.com/google/gopacket"
)
type (
// ASFEntity is the type of individual entities that a Presence Pong
// response can indicate support of. The entities currently implemented by
// the spec are IPMI and ASFv1.
ASFEntity uint8
// ASFInteraction is the type of individual interactions that a Presence
// Pong response can indicate support for. The interactions currently
// implemented by the spec are RMCP security extensions. Although not
// specified, IPMI uses this field to indicate support for DASH, which is
// supported as well.
ASFInteraction uint8
)
const (
// ASFDCMIEnterprise is the IANA-assigned Enterprise Number of the Data
// Center Manageability Interface Forum. The Presence Pong response's
// Enterprise field being set to this value indicates support for DCMI. The
// DCMI spec regards the OEM field as reserved, so these should be null.
ASFDCMIEnterprise uint32 = 36465
// ASFPresencePongEntityIPMI ANDs with Presence Pong's supported entities
// field if the managed system supports IPMI.
ASFPresencePongEntityIPMI ASFEntity = 1 << 7
// ASFPresencePongEntityASFv1 ANDs with Presence Pong's supported entities
// field if the managed system supports ASF v1.0.
ASFPresencePongEntityASFv1 ASFEntity = 1
// ASFPresencePongInteractionSecurityExtensions ANDs with Presence Pong's
// supported interactions field if the managed system supports RMCP v2.0
// security extensions. See section 3.2.3.
ASFPresencePongInteractionSecurityExtensions ASFInteraction = 1 << 7
// ASFPresencePongInteractionDASH ANDs with Presence Pong's supported
// interactions field if the managed system supports DMTF DASH. See
// https://www.dmtf.org/standards/dash.
ASFPresencePongInteractionDASH ASFInteraction = 1 << 5
)
// ASFPresencePong defines the structure of a Presence Pong message's payload.
// See section 3.2.4.3.
type ASFPresencePong struct {
BaseLayer
// Enterprise is the IANA Enterprise Number of an entity that has defined
// OEM-specific capabilities for the managed client. If no such capabilities
// exist, this is set to ASF's IANA Enterprise Number.
Enterprise uint32
// OEM identifies OEM-specific capabilities. Its structure is defined by the
// OEM. This is set to 0s if no OEM-specific capabilities exist. This
// implementation does not change byte order from the wire for this field.
OEM [4]byte
// We break out entities and interactions into separate booleans as
// discovery is the entire point of this type of message, so we assume they
// are accessed. It also makes gopacket's default layer printing more
// useful.
// IPMI is true if IPMI is supported by the managed system. There is no
// explicit version in the specification, however given the dates, this is
// assumed to be IPMI v1.0. Support for IPMI is contained in the "supported
// entities" field of the presence pong payload.
IPMI bool
// ASFv1 indicates support for ASF v1.0. This seems somewhat redundant as
// ASF must be supported in order to receive a response. This is contained
// in the "supported entities" field of the presence pong payload.
ASFv1 bool
// SecurityExtensions indicates support for RMCP Security Extensions,
// specified in ASF v2.0. This will always be false for v1.x
// implementations. This is contained in the "supported interactions" field
// of the presence pong payload. This field is defined in ASF v1.0, but has
// no useful value.
SecurityExtensions bool
// DASH is true if DMTF DASH is supported. This is not specified in ASF
// v2.0, but in IPMI v2.0, however the former does not preclude it, so we
// support it.
DASH bool
// 6 bytes reserved after the entities and interactions fields, set to 0s.
}
// SupportsDCMI returns whether the Presence Pong message indicates support for
// the Data Center Management Interface, which is an extension of IPMI v2.0.
func (a *ASFPresencePong) SupportsDCMI() bool {
return a.Enterprise == ASFDCMIEnterprise && a.IPMI && a.ASFv1
}
// LayerType returns LayerTypeASFPresencePong. It partially satisfies Layer and
// SerializableLayer.
func (*ASFPresencePong) LayerType() gopacket.LayerType {
return LayerTypeASFPresencePong
}
// CanDecode returns LayerTypeASFPresencePong. It partially satisfies
// DecodingLayer.
func (a *ASFPresencePong) CanDecode() gopacket.LayerClass {
return a.LayerType()
}
// DecodeFromBytes makes the layer represent the provided bytes. It partially
// satisfies DecodingLayer.
func (a *ASFPresencePong) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 16 {
df.SetTruncated()
return fmt.Errorf("invalid ASF presence pong payload, length %v less than 16",
len(data))
}
a.BaseLayer.Contents = data[:16]
a.BaseLayer.Payload = data[16:]
a.Enterprise = binary.BigEndian.Uint32(data[:4])
copy(a.OEM[:], data[4:8]) // N.B. no byte order change
a.IPMI = data[8]&uint8(ASFPresencePongEntityIPMI) != 0
a.ASFv1 = data[8]&uint8(ASFPresencePongEntityASFv1) != 0
a.SecurityExtensions = data[9]&uint8(ASFPresencePongInteractionSecurityExtensions) != 0
a.DASH = data[9]&uint8(ASFPresencePongInteractionDASH) != 0
// ignore remaining 6 bytes; should be set to 0s
return nil
}
// NextLayerType returns LayerTypePayload, as there are no further layers to
// decode. This partially satisfies DecodingLayer.
func (a *ASFPresencePong) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
// SerializeTo writes the serialized fom of this layer into the SerializeBuffer,
// partially satisfying SerializableLayer.
func (a *ASFPresencePong) SerializeTo(b gopacket.SerializeBuffer, _ gopacket.SerializeOptions) error {
bytes, err := b.PrependBytes(16)
if err != nil {
return err
}
binary.BigEndian.PutUint32(bytes[:4], a.Enterprise)
copy(bytes[4:8], a.OEM[:])
bytes[8] = 0
if a.IPMI {
bytes[8] |= uint8(ASFPresencePongEntityIPMI)
}
if a.ASFv1 {
bytes[8] |= uint8(ASFPresencePongEntityASFv1)
}
bytes[9] = 0
if a.SecurityExtensions {
bytes[9] |= uint8(ASFPresencePongInteractionSecurityExtensions)
}
if a.DASH {
bytes[9] |= uint8(ASFPresencePongInteractionDASH)
}
// zero-out remaining 6 bytes
for i := 10; i < len(bytes); i++ {
bytes[i] = 0x00
}
return nil
}
// decodeASFPresencePong decodes the byte slice into an RMCP-ASF Presence Pong
// struct.
func decodeASFPresencePong(data []byte, p gopacket.PacketBuilder) error {
return decodingLayerDecoder(&ASFPresencePong{}, data, p)
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"github.com/google/gopacket"
)
// BaseLayer is a convenience struct which implements the LayerData and
// LayerPayload functions of the Layer interface.
type BaseLayer struct {
// Contents is the set of bytes that make up this layer. IE: for an
// Ethernet packet, this would be the set of bytes making up the
// Ethernet frame.
Contents []byte
// Payload is the set of bytes contained by (but not part of) this
// Layer. Again, to take Ethernet as an example, this would be the
// set of bytes encapsulated by the Ethernet protocol.
Payload []byte
}
// LayerContents returns the bytes of the packet layer.
func (b *BaseLayer) LayerContents() []byte { return b.Contents }
// LayerPayload returns the bytes contained within the packet layer.
func (b *BaseLayer) LayerPayload() []byte { return b.Payload }
type layerDecodingLayer interface {
gopacket.Layer
DecodeFromBytes([]byte, gopacket.DecodeFeedback) error
NextLayerType() gopacket.LayerType
}
func decodingLayerDecoder(d layerDecodingLayer, data []byte, p gopacket.PacketBuilder) error {
err := d.DecodeFromBytes(data, p)
if err != nil {
return err
}
p.AddLayer(d)
next := d.NextLayerType()
if next == gopacket.LayerTypeZero {
return nil
}
return p.NextDecoder(next)
}
// hacky way to zero out memory... there must be a better way?
var lotsOfZeros [1024]byte
// Copyright 2017 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
//
package layers
import (
"encoding/binary"
"errors"
"github.com/google/gopacket"
)
// BFD Control Packet Format
// -------------------------
// The current version of BFD's RFC (RFC 5880) contains the following
// diagram for the BFD Control packet format:
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |Vers | Diag |Sta|P|F|C|A|D|M| Detect Mult | Length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | My Discriminator |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Your Discriminator |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Desired Min TX Interval |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Required Min RX Interval |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Required Min Echo RX Interval |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// An optional Authentication Section MAY be present:
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Auth Type | Auth Len | Authentication Data... |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
//
// Simple Password Authentication Section Format
// ---------------------------------------------
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Auth Type | Auth Len | Auth Key ID | Password... |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | ... |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
//
// Keyed MD5 and Meticulous Keyed MD5 Authentication Section Format
// ----------------------------------------------------------------
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Auth Type | Auth Len | Auth Key ID | Reserved |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Sequence Number |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Auth Key/Digest... |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | ... |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
//
// Keyed SHA1 and Meticulous Keyed SHA1 Authentication Section Format
// ------------------------------------------------------------------
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Auth Type | Auth Len | Auth Key ID | Reserved |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Sequence Number |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Auth Key/Hash... |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | ... |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// From https://tools.ietf.org/rfc/rfc5880.txt
const bfdMinimumRecordSizeInBytes int = 24
// BFDVersion represents the version as decoded from the BFD control message
type BFDVersion uint8
// BFDDiagnostic represents diagnostic infomation about a BFD session
type BFDDiagnostic uint8
// constants that define BFDDiagnostic flags
const (
BFDDiagnosticNone BFDDiagnostic = 0 // No Diagnostic
BFDDiagnosticTimeExpired BFDDiagnostic = 1 // Control Detection Time Expired
BFDDiagnosticEchoFailed BFDDiagnostic = 2 // Echo Function Failed
BFDDiagnosticNeighborSignalDown BFDDiagnostic = 3 // Neighbor Signaled Session Down
BFDDiagnosticForwardPlaneReset BFDDiagnostic = 4 // Forwarding Plane Reset
BFDDiagnosticPathDown BFDDiagnostic = 5 // Path Down
BFDDiagnosticConcatPathDown BFDDiagnostic = 6 // Concatenated Path Down
BFDDiagnosticAdminDown BFDDiagnostic = 7 // Administratively Down
BFDDiagnosticRevConcatPathDown BFDDiagnostic = 8 // Reverse Concatenated Path Dow
)
// String returns a string version of BFDDiagnostic
func (bd BFDDiagnostic) String() string {
switch bd {
default:
return "Unknown"
case BFDDiagnosticNone:
return "None"
case BFDDiagnosticTimeExpired:
return "Control Detection Time Expired"
case BFDDiagnosticEchoFailed:
return "Echo Function Failed"
case BFDDiagnosticNeighborSignalDown:
return "Neighbor Signaled Session Down"
case BFDDiagnosticForwardPlaneReset:
return "Forwarding Plane Reset"
case BFDDiagnosticPathDown:
return "Path Down"
case BFDDiagnosticConcatPathDown:
return "Concatenated Path Down"
case BFDDiagnosticAdminDown:
return "Administratively Down"
case BFDDiagnosticRevConcatPathDown:
return "Reverse Concatenated Path Down"
}
}
// BFDState represents the state of a BFD session
type BFDState uint8
// constants that define BFDState
const (
BFDStateAdminDown BFDState = 0
BFDStateDown BFDState = 1
BFDStateInit BFDState = 2
BFDStateUp BFDState = 3
)
// String returns a string version of BFDState
func (s BFDState) String() string {
switch s {
default:
return "Unknown"
case BFDStateAdminDown:
return "Admin Down"
case BFDStateDown:
return "Down"
case BFDStateInit:
return "Init"
case BFDStateUp:
return "Up"
}
}
// BFDDetectMultiplier represents the negotiated transmit interval,
// multiplied by this value, provides the Detection Time for the
// receiving system in Asynchronous mode.
type BFDDetectMultiplier uint8
// BFDDiscriminator is a unique, nonzero discriminator value used
// to demultiplex multiple BFD sessions between the same pair of systems.
type BFDDiscriminator uint32
// BFDTimeInterval represents a time interval in microseconds
type BFDTimeInterval uint32
// BFDAuthType represents the authentication used in the BFD session
type BFDAuthType uint8
// constants that define the BFDAuthType
const (
BFDAuthTypeNone BFDAuthType = 0 // No Auth
BFDAuthTypePassword BFDAuthType = 1 // Simple Password
BFDAuthTypeKeyedMD5 BFDAuthType = 2 // Keyed MD5
BFDAuthTypeMeticulousKeyedMD5 BFDAuthType = 3 // Meticulous Keyed MD5
BFDAuthTypeKeyedSHA1 BFDAuthType = 4 // Keyed SHA1
BFDAuthTypeMeticulousKeyedSHA1 BFDAuthType = 5 // Meticulous Keyed SHA1
)
// String returns a string version of BFDAuthType
func (at BFDAuthType) String() string {
switch at {
default:
return "Unknown"
case BFDAuthTypeNone:
return "No Authentication"
case BFDAuthTypePassword:
return "Simple Password"
case BFDAuthTypeKeyedMD5:
return "Keyed MD5"
case BFDAuthTypeMeticulousKeyedMD5:
return "Meticulous Keyed MD5"
case BFDAuthTypeKeyedSHA1:
return "Keyed SHA1"
case BFDAuthTypeMeticulousKeyedSHA1:
return "Meticulous Keyed SHA1"
}
}
// BFDAuthKeyID represents the authentication key ID in use for
// this packet. This allows multiple keys to be active simultaneously.
type BFDAuthKeyID uint8
// BFDAuthSequenceNumber represents the sequence number for this packet.
// For Keyed Authentication, this value is incremented occasionally. For
// Meticulous Keyed Authentication, this value is incremented for each
// successive packet transmitted for a session. This provides protection
// against replay attacks.
type BFDAuthSequenceNumber uint32
// BFDAuthData represents the authentication key or digest
type BFDAuthData []byte
// BFDAuthHeader represents authentication data used in the BFD session
type BFDAuthHeader struct {
AuthType BFDAuthType
KeyID BFDAuthKeyID
SequenceNumber BFDAuthSequenceNumber
Data BFDAuthData
}
// Length returns the data length of the BFDAuthHeader based on the
// authentication type
func (h *BFDAuthHeader) Length() int {
switch h.AuthType {
case BFDAuthTypePassword:
return 3 + len(h.Data)
case BFDAuthTypeKeyedMD5, BFDAuthTypeMeticulousKeyedMD5:
return 8 + len(h.Data)
case BFDAuthTypeKeyedSHA1, BFDAuthTypeMeticulousKeyedSHA1:
return 8 + len(h.Data)
default:
return 0
}
}
// BFD represents a BFD control message packet whose payload contains
// the control information required to for a BFD session.
//
// References
// ----------
//
// Wikipedia's BFD entry:
// https://en.wikipedia.org/wiki/Bidirectional_Forwarding_Detection
// This is the best place to get an overview of BFD.
//
// RFC 5880 "Bidirectional Forwarding Detection (BFD)" (2010)
// https://tools.ietf.org/html/rfc5880
// This is the original BFD specification.
//
// RFC 5881 "Bidirectional Forwarding Detection (BFD) for IPv4 and IPv6 (Single Hop)" (2010)
// https://tools.ietf.org/html/rfc5881
// Describes the use of the Bidirectional Forwarding Detection (BFD)
// protocol over IPv4 and IPv6 for single IP hops.
type BFD struct {
BaseLayer // Stores the packet bytes and payload bytes.
Version BFDVersion // Version of the BFD protocol.
Diagnostic BFDDiagnostic // Diagnostic code for last state change
State BFDState // Current state
Poll bool // Requesting verification
Final bool // Responding to a received BFD Control packet that had the Poll (P) bit set.
ControlPlaneIndependent bool // BFD implementation does not share fate with its control plane
AuthPresent bool // Authentication Section is present and the session is to be authenticated
Demand bool // Demand mode is active
Multipoint bool // For future point-to-multipoint extensions. Must always be zero
DetectMultiplier BFDDetectMultiplier // Detection time multiplier
MyDiscriminator BFDDiscriminator // A unique, nonzero discriminator value
YourDiscriminator BFDDiscriminator // discriminator received from the remote system.
DesiredMinTxInterval BFDTimeInterval // Minimum interval, in microseconds, the local system would like to use when transmitting BFD Control packets
RequiredMinRxInterval BFDTimeInterval // Minimum interval, in microseconds, between received BFD Control packets that this system is capable of supporting
RequiredMinEchoRxInterval BFDTimeInterval // Minimum interval, in microseconds, between received BFD Echo packets that this system is capable of supporting
AuthHeader *BFDAuthHeader // Authentication data, variable length.
}
// Length returns the data length of a BFD Control message which
// changes based on the presence and type of authentication
// contained in the message
func (d *BFD) Length() int {
if d.AuthPresent && (d.AuthHeader != nil) {
return bfdMinimumRecordSizeInBytes + d.AuthHeader.Length()
}
return bfdMinimumRecordSizeInBytes
}
// LayerType returns the layer type of the BFD object, which is LayerTypeBFD.
func (d *BFD) LayerType() gopacket.LayerType {
return LayerTypeBFD
}
// decodeBFD analyses a byte slice and attempts to decode it as a BFD
// control packet
//
// If it succeeds, it loads p with information about the packet and returns nil.
// If it fails, it returns an error (non nil).
//
// This function is employed in layertypes.go to register the BFD layer.
func decodeBFD(data []byte, p gopacket.PacketBuilder) error {
// Attempt to decode the byte slice.
d := &BFD{}
err := d.DecodeFromBytes(data, p)
if err != nil {
return err
}
// If the decoding worked, add the layer to the packet and set it
// as the application layer too, if there isn't already one.
p.AddLayer(d)
p.SetApplicationLayer(d)
return nil
}
// DecodeFromBytes analyses a byte slice and attempts to decode it as a BFD
// control packet.
//
// Upon succeeds, it loads the BFD object with information about the packet
// and returns nil.
// Upon failure, it returns an error (non nil).
func (d *BFD) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
// If the data block is too short to be a BFD record, then return an error.
if len(data) < bfdMinimumRecordSizeInBytes {
df.SetTruncated()
return errors.New("BFD packet too short")
}
pLen := uint8(data[3])
if len(data) != int(pLen) {
return errors.New("BFD packet length does not match")
}
// BFD type embeds type BaseLayer which contains two fields:
// Contents is supposed to contain the bytes of the data at this level.
// Payload is supposed to contain the payload of this level.
// Here we set the baselayer to be the bytes of the BFD record.
d.BaseLayer = BaseLayer{Contents: data[:len(data)]}
// Extract the fields from the block of bytes.
// To make sense of this, refer to the packet diagram
// above and the section on endian conventions.
// The first few fields are all packed into the first 32 bits. Unpack them.
d.Version = BFDVersion(((data[0] & 0xE0) >> 5))
d.Diagnostic = BFDDiagnostic(data[0] & 0x1F)
data = data[1:]
d.State = BFDState((data[0] & 0xC0) >> 6)
d.Poll = data[0]&0x20 != 0
d.Final = data[0]&0x10 != 0
d.ControlPlaneIndependent = data[0]&0x08 != 0
d.AuthPresent = data[0]&0x04 != 0
d.Demand = data[0]&0x02 != 0
d.Multipoint = data[0]&0x01 != 0
data = data[1:]
data, d.DetectMultiplier = data[1:], BFDDetectMultiplier(data[0])
data, _ = data[1:], uint8(data[0]) // Consume length
// The remaining fields can just be copied in big endian order.
data, d.MyDiscriminator = data[4:], BFDDiscriminator(binary.BigEndian.Uint32(data[:4]))
data, d.YourDiscriminator = data[4:], BFDDiscriminator(binary.BigEndian.Uint32(data[:4]))
data, d.DesiredMinTxInterval = data[4:], BFDTimeInterval(binary.BigEndian.Uint32(data[:4]))
data, d.RequiredMinRxInterval = data[4:], BFDTimeInterval(binary.BigEndian.Uint32(data[:4]))
data, d.RequiredMinEchoRxInterval = data[4:], BFDTimeInterval(binary.BigEndian.Uint32(data[:4]))
if d.AuthPresent && (len(data) > 2) {
d.AuthHeader = &BFDAuthHeader{}
data, d.AuthHeader.AuthType = data[1:], BFDAuthType(data[0])
data, _ = data[1:], uint8(data[0]) // Consume length
data, d.AuthHeader.KeyID = data[1:], BFDAuthKeyID(data[0])
switch d.AuthHeader.AuthType {
case BFDAuthTypePassword:
d.AuthHeader.Data = BFDAuthData(data)
case BFDAuthTypeKeyedMD5, BFDAuthTypeMeticulousKeyedMD5:
// Skipped reserved byte
data, d.AuthHeader.SequenceNumber = data[5:], BFDAuthSequenceNumber(binary.BigEndian.Uint32(data[1:5]))
d.AuthHeader.Data = BFDAuthData(data)
case BFDAuthTypeKeyedSHA1, BFDAuthTypeMeticulousKeyedSHA1:
// Skipped reserved byte
data, d.AuthHeader.SequenceNumber = data[5:], BFDAuthSequenceNumber(binary.BigEndian.Uint32(data[1:5]))
d.AuthHeader.Data = BFDAuthData(data)
}
}
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (d *BFD) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
data, err := b.PrependBytes(bfdMinimumRecordSizeInBytes)
if err != nil {
return err
}
// Pack the first few fields into the first 32 bits.
data[0] = byte(byte(d.Version<<5) | byte(d.Diagnostic))
h := uint8(0)
h |= (uint8(d.State) << 6)
h |= (uint8(bool2uint8(d.Poll)) << 5)
h |= (uint8(bool2uint8(d.Final)) << 4)
h |= (uint8(bool2uint8(d.ControlPlaneIndependent)) << 3)
h |= (uint8(bool2uint8(d.AuthPresent)) << 2)
h |= (uint8(bool2uint8(d.Demand)) << 1)
h |= uint8(bool2uint8(d.Multipoint))
data[1] = byte(h)
data[2] = byte(d.DetectMultiplier)
data[3] = byte(d.Length())
// The remaining fields can just be copied in big endian order.
binary.BigEndian.PutUint32(data[4:], uint32(d.MyDiscriminator))
binary.BigEndian.PutUint32(data[8:], uint32(d.YourDiscriminator))
binary.BigEndian.PutUint32(data[12:], uint32(d.DesiredMinTxInterval))
binary.BigEndian.PutUint32(data[16:], uint32(d.RequiredMinRxInterval))
binary.BigEndian.PutUint32(data[20:], uint32(d.RequiredMinEchoRxInterval))
if d.AuthPresent && (d.AuthHeader != nil) {
auth, err := b.AppendBytes(int(d.AuthHeader.Length()))
if err != nil {
return err
}
auth[0] = byte(d.AuthHeader.AuthType)
auth[1] = byte(d.AuthHeader.Length())
auth[2] = byte(d.AuthHeader.KeyID)
switch d.AuthHeader.AuthType {
case BFDAuthTypePassword:
copy(auth[3:], d.AuthHeader.Data)
case BFDAuthTypeKeyedMD5, BFDAuthTypeMeticulousKeyedMD5:
auth[3] = byte(0)
binary.BigEndian.PutUint32(auth[4:], uint32(d.AuthHeader.SequenceNumber))
copy(auth[8:], d.AuthHeader.Data)
case BFDAuthTypeKeyedSHA1, BFDAuthTypeMeticulousKeyedSHA1:
auth[3] = byte(0)
binary.BigEndian.PutUint32(auth[4:], uint32(d.AuthHeader.SequenceNumber))
copy(auth[8:], d.AuthHeader.Data)
}
}
return nil
}
// CanDecode returns a set of layers that BFD objects can decode.
// As BFD objects can only decide the BFD layer, we can return just that layer.
// Apparently a single layer type implements LayerClass.
func (d *BFD) CanDecode() gopacket.LayerClass {
return LayerTypeBFD
}
// NextLayerType specifies the next layer that GoPacket should attempt to
// analyse after this (BFD) layer. As BFD packets do not contain any payload
// bytes, there are no further layers to analyse.
func (d *BFD) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypeZero
}
// Payload returns an empty byte slice as BFD packets do not carry a payload
func (d *BFD) Payload() []byte {
return nil
}
// bool2uint8 converts a bool to uint8
func bool2uint8(b bool) uint8 {
if b {
return 1
}
return 0
}
// Copyright 2021 The GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file in the root of the source tree.
package layers
type bitfield [1024]uint64
// set sets bit i in bitfield b to 1.
func (b *bitfield) set(i uint16) {
b[i>>6] |= (1 << (i & 0x3f))
}
// has reports whether bit i is set to 1 in bitfield b.
func (b *bitfield) has(i uint16) bool {
return b[i>>6]&(1<<(i&0x3f)) != 0
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
// Enum types courtesy of...
// http://search.cpan.org/~mchapman/Net-CDP-0.09/lib/Net/CDP.pm
// https://code.google.com/p/ladvd/
// http://anonsvn.wireshark.org/viewvc/releases/wireshark-1.8.6/epan/dissectors/packet-cdp.c
package layers
import (
"encoding/binary"
"errors"
"fmt"
"net"
"github.com/google/gopacket"
)
// CDPTLVType is the type of each TLV value in a CiscoDiscovery packet.
type CDPTLVType uint16
// CDPTLVType values.
const (
CDPTLVDevID CDPTLVType = 0x0001
CDPTLVAddress CDPTLVType = 0x0002
CDPTLVPortID CDPTLVType = 0x0003
CDPTLVCapabilities CDPTLVType = 0x0004
CDPTLVVersion CDPTLVType = 0x0005
CDPTLVPlatform CDPTLVType = 0x0006
CDPTLVIPPrefix CDPTLVType = 0x0007
CDPTLVHello CDPTLVType = 0x0008
CDPTLVVTPDomain CDPTLVType = 0x0009
CDPTLVNativeVLAN CDPTLVType = 0x000a
CDPTLVFullDuplex CDPTLVType = 0x000b
CDPTLVVLANReply CDPTLVType = 0x000e
CDPTLVVLANQuery CDPTLVType = 0x000f
CDPTLVPower CDPTLVType = 0x0010
CDPTLVMTU CDPTLVType = 0x0011
CDPTLVExtendedTrust CDPTLVType = 0x0012
CDPTLVUntrustedCOS CDPTLVType = 0x0013
CDPTLVSysName CDPTLVType = 0x0014
CDPTLVSysOID CDPTLVType = 0x0015
CDPTLVMgmtAddresses CDPTLVType = 0x0016
CDPTLVLocation CDPTLVType = 0x0017
CDPTLVExternalPortID CDPTLVType = 0x0018
CDPTLVPowerRequested CDPTLVType = 0x0019
CDPTLVPowerAvailable CDPTLVType = 0x001a
CDPTLVPortUnidirectional CDPTLVType = 0x001b
CDPTLVEnergyWise CDPTLVType = 0x001d
CDPTLVSparePairPOE CDPTLVType = 0x001f
)
// CiscoDiscoveryValue is a TLV value inside a CiscoDiscovery packet layer.
type CiscoDiscoveryValue struct {
Type CDPTLVType
Length uint16
Value []byte
}
// CiscoDiscovery is a packet layer containing the Cisco Discovery Protocol.
// See http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm#31885
type CiscoDiscovery struct {
BaseLayer
Version byte
TTL byte
Checksum uint16
Values []CiscoDiscoveryValue
}
// CDPCapability is the set of capabilities advertised by a CDP device.
type CDPCapability uint32
// CDPCapability values.
const (
CDPCapMaskRouter CDPCapability = 0x0001
CDPCapMaskTBBridge CDPCapability = 0x0002
CDPCapMaskSPBridge CDPCapability = 0x0004
CDPCapMaskSwitch CDPCapability = 0x0008
CDPCapMaskHost CDPCapability = 0x0010
CDPCapMaskIGMPFilter CDPCapability = 0x0020
CDPCapMaskRepeater CDPCapability = 0x0040
CDPCapMaskPhone CDPCapability = 0x0080
CDPCapMaskRemote CDPCapability = 0x0100
)
// CDPCapabilities represents the capabilities of a device
type CDPCapabilities struct {
L3Router bool
TBBridge bool
SPBridge bool
L2Switch bool
IsHost bool
IGMPFilter bool
L1Repeater bool
IsPhone bool
RemotelyManaged bool
}
// CDP Power-over-Ethernet values.
const (
CDPPoEFourWire byte = 0x01
CDPPoEPDArch byte = 0x02
CDPPoEPDRequest byte = 0x04
CDPPoEPSE byte = 0x08
)
// CDPSparePairPoE provides information on PoE.
type CDPSparePairPoE struct {
PSEFourWire bool // Supported / Not supported
PDArchShared bool // Shared / Independent
PDRequestOn bool // On / Off
PSEOn bool // On / Off
}
// CDPVLANDialogue encapsulates a VLAN Query/Reply
type CDPVLANDialogue struct {
ID uint8
VLAN uint16
}
// CDPPowerDialogue encapsulates a Power Query/Reply
type CDPPowerDialogue struct {
ID uint16
MgmtID uint16
Values []uint32
}
// CDPLocation provides location information for a CDP device.
type CDPLocation struct {
Type uint8 // Undocumented
Location string
}
// CDPHello is a Cisco Hello message (undocumented, hence the "Unknown" fields)
type CDPHello struct {
OUI []byte
ProtocolID uint16
ClusterMaster net.IP
Unknown1 net.IP
Version byte
SubVersion byte
Status byte
Unknown2 byte
ClusterCommander net.HardwareAddr
SwitchMAC net.HardwareAddr
Unknown3 byte
ManagementVLAN uint16
}
// CDPEnergyWiseSubtype is used within CDP to define TLV values.
type CDPEnergyWiseSubtype uint32
// CDPEnergyWiseSubtype values.
const (
CDPEnergyWiseRole CDPEnergyWiseSubtype = 0x00000007
CDPEnergyWiseDomain CDPEnergyWiseSubtype = 0x00000008
CDPEnergyWiseName CDPEnergyWiseSubtype = 0x00000009
CDPEnergyWiseReplyTo CDPEnergyWiseSubtype = 0x00000017
)
// CDPEnergyWise is used by CDP to monitor and control power usage.
type CDPEnergyWise struct {
EncryptedData []byte
Unknown1 uint32
SequenceNumber uint32
ModelNumber string
Unknown2 uint16
HardwareID string
SerialNum string
Unknown3 []byte
Role string
Domain string
Name string
ReplyUnknown1 []byte
ReplyPort []byte
ReplyAddress []byte
ReplyUnknown2 []byte
ReplyUnknown3 []byte
}
// CiscoDiscoveryInfo represents the decoded details for a set of CiscoDiscoveryValues
type CiscoDiscoveryInfo struct {
BaseLayer
CDPHello
DeviceID string
Addresses []net.IP
PortID string
Capabilities CDPCapabilities
Version string
Platform string
IPPrefixes []net.IPNet
VTPDomain string
NativeVLAN uint16
FullDuplex bool
VLANReply CDPVLANDialogue
VLANQuery CDPVLANDialogue
PowerConsumption uint16
MTU uint32
ExtendedTrust uint8
UntrustedCOS uint8
SysName string
SysOID string
MgmtAddresses []net.IP
Location CDPLocation
PowerRequest CDPPowerDialogue
PowerAvailable CDPPowerDialogue
SparePairPoe CDPSparePairPoE
EnergyWise CDPEnergyWise
Unknown []CiscoDiscoveryValue
}
// LayerType returns gopacket.LayerTypeCiscoDiscovery.
func (c *CiscoDiscovery) LayerType() gopacket.LayerType {
return LayerTypeCiscoDiscovery
}
func decodeCiscoDiscovery(data []byte, p gopacket.PacketBuilder) error {
c := &CiscoDiscovery{
Version: data[0],
TTL: data[1],
Checksum: binary.BigEndian.Uint16(data[2:4]),
}
if c.Version != 1 && c.Version != 2 {
return fmt.Errorf("Invalid CiscoDiscovery version number %d", c.Version)
}
var err error
c.Values, err = decodeCiscoDiscoveryTLVs(data[4:], p)
if err != nil {
return err
}
c.Contents = data[0:4]
c.Payload = data[4:]
p.AddLayer(c)
return p.NextDecoder(gopacket.DecodeFunc(decodeCiscoDiscoveryInfo))
}
// LayerType returns gopacket.LayerTypeCiscoDiscoveryInfo.
func (c *CiscoDiscoveryInfo) LayerType() gopacket.LayerType {
return LayerTypeCiscoDiscoveryInfo
}
func decodeCiscoDiscoveryTLVs(data []byte, p gopacket.PacketBuilder) (values []CiscoDiscoveryValue, err error) {
for len(data) > 0 {
if len(data) < 4 {
p.SetTruncated()
return nil, errors.New("CDP TLV < 4 bytes")
}
val := CiscoDiscoveryValue{
Type: CDPTLVType(binary.BigEndian.Uint16(data[:2])),
Length: binary.BigEndian.Uint16(data[2:4]),
}
if val.Length < 4 {
err = fmt.Errorf("Invalid CiscoDiscovery value length %d", val.Length)
break
} else if len(data) < int(val.Length) {
p.SetTruncated()
return nil, fmt.Errorf("CDP TLV < length %d", val.Length)
}
val.Value = data[4:val.Length]
values = append(values, val)
data = data[val.Length:]
}
return
}
func decodeCiscoDiscoveryInfo(data []byte, p gopacket.PacketBuilder) error {
var err error
info := &CiscoDiscoveryInfo{BaseLayer: BaseLayer{Contents: data}}
p.AddLayer(info)
values, err := decodeCiscoDiscoveryTLVs(data, p)
if err != nil { // Unlikely, as parent decode will fail, but better safe...
return err
}
for _, val := range values {
switch val.Type {
case CDPTLVDevID:
info.DeviceID = string(val.Value)
case CDPTLVAddress:
if err = checkCDPTLVLen(val, 4); err != nil {
return err
}
info.Addresses, err = decodeAddresses(val.Value)
if err != nil {
return err
}
case CDPTLVPortID:
info.PortID = string(val.Value)
case CDPTLVCapabilities:
if err = checkCDPTLVLen(val, 4); err != nil {
return err
}
val := CDPCapability(binary.BigEndian.Uint32(val.Value[0:4]))
info.Capabilities.L3Router = (val&CDPCapMaskRouter > 0)
info.Capabilities.TBBridge = (val&CDPCapMaskTBBridge > 0)
info.Capabilities.SPBridge = (val&CDPCapMaskSPBridge > 0)
info.Capabilities.L2Switch = (val&CDPCapMaskSwitch > 0)
info.Capabilities.IsHost = (val&CDPCapMaskHost > 0)
info.Capabilities.IGMPFilter = (val&CDPCapMaskIGMPFilter > 0)
info.Capabilities.L1Repeater = (val&CDPCapMaskRepeater > 0)
info.Capabilities.IsPhone = (val&CDPCapMaskPhone > 0)
info.Capabilities.RemotelyManaged = (val&CDPCapMaskRemote > 0)
case CDPTLVVersion:
info.Version = string(val.Value)
case CDPTLVPlatform:
info.Platform = string(val.Value)
case CDPTLVIPPrefix:
v := val.Value
l := len(v)
if l%5 == 0 && l >= 5 {
for len(v) > 0 {
_, ipnet, _ := net.ParseCIDR(fmt.Sprintf("%d.%d.%d.%d/%d", v[0], v[1], v[2], v[3], v[4]))
info.IPPrefixes = append(info.IPPrefixes, *ipnet)
v = v[5:]
}
} else {
return fmt.Errorf("Invalid TLV %v length %d", val.Type, len(val.Value))
}
case CDPTLVHello:
if err = checkCDPTLVLen(val, 32); err != nil {
return err
}
v := val.Value
info.CDPHello.OUI = v[0:3]
info.CDPHello.ProtocolID = binary.BigEndian.Uint16(v[3:5])
info.CDPHello.ClusterMaster = v[5:9]
info.CDPHello.Unknown1 = v[9:13]
info.CDPHello.Version = v[13]
info.CDPHello.SubVersion = v[14]
info.CDPHello.Status = v[15]
info.CDPHello.Unknown2 = v[16]
info.CDPHello.ClusterCommander = v[17:23]
info.CDPHello.SwitchMAC = v[23:29]
info.CDPHello.Unknown3 = v[29]
info.CDPHello.ManagementVLAN = binary.BigEndian.Uint16(v[30:32])
case CDPTLVVTPDomain:
info.VTPDomain = string(val.Value)
case CDPTLVNativeVLAN:
if err = checkCDPTLVLen(val, 2); err != nil {
return err
}
info.NativeVLAN = binary.BigEndian.Uint16(val.Value[0:2])
case CDPTLVFullDuplex:
if err = checkCDPTLVLen(val, 1); err != nil {
return err
}
info.FullDuplex = (val.Value[0] == 1)
case CDPTLVVLANReply:
if err = checkCDPTLVLen(val, 3); err != nil {
return err
}
info.VLANReply.ID = uint8(val.Value[0])
info.VLANReply.VLAN = binary.BigEndian.Uint16(val.Value[1:3])
case CDPTLVVLANQuery:
if err = checkCDPTLVLen(val, 3); err != nil {
return err
}
info.VLANQuery.ID = uint8(val.Value[0])
info.VLANQuery.VLAN = binary.BigEndian.Uint16(val.Value[1:3])
case CDPTLVPower:
if err = checkCDPTLVLen(val, 2); err != nil {
return err
}
info.PowerConsumption = binary.BigEndian.Uint16(val.Value[0:2])
case CDPTLVMTU:
if err = checkCDPTLVLen(val, 4); err != nil {
return err
}
info.MTU = binary.BigEndian.Uint32(val.Value[0:4])
case CDPTLVExtendedTrust:
if err = checkCDPTLVLen(val, 1); err != nil {
return err
}
info.ExtendedTrust = uint8(val.Value[0])
case CDPTLVUntrustedCOS:
if err = checkCDPTLVLen(val, 1); err != nil {
return err
}
info.UntrustedCOS = uint8(val.Value[0])
case CDPTLVSysName:
info.SysName = string(val.Value)
case CDPTLVSysOID:
info.SysOID = string(val.Value)
case CDPTLVMgmtAddresses:
if err = checkCDPTLVLen(val, 4); err != nil {
return err
}
info.MgmtAddresses, err = decodeAddresses(val.Value)
if err != nil {
return err
}
case CDPTLVLocation:
if err = checkCDPTLVLen(val, 2); err != nil {
return err
}
info.Location.Type = uint8(val.Value[0])
info.Location.Location = string(val.Value[1:])
// case CDPTLVLExternalPortID:
// Undocumented
case CDPTLVPowerRequested:
if err = checkCDPTLVLen(val, 4); err != nil {
return err
}
info.PowerRequest.ID = binary.BigEndian.Uint16(val.Value[0:2])
info.PowerRequest.MgmtID = binary.BigEndian.Uint16(val.Value[2:4])
for n := 4; n < len(val.Value); n += 4 {
info.PowerRequest.Values = append(info.PowerRequest.Values, binary.BigEndian.Uint32(val.Value[n:n+4]))
}
case CDPTLVPowerAvailable:
if err = checkCDPTLVLen(val, 4); err != nil {
return err
}
info.PowerAvailable.ID = binary.BigEndian.Uint16(val.Value[0:2])
info.PowerAvailable.MgmtID = binary.BigEndian.Uint16(val.Value[2:4])
for n := 4; n < len(val.Value); n += 4 {
info.PowerAvailable.Values = append(info.PowerAvailable.Values, binary.BigEndian.Uint32(val.Value[n:n+4]))
}
// case CDPTLVPortUnidirectional
// Undocumented
case CDPTLVEnergyWise:
if err = checkCDPTLVLen(val, 72); err != nil {
return err
}
info.EnergyWise.EncryptedData = val.Value[0:20]
info.EnergyWise.Unknown1 = binary.BigEndian.Uint32(val.Value[20:24])
info.EnergyWise.SequenceNumber = binary.BigEndian.Uint32(val.Value[24:28])
info.EnergyWise.ModelNumber = string(val.Value[28:44])
info.EnergyWise.Unknown2 = binary.BigEndian.Uint16(val.Value[44:46])
info.EnergyWise.HardwareID = string(val.Value[46:49])
info.EnergyWise.SerialNum = string(val.Value[49:60])
info.EnergyWise.Unknown3 = val.Value[60:68]
tlvLen := binary.BigEndian.Uint16(val.Value[68:70])
tlvNum := binary.BigEndian.Uint16(val.Value[70:72])
data := val.Value[72:]
if len(data) < int(tlvLen) {
return fmt.Errorf("Invalid TLV length %d vs %d", tlvLen, len(data))
}
numSeen := 0
for len(data) > 8 {
numSeen++
if numSeen > int(tlvNum) { // Too many TLV's ?
return fmt.Errorf("Too many TLV's - wanted %d, saw %d", tlvNum, numSeen)
}
tType := CDPEnergyWiseSubtype(binary.BigEndian.Uint32(data[0:4]))
tLen := int(binary.BigEndian.Uint32(data[4:8]))
if tLen > len(data)-8 {
return fmt.Errorf("Invalid TLV length %d vs %d", tLen, len(data)-8)
}
data = data[8:]
switch tType {
case CDPEnergyWiseRole:
info.EnergyWise.Role = string(data[:])
case CDPEnergyWiseDomain:
info.EnergyWise.Domain = string(data[:])
case CDPEnergyWiseName:
info.EnergyWise.Name = string(data[:])
case CDPEnergyWiseReplyTo:
if len(data) >= 18 {
info.EnergyWise.ReplyUnknown1 = data[0:2]
info.EnergyWise.ReplyPort = data[2:4]
info.EnergyWise.ReplyAddress = data[4:8]
info.EnergyWise.ReplyUnknown2 = data[8:10]
info.EnergyWise.ReplyUnknown3 = data[10:14]
}
}
data = data[tLen:]
}
case CDPTLVSparePairPOE:
if err = checkCDPTLVLen(val, 1); err != nil {
return err
}
v := val.Value[0]
info.SparePairPoe.PSEFourWire = (v&CDPPoEFourWire > 0)
info.SparePairPoe.PDArchShared = (v&CDPPoEPDArch > 0)
info.SparePairPoe.PDRequestOn = (v&CDPPoEPDRequest > 0)
info.SparePairPoe.PSEOn = (v&CDPPoEPSE > 0)
default:
info.Unknown = append(info.Unknown, val)
}
}
return nil
}
// CDP Protocol Types
const (
CDPProtocolTypeNLPID byte = 1
CDPProtocolType802_2 byte = 2
)
// CDPAddressType is used to define TLV values within CDP addresses.
type CDPAddressType uint64
// CDP Address types.
const (
CDPAddressTypeCLNP CDPAddressType = 0x81
CDPAddressTypeIPV4 CDPAddressType = 0xcc
CDPAddressTypeIPV6 CDPAddressType = 0xaaaa030000000800
CDPAddressTypeDECNET CDPAddressType = 0xaaaa030000006003
CDPAddressTypeAPPLETALK CDPAddressType = 0xaaaa03000000809b
CDPAddressTypeIPX CDPAddressType = 0xaaaa030000008137
CDPAddressTypeVINES CDPAddressType = 0xaaaa0300000080c4
CDPAddressTypeXNS CDPAddressType = 0xaaaa030000000600
CDPAddressTypeAPOLLO CDPAddressType = 0xaaaa030000008019
)
func decodeAddresses(v []byte) (addresses []net.IP, err error) {
numaddr := int(binary.BigEndian.Uint32(v[0:4]))
if numaddr < 1 {
return nil, fmt.Errorf("Invalid Address TLV number %d", numaddr)
}
v = v[4:]
if len(v) < numaddr*8 {
return nil, fmt.Errorf("Invalid Address TLV length %d", len(v))
}
for i := 0; i < numaddr; i++ {
prottype := v[0]
if prottype != CDPProtocolTypeNLPID && prottype != CDPProtocolType802_2 { // invalid protocol type
return nil, fmt.Errorf("Invalid Address Protocol %d", prottype)
}
protlen := int(v[1])
if (prottype == CDPProtocolTypeNLPID && protlen != 1) ||
(prottype == CDPProtocolType802_2 && protlen != 3 && protlen != 8) { // invalid length
return nil, fmt.Errorf("Invalid Address Protocol length %d", protlen)
}
plen := make([]byte, 8)
copy(plen[8-protlen:], v[2:2+protlen])
protocol := CDPAddressType(binary.BigEndian.Uint64(plen))
v = v[2+protlen:]
addrlen := binary.BigEndian.Uint16(v[0:2])
ab := v[2 : 2+addrlen]
if protocol == CDPAddressTypeIPV4 && addrlen == 4 {
addresses = append(addresses, net.IPv4(ab[0], ab[1], ab[2], ab[3]))
} else if protocol == CDPAddressTypeIPV6 && addrlen == 16 {
addresses = append(addresses, net.IP(ab))
} else {
// only handle IPV4 & IPV6 for now
}
v = v[2+addrlen:]
if len(v) < 8 {
break
}
}
return
}
func (t CDPTLVType) String() (s string) {
switch t {
case CDPTLVDevID:
s = "Device ID"
case CDPTLVAddress:
s = "Addresses"
case CDPTLVPortID:
s = "Port ID"
case CDPTLVCapabilities:
s = "Capabilities"
case CDPTLVVersion:
s = "Software Version"
case CDPTLVPlatform:
s = "Platform"
case CDPTLVIPPrefix:
s = "IP Prefix"
case CDPTLVHello:
s = "Protocol Hello"
case CDPTLVVTPDomain:
s = "VTP Management Domain"
case CDPTLVNativeVLAN:
s = "Native VLAN"
case CDPTLVFullDuplex:
s = "Full Duplex"
case CDPTLVVLANReply:
s = "VoIP VLAN Reply"
case CDPTLVVLANQuery:
s = "VLANQuery"
case CDPTLVPower:
s = "Power consumption"
case CDPTLVMTU:
s = "MTU"
case CDPTLVExtendedTrust:
s = "Extended Trust Bitmap"
case CDPTLVUntrustedCOS:
s = "Untrusted Port CoS"
case CDPTLVSysName:
s = "System Name"
case CDPTLVSysOID:
s = "System OID"
case CDPTLVMgmtAddresses:
s = "Management Addresses"
case CDPTLVLocation:
s = "Location"
case CDPTLVExternalPortID:
s = "External Port ID"
case CDPTLVPowerRequested:
s = "Power Requested"
case CDPTLVPowerAvailable:
s = "Power Available"
case CDPTLVPortUnidirectional:
s = "Port Unidirectional"
case CDPTLVEnergyWise:
s = "Energy Wise"
case CDPTLVSparePairPOE:
s = "Spare Pair POE"
default:
s = "Unknown"
}
return
}
func (a CDPAddressType) String() (s string) {
switch a {
case CDPAddressTypeCLNP:
s = "Connectionless Network Protocol"
case CDPAddressTypeIPV4:
s = "IPv4"
case CDPAddressTypeIPV6:
s = "IPv6"
case CDPAddressTypeDECNET:
s = "DECnet Phase IV"
case CDPAddressTypeAPPLETALK:
s = "Apple Talk"
case CDPAddressTypeIPX:
s = "Novell IPX"
case CDPAddressTypeVINES:
s = "Banyan VINES"
case CDPAddressTypeXNS:
s = "Xerox Network Systems"
case CDPAddressTypeAPOLLO:
s = "Apollo"
default:
s = "Unknown"
}
return
}
func (t CDPEnergyWiseSubtype) String() (s string) {
switch t {
case CDPEnergyWiseRole:
s = "Role"
case CDPEnergyWiseDomain:
s = "Domain"
case CDPEnergyWiseName:
s = "Name"
case CDPEnergyWiseReplyTo:
s = "ReplyTo"
default:
s = "Unknown"
}
return
}
func checkCDPTLVLen(v CiscoDiscoveryValue, l int) (err error) {
if len(v.Value) < l {
err = fmt.Errorf("Invalid TLV %v length %d", v.Type, len(v.Value))
}
return
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"fmt"
"github.com/google/gopacket"
)
// EthernetCTPFunction is the function code used by the EthernetCTP protocol to identify each
// EthernetCTP layer.
type EthernetCTPFunction uint16
// EthernetCTPFunction values.
const (
EthernetCTPFunctionReply EthernetCTPFunction = 1
EthernetCTPFunctionForwardData EthernetCTPFunction = 2
)
// EthernetCTP implements the EthernetCTP protocol, see http://www.mit.edu/people/jhawk/ctp.html.
// We split EthernetCTP up into the top-level EthernetCTP layer, followed by zero or more
// EthernetCTPForwardData layers, followed by a final EthernetCTPReply layer.
type EthernetCTP struct {
BaseLayer
SkipCount uint16
}
// LayerType returns gopacket.LayerTypeEthernetCTP.
func (c *EthernetCTP) LayerType() gopacket.LayerType {
return LayerTypeEthernetCTP
}
// EthernetCTPForwardData is the ForwardData layer inside EthernetCTP. See EthernetCTP's docs for more
// details.
type EthernetCTPForwardData struct {
BaseLayer
Function EthernetCTPFunction
ForwardAddress []byte
}
// LayerType returns gopacket.LayerTypeEthernetCTPForwardData.
func (c *EthernetCTPForwardData) LayerType() gopacket.LayerType {
return LayerTypeEthernetCTPForwardData
}
// ForwardEndpoint returns the EthernetCTPForwardData ForwardAddress as an endpoint.
func (c *EthernetCTPForwardData) ForwardEndpoint() gopacket.Endpoint {
return gopacket.NewEndpoint(EndpointMAC, c.ForwardAddress)
}
// EthernetCTPReply is the Reply layer inside EthernetCTP. See EthernetCTP's docs for more details.
type EthernetCTPReply struct {
BaseLayer
Function EthernetCTPFunction
ReceiptNumber uint16
Data []byte
}
// LayerType returns gopacket.LayerTypeEthernetCTPReply.
func (c *EthernetCTPReply) LayerType() gopacket.LayerType {
return LayerTypeEthernetCTPReply
}
// Payload returns the EthernetCTP reply's Data bytes.
func (c *EthernetCTPReply) Payload() []byte { return c.Data }
func decodeEthernetCTP(data []byte, p gopacket.PacketBuilder) error {
c := &EthernetCTP{
SkipCount: binary.LittleEndian.Uint16(data[:2]),
BaseLayer: BaseLayer{data[:2], data[2:]},
}
if c.SkipCount%2 != 0 {
return fmt.Errorf("EthernetCTP skip count is odd: %d", c.SkipCount)
}
p.AddLayer(c)
return p.NextDecoder(gopacket.DecodeFunc(decodeEthernetCTPFromFunctionType))
}
// decodeEthernetCTPFromFunctionType reads in the first 2 bytes to determine the EthernetCTP
// layer type to decode next, then decodes based on that.
func decodeEthernetCTPFromFunctionType(data []byte, p gopacket.PacketBuilder) error {
function := EthernetCTPFunction(binary.LittleEndian.Uint16(data[:2]))
switch function {
case EthernetCTPFunctionReply:
reply := &EthernetCTPReply{
Function: function,
ReceiptNumber: binary.LittleEndian.Uint16(data[2:4]),
Data: data[4:],
BaseLayer: BaseLayer{data, nil},
}
p.AddLayer(reply)
p.SetApplicationLayer(reply)
return nil
case EthernetCTPFunctionForwardData:
forward := &EthernetCTPForwardData{
Function: function,
ForwardAddress: data[2:8],
BaseLayer: BaseLayer{data[:8], data[8:]},
}
p.AddLayer(forward)
return p.NextDecoder(gopacket.DecodeFunc(decodeEthernetCTPFromFunctionType))
}
return fmt.Errorf("Unknown EthernetCTP function type %v", function)
}
// Copyright 2016 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"bytes"
"encoding/binary"
"fmt"
"net"
"github.com/google/gopacket"
)
// DHCPOp rerprents a bootp operation
type DHCPOp byte
// bootp operations
const (
DHCPOpRequest DHCPOp = 1
DHCPOpReply DHCPOp = 2
)
// String returns a string version of a DHCPOp.
func (o DHCPOp) String() string {
switch o {
case DHCPOpRequest:
return "Request"
case DHCPOpReply:
return "Reply"
default:
return "Unknown"
}
}
// DHCPMsgType represents a DHCP operation
type DHCPMsgType byte
// Constants that represent DHCP operations
const (
DHCPMsgTypeUnspecified DHCPMsgType = iota
DHCPMsgTypeDiscover
DHCPMsgTypeOffer
DHCPMsgTypeRequest
DHCPMsgTypeDecline
DHCPMsgTypeAck
DHCPMsgTypeNak
DHCPMsgTypeRelease
DHCPMsgTypeInform
)
// String returns a string version of a DHCPMsgType.
func (o DHCPMsgType) String() string {
switch o {
case DHCPMsgTypeUnspecified:
return "Unspecified"
case DHCPMsgTypeDiscover:
return "Discover"
case DHCPMsgTypeOffer:
return "Offer"
case DHCPMsgTypeRequest:
return "Request"
case DHCPMsgTypeDecline:
return "Decline"
case DHCPMsgTypeAck:
return "Ack"
case DHCPMsgTypeNak:
return "Nak"
case DHCPMsgTypeRelease:
return "Release"
case DHCPMsgTypeInform:
return "Inform"
default:
return "Unknown"
}
}
//DHCPMagic is the RFC 2131 "magic cooke" for DHCP.
var DHCPMagic uint32 = 0x63825363
// DHCPv4 contains data for a single DHCP packet.
type DHCPv4 struct {
BaseLayer
Operation DHCPOp
HardwareType LinkType
HardwareLen uint8
HardwareOpts uint8
Xid uint32
Secs uint16
Flags uint16
ClientIP net.IP
YourClientIP net.IP
NextServerIP net.IP
RelayAgentIP net.IP
ClientHWAddr net.HardwareAddr
ServerName []byte
File []byte
Options DHCPOptions
}
// DHCPOptions is used to get nicely printed option lists which would normally
// be cut off after 5 options.
type DHCPOptions []DHCPOption
// String returns a string version of the options list.
func (o DHCPOptions) String() string {
buf := &bytes.Buffer{}
buf.WriteByte('[')
for i, opt := range o {
buf.WriteString(opt.String())
if i+1 != len(o) {
buf.WriteString(", ")
}
}
buf.WriteByte(']')
return buf.String()
}
// LayerType returns gopacket.LayerTypeDHCPv4
func (d *DHCPv4) LayerType() gopacket.LayerType { return LayerTypeDHCPv4 }
// DecodeFromBytes decodes the given bytes into this layer.
func (d *DHCPv4) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 240 {
df.SetTruncated()
return fmt.Errorf("DHCPv4 length %d too short", len(data))
}
d.Options = d.Options[:0]
d.Operation = DHCPOp(data[0])
d.HardwareType = LinkType(data[1])
d.HardwareLen = data[2]
d.HardwareOpts = data[3]
d.Xid = binary.BigEndian.Uint32(data[4:8])
d.Secs = binary.BigEndian.Uint16(data[8:10])
d.Flags = binary.BigEndian.Uint16(data[10:12])
d.ClientIP = net.IP(data[12:16])
d.YourClientIP = net.IP(data[16:20])
d.NextServerIP = net.IP(data[20:24])
d.RelayAgentIP = net.IP(data[24:28])
d.ClientHWAddr = net.HardwareAddr(data[28 : 28+d.HardwareLen])
d.ServerName = data[44:108]
d.File = data[108:236]
if binary.BigEndian.Uint32(data[236:240]) != DHCPMagic {
return InvalidMagicCookie
}
if len(data) <= 240 {
// DHCP Packet could have no option (??)
return nil
}
options := data[240:]
stop := len(options)
start := 0
for start < stop {
o := DHCPOption{}
if err := o.decode(options[start:]); err != nil {
return err
}
if o.Type == DHCPOptEnd {
break
}
d.Options = append(d.Options, o)
// Check if the option is a single byte pad
if o.Type == DHCPOptPad {
start++
} else {
start += int(o.Length) + 2
}
}
d.Contents = data
return nil
}
// Len returns the length of a DHCPv4 packet.
func (d *DHCPv4) Len() uint16 {
n := uint16(240)
for _, o := range d.Options {
if o.Type == DHCPOptPad {
n++
} else {
n += uint16(o.Length) + 2
}
}
n++ // for opt end
return n
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (d *DHCPv4) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
plen := int(d.Len())
data, err := b.PrependBytes(plen)
if err != nil {
return err
}
data[0] = byte(d.Operation)
data[1] = byte(d.HardwareType)
if opts.FixLengths {
d.HardwareLen = uint8(len(d.ClientHWAddr))
}
data[2] = d.HardwareLen
data[3] = d.HardwareOpts
binary.BigEndian.PutUint32(data[4:8], d.Xid)
binary.BigEndian.PutUint16(data[8:10], d.Secs)
binary.BigEndian.PutUint16(data[10:12], d.Flags)
copy(data[12:16], d.ClientIP.To4())
copy(data[16:20], d.YourClientIP.To4())
copy(data[20:24], d.NextServerIP.To4())
copy(data[24:28], d.RelayAgentIP.To4())
copy(data[28:44], d.ClientHWAddr)
copy(data[44:108], d.ServerName)
copy(data[108:236], d.File)
binary.BigEndian.PutUint32(data[236:240], DHCPMagic)
if len(d.Options) > 0 {
offset := 240
for _, o := range d.Options {
if err := o.encode(data[offset:]); err != nil {
return err
}
// A pad option is only a single byte
if o.Type == DHCPOptPad {
offset++
} else {
offset += 2 + len(o.Data)
}
}
optend := NewDHCPOption(DHCPOptEnd, nil)
if err := optend.encode(data[offset:]); err != nil {
return err
}
}
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (d *DHCPv4) CanDecode() gopacket.LayerClass {
return LayerTypeDHCPv4
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (d *DHCPv4) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
func decodeDHCPv4(data []byte, p gopacket.PacketBuilder) error {
dhcp := &DHCPv4{}
err := dhcp.DecodeFromBytes(data, p)
if err != nil {
return err
}
p.AddLayer(dhcp)
return p.NextDecoder(gopacket.LayerTypePayload)
}
// DHCPOpt represents a DHCP option or parameter from RFC-2132
type DHCPOpt byte
// Constants for the DHCPOpt options.
const (
DHCPOptPad DHCPOpt = 0
DHCPOptSubnetMask DHCPOpt = 1 // 4, net.IP
DHCPOptTimeOffset DHCPOpt = 2 // 4, int32 (signed seconds from UTC)
DHCPOptRouter DHCPOpt = 3 // n*4, [n]net.IP
DHCPOptTimeServer DHCPOpt = 4 // n*4, [n]net.IP
DHCPOptNameServer DHCPOpt = 5 // n*4, [n]net.IP
DHCPOptDNS DHCPOpt = 6 // n*4, [n]net.IP
DHCPOptLogServer DHCPOpt = 7 // n*4, [n]net.IP
DHCPOptCookieServer DHCPOpt = 8 // n*4, [n]net.IP
DHCPOptLPRServer DHCPOpt = 9 // n*4, [n]net.IP
DHCPOptImpressServer DHCPOpt = 10 // n*4, [n]net.IP
DHCPOptResLocServer DHCPOpt = 11 // n*4, [n]net.IP
DHCPOptHostname DHCPOpt = 12 // n, string
DHCPOptBootfileSize DHCPOpt = 13 // 2, uint16
DHCPOptMeritDumpFile DHCPOpt = 14 // >1, string
DHCPOptDomainName DHCPOpt = 15 // n, string
DHCPOptSwapServer DHCPOpt = 16 // n*4, [n]net.IP
DHCPOptRootPath DHCPOpt = 17 // n, string
DHCPOptExtensionsPath DHCPOpt = 18 // n, string
DHCPOptIPForwarding DHCPOpt = 19 // 1, bool
DHCPOptSourceRouting DHCPOpt = 20 // 1, bool
DHCPOptPolicyFilter DHCPOpt = 21 // 8*n, [n]{net.IP/net.IP}
DHCPOptDatagramMTU DHCPOpt = 22 // 2, uint16
DHCPOptDefaultTTL DHCPOpt = 23 // 1, byte
DHCPOptPathMTUAgingTimeout DHCPOpt = 24 // 4, uint32
DHCPOptPathPlateuTableOption DHCPOpt = 25 // 2*n, []uint16
DHCPOptInterfaceMTU DHCPOpt = 26 // 2, uint16
DHCPOptAllSubsLocal DHCPOpt = 27 // 1, bool
DHCPOptBroadcastAddr DHCPOpt = 28 // 4, net.IP
DHCPOptMaskDiscovery DHCPOpt = 29 // 1, bool
DHCPOptMaskSupplier DHCPOpt = 30 // 1, bool
DHCPOptRouterDiscovery DHCPOpt = 31 // 1, bool
DHCPOptSolicitAddr DHCPOpt = 32 // 4, net.IP
DHCPOptStaticRoute DHCPOpt = 33 // n*8, [n]{net.IP/net.IP} -- note the 2nd is router not mask
DHCPOptARPTrailers DHCPOpt = 34 // 1, bool
DHCPOptARPTimeout DHCPOpt = 35 // 4, uint32
DHCPOptEthernetEncap DHCPOpt = 36 // 1, bool
DHCPOptTCPTTL DHCPOpt = 37 // 1, byte
DHCPOptTCPKeepAliveInt DHCPOpt = 38 // 4, uint32
DHCPOptTCPKeepAliveGarbage DHCPOpt = 39 // 1, bool
DHCPOptNISDomain DHCPOpt = 40 // n, string
DHCPOptNISServers DHCPOpt = 41 // 4*n, [n]net.IP
DHCPOptNTPServers DHCPOpt = 42 // 4*n, [n]net.IP
DHCPOptVendorOption DHCPOpt = 43 // n, [n]byte // may be encapsulated.
DHCPOptNetBIOSTCPNS DHCPOpt = 44 // 4*n, [n]net.IP
DHCPOptNetBIOSTCPDDS DHCPOpt = 45 // 4*n, [n]net.IP
DHCPOptNETBIOSTCPNodeType DHCPOpt = 46 // 1, magic byte
DHCPOptNetBIOSTCPScope DHCPOpt = 47 // n, string
DHCPOptXFontServer DHCPOpt = 48 // n, string
DHCPOptXDisplayManager DHCPOpt = 49 // n, string
DHCPOptRequestIP DHCPOpt = 50 // 4, net.IP
DHCPOptLeaseTime DHCPOpt = 51 // 4, uint32
DHCPOptExtOptions DHCPOpt = 52 // 1, 1/2/3
DHCPOptMessageType DHCPOpt = 53 // 1, 1-7
DHCPOptServerID DHCPOpt = 54 // 4, net.IP
DHCPOptParamsRequest DHCPOpt = 55 // n, []byte
DHCPOptMessage DHCPOpt = 56 // n, 3
DHCPOptMaxMessageSize DHCPOpt = 57 // 2, uint16
DHCPOptT1 DHCPOpt = 58 // 4, uint32
DHCPOptT2 DHCPOpt = 59 // 4, uint32
DHCPOptClassID DHCPOpt = 60 // n, []byte
DHCPOptClientID DHCPOpt = 61 // n >= 2, []byte
DHCPOptDomainSearch DHCPOpt = 119 // n, string
DHCPOptSIPServers DHCPOpt = 120 // n, url
DHCPOptClasslessStaticRoute DHCPOpt = 121 //
DHCPOptMUDURLV4 DHCPOpt = 161 // n, string
DHCPOptEnd DHCPOpt = 255
)
// String returns a string version of a DHCPOpt.
func (o DHCPOpt) String() string {
switch o {
case DHCPOptPad:
return "(padding)"
case DHCPOptSubnetMask:
return "SubnetMask"
case DHCPOptTimeOffset:
return "TimeOffset"
case DHCPOptRouter:
return "Router"
case DHCPOptTimeServer:
return "rfc868" // old time server protocol stringified to dissuade confusion w. NTP
case DHCPOptNameServer:
return "ien116" // obscure nameserver protocol stringified to dissuade confusion w. DNS
case DHCPOptDNS:
return "DNS"
case DHCPOptLogServer:
return "mitLCS" // MIT LCS server protocol yada yada w. Syslog
case DHCPOptCookieServer:
return "CookieServer"
case DHCPOptLPRServer:
return "LPRServer"
case DHCPOptImpressServer:
return "ImpressServer"
case DHCPOptResLocServer:
return "ResourceLocationServer"
case DHCPOptHostname:
return "Hostname"
case DHCPOptBootfileSize:
return "BootfileSize"
case DHCPOptMeritDumpFile:
return "MeritDumpFile"
case DHCPOptDomainName:
return "DomainName"
case DHCPOptSwapServer:
return "SwapServer"
case DHCPOptRootPath:
return "RootPath"
case DHCPOptExtensionsPath:
return "ExtensionsPath"
case DHCPOptIPForwarding:
return "IPForwarding"
case DHCPOptSourceRouting:
return "SourceRouting"
case DHCPOptPolicyFilter:
return "PolicyFilter"
case DHCPOptDatagramMTU:
return "DatagramMTU"
case DHCPOptDefaultTTL:
return "DefaultTTL"
case DHCPOptPathMTUAgingTimeout:
return "PathMTUAgingTimeout"
case DHCPOptPathPlateuTableOption:
return "PathPlateuTableOption"
case DHCPOptInterfaceMTU:
return "InterfaceMTU"
case DHCPOptAllSubsLocal:
return "AllSubsLocal"
case DHCPOptBroadcastAddr:
return "BroadcastAddress"
case DHCPOptMaskDiscovery:
return "MaskDiscovery"
case DHCPOptMaskSupplier:
return "MaskSupplier"
case DHCPOptRouterDiscovery:
return "RouterDiscovery"
case DHCPOptSolicitAddr:
return "SolicitAddr"
case DHCPOptStaticRoute:
return "StaticRoute"
case DHCPOptARPTrailers:
return "ARPTrailers"
case DHCPOptARPTimeout:
return "ARPTimeout"
case DHCPOptEthernetEncap:
return "EthernetEncap"
case DHCPOptTCPTTL:
return "TCPTTL"
case DHCPOptTCPKeepAliveInt:
return "TCPKeepAliveInt"
case DHCPOptTCPKeepAliveGarbage:
return "TCPKeepAliveGarbage"
case DHCPOptNISDomain:
return "NISDomain"
case DHCPOptNISServers:
return "NISServers"
case DHCPOptNTPServers:
return "NTPServers"
case DHCPOptVendorOption:
return "VendorOption"
case DHCPOptNetBIOSTCPNS:
return "NetBIOSOverTCPNS"
case DHCPOptNetBIOSTCPDDS:
return "NetBiosOverTCPDDS"
case DHCPOptNETBIOSTCPNodeType:
return "NetBIOSOverTCPNodeType"
case DHCPOptNetBIOSTCPScope:
return "NetBIOSOverTCPScope"
case DHCPOptXFontServer:
return "XFontServer"
case DHCPOptXDisplayManager:
return "XDisplayManager"
case DHCPOptEnd:
return "(end)"
case DHCPOptSIPServers:
return "SipServers"
case DHCPOptRequestIP:
return "RequestIP"
case DHCPOptLeaseTime:
return "LeaseTime"
case DHCPOptExtOptions:
return "ExtOpts"
case DHCPOptMessageType:
return "MessageType"
case DHCPOptServerID:
return "ServerID"
case DHCPOptParamsRequest:
return "ParamsRequest"
case DHCPOptMessage:
return "Message"
case DHCPOptMaxMessageSize:
return "MaxDHCPSize"
case DHCPOptT1:
return "Timer1"
case DHCPOptT2:
return "Timer2"
case DHCPOptClassID:
return "ClassID"
case DHCPOptClientID:
return "ClientID"
case DHCPOptDomainSearch:
return "DomainSearch"
case DHCPOptClasslessStaticRoute:
return "ClasslessStaticRoute"
case DHCPOptMUDURLV4:
return "ManufacturerUsageDescriptionURL"
default:
return "Unknown"
}
}
// DHCPOption rerpresents a DHCP option.
type DHCPOption struct {
Type DHCPOpt
Length uint8
Data []byte
}
// String returns a string version of a DHCP Option.
func (o DHCPOption) String() string {
switch o.Type {
case DHCPOptHostname, DHCPOptMeritDumpFile, DHCPOptDomainName, DHCPOptRootPath,
DHCPOptExtensionsPath, DHCPOptNISDomain, DHCPOptNetBIOSTCPScope, DHCPOptXFontServer,
DHCPOptXDisplayManager, DHCPOptMessage, DHCPOptDomainSearch: // string
return fmt.Sprintf("Option(%s:%s)", o.Type, string(o.Data))
case DHCPOptMessageType:
if len(o.Data) != 1 {
return fmt.Sprintf("Option(%s:INVALID)", o.Type)
}
return fmt.Sprintf("Option(%s:%s)", o.Type, DHCPMsgType(o.Data[0]))
case DHCPOptSubnetMask, DHCPOptServerID, DHCPOptBroadcastAddr,
DHCPOptSolicitAddr, DHCPOptRequestIP: // net.IP
if len(o.Data) < 4 {
return fmt.Sprintf("Option(%s:INVALID)", o.Type)
}
return fmt.Sprintf("Option(%s:%s)", o.Type, net.IP(o.Data))
case DHCPOptT1, DHCPOptT2, DHCPOptLeaseTime, DHCPOptPathMTUAgingTimeout,
DHCPOptARPTimeout, DHCPOptTCPKeepAliveInt: // uint32
if len(o.Data) != 4 {
return fmt.Sprintf("Option(%s:INVALID)", o.Type)
}
return fmt.Sprintf("Option(%s:%d)", o.Type,
uint32(o.Data[0])<<24|uint32(o.Data[1])<<16|uint32(o.Data[2])<<8|uint32(o.Data[3]))
case DHCPOptParamsRequest:
buf := &bytes.Buffer{}
buf.WriteString(fmt.Sprintf("Option(%s:", o.Type))
for i, v := range o.Data {
buf.WriteString(DHCPOpt(v).String())
if i+1 != len(o.Data) {
buf.WriteByte(',')
}
}
buf.WriteString(")")
return buf.String()
default:
return fmt.Sprintf("Option(%s:%v)", o.Type, o.Data)
}
}
// NewDHCPOption constructs a new DHCPOption with a given type and data.
func NewDHCPOption(t DHCPOpt, data []byte) DHCPOption {
o := DHCPOption{Type: t}
if data != nil {
o.Data = data
o.Length = uint8(len(data))
}
return o
}
func (o *DHCPOption) encode(b []byte) error {
switch o.Type {
case DHCPOptPad, DHCPOptEnd:
b[0] = byte(o.Type)
default:
b[0] = byte(o.Type)
b[1] = o.Length
copy(b[2:], o.Data)
}
return nil
}
func (o *DHCPOption) decode(data []byte) error {
if len(data) < 1 {
// Pad/End have a length of 1
return DecOptionNotEnoughData
}
o.Type = DHCPOpt(data[0])
switch o.Type {
case DHCPOptPad, DHCPOptEnd:
o.Data = nil
default:
if len(data) < 2 {
return DecOptionNotEnoughData
}
o.Length = data[1]
if int(o.Length) > len(data[2:]) {
return DecOptionMalformed
}
o.Data = data[2 : 2+int(o.Length)]
}
return nil
}
// DHCPv4Error is used for constant errors for DHCPv4. It is needed for test asserts.
type DHCPv4Error string
// DHCPv4Error implements error interface.
func (d DHCPv4Error) Error() string {
return string(d)
}
const (
// DecOptionNotEnoughData is returned when there is not enough data during option's decode process
DecOptionNotEnoughData = DHCPv4Error("Not enough data to decode")
// DecOptionMalformed is returned when the option is malformed
DecOptionMalformed = DHCPv4Error("Option is malformed")
// InvalidMagicCookie is returned when Magic cookie is missing into BOOTP header
InvalidMagicCookie = DHCPv4Error("Bad DHCP header")
)
// Copyright 2018 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"fmt"
"net"
"github.com/google/gopacket"
)
// DHCPv6MsgType represents a DHCPv6 operation
type DHCPv6MsgType byte
// Constants that represent DHCP operations
const (
DHCPv6MsgTypeUnspecified DHCPv6MsgType = iota
DHCPv6MsgTypeSolicit
DHCPv6MsgTypeAdvertise
DHCPv6MsgTypeRequest
DHCPv6MsgTypeConfirm
DHCPv6MsgTypeRenew
DHCPv6MsgTypeRebind
DHCPv6MsgTypeReply
DHCPv6MsgTypeRelease
DHCPv6MsgTypeDecline
DHCPv6MsgTypeReconfigure
DHCPv6MsgTypeInformationRequest
DHCPv6MsgTypeRelayForward
DHCPv6MsgTypeRelayReply
)
// String returns a string version of a DHCPv6MsgType.
func (o DHCPv6MsgType) String() string {
switch o {
case DHCPv6MsgTypeUnspecified:
return "Unspecified"
case DHCPv6MsgTypeSolicit:
return "Solicit"
case DHCPv6MsgTypeAdvertise:
return "Advertise"
case DHCPv6MsgTypeRequest:
return "Request"
case DHCPv6MsgTypeConfirm:
return "Confirm"
case DHCPv6MsgTypeRenew:
return "Renew"
case DHCPv6MsgTypeRebind:
return "Rebind"
case DHCPv6MsgTypeReply:
return "Reply"
case DHCPv6MsgTypeRelease:
return "Release"
case DHCPv6MsgTypeDecline:
return "Decline"
case DHCPv6MsgTypeReconfigure:
return "Reconfigure"
case DHCPv6MsgTypeInformationRequest:
return "InformationRequest"
case DHCPv6MsgTypeRelayForward:
return "RelayForward"
case DHCPv6MsgTypeRelayReply:
return "RelayReply"
default:
return "Unknown"
}
}
// DHCPv6 contains data for a single DHCP packet.
type DHCPv6 struct {
BaseLayer
MsgType DHCPv6MsgType
HopCount uint8
LinkAddr net.IP
PeerAddr net.IP
TransactionID []byte
Options DHCPv6Options
}
// LayerType returns gopacket.LayerTypeDHCPv6
func (d *DHCPv6) LayerType() gopacket.LayerType { return LayerTypeDHCPv6 }
// DecodeFromBytes decodes the given bytes into this layer.
func (d *DHCPv6) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 4 {
df.SetTruncated()
return fmt.Errorf("DHCPv6 length %d too short", len(data))
}
d.BaseLayer = BaseLayer{Contents: data}
d.Options = d.Options[:0]
d.MsgType = DHCPv6MsgType(data[0])
offset := 0
if d.MsgType == DHCPv6MsgTypeRelayForward || d.MsgType == DHCPv6MsgTypeRelayReply {
if len(data) < 34 {
df.SetTruncated()
return fmt.Errorf("DHCPv6 length %d too short for message type %d", len(data), d.MsgType)
}
d.HopCount = data[1]
d.LinkAddr = net.IP(data[2:18])
d.PeerAddr = net.IP(data[18:34])
offset = 34
} else {
d.TransactionID = data[1:4]
offset = 4
}
stop := len(data)
for offset < stop {
o := DHCPv6Option{}
if err := o.decode(data[offset:]); err != nil {
return err
}
d.Options = append(d.Options, o)
offset += int(o.Length) + 4 // 2 from option code, 2 from option length
}
return nil
}
// Len returns the length of a DHCPv6 packet.
func (d *DHCPv6) Len() int {
n := 1
if d.MsgType == DHCPv6MsgTypeRelayForward || d.MsgType == DHCPv6MsgTypeRelayReply {
n += 33
} else {
n += 3
}
for _, o := range d.Options {
n += int(o.Length) + 4 // 2 from option code, 2 from option length
}
return n
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (d *DHCPv6) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
plen := int(d.Len())
data, err := b.PrependBytes(plen)
if err != nil {
return err
}
offset := 0
data[0] = byte(d.MsgType)
if d.MsgType == DHCPv6MsgTypeRelayForward || d.MsgType == DHCPv6MsgTypeRelayReply {
data[1] = byte(d.HopCount)
copy(data[2:18], d.LinkAddr.To16())
copy(data[18:34], d.PeerAddr.To16())
offset = 34
} else {
copy(data[1:4], d.TransactionID)
offset = 4
}
if len(d.Options) > 0 {
for _, o := range d.Options {
if err := o.encode(data[offset:], opts); err != nil {
return err
}
offset += int(o.Length) + 4 // 2 from option code, 2 from option length
}
}
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (d *DHCPv6) CanDecode() gopacket.LayerClass {
return LayerTypeDHCPv6
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (d *DHCPv6) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
func decodeDHCPv6(data []byte, p gopacket.PacketBuilder) error {
dhcp := &DHCPv6{}
err := dhcp.DecodeFromBytes(data, p)
if err != nil {
return err
}
p.AddLayer(dhcp)
return p.NextDecoder(gopacket.LayerTypePayload)
}
// DHCPv6StatusCode represents a DHCP status code - RFC-3315
type DHCPv6StatusCode uint16
// Constants for the DHCPv6StatusCode.
const (
DHCPv6StatusCodeSuccess DHCPv6StatusCode = iota
DHCPv6StatusCodeUnspecFail
DHCPv6StatusCodeNoAddrsAvail
DHCPv6StatusCodeNoBinding
DHCPv6StatusCodeNotOnLink
DHCPv6StatusCodeUseMulticast
)
// String returns a string version of a DHCPv6StatusCode.
func (o DHCPv6StatusCode) String() string {
switch o {
case DHCPv6StatusCodeSuccess:
return "Success"
case DHCPv6StatusCodeUnspecFail:
return "UnspecifiedFailure"
case DHCPv6StatusCodeNoAddrsAvail:
return "NoAddressAvailable"
case DHCPv6StatusCodeNoBinding:
return "NoBinding"
case DHCPv6StatusCodeNotOnLink:
return "NotOnLink"
case DHCPv6StatusCodeUseMulticast:
return "UseMulticast"
default:
return "Unknown"
}
}
// DHCPv6DUIDType represents a DHCP DUID - RFC-3315
type DHCPv6DUIDType uint16
// Constants for the DHCPv6DUIDType.
const (
DHCPv6DUIDTypeLLT DHCPv6DUIDType = iota + 1
DHCPv6DUIDTypeEN
DHCPv6DUIDTypeLL
)
// String returns a string version of a DHCPv6DUIDType.
func (o DHCPv6DUIDType) String() string {
switch o {
case DHCPv6DUIDTypeLLT:
return "LLT"
case DHCPv6DUIDTypeEN:
return "EN"
case DHCPv6DUIDTypeLL:
return "LL"
default:
return "Unknown"
}
}
// DHCPv6DUID means DHCP Unique Identifier as stated in RFC 3315, section 9 (https://tools.ietf.org/html/rfc3315#page-19)
type DHCPv6DUID struct {
Type DHCPv6DUIDType
// LLT, LL
HardwareType []byte
// EN
EnterpriseNumber []byte
// LLT
Time []byte
// LLT, LL
LinkLayerAddress net.HardwareAddr
// EN
Identifier []byte
}
// DecodeFromBytes decodes the given bytes into a DHCPv6DUID
func (d *DHCPv6DUID) DecodeFromBytes(data []byte) error {
if len(data) < 2 {
return fmt.Errorf("Not enough bytes to decode: %d", len(data))
}
d.Type = DHCPv6DUIDType(binary.BigEndian.Uint16(data[:2]))
if d.Type == DHCPv6DUIDTypeLLT || d.Type == DHCPv6DUIDTypeLL {
if len(data) < 4 {
return fmt.Errorf("Not enough bytes to decode: %d", len(data))
}
d.HardwareType = data[2:4]
}
if d.Type == DHCPv6DUIDTypeLLT {
if len(data) < 8 {
return fmt.Errorf("Not enough bytes to decode: %d", len(data))
}
d.Time = data[4:8]
d.LinkLayerAddress = net.HardwareAddr(data[8:])
} else if d.Type == DHCPv6DUIDTypeEN {
if len(data) < 6 {
return fmt.Errorf("Not enough bytes to decode: %d", len(data))
}
d.EnterpriseNumber = data[2:6]
d.Identifier = data[6:]
} else { // DHCPv6DUIDTypeLL
if len(data) < 4 {
return fmt.Errorf("Not enough bytes to decode: %d", len(data))
}
d.LinkLayerAddress = net.HardwareAddr(data[4:])
}
return nil
}
// Encode encodes the DHCPv6DUID in a slice of bytes
func (d *DHCPv6DUID) Encode() []byte {
length := d.Len()
data := make([]byte, length)
binary.BigEndian.PutUint16(data[0:2], uint16(d.Type))
if d.Type == DHCPv6DUIDTypeLLT || d.Type == DHCPv6DUIDTypeLL {
copy(data[2:4], d.HardwareType)
}
if d.Type == DHCPv6DUIDTypeLLT {
copy(data[4:8], d.Time)
copy(data[8:], d.LinkLayerAddress)
} else if d.Type == DHCPv6DUIDTypeEN {
copy(data[2:6], d.EnterpriseNumber)
copy(data[6:], d.Identifier)
} else {
copy(data[4:], d.LinkLayerAddress)
}
return data
}
// Len returns the length of the DHCPv6DUID, respecting the type
func (d *DHCPv6DUID) Len() int {
length := 2 // d.Type
if d.Type == DHCPv6DUIDTypeLLT {
length += 2 /*HardwareType*/ + 4 /*d.Time*/ + len(d.LinkLayerAddress)
} else if d.Type == DHCPv6DUIDTypeEN {
length += 4 /*d.EnterpriseNumber*/ + len(d.Identifier)
} else { // LL
length += 2 /*d.HardwareType*/ + len(d.LinkLayerAddress)
}
return length
}
func (d *DHCPv6DUID) String() string {
duid := "Type: " + d.Type.String() + ", "
if d.Type == DHCPv6DUIDTypeLLT {
duid += fmt.Sprintf("HardwareType: %v, Time: %v, LinkLayerAddress: %v", d.HardwareType, d.Time, d.LinkLayerAddress)
} else if d.Type == DHCPv6DUIDTypeEN {
duid += fmt.Sprintf("EnterpriseNumber: %v, Identifier: %v", d.EnterpriseNumber, d.Identifier)
} else { // DHCPv6DUIDTypeLL
duid += fmt.Sprintf("HardwareType: %v, LinkLayerAddress: %v", d.HardwareType, d.LinkLayerAddress)
}
return duid
}
func decodeDHCPv6DUID(data []byte) (*DHCPv6DUID, error) {
duid := &DHCPv6DUID{}
err := duid.DecodeFromBytes(data)
if err != nil {
return nil, err
}
return duid, nil
}
// Copyright 2018 The GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"github.com/google/gopacket"
)
// DHCPv6Opt represents a DHCP option or parameter from RFC-3315
type DHCPv6Opt uint16
// Constants for the DHCPv6Opt options.
const (
DHCPv6OptClientID DHCPv6Opt = 1
DHCPv6OptServerID DHCPv6Opt = 2
DHCPv6OptIANA DHCPv6Opt = 3
DHCPv6OptIATA DHCPv6Opt = 4
DHCPv6OptIAAddr DHCPv6Opt = 5
DHCPv6OptOro DHCPv6Opt = 6
DHCPv6OptPreference DHCPv6Opt = 7
DHCPv6OptElapsedTime DHCPv6Opt = 8
DHCPv6OptRelayMessage DHCPv6Opt = 9
DHCPv6OptAuth DHCPv6Opt = 11
DHCPv6OptUnicast DHCPv6Opt = 12
DHCPv6OptStatusCode DHCPv6Opt = 13
DHCPv6OptRapidCommit DHCPv6Opt = 14
DHCPv6OptUserClass DHCPv6Opt = 15
DHCPv6OptVendorClass DHCPv6Opt = 16
DHCPv6OptVendorOpts DHCPv6Opt = 17
DHCPv6OptInterfaceID DHCPv6Opt = 18
DHCPv6OptReconfigureMessage DHCPv6Opt = 19
DHCPv6OptReconfigureAccept DHCPv6Opt = 20
// RFC 3319 Session Initiation Protocol (SIP)
DHCPv6OptSIPServersDomainList DHCPv6Opt = 21
DHCPv6OptSIPServersAddressList DHCPv6Opt = 22
// RFC 3646 DNS Configuration
DHCPv6OptDNSServers DHCPv6Opt = 23
DHCPv6OptDomainList DHCPv6Opt = 24
// RFC 3633 Prefix Delegation
DHCPv6OptIAPD DHCPv6Opt = 25
DHCPv6OptIAPrefix DHCPv6Opt = 26
// RFC 3898 Network Information Service (NIS)
DHCPv6OptNISServers DHCPv6Opt = 27
DHCPv6OptNISPServers DHCPv6Opt = 28
DHCPv6OptNISDomainName DHCPv6Opt = 29
DHCPv6OptNISPDomainName DHCPv6Opt = 30
// RFC 4075 Simple Network Time Protocol (SNTP)
DHCPv6OptSNTPServers DHCPv6Opt = 31
// RFC 4242 Information Refresh Time Option
DHCPv6OptInformationRefreshTime DHCPv6Opt = 32
// RFC 4280 Broadcast and Multicast Control Servers
DHCPv6OptBCMCSServerDomainNameList DHCPv6Opt = 33
DHCPv6OptBCMCSServerAddressList DHCPv6Opt = 34
// RFC 4776 Civic Address ConfigurationOption
DHCPv6OptGeoconfCivic DHCPv6Opt = 36
// RFC 4649 Relay Agent Remote-ID
DHCPv6OptRemoteID DHCPv6Opt = 37
// RFC 4580 Relay Agent Subscriber-ID
DHCPv6OptSubscriberID DHCPv6Opt = 38
// RFC 4704 Client Full Qualified Domain Name (FQDN)
DHCPv6OptClientFQDN DHCPv6Opt = 39
// RFC 5192 Protocol for Carrying Authentication for Network Access (PANA)
DHCPv6OptPanaAgent DHCPv6Opt = 40
// RFC 4833 Timezone Options
DHCPv6OptNewPOSIXTimezone DHCPv6Opt = 41
DHCPv6OptNewTZDBTimezone DHCPv6Opt = 42
// RFC 4994 Relay Agent Echo Request
DHCPv6OptEchoRequestOption DHCPv6Opt = 43
// RFC 5007 Leasequery
DHCPv6OptLQQuery DHCPv6Opt = 44
DHCPv6OptCLTTime DHCPv6Opt = 45
DHCPv6OptClientData DHCPv6Opt = 46
DHCPv6OptLQRelayData DHCPv6Opt = 47
DHCPv6OptLQClientLink DHCPv6Opt = 48
// RFC 6610 Home Information Discovery in Mobile IPv6 (MIPv6)
DHCPv6OptMIP6HNIDF DHCPv6Opt = 49
DHCPv6OptMIP6VDINF DHCPv6Opt = 50
DHCPv6OptMIP6IDINF DHCPv6Opt = 69
DHCPv6OptMIP6UDINF DHCPv6Opt = 70
DHCPv6OptMIP6HNP DHCPv6Opt = 71
DHCPv6OptMIP6HAA DHCPv6Opt = 72
DHCPv6OptMIP6HAF DHCPv6Opt = 73
// RFC 5223 Discovering Location-to-Service Translation (LoST) Servers
DHCPv6OptV6LOST DHCPv6Opt = 51
// RFC 5417 Control And Provisioning of Wireless Access Points (CAPWAP)
DHCPv6OptCAPWAPACV6 DHCPv6Opt = 52
// RFC 5460 Bulk Leasequery
DHCPv6OptRelayID DHCPv6Opt = 53
// RFC 5678 IEEE 802.21 Mobility Services (MoS) Discovery
DHCPv6OptIPv6AddressMoS DHCPv6Opt = 54
DHCPv6OptIPv6FQDNMoS DHCPv6Opt = 55
// RFC 5908 NTP Server Option
DHCPv6OptNTPServer DHCPv6Opt = 56
// RFC 5986 Discovering the Local Location Information Server (LIS)
DHCPv6OptV6AccessDomain DHCPv6Opt = 57
// RFC 5986 SIP User Agent
DHCPv6OptSIPUACSList DHCPv6Opt = 58
// RFC 5970 Options for Network Boot
DHCPv6OptBootFileURL DHCPv6Opt = 59
DHCPv6OptBootFileParam DHCPv6Opt = 60
DHCPv6OptClientArchType DHCPv6Opt = 61
DHCPv6OptNII DHCPv6Opt = 62
// RFC 6225 Coordinate-Based Location Configuration Information
DHCPv6OptGeolocation DHCPv6Opt = 63
// RFC 6334 Dual-Stack Lite
DHCPv6OptAFTRName DHCPv6Opt = 64
// RFC 6440 EAP Re-authentication Protocol (ERP)
DHCPv6OptERPLocalDomainName DHCPv6Opt = 65
// RFC 6422 Relay-Supplied DHCP Options
DHCPv6OptRSOO DHCPv6Opt = 66
// RFC 6603 Prefix Exclude Option for DHCPv6-based Prefix Delegation
DHCPv6OptPDExclude DHCPv6Opt = 67
// RFC 6607 Virtual Subnet Selection
DHCPv6OptVSS DHCPv6Opt = 68
// RFC 6731 Improved Recursive DNS Server Selection for Multi-Interfaced Nodes
DHCPv6OptRDNSSSelection DHCPv6Opt = 74
// RFC 6784 Kerberos Options for DHCPv6
DHCPv6OptKRBPrincipalName DHCPv6Opt = 75
DHCPv6OptKRBRealmName DHCPv6Opt = 76
DHCPv6OptKRBKDC DHCPv6Opt = 77
// RFC 6939 Client Link-Layer Address Option
DHCPv6OptClientLinkLayerAddress DHCPv6Opt = 79
// RFC 6977 Triggering DHCPv6 Reconfiguration from Relay Agents
DHCPv6OptLinkAddress DHCPv6Opt = 80
// RFC 7037 RADIUS Option for the DHCPv6 Relay Agent
DHCPv6OptRADIUS DHCPv6Opt = 81
// RFC 7083 Modification to Default Values of SOL_MAX_RT and INF_MAX_RT
DHCPv6OptSolMaxRt DHCPv6Opt = 82
DHCPv6OptInfMaxRt DHCPv6Opt = 83
// RFC 7078 Distributing Address Selection Policy
DHCPv6OptAddrSel DHCPv6Opt = 84
DHCPv6OptAddrSelTable DHCPv6Opt = 85
// RFC 7291 DHCP Options for the Port Control Protocol (PCP)
DHCPv6OptV6PCPServer DHCPv6Opt = 86
// RFC 7341 DHCPv4-over-DHCPv6 (DHCP 4o6) Transport
DHCPv6OptDHCPv4Message DHCPv6Opt = 87
DHCPv6OptDHCPv4OverDHCPv6Server DHCPv6Opt = 88
// RFC 7598 Configuration of Softwire Address and Port-Mapped Clients
DHCPv6OptS46Rule DHCPv6Opt = 89
DHCPv6OptS46BR DHCPv6Opt = 90
DHCPv6OptS46DMR DHCPv6Opt = 91
DHCPv6OptS46V4V4Bind DHCPv6Opt = 92
DHCPv6OptS46PortParameters DHCPv6Opt = 93
DHCPv6OptS46ContMAPE DHCPv6Opt = 94
DHCPv6OptS46ContMAPT DHCPv6Opt = 95
DHCPv6OptS46ContLW DHCPv6Opt = 96
// RFC 7600 IPv4 Residual Deployment via IPv6
DHCPv6Opt4RD DHCPv6Opt = 97
DHCPv6Opt4RDMapRule DHCPv6Opt = 98
DHCPv6Opt4RDNonMapRule DHCPv6Opt = 99
// RFC 7653 Active Leasequery
DHCPv6OptLQBaseTime DHCPv6Opt = 100
DHCPv6OptLQStartTime DHCPv6Opt = 101
DHCPv6OptLQEndTime DHCPv6Opt = 102
// RFC 7710 Captive-Portal Identification
DHCPv6OptCaptivePortal DHCPv6Opt = 103
// RFC 7774 Multicast Protocol for Low-Power and Lossy Networks (MPL) Parameter Configuration
DHCPv6OptMPLParameters DHCPv6Opt = 104
// RFC 7839 Access-Network-Identifier (ANI)
DHCPv6OptANIATT DHCPv6Opt = 105
DHCPv6OptANINetworkName DHCPv6Opt = 106
DHCPv6OptANIAPName DHCPv6Opt = 107
DHCPv6OptANIAPBSSID DHCPv6Opt = 108
DHCPv6OptANIOperatorID DHCPv6Opt = 109
DHCPv6OptANIOperatorRealm DHCPv6Opt = 110
// RFC 8026 Unified IPv4-in-IPv6 Softwire Customer Premises Equipment (CPE)
DHCPv6OptS46Priority DHCPv6Opt = 111
// draft-ietf-opsawg-mud-25 Manufacturer Usage Description (MUD)
DHCPv6OptMUDURLV6 DHCPv6Opt = 112
// RFC 8115 IPv4-Embedded Multicast and Unicast IPv6 Prefixes
DHCPv6OptV6Prefix64 DHCPv6Opt = 113
// RFC 8156 DHCPv6 Failover Protocol
DHCPv6OptFBindingStatus DHCPv6Opt = 114
DHCPv6OptFConnectFlags DHCPv6Opt = 115
DHCPv6OptFDNSRemovalInfo DHCPv6Opt = 116
DHCPv6OptFDNSHostName DHCPv6Opt = 117
DHCPv6OptFDNSZoneName DHCPv6Opt = 118
DHCPv6OptFDNSFlags DHCPv6Opt = 119
DHCPv6OptFExpirationTime DHCPv6Opt = 120
DHCPv6OptFMaxUnacknowledgedBNDUPD DHCPv6Opt = 121
DHCPv6OptFMCLT DHCPv6Opt = 122
DHCPv6OptFPartnerLifetime DHCPv6Opt = 123
DHCPv6OptFPartnerLifetimeSent DHCPv6Opt = 124
DHCPv6OptFPartnerDownTime DHCPv6Opt = 125
DHCPv6OptFPartnerRawCltTime DHCPv6Opt = 126
DHCPv6OptFProtocolVersion DHCPv6Opt = 127
DHCPv6OptFKeepaliveTime DHCPv6Opt = 128
DHCPv6OptFReconfigureData DHCPv6Opt = 129
DHCPv6OptFRelationshipName DHCPv6Opt = 130
DHCPv6OptFServerFlags DHCPv6Opt = 131
DHCPv6OptFServerState DHCPv6Opt = 132
DHCPv6OptFStartTimeOfState DHCPv6Opt = 133
DHCPv6OptFStateExpirationTime DHCPv6Opt = 134
// RFC 8357 Generalized UDP Source Port for DHCP Relay
DHCPv6OptRelayPort DHCPv6Opt = 135
// draft-ietf-netconf-zerotouch-25 Zero Touch Provisioning for Networking Devices
DHCPv6OptV6ZeroTouchRedirect DHCPv6Opt = 136
// RFC 6153 Access Network Discovery and Selection Function (ANDSF) Discovery
DHCPv6OptIPV6AddressANDSF DHCPv6Opt = 143
)
// String returns a string version of a DHCPv6Opt.
func (o DHCPv6Opt) String() string {
switch o {
case DHCPv6OptClientID:
return "ClientID"
case DHCPv6OptServerID:
return "ServerID"
case DHCPv6OptIANA:
return "IA_NA"
case DHCPv6OptIATA:
return "IA_TA"
case DHCPv6OptIAAddr:
return "IAAddr"
case DHCPv6OptOro:
return "Oro"
case DHCPv6OptPreference:
return "Preference"
case DHCPv6OptElapsedTime:
return "ElapsedTime"
case DHCPv6OptRelayMessage:
return "RelayMessage"
case DHCPv6OptAuth:
return "Auth"
case DHCPv6OptUnicast:
return "Unicast"
case DHCPv6OptStatusCode:
return "StatusCode"
case DHCPv6OptRapidCommit:
return "RapidCommit"
case DHCPv6OptUserClass:
return "UserClass"
case DHCPv6OptVendorClass:
return "VendorClass"
case DHCPv6OptVendorOpts:
return "VendorOpts"
case DHCPv6OptInterfaceID:
return "InterfaceID"
case DHCPv6OptReconfigureMessage:
return "ReconfigureMessage"
case DHCPv6OptReconfigureAccept:
return "ReconfigureAccept"
case DHCPv6OptSIPServersDomainList:
return "SIPServersDomainList"
case DHCPv6OptSIPServersAddressList:
return "SIPServersAddressList"
case DHCPv6OptDNSServers:
return "DNSRecursiveNameServer"
case DHCPv6OptDomainList:
return "DomainSearchList"
case DHCPv6OptIAPD:
return "IdentityAssociationPrefixDelegation"
case DHCPv6OptIAPrefix:
return "IAPDPrefix"
case DHCPv6OptNISServers:
return "NISServers"
case DHCPv6OptNISPServers:
return "NISv2Servers"
case DHCPv6OptNISDomainName:
return "NISDomainName"
case DHCPv6OptNISPDomainName:
return "NISv2DomainName"
case DHCPv6OptSNTPServers:
return "SNTPServers"
case DHCPv6OptInformationRefreshTime:
return "InformationRefreshTime"
case DHCPv6OptBCMCSServerDomainNameList:
return "BCMCSControlServersDomainNameList"
case DHCPv6OptBCMCSServerAddressList:
return "BCMCSControlServersAddressList"
case DHCPv6OptGeoconfCivic:
return "CivicAddress"
case DHCPv6OptRemoteID:
return "RelayAgentRemoteID"
case DHCPv6OptSubscriberID:
return "RelayAgentSubscriberID"
case DHCPv6OptClientFQDN:
return "ClientFQDN"
case DHCPv6OptPanaAgent:
return "PANAAuthenticationAgent"
case DHCPv6OptNewPOSIXTimezone:
return "NewPOSIXTimezone"
case DHCPv6OptNewTZDBTimezone:
return "NewTZDBTimezone"
case DHCPv6OptEchoRequestOption:
return "EchoRequest"
case DHCPv6OptLQQuery:
return "LeasequeryQuery"
case DHCPv6OptClientData:
return "LeasequeryClientData"
case DHCPv6OptCLTTime:
return "LeasequeryClientLastTransactionTime"
case DHCPv6OptLQRelayData:
return "LeasequeryRelayData"
case DHCPv6OptLQClientLink:
return "LeasequeryClientLink"
case DHCPv6OptMIP6HNIDF:
return "MIPv6HomeNetworkIDFQDN"
case DHCPv6OptMIP6VDINF:
return "MIPv6VisitedHomeNetworkInformation"
case DHCPv6OptMIP6IDINF:
return "MIPv6IdentifiedHomeNetworkInformation"
case DHCPv6OptMIP6UDINF:
return "MIPv6UnrestrictedHomeNetworkInformation"
case DHCPv6OptMIP6HNP:
return "MIPv6HomeNetworkPrefix"
case DHCPv6OptMIP6HAA:
return "MIPv6HomeAgentAddress"
case DHCPv6OptMIP6HAF:
return "MIPv6HomeAgentFQDN"
case DHCPv6OptV6LOST:
return "LoST Server"
case DHCPv6OptCAPWAPACV6:
return "CAPWAPAccessControllerV6"
case DHCPv6OptRelayID:
return "LeasequeryRelayID"
case DHCPv6OptIPv6AddressMoS:
return "MoSIPv6Address"
case DHCPv6OptIPv6FQDNMoS:
return "MoSDomainNameList"
case DHCPv6OptNTPServer:
return "NTPServer"
case DHCPv6OptV6AccessDomain:
return "AccessNetworkDomainName"
case DHCPv6OptSIPUACSList:
return "SIPUserAgentConfigurationServiceDomains"
case DHCPv6OptBootFileURL:
return "BootFileURL"
case DHCPv6OptBootFileParam:
return "BootFileParameters"
case DHCPv6OptClientArchType:
return "ClientSystemArchitectureType"
case DHCPv6OptNII:
return "ClientNetworkInterfaceIdentifier"
case DHCPv6OptGeolocation:
return "Geolocation"
case DHCPv6OptAFTRName:
return "AFTRName"
case DHCPv6OptERPLocalDomainName:
return "AFTRName"
case DHCPv6OptRSOO:
return "RSOOption"
case DHCPv6OptPDExclude:
return "PrefixExclude"
case DHCPv6OptVSS:
return "VirtualSubnetSelection"
case DHCPv6OptRDNSSSelection:
return "RDNSSSelection"
case DHCPv6OptKRBPrincipalName:
return "KerberosPrincipalName"
case DHCPv6OptKRBRealmName:
return "KerberosRealmName"
case DHCPv6OptKRBKDC:
return "KerberosKDC"
case DHCPv6OptClientLinkLayerAddress:
return "ClientLinkLayerAddress"
case DHCPv6OptLinkAddress:
return "LinkAddress"
case DHCPv6OptRADIUS:
return "RADIUS"
case DHCPv6OptSolMaxRt:
return "SolMaxRt"
case DHCPv6OptInfMaxRt:
return "InfMaxRt"
case DHCPv6OptAddrSel:
return "AddressSelection"
case DHCPv6OptAddrSelTable:
return "AddressSelectionTable"
case DHCPv6OptV6PCPServer:
return "PCPServer"
case DHCPv6OptDHCPv4Message:
return "DHCPv4Message"
case DHCPv6OptDHCPv4OverDHCPv6Server:
return "DHCP4o6ServerAddress"
case DHCPv6OptS46Rule:
return "S46Rule"
case DHCPv6OptS46BR:
return "S46BR"
case DHCPv6OptS46DMR:
return "S46DMR"
case DHCPv6OptS46V4V4Bind:
return "S46IPv4IPv6AddressBinding"
case DHCPv6OptS46PortParameters:
return "S46PortParameters"
case DHCPv6OptS46ContMAPE:
return "S46MAPEContainer"
case DHCPv6OptS46ContMAPT:
return "S46MAPTContainer"
case DHCPv6OptS46ContLW:
return "S46Lightweight4Over6Container"
case DHCPv6Opt4RD:
return "4RD"
case DHCPv6Opt4RDMapRule:
return "4RDMapRule"
case DHCPv6Opt4RDNonMapRule:
return "4RDNonMapRule"
case DHCPv6OptLQBaseTime:
return "LQBaseTime"
case DHCPv6OptLQStartTime:
return "LQStartTime"
case DHCPv6OptLQEndTime:
return "LQEndTime"
case DHCPv6OptCaptivePortal:
return "CaptivePortal"
case DHCPv6OptMPLParameters:
return "MPLParameterConfiguration"
case DHCPv6OptANIATT:
return "ANIAccessTechnologyType"
case DHCPv6OptANINetworkName:
return "ANINetworkName"
case DHCPv6OptANIAPName:
return "ANIAccessPointName"
case DHCPv6OptANIAPBSSID:
return "ANIAccessPointBSSID"
case DHCPv6OptANIOperatorID:
return "ANIOperatorIdentifier"
case DHCPv6OptANIOperatorRealm:
return "ANIOperatorRealm"
case DHCPv6OptS46Priority:
return "S64Priority"
case DHCPv6OptMUDURLV6:
return "ManufacturerUsageDescriptionURL"
case DHCPv6OptV6Prefix64:
return "V6Prefix64"
case DHCPv6OptFBindingStatus:
return "FailoverBindingStatus"
case DHCPv6OptFConnectFlags:
return "FailoverConnectFlags"
case DHCPv6OptFDNSRemovalInfo:
return "FailoverDNSRemovalInfo"
case DHCPv6OptFDNSHostName:
return "FailoverDNSHostName"
case DHCPv6OptFDNSZoneName:
return "FailoverDNSZoneName"
case DHCPv6OptFDNSFlags:
return "FailoverDNSFlags"
case DHCPv6OptFExpirationTime:
return "FailoverExpirationTime"
case DHCPv6OptFMaxUnacknowledgedBNDUPD:
return "FailoverMaxUnacknowledgedBNDUPDMessages"
case DHCPv6OptFMCLT:
return "FailoverMaximumClientLeadTime"
case DHCPv6OptFPartnerLifetime:
return "FailoverPartnerLifetime"
case DHCPv6OptFPartnerLifetimeSent:
return "FailoverPartnerLifetimeSent"
case DHCPv6OptFPartnerDownTime:
return "FailoverPartnerDownTime"
case DHCPv6OptFPartnerRawCltTime:
return "FailoverPartnerRawClientLeadTime"
case DHCPv6OptFProtocolVersion:
return "FailoverProtocolVersion"
case DHCPv6OptFKeepaliveTime:
return "FailoverKeepaliveTime"
case DHCPv6OptFReconfigureData:
return "FailoverReconfigureData"
case DHCPv6OptFRelationshipName:
return "FailoverRelationshipName"
case DHCPv6OptFServerFlags:
return "FailoverServerFlags"
case DHCPv6OptFServerState:
return "FailoverServerState"
case DHCPv6OptFStartTimeOfState:
return "FailoverStartTimeOfState"
case DHCPv6OptFStateExpirationTime:
return "FailoverStateExpirationTime"
case DHCPv6OptRelayPort:
return "RelayPort"
case DHCPv6OptV6ZeroTouchRedirect:
return "ZeroTouch"
case DHCPv6OptIPV6AddressANDSF:
return "ANDSFIPv6Address"
default:
return fmt.Sprintf("Unknown(%d)", uint16(o))
}
}
// DHCPv6Options is used to get nicely printed option lists which would normally
// be cut off after 5 options.
type DHCPv6Options []DHCPv6Option
// String returns a string version of the options list.
func (o DHCPv6Options) String() string {
buf := &bytes.Buffer{}
buf.WriteByte('[')
for i, opt := range o {
buf.WriteString(opt.String())
if i+1 != len(o) {
buf.WriteString(", ")
}
}
buf.WriteByte(']')
return buf.String()
}
// DHCPv6Option rerpresents a DHCP option.
type DHCPv6Option struct {
Code DHCPv6Opt
Length uint16
Data []byte
}
// String returns a string version of a DHCP Option.
func (o DHCPv6Option) String() string {
switch o.Code {
case DHCPv6OptClientID, DHCPv6OptServerID:
duid, err := decodeDHCPv6DUID(o.Data)
if err != nil {
return fmt.Sprintf("Option(%s:INVALID)", o.Code)
}
return fmt.Sprintf("Option(%s:[%s])", o.Code, duid.String())
case DHCPv6OptOro:
options := ""
for i := 0; i < int(o.Length); i += 2 {
if options != "" {
options += ","
}
option := DHCPv6Opt(binary.BigEndian.Uint16(o.Data[i : i+2]))
options += option.String()
}
return fmt.Sprintf("Option(%s:[%s])", o.Code, options)
default:
return fmt.Sprintf("Option(%s:%v)", o.Code, o.Data)
}
}
// NewDHCPv6Option constructs a new DHCPv6Option with a given type and data.
func NewDHCPv6Option(code DHCPv6Opt, data []byte) DHCPv6Option {
o := DHCPv6Option{Code: code}
if data != nil {
o.Data = data
o.Length = uint16(len(data))
}
return o
}
func (o *DHCPv6Option) encode(b []byte, opts gopacket.SerializeOptions) error {
binary.BigEndian.PutUint16(b[0:2], uint16(o.Code))
if opts.FixLengths {
binary.BigEndian.PutUint16(b[2:4], uint16(len(o.Data)))
} else {
binary.BigEndian.PutUint16(b[2:4], o.Length)
}
copy(b[4:], o.Data)
return nil
}
func (o *DHCPv6Option) decode(data []byte) error {
if len(data) < 4 {
return errors.New("not enough data to decode")
}
o.Code = DHCPv6Opt(binary.BigEndian.Uint16(data[0:2]))
o.Length = binary.BigEndian.Uint16(data[2:4])
if len(data) < 4+int(o.Length) {
return fmt.Errorf("dhcpv6 option size < length %d", 4+o.Length)
}
o.Data = data[4 : 4+o.Length]
return nil
}
// Copyright 2014, 2018 GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"net"
"strings"
"github.com/google/gopacket"
)
// DNSClass defines the class associated with a request/response. Different DNS
// classes can be thought of as an array of parallel namespace trees.
type DNSClass uint16
// DNSClass known values.
const (
DNSClassIN DNSClass = 1 // Internet
DNSClassCS DNSClass = 2 // the CSNET class (Obsolete)
DNSClassCH DNSClass = 3 // the CHAOS class
DNSClassHS DNSClass = 4 // Hesiod [Dyer 87]
DNSClassAny DNSClass = 255 // AnyClass
)
func (dc DNSClass) String() string {
switch dc {
default:
return "Unknown"
case DNSClassIN:
return "IN"
case DNSClassCS:
return "CS"
case DNSClassCH:
return "CH"
case DNSClassHS:
return "HS"
case DNSClassAny:
return "Any"
}
}
// DNSType defines the type of data being requested/returned in a
// question/answer.
type DNSType uint16
// DNSType known values.
const (
DNSTypeA DNSType = 1 // a host address
DNSTypeNS DNSType = 2 // an authoritative name server
DNSTypeMD DNSType = 3 // a mail destination (Obsolete - use MX)
DNSTypeMF DNSType = 4 // a mail forwarder (Obsolete - use MX)
DNSTypeCNAME DNSType = 5 // the canonical name for an alias
DNSTypeSOA DNSType = 6 // marks the start of a zone of authority
DNSTypeMB DNSType = 7 // a mailbox domain name (EXPERIMENTAL)
DNSTypeMG DNSType = 8 // a mail group member (EXPERIMENTAL)
DNSTypeMR DNSType = 9 // a mail rename domain name (EXPERIMENTAL)
DNSTypeNULL DNSType = 10 // a null RR (EXPERIMENTAL)
DNSTypeWKS DNSType = 11 // a well known service description
DNSTypePTR DNSType = 12 // a domain name pointer
DNSTypeHINFO DNSType = 13 // host information
DNSTypeMINFO DNSType = 14 // mailbox or mail list information
DNSTypeMX DNSType = 15 // mail exchange
DNSTypeTXT DNSType = 16 // text strings
DNSTypeAAAA DNSType = 28 // a IPv6 host address [RFC3596]
DNSTypeSRV DNSType = 33 // server discovery [RFC2782] [RFC6195]
DNSTypeOPT DNSType = 41 // OPT Pseudo-RR [RFC6891]
DNSTypeURI DNSType = 256 // URI RR [RFC7553]
)
func (dt DNSType) String() string {
switch dt {
default:
return "Unknown"
case DNSTypeA:
return "A"
case DNSTypeNS:
return "NS"
case DNSTypeMD:
return "MD"
case DNSTypeMF:
return "MF"
case DNSTypeCNAME:
return "CNAME"
case DNSTypeSOA:
return "SOA"
case DNSTypeMB:
return "MB"
case DNSTypeMG:
return "MG"
case DNSTypeMR:
return "MR"
case DNSTypeNULL:
return "NULL"
case DNSTypeWKS:
return "WKS"
case DNSTypePTR:
return "PTR"
case DNSTypeHINFO:
return "HINFO"
case DNSTypeMINFO:
return "MINFO"
case DNSTypeMX:
return "MX"
case DNSTypeTXT:
return "TXT"
case DNSTypeAAAA:
return "AAAA"
case DNSTypeSRV:
return "SRV"
case DNSTypeOPT:
return "OPT"
case DNSTypeURI:
return "URI"
}
}
// DNSResponseCode provides response codes for question answers.
type DNSResponseCode uint8
// DNSResponseCode known values.
const (
DNSResponseCodeNoErr DNSResponseCode = 0 // No error
DNSResponseCodeFormErr DNSResponseCode = 1 // Format Error [RFC1035]
DNSResponseCodeServFail DNSResponseCode = 2 // Server Failure [RFC1035]
DNSResponseCodeNXDomain DNSResponseCode = 3 // Non-Existent Domain [RFC1035]
DNSResponseCodeNotImp DNSResponseCode = 4 // Not Implemented [RFC1035]
DNSResponseCodeRefused DNSResponseCode = 5 // Query Refused [RFC1035]
DNSResponseCodeYXDomain DNSResponseCode = 6 // Name Exists when it should not [RFC2136]
DNSResponseCodeYXRRSet DNSResponseCode = 7 // RR Set Exists when it should not [RFC2136]
DNSResponseCodeNXRRSet DNSResponseCode = 8 // RR Set that should exist does not [RFC2136]
DNSResponseCodeNotAuth DNSResponseCode = 9 // Server Not Authoritative for zone [RFC2136]
DNSResponseCodeNotZone DNSResponseCode = 10 // Name not contained in zone [RFC2136]
DNSResponseCodeBadVers DNSResponseCode = 16 // Bad OPT Version [RFC2671]
DNSResponseCodeBadSig DNSResponseCode = 16 // TSIG Signature Failure [RFC2845]
DNSResponseCodeBadKey DNSResponseCode = 17 // Key not recognized [RFC2845]
DNSResponseCodeBadTime DNSResponseCode = 18 // Signature out of time window [RFC2845]
DNSResponseCodeBadMode DNSResponseCode = 19 // Bad TKEY Mode [RFC2930]
DNSResponseCodeBadName DNSResponseCode = 20 // Duplicate key name [RFC2930]
DNSResponseCodeBadAlg DNSResponseCode = 21 // Algorithm not supported [RFC2930]
DNSResponseCodeBadTruc DNSResponseCode = 22 // Bad Truncation [RFC4635]
DNSResponseCodeBadCookie DNSResponseCode = 23 // Bad/missing Server Cookie [RFC7873]
)
func (drc DNSResponseCode) String() string {
switch drc {
default:
return "Unknown"
case DNSResponseCodeNoErr:
return "No Error"
case DNSResponseCodeFormErr:
return "Format Error"
case DNSResponseCodeServFail:
return "Server Failure "
case DNSResponseCodeNXDomain:
return "Non-Existent Domain"
case DNSResponseCodeNotImp:
return "Not Implemented"
case DNSResponseCodeRefused:
return "Query Refused"
case DNSResponseCodeYXDomain:
return "Name Exists when it should not"
case DNSResponseCodeYXRRSet:
return "RR Set Exists when it should not"
case DNSResponseCodeNXRRSet:
return "RR Set that should exist does not"
case DNSResponseCodeNotAuth:
return "Server Not Authoritative for zone"
case DNSResponseCodeNotZone:
return "Name not contained in zone"
case DNSResponseCodeBadVers:
return "Bad OPT Version"
case DNSResponseCodeBadKey:
return "Key not recognized"
case DNSResponseCodeBadTime:
return "Signature out of time window"
case DNSResponseCodeBadMode:
return "Bad TKEY Mode"
case DNSResponseCodeBadName:
return "Duplicate key name"
case DNSResponseCodeBadAlg:
return "Algorithm not supported"
case DNSResponseCodeBadTruc:
return "Bad Truncation"
case DNSResponseCodeBadCookie:
return "Bad Cookie"
}
}
// DNSOpCode defines a set of different operation types.
type DNSOpCode uint8
// DNSOpCode known values.
const (
DNSOpCodeQuery DNSOpCode = 0 // Query [RFC1035]
DNSOpCodeIQuery DNSOpCode = 1 // Inverse Query Obsolete [RFC3425]
DNSOpCodeStatus DNSOpCode = 2 // Status [RFC1035]
DNSOpCodeNotify DNSOpCode = 4 // Notify [RFC1996]
DNSOpCodeUpdate DNSOpCode = 5 // Update [RFC2136]
)
func (doc DNSOpCode) String() string {
switch doc {
default:
return "Unknown"
case DNSOpCodeQuery:
return "Query"
case DNSOpCodeIQuery:
return "Inverse Query"
case DNSOpCodeStatus:
return "Status"
case DNSOpCodeNotify:
return "Notify"
case DNSOpCodeUpdate:
return "Update"
}
}
// DNS is specified in RFC 1034 / RFC 1035
// +---------------------+
// | Header |
// +---------------------+
// | Question | the question for the name server
// +---------------------+
// | Answer | RRs answering the question
// +---------------------+
// | Authority | RRs pointing toward an authority
// +---------------------+
// | Additional | RRs holding additional information
// +---------------------+
//
// DNS Header
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | ID |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | QDCOUNT |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | ANCOUNT |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | NSCOUNT |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | ARCOUNT |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// DNS contains data from a single Domain Name Service packet.
type DNS struct {
BaseLayer
// Header fields
ID uint16
QR bool
OpCode DNSOpCode
AA bool // Authoritative answer
TC bool // Truncated
RD bool // Recursion desired
RA bool // Recursion available
Z uint8 // Reserved for future use
ResponseCode DNSResponseCode
QDCount uint16 // Number of questions to expect
ANCount uint16 // Number of answers to expect
NSCount uint16 // Number of authorities to expect
ARCount uint16 // Number of additional records to expect
// Entries
Questions []DNSQuestion
Answers []DNSResourceRecord
Authorities []DNSResourceRecord
Additionals []DNSResourceRecord
// buffer for doing name decoding. We use a single reusable buffer to avoid
// name decoding on a single object via multiple DecodeFromBytes calls
// requiring constant allocation of small byte slices.
buffer []byte
}
// LayerType returns gopacket.LayerTypeDNS.
func (d *DNS) LayerType() gopacket.LayerType { return LayerTypeDNS }
// decodeDNS decodes the byte slice into a DNS type. It also
// setups the application Layer in PacketBuilder.
func decodeDNS(data []byte, p gopacket.PacketBuilder) error {
d := &DNS{}
err := d.DecodeFromBytes(data, p)
if err != nil {
return err
}
p.AddLayer(d)
p.SetApplicationLayer(d)
return nil
}
// DecodeFromBytes decodes the slice into the DNS struct.
func (d *DNS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
d.buffer = d.buffer[:0]
if len(data) < 12 {
df.SetTruncated()
return errDNSPacketTooShort
}
// since there are no further layers, the baselayer's content is
// pointing to this layer
d.BaseLayer = BaseLayer{Contents: data[:len(data)]}
d.ID = binary.BigEndian.Uint16(data[:2])
d.QR = data[2]&0x80 != 0
d.OpCode = DNSOpCode(data[2]>>3) & 0x0F
d.AA = data[2]&0x04 != 0
d.TC = data[2]&0x02 != 0
d.RD = data[2]&0x01 != 0
d.RA = data[3]&0x80 != 0
d.Z = uint8(data[3]>>4) & 0x7
d.ResponseCode = DNSResponseCode(data[3] & 0xF)
d.QDCount = binary.BigEndian.Uint16(data[4:6])
d.ANCount = binary.BigEndian.Uint16(data[6:8])
d.NSCount = binary.BigEndian.Uint16(data[8:10])
d.ARCount = binary.BigEndian.Uint16(data[10:12])
d.Questions = d.Questions[:0]
d.Answers = d.Answers[:0]
d.Authorities = d.Authorities[:0]
d.Additionals = d.Additionals[:0]
offset := 12
var err error
for i := 0; i < int(d.QDCount); i++ {
var q DNSQuestion
if offset, err = q.decode(data, offset, df, &d.buffer); err != nil {
return err
}
d.Questions = append(d.Questions, q)
}
// For some horrible reason, if we do the obvious thing in this loop:
// var r DNSResourceRecord
// if blah := r.decode(blah); err != nil {
// return err
// }
// d.Foo = append(d.Foo, r)
// the Go compiler thinks that 'r' escapes to the heap, causing a malloc for
// every Answer, Authority, and Additional. To get around this, we do
// something really silly: we append an empty resource record to our slice,
// then use the last value in the slice to call decode. Since the value is
// already in the slice, there's no WAY it can escape... on the other hand our
// code is MUCH uglier :(
for i := 0; i < int(d.ANCount); i++ {
d.Answers = append(d.Answers, DNSResourceRecord{})
if offset, err = d.Answers[i].decode(data, offset, df, &d.buffer); err != nil {
d.Answers = d.Answers[:i] // strip off erroneous value
return err
}
}
for i := 0; i < int(d.NSCount); i++ {
d.Authorities = append(d.Authorities, DNSResourceRecord{})
if offset, err = d.Authorities[i].decode(data, offset, df, &d.buffer); err != nil {
d.Authorities = d.Authorities[:i] // strip off erroneous value
return err
}
}
for i := 0; i < int(d.ARCount); i++ {
d.Additionals = append(d.Additionals, DNSResourceRecord{})
if offset, err = d.Additionals[i].decode(data, offset, df, &d.buffer); err != nil {
d.Additionals = d.Additionals[:i] // strip off erroneous value
return err
}
// extract extended RCODE from OPT RRs, RFC 6891 section 6.1.3
if d.Additionals[i].Type == DNSTypeOPT {
d.ResponseCode = DNSResponseCode(uint8(d.ResponseCode) | uint8(d.Additionals[i].TTL>>20&0xF0))
}
}
if uint16(len(d.Questions)) != d.QDCount {
return errDecodeQueryBadQDCount
} else if uint16(len(d.Answers)) != d.ANCount {
return errDecodeQueryBadANCount
} else if uint16(len(d.Authorities)) != d.NSCount {
return errDecodeQueryBadNSCount
} else if uint16(len(d.Additionals)) != d.ARCount {
return errDecodeQueryBadARCount
}
return nil
}
// CanDecode implements gopacket.DecodingLayer.
func (d *DNS) CanDecode() gopacket.LayerClass {
return LayerTypeDNS
}
// NextLayerType implements gopacket.DecodingLayer.
func (d *DNS) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
// Payload returns nil.
func (d *DNS) Payload() []byte {
return nil
}
func b2i(b bool) int {
if b {
return 1
}
return 0
}
func recSize(rr *DNSResourceRecord) int {
switch rr.Type {
case DNSTypeA:
return 4
case DNSTypeAAAA:
return 16
case DNSTypeNS:
return len(rr.NS) + 2
case DNSTypeCNAME:
return len(rr.CNAME) + 2
case DNSTypePTR:
return len(rr.PTR) + 2
case DNSTypeSOA:
return len(rr.SOA.MName) + 2 + len(rr.SOA.RName) + 2 + 20
case DNSTypeMX:
return 2 + len(rr.MX.Name) + 2
case DNSTypeTXT:
l := len(rr.TXTs)
for _, txt := range rr.TXTs {
l += len(txt)
}
return l
case DNSTypeSRV:
return 6 + len(rr.SRV.Name) + 2
case DNSTypeURI:
return 4 + len(rr.URI.Target)
case DNSTypeOPT:
l := len(rr.OPT) * 4
for _, opt := range rr.OPT {
l += len(opt.Data)
}
return l
}
return 0
}
func computeSize(recs []DNSResourceRecord) int {
sz := 0
for _, rr := range recs {
v := len(rr.Name)
if v == 0 {
sz += v + 11
} else {
sz += v + 12
}
sz += recSize(&rr)
}
return sz
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
func (d *DNS) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
dsz := 0
for _, q := range d.Questions {
dsz += len(q.Name) + 6
}
dsz += computeSize(d.Answers)
dsz += computeSize(d.Authorities)
dsz += computeSize(d.Additionals)
bytes, err := b.PrependBytes(12 + dsz)
if err != nil {
return err
}
binary.BigEndian.PutUint16(bytes, d.ID)
bytes[2] = byte((b2i(d.QR) << 7) | (int(d.OpCode) << 3) | (b2i(d.AA) << 2) | (b2i(d.TC) << 1) | b2i(d.RD))
bytes[3] = byte((b2i(d.RA) << 7) | (int(d.Z) << 4) | int(d.ResponseCode))
if opts.FixLengths {
d.QDCount = uint16(len(d.Questions))
d.ANCount = uint16(len(d.Answers))
d.NSCount = uint16(len(d.Authorities))
d.ARCount = uint16(len(d.Additionals))
}
binary.BigEndian.PutUint16(bytes[4:], d.QDCount)
binary.BigEndian.PutUint16(bytes[6:], d.ANCount)
binary.BigEndian.PutUint16(bytes[8:], d.NSCount)
binary.BigEndian.PutUint16(bytes[10:], d.ARCount)
off := 12
for _, qd := range d.Questions {
n := qd.encode(bytes, off)
off += n
}
for i := range d.Answers {
// done this way so we can modify DNSResourceRecord to fix
// lengths if requested
qa := &d.Answers[i]
n, err := qa.encode(bytes, off, opts)
if err != nil {
return err
}
off += n
}
for i := range d.Authorities {
qa := &d.Authorities[i]
n, err := qa.encode(bytes, off, opts)
if err != nil {
return err
}
off += n
}
for i := range d.Additionals {
qa := &d.Additionals[i]
n, err := qa.encode(bytes, off, opts)
if err != nil {
return err
}
off += n
}
return nil
}
const maxRecursionLevel = 255
func decodeName(data []byte, offset int, buffer *[]byte, level int) ([]byte, int, error) {
if level > maxRecursionLevel {
return nil, 0, errMaxRecursion
} else if offset >= len(data) {
return nil, 0, errDNSNameOffsetTooHigh
} else if offset < 0 {
return nil, 0, errDNSNameOffsetNegative
}
start := len(*buffer)
index := offset
if data[index] == 0x00 {
return nil, index + 1, nil
}
loop:
for data[index] != 0x00 {
switch data[index] & 0xc0 {
default:
/* RFC 1035
A domain name represented as a sequence of labels, where
each label consists of a length octet followed by that
number of octets. The domain name terminates with the
zero length octet for the null label of the root. Note
that this field may be an odd number of octets; no
padding is used.
*/
index2 := index + int(data[index]) + 1
if index2-offset > 255 {
return nil, 0, errDNSNameTooLong
} else if index2 < index+1 || index2 > len(data) {
return nil, 0, errDNSNameInvalidIndex
}
*buffer = append(*buffer, '.')
*buffer = append(*buffer, data[index+1:index2]...)
index = index2
case 0xc0:
/* RFC 1035
The pointer takes the form of a two octet sequence.
The first two bits are ones. This allows a pointer to
be distinguished from a label, since the label must
begin with two zero bits because labels are restricted
to 63 octets or less. (The 10 and 01 combinations are
reserved for future use.) The OFFSET field specifies
an offset from the start of the message (i.e., the
first octet of the ID field in the domain header). A
zero offset specifies the first byte of the ID field,
etc.
The compression scheme allows a domain name in a message to be
represented as either:
- a sequence of labels ending in a zero octet
- a pointer
- a sequence of labels ending with a pointer
*/
if index+2 > len(data) {
return nil, 0, errDNSPointerOffsetTooHigh
}
offsetp := int(binary.BigEndian.Uint16(data[index:index+2]) & 0x3fff)
if offsetp > len(data) {
return nil, 0, errDNSPointerOffsetTooHigh
}
// This looks a little tricky, but actually isn't. Because of how
// decodeName is written, calling it appends the decoded name to the
// current buffer. We already have the start of the buffer, then, so
// once this call is done buffer[start:] will contain our full name.
_, _, err := decodeName(data, offsetp, buffer, level+1)
if err != nil {
return nil, 0, err
}
index++ // pointer is two bytes, so add an extra byte here.
break loop
/* EDNS, or other DNS option ? */
case 0x40: // RFC 2673
return nil, 0, fmt.Errorf("qname '0x40' - RFC 2673 unsupported yet (data=%x index=%d)",
data[index], index)
case 0x80:
return nil, 0, fmt.Errorf("qname '0x80' unsupported yet (data=%x index=%d)",
data[index], index)
}
if index >= len(data) {
return nil, 0, errDNSIndexOutOfRange
}
}
if len(*buffer) <= start {
return (*buffer)[start:], index + 1, nil
}
return (*buffer)[start+1:], index + 1, nil
}
// DNSQuestion wraps a single request (question) within a DNS query.
type DNSQuestion struct {
Name []byte
Type DNSType
Class DNSClass
}
func (q *DNSQuestion) decode(data []byte, offset int, df gopacket.DecodeFeedback, buffer *[]byte) (int, error) {
name, endq, err := decodeName(data, offset, buffer, 1)
if err != nil {
return 0, err
}
if len(data) < endq+4 {
return 0, errors.New("DNS question too small")
}
q.Name = name
q.Type = DNSType(binary.BigEndian.Uint16(data[endq : endq+2]))
q.Class = DNSClass(binary.BigEndian.Uint16(data[endq+2 : endq+4]))
return endq + 4, nil
}
func (q *DNSQuestion) encode(data []byte, offset int) int {
noff := encodeName(q.Name, data, offset)
nSz := noff - offset
binary.BigEndian.PutUint16(data[noff:], uint16(q.Type))
binary.BigEndian.PutUint16(data[noff+2:], uint16(q.Class))
return nSz + 4
}
// DNSResourceRecord
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | |
// / /
// / NAME /
// | |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | TYPE |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | CLASS |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | TTL |
// | |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | RDLENGTH |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
// / RDATA /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// DNSResourceRecord wraps the data from a single DNS resource within a
// response.
type DNSResourceRecord struct {
// Header
Name []byte
Type DNSType
Class DNSClass
TTL uint32
// RDATA Raw Values
DataLength uint16
Data []byte
// RDATA Decoded Values
IP net.IP
NS, CNAME, PTR []byte
TXTs [][]byte
SOA DNSSOA
SRV DNSSRV
MX DNSMX
OPT []DNSOPT // See RFC 6891, section 6.1.2
URI DNSURI
// Undecoded TXT for backward compatibility
TXT []byte
}
// decode decodes the resource record, returning the total length of the record.
func (rr *DNSResourceRecord) decode(data []byte, offset int, df gopacket.DecodeFeedback, buffer *[]byte) (int, error) {
name, endq, err := decodeName(data, offset, buffer, 1)
if err != nil {
return 0, err
}
if len(data) < endq+10 {
return 0, errors.New("DNS record too small")
}
rr.Name = name
rr.Type = DNSType(binary.BigEndian.Uint16(data[endq : endq+2]))
rr.Class = DNSClass(binary.BigEndian.Uint16(data[endq+2 : endq+4]))
rr.TTL = binary.BigEndian.Uint32(data[endq+4 : endq+8])
rr.DataLength = binary.BigEndian.Uint16(data[endq+8 : endq+10])
end := endq + 10 + int(rr.DataLength)
if end > len(data) {
return 0, errDecodeRecordLength
}
rr.Data = data[endq+10 : end]
if rr.DataLength > 0 {
if err = rr.decodeRData(data[:end], endq+10, buffer); err != nil {
return 0, err
}
}
return endq + 10 + int(rr.DataLength), nil
}
func encodeName(name []byte, data []byte, offset int) int {
l := 0
for i := range name {
if name[i] == '.' {
data[offset+i-l] = byte(l)
l = 0
} else {
// skip one to write the length
data[offset+i+1] = name[i]
l++
}
}
if len(name) == 0 {
data[offset] = 0x00 // terminal
return offset + 1
}
// length for final portion
data[offset+len(name)-l] = byte(l)
data[offset+len(name)+1] = 0x00 // terminal
return offset + len(name) + 2
}
func (rr *DNSResourceRecord) encode(data []byte, offset int, opts gopacket.SerializeOptions) (int, error) {
noff := encodeName(rr.Name, data, offset)
nSz := noff - offset
binary.BigEndian.PutUint16(data[noff:], uint16(rr.Type))
binary.BigEndian.PutUint16(data[noff+2:], uint16(rr.Class))
binary.BigEndian.PutUint32(data[noff+4:], uint32(rr.TTL))
switch rr.Type {
case DNSTypeA:
copy(data[noff+10:], rr.IP.To4())
case DNSTypeAAAA:
copy(data[noff+10:], rr.IP)
case DNSTypeNS:
encodeName(rr.NS, data, noff+10)
case DNSTypeCNAME:
encodeName(rr.CNAME, data, noff+10)
case DNSTypePTR:
encodeName(rr.PTR, data, noff+10)
case DNSTypeSOA:
noff2 := encodeName(rr.SOA.MName, data, noff+10)
noff2 = encodeName(rr.SOA.RName, data, noff2)
binary.BigEndian.PutUint32(data[noff2:], rr.SOA.Serial)
binary.BigEndian.PutUint32(data[noff2+4:], rr.SOA.Refresh)
binary.BigEndian.PutUint32(data[noff2+8:], rr.SOA.Retry)
binary.BigEndian.PutUint32(data[noff2+12:], rr.SOA.Expire)
binary.BigEndian.PutUint32(data[noff2+16:], rr.SOA.Minimum)
case DNSTypeMX:
binary.BigEndian.PutUint16(data[noff+10:], rr.MX.Preference)
encodeName(rr.MX.Name, data, noff+12)
case DNSTypeTXT:
noff2 := noff + 10
for _, txt := range rr.TXTs {
data[noff2] = byte(len(txt))
copy(data[noff2+1:], txt)
noff2 += 1 + len(txt)
}
case DNSTypeSRV:
binary.BigEndian.PutUint16(data[noff+10:], rr.SRV.Priority)
binary.BigEndian.PutUint16(data[noff+12:], rr.SRV.Weight)
binary.BigEndian.PutUint16(data[noff+14:], rr.SRV.Port)
encodeName(rr.SRV.Name, data, noff+16)
case DNSTypeURI:
binary.BigEndian.PutUint16(data[noff+10:], rr.URI.Priority)
binary.BigEndian.PutUint16(data[noff+12:], rr.URI.Weight)
copy(data[noff+14:], rr.URI.Target)
case DNSTypeOPT:
noff2 := noff + 10
for _, opt := range rr.OPT {
binary.BigEndian.PutUint16(data[noff2:], uint16(opt.Code))
binary.BigEndian.PutUint16(data[noff2+2:], uint16(len(opt.Data)))
copy(data[noff2+4:], opt.Data)
noff2 += 4 + len(opt.Data)
}
default:
return 0, fmt.Errorf("serializing resource record of type %v not supported", rr.Type)
}
// DataLength
dSz := recSize(rr)
binary.BigEndian.PutUint16(data[noff+8:], uint16(dSz))
if opts.FixLengths {
rr.DataLength = uint16(dSz)
}
return nSz + 10 + dSz, nil
}
func (rr *DNSResourceRecord) String() string {
if rr.Type == DNSTypeOPT {
opts := make([]string, len(rr.OPT))
for i, opt := range rr.OPT {
opts[i] = opt.String()
}
return "OPT " + strings.Join(opts, ",")
}
if rr.Type == DNSTypeURI {
return fmt.Sprintf("URI %d %d %s", rr.URI.Priority, rr.URI.Weight, string(rr.URI.Target))
}
if rr.Class == DNSClassIN {
switch rr.Type {
case DNSTypeA, DNSTypeAAAA:
return rr.IP.String()
case DNSTypeNS:
return "NS " + string(rr.NS)
case DNSTypeCNAME:
return "CNAME " + string(rr.CNAME)
case DNSTypePTR:
return "PTR " + string(rr.PTR)
case DNSTypeTXT:
return "TXT " + string(rr.TXT)
}
}
return fmt.Sprintf("<%v, %v>", rr.Class, rr.Type)
}
func decodeCharacterStrings(data []byte) ([][]byte, error) {
strings := make([][]byte, 0, 1)
end := len(data)
for index, index2 := 0, 0; index != end; index = index2 {
index2 = index + 1 + int(data[index]) // index increases by 1..256 and does not overflow
if index2 > end {
return nil, errCharStringMissData
}
strings = append(strings, data[index+1:index2])
}
return strings, nil
}
func decodeOPTs(data []byte, offset int) ([]DNSOPT, error) {
allOPT := []DNSOPT{}
end := len(data)
if offset == end {
return allOPT, nil // There is no data to read
}
if offset+4 > end {
return allOPT, fmt.Errorf("DNSOPT record is of length %d, it should be at least length 4", end-offset)
}
for i := offset; i < end; {
opt := DNSOPT{}
if len(data) < i+4 {
return allOPT, fmt.Errorf("Malformed DNSOPT record. Length %d < %d", len(data), i+4)
}
opt.Code = DNSOptionCode(binary.BigEndian.Uint16(data[i : i+2]))
l := binary.BigEndian.Uint16(data[i+2 : i+4])
if i+4+int(l) > end {
return allOPT, fmt.Errorf("Malformed DNSOPT record. The length (%d) field implies a packet larger than the one received", l)
}
opt.Data = data[i+4 : i+4+int(l)]
allOPT = append(allOPT, opt)
i += int(l) + 4
}
return allOPT, nil
}
func (rr *DNSResourceRecord) decodeRData(data []byte, offset int, buffer *[]byte) error {
switch rr.Type {
case DNSTypeA:
rr.IP = rr.Data
case DNSTypeAAAA:
rr.IP = rr.Data
case DNSTypeTXT, DNSTypeHINFO:
rr.TXT = rr.Data
txts, err := decodeCharacterStrings(rr.Data)
if err != nil {
return err
}
rr.TXTs = txts
case DNSTypeNS:
name, _, err := decodeName(data, offset, buffer, 1)
if err != nil {
return err
}
rr.NS = name
case DNSTypeCNAME:
name, _, err := decodeName(data, offset, buffer, 1)
if err != nil {
return err
}
rr.CNAME = name
case DNSTypePTR:
name, _, err := decodeName(data, offset, buffer, 1)
if err != nil {
return err
}
rr.PTR = name
case DNSTypeSOA:
name, endq, err := decodeName(data, offset, buffer, 1)
if err != nil {
return err
}
rr.SOA.MName = name
name, endq, err = decodeName(data, endq, buffer, 1)
if err != nil {
return err
}
if len(data) < endq+20 {
return errors.New("SOA too small")
}
rr.SOA.RName = name
rr.SOA.Serial = binary.BigEndian.Uint32(data[endq : endq+4])
rr.SOA.Refresh = binary.BigEndian.Uint32(data[endq+4 : endq+8])
rr.SOA.Retry = binary.BigEndian.Uint32(data[endq+8 : endq+12])
rr.SOA.Expire = binary.BigEndian.Uint32(data[endq+12 : endq+16])
rr.SOA.Minimum = binary.BigEndian.Uint32(data[endq+16 : endq+20])
case DNSTypeMX:
if len(data) < offset+2 {
return errors.New("MX too small")
}
rr.MX.Preference = binary.BigEndian.Uint16(data[offset : offset+2])
name, _, err := decodeName(data, offset+2, buffer, 1)
if err != nil {
return err
}
rr.MX.Name = name
case DNSTypeURI:
if len(rr.Data) < 4 {
return errors.New("URI too small")
}
rr.URI.Priority = binary.BigEndian.Uint16(data[offset : offset+2])
rr.URI.Weight = binary.BigEndian.Uint16(data[offset+2 : offset+4])
rr.URI.Target = rr.Data[4:]
case DNSTypeSRV:
if len(data) < offset+6 {
return errors.New("SRV too small")
}
rr.SRV.Priority = binary.BigEndian.Uint16(data[offset : offset+2])
rr.SRV.Weight = binary.BigEndian.Uint16(data[offset+2 : offset+4])
rr.SRV.Port = binary.BigEndian.Uint16(data[offset+4 : offset+6])
name, _, err := decodeName(data, offset+6, buffer, 1)
if err != nil {
return err
}
rr.SRV.Name = name
case DNSTypeOPT:
allOPT, err := decodeOPTs(data, offset)
if err != nil {
return err
}
rr.OPT = allOPT
}
return nil
}
// DNSSOA is a Start of Authority record. Each domain requires a SOA record at
// the cutover where a domain is delegated from its parent.
type DNSSOA struct {
MName, RName []byte
Serial, Refresh, Retry, Expire, Minimum uint32
}
// DNSSRV is a Service record, defining a location (hostname/port) of a
// server/service.
type DNSSRV struct {
Priority, Weight, Port uint16
Name []byte
}
// DNSMX is a mail exchange record, defining a mail server for a recipient's
// domain.
type DNSMX struct {
Preference uint16
Name []byte
}
// DNSURI is a URI record, defining a target (URI) of a server/service
type DNSURI struct {
Priority, Weight uint16
Target []byte
}
// DNSOptionCode represents the code of a DNS Option, see RFC6891, section 6.1.2
type DNSOptionCode uint16
func (doc DNSOptionCode) String() string {
switch doc {
default:
return "Unknown"
case DNSOptionCodeNSID:
return "NSID"
case DNSOptionCodeDAU:
return "DAU"
case DNSOptionCodeDHU:
return "DHU"
case DNSOptionCodeN3U:
return "N3U"
case DNSOptionCodeEDNSClientSubnet:
return "EDNSClientSubnet"
case DNSOptionCodeEDNSExpire:
return "EDNSExpire"
case DNSOptionCodeCookie:
return "Cookie"
case DNSOptionCodeEDNSKeepAlive:
return "EDNSKeepAlive"
case DNSOptionCodePadding:
return "CodePadding"
case DNSOptionCodeChain:
return "CodeChain"
case DNSOptionCodeEDNSKeyTag:
return "CodeEDNSKeyTag"
case DNSOptionCodeEDNSClientTag:
return "EDNSClientTag"
case DNSOptionCodeEDNSServerTag:
return "EDNSServerTag"
case DNSOptionCodeDeviceID:
return "DeviceID"
}
}
// DNSOptionCode known values. See IANA
const (
DNSOptionCodeNSID DNSOptionCode = 3
DNSOptionCodeDAU DNSOptionCode = 5
DNSOptionCodeDHU DNSOptionCode = 6
DNSOptionCodeN3U DNSOptionCode = 7
DNSOptionCodeEDNSClientSubnet DNSOptionCode = 8
DNSOptionCodeEDNSExpire DNSOptionCode = 9
DNSOptionCodeCookie DNSOptionCode = 10
DNSOptionCodeEDNSKeepAlive DNSOptionCode = 11
DNSOptionCodePadding DNSOptionCode = 12
DNSOptionCodeChain DNSOptionCode = 13
DNSOptionCodeEDNSKeyTag DNSOptionCode = 14
DNSOptionCodeEDNSClientTag DNSOptionCode = 16
DNSOptionCodeEDNSServerTag DNSOptionCode = 17
DNSOptionCodeDeviceID DNSOptionCode = 26946
)
// DNSOPT is a DNS Option, see RFC6891, section 6.1.2
type DNSOPT struct {
Code DNSOptionCode
Data []byte
}
func (opt DNSOPT) String() string {
return fmt.Sprintf("%s=%x", opt.Code, opt.Data)
}
var (
errMaxRecursion = errors.New("max DNS recursion level hit")
errDNSNameOffsetTooHigh = errors.New("dns name offset too high")
errDNSNameOffsetNegative = errors.New("dns name offset is negative")
errDNSPacketTooShort = errors.New("DNS packet too short")
errDNSNameTooLong = errors.New("dns name is too long")
errDNSNameInvalidIndex = errors.New("dns name uncomputable: invalid index")
errDNSPointerOffsetTooHigh = errors.New("dns offset pointer too high")
errDNSIndexOutOfRange = errors.New("dns index walked out of range")
errDNSNameHasNoData = errors.New("no dns data found for name")
errCharStringMissData = errors.New("Insufficient data for a <character-string>")
errDecodeRecordLength = errors.New("resource record length exceeds data")
errDecodeQueryBadQDCount = errors.New("Invalid query decoding, not the right number of questions")
errDecodeQueryBadANCount = errors.New("Invalid query decoding, not the right number of answers")
errDecodeQueryBadNSCount = errors.New("Invalid query decoding, not the right number of authorities")
errDecodeQueryBadARCount = errors.New("Invalid query decoding, not the right number of additionals info")
)
// Copyright 2014 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
// See http://standards.ieee.org/findstds/standard/802.11-2012.html for info on
// all of the layers in this file.
package layers
import (
"bytes"
"encoding/binary"
"fmt"
"hash/crc32"
"net"
"github.com/google/gopacket"
)
// Dot11Flags contains the set of 8 flags in the IEEE 802.11 frame control
// header, all in one place.
type Dot11Flags uint8
const (
Dot11FlagsToDS Dot11Flags = 1 << iota
Dot11FlagsFromDS
Dot11FlagsMF
Dot11FlagsRetry
Dot11FlagsPowerManagement
Dot11FlagsMD
Dot11FlagsWEP
Dot11FlagsOrder
)
func (d Dot11Flags) ToDS() bool {
return d&Dot11FlagsToDS != 0
}
func (d Dot11Flags) FromDS() bool {
return d&Dot11FlagsFromDS != 0
}
func (d Dot11Flags) MF() bool {
return d&Dot11FlagsMF != 0
}
func (d Dot11Flags) Retry() bool {
return d&Dot11FlagsRetry != 0
}
func (d Dot11Flags) PowerManagement() bool {
return d&Dot11FlagsPowerManagement != 0
}
func (d Dot11Flags) MD() bool {
return d&Dot11FlagsMD != 0
}
func (d Dot11Flags) WEP() bool {
return d&Dot11FlagsWEP != 0
}
func (d Dot11Flags) Order() bool {
return d&Dot11FlagsOrder != 0
}
// String provides a human readable string for Dot11Flags.
// This string is possibly subject to change over time; if you're storing this
// persistently, you should probably store the Dot11Flags value, not its string.
func (a Dot11Flags) String() string {
var out bytes.Buffer
if a.ToDS() {
out.WriteString("TO-DS,")
}
if a.FromDS() {
out.WriteString("FROM-DS,")
}
if a.MF() {
out.WriteString("MF,")
}
if a.Retry() {
out.WriteString("Retry,")
}
if a.PowerManagement() {
out.WriteString("PowerManagement,")
}
if a.MD() {
out.WriteString("MD,")
}
if a.WEP() {
out.WriteString("WEP,")
}
if a.Order() {
out.WriteString("Order,")
}
if length := out.Len(); length > 0 {
return string(out.Bytes()[:length-1]) // strip final comma
}
return ""
}
type Dot11Reason uint16
// TODO: Verify these reasons, and append more reasons if necessary.
const (
Dot11ReasonReserved Dot11Reason = 1
Dot11ReasonUnspecified Dot11Reason = 2
Dot11ReasonAuthExpired Dot11Reason = 3
Dot11ReasonDeauthStLeaving Dot11Reason = 4
Dot11ReasonInactivity Dot11Reason = 5
Dot11ReasonApFull Dot11Reason = 6
Dot11ReasonClass2FromNonAuth Dot11Reason = 7
Dot11ReasonClass3FromNonAss Dot11Reason = 8
Dot11ReasonDisasStLeaving Dot11Reason = 9
Dot11ReasonStNotAuth Dot11Reason = 10
)
// String provides a human readable string for Dot11Reason.
// This string is possibly subject to change over time; if you're storing this
// persistently, you should probably store the Dot11Reason value, not its string.
func (a Dot11Reason) String() string {
switch a {
case Dot11ReasonReserved:
return "Reserved"
case Dot11ReasonUnspecified:
return "Unspecified"
case Dot11ReasonAuthExpired:
return "Auth. expired"
case Dot11ReasonDeauthStLeaving:
return "Deauth. st. leaving"
case Dot11ReasonInactivity:
return "Inactivity"
case Dot11ReasonApFull:
return "Ap. full"
case Dot11ReasonClass2FromNonAuth:
return "Class2 from non auth."
case Dot11ReasonClass3FromNonAss:
return "Class3 from non ass."
case Dot11ReasonDisasStLeaving:
return "Disass st. leaving"
case Dot11ReasonStNotAuth:
return "St. not auth."
default:
return "Unknown reason"
}
}
type Dot11Status uint16
const (
Dot11StatusSuccess Dot11Status = 0
Dot11StatusFailure Dot11Status = 1 // Unspecified failure
Dot11StatusCannotSupportAllCapabilities Dot11Status = 10 // Cannot support all requested capabilities in the Capability Information field
Dot11StatusInabilityExistsAssociation Dot11Status = 11 // Reassociation denied due to inability to confirm that association exists
Dot11StatusAssociationDenied Dot11Status = 12 // Association denied due to reason outside the scope of this standard
Dot11StatusAlgorithmUnsupported Dot11Status = 13 // Responding station does not support the specified authentication algorithm
Dot11StatusOufOfExpectedSequence Dot11Status = 14 // Received an Authentication frame with authentication transaction sequence number out of expected sequence
Dot11StatusChallengeFailure Dot11Status = 15 // Authentication rejected because of challenge failure
Dot11StatusTimeout Dot11Status = 16 // Authentication rejected due to timeout waiting for next frame in sequence
Dot11StatusAPUnableToHandle Dot11Status = 17 // Association denied because AP is unable to handle additional associated stations
Dot11StatusRateUnsupported Dot11Status = 18 // Association denied due to requesting station not supporting all of the data rates in the BSSBasicRateSet parameter
)
// String provides a human readable string for Dot11Status.
// This string is possibly subject to change over time; if you're storing this
// persistently, you should probably store the Dot11Status value, not its string.
func (a Dot11Status) String() string {
switch a {
case Dot11StatusSuccess:
return "success"
case Dot11StatusFailure:
return "failure"
case Dot11StatusCannotSupportAllCapabilities:
return "cannot-support-all-capabilities"
case Dot11StatusInabilityExistsAssociation:
return "inability-exists-association"
case Dot11StatusAssociationDenied:
return "association-denied"
case Dot11StatusAlgorithmUnsupported:
return "algorithm-unsupported"
case Dot11StatusOufOfExpectedSequence:
return "out-of-expected-sequence"
case Dot11StatusChallengeFailure:
return "challenge-failure"
case Dot11StatusTimeout:
return "timeout"
case Dot11StatusAPUnableToHandle:
return "ap-unable-to-handle"
case Dot11StatusRateUnsupported:
return "rate-unsupported"
default:
return "unknown status"
}
}
type Dot11AckPolicy uint8
const (
Dot11AckPolicyNormal Dot11AckPolicy = 0
Dot11AckPolicyNone Dot11AckPolicy = 1
Dot11AckPolicyNoExplicit Dot11AckPolicy = 2
Dot11AckPolicyBlock Dot11AckPolicy = 3
)
// String provides a human readable string for Dot11AckPolicy.
// This string is possibly subject to change over time; if you're storing this
// persistently, you should probably store the Dot11AckPolicy value, not its string.
func (a Dot11AckPolicy) String() string {
switch a {
case Dot11AckPolicyNormal:
return "normal-ack"
case Dot11AckPolicyNone:
return "no-ack"
case Dot11AckPolicyNoExplicit:
return "no-explicit-ack"
case Dot11AckPolicyBlock:
return "block-ack"
default:
return "unknown-ack-policy"
}
}
type Dot11Algorithm uint16
const (
Dot11AlgorithmOpen Dot11Algorithm = 0
Dot11AlgorithmSharedKey Dot11Algorithm = 1
)
// String provides a human readable string for Dot11Algorithm.
// This string is possibly subject to change over time; if you're storing this
// persistently, you should probably store the Dot11Algorithm value, not its string.
func (a Dot11Algorithm) String() string {
switch a {
case Dot11AlgorithmOpen:
return "open"
case Dot11AlgorithmSharedKey:
return "shared-key"
default:
return "unknown-algorithm"
}
}
type Dot11InformationElementID uint8
const (
Dot11InformationElementIDSSID Dot11InformationElementID = 0
Dot11InformationElementIDRates Dot11InformationElementID = 1
Dot11InformationElementIDFHSet Dot11InformationElementID = 2
Dot11InformationElementIDDSSet Dot11InformationElementID = 3
Dot11InformationElementIDCFSet Dot11InformationElementID = 4
Dot11InformationElementIDTIM Dot11InformationElementID = 5
Dot11InformationElementIDIBSSSet Dot11InformationElementID = 6
Dot11InformationElementIDCountryInfo Dot11InformationElementID = 7
Dot11InformationElementIDHoppingPatternParam Dot11InformationElementID = 8
Dot11InformationElementIDHoppingPatternTable Dot11InformationElementID = 9
Dot11InformationElementIDRequest Dot11InformationElementID = 10
Dot11InformationElementIDQBSSLoadElem Dot11InformationElementID = 11
Dot11InformationElementIDEDCAParamSet Dot11InformationElementID = 12
Dot11InformationElementIDTrafficSpec Dot11InformationElementID = 13
Dot11InformationElementIDTrafficClass Dot11InformationElementID = 14
Dot11InformationElementIDSchedule Dot11InformationElementID = 15
Dot11InformationElementIDChallenge Dot11InformationElementID = 16
Dot11InformationElementIDPowerConst Dot11InformationElementID = 32
Dot11InformationElementIDPowerCapability Dot11InformationElementID = 33
Dot11InformationElementIDTPCRequest Dot11InformationElementID = 34
Dot11InformationElementIDTPCReport Dot11InformationElementID = 35
Dot11InformationElementIDSupportedChannels Dot11InformationElementID = 36
Dot11InformationElementIDSwitchChannelAnnounce Dot11InformationElementID = 37
Dot11InformationElementIDMeasureRequest Dot11InformationElementID = 38
Dot11InformationElementIDMeasureReport Dot11InformationElementID = 39
Dot11InformationElementIDQuiet Dot11InformationElementID = 40
Dot11InformationElementIDIBSSDFS Dot11InformationElementID = 41
Dot11InformationElementIDERPInfo Dot11InformationElementID = 42
Dot11InformationElementIDTSDelay Dot11InformationElementID = 43
Dot11InformationElementIDTCLASProcessing Dot11InformationElementID = 44
Dot11InformationElementIDHTCapabilities Dot11InformationElementID = 45
Dot11InformationElementIDQOSCapability Dot11InformationElementID = 46
Dot11InformationElementIDERPInfo2 Dot11InformationElementID = 47
Dot11InformationElementIDRSNInfo Dot11InformationElementID = 48
Dot11InformationElementIDESRates Dot11InformationElementID = 50
Dot11InformationElementIDAPChannelReport Dot11InformationElementID = 51
Dot11InformationElementIDNeighborReport Dot11InformationElementID = 52
Dot11InformationElementIDRCPI Dot11InformationElementID = 53
Dot11InformationElementIDMobilityDomain Dot11InformationElementID = 54
Dot11InformationElementIDFastBSSTrans Dot11InformationElementID = 55
Dot11InformationElementIDTimeoutInt Dot11InformationElementID = 56
Dot11InformationElementIDRICData Dot11InformationElementID = 57
Dot11InformationElementIDDSERegisteredLoc Dot11InformationElementID = 58
Dot11InformationElementIDSuppOperatingClass Dot11InformationElementID = 59
Dot11InformationElementIDExtChanSwitchAnnounce Dot11InformationElementID = 60
Dot11InformationElementIDHTInfo Dot11InformationElementID = 61
Dot11InformationElementIDSecChanOffset Dot11InformationElementID = 62
Dot11InformationElementIDBSSAverageAccessDelay Dot11InformationElementID = 63
Dot11InformationElementIDAntenna Dot11InformationElementID = 64
Dot11InformationElementIDRSNI Dot11InformationElementID = 65
Dot11InformationElementIDMeasurePilotTrans Dot11InformationElementID = 66
Dot11InformationElementIDBSSAvailAdmCapacity Dot11InformationElementID = 67
Dot11InformationElementIDBSSACAccDelayWAPIParam Dot11InformationElementID = 68
Dot11InformationElementIDTimeAdvertisement Dot11InformationElementID = 69
Dot11InformationElementIDRMEnabledCapabilities Dot11InformationElementID = 70
Dot11InformationElementIDMultipleBSSID Dot11InformationElementID = 71
Dot11InformationElementID2040BSSCoExist Dot11InformationElementID = 72
Dot11InformationElementID2040BSSIntChanReport Dot11InformationElementID = 73
Dot11InformationElementIDOverlapBSSScanParam Dot11InformationElementID = 74
Dot11InformationElementIDRICDescriptor Dot11InformationElementID = 75
Dot11InformationElementIDManagementMIC Dot11InformationElementID = 76
Dot11InformationElementIDEventRequest Dot11InformationElementID = 78
Dot11InformationElementIDEventReport Dot11InformationElementID = 79
Dot11InformationElementIDDiagnosticRequest Dot11InformationElementID = 80
Dot11InformationElementIDDiagnosticReport Dot11InformationElementID = 81
Dot11InformationElementIDLocationParam Dot11InformationElementID = 82
Dot11InformationElementIDNonTransBSSIDCapability Dot11InformationElementID = 83
Dot11InformationElementIDSSIDList Dot11InformationElementID = 84
Dot11InformationElementIDMultipleBSSIDIndex Dot11InformationElementID = 85
Dot11InformationElementIDFMSDescriptor Dot11InformationElementID = 86
Dot11InformationElementIDFMSRequest Dot11InformationElementID = 87
Dot11InformationElementIDFMSResponse Dot11InformationElementID = 88
Dot11InformationElementIDQOSTrafficCapability Dot11InformationElementID = 89
Dot11InformationElementIDBSSMaxIdlePeriod Dot11InformationElementID = 90
Dot11InformationElementIDTFSRequest Dot11InformationElementID = 91
Dot11InformationElementIDTFSResponse Dot11InformationElementID = 92
Dot11InformationElementIDWNMSleepMode Dot11InformationElementID = 93
Dot11InformationElementIDTIMBroadcastRequest Dot11InformationElementID = 94
Dot11InformationElementIDTIMBroadcastResponse Dot11InformationElementID = 95
Dot11InformationElementIDCollInterferenceReport Dot11InformationElementID = 96
Dot11InformationElementIDChannelUsage Dot11InformationElementID = 97
Dot11InformationElementIDTimeZone Dot11InformationElementID = 98
Dot11InformationElementIDDMSRequest Dot11InformationElementID = 99
Dot11InformationElementIDDMSResponse Dot11InformationElementID = 100
Dot11InformationElementIDLinkIdentifier Dot11InformationElementID = 101
Dot11InformationElementIDWakeupSchedule Dot11InformationElementID = 102
Dot11InformationElementIDChannelSwitchTiming Dot11InformationElementID = 104
Dot11InformationElementIDPTIControl Dot11InformationElementID = 105
Dot11InformationElementIDPUBufferStatus Dot11InformationElementID = 106
Dot11InformationElementIDInterworking Dot11InformationElementID = 107
Dot11InformationElementIDAdvertisementProtocol Dot11InformationElementID = 108
Dot11InformationElementIDExpBWRequest Dot11InformationElementID = 109
Dot11InformationElementIDQOSMapSet Dot11InformationElementID = 110
Dot11InformationElementIDRoamingConsortium Dot11InformationElementID = 111
Dot11InformationElementIDEmergencyAlertIdentifier Dot11InformationElementID = 112
Dot11InformationElementIDMeshConfiguration Dot11InformationElementID = 113
Dot11InformationElementIDMeshID Dot11InformationElementID = 114
Dot11InformationElementIDMeshLinkMetricReport Dot11InformationElementID = 115
Dot11InformationElementIDCongestionNotification Dot11InformationElementID = 116
Dot11InformationElementIDMeshPeeringManagement Dot11InformationElementID = 117
Dot11InformationElementIDMeshChannelSwitchParam Dot11InformationElementID = 118
Dot11InformationElementIDMeshAwakeWindows Dot11InformationElementID = 119
Dot11InformationElementIDBeaconTiming Dot11InformationElementID = 120
Dot11InformationElementIDMCCAOPSetupRequest Dot11InformationElementID = 121
Dot11InformationElementIDMCCAOPSetupReply Dot11InformationElementID = 122
Dot11InformationElementIDMCCAOPAdvertisement Dot11InformationElementID = 123
Dot11InformationElementIDMCCAOPTeardown Dot11InformationElementID = 124
Dot11InformationElementIDGateAnnouncement Dot11InformationElementID = 125
Dot11InformationElementIDRootAnnouncement Dot11InformationElementID = 126
Dot11InformationElementIDExtCapability Dot11InformationElementID = 127
Dot11InformationElementIDAgereProprietary Dot11InformationElementID = 128
Dot11InformationElementIDPathRequest Dot11InformationElementID = 130
Dot11InformationElementIDPathReply Dot11InformationElementID = 131
Dot11InformationElementIDPathError Dot11InformationElementID = 132
Dot11InformationElementIDCiscoCCX1CKIPDeviceName Dot11InformationElementID = 133
Dot11InformationElementIDCiscoCCX2 Dot11InformationElementID = 136
Dot11InformationElementIDProxyUpdate Dot11InformationElementID = 137
Dot11InformationElementIDProxyUpdateConfirmation Dot11InformationElementID = 138
Dot11InformationElementIDAuthMeshPerringExch Dot11InformationElementID = 139
Dot11InformationElementIDMIC Dot11InformationElementID = 140
Dot11InformationElementIDDestinationURI Dot11InformationElementID = 141
Dot11InformationElementIDUAPSDCoexistence Dot11InformationElementID = 142
Dot11InformationElementIDWakeupSchedule80211ad Dot11InformationElementID = 143
Dot11InformationElementIDExtendedSchedule Dot11InformationElementID = 144
Dot11InformationElementIDSTAAvailability Dot11InformationElementID = 145
Dot11InformationElementIDDMGTSPEC Dot11InformationElementID = 146
Dot11InformationElementIDNextDMGATI Dot11InformationElementID = 147
Dot11InformationElementIDDMSCapabilities Dot11InformationElementID = 148
Dot11InformationElementIDCiscoUnknown95 Dot11InformationElementID = 149
Dot11InformationElementIDVendor2 Dot11InformationElementID = 150
Dot11InformationElementIDDMGOperating Dot11InformationElementID = 151
Dot11InformationElementIDDMGBSSParamChange Dot11InformationElementID = 152
Dot11InformationElementIDDMGBeamRefinement Dot11InformationElementID = 153
Dot11InformationElementIDChannelMeasFeedback Dot11InformationElementID = 154
Dot11InformationElementIDAwakeWindow Dot11InformationElementID = 157
Dot11InformationElementIDMultiBand Dot11InformationElementID = 158
Dot11InformationElementIDADDBAExtension Dot11InformationElementID = 159
Dot11InformationElementIDNEXTPCPList Dot11InformationElementID = 160
Dot11InformationElementIDPCPHandover Dot11InformationElementID = 161
Dot11InformationElementIDDMGLinkMargin Dot11InformationElementID = 162
Dot11InformationElementIDSwitchingStream Dot11InformationElementID = 163
Dot11InformationElementIDSessionTransmission Dot11InformationElementID = 164
Dot11InformationElementIDDynamicTonePairReport Dot11InformationElementID = 165
Dot11InformationElementIDClusterReport Dot11InformationElementID = 166
Dot11InformationElementIDRelayCapabilities Dot11InformationElementID = 167
Dot11InformationElementIDRelayTransferParameter Dot11InformationElementID = 168
Dot11InformationElementIDBeamlinkMaintenance Dot11InformationElementID = 169
Dot11InformationElementIDMultipleMacSublayers Dot11InformationElementID = 170
Dot11InformationElementIDUPID Dot11InformationElementID = 171
Dot11InformationElementIDDMGLinkAdaptionAck Dot11InformationElementID = 172
Dot11InformationElementIDSymbolProprietary Dot11InformationElementID = 173
Dot11InformationElementIDMCCAOPAdvertOverview Dot11InformationElementID = 174
Dot11InformationElementIDQuietPeriodRequest Dot11InformationElementID = 175
Dot11InformationElementIDQuietPeriodResponse Dot11InformationElementID = 177
Dot11InformationElementIDECPACPolicy Dot11InformationElementID = 182
Dot11InformationElementIDClusterTimeOffset Dot11InformationElementID = 183
Dot11InformationElementIDAntennaSectorID Dot11InformationElementID = 190
Dot11InformationElementIDVHTCapabilities Dot11InformationElementID = 191
Dot11InformationElementIDVHTOperation Dot11InformationElementID = 192
Dot11InformationElementIDExtendedBSSLoad Dot11InformationElementID = 193
Dot11InformationElementIDWideBWChannelSwitch Dot11InformationElementID = 194
Dot11InformationElementIDVHTTxPowerEnvelope Dot11InformationElementID = 195
Dot11InformationElementIDChannelSwitchWrapper Dot11InformationElementID = 196
Dot11InformationElementIDOperatingModeNotification Dot11InformationElementID = 199
Dot11InformationElementIDUPSIM Dot11InformationElementID = 200
Dot11InformationElementIDReducedNeighborReport Dot11InformationElementID = 201
Dot11InformationElementIDTVHTOperation Dot11InformationElementID = 202
Dot11InformationElementIDDeviceLocation Dot11InformationElementID = 204
Dot11InformationElementIDWhiteSpaceMap Dot11InformationElementID = 205
Dot11InformationElementIDFineTuningMeasureParams Dot11InformationElementID = 206
Dot11InformationElementIDVendor Dot11InformationElementID = 221
)
// String provides a human readable string for Dot11InformationElementID.
// This string is possibly subject to change over time; if you're storing this
// persistently, you should probably store the Dot11InformationElementID value,
// not its string.
func (a Dot11InformationElementID) String() string {
switch a {
case Dot11InformationElementIDSSID:
return "SSID parameter set"
case Dot11InformationElementIDRates:
return "Supported Rates"
case Dot11InformationElementIDFHSet:
return "FH Parameter set"
case Dot11InformationElementIDDSSet:
return "DS Parameter set"
case Dot11InformationElementIDCFSet:
return "CF Parameter set"
case Dot11InformationElementIDTIM:
return "Traffic Indication Map (TIM)"
case Dot11InformationElementIDIBSSSet:
return "IBSS Parameter set"
case Dot11InformationElementIDCountryInfo:
return "Country Information"
case Dot11InformationElementIDHoppingPatternParam:
return "Hopping Pattern Parameters"
case Dot11InformationElementIDHoppingPatternTable:
return "Hopping Pattern Table"
case Dot11InformationElementIDRequest:
return "Request"
case Dot11InformationElementIDQBSSLoadElem:
return "QBSS Load Element"
case Dot11InformationElementIDEDCAParamSet:
return "EDCA Parameter Set"
case Dot11InformationElementIDTrafficSpec:
return "Traffic Specification"
case Dot11InformationElementIDTrafficClass:
return "Traffic Classification"
case Dot11InformationElementIDSchedule:
return "Schedule"
case Dot11InformationElementIDChallenge:
return "Challenge text"
case Dot11InformationElementIDPowerConst:
return "Power Constraint"
case Dot11InformationElementIDPowerCapability:
return "Power Capability"
case Dot11InformationElementIDTPCRequest:
return "TPC Request"
case Dot11InformationElementIDTPCReport:
return "TPC Report"
case Dot11InformationElementIDSupportedChannels:
return "Supported Channels"
case Dot11InformationElementIDSwitchChannelAnnounce:
return "Channel Switch Announcement"
case Dot11InformationElementIDMeasureRequest:
return "Measurement Request"
case Dot11InformationElementIDMeasureReport:
return "Measurement Report"
case Dot11InformationElementIDQuiet:
return "Quiet"
case Dot11InformationElementIDIBSSDFS:
return "IBSS DFS"
case Dot11InformationElementIDERPInfo:
return "ERP Information"
case Dot11InformationElementIDTSDelay:
return "TS Delay"
case Dot11InformationElementIDTCLASProcessing:
return "TCLAS Processing"
case Dot11InformationElementIDHTCapabilities:
return "HT Capabilities (802.11n D1.10)"
case Dot11InformationElementIDQOSCapability:
return "QOS Capability"
case Dot11InformationElementIDERPInfo2:
return "ERP Information-2"
case Dot11InformationElementIDRSNInfo:
return "RSN Information"
case Dot11InformationElementIDESRates:
return "Extended Supported Rates"
case Dot11InformationElementIDAPChannelReport:
return "AP Channel Report"
case Dot11InformationElementIDNeighborReport:
return "Neighbor Report"
case Dot11InformationElementIDRCPI:
return "RCPI"
case Dot11InformationElementIDMobilityDomain:
return "Mobility Domain"
case Dot11InformationElementIDFastBSSTrans:
return "Fast BSS Transition"
case Dot11InformationElementIDTimeoutInt:
return "Timeout Interval"
case Dot11InformationElementIDRICData:
return "RIC Data"
case Dot11InformationElementIDDSERegisteredLoc:
return "DSE Registered Location"
case Dot11InformationElementIDSuppOperatingClass:
return "Supported Operating Classes"
case Dot11InformationElementIDExtChanSwitchAnnounce:
return "Extended Channel Switch Announcement"
case Dot11InformationElementIDHTInfo:
return "HT Information (802.11n D1.10)"
case Dot11InformationElementIDSecChanOffset:
return "Secondary Channel Offset (802.11n D1.10)"
case Dot11InformationElementIDBSSAverageAccessDelay:
return "BSS Average Access Delay"
case Dot11InformationElementIDAntenna:
return "Antenna"
case Dot11InformationElementIDRSNI:
return "RSNI"
case Dot11InformationElementIDMeasurePilotTrans:
return "Measurement Pilot Transmission"
case Dot11InformationElementIDBSSAvailAdmCapacity:
return "BSS Available Admission Capacity"
case Dot11InformationElementIDBSSACAccDelayWAPIParam:
return "BSS AC Access Delay/WAPI Parameter Set"
case Dot11InformationElementIDTimeAdvertisement:
return "Time Advertisement"
case Dot11InformationElementIDRMEnabledCapabilities:
return "RM Enabled Capabilities"
case Dot11InformationElementIDMultipleBSSID:
return "Multiple BSSID"
case Dot11InformationElementID2040BSSCoExist:
return "20/40 BSS Coexistence"
case Dot11InformationElementID2040BSSIntChanReport:
return "20/40 BSS Intolerant Channel Report"
case Dot11InformationElementIDOverlapBSSScanParam:
return "Overlapping BSS Scan Parameters"
case Dot11InformationElementIDRICDescriptor:
return "RIC Descriptor"
case Dot11InformationElementIDManagementMIC:
return "Management MIC"
case Dot11InformationElementIDEventRequest:
return "Event Request"
case Dot11InformationElementIDEventReport:
return "Event Report"
case Dot11InformationElementIDDiagnosticRequest:
return "Diagnostic Request"
case Dot11InformationElementIDDiagnosticReport:
return "Diagnostic Report"
case Dot11InformationElementIDLocationParam:
return "Location Parameters"
case Dot11InformationElementIDNonTransBSSIDCapability:
return "Non Transmitted BSSID Capability"
case Dot11InformationElementIDSSIDList:
return "SSID List"
case Dot11InformationElementIDMultipleBSSIDIndex:
return "Multiple BSSID Index"
case Dot11InformationElementIDFMSDescriptor:
return "FMS Descriptor"
case Dot11InformationElementIDFMSRequest:
return "FMS Request"
case Dot11InformationElementIDFMSResponse:
return "FMS Response"
case Dot11InformationElementIDQOSTrafficCapability:
return "QoS Traffic Capability"
case Dot11InformationElementIDBSSMaxIdlePeriod:
return "BSS Max Idle Period"
case Dot11InformationElementIDTFSRequest:
return "TFS Request"
case Dot11InformationElementIDTFSResponse:
return "TFS Response"
case Dot11InformationElementIDWNMSleepMode:
return "WNM-Sleep Mode"
case Dot11InformationElementIDTIMBroadcastRequest:
return "TIM Broadcast Request"
case Dot11InformationElementIDTIMBroadcastResponse:
return "TIM Broadcast Response"
case Dot11InformationElementIDCollInterferenceReport:
return "Collocated Interference Report"
case Dot11InformationElementIDChannelUsage:
return "Channel Usage"
case Dot11InformationElementIDTimeZone:
return "Time Zone"
case Dot11InformationElementIDDMSRequest:
return "DMS Request"
case Dot11InformationElementIDDMSResponse:
return "DMS Response"
case Dot11InformationElementIDLinkIdentifier:
return "Link Identifier"
case Dot11InformationElementIDWakeupSchedule:
return "Wakeup Schedule"
case Dot11InformationElementIDChannelSwitchTiming:
return "Channel Switch Timing"
case Dot11InformationElementIDPTIControl:
return "PTI Control"
case Dot11InformationElementIDPUBufferStatus:
return "PU Buffer Status"
case Dot11InformationElementIDInterworking:
return "Interworking"
case Dot11InformationElementIDAdvertisementProtocol:
return "Advertisement Protocol"
case Dot11InformationElementIDExpBWRequest:
return "Expedited Bandwidth Request"
case Dot11InformationElementIDQOSMapSet:
return "QoS Map Set"
case Dot11InformationElementIDRoamingConsortium:
return "Roaming Consortium"
case Dot11InformationElementIDEmergencyAlertIdentifier:
return "Emergency Alert Identifier"
case Dot11InformationElementIDMeshConfiguration:
return "Mesh Configuration"
case Dot11InformationElementIDMeshID:
return "Mesh ID"
case Dot11InformationElementIDMeshLinkMetricReport:
return "Mesh Link Metric Report"
case Dot11InformationElementIDCongestionNotification:
return "Congestion Notification"
case Dot11InformationElementIDMeshPeeringManagement:
return "Mesh Peering Management"
case Dot11InformationElementIDMeshChannelSwitchParam:
return "Mesh Channel Switch Parameters"
case Dot11InformationElementIDMeshAwakeWindows:
return "Mesh Awake Windows"
case Dot11InformationElementIDBeaconTiming:
return "Beacon Timing"
case Dot11InformationElementIDMCCAOPSetupRequest:
return "MCCAOP Setup Request"
case Dot11InformationElementIDMCCAOPSetupReply:
return "MCCAOP SETUP Reply"
case Dot11InformationElementIDMCCAOPAdvertisement:
return "MCCAOP Advertisement"
case Dot11InformationElementIDMCCAOPTeardown:
return "MCCAOP Teardown"
case Dot11InformationElementIDGateAnnouncement:
return "Gate Announcement"
case Dot11InformationElementIDRootAnnouncement:
return "Root Announcement"
case Dot11InformationElementIDExtCapability:
return "Extended Capabilities"
case Dot11InformationElementIDAgereProprietary:
return "Agere Proprietary"
case Dot11InformationElementIDPathRequest:
return "Path Request"
case Dot11InformationElementIDPathReply:
return "Path Reply"
case Dot11InformationElementIDPathError:
return "Path Error"
case Dot11InformationElementIDCiscoCCX1CKIPDeviceName:
return "Cisco CCX1 CKIP + Device Name"
case Dot11InformationElementIDCiscoCCX2:
return "Cisco CCX2"
case Dot11InformationElementIDProxyUpdate:
return "Proxy Update"
case Dot11InformationElementIDProxyUpdateConfirmation:
return "Proxy Update Confirmation"
case Dot11InformationElementIDAuthMeshPerringExch:
return "Auhenticated Mesh Perring Exchange"
case Dot11InformationElementIDMIC:
return "MIC (Message Integrity Code)"
case Dot11InformationElementIDDestinationURI:
return "Destination URI"
case Dot11InformationElementIDUAPSDCoexistence:
return "U-APSD Coexistence"
case Dot11InformationElementIDWakeupSchedule80211ad:
return "Wakeup Schedule 802.11ad"
case Dot11InformationElementIDExtendedSchedule:
return "Extended Schedule"
case Dot11InformationElementIDSTAAvailability:
return "STA Availability"
case Dot11InformationElementIDDMGTSPEC:
return "DMG TSPEC"
case Dot11InformationElementIDNextDMGATI:
return "Next DMG ATI"
case Dot11InformationElementIDDMSCapabilities:
return "DMG Capabilities"
case Dot11InformationElementIDCiscoUnknown95:
return "Cisco Unknown 95"
case Dot11InformationElementIDVendor2:
return "Vendor Specific"
case Dot11InformationElementIDDMGOperating:
return "DMG Operating"
case Dot11InformationElementIDDMGBSSParamChange:
return "DMG BSS Parameter Change"
case Dot11InformationElementIDDMGBeamRefinement:
return "DMG Beam Refinement"
case Dot11InformationElementIDChannelMeasFeedback:
return "Channel Measurement Feedback"
case Dot11InformationElementIDAwakeWindow:
return "Awake Window"
case Dot11InformationElementIDMultiBand:
return "Multi Band"
case Dot11InformationElementIDADDBAExtension:
return "ADDBA Extension"
case Dot11InformationElementIDNEXTPCPList:
return "NEXTPCP List"
case Dot11InformationElementIDPCPHandover:
return "PCP Handover"
case Dot11InformationElementIDDMGLinkMargin:
return "DMG Link Margin"
case Dot11InformationElementIDSwitchingStream:
return "Switching Stream"
case Dot11InformationElementIDSessionTransmission:
return "Session Transmission"
case Dot11InformationElementIDDynamicTonePairReport:
return "Dynamic Tone Pairing Report"
case Dot11InformationElementIDClusterReport:
return "Cluster Report"
case Dot11InformationElementIDRelayCapabilities:
return "Relay Capabilities"
case Dot11InformationElementIDRelayTransferParameter:
return "Relay Transfer Parameter"
case Dot11InformationElementIDBeamlinkMaintenance:
return "Beamlink Maintenance"
case Dot11InformationElementIDMultipleMacSublayers:
return "Multiple MAC Sublayers"
case Dot11InformationElementIDUPID:
return "U-PID"
case Dot11InformationElementIDDMGLinkAdaptionAck:
return "DMG Link Adaption Acknowledgment"
case Dot11InformationElementIDSymbolProprietary:
return "Symbol Proprietary"
case Dot11InformationElementIDMCCAOPAdvertOverview:
return "MCCAOP Advertisement Overview"
case Dot11InformationElementIDQuietPeriodRequest:
return "Quiet Period Request"
case Dot11InformationElementIDQuietPeriodResponse:
return "Quiet Period Response"
case Dot11InformationElementIDECPACPolicy:
return "ECPAC Policy"
case Dot11InformationElementIDClusterTimeOffset:
return "Cluster Time Offset"
case Dot11InformationElementIDAntennaSectorID:
return "Antenna Sector ID"
case Dot11InformationElementIDVHTCapabilities:
return "VHT Capabilities (IEEE Std 802.11ac/D3.1)"
case Dot11InformationElementIDVHTOperation:
return "VHT Operation (IEEE Std 802.11ac/D3.1)"
case Dot11InformationElementIDExtendedBSSLoad:
return "Extended BSS Load"
case Dot11InformationElementIDWideBWChannelSwitch:
return "Wide Bandwidth Channel Switch"
case Dot11InformationElementIDVHTTxPowerEnvelope:
return "VHT Tx Power Envelope (IEEE Std 802.11ac/D5.0)"
case Dot11InformationElementIDChannelSwitchWrapper:
return "Channel Switch Wrapper"
case Dot11InformationElementIDOperatingModeNotification:
return "Operating Mode Notification"
case Dot11InformationElementIDUPSIM:
return "UP SIM"
case Dot11InformationElementIDReducedNeighborReport:
return "Reduced Neighbor Report"
case Dot11InformationElementIDTVHTOperation:
return "TVHT Op"
case Dot11InformationElementIDDeviceLocation:
return "Device Location"
case Dot11InformationElementIDWhiteSpaceMap:
return "White Space Map"
case Dot11InformationElementIDFineTuningMeasureParams:
return "Fine Tuning Measure Parameters"
case Dot11InformationElementIDVendor:
return "Vendor"
default:
return "Unknown information element id"
}
}
// Dot11 provides an IEEE 802.11 base packet header.
// See http://standards.ieee.org/findstds/standard/802.11-2012.html
// for excruciating detail.
type Dot11 struct {
BaseLayer
Type Dot11Type
Proto uint8
Flags Dot11Flags
DurationID uint16
Address1 net.HardwareAddr
Address2 net.HardwareAddr
Address3 net.HardwareAddr
Address4 net.HardwareAddr
SequenceNumber uint16
FragmentNumber uint16
Checksum uint32
QOS *Dot11QOS
HTControl *Dot11HTControl
DataLayer gopacket.Layer
}
type Dot11QOS struct {
TID uint8 /* Traffic IDentifier */
EOSP bool /* End of service period */
AckPolicy Dot11AckPolicy
TXOP uint8
}
type Dot11HTControl struct {
ACConstraint bool
RDGMorePPDU bool
VHT *Dot11HTControlVHT
HT *Dot11HTControlHT
}
type Dot11HTControlHT struct {
LinkAdapationControl *Dot11LinkAdapationControl
CalibrationPosition uint8
CalibrationSequence uint8
CSISteering uint8
NDPAnnouncement bool
DEI bool
}
type Dot11HTControlVHT struct {
MRQ bool
UnsolicitedMFB bool
MSI *uint8
MFB Dot11HTControlMFB
CompressedMSI *uint8
STBCIndication bool
MFSI *uint8
GID *uint8
CodingType *Dot11CodingType
FbTXBeamformed bool
}
type Dot11HTControlMFB struct {
NumSTS uint8
VHTMCS uint8
BW uint8
SNR int8
}
type Dot11LinkAdapationControl struct {
TRQ bool
MRQ bool
MSI uint8
MFSI uint8
ASEL *Dot11ASEL
MFB *uint8
}
type Dot11ASEL struct {
Command uint8
Data uint8
}
type Dot11CodingType uint8
const (
Dot11CodingTypeBCC = 0
Dot11CodingTypeLDPC = 1
)
func (a Dot11CodingType) String() string {
switch a {
case Dot11CodingTypeBCC:
return "BCC"
case Dot11CodingTypeLDPC:
return "LDPC"
default:
return "Unknown coding type"
}
}
func (m *Dot11HTControlMFB) NoFeedBackPresent() bool {
return m.VHTMCS == 15 && m.NumSTS == 7
}
func decodeDot11(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11{}
err := d.DecodeFromBytes(data, p)
if err != nil {
return err
}
p.AddLayer(d)
if d.DataLayer != nil {
p.AddLayer(d.DataLayer)
}
return p.NextDecoder(d.NextLayerType())
}
func (m *Dot11) LayerType() gopacket.LayerType { return LayerTypeDot11 }
func (m *Dot11) CanDecode() gopacket.LayerClass { return LayerTypeDot11 }
func (m *Dot11) NextLayerType() gopacket.LayerType {
if m.DataLayer != nil {
if m.Flags.WEP() {
return LayerTypeDot11WEP
}
return m.DataLayer.(gopacket.DecodingLayer).NextLayerType()
}
return m.Type.LayerType()
}
func createU8(x uint8) *uint8 {
return &x
}
var dataDecodeMap = map[Dot11Type]func() gopacket.DecodingLayer{
Dot11TypeData: func() gopacket.DecodingLayer { return &Dot11Data{} },
Dot11TypeDataCFAck: func() gopacket.DecodingLayer { return &Dot11DataCFAck{} },
Dot11TypeDataCFPoll: func() gopacket.DecodingLayer { return &Dot11DataCFPoll{} },
Dot11TypeDataCFAckPoll: func() gopacket.DecodingLayer { return &Dot11DataCFAckPoll{} },
Dot11TypeDataNull: func() gopacket.DecodingLayer { return &Dot11DataNull{} },
Dot11TypeDataCFAckNoData: func() gopacket.DecodingLayer { return &Dot11DataCFAckNoData{} },
Dot11TypeDataCFPollNoData: func() gopacket.DecodingLayer { return &Dot11DataCFPollNoData{} },
Dot11TypeDataCFAckPollNoData: func() gopacket.DecodingLayer { return &Dot11DataCFAckPollNoData{} },
Dot11TypeDataQOSData: func() gopacket.DecodingLayer { return &Dot11DataQOSData{} },
Dot11TypeDataQOSDataCFAck: func() gopacket.DecodingLayer { return &Dot11DataQOSDataCFAck{} },
Dot11TypeDataQOSDataCFPoll: func() gopacket.DecodingLayer { return &Dot11DataQOSDataCFPoll{} },
Dot11TypeDataQOSDataCFAckPoll: func() gopacket.DecodingLayer { return &Dot11DataQOSDataCFAckPoll{} },
Dot11TypeDataQOSNull: func() gopacket.DecodingLayer { return &Dot11DataQOSNull{} },
Dot11TypeDataQOSCFPollNoData: func() gopacket.DecodingLayer { return &Dot11DataQOSCFPollNoData{} },
Dot11TypeDataQOSCFAckPollNoData: func() gopacket.DecodingLayer { return &Dot11DataQOSCFAckPollNoData{} },
}
func (m *Dot11) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 10 {
df.SetTruncated()
return fmt.Errorf("Dot11 length %v too short, %v required", len(data), 10)
}
m.Type = Dot11Type((data[0])&0xFC) >> 2
m.DataLayer = nil
m.Proto = uint8(data[0]) & 0x0003
m.Flags = Dot11Flags(data[1])
m.DurationID = binary.LittleEndian.Uint16(data[2:4])
m.Address1 = net.HardwareAddr(data[4:10])
offset := 10
mainType := m.Type.MainType()
switch mainType {
case Dot11TypeCtrl:
switch m.Type {
case Dot11TypeCtrlRTS, Dot11TypeCtrlPowersavePoll, Dot11TypeCtrlCFEnd, Dot11TypeCtrlCFEndAck:
if len(data) < offset+6 {
df.SetTruncated()
return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+6)
}
m.Address2 = net.HardwareAddr(data[offset : offset+6])
offset += 6
}
case Dot11TypeMgmt, Dot11TypeData:
if len(data) < offset+14 {
df.SetTruncated()
return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+14)
}
m.Address2 = net.HardwareAddr(data[offset : offset+6])
offset += 6
m.Address3 = net.HardwareAddr(data[offset : offset+6])
offset += 6
m.SequenceNumber = (binary.LittleEndian.Uint16(data[offset:offset+2]) & 0xFFF0) >> 4
m.FragmentNumber = (binary.LittleEndian.Uint16(data[offset:offset+2]) & 0x000F)
offset += 2
}
if mainType == Dot11TypeData && m.Flags.FromDS() && m.Flags.ToDS() {
if len(data) < offset+6 {
df.SetTruncated()
return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+6)
}
m.Address4 = net.HardwareAddr(data[offset : offset+6])
offset += 6
}
if m.Type.QOS() {
if len(data) < offset+2 {
df.SetTruncated()
return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+6)
}
m.QOS = &Dot11QOS{
TID: (uint8(data[offset]) & 0x0F),
EOSP: (uint8(data[offset]) & 0x10) == 0x10,
AckPolicy: Dot11AckPolicy((uint8(data[offset]) & 0x60) >> 5),
TXOP: uint8(data[offset+1]),
}
offset += 2
}
if m.Flags.Order() && (m.Type.QOS() || mainType == Dot11TypeMgmt) {
if len(data) < offset+4 {
df.SetTruncated()
return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+6)
}
htc := &Dot11HTControl{
ACConstraint: data[offset+3]&0x40 != 0,
RDGMorePPDU: data[offset+3]&0x80 != 0,
}
m.HTControl = htc
if data[offset]&0x1 != 0 { // VHT Variant
vht := &Dot11HTControlVHT{}
htc.VHT = vht
vht.MRQ = data[offset]&0x4 != 0
vht.UnsolicitedMFB = data[offset+3]&0x20 != 0
vht.MFB = Dot11HTControlMFB{
NumSTS: uint8(data[offset+1] >> 1 & 0x7),
VHTMCS: uint8(data[offset+1] >> 4 & 0xF),
BW: uint8(data[offset+2] & 0x3),
SNR: int8((-(data[offset+2] >> 2 & 0x20))+data[offset+2]>>2&0x1F) + 22,
}
if vht.UnsolicitedMFB {
if !vht.MFB.NoFeedBackPresent() {
vht.CompressedMSI = createU8(data[offset] >> 3 & 0x3)
vht.STBCIndication = data[offset]&0x20 != 0
vht.CodingType = (*Dot11CodingType)(createU8(data[offset+3] >> 3 & 0x1))
vht.FbTXBeamformed = data[offset+3]&0x10 != 0
vht.GID = createU8(
data[offset]>>6 +
(data[offset+1] & 0x1 << 2) +
data[offset+3]&0x7<<3)
}
} else {
if vht.MRQ {
vht.MSI = createU8((data[offset] >> 3) & 0x07)
}
vht.MFSI = createU8(data[offset]>>6 + (data[offset+1] & 0x1 << 2))
}
} else { // HT Variant
ht := &Dot11HTControlHT{}
htc.HT = ht
lac := &Dot11LinkAdapationControl{}
ht.LinkAdapationControl = lac
lac.TRQ = data[offset]&0x2 != 0
lac.MFSI = data[offset]>>6&0x3 + data[offset+1]&0x1<<3
if data[offset]&0x3C == 0x38 { // ASEL
lac.ASEL = &Dot11ASEL{
Command: data[offset+1] >> 1 & 0x7,
Data: data[offset+1] >> 4 & 0xF,
}
} else {
lac.MRQ = data[offset]&0x4 != 0
if lac.MRQ {
lac.MSI = data[offset] >> 3 & 0x7
}
lac.MFB = createU8(data[offset+1] >> 1)
}
ht.CalibrationPosition = data[offset+2] & 0x3
ht.CalibrationSequence = data[offset+2] >> 2 & 0x3
ht.CSISteering = data[offset+2] >> 6 & 0x3
ht.NDPAnnouncement = data[offset+3]&0x1 != 0
if mainType != Dot11TypeMgmt {
ht.DEI = data[offset+3]&0x20 != 0
}
}
offset += 4
}
if len(data) < offset+4 {
df.SetTruncated()
return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+4)
}
m.BaseLayer = BaseLayer{
Contents: data[0:offset],
Payload: data[offset : len(data)-4],
}
if mainType == Dot11TypeData {
d := dataDecodeMap[m.Type]
if d == nil {
return fmt.Errorf("unsupported type: %v", m.Type)
}
l := d()
err := l.DecodeFromBytes(m.BaseLayer.Payload, df)
if err != nil {
return err
}
m.DataLayer = l.(gopacket.Layer)
}
m.Checksum = binary.LittleEndian.Uint32(data[len(data)-4 : len(data)])
return nil
}
func (m *Dot11) ChecksumValid() bool {
// only for CTRL and MGMT frames
h := crc32.NewIEEE()
h.Write(m.Contents)
h.Write(m.Payload)
return m.Checksum == h.Sum32()
}
func (m Dot11) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
buf, err := b.PrependBytes(24)
if err != nil {
return err
}
buf[0] = (uint8(m.Type) << 2) | m.Proto
buf[1] = uint8(m.Flags)
binary.LittleEndian.PutUint16(buf[2:4], m.DurationID)
copy(buf[4:10], m.Address1)
offset := 10
switch m.Type.MainType() {
case Dot11TypeCtrl:
switch m.Type {
case Dot11TypeCtrlRTS, Dot11TypeCtrlPowersavePoll, Dot11TypeCtrlCFEnd, Dot11TypeCtrlCFEndAck:
copy(buf[offset:offset+6], m.Address2)
offset += 6
}
case Dot11TypeMgmt, Dot11TypeData:
copy(buf[offset:offset+6], m.Address2)
offset += 6
copy(buf[offset:offset+6], m.Address3)
offset += 6
binary.LittleEndian.PutUint16(buf[offset:offset+2], (m.SequenceNumber<<4)|m.FragmentNumber)
offset += 2
}
if m.Type.MainType() == Dot11TypeData && m.Flags.FromDS() && m.Flags.ToDS() {
copy(buf[offset:offset+6], m.Address4)
offset += 6
}
return nil
}
// Dot11Mgmt is a base for all IEEE 802.11 management layers.
type Dot11Mgmt struct {
BaseLayer
}
func (m *Dot11Mgmt) NextLayerType() gopacket.LayerType { return gopacket.LayerTypePayload }
func (m *Dot11Mgmt) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
m.Contents = data
return nil
}
// Dot11Ctrl is a base for all IEEE 802.11 control layers.
type Dot11Ctrl struct {
BaseLayer
}
func (m *Dot11Ctrl) NextLayerType() gopacket.LayerType { return gopacket.LayerTypePayload }
func (m *Dot11Ctrl) LayerType() gopacket.LayerType { return LayerTypeDot11Ctrl }
func (m *Dot11Ctrl) CanDecode() gopacket.LayerClass { return LayerTypeDot11Ctrl }
func (m *Dot11Ctrl) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
m.Contents = data
return nil
}
func decodeDot11Ctrl(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11Ctrl{}
return decodingLayerDecoder(d, data, p)
}
// Dot11WEP contains WEP encrpted IEEE 802.11 data.
type Dot11WEP struct {
BaseLayer
}
func (m *Dot11WEP) NextLayerType() gopacket.LayerType { return gopacket.LayerTypePayload }
func (m *Dot11WEP) LayerType() gopacket.LayerType { return LayerTypeDot11WEP }
func (m *Dot11WEP) CanDecode() gopacket.LayerClass { return LayerTypeDot11WEP }
func (m *Dot11WEP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
m.Contents = data
return nil
}
func decodeDot11WEP(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11WEP{}
return decodingLayerDecoder(d, data, p)
}
// Dot11Data is a base for all IEEE 802.11 data layers.
type Dot11Data struct {
BaseLayer
}
func (m *Dot11Data) NextLayerType() gopacket.LayerType {
return LayerTypeLLC
}
func (m *Dot11Data) LayerType() gopacket.LayerType { return LayerTypeDot11Data }
func (m *Dot11Data) CanDecode() gopacket.LayerClass { return LayerTypeDot11Data }
func (m *Dot11Data) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
m.Payload = data
return nil
}
func decodeDot11Data(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11Data{}
return decodingLayerDecoder(d, data, p)
}
type Dot11DataCFAck struct {
Dot11Data
}
func decodeDot11DataCFAck(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11DataCFAck{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11DataCFAck) LayerType() gopacket.LayerType { return LayerTypeDot11DataCFAck }
func (m *Dot11DataCFAck) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataCFAck }
func (m *Dot11DataCFAck) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
return m.Dot11Data.DecodeFromBytes(data, df)
}
type Dot11DataCFPoll struct {
Dot11Data
}
func decodeDot11DataCFPoll(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11DataCFPoll{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11DataCFPoll) LayerType() gopacket.LayerType { return LayerTypeDot11DataCFPoll }
func (m *Dot11DataCFPoll) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataCFPoll }
func (m *Dot11DataCFPoll) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
return m.Dot11Data.DecodeFromBytes(data, df)
}
type Dot11DataCFAckPoll struct {
Dot11Data
}
func decodeDot11DataCFAckPoll(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11DataCFAckPoll{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11DataCFAckPoll) LayerType() gopacket.LayerType { return LayerTypeDot11DataCFAckPoll }
func (m *Dot11DataCFAckPoll) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataCFAckPoll }
func (m *Dot11DataCFAckPoll) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
return m.Dot11Data.DecodeFromBytes(data, df)
}
type Dot11DataNull struct {
Dot11Data
}
func decodeDot11DataNull(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11DataNull{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11DataNull) LayerType() gopacket.LayerType { return LayerTypeDot11DataNull }
func (m *Dot11DataNull) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataNull }
func (m *Dot11DataNull) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
return m.Dot11Data.DecodeFromBytes(data, df)
}
type Dot11DataCFAckNoData struct {
Dot11Data
}
func decodeDot11DataCFAckNoData(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11DataCFAckNoData{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11DataCFAckNoData) LayerType() gopacket.LayerType { return LayerTypeDot11DataCFAckNoData }
func (m *Dot11DataCFAckNoData) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataCFAckNoData }
func (m *Dot11DataCFAckNoData) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
return m.Dot11Data.DecodeFromBytes(data, df)
}
type Dot11DataCFPollNoData struct {
Dot11Data
}
func decodeDot11DataCFPollNoData(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11DataCFPollNoData{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11DataCFPollNoData) LayerType() gopacket.LayerType { return LayerTypeDot11DataCFPollNoData }
func (m *Dot11DataCFPollNoData) CanDecode() gopacket.LayerClass {
return LayerTypeDot11DataCFPollNoData
}
func (m *Dot11DataCFPollNoData) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
return m.Dot11Data.DecodeFromBytes(data, df)
}
type Dot11DataCFAckPollNoData struct {
Dot11Data
}
func decodeDot11DataCFAckPollNoData(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11DataCFAckPollNoData{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11DataCFAckPollNoData) LayerType() gopacket.LayerType {
return LayerTypeDot11DataCFAckPollNoData
}
func (m *Dot11DataCFAckPollNoData) CanDecode() gopacket.LayerClass {
return LayerTypeDot11DataCFAckPollNoData
}
func (m *Dot11DataCFAckPollNoData) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
return m.Dot11Data.DecodeFromBytes(data, df)
}
type Dot11DataQOS struct {
Dot11Ctrl
}
func (m *Dot11DataQOS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
m.BaseLayer = BaseLayer{Payload: data}
return nil
}
type Dot11DataQOSData struct {
Dot11DataQOS
}
func decodeDot11DataQOSData(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11DataQOSData{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11DataQOSData) LayerType() gopacket.LayerType { return LayerTypeDot11DataQOSData }
func (m *Dot11DataQOSData) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataQOSData }
func (m *Dot11DataQOSData) NextLayerType() gopacket.LayerType {
return LayerTypeDot11Data
}
type Dot11DataQOSDataCFAck struct {
Dot11DataQOS
}
func decodeDot11DataQOSDataCFAck(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11DataQOSDataCFAck{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11DataQOSDataCFAck) LayerType() gopacket.LayerType { return LayerTypeDot11DataQOSDataCFAck }
func (m *Dot11DataQOSDataCFAck) CanDecode() gopacket.LayerClass {
return LayerTypeDot11DataQOSDataCFAck
}
func (m *Dot11DataQOSDataCFAck) NextLayerType() gopacket.LayerType { return LayerTypeDot11DataCFAck }
type Dot11DataQOSDataCFPoll struct {
Dot11DataQOS
}
func decodeDot11DataQOSDataCFPoll(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11DataQOSDataCFPoll{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11DataQOSDataCFPoll) LayerType() gopacket.LayerType {
return LayerTypeDot11DataQOSDataCFPoll
}
func (m *Dot11DataQOSDataCFPoll) CanDecode() gopacket.LayerClass {
return LayerTypeDot11DataQOSDataCFPoll
}
func (m *Dot11DataQOSDataCFPoll) NextLayerType() gopacket.LayerType { return LayerTypeDot11DataCFPoll }
type Dot11DataQOSDataCFAckPoll struct {
Dot11DataQOS
}
func decodeDot11DataQOSDataCFAckPoll(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11DataQOSDataCFAckPoll{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11DataQOSDataCFAckPoll) LayerType() gopacket.LayerType {
return LayerTypeDot11DataQOSDataCFAckPoll
}
func (m *Dot11DataQOSDataCFAckPoll) CanDecode() gopacket.LayerClass {
return LayerTypeDot11DataQOSDataCFAckPoll
}
func (m *Dot11DataQOSDataCFAckPoll) NextLayerType() gopacket.LayerType {
return LayerTypeDot11DataCFAckPoll
}
type Dot11DataQOSNull struct {
Dot11DataQOS
}
func decodeDot11DataQOSNull(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11DataQOSNull{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11DataQOSNull) LayerType() gopacket.LayerType { return LayerTypeDot11DataQOSNull }
func (m *Dot11DataQOSNull) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataQOSNull }
func (m *Dot11DataQOSNull) NextLayerType() gopacket.LayerType { return LayerTypeDot11DataNull }
type Dot11DataQOSCFPollNoData struct {
Dot11DataQOS
}
func decodeDot11DataQOSCFPollNoData(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11DataQOSCFPollNoData{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11DataQOSCFPollNoData) LayerType() gopacket.LayerType {
return LayerTypeDot11DataQOSCFPollNoData
}
func (m *Dot11DataQOSCFPollNoData) CanDecode() gopacket.LayerClass {
return LayerTypeDot11DataQOSCFPollNoData
}
func (m *Dot11DataQOSCFPollNoData) NextLayerType() gopacket.LayerType {
return LayerTypeDot11DataCFPollNoData
}
type Dot11DataQOSCFAckPollNoData struct {
Dot11DataQOS
}
func decodeDot11DataQOSCFAckPollNoData(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11DataQOSCFAckPollNoData{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11DataQOSCFAckPollNoData) LayerType() gopacket.LayerType {
return LayerTypeDot11DataQOSCFAckPollNoData
}
func (m *Dot11DataQOSCFAckPollNoData) CanDecode() gopacket.LayerClass {
return LayerTypeDot11DataQOSCFAckPollNoData
}
func (m *Dot11DataQOSCFAckPollNoData) NextLayerType() gopacket.LayerType {
return LayerTypeDot11DataCFAckPollNoData
}
type Dot11InformationElement struct {
BaseLayer
ID Dot11InformationElementID
Length uint8
OUI []byte
Info []byte
}
func (m *Dot11InformationElement) LayerType() gopacket.LayerType {
return LayerTypeDot11InformationElement
}
func (m *Dot11InformationElement) CanDecode() gopacket.LayerClass {
return LayerTypeDot11InformationElement
}
func (m *Dot11InformationElement) NextLayerType() gopacket.LayerType {
return LayerTypeDot11InformationElement
}
func (m *Dot11InformationElement) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 2 {
df.SetTruncated()
return fmt.Errorf("Dot11InformationElement length %v too short, %v required", len(data), 2)
}
m.ID = Dot11InformationElementID(data[0])
m.Length = data[1]
offset := int(2)
if len(data) < offset+int(m.Length) {
df.SetTruncated()
return fmt.Errorf("Dot11InformationElement length %v too short, %v required", len(data), offset+int(m.Length))
}
if len(data) < offset+4 {
df.SetTruncated()
return fmt.Errorf("vendor extension size < %d", offset+int(m.Length))
}
if m.ID == 221 {
// Vendor extension
m.OUI = data[offset : offset+4]
m.Info = data[offset+4 : offset+int(m.Length)]
} else {
m.Info = data[offset : offset+int(m.Length)]
}
offset += int(m.Length)
m.BaseLayer = BaseLayer{Contents: data[:offset], Payload: data[offset:]}
return nil
}
func (d *Dot11InformationElement) String() string {
if d.ID == 0 {
return fmt.Sprintf("802.11 Information Element (ID: %v, Length: %v, SSID: %v)", d.ID, d.Length, string(d.Info))
} else if d.ID == 1 {
rates := ""
for i := 0; i < len(d.Info); i++ {
if d.Info[i]&0x80 == 0 {
rates += fmt.Sprintf("%.1f ", float32(d.Info[i])*0.5)
} else {
rates += fmt.Sprintf("%.1f* ", float32(d.Info[i]&0x7F)*0.5)
}
}
return fmt.Sprintf("802.11 Information Element (ID: %v, Length: %v, Rates: %s Mbit)", d.ID, d.Length, rates)
} else if d.ID == 221 {
return fmt.Sprintf("802.11 Information Element (ID: %v, Length: %v, OUI: %X, Info: %X)", d.ID, d.Length, d.OUI, d.Info)
} else {
return fmt.Sprintf("802.11 Information Element (ID: %v, Length: %v, Info: %X)", d.ID, d.Length, d.Info)
}
}
func (m Dot11InformationElement) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
length := len(m.Info) + len(m.OUI)
if buf, err := b.PrependBytes(2 + length); err != nil {
return err
} else {
buf[0] = uint8(m.ID)
buf[1] = uint8(length)
copy(buf[2:], m.OUI)
copy(buf[2+len(m.OUI):], m.Info)
}
return nil
}
func decodeDot11InformationElement(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11InformationElement{}
return decodingLayerDecoder(d, data, p)
}
type Dot11CtrlCTS struct {
Dot11Ctrl
}
func decodeDot11CtrlCTS(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11CtrlCTS{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11CtrlCTS) LayerType() gopacket.LayerType {
return LayerTypeDot11CtrlCTS
}
func (m *Dot11CtrlCTS) CanDecode() gopacket.LayerClass {
return LayerTypeDot11CtrlCTS
}
func (m *Dot11CtrlCTS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
return m.Dot11Ctrl.DecodeFromBytes(data, df)
}
type Dot11CtrlRTS struct {
Dot11Ctrl
}
func decodeDot11CtrlRTS(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11CtrlRTS{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11CtrlRTS) LayerType() gopacket.LayerType {
return LayerTypeDot11CtrlRTS
}
func (m *Dot11CtrlRTS) CanDecode() gopacket.LayerClass {
return LayerTypeDot11CtrlRTS
}
func (m *Dot11CtrlRTS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
return m.Dot11Ctrl.DecodeFromBytes(data, df)
}
type Dot11CtrlBlockAckReq struct {
Dot11Ctrl
}
func decodeDot11CtrlBlockAckReq(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11CtrlBlockAckReq{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11CtrlBlockAckReq) LayerType() gopacket.LayerType {
return LayerTypeDot11CtrlBlockAckReq
}
func (m *Dot11CtrlBlockAckReq) CanDecode() gopacket.LayerClass {
return LayerTypeDot11CtrlBlockAckReq
}
func (m *Dot11CtrlBlockAckReq) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
return m.Dot11Ctrl.DecodeFromBytes(data, df)
}
type Dot11CtrlBlockAck struct {
Dot11Ctrl
}
func decodeDot11CtrlBlockAck(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11CtrlBlockAck{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11CtrlBlockAck) LayerType() gopacket.LayerType { return LayerTypeDot11CtrlBlockAck }
func (m *Dot11CtrlBlockAck) CanDecode() gopacket.LayerClass { return LayerTypeDot11CtrlBlockAck }
func (m *Dot11CtrlBlockAck) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
return m.Dot11Ctrl.DecodeFromBytes(data, df)
}
type Dot11CtrlPowersavePoll struct {
Dot11Ctrl
}
func decodeDot11CtrlPowersavePoll(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11CtrlPowersavePoll{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11CtrlPowersavePoll) LayerType() gopacket.LayerType {
return LayerTypeDot11CtrlPowersavePoll
}
func (m *Dot11CtrlPowersavePoll) CanDecode() gopacket.LayerClass {
return LayerTypeDot11CtrlPowersavePoll
}
func (m *Dot11CtrlPowersavePoll) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
return m.Dot11Ctrl.DecodeFromBytes(data, df)
}
type Dot11CtrlAck struct {
Dot11Ctrl
}
func decodeDot11CtrlAck(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11CtrlAck{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11CtrlAck) LayerType() gopacket.LayerType { return LayerTypeDot11CtrlAck }
func (m *Dot11CtrlAck) CanDecode() gopacket.LayerClass { return LayerTypeDot11CtrlAck }
func (m *Dot11CtrlAck) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
return m.Dot11Ctrl.DecodeFromBytes(data, df)
}
type Dot11CtrlCFEnd struct {
Dot11Ctrl
}
func decodeDot11CtrlCFEnd(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11CtrlCFEnd{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11CtrlCFEnd) LayerType() gopacket.LayerType {
return LayerTypeDot11CtrlCFEnd
}
func (m *Dot11CtrlCFEnd) CanDecode() gopacket.LayerClass {
return LayerTypeDot11CtrlCFEnd
}
func (m *Dot11CtrlCFEnd) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
return m.Dot11Ctrl.DecodeFromBytes(data, df)
}
type Dot11CtrlCFEndAck struct {
Dot11Ctrl
}
func decodeDot11CtrlCFEndAck(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11CtrlCFEndAck{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11CtrlCFEndAck) LayerType() gopacket.LayerType {
return LayerTypeDot11CtrlCFEndAck
}
func (m *Dot11CtrlCFEndAck) CanDecode() gopacket.LayerClass {
return LayerTypeDot11CtrlCFEndAck
}
func (m *Dot11CtrlCFEndAck) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
return m.Dot11Ctrl.DecodeFromBytes(data, df)
}
type Dot11MgmtAssociationReq struct {
Dot11Mgmt
CapabilityInfo uint16
ListenInterval uint16
}
func decodeDot11MgmtAssociationReq(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11MgmtAssociationReq{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11MgmtAssociationReq) LayerType() gopacket.LayerType {
return LayerTypeDot11MgmtAssociationReq
}
func (m *Dot11MgmtAssociationReq) CanDecode() gopacket.LayerClass {
return LayerTypeDot11MgmtAssociationReq
}
func (m *Dot11MgmtAssociationReq) NextLayerType() gopacket.LayerType {
return LayerTypeDot11InformationElement
}
func (m *Dot11MgmtAssociationReq) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 4 {
df.SetTruncated()
return fmt.Errorf("Dot11MgmtAssociationReq length %v too short, %v required", len(data), 4)
}
m.CapabilityInfo = binary.LittleEndian.Uint16(data[0:2])
m.ListenInterval = binary.LittleEndian.Uint16(data[2:4])
m.Payload = data[4:]
return m.Dot11Mgmt.DecodeFromBytes(data, df)
}
func (m Dot11MgmtAssociationReq) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
buf, err := b.PrependBytes(4)
if err != nil {
return err
}
binary.LittleEndian.PutUint16(buf[0:2], m.CapabilityInfo)
binary.LittleEndian.PutUint16(buf[2:4], m.ListenInterval)
return nil
}
type Dot11MgmtAssociationResp struct {
Dot11Mgmt
CapabilityInfo uint16
Status Dot11Status
AID uint16
}
func decodeDot11MgmtAssociationResp(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11MgmtAssociationResp{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11MgmtAssociationResp) CanDecode() gopacket.LayerClass {
return LayerTypeDot11MgmtAssociationResp
}
func (m *Dot11MgmtAssociationResp) LayerType() gopacket.LayerType {
return LayerTypeDot11MgmtAssociationResp
}
func (m *Dot11MgmtAssociationResp) NextLayerType() gopacket.LayerType {
return LayerTypeDot11InformationElement
}
func (m *Dot11MgmtAssociationResp) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 6 {
df.SetTruncated()
return fmt.Errorf("Dot11MgmtAssociationResp length %v too short, %v required", len(data), 6)
}
m.CapabilityInfo = binary.LittleEndian.Uint16(data[0:2])
m.Status = Dot11Status(binary.LittleEndian.Uint16(data[2:4]))
m.AID = binary.LittleEndian.Uint16(data[4:6])
m.Payload = data[6:]
return m.Dot11Mgmt.DecodeFromBytes(data, df)
}
func (m Dot11MgmtAssociationResp) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
buf, err := b.PrependBytes(6)
if err != nil {
return err
}
binary.LittleEndian.PutUint16(buf[0:2], m.CapabilityInfo)
binary.LittleEndian.PutUint16(buf[2:4], uint16(m.Status))
binary.LittleEndian.PutUint16(buf[4:6], m.AID)
return nil
}
type Dot11MgmtReassociationReq struct {
Dot11Mgmt
CapabilityInfo uint16
ListenInterval uint16
CurrentApAddress net.HardwareAddr
}
func decodeDot11MgmtReassociationReq(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11MgmtReassociationReq{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11MgmtReassociationReq) LayerType() gopacket.LayerType {
return LayerTypeDot11MgmtReassociationReq
}
func (m *Dot11MgmtReassociationReq) CanDecode() gopacket.LayerClass {
return LayerTypeDot11MgmtReassociationReq
}
func (m *Dot11MgmtReassociationReq) NextLayerType() gopacket.LayerType {
return LayerTypeDot11InformationElement
}
func (m *Dot11MgmtReassociationReq) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 10 {
df.SetTruncated()
return fmt.Errorf("Dot11MgmtReassociationReq length %v too short, %v required", len(data), 10)
}
m.CapabilityInfo = binary.LittleEndian.Uint16(data[0:2])
m.ListenInterval = binary.LittleEndian.Uint16(data[2:4])
m.CurrentApAddress = net.HardwareAddr(data[4:10])
m.Payload = data[10:]
return m.Dot11Mgmt.DecodeFromBytes(data, df)
}
func (m Dot11MgmtReassociationReq) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
buf, err := b.PrependBytes(10)
if err != nil {
return err
}
binary.LittleEndian.PutUint16(buf[0:2], m.CapabilityInfo)
binary.LittleEndian.PutUint16(buf[2:4], m.ListenInterval)
copy(buf[4:10], m.CurrentApAddress)
return nil
}
type Dot11MgmtReassociationResp struct {
Dot11Mgmt
}
func decodeDot11MgmtReassociationResp(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11MgmtReassociationResp{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11MgmtReassociationResp) LayerType() gopacket.LayerType {
return LayerTypeDot11MgmtReassociationResp
}
func (m *Dot11MgmtReassociationResp) CanDecode() gopacket.LayerClass {
return LayerTypeDot11MgmtReassociationResp
}
func (m *Dot11MgmtReassociationResp) NextLayerType() gopacket.LayerType {
return LayerTypeDot11InformationElement
}
type Dot11MgmtProbeReq struct {
Dot11Mgmt
}
func decodeDot11MgmtProbeReq(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11MgmtProbeReq{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11MgmtProbeReq) LayerType() gopacket.LayerType { return LayerTypeDot11MgmtProbeReq }
func (m *Dot11MgmtProbeReq) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtProbeReq }
func (m *Dot11MgmtProbeReq) NextLayerType() gopacket.LayerType {
return LayerTypeDot11InformationElement
}
type Dot11MgmtProbeResp struct {
Dot11Mgmt
Timestamp uint64
Interval uint16
Flags uint16
}
func decodeDot11MgmtProbeResp(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11MgmtProbeResp{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11MgmtProbeResp) LayerType() gopacket.LayerType { return LayerTypeDot11MgmtProbeResp }
func (m *Dot11MgmtProbeResp) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtProbeResp }
func (m *Dot11MgmtProbeResp) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 12 {
df.SetTruncated()
return fmt.Errorf("Dot11MgmtProbeResp length %v too short, %v required", len(data), 12)
}
m.Timestamp = binary.LittleEndian.Uint64(data[0:8])
m.Interval = binary.LittleEndian.Uint16(data[8:10])
m.Flags = binary.LittleEndian.Uint16(data[10:12])
m.Payload = data[12:]
return m.Dot11Mgmt.DecodeFromBytes(data, df)
}
func (m *Dot11MgmtProbeResp) NextLayerType() gopacket.LayerType {
return LayerTypeDot11InformationElement
}
func (m Dot11MgmtProbeResp) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
buf, err := b.PrependBytes(12)
if err != nil {
return err
}
binary.LittleEndian.PutUint64(buf[0:8], m.Timestamp)
binary.LittleEndian.PutUint16(buf[8:10], m.Interval)
binary.LittleEndian.PutUint16(buf[10:12], m.Flags)
return nil
}
type Dot11MgmtMeasurementPilot struct {
Dot11Mgmt
}
func decodeDot11MgmtMeasurementPilot(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11MgmtMeasurementPilot{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11MgmtMeasurementPilot) LayerType() gopacket.LayerType {
return LayerTypeDot11MgmtMeasurementPilot
}
func (m *Dot11MgmtMeasurementPilot) CanDecode() gopacket.LayerClass {
return LayerTypeDot11MgmtMeasurementPilot
}
type Dot11MgmtBeacon struct {
Dot11Mgmt
Timestamp uint64
Interval uint16
Flags uint16
}
func decodeDot11MgmtBeacon(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11MgmtBeacon{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11MgmtBeacon) LayerType() gopacket.LayerType { return LayerTypeDot11MgmtBeacon }
func (m *Dot11MgmtBeacon) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtBeacon }
func (m *Dot11MgmtBeacon) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 12 {
df.SetTruncated()
return fmt.Errorf("Dot11MgmtBeacon length %v too short, %v required", len(data), 12)
}
m.Timestamp = binary.LittleEndian.Uint64(data[0:8])
m.Interval = binary.LittleEndian.Uint16(data[8:10])
m.Flags = binary.LittleEndian.Uint16(data[10:12])
m.Payload = data[12:]
return m.Dot11Mgmt.DecodeFromBytes(data, df)
}
func (m *Dot11MgmtBeacon) NextLayerType() gopacket.LayerType { return LayerTypeDot11InformationElement }
func (m Dot11MgmtBeacon) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
buf, err := b.PrependBytes(12)
if err != nil {
return err
}
binary.LittleEndian.PutUint64(buf[0:8], m.Timestamp)
binary.LittleEndian.PutUint16(buf[8:10], m.Interval)
binary.LittleEndian.PutUint16(buf[10:12], m.Flags)
return nil
}
type Dot11MgmtATIM struct {
Dot11Mgmt
}
func decodeDot11MgmtATIM(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11MgmtATIM{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11MgmtATIM) LayerType() gopacket.LayerType { return LayerTypeDot11MgmtATIM }
func (m *Dot11MgmtATIM) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtATIM }
type Dot11MgmtDisassociation struct {
Dot11Mgmt
Reason Dot11Reason
}
func decodeDot11MgmtDisassociation(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11MgmtDisassociation{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11MgmtDisassociation) LayerType() gopacket.LayerType {
return LayerTypeDot11MgmtDisassociation
}
func (m *Dot11MgmtDisassociation) CanDecode() gopacket.LayerClass {
return LayerTypeDot11MgmtDisassociation
}
func (m *Dot11MgmtDisassociation) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 2 {
df.SetTruncated()
return fmt.Errorf("Dot11MgmtDisassociation length %v too short, %v required", len(data), 2)
}
m.Reason = Dot11Reason(binary.LittleEndian.Uint16(data[0:2]))
return m.Dot11Mgmt.DecodeFromBytes(data, df)
}
func (m Dot11MgmtDisassociation) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
buf, err := b.PrependBytes(2)
if err != nil {
return err
}
binary.LittleEndian.PutUint16(buf[0:2], uint16(m.Reason))
return nil
}
type Dot11MgmtAuthentication struct {
Dot11Mgmt
Algorithm Dot11Algorithm
Sequence uint16
Status Dot11Status
}
func decodeDot11MgmtAuthentication(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11MgmtAuthentication{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11MgmtAuthentication) LayerType() gopacket.LayerType {
return LayerTypeDot11MgmtAuthentication
}
func (m *Dot11MgmtAuthentication) CanDecode() gopacket.LayerClass {
return LayerTypeDot11MgmtAuthentication
}
func (m *Dot11MgmtAuthentication) NextLayerType() gopacket.LayerType {
return LayerTypeDot11InformationElement
}
func (m *Dot11MgmtAuthentication) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 6 {
df.SetTruncated()
return fmt.Errorf("Dot11MgmtAuthentication length %v too short, %v required", len(data), 6)
}
m.Algorithm = Dot11Algorithm(binary.LittleEndian.Uint16(data[0:2]))
m.Sequence = binary.LittleEndian.Uint16(data[2:4])
m.Status = Dot11Status(binary.LittleEndian.Uint16(data[4:6]))
m.Payload = data[6:]
return m.Dot11Mgmt.DecodeFromBytes(data, df)
}
func (m Dot11MgmtAuthentication) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
buf, err := b.PrependBytes(6)
if err != nil {
return err
}
binary.LittleEndian.PutUint16(buf[0:2], uint16(m.Algorithm))
binary.LittleEndian.PutUint16(buf[2:4], m.Sequence)
binary.LittleEndian.PutUint16(buf[4:6], uint16(m.Status))
return nil
}
type Dot11MgmtDeauthentication struct {
Dot11Mgmt
Reason Dot11Reason
}
func decodeDot11MgmtDeauthentication(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11MgmtDeauthentication{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11MgmtDeauthentication) LayerType() gopacket.LayerType {
return LayerTypeDot11MgmtDeauthentication
}
func (m *Dot11MgmtDeauthentication) CanDecode() gopacket.LayerClass {
return LayerTypeDot11MgmtDeauthentication
}
func (m *Dot11MgmtDeauthentication) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 2 {
df.SetTruncated()
return fmt.Errorf("Dot11MgmtDeauthentication length %v too short, %v required", len(data), 2)
}
m.Reason = Dot11Reason(binary.LittleEndian.Uint16(data[0:2]))
return m.Dot11Mgmt.DecodeFromBytes(data, df)
}
func (m Dot11MgmtDeauthentication) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
buf, err := b.PrependBytes(2)
if err != nil {
return err
}
binary.LittleEndian.PutUint16(buf[0:2], uint16(m.Reason))
return nil
}
type Dot11MgmtAction struct {
Dot11Mgmt
}
func decodeDot11MgmtAction(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11MgmtAction{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11MgmtAction) LayerType() gopacket.LayerType { return LayerTypeDot11MgmtAction }
func (m *Dot11MgmtAction) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtAction }
type Dot11MgmtActionNoAck struct {
Dot11Mgmt
}
func decodeDot11MgmtActionNoAck(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11MgmtActionNoAck{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11MgmtActionNoAck) LayerType() gopacket.LayerType { return LayerTypeDot11MgmtActionNoAck }
func (m *Dot11MgmtActionNoAck) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtActionNoAck }
type Dot11MgmtArubaWLAN struct {
Dot11Mgmt
}
func decodeDot11MgmtArubaWLAN(data []byte, p gopacket.PacketBuilder) error {
d := &Dot11MgmtArubaWLAN{}
return decodingLayerDecoder(d, data, p)
}
func (m *Dot11MgmtArubaWLAN) LayerType() gopacket.LayerType { return LayerTypeDot11MgmtArubaWLAN }
func (m *Dot11MgmtArubaWLAN) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtArubaWLAN }
// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"fmt"
"github.com/google/gopacket"
)
// Dot1Q is the packet layer for 802.1Q VLAN headers.
type Dot1Q struct {
BaseLayer
Priority uint8
DropEligible bool
VLANIdentifier uint16
Type EthernetType
}
// LayerType returns gopacket.LayerTypeDot1Q
func (d *Dot1Q) LayerType() gopacket.LayerType { return LayerTypeDot1Q }
// DecodeFromBytes decodes the given bytes into this layer.
func (d *Dot1Q) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 4 {
df.SetTruncated()
return fmt.Errorf("802.1Q tag length %d too short", len(data))
}
d.Priority = (data[0] & 0xE0) >> 5
d.DropEligible = data[0]&0x10 != 0
d.VLANIdentifier = binary.BigEndian.Uint16(data[:2]) & 0x0FFF
d.Type = EthernetType(binary.BigEndian.Uint16(data[2:4]))
d.BaseLayer = BaseLayer{Contents: data[:4], Payload: data[4:]}
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (d *Dot1Q) CanDecode() gopacket.LayerClass {
return LayerTypeDot1Q
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (d *Dot1Q) NextLayerType() gopacket.LayerType {
return d.Type.LayerType()
}
func decodeDot1Q(data []byte, p gopacket.PacketBuilder) error {
d := &Dot1Q{}
return decodingLayerDecoder(d, data, p)
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (d *Dot1Q) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
bytes, err := b.PrependBytes(4)
if err != nil {
return err
}
if d.VLANIdentifier > 0xFFF {
return fmt.Errorf("vlan identifier %v is too high", d.VLANIdentifier)
}
firstBytes := uint16(d.Priority)<<13 | d.VLANIdentifier
if d.DropEligible {
firstBytes |= 0x1000
}
binary.BigEndian.PutUint16(bytes, firstBytes)
binary.BigEndian.PutUint16(bytes[2:], uint16(d.Type))
return nil
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"fmt"
"github.com/google/gopacket"
)
type EAPCode uint8
type EAPType uint8
const (
EAPCodeRequest EAPCode = 1
EAPCodeResponse EAPCode = 2
EAPCodeSuccess EAPCode = 3
EAPCodeFailure EAPCode = 4
// EAPTypeNone means that this EAP layer has no Type or TypeData.
// Success and Failure EAPs will have this set.
EAPTypeNone EAPType = 0
EAPTypeIdentity EAPType = 1
EAPTypeNotification EAPType = 2
EAPTypeNACK EAPType = 3
EAPTypeOTP EAPType = 4
EAPTypeTokenCard EAPType = 5
)
// EAP defines an Extensible Authentication Protocol (rfc 3748) layer.
type EAP struct {
BaseLayer
Code EAPCode
Id uint8
Length uint16
Type EAPType
TypeData []byte
}
// LayerType returns LayerTypeEAP.
func (e *EAP) LayerType() gopacket.LayerType { return LayerTypeEAP }
// DecodeFromBytes decodes the given bytes into this layer.
func (e *EAP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 4 {
df.SetTruncated()
return fmt.Errorf("EAP length %d too short", len(data))
}
e.Code = EAPCode(data[0])
e.Id = data[1]
e.Length = binary.BigEndian.Uint16(data[2:4])
if len(data) < int(e.Length) {
df.SetTruncated()
return fmt.Errorf("EAP length %d too short, %d expected", len(data), e.Length)
}
switch {
case e.Length > 4:
e.Type = EAPType(data[4])
e.TypeData = data[5:]
case e.Length == 4:
e.Type = 0
e.TypeData = nil
default:
return fmt.Errorf("invalid EAP length %d", e.Length)
}
e.BaseLayer.Contents = data[:e.Length]
e.BaseLayer.Payload = data[e.Length:] // Should be 0 bytes
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (e *EAP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
if opts.FixLengths {
e.Length = uint16(len(e.TypeData) + 1)
}
size := len(e.TypeData) + 4
if size > 4 {
size++
}
bytes, err := b.PrependBytes(size)
if err != nil {
return err
}
bytes[0] = byte(e.Code)
bytes[1] = e.Id
binary.BigEndian.PutUint16(bytes[2:], e.Length)
if size > 4 {
bytes[4] = byte(e.Type)
copy(bytes[5:], e.TypeData)
}
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (e *EAP) CanDecode() gopacket.LayerClass {
return LayerTypeEAP
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (e *EAP) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypeZero
}
func decodeEAP(data []byte, p gopacket.PacketBuilder) error {
e := &EAP{}
return decodingLayerDecoder(e, data, p)
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"fmt"
"github.com/google/gopacket"
)
// EAPOL defines an EAP over LAN (802.1x) layer.
type EAPOL struct {
BaseLayer
Version uint8
Type EAPOLType
Length uint16
}
// LayerType returns LayerTypeEAPOL.
func (e *EAPOL) LayerType() gopacket.LayerType { return LayerTypeEAPOL }
// DecodeFromBytes decodes the given bytes into this layer.
func (e *EAPOL) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 4 {
df.SetTruncated()
return fmt.Errorf("EAPOL length %d too short", len(data))
}
e.Version = data[0]
e.Type = EAPOLType(data[1])
e.Length = binary.BigEndian.Uint16(data[2:4])
e.BaseLayer = BaseLayer{data[:4], data[4:]}
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer
func (e *EAPOL) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
bytes, _ := b.PrependBytes(4)
bytes[0] = e.Version
bytes[1] = byte(e.Type)
binary.BigEndian.PutUint16(bytes[2:], e.Length)
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (e *EAPOL) CanDecode() gopacket.LayerClass {
return LayerTypeEAPOL
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (e *EAPOL) NextLayerType() gopacket.LayerType {
return e.Type.LayerType()
}
func decodeEAPOL(data []byte, p gopacket.PacketBuilder) error {
e := &EAPOL{}
return decodingLayerDecoder(e, data, p)
}
// EAPOLKeyDescriptorType is an enumeration of key descriptor types
// as specified by 802.1x in the EAPOL-Key frame
type EAPOLKeyDescriptorType uint8
// Enumeration of EAPOLKeyDescriptorType
const (
EAPOLKeyDescriptorTypeRC4 EAPOLKeyDescriptorType = 1
EAPOLKeyDescriptorTypeDot11 EAPOLKeyDescriptorType = 2
EAPOLKeyDescriptorTypeWPA EAPOLKeyDescriptorType = 254
)
func (kdt EAPOLKeyDescriptorType) String() string {
switch kdt {
case EAPOLKeyDescriptorTypeRC4:
return "RC4"
case EAPOLKeyDescriptorTypeDot11:
return "802.11"
case EAPOLKeyDescriptorTypeWPA:
return "WPA"
default:
return fmt.Sprintf("unknown descriptor type %d", kdt)
}
}
// EAPOLKeyDescriptorVersion is an enumeration of versions specifying the
// encryption algorithm for the key data and the authentication for the
// message integrity code (MIC)
type EAPOLKeyDescriptorVersion uint8
// Enumeration of EAPOLKeyDescriptorVersion
const (
EAPOLKeyDescriptorVersionOther EAPOLKeyDescriptorVersion = 0
EAPOLKeyDescriptorVersionRC4HMACMD5 EAPOLKeyDescriptorVersion = 1
EAPOLKeyDescriptorVersionAESHMACSHA1 EAPOLKeyDescriptorVersion = 2
EAPOLKeyDescriptorVersionAES128CMAC EAPOLKeyDescriptorVersion = 3
)
func (v EAPOLKeyDescriptorVersion) String() string {
switch v {
case EAPOLKeyDescriptorVersionOther:
return "Other"
case EAPOLKeyDescriptorVersionRC4HMACMD5:
return "RC4-HMAC-MD5"
case EAPOLKeyDescriptorVersionAESHMACSHA1:
return "AES-HMAC-SHA1-128"
case EAPOLKeyDescriptorVersionAES128CMAC:
return "AES-128-CMAC"
default:
return fmt.Sprintf("unknown version %d", v)
}
}
// EAPOLKeyType is an enumeration of key derivation types describing
// the purpose of the keys being derived.
type EAPOLKeyType uint8
// Enumeration of EAPOLKeyType
const (
EAPOLKeyTypeGroupSMK EAPOLKeyType = 0
EAPOLKeyTypePairwise EAPOLKeyType = 1
)
func (kt EAPOLKeyType) String() string {
switch kt {
case EAPOLKeyTypeGroupSMK:
return "Group/SMK"
case EAPOLKeyTypePairwise:
return "Pairwise"
default:
return fmt.Sprintf("unknown key type %d", kt)
}
}
// EAPOLKey defines an EAPOL-Key frame for 802.1x authentication
type EAPOLKey struct {
BaseLayer
KeyDescriptorType EAPOLKeyDescriptorType
KeyDescriptorVersion EAPOLKeyDescriptorVersion
KeyType EAPOLKeyType
KeyIndex uint8
Install bool
KeyACK bool
KeyMIC bool
Secure bool
MICError bool
Request bool
HasEncryptedKeyData bool
SMKMessage bool
KeyLength uint16
ReplayCounter uint64
Nonce []byte
IV []byte
RSC uint64
ID uint64
MIC []byte
KeyDataLength uint16
EncryptedKeyData []byte
}
// LayerType returns LayerTypeEAPOLKey.
func (ek *EAPOLKey) LayerType() gopacket.LayerType {
return LayerTypeEAPOLKey
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (ek *EAPOLKey) CanDecode() gopacket.LayerType {
return LayerTypeEAPOLKey
}
// NextLayerType returns layers.LayerTypeDot11InformationElement if the key
// data exists and is unencrypted, otherwise it does not expect a next layer.
func (ek *EAPOLKey) NextLayerType() gopacket.LayerType {
if !ek.HasEncryptedKeyData && ek.KeyDataLength > 0 {
return LayerTypeDot11InformationElement
}
return gopacket.LayerTypePayload
}
const eapolKeyFrameLen = 95
// DecodeFromBytes decodes the given bytes into this layer.
func (ek *EAPOLKey) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < eapolKeyFrameLen {
df.SetTruncated()
return fmt.Errorf("EAPOLKey length %v too short, %v required",
len(data), eapolKeyFrameLen)
}
ek.KeyDescriptorType = EAPOLKeyDescriptorType(data[0])
info := binary.BigEndian.Uint16(data[1:3])
ek.KeyDescriptorVersion = EAPOLKeyDescriptorVersion(info & 0x0007)
ek.KeyType = EAPOLKeyType((info & 0x0008) >> 3)
ek.KeyIndex = uint8((info & 0x0030) >> 4)
ek.Install = (info & 0x0040) != 0
ek.KeyACK = (info & 0x0080) != 0
ek.KeyMIC = (info & 0x0100) != 0
ek.Secure = (info & 0x0200) != 0
ek.MICError = (info & 0x0400) != 0
ek.Request = (info & 0x0800) != 0
ek.HasEncryptedKeyData = (info & 0x1000) != 0
ek.SMKMessage = (info & 0x2000) != 0
ek.KeyLength = binary.BigEndian.Uint16(data[3:5])
ek.ReplayCounter = binary.BigEndian.Uint64(data[5:13])
ek.Nonce = data[13:45]
ek.IV = data[45:61]
ek.RSC = binary.BigEndian.Uint64(data[61:69])
ek.ID = binary.BigEndian.Uint64(data[69:77])
ek.MIC = data[77:93]
ek.KeyDataLength = binary.BigEndian.Uint16(data[93:95])
totalLength := eapolKeyFrameLen + int(ek.KeyDataLength)
if len(data) < totalLength {
df.SetTruncated()
return fmt.Errorf("EAPOLKey data length %d too short, %d required",
len(data)-eapolKeyFrameLen, ek.KeyDataLength)
}
if ek.HasEncryptedKeyData {
ek.EncryptedKeyData = data[eapolKeyFrameLen:totalLength]
ek.BaseLayer = BaseLayer{
Contents: data[:totalLength],
Payload: data[totalLength:],
}
} else {
ek.BaseLayer = BaseLayer{
Contents: data[:eapolKeyFrameLen],
Payload: data[eapolKeyFrameLen:],
}
}
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (ek *EAPOLKey) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
buf, err := b.PrependBytes(eapolKeyFrameLen + len(ek.EncryptedKeyData))
if err != nil {
return err
}
buf[0] = byte(ek.KeyDescriptorType)
var info uint16
info |= uint16(ek.KeyDescriptorVersion)
info |= uint16(ek.KeyType) << 3
info |= uint16(ek.KeyIndex) << 4
if ek.Install {
info |= 0x0040
}
if ek.KeyACK {
info |= 0x0080
}
if ek.KeyMIC {
info |= 0x0100
}
if ek.Secure {
info |= 0x0200
}
if ek.MICError {
info |= 0x0400
}
if ek.Request {
info |= 0x0800
}
if ek.HasEncryptedKeyData {
info |= 0x1000
}
if ek.SMKMessage {
info |= 0x2000
}
binary.BigEndian.PutUint16(buf[1:3], info)
binary.BigEndian.PutUint16(buf[3:5], ek.KeyLength)
binary.BigEndian.PutUint64(buf[5:13], ek.ReplayCounter)
copy(buf[13:45], ek.Nonce)
copy(buf[45:61], ek.IV)
binary.BigEndian.PutUint64(buf[61:69], ek.RSC)
binary.BigEndian.PutUint64(buf[69:77], ek.ID)
copy(buf[77:93], ek.MIC)
binary.BigEndian.PutUint16(buf[93:95], ek.KeyDataLength)
if len(ek.EncryptedKeyData) > 0 {
copy(buf[95:95+len(ek.EncryptedKeyData)], ek.EncryptedKeyData)
}
return nil
}
func decodeEAPOLKey(data []byte, p gopacket.PacketBuilder) error {
ek := &EAPOLKey{}
return decodingLayerDecoder(ek, data, p)
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"github.com/google/gopacket"
"net"
"strconv"
)
var (
// We use two different endpoint types for IPv4 vs IPv6 addresses, so that
// ordering with endpointA.LessThan(endpointB) sanely groups all IPv4
// addresses and all IPv6 addresses, such that IPv6 > IPv4 for all addresses.
EndpointIPv4 = gopacket.RegisterEndpointType(1, gopacket.EndpointTypeMetadata{Name: "IPv4", Formatter: func(b []byte) string {
return net.IP(b).String()
}})
EndpointIPv6 = gopacket.RegisterEndpointType(2, gopacket.EndpointTypeMetadata{Name: "IPv6", Formatter: func(b []byte) string {
return net.IP(b).String()
}})
EndpointMAC = gopacket.RegisterEndpointType(3, gopacket.EndpointTypeMetadata{Name: "MAC", Formatter: func(b []byte) string {
return net.HardwareAddr(b).String()
}})
EndpointTCPPort = gopacket.RegisterEndpointType(4, gopacket.EndpointTypeMetadata{Name: "TCP", Formatter: func(b []byte) string {
return strconv.Itoa(int(binary.BigEndian.Uint16(b)))
}})
EndpointUDPPort = gopacket.RegisterEndpointType(5, gopacket.EndpointTypeMetadata{Name: "UDP", Formatter: func(b []byte) string {
return strconv.Itoa(int(binary.BigEndian.Uint16(b)))
}})
EndpointSCTPPort = gopacket.RegisterEndpointType(6, gopacket.EndpointTypeMetadata{Name: "SCTP", Formatter: func(b []byte) string {
return strconv.Itoa(int(binary.BigEndian.Uint16(b)))
}})
EndpointRUDPPort = gopacket.RegisterEndpointType(7, gopacket.EndpointTypeMetadata{Name: "RUDP", Formatter: func(b []byte) string {
return strconv.Itoa(int(b[0]))
}})
EndpointUDPLitePort = gopacket.RegisterEndpointType(8, gopacket.EndpointTypeMetadata{Name: "UDPLite", Formatter: func(b []byte) string {
return strconv.Itoa(int(binary.BigEndian.Uint16(b)))
}})
EndpointPPP = gopacket.RegisterEndpointType(9, gopacket.EndpointTypeMetadata{Name: "PPP", Formatter: func([]byte) string {
return "point"
}})
)
// NewIPEndpoint creates a new IP (v4 or v6) endpoint from a net.IP address.
// It returns gopacket.InvalidEndpoint if the IP address is invalid.
func NewIPEndpoint(a net.IP) gopacket.Endpoint {
ipv4 := a.To4()
if ipv4 != nil {
return gopacket.NewEndpoint(EndpointIPv4, []byte(ipv4))
}
ipv6 := a.To16()
if ipv6 != nil {
return gopacket.NewEndpoint(EndpointIPv6, []byte(ipv6))
}
return gopacket.InvalidEndpoint
}
// NewMACEndpoint returns a new MAC address endpoint.
func NewMACEndpoint(a net.HardwareAddr) gopacket.Endpoint {
return gopacket.NewEndpoint(EndpointMAC, []byte(a))
}
func newPortEndpoint(t gopacket.EndpointType, p uint16) gopacket.Endpoint {
return gopacket.NewEndpoint(t, []byte{byte(p >> 8), byte(p)})
}
// NewTCPPortEndpoint returns an endpoint based on a TCP port.
func NewTCPPortEndpoint(p TCPPort) gopacket.Endpoint {
return newPortEndpoint(EndpointTCPPort, uint16(p))
}
// NewUDPPortEndpoint returns an endpoint based on a UDP port.
func NewUDPPortEndpoint(p UDPPort) gopacket.Endpoint {
return newPortEndpoint(EndpointUDPPort, uint16(p))
}
// NewSCTPPortEndpoint returns an endpoint based on a SCTP port.
func NewSCTPPortEndpoint(p SCTPPort) gopacket.Endpoint {
return newPortEndpoint(EndpointSCTPPort, uint16(p))
}
// NewRUDPPortEndpoint returns an endpoint based on a RUDP port.
func NewRUDPPortEndpoint(p RUDPPort) gopacket.Endpoint {
return gopacket.NewEndpoint(EndpointRUDPPort, []byte{byte(p)})
}
// NewUDPLitePortEndpoint returns an endpoint based on a UDPLite port.
func NewUDPLitePortEndpoint(p UDPLitePort) gopacket.Endpoint {
return newPortEndpoint(EndpointUDPLitePort, uint16(p))
}
// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"fmt"
"runtime"
"github.com/google/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
// LayerType is the layer type implied by the given enum.
LayerType gopacket.LayerType
}
// EthernetType is an enumeration of ethernet type values, and acts as a decoder
// for any type it supports.
type EthernetType uint16
const (
// EthernetTypeLLC is not an actual ethernet type. It is instead a
// placeholder we use in Ethernet frames that use the 802.3 standard of
// srcmac|dstmac|length|LLC instead of srcmac|dstmac|ethertype.
EthernetTypeLLC EthernetType = 0
EthernetTypeIPv4 EthernetType = 0x0800
EthernetTypeARP EthernetType = 0x0806
EthernetTypeIPv6 EthernetType = 0x86DD
EthernetTypeCiscoDiscovery EthernetType = 0x2000
EthernetTypeNortelDiscovery EthernetType = 0x01a2
EthernetTypeTransparentEthernetBridging EthernetType = 0x6558
EthernetTypeDot1Q EthernetType = 0x8100
EthernetTypePPP EthernetType = 0x880b
EthernetTypePPPoEDiscovery EthernetType = 0x8863
EthernetTypePPPoESession EthernetType = 0x8864
EthernetTypeMPLSUnicast EthernetType = 0x8847
EthernetTypeMPLSMulticast EthernetType = 0x8848
EthernetTypeEAPOL EthernetType = 0x888e
EthernetTypeERSPAN EthernetType = 0x88be
EthernetTypeQinQ EthernetType = 0x88a8
EthernetTypeLinkLayerDiscovery EthernetType = 0x88cc
EthernetTypeEthernetCTP EthernetType = 0x9000
)
// IPProtocol is an enumeration of IP protocol values, and acts as a decoder
// for any type it supports.
type IPProtocol uint8
const (
IPProtocolIPv6HopByHop IPProtocol = 0
IPProtocolICMPv4 IPProtocol = 1
IPProtocolIGMP IPProtocol = 2
IPProtocolIPv4 IPProtocol = 4
IPProtocolTCP IPProtocol = 6
IPProtocolUDP IPProtocol = 17
IPProtocolRUDP IPProtocol = 27
IPProtocolIPv6 IPProtocol = 41
IPProtocolIPv6Routing IPProtocol = 43
IPProtocolIPv6Fragment IPProtocol = 44
IPProtocolGRE IPProtocol = 47
IPProtocolESP IPProtocol = 50
IPProtocolAH IPProtocol = 51
IPProtocolICMPv6 IPProtocol = 58
IPProtocolNoNextHeader IPProtocol = 59
IPProtocolIPv6Destination IPProtocol = 60
IPProtocolOSPF IPProtocol = 89
IPProtocolIPIP IPProtocol = 94
IPProtocolEtherIP IPProtocol = 97
IPProtocolVRRP IPProtocol = 112
IPProtocolSCTP IPProtocol = 132
IPProtocolUDPLite IPProtocol = 136
IPProtocolMPLSInIP IPProtocol = 137
)
// LinkType is an enumeration of link types, and acts as a decoder for any
// link type it supports.
type LinkType uint8
const (
// According to pcap-linktype(7) and http://www.tcpdump.org/linktypes.html
LinkTypeNull LinkType = 0
LinkTypeEthernet LinkType = 1
LinkTypeAX25 LinkType = 3
LinkTypeTokenRing LinkType = 6
LinkTypeArcNet LinkType = 7
LinkTypeSLIP LinkType = 8
LinkTypePPP LinkType = 9
LinkTypeFDDI LinkType = 10
LinkTypePPP_HDLC LinkType = 50
LinkTypePPPEthernet LinkType = 51
LinkTypeATM_RFC1483 LinkType = 100
LinkTypeRaw LinkType = 101
LinkTypeC_HDLC LinkType = 104
LinkTypeIEEE802_11 LinkType = 105
LinkTypeFRelay LinkType = 107
LinkTypeLoop LinkType = 108
LinkTypeLinuxSLL LinkType = 113
LinkTypeLTalk LinkType = 114
LinkTypePFLog LinkType = 117
LinkTypePrismHeader LinkType = 119
LinkTypeIPOverFC LinkType = 122
LinkTypeSunATM LinkType = 123
LinkTypeIEEE80211Radio LinkType = 127
LinkTypeARCNetLinux LinkType = 129
LinkTypeIPOver1394 LinkType = 138
LinkTypeMTP2Phdr LinkType = 139
LinkTypeMTP2 LinkType = 140
LinkTypeMTP3 LinkType = 141
LinkTypeSCCP LinkType = 142
LinkTypeDOCSIS LinkType = 143
LinkTypeLinuxIRDA LinkType = 144
LinkTypeLinuxLAPD LinkType = 177
LinkTypeLinuxUSB LinkType = 220
LinkTypeFC2 LinkType = 224
LinkTypeFC2Framed LinkType = 225
LinkTypeIPv4 LinkType = 228
LinkTypeIPv6 LinkType = 229
)
// PPPoECode is the PPPoE code enum, taken from http://tools.ietf.org/html/rfc2516
type PPPoECode uint8
const (
PPPoECodePADI PPPoECode = 0x09
PPPoECodePADO PPPoECode = 0x07
PPPoECodePADR PPPoECode = 0x19
PPPoECodePADS PPPoECode = 0x65
PPPoECodePADT PPPoECode = 0xA7
PPPoECodeSession PPPoECode = 0x00
)
// PPPType is an enumeration of PPP type values, and acts as a decoder for any
// type it supports.
type PPPType uint16
const (
PPPTypeIPv4 PPPType = 0x0021
PPPTypeIPv6 PPPType = 0x0057
PPPTypeMPLSUnicast PPPType = 0x0281
PPPTypeMPLSMulticast PPPType = 0x0283
)
// SCTPChunkType is an enumeration of chunk types inside SCTP packets.
type SCTPChunkType uint8
const (
SCTPChunkTypeData SCTPChunkType = 0
SCTPChunkTypeInit SCTPChunkType = 1
SCTPChunkTypeInitAck SCTPChunkType = 2
SCTPChunkTypeSack SCTPChunkType = 3
SCTPChunkTypeHeartbeat SCTPChunkType = 4
SCTPChunkTypeHeartbeatAck SCTPChunkType = 5
SCTPChunkTypeAbort SCTPChunkType = 6
SCTPChunkTypeShutdown SCTPChunkType = 7
SCTPChunkTypeShutdownAck SCTPChunkType = 8
SCTPChunkTypeError SCTPChunkType = 9
SCTPChunkTypeCookieEcho SCTPChunkType = 10
SCTPChunkTypeCookieAck SCTPChunkType = 11
SCTPChunkTypeShutdownComplete SCTPChunkType = 14
)
// FDDIFrameControl is an enumeration of FDDI frame control bytes.
type FDDIFrameControl uint8
const (
FDDIFrameControlLLC FDDIFrameControl = 0x50
)
// EAPOLType is an enumeration of EAPOL packet types.
type EAPOLType uint8
const (
EAPOLTypeEAP EAPOLType = 0
EAPOLTypeStart EAPOLType = 1
EAPOLTypeLogOff EAPOLType = 2
EAPOLTypeKey EAPOLType = 3
EAPOLTypeASFAlert EAPOLType = 4
)
// ProtocolFamily is the set of values defined as PF_* in sys/socket.h
type ProtocolFamily uint8
const (
ProtocolFamilyIPv4 ProtocolFamily = 2
// BSDs use different values for INET6... glory be. These values taken from
// tcpdump 4.3.0.
ProtocolFamilyIPv6BSD ProtocolFamily = 24
ProtocolFamilyIPv6FreeBSD ProtocolFamily = 28
ProtocolFamilyIPv6Darwin ProtocolFamily = 30
ProtocolFamilyIPv6Linux ProtocolFamily = 10
)
// Dot11Type is a combination of IEEE 802.11 frame's Type and Subtype fields.
// By combining these two fields together into a single type, we're able to
// provide a String function that correctly displays the subtype given the
// top-level type.
//
// If you just care about the top-level type, use the MainType function.
type Dot11Type uint8
// MainType strips the subtype information from the given type,
// returning just the overarching type (Mgmt, Ctrl, Data, Reserved).
func (d Dot11Type) MainType() Dot11Type {
return d & dot11TypeMask
}
func (d Dot11Type) QOS() bool {
return d&dot11QOSMask == Dot11TypeDataQOSData
}
const (
Dot11TypeMgmt Dot11Type = 0x00
Dot11TypeCtrl Dot11Type = 0x01
Dot11TypeData Dot11Type = 0x02
Dot11TypeReserved Dot11Type = 0x03
dot11TypeMask = 0x03
dot11QOSMask = 0x23
// The following are type/subtype conglomerations.
// Management
Dot11TypeMgmtAssociationReq Dot11Type = 0x00
Dot11TypeMgmtAssociationResp Dot11Type = 0x04
Dot11TypeMgmtReassociationReq Dot11Type = 0x08
Dot11TypeMgmtReassociationResp Dot11Type = 0x0c
Dot11TypeMgmtProbeReq Dot11Type = 0x10
Dot11TypeMgmtProbeResp Dot11Type = 0x14
Dot11TypeMgmtMeasurementPilot Dot11Type = 0x18
Dot11TypeMgmtBeacon Dot11Type = 0x20
Dot11TypeMgmtATIM Dot11Type = 0x24
Dot11TypeMgmtDisassociation Dot11Type = 0x28
Dot11TypeMgmtAuthentication Dot11Type = 0x2c
Dot11TypeMgmtDeauthentication Dot11Type = 0x30
Dot11TypeMgmtAction Dot11Type = 0x34
Dot11TypeMgmtActionNoAck Dot11Type = 0x38
// Control
Dot11TypeCtrlWrapper Dot11Type = 0x1d
Dot11TypeCtrlBlockAckReq Dot11Type = 0x21
Dot11TypeCtrlBlockAck Dot11Type = 0x25
Dot11TypeCtrlPowersavePoll Dot11Type = 0x29
Dot11TypeCtrlRTS Dot11Type = 0x2d
Dot11TypeCtrlCTS Dot11Type = 0x31
Dot11TypeCtrlAck Dot11Type = 0x35
Dot11TypeCtrlCFEnd Dot11Type = 0x39
Dot11TypeCtrlCFEndAck Dot11Type = 0x3d
// Data
Dot11TypeDataCFAck Dot11Type = 0x06
Dot11TypeDataCFPoll Dot11Type = 0x0a
Dot11TypeDataCFAckPoll Dot11Type = 0x0e
Dot11TypeDataNull Dot11Type = 0x12
Dot11TypeDataCFAckNoData Dot11Type = 0x16
Dot11TypeDataCFPollNoData Dot11Type = 0x1a
Dot11TypeDataCFAckPollNoData Dot11Type = 0x1e
Dot11TypeDataQOSData Dot11Type = 0x22
Dot11TypeDataQOSDataCFAck Dot11Type = 0x26
Dot11TypeDataQOSDataCFPoll Dot11Type = 0x2a
Dot11TypeDataQOSDataCFAckPoll Dot11Type = 0x2e
Dot11TypeDataQOSNull Dot11Type = 0x32
Dot11TypeDataQOSCFPollNoData Dot11Type = 0x3a
Dot11TypeDataQOSCFAckPollNoData Dot11Type = 0x3e
)
// Decode a raw v4 or v6 IP packet.
func decodeIPv4or6(data []byte, p gopacket.PacketBuilder) error {
version := data[0] >> 4
switch version {
case 4:
return decodeIPv4(data, p)
case 6:
return decodeIPv6(data, p)
}
return fmt.Errorf("Invalid IP packet version %v", version)
}
func initActualTypeData() {
// Each of the XXXTypeMetadata arrays contains mappings of how to handle enum
// values for various enum types in gopacket/layers.
// These arrays are actually created by gen2.go and stored in
// enums_generated.go.
//
// 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.
// Here we link up all enumerations with their respective names and decoders.
EthernetTypeMetadata[EthernetTypeLLC] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeLLC), Name: "LLC", LayerType: LayerTypeLLC}
EthernetTypeMetadata[EthernetTypeIPv4] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4), Name: "IPv4", LayerType: LayerTypeIPv4}
EthernetTypeMetadata[EthernetTypeIPv6] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6), Name: "IPv6", LayerType: LayerTypeIPv6}
EthernetTypeMetadata[EthernetTypeARP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeARP), Name: "ARP", LayerType: LayerTypeARP}
EthernetTypeMetadata[EthernetTypeDot1Q] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot1Q), Name: "Dot1Q", LayerType: LayerTypeDot1Q}
EthernetTypeMetadata[EthernetTypePPP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodePPP), Name: "PPP", LayerType: LayerTypePPP}
EthernetTypeMetadata[EthernetTypePPPoEDiscovery] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodePPPoE), Name: "PPPoEDiscovery", LayerType: LayerTypePPPoE}
EthernetTypeMetadata[EthernetTypePPPoESession] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodePPPoE), Name: "PPPoESession", LayerType: LayerTypePPPoE}
EthernetTypeMetadata[EthernetTypeEthernetCTP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeEthernetCTP), Name: "EthernetCTP", LayerType: LayerTypeEthernetCTP}
EthernetTypeMetadata[EthernetTypeCiscoDiscovery] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeCiscoDiscovery), Name: "CiscoDiscovery", LayerType: LayerTypeCiscoDiscovery}
EthernetTypeMetadata[EthernetTypeNortelDiscovery] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeNortelDiscovery), Name: "NortelDiscovery", LayerType: LayerTypeNortelDiscovery}
EthernetTypeMetadata[EthernetTypeLinkLayerDiscovery] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeLinkLayerDiscovery), Name: "LinkLayerDiscovery", LayerType: LayerTypeLinkLayerDiscovery}
EthernetTypeMetadata[EthernetTypeMPLSUnicast] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeMPLS), Name: "MPLSUnicast", LayerType: LayerTypeMPLS}
EthernetTypeMetadata[EthernetTypeMPLSMulticast] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeMPLS), Name: "MPLSMulticast", LayerType: LayerTypeMPLS}
EthernetTypeMetadata[EthernetTypeEAPOL] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeEAPOL), Name: "EAPOL", LayerType: LayerTypeEAPOL}
EthernetTypeMetadata[EthernetTypeQinQ] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot1Q), Name: "Dot1Q", LayerType: LayerTypeDot1Q}
EthernetTypeMetadata[EthernetTypeTransparentEthernetBridging] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeEthernet), Name: "TransparentEthernetBridging", LayerType: LayerTypeEthernet}
EthernetTypeMetadata[EthernetTypeERSPAN] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeERSPANII), Name: "ERSPAN Type II", LayerType: LayerTypeERSPANII}
IPProtocolMetadata[IPProtocolIPv4] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4), Name: "IPv4", LayerType: LayerTypeIPv4}
IPProtocolMetadata[IPProtocolTCP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeTCP), Name: "TCP", LayerType: LayerTypeTCP}
IPProtocolMetadata[IPProtocolUDP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeUDP), Name: "UDP", LayerType: LayerTypeUDP}
IPProtocolMetadata[IPProtocolICMPv4] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeICMPv4), Name: "ICMPv4", LayerType: LayerTypeICMPv4}
IPProtocolMetadata[IPProtocolICMPv6] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeICMPv6), Name: "ICMPv6", LayerType: LayerTypeICMPv6}
IPProtocolMetadata[IPProtocolSCTP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTP), Name: "SCTP", LayerType: LayerTypeSCTP}
IPProtocolMetadata[IPProtocolIPv6] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6), Name: "IPv6", LayerType: LayerTypeIPv6}
IPProtocolMetadata[IPProtocolIPIP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4), Name: "IPv4", LayerType: LayerTypeIPv4}
IPProtocolMetadata[IPProtocolEtherIP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeEtherIP), Name: "EtherIP", LayerType: LayerTypeEtherIP}
IPProtocolMetadata[IPProtocolRUDP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeRUDP), Name: "RUDP", LayerType: LayerTypeRUDP}
IPProtocolMetadata[IPProtocolGRE] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeGRE), Name: "GRE", LayerType: LayerTypeGRE}
IPProtocolMetadata[IPProtocolIPv6HopByHop] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6HopByHop), Name: "IPv6HopByHop", LayerType: LayerTypeIPv6HopByHop}
IPProtocolMetadata[IPProtocolIPv6Routing] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6Routing), Name: "IPv6Routing", LayerType: LayerTypeIPv6Routing}
IPProtocolMetadata[IPProtocolIPv6Fragment] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6Fragment), Name: "IPv6Fragment", LayerType: LayerTypeIPv6Fragment}
IPProtocolMetadata[IPProtocolIPv6Destination] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6Destination), Name: "IPv6Destination", LayerType: LayerTypeIPv6Destination}
IPProtocolMetadata[IPProtocolOSPF] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeOSPF), Name: "OSPF", LayerType: LayerTypeOSPF}
IPProtocolMetadata[IPProtocolAH] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPSecAH), Name: "IPSecAH", LayerType: LayerTypeIPSecAH}
IPProtocolMetadata[IPProtocolESP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPSecESP), Name: "IPSecESP", LayerType: LayerTypeIPSecESP}
IPProtocolMetadata[IPProtocolUDPLite] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeUDPLite), Name: "UDPLite", LayerType: LayerTypeUDPLite}
IPProtocolMetadata[IPProtocolMPLSInIP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeMPLS), Name: "MPLS", LayerType: LayerTypeMPLS}
IPProtocolMetadata[IPProtocolNoNextHeader] = EnumMetadata{DecodeWith: gopacket.DecodePayload, Name: "NoNextHeader", LayerType: gopacket.LayerTypePayload}
IPProtocolMetadata[IPProtocolIGMP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIGMP), Name: "IGMP", LayerType: LayerTypeIGMP}
IPProtocolMetadata[IPProtocolVRRP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeVRRP), Name: "VRRP", LayerType: LayerTypeVRRP}
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"}
PPPTypeMetadata[PPPTypeMPLSUnicast] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeMPLS), Name: "MPLSUnicast"}
PPPTypeMetadata[PPPTypeMPLSMulticast] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeMPLS), Name: "MPLSMulticast"}
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"}
LinkTypeMetadata[LinkTypeFDDI] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeFDDI), Name: "FDDI"}
LinkTypeMetadata[LinkTypeNull] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeLoopback), Name: "Null"}
LinkTypeMetadata[LinkTypeIEEE802_11] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11), Name: "Dot11"}
LinkTypeMetadata[LinkTypeLoop] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeLoopback), Name: "Loop"}
LinkTypeMetadata[LinkTypeIEEE802_11] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11), Name: "802.11"}
LinkTypeMetadata[LinkTypeRaw] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4or6), Name: "Raw"}
// See https://github.com/the-tcpdump-group/libpcap/blob/170f717e6e818cdc4bcbbfd906b63088eaa88fa0/pcap/dlt.h#L85
// Or https://github.com/wireshark/wireshark/blob/854cfe53efe44080609c78053ecfb2342ad84a08/wiretap/pcap-common.c#L508
if runtime.GOOS == "openbsd" {
LinkTypeMetadata[14] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4or6), Name: "Raw"}
} else {
LinkTypeMetadata[12] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4or6), Name: "Raw"}
}
LinkTypeMetadata[LinkTypePFLog] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodePFLog), Name: "PFLog"}
LinkTypeMetadata[LinkTypeIEEE80211Radio] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeRadioTap), Name: "RadioTap"}
LinkTypeMetadata[LinkTypeLinuxUSB] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeUSB), Name: "USB"}
LinkTypeMetadata[LinkTypeLinuxSLL] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeLinuxSLL), Name: "Linux SLL"}
LinkTypeMetadata[LinkTypePrismHeader] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodePrismHeader), Name: "Prism"}
FDDIFrameControlMetadata[FDDIFrameControlLLC] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeLLC), Name: "LLC"}
EAPOLTypeMetadata[EAPOLTypeEAP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeEAP), Name: "EAP", LayerType: LayerTypeEAP}
EAPOLTypeMetadata[EAPOLTypeKey] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeEAPOLKey), Name: "EAPOLKey", LayerType: LayerTypeEAPOLKey}
ProtocolFamilyMetadata[ProtocolFamilyIPv4] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4), Name: "IPv4", LayerType: LayerTypeIPv4}
ProtocolFamilyMetadata[ProtocolFamilyIPv6BSD] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6), Name: "IPv6", LayerType: LayerTypeIPv6}
ProtocolFamilyMetadata[ProtocolFamilyIPv6FreeBSD] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6), Name: "IPv6", LayerType: LayerTypeIPv6}
ProtocolFamilyMetadata[ProtocolFamilyIPv6Darwin] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6), Name: "IPv6", LayerType: LayerTypeIPv6}
ProtocolFamilyMetadata[ProtocolFamilyIPv6Linux] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6), Name: "IPv6", LayerType: LayerTypeIPv6}
Dot11TypeMetadata[Dot11TypeMgmtAssociationReq] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtAssociationReq), Name: "MgmtAssociationReq", LayerType: LayerTypeDot11MgmtAssociationReq}
Dot11TypeMetadata[Dot11TypeMgmtAssociationResp] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtAssociationResp), Name: "MgmtAssociationResp", LayerType: LayerTypeDot11MgmtAssociationResp}
Dot11TypeMetadata[Dot11TypeMgmtReassociationReq] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtReassociationReq), Name: "MgmtReassociationReq", LayerType: LayerTypeDot11MgmtReassociationReq}
Dot11TypeMetadata[Dot11TypeMgmtReassociationResp] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtReassociationResp), Name: "MgmtReassociationResp", LayerType: LayerTypeDot11MgmtReassociationResp}
Dot11TypeMetadata[Dot11TypeMgmtProbeReq] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtProbeReq), Name: "MgmtProbeReq", LayerType: LayerTypeDot11MgmtProbeReq}
Dot11TypeMetadata[Dot11TypeMgmtProbeResp] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtProbeResp), Name: "MgmtProbeResp", LayerType: LayerTypeDot11MgmtProbeResp}
Dot11TypeMetadata[Dot11TypeMgmtMeasurementPilot] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtMeasurementPilot), Name: "MgmtMeasurementPilot", LayerType: LayerTypeDot11MgmtMeasurementPilot}
Dot11TypeMetadata[Dot11TypeMgmtBeacon] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtBeacon), Name: "MgmtBeacon", LayerType: LayerTypeDot11MgmtBeacon}
Dot11TypeMetadata[Dot11TypeMgmtATIM] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtATIM), Name: "MgmtATIM", LayerType: LayerTypeDot11MgmtATIM}
Dot11TypeMetadata[Dot11TypeMgmtDisassociation] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtDisassociation), Name: "MgmtDisassociation", LayerType: LayerTypeDot11MgmtDisassociation}
Dot11TypeMetadata[Dot11TypeMgmtAuthentication] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtAuthentication), Name: "MgmtAuthentication", LayerType: LayerTypeDot11MgmtAuthentication}
Dot11TypeMetadata[Dot11TypeMgmtDeauthentication] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtDeauthentication), Name: "MgmtDeauthentication", LayerType: LayerTypeDot11MgmtDeauthentication}
Dot11TypeMetadata[Dot11TypeMgmtAction] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtAction), Name: "MgmtAction", LayerType: LayerTypeDot11MgmtAction}
Dot11TypeMetadata[Dot11TypeMgmtActionNoAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtActionNoAck), Name: "MgmtActionNoAck", LayerType: LayerTypeDot11MgmtActionNoAck}
Dot11TypeMetadata[Dot11TypeCtrl] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11Ctrl), Name: "Ctrl", LayerType: LayerTypeDot11Ctrl}
Dot11TypeMetadata[Dot11TypeCtrlWrapper] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11Ctrl), Name: "CtrlWrapper", LayerType: LayerTypeDot11Ctrl}
Dot11TypeMetadata[Dot11TypeCtrlBlockAckReq] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11CtrlBlockAckReq), Name: "CtrlBlockAckReq", LayerType: LayerTypeDot11CtrlBlockAckReq}
Dot11TypeMetadata[Dot11TypeCtrlBlockAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11CtrlBlockAck), Name: "CtrlBlockAck", LayerType: LayerTypeDot11CtrlBlockAck}
Dot11TypeMetadata[Dot11TypeCtrlPowersavePoll] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11CtrlPowersavePoll), Name: "CtrlPowersavePoll", LayerType: LayerTypeDot11CtrlPowersavePoll}
Dot11TypeMetadata[Dot11TypeCtrlRTS] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11CtrlRTS), Name: "CtrlRTS", LayerType: LayerTypeDot11CtrlRTS}
Dot11TypeMetadata[Dot11TypeCtrlCTS] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11CtrlCTS), Name: "CtrlCTS", LayerType: LayerTypeDot11CtrlCTS}
Dot11TypeMetadata[Dot11TypeCtrlAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11CtrlAck), Name: "CtrlAck", LayerType: LayerTypeDot11CtrlAck}
Dot11TypeMetadata[Dot11TypeCtrlCFEnd] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11CtrlCFEnd), Name: "CtrlCFEnd", LayerType: LayerTypeDot11CtrlCFEnd}
Dot11TypeMetadata[Dot11TypeCtrlCFEndAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11CtrlCFEndAck), Name: "CtrlCFEndAck", LayerType: LayerTypeDot11CtrlCFEndAck}
Dot11TypeMetadata[Dot11TypeData] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11Data), Name: "Data", LayerType: LayerTypeDot11Data}
Dot11TypeMetadata[Dot11TypeDataCFAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataCFAck), Name: "DataCFAck", LayerType: LayerTypeDot11DataCFAck}
Dot11TypeMetadata[Dot11TypeDataCFPoll] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataCFPoll), Name: "DataCFPoll", LayerType: LayerTypeDot11DataCFPoll}
Dot11TypeMetadata[Dot11TypeDataCFAckPoll] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataCFAckPoll), Name: "DataCFAckPoll", LayerType: LayerTypeDot11DataCFAckPoll}
Dot11TypeMetadata[Dot11TypeDataNull] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataNull), Name: "DataNull", LayerType: LayerTypeDot11DataNull}
Dot11TypeMetadata[Dot11TypeDataCFAckNoData] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataCFAckNoData), Name: "DataCFAckNoData", LayerType: LayerTypeDot11DataCFAckNoData}
Dot11TypeMetadata[Dot11TypeDataCFPollNoData] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataCFPollNoData), Name: "DataCFPollNoData", LayerType: LayerTypeDot11DataCFPollNoData}
Dot11TypeMetadata[Dot11TypeDataCFAckPollNoData] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataCFAckPollNoData), Name: "DataCFAckPollNoData", LayerType: LayerTypeDot11DataCFAckPollNoData}
Dot11TypeMetadata[Dot11TypeDataQOSData] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataQOSData), Name: "DataQOSData", LayerType: LayerTypeDot11DataQOSData}
Dot11TypeMetadata[Dot11TypeDataQOSDataCFAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataQOSDataCFAck), Name: "DataQOSDataCFAck", LayerType: LayerTypeDot11DataQOSDataCFAck}
Dot11TypeMetadata[Dot11TypeDataQOSDataCFPoll] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataQOSDataCFPoll), Name: "DataQOSDataCFPoll", LayerType: LayerTypeDot11DataQOSDataCFPoll}
Dot11TypeMetadata[Dot11TypeDataQOSDataCFAckPoll] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataQOSDataCFAckPoll), Name: "DataQOSDataCFAckPoll", LayerType: LayerTypeDot11DataQOSDataCFAckPoll}
Dot11TypeMetadata[Dot11TypeDataQOSNull] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataQOSNull), Name: "DataQOSNull", LayerType: LayerTypeDot11DataQOSNull}
Dot11TypeMetadata[Dot11TypeDataQOSCFPollNoData] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataQOSCFPollNoData), Name: "DataQOSCFPollNoData", LayerType: LayerTypeDot11DataQOSCFPollNoData}
Dot11TypeMetadata[Dot11TypeDataQOSCFAckPollNoData] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataQOSCFAckPollNoData), Name: "DataQOSCFAckPollNoData", LayerType: LayerTypeDot11DataQOSCFAckPollNoData}
USBTransportTypeMetadata[USBTransportTypeInterrupt] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeUSBInterrupt), Name: "Interrupt", LayerType: LayerTypeUSBInterrupt}
USBTransportTypeMetadata[USBTransportTypeControl] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeUSBControl), Name: "Control", LayerType: LayerTypeUSBControl}
USBTransportTypeMetadata[USBTransportTypeBulk] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeUSBBulk), Name: "Bulk", LayerType: LayerTypeUSBBulk}
}
// Copyright 2012 Google, Inc. All rights reserved.
package layers
// Created by gen2.go, don't edit manually
// Generated at 2017-10-23 10:20:24.458771856 -0600 MDT m=+0.001159033
import (
"fmt"
"github.com/google/gopacket"
)
func init() {
initUnknownTypesForLinkType()
initUnknownTypesForEthernetType()
initUnknownTypesForPPPType()
initUnknownTypesForIPProtocol()
initUnknownTypesForSCTPChunkType()
initUnknownTypesForPPPoECode()
initUnknownTypesForFDDIFrameControl()
initUnknownTypesForEAPOLType()
initUnknownTypesForProtocolFamily()
initUnknownTypesForDot11Type()
initUnknownTypesForUSBTransportType()
initActualTypeData()
}
// Decoder calls LinkTypeMetadata.DecodeWith's decoder.
func (a LinkType) Decode(data []byte, p gopacket.PacketBuilder) error {
return LinkTypeMetadata[a].DecodeWith.Decode(data, p)
}
// String returns LinkTypeMetadata.Name.
func (a LinkType) String() string {
return LinkTypeMetadata[a].Name
}
// LayerType returns LinkTypeMetadata.LayerType.
func (a LinkType) LayerType() gopacket.LayerType {
return LinkTypeMetadata[a].LayerType
}
type errorDecoderForLinkType int
func (a *errorDecoderForLinkType) Decode(data []byte, p gopacket.PacketBuilder) error {
return a
}
func (a *errorDecoderForLinkType) Error() string {
return fmt.Sprintf("Unable to decode LinkType %d", int(*a))
}
var errorDecodersForLinkType [256]errorDecoderForLinkType
var LinkTypeMetadata [256]EnumMetadata
func initUnknownTypesForLinkType() {
for i := 0; i < 256; i++ {
errorDecodersForLinkType[i] = errorDecoderForLinkType(i)
LinkTypeMetadata[i] = EnumMetadata{
DecodeWith: &errorDecodersForLinkType[i],
Name: "UnknownLinkType",
}
}
}
// Decoder calls EthernetTypeMetadata.DecodeWith's decoder.
func (a EthernetType) Decode(data []byte, p gopacket.PacketBuilder) error {
return EthernetTypeMetadata[a].DecodeWith.Decode(data, p)
}
// String returns EthernetTypeMetadata.Name.
func (a EthernetType) String() string {
return EthernetTypeMetadata[a].Name
}
// LayerType returns EthernetTypeMetadata.LayerType.
func (a EthernetType) LayerType() gopacket.LayerType {
return EthernetTypeMetadata[a].LayerType
}
type errorDecoderForEthernetType int
func (a *errorDecoderForEthernetType) Decode(data []byte, p gopacket.PacketBuilder) error {
return a
}
func (a *errorDecoderForEthernetType) Error() string {
return fmt.Sprintf("Unable to decode EthernetType %d", int(*a))
}
var errorDecodersForEthernetType [65536]errorDecoderForEthernetType
var EthernetTypeMetadata [65536]EnumMetadata
func initUnknownTypesForEthernetType() {
for i := 0; i < 65536; i++ {
errorDecodersForEthernetType[i] = errorDecoderForEthernetType(i)
EthernetTypeMetadata[i] = EnumMetadata{
DecodeWith: &errorDecodersForEthernetType[i],
Name: "UnknownEthernetType",
}
}
}
// Decoder calls PPPTypeMetadata.DecodeWith's decoder.
func (a PPPType) Decode(data []byte, p gopacket.PacketBuilder) error {
return PPPTypeMetadata[a].DecodeWith.Decode(data, p)
}
// String returns PPPTypeMetadata.Name.
func (a PPPType) String() string {
return PPPTypeMetadata[a].Name
}
// LayerType returns PPPTypeMetadata.LayerType.
func (a PPPType) LayerType() gopacket.LayerType {
return PPPTypeMetadata[a].LayerType
}
type errorDecoderForPPPType int
func (a *errorDecoderForPPPType) Decode(data []byte, p gopacket.PacketBuilder) error {
return a
}
func (a *errorDecoderForPPPType) Error() string {
return fmt.Sprintf("Unable to decode PPPType %d", int(*a))
}
var errorDecodersForPPPType [65536]errorDecoderForPPPType
var PPPTypeMetadata [65536]EnumMetadata
func initUnknownTypesForPPPType() {
for i := 0; i < 65536; i++ {
errorDecodersForPPPType[i] = errorDecoderForPPPType(i)
PPPTypeMetadata[i] = EnumMetadata{
DecodeWith: &errorDecodersForPPPType[i],
Name: "UnknownPPPType",
}
}
}
// Decoder calls IPProtocolMetadata.DecodeWith's decoder.
func (a IPProtocol) Decode(data []byte, p gopacket.PacketBuilder) error {
return IPProtocolMetadata[a].DecodeWith.Decode(data, p)
}
// String returns IPProtocolMetadata.Name.
func (a IPProtocol) String() string {
return IPProtocolMetadata[a].Name
}
// LayerType returns IPProtocolMetadata.LayerType.
func (a IPProtocol) LayerType() gopacket.LayerType {
return IPProtocolMetadata[a].LayerType
}
type errorDecoderForIPProtocol int
func (a *errorDecoderForIPProtocol) Decode(data []byte, p gopacket.PacketBuilder) error {
return a
}
func (a *errorDecoderForIPProtocol) Error() string {
return fmt.Sprintf("Unable to decode IPProtocol %d", int(*a))
}
var errorDecodersForIPProtocol [256]errorDecoderForIPProtocol
var IPProtocolMetadata [256]EnumMetadata
func initUnknownTypesForIPProtocol() {
for i := 0; i < 256; i++ {
errorDecodersForIPProtocol[i] = errorDecoderForIPProtocol(i)
IPProtocolMetadata[i] = EnumMetadata{
DecodeWith: &errorDecodersForIPProtocol[i],
Name: "UnknownIPProtocol",
}
}
}
// Decoder calls SCTPChunkTypeMetadata.DecodeWith's decoder.
func (a SCTPChunkType) Decode(data []byte, p gopacket.PacketBuilder) error {
return SCTPChunkTypeMetadata[a].DecodeWith.Decode(data, p)
}
// String returns SCTPChunkTypeMetadata.Name.
func (a SCTPChunkType) String() string {
return SCTPChunkTypeMetadata[a].Name
}
// LayerType returns SCTPChunkTypeMetadata.LayerType.
func (a SCTPChunkType) LayerType() gopacket.LayerType {
return SCTPChunkTypeMetadata[a].LayerType
}
type errorDecoderForSCTPChunkType int
func (a *errorDecoderForSCTPChunkType) Decode(data []byte, p gopacket.PacketBuilder) error {
return a
}
func (a *errorDecoderForSCTPChunkType) Error() string {
return fmt.Sprintf("Unable to decode SCTPChunkType %d", int(*a))
}
var errorDecodersForSCTPChunkType [256]errorDecoderForSCTPChunkType
var SCTPChunkTypeMetadata [256]EnumMetadata
func initUnknownTypesForSCTPChunkType() {
for i := 0; i < 256; i++ {
errorDecodersForSCTPChunkType[i] = errorDecoderForSCTPChunkType(i)
SCTPChunkTypeMetadata[i] = EnumMetadata{
DecodeWith: &errorDecodersForSCTPChunkType[i],
Name: "UnknownSCTPChunkType",
}
}
}
// Decoder calls PPPoECodeMetadata.DecodeWith's decoder.
func (a PPPoECode) Decode(data []byte, p gopacket.PacketBuilder) error {
return PPPoECodeMetadata[a].DecodeWith.Decode(data, p)
}
// String returns PPPoECodeMetadata.Name.
func (a PPPoECode) String() string {
return PPPoECodeMetadata[a].Name
}
// LayerType returns PPPoECodeMetadata.LayerType.
func (a PPPoECode) LayerType() gopacket.LayerType {
return PPPoECodeMetadata[a].LayerType
}
type errorDecoderForPPPoECode int
func (a *errorDecoderForPPPoECode) Decode(data []byte, p gopacket.PacketBuilder) error {
return a
}
func (a *errorDecoderForPPPoECode) Error() string {
return fmt.Sprintf("Unable to decode PPPoECode %d", int(*a))
}
var errorDecodersForPPPoECode [256]errorDecoderForPPPoECode
var PPPoECodeMetadata [256]EnumMetadata
func initUnknownTypesForPPPoECode() {
for i := 0; i < 256; i++ {
errorDecodersForPPPoECode[i] = errorDecoderForPPPoECode(i)
PPPoECodeMetadata[i] = EnumMetadata{
DecodeWith: &errorDecodersForPPPoECode[i],
Name: "UnknownPPPoECode",
}
}
}
// Decoder calls FDDIFrameControlMetadata.DecodeWith's decoder.
func (a FDDIFrameControl) Decode(data []byte, p gopacket.PacketBuilder) error {
return FDDIFrameControlMetadata[a].DecodeWith.Decode(data, p)
}
// String returns FDDIFrameControlMetadata.Name.
func (a FDDIFrameControl) String() string {
return FDDIFrameControlMetadata[a].Name
}
// LayerType returns FDDIFrameControlMetadata.LayerType.
func (a FDDIFrameControl) LayerType() gopacket.LayerType {
return FDDIFrameControlMetadata[a].LayerType
}
type errorDecoderForFDDIFrameControl int
func (a *errorDecoderForFDDIFrameControl) Decode(data []byte, p gopacket.PacketBuilder) error {
return a
}
func (a *errorDecoderForFDDIFrameControl) Error() string {
return fmt.Sprintf("Unable to decode FDDIFrameControl %d", int(*a))
}
var errorDecodersForFDDIFrameControl [256]errorDecoderForFDDIFrameControl
var FDDIFrameControlMetadata [256]EnumMetadata
func initUnknownTypesForFDDIFrameControl() {
for i := 0; i < 256; i++ {
errorDecodersForFDDIFrameControl[i] = errorDecoderForFDDIFrameControl(i)
FDDIFrameControlMetadata[i] = EnumMetadata{
DecodeWith: &errorDecodersForFDDIFrameControl[i],
Name: "UnknownFDDIFrameControl",
}
}
}
// Decoder calls EAPOLTypeMetadata.DecodeWith's decoder.
func (a EAPOLType) Decode(data []byte, p gopacket.PacketBuilder) error {
return EAPOLTypeMetadata[a].DecodeWith.Decode(data, p)
}
// String returns EAPOLTypeMetadata.Name.
func (a EAPOLType) String() string {
return EAPOLTypeMetadata[a].Name
}
// LayerType returns EAPOLTypeMetadata.LayerType.
func (a EAPOLType) LayerType() gopacket.LayerType {
return EAPOLTypeMetadata[a].LayerType
}
type errorDecoderForEAPOLType int
func (a *errorDecoderForEAPOLType) Decode(data []byte, p gopacket.PacketBuilder) error {
return a
}
func (a *errorDecoderForEAPOLType) Error() string {
return fmt.Sprintf("Unable to decode EAPOLType %d", int(*a))
}
var errorDecodersForEAPOLType [256]errorDecoderForEAPOLType
var EAPOLTypeMetadata [256]EnumMetadata
func initUnknownTypesForEAPOLType() {
for i := 0; i < 256; i++ {
errorDecodersForEAPOLType[i] = errorDecoderForEAPOLType(i)
EAPOLTypeMetadata[i] = EnumMetadata{
DecodeWith: &errorDecodersForEAPOLType[i],
Name: "UnknownEAPOLType",
}
}
}
// Decoder calls ProtocolFamilyMetadata.DecodeWith's decoder.
func (a ProtocolFamily) Decode(data []byte, p gopacket.PacketBuilder) error {
return ProtocolFamilyMetadata[a].DecodeWith.Decode(data, p)
}
// String returns ProtocolFamilyMetadata.Name.
func (a ProtocolFamily) String() string {
return ProtocolFamilyMetadata[a].Name
}
// LayerType returns ProtocolFamilyMetadata.LayerType.
func (a ProtocolFamily) LayerType() gopacket.LayerType {
return ProtocolFamilyMetadata[a].LayerType
}
type errorDecoderForProtocolFamily int
func (a *errorDecoderForProtocolFamily) Decode(data []byte, p gopacket.PacketBuilder) error {
return a
}
func (a *errorDecoderForProtocolFamily) Error() string {
return fmt.Sprintf("Unable to decode ProtocolFamily %d", int(*a))
}
var errorDecodersForProtocolFamily [256]errorDecoderForProtocolFamily
var ProtocolFamilyMetadata [256]EnumMetadata
func initUnknownTypesForProtocolFamily() {
for i := 0; i < 256; i++ {
errorDecodersForProtocolFamily[i] = errorDecoderForProtocolFamily(i)
ProtocolFamilyMetadata[i] = EnumMetadata{
DecodeWith: &errorDecodersForProtocolFamily[i],
Name: "UnknownProtocolFamily",
}
}
}
// Decoder calls Dot11TypeMetadata.DecodeWith's decoder.
func (a Dot11Type) Decode(data []byte, p gopacket.PacketBuilder) error {
return Dot11TypeMetadata[a].DecodeWith.Decode(data, p)
}
// String returns Dot11TypeMetadata.Name.
func (a Dot11Type) String() string {
return Dot11TypeMetadata[a].Name
}
// LayerType returns Dot11TypeMetadata.LayerType.
func (a Dot11Type) LayerType() gopacket.LayerType {
return Dot11TypeMetadata[a].LayerType
}
type errorDecoderForDot11Type int
func (a *errorDecoderForDot11Type) Decode(data []byte, p gopacket.PacketBuilder) error {
return a
}
func (a *errorDecoderForDot11Type) Error() string {
return fmt.Sprintf("Unable to decode Dot11Type %d", int(*a))
}
var errorDecodersForDot11Type [256]errorDecoderForDot11Type
var Dot11TypeMetadata [256]EnumMetadata
func initUnknownTypesForDot11Type() {
for i := 0; i < 256; i++ {
errorDecodersForDot11Type[i] = errorDecoderForDot11Type(i)
Dot11TypeMetadata[i] = EnumMetadata{
DecodeWith: &errorDecodersForDot11Type[i],
Name: "UnknownDot11Type",
}
}
}
// Decoder calls USBTransportTypeMetadata.DecodeWith's decoder.
func (a USBTransportType) Decode(data []byte, p gopacket.PacketBuilder) error {
return USBTransportTypeMetadata[a].DecodeWith.Decode(data, p)
}
// String returns USBTransportTypeMetadata.Name.
func (a USBTransportType) String() string {
return USBTransportTypeMetadata[a].Name
}
// LayerType returns USBTransportTypeMetadata.LayerType.
func (a USBTransportType) LayerType() gopacket.LayerType {
return USBTransportTypeMetadata[a].LayerType
}
type errorDecoderForUSBTransportType int
func (a *errorDecoderForUSBTransportType) Decode(data []byte, p gopacket.PacketBuilder) error {
return a
}
func (a *errorDecoderForUSBTransportType) Error() string {
return fmt.Sprintf("Unable to decode USBTransportType %d", int(*a))
}
var errorDecodersForUSBTransportType [256]errorDecoderForUSBTransportType
var USBTransportTypeMetadata [256]EnumMetadata
func initUnknownTypesForUSBTransportType() {
for i := 0; i < 256; i++ {
errorDecodersForUSBTransportType[i] = errorDecoderForUSBTransportType(i)
USBTransportTypeMetadata[i] = EnumMetadata{
DecodeWith: &errorDecodersForUSBTransportType[i],
Name: "UnknownUSBTransportType",
}
}
}
// Copyright 2018 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"github.com/google/gopacket"
)
const (
//ERSPANIIVersionObsolete - The obsolete value for the version field
ERSPANIIVersionObsolete = 0x0
// ERSPANIIVersion - The current value for the version field
ERSPANIIVersion = 0x1
)
// ERSPANII contains all of the fields found in an ERSPAN Type II header
// https://tools.ietf.org/html/draft-foschiano-erspan-03
type ERSPANII struct {
BaseLayer
IsTruncated bool
Version, CoS, TrunkEncap uint8
VLANIdentifier, SessionID, Reserved uint16
Index uint32
}
func (erspan2 *ERSPANII) LayerType() gopacket.LayerType { return LayerTypeERSPANII }
// DecodeFromBytes decodes the given bytes into this layer.
func (erspan2 *ERSPANII) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
erspan2Length := 8
erspan2.Version = data[0] & 0xF0 >> 4
erspan2.VLANIdentifier = binary.BigEndian.Uint16(data[:2]) & 0x0FFF
erspan2.CoS = data[2] & 0xE0 >> 5
erspan2.TrunkEncap = data[2] & 0x18 >> 3
erspan2.IsTruncated = data[2]&0x4>>2 != 0
erspan2.SessionID = binary.BigEndian.Uint16(data[2:4]) & 0x03FF
erspan2.Reserved = binary.BigEndian.Uint16(data[4:6]) & 0xFFF0 >> 4
erspan2.Index = binary.BigEndian.Uint32(data[4:8]) & 0x000FFFFF
erspan2.Contents = data[:erspan2Length]
erspan2.Payload = data[erspan2Length:]
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (erspan2 *ERSPANII) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
bytes, err := b.PrependBytes(8)
if err != nil {
return err
}
twoByteInt := uint16(erspan2.Version&0xF)<<12 | erspan2.VLANIdentifier&0x0FFF
binary.BigEndian.PutUint16(bytes, twoByteInt)
twoByteInt = uint16(erspan2.CoS&0x7)<<13 | uint16(erspan2.TrunkEncap&0x3)<<11 | erspan2.SessionID&0x03FF
if erspan2.IsTruncated {
twoByteInt |= 0x400
}
binary.BigEndian.PutUint16(bytes[2:], twoByteInt)
fourByteInt := uint32(erspan2.Reserved&0x0FFF)<<20 | erspan2.Index&0x000FFFFF
binary.BigEndian.PutUint32(bytes[4:], fourByteInt)
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (erspan2 *ERSPANII) CanDecode() gopacket.LayerClass {
return LayerTypeERSPANII
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (erspan2 *ERSPANII) NextLayerType() gopacket.LayerType {
return LayerTypeEthernet
}
func decodeERSPANII(data []byte, p gopacket.PacketBuilder) error {
erspan2 := &ERSPANII{}
return decodingLayerDecoder(erspan2, data, p)
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"github.com/google/gopacket"
)
// EtherIP is the struct for storing RFC 3378 EtherIP packet headers.
type EtherIP struct {
BaseLayer
Version uint8
Reserved uint16
}
// LayerType returns gopacket.LayerTypeEtherIP.
func (e *EtherIP) LayerType() gopacket.LayerType { return LayerTypeEtherIP }
// DecodeFromBytes decodes the given bytes into this layer.
func (e *EtherIP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
e.Version = data[0] >> 4
e.Reserved = binary.BigEndian.Uint16(data[:2]) & 0x0fff
e.BaseLayer = BaseLayer{data[:2], data[2:]}
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (e *EtherIP) CanDecode() gopacket.LayerClass {
return LayerTypeEtherIP
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (e *EtherIP) NextLayerType() gopacket.LayerType {
return LayerTypeEthernet
}
func decodeEtherIP(data []byte, p gopacket.PacketBuilder) error {
e := &EtherIP{}
return decodingLayerDecoder(e, data, p)
}
// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"github.com/google/gopacket"
"net"
)
// EthernetBroadcast is the broadcast MAC address used by Ethernet.
var EthernetBroadcast = net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
// Ethernet is the layer for Ethernet frame headers.
type Ethernet struct {
BaseLayer
SrcMAC, DstMAC net.HardwareAddr
EthernetType EthernetType
// Length is only set if a length field exists within this header. Ethernet
// headers follow two different standards, one that uses an EthernetType, the
// other which defines a length the follows with a LLC header (802.3). If the
// former is the case, we set EthernetType and Length stays 0. In the latter
// case, we set Length and EthernetType = EthernetTypeLLC.
Length uint16
}
// LayerType returns LayerTypeEthernet
func (e *Ethernet) LayerType() gopacket.LayerType { return LayerTypeEthernet }
func (e *Ethernet) LinkFlow() gopacket.Flow {
return gopacket.NewFlow(EndpointMAC, e.SrcMAC, e.DstMAC)
}
func (eth *Ethernet) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 14 {
return errors.New("Ethernet packet too small")
}
eth.DstMAC = net.HardwareAddr(data[0:6])
eth.SrcMAC = net.HardwareAddr(data[6:12])
eth.EthernetType = EthernetType(binary.BigEndian.Uint16(data[12:14]))
eth.BaseLayer = BaseLayer{data[:14], data[14:]}
eth.Length = 0
if eth.EthernetType < 0x0600 {
eth.Length = uint16(eth.EthernetType)
eth.EthernetType = EthernetTypeLLC
if cmp := len(eth.Payload) - int(eth.Length); cmp < 0 {
df.SetTruncated()
} else if cmp > 0 {
// Strip off bytes at the end, since we have too many bytes
eth.Payload = eth.Payload[:len(eth.Payload)-cmp]
}
// fmt.Println(eth)
}
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (eth *Ethernet) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
if len(eth.DstMAC) != 6 {
return fmt.Errorf("invalid dst MAC: %v", eth.DstMAC)
}
if len(eth.SrcMAC) != 6 {
return fmt.Errorf("invalid src MAC: %v", eth.SrcMAC)
}
payload := b.Bytes()
bytes, err := b.PrependBytes(14)
if err != nil {
return err
}
copy(bytes, eth.DstMAC)
copy(bytes[6:], eth.SrcMAC)
if eth.Length != 0 || eth.EthernetType == EthernetTypeLLC {
if opts.FixLengths {
eth.Length = uint16(len(payload))
}
if eth.EthernetType != EthernetTypeLLC {
return fmt.Errorf("ethernet type %v not compatible with length value %v", eth.EthernetType, eth.Length)
} else if eth.Length > 0x0600 {
return fmt.Errorf("invalid ethernet length %v", eth.Length)
}
binary.BigEndian.PutUint16(bytes[12:], eth.Length)
} else {
binary.BigEndian.PutUint16(bytes[12:], uint16(eth.EthernetType))
}
length := len(b.Bytes())
if length < 60 {
// Pad out to 60 bytes.
padding, err := b.AppendBytes(60 - length)
if err != nil {
return err
}
copy(padding, lotsOfZeros[:])
}
return nil
}
func (eth *Ethernet) CanDecode() gopacket.LayerClass {
return LayerTypeEthernet
}
func (eth *Ethernet) NextLayerType() gopacket.LayerType {
return eth.EthernetType.LayerType()
}
func decodeEthernet(data []byte, p gopacket.PacketBuilder) error {
eth := &Ethernet{}
err := eth.DecodeFromBytes(data, p)
if err != nil {
return err
}
p.AddLayer(eth)
p.SetLinkLayer(eth)
return p.NextDecoder(eth.EthernetType)
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"github.com/google/gopacket"
"net"
)
// FDDI contains the header for FDDI frames.
type FDDI struct {
BaseLayer
FrameControl FDDIFrameControl
Priority uint8
SrcMAC, DstMAC net.HardwareAddr
}
// LayerType returns LayerTypeFDDI.
func (f *FDDI) LayerType() gopacket.LayerType { return LayerTypeFDDI }
// LinkFlow returns a new flow of type EndpointMAC.
func (f *FDDI) LinkFlow() gopacket.Flow {
return gopacket.NewFlow(EndpointMAC, f.SrcMAC, f.DstMAC)
}
func decodeFDDI(data []byte, p gopacket.PacketBuilder) error {
f := &FDDI{
FrameControl: FDDIFrameControl(data[0] & 0xF8),
Priority: data[0] & 0x07,
SrcMAC: net.HardwareAddr(data[1:7]),
DstMAC: net.HardwareAddr(data[7:13]),
BaseLayer: BaseLayer{data[:13], data[13:]},
}
p.SetLinkLayer(f)
p.AddLayer(f)
return p.NextDecoder(f.FrameControl)
}
// Copyright 2019 The GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file in the root of the source tree.
package layers
import (
"encoding/binary"
"github.com/google/gopacket"
)
// FuzzLayer is a fuzz target for the layers package of gopacket
// A fuzz target is a function processing a binary blob (byte slice)
// The process here is to interpret this data as a packet, and print the layers contents.
// The decoding options and the starting layer are encoded in the first bytes.
// The function returns 1 if this is a valid packet (no error layer)
func FuzzLayer(data []byte) int {
if len(data) < 3 {
return 0
}
// use the first two bytes to choose the top level layer
startLayer := binary.BigEndian.Uint16(data[:2])
var fuzzOpts = gopacket.DecodeOptions{
Lazy: data[2]&0x1 != 0,
NoCopy: data[2]&0x2 != 0,
SkipDecodeRecovery: data[2]&0x4 != 0,
DecodeStreamsAsDatagrams: data[2]&0x8 != 0,
}
p := gopacket.NewPacket(data[3:], gopacket.LayerType(startLayer), fuzzOpts)
for _, l := range p.Layers() {
gopacket.LayerString(l)
}
if p.ErrorLayer() != nil {
return 0
}
return 1
}
// Copyright 2016 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"github.com/google/gopacket"
)
// Geneve is specifed here https://tools.ietf.org/html/draft-ietf-nvo3-geneve-03
// Geneve Header:
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |Ver| Opt Len |O|C| Rsvd. | Protocol Type |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Virtual Network Identifier (VNI) | Reserved |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Variable Length Options |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type Geneve struct {
BaseLayer
Version uint8 // 2 bits
OptionsLength uint8 // 6 bits
OAMPacket bool // 1 bits
CriticalOption bool // 1 bits
Protocol EthernetType // 16 bits
VNI uint32 // 24bits
Options []*GeneveOption
}
// Geneve Tunnel Options
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Option Class | Type |R|R|R| Length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Variable Option Data |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type GeneveOption struct {
Class uint16 // 16 bits
Type uint8 // 8 bits
Flags uint8 // 3 bits
Length uint8 // 5 bits
Data []byte
}
// LayerType returns LayerTypeGeneve
func (gn *Geneve) LayerType() gopacket.LayerType { return LayerTypeGeneve }
func decodeGeneveOption(data []byte, gn *Geneve, df gopacket.DecodeFeedback) (*GeneveOption, uint8, error) {
if len(data) < 3 {
df.SetTruncated()
return nil, 0, errors.New("geneve option too small")
}
opt := &GeneveOption{}
opt.Class = binary.BigEndian.Uint16(data[0:2])
opt.Type = data[2]
opt.Flags = data[3] >> 4
opt.Length = (data[3]&0xf)*4 + 4
if len(data) < int(opt.Length) {
df.SetTruncated()
return nil, 0, errors.New("geneve option too small")
}
opt.Data = make([]byte, opt.Length-4)
copy(opt.Data, data[4:opt.Length])
return opt, opt.Length, nil
}
func (gn *Geneve) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 7 {
df.SetTruncated()
return errors.New("geneve packet too short")
}
gn.Version = data[0] >> 7
gn.OptionsLength = (data[0] & 0x3f) * 4
gn.OAMPacket = data[1]&0x80 > 0
gn.CriticalOption = data[1]&0x40 > 0
gn.Protocol = EthernetType(binary.BigEndian.Uint16(data[2:4]))
var buf [4]byte
copy(buf[1:], data[4:7])
gn.VNI = binary.BigEndian.Uint32(buf[:])
offset, length := uint8(8), int32(gn.OptionsLength)
if len(data) < int(length+7) {
df.SetTruncated()
return errors.New("geneve packet too short")
}
for length > 0 {
opt, len, err := decodeGeneveOption(data[offset:], gn, df)
if err != nil {
return err
}
gn.Options = append(gn.Options, opt)
length -= int32(len)
offset += len
}
gn.BaseLayer = BaseLayer{data[:offset], data[offset:]}
return nil
}
func (gn *Geneve) NextLayerType() gopacket.LayerType {
return gn.Protocol.LayerType()
}
func decodeGeneve(data []byte, p gopacket.PacketBuilder) error {
gn := &Geneve{}
return decodingLayerDecoder(gn, data, p)
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (gn *Geneve) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
plen := int(gn.OptionsLength + 8)
bytes, err := b.PrependBytes(plen)
if err != nil {
return err
}
// PrependBytes does not guarantee that bytes are zeroed. Setting flags via OR requires that they start off at zero
bytes[0] = 0
bytes[1] = 0
// Construct Geneve
bytes[0] |= gn.Version << 6
bytes[0] |= ((gn.OptionsLength >> 2) & 0x3f)
if gn.OAMPacket {
bytes[1] |= 0x80
}
if gn.CriticalOption {
bytes[1] |= 0x40
}
binary.BigEndian.PutUint16(bytes[2:4], uint16(gn.Protocol))
if gn.VNI >= 1<<24 {
return fmt.Errorf("Virtual Network Identifier = %x exceeds max for 24-bit uint", gn.VNI)
}
binary.BigEndian.PutUint32(bytes[4:8], gn.VNI<<8)
// Construct Options
offset, _ := uint8(8), int32(gn.OptionsLength)
for _, o := range gn.Options {
binary.BigEndian.PutUint16(bytes[offset:(offset+2)], uint16(o.Class))
offset += 2
bytes[offset] = o.Type
offset += 1
bytes[offset] |= o.Flags << 5
bytes[offset] |= ((o.Length - 4) >> 2) & 0x1f
offset += 1
copy(bytes[offset:(offset+o.Length-4)], o.Data)
offset += o.Length - 4
}
return nil
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"github.com/google/gopacket"
)
// GRE is a Generic Routing Encapsulation header.
type GRE struct {
BaseLayer
ChecksumPresent, RoutingPresent, KeyPresent, SeqPresent, StrictSourceRoute, AckPresent bool
RecursionControl, Flags, Version uint8
Protocol EthernetType
Checksum, Offset uint16
Key, Seq, Ack uint32
*GRERouting
}
// GRERouting is GRE routing information, present if the RoutingPresent flag is
// set.
type GRERouting struct {
AddressFamily uint16
SREOffset, SRELength uint8
RoutingInformation []byte
Next *GRERouting
}
// LayerType returns gopacket.LayerTypeGRE.
func (g *GRE) LayerType() gopacket.LayerType { return LayerTypeGRE }
// DecodeFromBytes decodes the given bytes into this layer.
func (g *GRE) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
g.ChecksumPresent = data[0]&0x80 != 0
g.RoutingPresent = data[0]&0x40 != 0
g.KeyPresent = data[0]&0x20 != 0
g.SeqPresent = data[0]&0x10 != 0
g.StrictSourceRoute = data[0]&0x08 != 0
g.AckPresent = data[1]&0x80 != 0
g.RecursionControl = data[0] & 0x7
g.Flags = data[1] >> 3
g.Version = data[1] & 0x7
g.Protocol = EthernetType(binary.BigEndian.Uint16(data[2:4]))
offset := 4
if g.ChecksumPresent || g.RoutingPresent {
g.Checksum = binary.BigEndian.Uint16(data[offset : offset+2])
g.Offset = binary.BigEndian.Uint16(data[offset+2 : offset+4])
offset += 4
}
if g.KeyPresent {
g.Key = binary.BigEndian.Uint32(data[offset : offset+4])
offset += 4
}
if g.SeqPresent {
g.Seq = binary.BigEndian.Uint32(data[offset : offset+4])
offset += 4
}
if g.RoutingPresent {
tail := &g.GRERouting
for {
sre := &GRERouting{
AddressFamily: binary.BigEndian.Uint16(data[offset : offset+2]),
SREOffset: data[offset+2],
SRELength: data[offset+3],
}
sre.RoutingInformation = data[offset+4 : offset+4+int(sre.SRELength)]
offset += 4 + int(sre.SRELength)
if sre.AddressFamily == 0 && sre.SRELength == 0 {
break
}
(*tail) = sre
tail = &sre.Next
}
}
if g.AckPresent {
g.Ack = binary.BigEndian.Uint32(data[offset : offset+4])
offset += 4
}
g.BaseLayer = BaseLayer{data[:offset], data[offset:]}
return nil
}
// SerializeTo writes the serialized form of this layer into the SerializationBuffer,
// implementing gopacket.SerializableLayer. See the docs for gopacket.SerializableLayer for more info.
func (g *GRE) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
size := 4
if g.ChecksumPresent || g.RoutingPresent {
size += 4
}
if g.KeyPresent {
size += 4
}
if g.SeqPresent {
size += 4
}
if g.RoutingPresent {
r := g.GRERouting
for r != nil {
size += 4 + int(r.SRELength)
r = r.Next
}
size += 4
}
if g.AckPresent {
size += 4
}
buf, err := b.PrependBytes(size)
if err != nil {
return err
}
// Reset any potentially dirty memory in the first 2 bytes, as these use OR to set flags.
buf[0] = 0
buf[1] = 0
if g.ChecksumPresent {
buf[0] |= 0x80
}
if g.RoutingPresent {
buf[0] |= 0x40
}
if g.KeyPresent {
buf[0] |= 0x20
}
if g.SeqPresent {
buf[0] |= 0x10
}
if g.StrictSourceRoute {
buf[0] |= 0x08
}
if g.AckPresent {
buf[1] |= 0x80
}
buf[0] |= g.RecursionControl
buf[1] |= g.Flags << 3
buf[1] |= g.Version
binary.BigEndian.PutUint16(buf[2:4], uint16(g.Protocol))
offset := 4
if g.ChecksumPresent || g.RoutingPresent {
// Don't write the checksum value yet, as we may need to compute it,
// which requires the entire header be complete.
// Instead we zeroize the memory in case it is dirty.
buf[offset] = 0
buf[offset+1] = 0
binary.BigEndian.PutUint16(buf[offset+2:offset+4], g.Offset)
offset += 4
}
if g.KeyPresent {
binary.BigEndian.PutUint32(buf[offset:offset+4], g.Key)
offset += 4
}
if g.SeqPresent {
binary.BigEndian.PutUint32(buf[offset:offset+4], g.Seq)
offset += 4
}
if g.RoutingPresent {
sre := g.GRERouting
for sre != nil {
binary.BigEndian.PutUint16(buf[offset:offset+2], sre.AddressFamily)
buf[offset+2] = sre.SREOffset
buf[offset+3] = sre.SRELength
copy(buf[offset+4:offset+4+int(sre.SRELength)], sre.RoutingInformation)
offset += 4 + int(sre.SRELength)
sre = sre.Next
}
// Terminate routing field with a "NULL" SRE.
binary.BigEndian.PutUint32(buf[offset:offset+4], 0)
}
if g.AckPresent {
binary.BigEndian.PutUint32(buf[offset:offset+4], g.Ack)
offset += 4
}
if g.ChecksumPresent {
if opts.ComputeChecksums {
g.Checksum = tcpipChecksum(b.Bytes(), 0)
}
binary.BigEndian.PutUint16(buf[4:6], g.Checksum)
}
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (g *GRE) CanDecode() gopacket.LayerClass {
return LayerTypeGRE
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (g *GRE) NextLayerType() gopacket.LayerType {
return g.Protocol.LayerType()
}
func decodeGRE(data []byte, p gopacket.PacketBuilder) error {
g := &GRE{}
return decodingLayerDecoder(g, data, p)
}
// Copyright 2017 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
//
package layers
import (
"encoding/binary"
"fmt"
"github.com/google/gopacket"
)
const gtpMinimumSizeInBytes int = 8
// GTPExtensionHeader is used to carry extra data and enable future extensions of the GTP without the need to use another version number.
type GTPExtensionHeader struct {
Type uint8
Content []byte
}
// GTPv1U protocol is used to exchange user data over GTP tunnels across the Sx interfaces.
// Defined in https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=1595
type GTPv1U struct {
BaseLayer
Version uint8
ProtocolType uint8
Reserved uint8
ExtensionHeaderFlag bool
SequenceNumberFlag bool
NPDUFlag bool
MessageType uint8
MessageLength uint16
TEID uint32
SequenceNumber uint16
NPDU uint8
GTPExtensionHeaders []GTPExtensionHeader
}
// LayerType returns LayerTypeGTPV1U
func (g *GTPv1U) LayerType() gopacket.LayerType { return LayerTypeGTPv1U }
// DecodeFromBytes analyses a byte slice and attempts to decode it as a GTPv1U packet
func (g *GTPv1U) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
hLen := gtpMinimumSizeInBytes
dLen := len(data)
if dLen < hLen {
return fmt.Errorf("GTP packet too small: %d bytes", dLen)
}
g.Version = (data[0] >> 5) & 0x07
g.ProtocolType = (data[0] >> 4) & 0x01
g.Reserved = (data[0] >> 3) & 0x01
g.SequenceNumberFlag = ((data[0] >> 1) & 0x01) == 1
g.NPDUFlag = (data[0] & 0x01) == 1
g.ExtensionHeaderFlag = ((data[0] >> 2) & 0x01) == 1
g.MessageType = data[1]
g.MessageLength = binary.BigEndian.Uint16(data[2:4])
pLen := 8 + g.MessageLength
if uint16(dLen) < pLen {
return fmt.Errorf("GTP packet too small: %d bytes", dLen)
}
// Field used to multiplex different connections in the same GTP tunnel.
g.TEID = binary.BigEndian.Uint32(data[4:8])
cIndex := uint16(hLen)
if g.SequenceNumberFlag || g.NPDUFlag || g.ExtensionHeaderFlag {
hLen += 4
cIndex += 4
if dLen < hLen {
return fmt.Errorf("GTP packet too small: %d bytes", dLen)
}
if g.SequenceNumberFlag {
g.SequenceNumber = binary.BigEndian.Uint16(data[8:10])
}
if g.NPDUFlag {
g.NPDU = data[10]
}
if g.ExtensionHeaderFlag {
extensionFlag := true
for extensionFlag {
extensionType := uint8(data[cIndex-1])
extensionLength := uint(data[cIndex])
if extensionLength == 0 {
return fmt.Errorf("GTP packet with invalid extension header")
}
// extensionLength is in 4-octet units
lIndex := cIndex + (uint16(extensionLength) * 4)
if uint16(dLen) < lIndex {
return fmt.Errorf("GTP packet with small extension header: %d bytes", dLen)
}
content := data[cIndex+1 : lIndex-1]
eh := GTPExtensionHeader{Type: extensionType, Content: content}
g.GTPExtensionHeaders = append(g.GTPExtensionHeaders, eh)
cIndex = lIndex
// Check if coming bytes are from an extension header
extensionFlag = data[cIndex-1] != 0
}
}
}
g.BaseLayer = BaseLayer{Contents: data[:cIndex], Payload: data[cIndex:]}
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (g *GTPv1U) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
data, err := b.PrependBytes(gtpMinimumSizeInBytes)
if err != nil {
return err
}
data[0] |= (g.Version << 5)
data[0] |= (1 << 4)
if len(g.GTPExtensionHeaders) > 0 {
data[0] |= 0x04
g.ExtensionHeaderFlag = true
}
if g.SequenceNumberFlag {
data[0] |= 0x02
}
if g.NPDUFlag {
data[0] |= 0x01
}
data[1] = g.MessageType
binary.BigEndian.PutUint16(data[2:4], g.MessageLength)
binary.BigEndian.PutUint32(data[4:8], g.TEID)
if g.ExtensionHeaderFlag || g.SequenceNumberFlag || g.NPDUFlag {
data, err := b.AppendBytes(4)
if err != nil {
return err
}
binary.BigEndian.PutUint16(data[:2], g.SequenceNumber)
data[2] = g.NPDU
for _, eh := range g.GTPExtensionHeaders {
data[len(data)-1] = eh.Type
lContent := len(eh.Content)
// extensionLength is in 4-octet units
extensionLength := (lContent + 2) / 4
// Get two extra byte for the next extension header type and length
data, err = b.AppendBytes(lContent + 2)
if err != nil {
return err
}
data[0] = byte(extensionLength)
copy(data[1:lContent+1], eh.Content)
}
}
return nil
}
// CanDecode returns a set of layers that GTP objects can decode.
func (g *GTPv1U) CanDecode() gopacket.LayerClass {
return LayerTypeGTPv1U
}
// NextLayerType specifies the next layer that GoPacket should attempt to
func (g *GTPv1U) NextLayerType() gopacket.LayerType {
if len(g.LayerPayload()) == 0 {
return gopacket.LayerTypeZero
}
version := uint8(g.LayerPayload()[0]) >> 4
if version == 4 {
return LayerTypeIPv4
} else if version == 6 {
return LayerTypeIPv6
} else {
return LayerTypePPP
}
}
func decodeGTPv1u(data []byte, p gopacket.PacketBuilder) error {
gtp := >Pv1U{}
err := gtp.DecodeFromBytes(data, p)
if err != nil {
return err
}
p.AddLayer(gtp)
return p.NextDecoder(gtp.NextLayerType())
}
// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"reflect"
"github.com/google/gopacket"
)
const (
ICMPv4TypeEchoReply = 0
ICMPv4TypeDestinationUnreachable = 3
ICMPv4TypeSourceQuench = 4
ICMPv4TypeRedirect = 5
ICMPv4TypeEchoRequest = 8
ICMPv4TypeRouterAdvertisement = 9
ICMPv4TypeRouterSolicitation = 10
ICMPv4TypeTimeExceeded = 11
ICMPv4TypeParameterProblem = 12
ICMPv4TypeTimestampRequest = 13
ICMPv4TypeTimestampReply = 14
ICMPv4TypeInfoRequest = 15
ICMPv4TypeInfoReply = 16
ICMPv4TypeAddressMaskRequest = 17
ICMPv4TypeAddressMaskReply = 18
)
const (
// DestinationUnreachable
ICMPv4CodeNet = 0
ICMPv4CodeHost = 1
ICMPv4CodeProtocol = 2
ICMPv4CodePort = 3
ICMPv4CodeFragmentationNeeded = 4
ICMPv4CodeSourceRoutingFailed = 5
ICMPv4CodeNetUnknown = 6
ICMPv4CodeHostUnknown = 7
ICMPv4CodeSourceIsolated = 8
ICMPv4CodeNetAdminProhibited = 9
ICMPv4CodeHostAdminProhibited = 10
ICMPv4CodeNetTOS = 11
ICMPv4CodeHostTOS = 12
ICMPv4CodeCommAdminProhibited = 13
ICMPv4CodeHostPrecedence = 14
ICMPv4CodePrecedenceCutoff = 15
// TimeExceeded
ICMPv4CodeTTLExceeded = 0
ICMPv4CodeFragmentReassemblyTimeExceeded = 1
// ParameterProblem
ICMPv4CodePointerIndicatesError = 0
ICMPv4CodeMissingOption = 1
ICMPv4CodeBadLength = 2
// Redirect
// ICMPv4CodeNet = same as for DestinationUnreachable
// ICMPv4CodeHost = same as for DestinationUnreachable
ICMPv4CodeTOSNet = 2
ICMPv4CodeTOSHost = 3
)
type icmpv4TypeCodeInfoStruct struct {
typeStr string
codeStr *map[uint8]string
}
var (
icmpv4TypeCodeInfo = map[uint8]icmpv4TypeCodeInfoStruct{
ICMPv4TypeDestinationUnreachable: icmpv4TypeCodeInfoStruct{
"DestinationUnreachable", &map[uint8]string{
ICMPv4CodeNet: "Net",
ICMPv4CodeHost: "Host",
ICMPv4CodeProtocol: "Protocol",
ICMPv4CodePort: "Port",
ICMPv4CodeFragmentationNeeded: "FragmentationNeeded",
ICMPv4CodeSourceRoutingFailed: "SourceRoutingFailed",
ICMPv4CodeNetUnknown: "NetUnknown",
ICMPv4CodeHostUnknown: "HostUnknown",
ICMPv4CodeSourceIsolated: "SourceIsolated",
ICMPv4CodeNetAdminProhibited: "NetAdminProhibited",
ICMPv4CodeHostAdminProhibited: "HostAdminProhibited",
ICMPv4CodeNetTOS: "NetTOS",
ICMPv4CodeHostTOS: "HostTOS",
ICMPv4CodeCommAdminProhibited: "CommAdminProhibited",
ICMPv4CodeHostPrecedence: "HostPrecedence",
ICMPv4CodePrecedenceCutoff: "PrecedenceCutoff",
},
},
ICMPv4TypeTimeExceeded: icmpv4TypeCodeInfoStruct{
"TimeExceeded", &map[uint8]string{
ICMPv4CodeTTLExceeded: "TTLExceeded",
ICMPv4CodeFragmentReassemblyTimeExceeded: "FragmentReassemblyTimeExceeded",
},
},
ICMPv4TypeParameterProblem: icmpv4TypeCodeInfoStruct{
"ParameterProblem", &map[uint8]string{
ICMPv4CodePointerIndicatesError: "PointerIndicatesError",
ICMPv4CodeMissingOption: "MissingOption",
ICMPv4CodeBadLength: "BadLength",
},
},
ICMPv4TypeSourceQuench: icmpv4TypeCodeInfoStruct{
"SourceQuench", nil,
},
ICMPv4TypeRedirect: icmpv4TypeCodeInfoStruct{
"Redirect", &map[uint8]string{
ICMPv4CodeNet: "Net",
ICMPv4CodeHost: "Host",
ICMPv4CodeTOSNet: "TOS+Net",
ICMPv4CodeTOSHost: "TOS+Host",
},
},
ICMPv4TypeEchoRequest: icmpv4TypeCodeInfoStruct{
"EchoRequest", nil,
},
ICMPv4TypeEchoReply: icmpv4TypeCodeInfoStruct{
"EchoReply", nil,
},
ICMPv4TypeTimestampRequest: icmpv4TypeCodeInfoStruct{
"TimestampRequest", nil,
},
ICMPv4TypeTimestampReply: icmpv4TypeCodeInfoStruct{
"TimestampReply", nil,
},
ICMPv4TypeInfoRequest: icmpv4TypeCodeInfoStruct{
"InfoRequest", nil,
},
ICMPv4TypeInfoReply: icmpv4TypeCodeInfoStruct{
"InfoReply", nil,
},
ICMPv4TypeRouterSolicitation: icmpv4TypeCodeInfoStruct{
"RouterSolicitation", nil,
},
ICMPv4TypeRouterAdvertisement: icmpv4TypeCodeInfoStruct{
"RouterAdvertisement", nil,
},
ICMPv4TypeAddressMaskRequest: icmpv4TypeCodeInfoStruct{
"AddressMaskRequest", nil,
},
ICMPv4TypeAddressMaskReply: icmpv4TypeCodeInfoStruct{
"AddressMaskReply", nil,
},
}
)
type ICMPv4TypeCode uint16
// Type returns the ICMPv4 type field.
func (a ICMPv4TypeCode) Type() uint8 {
return uint8(a >> 8)
}
// Code returns the ICMPv4 code field.
func (a ICMPv4TypeCode) Code() uint8 {
return uint8(a)
}
func (a ICMPv4TypeCode) String() string {
t, c := a.Type(), a.Code()
strInfo, ok := icmpv4TypeCodeInfo[t]
if !ok {
// Unknown ICMPv4 type field
return fmt.Sprintf("%d(%d)", t, c)
}
typeStr := strInfo.typeStr
if strInfo.codeStr == nil && c == 0 {
// The ICMPv4 type does not make use of the code field
return fmt.Sprintf("%s", strInfo.typeStr)
}
if strInfo.codeStr == nil && c != 0 {
// The ICMPv4 type does not make use of the code field, but it is present anyway
return fmt.Sprintf("%s(Code: %d)", typeStr, c)
}
codeStr, ok := (*strInfo.codeStr)[c]
if !ok {
// We don't know this ICMPv4 code; print the numerical value
return fmt.Sprintf("%s(Code: %d)", typeStr, c)
}
return fmt.Sprintf("%s(%s)", typeStr, codeStr)
}
func (a ICMPv4TypeCode) GoString() string {
t := reflect.TypeOf(a)
return fmt.Sprintf("%s(%d, %d)", t.String(), a.Type(), a.Code())
}
// SerializeTo writes the ICMPv4TypeCode value to the 'bytes' buffer.
func (a ICMPv4TypeCode) SerializeTo(bytes []byte) {
binary.BigEndian.PutUint16(bytes, uint16(a))
}
// CreateICMPv4TypeCode is a convenience function to create an ICMPv4TypeCode
// gopacket type from the ICMPv4 type and code values.
func CreateICMPv4TypeCode(typ uint8, code uint8) ICMPv4TypeCode {
return ICMPv4TypeCode(binary.BigEndian.Uint16([]byte{typ, code}))
}
// ICMPv4 is the layer for IPv4 ICMP packet data.
type ICMPv4 struct {
BaseLayer
TypeCode ICMPv4TypeCode
Checksum uint16
Id uint16
Seq uint16
}
// LayerType returns LayerTypeICMPv4.
func (i *ICMPv4) LayerType() gopacket.LayerType { return LayerTypeICMPv4 }
// DecodeFromBytes decodes the given bytes into this layer.
func (i *ICMPv4) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 8 {
df.SetTruncated()
return errors.New("ICMP layer less then 8 bytes for ICMPv4 packet")
}
i.TypeCode = CreateICMPv4TypeCode(data[0], data[1])
i.Checksum = binary.BigEndian.Uint16(data[2:4])
i.Id = binary.BigEndian.Uint16(data[4:6])
i.Seq = binary.BigEndian.Uint16(data[6:8])
i.BaseLayer = BaseLayer{data[:8], data[8:]}
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (i *ICMPv4) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
bytes, err := b.PrependBytes(8)
if err != nil {
return err
}
i.TypeCode.SerializeTo(bytes)
binary.BigEndian.PutUint16(bytes[4:], i.Id)
binary.BigEndian.PutUint16(bytes[6:], i.Seq)
if opts.ComputeChecksums {
bytes[2] = 0
bytes[3] = 0
i.Checksum = tcpipChecksum(b.Bytes(), 0)
}
binary.BigEndian.PutUint16(bytes[2:], i.Checksum)
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (i *ICMPv4) CanDecode() gopacket.LayerClass {
return LayerTypeICMPv4
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (i *ICMPv4) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
func decodeICMPv4(data []byte, p gopacket.PacketBuilder) error {
i := &ICMPv4{}
return decodingLayerDecoder(i, data, p)
}
// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"reflect"
"github.com/google/gopacket"
)
const (
// The following are from RFC 4443
ICMPv6TypeDestinationUnreachable = 1
ICMPv6TypePacketTooBig = 2
ICMPv6TypeTimeExceeded = 3
ICMPv6TypeParameterProblem = 4
ICMPv6TypeEchoRequest = 128
ICMPv6TypeEchoReply = 129
// The following are from RFC 4861
ICMPv6TypeRouterSolicitation = 133
ICMPv6TypeRouterAdvertisement = 134
ICMPv6TypeNeighborSolicitation = 135
ICMPv6TypeNeighborAdvertisement = 136
ICMPv6TypeRedirect = 137
// The following are from RFC 2710
ICMPv6TypeMLDv1MulticastListenerQueryMessage = 130
ICMPv6TypeMLDv1MulticastListenerReportMessage = 131
ICMPv6TypeMLDv1MulticastListenerDoneMessage = 132
// The following are from RFC 3810
ICMPv6TypeMLDv2MulticastListenerReportMessageV2 = 143
)
const (
// DestinationUnreachable
ICMPv6CodeNoRouteToDst = 0
ICMPv6CodeAdminProhibited = 1
ICMPv6CodeBeyondScopeOfSrc = 2
ICMPv6CodeAddressUnreachable = 3
ICMPv6CodePortUnreachable = 4
ICMPv6CodeSrcAddressFailedPolicy = 5
ICMPv6CodeRejectRouteToDst = 6
// TimeExceeded
ICMPv6CodeHopLimitExceeded = 0
ICMPv6CodeFragmentReassemblyTimeExceeded = 1
// ParameterProblem
ICMPv6CodeErroneousHeaderField = 0
ICMPv6CodeUnrecognizedNextHeader = 1
ICMPv6CodeUnrecognizedIPv6Option = 2
)
type icmpv6TypeCodeInfoStruct struct {
typeStr string
codeStr *map[uint8]string
}
var (
icmpv6TypeCodeInfo = map[uint8]icmpv6TypeCodeInfoStruct{
ICMPv6TypeDestinationUnreachable: icmpv6TypeCodeInfoStruct{
"DestinationUnreachable", &map[uint8]string{
ICMPv6CodeNoRouteToDst: "NoRouteToDst",
ICMPv6CodeAdminProhibited: "AdminProhibited",
ICMPv6CodeBeyondScopeOfSrc: "BeyondScopeOfSrc",
ICMPv6CodeAddressUnreachable: "AddressUnreachable",
ICMPv6CodePortUnreachable: "PortUnreachable",
ICMPv6CodeSrcAddressFailedPolicy: "SrcAddressFailedPolicy",
ICMPv6CodeRejectRouteToDst: "RejectRouteToDst",
},
},
ICMPv6TypePacketTooBig: icmpv6TypeCodeInfoStruct{
"PacketTooBig", nil,
},
ICMPv6TypeTimeExceeded: icmpv6TypeCodeInfoStruct{
"TimeExceeded", &map[uint8]string{
ICMPv6CodeHopLimitExceeded: "HopLimitExceeded",
ICMPv6CodeFragmentReassemblyTimeExceeded: "FragmentReassemblyTimeExceeded",
},
},
ICMPv6TypeParameterProblem: icmpv6TypeCodeInfoStruct{
"ParameterProblem", &map[uint8]string{
ICMPv6CodeErroneousHeaderField: "ErroneousHeaderField",
ICMPv6CodeUnrecognizedNextHeader: "UnrecognizedNextHeader",
ICMPv6CodeUnrecognizedIPv6Option: "UnrecognizedIPv6Option",
},
},
ICMPv6TypeEchoRequest: icmpv6TypeCodeInfoStruct{
"EchoRequest", nil,
},
ICMPv6TypeEchoReply: icmpv6TypeCodeInfoStruct{
"EchoReply", nil,
},
ICMPv6TypeRouterSolicitation: icmpv6TypeCodeInfoStruct{
"RouterSolicitation", nil,
},
ICMPv6TypeRouterAdvertisement: icmpv6TypeCodeInfoStruct{
"RouterAdvertisement", nil,
},
ICMPv6TypeNeighborSolicitation: icmpv6TypeCodeInfoStruct{
"NeighborSolicitation", nil,
},
ICMPv6TypeNeighborAdvertisement: icmpv6TypeCodeInfoStruct{
"NeighborAdvertisement", nil,
},
ICMPv6TypeRedirect: icmpv6TypeCodeInfoStruct{
"Redirect", nil,
},
}
)
type ICMPv6TypeCode uint16
// Type returns the ICMPv6 type field.
func (a ICMPv6TypeCode) Type() uint8 {
return uint8(a >> 8)
}
// Code returns the ICMPv6 code field.
func (a ICMPv6TypeCode) Code() uint8 {
return uint8(a)
}
func (a ICMPv6TypeCode) String() string {
t, c := a.Type(), a.Code()
strInfo, ok := icmpv6TypeCodeInfo[t]
if !ok {
// Unknown ICMPv6 type field
return fmt.Sprintf("%d(%d)", t, c)
}
typeStr := strInfo.typeStr
if strInfo.codeStr == nil && c == 0 {
// The ICMPv6 type does not make use of the code field
return fmt.Sprintf("%s", strInfo.typeStr)
}
if strInfo.codeStr == nil && c != 0 {
// The ICMPv6 type does not make use of the code field, but it is present anyway
return fmt.Sprintf("%s(Code: %d)", typeStr, c)
}
codeStr, ok := (*strInfo.codeStr)[c]
if !ok {
// We don't know this ICMPv6 code; print the numerical value
return fmt.Sprintf("%s(Code: %d)", typeStr, c)
}
return fmt.Sprintf("%s(%s)", typeStr, codeStr)
}
func (a ICMPv6TypeCode) GoString() string {
t := reflect.TypeOf(a)
return fmt.Sprintf("%s(%d, %d)", t.String(), a.Type(), a.Code())
}
// SerializeTo writes the ICMPv6TypeCode value to the 'bytes' buffer.
func (a ICMPv6TypeCode) SerializeTo(bytes []byte) {
binary.BigEndian.PutUint16(bytes, uint16(a))
}
// CreateICMPv6TypeCode is a convenience function to create an ICMPv6TypeCode
// gopacket type from the ICMPv6 type and code values.
func CreateICMPv6TypeCode(typ uint8, code uint8) ICMPv6TypeCode {
return ICMPv6TypeCode(binary.BigEndian.Uint16([]byte{typ, code}))
}
// ICMPv6 is the layer for IPv6 ICMP packet data
type ICMPv6 struct {
BaseLayer
TypeCode ICMPv6TypeCode
Checksum uint16
// TypeBytes is deprecated and always nil. See the different ICMPv6 message types
// instead (e.g. ICMPv6TypeRouterSolicitation).
TypeBytes []byte
tcpipchecksum
}
// LayerType returns LayerTypeICMPv6.
func (i *ICMPv6) LayerType() gopacket.LayerType { return LayerTypeICMPv6 }
// DecodeFromBytes decodes the given bytes into this layer.
func (i *ICMPv6) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 4 {
df.SetTruncated()
return errors.New("ICMP layer less then 4 bytes for ICMPv6 packet")
}
i.TypeCode = CreateICMPv6TypeCode(data[0], data[1])
i.Checksum = binary.BigEndian.Uint16(data[2:4])
i.BaseLayer = BaseLayer{data[:4], data[4:]}
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (i *ICMPv6) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
bytes, err := b.PrependBytes(4)
if err != nil {
return err
}
i.TypeCode.SerializeTo(bytes)
if opts.ComputeChecksums {
bytes[2] = 0
bytes[3] = 0
csum, err := i.computeChecksum(b.Bytes(), IPProtocolICMPv6)
if err != nil {
return err
}
i.Checksum = csum
}
binary.BigEndian.PutUint16(bytes[2:], i.Checksum)
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (i *ICMPv6) CanDecode() gopacket.LayerClass {
return LayerTypeICMPv6
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (i *ICMPv6) NextLayerType() gopacket.LayerType {
switch i.TypeCode.Type() {
case ICMPv6TypeEchoRequest:
return LayerTypeICMPv6Echo
case ICMPv6TypeEchoReply:
return LayerTypeICMPv6Echo
case ICMPv6TypeRouterSolicitation:
return LayerTypeICMPv6RouterSolicitation
case ICMPv6TypeRouterAdvertisement:
return LayerTypeICMPv6RouterAdvertisement
case ICMPv6TypeNeighborSolicitation:
return LayerTypeICMPv6NeighborSolicitation
case ICMPv6TypeNeighborAdvertisement:
return LayerTypeICMPv6NeighborAdvertisement
case ICMPv6TypeRedirect:
return LayerTypeICMPv6Redirect
case ICMPv6TypeMLDv1MulticastListenerQueryMessage: // Same Code for MLDv1 Query and MLDv2 Query
if len(i.Payload) > 20 { // Only payload size differs
return LayerTypeMLDv2MulticastListenerQuery
} else {
return LayerTypeMLDv1MulticastListenerQuery
}
case ICMPv6TypeMLDv1MulticastListenerDoneMessage:
return LayerTypeMLDv1MulticastListenerDone
case ICMPv6TypeMLDv1MulticastListenerReportMessage:
return LayerTypeMLDv1MulticastListenerReport
case ICMPv6TypeMLDv2MulticastListenerReportMessageV2:
return LayerTypeMLDv2MulticastListenerReport
}
return gopacket.LayerTypePayload
}
func decodeICMPv6(data []byte, p gopacket.PacketBuilder) error {
i := &ICMPv6{}
return decodingLayerDecoder(i, data, p)
}
// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
"net"
"time"
"github.com/google/gopacket"
)
// Based on RFC 4861
// ICMPv6Opt indicate how to decode the data associated with each ICMPv6Option.
type ICMPv6Opt uint8
const (
_ ICMPv6Opt = iota
// ICMPv6OptSourceAddress contains the link-layer address of the sender of
// the packet. It is used in the Neighbor Solicitation, Router
// Solicitation, and Router Advertisement packets. Must be ignored for other
// Neighbor discovery messages.
ICMPv6OptSourceAddress
// ICMPv6OptTargetAddress contains the link-layer address of the target. It
// is used in Neighbor Advertisement and Redirect packets. Must be ignored
// for other Neighbor discovery messages.
ICMPv6OptTargetAddress
// ICMPv6OptPrefixInfo provides hosts with on-link prefixes and prefixes
// for Address Autoconfiguration. The Prefix Information option appears in
// Router Advertisement packets and MUST be silently ignored for other
// messages.
ICMPv6OptPrefixInfo
// ICMPv6OptRedirectedHeader is used in Redirect messages and contains all
// or part of the packet that is being redirected.
ICMPv6OptRedirectedHeader
// ICMPv6OptMTU is used in Router Advertisement messages to ensure that all
// nodes on a link use the same MTU value in those cases where the link MTU
// is not well known. This option MUST be silently ignored for other
// Neighbor Discovery messages.
ICMPv6OptMTU
)
// ICMPv6Echo represents the structure of a ping.
type ICMPv6Echo struct {
BaseLayer
Identifier uint16
SeqNumber uint16
}
// ICMPv6RouterSolicitation is sent by hosts to find routers.
type ICMPv6RouterSolicitation struct {
BaseLayer
Options ICMPv6Options
}
// ICMPv6RouterAdvertisement is sent by routers in response to Solicitation.
type ICMPv6RouterAdvertisement struct {
BaseLayer
HopLimit uint8
Flags uint8
RouterLifetime uint16
ReachableTime uint32
RetransTimer uint32
Options ICMPv6Options
}
// ICMPv6NeighborSolicitation is sent to request the link-layer address of a
// target node.
type ICMPv6NeighborSolicitation struct {
BaseLayer
TargetAddress net.IP
Options ICMPv6Options
}
// ICMPv6NeighborAdvertisement is sent by nodes in response to Solicitation.
type ICMPv6NeighborAdvertisement struct {
BaseLayer
Flags uint8
TargetAddress net.IP
Options ICMPv6Options
}
// ICMPv6Redirect is sent by routers to inform hosts of a better first-hop node
// on the path to a destination.
type ICMPv6Redirect struct {
BaseLayer
TargetAddress net.IP
DestinationAddress net.IP
Options ICMPv6Options
}
// ICMPv6Option contains the type and data for a single option.
type ICMPv6Option struct {
Type ICMPv6Opt
Data []byte
}
// ICMPv6Options is a slice of ICMPv6Option.
type ICMPv6Options []ICMPv6Option
func (i ICMPv6Opt) String() string {
switch i {
case ICMPv6OptSourceAddress:
return "SourceAddress"
case ICMPv6OptTargetAddress:
return "TargetAddress"
case ICMPv6OptPrefixInfo:
return "PrefixInfo"
case ICMPv6OptRedirectedHeader:
return "RedirectedHeader"
case ICMPv6OptMTU:
return "MTU"
default:
return fmt.Sprintf("Unknown(%d)", i)
}
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (i *ICMPv6Echo) CanDecode() gopacket.LayerClass {
return LayerTypeICMPv6Echo
}
// LayerType returns LayerTypeICMPv6Echo.
func (i *ICMPv6Echo) LayerType() gopacket.LayerType {
return LayerTypeICMPv6Echo
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (i *ICMPv6Echo) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
// DecodeFromBytes decodes the given bytes into this layer.
func (i *ICMPv6Echo) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 4 {
df.SetTruncated()
return errors.New("ICMP layer less then 4 bytes for ICMPv6 Echo")
}
i.Identifier = binary.BigEndian.Uint16(data[0:2])
i.SeqNumber = binary.BigEndian.Uint16(data[2:4])
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (i *ICMPv6Echo) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
buf, err := b.PrependBytes(4)
if err != nil {
return err
}
binary.BigEndian.PutUint16(buf, i.Identifier)
binary.BigEndian.PutUint16(buf[2:], i.SeqNumber)
return nil
}
// LayerType returns LayerTypeICMPv6.
func (i *ICMPv6RouterSolicitation) LayerType() gopacket.LayerType {
return LayerTypeICMPv6RouterSolicitation
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (i *ICMPv6RouterSolicitation) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
// DecodeFromBytes decodes the given bytes into this layer.
func (i *ICMPv6RouterSolicitation) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
// first 4 bytes are reserved followed by options
if len(data) < 4 {
df.SetTruncated()
return errors.New("ICMP layer less then 4 bytes for ICMPv6 router solicitation")
}
// truncate old options
i.Options = i.Options[:0]
return i.Options.DecodeFromBytes(data[4:], df)
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (i *ICMPv6RouterSolicitation) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
if err := i.Options.SerializeTo(b, opts); err != nil {
return err
}
buf, err := b.PrependBytes(4)
if err != nil {
return err
}
copy(buf, lotsOfZeros[:4])
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (i *ICMPv6RouterSolicitation) CanDecode() gopacket.LayerClass {
return LayerTypeICMPv6RouterSolicitation
}
// LayerType returns LayerTypeICMPv6RouterAdvertisement.
func (i *ICMPv6RouterAdvertisement) LayerType() gopacket.LayerType {
return LayerTypeICMPv6RouterAdvertisement
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (i *ICMPv6RouterAdvertisement) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
// DecodeFromBytes decodes the given bytes into this layer.
func (i *ICMPv6RouterAdvertisement) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 12 {
df.SetTruncated()
return errors.New("ICMP layer less then 12 bytes for ICMPv6 router advertisement")
}
i.HopLimit = uint8(data[0])
// M, O bit followed by 6 reserved bits
i.Flags = uint8(data[1])
i.RouterLifetime = binary.BigEndian.Uint16(data[2:4])
i.ReachableTime = binary.BigEndian.Uint32(data[4:8])
i.RetransTimer = binary.BigEndian.Uint32(data[8:12])
i.BaseLayer = BaseLayer{data, nil} // assume no payload
// truncate old options
i.Options = i.Options[:0]
return i.Options.DecodeFromBytes(data[12:], df)
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (i *ICMPv6RouterAdvertisement) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
if err := i.Options.SerializeTo(b, opts); err != nil {
return err
}
buf, err := b.PrependBytes(12)
if err != nil {
return err
}
buf[0] = byte(i.HopLimit)
buf[1] = byte(i.Flags)
binary.BigEndian.PutUint16(buf[2:], i.RouterLifetime)
binary.BigEndian.PutUint32(buf[4:], i.ReachableTime)
binary.BigEndian.PutUint32(buf[8:], i.RetransTimer)
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (i *ICMPv6RouterAdvertisement) CanDecode() gopacket.LayerClass {
return LayerTypeICMPv6RouterAdvertisement
}
// ManagedAddressConfig is true when addresses are available via DHCPv6. If
// set, the OtherConfig flag is redundant.
func (i *ICMPv6RouterAdvertisement) ManagedAddressConfig() bool {
return i.Flags&0x80 != 0
}
// OtherConfig is true when there is other configuration information available
// via DHCPv6. For example, DNS-related information.
func (i *ICMPv6RouterAdvertisement) OtherConfig() bool {
return i.Flags&0x40 != 0
}
// LayerType returns LayerTypeICMPv6NeighborSolicitation.
func (i *ICMPv6NeighborSolicitation) LayerType() gopacket.LayerType {
return LayerTypeICMPv6NeighborSolicitation
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (i *ICMPv6NeighborSolicitation) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
// DecodeFromBytes decodes the given bytes into this layer.
func (i *ICMPv6NeighborSolicitation) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 20 {
df.SetTruncated()
return errors.New("ICMP layer less then 20 bytes for ICMPv6 neighbor solicitation")
}
i.TargetAddress = net.IP(data[4:20])
i.BaseLayer = BaseLayer{data, nil} // assume no payload
// truncate old options
i.Options = i.Options[:0]
return i.Options.DecodeFromBytes(data[20:], df)
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (i *ICMPv6NeighborSolicitation) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
if err := i.Options.SerializeTo(b, opts); err != nil {
return err
}
buf, err := b.PrependBytes(20)
if err != nil {
return err
}
copy(buf, lotsOfZeros[:4])
copy(buf[4:], i.TargetAddress)
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (i *ICMPv6NeighborSolicitation) CanDecode() gopacket.LayerClass {
return LayerTypeICMPv6NeighborSolicitation
}
// LayerType returns LayerTypeICMPv6NeighborAdvertisement.
func (i *ICMPv6NeighborAdvertisement) LayerType() gopacket.LayerType {
return LayerTypeICMPv6NeighborAdvertisement
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (i *ICMPv6NeighborAdvertisement) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
// DecodeFromBytes decodes the given bytes into this layer.
func (i *ICMPv6NeighborAdvertisement) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 20 {
df.SetTruncated()
return errors.New("ICMP layer less then 20 bytes for ICMPv6 neighbor advertisement")
}
i.Flags = uint8(data[0])
i.TargetAddress = net.IP(data[4:20])
i.BaseLayer = BaseLayer{data, nil} // assume no payload
// truncate old options
i.Options = i.Options[:0]
return i.Options.DecodeFromBytes(data[20:], df)
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (i *ICMPv6NeighborAdvertisement) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
if err := i.Options.SerializeTo(b, opts); err != nil {
return err
}
buf, err := b.PrependBytes(20)
if err != nil {
return err
}
buf[0] = byte(i.Flags)
copy(buf[1:], lotsOfZeros[:3])
copy(buf[4:], i.TargetAddress)
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (i *ICMPv6NeighborAdvertisement) CanDecode() gopacket.LayerClass {
return LayerTypeICMPv6NeighborAdvertisement
}
// Router indicates whether the sender is a router or not.
func (i *ICMPv6NeighborAdvertisement) Router() bool {
return i.Flags&0x80 != 0
}
// Solicited indicates whether the advertisement was solicited or not.
func (i *ICMPv6NeighborAdvertisement) Solicited() bool {
return i.Flags&0x40 != 0
}
// Override indicates whether the advertisement should Override an existing
// cache entry.
func (i *ICMPv6NeighborAdvertisement) Override() bool {
return i.Flags&0x20 != 0
}
// LayerType returns LayerTypeICMPv6Redirect.
func (i *ICMPv6Redirect) LayerType() gopacket.LayerType {
return LayerTypeICMPv6Redirect
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (i *ICMPv6Redirect) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
// DecodeFromBytes decodes the given bytes into this layer.
func (i *ICMPv6Redirect) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 36 {
df.SetTruncated()
return errors.New("ICMP layer less then 36 bytes for ICMPv6 redirect")
}
i.TargetAddress = net.IP(data[4:20])
i.DestinationAddress = net.IP(data[20:36])
i.BaseLayer = BaseLayer{data, nil} // assume no payload
// truncate old options
i.Options = i.Options[:0]
return i.Options.DecodeFromBytes(data[36:], df)
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (i *ICMPv6Redirect) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
if err := i.Options.SerializeTo(b, opts); err != nil {
return err
}
buf, err := b.PrependBytes(36)
if err != nil {
return err
}
copy(buf, lotsOfZeros[:4])
copy(buf[4:], i.TargetAddress)
copy(buf[20:], i.DestinationAddress)
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (i *ICMPv6Redirect) CanDecode() gopacket.LayerClass {
return LayerTypeICMPv6Redirect
}
func (i ICMPv6Option) String() string {
hd := hex.EncodeToString(i.Data)
if len(hd) > 0 {
hd = " 0x" + hd
}
switch i.Type {
case ICMPv6OptSourceAddress, ICMPv6OptTargetAddress:
return fmt.Sprintf("ICMPv6Option(%s:%v)",
i.Type,
net.HardwareAddr(i.Data))
case ICMPv6OptPrefixInfo:
if len(i.Data) == 30 {
prefixLen := uint8(i.Data[0])
onLink := (i.Data[1]&0x80 != 0)
autonomous := (i.Data[1]&0x40 != 0)
validLifetime := time.Duration(binary.BigEndian.Uint32(i.Data[2:6])) * time.Second
preferredLifetime := time.Duration(binary.BigEndian.Uint32(i.Data[6:10])) * time.Second
prefix := net.IP(i.Data[14:])
return fmt.Sprintf("ICMPv6Option(%s:%v/%v:%t:%t:%v:%v)",
i.Type,
prefix, prefixLen,
onLink, autonomous,
validLifetime, preferredLifetime)
}
case ICMPv6OptRedirectedHeader:
// could invoke IP decoder on data... probably best not to
break
case ICMPv6OptMTU:
if len(i.Data) == 6 {
return fmt.Sprintf("ICMPv6Option(%s:%v)",
i.Type,
binary.BigEndian.Uint32(i.Data[2:]))
}
}
return fmt.Sprintf("ICMPv6Option(%s:%s)", i.Type, hd)
}
// DecodeFromBytes decodes the given bytes into this layer.
func (i *ICMPv6Options) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
for len(data) > 0 {
if len(data) < 2 {
df.SetTruncated()
return errors.New("ICMP layer less then 2 bytes for ICMPv6 message option")
}
// unit is 8 octets, convert to bytes
length := int(data[1]) * 8
if length == 0 {
df.SetTruncated()
return errors.New("ICMPv6 message option with length 0")
}
if len(data) < length {
df.SetTruncated()
return fmt.Errorf("ICMP layer only %v bytes for ICMPv6 message option with length %v", len(data), length)
}
o := ICMPv6Option{
Type: ICMPv6Opt(data[0]),
Data: data[2:length],
}
// chop off option we just consumed
data = data[length:]
*i = append(*i, o)
}
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (i *ICMPv6Options) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
for _, opt := range []ICMPv6Option(*i) {
length := len(opt.Data) + 2
buf, err := b.PrependBytes(length)
if err != nil {
return err
}
buf[0] = byte(opt.Type)
buf[1] = byte(length / 8)
copy(buf[2:], opt.Data)
}
return nil
}
func decodeICMPv6Echo(data []byte, p gopacket.PacketBuilder) error {
i := &ICMPv6Echo{}
return decodingLayerDecoder(i, data, p)
}
func decodeICMPv6RouterSolicitation(data []byte, p gopacket.PacketBuilder) error {
i := &ICMPv6RouterSolicitation{}
return decodingLayerDecoder(i, data, p)
}
func decodeICMPv6RouterAdvertisement(data []byte, p gopacket.PacketBuilder) error {
i := &ICMPv6RouterAdvertisement{}
return decodingLayerDecoder(i, data, p)
}
func decodeICMPv6NeighborSolicitation(data []byte, p gopacket.PacketBuilder) error {
i := &ICMPv6NeighborSolicitation{}
return decodingLayerDecoder(i, data, p)
}
func decodeICMPv6NeighborAdvertisement(data []byte, p gopacket.PacketBuilder) error {
i := &ICMPv6NeighborAdvertisement{}
return decodingLayerDecoder(i, data, p)
}
func decodeICMPv6Redirect(data []byte, p gopacket.PacketBuilder) error {
i := &ICMPv6Redirect{}
return decodingLayerDecoder(i, data, p)
}
// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"net"
"time"
"github.com/google/gopacket"
)
type IGMPType uint8
const (
IGMPMembershipQuery IGMPType = 0x11 // General or group specific query
IGMPMembershipReportV1 IGMPType = 0x12 // Version 1 Membership Report
IGMPMembershipReportV2 IGMPType = 0x16 // Version 2 Membership Report
IGMPLeaveGroup IGMPType = 0x17 // Leave Group
IGMPMembershipReportV3 IGMPType = 0x22 // Version 3 Membership Report
)
// String conversions for IGMP message types
func (i IGMPType) String() string {
switch i {
case IGMPMembershipQuery:
return "IGMP Membership Query"
case IGMPMembershipReportV1:
return "IGMPv1 Membership Report"
case IGMPMembershipReportV2:
return "IGMPv2 Membership Report"
case IGMPMembershipReportV3:
return "IGMPv3 Membership Report"
case IGMPLeaveGroup:
return "Leave Group"
default:
return ""
}
}
type IGMPv3GroupRecordType uint8
const (
IGMPIsIn IGMPv3GroupRecordType = 0x01 // Type MODE_IS_INCLUDE, source addresses x
IGMPIsEx IGMPv3GroupRecordType = 0x02 // Type MODE_IS_EXCLUDE, source addresses x
IGMPToIn IGMPv3GroupRecordType = 0x03 // Type CHANGE_TO_INCLUDE_MODE, source addresses x
IGMPToEx IGMPv3GroupRecordType = 0x04 // Type CHANGE_TO_EXCLUDE_MODE, source addresses x
IGMPAllow IGMPv3GroupRecordType = 0x05 // Type ALLOW_NEW_SOURCES, source addresses x
IGMPBlock IGMPv3GroupRecordType = 0x06 // Type BLOCK_OLD_SOURCES, source addresses x
)
func (i IGMPv3GroupRecordType) String() string {
switch i {
case IGMPIsIn:
return "MODE_IS_INCLUDE"
case IGMPIsEx:
return "MODE_IS_EXCLUDE"
case IGMPToIn:
return "CHANGE_TO_INCLUDE_MODE"
case IGMPToEx:
return "CHANGE_TO_EXCLUDE_MODE"
case IGMPAllow:
return "ALLOW_NEW_SOURCES"
case IGMPBlock:
return "BLOCK_OLD_SOURCES"
default:
return ""
}
}
// IGMP represents an IGMPv3 message.
type IGMP struct {
BaseLayer
Type IGMPType
MaxResponseTime time.Duration
Checksum uint16
GroupAddress net.IP
SupressRouterProcessing bool
RobustnessValue uint8
IntervalTime time.Duration
SourceAddresses []net.IP
NumberOfGroupRecords uint16
NumberOfSources uint16
GroupRecords []IGMPv3GroupRecord
Version uint8 // IGMP protocol version
}
// IGMPv1or2 stores header details for an IGMPv1 or IGMPv2 packet.
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type | Max Resp Time | Checksum |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Group Address |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type IGMPv1or2 struct {
BaseLayer
Type IGMPType // IGMP message type
MaxResponseTime time.Duration // meaningful only in Membership Query messages
Checksum uint16 // 16-bit checksum of entire ip payload
GroupAddress net.IP // either 0 or an IP multicast address
Version uint8
}
// decodeResponse dissects IGMPv1 or IGMPv2 packet.
func (i *IGMPv1or2) decodeResponse(data []byte) error {
if len(data) < 8 {
return errors.New("IGMP packet too small")
}
i.MaxResponseTime = igmpTimeDecode(data[1])
i.Checksum = binary.BigEndian.Uint16(data[2:4])
i.GroupAddress = net.IP(data[4:8])
return nil
}
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type = 0x22 | Reserved | Checksum |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Reserved | Number of Group Records (M) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . Group Record [1] .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . Group Record [2] .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . Group Record [M] .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Record Type | Aux Data Len | Number of Sources (N) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Multicast Address |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Source Address [1] |
// +- -+
// | Source Address [2] |
// +- -+
// | Source Address [N] |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . Auxiliary Data .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// IGMPv3GroupRecord stores individual group records for a V3 Membership Report message.
type IGMPv3GroupRecord struct {
Type IGMPv3GroupRecordType
AuxDataLen uint8 // this should always be 0 as per IGMPv3 spec.
NumberOfSources uint16
MulticastAddress net.IP
SourceAddresses []net.IP
AuxData uint32 // NOT USED
}
func (i *IGMP) decodeIGMPv3MembershipReport(data []byte) error {
if len(data) < 8 {
return errors.New("IGMPv3 Membership Report too small #1")
}
i.Checksum = binary.BigEndian.Uint16(data[2:4])
i.NumberOfGroupRecords = binary.BigEndian.Uint16(data[6:8])
recordOffset := 8
for j := 0; j < int(i.NumberOfGroupRecords); j++ {
if len(data) < recordOffset+8 {
return errors.New("IGMPv3 Membership Report too small #2")
}
var gr IGMPv3GroupRecord
gr.Type = IGMPv3GroupRecordType(data[recordOffset])
gr.AuxDataLen = data[recordOffset+1]
gr.NumberOfSources = binary.BigEndian.Uint16(data[recordOffset+2 : recordOffset+4])
gr.MulticastAddress = net.IP(data[recordOffset+4 : recordOffset+8])
if len(data) < recordOffset+8+int(gr.NumberOfSources)*4 {
return errors.New("IGMPv3 Membership Report too small #3")
}
// append source address records.
for i := 0; i < int(gr.NumberOfSources); i++ {
sourceAddr := net.IP(data[recordOffset+8+i*4 : recordOffset+12+i*4])
gr.SourceAddresses = append(gr.SourceAddresses, sourceAddr)
}
i.GroupRecords = append(i.GroupRecords, gr)
recordOffset += 8 + 4*int(gr.NumberOfSources)
}
return nil
}
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type = 0x11 | Max Resp Code | Checksum |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Group Address |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Resv |S| QRV | QQIC | Number of Sources (N) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Source Address [1] |
// +- -+
// | Source Address [2] |
// +- . -+
// | Source Address [N] |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// decodeIGMPv3MembershipQuery parses the IGMPv3 message of type 0x11
func (i *IGMP) decodeIGMPv3MembershipQuery(data []byte) error {
if len(data) < 12 {
return errors.New("IGMPv3 Membership Query too small #1")
}
i.MaxResponseTime = igmpTimeDecode(data[1])
i.Checksum = binary.BigEndian.Uint16(data[2:4])
i.SupressRouterProcessing = data[8]&0x8 != 0
i.GroupAddress = net.IP(data[4:8])
i.RobustnessValue = data[8] & 0x7
i.IntervalTime = igmpTimeDecode(data[9])
i.NumberOfSources = binary.BigEndian.Uint16(data[10:12])
if len(data) < 12+int(i.NumberOfSources)*4 {
return errors.New("IGMPv3 Membership Query too small #2")
}
for j := 0; j < int(i.NumberOfSources); j++ {
i.SourceAddresses = append(i.SourceAddresses, net.IP(data[12+j*4:16+j*4]))
}
return nil
}
// igmpTimeDecode decodes the duration created by the given byte, using the
// algorithm in http://www.rfc-base.org/txt/rfc-3376.txt section 4.1.1.
func igmpTimeDecode(t uint8) time.Duration {
if t&0x80 == 0 {
return time.Millisecond * 100 * time.Duration(t)
}
mant := (t & 0x70) >> 4
exp := t & 0x0F
return time.Millisecond * 100 * time.Duration((mant|0x10)<<(exp+3))
}
// LayerType returns LayerTypeIGMP for the V1,2,3 message protocol formats.
func (i *IGMP) LayerType() gopacket.LayerType { return LayerTypeIGMP }
func (i *IGMPv1or2) LayerType() gopacket.LayerType { return LayerTypeIGMP }
func (i *IGMPv1or2) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 8 {
return errors.New("IGMP Packet too small")
}
i.Type = IGMPType(data[0])
i.MaxResponseTime = igmpTimeDecode(data[1])
i.Checksum = binary.BigEndian.Uint16(data[2:4])
i.GroupAddress = net.IP(data[4:8])
return nil
}
func (i *IGMPv1or2) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypeZero
}
func (i *IGMPv1or2) CanDecode() gopacket.LayerClass {
return LayerTypeIGMP
}
// DecodeFromBytes decodes the given bytes into this layer.
func (i *IGMP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 1 {
return errors.New("IGMP packet is too small")
}
// common IGMP header values between versions 1..3 of IGMP specification..
i.Type = IGMPType(data[0])
switch i.Type {
case IGMPMembershipQuery:
i.decodeIGMPv3MembershipQuery(data)
case IGMPMembershipReportV3:
i.decodeIGMPv3MembershipReport(data)
default:
return errors.New("unsupported IGMP type")
}
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (i *IGMP) CanDecode() gopacket.LayerClass {
return LayerTypeIGMP
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (i *IGMP) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypeZero
}
// decodeIGMP will parse IGMP v1,2 or 3 protocols. Checks against the
// IGMP type are performed against byte[0], logic then iniitalizes and
// passes the appropriate struct (IGMP or IGMPv1or2) to
// decodingLayerDecoder.
func decodeIGMP(data []byte, p gopacket.PacketBuilder) error {
if len(data) < 1 {
return errors.New("IGMP packet is too small")
}
// byte 0 contains IGMP message type.
switch IGMPType(data[0]) {
case IGMPMembershipQuery:
// IGMPv3 Membership Query payload is >= 12
if len(data) >= 12 {
i := &IGMP{Version: 3}
return decodingLayerDecoder(i, data, p)
} else if len(data) == 8 {
i := &IGMPv1or2{}
if data[1] == 0x00 {
i.Version = 1 // IGMPv1 has a query length of 8 and MaxResp = 0
} else {
i.Version = 2 // IGMPv2 has a query length of 8 and MaxResp != 0
}
return decodingLayerDecoder(i, data, p)
}
case IGMPMembershipReportV3:
i := &IGMP{Version: 3}
return decodingLayerDecoder(i, data, p)
case IGMPMembershipReportV1:
i := &IGMPv1or2{Version: 1}
return decodingLayerDecoder(i, data, p)
case IGMPLeaveGroup, IGMPMembershipReportV2:
// leave group and Query Report v2 used in IGMPv2 only.
i := &IGMPv1or2{Version: 2}
return decodingLayerDecoder(i, data, p)
default:
}
return errors.New("Unable to determine IGMP type.")
}
// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"net"
"strings"
"github.com/google/gopacket"
)
type IPv4Flag uint8
const (
IPv4EvilBit IPv4Flag = 1 << 2 // http://tools.ietf.org/html/rfc3514 ;)
IPv4DontFragment IPv4Flag = 1 << 1
IPv4MoreFragments IPv4Flag = 1 << 0
)
func (f IPv4Flag) String() string {
var s []string
if f&IPv4EvilBit != 0 {
s = append(s, "Evil")
}
if f&IPv4DontFragment != 0 {
s = append(s, "DF")
}
if f&IPv4MoreFragments != 0 {
s = append(s, "MF")
}
return strings.Join(s, "|")
}
// IPv4 is the header of an IP packet.
type IPv4 struct {
BaseLayer
Version uint8
IHL uint8
TOS uint8
Length uint16
Id uint16
Flags IPv4Flag
FragOffset uint16
TTL uint8
Protocol IPProtocol
Checksum uint16
SrcIP net.IP
DstIP net.IP
Options []IPv4Option
Padding []byte
}
// LayerType returns LayerTypeIPv4
func (i *IPv4) LayerType() gopacket.LayerType { return LayerTypeIPv4 }
func (i *IPv4) NetworkFlow() gopacket.Flow {
return gopacket.NewFlow(EndpointIPv4, i.SrcIP, i.DstIP)
}
type IPv4Option struct {
OptionType uint8
OptionLength uint8
OptionData []byte
}
func (i IPv4Option) String() string {
return fmt.Sprintf("IPv4Option(%v:%v)", i.OptionType, i.OptionData)
}
// for the current ipv4 options, return the number of bytes (including
// padding that the options used)
func (ip *IPv4) getIPv4OptionSize() uint8 {
optionSize := uint8(0)
for _, opt := range ip.Options {
switch opt.OptionType {
case 0:
// this is the end of option lists
optionSize++
case 1:
// this is the padding
optionSize++
default:
optionSize += opt.OptionLength
}
}
// make sure the options are aligned to 32 bit boundary
if (optionSize % 4) != 0 {
optionSize += 4 - (optionSize % 4)
}
return optionSize
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
func (ip *IPv4) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
optionLength := ip.getIPv4OptionSize()
bytes, err := b.PrependBytes(20 + int(optionLength))
if err != nil {
return err
}
if opts.FixLengths {
ip.IHL = 5 + (optionLength / 4)
ip.Length = uint16(len(b.Bytes()))
}
bytes[0] = (ip.Version << 4) | ip.IHL
bytes[1] = ip.TOS
binary.BigEndian.PutUint16(bytes[2:], ip.Length)
binary.BigEndian.PutUint16(bytes[4:], ip.Id)
binary.BigEndian.PutUint16(bytes[6:], ip.flagsfrags())
bytes[8] = ip.TTL
bytes[9] = byte(ip.Protocol)
if err := ip.AddressTo4(); err != nil {
return err
}
copy(bytes[12:16], ip.SrcIP)
copy(bytes[16:20], ip.DstIP)
curLocation := 20
// Now, we will encode the options
for _, opt := range ip.Options {
switch opt.OptionType {
case 0:
// this is the end of option lists
bytes[curLocation] = 0
curLocation++
case 1:
// this is the padding
bytes[curLocation] = 1
curLocation++
default:
bytes[curLocation] = opt.OptionType
bytes[curLocation+1] = opt.OptionLength
// sanity checking to protect us from buffer overrun
if len(opt.OptionData) > int(opt.OptionLength-2) {
return errors.New("option length is smaller than length of option data")
}
copy(bytes[curLocation+2:curLocation+int(opt.OptionLength)], opt.OptionData)
curLocation += int(opt.OptionLength)
}
}
if opts.ComputeChecksums {
ip.Checksum = checksum(bytes)
}
binary.BigEndian.PutUint16(bytes[10:], ip.Checksum)
return nil
}
func checksum(bytes []byte) uint16 {
// Clear checksum bytes
bytes[10] = 0
bytes[11] = 0
// Compute checksum
var csum uint32
for i := 0; i < len(bytes); i += 2 {
csum += uint32(bytes[i]) << 8
csum += uint32(bytes[i+1])
}
for {
// Break when sum is less or equals to 0xFFFF
if csum <= 65535 {
break
}
// Add carry to the sum
csum = (csum >> 16) + uint32(uint16(csum))
}
// Flip all the bits
return ^uint16(csum)
}
func (ip *IPv4) flagsfrags() (ff uint16) {
ff |= uint16(ip.Flags) << 13
ff |= ip.FragOffset
return
}
// DecodeFromBytes decodes the given bytes into this layer.
func (ip *IPv4) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 20 {
df.SetTruncated()
return fmt.Errorf("Invalid ip4 header. Length %d less than 20", len(data))
}
flagsfrags := binary.BigEndian.Uint16(data[6:8])
ip.Version = uint8(data[0]) >> 4
ip.IHL = uint8(data[0]) & 0x0F
ip.TOS = data[1]
ip.Length = binary.BigEndian.Uint16(data[2:4])
ip.Id = binary.BigEndian.Uint16(data[4:6])
ip.Flags = IPv4Flag(flagsfrags >> 13)
ip.FragOffset = flagsfrags & 0x1FFF
ip.TTL = data[8]
ip.Protocol = IPProtocol(data[9])
ip.Checksum = binary.BigEndian.Uint16(data[10:12])
ip.SrcIP = data[12:16]
ip.DstIP = data[16:20]
ip.Options = ip.Options[:0]
ip.Padding = nil
// Set up an initial guess for contents/payload... we'll reset these soon.
ip.BaseLayer = BaseLayer{Contents: data}
// This code is added for the following enviroment:
// * Windows 10 with TSO option activated. ( tested on Hyper-V, RealTek ethernet driver )
if ip.Length == 0 {
// If using TSO(TCP Segmentation Offload), length is zero.
// The actual packet length is the length of data.
ip.Length = uint16(len(data))
}
if ip.Length < 20 {
return fmt.Errorf("Invalid (too small) IP length (%d < 20)", ip.Length)
} else if ip.IHL < 5 {
return fmt.Errorf("Invalid (too small) IP header length (%d < 5)", ip.IHL)
} else if int(ip.IHL*4) > int(ip.Length) {
return fmt.Errorf("Invalid IP header length > IP length (%d > %d)", ip.IHL, ip.Length)
}
if cmp := len(data) - int(ip.Length); cmp > 0 {
data = data[:ip.Length]
} else if cmp < 0 {
df.SetTruncated()
if int(ip.IHL)*4 > len(data) {
return errors.New("Not all IP header bytes available")
}
}
ip.Contents = data[:ip.IHL*4]
ip.Payload = data[ip.IHL*4:]
// From here on, data contains the header options.
data = data[20 : ip.IHL*4]
// Pull out IP options
for len(data) > 0 {
if ip.Options == nil {
// Pre-allocate to avoid growing the slice too much.
ip.Options = make([]IPv4Option, 0, 4)
}
opt := IPv4Option{OptionType: data[0]}
switch opt.OptionType {
case 0: // End of options
opt.OptionLength = 1
ip.Options = append(ip.Options, opt)
ip.Padding = data[1:]
return nil
case 1: // 1 byte padding
opt.OptionLength = 1
data = data[1:]
ip.Options = append(ip.Options, opt)
default:
if len(data) < 2 {
df.SetTruncated()
return fmt.Errorf("Invalid ip4 option length. Length %d less than 2", len(data))
}
opt.OptionLength = data[1]
if len(data) < int(opt.OptionLength) {
df.SetTruncated()
return fmt.Errorf("IP option length exceeds remaining IP header size, option type %v length %v", opt.OptionType, opt.OptionLength)
}
if opt.OptionLength <= 2 {
return fmt.Errorf("Invalid IP option type %v length %d. Must be greater than 2", opt.OptionType, opt.OptionLength)
}
opt.OptionData = data[2:opt.OptionLength]
data = data[opt.OptionLength:]
ip.Options = append(ip.Options, opt)
}
}
return nil
}
func (i *IPv4) CanDecode() gopacket.LayerClass {
return LayerTypeIPv4
}
func (i *IPv4) NextLayerType() gopacket.LayerType {
if i.Flags&IPv4MoreFragments != 0 || i.FragOffset != 0 {
return gopacket.LayerTypeFragment
}
return i.Protocol.LayerType()
}
func decodeIPv4(data []byte, p gopacket.PacketBuilder) error {
ip := &IPv4{}
err := ip.DecodeFromBytes(data, p)
p.AddLayer(ip)
p.SetNetworkLayer(ip)
if err != nil {
return err
}
return p.NextDecoder(ip.NextLayerType())
}
func checkIPv4Address(addr net.IP) (net.IP, error) {
if c := addr.To4(); c != nil {
return c, nil
}
if len(addr) == net.IPv6len {
return nil, errors.New("address is IPv6")
}
return nil, fmt.Errorf("wrong length of %d bytes instead of %d", len(addr), net.IPv4len)
}
func (ip *IPv4) AddressTo4() error {
var src, dst net.IP
if addr, err := checkIPv4Address(ip.SrcIP); err != nil {
return fmt.Errorf("Invalid source IPv4 address (%s)", err)
} else {
src = addr
}
if addr, err := checkIPv4Address(ip.DstIP); err != nil {
return fmt.Errorf("Invalid destination IPv4 address (%s)", err)
} else {
dst = addr
}
ip.SrcIP = src
ip.DstIP = dst
return nil
}
// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"net"
"github.com/google/gopacket"
)
const (
// IPv6HopByHopOptionJumbogram code as defined in RFC 2675
IPv6HopByHopOptionJumbogram = 0xC2
)
const (
ipv6MaxPayloadLength = 65535
)
// IPv6 is the layer for the IPv6 header.
type IPv6 struct {
// http://www.networksorcery.com/enp/protocol/ipv6.htm
BaseLayer
Version uint8
TrafficClass uint8
FlowLabel uint32
Length uint16
NextHeader IPProtocol
HopLimit uint8
SrcIP net.IP
DstIP net.IP
HopByHop *IPv6HopByHop
// hbh will be pointed to by HopByHop if that layer exists.
hbh IPv6HopByHop
}
// LayerType returns LayerTypeIPv6
func (ipv6 *IPv6) LayerType() gopacket.LayerType { return LayerTypeIPv6 }
// NetworkFlow returns this new Flow (EndpointIPv6, SrcIP, DstIP)
func (ipv6 *IPv6) NetworkFlow() gopacket.Flow {
return gopacket.NewFlow(EndpointIPv6, ipv6.SrcIP, ipv6.DstIP)
}
// Search for Jumbo Payload TLV in IPv6HopByHop and return (length, true) if found
func getIPv6HopByHopJumboLength(hopopts *IPv6HopByHop) (uint32, bool, error) {
var tlv *IPv6HopByHopOption
for _, t := range hopopts.Options {
if t.OptionType == IPv6HopByHopOptionJumbogram {
tlv = t
break
}
}
if tlv == nil {
// Not found
return 0, false, nil
}
if len(tlv.OptionData) != 4 {
return 0, false, errors.New("Jumbo length TLV data must have length 4")
}
l := binary.BigEndian.Uint32(tlv.OptionData)
if l <= ipv6MaxPayloadLength {
return 0, false, fmt.Errorf("Jumbo length cannot be less than %d", ipv6MaxPayloadLength+1)
}
// Found
return l, true, nil
}
// Adds zero-valued Jumbo TLV to IPv6 header if it does not exist
// (if necessary add hop-by-hop header)
func addIPv6JumboOption(ip6 *IPv6) {
var tlv *IPv6HopByHopOption
if ip6.HopByHop == nil {
// Add IPv6 HopByHop
ip6.HopByHop = &IPv6HopByHop{}
ip6.HopByHop.NextHeader = ip6.NextHeader
ip6.HopByHop.HeaderLength = 0
ip6.NextHeader = IPProtocolIPv6HopByHop
}
for _, t := range ip6.HopByHop.Options {
if t.OptionType == IPv6HopByHopOptionJumbogram {
tlv = t
break
}
}
if tlv == nil {
// Add Jumbo TLV
tlv = &IPv6HopByHopOption{}
ip6.HopByHop.Options = append(ip6.HopByHop.Options, tlv)
}
tlv.SetJumboLength(0)
}
// Set jumbo length in serialized IPv6 payload (starting with HopByHop header)
func setIPv6PayloadJumboLength(hbh []byte) error {
pLen := len(hbh)
if pLen < 8 {
//HopByHop is minimum 8 bytes
return fmt.Errorf("Invalid IPv6 payload (length %d)", pLen)
}
hbhLen := int((hbh[1] + 1) * 8)
if hbhLen > pLen {
return fmt.Errorf("Invalid hop-by-hop length (length: %d, payload: %d", hbhLen, pLen)
}
offset := 2 //start with options
for offset < hbhLen {
opt := hbh[offset]
if opt == 0 {
//Pad1
offset++
continue
}
optLen := int(hbh[offset+1])
if opt == IPv6HopByHopOptionJumbogram {
if optLen == 4 {
binary.BigEndian.PutUint32(hbh[offset+2:], uint32(pLen))
return nil
}
return fmt.Errorf("Jumbo TLV too short (%d bytes)", optLen)
}
offset += 2 + optLen
}
return errors.New("Jumbo TLV not found")
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (ipv6 *IPv6) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
var jumbo bool
var err error
payload := b.Bytes()
pLen := len(payload)
if pLen > ipv6MaxPayloadLength {
jumbo = true
if opts.FixLengths {
// We need to set the length later because the hop-by-hop header may
// not exist or else need padding, so pLen may yet change
addIPv6JumboOption(ipv6)
} else if ipv6.HopByHop == nil {
return fmt.Errorf("Cannot fit payload length of %d into IPv6 packet", pLen)
} else {
_, ok, err := getIPv6HopByHopJumboLength(ipv6.HopByHop)
if err != nil {
return err
}
if !ok {
return errors.New("Missing jumbo length hop-by-hop option")
}
}
}
hbhAlreadySerialized := false
if ipv6.HopByHop != nil {
for _, l := range b.Layers() {
if l == LayerTypeIPv6HopByHop {
hbhAlreadySerialized = true
break
}
}
}
if ipv6.HopByHop != nil && !hbhAlreadySerialized {
if ipv6.NextHeader != IPProtocolIPv6HopByHop {
// Just fix it instead of throwing an error
ipv6.NextHeader = IPProtocolIPv6HopByHop
}
err = ipv6.HopByHop.SerializeTo(b, opts)
if err != nil {
return err
}
payload = b.Bytes()
pLen = len(payload)
if opts.FixLengths && jumbo {
err := setIPv6PayloadJumboLength(payload)
if err != nil {
return err
}
}
}
if !jumbo && pLen > ipv6MaxPayloadLength {
return errors.New("Cannot fit payload into IPv6 header")
}
bytes, err := b.PrependBytes(40)
if err != nil {
return err
}
bytes[0] = (ipv6.Version << 4) | (ipv6.TrafficClass >> 4)
bytes[1] = (ipv6.TrafficClass << 4) | uint8(ipv6.FlowLabel>>16)
binary.BigEndian.PutUint16(bytes[2:], uint16(ipv6.FlowLabel))
if opts.FixLengths {
if jumbo {
ipv6.Length = 0
} else {
ipv6.Length = uint16(pLen)
}
}
binary.BigEndian.PutUint16(bytes[4:], ipv6.Length)
bytes[6] = byte(ipv6.NextHeader)
bytes[7] = byte(ipv6.HopLimit)
if err := ipv6.AddressTo16(); err != nil {
return err
}
copy(bytes[8:], ipv6.SrcIP)
copy(bytes[24:], ipv6.DstIP)
return nil
}
// DecodeFromBytes implementation according to gopacket.DecodingLayer
func (ipv6 *IPv6) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 40 {
df.SetTruncated()
return fmt.Errorf("Invalid ip6 header. Length %d less than 40", len(data))
}
ipv6.Version = uint8(data[0]) >> 4
ipv6.TrafficClass = uint8((binary.BigEndian.Uint16(data[0:2]) >> 4) & 0x00FF)
ipv6.FlowLabel = binary.BigEndian.Uint32(data[0:4]) & 0x000FFFFF
ipv6.Length = binary.BigEndian.Uint16(data[4:6])
ipv6.NextHeader = IPProtocol(data[6])
ipv6.HopLimit = data[7]
ipv6.SrcIP = data[8:24]
ipv6.DstIP = data[24:40]
ipv6.HopByHop = nil
ipv6.BaseLayer = BaseLayer{data[:40], data[40:]}
// We treat a HopByHop IPv6 option as part of the IPv6 packet, since its
// options are crucial for understanding what's actually happening per packet.
if ipv6.NextHeader == IPProtocolIPv6HopByHop {
err := ipv6.hbh.DecodeFromBytes(ipv6.Payload, df)
if err != nil {
return err
}
ipv6.HopByHop = &ipv6.hbh
pEnd, jumbo, err := getIPv6HopByHopJumboLength(ipv6.HopByHop)
if err != nil {
return err
}
if jumbo && ipv6.Length == 0 {
pEnd := int(pEnd)
if pEnd > len(ipv6.Payload) {
df.SetTruncated()
pEnd = len(ipv6.Payload)
}
ipv6.Payload = ipv6.Payload[:pEnd]
return nil
} else if jumbo && ipv6.Length != 0 {
return errors.New("IPv6 has jumbo length and IPv6 length is not 0")
} else if !jumbo && ipv6.Length == 0 {
return errors.New("IPv6 length 0, but HopByHop header does not have jumbogram option")
} else {
ipv6.Payload = ipv6.Payload[ipv6.hbh.ActualLength:]
}
}
if ipv6.Length == 0 {
return fmt.Errorf("IPv6 length 0, but next header is %v, not HopByHop", ipv6.NextHeader)
}
pEnd := int(ipv6.Length)
if pEnd > len(ipv6.Payload) {
df.SetTruncated()
pEnd = len(ipv6.Payload)
}
ipv6.Payload = ipv6.Payload[:pEnd]
return nil
}
// CanDecode implementation according to gopacket.DecodingLayer
func (ipv6 *IPv6) CanDecode() gopacket.LayerClass {
return LayerTypeIPv6
}
// NextLayerType implementation according to gopacket.DecodingLayer
func (ipv6 *IPv6) NextLayerType() gopacket.LayerType {
if ipv6.HopByHop != nil {
return ipv6.HopByHop.NextHeader.LayerType()
}
return ipv6.NextHeader.LayerType()
}
func decodeIPv6(data []byte, p gopacket.PacketBuilder) error {
ip6 := &IPv6{}
err := ip6.DecodeFromBytes(data, p)
p.AddLayer(ip6)
p.SetNetworkLayer(ip6)
if ip6.HopByHop != nil {
p.AddLayer(ip6.HopByHop)
}
if err != nil {
return err
}
return p.NextDecoder(ip6.NextLayerType())
}
type ipv6HeaderTLVOption struct {
OptionType, OptionLength uint8
ActualLength int
OptionData []byte
OptionAlignment [2]uint8 // Xn+Y = [2]uint8{X, Y}
}
func (h *ipv6HeaderTLVOption) serializeTo(data []byte, fixLengths bool, dryrun bool) int {
if fixLengths {
h.OptionLength = uint8(len(h.OptionData))
}
length := int(h.OptionLength) + 2
if !dryrun {
data[0] = h.OptionType
data[1] = h.OptionLength
copy(data[2:], h.OptionData)
}
return length
}
func decodeIPv6HeaderTLVOption(data []byte, df gopacket.DecodeFeedback) (h *ipv6HeaderTLVOption, _ error) {
if len(data) < 2 {
df.SetTruncated()
return nil, errors.New("IPv6 header option too small")
}
h = &ipv6HeaderTLVOption{}
if data[0] == 0 {
h.ActualLength = 1
return
}
h.OptionType = data[0]
h.OptionLength = data[1]
h.ActualLength = int(h.OptionLength) + 2
if len(data) < h.ActualLength {
df.SetTruncated()
return nil, errors.New("IPv6 header TLV option too small")
}
h.OptionData = data[2:h.ActualLength]
return
}
func serializeTLVOptionPadding(data []byte, padLength int) {
if padLength <= 0 {
return
}
if padLength == 1 {
data[0] = 0x0
return
}
tlvLength := uint8(padLength) - 2
data[0] = 0x1
data[1] = tlvLength
if tlvLength != 0 {
for k := range data[2:] {
data[k+2] = 0x0
}
}
return
}
// If buf is 'nil' do a serialize dry run
func serializeIPv6HeaderTLVOptions(buf []byte, options []*ipv6HeaderTLVOption, fixLengths bool) int {
var l int
dryrun := buf == nil
length := 2
for _, opt := range options {
if fixLengths {
x := int(opt.OptionAlignment[0])
y := int(opt.OptionAlignment[1])
if x != 0 {
n := length / x
offset := x*n + y
if offset < length {
offset += x
}
if length != offset {
pad := offset - length
if !dryrun {
serializeTLVOptionPadding(buf[length-2:], pad)
}
length += pad
}
}
}
if dryrun {
l = opt.serializeTo(nil, fixLengths, true)
} else {
l = opt.serializeTo(buf[length-2:], fixLengths, false)
}
length += l
}
if fixLengths {
pad := length % 8
if pad != 0 {
if !dryrun {
serializeTLVOptionPadding(buf[length-2:], pad)
}
length += pad
}
}
return length - 2
}
type ipv6ExtensionBase struct {
BaseLayer
NextHeader IPProtocol
HeaderLength uint8
ActualLength int
}
func decodeIPv6ExtensionBase(data []byte, df gopacket.DecodeFeedback) (i ipv6ExtensionBase, returnedErr error) {
if len(data) < 2 {
df.SetTruncated()
return ipv6ExtensionBase{}, fmt.Errorf("Invalid ip6-extension header. Length %d less than 2", len(data))
}
i.NextHeader = IPProtocol(data[0])
i.HeaderLength = data[1]
i.ActualLength = int(i.HeaderLength)*8 + 8
if len(data) < i.ActualLength {
return ipv6ExtensionBase{}, fmt.Errorf("Invalid ip6-extension header. Length %d less than specified length %d", len(data), i.ActualLength)
}
i.Contents = data[:i.ActualLength]
i.Payload = data[i.ActualLength:]
return
}
// IPv6ExtensionSkipper is a DecodingLayer which decodes and ignores v6
// extensions. You can use it with a DecodingLayerParser to handle IPv6 stacks
// which may or may not have extensions.
type IPv6ExtensionSkipper struct {
NextHeader IPProtocol
BaseLayer
}
// DecodeFromBytes implementation according to gopacket.DecodingLayer
func (i *IPv6ExtensionSkipper) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
extension, err := decodeIPv6ExtensionBase(data, df)
if err != nil {
return err
}
i.BaseLayer = BaseLayer{data[:extension.ActualLength], data[extension.ActualLength:]}
i.NextHeader = extension.NextHeader
return nil
}
// CanDecode implementation according to gopacket.DecodingLayer
func (i *IPv6ExtensionSkipper) CanDecode() gopacket.LayerClass {
return LayerClassIPv6Extension
}
// NextLayerType implementation according to gopacket.DecodingLayer
func (i *IPv6ExtensionSkipper) NextLayerType() gopacket.LayerType {
return i.NextHeader.LayerType()
}
// IPv6HopByHopOption is a TLV option present in an IPv6 hop-by-hop extension.
type IPv6HopByHopOption ipv6HeaderTLVOption
// IPv6HopByHop is the IPv6 hop-by-hop extension.
type IPv6HopByHop struct {
ipv6ExtensionBase
Options []*IPv6HopByHopOption
}
// LayerType returns LayerTypeIPv6HopByHop.
func (i *IPv6HopByHop) LayerType() gopacket.LayerType { return LayerTypeIPv6HopByHop }
// SerializeTo implementation according to gopacket.SerializableLayer
func (i *IPv6HopByHop) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
var bytes []byte
var err error
o := make([]*ipv6HeaderTLVOption, 0, len(i.Options))
for _, v := range i.Options {
o = append(o, (*ipv6HeaderTLVOption)(v))
}
l := serializeIPv6HeaderTLVOptions(nil, o, opts.FixLengths)
bytes, err = b.PrependBytes(l)
if err != nil {
return err
}
serializeIPv6HeaderTLVOptions(bytes, o, opts.FixLengths)
length := len(bytes) + 2
if length%8 != 0 {
return errors.New("IPv6HopByHop actual length must be multiple of 8")
}
bytes, err = b.PrependBytes(2)
if err != nil {
return err
}
bytes[0] = uint8(i.NextHeader)
if opts.FixLengths {
i.HeaderLength = uint8((length / 8) - 1)
}
bytes[1] = uint8(i.HeaderLength)
return nil
}
// DecodeFromBytes implementation according to gopacket.DecodingLayer
func (i *IPv6HopByHop) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
var err error
i.ipv6ExtensionBase, err = decodeIPv6ExtensionBase(data, df)
if err != nil {
return err
}
i.Options = i.Options[:0]
offset := 2
for offset < i.ActualLength {
opt, err := decodeIPv6HeaderTLVOption(data[offset:], df)
if err != nil {
return err
}
i.Options = append(i.Options, (*IPv6HopByHopOption)(opt))
offset += opt.ActualLength
}
return nil
}
func decodeIPv6HopByHop(data []byte, p gopacket.PacketBuilder) error {
i := &IPv6HopByHop{}
err := i.DecodeFromBytes(data, p)
p.AddLayer(i)
if err != nil {
return err
}
return p.NextDecoder(i.NextHeader)
}
// SetJumboLength adds the IPv6HopByHopOptionJumbogram with the given length
func (o *IPv6HopByHopOption) SetJumboLength(len uint32) {
o.OptionType = IPv6HopByHopOptionJumbogram
o.OptionLength = 4
o.ActualLength = 6
if o.OptionData == nil {
o.OptionData = make([]byte, 4)
}
binary.BigEndian.PutUint32(o.OptionData, len)
o.OptionAlignment = [2]uint8{4, 2}
}
// IPv6Routing is the IPv6 routing extension.
type IPv6Routing struct {
ipv6ExtensionBase
RoutingType uint8
SegmentsLeft uint8
// This segment is supposed to be zero according to RFC2460, the second set of
// 4 bytes in the extension.
Reserved []byte
// SourceRoutingIPs is the set of IPv6 addresses requested for source routing,
// set only if RoutingType == 0.
SourceRoutingIPs []net.IP
}
// LayerType returns LayerTypeIPv6Routing.
func (i *IPv6Routing) LayerType() gopacket.LayerType { return LayerTypeIPv6Routing }
func decodeIPv6Routing(data []byte, p gopacket.PacketBuilder) error {
base, err := decodeIPv6ExtensionBase(data, p)
if err != nil {
return err
}
i := &IPv6Routing{
ipv6ExtensionBase: base,
RoutingType: data[2],
SegmentsLeft: data[3],
Reserved: data[4:8],
}
switch i.RoutingType {
case 0: // Source routing
if (i.ActualLength-8)%16 != 0 {
return fmt.Errorf("Invalid IPv6 source routing, length of type 0 packet %d", i.ActualLength)
}
for d := i.Contents[8:]; len(d) >= 16; d = d[16:] {
i.SourceRoutingIPs = append(i.SourceRoutingIPs, net.IP(d[:16]))
}
default:
return fmt.Errorf("Unknown IPv6 routing header type %d", i.RoutingType)
}
p.AddLayer(i)
return p.NextDecoder(i.NextHeader)
}
// IPv6Fragment is the IPv6 fragment header, used for packet
// fragmentation/defragmentation.
type IPv6Fragment struct {
BaseLayer
NextHeader IPProtocol
// Reserved1 is bits [8-16), from least to most significant, 0-indexed
Reserved1 uint8
FragmentOffset uint16
// Reserved2 is bits [29-31), from least to most significant, 0-indexed
Reserved2 uint8
MoreFragments bool
Identification uint32
}
// LayerType returns LayerTypeIPv6Fragment.
func (i *IPv6Fragment) LayerType() gopacket.LayerType { return LayerTypeIPv6Fragment }
func decodeIPv6Fragment(data []byte, p gopacket.PacketBuilder) error {
if len(data) < 8 {
p.SetTruncated()
return fmt.Errorf("Invalid ip6-fragment header. Length %d less than 8", len(data))
}
i := &IPv6Fragment{
BaseLayer: BaseLayer{data[:8], data[8:]},
NextHeader: IPProtocol(data[0]),
Reserved1: data[1],
FragmentOffset: binary.BigEndian.Uint16(data[2:4]) >> 3,
Reserved2: data[3] & 0x6 >> 1,
MoreFragments: data[3]&0x1 != 0,
Identification: binary.BigEndian.Uint32(data[4:8]),
}
p.AddLayer(i)
return p.NextDecoder(gopacket.DecodeFragment)
}
// IPv6DestinationOption is a TLV option present in an IPv6 destination options extension.
type IPv6DestinationOption ipv6HeaderTLVOption
// IPv6Destination is the IPv6 destination options header.
type IPv6Destination struct {
ipv6ExtensionBase
Options []*IPv6DestinationOption
}
// LayerType returns LayerTypeIPv6Destination.
func (i *IPv6Destination) LayerType() gopacket.LayerType { return LayerTypeIPv6Destination }
// DecodeFromBytes implementation according to gopacket.DecodingLayer
func (i *IPv6Destination) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
var err error
i.ipv6ExtensionBase, err = decodeIPv6ExtensionBase(data, df)
if err != nil {
return err
}
offset := 2
for offset < i.ActualLength {
opt, err := decodeIPv6HeaderTLVOption(data[offset:], df)
if err != nil {
return err
}
i.Options = append(i.Options, (*IPv6DestinationOption)(opt))
offset += opt.ActualLength
}
return nil
}
func decodeIPv6Destination(data []byte, p gopacket.PacketBuilder) error {
i := &IPv6Destination{}
err := i.DecodeFromBytes(data, p)
p.AddLayer(i)
if err != nil {
return err
}
return p.NextDecoder(i.NextHeader)
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (i *IPv6Destination) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
var bytes []byte
var err error
o := make([]*ipv6HeaderTLVOption, 0, len(i.Options))
for _, v := range i.Options {
o = append(o, (*ipv6HeaderTLVOption)(v))
}
l := serializeIPv6HeaderTLVOptions(nil, o, opts.FixLengths)
bytes, err = b.PrependBytes(l)
if err != nil {
return err
}
serializeIPv6HeaderTLVOptions(bytes, o, opts.FixLengths)
length := len(bytes) + 2
if length%8 != 0 {
return errors.New("IPv6Destination actual length must be multiple of 8")
}
bytes, err = b.PrependBytes(2)
if err != nil {
return err
}
bytes[0] = uint8(i.NextHeader)
if opts.FixLengths {
i.HeaderLength = uint8((length / 8) - 1)
}
bytes[1] = uint8(i.HeaderLength)
return nil
}
func checkIPv6Address(addr net.IP) error {
if len(addr) == net.IPv6len {
return nil
}
if len(addr) == net.IPv4len {
return errors.New("address is IPv4")
}
return fmt.Errorf("wrong length of %d bytes instead of %d", len(addr), net.IPv6len)
}
// AddressTo16 ensures IPv6.SrcIP and IPv6.DstIP are actually IPv6 addresses (i.e. 16 byte addresses)
func (ipv6 *IPv6) AddressTo16() error {
if err := checkIPv6Address(ipv6.SrcIP); err != nil {
return fmt.Errorf("Invalid source IPv6 address (%s)", err)
}
if err := checkIPv6Address(ipv6.DstIP); err != nil {
return fmt.Errorf("Invalid destination IPv6 address (%s)", err)
}
return nil
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"github.com/google/gopacket"
)
// IPSecAH is the authentication header for IPv4/6 defined in
// http://tools.ietf.org/html/rfc2402
type IPSecAH struct {
// While the auth header can be used for both IPv4 and v6, its format is that of
// an IPv6 extension (NextHeader, PayloadLength, etc...), so we use ipv6ExtensionBase
// to build it.
ipv6ExtensionBase
Reserved uint16
SPI, Seq uint32
AuthenticationData []byte
}
// LayerType returns LayerTypeIPSecAH.
func (i *IPSecAH) LayerType() gopacket.LayerType { return LayerTypeIPSecAH }
func decodeIPSecAH(data []byte, p gopacket.PacketBuilder) error {
if len(data) < 12 {
p.SetTruncated()
return errors.New("IPSec AH packet less than 12 bytes")
}
i := &IPSecAH{
ipv6ExtensionBase: ipv6ExtensionBase{
NextHeader: IPProtocol(data[0]),
HeaderLength: data[1],
},
Reserved: binary.BigEndian.Uint16(data[2:4]),
SPI: binary.BigEndian.Uint32(data[4:8]),
Seq: binary.BigEndian.Uint32(data[8:12]),
}
i.ActualLength = (int(i.HeaderLength) + 2) * 4
if len(data) < i.ActualLength {
p.SetTruncated()
return errors.New("Truncated AH packet < ActualLength")
}
i.AuthenticationData = data[12:i.ActualLength]
i.Contents = data[:i.ActualLength]
i.Payload = data[i.ActualLength:]
p.AddLayer(i)
return p.NextDecoder(i.NextHeader)
}
// IPSecESP is the encapsulating security payload defined in
// http://tools.ietf.org/html/rfc2406
type IPSecESP struct {
BaseLayer
SPI, Seq uint32
// Encrypted contains the encrypted set of bytes sent in an ESP
Encrypted []byte
}
// LayerType returns LayerTypeIPSecESP.
func (i *IPSecESP) LayerType() gopacket.LayerType { return LayerTypeIPSecESP }
func decodeIPSecESP(data []byte, p gopacket.PacketBuilder) error {
i := &IPSecESP{
BaseLayer: BaseLayer{data, nil},
SPI: binary.BigEndian.Uint32(data[:4]),
Seq: binary.BigEndian.Uint32(data[4:8]),
Encrypted: data[8:],
}
p.AddLayer(i)
return nil
}
// Copyright 2018 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"github.com/google/gopacket"
)
const (
// LCMShortHeaderMagic is the LCM small message header magic number
LCMShortHeaderMagic uint32 = 0x4c433032
// LCMFragmentedHeaderMagic is the LCM fragmented message header magic number
LCMFragmentedHeaderMagic uint32 = 0x4c433033
)
// LCM (Lightweight Communications and Marshalling) is a set of libraries and
// tools for message passing and data marshalling, targeted at real-time systems
// where high-bandwidth and low latency are critical. It provides a
// publish/subscribe message passing model and automatic
// marshalling/unmarshalling code generation with bindings for applications in a
// variety of programming languages.
//
// References
// https://lcm-proj.github.io/
// https://github.com/lcm-proj/lcm
type LCM struct {
// Common (short & fragmented header) fields
Magic uint32
SequenceNumber uint32
// Fragmented header only fields
PayloadSize uint32
FragmentOffset uint32
FragmentNumber uint16
TotalFragments uint16
// Common field
ChannelName string
// Gopacket helper fields
Fragmented bool
fingerprint LCMFingerprint
contents []byte
payload []byte
}
// LCMFingerprint is the type of a LCM fingerprint.
type LCMFingerprint uint64
var (
// lcmLayerTypes contains a map of all LCM fingerprints that we support and
// their LayerType
lcmLayerTypes = map[LCMFingerprint]gopacket.LayerType{}
layerTypeIndex = 1001
)
// RegisterLCMLayerType allows users to register decoders for the underlying
// LCM payload. This is done based on the fingerprint that every LCM message
// contains and which identifies it uniquely. If num is not the zero value it
// will be used when registering with RegisterLayerType towards gopacket,
// otherwise an incremental value starting from 1001 will be used.
func RegisterLCMLayerType(num int, name string, fingerprint LCMFingerprint,
decoder gopacket.Decoder) gopacket.LayerType {
metadata := gopacket.LayerTypeMetadata{Name: name, Decoder: decoder}
if num == 0 {
num = layerTypeIndex
layerTypeIndex++
}
lcmLayerTypes[fingerprint] = gopacket.RegisterLayerType(num, metadata)
return lcmLayerTypes[fingerprint]
}
// SupportedLCMFingerprints returns a slice of all LCM fingerprints that has
// been registered so far.
func SupportedLCMFingerprints() []LCMFingerprint {
fingerprints := make([]LCMFingerprint, 0, len(lcmLayerTypes))
for fp := range lcmLayerTypes {
fingerprints = append(fingerprints, fp)
}
return fingerprints
}
// GetLCMLayerType returns the underlying LCM message's LayerType.
// This LayerType has to be registered by using RegisterLCMLayerType.
func GetLCMLayerType(fingerprint LCMFingerprint) gopacket.LayerType {
layerType, ok := lcmLayerTypes[fingerprint]
if !ok {
return gopacket.LayerTypePayload
}
return layerType
}
func decodeLCM(data []byte, p gopacket.PacketBuilder) error {
lcm := &LCM{}
err := lcm.DecodeFromBytes(data, p)
if err != nil {
return err
}
p.AddLayer(lcm)
p.SetApplicationLayer(lcm)
return p.NextDecoder(lcm.NextLayerType())
}
// DecodeFromBytes decodes the given bytes into this layer.
func (lcm *LCM) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 8 {
df.SetTruncated()
return errors.New("LCM < 8 bytes")
}
offset := 0
lcm.Magic = binary.BigEndian.Uint32(data[offset:4])
offset += 4
if lcm.Magic != LCMShortHeaderMagic && lcm.Magic != LCMFragmentedHeaderMagic {
return fmt.Errorf("Received LCM header magic %v does not match know "+
"LCM magic numbers. Dropping packet.", lcm.Magic)
}
lcm.SequenceNumber = binary.BigEndian.Uint32(data[offset:8])
offset += 4
if lcm.Magic == LCMFragmentedHeaderMagic {
lcm.Fragmented = true
lcm.PayloadSize = binary.BigEndian.Uint32(data[offset : offset+4])
offset += 4
lcm.FragmentOffset = binary.BigEndian.Uint32(data[offset : offset+4])
offset += 4
lcm.FragmentNumber = binary.BigEndian.Uint16(data[offset : offset+2])
offset += 2
lcm.TotalFragments = binary.BigEndian.Uint16(data[offset : offset+2])
offset += 2
} else {
lcm.Fragmented = false
}
if !lcm.Fragmented || (lcm.Fragmented && lcm.FragmentNumber == 0) {
buffer := make([]byte, 0)
for _, b := range data[offset:] {
offset++
if b == 0 {
break
}
buffer = append(buffer, b)
}
lcm.ChannelName = string(buffer)
}
lcm.fingerprint = LCMFingerprint(
binary.BigEndian.Uint64(data[offset : offset+8]))
lcm.contents = data[:offset]
lcm.payload = data[offset:]
return nil
}
// CanDecode returns a set of layers that LCM objects can decode.
// As LCM objects can only decode the LCM layer, we just return that layer.
func (lcm LCM) CanDecode() gopacket.LayerClass {
return LayerTypeLCM
}
// NextLayerType specifies the LCM payload layer type following this header.
// As LCM packets are serialized structs with uniq fingerprints for each uniq
// combination of data types, lookup of correct layer type is based on that
// fingerprint.
func (lcm LCM) NextLayerType() gopacket.LayerType {
if !lcm.Fragmented || (lcm.Fragmented && lcm.FragmentNumber == 0) {
return GetLCMLayerType(lcm.fingerprint)
}
return gopacket.LayerTypeFragment
}
// LayerType returns LayerTypeLCM
func (lcm LCM) LayerType() gopacket.LayerType {
return LayerTypeLCM
}
// LayerContents returns the contents of the LCM header.
func (lcm LCM) LayerContents() []byte {
return lcm.contents
}
// LayerPayload returns the payload following this LCM header.
func (lcm LCM) LayerPayload() []byte {
return lcm.payload
}
// Payload returns the payload following this LCM header.
func (lcm LCM) Payload() []byte {
return lcm.LayerPayload()
}
// Fingerprint returns the LCM fingerprint of the underlying message.
func (lcm LCM) Fingerprint() LCMFingerprint {
return lcm.fingerprint
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"net"
"github.com/google/gopacket"
)
type LinuxSLLPacketType uint16
const (
LinuxSLLPacketTypeHost LinuxSLLPacketType = 0 // To us
LinuxSLLPacketTypeBroadcast LinuxSLLPacketType = 1 // To all
LinuxSLLPacketTypeMulticast LinuxSLLPacketType = 2 // To group
LinuxSLLPacketTypeOtherhost LinuxSLLPacketType = 3 // To someone else
LinuxSLLPacketTypeOutgoing LinuxSLLPacketType = 4 // Outgoing of any type
// These ones are invisible by user level
LinuxSLLPacketTypeLoopback LinuxSLLPacketType = 5 // MC/BRD frame looped back
LinuxSLLPacketTypeFastroute LinuxSLLPacketType = 6 // Fastrouted frame
)
func (l LinuxSLLPacketType) String() string {
switch l {
case LinuxSLLPacketTypeHost:
return "host"
case LinuxSLLPacketTypeBroadcast:
return "broadcast"
case LinuxSLLPacketTypeMulticast:
return "multicast"
case LinuxSLLPacketTypeOtherhost:
return "otherhost"
case LinuxSLLPacketTypeOutgoing:
return "outgoing"
case LinuxSLLPacketTypeLoopback:
return "loopback"
case LinuxSLLPacketTypeFastroute:
return "fastroute"
}
return fmt.Sprintf("Unknown(%d)", int(l))
}
type LinuxSLL struct {
BaseLayer
PacketType LinuxSLLPacketType
AddrLen uint16
Addr net.HardwareAddr
EthernetType EthernetType
AddrType uint16
}
// LayerType returns LayerTypeLinuxSLL.
func (sll *LinuxSLL) LayerType() gopacket.LayerType { return LayerTypeLinuxSLL }
func (sll *LinuxSLL) CanDecode() gopacket.LayerClass {
return LayerTypeLinuxSLL
}
func (sll *LinuxSLL) LinkFlow() gopacket.Flow {
return gopacket.NewFlow(EndpointMAC, sll.Addr, nil)
}
func (sll *LinuxSLL) NextLayerType() gopacket.LayerType {
return sll.EthernetType.LayerType()
}
func (sll *LinuxSLL) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 16 {
return errors.New("Linux SLL packet too small")
}
sll.PacketType = LinuxSLLPacketType(binary.BigEndian.Uint16(data[0:2]))
sll.AddrType = binary.BigEndian.Uint16(data[2:4])
sll.AddrLen = binary.BigEndian.Uint16(data[4:6])
sll.Addr = net.HardwareAddr(data[6 : sll.AddrLen+6])
sll.EthernetType = EthernetType(binary.BigEndian.Uint16(data[14:16]))
sll.BaseLayer = BaseLayer{data[:16], data[16:]}
return nil
}
func decodeLinuxSLL(data []byte, p gopacket.PacketBuilder) error {
sll := &LinuxSLL{}
if err := sll.DecodeFromBytes(data, p); err != nil {
return err
}
p.AddLayer(sll)
p.SetLinkLayer(sll)
return p.NextDecoder(sll.EthernetType)
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"github.com/google/gopacket"
)
// LLC is the layer used for 802.2 Logical Link Control headers.
// See http://standards.ieee.org/getieee802/download/802.2-1998.pdf
type LLC struct {
BaseLayer
DSAP uint8
IG bool // true means group, false means individual
SSAP uint8
CR bool // true means response, false means command
Control uint16
}
// LayerType returns gopacket.LayerTypeLLC.
func (l *LLC) LayerType() gopacket.LayerType { return LayerTypeLLC }
// DecodeFromBytes decodes the given bytes into this layer.
func (l *LLC) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 3 {
return errors.New("LLC header too small")
}
l.DSAP = data[0] & 0xFE
l.IG = data[0]&0x1 != 0
l.SSAP = data[1] & 0xFE
l.CR = data[1]&0x1 != 0
l.Control = uint16(data[2])
if l.Control&0x1 == 0 || l.Control&0x3 == 0x1 {
if len(data) < 4 {
return errors.New("LLC header too small")
}
l.Control = l.Control<<8 | uint16(data[3])
l.Contents = data[:4]
l.Payload = data[4:]
} else {
l.Contents = data[:3]
l.Payload = data[3:]
}
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (l *LLC) CanDecode() gopacket.LayerClass {
return LayerTypeLLC
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (l *LLC) NextLayerType() gopacket.LayerType {
switch {
case l.DSAP == 0xAA && l.SSAP == 0xAA:
return LayerTypeSNAP
case l.DSAP == 0x42 && l.SSAP == 0x42:
return LayerTypeSTP
}
return gopacket.LayerTypeZero // Not implemented
}
// SNAP is used inside LLC. See
// http://standards.ieee.org/getieee802/download/802-2001.pdf.
// From http://en.wikipedia.org/wiki/Subnetwork_Access_Protocol:
// "[T]he Subnetwork Access Protocol (SNAP) is a mechanism for multiplexing,
// on networks using IEEE 802.2 LLC, more protocols than can be distinguished
// by the 8-bit 802.2 Service Access Point (SAP) fields."
type SNAP struct {
BaseLayer
OrganizationalCode []byte
Type EthernetType
}
// LayerType returns gopacket.LayerTypeSNAP.
func (s *SNAP) LayerType() gopacket.LayerType { return LayerTypeSNAP }
// DecodeFromBytes decodes the given bytes into this layer.
func (s *SNAP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 5 {
return errors.New("SNAP header too small")
}
s.OrganizationalCode = data[:3]
s.Type = EthernetType(binary.BigEndian.Uint16(data[3:5]))
s.BaseLayer = BaseLayer{data[:5], data[5:]}
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (s *SNAP) CanDecode() gopacket.LayerClass {
return LayerTypeSNAP
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (s *SNAP) NextLayerType() gopacket.LayerType {
// See BUG(gconnel) in decodeSNAP
return s.Type.LayerType()
}
func decodeLLC(data []byte, p gopacket.PacketBuilder) error {
l := &LLC{}
err := l.DecodeFromBytes(data, p)
if err != nil {
return err
}
p.AddLayer(l)
return p.NextDecoder(l.NextLayerType())
}
func decodeSNAP(data []byte, p gopacket.PacketBuilder) error {
s := &SNAP{}
err := s.DecodeFromBytes(data, p)
if err != nil {
return err
}
p.AddLayer(s)
// BUG(gconnell): When decoding SNAP, we treat the SNAP type as an Ethernet
// type. This may not actually be an ethernet type in all cases,
// depending on the organizational code. Right now, we don't check.
return p.NextDecoder(s.Type)
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (l *LLC) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
var igFlag, crFlag byte
var length int
if l.Control&0xFF00 != 0 {
length = 4
} else {
length = 3
}
if l.DSAP&0x1 != 0 {
return errors.New("DSAP value invalid, should not include IG flag bit")
}
if l.SSAP&0x1 != 0 {
return errors.New("SSAP value invalid, should not include CR flag bit")
}
if buf, err := b.PrependBytes(length); err != nil {
return err
} else {
igFlag = 0
if l.IG {
igFlag = 0x1
}
crFlag = 0
if l.CR {
crFlag = 0x1
}
buf[0] = l.DSAP + igFlag
buf[1] = l.SSAP + crFlag
if length == 4 {
buf[2] = uint8(l.Control >> 8)
buf[3] = uint8(l.Control)
} else {
buf[2] = uint8(l.Control)
}
}
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (s *SNAP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
if buf, err := b.PrependBytes(5); err != nil {
return err
} else {
buf[0] = s.OrganizationalCode[0]
buf[1] = s.OrganizationalCode[1]
buf[2] = s.OrganizationalCode[2]
binary.BigEndian.PutUint16(buf[3:5], uint16(s.Type))
}
return nil
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"github.com/google/gopacket"
)
// LLDPTLVType is the type of each TLV value in a LinkLayerDiscovery packet.
type LLDPTLVType byte
const (
LLDPTLVEnd LLDPTLVType = 0
LLDPTLVChassisID LLDPTLVType = 1
LLDPTLVPortID LLDPTLVType = 2
LLDPTLVTTL LLDPTLVType = 3
LLDPTLVPortDescription LLDPTLVType = 4
LLDPTLVSysName LLDPTLVType = 5
LLDPTLVSysDescription LLDPTLVType = 6
LLDPTLVSysCapabilities LLDPTLVType = 7
LLDPTLVMgmtAddress LLDPTLVType = 8
LLDPTLVOrgSpecific LLDPTLVType = 127
)
// LinkLayerDiscoveryValue is a TLV value inside a LinkLayerDiscovery packet layer.
type LinkLayerDiscoveryValue struct {
Type LLDPTLVType
Length uint16
Value []byte
}
func (c *LinkLayerDiscoveryValue) len() int {
return 0
}
// LLDPChassisIDSubType specifies the value type for a single LLDPChassisID.ID
type LLDPChassisIDSubType byte
// LLDP Chassis Types
const (
LLDPChassisIDSubTypeReserved LLDPChassisIDSubType = 0
LLDPChassisIDSubTypeChassisComp LLDPChassisIDSubType = 1
LLDPChassisIDSubtypeIfaceAlias LLDPChassisIDSubType = 2
LLDPChassisIDSubTypePortComp LLDPChassisIDSubType = 3
LLDPChassisIDSubTypeMACAddr LLDPChassisIDSubType = 4
LLDPChassisIDSubTypeNetworkAddr LLDPChassisIDSubType = 5
LLDPChassisIDSubtypeIfaceName LLDPChassisIDSubType = 6
LLDPChassisIDSubTypeLocal LLDPChassisIDSubType = 7
)
type LLDPChassisID struct {
Subtype LLDPChassisIDSubType
ID []byte
}
func (c *LLDPChassisID) serialize() []byte {
var buf = make([]byte, c.serializedLen())
idLen := uint16(LLDPTLVChassisID)<<9 | uint16(len(c.ID)+1) //id should take 7 bits, length should take 9 bits, +1 for subtype
binary.BigEndian.PutUint16(buf[0:2], idLen)
buf[2] = byte(c.Subtype)
copy(buf[3:], c.ID)
return buf
}
func (c *LLDPChassisID) serializedLen() int {
return len(c.ID) + 3 // +2 for id and length, +1 for subtype
}
// LLDPPortIDSubType specifies the value type for a single LLDPPortID.ID
type LLDPPortIDSubType byte
// LLDP PortID types
const (
LLDPPortIDSubtypeReserved LLDPPortIDSubType = 0
LLDPPortIDSubtypeIfaceAlias LLDPPortIDSubType = 1
LLDPPortIDSubtypePortComp LLDPPortIDSubType = 2
LLDPPortIDSubtypeMACAddr LLDPPortIDSubType = 3
LLDPPortIDSubtypeNetworkAddr LLDPPortIDSubType = 4
LLDPPortIDSubtypeIfaceName LLDPPortIDSubType = 5
LLDPPortIDSubtypeAgentCircuitID LLDPPortIDSubType = 6
LLDPPortIDSubtypeLocal LLDPPortIDSubType = 7
)
type LLDPPortID struct {
Subtype LLDPPortIDSubType
ID []byte
}
func (c *LLDPPortID) serialize() []byte {
var buf = make([]byte, c.serializedLen())
idLen := uint16(LLDPTLVPortID)<<9 | uint16(len(c.ID)+1) //id should take 7 bits, length should take 9 bits, +1 for subtype
binary.BigEndian.PutUint16(buf[0:2], idLen)
buf[2] = byte(c.Subtype)
copy(buf[3:], c.ID)
return buf
}
func (c *LLDPPortID) serializedLen() int {
return len(c.ID) + 3 // +2 for id and length, +1 for subtype
}
// LinkLayerDiscovery is a packet layer containing the LinkLayer Discovery Protocol.
// See http:http://standards.ieee.org/getieee802/download/802.1AB-2009.pdf
// ChassisID, PortID and TTL are mandatory TLV's. Other values can be decoded
// with DecodeValues()
type LinkLayerDiscovery struct {
BaseLayer
ChassisID LLDPChassisID
PortID LLDPPortID
TTL uint16
Values []LinkLayerDiscoveryValue
}
type IEEEOUI uint32
// http://standards.ieee.org/develop/regauth/oui/oui.txt
const (
IEEEOUI8021 IEEEOUI = 0x0080c2
IEEEOUI8023 IEEEOUI = 0x00120f
IEEEOUI80211 IEEEOUI = 0x000fac
IEEEOUI8021Qbg IEEEOUI = 0x0013BF
IEEEOUICisco2 IEEEOUI = 0x000142
IEEEOUIMedia IEEEOUI = 0x0012bb // TR-41
IEEEOUIProfinet IEEEOUI = 0x000ecf
IEEEOUIDCBX IEEEOUI = 0x001b21
)
// LLDPOrgSpecificTLV is an Organisation-specific TLV
type LLDPOrgSpecificTLV struct {
OUI IEEEOUI
SubType uint8
Info []byte
}
// LLDPCapabilities Types
const (
LLDPCapsOther uint16 = 1 << 0
LLDPCapsRepeater uint16 = 1 << 1
LLDPCapsBridge uint16 = 1 << 2
LLDPCapsWLANAP uint16 = 1 << 3
LLDPCapsRouter uint16 = 1 << 4
LLDPCapsPhone uint16 = 1 << 5
LLDPCapsDocSis uint16 = 1 << 6
LLDPCapsStationOnly uint16 = 1 << 7
LLDPCapsCVLAN uint16 = 1 << 8
LLDPCapsSVLAN uint16 = 1 << 9
LLDPCapsTmpr uint16 = 1 << 10
)
// LLDPCapabilities represents the capabilities of a device
type LLDPCapabilities struct {
Other bool
Repeater bool
Bridge bool
WLANAP bool
Router bool
Phone bool
DocSis bool
StationOnly bool
CVLAN bool
SVLAN bool
TMPR bool
}
type LLDPSysCapabilities struct {
SystemCap LLDPCapabilities
EnabledCap LLDPCapabilities
}
type IANAAddressFamily byte
// LLDP Management Address Subtypes
// http://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml
const (
IANAAddressFamilyReserved IANAAddressFamily = 0
IANAAddressFamilyIPV4 IANAAddressFamily = 1
IANAAddressFamilyIPV6 IANAAddressFamily = 2
IANAAddressFamilyNSAP IANAAddressFamily = 3
IANAAddressFamilyHDLC IANAAddressFamily = 4
IANAAddressFamilyBBN1822 IANAAddressFamily = 5
IANAAddressFamily802 IANAAddressFamily = 6
IANAAddressFamilyE163 IANAAddressFamily = 7
IANAAddressFamilyE164 IANAAddressFamily = 8
IANAAddressFamilyF69 IANAAddressFamily = 9
IANAAddressFamilyX121 IANAAddressFamily = 10
IANAAddressFamilyIPX IANAAddressFamily = 11
IANAAddressFamilyAtalk IANAAddressFamily = 12
IANAAddressFamilyDecnet IANAAddressFamily = 13
IANAAddressFamilyBanyan IANAAddressFamily = 14
IANAAddressFamilyE164NSAP IANAAddressFamily = 15
IANAAddressFamilyDNS IANAAddressFamily = 16
IANAAddressFamilyDistname IANAAddressFamily = 17
IANAAddressFamilyASNumber IANAAddressFamily = 18
IANAAddressFamilyXTPIPV4 IANAAddressFamily = 19
IANAAddressFamilyXTPIPV6 IANAAddressFamily = 20
IANAAddressFamilyXTP IANAAddressFamily = 21
IANAAddressFamilyFcWWPN IANAAddressFamily = 22
IANAAddressFamilyFcWWNN IANAAddressFamily = 23
IANAAddressFamilyGWID IANAAddressFamily = 24
IANAAddressFamilyL2VPN IANAAddressFamily = 25
)
type LLDPInterfaceSubtype byte
// LLDP Interface Subtypes
const (
LLDPInterfaceSubtypeUnknown LLDPInterfaceSubtype = 1
LLDPInterfaceSubtypeifIndex LLDPInterfaceSubtype = 2
LLDPInterfaceSubtypeSysPort LLDPInterfaceSubtype = 3
)
type LLDPMgmtAddress struct {
Subtype IANAAddressFamily
Address []byte
InterfaceSubtype LLDPInterfaceSubtype
InterfaceNumber uint32
OID string
}
// LinkLayerDiscoveryInfo represents the decoded details for a set of LinkLayerDiscoveryValues
// Organisation-specific TLV's can be decoded using the various Decode() methods
type LinkLayerDiscoveryInfo struct {
BaseLayer
PortDescription string
SysName string
SysDescription string
SysCapabilities LLDPSysCapabilities
MgmtAddress LLDPMgmtAddress
OrgTLVs []LLDPOrgSpecificTLV // Private TLVs
Unknown []LinkLayerDiscoveryValue // undecoded TLVs
}
/// IEEE 802.1 TLV Subtypes
const (
LLDP8021SubtypePortVLANID uint8 = 1
LLDP8021SubtypeProtocolVLANID uint8 = 2
LLDP8021SubtypeVLANName uint8 = 3
LLDP8021SubtypeProtocolIdentity uint8 = 4
LLDP8021SubtypeVDIUsageDigest uint8 = 5
LLDP8021SubtypeManagementVID uint8 = 6
LLDP8021SubtypeLinkAggregation uint8 = 7
)
// VLAN Port Protocol ID options
const (
LLDPProtocolVLANIDCapability byte = 1 << 1
LLDPProtocolVLANIDStatus byte = 1 << 2
)
type PortProtocolVLANID struct {
Supported bool
Enabled bool
ID uint16
}
type VLANName struct {
ID uint16
Name string
}
type ProtocolIdentity []byte
// LACP options
const (
LLDPAggregationCapability byte = 1 << 0
LLDPAggregationStatus byte = 1 << 1
)
// IEEE 802 Link Aggregation parameters
type LLDPLinkAggregation struct {
Supported bool
Enabled bool
PortID uint32
}
// LLDPInfo8021 represents the information carried in 802.1 Org-specific TLVs
type LLDPInfo8021 struct {
PVID uint16
PPVIDs []PortProtocolVLANID
VLANNames []VLANName
ProtocolIdentities []ProtocolIdentity
VIDUsageDigest uint32
ManagementVID uint16
LinkAggregation LLDPLinkAggregation
}
// IEEE 802.3 TLV Subtypes
const (
LLDP8023SubtypeMACPHY uint8 = 1
LLDP8023SubtypeMDIPower uint8 = 2
LLDP8023SubtypeLinkAggregation uint8 = 3
LLDP8023SubtypeMTU uint8 = 4
)
// MACPHY options
const (
LLDPMACPHYCapability byte = 1 << 0
LLDPMACPHYStatus byte = 1 << 1
)
// From IANA-MAU-MIB (introduced by RFC 4836) - dot3MauType
const (
LLDPMAUTypeUnknown uint16 = 0
LLDPMAUTypeAUI uint16 = 1
LLDPMAUType10Base5 uint16 = 2
LLDPMAUTypeFOIRL uint16 = 3
LLDPMAUType10Base2 uint16 = 4
LLDPMAUType10BaseT uint16 = 5
LLDPMAUType10BaseFP uint16 = 6
LLDPMAUType10BaseFB uint16 = 7
LLDPMAUType10BaseFL uint16 = 8
LLDPMAUType10BROAD36 uint16 = 9
LLDPMAUType10BaseT_HD uint16 = 10
LLDPMAUType10BaseT_FD uint16 = 11
LLDPMAUType10BaseFL_HD uint16 = 12
LLDPMAUType10BaseFL_FD uint16 = 13
LLDPMAUType100BaseT4 uint16 = 14
LLDPMAUType100BaseTX_HD uint16 = 15
LLDPMAUType100BaseTX_FD uint16 = 16
LLDPMAUType100BaseFX_HD uint16 = 17
LLDPMAUType100BaseFX_FD uint16 = 18
LLDPMAUType100BaseT2_HD uint16 = 19
LLDPMAUType100BaseT2_FD uint16 = 20
LLDPMAUType1000BaseX_HD uint16 = 21
LLDPMAUType1000BaseX_FD uint16 = 22
LLDPMAUType1000BaseLX_HD uint16 = 23
LLDPMAUType1000BaseLX_FD uint16 = 24
LLDPMAUType1000BaseSX_HD uint16 = 25
LLDPMAUType1000BaseSX_FD uint16 = 26
LLDPMAUType1000BaseCX_HD uint16 = 27
LLDPMAUType1000BaseCX_FD uint16 = 28
LLDPMAUType1000BaseT_HD uint16 = 29
LLDPMAUType1000BaseT_FD uint16 = 30
LLDPMAUType10GBaseX uint16 = 31
LLDPMAUType10GBaseLX4 uint16 = 32
LLDPMAUType10GBaseR uint16 = 33
LLDPMAUType10GBaseER uint16 = 34
LLDPMAUType10GBaseLR uint16 = 35
LLDPMAUType10GBaseSR uint16 = 36
LLDPMAUType10GBaseW uint16 = 37
LLDPMAUType10GBaseEW uint16 = 38
LLDPMAUType10GBaseLW uint16 = 39
LLDPMAUType10GBaseSW uint16 = 40
LLDPMAUType10GBaseCX4 uint16 = 41
LLDPMAUType2BaseTL uint16 = 42
LLDPMAUType10PASS_TS uint16 = 43
LLDPMAUType100BaseBX10D uint16 = 44
LLDPMAUType100BaseBX10U uint16 = 45
LLDPMAUType100BaseLX10 uint16 = 46
LLDPMAUType1000BaseBX10D uint16 = 47
LLDPMAUType1000BaseBX10U uint16 = 48
LLDPMAUType1000BaseLX10 uint16 = 49
LLDPMAUType1000BasePX10D uint16 = 50
LLDPMAUType1000BasePX10U uint16 = 51
LLDPMAUType1000BasePX20D uint16 = 52
LLDPMAUType1000BasePX20U uint16 = 53
LLDPMAUType10GBaseT uint16 = 54
LLDPMAUType10GBaseLRM uint16 = 55
LLDPMAUType1000BaseKX uint16 = 56
LLDPMAUType10GBaseKX4 uint16 = 57
LLDPMAUType10GBaseKR uint16 = 58
LLDPMAUType10_1GBasePRX_D1 uint16 = 59
LLDPMAUType10_1GBasePRX_D2 uint16 = 60
LLDPMAUType10_1GBasePRX_D3 uint16 = 61
LLDPMAUType10_1GBasePRX_U1 uint16 = 62
LLDPMAUType10_1GBasePRX_U2 uint16 = 63
LLDPMAUType10_1GBasePRX_U3 uint16 = 64
LLDPMAUType10GBasePR_D1 uint16 = 65
LLDPMAUType10GBasePR_D2 uint16 = 66
LLDPMAUType10GBasePR_D3 uint16 = 67
LLDPMAUType10GBasePR_U1 uint16 = 68
LLDPMAUType10GBasePR_U3 uint16 = 69
)
// From RFC 3636 - ifMauAutoNegCapAdvertisedBits
const (
LLDPMAUPMDOther uint16 = 1 << 15
LLDPMAUPMD10BaseT uint16 = 1 << 14
LLDPMAUPMD10BaseT_FD uint16 = 1 << 13
LLDPMAUPMD100BaseT4 uint16 = 1 << 12
LLDPMAUPMD100BaseTX uint16 = 1 << 11
LLDPMAUPMD100BaseTX_FD uint16 = 1 << 10
LLDPMAUPMD100BaseT2 uint16 = 1 << 9
LLDPMAUPMD100BaseT2_FD uint16 = 1 << 8
LLDPMAUPMDFDXPAUSE uint16 = 1 << 7
LLDPMAUPMDFDXAPAUSE uint16 = 1 << 6
LLDPMAUPMDFDXSPAUSE uint16 = 1 << 5
LLDPMAUPMDFDXBPAUSE uint16 = 1 << 4
LLDPMAUPMD1000BaseX uint16 = 1 << 3
LLDPMAUPMD1000BaseX_FD uint16 = 1 << 2
LLDPMAUPMD1000BaseT uint16 = 1 << 1
LLDPMAUPMD1000BaseT_FD uint16 = 1 << 0
)
// Inverted ifMauAutoNegCapAdvertisedBits if required
// (Some manufacturers misinterpreted the spec -
// see https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=1455)
const (
LLDPMAUPMDOtherInv uint16 = 1 << 0
LLDPMAUPMD10BaseTInv uint16 = 1 << 1
LLDPMAUPMD10BaseT_FDInv uint16 = 1 << 2
LLDPMAUPMD100BaseT4Inv uint16 = 1 << 3
LLDPMAUPMD100BaseTXInv uint16 = 1 << 4
LLDPMAUPMD100BaseTX_FDInv uint16 = 1 << 5
LLDPMAUPMD100BaseT2Inv uint16 = 1 << 6
LLDPMAUPMD100BaseT2_FDInv uint16 = 1 << 7
LLDPMAUPMDFDXPAUSEInv uint16 = 1 << 8
LLDPMAUPMDFDXAPAUSEInv uint16 = 1 << 9
LLDPMAUPMDFDXSPAUSEInv uint16 = 1 << 10
LLDPMAUPMDFDXBPAUSEInv uint16 = 1 << 11
LLDPMAUPMD1000BaseXInv uint16 = 1 << 12
LLDPMAUPMD1000BaseX_FDInv uint16 = 1 << 13
LLDPMAUPMD1000BaseTInv uint16 = 1 << 14
LLDPMAUPMD1000BaseT_FDInv uint16 = 1 << 15
)
type LLDPMACPHYConfigStatus struct {
AutoNegSupported bool
AutoNegEnabled bool
AutoNegCapability uint16
MAUType uint16
}
// MDI Power options
const (
LLDPMDIPowerPortClass byte = 1 << 0
LLDPMDIPowerCapability byte = 1 << 1
LLDPMDIPowerStatus byte = 1 << 2
LLDPMDIPowerPairsAbility byte = 1 << 3
)
type LLDPPowerType byte
type LLDPPowerSource byte
type LLDPPowerPriority byte
const (
LLDPPowerPriorityUnknown LLDPPowerPriority = 0
LLDPPowerPriorityMedium LLDPPowerPriority = 1
LLDPPowerPriorityHigh LLDPPowerPriority = 2
LLDPPowerPriorityLow LLDPPowerPriority = 3
)
type LLDPPowerViaMDI8023 struct {
PortClassPSE bool // false = PD
PSESupported bool
PSEEnabled bool
PSEPairsAbility bool
PSEPowerPair uint8
PSEClass uint8
Type LLDPPowerType
Source LLDPPowerSource
Priority LLDPPowerPriority
Requested uint16 // 1-510 Watts
Allocated uint16 // 1-510 Watts
}
// LLDPInfo8023 represents the information carried in 802.3 Org-specific TLVs
type LLDPInfo8023 struct {
MACPHYConfigStatus LLDPMACPHYConfigStatus
PowerViaMDI LLDPPowerViaMDI8023
LinkAggregation LLDPLinkAggregation
MTU uint16
}
// IEEE 802.1Qbg TLV Subtypes
const (
LLDP8021QbgEVB uint8 = 0
LLDP8021QbgCDCP uint8 = 1
LLDP8021QbgVDP uint8 = 2
LLDP8021QbgEVB22 uint8 = 13
)
// LLDPEVBCapabilities Types
const (
LLDPEVBCapsSTD uint16 = 1 << 7
LLDPEVBCapsRR uint16 = 1 << 6
LLDPEVBCapsRTE uint16 = 1 << 2
LLDPEVBCapsECP uint16 = 1 << 1
LLDPEVBCapsVDP uint16 = 1 << 0
)
// LLDPEVBCapabilities represents the EVB capabilities of a device
type LLDPEVBCapabilities struct {
StandardBridging bool
ReflectiveRelay bool
RetransmissionTimerExponent bool
EdgeControlProtocol bool
VSIDiscoveryProtocol bool
}
type LLDPEVBSettings struct {
Supported LLDPEVBCapabilities
Enabled LLDPEVBCapabilities
SupportedVSIs uint16
ConfiguredVSIs uint16
RTEExponent uint8
}
// LLDPInfo8021Qbg represents the information carried in 802.1Qbg Org-specific TLVs
type LLDPInfo8021Qbg struct {
EVBSettings LLDPEVBSettings
}
type LLDPMediaSubtype uint8
// Media TLV Subtypes
const (
LLDPMediaTypeCapabilities LLDPMediaSubtype = 1
LLDPMediaTypeNetwork LLDPMediaSubtype = 2
LLDPMediaTypeLocation LLDPMediaSubtype = 3
LLDPMediaTypePower LLDPMediaSubtype = 4
LLDPMediaTypeHardware LLDPMediaSubtype = 5
LLDPMediaTypeFirmware LLDPMediaSubtype = 6
LLDPMediaTypeSoftware LLDPMediaSubtype = 7
LLDPMediaTypeSerial LLDPMediaSubtype = 8
LLDPMediaTypeManufacturer LLDPMediaSubtype = 9
LLDPMediaTypeModel LLDPMediaSubtype = 10
LLDPMediaTypeAssetID LLDPMediaSubtype = 11
)
type LLDPMediaClass uint8
// Media Class Values
const (
LLDPMediaClassUndefined LLDPMediaClass = 0
LLDPMediaClassEndpointI LLDPMediaClass = 1
LLDPMediaClassEndpointII LLDPMediaClass = 2
LLDPMediaClassEndpointIII LLDPMediaClass = 3
LLDPMediaClassNetwork LLDPMediaClass = 4
)
// LLDPMediaCapabilities Types
const (
LLDPMediaCapsLLDP uint16 = 1 << 0
LLDPMediaCapsNetwork uint16 = 1 << 1
LLDPMediaCapsLocation uint16 = 1 << 2
LLDPMediaCapsPowerPSE uint16 = 1 << 3
LLDPMediaCapsPowerPD uint16 = 1 << 4
LLDPMediaCapsInventory uint16 = 1 << 5
)
// LLDPMediaCapabilities represents the LLDP Media capabilities of a device
type LLDPMediaCapabilities struct {
Capabilities bool
NetworkPolicy bool
Location bool
PowerPSE bool
PowerPD bool
Inventory bool
Class LLDPMediaClass
}
type LLDPApplicationType uint8
const (
LLDPAppTypeReserved LLDPApplicationType = 0
LLDPAppTypeVoice LLDPApplicationType = 1
LLDPappTypeVoiceSignaling LLDPApplicationType = 2
LLDPappTypeGuestVoice LLDPApplicationType = 3
LLDPappTypeGuestVoiceSignaling LLDPApplicationType = 4
LLDPappTypeSoftphoneVoice LLDPApplicationType = 5
LLDPappTypeVideoConferencing LLDPApplicationType = 6
LLDPappTypeStreamingVideo LLDPApplicationType = 7
LLDPappTypeVideoSignaling LLDPApplicationType = 8
)
type LLDPNetworkPolicy struct {
ApplicationType LLDPApplicationType
Defined bool
Tagged bool
VLANId uint16
L2Priority uint16
DSCPValue uint8
}
type LLDPLocationFormat uint8
const (
LLDPLocationFormatInvalid LLDPLocationFormat = 0
LLDPLocationFormatCoordinate LLDPLocationFormat = 1
LLDPLocationFormatAddress LLDPLocationFormat = 2
LLDPLocationFormatECS LLDPLocationFormat = 3
)
type LLDPLocationAddressWhat uint8
const (
LLDPLocationAddressWhatDHCP LLDPLocationAddressWhat = 0
LLDPLocationAddressWhatNetwork LLDPLocationAddressWhat = 1
LLDPLocationAddressWhatClient LLDPLocationAddressWhat = 2
)
type LLDPLocationAddressType uint8
const (
LLDPLocationAddressTypeLanguage LLDPLocationAddressType = 0
LLDPLocationAddressTypeNational LLDPLocationAddressType = 1
LLDPLocationAddressTypeCounty LLDPLocationAddressType = 2
LLDPLocationAddressTypeCity LLDPLocationAddressType = 3
LLDPLocationAddressTypeCityDivision LLDPLocationAddressType = 4
LLDPLocationAddressTypeNeighborhood LLDPLocationAddressType = 5
LLDPLocationAddressTypeStreet LLDPLocationAddressType = 6
LLDPLocationAddressTypeLeadingStreet LLDPLocationAddressType = 16
LLDPLocationAddressTypeTrailingStreet LLDPLocationAddressType = 17
LLDPLocationAddressTypeStreetSuffix LLDPLocationAddressType = 18
LLDPLocationAddressTypeHouseNum LLDPLocationAddressType = 19
LLDPLocationAddressTypeHouseSuffix LLDPLocationAddressType = 20
LLDPLocationAddressTypeLandmark LLDPLocationAddressType = 21
LLDPLocationAddressTypeAdditional LLDPLocationAddressType = 22
LLDPLocationAddressTypeName LLDPLocationAddressType = 23
LLDPLocationAddressTypePostal LLDPLocationAddressType = 24
LLDPLocationAddressTypeBuilding LLDPLocationAddressType = 25
LLDPLocationAddressTypeUnit LLDPLocationAddressType = 26
LLDPLocationAddressTypeFloor LLDPLocationAddressType = 27
LLDPLocationAddressTypeRoom LLDPLocationAddressType = 28
LLDPLocationAddressTypePlace LLDPLocationAddressType = 29
LLDPLocationAddressTypeScript LLDPLocationAddressType = 128
)
type LLDPLocationCoordinate struct {
LatitudeResolution uint8
Latitude uint64
LongitudeResolution uint8
Longitude uint64
AltitudeType uint8
AltitudeResolution uint16
Altitude uint32
Datum uint8
}
type LLDPLocationAddressLine struct {
Type LLDPLocationAddressType
Value string
}
type LLDPLocationAddress struct {
What LLDPLocationAddressWhat
CountryCode string
AddressLines []LLDPLocationAddressLine
}
type LLDPLocationECS struct {
ELIN string
}
// LLDP represents a physical location.
// Only one of the embedded types will contain values, depending on Format.
type LLDPLocation struct {
Format LLDPLocationFormat
Coordinate LLDPLocationCoordinate
Address LLDPLocationAddress
ECS LLDPLocationECS
}
type LLDPPowerViaMDI struct {
Type LLDPPowerType
Source LLDPPowerSource
Priority LLDPPowerPriority
Value uint16
}
// LLDPInfoMedia represents the information carried in TR-41 Org-specific TLVs
type LLDPInfoMedia struct {
MediaCapabilities LLDPMediaCapabilities
NetworkPolicy LLDPNetworkPolicy
Location LLDPLocation
PowerViaMDI LLDPPowerViaMDI
HardwareRevision string
FirmwareRevision string
SoftwareRevision string
SerialNumber string
Manufacturer string
Model string
AssetID string
}
type LLDPCisco2Subtype uint8
// Cisco2 TLV Subtypes
const (
LLDPCisco2PowerViaMDI LLDPCisco2Subtype = 1
)
const (
LLDPCiscoPSESupport uint8 = 1 << 0
LLDPCiscoArchShared uint8 = 1 << 1
LLDPCiscoPDSparePair uint8 = 1 << 2
LLDPCiscoPSESparePair uint8 = 1 << 3
)
// LLDPInfoCisco2 represents the information carried in Cisco Org-specific TLVs
type LLDPInfoCisco2 struct {
PSEFourWirePoESupported bool
PDSparePairArchitectureShared bool
PDRequestSparePairPoEOn bool
PSESparePairPoEOn bool
}
// Profinet Subtypes
type LLDPProfinetSubtype uint8
const (
LLDPProfinetPNIODelay LLDPProfinetSubtype = 1
LLDPProfinetPNIOPortStatus LLDPProfinetSubtype = 2
LLDPProfinetPNIOMRPPortStatus LLDPProfinetSubtype = 4
LLDPProfinetPNIOChassisMAC LLDPProfinetSubtype = 5
LLDPProfinetPNIOPTCPStatus LLDPProfinetSubtype = 6
)
type LLDPPNIODelay struct {
RXLocal uint32
RXRemote uint32
TXLocal uint32
TXRemote uint32
CableLocal uint32
}
type LLDPPNIOPortStatus struct {
Class2 uint16
Class3 uint16
}
type LLDPPNIOMRPPortStatus struct {
UUID []byte
Status uint16
}
type LLDPPNIOPTCPStatus struct {
MasterAddress []byte
SubdomainUUID []byte
IRDataUUID []byte
PeriodValid bool
PeriodLength uint32
RedPeriodValid bool
RedPeriodBegin uint32
OrangePeriodValid bool
OrangePeriodBegin uint32
GreenPeriodValid bool
GreenPeriodBegin uint32
}
// LLDPInfoProfinet represents the information carried in Profinet Org-specific TLVs
type LLDPInfoProfinet struct {
PNIODelay LLDPPNIODelay
PNIOPortStatus LLDPPNIOPortStatus
PNIOMRPPortStatus LLDPPNIOMRPPortStatus
ChassisMAC []byte
PNIOPTCPStatus LLDPPNIOPTCPStatus
}
// LayerType returns gopacket.LayerTypeLinkLayerDiscovery.
func (c *LinkLayerDiscovery) LayerType() gopacket.LayerType {
return LayerTypeLinkLayerDiscovery
}
// SerializeTo serializes LLDP packet to bytes and writes on SerializeBuffer.
func (c *LinkLayerDiscovery) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
chassIDLen := c.ChassisID.serializedLen()
portIDLen := c.PortID.serializedLen()
vb, err := b.AppendBytes(chassIDLen + portIDLen + 4) // +4 for TTL
if err != nil {
return err
}
copy(vb[:chassIDLen], c.ChassisID.serialize())
copy(vb[chassIDLen:], c.PortID.serialize())
ttlIDLen := uint16(LLDPTLVTTL)<<9 | uint16(2)
binary.BigEndian.PutUint16(vb[chassIDLen+portIDLen:], ttlIDLen)
binary.BigEndian.PutUint16(vb[chassIDLen+portIDLen+2:], c.TTL)
for _, v := range c.Values {
vb, err := b.AppendBytes(int(v.Length) + 2) // +2 for TLV type and length; 1 byte for subtype is included in v.Value
if err != nil {
return err
}
idLen := ((uint16(v.Type) << 9) | v.Length)
binary.BigEndian.PutUint16(vb[0:2], idLen)
copy(vb[2:], v.Value)
}
vb, err = b.AppendBytes(2) // End Tlv, 2 bytes
if err != nil {
return err
}
binary.BigEndian.PutUint16(vb[len(vb)-2:], uint16(0)) //End tlv, 2 bytes, all zero
return nil
}
func decodeLinkLayerDiscovery(data []byte, p gopacket.PacketBuilder) error {
var vals []LinkLayerDiscoveryValue
vData := data[0:]
for len(vData) > 0 {
if len(vData) < 2 {
p.SetTruncated()
return errors.New("LLDP vdata < 2 bytes")
}
nbit := vData[0] & 0x01
t := LLDPTLVType(vData[0] >> 1)
val := LinkLayerDiscoveryValue{Type: t, Length: uint16(nbit)<<8 + uint16(vData[1])}
if val.Length > 0 {
if len(vData) < int(val.Length+2) {
p.SetTruncated()
return fmt.Errorf("LLDP VData < %d bytes", val.Length+2)
}
val.Value = vData[2 : val.Length+2]
}
vals = append(vals, val)
if t == LLDPTLVEnd {
break
}
if len(vData) < int(2+val.Length) {
return errors.New("Malformed LinkLayerDiscovery Header")
}
vData = vData[2+val.Length:]
}
if len(vals) < 4 {
return errors.New("Missing mandatory LinkLayerDiscovery TLV")
}
c := &LinkLayerDiscovery{}
gotEnd := false
for _, v := range vals {
switch v.Type {
case LLDPTLVEnd:
gotEnd = true
case LLDPTLVChassisID:
if len(v.Value) < 2 {
return errors.New("Malformed LinkLayerDiscovery ChassisID TLV")
}
c.ChassisID.Subtype = LLDPChassisIDSubType(v.Value[0])
c.ChassisID.ID = v.Value[1:]
case LLDPTLVPortID:
if len(v.Value) < 2 {
return errors.New("Malformed LinkLayerDiscovery PortID TLV")
}
c.PortID.Subtype = LLDPPortIDSubType(v.Value[0])
c.PortID.ID = v.Value[1:]
case LLDPTLVTTL:
if len(v.Value) < 2 {
return errors.New("Malformed LinkLayerDiscovery TTL TLV")
}
c.TTL = binary.BigEndian.Uint16(v.Value[0:2])
default:
c.Values = append(c.Values, v)
}
}
if c.ChassisID.Subtype == 0 || c.PortID.Subtype == 0 || !gotEnd {
return errors.New("Missing mandatory LinkLayerDiscovery TLV")
}
c.Contents = data
p.AddLayer(c)
info := &LinkLayerDiscoveryInfo{}
p.AddLayer(info)
for _, v := range c.Values {
switch v.Type {
case LLDPTLVPortDescription:
info.PortDescription = string(v.Value)
case LLDPTLVSysName:
info.SysName = string(v.Value)
case LLDPTLVSysDescription:
info.SysDescription = string(v.Value)
case LLDPTLVSysCapabilities:
if err := checkLLDPTLVLen(v, 4); err != nil {
return err
}
info.SysCapabilities.SystemCap = getCapabilities(binary.BigEndian.Uint16(v.Value[0:2]))
info.SysCapabilities.EnabledCap = getCapabilities(binary.BigEndian.Uint16(v.Value[2:4]))
case LLDPTLVMgmtAddress:
if err := checkLLDPTLVLen(v, 9); err != nil {
return err
}
mlen := v.Value[0]
if err := checkLLDPTLVLen(v, int(mlen+7)); err != nil {
return err
}
info.MgmtAddress.Subtype = IANAAddressFamily(v.Value[1])
info.MgmtAddress.Address = v.Value[2 : mlen+1]
info.MgmtAddress.InterfaceSubtype = LLDPInterfaceSubtype(v.Value[mlen+1])
info.MgmtAddress.InterfaceNumber = binary.BigEndian.Uint32(v.Value[mlen+2 : mlen+6])
olen := v.Value[mlen+6]
if err := checkLLDPTLVLen(v, int(mlen+7+olen)); err != nil {
return err
}
info.MgmtAddress.OID = string(v.Value[mlen+7 : mlen+7+olen])
case LLDPTLVOrgSpecific:
if err := checkLLDPTLVLen(v, 4); err != nil {
return err
}
info.OrgTLVs = append(info.OrgTLVs, LLDPOrgSpecificTLV{IEEEOUI(binary.BigEndian.Uint32(append([]byte{byte(0)}, v.Value[0:3]...))), uint8(v.Value[3]), v.Value[4:]})
}
}
return nil
}
func (l *LinkLayerDiscoveryInfo) Decode8021() (info LLDPInfo8021, err error) {
for _, o := range l.OrgTLVs {
if o.OUI != IEEEOUI8021 {
continue
}
switch o.SubType {
case LLDP8021SubtypePortVLANID:
if err = checkLLDPOrgSpecificLen(o, 2); err != nil {
return
}
info.PVID = binary.BigEndian.Uint16(o.Info[0:2])
case LLDP8021SubtypeProtocolVLANID:
if err = checkLLDPOrgSpecificLen(o, 3); err != nil {
return
}
sup := (o.Info[0]&LLDPProtocolVLANIDCapability > 0)
en := (o.Info[0]&LLDPProtocolVLANIDStatus > 0)
id := binary.BigEndian.Uint16(o.Info[1:3])
info.PPVIDs = append(info.PPVIDs, PortProtocolVLANID{sup, en, id})
case LLDP8021SubtypeVLANName:
if err = checkLLDPOrgSpecificLen(o, 2); err != nil {
return
}
id := binary.BigEndian.Uint16(o.Info[0:2])
info.VLANNames = append(info.VLANNames, VLANName{id, string(o.Info[3:])})
case LLDP8021SubtypeProtocolIdentity:
if err = checkLLDPOrgSpecificLen(o, 1); err != nil {
return
}
l := int(o.Info[0])
if l > 0 {
info.ProtocolIdentities = append(info.ProtocolIdentities, o.Info[1:1+l])
}
case LLDP8021SubtypeVDIUsageDigest:
if err = checkLLDPOrgSpecificLen(o, 4); err != nil {
return
}
info.VIDUsageDigest = binary.BigEndian.Uint32(o.Info[0:4])
case LLDP8021SubtypeManagementVID:
if err = checkLLDPOrgSpecificLen(o, 2); err != nil {
return
}
info.ManagementVID = binary.BigEndian.Uint16(o.Info[0:2])
case LLDP8021SubtypeLinkAggregation:
if err = checkLLDPOrgSpecificLen(o, 5); err != nil {
return
}
sup := (o.Info[0]&LLDPAggregationCapability > 0)
en := (o.Info[0]&LLDPAggregationStatus > 0)
info.LinkAggregation = LLDPLinkAggregation{sup, en, binary.BigEndian.Uint32(o.Info[1:5])}
}
}
return
}
func (l *LinkLayerDiscoveryInfo) Decode8023() (info LLDPInfo8023, err error) {
for _, o := range l.OrgTLVs {
if o.OUI != IEEEOUI8023 {
continue
}
switch o.SubType {
case LLDP8023SubtypeMACPHY:
if err = checkLLDPOrgSpecificLen(o, 5); err != nil {
return
}
sup := (o.Info[0]&LLDPMACPHYCapability > 0)
en := (o.Info[0]&LLDPMACPHYStatus > 0)
ca := binary.BigEndian.Uint16(o.Info[1:3])
mau := binary.BigEndian.Uint16(o.Info[3:5])
info.MACPHYConfigStatus = LLDPMACPHYConfigStatus{sup, en, ca, mau}
case LLDP8023SubtypeMDIPower:
if err = checkLLDPOrgSpecificLen(o, 3); err != nil {
return
}
info.PowerViaMDI.PortClassPSE = (o.Info[0]&LLDPMDIPowerPortClass > 0)
info.PowerViaMDI.PSESupported = (o.Info[0]&LLDPMDIPowerCapability > 0)
info.PowerViaMDI.PSEEnabled = (o.Info[0]&LLDPMDIPowerStatus > 0)
info.PowerViaMDI.PSEPairsAbility = (o.Info[0]&LLDPMDIPowerPairsAbility > 0)
info.PowerViaMDI.PSEPowerPair = uint8(o.Info[1])
info.PowerViaMDI.PSEClass = uint8(o.Info[2])
if len(o.Info) >= 7 {
info.PowerViaMDI.Type = LLDPPowerType((o.Info[3] & 0xc0) >> 6)
info.PowerViaMDI.Source = LLDPPowerSource((o.Info[3] & 0x30) >> 4)
if info.PowerViaMDI.Type == 1 || info.PowerViaMDI.Type == 3 {
info.PowerViaMDI.Source += 128 // For Stringify purposes
}
info.PowerViaMDI.Priority = LLDPPowerPriority(o.Info[3] & 0x0f)
info.PowerViaMDI.Requested = binary.BigEndian.Uint16(o.Info[4:6])
info.PowerViaMDI.Allocated = binary.BigEndian.Uint16(o.Info[6:8])
}
case LLDP8023SubtypeLinkAggregation:
if err = checkLLDPOrgSpecificLen(o, 5); err != nil {
return
}
sup := (o.Info[0]&LLDPAggregationCapability > 0)
en := (o.Info[0]&LLDPAggregationStatus > 0)
info.LinkAggregation = LLDPLinkAggregation{sup, en, binary.BigEndian.Uint32(o.Info[1:5])}
case LLDP8023SubtypeMTU:
if err = checkLLDPOrgSpecificLen(o, 2); err != nil {
return
}
info.MTU = binary.BigEndian.Uint16(o.Info[0:2])
}
}
return
}
func (l *LinkLayerDiscoveryInfo) Decode8021Qbg() (info LLDPInfo8021Qbg, err error) {
for _, o := range l.OrgTLVs {
if o.OUI != IEEEOUI8021Qbg {
continue
}
switch o.SubType {
case LLDP8021QbgEVB:
if err = checkLLDPOrgSpecificLen(o, 9); err != nil {
return
}
info.EVBSettings.Supported = getEVBCapabilities(binary.BigEndian.Uint16(o.Info[0:2]))
info.EVBSettings.Enabled = getEVBCapabilities(binary.BigEndian.Uint16(o.Info[2:4]))
info.EVBSettings.SupportedVSIs = binary.BigEndian.Uint16(o.Info[4:6])
info.EVBSettings.ConfiguredVSIs = binary.BigEndian.Uint16(o.Info[6:8])
info.EVBSettings.RTEExponent = uint8(o.Info[8])
}
}
return
}
func (l *LinkLayerDiscoveryInfo) DecodeMedia() (info LLDPInfoMedia, err error) {
for _, o := range l.OrgTLVs {
if o.OUI != IEEEOUIMedia {
continue
}
switch LLDPMediaSubtype(o.SubType) {
case LLDPMediaTypeCapabilities:
if err = checkLLDPOrgSpecificLen(o, 3); err != nil {
return
}
b := binary.BigEndian.Uint16(o.Info[0:2])
info.MediaCapabilities.Capabilities = (b & LLDPMediaCapsLLDP) > 0
info.MediaCapabilities.NetworkPolicy = (b & LLDPMediaCapsNetwork) > 0
info.MediaCapabilities.Location = (b & LLDPMediaCapsLocation) > 0
info.MediaCapabilities.PowerPSE = (b & LLDPMediaCapsPowerPSE) > 0
info.MediaCapabilities.PowerPD = (b & LLDPMediaCapsPowerPD) > 0
info.MediaCapabilities.Inventory = (b & LLDPMediaCapsInventory) > 0
info.MediaCapabilities.Class = LLDPMediaClass(o.Info[2])
case LLDPMediaTypeNetwork:
if err = checkLLDPOrgSpecificLen(o, 4); err != nil {
return
}
info.NetworkPolicy.ApplicationType = LLDPApplicationType(o.Info[0])
b := binary.BigEndian.Uint16(o.Info[1:3])
info.NetworkPolicy.Defined = (b & 0x8000) == 0
info.NetworkPolicy.Tagged = (b & 0x4000) > 0
info.NetworkPolicy.VLANId = (b & 0x1ffe) >> 1
b = binary.BigEndian.Uint16(o.Info[2:4])
info.NetworkPolicy.L2Priority = (b & 0x01c0) >> 6
info.NetworkPolicy.DSCPValue = uint8(o.Info[3] & 0x3f)
case LLDPMediaTypeLocation:
if err = checkLLDPOrgSpecificLen(o, 1); err != nil {
return
}
info.Location.Format = LLDPLocationFormat(o.Info[0])
o.Info = o.Info[1:]
switch info.Location.Format {
case LLDPLocationFormatCoordinate:
if err = checkLLDPOrgSpecificLen(o, 16); err != nil {
return
}
info.Location.Coordinate.LatitudeResolution = uint8(o.Info[0]&0xfc) >> 2
b := binary.BigEndian.Uint64(o.Info[0:8])
info.Location.Coordinate.Latitude = (b & 0x03ffffffff000000) >> 24
info.Location.Coordinate.LongitudeResolution = uint8(o.Info[5]&0xfc) >> 2
b = binary.BigEndian.Uint64(o.Info[5:13])
info.Location.Coordinate.Longitude = (b & 0x03ffffffff000000) >> 24
info.Location.Coordinate.AltitudeType = uint8((o.Info[10] & 0x30) >> 4)
b1 := binary.BigEndian.Uint16(o.Info[10:12])
info.Location.Coordinate.AltitudeResolution = (b1 & 0xfc0) >> 6
b2 := binary.BigEndian.Uint32(o.Info[11:15])
info.Location.Coordinate.Altitude = b2 & 0x3fffffff
info.Location.Coordinate.Datum = uint8(o.Info[15])
case LLDPLocationFormatAddress:
if err = checkLLDPOrgSpecificLen(o, 3); err != nil {
return
}
//ll := uint8(o.Info[0])
info.Location.Address.What = LLDPLocationAddressWhat(o.Info[1])
info.Location.Address.CountryCode = string(o.Info[2:4])
data := o.Info[4:]
for len(data) > 1 {
aType := LLDPLocationAddressType(data[0])
aLen := int(data[1])
if len(data) >= aLen+2 {
info.Location.Address.AddressLines = append(info.Location.Address.AddressLines, LLDPLocationAddressLine{aType, string(data[2 : aLen+2])})
data = data[aLen+2:]
} else {
break
}
}
case LLDPLocationFormatECS:
info.Location.ECS.ELIN = string(o.Info)
}
case LLDPMediaTypePower:
if err = checkLLDPOrgSpecificLen(o, 3); err != nil {
return
}
info.PowerViaMDI.Type = LLDPPowerType((o.Info[0] & 0xc0) >> 6)
info.PowerViaMDI.Source = LLDPPowerSource((o.Info[0] & 0x30) >> 4)
if info.PowerViaMDI.Type == 1 || info.PowerViaMDI.Type == 3 {
info.PowerViaMDI.Source += 128 // For Stringify purposes
}
info.PowerViaMDI.Priority = LLDPPowerPriority(o.Info[0] & 0x0f)
info.PowerViaMDI.Value = binary.BigEndian.Uint16(o.Info[1:3]) * 100 // 0 to 102.3 w, 0.1W increments
case LLDPMediaTypeHardware:
info.HardwareRevision = string(o.Info)
case LLDPMediaTypeFirmware:
info.FirmwareRevision = string(o.Info)
case LLDPMediaTypeSoftware:
info.SoftwareRevision = string(o.Info)
case LLDPMediaTypeSerial:
info.SerialNumber = string(o.Info)
case LLDPMediaTypeManufacturer:
info.Manufacturer = string(o.Info)
case LLDPMediaTypeModel:
info.Model = string(o.Info)
case LLDPMediaTypeAssetID:
info.AssetID = string(o.Info)
}
}
return
}
func (l *LinkLayerDiscoveryInfo) DecodeCisco2() (info LLDPInfoCisco2, err error) {
for _, o := range l.OrgTLVs {
if o.OUI != IEEEOUICisco2 {
continue
}
switch LLDPCisco2Subtype(o.SubType) {
case LLDPCisco2PowerViaMDI:
if err = checkLLDPOrgSpecificLen(o, 1); err != nil {
return
}
info.PSEFourWirePoESupported = (o.Info[0] & LLDPCiscoPSESupport) > 0
info.PDSparePairArchitectureShared = (o.Info[0] & LLDPCiscoArchShared) > 0
info.PDRequestSparePairPoEOn = (o.Info[0] & LLDPCiscoPDSparePair) > 0
info.PSESparePairPoEOn = (o.Info[0] & LLDPCiscoPSESparePair) > 0
}
}
return
}
func (l *LinkLayerDiscoveryInfo) DecodeProfinet() (info LLDPInfoProfinet, err error) {
for _, o := range l.OrgTLVs {
if o.OUI != IEEEOUIProfinet {
continue
}
switch LLDPProfinetSubtype(o.SubType) {
case LLDPProfinetPNIODelay:
if err = checkLLDPOrgSpecificLen(o, 20); err != nil {
return
}
info.PNIODelay.RXLocal = binary.BigEndian.Uint32(o.Info[0:4])
info.PNIODelay.RXRemote = binary.BigEndian.Uint32(o.Info[4:8])
info.PNIODelay.TXLocal = binary.BigEndian.Uint32(o.Info[8:12])
info.PNIODelay.TXRemote = binary.BigEndian.Uint32(o.Info[12:16])
info.PNIODelay.CableLocal = binary.BigEndian.Uint32(o.Info[16:20])
case LLDPProfinetPNIOPortStatus:
if err = checkLLDPOrgSpecificLen(o, 4); err != nil {
return
}
info.PNIOPortStatus.Class2 = binary.BigEndian.Uint16(o.Info[0:2])
info.PNIOPortStatus.Class3 = binary.BigEndian.Uint16(o.Info[2:4])
case LLDPProfinetPNIOMRPPortStatus:
if err = checkLLDPOrgSpecificLen(o, 18); err != nil {
return
}
info.PNIOMRPPortStatus.UUID = o.Info[0:16]
info.PNIOMRPPortStatus.Status = binary.BigEndian.Uint16(o.Info[16:18])
case LLDPProfinetPNIOChassisMAC:
if err = checkLLDPOrgSpecificLen(o, 6); err != nil {
return
}
info.ChassisMAC = o.Info[0:6]
case LLDPProfinetPNIOPTCPStatus:
if err = checkLLDPOrgSpecificLen(o, 54); err != nil {
return
}
info.PNIOPTCPStatus.MasterAddress = o.Info[0:6]
info.PNIOPTCPStatus.SubdomainUUID = o.Info[6:22]
info.PNIOPTCPStatus.IRDataUUID = o.Info[22:38]
b := binary.BigEndian.Uint32(o.Info[38:42])
info.PNIOPTCPStatus.PeriodValid = (b & 0x80000000) > 0
info.PNIOPTCPStatus.PeriodLength = b & 0x7fffffff
b = binary.BigEndian.Uint32(o.Info[42:46])
info.PNIOPTCPStatus.RedPeriodValid = (b & 0x80000000) > 0
info.PNIOPTCPStatus.RedPeriodBegin = b & 0x7fffffff
b = binary.BigEndian.Uint32(o.Info[46:50])
info.PNIOPTCPStatus.OrangePeriodValid = (b & 0x80000000) > 0
info.PNIOPTCPStatus.OrangePeriodBegin = b & 0x7fffffff
b = binary.BigEndian.Uint32(o.Info[50:54])
info.PNIOPTCPStatus.GreenPeriodValid = (b & 0x80000000) > 0
info.PNIOPTCPStatus.GreenPeriodBegin = b & 0x7fffffff
}
}
return
}
// LayerType returns gopacket.LayerTypeLinkLayerDiscoveryInfo.
func (c *LinkLayerDiscoveryInfo) LayerType() gopacket.LayerType {
return LayerTypeLinkLayerDiscoveryInfo
}
func getCapabilities(v uint16) (c LLDPCapabilities) {
c.Other = (v&LLDPCapsOther > 0)
c.Repeater = (v&LLDPCapsRepeater > 0)
c.Bridge = (v&LLDPCapsBridge > 0)
c.WLANAP = (v&LLDPCapsWLANAP > 0)
c.Router = (v&LLDPCapsRouter > 0)
c.Phone = (v&LLDPCapsPhone > 0)
c.DocSis = (v&LLDPCapsDocSis > 0)
c.StationOnly = (v&LLDPCapsStationOnly > 0)
c.CVLAN = (v&LLDPCapsCVLAN > 0)
c.SVLAN = (v&LLDPCapsSVLAN > 0)
c.TMPR = (v&LLDPCapsTmpr > 0)
return
}
func getEVBCapabilities(v uint16) (c LLDPEVBCapabilities) {
c.StandardBridging = (v & LLDPEVBCapsSTD) > 0
c.StandardBridging = (v & LLDPEVBCapsSTD) > 0
c.ReflectiveRelay = (v & LLDPEVBCapsRR) > 0
c.RetransmissionTimerExponent = (v & LLDPEVBCapsRTE) > 0
c.EdgeControlProtocol = (v & LLDPEVBCapsECP) > 0
c.VSIDiscoveryProtocol = (v & LLDPEVBCapsVDP) > 0
return
}
func (t LLDPTLVType) String() (s string) {
switch t {
case LLDPTLVEnd:
s = "TLV End"
case LLDPTLVChassisID:
s = "Chassis ID"
case LLDPTLVPortID:
s = "Port ID"
case LLDPTLVTTL:
s = "TTL"
case LLDPTLVPortDescription:
s = "Port Description"
case LLDPTLVSysName:
s = "System Name"
case LLDPTLVSysDescription:
s = "System Description"
case LLDPTLVSysCapabilities:
s = "System Capabilities"
case LLDPTLVMgmtAddress:
s = "Management Address"
case LLDPTLVOrgSpecific:
s = "Organisation Specific"
default:
s = "Unknown"
}
return
}
func (t LLDPChassisIDSubType) String() (s string) {
switch t {
case LLDPChassisIDSubTypeReserved:
s = "Reserved"
case LLDPChassisIDSubTypeChassisComp:
s = "Chassis Component"
case LLDPChassisIDSubtypeIfaceAlias:
s = "Interface Alias"
case LLDPChassisIDSubTypePortComp:
s = "Port Component"
case LLDPChassisIDSubTypeMACAddr:
s = "MAC Address"
case LLDPChassisIDSubTypeNetworkAddr:
s = "Network Address"
case LLDPChassisIDSubtypeIfaceName:
s = "Interface Name"
case LLDPChassisIDSubTypeLocal:
s = "Local"
default:
s = "Unknown"
}
return
}
func (t LLDPPortIDSubType) String() (s string) {
switch t {
case LLDPPortIDSubtypeReserved:
s = "Reserved"
case LLDPPortIDSubtypeIfaceAlias:
s = "Interface Alias"
case LLDPPortIDSubtypePortComp:
s = "Port Component"
case LLDPPortIDSubtypeMACAddr:
s = "MAC Address"
case LLDPPortIDSubtypeNetworkAddr:
s = "Network Address"
case LLDPPortIDSubtypeIfaceName:
s = "Interface Name"
case LLDPPortIDSubtypeAgentCircuitID:
s = "Agent Circuit ID"
case LLDPPortIDSubtypeLocal:
s = "Local"
default:
s = "Unknown"
}
return
}
func (t IANAAddressFamily) String() (s string) {
switch t {
case IANAAddressFamilyReserved:
s = "Reserved"
case IANAAddressFamilyIPV4:
s = "IPv4"
case IANAAddressFamilyIPV6:
s = "IPv6"
case IANAAddressFamilyNSAP:
s = "NSAP"
case IANAAddressFamilyHDLC:
s = "HDLC"
case IANAAddressFamilyBBN1822:
s = "BBN 1822"
case IANAAddressFamily802:
s = "802 media plus Ethernet 'canonical format'"
case IANAAddressFamilyE163:
s = "E.163"
case IANAAddressFamilyE164:
s = "E.164 (SMDS, Frame Relay, ATM)"
case IANAAddressFamilyF69:
s = "F.69 (Telex)"
case IANAAddressFamilyX121:
s = "X.121, X.25, Frame Relay"
case IANAAddressFamilyIPX:
s = "IPX"
case IANAAddressFamilyAtalk:
s = "Appletalk"
case IANAAddressFamilyDecnet:
s = "Decnet IV"
case IANAAddressFamilyBanyan:
s = "Banyan Vines"
case IANAAddressFamilyE164NSAP:
s = "E.164 with NSAP format subaddress"
case IANAAddressFamilyDNS:
s = "DNS"
case IANAAddressFamilyDistname:
s = "Distinguished Name"
case IANAAddressFamilyASNumber:
s = "AS Number"
case IANAAddressFamilyXTPIPV4:
s = "XTP over IP version 4"
case IANAAddressFamilyXTPIPV6:
s = "XTP over IP version 6"
case IANAAddressFamilyXTP:
s = "XTP native mode XTP"
case IANAAddressFamilyFcWWPN:
s = "Fibre Channel World-Wide Port Name"
case IANAAddressFamilyFcWWNN:
s = "Fibre Channel World-Wide Node Name"
case IANAAddressFamilyGWID:
s = "GWID"
case IANAAddressFamilyL2VPN:
s = "AFI for Layer 2 VPN"
default:
s = "Unknown"
}
return
}
func (t LLDPInterfaceSubtype) String() (s string) {
switch t {
case LLDPInterfaceSubtypeUnknown:
s = "Unknown"
case LLDPInterfaceSubtypeifIndex:
s = "IfIndex"
case LLDPInterfaceSubtypeSysPort:
s = "System Port Number"
default:
s = "Unknown"
}
return
}
func (t LLDPPowerType) String() (s string) {
switch t {
case 0:
s = "Type 2 PSE Device"
case 1:
s = "Type 2 PD Device"
case 2:
s = "Type 1 PSE Device"
case 3:
s = "Type 1 PD Device"
default:
s = "Unknown"
}
return
}
func (t LLDPPowerSource) String() (s string) {
switch t {
// PD Device
case 0:
s = "Unknown"
case 1:
s = "PSE"
case 2:
s = "Local"
case 3:
s = "PSE and Local"
// PSE Device (Actual value + 128)
case 128:
s = "Unknown"
case 129:
s = "Primary Power Source"
case 130:
s = "Backup Power Source"
default:
s = "Unknown"
}
return
}
func (t LLDPPowerPriority) String() (s string) {
switch t {
case 0:
s = "Unknown"
case 1:
s = "Critical"
case 2:
s = "High"
case 3:
s = "Low"
default:
s = "Unknown"
}
return
}
func (t LLDPMediaSubtype) String() (s string) {
switch t {
case LLDPMediaTypeCapabilities:
s = "Media Capabilities "
case LLDPMediaTypeNetwork:
s = "Network Policy"
case LLDPMediaTypeLocation:
s = "Location Identification"
case LLDPMediaTypePower:
s = "Extended Power-via-MDI"
case LLDPMediaTypeHardware:
s = "Hardware Revision"
case LLDPMediaTypeFirmware:
s = "Firmware Revision"
case LLDPMediaTypeSoftware:
s = "Software Revision"
case LLDPMediaTypeSerial:
s = "Serial Number"
case LLDPMediaTypeManufacturer:
s = "Manufacturer"
case LLDPMediaTypeModel:
s = "Model"
case LLDPMediaTypeAssetID:
s = "Asset ID"
default:
s = "Unknown"
}
return
}
func (t LLDPMediaClass) String() (s string) {
switch t {
case LLDPMediaClassUndefined:
s = "Undefined"
case LLDPMediaClassEndpointI:
s = "Endpoint Class I"
case LLDPMediaClassEndpointII:
s = "Endpoint Class II"
case LLDPMediaClassEndpointIII:
s = "Endpoint Class III"
case LLDPMediaClassNetwork:
s = "Network connectivity "
default:
s = "Unknown"
}
return
}
func (t LLDPApplicationType) String() (s string) {
switch t {
case LLDPAppTypeReserved:
s = "Reserved"
case LLDPAppTypeVoice:
s = "Voice"
case LLDPappTypeVoiceSignaling:
s = "Voice Signaling"
case LLDPappTypeGuestVoice:
s = "Guest Voice"
case LLDPappTypeGuestVoiceSignaling:
s = "Guest Voice Signaling"
case LLDPappTypeSoftphoneVoice:
s = "Softphone Voice"
case LLDPappTypeVideoConferencing:
s = "Video Conferencing"
case LLDPappTypeStreamingVideo:
s = "Streaming Video"
case LLDPappTypeVideoSignaling:
s = "Video Signaling"
default:
s = "Unknown"
}
return
}
func (t LLDPLocationFormat) String() (s string) {
switch t {
case LLDPLocationFormatInvalid:
s = "Invalid"
case LLDPLocationFormatCoordinate:
s = "Coordinate-based LCI"
case LLDPLocationFormatAddress:
s = "Address-based LCO"
case LLDPLocationFormatECS:
s = "ECS ELIN"
default:
s = "Unknown"
}
return
}
func (t LLDPLocationAddressType) String() (s string) {
switch t {
case LLDPLocationAddressTypeLanguage:
s = "Language"
case LLDPLocationAddressTypeNational:
s = "National subdivisions (province, state, etc)"
case LLDPLocationAddressTypeCounty:
s = "County, parish, district"
case LLDPLocationAddressTypeCity:
s = "City, township"
case LLDPLocationAddressTypeCityDivision:
s = "City division, borough, ward"
case LLDPLocationAddressTypeNeighborhood:
s = "Neighborhood, block"
case LLDPLocationAddressTypeStreet:
s = "Street"
case LLDPLocationAddressTypeLeadingStreet:
s = "Leading street direction"
case LLDPLocationAddressTypeTrailingStreet:
s = "Trailing street suffix"
case LLDPLocationAddressTypeStreetSuffix:
s = "Street suffix"
case LLDPLocationAddressTypeHouseNum:
s = "House number"
case LLDPLocationAddressTypeHouseSuffix:
s = "House number suffix"
case LLDPLocationAddressTypeLandmark:
s = "Landmark or vanity address"
case LLDPLocationAddressTypeAdditional:
s = "Additional location information"
case LLDPLocationAddressTypeName:
s = "Name"
case LLDPLocationAddressTypePostal:
s = "Postal/ZIP code"
case LLDPLocationAddressTypeBuilding:
s = "Building"
case LLDPLocationAddressTypeUnit:
s = "Unit"
case LLDPLocationAddressTypeFloor:
s = "Floor"
case LLDPLocationAddressTypeRoom:
s = "Room number"
case LLDPLocationAddressTypePlace:
s = "Place type"
case LLDPLocationAddressTypeScript:
s = "Script"
default:
s = "Unknown"
}
return
}
func checkLLDPTLVLen(v LinkLayerDiscoveryValue, l int) (err error) {
if len(v.Value) < l {
err = fmt.Errorf("Invalid TLV %v length %d (wanted mimimum %v", v.Type, len(v.Value), l)
}
return
}
func checkLLDPOrgSpecificLen(o LLDPOrgSpecificTLV, l int) (err error) {
if len(o.Info) < l {
err = fmt.Errorf("Invalid Org Specific TLV %v length %d (wanted minimum %v)", o.SubType, len(o.Info), l)
}
return
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"github.com/google/gopacket"
)
// Loopback contains the header for loopback encapsulation. This header is
// used by both BSD and OpenBSD style loopback decoding (pcap's DLT_NULL
// and DLT_LOOP, respectively).
type Loopback struct {
BaseLayer
Family ProtocolFamily
}
// LayerType returns LayerTypeLoopback.
func (l *Loopback) LayerType() gopacket.LayerType { return LayerTypeLoopback }
// DecodeFromBytes decodes the given bytes into this layer.
func (l *Loopback) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 4 {
return errors.New("Loopback packet too small")
}
// The protocol could be either big-endian or little-endian, we're
// not sure. But we're PRETTY sure that the value is less than
// 256, so we can check the first two bytes.
var prot uint32
if data[0] == 0 && data[1] == 0 {
prot = binary.BigEndian.Uint32(data[:4])
} else {
prot = binary.LittleEndian.Uint32(data[:4])
}
if prot > 0xFF {
return fmt.Errorf("Invalid loopback protocol %q", data[:4])
}
l.Family = ProtocolFamily(prot)
l.BaseLayer = BaseLayer{data[:4], data[4:]}
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (l *Loopback) CanDecode() gopacket.LayerClass {
return LayerTypeLoopback
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (l *Loopback) NextLayerType() gopacket.LayerType {
return l.Family.LayerType()
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
func (l *Loopback) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
bytes, err := b.PrependBytes(4)
if err != nil {
return err
}
binary.LittleEndian.PutUint32(bytes, uint32(l.Family))
return nil
}
func decodeLoopback(data []byte, p gopacket.PacketBuilder) error {
l := Loopback{}
if err := l.DecodeFromBytes(data, gopacket.NilDecodeFeedback); err != nil {
return err
}
p.AddLayer(&l)
return p.NextDecoder(l.Family)
}
// Copyright 2018 GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"math"
"net"
"time"
"github.com/google/gopacket"
)
// MLDv1Message represents the common structure of all MLDv1 messages
type MLDv1Message struct {
BaseLayer
// 3.4. Maximum Response Delay
MaximumResponseDelay time.Duration
// 3.6. Multicast Address
// Zero in general query
// Specific IPv6 multicast address otherwise
MulticastAddress net.IP
}
// DecodeFromBytes decodes the given bytes into this layer.
func (m *MLDv1Message) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 20 {
df.SetTruncated()
return errors.New("ICMP layer less than 20 bytes for Multicast Listener Query Message V1")
}
m.MaximumResponseDelay = time.Duration(binary.BigEndian.Uint16(data[0:2])) * time.Millisecond
// data[2:4] is reserved and not used in mldv1
m.MulticastAddress = data[4:20]
return nil
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (*MLDv1Message) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypeZero
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (m *MLDv1Message) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
buf, err := b.PrependBytes(20)
if err != nil {
return err
}
if m.MaximumResponseDelay < 0 {
return errors.New("maximum response delay must not be negative")
}
dms := m.MaximumResponseDelay / time.Millisecond
if dms > math.MaxUint16 {
return fmt.Errorf("maximum response delay %dms is more than the allowed 65535ms", dms)
}
binary.BigEndian.PutUint16(buf[0:2], uint16(dms))
copy(buf[2:4], []byte{0x0, 0x0})
ma16 := m.MulticastAddress.To16()
if ma16 == nil {
return fmt.Errorf("invalid multicast address '%s'", m.MulticastAddress)
}
copy(buf[4:20], ma16)
return nil
}
// Sums this layer up nicely formatted
func (m *MLDv1Message) String() string {
return fmt.Sprintf(
"Maximum Response Delay: %dms, Multicast Address: %s",
m.MaximumResponseDelay/time.Millisecond,
m.MulticastAddress)
}
// MLDv1MulticastListenerQueryMessage are sent by the router to determine
// whether there are multicast listeners on the link.
// https://tools.ietf.org/html/rfc2710 Page 5
type MLDv1MulticastListenerQueryMessage struct {
MLDv1Message
}
// DecodeFromBytes decodes the given bytes into this layer.
func (m *MLDv1MulticastListenerQueryMessage) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
err := m.MLDv1Message.DecodeFromBytes(data, df)
if err != nil {
return err
}
if len(data) > 20 {
m.Payload = data[20:]
}
return nil
}
// LayerType returns LayerTypeMLDv1MulticastListenerQuery.
func (*MLDv1MulticastListenerQueryMessage) LayerType() gopacket.LayerType {
return LayerTypeMLDv1MulticastListenerQuery
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (*MLDv1MulticastListenerQueryMessage) CanDecode() gopacket.LayerClass {
return LayerTypeMLDv1MulticastListenerQuery
}
// IsGeneralQuery is true when this is a general query.
// In a Query message, the Multicast Address field is set to zero when
// sending a General Query.
// https://tools.ietf.org/html/rfc2710#section-3.6
func (m *MLDv1MulticastListenerQueryMessage) IsGeneralQuery() bool {
return net.IPv6zero.Equal(m.MulticastAddress)
}
// IsSpecificQuery is true when this is not a general query.
// In a Query message, the Multicast Address field is set to a specific
// IPv6 multicast address when sending a Multicast-Address-Specific Query.
// https://tools.ietf.org/html/rfc2710#section-3.6
func (m *MLDv1MulticastListenerQueryMessage) IsSpecificQuery() bool {
return !m.IsGeneralQuery()
}
// MLDv1MulticastListenerReportMessage is sent by a client listening on
// a specific multicast address to indicate that it is (still) listening
// on the specific multicast address.
// https://tools.ietf.org/html/rfc2710 Page 6
type MLDv1MulticastListenerReportMessage struct {
MLDv1Message
}
// LayerType returns LayerTypeMLDv1MulticastListenerReport.
func (*MLDv1MulticastListenerReportMessage) LayerType() gopacket.LayerType {
return LayerTypeMLDv1MulticastListenerReport
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (*MLDv1MulticastListenerReportMessage) CanDecode() gopacket.LayerClass {
return LayerTypeMLDv1MulticastListenerReport
}
// MLDv1MulticastListenerDoneMessage should be sent by a client when it ceases
// to listen to a multicast address on an interface.
// https://tools.ietf.org/html/rfc2710 Page 7
type MLDv1MulticastListenerDoneMessage struct {
MLDv1Message
}
// LayerType returns LayerTypeMLDv1MulticastListenerDone.
func (*MLDv1MulticastListenerDoneMessage) LayerType() gopacket.LayerType {
return LayerTypeMLDv1MulticastListenerDone
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (*MLDv1MulticastListenerDoneMessage) CanDecode() gopacket.LayerClass {
return LayerTypeMLDv1MulticastListenerDone
}
func decodeMLDv1MulticastListenerReport(data []byte, p gopacket.PacketBuilder) error {
m := &MLDv1MulticastListenerReportMessage{}
return decodingLayerDecoder(m, data, p)
}
func decodeMLDv1MulticastListenerQuery(data []byte, p gopacket.PacketBuilder) error {
m := &MLDv1MulticastListenerQueryMessage{}
return decodingLayerDecoder(m, data, p)
}
func decodeMLDv1MulticastListenerDone(data []byte, p gopacket.PacketBuilder) error {
m := &MLDv1MulticastListenerDoneMessage{}
return decodingLayerDecoder(m, data, p)
}
// Copyright 2018 GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"math"
"net"
"time"
"github.com/google/gopacket"
)
const (
// S Flag bit is 1
mldv2STrue uint8 = 0x8
// S Flag value mask
// mldv2STrue & mldv2SMask == mldv2STrue // true
// 0x1 & mldv2SMask == mldv2STrue // true
// 0x0 & mldv2SMask == mldv2STrue // false
mldv2SMask uint8 = 0x8
// QRV value mask
mldv2QRVMask uint8 = 0x7
)
// MLDv2MulticastListenerQueryMessage are sent by multicast routers to query the
// multicast listening state of neighboring interfaces.
// https://tools.ietf.org/html/rfc3810#section-5.1
//
// Some information, like Maximum Response Code and Multicast Address are in the
// previous layer LayerTypeMLDv1MulticastListenerQuery
type MLDv2MulticastListenerQueryMessage struct {
BaseLayer
// 5.1.3. Maximum Response Delay COde
MaximumResponseCode uint16
// 5.1.5. Multicast Address
// Zero in general query
// Specific IPv6 multicast address otherwise
MulticastAddress net.IP
// 5.1.7. S Flag (Suppress Router-Side Processing)
SuppressRoutersideProcessing bool
// 5.1.8. QRV (Querier's Robustness Variable)
QueriersRobustnessVariable uint8
// 5.1.9. QQIC (Querier's Query Interval Code)
QueriersQueryIntervalCode uint8
// 5.1.10. Number of Sources (N)
NumberOfSources uint16
// 5.1.11 Source Address [i]
SourceAddresses []net.IP
}
// DecodeFromBytes decodes the given bytes into this layer.
func (m *MLDv2MulticastListenerQueryMessage) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 24 {
df.SetTruncated()
return errors.New("ICMP layer less than 24 bytes for Multicast Listener Query Message V2")
}
m.MaximumResponseCode = binary.BigEndian.Uint16(data[0:2])
// ignore data[2:4] as per https://tools.ietf.org/html/rfc3810#section-5.1.4
m.MulticastAddress = data[4:20]
m.SuppressRoutersideProcessing = (data[20] & mldv2SMask) == mldv2STrue
m.QueriersRobustnessVariable = data[20] & mldv2QRVMask
m.QueriersQueryIntervalCode = data[21]
m.NumberOfSources = binary.BigEndian.Uint16(data[22:24])
var end int
for i := uint16(0); i < m.NumberOfSources; i++ {
begin := 24 + (int(i) * 16)
end = begin + 16
if end > len(data) {
df.SetTruncated()
return fmt.Errorf("ICMP layer less than %d bytes for Multicast Listener Query Message V2", end)
}
m.SourceAddresses = append(m.SourceAddresses, data[begin:end])
}
return nil
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (*MLDv2MulticastListenerQueryMessage) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypeZero
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (m *MLDv2MulticastListenerQueryMessage) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
if err := m.serializeSourceAddressesTo(b, opts); err != nil {
return err
}
buf, err := b.PrependBytes(24)
if err != nil {
return err
}
binary.BigEndian.PutUint16(buf[0:2], m.MaximumResponseCode)
copy(buf[2:4], []byte{0x00, 0x00}) // set reserved bytes to zero
ma16 := m.MulticastAddress.To16()
if ma16 == nil {
return fmt.Errorf("invalid MulticastAddress '%s'", m.MulticastAddress)
}
copy(buf[4:20], ma16)
byte20 := m.QueriersRobustnessVariable & mldv2QRVMask
if m.SuppressRoutersideProcessing {
byte20 |= mldv2STrue
} else {
byte20 &= ^mldv2STrue // the complement of mldv2STrue
}
byte20 &= 0x0F // set reserved bits to zero
buf[20] = byte20
binary.BigEndian.PutUint16(buf[22:24], m.NumberOfSources)
buf[21] = m.QueriersQueryIntervalCode
return nil
}
// writes each source address to the buffer preserving the order
func (m *MLDv2MulticastListenerQueryMessage) serializeSourceAddressesTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
numberOfSourceAddresses := len(m.SourceAddresses)
if numberOfSourceAddresses > math.MaxUint16 {
return fmt.Errorf(
"there are more than %d source addresses, but 65535 is the maximum number of supported addresses",
numberOfSourceAddresses)
}
if opts.FixLengths {
m.NumberOfSources = uint16(numberOfSourceAddresses)
}
lastSAIdx := numberOfSourceAddresses - 1
for k := range m.SourceAddresses {
i := lastSAIdx - k // reverse order
buf, err := b.PrependBytes(16)
if err != nil {
return err
}
sa16 := m.SourceAddresses[i].To16()
if sa16 == nil {
return fmt.Errorf("invalid source address [%d] '%s'", i, m.SourceAddresses[i])
}
copy(buf[0:16], sa16)
}
return nil
}
// String sums this layer up nicely formatted
func (m *MLDv2MulticastListenerQueryMessage) String() string {
return fmt.Sprintf(
"Maximum Response Code: %#x (%dms), Multicast Address: %s, Suppress Routerside Processing: %t, QRV: %#x, QQIC: %#x (%ds), Number of Source Address: %d (actual: %d), Source Addresses: %s",
m.MaximumResponseCode,
m.MaximumResponseDelay(),
m.MulticastAddress,
m.SuppressRoutersideProcessing,
m.QueriersRobustnessVariable,
m.QueriersQueryIntervalCode,
m.QQI()/time.Second,
m.NumberOfSources,
len(m.SourceAddresses),
m.SourceAddresses)
}
// LayerType returns LayerTypeMLDv2MulticastListenerQuery.
func (*MLDv2MulticastListenerQueryMessage) LayerType() gopacket.LayerType {
return LayerTypeMLDv2MulticastListenerQuery
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (*MLDv2MulticastListenerQueryMessage) CanDecode() gopacket.LayerClass {
return LayerTypeMLDv2MulticastListenerQuery
}
// QQI calculates the Querier's Query Interval based on the QQIC
// according to https://tools.ietf.org/html/rfc3810#section-5.1.9
func (m *MLDv2MulticastListenerQueryMessage) QQI() time.Duration {
data := m.QueriersQueryIntervalCode
if data < 128 {
return time.Second * time.Duration(data)
}
exp := uint16(data) & 0x70 >> 4
mant := uint16(data) & 0x0F
return time.Second * time.Duration(mant|0x1000<<(exp+3))
}
// SetQQI calculates and updates the Querier's Query Interval Code (QQIC)
// according to https://tools.ietf.org/html/rfc3810#section-5.1.9
func (m *MLDv2MulticastListenerQueryMessage) SetQQI(d time.Duration) error {
if d < 0 {
m.QueriersQueryIntervalCode = 0
return errors.New("QQI duration is negative")
}
if d == 0 {
m.QueriersQueryIntervalCode = 0
return nil
}
dms := d / time.Second
if dms < 128 {
m.QueriersQueryIntervalCode = uint8(dms)
}
if dms > 31744 { // mant=0xF, exp=0x7
m.QueriersQueryIntervalCode = 0xFF
return fmt.Errorf("QQI duration %ds is, maximum allowed is 31744s", dms)
}
value := uint16(dms) // ok, because 31744 < math.MaxUint16
exp := uint8(7)
for mask := uint16(0x4000); exp > 0; exp-- {
if mask&value != 0 {
break
}
mask >>= 1
}
mant := uint8(0x000F & (value >> (exp + 3)))
sig := uint8(0x10)
m.QueriersQueryIntervalCode = sig | exp<<4 | mant
return nil
}
// MaximumResponseDelay returns the Maximum Response Delay based on the
// Maximum Response Code according to
// https://tools.ietf.org/html/rfc3810#section-5.1.3
func (m *MLDv2MulticastListenerQueryMessage) MaximumResponseDelay() time.Duration {
if m.MaximumResponseCode < 0x8000 {
return time.Duration(m.MaximumResponseCode)
}
exp := m.MaximumResponseCode & 0x7000 >> 12
mant := m.MaximumResponseCode & 0x0FFF
return time.Millisecond * time.Duration(mant|0x1000<<(exp+3))
}
// SetMLDv2MaximumResponseDelay updates the Maximum Response Code according to
// https://tools.ietf.org/html/rfc3810#section-5.1.3
func (m *MLDv2MulticastListenerQueryMessage) SetMLDv2MaximumResponseDelay(d time.Duration) error {
if d == 0 {
m.MaximumResponseCode = 0
return nil
}
if d < 0 {
return errors.New("maximum response delay must not be negative")
}
dms := d / time.Millisecond
if dms < 32768 {
m.MaximumResponseCode = uint16(dms)
}
if dms > 4193280 { // mant=0xFFF, exp=0x7
return fmt.Errorf("maximum response delay %dms is bigger the than maximum of 4193280ms", dms)
}
value := uint32(dms) // ok, because 4193280 < math.MaxUint32
exp := uint8(7)
for mask := uint32(0x40000000); exp > 0; exp-- {
if mask&value != 0 {
break
}
mask >>= 1
}
mant := uint16(0x00000FFF & (value >> (exp + 3)))
sig := uint16(0x1000)
m.MaximumResponseCode = sig | uint16(exp)<<12 | mant
return nil
}
// MLDv2MulticastListenerReportMessage is sent by an IP node to report the
// current multicast listening state, or changes therein.
// https://tools.ietf.org/html/rfc3810#section-5.2
type MLDv2MulticastListenerReportMessage struct {
BaseLayer
// 5.2.3. Nr of Mcast Address Records
NumberOfMulticastAddressRecords uint16
// 5.2.4. Multicast Address Record [i]
MulticastAddressRecords []MLDv2MulticastAddressRecord
}
// DecodeFromBytes decodes the given bytes into this layer.
func (m *MLDv2MulticastListenerReportMessage) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 4 {
df.SetTruncated()
return errors.New("ICMP layer less than 4 bytes for Multicast Listener Report Message V2")
}
// ignore data[0:2] as per RFC
// https://tools.ietf.org/html/rfc3810#section-5.2.1
m.NumberOfMulticastAddressRecords = binary.BigEndian.Uint16(data[2:4])
begin := 4
for i := uint16(0); i < m.NumberOfMulticastAddressRecords; i++ {
mar := MLDv2MulticastAddressRecord{}
read, err := mar.decode(data[begin:], df)
if err != nil {
return err
}
m.MulticastAddressRecords = append(m.MulticastAddressRecords, mar)
begin += read
}
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (m *MLDv2MulticastListenerReportMessage) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
lastItemIdx := len(m.MulticastAddressRecords) - 1
for k := range m.MulticastAddressRecords {
i := lastItemIdx - k // reverse order
err := m.MulticastAddressRecords[i].serializeTo(b, opts)
if err != nil {
return err
}
}
if opts.FixLengths {
numberOfMAR := len(m.MulticastAddressRecords)
if numberOfMAR > math.MaxUint16 {
return fmt.Errorf(
"%d multicast address records added, but the maximum is 65535",
numberOfMAR)
}
m.NumberOfMulticastAddressRecords = uint16(numberOfMAR)
}
buf, err := b.PrependBytes(4)
if err != nil {
return err
}
copy(buf[0:2], []byte{0x0, 0x0})
binary.BigEndian.PutUint16(buf[2:4], m.NumberOfMulticastAddressRecords)
return nil
}
// Sums this layer up nicely formatted
func (m *MLDv2MulticastListenerReportMessage) String() string {
return fmt.Sprintf(
"Number of Mcast Addr Records: %d (actual %d), Multicast Address Records: %+v",
m.NumberOfMulticastAddressRecords,
len(m.MulticastAddressRecords),
m.MulticastAddressRecords)
}
// LayerType returns LayerTypeMLDv2MulticastListenerQuery.
func (*MLDv2MulticastListenerReportMessage) LayerType() gopacket.LayerType {
return LayerTypeMLDv2MulticastListenerReport
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (*MLDv2MulticastListenerReportMessage) CanDecode() gopacket.LayerClass {
return LayerTypeMLDv2MulticastListenerReport
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (*MLDv2MulticastListenerReportMessage) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
// MLDv2MulticastAddressRecordType holds the type of a
// Multicast Address Record, according to
// https://tools.ietf.org/html/rfc3810#section-5.2.5 and
// https://tools.ietf.org/html/rfc3810#section-5.2.12
type MLDv2MulticastAddressRecordType uint8
const (
// MLDv2MulticastAddressRecordTypeModeIsIncluded stands for
// MODE_IS_INCLUDE - indicates that the interface has a filter
// mode of INCLUDE for the specified multicast address.
MLDv2MulticastAddressRecordTypeModeIsIncluded MLDv2MulticastAddressRecordType = 1
// MLDv2MulticastAddressRecordTypeModeIsExcluded stands for
// MODE_IS_EXCLUDE - indicates that the interface has a filter
// mode of EXCLUDE for the specified multicast address.
MLDv2MulticastAddressRecordTypeModeIsExcluded MLDv2MulticastAddressRecordType = 2
// MLDv2MulticastAddressRecordTypeChangeToIncludeMode stands for
// CHANGE_TO_INCLUDE_MODE - indicates that the interface has
// changed to INCLUDE filter mode for the specified multicast
// address.
MLDv2MulticastAddressRecordTypeChangeToIncludeMode MLDv2MulticastAddressRecordType = 3
// MLDv2MulticastAddressRecordTypeChangeToExcludeMode stands for
// CHANGE_TO_EXCLUDE_MODE - indicates that the interface has
// changed to EXCLUDE filter mode for the specified multicast
// address
MLDv2MulticastAddressRecordTypeChangeToExcludeMode MLDv2MulticastAddressRecordType = 4
// MLDv2MulticastAddressRecordTypeAllowNewSources stands for
// ALLOW_NEW_SOURCES - indicates that the Source Address [i]
// fields in this Multicast Address Record contain a list of
// the additional sources that the node wishes to listen to,
// for packets sent to the specified multicast address.
MLDv2MulticastAddressRecordTypeAllowNewSources MLDv2MulticastAddressRecordType = 5
// MLDv2MulticastAddressRecordTypeBlockOldSources stands for
// BLOCK_OLD_SOURCES - indicates that the Source Address [i]
// fields in this Multicast Address Record contain a list of
// the sources that the node no longer wishes to listen to,
// for packets sent to the specified multicast address.
MLDv2MulticastAddressRecordTypeBlockOldSources MLDv2MulticastAddressRecordType = 6
)
// Human readable record types
// Naming follows https://tools.ietf.org/html/rfc3810#section-5.2.12
func (m MLDv2MulticastAddressRecordType) String() string {
switch m {
case MLDv2MulticastAddressRecordTypeModeIsIncluded:
return "MODE_IS_INCLUDE"
case MLDv2MulticastAddressRecordTypeModeIsExcluded:
return "MODE_IS_EXCLUDE"
case MLDv2MulticastAddressRecordTypeChangeToIncludeMode:
return "CHANGE_TO_INCLUDE_MODE"
case MLDv2MulticastAddressRecordTypeChangeToExcludeMode:
return "CHANGE_TO_EXCLUDE_MODE"
case MLDv2MulticastAddressRecordTypeAllowNewSources:
return "ALLOW_NEW_SOURCES"
case MLDv2MulticastAddressRecordTypeBlockOldSources:
return "BLOCK_OLD_SOURCES"
default:
return fmt.Sprintf("UNKNOWN(%d)", m)
}
}
// MLDv2MulticastAddressRecord contains information on the sender listening to a
// single multicast address on the interface the report is sent.
// https://tools.ietf.org/html/rfc3810#section-5.2.4
type MLDv2MulticastAddressRecord struct {
// 5.2.5. Record Type
RecordType MLDv2MulticastAddressRecordType
// 5.2.6. Auxiliary Data Length (number of 32-bit words)
AuxDataLen uint8
// 5.2.7. Number Of Sources (N)
N uint16
// 5.2.8. Multicast Address
MulticastAddress net.IP
// 5.2.9 Source Address [i]
SourceAddresses []net.IP
// 5.2.10 Auxiliary Data
AuxiliaryData []byte
}
// decodes a multicast address record from bytes
func (m *MLDv2MulticastAddressRecord) decode(data []byte, df gopacket.DecodeFeedback) (int, error) {
if len(data) < 20 {
df.SetTruncated()
return 0, errors.New(
"Multicast Listener Report Message V2 layer less than 4 bytes for Multicast Address Record")
}
m.RecordType = MLDv2MulticastAddressRecordType(data[0])
m.AuxDataLen = data[1]
m.N = binary.BigEndian.Uint16(data[2:4])
m.MulticastAddress = data[4:20]
for i := uint16(0); i < m.N; i++ {
begin := 20 + (int(i) * 16)
end := begin + 16
if len(data) < end {
df.SetTruncated()
return begin, fmt.Errorf(
"Multicast Listener Report Message V2 layer less than %d bytes for Multicast Address Record", end)
}
m.SourceAddresses = append(m.SourceAddresses, data[begin:end])
}
expectedLengthWithouAuxData := 20 + (int(m.N) * 16)
expectedTotalLength := (int(m.AuxDataLen) * 4) + expectedLengthWithouAuxData // *4 because AuxDataLen are 32bit words
if len(data) < expectedTotalLength {
return expectedLengthWithouAuxData, fmt.Errorf(
"Multicast Listener Report Message V2 layer less than %d bytes for Multicast Address Record",
expectedLengthWithouAuxData)
}
m.AuxiliaryData = data[expectedLengthWithouAuxData:expectedTotalLength]
return expectedTotalLength, nil
}
// String sums this layer up nicely formatted
func (m *MLDv2MulticastAddressRecord) String() string {
return fmt.Sprintf(
"RecordType: %d (%s), AuxDataLen: %d [32-bit words], N: %d, Multicast Address: %s, SourceAddresses: %s, Auxiliary Data: %#x",
m.RecordType,
m.RecordType.String(),
m.AuxDataLen,
m.N,
m.MulticastAddress.To16(),
m.SourceAddresses,
m.AuxiliaryData)
}
// serializes a multicast address record
func (m *MLDv2MulticastAddressRecord) serializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
if err := m.serializeAuxiliaryDataTo(b, opts); err != nil {
return err
}
if err := m.serializeSourceAddressesTo(b, opts); err != nil {
return err
}
buf, err := b.PrependBytes(20)
if err != nil {
return err
}
buf[0] = uint8(m.RecordType)
buf[1] = m.AuxDataLen
binary.BigEndian.PutUint16(buf[2:4], m.N)
ma16 := m.MulticastAddress.To16()
if ma16 == nil {
return fmt.Errorf("invalid multicast address '%s'", m.MulticastAddress)
}
copy(buf[4:20], ma16)
return nil
}
// serializes the auxiliary data of a multicast address record
func (m *MLDv2MulticastAddressRecord) serializeAuxiliaryDataTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
if remainder := len(m.AuxiliaryData) % 4; remainder != 0 {
zeroWord := []byte{0x0, 0x0, 0x0, 0x0}
m.AuxiliaryData = append(m.AuxiliaryData, zeroWord[:remainder]...)
}
if opts.FixLengths {
auxDataLen := len(m.AuxiliaryData) / 4
if auxDataLen > math.MaxUint8 {
return fmt.Errorf("auxilary data is %d 32-bit words, but the maximum is 255 32-bit words", auxDataLen)
}
m.AuxDataLen = uint8(auxDataLen)
}
buf, err := b.PrependBytes(len(m.AuxiliaryData))
if err != nil {
return err
}
copy(buf, m.AuxiliaryData)
return nil
}
// serializes the source addresses of a multicast address record preserving the order
func (m *MLDv2MulticastAddressRecord) serializeSourceAddressesTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
if opts.FixLengths {
numberOfSourceAddresses := len(m.SourceAddresses)
if numberOfSourceAddresses > math.MaxUint16 {
return fmt.Errorf(
"%d source addresses added, but the maximum is 65535",
numberOfSourceAddresses)
}
m.N = uint16(numberOfSourceAddresses)
}
lastItemIdx := len(m.SourceAddresses) - 1
for k := range m.SourceAddresses {
i := lastItemIdx - k // reverse order
buf, err := b.PrependBytes(16)
if err != nil {
return err
}
sa16 := m.SourceAddresses[i].To16()
if sa16 == nil {
return fmt.Errorf("invalid source address [%d] '%s'", i, m.SourceAddresses[i])
}
copy(buf, sa16)
}
return nil
}
func decodeMLDv2MulticastListenerReport(data []byte, p gopacket.PacketBuilder) error {
m := &MLDv2MulticastListenerReportMessage{}
return decodingLayerDecoder(m, data, p)
}
func decodeMLDv2MulticastListenerQuery(data []byte, p gopacket.PacketBuilder) error {
m := &MLDv2MulticastListenerQueryMessage{}
return decodingLayerDecoder(m, data, p)
}
// Copyright 2018, The GoPacket Authors, All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
//
//******************************************************************************
package layers
import (
"encoding/binary"
"errors"
"github.com/google/gopacket"
)
//******************************************************************************
//
// ModbusTCP Decoding Layer
// ------------------------------------------
// This file provides a GoPacket decoding layer for ModbusTCP.
//
//******************************************************************************
const mbapRecordSizeInBytes int = 7
const modbusPDUMinimumRecordSizeInBytes int = 2
const modbusPDUMaximumRecordSizeInBytes int = 253
// ModbusProtocol type
type ModbusProtocol uint16
// ModbusProtocol known values.
const (
ModbusProtocolModbus ModbusProtocol = 0
)
func (mp ModbusProtocol) String() string {
switch mp {
default:
return "Unknown"
case ModbusProtocolModbus:
return "Modbus"
}
}
//******************************************************************************
// ModbusTCP Type
// --------
// Type ModbusTCP implements the DecodingLayer interface. Each ModbusTCP object
// represents in a structured form the MODBUS Application Protocol header (MBAP) record present as the TCP
// payload in an ModbusTCP TCP packet.
//
type ModbusTCP struct {
BaseLayer // Stores the packet bytes and payload (Modbus PDU) bytes .
TransactionIdentifier uint16 // Identification of a MODBUS Request/Response transaction
ProtocolIdentifier ModbusProtocol // It is used for intra-system multiplexing
Length uint16 // Number of following bytes (includes 1 byte for UnitIdentifier + Modbus data length
UnitIdentifier uint8 // Identification of a remote slave connected on a serial line or on other buses
}
//******************************************************************************
// LayerType returns the layer type of the ModbusTCP object, which is LayerTypeModbusTCP.
func (d *ModbusTCP) LayerType() gopacket.LayerType {
return LayerTypeModbusTCP
}
//******************************************************************************
// decodeModbusTCP analyses a byte slice and attempts to decode it as an ModbusTCP
// record of a TCP packet.
//
// If it succeeds, it loads p with information about the packet and returns nil.
// If it fails, it returns an error (non nil).
//
// This function is employed in layertypes.go to register the ModbusTCP layer.
func decodeModbusTCP(data []byte, p gopacket.PacketBuilder) error {
// Attempt to decode the byte slice.
d := &ModbusTCP{}
err := d.DecodeFromBytes(data, p)
if err != nil {
return err
}
// If the decoding worked, add the layer to the packet and set it
// as the application layer too, if there isn't already one.
p.AddLayer(d)
p.SetApplicationLayer(d)
return p.NextDecoder(d.NextLayerType())
}
//******************************************************************************
// DecodeFromBytes analyses a byte slice and attempts to decode it as an ModbusTCP
// record of a TCP packet.
//
// Upon succeeds, it loads the ModbusTCP object with information about the packet
// and returns nil.
// Upon failure, it returns an error (non nil).
func (d *ModbusTCP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
// If the data block is too short to be a MBAP record, then return an error.
if len(data) < mbapRecordSizeInBytes+modbusPDUMinimumRecordSizeInBytes {
df.SetTruncated()
return errors.New("ModbusTCP packet too short")
}
if len(data) > mbapRecordSizeInBytes+modbusPDUMaximumRecordSizeInBytes {
df.SetTruncated()
return errors.New("ModbusTCP packet too long")
}
// ModbusTCP type embeds type BaseLayer which contains two fields:
// Contents is supposed to contain the bytes of the data at this level (MPBA).
// Payload is supposed to contain the payload of this level (PDU).
d.BaseLayer = BaseLayer{Contents: data[:mbapRecordSizeInBytes], Payload: data[mbapRecordSizeInBytes:len(data)]}
// Extract the fields from the block of bytes.
// The fields can just be copied in big endian order.
d.TransactionIdentifier = binary.BigEndian.Uint16(data[:2])
d.ProtocolIdentifier = ModbusProtocol(binary.BigEndian.Uint16(data[2:4]))
d.Length = binary.BigEndian.Uint16(data[4:6])
// Length should have the size of the payload plus one byte (size of UnitIdentifier)
if d.Length != uint16(len(d.BaseLayer.Payload)+1) {
df.SetTruncated()
return errors.New("ModbusTCP packet with wrong field value (Length)")
}
d.UnitIdentifier = uint8(data[6])
return nil
}
//******************************************************************************
// NextLayerType returns the layer type of the ModbusTCP payload, which is LayerTypePayload.
func (d *ModbusTCP) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
//******************************************************************************
// Payload returns Modbus Protocol Data Unit (PDU) composed by Function Code and Data, it is carried within ModbusTCP packets
func (d *ModbusTCP) Payload() []byte {
return d.BaseLayer.Payload
}
// CanDecode returns the set of layer types that this DecodingLayer can decode
func (s *ModbusTCP) CanDecode() gopacket.LayerClass {
return LayerTypeModbusTCP
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"github.com/google/gopacket"
)
// MPLS is the MPLS packet header.
type MPLS struct {
BaseLayer
Label uint32
TrafficClass uint8
StackBottom bool
TTL uint8
}
// LayerType returns gopacket.LayerTypeMPLS.
func (m *MPLS) LayerType() gopacket.LayerType { return LayerTypeMPLS }
// ProtocolGuessingDecoder attempts to guess the protocol of the bytes it's
// given, then decode the packet accordingly. Its algorithm for guessing is:
// If the packet starts with byte 0x45-0x4F: IPv4
// If the packet starts with byte 0x60-0x6F: IPv6
// Otherwise: Error
// See draft-hsmit-isis-aal5mux-00.txt for more detail on this approach.
type ProtocolGuessingDecoder struct{}
func (ProtocolGuessingDecoder) Decode(data []byte, p gopacket.PacketBuilder) error {
switch data[0] {
// 0x40 | header_len, where header_len is at least 5.
case 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f:
return decodeIPv4(data, p)
// IPv6 can start with any byte whose first 4 bits are 0x6.
case 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f:
return decodeIPv6(data, p)
}
return errors.New("Unable to guess protocol of packet data")
}
// MPLSPayloadDecoder is the decoder used to data encapsulated by each MPLS
// layer. MPLS contains no type information, so we have to explicitly decide
// which decoder to use. This is initially set to ProtocolGuessingDecoder, our
// simple attempt at guessing protocols based on the first few bytes of data
// available to us. However, if you know that in your environment MPLS always
// encapsulates a specific protocol, you may reset this.
var MPLSPayloadDecoder gopacket.Decoder = ProtocolGuessingDecoder{}
func decodeMPLS(data []byte, p gopacket.PacketBuilder) error {
decoded := binary.BigEndian.Uint32(data[:4])
mpls := &MPLS{
Label: decoded >> 12,
TrafficClass: uint8(decoded>>9) & 0x7,
StackBottom: decoded&0x100 != 0,
TTL: uint8(decoded),
BaseLayer: BaseLayer{data[:4], data[4:]},
}
p.AddLayer(mpls)
if mpls.StackBottom {
return p.NextDecoder(MPLSPayloadDecoder)
}
return p.NextDecoder(gopacket.DecodeFunc(decodeMPLS))
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (m *MPLS) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
bytes, err := b.PrependBytes(4)
if err != nil {
return err
}
encoded := m.Label << 12
encoded |= uint32(m.TrafficClass) << 9
encoded |= uint32(m.TTL)
if m.StackBottom {
encoded |= 0x100
}
binary.BigEndian.PutUint32(bytes, encoded)
return nil
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
// Enum types courtesy of...
// http://anonsvn.wireshark.org/wireshark/trunk/epan/dissectors/packet-ndp.c
package layers
import (
"fmt"
"github.com/google/gopacket"
"net"
)
type NDPChassisType uint8
// Nortel Chassis Types
const (
NDPChassisother NDPChassisType = 1
NDPChassis3000 NDPChassisType = 2
NDPChassis3030 NDPChassisType = 3
NDPChassis2310 NDPChassisType = 4
NDPChassis2810 NDPChassisType = 5
NDPChassis2912 NDPChassisType = 6
NDPChassis2914 NDPChassisType = 7
NDPChassis271x NDPChassisType = 8
NDPChassis2813 NDPChassisType = 9
NDPChassis2814 NDPChassisType = 10
NDPChassis2915 NDPChassisType = 11
NDPChassis5000 NDPChassisType = 12
NDPChassis2813SA NDPChassisType = 13
NDPChassis2814SA NDPChassisType = 14
NDPChassis810M NDPChassisType = 15
NDPChassisEthercell NDPChassisType = 16
NDPChassis5005 NDPChassisType = 17
NDPChassisAlcatelEWC NDPChassisType = 18
NDPChassis2715SA NDPChassisType = 20
NDPChassis2486 NDPChassisType = 21
NDPChassis28000series NDPChassisType = 22
NDPChassis23000series NDPChassisType = 23
NDPChassis5DN00xseries NDPChassisType = 24
NDPChassisBayStackEthernet NDPChassisType = 25
NDPChassis23100series NDPChassisType = 26
NDPChassis100BaseTHub NDPChassisType = 27
NDPChassis3000FastEthernet NDPChassisType = 28
NDPChassisOrionSwitch NDPChassisType = 29
NDPChassisDDS NDPChassisType = 31
NDPChassisCentillion6slot NDPChassisType = 32
NDPChassisCentillion12slot NDPChassisType = 33
NDPChassisCentillion1slot NDPChassisType = 34
NDPChassisBayStack301 NDPChassisType = 35
NDPChassisBayStackTokenRingHub NDPChassisType = 36
NDPChassisFVCMultimediaSwitch NDPChassisType = 37
NDPChassisSwitchNode NDPChassisType = 38
NDPChassisBayStack302Switch NDPChassisType = 39
NDPChassisBayStack350Switch NDPChassisType = 40
NDPChassisBayStack150EthernetHub NDPChassisType = 41
NDPChassisCentillion50NSwitch NDPChassisType = 42
NDPChassisCentillion50TSwitch NDPChassisType = 43
NDPChassisBayStack303304Switches NDPChassisType = 44
NDPChassisBayStack200EthernetHub NDPChassisType = 45
NDPChassisBayStack25010100EthernetHub NDPChassisType = 46
NDPChassisBayStack450101001000Switches NDPChassisType = 48
NDPChassisBayStack41010100Switches NDPChassisType = 49
NDPChassisPassport1200L3Switch NDPChassisType = 50
NDPChassisPassport1250L3Switch NDPChassisType = 51
NDPChassisPassport1100L3Switch NDPChassisType = 52
NDPChassisPassport1150L3Switch NDPChassisType = 53
NDPChassisPassport1050L3Switch NDPChassisType = 54
NDPChassisPassport1051L3Switch NDPChassisType = 55
NDPChassisPassport8610L3Switch NDPChassisType = 56
NDPChassisPassport8606L3Switch NDPChassisType = 57
NDPChassisPassport8010 NDPChassisType = 58
NDPChassisPassport8006 NDPChassisType = 59
NDPChassisBayStack670wirelessaccesspoint NDPChassisType = 60
NDPChassisPassport740 NDPChassisType = 61
NDPChassisPassport750 NDPChassisType = 62
NDPChassisPassport790 NDPChassisType = 63
NDPChassisBusinessPolicySwitch200010100Switches NDPChassisType = 64
NDPChassisPassport8110L2Switch NDPChassisType = 65
NDPChassisPassport8106L2Switch NDPChassisType = 66
NDPChassisBayStack3580GigSwitch NDPChassisType = 67
NDPChassisBayStack10PowerSupplyUnit NDPChassisType = 68
NDPChassisBayStack42010100Switch NDPChassisType = 69
NDPChassisOPTeraMetro1200EthernetServiceModule NDPChassisType = 70
NDPChassisOPTera8010co NDPChassisType = 71
NDPChassisOPTera8610coL3Switch NDPChassisType = 72
NDPChassisOPTera8110coL2Switch NDPChassisType = 73
NDPChassisOPTera8003 NDPChassisType = 74
NDPChassisOPTera8603L3Switch NDPChassisType = 75
NDPChassisOPTera8103L2Switch NDPChassisType = 76
NDPChassisBayStack380101001000Switch NDPChassisType = 77
NDPChassisEthernetSwitch47048T NDPChassisType = 78
NDPChassisOPTeraMetro1450EthernetServiceModule NDPChassisType = 79
NDPChassisOPTeraMetro1400EthernetServiceModule NDPChassisType = 80
NDPChassisAlteonSwitchFamily NDPChassisType = 81
NDPChassisEthernetSwitch46024TPWR NDPChassisType = 82
NDPChassisOPTeraMetro8010OPML2Switch NDPChassisType = 83
NDPChassisOPTeraMetro8010coOPML2Switch NDPChassisType = 84
NDPChassisOPTeraMetro8006OPML2Switch NDPChassisType = 85
NDPChassisOPTeraMetro8003OPML2Switch NDPChassisType = 86
NDPChassisAlteon180e NDPChassisType = 87
NDPChassisAlteonAD3 NDPChassisType = 88
NDPChassisAlteon184 NDPChassisType = 89
NDPChassisAlteonAD4 NDPChassisType = 90
NDPChassisPassport1424L3Switch NDPChassisType = 91
NDPChassisPassport1648L3Switch NDPChassisType = 92
NDPChassisPassport1612L3Switch NDPChassisType = 93
NDPChassisPassport1624L3Switch NDPChassisType = 94
NDPChassisBayStack38024FFiber1000Switch NDPChassisType = 95
NDPChassisEthernetRoutingSwitch551024T NDPChassisType = 96
NDPChassisEthernetRoutingSwitch551048T NDPChassisType = 97
NDPChassisEthernetSwitch47024T NDPChassisType = 98
NDPChassisNortelNetworksWirelessLANAccessPoint2220 NDPChassisType = 99
NDPChassisPassportRBS2402L3Switch NDPChassisType = 100
NDPChassisAlteonApplicationSwitch2424 NDPChassisType = 101
NDPChassisAlteonApplicationSwitch2224 NDPChassisType = 102
NDPChassisAlteonApplicationSwitch2208 NDPChassisType = 103
NDPChassisAlteonApplicationSwitch2216 NDPChassisType = 104
NDPChassisAlteonApplicationSwitch3408 NDPChassisType = 105
NDPChassisAlteonApplicationSwitch3416 NDPChassisType = 106
NDPChassisNortelNetworksWirelessLANSecuritySwitch2250 NDPChassisType = 107
NDPChassisEthernetSwitch42548T NDPChassisType = 108
NDPChassisEthernetSwitch42524T NDPChassisType = 109
NDPChassisNortelNetworksWirelessLANAccessPoint2221 NDPChassisType = 110
NDPChassisNortelMetroEthernetServiceUnit24TSPFswitch NDPChassisType = 111
NDPChassisNortelMetroEthernetServiceUnit24TLXDCswitch NDPChassisType = 112
NDPChassisPassport830010slotchassis NDPChassisType = 113
NDPChassisPassport83006slotchassis NDPChassisType = 114
NDPChassisEthernetRoutingSwitch552024TPWR NDPChassisType = 115
NDPChassisEthernetRoutingSwitch552048TPWR NDPChassisType = 116
NDPChassisNortelNetworksVPNGateway3050 NDPChassisType = 117
NDPChassisAlteonSSL31010100 NDPChassisType = 118
NDPChassisAlteonSSL31010100Fiber NDPChassisType = 119
NDPChassisAlteonSSL31010100FIPS NDPChassisType = 120
NDPChassisAlteonSSL410101001000 NDPChassisType = 121
NDPChassisAlteonSSL410101001000Fiber NDPChassisType = 122
NDPChassisAlteonApplicationSwitch2424SSL NDPChassisType = 123
NDPChassisEthernetSwitch32524T NDPChassisType = 124
NDPChassisEthernetSwitch32524G NDPChassisType = 125
NDPChassisNortelNetworksWirelessLANAccessPoint2225 NDPChassisType = 126
NDPChassisNortelNetworksWirelessLANSecuritySwitch2270 NDPChassisType = 127
NDPChassis24portEthernetSwitch47024TPWR NDPChassisType = 128
NDPChassis48portEthernetSwitch47048TPWR NDPChassisType = 129
NDPChassisEthernetRoutingSwitch553024TFD NDPChassisType = 130
NDPChassisEthernetSwitch351024T NDPChassisType = 131
NDPChassisNortelMetroEthernetServiceUnit12GACL3Switch NDPChassisType = 132
NDPChassisNortelMetroEthernetServiceUnit12GDCL3Switch NDPChassisType = 133
NDPChassisNortelSecureAccessSwitch NDPChassisType = 134
NDPChassisNortelNetworksVPNGateway3070 NDPChassisType = 135
NDPChassisOPTeraMetro3500 NDPChassisType = 136
NDPChassisSMBBES101024T NDPChassisType = 137
NDPChassisSMBBES101048T NDPChassisType = 138
NDPChassisSMBBES102024TPWR NDPChassisType = 139
NDPChassisSMBBES102048TPWR NDPChassisType = 140
NDPChassisSMBBES201024T NDPChassisType = 141
NDPChassisSMBBES201048T NDPChassisType = 142
NDPChassisSMBBES202024TPWR NDPChassisType = 143
NDPChassisSMBBES202048TPWR NDPChassisType = 144
NDPChassisSMBBES11024T NDPChassisType = 145
NDPChassisSMBBES11048T NDPChassisType = 146
NDPChassisSMBBES12024TPWR NDPChassisType = 147
NDPChassisSMBBES12048TPWR NDPChassisType = 148
NDPChassisSMBBES21024T NDPChassisType = 149
NDPChassisSMBBES21048T NDPChassisType = 150
NDPChassisSMBBES22024TPWR NDPChassisType = 151
NDPChassisSMBBES22048TPWR NDPChassisType = 152
NDPChassisOME6500 NDPChassisType = 153
NDPChassisEthernetRoutingSwitch4548GT NDPChassisType = 154
NDPChassisEthernetRoutingSwitch4548GTPWR NDPChassisType = 155
NDPChassisEthernetRoutingSwitch4550T NDPChassisType = 156
NDPChassisEthernetRoutingSwitch4550TPWR NDPChassisType = 157
NDPChassisEthernetRoutingSwitch4526FX NDPChassisType = 158
NDPChassisEthernetRoutingSwitch250026T NDPChassisType = 159
NDPChassisEthernetRoutingSwitch250026TPWR NDPChassisType = 160
NDPChassisEthernetRoutingSwitch250050T NDPChassisType = 161
NDPChassisEthernetRoutingSwitch250050TPWR NDPChassisType = 162
)
type NDPBackplaneType uint8
// Nortel Backplane Types
const (
NDPBackplaneOther NDPBackplaneType = 1
NDPBackplaneEthernet NDPBackplaneType = 2
NDPBackplaneEthernetTokenring NDPBackplaneType = 3
NDPBackplaneEthernetFDDI NDPBackplaneType = 4
NDPBackplaneEthernetTokenringFDDI NDPBackplaneType = 5
NDPBackplaneEthernetTokenringRedundantPower NDPBackplaneType = 6
NDPBackplaneEthernetTokenringFDDIRedundantPower NDPBackplaneType = 7
NDPBackplaneTokenRing NDPBackplaneType = 8
NDPBackplaneEthernetTokenringFastEthernet NDPBackplaneType = 9
NDPBackplaneEthernetFastEthernet NDPBackplaneType = 10
NDPBackplaneEthernetTokenringFastEthernetRedundantPower NDPBackplaneType = 11
NDPBackplaneEthernetFastEthernetGigabitEthernet NDPBackplaneType = 12
)
type NDPState uint8
// Device State
const (
NDPStateTopology NDPState = 1
NDPStateHeartbeat NDPState = 2
NDPStateNew NDPState = 3
)
// NortelDiscovery is a packet layer containing the Nortel Discovery Protocol.
type NortelDiscovery struct {
BaseLayer
IPAddress net.IP
SegmentID []byte
Chassis NDPChassisType
Backplane NDPBackplaneType
State NDPState
NumLinks uint8
}
// LayerType returns gopacket.LayerTypeNortelDiscovery.
func (c *NortelDiscovery) LayerType() gopacket.LayerType {
return LayerTypeNortelDiscovery
}
func decodeNortelDiscovery(data []byte, p gopacket.PacketBuilder) error {
c := &NortelDiscovery{}
if len(data) < 11 {
return fmt.Errorf("Invalid NortelDiscovery packet length %d", len(data))
}
c.IPAddress = data[0:4]
c.SegmentID = data[4:7]
c.Chassis = NDPChassisType(data[7])
c.Backplane = NDPBackplaneType(data[8])
c.State = NDPState(data[9])
c.NumLinks = uint8(data[10])
p.AddLayer(c)
return nil
}
func (t NDPChassisType) String() (s string) {
switch t {
case NDPChassisother:
s = "other"
case NDPChassis3000:
s = "3000"
case NDPChassis3030:
s = "3030"
case NDPChassis2310:
s = "2310"
case NDPChassis2810:
s = "2810"
case NDPChassis2912:
s = "2912"
case NDPChassis2914:
s = "2914"
case NDPChassis271x:
s = "271x"
case NDPChassis2813:
s = "2813"
case NDPChassis2814:
s = "2814"
case NDPChassis2915:
s = "2915"
case NDPChassis5000:
s = "5000"
case NDPChassis2813SA:
s = "2813SA"
case NDPChassis2814SA:
s = "2814SA"
case NDPChassis810M:
s = "810M"
case NDPChassisEthercell:
s = "Ethercell"
case NDPChassis5005:
s = "5005"
case NDPChassisAlcatelEWC:
s = "Alcatel Ethernet workgroup conc."
case NDPChassis2715SA:
s = "2715SA"
case NDPChassis2486:
s = "2486"
case NDPChassis28000series:
s = "28000 series"
case NDPChassis23000series:
s = "23000 series"
case NDPChassis5DN00xseries:
s = "5DN00x series"
case NDPChassisBayStackEthernet:
s = "BayStack Ethernet"
case NDPChassis23100series:
s = "23100 series"
case NDPChassis100BaseTHub:
s = "100Base-T Hub"
case NDPChassis3000FastEthernet:
s = "3000 Fast Ethernet"
case NDPChassisOrionSwitch:
s = "Orion switch"
case NDPChassisDDS:
s = "DDS"
case NDPChassisCentillion6slot:
s = "Centillion (6 slot)"
case NDPChassisCentillion12slot:
s = "Centillion (12 slot)"
case NDPChassisCentillion1slot:
s = "Centillion (1 slot)"
case NDPChassisBayStack301:
s = "BayStack 301"
case NDPChassisBayStackTokenRingHub:
s = "BayStack TokenRing Hub"
case NDPChassisFVCMultimediaSwitch:
s = "FVC Multimedia Switch"
case NDPChassisSwitchNode:
s = "Switch Node"
case NDPChassisBayStack302Switch:
s = "BayStack 302 Switch"
case NDPChassisBayStack350Switch:
s = "BayStack 350 Switch"
case NDPChassisBayStack150EthernetHub:
s = "BayStack 150 Ethernet Hub"
case NDPChassisCentillion50NSwitch:
s = "Centillion 50N switch"
case NDPChassisCentillion50TSwitch:
s = "Centillion 50T switch"
case NDPChassisBayStack303304Switches:
s = "BayStack 303 and 304 Switches"
case NDPChassisBayStack200EthernetHub:
s = "BayStack 200 Ethernet Hub"
case NDPChassisBayStack25010100EthernetHub:
s = "BayStack 250 10/100 Ethernet Hub"
case NDPChassisBayStack450101001000Switches:
s = "BayStack 450 10/100/1000 Switches"
case NDPChassisBayStack41010100Switches:
s = "BayStack 410 10/100 Switches"
case NDPChassisPassport1200L3Switch:
s = "Passport 1200 L3 Switch"
case NDPChassisPassport1250L3Switch:
s = "Passport 1250 L3 Switch"
case NDPChassisPassport1100L3Switch:
s = "Passport 1100 L3 Switch"
case NDPChassisPassport1150L3Switch:
s = "Passport 1150 L3 Switch"
case NDPChassisPassport1050L3Switch:
s = "Passport 1050 L3 Switch"
case NDPChassisPassport1051L3Switch:
s = "Passport 1051 L3 Switch"
case NDPChassisPassport8610L3Switch:
s = "Passport 8610 L3 Switch"
case NDPChassisPassport8606L3Switch:
s = "Passport 8606 L3 Switch"
case NDPChassisPassport8010:
s = "Passport 8010"
case NDPChassisPassport8006:
s = "Passport 8006"
case NDPChassisBayStack670wirelessaccesspoint:
s = "BayStack 670 wireless access point"
case NDPChassisPassport740:
s = "Passport 740"
case NDPChassisPassport750:
s = "Passport 750"
case NDPChassisPassport790:
s = "Passport 790"
case NDPChassisBusinessPolicySwitch200010100Switches:
s = "Business Policy Switch 2000 10/100 Switches"
case NDPChassisPassport8110L2Switch:
s = "Passport 8110 L2 Switch"
case NDPChassisPassport8106L2Switch:
s = "Passport 8106 L2 Switch"
case NDPChassisBayStack3580GigSwitch:
s = "BayStack 3580 Gig Switch"
case NDPChassisBayStack10PowerSupplyUnit:
s = "BayStack 10 Power Supply Unit"
case NDPChassisBayStack42010100Switch:
s = "BayStack 420 10/100 Switch"
case NDPChassisOPTeraMetro1200EthernetServiceModule:
s = "OPTera Metro 1200 Ethernet Service Module"
case NDPChassisOPTera8010co:
s = "OPTera 8010co"
case NDPChassisOPTera8610coL3Switch:
s = "OPTera 8610co L3 switch"
case NDPChassisOPTera8110coL2Switch:
s = "OPTera 8110co L2 switch"
case NDPChassisOPTera8003:
s = "OPTera 8003"
case NDPChassisOPTera8603L3Switch:
s = "OPTera 8603 L3 switch"
case NDPChassisOPTera8103L2Switch:
s = "OPTera 8103 L2 switch"
case NDPChassisBayStack380101001000Switch:
s = "BayStack 380 10/100/1000 Switch"
case NDPChassisEthernetSwitch47048T:
s = "Ethernet Switch 470-48T"
case NDPChassisOPTeraMetro1450EthernetServiceModule:
s = "OPTera Metro 1450 Ethernet Service Module"
case NDPChassisOPTeraMetro1400EthernetServiceModule:
s = "OPTera Metro 1400 Ethernet Service Module"
case NDPChassisAlteonSwitchFamily:
s = "Alteon Switch Family"
case NDPChassisEthernetSwitch46024TPWR:
s = "Ethernet Switch 460-24T-PWR"
case NDPChassisOPTeraMetro8010OPML2Switch:
s = "OPTera Metro 8010 OPM L2 Switch"
case NDPChassisOPTeraMetro8010coOPML2Switch:
s = "OPTera Metro 8010co OPM L2 Switch"
case NDPChassisOPTeraMetro8006OPML2Switch:
s = "OPTera Metro 8006 OPM L2 Switch"
case NDPChassisOPTeraMetro8003OPML2Switch:
s = "OPTera Metro 8003 OPM L2 Switch"
case NDPChassisAlteon180e:
s = "Alteon 180e"
case NDPChassisAlteonAD3:
s = "Alteon AD3"
case NDPChassisAlteon184:
s = "Alteon 184"
case NDPChassisAlteonAD4:
s = "Alteon AD4"
case NDPChassisPassport1424L3Switch:
s = "Passport 1424 L3 switch"
case NDPChassisPassport1648L3Switch:
s = "Passport 1648 L3 switch"
case NDPChassisPassport1612L3Switch:
s = "Passport 1612 L3 switch"
case NDPChassisPassport1624L3Switch:
s = "Passport 1624 L3 switch"
case NDPChassisBayStack38024FFiber1000Switch:
s = "BayStack 380-24F Fiber 1000 Switch"
case NDPChassisEthernetRoutingSwitch551024T:
s = "Ethernet Routing Switch 5510-24T"
case NDPChassisEthernetRoutingSwitch551048T:
s = "Ethernet Routing Switch 5510-48T"
case NDPChassisEthernetSwitch47024T:
s = "Ethernet Switch 470-24T"
case NDPChassisNortelNetworksWirelessLANAccessPoint2220:
s = "Nortel Networks Wireless LAN Access Point 2220"
case NDPChassisPassportRBS2402L3Switch:
s = "Passport RBS 2402 L3 switch"
case NDPChassisAlteonApplicationSwitch2424:
s = "Alteon Application Switch 2424"
case NDPChassisAlteonApplicationSwitch2224:
s = "Alteon Application Switch 2224"
case NDPChassisAlteonApplicationSwitch2208:
s = "Alteon Application Switch 2208"
case NDPChassisAlteonApplicationSwitch2216:
s = "Alteon Application Switch 2216"
case NDPChassisAlteonApplicationSwitch3408:
s = "Alteon Application Switch 3408"
case NDPChassisAlteonApplicationSwitch3416:
s = "Alteon Application Switch 3416"
case NDPChassisNortelNetworksWirelessLANSecuritySwitch2250:
s = "Nortel Networks Wireless LAN SecuritySwitch 2250"
case NDPChassisEthernetSwitch42548T:
s = "Ethernet Switch 425-48T"
case NDPChassisEthernetSwitch42524T:
s = "Ethernet Switch 425-24T"
case NDPChassisNortelNetworksWirelessLANAccessPoint2221:
s = "Nortel Networks Wireless LAN Access Point 2221"
case NDPChassisNortelMetroEthernetServiceUnit24TSPFswitch:
s = "Nortel Metro Ethernet Service Unit 24-T SPF switch"
case NDPChassisNortelMetroEthernetServiceUnit24TLXDCswitch:
s = " Nortel Metro Ethernet Service Unit 24-T LX DC switch"
case NDPChassisPassport830010slotchassis:
s = "Passport 8300 10-slot chassis"
case NDPChassisPassport83006slotchassis:
s = "Passport 8300 6-slot chassis"
case NDPChassisEthernetRoutingSwitch552024TPWR:
s = "Ethernet Routing Switch 5520-24T-PWR"
case NDPChassisEthernetRoutingSwitch552048TPWR:
s = "Ethernet Routing Switch 5520-48T-PWR"
case NDPChassisNortelNetworksVPNGateway3050:
s = "Nortel Networks VPN Gateway 3050"
case NDPChassisAlteonSSL31010100:
s = "Alteon SSL 310 10/100"
case NDPChassisAlteonSSL31010100Fiber:
s = "Alteon SSL 310 10/100 Fiber"
case NDPChassisAlteonSSL31010100FIPS:
s = "Alteon SSL 310 10/100 FIPS"
case NDPChassisAlteonSSL410101001000:
s = "Alteon SSL 410 10/100/1000"
case NDPChassisAlteonSSL410101001000Fiber:
s = "Alteon SSL 410 10/100/1000 Fiber"
case NDPChassisAlteonApplicationSwitch2424SSL:
s = "Alteon Application Switch 2424-SSL"
case NDPChassisEthernetSwitch32524T:
s = "Ethernet Switch 325-24T"
case NDPChassisEthernetSwitch32524G:
s = "Ethernet Switch 325-24G"
case NDPChassisNortelNetworksWirelessLANAccessPoint2225:
s = "Nortel Networks Wireless LAN Access Point 2225"
case NDPChassisNortelNetworksWirelessLANSecuritySwitch2270:
s = "Nortel Networks Wireless LAN SecuritySwitch 2270"
case NDPChassis24portEthernetSwitch47024TPWR:
s = "24-port Ethernet Switch 470-24T-PWR"
case NDPChassis48portEthernetSwitch47048TPWR:
s = "48-port Ethernet Switch 470-48T-PWR"
case NDPChassisEthernetRoutingSwitch553024TFD:
s = "Ethernet Routing Switch 5530-24TFD"
case NDPChassisEthernetSwitch351024T:
s = "Ethernet Switch 3510-24T"
case NDPChassisNortelMetroEthernetServiceUnit12GACL3Switch:
s = "Nortel Metro Ethernet Service Unit 12G AC L3 switch"
case NDPChassisNortelMetroEthernetServiceUnit12GDCL3Switch:
s = "Nortel Metro Ethernet Service Unit 12G DC L3 switch"
case NDPChassisNortelSecureAccessSwitch:
s = "Nortel Secure Access Switch"
case NDPChassisNortelNetworksVPNGateway3070:
s = "Nortel Networks VPN Gateway 3070"
case NDPChassisOPTeraMetro3500:
s = "OPTera Metro 3500"
case NDPChassisSMBBES101024T:
s = "SMB BES 1010 24T"
case NDPChassisSMBBES101048T:
s = "SMB BES 1010 48T"
case NDPChassisSMBBES102024TPWR:
s = "SMB BES 1020 24T PWR"
case NDPChassisSMBBES102048TPWR:
s = "SMB BES 1020 48T PWR"
case NDPChassisSMBBES201024T:
s = "SMB BES 2010 24T"
case NDPChassisSMBBES201048T:
s = "SMB BES 2010 48T"
case NDPChassisSMBBES202024TPWR:
s = "SMB BES 2020 24T PWR"
case NDPChassisSMBBES202048TPWR:
s = "SMB BES 2020 48T PWR"
case NDPChassisSMBBES11024T:
s = "SMB BES 110 24T"
case NDPChassisSMBBES11048T:
s = "SMB BES 110 48T"
case NDPChassisSMBBES12024TPWR:
s = "SMB BES 120 24T PWR"
case NDPChassisSMBBES12048TPWR:
s = "SMB BES 120 48T PWR"
case NDPChassisSMBBES21024T:
s = "SMB BES 210 24T"
case NDPChassisSMBBES21048T:
s = "SMB BES 210 48T"
case NDPChassisSMBBES22024TPWR:
s = "SMB BES 220 24T PWR"
case NDPChassisSMBBES22048TPWR:
s = "SMB BES 220 48T PWR"
case NDPChassisOME6500:
s = "OME 6500"
case NDPChassisEthernetRoutingSwitch4548GT:
s = "Ethernet Routing Switch 4548GT"
case NDPChassisEthernetRoutingSwitch4548GTPWR:
s = "Ethernet Routing Switch 4548GT-PWR"
case NDPChassisEthernetRoutingSwitch4550T:
s = "Ethernet Routing Switch 4550T"
case NDPChassisEthernetRoutingSwitch4550TPWR:
s = "Ethernet Routing Switch 4550T-PWR"
case NDPChassisEthernetRoutingSwitch4526FX:
s = "Ethernet Routing Switch 4526FX"
case NDPChassisEthernetRoutingSwitch250026T:
s = "Ethernet Routing Switch 2500-26T"
case NDPChassisEthernetRoutingSwitch250026TPWR:
s = "Ethernet Routing Switch 2500-26T-PWR"
case NDPChassisEthernetRoutingSwitch250050T:
s = "Ethernet Routing Switch 2500-50T"
case NDPChassisEthernetRoutingSwitch250050TPWR:
s = "Ethernet Routing Switch 2500-50T-PWR"
default:
s = "Unknown"
}
return
}
func (t NDPBackplaneType) String() (s string) {
switch t {
case NDPBackplaneOther:
s = "Other"
case NDPBackplaneEthernet:
s = "Ethernet"
case NDPBackplaneEthernetTokenring:
s = "Ethernet and Tokenring"
case NDPBackplaneEthernetFDDI:
s = "Ethernet and FDDI"
case NDPBackplaneEthernetTokenringFDDI:
s = "Ethernet, Tokenring and FDDI"
case NDPBackplaneEthernetTokenringRedundantPower:
s = "Ethernet and Tokenring with redundant power"
case NDPBackplaneEthernetTokenringFDDIRedundantPower:
s = "Ethernet, Tokenring, FDDI with redundant power"
case NDPBackplaneTokenRing:
s = "Token Ring"
case NDPBackplaneEthernetTokenringFastEthernet:
s = "Ethernet, Tokenring and Fast Ethernet"
case NDPBackplaneEthernetFastEthernet:
s = "Ethernet and Fast Ethernet"
case NDPBackplaneEthernetTokenringFastEthernetRedundantPower:
s = "Ethernet, Tokenring, Fast Ethernet with redundant power"
case NDPBackplaneEthernetFastEthernetGigabitEthernet:
s = "Ethernet, Fast Ethernet and Gigabit Ethernet"
default:
s = "Unknown"
}
return
}
func (t NDPState) String() (s string) {
switch t {
case NDPStateTopology:
s = "Topology Change"
case NDPStateHeartbeat:
s = "Heartbeat"
case NDPStateNew:
s = "New"
default:
s = "Unknown"
}
return
}
// Copyright 2016 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
//
//******************************************************************************
package layers
import (
"encoding/binary"
"errors"
"github.com/google/gopacket"
)
//******************************************************************************
//
// Network Time Protocol (NTP) Decoding Layer
// ------------------------------------------
// This file provides a GoPacket decoding layer for NTP.
//
//******************************************************************************
//
// About The Network Time Protocol (NTP)
// -------------------------------------
// NTP is a protocol that enables computers on the internet to set their
// clocks to the correct time (or to a time that is acceptably close to the
// correct time). NTP runs on top of UDP.
//
// There have been a series of versions of the NTP protocol. The latest
// version is V4 and is specified in RFC 5905:
// http://www.ietf.org/rfc/rfc5905.txt
//
//******************************************************************************
//
// References
// ----------
//
// Wikipedia's NTP entry:
// https://en.wikipedia.org/wiki/Network_Time_Protocol
// This is the best place to get an overview of NTP.
//
// Network Time Protocol Home Website:
// http://www.ntp.org/
// This appears to be the official website of NTP.
//
// List of current NTP Protocol RFCs:
// http://www.ntp.org/rfc.html
//
// RFC 958: "Network Time Protocol (NTP)" (1985)
// https://tools.ietf.org/html/rfc958
// This is the original NTP specification.
//
// RFC 1305: "Network Time Protocol (Version 3) Specification, Implementation and Analysis" (1992)
// https://tools.ietf.org/html/rfc1305
// The protocol was updated in 1992 yielding NTP V3.
//
// RFC 5905: "Network Time Protocol Version 4: Protocol and Algorithms Specification" (2010)
// https://www.ietf.org/rfc/rfc5905.txt
// The protocol was updated in 2010 yielding NTP V4.
// V4 is backwards compatible with all previous versions of NTP.
//
// RFC 5906: "Network Time Protocol Version 4: Autokey Specification"
// https://tools.ietf.org/html/rfc5906
// This document addresses the security of the NTP protocol
// and is probably not relevant to this package.
//
// RFC 5907: "Definitions of Managed Objects for Network Time Protocol Version 4 (NTPv4)"
// https://tools.ietf.org/html/rfc5907
// This document addresses the management of NTP servers and
// is probably not relevant to this package.
//
// RFC 5908: "Network Time Protocol (NTP) Server Option for DHCPv6"
// https://tools.ietf.org/html/rfc5908
// This document addresses the use of NTP in DHCPv6 and is
// probably not relevant to this package.
//
// "Let's make a NTP Client in C"
// https://lettier.github.io/posts/2016-04-26-lets-make-a-ntp-client-in-c.html
// This web page contains useful information about the details of NTP,
// including an NTP record struture in C, and C code.
//
// "NTP Packet Header (NTP Reference Implementation) (Computer Network Time Synchronization)"
// http://what-when-how.com/computer-network-time-synchronization/
// ntp-packet-header-ntp-reference-implementation-computer-network-time-synchronization/
// This web page contains useful information on the details of NTP.
//
// "Technical information - NTP Data Packet"
// https://www.meinbergglobal.com/english/info/ntp-packet.htm
// This page has a helpful diagram of an NTP V4 packet.
//
//******************************************************************************
//
// Obsolete References
// -------------------
//
// RFC 1119: "RFC-1119 "Network Time Protocol (Version 2) Specification and Implementation" (1989)
// https://tools.ietf.org/html/rfc1119
// Version 2 was drafted in 1989.
// It is unclear whether V2 was ever implememented or whether the
// ideas ended up in V3 (which was implemented in 1992).
//
// RFC 1361: "Simple Network Time Protocol (SNTP)"
// https://tools.ietf.org/html/rfc1361
// This document is obsoleted by RFC 1769 and is included only for completeness.
//
// RFC 1769: "Simple Network Time Protocol (SNTP)"
// https://tools.ietf.org/html/rfc1769
// This document is obsoleted by RFC 2030 and RFC 4330 and is included only for completeness.
//
// RFC 2030: "Simple Network Time Protocol (SNTP) Version 4 for IPv4, IPv6 and OSI"
// https://tools.ietf.org/html/rfc2030
// This document is obsoleted by RFC 4330 and is included only for completeness.
//
// RFC 4330: "Simple Network Time Protocol (SNTP) Version 4 for IPv4, IPv6 and OSI"
// https://tools.ietf.org/html/rfc4330
// This document is obsoleted by RFC 5905 and is included only for completeness.
//
//******************************************************************************
//
// Endian And Bit Numbering Issues
// -------------------------------
//
// Endian and bit numbering issues can be confusing. Here is some
// clarification:
//
// ENDIAN: Values are sent big endian.
// https://en.wikipedia.org/wiki/Endianness
//
// BIT NUMBERING: Bits are numbered 0 upwards from the most significant
// bit to the least significant bit. This means that if there is a 32-bit
// value, the most significant bit is called bit 0 and the least
// significant bit is called bit 31.
//
// See RFC 791 Appendix B for more discussion.
//
//******************************************************************************
//
// NTP V3 and V4 Packet Format
// ---------------------------
// NTP packets are UDP packets whose payload contains an NTP record.
//
// The NTP RFC defines the format of the NTP record.
//
// There have been four versions of the protocol:
//
// V1 in 1985
// V2 in 1989
// V3 in 1992
// V4 in 2010
//
// It is clear that V1 and V2 are obsolete, and there is no need to
// cater for these formats.
//
// V3 and V4 essentially use the same format, with V4 adding some optional
// fields on the end. So this package supports the V3 and V4 formats.
//
// The current version of NTP (NTP V4)'s RFC (V4 - RFC 5905) contains
// the following diagram for the NTP record format:
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |LI | VN |Mode | Stratum | Poll | Precision |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Root Delay |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Root Dispersion |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Reference ID |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// + Reference Timestamp (64) +
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// + Origin Timestamp (64) +
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// + Receive Timestamp (64) +
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// + Transmit Timestamp (64) +
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . .
// . Extension Field 1 (variable) .
// . .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . .
// . Extension Field 2 (variable) .
// . .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Key Identifier |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// | dgst (128) |
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// From http://www.ietf.org/rfc/rfc5905.txt
//
// The fields "Extension Field 1 (variable)" and later are optional fields,
// and so we can set a minimum NTP record size of 48 bytes.
//
const ntpMinimumRecordSizeInBytes int = 48
//******************************************************************************
// NTP Type
// --------
// Type NTP implements the DecodingLayer interface. Each NTP object
// represents in a structured form the NTP record present as the UDP
// payload in an NTP UDP packet.
//
type NTPLeapIndicator uint8
type NTPVersion uint8
type NTPMode uint8
type NTPStratum uint8
type NTPLog2Seconds int8
type NTPFixed16Seconds uint32
type NTPReferenceID uint32
type NTPTimestamp uint64
type NTP struct {
BaseLayer // Stores the packet bytes and payload bytes.
LeapIndicator NTPLeapIndicator // [0,3]. Indicates whether leap second(s) is to be added.
Version NTPVersion // [0,7]. Version of the NTP protocol.
Mode NTPMode // [0,7]. Mode.
Stratum NTPStratum // [0,255]. Stratum of time server in the server tree.
Poll NTPLog2Seconds // [-128,127]. The maximum interval between successive messages, in log2 seconds.
Precision NTPLog2Seconds // [-128,127]. The precision of the system clock, in log2 seconds.
RootDelay NTPFixed16Seconds // [0,2^32-1]. Total round trip delay to the reference clock in seconds times 2^16.
RootDispersion NTPFixed16Seconds // [0,2^32-1]. Total dispersion to the reference clock, in seconds times 2^16.
ReferenceID NTPReferenceID // ID code of reference clock [0,2^32-1].
ReferenceTimestamp NTPTimestamp // Most recent timestamp from the reference clock.
OriginTimestamp NTPTimestamp // Local time when request was sent from local host.
ReceiveTimestamp NTPTimestamp // Local time (on server) that request arrived at server host.
TransmitTimestamp NTPTimestamp // Local time (on server) that request departed server host.
// FIX: This package should analyse the extension fields and represent the extension fields too.
ExtensionBytes []byte // Just put extensions in a byte slice.
}
//******************************************************************************
// LayerType returns the layer type of the NTP object, which is LayerTypeNTP.
func (d *NTP) LayerType() gopacket.LayerType {
return LayerTypeNTP
}
//******************************************************************************
// decodeNTP analyses a byte slice and attempts to decode it as an NTP
// record of a UDP packet.
//
// If it succeeds, it loads p with information about the packet and returns nil.
// If it fails, it returns an error (non nil).
//
// This function is employed in layertypes.go to register the NTP layer.
func decodeNTP(data []byte, p gopacket.PacketBuilder) error {
// Attempt to decode the byte slice.
d := &NTP{}
err := d.DecodeFromBytes(data, p)
if err != nil {
return err
}
// If the decoding worked, add the layer to the packet and set it
// as the application layer too, if there isn't already one.
p.AddLayer(d)
p.SetApplicationLayer(d)
return nil
}
//******************************************************************************
// DecodeFromBytes analyses a byte slice and attempts to decode it as an NTP
// record of a UDP packet.
//
// Upon succeeds, it loads the NTP object with information about the packet
// and returns nil.
// Upon failure, it returns an error (non nil).
func (d *NTP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
// If the data block is too short to be a NTP record, then return an error.
if len(data) < ntpMinimumRecordSizeInBytes {
df.SetTruncated()
return errors.New("NTP packet too short")
}
// RFC 5905 does not appear to define a maximum NTP record length.
// The protocol allows "extension fields" to be included in the record,
// and states about these fields:"
//
// "While the minimum field length containing required fields is
// four words (16 octets), a maximum field length remains to be
// established."
//
// For this reason, the packet length is not checked here for being too long.
// NTP type embeds type BaseLayer which contains two fields:
// Contents is supposed to contain the bytes of the data at this level.
// Payload is supposed to contain the payload of this level.
// Here we set the baselayer to be the bytes of the NTP record.
d.BaseLayer = BaseLayer{Contents: data[:len(data)]}
// Extract the fields from the block of bytes.
// To make sense of this, refer to the packet diagram
// above and the section on endian conventions.
// The first few fields are all packed into the first 32 bits. Unpack them.
f := data[0]
d.LeapIndicator = NTPLeapIndicator((f & 0xC0) >> 6)
d.Version = NTPVersion((f & 0x38) >> 3)
d.Mode = NTPMode(f & 0x07)
d.Stratum = NTPStratum(data[1])
d.Poll = NTPLog2Seconds(data[2])
d.Precision = NTPLog2Seconds(data[3])
// The remaining fields can just be copied in big endian order.
d.RootDelay = NTPFixed16Seconds(binary.BigEndian.Uint32(data[4:8]))
d.RootDispersion = NTPFixed16Seconds(binary.BigEndian.Uint32(data[8:12]))
d.ReferenceID = NTPReferenceID(binary.BigEndian.Uint32(data[12:16]))
d.ReferenceTimestamp = NTPTimestamp(binary.BigEndian.Uint64(data[16:24]))
d.OriginTimestamp = NTPTimestamp(binary.BigEndian.Uint64(data[24:32]))
d.ReceiveTimestamp = NTPTimestamp(binary.BigEndian.Uint64(data[32:40]))
d.TransmitTimestamp = NTPTimestamp(binary.BigEndian.Uint64(data[40:48]))
// This layer does not attempt to analyse the extension bytes.
// But if there are any, we'd like the user to know. So we just
// place them all in an ExtensionBytes field.
d.ExtensionBytes = data[48:]
// Return no error.
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (d *NTP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
data, err := b.PrependBytes(ntpMinimumRecordSizeInBytes)
if err != nil {
return err
}
// Pack the first few fields into the first 32 bits.
h := uint8(0)
h |= (uint8(d.LeapIndicator) << 6) & 0xC0
h |= (uint8(d.Version) << 3) & 0x38
h |= (uint8(d.Mode)) & 0x07
data[0] = byte(h)
data[1] = byte(d.Stratum)
data[2] = byte(d.Poll)
data[3] = byte(d.Precision)
// The remaining fields can just be copied in big endian order.
binary.BigEndian.PutUint32(data[4:8], uint32(d.RootDelay))
binary.BigEndian.PutUint32(data[8:12], uint32(d.RootDispersion))
binary.BigEndian.PutUint32(data[12:16], uint32(d.ReferenceID))
binary.BigEndian.PutUint64(data[16:24], uint64(d.ReferenceTimestamp))
binary.BigEndian.PutUint64(data[24:32], uint64(d.OriginTimestamp))
binary.BigEndian.PutUint64(data[32:40], uint64(d.ReceiveTimestamp))
binary.BigEndian.PutUint64(data[40:48], uint64(d.TransmitTimestamp))
ex, err := b.AppendBytes(len(d.ExtensionBytes))
if err != nil {
return err
}
copy(ex, d.ExtensionBytes)
return nil
}
//******************************************************************************
// CanDecode returns a set of layers that NTP objects can decode.
// As NTP objects can only decide the NTP layer, we can return just that layer.
// Apparently a single layer type implements LayerClass.
func (d *NTP) CanDecode() gopacket.LayerClass {
return LayerTypeNTP
}
//******************************************************************************
// NextLayerType specifies the next layer that GoPacket should attempt to
// analyse after this (NTP) layer. As NTP packets do not contain any payload
// bytes, there are no further layers to analyse.
func (d *NTP) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypeZero
}
//******************************************************************************
// NTP packets do not carry any data payload, so the empty byte slice is retured.
// In Go, a nil slice is functionally identical to an empty slice, so we
// return nil to avoid a heap allocation.
func (d *NTP) Payload() []byte {
return nil
}
//******************************************************************************
//* End Of NTP File *
//******************************************************************************
// Copyright 2017 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"github.com/google/gopacket"
)
// OSPFType denotes what kind of OSPF type it is
type OSPFType uint8
// Potential values for OSPF.Type.
const (
OSPFHello OSPFType = 1
OSPFDatabaseDescription OSPFType = 2
OSPFLinkStateRequest OSPFType = 3
OSPFLinkStateUpdate OSPFType = 4
OSPFLinkStateAcknowledgment OSPFType = 5
)
// LSA Function Codes for LSAheader.LSType
const (
RouterLSAtypeV2 = 0x1
RouterLSAtype = 0x2001
NetworkLSAtypeV2 = 0x2
NetworkLSAtype = 0x2002
SummaryLSANetworktypeV2 = 0x3
InterAreaPrefixLSAtype = 0x2003
SummaryLSAASBRtypeV2 = 0x4
InterAreaRouterLSAtype = 0x2004
ASExternalLSAtypeV2 = 0x5
ASExternalLSAtype = 0x4005
NSSALSAtype = 0x2007
NSSALSAtypeV2 = 0x7
LinkLSAtype = 0x0008
IntraAreaPrefixLSAtype = 0x2009
)
// String conversions for OSPFType
func (i OSPFType) String() string {
switch i {
case OSPFHello:
return "Hello"
case OSPFDatabaseDescription:
return "Database Description"
case OSPFLinkStateRequest:
return "Link State Request"
case OSPFLinkStateUpdate:
return "Link State Update"
case OSPFLinkStateAcknowledgment:
return "Link State Acknowledgment"
default:
return ""
}
}
// Prefix extends IntraAreaPrefixLSA
type Prefix struct {
PrefixLength uint8
PrefixOptions uint8
Metric uint16
AddressPrefix []byte
}
// IntraAreaPrefixLSA is the struct from RFC 5340 A.4.10.
type IntraAreaPrefixLSA struct {
NumOfPrefixes uint16
RefLSType uint16
RefLinkStateID uint32
RefAdvRouter uint32
Prefixes []Prefix
}
// LinkLSA is the struct from RFC 5340 A.4.9.
type LinkLSA struct {
RtrPriority uint8
Options uint32
LinkLocalAddress []byte
NumOfPrefixes uint32
Prefixes []Prefix
}
// ASExternalLSAV2 is the struct from RFC 2328 A.4.5.
type ASExternalLSAV2 struct {
NetworkMask uint32
ExternalBit uint8
Metric uint32
ForwardingAddress uint32
ExternalRouteTag uint32
}
// ASExternalLSA is the struct from RFC 5340 A.4.7.
type ASExternalLSA struct {
Flags uint8
Metric uint32
PrefixLength uint8
PrefixOptions uint8
RefLSType uint16
AddressPrefix []byte
ForwardingAddress []byte
ExternalRouteTag uint32
RefLinkStateID uint32
}
// InterAreaRouterLSA is the struct from RFC 5340 A.4.6.
type InterAreaRouterLSA struct {
Options uint32
Metric uint32
DestinationRouterID uint32
}
// InterAreaPrefixLSA is the struct from RFC 5340 A.4.5.
type InterAreaPrefixLSA struct {
Metric uint32
PrefixLength uint8
PrefixOptions uint8
AddressPrefix []byte
}
// NetworkLSA is the struct from RFC 5340 A.4.4.
type NetworkLSA struct {
Options uint32
AttachedRouter []uint32
}
// NetworkLSAV2 is the struct from RFC 2328 A.4.3.
type NetworkLSAV2 struct {
NetworkMask uint32
AttachedRouter []uint32
}
// RouterV2 extends RouterLSAV2
type RouterV2 struct {
Type uint8
LinkID uint32
LinkData uint32
Metric uint16
}
// RouterLSAV2 is the struct from RFC 2328 A.4.2.
type RouterLSAV2 struct {
Flags uint8
Links uint16
Routers []RouterV2
}
// Router extends RouterLSA
type Router struct {
Type uint8
Metric uint16
InterfaceID uint32
NeighborInterfaceID uint32
NeighborRouterID uint32
}
// RouterLSA is the struct from RFC 5340 A.4.3.
type RouterLSA struct {
Flags uint8
Options uint32
Routers []Router
}
// LSAheader is the struct from RFC 5340 A.4.2 and RFC 2328 A.4.1.
type LSAheader struct {
LSAge uint16
LSType uint16
LinkStateID uint32
AdvRouter uint32
LSSeqNumber uint32
LSChecksum uint16
Length uint16
LSOptions uint8
}
// LSA links LSAheader with the structs from RFC 5340 A.4.
type LSA struct {
LSAheader
Content interface{}
}
// LSUpdate is the struct from RFC 5340 A.3.5.
type LSUpdate struct {
NumOfLSAs uint32
LSAs []LSA
}
// LSReq is the struct from RFC 5340 A.3.4.
type LSReq struct {
LSType uint16
LSID uint32
AdvRouter uint32
}
// DbDescPkg is the struct from RFC 5340 A.3.3.
type DbDescPkg struct {
Options uint32
InterfaceMTU uint16
Flags uint16
DDSeqNumber uint32
LSAinfo []LSAheader
}
// HelloPkg is the struct from RFC 5340 A.3.2.
type HelloPkg struct {
InterfaceID uint32
RtrPriority uint8
Options uint32
HelloInterval uint16
RouterDeadInterval uint32
DesignatedRouterID uint32
BackupDesignatedRouterID uint32
NeighborID []uint32
}
// HelloPkgV2 extends the HelloPkg struct with OSPFv2 information
type HelloPkgV2 struct {
HelloPkg
NetworkMask uint32
}
// OSPF is a basic OSPF packet header with common fields of Version 2 and Version 3.
type OSPF struct {
Version uint8
Type OSPFType
PacketLength uint16
RouterID uint32
AreaID uint32
Checksum uint16
Content interface{}
}
//OSPFv2 extend the OSPF head with version 2 specific fields
type OSPFv2 struct {
BaseLayer
OSPF
AuType uint16
Authentication uint64
}
// OSPFv3 extend the OSPF head with version 3 specific fields
type OSPFv3 struct {
BaseLayer
OSPF
Instance uint8
Reserved uint8
}
// getLSAsv2 parses the LSA information from the packet for OSPFv2
func getLSAsv2(num uint32, data []byte) ([]LSA, error) {
var lsas []LSA
var i uint32 = 0
var offset uint32 = 0
for ; i < num; i++ {
lstype := uint16(data[offset+3])
lsalength := binary.BigEndian.Uint16(data[offset+18 : offset+20])
content, err := extractLSAInformation(lstype, lsalength, data[offset:])
if err != nil {
return nil, fmt.Errorf("Could not extract Link State type.")
}
lsa := LSA{
LSAheader: LSAheader{
LSAge: binary.BigEndian.Uint16(data[offset : offset+2]),
LSOptions: data[offset+2],
LSType: lstype,
LinkStateID: binary.BigEndian.Uint32(data[offset+4 : offset+8]),
AdvRouter: binary.BigEndian.Uint32(data[offset+8 : offset+12]),
LSSeqNumber: binary.BigEndian.Uint32(data[offset+12 : offset+16]),
LSChecksum: binary.BigEndian.Uint16(data[offset+16 : offset+18]),
Length: lsalength,
},
Content: content,
}
lsas = append(lsas, lsa)
offset += uint32(lsalength)
}
return lsas, nil
}
// extractLSAInformation extracts all the LSA information
func extractLSAInformation(lstype, lsalength uint16, data []byte) (interface{}, error) {
if lsalength < 20 {
return nil, fmt.Errorf("Link State header length %v too short, %v required", lsalength, 20)
}
if len(data) < int(lsalength) {
return nil, fmt.Errorf("Link State header length %v too short, %v required", len(data), lsalength)
}
var content interface{}
switch lstype {
case RouterLSAtypeV2:
var routers []RouterV2
var j uint32
for j = 24; j < uint32(lsalength); j += 12 {
if len(data) < int(j+12) {
return nil, errors.New("LSAtypeV2 too small")
}
router := RouterV2{
LinkID: binary.BigEndian.Uint32(data[j : j+4]),
LinkData: binary.BigEndian.Uint32(data[j+4 : j+8]),
Type: uint8(data[j+8]),
Metric: binary.BigEndian.Uint16(data[j+10 : j+12]),
}
routers = append(routers, router)
}
if len(data) < 24 {
return nil, errors.New("LSAtypeV2 too small")
}
links := binary.BigEndian.Uint16(data[22:24])
content = RouterLSAV2{
Flags: data[20],
Links: links,
Routers: routers,
}
case NSSALSAtypeV2:
fallthrough
case ASExternalLSAtypeV2:
content = ASExternalLSAV2{
NetworkMask: binary.BigEndian.Uint32(data[20:24]),
ExternalBit: data[24] & 0x80,
Metric: binary.BigEndian.Uint32(data[24:28]) & 0x00FFFFFF,
ForwardingAddress: binary.BigEndian.Uint32(data[28:32]),
ExternalRouteTag: binary.BigEndian.Uint32(data[32:36]),
}
case NetworkLSAtypeV2:
var routers []uint32
var j uint32
for j = 24; j < uint32(lsalength); j += 4 {
routers = append(routers, binary.BigEndian.Uint32(data[j:j+4]))
}
content = NetworkLSAV2{
NetworkMask: binary.BigEndian.Uint32(data[20:24]),
AttachedRouter: routers,
}
case RouterLSAtype:
var routers []Router
var j uint32
for j = 24; j < uint32(lsalength); j += 16 {
router := Router{
Type: uint8(data[j]),
Metric: binary.BigEndian.Uint16(data[j+2 : j+4]),
InterfaceID: binary.BigEndian.Uint32(data[j+4 : j+8]),
NeighborInterfaceID: binary.BigEndian.Uint32(data[j+8 : j+12]),
NeighborRouterID: binary.BigEndian.Uint32(data[j+12 : j+16]),
}
routers = append(routers, router)
}
content = RouterLSA{
Flags: uint8(data[20]),
Options: binary.BigEndian.Uint32(data[20:24]) & 0x00FFFFFF,
Routers: routers,
}
case NetworkLSAtype:
var routers []uint32
var j uint32
for j = 24; j < uint32(lsalength); j += 4 {
routers = append(routers, binary.BigEndian.Uint32(data[j:j+4]))
}
content = NetworkLSA{
Options: binary.BigEndian.Uint32(data[20:24]) & 0x00FFFFFF,
AttachedRouter: routers,
}
case InterAreaPrefixLSAtype:
content = InterAreaPrefixLSA{
Metric: binary.BigEndian.Uint32(data[20:24]) & 0x00FFFFFF,
PrefixLength: uint8(data[24]),
PrefixOptions: uint8(data[25]),
AddressPrefix: data[28:uint32(lsalength)],
}
case InterAreaRouterLSAtype:
content = InterAreaRouterLSA{
Options: binary.BigEndian.Uint32(data[20:24]) & 0x00FFFFFF,
Metric: binary.BigEndian.Uint32(data[24:28]) & 0x00FFFFFF,
DestinationRouterID: binary.BigEndian.Uint32(data[28:32]),
}
case ASExternalLSAtype:
fallthrough
case NSSALSAtype:
flags := uint8(data[20])
prefixLen := uint8(data[24]) / 8
var forwardingAddress []byte
if (flags & 0x02) == 0x02 {
forwardingAddress = data[28+uint32(prefixLen) : 28+uint32(prefixLen)+16]
}
content = ASExternalLSA{
Flags: flags,
Metric: binary.BigEndian.Uint32(data[20:24]) & 0x00FFFFFF,
PrefixLength: prefixLen,
PrefixOptions: uint8(data[25]),
RefLSType: binary.BigEndian.Uint16(data[26:28]),
AddressPrefix: data[28 : 28+uint32(prefixLen)],
ForwardingAddress: forwardingAddress,
}
case LinkLSAtype:
var prefixes []Prefix
var prefixOffset uint32 = 44
var j uint32
numOfPrefixes := binary.BigEndian.Uint32(data[40:44])
for j = 0; j < numOfPrefixes; j++ {
prefixLen := uint8(data[prefixOffset])
prefix := Prefix{
PrefixLength: prefixLen,
PrefixOptions: uint8(data[prefixOffset+1]),
AddressPrefix: data[prefixOffset+4 : prefixOffset+4+uint32(prefixLen)/8],
}
prefixes = append(prefixes, prefix)
prefixOffset = prefixOffset + 4 + uint32(prefixLen)/8
}
content = LinkLSA{
RtrPriority: uint8(data[20]),
Options: binary.BigEndian.Uint32(data[20:24]) & 0x00FFFFFF,
LinkLocalAddress: data[24:40],
NumOfPrefixes: numOfPrefixes,
Prefixes: prefixes,
}
case IntraAreaPrefixLSAtype:
var prefixes []Prefix
var prefixOffset uint32 = 32
var j uint16
numOfPrefixes := binary.BigEndian.Uint16(data[20:22])
for j = 0; j < numOfPrefixes; j++ {
prefixLen := uint8(data[prefixOffset])
prefix := Prefix{
PrefixLength: prefixLen,
PrefixOptions: uint8(data[prefixOffset+1]),
Metric: binary.BigEndian.Uint16(data[prefixOffset+2 : prefixOffset+4]),
AddressPrefix: data[prefixOffset+4 : prefixOffset+4+uint32(prefixLen)/8],
}
prefixes = append(prefixes, prefix)
prefixOffset = prefixOffset + 4 + uint32(prefixLen)
}
content = IntraAreaPrefixLSA{
NumOfPrefixes: numOfPrefixes,
RefLSType: binary.BigEndian.Uint16(data[22:24]),
RefLinkStateID: binary.BigEndian.Uint32(data[24:28]),
RefAdvRouter: binary.BigEndian.Uint32(data[28:32]),
Prefixes: prefixes,
}
default:
return nil, fmt.Errorf("Unknown Link State type.")
}
return content, nil
}
// getLSAs parses the LSA information from the packet for OSPFv3
func getLSAs(num uint32, data []byte) ([]LSA, error) {
var lsas []LSA
var i uint32 = 0
var offset uint32 = 0
for ; i < num; i++ {
var content interface{}
lstype := binary.BigEndian.Uint16(data[offset+2 : offset+4])
lsalength := binary.BigEndian.Uint16(data[offset+18 : offset+20])
content, err := extractLSAInformation(lstype, lsalength, data[offset:])
if err != nil {
return nil, fmt.Errorf("Could not extract Link State type.")
}
lsa := LSA{
LSAheader: LSAheader{
LSAge: binary.BigEndian.Uint16(data[offset : offset+2]),
LSType: lstype,
LinkStateID: binary.BigEndian.Uint32(data[offset+4 : offset+8]),
AdvRouter: binary.BigEndian.Uint32(data[offset+8 : offset+12]),
LSSeqNumber: binary.BigEndian.Uint32(data[offset+12 : offset+16]),
LSChecksum: binary.BigEndian.Uint16(data[offset+16 : offset+18]),
Length: lsalength,
},
Content: content,
}
lsas = append(lsas, lsa)
offset += uint32(lsalength)
}
return lsas, nil
}
// DecodeFromBytes decodes the given bytes into the OSPF layer.
func (ospf *OSPFv2) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 24 {
return fmt.Errorf("Packet too smal for OSPF Version 2")
}
ospf.Version = uint8(data[0])
ospf.Type = OSPFType(data[1])
ospf.PacketLength = binary.BigEndian.Uint16(data[2:4])
ospf.RouterID = binary.BigEndian.Uint32(data[4:8])
ospf.AreaID = binary.BigEndian.Uint32(data[8:12])
ospf.Checksum = binary.BigEndian.Uint16(data[12:14])
ospf.AuType = binary.BigEndian.Uint16(data[14:16])
ospf.Authentication = binary.BigEndian.Uint64(data[16:24])
switch ospf.Type {
case OSPFHello:
var neighbors []uint32
for i := 44; uint16(i+4) <= ospf.PacketLength; i += 4 {
neighbors = append(neighbors, binary.BigEndian.Uint32(data[i:i+4]))
}
ospf.Content = HelloPkgV2{
NetworkMask: binary.BigEndian.Uint32(data[24:28]),
HelloPkg: HelloPkg{
HelloInterval: binary.BigEndian.Uint16(data[28:30]),
Options: uint32(data[30]),
RtrPriority: uint8(data[31]),
RouterDeadInterval: binary.BigEndian.Uint32(data[32:36]),
DesignatedRouterID: binary.BigEndian.Uint32(data[36:40]),
BackupDesignatedRouterID: binary.BigEndian.Uint32(data[40:44]),
NeighborID: neighbors,
},
}
case OSPFDatabaseDescription:
var lsas []LSAheader
for i := 32; uint16(i+20) <= ospf.PacketLength; i += 20 {
lsa := LSAheader{
LSAge: binary.BigEndian.Uint16(data[i : i+2]),
LSType: binary.BigEndian.Uint16(data[i+2 : i+4]),
LinkStateID: binary.BigEndian.Uint32(data[i+4 : i+8]),
AdvRouter: binary.BigEndian.Uint32(data[i+8 : i+12]),
LSSeqNumber: binary.BigEndian.Uint32(data[i+12 : i+16]),
LSChecksum: binary.BigEndian.Uint16(data[i+16 : i+18]),
Length: binary.BigEndian.Uint16(data[i+18 : i+20]),
}
lsas = append(lsas, lsa)
}
ospf.Content = DbDescPkg{
InterfaceMTU: binary.BigEndian.Uint16(data[24:26]),
Options: uint32(data[26]),
Flags: uint16(data[27]),
DDSeqNumber: binary.BigEndian.Uint32(data[28:32]),
LSAinfo: lsas,
}
case OSPFLinkStateRequest:
var lsrs []LSReq
for i := 24; uint16(i+12) <= ospf.PacketLength; i += 12 {
lsr := LSReq{
LSType: binary.BigEndian.Uint16(data[i+2 : i+4]),
LSID: binary.BigEndian.Uint32(data[i+4 : i+8]),
AdvRouter: binary.BigEndian.Uint32(data[i+8 : i+12]),
}
lsrs = append(lsrs, lsr)
}
ospf.Content = lsrs
case OSPFLinkStateUpdate:
num := binary.BigEndian.Uint32(data[24:28])
lsas, err := getLSAsv2(num, data[28:])
if err != nil {
return fmt.Errorf("Cannot parse Link State Update packet: %v", err)
}
ospf.Content = LSUpdate{
NumOfLSAs: num,
LSAs: lsas,
}
case OSPFLinkStateAcknowledgment:
var lsas []LSAheader
for i := 24; uint16(i+20) <= ospf.PacketLength; i += 20 {
lsa := LSAheader{
LSAge: binary.BigEndian.Uint16(data[i : i+2]),
LSOptions: data[i+2],
LSType: uint16(data[i+3]),
LinkStateID: binary.BigEndian.Uint32(data[i+4 : i+8]),
AdvRouter: binary.BigEndian.Uint32(data[i+8 : i+12]),
LSSeqNumber: binary.BigEndian.Uint32(data[i+12 : i+16]),
LSChecksum: binary.BigEndian.Uint16(data[i+16 : i+18]),
Length: binary.BigEndian.Uint16(data[i+18 : i+20]),
}
lsas = append(lsas, lsa)
}
ospf.Content = lsas
}
return nil
}
// DecodeFromBytes decodes the given bytes into the OSPF layer.
func (ospf *OSPFv3) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 16 {
return fmt.Errorf("Packet too smal for OSPF Version 3")
}
ospf.Version = uint8(data[0])
ospf.Type = OSPFType(data[1])
ospf.PacketLength = binary.BigEndian.Uint16(data[2:4])
ospf.RouterID = binary.BigEndian.Uint32(data[4:8])
ospf.AreaID = binary.BigEndian.Uint32(data[8:12])
ospf.Checksum = binary.BigEndian.Uint16(data[12:14])
ospf.Instance = uint8(data[14])
ospf.Reserved = uint8(data[15])
switch ospf.Type {
case OSPFHello:
var neighbors []uint32
for i := 36; uint16(i+4) <= ospf.PacketLength; i += 4 {
neighbors = append(neighbors, binary.BigEndian.Uint32(data[i:i+4]))
}
ospf.Content = HelloPkg{
InterfaceID: binary.BigEndian.Uint32(data[16:20]),
RtrPriority: uint8(data[20]),
Options: binary.BigEndian.Uint32(data[21:25]) >> 8,
HelloInterval: binary.BigEndian.Uint16(data[24:26]),
RouterDeadInterval: uint32(binary.BigEndian.Uint16(data[26:28])),
DesignatedRouterID: binary.BigEndian.Uint32(data[28:32]),
BackupDesignatedRouterID: binary.BigEndian.Uint32(data[32:36]),
NeighborID: neighbors,
}
case OSPFDatabaseDescription:
var lsas []LSAheader
for i := 28; uint16(i+20) <= ospf.PacketLength; i += 20 {
lsa := LSAheader{
LSAge: binary.BigEndian.Uint16(data[i : i+2]),
LSType: binary.BigEndian.Uint16(data[i+2 : i+4]),
LinkStateID: binary.BigEndian.Uint32(data[i+4 : i+8]),
AdvRouter: binary.BigEndian.Uint32(data[i+8 : i+12]),
LSSeqNumber: binary.BigEndian.Uint32(data[i+12 : i+16]),
LSChecksum: binary.BigEndian.Uint16(data[i+16 : i+18]),
Length: binary.BigEndian.Uint16(data[i+18 : i+20]),
}
lsas = append(lsas, lsa)
}
ospf.Content = DbDescPkg{
Options: binary.BigEndian.Uint32(data[16:20]) & 0x00FFFFFF,
InterfaceMTU: binary.BigEndian.Uint16(data[20:22]),
Flags: binary.BigEndian.Uint16(data[22:24]),
DDSeqNumber: binary.BigEndian.Uint32(data[24:28]),
LSAinfo: lsas,
}
case OSPFLinkStateRequest:
var lsrs []LSReq
for i := 16; uint16(i+12) <= ospf.PacketLength; i += 12 {
lsr := LSReq{
LSType: binary.BigEndian.Uint16(data[i+2 : i+4]),
LSID: binary.BigEndian.Uint32(data[i+4 : i+8]),
AdvRouter: binary.BigEndian.Uint32(data[i+8 : i+12]),
}
lsrs = append(lsrs, lsr)
}
ospf.Content = lsrs
case OSPFLinkStateUpdate:
num := binary.BigEndian.Uint32(data[16:20])
lsas, err := getLSAs(num, data[20:])
if err != nil {
return fmt.Errorf("Cannot parse Link State Update packet: %v", err)
}
ospf.Content = LSUpdate{
NumOfLSAs: num,
LSAs: lsas,
}
case OSPFLinkStateAcknowledgment:
var lsas []LSAheader
for i := 16; uint16(i+20) <= ospf.PacketLength; i += 20 {
lsa := LSAheader{
LSAge: binary.BigEndian.Uint16(data[i : i+2]),
LSType: binary.BigEndian.Uint16(data[i+2 : i+4]),
LinkStateID: binary.BigEndian.Uint32(data[i+4 : i+8]),
AdvRouter: binary.BigEndian.Uint32(data[i+8 : i+12]),
LSSeqNumber: binary.BigEndian.Uint32(data[i+12 : i+16]),
LSChecksum: binary.BigEndian.Uint16(data[i+16 : i+18]),
Length: binary.BigEndian.Uint16(data[i+18 : i+20]),
}
lsas = append(lsas, lsa)
}
ospf.Content = lsas
default:
}
return nil
}
// LayerType returns LayerTypeOSPF
func (ospf *OSPFv2) LayerType() gopacket.LayerType {
return LayerTypeOSPF
}
func (ospf *OSPFv3) LayerType() gopacket.LayerType {
return LayerTypeOSPF
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (ospf *OSPFv2) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypeZero
}
func (ospf *OSPFv3) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypeZero
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (ospf *OSPFv2) CanDecode() gopacket.LayerClass {
return LayerTypeOSPF
}
func (ospf *OSPFv3) CanDecode() gopacket.LayerClass {
return LayerTypeOSPF
}
func decodeOSPF(data []byte, p gopacket.PacketBuilder) error {
if len(data) < 14 {
return fmt.Errorf("Packet too smal for OSPF")
}
switch uint8(data[0]) {
case 2:
ospf := &OSPFv2{}
return decodingLayerDecoder(ospf, data, p)
case 3:
ospf := &OSPFv3{}
return decodingLayerDecoder(ospf, data, p)
default:
}
return fmt.Errorf("Unable to determine OSPF type.")
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"github.com/google/gopacket"
)
type PFDirection uint8
const (
PFDirectionInOut PFDirection = 0
PFDirectionIn PFDirection = 1
PFDirectionOut PFDirection = 2
)
// PFLog provides the layer for 'pf' packet-filter logging, as described at
// http://www.freebsd.org/cgi/man.cgi?query=pflog&sektion=4
type PFLog struct {
BaseLayer
Length uint8
Family ProtocolFamily
Action, Reason uint8
IFName, Ruleset []byte
RuleNum, SubruleNum uint32
UID uint32
PID int32
RuleUID uint32
RulePID int32
Direction PFDirection
// The remainder is padding
}
func (pf *PFLog) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 60 {
df.SetTruncated()
return errors.New("PFLog data less than 60 bytes")
}
pf.Length = data[0]
pf.Family = ProtocolFamily(data[1])
pf.Action = data[2]
pf.Reason = data[3]
pf.IFName = data[4:20]
pf.Ruleset = data[20:36]
pf.RuleNum = binary.BigEndian.Uint32(data[36:40])
pf.SubruleNum = binary.BigEndian.Uint32(data[40:44])
pf.UID = binary.BigEndian.Uint32(data[44:48])
pf.PID = int32(binary.BigEndian.Uint32(data[48:52]))
pf.RuleUID = binary.BigEndian.Uint32(data[52:56])
pf.RulePID = int32(binary.BigEndian.Uint32(data[56:60]))
pf.Direction = PFDirection(data[60])
if pf.Length%4 != 1 {
return errors.New("PFLog header length should be 3 less than multiple of 4")
}
actualLength := int(pf.Length) + 3
if len(data) < actualLength {
return fmt.Errorf("PFLog data size < %d", actualLength)
}
pf.Contents = data[:actualLength]
pf.Payload = data[actualLength:]
return nil
}
// LayerType returns layers.LayerTypePFLog
func (pf *PFLog) LayerType() gopacket.LayerType { return LayerTypePFLog }
func (pf *PFLog) CanDecode() gopacket.LayerClass { return LayerTypePFLog }
func (pf *PFLog) NextLayerType() gopacket.LayerType {
return pf.Family.LayerType()
}
func decodePFLog(data []byte, p gopacket.PacketBuilder) error {
pf := &PFLog{}
return decodingLayerDecoder(pf, data, p)
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"fmt"
"strconv"
"github.com/google/gopacket"
)
// TCPPort is a port in a TCP layer.
type TCPPort uint16
// UDPPort is a port in a UDP layer.
type UDPPort uint16
// RUDPPort is a port in a RUDP layer.
type RUDPPort uint8
// SCTPPort is a port in a SCTP layer.
type SCTPPort uint16
// UDPLitePort is a port in a UDPLite layer.
type UDPLitePort uint16
// RUDPPortNames contains the string names for all RUDP ports.
var RUDPPortNames = map[RUDPPort]string{}
// UDPLitePortNames contains the string names for all UDPLite ports.
var UDPLitePortNames = map[UDPLitePort]string{}
// {TCP,UDP,SCTP}PortNames can be found in iana_ports.go
// String returns the port as "number(name)" if there's a well-known port name,
// or just "number" if there isn't. Well-known names are stored in
// TCPPortNames.
func (a TCPPort) String() string {
if name, ok := TCPPortNames[a]; ok {
return fmt.Sprintf("%d(%s)", a, name)
}
return strconv.Itoa(int(a))
}
// LayerType returns a LayerType that would be able to decode the
// application payload. It uses some well-known ports such as 53 for
// DNS.
//
// Returns gopacket.LayerTypePayload for unknown/unsupported port numbers.
func (a TCPPort) LayerType() gopacket.LayerType {
lt := tcpPortLayerType[uint16(a)]
if lt != 0 {
return lt
}
return gopacket.LayerTypePayload
}
var tcpPortLayerType = [65536]gopacket.LayerType{
53: LayerTypeDNS,
443: LayerTypeTLS, // https
502: LayerTypeModbusTCP, // modbustcp
636: LayerTypeTLS, // ldaps
989: LayerTypeTLS, // ftps-data
990: LayerTypeTLS, // ftps
992: LayerTypeTLS, // telnets
993: LayerTypeTLS, // imaps
994: LayerTypeTLS, // ircs
995: LayerTypeTLS, // pop3s
5061: LayerTypeTLS, // ips
}
// RegisterTCPPortLayerType creates a new mapping between a TCPPort
// and an underlaying LayerType.
func RegisterTCPPortLayerType(port TCPPort, layerType gopacket.LayerType) {
tcpPortLayerType[port] = layerType
}
// String returns the port as "number(name)" if there's a well-known port name,
// or just "number" if there isn't. Well-known names are stored in
// UDPPortNames.
func (a UDPPort) String() string {
if name, ok := UDPPortNames[a]; ok {
return fmt.Sprintf("%d(%s)", a, name)
}
return strconv.Itoa(int(a))
}
// LayerType returns a LayerType that would be able to decode the
// application payload. It uses some well-known ports such as 53 for
// DNS.
//
// Returns gopacket.LayerTypePayload for unknown/unsupported port numbers.
func (a UDPPort) LayerType() gopacket.LayerType {
lt := udpPortLayerType[uint16(a)]
if lt != 0 {
return lt
}
return gopacket.LayerTypePayload
}
var udpPortLayerType = [65536]gopacket.LayerType{
53: LayerTypeDNS,
123: LayerTypeNTP,
4789: LayerTypeVXLAN,
67: LayerTypeDHCPv4,
68: LayerTypeDHCPv4,
546: LayerTypeDHCPv6,
547: LayerTypeDHCPv6,
666: LayerTypeAGUEVar0,
1000: LayerTypeAPSP,
5060: LayerTypeSIP,
6343: LayerTypeSFlow,
6081: LayerTypeGeneve,
3784: LayerTypeBFD,
2152: LayerTypeGTPv1U,
623: LayerTypeRMCP,
1812: LayerTypeRADIUS,
}
// RegisterUDPPortLayerType creates a new mapping between a UDPPort
// and an underlaying LayerType.
func RegisterUDPPortLayerType(port UDPPort, layerType gopacket.LayerType) {
udpPortLayerType[port] = layerType
}
// String returns the port as "number(name)" if there's a well-known port name,
// or just "number" if there isn't. Well-known names are stored in
// RUDPPortNames.
func (a RUDPPort) String() string {
if name, ok := RUDPPortNames[a]; ok {
return fmt.Sprintf("%d(%s)", a, name)
}
return strconv.Itoa(int(a))
}
// String returns the port as "number(name)" if there's a well-known port name,
// or just "number" if there isn't. Well-known names are stored in
// SCTPPortNames.
func (a SCTPPort) String() string {
if name, ok := SCTPPortNames[a]; ok {
return fmt.Sprintf("%d(%s)", a, name)
}
return strconv.Itoa(int(a))
}
// String returns the port as "number(name)" if there's a well-known port name,
// or just "number" if there isn't. Well-known names are stored in
// UDPLitePortNames.
func (a UDPLitePort) String() string {
if name, ok := UDPLitePortNames[a]; ok {
return fmt.Sprintf("%d(%s)", a, name)
}
return strconv.Itoa(int(a))
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"github.com/google/gopacket"
)
// PPP is the layer for PPP encapsulation headers.
type PPP struct {
BaseLayer
PPPType PPPType
HasPPTPHeader bool
}
// PPPEndpoint is a singleton endpoint for PPP. Since there is no actual
// addressing for the two ends of a PPP connection, we use a singleton value
// named 'point' for each endpoint.
var PPPEndpoint = gopacket.NewEndpoint(EndpointPPP, nil)
// PPPFlow is a singleton flow for PPP. Since there is no actual addressing for
// the two ends of a PPP connection, we use a singleton value to represent the
// flow for all PPP connections.
var PPPFlow = gopacket.NewFlow(EndpointPPP, nil, nil)
// LayerType returns LayerTypePPP
func (p *PPP) LayerType() gopacket.LayerType { return LayerTypePPP }
// LinkFlow returns PPPFlow.
func (p *PPP) LinkFlow() gopacket.Flow { return PPPFlow }
func decodePPP(data []byte, p gopacket.PacketBuilder) error {
ppp := &PPP{}
offset := 0
if data[0] == 0xff && data[1] == 0x03 {
offset = 2
ppp.HasPPTPHeader = true
}
if data[offset]&0x1 == 0 {
if data[offset+1]&0x1 == 0 {
return errors.New("PPP has invalid type")
}
ppp.PPPType = PPPType(binary.BigEndian.Uint16(data[offset : offset+2]))
ppp.Contents = data[offset : offset+2]
ppp.Payload = data[offset+2:]
} else {
ppp.PPPType = PPPType(data[offset])
ppp.Contents = data[offset : offset+1]
ppp.Payload = data[offset+1:]
}
p.AddLayer(ppp)
p.SetLinkLayer(ppp)
return p.NextDecoder(ppp.PPPType)
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (p *PPP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
if p.PPPType&0x100 == 0 {
bytes, err := b.PrependBytes(2)
if err != nil {
return err
}
binary.BigEndian.PutUint16(bytes, uint16(p.PPPType))
} else {
bytes, err := b.PrependBytes(1)
if err != nil {
return err
}
bytes[0] = uint8(p.PPPType)
}
if p.HasPPTPHeader {
bytes, err := b.PrependBytes(2)
if err != nil {
return err
}
bytes[0] = 0xff
bytes[1] = 0x03
}
return nil
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"github.com/google/gopacket"
)
// PPPoE is the layer for PPPoE encapsulation headers.
type PPPoE struct {
BaseLayer
Version uint8
Type uint8
Code PPPoECode
SessionId uint16
Length uint16
}
// LayerType returns gopacket.LayerTypePPPoE.
func (p *PPPoE) LayerType() gopacket.LayerType {
return LayerTypePPPoE
}
// decodePPPoE decodes the PPPoE header (see http://tools.ietf.org/html/rfc2516).
func decodePPPoE(data []byte, p gopacket.PacketBuilder) error {
pppoe := &PPPoE{
Version: data[0] >> 4,
Type: data[0] & 0x0F,
Code: PPPoECode(data[1]),
SessionId: binary.BigEndian.Uint16(data[2:4]),
Length: binary.BigEndian.Uint16(data[4:6]),
}
pppoe.BaseLayer = BaseLayer{data[:6], data[6 : 6+pppoe.Length]}
p.AddLayer(pppoe)
return p.NextDecoder(pppoe.Code)
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (p *PPPoE) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
payload := b.Bytes()
bytes, err := b.PrependBytes(6)
if err != nil {
return err
}
bytes[0] = (p.Version << 4) | p.Type
bytes[1] = byte(p.Code)
binary.BigEndian.PutUint16(bytes[2:], p.SessionId)
if opts.FixLengths {
p.Length = uint16(len(payload))
}
binary.BigEndian.PutUint16(bytes[4:], p.Length)
return nil
}
// Copyright 2015 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
// http://www.tcpdump.org/linktypes/LINKTYPE_IEEE802_11_PRISM.html
package layers
import (
"encoding/binary"
"errors"
"github.com/google/gopacket"
)
func decodePrismValue(data []byte, pv *PrismValue) {
pv.DID = PrismDID(binary.LittleEndian.Uint32(data[0:4]))
pv.Status = binary.LittleEndian.Uint16(data[4:6])
pv.Length = binary.LittleEndian.Uint16(data[6:8])
pv.Data = data[8 : 8+pv.Length]
}
type PrismDID uint32
const (
PrismDIDType1HostTime PrismDID = 0x10044
PrismDIDType2HostTime PrismDID = 0x01041
PrismDIDType1MACTime PrismDID = 0x20044
PrismDIDType2MACTime PrismDID = 0x02041
PrismDIDType1Channel PrismDID = 0x30044
PrismDIDType2Channel PrismDID = 0x03041
PrismDIDType1RSSI PrismDID = 0x40044
PrismDIDType2RSSI PrismDID = 0x04041
PrismDIDType1SignalQuality PrismDID = 0x50044
PrismDIDType2SignalQuality PrismDID = 0x05041
PrismDIDType1Signal PrismDID = 0x60044
PrismDIDType2Signal PrismDID = 0x06041
PrismDIDType1Noise PrismDID = 0x70044
PrismDIDType2Noise PrismDID = 0x07041
PrismDIDType1Rate PrismDID = 0x80044
PrismDIDType2Rate PrismDID = 0x08041
PrismDIDType1TransmittedFrameIndicator PrismDID = 0x90044
PrismDIDType2TransmittedFrameIndicator PrismDID = 0x09041
PrismDIDType1FrameLength PrismDID = 0xA0044
PrismDIDType2FrameLength PrismDID = 0x0A041
)
const (
PrismType1MessageCode uint16 = 0x00000044
PrismType2MessageCode uint16 = 0x00000041
)
func (p PrismDID) String() string {
dids := map[PrismDID]string{
PrismDIDType1HostTime: "Host Time",
PrismDIDType2HostTime: "Host Time",
PrismDIDType1MACTime: "MAC Time",
PrismDIDType2MACTime: "MAC Time",
PrismDIDType1Channel: "Channel",
PrismDIDType2Channel: "Channel",
PrismDIDType1RSSI: "RSSI",
PrismDIDType2RSSI: "RSSI",
PrismDIDType1SignalQuality: "Signal Quality",
PrismDIDType2SignalQuality: "Signal Quality",
PrismDIDType1Signal: "Signal",
PrismDIDType2Signal: "Signal",
PrismDIDType1Noise: "Noise",
PrismDIDType2Noise: "Noise",
PrismDIDType1Rate: "Rate",
PrismDIDType2Rate: "Rate",
PrismDIDType1TransmittedFrameIndicator: "Transmitted Frame Indicator",
PrismDIDType2TransmittedFrameIndicator: "Transmitted Frame Indicator",
PrismDIDType1FrameLength: "Frame Length",
PrismDIDType2FrameLength: "Frame Length",
}
if str, ok := dids[p]; ok {
return str
}
return "Unknown DID"
}
type PrismValue struct {
DID PrismDID
Status uint16
Length uint16
Data []byte
}
func (pv *PrismValue) IsSupplied() bool {
return pv.Status == 1
}
var ErrPrismExpectedMoreData = errors.New("Expected more data.")
var ErrPrismInvalidCode = errors.New("Invalid header code.")
func decodePrismHeader(data []byte, p gopacket.PacketBuilder) error {
d := &PrismHeader{}
return decodingLayerDecoder(d, data, p)
}
type PrismHeader struct {
BaseLayer
Code uint16
Length uint16
DeviceName string
Values []PrismValue
}
func (m *PrismHeader) LayerType() gopacket.LayerType { return LayerTypePrismHeader }
func (m *PrismHeader) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
m.Code = binary.LittleEndian.Uint16(data[0:4])
m.Length = binary.LittleEndian.Uint16(data[4:8])
m.DeviceName = string(data[8:24])
m.BaseLayer = BaseLayer{Contents: data[:m.Length], Payload: data[m.Length:len(data)]}
switch m.Code {
case PrismType1MessageCode:
fallthrough
case PrismType2MessageCode:
// valid message code
default:
return ErrPrismInvalidCode
}
offset := uint16(24)
m.Values = make([]PrismValue, (m.Length-offset)/12)
for i := 0; i < len(m.Values); i++ {
decodePrismValue(data[offset:offset+12], &m.Values[i])
offset += 12
}
if offset != m.Length {
return ErrPrismExpectedMoreData
}
return nil
}
func (m *PrismHeader) CanDecode() gopacket.LayerClass { return LayerTypePrismHeader }
func (m *PrismHeader) NextLayerType() gopacket.LayerType { return LayerTypeDot11 }
// Copyright 2014 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"hash/crc32"
"strings"
"github.com/google/gopacket"
)
// align calculates the number of bytes needed to align with the width
// on the offset, returning the number of bytes we need to skip to
// align to the offset (width).
func align(offset uint16, width uint16) uint16 {
return ((((offset) + ((width) - 1)) & (^((width) - 1))) - offset)
}
type RadioTapPresent uint32
const (
RadioTapPresentTSFT RadioTapPresent = 1 << iota
RadioTapPresentFlags
RadioTapPresentRate
RadioTapPresentChannel
RadioTapPresentFHSS
RadioTapPresentDBMAntennaSignal
RadioTapPresentDBMAntennaNoise
RadioTapPresentLockQuality
RadioTapPresentTxAttenuation
RadioTapPresentDBTxAttenuation
RadioTapPresentDBMTxPower
RadioTapPresentAntenna
RadioTapPresentDBAntennaSignal
RadioTapPresentDBAntennaNoise
RadioTapPresentRxFlags
RadioTapPresentTxFlags
RadioTapPresentRtsRetries
RadioTapPresentDataRetries
_
RadioTapPresentMCS
RadioTapPresentAMPDUStatus
RadioTapPresentVHT
RadioTapPresentEXT RadioTapPresent = 1 << 31
)
func (r RadioTapPresent) TSFT() bool {
return r&RadioTapPresentTSFT != 0
}
func (r RadioTapPresent) Flags() bool {
return r&RadioTapPresentFlags != 0
}
func (r RadioTapPresent) Rate() bool {
return r&RadioTapPresentRate != 0
}
func (r RadioTapPresent) Channel() bool {
return r&RadioTapPresentChannel != 0
}
func (r RadioTapPresent) FHSS() bool {
return r&RadioTapPresentFHSS != 0
}
func (r RadioTapPresent) DBMAntennaSignal() bool {
return r&RadioTapPresentDBMAntennaSignal != 0
}
func (r RadioTapPresent) DBMAntennaNoise() bool {
return r&RadioTapPresentDBMAntennaNoise != 0
}
func (r RadioTapPresent) LockQuality() bool {
return r&RadioTapPresentLockQuality != 0
}
func (r RadioTapPresent) TxAttenuation() bool {
return r&RadioTapPresentTxAttenuation != 0
}
func (r RadioTapPresent) DBTxAttenuation() bool {
return r&RadioTapPresentDBTxAttenuation != 0
}
func (r RadioTapPresent) DBMTxPower() bool {
return r&RadioTapPresentDBMTxPower != 0
}
func (r RadioTapPresent) Antenna() bool {
return r&RadioTapPresentAntenna != 0
}
func (r RadioTapPresent) DBAntennaSignal() bool {
return r&RadioTapPresentDBAntennaSignal != 0
}
func (r RadioTapPresent) DBAntennaNoise() bool {
return r&RadioTapPresentDBAntennaNoise != 0
}
func (r RadioTapPresent) RxFlags() bool {
return r&RadioTapPresentRxFlags != 0
}
func (r RadioTapPresent) TxFlags() bool {
return r&RadioTapPresentTxFlags != 0
}
func (r RadioTapPresent) RtsRetries() bool {
return r&RadioTapPresentRtsRetries != 0
}
func (r RadioTapPresent) DataRetries() bool {
return r&RadioTapPresentDataRetries != 0
}
func (r RadioTapPresent) MCS() bool {
return r&RadioTapPresentMCS != 0
}
func (r RadioTapPresent) AMPDUStatus() bool {
return r&RadioTapPresentAMPDUStatus != 0
}
func (r RadioTapPresent) VHT() bool {
return r&RadioTapPresentVHT != 0
}
func (r RadioTapPresent) EXT() bool {
return r&RadioTapPresentEXT != 0
}
type RadioTapChannelFlags uint16
const (
RadioTapChannelFlagsTurbo RadioTapChannelFlags = 0x0010 // Turbo channel
RadioTapChannelFlagsCCK RadioTapChannelFlags = 0x0020 // CCK channel
RadioTapChannelFlagsOFDM RadioTapChannelFlags = 0x0040 // OFDM channel
RadioTapChannelFlagsGhz2 RadioTapChannelFlags = 0x0080 // 2 GHz spectrum channel.
RadioTapChannelFlagsGhz5 RadioTapChannelFlags = 0x0100 // 5 GHz spectrum channel
RadioTapChannelFlagsPassive RadioTapChannelFlags = 0x0200 // Only passive scan allowed
RadioTapChannelFlagsDynamic RadioTapChannelFlags = 0x0400 // Dynamic CCK-OFDM channel
RadioTapChannelFlagsGFSK RadioTapChannelFlags = 0x0800 // GFSK channel (FHSS PHY)
)
func (r RadioTapChannelFlags) Turbo() bool {
return r&RadioTapChannelFlagsTurbo != 0
}
func (r RadioTapChannelFlags) CCK() bool {
return r&RadioTapChannelFlagsCCK != 0
}
func (r RadioTapChannelFlags) OFDM() bool {
return r&RadioTapChannelFlagsOFDM != 0
}
func (r RadioTapChannelFlags) Ghz2() bool {
return r&RadioTapChannelFlagsGhz2 != 0
}
func (r RadioTapChannelFlags) Ghz5() bool {
return r&RadioTapChannelFlagsGhz5 != 0
}
func (r RadioTapChannelFlags) Passive() bool {
return r&RadioTapChannelFlagsPassive != 0
}
func (r RadioTapChannelFlags) Dynamic() bool {
return r&RadioTapChannelFlagsDynamic != 0
}
func (r RadioTapChannelFlags) GFSK() bool {
return r&RadioTapChannelFlagsGFSK != 0
}
// String provides a human readable string for RadioTapChannelFlags.
// This string is possibly subject to change over time; if you're storing this
// persistently, you should probably store the RadioTapChannelFlags value, not its string.
func (a RadioTapChannelFlags) String() string {
var out bytes.Buffer
if a.Turbo() {
out.WriteString("Turbo,")
}
if a.CCK() {
out.WriteString("CCK,")
}
if a.OFDM() {
out.WriteString("OFDM,")
}
if a.Ghz2() {
out.WriteString("Ghz2,")
}
if a.Ghz5() {
out.WriteString("Ghz5,")
}
if a.Passive() {
out.WriteString("Passive,")
}
if a.Dynamic() {
out.WriteString("Dynamic,")
}
if a.GFSK() {
out.WriteString("GFSK,")
}
if length := out.Len(); length > 0 {
return string(out.Bytes()[:length-1]) // strip final comma
}
return ""
}
type RadioTapFlags uint8
const (
RadioTapFlagsCFP RadioTapFlags = 1 << iota // sent/received during CFP
RadioTapFlagsShortPreamble // sent/received * with short * preamble
RadioTapFlagsWEP // sent/received * with WEP encryption
RadioTapFlagsFrag // sent/received * with fragmentation
RadioTapFlagsFCS // frame includes FCS
RadioTapFlagsDatapad // frame has padding between * 802.11 header and payload * (to 32-bit boundary)
RadioTapFlagsBadFCS // does not pass FCS check
RadioTapFlagsShortGI // HT short GI
)
func (r RadioTapFlags) CFP() bool {
return r&RadioTapFlagsCFP != 0
}
func (r RadioTapFlags) ShortPreamble() bool {
return r&RadioTapFlagsShortPreamble != 0
}
func (r RadioTapFlags) WEP() bool {
return r&RadioTapFlagsWEP != 0
}
func (r RadioTapFlags) Frag() bool {
return r&RadioTapFlagsFrag != 0
}
func (r RadioTapFlags) FCS() bool {
return r&RadioTapFlagsFCS != 0
}
func (r RadioTapFlags) Datapad() bool {
return r&RadioTapFlagsDatapad != 0
}
func (r RadioTapFlags) BadFCS() bool {
return r&RadioTapFlagsBadFCS != 0
}
func (r RadioTapFlags) ShortGI() bool {
return r&RadioTapFlagsShortGI != 0
}
// String provides a human readable string for RadioTapFlags.
// This string is possibly subject to change over time; if you're storing this
// persistently, you should probably store the RadioTapFlags value, not its string.
func (a RadioTapFlags) String() string {
var out bytes.Buffer
if a.CFP() {
out.WriteString("CFP,")
}
if a.ShortPreamble() {
out.WriteString("SHORT-PREAMBLE,")
}
if a.WEP() {
out.WriteString("WEP,")
}
if a.Frag() {
out.WriteString("FRAG,")
}
if a.FCS() {
out.WriteString("FCS,")
}
if a.Datapad() {
out.WriteString("DATAPAD,")
}
if a.ShortGI() {
out.WriteString("SHORT-GI,")
}
if length := out.Len(); length > 0 {
return string(out.Bytes()[:length-1]) // strip final comma
}
return ""
}
type RadioTapRate uint8
func (a RadioTapRate) String() string {
return fmt.Sprintf("%v Mb/s", 0.5*float32(a))
}
type RadioTapChannelFrequency uint16
func (a RadioTapChannelFrequency) String() string {
return fmt.Sprintf("%d MHz", a)
}
type RadioTapRxFlags uint16
const (
RadioTapRxFlagsBadPlcp RadioTapRxFlags = 0x0002
)
func (self RadioTapRxFlags) BadPlcp() bool {
return self&RadioTapRxFlagsBadPlcp != 0
}
func (self RadioTapRxFlags) String() string {
if self.BadPlcp() {
return "BADPLCP"
}
return ""
}
type RadioTapTxFlags uint16
const (
RadioTapTxFlagsFail RadioTapTxFlags = 1 << iota
RadioTapTxFlagsCTS
RadioTapTxFlagsRTS
RadioTapTxFlagsNoACK
)
func (self RadioTapTxFlags) Fail() bool { return self&RadioTapTxFlagsFail != 0 }
func (self RadioTapTxFlags) CTS() bool { return self&RadioTapTxFlagsCTS != 0 }
func (self RadioTapTxFlags) RTS() bool { return self&RadioTapTxFlagsRTS != 0 }
func (self RadioTapTxFlags) NoACK() bool { return self&RadioTapTxFlagsNoACK != 0 }
func (self RadioTapTxFlags) String() string {
var tokens []string
if self.Fail() {
tokens = append(tokens, "Fail")
}
if self.CTS() {
tokens = append(tokens, "CTS")
}
if self.RTS() {
tokens = append(tokens, "RTS")
}
if self.NoACK() {
tokens = append(tokens, "NoACK")
}
return strings.Join(tokens, ",")
}
type RadioTapMCS struct {
Known RadioTapMCSKnown
Flags RadioTapMCSFlags
MCS uint8
}
func (self RadioTapMCS) String() string {
var tokens []string
if self.Known.Bandwidth() {
token := "?"
switch self.Flags.Bandwidth() {
case 0:
token = "20"
case 1:
token = "40"
case 2:
token = "40(20L)"
case 3:
token = "40(20U)"
}
tokens = append(tokens, token)
}
if self.Known.MCSIndex() {
tokens = append(tokens, fmt.Sprintf("MCSIndex#%d", self.MCS))
}
if self.Known.GuardInterval() {
if self.Flags.ShortGI() {
tokens = append(tokens, fmt.Sprintf("shortGI"))
} else {
tokens = append(tokens, fmt.Sprintf("longGI"))
}
}
if self.Known.HTFormat() {
if self.Flags.Greenfield() {
tokens = append(tokens, fmt.Sprintf("HT-greenfield"))
} else {
tokens = append(tokens, fmt.Sprintf("HT-mixed"))
}
}
if self.Known.FECType() {
if self.Flags.FECLDPC() {
tokens = append(tokens, fmt.Sprintf("LDPC"))
} else {
tokens = append(tokens, fmt.Sprintf("BCC"))
}
}
if self.Known.STBC() {
tokens = append(tokens, fmt.Sprintf("STBC#%d", self.Flags.STBC()))
}
if self.Known.NESS() {
num := 0
if self.Known.NESS1() {
num |= 0x02
}
if self.Flags.NESS0() {
num |= 0x01
}
tokens = append(tokens, fmt.Sprintf("num-of-ESS#%d", num))
}
return strings.Join(tokens, ",")
}
type RadioTapMCSKnown uint8
const (
RadioTapMCSKnownBandwidth RadioTapMCSKnown = 1 << iota
RadioTapMCSKnownMCSIndex
RadioTapMCSKnownGuardInterval
RadioTapMCSKnownHTFormat
RadioTapMCSKnownFECType
RadioTapMCSKnownSTBC
RadioTapMCSKnownNESS
RadioTapMCSKnownNESS1
)
func (self RadioTapMCSKnown) Bandwidth() bool { return self&RadioTapMCSKnownBandwidth != 0 }
func (self RadioTapMCSKnown) MCSIndex() bool { return self&RadioTapMCSKnownMCSIndex != 0 }
func (self RadioTapMCSKnown) GuardInterval() bool { return self&RadioTapMCSKnownGuardInterval != 0 }
func (self RadioTapMCSKnown) HTFormat() bool { return self&RadioTapMCSKnownHTFormat != 0 }
func (self RadioTapMCSKnown) FECType() bool { return self&RadioTapMCSKnownFECType != 0 }
func (self RadioTapMCSKnown) STBC() bool { return self&RadioTapMCSKnownSTBC != 0 }
func (self RadioTapMCSKnown) NESS() bool { return self&RadioTapMCSKnownNESS != 0 }
func (self RadioTapMCSKnown) NESS1() bool { return self&RadioTapMCSKnownNESS1 != 0 }
type RadioTapMCSFlags uint8
const (
RadioTapMCSFlagsBandwidthMask RadioTapMCSFlags = 0x03
RadioTapMCSFlagsShortGI = 0x04
RadioTapMCSFlagsGreenfield = 0x08
RadioTapMCSFlagsFECLDPC = 0x10
RadioTapMCSFlagsSTBCMask = 0x60
RadioTapMCSFlagsNESS0 = 0x80
)
func (self RadioTapMCSFlags) Bandwidth() int {
return int(self & RadioTapMCSFlagsBandwidthMask)
}
func (self RadioTapMCSFlags) ShortGI() bool { return self&RadioTapMCSFlagsShortGI != 0 }
func (self RadioTapMCSFlags) Greenfield() bool { return self&RadioTapMCSFlagsGreenfield != 0 }
func (self RadioTapMCSFlags) FECLDPC() bool { return self&RadioTapMCSFlagsFECLDPC != 0 }
func (self RadioTapMCSFlags) STBC() int {
return int(self&RadioTapMCSFlagsSTBCMask) >> 5
}
func (self RadioTapMCSFlags) NESS0() bool { return self&RadioTapMCSFlagsNESS0 != 0 }
type RadioTapAMPDUStatus struct {
Reference uint32
Flags RadioTapAMPDUStatusFlags
CRC uint8
}
func (self RadioTapAMPDUStatus) String() string {
tokens := []string{
fmt.Sprintf("ref#%x", self.Reference),
}
if self.Flags.ReportZerolen() && self.Flags.IsZerolen() {
tokens = append(tokens, fmt.Sprintf("zero-length"))
}
if self.Flags.LastKnown() && self.Flags.IsLast() {
tokens = append(tokens, "last")
}
if self.Flags.DelimCRCErr() {
tokens = append(tokens, "delimiter CRC error")
}
if self.Flags.DelimCRCKnown() {
tokens = append(tokens, fmt.Sprintf("delimiter-CRC=%02x", self.CRC))
}
return strings.Join(tokens, ",")
}
type RadioTapAMPDUStatusFlags uint16
const (
RadioTapAMPDUStatusFlagsReportZerolen RadioTapAMPDUStatusFlags = 1 << iota
RadioTapAMPDUIsZerolen
RadioTapAMPDULastKnown
RadioTapAMPDUIsLast
RadioTapAMPDUDelimCRCErr
RadioTapAMPDUDelimCRCKnown
)
func (self RadioTapAMPDUStatusFlags) ReportZerolen() bool {
return self&RadioTapAMPDUStatusFlagsReportZerolen != 0
}
func (self RadioTapAMPDUStatusFlags) IsZerolen() bool { return self&RadioTapAMPDUIsZerolen != 0 }
func (self RadioTapAMPDUStatusFlags) LastKnown() bool { return self&RadioTapAMPDULastKnown != 0 }
func (self RadioTapAMPDUStatusFlags) IsLast() bool { return self&RadioTapAMPDUIsLast != 0 }
func (self RadioTapAMPDUStatusFlags) DelimCRCErr() bool { return self&RadioTapAMPDUDelimCRCErr != 0 }
func (self RadioTapAMPDUStatusFlags) DelimCRCKnown() bool {
return self&RadioTapAMPDUDelimCRCKnown != 0
}
type RadioTapVHT struct {
Known RadioTapVHTKnown
Flags RadioTapVHTFlags
Bandwidth uint8
MCSNSS [4]RadioTapVHTMCSNSS
Coding uint8
GroupId uint8
PartialAID uint16
}
func (self RadioTapVHT) String() string {
var tokens []string
if self.Known.STBC() {
if self.Flags.STBC() {
tokens = append(tokens, "STBC")
} else {
tokens = append(tokens, "no STBC")
}
}
if self.Known.TXOPPSNotAllowed() {
if self.Flags.TXOPPSNotAllowed() {
tokens = append(tokens, "TXOP doze not allowed")
} else {
tokens = append(tokens, "TXOP doze allowed")
}
}
if self.Known.GI() {
if self.Flags.SGI() {
tokens = append(tokens, "short GI")
} else {
tokens = append(tokens, "long GI")
}
}
if self.Known.SGINSYMDisambiguation() {
if self.Flags.SGINSYMMod() {
tokens = append(tokens, "NSYM mod 10=9")
} else {
tokens = append(tokens, "NSYM mod 10!=9 or no short GI")
}
}
if self.Known.LDPCExtraOFDMSymbol() {
if self.Flags.LDPCExtraOFDMSymbol() {
tokens = append(tokens, "LDPC extra OFDM symbols")
} else {
tokens = append(tokens, "no LDPC extra OFDM symbols")
}
}
if self.Known.Beamformed() {
if self.Flags.Beamformed() {
tokens = append(tokens, "beamformed")
} else {
tokens = append(tokens, "no beamformed")
}
}
if self.Known.Bandwidth() {
token := "?"
switch self.Bandwidth & 0x1f {
case 0:
token = "20"
case 1:
token = "40"
case 2:
token = "40(20L)"
case 3:
token = "40(20U)"
case 4:
token = "80"
case 5:
token = "80(40L)"
case 6:
token = "80(40U)"
case 7:
token = "80(20LL)"
case 8:
token = "80(20LU)"
case 9:
token = "80(20UL)"
case 10:
token = "80(20UU)"
case 11:
token = "160"
case 12:
token = "160(80L)"
case 13:
token = "160(80U)"
case 14:
token = "160(40LL)"
case 15:
token = "160(40LU)"
case 16:
token = "160(40UL)"
case 17:
token = "160(40UU)"
case 18:
token = "160(20LLL)"
case 19:
token = "160(20LLU)"
case 20:
token = "160(20LUL)"
case 21:
token = "160(20LUU)"
case 22:
token = "160(20ULL)"
case 23:
token = "160(20ULU)"
case 24:
token = "160(20UUL)"
case 25:
token = "160(20UUU)"
}
tokens = append(tokens, token)
}
for i, MCSNSS := range self.MCSNSS {
if MCSNSS.Present() {
fec := "?"
switch self.Coding & (1 << uint8(i)) {
case 0:
fec = "BCC"
case 1:
fec = "LDPC"
}
tokens = append(tokens, fmt.Sprintf("user%d(%s,%s)", i, MCSNSS.String(), fec))
}
}
if self.Known.GroupId() {
tokens = append(tokens,
fmt.Sprintf("group=%d", self.GroupId))
}
if self.Known.PartialAID() {
tokens = append(tokens,
fmt.Sprintf("partial-AID=%d", self.PartialAID))
}
return strings.Join(tokens, ",")
}
type RadioTapVHTKnown uint16
const (
RadioTapVHTKnownSTBC RadioTapVHTKnown = 1 << iota
RadioTapVHTKnownTXOPPSNotAllowed
RadioTapVHTKnownGI
RadioTapVHTKnownSGINSYMDisambiguation
RadioTapVHTKnownLDPCExtraOFDMSymbol
RadioTapVHTKnownBeamformed
RadioTapVHTKnownBandwidth
RadioTapVHTKnownGroupId
RadioTapVHTKnownPartialAID
)
func (self RadioTapVHTKnown) STBC() bool { return self&RadioTapVHTKnownSTBC != 0 }
func (self RadioTapVHTKnown) TXOPPSNotAllowed() bool {
return self&RadioTapVHTKnownTXOPPSNotAllowed != 0
}
func (self RadioTapVHTKnown) GI() bool { return self&RadioTapVHTKnownGI != 0 }
func (self RadioTapVHTKnown) SGINSYMDisambiguation() bool {
return self&RadioTapVHTKnownSGINSYMDisambiguation != 0
}
func (self RadioTapVHTKnown) LDPCExtraOFDMSymbol() bool {
return self&RadioTapVHTKnownLDPCExtraOFDMSymbol != 0
}
func (self RadioTapVHTKnown) Beamformed() bool { return self&RadioTapVHTKnownBeamformed != 0 }
func (self RadioTapVHTKnown) Bandwidth() bool { return self&RadioTapVHTKnownBandwidth != 0 }
func (self RadioTapVHTKnown) GroupId() bool { return self&RadioTapVHTKnownGroupId != 0 }
func (self RadioTapVHTKnown) PartialAID() bool { return self&RadioTapVHTKnownPartialAID != 0 }
type RadioTapVHTFlags uint8
const (
RadioTapVHTFlagsSTBC RadioTapVHTFlags = 1 << iota
RadioTapVHTFlagsTXOPPSNotAllowed
RadioTapVHTFlagsSGI
RadioTapVHTFlagsSGINSYMMod
RadioTapVHTFlagsLDPCExtraOFDMSymbol
RadioTapVHTFlagsBeamformed
)
func (self RadioTapVHTFlags) STBC() bool { return self&RadioTapVHTFlagsSTBC != 0 }
func (self RadioTapVHTFlags) TXOPPSNotAllowed() bool {
return self&RadioTapVHTFlagsTXOPPSNotAllowed != 0
}
func (self RadioTapVHTFlags) SGI() bool { return self&RadioTapVHTFlagsSGI != 0 }
func (self RadioTapVHTFlags) SGINSYMMod() bool { return self&RadioTapVHTFlagsSGINSYMMod != 0 }
func (self RadioTapVHTFlags) LDPCExtraOFDMSymbol() bool {
return self&RadioTapVHTFlagsLDPCExtraOFDMSymbol != 0
}
func (self RadioTapVHTFlags) Beamformed() bool { return self&RadioTapVHTFlagsBeamformed != 0 }
type RadioTapVHTMCSNSS uint8
func (self RadioTapVHTMCSNSS) Present() bool {
return self&0x0F != 0
}
func (self RadioTapVHTMCSNSS) String() string {
return fmt.Sprintf("NSS#%dMCS#%d", uint32(self&0xf), uint32(self>>4))
}
func decodeRadioTap(data []byte, p gopacket.PacketBuilder) error {
d := &RadioTap{}
// TODO: Should we set LinkLayer here? And implement LinkFlow
return decodingLayerDecoder(d, data, p)
}
type RadioTap struct {
BaseLayer
// Version 0. Only increases for drastic changes, introduction of compatible new fields does not count.
Version uint8
// Length of the whole header in bytes, including it_version, it_pad, it_len, and data fields.
Length uint16
// Present is a bitmap telling which fields are present. Set bit 31 (0x80000000) to extend the bitmap by another 32 bits. Additional extensions are made by setting bit 31.
Present RadioTapPresent
// TSFT: value in microseconds of the MAC's 64-bit 802.11 Time Synchronization Function timer when the first bit of the MPDU arrived at the MAC. For received frames, only.
TSFT uint64
Flags RadioTapFlags
// Rate Tx/Rx data rate
Rate RadioTapRate
// ChannelFrequency Tx/Rx frequency in MHz, followed by flags
ChannelFrequency RadioTapChannelFrequency
ChannelFlags RadioTapChannelFlags
// FHSS For frequency-hopping radios, the hop set (first byte) and pattern (second byte).
FHSS uint16
// DBMAntennaSignal RF signal power at the antenna, decibel difference from one milliwatt.
DBMAntennaSignal int8
// DBMAntennaNoise RF noise power at the antenna, decibel difference from one milliwatt.
DBMAntennaNoise int8
// LockQuality Quality of Barker code lock. Unitless. Monotonically nondecreasing with "better" lock strength. Called "Signal Quality" in datasheets.
LockQuality uint16
// TxAttenuation Transmit power expressed as unitless distance from max power set at factory calibration. 0 is max power. Monotonically nondecreasing with lower power levels.
TxAttenuation uint16
// DBTxAttenuation Transmit power expressed as decibel distance from max power set at factory calibration. 0 is max power. Monotonically nondecreasing with lower power levels.
DBTxAttenuation uint16
// DBMTxPower Transmit power expressed as dBm (decibels from a 1 milliwatt reference). This is the absolute power level measured at the antenna port.
DBMTxPower int8
// Antenna Unitless indication of the Rx/Tx antenna for this packet. The first antenna is antenna 0.
Antenna uint8
// DBAntennaSignal RF signal power at the antenna, decibel difference from an arbitrary, fixed reference.
DBAntennaSignal uint8
// DBAntennaNoise RF noise power at the antenna, decibel difference from an arbitrary, fixed reference point.
DBAntennaNoise uint8
//
RxFlags RadioTapRxFlags
TxFlags RadioTapTxFlags
RtsRetries uint8
DataRetries uint8
MCS RadioTapMCS
AMPDUStatus RadioTapAMPDUStatus
VHT RadioTapVHT
}
func (m *RadioTap) LayerType() gopacket.LayerType { return LayerTypeRadioTap }
func (m *RadioTap) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 8 {
df.SetTruncated()
return errors.New("RadioTap too small")
}
m.Version = uint8(data[0])
m.Length = binary.LittleEndian.Uint16(data[2:4])
m.Present = RadioTapPresent(binary.LittleEndian.Uint32(data[4:8]))
offset := uint16(4)
for (binary.LittleEndian.Uint32(data[offset:offset+4]) & 0x80000000) != 0 {
// This parser only handles standard radiotap namespace,
// and expects all fields are packed in the first it_present.
// Extended bitmap will be just ignored.
offset += 4
}
offset += 4 // skip the bitmap
if m.Present.TSFT() {
offset += align(offset, 8)
m.TSFT = binary.LittleEndian.Uint64(data[offset : offset+8])
offset += 8
}
if m.Present.Flags() {
m.Flags = RadioTapFlags(data[offset])
offset++
}
if m.Present.Rate() {
m.Rate = RadioTapRate(data[offset])
offset++
}
if m.Present.Channel() {
offset += align(offset, 2)
m.ChannelFrequency = RadioTapChannelFrequency(binary.LittleEndian.Uint16(data[offset : offset+2]))
offset += 2
m.ChannelFlags = RadioTapChannelFlags(binary.LittleEndian.Uint16(data[offset : offset+2]))
offset += 2
}
if m.Present.FHSS() {
m.FHSS = binary.LittleEndian.Uint16(data[offset : offset+2])
offset += 2
}
if m.Present.DBMAntennaSignal() {
m.DBMAntennaSignal = int8(data[offset])
offset++
}
if m.Present.DBMAntennaNoise() {
m.DBMAntennaNoise = int8(data[offset])
offset++
}
if m.Present.LockQuality() {
offset += align(offset, 2)
m.LockQuality = binary.LittleEndian.Uint16(data[offset : offset+2])
offset += 2
}
if m.Present.TxAttenuation() {
offset += align(offset, 2)
m.TxAttenuation = binary.LittleEndian.Uint16(data[offset : offset+2])
offset += 2
}
if m.Present.DBTxAttenuation() {
offset += align(offset, 2)
m.DBTxAttenuation = binary.LittleEndian.Uint16(data[offset : offset+2])
offset += 2
}
if m.Present.DBMTxPower() {
m.DBMTxPower = int8(data[offset])
offset++
}
if m.Present.Antenna() {
m.Antenna = uint8(data[offset])
offset++
}
if m.Present.DBAntennaSignal() {
m.DBAntennaSignal = uint8(data[offset])
offset++
}
if m.Present.DBAntennaNoise() {
m.DBAntennaNoise = uint8(data[offset])
offset++
}
if m.Present.RxFlags() {
offset += align(offset, 2)
m.RxFlags = RadioTapRxFlags(binary.LittleEndian.Uint16(data[offset:]))
offset += 2
}
if m.Present.TxFlags() {
offset += align(offset, 2)
m.TxFlags = RadioTapTxFlags(binary.LittleEndian.Uint16(data[offset:]))
offset += 2
}
if m.Present.RtsRetries() {
m.RtsRetries = uint8(data[offset])
offset++
}
if m.Present.DataRetries() {
m.DataRetries = uint8(data[offset])
offset++
}
if m.Present.MCS() {
m.MCS = RadioTapMCS{
RadioTapMCSKnown(data[offset]),
RadioTapMCSFlags(data[offset+1]),
uint8(data[offset+2]),
}
offset += 3
}
if m.Present.AMPDUStatus() {
offset += align(offset, 4)
m.AMPDUStatus = RadioTapAMPDUStatus{
Reference: binary.LittleEndian.Uint32(data[offset:]),
Flags: RadioTapAMPDUStatusFlags(binary.LittleEndian.Uint16(data[offset+4:])),
CRC: uint8(data[offset+6]),
}
offset += 8
}
if m.Present.VHT() {
offset += align(offset, 2)
m.VHT = RadioTapVHT{
Known: RadioTapVHTKnown(binary.LittleEndian.Uint16(data[offset:])),
Flags: RadioTapVHTFlags(data[offset+2]),
Bandwidth: uint8(data[offset+3]),
MCSNSS: [4]RadioTapVHTMCSNSS{
RadioTapVHTMCSNSS(data[offset+4]),
RadioTapVHTMCSNSS(data[offset+5]),
RadioTapVHTMCSNSS(data[offset+6]),
RadioTapVHTMCSNSS(data[offset+7]),
},
Coding: uint8(data[offset+8]),
GroupId: uint8(data[offset+9]),
PartialAID: binary.LittleEndian.Uint16(data[offset+10:]),
}
offset += 12
}
payload := data[m.Length:]
// Remove non standard padding used by some Wi-Fi drivers
if m.Flags.Datapad() &&
payload[0]&0xC == 0x8 { //&& // Data frame
headlen := 24
if payload[0]&0x8C == 0x88 { // QoS
headlen += 2
}
if payload[1]&0x3 == 0x3 { // 4 addresses
headlen += 2
}
if headlen%4 == 2 {
payload = append(payload[:headlen], payload[headlen+2:len(payload)]...)
}
}
if !m.Flags.FCS() {
// Dot11.DecodeFromBytes() expects FCS present and performs a hard chop on the checksum
// If a user is handing in subslices or packets from a buffered stream, the capacity of the slice
// may extend beyond the len, rather than expecting callers to enforce cap==len on every packet
// we take the hit in this one case and do a reallocation. If the user DOES enforce cap==len
// then the reallocation will happen anyway on the append. This is requried because the append
// write to the memory directly after the payload if there is sufficient capacity, which callers
// may not expect.
reallocPayload := make([]byte, len(payload)+4)
copy(reallocPayload[0:len(payload)], payload)
h := crc32.NewIEEE()
h.Write(payload)
binary.LittleEndian.PutUint32(reallocPayload[len(payload):], h.Sum32())
payload = reallocPayload
}
m.BaseLayer = BaseLayer{Contents: data[:m.Length], Payload: payload}
return nil
}
func (m RadioTap) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
buf := make([]byte, 1024)
buf[0] = m.Version
buf[1] = 0
binary.LittleEndian.PutUint32(buf[4:8], uint32(m.Present))
offset := uint16(4)
for (binary.LittleEndian.Uint32(buf[offset:offset+4]) & 0x80000000) != 0 {
offset += 4
}
offset += 4
if m.Present.TSFT() {
offset += align(offset, 8)
binary.LittleEndian.PutUint64(buf[offset:offset+8], m.TSFT)
offset += 8
}
if m.Present.Flags() {
buf[offset] = uint8(m.Flags)
offset++
}
if m.Present.Rate() {
buf[offset] = uint8(m.Rate)
offset++
}
if m.Present.Channel() {
offset += align(offset, 2)
binary.LittleEndian.PutUint16(buf[offset:offset+2], uint16(m.ChannelFrequency))
offset += 2
binary.LittleEndian.PutUint16(buf[offset:offset+2], uint16(m.ChannelFlags))
offset += 2
}
if m.Present.FHSS() {
binary.LittleEndian.PutUint16(buf[offset:offset+2], m.FHSS)
offset += 2
}
if m.Present.DBMAntennaSignal() {
buf[offset] = byte(m.DBMAntennaSignal)
offset++
}
if m.Present.DBMAntennaNoise() {
buf[offset] = byte(m.DBMAntennaNoise)
offset++
}
if m.Present.LockQuality() {
offset += align(offset, 2)
binary.LittleEndian.PutUint16(buf[offset:offset+2], m.LockQuality)
offset += 2
}
if m.Present.TxAttenuation() {
offset += align(offset, 2)
binary.LittleEndian.PutUint16(buf[offset:offset+2], m.TxAttenuation)
offset += 2
}
if m.Present.DBTxAttenuation() {
offset += align(offset, 2)
binary.LittleEndian.PutUint16(buf[offset:offset+2], m.DBTxAttenuation)
offset += 2
}
if m.Present.DBMTxPower() {
buf[offset] = byte(m.DBMTxPower)
offset++
}
if m.Present.Antenna() {
buf[offset] = uint8(m.Antenna)
offset++
}
if m.Present.DBAntennaSignal() {
buf[offset] = uint8(m.DBAntennaSignal)
offset++
}
if m.Present.DBAntennaNoise() {
buf[offset] = uint8(m.DBAntennaNoise)
offset++
}
if m.Present.RxFlags() {
offset += align(offset, 2)
binary.LittleEndian.PutUint16(buf[offset:offset+2], uint16(m.RxFlags))
offset += 2
}
if m.Present.TxFlags() {
offset += align(offset, 2)
binary.LittleEndian.PutUint16(buf[offset:offset+2], uint16(m.TxFlags))
offset += 2
}
if m.Present.RtsRetries() {
buf[offset] = m.RtsRetries
offset++
}
if m.Present.DataRetries() {
buf[offset] = m.DataRetries
offset++
}
if m.Present.MCS() {
buf[offset] = uint8(m.MCS.Known)
buf[offset+1] = uint8(m.MCS.Flags)
buf[offset+2] = uint8(m.MCS.MCS)
offset += 3
}
if m.Present.AMPDUStatus() {
offset += align(offset, 4)
binary.LittleEndian.PutUint32(buf[offset:offset+4], m.AMPDUStatus.Reference)
binary.LittleEndian.PutUint16(buf[offset+4:offset+6], uint16(m.AMPDUStatus.Flags))
buf[offset+6] = m.AMPDUStatus.CRC
offset += 8
}
if m.Present.VHT() {
offset += align(offset, 2)
binary.LittleEndian.PutUint16(buf[offset:], uint16(m.VHT.Known))
buf[offset+2] = uint8(m.VHT.Flags)
buf[offset+3] = uint8(m.VHT.Bandwidth)
buf[offset+4] = uint8(m.VHT.MCSNSS[0])
buf[offset+5] = uint8(m.VHT.MCSNSS[1])
buf[offset+6] = uint8(m.VHT.MCSNSS[2])
buf[offset+7] = uint8(m.VHT.MCSNSS[3])
buf[offset+8] = uint8(m.VHT.Coding)
buf[offset+9] = uint8(m.VHT.GroupId)
binary.LittleEndian.PutUint16(buf[offset+10:offset+12], m.VHT.PartialAID)
offset += 12
}
packetBuf, err := b.PrependBytes(int(offset))
if err != nil {
return err
}
if opts.FixLengths {
m.Length = offset
}
binary.LittleEndian.PutUint16(buf[2:4], m.Length)
copy(packetBuf, buf)
return nil
}
func (m *RadioTap) CanDecode() gopacket.LayerClass { return LayerTypeRadioTap }
func (m *RadioTap) NextLayerType() gopacket.LayerType { return LayerTypeDot11 }
// Copyright 2020 The GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file in the root of the source tree.
package layers
import (
"encoding/binary"
"fmt"
"github.com/google/gopacket"
)
const (
// RFC 2865 3. Packet Format
// `The minimum length is 20 and maximum length is 4096.`
radiusMinimumRecordSizeInBytes int = 20
radiusMaximumRecordSizeInBytes int = 4096
// RFC 2865 5. Attributes
// `The Length field is one octet, and indicates the length of this Attribute including the Type, Length and Value fields.`
// `The Value field is zero or more octets and contains information specific to the Attribute.`
radiusAttributesMinimumRecordSizeInBytes int = 2
)
// RADIUS represents a Remote Authentication Dial In User Service layer.
type RADIUS struct {
BaseLayer
Code RADIUSCode
Identifier RADIUSIdentifier
Length RADIUSLength
Authenticator RADIUSAuthenticator
Attributes []RADIUSAttribute
}
// RADIUSCode represents packet type.
type RADIUSCode uint8
// constants that define RADIUSCode.
const (
RADIUSCodeAccessRequest RADIUSCode = 1 // RFC2865 3. Packet Format
RADIUSCodeAccessAccept RADIUSCode = 2 // RFC2865 3. Packet Format
RADIUSCodeAccessReject RADIUSCode = 3 // RFC2865 3. Packet Format
RADIUSCodeAccountingRequest RADIUSCode = 4 // RFC2865 3. Packet Format
RADIUSCodeAccountingResponse RADIUSCode = 5 // RFC2865 3. Packet Format
RADIUSCodeAccessChallenge RADIUSCode = 11 // RFC2865 3. Packet Format
RADIUSCodeStatusServer RADIUSCode = 12 // RFC2865 3. Packet Format (experimental)
RADIUSCodeStatusClient RADIUSCode = 13 // RFC2865 3. Packet Format (experimental)
RADIUSCodeReserved RADIUSCode = 255 // RFC2865 3. Packet Format
)
// String returns a string version of a RADIUSCode.
func (t RADIUSCode) String() (s string) {
switch t {
case RADIUSCodeAccessRequest:
s = "Access-Request"
case RADIUSCodeAccessAccept:
s = "Access-Accept"
case RADIUSCodeAccessReject:
s = "Access-Reject"
case RADIUSCodeAccountingRequest:
s = "Accounting-Request"
case RADIUSCodeAccountingResponse:
s = "Accounting-Response"
case RADIUSCodeAccessChallenge:
s = "Access-Challenge"
case RADIUSCodeStatusServer:
s = "Status-Server"
case RADIUSCodeStatusClient:
s = "Status-Client"
case RADIUSCodeReserved:
s = "Reserved"
default:
s = fmt.Sprintf("Unknown(%d)", t)
}
return
}
// RADIUSIdentifier represents packet identifier.
type RADIUSIdentifier uint8
// RADIUSLength represents packet length.
type RADIUSLength uint16
// RADIUSAuthenticator represents authenticator.
type RADIUSAuthenticator [16]byte
// RADIUSAttribute represents attributes.
type RADIUSAttribute struct {
Type RADIUSAttributeType
Length RADIUSAttributeLength
Value RADIUSAttributeValue
}
// RADIUSAttributeType represents attribute type.
type RADIUSAttributeType uint8
// constants that define RADIUSAttributeType.
const (
RADIUSAttributeTypeUserName RADIUSAttributeType = 1 // RFC2865 5.1. User-Name
RADIUSAttributeTypeUserPassword RADIUSAttributeType = 2 // RFC2865 5.2. User-Password
RADIUSAttributeTypeCHAPPassword RADIUSAttributeType = 3 // RFC2865 5.3. CHAP-Password
RADIUSAttributeTypeNASIPAddress RADIUSAttributeType = 4 // RFC2865 5.4. NAS-IP-Address
RADIUSAttributeTypeNASPort RADIUSAttributeType = 5 // RFC2865 5.5. NAS-Port
RADIUSAttributeTypeServiceType RADIUSAttributeType = 6 // RFC2865 5.6. Service-Type
RADIUSAttributeTypeFramedProtocol RADIUSAttributeType = 7 // RFC2865 5.7. Framed-Protocol
RADIUSAttributeTypeFramedIPAddress RADIUSAttributeType = 8 // RFC2865 5.8. Framed-IP-Address
RADIUSAttributeTypeFramedIPNetmask RADIUSAttributeType = 9 // RFC2865 5.9. Framed-IP-Netmask
RADIUSAttributeTypeFramedRouting RADIUSAttributeType = 10 // RFC2865 5.10. Framed-Routing
RADIUSAttributeTypeFilterId RADIUSAttributeType = 11 // RFC2865 5.11. Filter-Id
RADIUSAttributeTypeFramedMTU RADIUSAttributeType = 12 // RFC2865 5.12. Framed-MTU
RADIUSAttributeTypeFramedCompression RADIUSAttributeType = 13 // RFC2865 5.13. Framed-Compression
RADIUSAttributeTypeLoginIPHost RADIUSAttributeType = 14 // RFC2865 5.14. Login-IP-Host
RADIUSAttributeTypeLoginService RADIUSAttributeType = 15 // RFC2865 5.15. Login-Service
RADIUSAttributeTypeLoginTCPPort RADIUSAttributeType = 16 // RFC2865 5.16. Login-TCP-Port
RADIUSAttributeTypeReplyMessage RADIUSAttributeType = 18 // RFC2865 5.18. Reply-Message
RADIUSAttributeTypeCallbackNumber RADIUSAttributeType = 19 // RFC2865 5.19. Callback-Number
RADIUSAttributeTypeCallbackId RADIUSAttributeType = 20 // RFC2865 5.20. Callback-Id
RADIUSAttributeTypeFramedRoute RADIUSAttributeType = 22 // RFC2865 5.22. Framed-Route
RADIUSAttributeTypeFramedIPXNetwork RADIUSAttributeType = 23 // RFC2865 5.23. Framed-IPX-Network
RADIUSAttributeTypeState RADIUSAttributeType = 24 // RFC2865 5.24. State
RADIUSAttributeTypeClass RADIUSAttributeType = 25 // RFC2865 5.25. Class
RADIUSAttributeTypeVendorSpecific RADIUSAttributeType = 26 // RFC2865 5.26. Vendor-Specific
RADIUSAttributeTypeSessionTimeout RADIUSAttributeType = 27 // RFC2865 5.27. Session-Timeout
RADIUSAttributeTypeIdleTimeout RADIUSAttributeType = 28 // RFC2865 5.28. Idle-Timeout
RADIUSAttributeTypeTerminationAction RADIUSAttributeType = 29 // RFC2865 5.29. Termination-Action
RADIUSAttributeTypeCalledStationId RADIUSAttributeType = 30 // RFC2865 5.30. Called-Station-Id
RADIUSAttributeTypeCallingStationId RADIUSAttributeType = 31 // RFC2865 5.31. Calling-Station-Id
RADIUSAttributeTypeNASIdentifier RADIUSAttributeType = 32 // RFC2865 5.32. NAS-Identifier
RADIUSAttributeTypeProxyState RADIUSAttributeType = 33 // RFC2865 5.33. Proxy-State
RADIUSAttributeTypeLoginLATService RADIUSAttributeType = 34 // RFC2865 5.34. Login-LAT-Service
RADIUSAttributeTypeLoginLATNode RADIUSAttributeType = 35 // RFC2865 5.35. Login-LAT-Node
RADIUSAttributeTypeLoginLATGroup RADIUSAttributeType = 36 // RFC2865 5.36. Login-LAT-Group
RADIUSAttributeTypeFramedAppleTalkLink RADIUSAttributeType = 37 // RFC2865 5.37. Framed-AppleTalk-Link
RADIUSAttributeTypeFramedAppleTalkNetwork RADIUSAttributeType = 38 // RFC2865 5.38. Framed-AppleTalk-Network
RADIUSAttributeTypeFramedAppleTalkZone RADIUSAttributeType = 39 // RFC2865 5.39. Framed-AppleTalk-Zone
RADIUSAttributeTypeAcctStatusType RADIUSAttributeType = 40 // RFC2866 5.1. Acct-Status-Type
RADIUSAttributeTypeAcctDelayTime RADIUSAttributeType = 41 // RFC2866 5.2. Acct-Delay-Time
RADIUSAttributeTypeAcctInputOctets RADIUSAttributeType = 42 // RFC2866 5.3. Acct-Input-Octets
RADIUSAttributeTypeAcctOutputOctets RADIUSAttributeType = 43 // RFC2866 5.4. Acct-Output-Octets
RADIUSAttributeTypeAcctSessionId RADIUSAttributeType = 44 // RFC2866 5.5. Acct-Session-Id
RADIUSAttributeTypeAcctAuthentic RADIUSAttributeType = 45 // RFC2866 5.6. Acct-Authentic
RADIUSAttributeTypeAcctSessionTime RADIUSAttributeType = 46 // RFC2866 5.7. Acct-Session-Time
RADIUSAttributeTypeAcctInputPackets RADIUSAttributeType = 47 // RFC2866 5.8. Acct-Input-Packets
RADIUSAttributeTypeAcctOutputPackets RADIUSAttributeType = 48 // RFC2866 5.9. Acct-Output-Packets
RADIUSAttributeTypeAcctTerminateCause RADIUSAttributeType = 49 // RFC2866 5.10. Acct-Terminate-Cause
RADIUSAttributeTypeAcctMultiSessionId RADIUSAttributeType = 50 // RFC2866 5.11. Acct-Multi-Session-Id
RADIUSAttributeTypeAcctLinkCount RADIUSAttributeType = 51 // RFC2866 5.12. Acct-Link-Count
RADIUSAttributeTypeAcctInputGigawords RADIUSAttributeType = 52 // RFC2869 5.1. Acct-Input-Gigawords
RADIUSAttributeTypeAcctOutputGigawords RADIUSAttributeType = 53 // RFC2869 5.2. Acct-Output-Gigawords
RADIUSAttributeTypeEventTimestamp RADIUSAttributeType = 55 // RFC2869 5.3. Event-Timestamp
RADIUSAttributeTypeCHAPChallenge RADIUSAttributeType = 60 // RFC2865 5.40. CHAP-Challenge
RADIUSAttributeTypeNASPortType RADIUSAttributeType = 61 // RFC2865 5.41. NAS-Port-Type
RADIUSAttributeTypePortLimit RADIUSAttributeType = 62 // RFC2865 5.42. Port-Limit
RADIUSAttributeTypeLoginLATPort RADIUSAttributeType = 63 // RFC2865 5.43. Login-LAT-Port
RADIUSAttributeTypeTunnelType RADIUSAttributeType = 64 // RFC2868 3.1. Tunnel-Type
RADIUSAttributeTypeTunnelMediumType RADIUSAttributeType = 65 // RFC2868 3.2. Tunnel-Medium-Type
RADIUSAttributeTypeTunnelClientEndpoint RADIUSAttributeType = 66 // RFC2868 3.3. Tunnel-Client-Endpoint
RADIUSAttributeTypeTunnelServerEndpoint RADIUSAttributeType = 67 // RFC2868 3.4. Tunnel-Server-Endpoint
RADIUSAttributeTypeAcctTunnelConnection RADIUSAttributeType = 68 // RFC2867 4.1. Acct-Tunnel-Connection
RADIUSAttributeTypeTunnelPassword RADIUSAttributeType = 69 // RFC2868 3.5. Tunnel-Password
RADIUSAttributeTypeARAPPassword RADIUSAttributeType = 70 // RFC2869 5.4. ARAP-Password
RADIUSAttributeTypeARAPFeatures RADIUSAttributeType = 71 // RFC2869 5.5. ARAP-Features
RADIUSAttributeTypeARAPZoneAccess RADIUSAttributeType = 72 // RFC2869 5.6. ARAP-Zone-Access
RADIUSAttributeTypeARAPSecurity RADIUSAttributeType = 73 // RFC2869 5.7. ARAP-Security
RADIUSAttributeTypeARAPSecurityData RADIUSAttributeType = 74 // RFC2869 5.8. ARAP-Security-Data
RADIUSAttributeTypePasswordRetry RADIUSAttributeType = 75 // RFC2869 5.9. Password-Retry
RADIUSAttributeTypePrompt RADIUSAttributeType = 76 // RFC2869 5.10. Prompt
RADIUSAttributeTypeConnectInfo RADIUSAttributeType = 77 // RFC2869 5.11. Connect-Info
RADIUSAttributeTypeConfigurationToken RADIUSAttributeType = 78 // RFC2869 5.12. Configuration-Token
RADIUSAttributeTypeEAPMessage RADIUSAttributeType = 79 // RFC2869 5.13. EAP-Message
RADIUSAttributeTypeMessageAuthenticator RADIUSAttributeType = 80 // RFC2869 5.14. Message-Authenticator
RADIUSAttributeTypeTunnelPrivateGroupID RADIUSAttributeType = 81 // RFC2868 3.6. Tunnel-Private-Group-ID
RADIUSAttributeTypeTunnelAssignmentID RADIUSAttributeType = 82 // RFC2868 3.7. Tunnel-Assignment-ID
RADIUSAttributeTypeTunnelPreference RADIUSAttributeType = 83 // RFC2868 3.8. Tunnel-Preference
RADIUSAttributeTypeARAPChallengeResponse RADIUSAttributeType = 84 // RFC2869 5.15. ARAP-Challenge-Response
RADIUSAttributeTypeAcctInterimInterval RADIUSAttributeType = 85 // RFC2869 5.16. Acct-Interim-Interval
RADIUSAttributeTypeAcctTunnelPacketsLost RADIUSAttributeType = 86 // RFC2867 4.2. Acct-Tunnel-Packets-Lost
RADIUSAttributeTypeNASPortId RADIUSAttributeType = 87 // RFC2869 5.17. NAS-Port-Id
RADIUSAttributeTypeFramedPool RADIUSAttributeType = 88 // RFC2869 5.18. Framed-Pool
RADIUSAttributeTypeTunnelClientAuthID RADIUSAttributeType = 90 // RFC2868 3.9. Tunnel-Client-Auth-ID
RADIUSAttributeTypeTunnelServerAuthID RADIUSAttributeType = 91 // RFC2868 3.10. Tunnel-Server-Auth-ID
)
// RADIUSAttributeType represents attribute length.
type RADIUSAttributeLength uint8
// RADIUSAttributeType represents attribute value.
type RADIUSAttributeValue []byte
// String returns a string version of a RADIUSAttributeType.
func (t RADIUSAttributeType) String() (s string) {
switch t {
case RADIUSAttributeTypeUserName:
s = "User-Name"
case RADIUSAttributeTypeUserPassword:
s = "User-Password"
case RADIUSAttributeTypeCHAPPassword:
s = "CHAP-Password"
case RADIUSAttributeTypeNASIPAddress:
s = "NAS-IP-Address"
case RADIUSAttributeTypeNASPort:
s = "NAS-Port"
case RADIUSAttributeTypeServiceType:
s = "Service-Type"
case RADIUSAttributeTypeFramedProtocol:
s = "Framed-Protocol"
case RADIUSAttributeTypeFramedIPAddress:
s = "Framed-IP-Address"
case RADIUSAttributeTypeFramedIPNetmask:
s = "Framed-IP-Netmask"
case RADIUSAttributeTypeFramedRouting:
s = "Framed-Routing"
case RADIUSAttributeTypeFilterId:
s = "Filter-Id"
case RADIUSAttributeTypeFramedMTU:
s = "Framed-MTU"
case RADIUSAttributeTypeFramedCompression:
s = "Framed-Compression"
case RADIUSAttributeTypeLoginIPHost:
s = "Login-IP-Host"
case RADIUSAttributeTypeLoginService:
s = "Login-Service"
case RADIUSAttributeTypeLoginTCPPort:
s = "Login-TCP-Port"
case RADIUSAttributeTypeReplyMessage:
s = "Reply-Message"
case RADIUSAttributeTypeCallbackNumber:
s = "Callback-Number"
case RADIUSAttributeTypeCallbackId:
s = "Callback-Id"
case RADIUSAttributeTypeFramedRoute:
s = "Framed-Route"
case RADIUSAttributeTypeFramedIPXNetwork:
s = "Framed-IPX-Network"
case RADIUSAttributeTypeState:
s = "State"
case RADIUSAttributeTypeClass:
s = "Class"
case RADIUSAttributeTypeVendorSpecific:
s = "Vendor-Specific"
case RADIUSAttributeTypeSessionTimeout:
s = "Session-Timeout"
case RADIUSAttributeTypeIdleTimeout:
s = "Idle-Timeout"
case RADIUSAttributeTypeTerminationAction:
s = "Termination-Action"
case RADIUSAttributeTypeCalledStationId:
s = "Called-Station-Id"
case RADIUSAttributeTypeCallingStationId:
s = "Calling-Station-Id"
case RADIUSAttributeTypeNASIdentifier:
s = "NAS-Identifier"
case RADIUSAttributeTypeProxyState:
s = "Proxy-State"
case RADIUSAttributeTypeLoginLATService:
s = "Login-LAT-Service"
case RADIUSAttributeTypeLoginLATNode:
s = "Login-LAT-Node"
case RADIUSAttributeTypeLoginLATGroup:
s = "Login-LAT-Group"
case RADIUSAttributeTypeFramedAppleTalkLink:
s = "Framed-AppleTalk-Link"
case RADIUSAttributeTypeFramedAppleTalkNetwork:
s = "Framed-AppleTalk-Network"
case RADIUSAttributeTypeFramedAppleTalkZone:
s = "Framed-AppleTalk-Zone"
case RADIUSAttributeTypeAcctStatusType:
s = "Acct-Status-Type"
case RADIUSAttributeTypeAcctDelayTime:
s = "Acct-Delay-Time"
case RADIUSAttributeTypeAcctInputOctets:
s = "Acct-Input-Octets"
case RADIUSAttributeTypeAcctOutputOctets:
s = "Acct-Output-Octets"
case RADIUSAttributeTypeAcctSessionId:
s = "Acct-Session-Id"
case RADIUSAttributeTypeAcctAuthentic:
s = "Acct-Authentic"
case RADIUSAttributeTypeAcctSessionTime:
s = "Acct-Session-Time"
case RADIUSAttributeTypeAcctInputPackets:
s = "Acct-Input-Packets"
case RADIUSAttributeTypeAcctOutputPackets:
s = "Acct-Output-Packets"
case RADIUSAttributeTypeAcctTerminateCause:
s = "Acct-Terminate-Cause"
case RADIUSAttributeTypeAcctMultiSessionId:
s = "Acct-Multi-Session-Id"
case RADIUSAttributeTypeAcctLinkCount:
s = "Acct-Link-Count"
case RADIUSAttributeTypeAcctInputGigawords:
s = "Acct-Input-Gigawords"
case RADIUSAttributeTypeAcctOutputGigawords:
s = "Acct-Output-Gigawords"
case RADIUSAttributeTypeEventTimestamp:
s = "Event-Timestamp"
case RADIUSAttributeTypeCHAPChallenge:
s = "CHAP-Challenge"
case RADIUSAttributeTypeNASPortType:
s = "NAS-Port-Type"
case RADIUSAttributeTypePortLimit:
s = "Port-Limit"
case RADIUSAttributeTypeLoginLATPort:
s = "Login-LAT-Port"
case RADIUSAttributeTypeTunnelType:
s = "Tunnel-Type"
case RADIUSAttributeTypeTunnelMediumType:
s = "Tunnel-Medium-Type"
case RADIUSAttributeTypeTunnelClientEndpoint:
s = "Tunnel-Client-Endpoint"
case RADIUSAttributeTypeTunnelServerEndpoint:
s = "Tunnel-Server-Endpoint"
case RADIUSAttributeTypeAcctTunnelConnection:
s = "Acct-Tunnel-Connection"
case RADIUSAttributeTypeTunnelPassword:
s = "Tunnel-Password"
case RADIUSAttributeTypeARAPPassword:
s = "ARAP-Password"
case RADIUSAttributeTypeARAPFeatures:
s = "ARAP-Features"
case RADIUSAttributeTypeARAPZoneAccess:
s = "ARAP-Zone-Access"
case RADIUSAttributeTypeARAPSecurity:
s = "ARAP-Security"
case RADIUSAttributeTypeARAPSecurityData:
s = "ARAP-Security-Data"
case RADIUSAttributeTypePasswordRetry:
s = "Password-Retry"
case RADIUSAttributeTypePrompt:
s = "Prompt"
case RADIUSAttributeTypeConnectInfo:
s = "Connect-Info"
case RADIUSAttributeTypeConfigurationToken:
s = "Configuration-Token"
case RADIUSAttributeTypeEAPMessage:
s = "EAP-Message"
case RADIUSAttributeTypeMessageAuthenticator:
s = "Message-Authenticator"
case RADIUSAttributeTypeTunnelPrivateGroupID:
s = "Tunnel-Private-Group-ID"
case RADIUSAttributeTypeTunnelAssignmentID:
s = "Tunnel-Assignment-ID"
case RADIUSAttributeTypeTunnelPreference:
s = "Tunnel-Preference"
case RADIUSAttributeTypeARAPChallengeResponse:
s = "ARAP-Challenge-Response"
case RADIUSAttributeTypeAcctInterimInterval:
s = "Acct-Interim-Interval"
case RADIUSAttributeTypeAcctTunnelPacketsLost:
s = "Acct-Tunnel-Packets-Lost"
case RADIUSAttributeTypeNASPortId:
s = "NAS-Port-Id"
case RADIUSAttributeTypeFramedPool:
s = "Framed-Pool"
case RADIUSAttributeTypeTunnelClientAuthID:
s = "Tunnel-Client-Auth-ID"
case RADIUSAttributeTypeTunnelServerAuthID:
s = "Tunnel-Server-Auth-ID"
default:
s = fmt.Sprintf("Unknown(%d)", t)
}
return
}
// Len returns the length of a RADIUS packet.
func (radius *RADIUS) Len() (int, error) {
n := radiusMinimumRecordSizeInBytes
for _, v := range radius.Attributes {
alen, err := attributeValueLength(v.Value)
if err != nil {
return 0, err
}
n += int(alen) + 2 // Added Type and Length
}
return n, nil
}
// LayerType returns LayerTypeRADIUS.
func (radius *RADIUS) LayerType() gopacket.LayerType {
return LayerTypeRADIUS
}
// DecodeFromBytes decodes the given bytes into this layer.
func (radius *RADIUS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) > radiusMaximumRecordSizeInBytes {
df.SetTruncated()
return fmt.Errorf("RADIUS length %d too big", len(data))
}
if len(data) < radiusMinimumRecordSizeInBytes {
df.SetTruncated()
return fmt.Errorf("RADIUS length %d too short", len(data))
}
radius.BaseLayer = BaseLayer{Contents: data}
radius.Code = RADIUSCode(data[0])
radius.Identifier = RADIUSIdentifier(data[1])
radius.Length = RADIUSLength(binary.BigEndian.Uint16(data[2:4]))
if int(radius.Length) > radiusMaximumRecordSizeInBytes {
df.SetTruncated()
return fmt.Errorf("RADIUS length %d too big", radius.Length)
}
if int(radius.Length) < radiusMinimumRecordSizeInBytes {
df.SetTruncated()
return fmt.Errorf("RADIUS length %d too short", radius.Length)
}
// RFC 2865 3. Packet Format
// `If the packet is shorter than the Length field indicates, it MUST be silently discarded.`
if int(radius.Length) > len(data) {
df.SetTruncated()
return fmt.Errorf("RADIUS length %d too big", radius.Length)
}
// RFC 2865 3. Packet Format
// `Octets outside the range of the Length field MUST be treated as padding and ignored on reception.`
if int(radius.Length) < len(data) {
df.SetTruncated()
data = data[:radius.Length]
}
copy(radius.Authenticator[:], data[4:20])
if len(data) == radiusMinimumRecordSizeInBytes {
return nil
}
pos := radiusMinimumRecordSizeInBytes
for {
if len(data) == pos {
break
}
if len(data[pos:]) < radiusAttributesMinimumRecordSizeInBytes {
df.SetTruncated()
return fmt.Errorf("RADIUS attributes length %d too short", len(data[pos:]))
}
attr := RADIUSAttribute{}
attr.Type = RADIUSAttributeType(data[pos])
attr.Length = RADIUSAttributeLength(data[pos+1])
if int(attr.Length) > len(data[pos:]) {
df.SetTruncated()
return fmt.Errorf("RADIUS attributes length %d too big", attr.Length)
}
if int(attr.Length) < radiusAttributesMinimumRecordSizeInBytes {
df.SetTruncated()
return fmt.Errorf("RADIUS attributes length %d too short", attr.Length)
}
if int(attr.Length) > radiusAttributesMinimumRecordSizeInBytes {
attr.Value = make([]byte, attr.Length-2)
copy(attr.Value[:], data[pos+2:pos+int(attr.Length)])
radius.Attributes = append(radius.Attributes, attr)
}
pos += int(attr.Length)
}
for _, v := range radius.Attributes {
if v.Type == RADIUSAttributeTypeEAPMessage {
radius.BaseLayer.Payload = append(radius.BaseLayer.Payload, v.Value...)
}
}
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (radius *RADIUS) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
plen, err := radius.Len()
if err != nil {
return err
}
if opts.FixLengths {
radius.Length = RADIUSLength(plen)
}
data, err := b.PrependBytes(plen)
if err != nil {
return err
}
data[0] = byte(radius.Code)
data[1] = byte(radius.Identifier)
binary.BigEndian.PutUint16(data[2:], uint16(radius.Length))
copy(data[4:20], radius.Authenticator[:])
pos := radiusMinimumRecordSizeInBytes
for _, v := range radius.Attributes {
if opts.FixLengths {
v.Length, err = attributeValueLength(v.Value)
if err != nil {
return err
}
}
data[pos] = byte(v.Type)
data[pos+1] = byte(v.Length)
copy(data[pos+2:], v.Value[:])
pos += len(v.Value) + 2 // Added Type and Length
}
return nil
}
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (radius *RADIUS) CanDecode() gopacket.LayerClass {
return LayerTypeRADIUS
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (radius *RADIUS) NextLayerType() gopacket.LayerType {
if len(radius.BaseLayer.Payload) > 0 {
return LayerTypeEAP
} else {
return gopacket.LayerTypeZero
}
}
// Payload returns the EAP Type-Data for EAP-Message attributes.
func (radius *RADIUS) Payload() []byte {
return radius.BaseLayer.Payload
}
func decodeRADIUS(data []byte, p gopacket.PacketBuilder) error {
radius := &RADIUS{}
err := radius.DecodeFromBytes(data, p)
if err != nil {
return err
}
p.AddLayer(radius)
p.SetApplicationLayer(radius)
next := radius.NextLayerType()
if next == gopacket.LayerTypeZero {
return nil
}
return p.NextDecoder(next)
}
func attributeValueLength(v []byte) (RADIUSAttributeLength, error) {
n := len(v)
if n > 255 {
return 0, fmt.Errorf("RADIUS attribute value length %d too long", n)
} else {
return RADIUSAttributeLength(n), nil
}
}
// Copyright 2019 The GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file in the root of the source tree.
package layers
// This file implements the ASF-RMCP header specified in section 3.2.2.2 of
// https://www.dmtf.org/sites/default/files/standards/documents/DSP0136.pdf
import (
"fmt"
"github.com/google/gopacket"
)
// RMCPClass is the class of a RMCP layer's payload, e.g. ASF or IPMI. This is a
// 4-bit unsigned int on the wire; all but 6 (ASF), 7 (IPMI) and 8 (OEM-defined)
// are currently reserved.
type RMCPClass uint8
// LayerType returns the payload layer type corresponding to a RMCP class.
func (c RMCPClass) LayerType() gopacket.LayerType {
if lt := rmcpClassLayerTypes[uint8(c)]; lt != 0 {
return lt
}
return gopacket.LayerTypePayload
}
func (c RMCPClass) String() string {
return fmt.Sprintf("%v(%v)", uint8(c), c.LayerType())
}
const (
// RMCPVersion1 identifies RMCP v1.0 in the Version header field. Lower
// values are considered legacy, while higher values are reserved by the
// specification.
RMCPVersion1 uint8 = 0x06
// RMCPNormal indicates a "normal" message, i.e. not an acknowledgement.
RMCPNormal uint8 = 0
// RMCPAck indicates a message is acknowledging a received normal message.
RMCPAck uint8 = 1 << 7
// RMCPClassASF identifies an RMCP message as containing an ASF-RMCP
// payload.
RMCPClassASF RMCPClass = 0x06
// RMCPClassIPMI identifies an RMCP message as containing an IPMI payload.
RMCPClassIPMI RMCPClass = 0x07
// RMCPClassOEM identifies an RMCP message as containing an OEM-defined
// payload.
RMCPClassOEM RMCPClass = 0x08
)
var (
rmcpClassLayerTypes = [16]gopacket.LayerType{
RMCPClassASF: LayerTypeASF,
// RMCPClassIPMI is to implement; RMCPClassOEM is deliberately not
// implemented, so we return LayerTypePayload
}
)
// RegisterRMCPLayerType allows specifying that the payload of a RMCP packet of
// a certain class should processed by the provided layer type. This overrides
// any existing registrations, including defaults.
func RegisterRMCPLayerType(c RMCPClass, l gopacket.LayerType) {
rmcpClassLayerTypes[c] = l
}
// RMCP describes the format of an RMCP header, which forms a UDP payload. See
// section 3.2.2.2.
type RMCP struct {
BaseLayer
// Version identifies the version of the RMCP header. 0x06 indicates RMCP
// v1.0; lower values are legacy, higher values are reserved.
Version uint8
// Sequence is the sequence number assicated with the message. Note that
// this rolls over to 0 after 254, not 255. Seq num 255 indicates the
// receiver must not send an ACK.
Sequence uint8
// Ack indicates whether this packet is an acknowledgement. If it is, the
// payload will be empty.
Ack bool
// Class idicates the structure of the payload. There are only 2^4 valid
// values, however there is no uint4 data type. N.B. the Ack bit has been
// split off into another field. The most significant 4 bits of this field
// will always be 0.
Class RMCPClass
}
// LayerType returns LayerTypeRMCP. It partially satisfies Layer and
// SerializableLayer.
func (*RMCP) LayerType() gopacket.LayerType {
return LayerTypeRMCP
}
// CanDecode returns LayerTypeRMCP. It partially satisfies DecodingLayer.
func (r *RMCP) CanDecode() gopacket.LayerClass {
return r.LayerType()
}
// DecodeFromBytes makes the layer represent the provided bytes. It partially
// satisfies DecodingLayer.
func (r *RMCP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 4 {
df.SetTruncated()
return fmt.Errorf("invalid RMCP header, length %v less than 4",
len(data))
}
r.BaseLayer.Contents = data[:4]
r.BaseLayer.Payload = data[4:]
r.Version = uint8(data[0])
// 1 byte reserved
r.Sequence = uint8(data[2])
r.Ack = data[3]&RMCPAck != 0
r.Class = RMCPClass(data[3] & 0xF)
return nil
}
// NextLayerType returns the data layer of this RMCP layer. This partially
// satisfies DecodingLayer.
func (r *RMCP) NextLayerType() gopacket.LayerType {
return r.Class.LayerType()
}
// Payload returns the data layer. It partially satisfies ApplicationLayer.
func (r *RMCP) Payload() []byte {
return r.BaseLayer.Payload
}
// SerializeTo writes the serialized fom of this layer into the SerializeBuffer,
// partially satisfying SerializableLayer.
func (r *RMCP) SerializeTo(b gopacket.SerializeBuffer, _ gopacket.SerializeOptions) error {
// The IPMI v1.5 spec contains a pad byte for frame sizes of certain lengths
// to work around issues in LAN chips. This is no longer necessary as of
// IPMI v2.0 (renamed to "legacy pad") so we do not attempt to add it. The
// same approach is taken by FreeIPMI:
// http://git.savannah.gnu.org/cgit/freeipmi.git/tree/libfreeipmi/interface/ipmi-lan-interface.c?id=b5ffcd38317daf42074458879f4c55ba6804a595#n836
bytes, err := b.PrependBytes(4)
if err != nil {
return err
}
bytes[0] = r.Version
bytes[1] = 0x00
bytes[2] = r.Sequence
bytes[3] = bool2uint8(r.Ack)<<7 | uint8(r.Class) // thanks, BFD layer
return nil
}
// decodeRMCP decodes the byte slice into an RMCP type, and sets the application
// layer to it.
func decodeRMCP(data []byte, p gopacket.PacketBuilder) error {
rmcp := &RMCP{}
err := rmcp.DecodeFromBytes(data, p)
p.AddLayer(rmcp)
p.SetApplicationLayer(rmcp)
if err != nil {
return err
}
return p.NextDecoder(rmcp.NextLayerType())
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"fmt"
"github.com/google/gopacket"
)
type RUDP struct {
BaseLayer
SYN, ACK, EACK, RST, NUL bool
Version uint8
HeaderLength uint8
SrcPort, DstPort RUDPPort
DataLength uint16
Seq, Ack, Checksum uint32
VariableHeaderArea []byte
// RUDPHeaderSyn contains SYN information for the RUDP packet,
// if the SYN flag is set
*RUDPHeaderSYN
// RUDPHeaderEack contains EACK information for the RUDP packet,
// if the EACK flag is set.
*RUDPHeaderEACK
}
type RUDPHeaderSYN struct {
MaxOutstandingSegments, MaxSegmentSize, OptionFlags uint16
}
type RUDPHeaderEACK struct {
SeqsReceivedOK []uint32
}
// LayerType returns gopacket.LayerTypeRUDP.
func (r *RUDP) LayerType() gopacket.LayerType { return LayerTypeRUDP }
func decodeRUDP(data []byte, p gopacket.PacketBuilder) error {
r := &RUDP{
SYN: data[0]&0x80 != 0,
ACK: data[0]&0x40 != 0,
EACK: data[0]&0x20 != 0,
RST: data[0]&0x10 != 0,
NUL: data[0]&0x08 != 0,
Version: data[0] & 0x3,
HeaderLength: data[1],
SrcPort: RUDPPort(data[2]),
DstPort: RUDPPort(data[3]),
DataLength: binary.BigEndian.Uint16(data[4:6]),
Seq: binary.BigEndian.Uint32(data[6:10]),
Ack: binary.BigEndian.Uint32(data[10:14]),
Checksum: binary.BigEndian.Uint32(data[14:18]),
}
if r.HeaderLength < 9 {
return fmt.Errorf("RUDP packet with too-short header length %d", r.HeaderLength)
}
hlen := int(r.HeaderLength) * 2
r.Contents = data[:hlen]
r.Payload = data[hlen : hlen+int(r.DataLength)]
r.VariableHeaderArea = data[18:hlen]
headerData := r.VariableHeaderArea
switch {
case r.SYN:
if len(headerData) != 6 {
return fmt.Errorf("RUDP packet invalid SYN header length: %d", len(headerData))
}
r.RUDPHeaderSYN = &RUDPHeaderSYN{
MaxOutstandingSegments: binary.BigEndian.Uint16(headerData[:2]),
MaxSegmentSize: binary.BigEndian.Uint16(headerData[2:4]),
OptionFlags: binary.BigEndian.Uint16(headerData[4:6]),
}
case r.EACK:
if len(headerData)%4 != 0 {
return fmt.Errorf("RUDP packet invalid EACK header length: %d", len(headerData))
}
r.RUDPHeaderEACK = &RUDPHeaderEACK{make([]uint32, len(headerData)/4)}
for i := 0; i < len(headerData); i += 4 {
r.SeqsReceivedOK[i/4] = binary.BigEndian.Uint32(headerData[i : i+4])
}
}
p.AddLayer(r)
p.SetTransportLayer(r)
return p.NextDecoder(gopacket.LayerTypePayload)
}
func (r *RUDP) TransportFlow() gopacket.Flow {
return gopacket.NewFlow(EndpointRUDPPort, []byte{byte(r.SrcPort)}, []byte{byte(r.DstPort)})
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"hash/crc32"
"github.com/google/gopacket"
)
// SCTP contains information on the top level of an SCTP packet.
type SCTP struct {
BaseLayer
SrcPort, DstPort SCTPPort
VerificationTag uint32
Checksum uint32
sPort, dPort []byte
}
// LayerType returns gopacket.LayerTypeSCTP
func (s *SCTP) LayerType() gopacket.LayerType { return LayerTypeSCTP }
func decodeSCTP(data []byte, p gopacket.PacketBuilder) error {
sctp := &SCTP{}
err := sctp.DecodeFromBytes(data, p)
p.AddLayer(sctp)
p.SetTransportLayer(sctp)
if err != nil {
return err
}
return p.NextDecoder(sctpChunkTypePrefixDecoder)
}
var sctpChunkTypePrefixDecoder = gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix)
// TransportFlow returns a flow based on the source and destination SCTP port.
func (s *SCTP) TransportFlow() gopacket.Flow {
return gopacket.NewFlow(EndpointSCTPPort, s.sPort, s.dPort)
}
func decodeWithSCTPChunkTypePrefix(data []byte, p gopacket.PacketBuilder) error {
chunkType := SCTPChunkType(data[0])
return chunkType.Decode(data, p)
}
// SerializeTo is for gopacket.SerializableLayer.
func (s SCTP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
bytes, err := b.PrependBytes(12)
if err != nil {
return err
}
binary.BigEndian.PutUint16(bytes[0:2], uint16(s.SrcPort))
binary.BigEndian.PutUint16(bytes[2:4], uint16(s.DstPort))
binary.BigEndian.PutUint32(bytes[4:8], s.VerificationTag)
if opts.ComputeChecksums {
// Note: MakeTable(Castagnoli) actually only creates the table once, then
// passes back a singleton on every other call, so this shouldn't cause
// excessive memory allocation.
binary.LittleEndian.PutUint32(bytes[8:12], crc32.Checksum(b.Bytes(), crc32.MakeTable(crc32.Castagnoli)))
}
return nil
}
func (sctp *SCTP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 12 {
return errors.New("Invalid SCTP common header length")
}
sctp.SrcPort = SCTPPort(binary.BigEndian.Uint16(data[:2]))
sctp.sPort = data[:2]
sctp.DstPort = SCTPPort(binary.BigEndian.Uint16(data[2:4]))
sctp.dPort = data[2:4]
sctp.VerificationTag = binary.BigEndian.Uint32(data[4:8])
sctp.Checksum = binary.BigEndian.Uint32(data[8:12])
sctp.BaseLayer = BaseLayer{data[:12], data[12:]}
return nil
}
func (t *SCTP) CanDecode() gopacket.LayerClass {
return LayerTypeSCTP
}
func (t *SCTP) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
// SCTPChunk contains the common fields in all SCTP chunks.
type SCTPChunk struct {
BaseLayer
Type SCTPChunkType
Flags uint8
Length uint16
// ActualLength is the total length of an SCTP chunk, including padding.
// SCTP chunks start and end on 4-byte boundaries. So if a chunk has a length
// of 18, it means that it has data up to and including byte 18, then padding
// up to the next 4-byte boundary, 20. In this case, Length would be 18, and
// ActualLength would be 20.
ActualLength int
}
func roundUpToNearest4(i int) int {
if i%4 == 0 {
return i
}
return i + 4 - (i % 4)
}
func decodeSCTPChunk(data []byte) (SCTPChunk, error) {
length := binary.BigEndian.Uint16(data[2:4])
if length < 4 {
return SCTPChunk{}, errors.New("invalid SCTP chunk length")
}
actual := roundUpToNearest4(int(length))
ct := SCTPChunkType(data[0])
// For SCTP Data, use a separate layer for the payload
delta := 0
if ct == SCTPChunkTypeData {
delta = int(actual) - int(length)
actual = 16
}
return SCTPChunk{
Type: ct,
Flags: data[1],
Length: length,
ActualLength: actual,
BaseLayer: BaseLayer{data[:actual], data[actual : len(data)-delta]},
}, nil
}
// SCTPParameter is a TLV parameter inside a SCTPChunk.
type SCTPParameter struct {
Type uint16
Length uint16
ActualLength int
Value []byte
}
func decodeSCTPParameter(data []byte) SCTPParameter {
length := binary.BigEndian.Uint16(data[2:4])
return SCTPParameter{
Type: binary.BigEndian.Uint16(data[0:2]),
Length: length,
Value: data[4:length],
ActualLength: roundUpToNearest4(int(length)),
}
}
func (p SCTPParameter) Bytes() []byte {
length := 4 + len(p.Value)
data := make([]byte, roundUpToNearest4(length))
binary.BigEndian.PutUint16(data[0:2], p.Type)
binary.BigEndian.PutUint16(data[2:4], uint16(length))
copy(data[4:], p.Value)
return data
}
// SCTPUnknownChunkType is the layer type returned when we don't recognize the
// chunk type. Since there's a length in a known location, we can skip over
// it even if we don't know what it is, and continue parsing the rest of the
// chunks. This chunk is stored as an ErrorLayer in the packet.
type SCTPUnknownChunkType struct {
SCTPChunk
bytes []byte
}
func decodeSCTPChunkTypeUnknown(data []byte, p gopacket.PacketBuilder) error {
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPUnknownChunkType{SCTPChunk: chunk}
sc.bytes = data[:sc.ActualLength]
p.AddLayer(sc)
p.SetErrorLayer(sc)
return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix))
}
// SerializeTo is for gopacket.SerializableLayer.
func (s SCTPUnknownChunkType) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
bytes, err := b.PrependBytes(s.ActualLength)
if err != nil {
return err
}
copy(bytes, s.bytes)
return nil
}
// LayerType returns gopacket.LayerTypeSCTPUnknownChunkType.
func (s *SCTPUnknownChunkType) LayerType() gopacket.LayerType { return LayerTypeSCTPUnknownChunkType }
// Payload returns all bytes in this header, including the decoded Type, Length,
// and Flags.
func (s *SCTPUnknownChunkType) Payload() []byte { return s.bytes }
// Error implements ErrorLayer.
func (s *SCTPUnknownChunkType) Error() error {
return fmt.Errorf("No decode method available for SCTP chunk type %s", s.Type)
}
// SCTPData is the SCTP Data chunk layer.
type SCTPData struct {
SCTPChunk
Unordered, BeginFragment, EndFragment bool
TSN uint32
StreamId uint16
StreamSequence uint16
PayloadProtocol SCTPPayloadProtocol
}
// LayerType returns gopacket.LayerTypeSCTPData.
func (s *SCTPData) LayerType() gopacket.LayerType { return LayerTypeSCTPData }
// SCTPPayloadProtocol represents a payload protocol
type SCTPPayloadProtocol uint32
// SCTPPayloadProtocol constonts from http://www.iana.org/assignments/sctp-parameters/sctp-parameters.xhtml
const (
SCTPProtocolReserved SCTPPayloadProtocol = 0
SCTPPayloadUIA = 1
SCTPPayloadM2UA = 2
SCTPPayloadM3UA = 3
SCTPPayloadSUA = 4
SCTPPayloadM2PA = 5
SCTPPayloadV5UA = 6
SCTPPayloadH248 = 7
SCTPPayloadBICC = 8
SCTPPayloadTALI = 9
SCTPPayloadDUA = 10
SCTPPayloadASAP = 11
SCTPPayloadENRP = 12
SCTPPayloadH323 = 13
SCTPPayloadQIPC = 14
SCTPPayloadSIMCO = 15
SCTPPayloadDDPSegment = 16
SCTPPayloadDDPStream = 17
SCTPPayloadS1AP = 18
)
func (p SCTPPayloadProtocol) String() string {
switch p {
case SCTPProtocolReserved:
return "Reserved"
case SCTPPayloadUIA:
return "UIA"
case SCTPPayloadM2UA:
return "M2UA"
case SCTPPayloadM3UA:
return "M3UA"
case SCTPPayloadSUA:
return "SUA"
case SCTPPayloadM2PA:
return "M2PA"
case SCTPPayloadV5UA:
return "V5UA"
case SCTPPayloadH248:
return "H.248"
case SCTPPayloadBICC:
return "BICC"
case SCTPPayloadTALI:
return "TALI"
case SCTPPayloadDUA:
return "DUA"
case SCTPPayloadASAP:
return "ASAP"
case SCTPPayloadENRP:
return "ENRP"
case SCTPPayloadH323:
return "H.323"
case SCTPPayloadQIPC:
return "QIPC"
case SCTPPayloadSIMCO:
return "SIMCO"
case SCTPPayloadDDPSegment:
return "DDPSegment"
case SCTPPayloadDDPStream:
return "DDPStream"
case SCTPPayloadS1AP:
return "S1AP"
}
return fmt.Sprintf("Unknown(%d)", p)
}
func decodeSCTPData(data []byte, p gopacket.PacketBuilder) error {
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPData{
SCTPChunk: chunk,
Unordered: data[1]&0x4 != 0,
BeginFragment: data[1]&0x2 != 0,
EndFragment: data[1]&0x1 != 0,
TSN: binary.BigEndian.Uint32(data[4:8]),
StreamId: binary.BigEndian.Uint16(data[8:10]),
StreamSequence: binary.BigEndian.Uint16(data[10:12]),
PayloadProtocol: SCTPPayloadProtocol(binary.BigEndian.Uint32(data[12:16])),
}
// Length is the length in bytes of the data, INCLUDING the 16-byte header.
p.AddLayer(sc)
return p.NextDecoder(gopacket.LayerTypePayload)
}
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPData) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
payload := b.Bytes()
// Pad the payload to a 32 bit boundary
if rem := len(payload) % 4; rem != 0 {
b.AppendBytes(4 - rem)
}
length := 16
bytes, err := b.PrependBytes(length)
if err != nil {
return err
}
bytes[0] = uint8(sc.Type)
flags := uint8(0)
if sc.Unordered {
flags |= 0x4
}
if sc.BeginFragment {
flags |= 0x2
}
if sc.EndFragment {
flags |= 0x1
}
bytes[1] = flags
binary.BigEndian.PutUint16(bytes[2:4], uint16(length+len(payload)))
binary.BigEndian.PutUint32(bytes[4:8], sc.TSN)
binary.BigEndian.PutUint16(bytes[8:10], sc.StreamId)
binary.BigEndian.PutUint16(bytes[10:12], sc.StreamSequence)
binary.BigEndian.PutUint32(bytes[12:16], uint32(sc.PayloadProtocol))
return nil
}
// SCTPInitParameter is a parameter for an SCTP Init or InitAck packet.
type SCTPInitParameter SCTPParameter
// SCTPInit is used as the return value for both SCTPInit and SCTPInitAck
// messages.
type SCTPInit struct {
SCTPChunk
InitiateTag uint32
AdvertisedReceiverWindowCredit uint32
OutboundStreams, InboundStreams uint16
InitialTSN uint32
Parameters []SCTPInitParameter
}
// LayerType returns either gopacket.LayerTypeSCTPInit or gopacket.LayerTypeSCTPInitAck.
func (sc *SCTPInit) LayerType() gopacket.LayerType {
if sc.Type == SCTPChunkTypeInitAck {
return LayerTypeSCTPInitAck
}
// sc.Type == SCTPChunkTypeInit
return LayerTypeSCTPInit
}
func decodeSCTPInit(data []byte, p gopacket.PacketBuilder) error {
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPInit{
SCTPChunk: chunk,
InitiateTag: binary.BigEndian.Uint32(data[4:8]),
AdvertisedReceiverWindowCredit: binary.BigEndian.Uint32(data[8:12]),
OutboundStreams: binary.BigEndian.Uint16(data[12:14]),
InboundStreams: binary.BigEndian.Uint16(data[14:16]),
InitialTSN: binary.BigEndian.Uint32(data[16:20]),
}
paramData := data[20:sc.ActualLength]
for len(paramData) > 0 {
p := SCTPInitParameter(decodeSCTPParameter(paramData))
paramData = paramData[p.ActualLength:]
sc.Parameters = append(sc.Parameters, p)
}
p.AddLayer(sc)
return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix))
}
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPInit) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
var payload []byte
for _, param := range sc.Parameters {
payload = append(payload, SCTPParameter(param).Bytes()...)
}
length := 20 + len(payload)
bytes, err := b.PrependBytes(roundUpToNearest4(length))
if err != nil {
return err
}
bytes[0] = uint8(sc.Type)
bytes[1] = sc.Flags
binary.BigEndian.PutUint16(bytes[2:4], uint16(length))
binary.BigEndian.PutUint32(bytes[4:8], sc.InitiateTag)
binary.BigEndian.PutUint32(bytes[8:12], sc.AdvertisedReceiverWindowCredit)
binary.BigEndian.PutUint16(bytes[12:14], sc.OutboundStreams)
binary.BigEndian.PutUint16(bytes[14:16], sc.InboundStreams)
binary.BigEndian.PutUint32(bytes[16:20], sc.InitialTSN)
copy(bytes[20:], payload)
return nil
}
// SCTPSack is the SCTP Selective ACK chunk layer.
type SCTPSack struct {
SCTPChunk
CumulativeTSNAck uint32
AdvertisedReceiverWindowCredit uint32
NumGapACKs, NumDuplicateTSNs uint16
GapACKs []uint16
DuplicateTSNs []uint32
}
// LayerType return LayerTypeSCTPSack
func (sc *SCTPSack) LayerType() gopacket.LayerType {
return LayerTypeSCTPSack
}
func decodeSCTPSack(data []byte, p gopacket.PacketBuilder) error {
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPSack{
SCTPChunk: chunk,
CumulativeTSNAck: binary.BigEndian.Uint32(data[4:8]),
AdvertisedReceiverWindowCredit: binary.BigEndian.Uint32(data[8:12]),
NumGapACKs: binary.BigEndian.Uint16(data[12:14]),
NumDuplicateTSNs: binary.BigEndian.Uint16(data[14:16]),
}
// We maximize gapAcks and dupTSNs here so we're not allocating tons
// of memory based on a user-controlable field. Our maximums are not exact,
// but should give us sane defaults... we'll still hit slice boundaries and
// fail if the user-supplied values are too high (in the for loops below), but
// the amount of memory we'll have allocated because of that should be small
// (< sc.ActualLength)
gapAcks := sc.SCTPChunk.ActualLength / 2
dupTSNs := (sc.SCTPChunk.ActualLength - gapAcks*2) / 4
if gapAcks > int(sc.NumGapACKs) {
gapAcks = int(sc.NumGapACKs)
}
if dupTSNs > int(sc.NumDuplicateTSNs) {
dupTSNs = int(sc.NumDuplicateTSNs)
}
sc.GapACKs = make([]uint16, 0, gapAcks)
sc.DuplicateTSNs = make([]uint32, 0, dupTSNs)
bytesRemaining := data[16:]
for i := 0; i < int(sc.NumGapACKs); i++ {
sc.GapACKs = append(sc.GapACKs, binary.BigEndian.Uint16(bytesRemaining[:2]))
bytesRemaining = bytesRemaining[2:]
}
for i := 0; i < int(sc.NumDuplicateTSNs); i++ {
sc.DuplicateTSNs = append(sc.DuplicateTSNs, binary.BigEndian.Uint32(bytesRemaining[:4]))
bytesRemaining = bytesRemaining[4:]
}
p.AddLayer(sc)
return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix))
}
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPSack) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
length := 16 + 2*len(sc.GapACKs) + 4*len(sc.DuplicateTSNs)
bytes, err := b.PrependBytes(roundUpToNearest4(length))
if err != nil {
return err
}
bytes[0] = uint8(sc.Type)
bytes[1] = sc.Flags
binary.BigEndian.PutUint16(bytes[2:4], uint16(length))
binary.BigEndian.PutUint32(bytes[4:8], sc.CumulativeTSNAck)
binary.BigEndian.PutUint32(bytes[8:12], sc.AdvertisedReceiverWindowCredit)
binary.BigEndian.PutUint16(bytes[12:14], uint16(len(sc.GapACKs)))
binary.BigEndian.PutUint16(bytes[14:16], uint16(len(sc.DuplicateTSNs)))
for i, v := range sc.GapACKs {
binary.BigEndian.PutUint16(bytes[16+i*2:], v)
}
offset := 16 + 2*len(sc.GapACKs)
for i, v := range sc.DuplicateTSNs {
binary.BigEndian.PutUint32(bytes[offset+i*4:], v)
}
return nil
}
// SCTPHeartbeatParameter is the parameter type used by SCTP heartbeat and
// heartbeat ack layers.
type SCTPHeartbeatParameter SCTPParameter
// SCTPHeartbeat is the SCTP heartbeat layer, also used for heatbeat ack.
type SCTPHeartbeat struct {
SCTPChunk
Parameters []SCTPHeartbeatParameter
}
// LayerType returns gopacket.LayerTypeSCTPHeartbeat.
func (sc *SCTPHeartbeat) LayerType() gopacket.LayerType {
if sc.Type == SCTPChunkTypeHeartbeatAck {
return LayerTypeSCTPHeartbeatAck
}
// sc.Type == SCTPChunkTypeHeartbeat
return LayerTypeSCTPHeartbeat
}
func decodeSCTPHeartbeat(data []byte, p gopacket.PacketBuilder) error {
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPHeartbeat{
SCTPChunk: chunk,
}
paramData := data[4:sc.Length]
for len(paramData) > 0 {
p := SCTPHeartbeatParameter(decodeSCTPParameter(paramData))
paramData = paramData[p.ActualLength:]
sc.Parameters = append(sc.Parameters, p)
}
p.AddLayer(sc)
return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix))
}
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPHeartbeat) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
var payload []byte
for _, param := range sc.Parameters {
payload = append(payload, SCTPParameter(param).Bytes()...)
}
length := 4 + len(payload)
bytes, err := b.PrependBytes(roundUpToNearest4(length))
if err != nil {
return err
}
bytes[0] = uint8(sc.Type)
bytes[1] = sc.Flags
binary.BigEndian.PutUint16(bytes[2:4], uint16(length))
copy(bytes[4:], payload)
return nil
}
// SCTPErrorParameter is the parameter type used by SCTP Abort and Error layers.
type SCTPErrorParameter SCTPParameter
// SCTPError is the SCTP error layer, also used for SCTP aborts.
type SCTPError struct {
SCTPChunk
Parameters []SCTPErrorParameter
}
// LayerType returns LayerTypeSCTPAbort or LayerTypeSCTPError.
func (sc *SCTPError) LayerType() gopacket.LayerType {
if sc.Type == SCTPChunkTypeAbort {
return LayerTypeSCTPAbort
}
// sc.Type == SCTPChunkTypeError
return LayerTypeSCTPError
}
func decodeSCTPError(data []byte, p gopacket.PacketBuilder) error {
// remarkably similar to decodeSCTPHeartbeat ;)
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPError{
SCTPChunk: chunk,
}
paramData := data[4:sc.Length]
for len(paramData) > 0 {
p := SCTPErrorParameter(decodeSCTPParameter(paramData))
paramData = paramData[p.ActualLength:]
sc.Parameters = append(sc.Parameters, p)
}
p.AddLayer(sc)
return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix))
}
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPError) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
var payload []byte
for _, param := range sc.Parameters {
payload = append(payload, SCTPParameter(param).Bytes()...)
}
length := 4 + len(payload)
bytes, err := b.PrependBytes(roundUpToNearest4(length))
if err != nil {
return err
}
bytes[0] = uint8(sc.Type)
bytes[1] = sc.Flags
binary.BigEndian.PutUint16(bytes[2:4], uint16(length))
copy(bytes[4:], payload)
return nil
}
// SCTPShutdown is the SCTP shutdown layer.
type SCTPShutdown struct {
SCTPChunk
CumulativeTSNAck uint32
}
// LayerType returns gopacket.LayerTypeSCTPShutdown.
func (sc *SCTPShutdown) LayerType() gopacket.LayerType { return LayerTypeSCTPShutdown }
func decodeSCTPShutdown(data []byte, p gopacket.PacketBuilder) error {
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPShutdown{
SCTPChunk: chunk,
CumulativeTSNAck: binary.BigEndian.Uint32(data[4:8]),
}
p.AddLayer(sc)
return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix))
}
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPShutdown) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
bytes, err := b.PrependBytes(8)
if err != nil {
return err
}
bytes[0] = uint8(sc.Type)
bytes[1] = sc.Flags
binary.BigEndian.PutUint16(bytes[2:4], 8)
binary.BigEndian.PutUint32(bytes[4:8], sc.CumulativeTSNAck)
return nil
}
// SCTPShutdownAck is the SCTP shutdown layer.
type SCTPShutdownAck struct {
SCTPChunk
}
// LayerType returns gopacket.LayerTypeSCTPShutdownAck.
func (sc *SCTPShutdownAck) LayerType() gopacket.LayerType { return LayerTypeSCTPShutdownAck }
func decodeSCTPShutdownAck(data []byte, p gopacket.PacketBuilder) error {
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPShutdownAck{
SCTPChunk: chunk,
}
p.AddLayer(sc)
return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix))
}
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPShutdownAck) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
bytes, err := b.PrependBytes(4)
if err != nil {
return err
}
bytes[0] = uint8(sc.Type)
bytes[1] = sc.Flags
binary.BigEndian.PutUint16(bytes[2:4], 4)
return nil
}
// SCTPCookieEcho is the SCTP Cookie Echo layer.
type SCTPCookieEcho struct {
SCTPChunk
Cookie []byte
}
// LayerType returns gopacket.LayerTypeSCTPCookieEcho.
func (sc *SCTPCookieEcho) LayerType() gopacket.LayerType { return LayerTypeSCTPCookieEcho }
func decodeSCTPCookieEcho(data []byte, p gopacket.PacketBuilder) error {
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPCookieEcho{
SCTPChunk: chunk,
}
sc.Cookie = data[4:sc.Length]
p.AddLayer(sc)
return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix))
}
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPCookieEcho) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
length := 4 + len(sc.Cookie)
bytes, err := b.PrependBytes(roundUpToNearest4(length))
if err != nil {
return err
}
bytes[0] = uint8(sc.Type)
bytes[1] = sc.Flags
binary.BigEndian.PutUint16(bytes[2:4], uint16(length))
copy(bytes[4:], sc.Cookie)
return nil
}
// This struct is used by all empty SCTP chunks (currently CookieAck and
// ShutdownComplete).
type SCTPEmptyLayer struct {
SCTPChunk
}
// LayerType returns either gopacket.LayerTypeSCTPShutdownComplete or
// LayerTypeSCTPCookieAck.
func (sc *SCTPEmptyLayer) LayerType() gopacket.LayerType {
if sc.Type == SCTPChunkTypeShutdownComplete {
return LayerTypeSCTPShutdownComplete
}
// sc.Type == SCTPChunkTypeCookieAck
return LayerTypeSCTPCookieAck
}
func decodeSCTPEmptyLayer(data []byte, p gopacket.PacketBuilder) error {
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPEmptyLayer{
SCTPChunk: chunk,
}
p.AddLayer(sc)
return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix))
}
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPEmptyLayer) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
bytes, err := b.PrependBytes(4)
if err != nil {
return err
}
bytes[0] = uint8(sc.Type)
bytes[1] = sc.Flags
binary.BigEndian.PutUint16(bytes[2:4], 4)
return nil
}
// Copyright 2014 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
/*
This layer decodes SFlow version 5 datagrams.
The specification can be found here: http://sflow.org/sflow_version_5.txt
Additional developer information about sflow can be found at:
http://sflow.org/developers/specifications.php
And SFlow in general:
http://sflow.org/index.php
Two forms of sample data are defined: compact and expanded. The
Specification has this to say:
Compact and expand forms of counter and flow samples are defined.
An agent must not mix compact/expanded encodings. If an agent
will never use ifIndex numbers >= 2^24 then it must use compact
encodings for all interfaces. Otherwise the expanded formats must
be used for all interfaces.
This decoder only supports the compact form, because that is the only
one for which data was available.
The datagram is composed of one or more samples of type flow or counter,
and each sample is composed of one or more records describing the sample.
A sample is a single instance of sampled inforamtion, and each record in
the sample gives additional / supplimentary information about the sample.
The following sample record types are supported:
Raw Packet Header
opaque = flow_data; enterprise = 0; format = 1
Extended Switch Data
opaque = flow_data; enterprise = 0; format = 1001
Extended Router Data
opaque = flow_data; enterprise = 0; format = 1002
Extended Gateway Data
opaque = flow_data; enterprise = 0; format = 1003
Extended User Data
opaque = flow_data; enterprise = 0; format = 1004
Extended URL Data
opaque = flow_data; enterprise = 0; format = 1005
The following types of counter records are supported:
Generic Interface Counters - see RFC 2233
opaque = counter_data; enterprise = 0; format = 1
Ethernet Interface Counters - see RFC 2358
opaque = counter_data; enterprise = 0; format = 2
SFlow is encoded using XDR (RFC4506). There are a few places
where the standard 4-byte fields are partitioned into two
bitfields of different lengths. I'm not sure why the designers
chose to pack together two values like this in some places, and
in others they use the entire 4-byte value to store a number that
will never be more than a few bits. In any case, there are a couple
of types defined to handle the decoding of these bitfields, and
that's why they're there. */
package layers
import (
"encoding/binary"
"errors"
"fmt"
"net"
"github.com/google/gopacket"
)
// SFlowRecord holds both flow sample records and counter sample records.
// A Record is the structure that actually holds the sampled data
// and / or counters.
type SFlowRecord interface {
}
// SFlowDataSource encodes a 2-bit SFlowSourceFormat in its most significant
// 2 bits, and an SFlowSourceValue in its least significant 30 bits.
// These types and values define the meaning of the inteface information
// presented in the sample metadata.
type SFlowDataSource int32
func (sdc SFlowDataSource) decode() (SFlowSourceFormat, SFlowSourceValue) {
leftField := sdc >> 30
rightField := uint32(0x3FFFFFFF) & uint32(sdc)
return SFlowSourceFormat(leftField), SFlowSourceValue(rightField)
}
type SFlowDataSourceExpanded struct {
SourceIDClass SFlowSourceFormat
SourceIDIndex SFlowSourceValue
}
func (sdce SFlowDataSourceExpanded) decode() (SFlowSourceFormat, SFlowSourceValue) {
leftField := sdce.SourceIDClass >> 30
rightField := uint32(0x3FFFFFFF) & uint32(sdce.SourceIDIndex)
return SFlowSourceFormat(leftField), SFlowSourceValue(rightField)
}
type SFlowSourceFormat uint32
type SFlowSourceValue uint32
const (
SFlowTypeSingleInterface SFlowSourceFormat = 0
SFlowTypePacketDiscarded SFlowSourceFormat = 1
SFlowTypeMultipleDestinations SFlowSourceFormat = 2
)
func (sdf SFlowSourceFormat) String() string {
switch sdf {
case SFlowTypeSingleInterface:
return "Single Interface"
case SFlowTypePacketDiscarded:
return "Packet Discarded"
case SFlowTypeMultipleDestinations:
return "Multiple Destinations"
default:
return "UNKNOWN"
}
}
func decodeSFlow(data []byte, p gopacket.PacketBuilder) error {
s := &SFlowDatagram{}
err := s.DecodeFromBytes(data, p)
if err != nil {
return err
}
p.AddLayer(s)
p.SetApplicationLayer(s)
return nil
}
// SFlowDatagram is the outermost container which holds some basic information
// about the reporting agent, and holds at least one sample record
type SFlowDatagram struct {
BaseLayer
DatagramVersion uint32
AgentAddress net.IP
SubAgentID uint32
SequenceNumber uint32
AgentUptime uint32
SampleCount uint32
FlowSamples []SFlowFlowSample
CounterSamples []SFlowCounterSample
}
// An SFlow datagram's outer container has the following
// structure:
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int sFlow version (2|4|5) |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int IP version of the Agent (1=v4|2=v6) |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// / Agent IP address (v4=4byte|v6=16byte) /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int sub agent id |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int datagram sequence number |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int switch uptime in ms |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int n samples in datagram |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// / n samples /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// SFlowDataFormat encodes the EnterpriseID in the most
// significant 12 bits, and the SampleType in the least significant
// 20 bits.
type SFlowDataFormat uint32
func (sdf SFlowDataFormat) decode() (SFlowEnterpriseID, SFlowSampleType) {
leftField := sdf >> 12
rightField := uint32(0xFFF) & uint32(sdf)
return SFlowEnterpriseID(leftField), SFlowSampleType(rightField)
}
// SFlowEnterpriseID is used to differentiate between the
// official SFlow standard, and other, vendor-specific
// types of flow data. (Similiar to SNMP's enterprise MIB
// OIDs) Only the office SFlow Enterprise ID is decoded
// here.
type SFlowEnterpriseID uint32
const (
SFlowStandard SFlowEnterpriseID = 0
)
func (eid SFlowEnterpriseID) String() string {
switch eid {
case SFlowStandard:
return "Standard SFlow"
default:
return ""
}
}
func (eid SFlowEnterpriseID) GetType() SFlowEnterpriseID {
return SFlowStandard
}
// SFlowSampleType specifies the type of sample. Only flow samples
// and counter samples are supported
type SFlowSampleType uint32
const (
SFlowTypeFlowSample SFlowSampleType = 1
SFlowTypeCounterSample SFlowSampleType = 2
SFlowTypeExpandedFlowSample SFlowSampleType = 3
SFlowTypeExpandedCounterSample SFlowSampleType = 4
)
func (st SFlowSampleType) GetType() SFlowSampleType {
switch st {
case SFlowTypeFlowSample:
return SFlowTypeFlowSample
case SFlowTypeCounterSample:
return SFlowTypeCounterSample
case SFlowTypeExpandedFlowSample:
return SFlowTypeExpandedFlowSample
case SFlowTypeExpandedCounterSample:
return SFlowTypeExpandedCounterSample
default:
panic("Invalid Sample Type")
}
}
func (st SFlowSampleType) String() string {
switch st {
case SFlowTypeFlowSample:
return "Flow Sample"
case SFlowTypeCounterSample:
return "Counter Sample"
case SFlowTypeExpandedFlowSample:
return "Expanded Flow Sample"
case SFlowTypeExpandedCounterSample:
return "Expanded Counter Sample"
default:
return ""
}
}
func (s *SFlowDatagram) LayerType() gopacket.LayerType { return LayerTypeSFlow }
func (d *SFlowDatagram) Payload() []byte { return nil }
func (d *SFlowDatagram) CanDecode() gopacket.LayerClass { return LayerTypeSFlow }
func (d *SFlowDatagram) NextLayerType() gopacket.LayerType { return gopacket.LayerTypePayload }
// SFlowIPType determines what form the IP address being decoded will
// take. This is an XDR union type allowing for both IPv4 and IPv6
type SFlowIPType uint32
const (
SFlowIPv4 SFlowIPType = 1
SFlowIPv6 SFlowIPType = 2
)
func (s SFlowIPType) String() string {
switch s {
case SFlowIPv4:
return "IPv4"
case SFlowIPv6:
return "IPv6"
default:
return ""
}
}
func (s SFlowIPType) Length() int {
switch s {
case SFlowIPv4:
return 4
case SFlowIPv6:
return 16
default:
return 0
}
}
func (s *SFlowDatagram) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
var agentAddressType SFlowIPType
data, s.DatagramVersion = data[4:], binary.BigEndian.Uint32(data[:4])
data, agentAddressType = data[4:], SFlowIPType(binary.BigEndian.Uint32(data[:4]))
data, s.AgentAddress = data[agentAddressType.Length():], data[:agentAddressType.Length()]
data, s.SubAgentID = data[4:], binary.BigEndian.Uint32(data[:4])
data, s.SequenceNumber = data[4:], binary.BigEndian.Uint32(data[:4])
data, s.AgentUptime = data[4:], binary.BigEndian.Uint32(data[:4])
data, s.SampleCount = data[4:], binary.BigEndian.Uint32(data[:4])
if s.SampleCount < 1 {
return fmt.Errorf("SFlow Datagram has invalid sample length: %d", s.SampleCount)
}
for i := uint32(0); i < s.SampleCount; i++ {
sdf := SFlowDataFormat(binary.BigEndian.Uint32(data[:4]))
_, sampleType := sdf.decode()
switch sampleType {
case SFlowTypeFlowSample:
if flowSample, err := decodeFlowSample(&data, false); err == nil {
s.FlowSamples = append(s.FlowSamples, flowSample)
} else {
return err
}
case SFlowTypeCounterSample:
if counterSample, err := decodeCounterSample(&data, false); err == nil {
s.CounterSamples = append(s.CounterSamples, counterSample)
} else {
return err
}
case SFlowTypeExpandedFlowSample:
if flowSample, err := decodeFlowSample(&data, true); err == nil {
s.FlowSamples = append(s.FlowSamples, flowSample)
} else {
return err
}
case SFlowTypeExpandedCounterSample:
if counterSample, err := decodeCounterSample(&data, true); err == nil {
s.CounterSamples = append(s.CounterSamples, counterSample)
} else {
return err
}
default:
return fmt.Errorf("Unsupported SFlow sample type %d", sampleType)
}
}
return nil
}
// SFlowFlowSample represents a sampled packet and contains
// one or more records describing the packet
type SFlowFlowSample struct {
EnterpriseID SFlowEnterpriseID
Format SFlowSampleType
SampleLength uint32
SequenceNumber uint32
SourceIDClass SFlowSourceFormat
SourceIDIndex SFlowSourceValue
SamplingRate uint32
SamplePool uint32
Dropped uint32
InputInterfaceFormat uint32
InputInterface uint32
OutputInterfaceFormat uint32
OutputInterface uint32
RecordCount uint32
Records []SFlowRecord
}
// Flow samples have the following structure. Note
// the bit fields to encode the Enterprise ID and the
// Flow record format: type 1
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | sample length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int sample sequence number |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |id type | src id index value |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int sampling rate |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int sample pool |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int drops |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int input ifIndex |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int output ifIndex |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int number of records |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// / flow records /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// Flow samples have the following structure.
// Flow record format: type 3
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | sample length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int sample sequence number |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int src id type |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int src id index value |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int sampling rate |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int sample pool |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int drops |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int input interface format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int input interface value |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int output interface format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int output interface value |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int number of records |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// / flow records /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowFlowDataFormat uint32
func (fdf SFlowFlowDataFormat) decode() (SFlowEnterpriseID, SFlowFlowRecordType) {
leftField := fdf >> 12
rightField := uint32(0xFFF) & uint32(fdf)
return SFlowEnterpriseID(leftField), SFlowFlowRecordType(rightField)
}
func (fs SFlowFlowSample) GetRecords() []SFlowRecord {
return fs.Records
}
func (fs SFlowFlowSample) GetType() SFlowSampleType {
return SFlowTypeFlowSample
}
func skipRecord(data *[]byte) {
recordLength := int(binary.BigEndian.Uint32((*data)[4:]))
*data = (*data)[(recordLength+((4-recordLength)%4))+8:]
}
func decodeFlowSample(data *[]byte, expanded bool) (SFlowFlowSample, error) {
s := SFlowFlowSample{}
var sdf SFlowDataFormat
*data, sdf = (*data)[4:], SFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
var sdc SFlowDataSource
s.EnterpriseID, s.Format = sdf.decode()
if len(*data) < 4 {
return SFlowFlowSample{}, errors.New("ethernet counters too small")
}
*data, s.SampleLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowFlowSample{}, errors.New("ethernet counters too small")
}
*data, s.SequenceNumber = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if expanded {
if len(*data) < 4 {
return SFlowFlowSample{}, errors.New("ethernet counters too small")
}
*data, s.SourceIDClass = (*data)[4:], SFlowSourceFormat(binary.BigEndian.Uint32((*data)[:4]))
if len(*data) < 4 {
return SFlowFlowSample{}, errors.New("ethernet counters too small")
}
*data, s.SourceIDIndex = (*data)[4:], SFlowSourceValue(binary.BigEndian.Uint32((*data)[:4]))
} else {
if len(*data) < 4 {
return SFlowFlowSample{}, errors.New("ethernet counters too small")
}
*data, sdc = (*data)[4:], SFlowDataSource(binary.BigEndian.Uint32((*data)[:4]))
s.SourceIDClass, s.SourceIDIndex = sdc.decode()
}
if len(*data) < 4 {
return SFlowFlowSample{}, errors.New("ethernet counters too small")
}
*data, s.SamplingRate = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowFlowSample{}, errors.New("ethernet counters too small")
}
*data, s.SamplePool = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowFlowSample{}, errors.New("ethernet counters too small")
}
*data, s.Dropped = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if expanded {
if len(*data) < 4 {
return SFlowFlowSample{}, errors.New("ethernet counters too small")
}
*data, s.InputInterfaceFormat = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowFlowSample{}, errors.New("ethernet counters too small")
}
*data, s.InputInterface = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowFlowSample{}, errors.New("ethernet counters too small")
}
*data, s.OutputInterfaceFormat = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowFlowSample{}, errors.New("ethernet counters too small")
}
*data, s.OutputInterface = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
} else {
if len(*data) < 4 {
return SFlowFlowSample{}, errors.New("ethernet counters too small")
}
*data, s.InputInterface = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowFlowSample{}, errors.New("ethernet counters too small")
}
*data, s.OutputInterface = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
}
if len(*data) < 4 {
return SFlowFlowSample{}, errors.New("ethernet counters too small")
}
*data, s.RecordCount = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
for i := uint32(0); i < s.RecordCount; i++ {
rdf := SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
enterpriseID, flowRecordType := rdf.decode()
// Try to decode when EnterpriseID is 0 signaling
// default sflow structs are used according specification
// Unexpected behavior detected for e.g. with pmacct
if enterpriseID == 0 {
switch flowRecordType {
case SFlowTypeRawPacketFlow:
if record, err := decodeRawPacketFlowRecord(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeExtendedUserFlow:
if record, err := decodeExtendedUserFlow(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeExtendedUrlFlow:
if record, err := decodeExtendedURLRecord(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeExtendedSwitchFlow:
if record, err := decodeExtendedSwitchFlowRecord(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeExtendedRouterFlow:
if record, err := decodeExtendedRouterFlowRecord(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeExtendedGatewayFlow:
if record, err := decodeExtendedGatewayFlowRecord(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeEthernetFrameFlow:
if record, err := decodeEthernetFrameFlowRecord(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeIpv4Flow:
if record, err := decodeSFlowIpv4Record(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeIpv6Flow:
if record, err := decodeSFlowIpv6Record(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeExtendedMlpsFlow:
// TODO
skipRecord(data)
return s, errors.New("skipping TypeExtendedMlpsFlow")
case SFlowTypeExtendedNatFlow:
// TODO
skipRecord(data)
return s, errors.New("skipping TypeExtendedNatFlow")
case SFlowTypeExtendedMlpsTunnelFlow:
// TODO
skipRecord(data)
return s, errors.New("skipping TypeExtendedMlpsTunnelFlow")
case SFlowTypeExtendedMlpsVcFlow:
// TODO
skipRecord(data)
return s, errors.New("skipping TypeExtendedMlpsVcFlow")
case SFlowTypeExtendedMlpsFecFlow:
// TODO
skipRecord(data)
return s, errors.New("skipping TypeExtendedMlpsFecFlow")
case SFlowTypeExtendedMlpsLvpFecFlow:
// TODO
skipRecord(data)
return s, errors.New("skipping TypeExtendedMlpsLvpFecFlow")
case SFlowTypeExtendedVlanFlow:
// TODO
skipRecord(data)
return s, errors.New("skipping TypeExtendedVlanFlow")
case SFlowTypeExtendedIpv4TunnelEgressFlow:
if record, err := decodeExtendedIpv4TunnelEgress(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeExtendedIpv4TunnelIngressFlow:
if record, err := decodeExtendedIpv4TunnelIngress(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeExtendedIpv6TunnelEgressFlow:
if record, err := decodeExtendedIpv6TunnelEgress(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeExtendedIpv6TunnelIngressFlow:
if record, err := decodeExtendedIpv6TunnelIngress(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeExtendedDecapsulateEgressFlow:
if record, err := decodeExtendedDecapsulateEgress(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeExtendedDecapsulateIngressFlow:
if record, err := decodeExtendedDecapsulateIngress(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeExtendedVniEgressFlow:
if record, err := decodeExtendedVniEgress(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeExtendedVniIngressFlow:
if record, err := decodeExtendedVniIngress(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
default:
return s, fmt.Errorf("Unsupported flow record type: %d", flowRecordType)
}
} else {
skipRecord(data)
}
}
return s, nil
}
// Counter samples report information about various counter
// objects. Typically these are items like IfInOctets, or
// CPU / Memory stats, etc. SFlow will report these at regular
// intervals as configured on the agent. If one were sufficiently
// industrious, this could be used to replace the typical
// SNMP polling used for such things.
type SFlowCounterSample struct {
EnterpriseID SFlowEnterpriseID
Format SFlowSampleType
SampleLength uint32
SequenceNumber uint32
SourceIDClass SFlowSourceFormat
SourceIDIndex SFlowSourceValue
RecordCount uint32
Records []SFlowRecord
}
// Counter samples have the following structure:
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int sample sequence number |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |id type | src id index value |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | int number of records |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// / counter records /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowCounterDataFormat uint32
func (cdf SFlowCounterDataFormat) decode() (SFlowEnterpriseID, SFlowCounterRecordType) {
leftField := cdf >> 12
rightField := uint32(0xFFF) & uint32(cdf)
return SFlowEnterpriseID(leftField), SFlowCounterRecordType(rightField)
}
// GetRecords will return a slice of interface types
// representing records. A type switch can be used to
// get at the underlying SFlowCounterRecordType.
func (cs SFlowCounterSample) GetRecords() []SFlowRecord {
return cs.Records
}
// GetType will report the type of sample. Only the
// compact form of counter samples is supported
func (cs SFlowCounterSample) GetType() SFlowSampleType {
return SFlowTypeCounterSample
}
type SFlowCounterRecordType uint32
const (
SFlowTypeGenericInterfaceCounters SFlowCounterRecordType = 1
SFlowTypeEthernetInterfaceCounters SFlowCounterRecordType = 2
SFlowTypeTokenRingInterfaceCounters SFlowCounterRecordType = 3
SFlowType100BaseVGInterfaceCounters SFlowCounterRecordType = 4
SFlowTypeVLANCounters SFlowCounterRecordType = 5
SFlowTypeLACPCounters SFlowCounterRecordType = 7
SFlowTypeProcessorCounters SFlowCounterRecordType = 1001
SFlowTypeOpenflowPortCounters SFlowCounterRecordType = 1004
SFlowTypePORTNAMECounters SFlowCounterRecordType = 1005
SFLowTypeAPPRESOURCESCounters SFlowCounterRecordType = 2203
SFlowTypeOVSDPCounters SFlowCounterRecordType = 2207
)
func (cr SFlowCounterRecordType) String() string {
switch cr {
case SFlowTypeGenericInterfaceCounters:
return "Generic Interface Counters"
case SFlowTypeEthernetInterfaceCounters:
return "Ethernet Interface Counters"
case SFlowTypeTokenRingInterfaceCounters:
return "Token Ring Interface Counters"
case SFlowType100BaseVGInterfaceCounters:
return "100BaseVG Interface Counters"
case SFlowTypeVLANCounters:
return "VLAN Counters"
case SFlowTypeLACPCounters:
return "LACP Counters"
case SFlowTypeProcessorCounters:
return "Processor Counters"
case SFlowTypeOpenflowPortCounters:
return "Openflow Port Counters"
case SFlowTypePORTNAMECounters:
return "PORT NAME Counters"
case SFLowTypeAPPRESOURCESCounters:
return "App Resources Counters"
case SFlowTypeOVSDPCounters:
return "OVSDP Counters"
default:
return ""
}
}
func decodeCounterSample(data *[]byte, expanded bool) (SFlowCounterSample, error) {
s := SFlowCounterSample{}
var sdc SFlowDataSource
var sdce SFlowDataSourceExpanded
var sdf SFlowDataFormat
*data, sdf = (*data)[4:], SFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
s.EnterpriseID, s.Format = sdf.decode()
*data, s.SampleLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, s.SequenceNumber = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if expanded {
*data, sdce = (*data)[8:], SFlowDataSourceExpanded{SFlowSourceFormat(binary.BigEndian.Uint32((*data)[:4])), SFlowSourceValue(binary.BigEndian.Uint32((*data)[4:8]))}
s.SourceIDClass, s.SourceIDIndex = sdce.decode()
} else {
*data, sdc = (*data)[4:], SFlowDataSource(binary.BigEndian.Uint32((*data)[:4]))
s.SourceIDClass, s.SourceIDIndex = sdc.decode()
}
*data, s.RecordCount = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
for i := uint32(0); i < s.RecordCount; i++ {
cdf := SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
_, counterRecordType := cdf.decode()
switch counterRecordType {
case SFlowTypeGenericInterfaceCounters:
if record, err := decodeGenericInterfaceCounters(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeEthernetInterfaceCounters:
if record, err := decodeEthernetCounters(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeTokenRingInterfaceCounters:
skipRecord(data)
return s, errors.New("skipping TypeTokenRingInterfaceCounters")
case SFlowType100BaseVGInterfaceCounters:
skipRecord(data)
return s, errors.New("skipping Type100BaseVGInterfaceCounters")
case SFlowTypeVLANCounters:
if record, err := decodeVLANCounters(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeLACPCounters:
if record, err := decodeLACPCounters(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeProcessorCounters:
if record, err := decodeProcessorCounters(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeOpenflowPortCounters:
if record, err := decodeOpenflowportCounters(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypePORTNAMECounters:
if record, err := decodePortnameCounters(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFLowTypeAPPRESOURCESCounters:
if record, err := decodeAppresourcesCounters(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
case SFlowTypeOVSDPCounters:
if record, err := decodeOVSDPCounters(data); err == nil {
s.Records = append(s.Records, record)
} else {
return s, err
}
default:
return s, fmt.Errorf("Invalid counter record type: %d", counterRecordType)
}
}
return s, nil
}
// SFlowBaseFlowRecord holds the fields common to all records
// of type SFlowFlowRecordType
type SFlowBaseFlowRecord struct {
EnterpriseID SFlowEnterpriseID
Format SFlowFlowRecordType
FlowDataLength uint32
}
func (bfr SFlowBaseFlowRecord) GetType() SFlowFlowRecordType {
return bfr.Format
}
// SFlowFlowRecordType denotes what kind of Flow Record is
// represented. See RFC 3176
type SFlowFlowRecordType uint32
const (
SFlowTypeRawPacketFlow SFlowFlowRecordType = 1
SFlowTypeEthernetFrameFlow SFlowFlowRecordType = 2
SFlowTypeIpv4Flow SFlowFlowRecordType = 3
SFlowTypeIpv6Flow SFlowFlowRecordType = 4
SFlowTypeExtendedSwitchFlow SFlowFlowRecordType = 1001
SFlowTypeExtendedRouterFlow SFlowFlowRecordType = 1002
SFlowTypeExtendedGatewayFlow SFlowFlowRecordType = 1003
SFlowTypeExtendedUserFlow SFlowFlowRecordType = 1004
SFlowTypeExtendedUrlFlow SFlowFlowRecordType = 1005
SFlowTypeExtendedMlpsFlow SFlowFlowRecordType = 1006
SFlowTypeExtendedNatFlow SFlowFlowRecordType = 1007
SFlowTypeExtendedMlpsTunnelFlow SFlowFlowRecordType = 1008
SFlowTypeExtendedMlpsVcFlow SFlowFlowRecordType = 1009
SFlowTypeExtendedMlpsFecFlow SFlowFlowRecordType = 1010
SFlowTypeExtendedMlpsLvpFecFlow SFlowFlowRecordType = 1011
SFlowTypeExtendedVlanFlow SFlowFlowRecordType = 1012
SFlowTypeExtendedIpv4TunnelEgressFlow SFlowFlowRecordType = 1023
SFlowTypeExtendedIpv4TunnelIngressFlow SFlowFlowRecordType = 1024
SFlowTypeExtendedIpv6TunnelEgressFlow SFlowFlowRecordType = 1025
SFlowTypeExtendedIpv6TunnelIngressFlow SFlowFlowRecordType = 1026
SFlowTypeExtendedDecapsulateEgressFlow SFlowFlowRecordType = 1027
SFlowTypeExtendedDecapsulateIngressFlow SFlowFlowRecordType = 1028
SFlowTypeExtendedVniEgressFlow SFlowFlowRecordType = 1029
SFlowTypeExtendedVniIngressFlow SFlowFlowRecordType = 1030
)
func (rt SFlowFlowRecordType) String() string {
switch rt {
case SFlowTypeRawPacketFlow:
return "Raw Packet Flow Record"
case SFlowTypeEthernetFrameFlow:
return "Ethernet Frame Flow Record"
case SFlowTypeIpv4Flow:
return "IPv4 Flow Record"
case SFlowTypeIpv6Flow:
return "IPv6 Flow Record"
case SFlowTypeExtendedSwitchFlow:
return "Extended Switch Flow Record"
case SFlowTypeExtendedRouterFlow:
return "Extended Router Flow Record"
case SFlowTypeExtendedGatewayFlow:
return "Extended Gateway Flow Record"
case SFlowTypeExtendedUserFlow:
return "Extended User Flow Record"
case SFlowTypeExtendedUrlFlow:
return "Extended URL Flow Record"
case SFlowTypeExtendedMlpsFlow:
return "Extended MPLS Flow Record"
case SFlowTypeExtendedNatFlow:
return "Extended NAT Flow Record"
case SFlowTypeExtendedMlpsTunnelFlow:
return "Extended MPLS Tunnel Flow Record"
case SFlowTypeExtendedMlpsVcFlow:
return "Extended MPLS VC Flow Record"
case SFlowTypeExtendedMlpsFecFlow:
return "Extended MPLS FEC Flow Record"
case SFlowTypeExtendedMlpsLvpFecFlow:
return "Extended MPLS LVP FEC Flow Record"
case SFlowTypeExtendedVlanFlow:
return "Extended VLAN Flow Record"
case SFlowTypeExtendedIpv4TunnelEgressFlow:
return "Extended IPv4 Tunnel Egress Record"
case SFlowTypeExtendedIpv4TunnelIngressFlow:
return "Extended IPv4 Tunnel Ingress Record"
case SFlowTypeExtendedIpv6TunnelEgressFlow:
return "Extended IPv6 Tunnel Egress Record"
case SFlowTypeExtendedIpv6TunnelIngressFlow:
return "Extended IPv6 Tunnel Ingress Record"
case SFlowTypeExtendedDecapsulateEgressFlow:
return "Extended Decapsulate Egress Record"
case SFlowTypeExtendedDecapsulateIngressFlow:
return "Extended Decapsulate Ingress Record"
case SFlowTypeExtendedVniEgressFlow:
return "Extended VNI Ingress Record"
case SFlowTypeExtendedVniIngressFlow:
return "Extended VNI Ingress Record"
default:
return ""
}
}
// SFlowRawPacketFlowRecords hold information about a sampled
// packet grabbed as it transited the agent. This is
// perhaps the most useful and interesting record type,
// as it holds the headers of the sampled packet and
// can be used to build up a complete picture of the
// traffic patterns on a network.
//
// The raw packet header is sent back into gopacket for
// decoding, and the resulting gopackt.Packet is stored
// in the Header member
type SFlowRawPacketFlowRecord struct {
SFlowBaseFlowRecord
HeaderProtocol SFlowRawHeaderProtocol
FrameLength uint32
PayloadRemoved uint32
HeaderLength uint32
Header gopacket.Packet
}
// Raw packet record types have the following structure:
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | record length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Header Protocol |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Frame Length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Payload Removed |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Header Length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// \ Header \
// \ \
// \ \
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowRawHeaderProtocol uint32
const (
SFlowProtoEthernet SFlowRawHeaderProtocol = 1
SFlowProtoISO88024 SFlowRawHeaderProtocol = 2
SFlowProtoISO88025 SFlowRawHeaderProtocol = 3
SFlowProtoFDDI SFlowRawHeaderProtocol = 4
SFlowProtoFrameRelay SFlowRawHeaderProtocol = 5
SFlowProtoX25 SFlowRawHeaderProtocol = 6
SFlowProtoPPP SFlowRawHeaderProtocol = 7
SFlowProtoSMDS SFlowRawHeaderProtocol = 8
SFlowProtoAAL5 SFlowRawHeaderProtocol = 9
SFlowProtoAAL5_IP SFlowRawHeaderProtocol = 10 /* e.g. Cisco AAL5 mux */
SFlowProtoIPv4 SFlowRawHeaderProtocol = 11
SFlowProtoIPv6 SFlowRawHeaderProtocol = 12
SFlowProtoMPLS SFlowRawHeaderProtocol = 13
SFlowProtoPOS SFlowRawHeaderProtocol = 14 /* RFC 1662, 2615 */
)
func (sfhp SFlowRawHeaderProtocol) String() string {
switch sfhp {
case SFlowProtoEthernet:
return "ETHERNET-ISO88023"
case SFlowProtoISO88024:
return "ISO88024-TOKENBUS"
case SFlowProtoISO88025:
return "ISO88025-TOKENRING"
case SFlowProtoFDDI:
return "FDDI"
case SFlowProtoFrameRelay:
return "FRAME-RELAY"
case SFlowProtoX25:
return "X25"
case SFlowProtoPPP:
return "PPP"
case SFlowProtoSMDS:
return "SMDS"
case SFlowProtoAAL5:
return "AAL5"
case SFlowProtoAAL5_IP:
return "AAL5-IP"
case SFlowProtoIPv4:
return "IPv4"
case SFlowProtoIPv6:
return "IPv6"
case SFlowProtoMPLS:
return "MPLS"
case SFlowProtoPOS:
return "POS"
}
return "UNKNOWN"
}
func decodeRawPacketFlowRecord(data *[]byte) (SFlowRawPacketFlowRecord, error) {
rec := SFlowRawPacketFlowRecord{}
header := []byte{}
var fdf SFlowFlowDataFormat
*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
rec.EnterpriseID, rec.Format = fdf.decode()
*data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, rec.HeaderProtocol = (*data)[4:], SFlowRawHeaderProtocol(binary.BigEndian.Uint32((*data)[:4]))
*data, rec.FrameLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, rec.PayloadRemoved = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, rec.HeaderLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
headerLenWithPadding := int(rec.HeaderLength + ((4 - rec.HeaderLength) % 4))
*data, header = (*data)[headerLenWithPadding:], (*data)[:headerLenWithPadding]
rec.Header = gopacket.NewPacket(header, LayerTypeEthernet, gopacket.Default)
return rec, nil
}
// SFlowExtendedSwitchFlowRecord give additional information
// about the sampled packet if it's available. It's mainly
// useful for getting at the incoming and outgoing VLANs
// An agent may or may not provide this information.
type SFlowExtendedSwitchFlowRecord struct {
SFlowBaseFlowRecord
IncomingVLAN uint32
IncomingVLANPriority uint32
OutgoingVLAN uint32
OutgoingVLANPriority uint32
}
// Extended switch records have the following structure:
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | record length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Incoming VLAN |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Incoming VLAN Priority |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Outgoing VLAN |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Outgoing VLAN Priority |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
func decodeExtendedSwitchFlowRecord(data *[]byte) (SFlowExtendedSwitchFlowRecord, error) {
es := SFlowExtendedSwitchFlowRecord{}
var fdf SFlowFlowDataFormat
*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
es.EnterpriseID, es.Format = fdf.decode()
*data, es.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, es.IncomingVLAN = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, es.IncomingVLANPriority = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, es.OutgoingVLAN = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, es.OutgoingVLANPriority = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
return es, nil
}
// SFlowExtendedRouterFlowRecord gives additional information
// about the layer 3 routing information used to forward
// the packet
type SFlowExtendedRouterFlowRecord struct {
SFlowBaseFlowRecord
NextHop net.IP
NextHopSourceMask uint32
NextHopDestinationMask uint32
}
// Extended router records have the following structure:
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | record length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IP version of next hop router (1=v4|2=v6) |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// / Next Hop address (v4=4byte|v6=16byte) /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Next Hop Source Mask |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Next Hop Destination Mask |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
func decodeExtendedRouterFlowRecord(data *[]byte) (SFlowExtendedRouterFlowRecord, error) {
er := SFlowExtendedRouterFlowRecord{}
var fdf SFlowFlowDataFormat
var extendedRouterAddressType SFlowIPType
*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
er.EnterpriseID, er.Format = fdf.decode()
*data, er.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, extendedRouterAddressType = (*data)[4:], SFlowIPType(binary.BigEndian.Uint32((*data)[:4]))
*data, er.NextHop = (*data)[extendedRouterAddressType.Length():], (*data)[:extendedRouterAddressType.Length()]
*data, er.NextHopSourceMask = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, er.NextHopDestinationMask = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
return er, nil
}
// SFlowExtendedGatewayFlowRecord describes information treasured by
// nework engineers everywhere: AS path information listing which
// BGP peer sent the packet, and various other BGP related info.
// This information is vital because it gives a picture of how much
// traffic is being sent from / received by various BGP peers.
// Extended gateway records have the following structure:
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | record length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IP version of next hop router (1=v4|2=v6) |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// / Next Hop address (v4=4byte|v6=16byte) /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | AS |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Source AS |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Peer AS |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | AS Path Count |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// / AS Path / Sequence /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// / Communities /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Local Pref |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// AS Path / Sequence:
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | AS Source Type (Path=1 / Sequence=2) |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Path / Sequence length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// / Path / Sequence Members /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// Communities:
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | communitiy length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// / communitiy Members /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowExtendedGatewayFlowRecord struct {
SFlowBaseFlowRecord
NextHop net.IP
AS uint32
SourceAS uint32
PeerAS uint32
ASPathCount uint32
ASPath []SFlowASDestination
Communities []uint32
LocalPref uint32
}
type SFlowASPathType uint32
const (
SFlowASSet SFlowASPathType = 1
SFlowASSequence SFlowASPathType = 2
)
func (apt SFlowASPathType) String() string {
switch apt {
case SFlowASSet:
return "AS Set"
case SFlowASSequence:
return "AS Sequence"
default:
return ""
}
}
type SFlowASDestination struct {
Type SFlowASPathType
Count uint32
Members []uint32
}
func (asd SFlowASDestination) String() string {
switch asd.Type {
case SFlowASSet:
return fmt.Sprint("AS Set:", asd.Members)
case SFlowASSequence:
return fmt.Sprint("AS Sequence:", asd.Members)
default:
return ""
}
}
func (ad *SFlowASDestination) decodePath(data *[]byte) {
*data, ad.Type = (*data)[4:], SFlowASPathType(binary.BigEndian.Uint32((*data)[:4]))
*data, ad.Count = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
ad.Members = make([]uint32, ad.Count)
for i := uint32(0); i < ad.Count; i++ {
var member uint32
*data, member = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
ad.Members[i] = member
}
}
func decodeExtendedGatewayFlowRecord(data *[]byte) (SFlowExtendedGatewayFlowRecord, error) {
eg := SFlowExtendedGatewayFlowRecord{}
var fdf SFlowFlowDataFormat
var extendedGatewayAddressType SFlowIPType
var communitiesLength uint32
var community uint32
*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
eg.EnterpriseID, eg.Format = fdf.decode()
*data, eg.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, extendedGatewayAddressType = (*data)[4:], SFlowIPType(binary.BigEndian.Uint32((*data)[:4]))
*data, eg.NextHop = (*data)[extendedGatewayAddressType.Length():], (*data)[:extendedGatewayAddressType.Length()]
*data, eg.AS = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, eg.SourceAS = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, eg.PeerAS = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, eg.ASPathCount = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
for i := uint32(0); i < eg.ASPathCount; i++ {
asPath := SFlowASDestination{}
asPath.decodePath(data)
eg.ASPath = append(eg.ASPath, asPath)
}
*data, communitiesLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
eg.Communities = make([]uint32, communitiesLength)
for j := uint32(0); j < communitiesLength; j++ {
*data, community = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
eg.Communities[j] = community
}
*data, eg.LocalPref = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
return eg, nil
}
// **************************************************
// Extended URL Flow Record
// **************************************************
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | record length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | direction |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | URL |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Host |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowURLDirection uint32
const (
SFlowURLsrc SFlowURLDirection = 1
SFlowURLdst SFlowURLDirection = 2
)
func (urld SFlowURLDirection) String() string {
switch urld {
case SFlowURLsrc:
return "Source address is the server"
case SFlowURLdst:
return "Destination address is the server"
default:
return ""
}
}
type SFlowExtendedURLRecord struct {
SFlowBaseFlowRecord
Direction SFlowURLDirection
URL string
Host string
}
func decodeExtendedURLRecord(data *[]byte) (SFlowExtendedURLRecord, error) {
eur := SFlowExtendedURLRecord{}
var fdf SFlowFlowDataFormat
var urlLen uint32
var urlLenWithPad int
var hostLen uint32
var hostLenWithPad int
var urlBytes []byte
var hostBytes []byte
*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
eur.EnterpriseID, eur.Format = fdf.decode()
*data, eur.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, eur.Direction = (*data)[4:], SFlowURLDirection(binary.BigEndian.Uint32((*data)[:4]))
*data, urlLen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
urlLenWithPad = int(urlLen + ((4 - urlLen) % 4))
*data, urlBytes = (*data)[urlLenWithPad:], (*data)[:urlLenWithPad]
eur.URL = string(urlBytes[:urlLen])
*data, hostLen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
hostLenWithPad = int(hostLen + ((4 - hostLen) % 4))
*data, hostBytes = (*data)[hostLenWithPad:], (*data)[:hostLenWithPad]
eur.Host = string(hostBytes[:hostLen])
return eur, nil
}
// **************************************************
// Extended User Flow Record
// **************************************************
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | record length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Source Character Set |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Source User Id |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Destination Character Set |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Destination User ID |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowExtendedUserFlow struct {
SFlowBaseFlowRecord
SourceCharSet SFlowCharSet
SourceUserID string
DestinationCharSet SFlowCharSet
DestinationUserID string
}
type SFlowCharSet uint32
const (
SFlowCSunknown SFlowCharSet = 2
SFlowCSASCII SFlowCharSet = 3
SFlowCSISOLatin1 SFlowCharSet = 4
SFlowCSISOLatin2 SFlowCharSet = 5
SFlowCSISOLatin3 SFlowCharSet = 6
SFlowCSISOLatin4 SFlowCharSet = 7
SFlowCSISOLatinCyrillic SFlowCharSet = 8
SFlowCSISOLatinArabic SFlowCharSet = 9
SFlowCSISOLatinGreek SFlowCharSet = 10
SFlowCSISOLatinHebrew SFlowCharSet = 11
SFlowCSISOLatin5 SFlowCharSet = 12
SFlowCSISOLatin6 SFlowCharSet = 13
SFlowCSISOTextComm SFlowCharSet = 14
SFlowCSHalfWidthKatakana SFlowCharSet = 15
SFlowCSJISEncoding SFlowCharSet = 16
SFlowCSShiftJIS SFlowCharSet = 17
SFlowCSEUCPkdFmtJapanese SFlowCharSet = 18
SFlowCSEUCFixWidJapanese SFlowCharSet = 19
SFlowCSISO4UnitedKingdom SFlowCharSet = 20
SFlowCSISO11SwedishForNames SFlowCharSet = 21
SFlowCSISO15Italian SFlowCharSet = 22
SFlowCSISO17Spanish SFlowCharSet = 23
SFlowCSISO21German SFlowCharSet = 24
SFlowCSISO60DanishNorwegian SFlowCharSet = 25
SFlowCSISO69French SFlowCharSet = 26
SFlowCSISO10646UTF1 SFlowCharSet = 27
SFlowCSISO646basic1983 SFlowCharSet = 28
SFlowCSINVARIANT SFlowCharSet = 29
SFlowCSISO2IntlRefVersion SFlowCharSet = 30
SFlowCSNATSSEFI SFlowCharSet = 31
SFlowCSNATSSEFIADD SFlowCharSet = 32
SFlowCSNATSDANO SFlowCharSet = 33
SFlowCSNATSDANOADD SFlowCharSet = 34
SFlowCSISO10Swedish SFlowCharSet = 35
SFlowCSKSC56011987 SFlowCharSet = 36
SFlowCSISO2022KR SFlowCharSet = 37
SFlowCSEUCKR SFlowCharSet = 38
SFlowCSISO2022JP SFlowCharSet = 39
SFlowCSISO2022JP2 SFlowCharSet = 40
SFlowCSISO13JISC6220jp SFlowCharSet = 41
SFlowCSISO14JISC6220ro SFlowCharSet = 42
SFlowCSISO16Portuguese SFlowCharSet = 43
SFlowCSISO18Greek7Old SFlowCharSet = 44
SFlowCSISO19LatinGreek SFlowCharSet = 45
SFlowCSISO25French SFlowCharSet = 46
SFlowCSISO27LatinGreek1 SFlowCharSet = 47
SFlowCSISO5427Cyrillic SFlowCharSet = 48
SFlowCSISO42JISC62261978 SFlowCharSet = 49
SFlowCSISO47BSViewdata SFlowCharSet = 50
SFlowCSISO49INIS SFlowCharSet = 51
SFlowCSISO50INIS8 SFlowCharSet = 52
SFlowCSISO51INISCyrillic SFlowCharSet = 53
SFlowCSISO54271981 SFlowCharSet = 54
SFlowCSISO5428Greek SFlowCharSet = 55
SFlowCSISO57GB1988 SFlowCharSet = 56
SFlowCSISO58GB231280 SFlowCharSet = 57
SFlowCSISO61Norwegian2 SFlowCharSet = 58
SFlowCSISO70VideotexSupp1 SFlowCharSet = 59
SFlowCSISO84Portuguese2 SFlowCharSet = 60
SFlowCSISO85Spanish2 SFlowCharSet = 61
SFlowCSISO86Hungarian SFlowCharSet = 62
SFlowCSISO87JISX0208 SFlowCharSet = 63
SFlowCSISO88Greek7 SFlowCharSet = 64
SFlowCSISO89ASMO449 SFlowCharSet = 65
SFlowCSISO90 SFlowCharSet = 66
SFlowCSISO91JISC62291984a SFlowCharSet = 67
SFlowCSISO92JISC62991984b SFlowCharSet = 68
SFlowCSISO93JIS62291984badd SFlowCharSet = 69
SFlowCSISO94JIS62291984hand SFlowCharSet = 70
SFlowCSISO95JIS62291984handadd SFlowCharSet = 71
SFlowCSISO96JISC62291984kana SFlowCharSet = 72
SFlowCSISO2033 SFlowCharSet = 73
SFlowCSISO99NAPLPS SFlowCharSet = 74
SFlowCSISO102T617bit SFlowCharSet = 75
SFlowCSISO103T618bit SFlowCharSet = 76
SFlowCSISO111ECMACyrillic SFlowCharSet = 77
SFlowCSa71 SFlowCharSet = 78
SFlowCSa72 SFlowCharSet = 79
SFlowCSISO123CSAZ24341985gr SFlowCharSet = 80
SFlowCSISO88596E SFlowCharSet = 81
SFlowCSISO88596I SFlowCharSet = 82
SFlowCSISO128T101G2 SFlowCharSet = 83
SFlowCSISO88598E SFlowCharSet = 84
SFlowCSISO88598I SFlowCharSet = 85
SFlowCSISO139CSN369103 SFlowCharSet = 86
SFlowCSISO141JUSIB1002 SFlowCharSet = 87
SFlowCSISO143IECP271 SFlowCharSet = 88
SFlowCSISO146Serbian SFlowCharSet = 89
SFlowCSISO147Macedonian SFlowCharSet = 90
SFlowCSISO150 SFlowCharSet = 91
SFlowCSISO151Cuba SFlowCharSet = 92
SFlowCSISO6937Add SFlowCharSet = 93
SFlowCSISO153GOST1976874 SFlowCharSet = 94
SFlowCSISO8859Supp SFlowCharSet = 95
SFlowCSISO10367Box SFlowCharSet = 96
SFlowCSISO158Lap SFlowCharSet = 97
SFlowCSISO159JISX02121990 SFlowCharSet = 98
SFlowCSISO646Danish SFlowCharSet = 99
SFlowCSUSDK SFlowCharSet = 100
SFlowCSDKUS SFlowCharSet = 101
SFlowCSKSC5636 SFlowCharSet = 102
SFlowCSUnicode11UTF7 SFlowCharSet = 103
SFlowCSISO2022CN SFlowCharSet = 104
SFlowCSISO2022CNEXT SFlowCharSet = 105
SFlowCSUTF8 SFlowCharSet = 106
SFlowCSISO885913 SFlowCharSet = 109
SFlowCSISO885914 SFlowCharSet = 110
SFlowCSISO885915 SFlowCharSet = 111
SFlowCSISO885916 SFlowCharSet = 112
SFlowCSGBK SFlowCharSet = 113
SFlowCSGB18030 SFlowCharSet = 114
SFlowCSOSDEBCDICDF0415 SFlowCharSet = 115
SFlowCSOSDEBCDICDF03IRV SFlowCharSet = 116
SFlowCSOSDEBCDICDF041 SFlowCharSet = 117
SFlowCSISO115481 SFlowCharSet = 118
SFlowCSKZ1048 SFlowCharSet = 119
SFlowCSUnicode SFlowCharSet = 1000
SFlowCSUCS4 SFlowCharSet = 1001
SFlowCSUnicodeASCII SFlowCharSet = 1002
SFlowCSUnicodeLatin1 SFlowCharSet = 1003
SFlowCSUnicodeJapanese SFlowCharSet = 1004
SFlowCSUnicodeIBM1261 SFlowCharSet = 1005
SFlowCSUnicodeIBM1268 SFlowCharSet = 1006
SFlowCSUnicodeIBM1276 SFlowCharSet = 1007
SFlowCSUnicodeIBM1264 SFlowCharSet = 1008
SFlowCSUnicodeIBM1265 SFlowCharSet = 1009
SFlowCSUnicode11 SFlowCharSet = 1010
SFlowCSSCSU SFlowCharSet = 1011
SFlowCSUTF7 SFlowCharSet = 1012
SFlowCSUTF16BE SFlowCharSet = 1013
SFlowCSUTF16LE SFlowCharSet = 1014
SFlowCSUTF16 SFlowCharSet = 1015
SFlowCSCESU8 SFlowCharSet = 1016
SFlowCSUTF32 SFlowCharSet = 1017
SFlowCSUTF32BE SFlowCharSet = 1018
SFlowCSUTF32LE SFlowCharSet = 1019
SFlowCSBOCU1 SFlowCharSet = 1020
SFlowCSWindows30Latin1 SFlowCharSet = 2000
SFlowCSWindows31Latin1 SFlowCharSet = 2001
SFlowCSWindows31Latin2 SFlowCharSet = 2002
SFlowCSWindows31Latin5 SFlowCharSet = 2003
SFlowCSHPRoman8 SFlowCharSet = 2004
SFlowCSAdobeStandardEncoding SFlowCharSet = 2005
SFlowCSVenturaUS SFlowCharSet = 2006
SFlowCSVenturaInternational SFlowCharSet = 2007
SFlowCSDECMCS SFlowCharSet = 2008
SFlowCSPC850Multilingual SFlowCharSet = 2009
SFlowCSPCp852 SFlowCharSet = 2010
SFlowCSPC8CodePage437 SFlowCharSet = 2011
SFlowCSPC8DanishNorwegian SFlowCharSet = 2012
SFlowCSPC862LatinHebrew SFlowCharSet = 2013
SFlowCSPC8Turkish SFlowCharSet = 2014
SFlowCSIBMSymbols SFlowCharSet = 2015
SFlowCSIBMThai SFlowCharSet = 2016
SFlowCSHPLegal SFlowCharSet = 2017
SFlowCSHPPiFont SFlowCharSet = 2018
SFlowCSHPMath8 SFlowCharSet = 2019
SFlowCSHPPSMath SFlowCharSet = 2020
SFlowCSHPDesktop SFlowCharSet = 2021
SFlowCSVenturaMath SFlowCharSet = 2022
SFlowCSMicrosoftPublishing SFlowCharSet = 2023
SFlowCSWindows31J SFlowCharSet = 2024
SFlowCSGB2312 SFlowCharSet = 2025
SFlowCSBig5 SFlowCharSet = 2026
SFlowCSMacintosh SFlowCharSet = 2027
SFlowCSIBM037 SFlowCharSet = 2028
SFlowCSIBM038 SFlowCharSet = 2029
SFlowCSIBM273 SFlowCharSet = 2030
SFlowCSIBM274 SFlowCharSet = 2031
SFlowCSIBM275 SFlowCharSet = 2032
SFlowCSIBM277 SFlowCharSet = 2033
SFlowCSIBM278 SFlowCharSet = 2034
SFlowCSIBM280 SFlowCharSet = 2035
SFlowCSIBM281 SFlowCharSet = 2036
SFlowCSIBM284 SFlowCharSet = 2037
SFlowCSIBM285 SFlowCharSet = 2038
SFlowCSIBM290 SFlowCharSet = 2039
SFlowCSIBM297 SFlowCharSet = 2040
SFlowCSIBM420 SFlowCharSet = 2041
SFlowCSIBM423 SFlowCharSet = 2042
SFlowCSIBM424 SFlowCharSet = 2043
SFlowCSIBM500 SFlowCharSet = 2044
SFlowCSIBM851 SFlowCharSet = 2045
SFlowCSIBM855 SFlowCharSet = 2046
SFlowCSIBM857 SFlowCharSet = 2047
SFlowCSIBM860 SFlowCharSet = 2048
SFlowCSIBM861 SFlowCharSet = 2049
SFlowCSIBM863 SFlowCharSet = 2050
SFlowCSIBM864 SFlowCharSet = 2051
SFlowCSIBM865 SFlowCharSet = 2052
SFlowCSIBM868 SFlowCharSet = 2053
SFlowCSIBM869 SFlowCharSet = 2054
SFlowCSIBM870 SFlowCharSet = 2055
SFlowCSIBM871 SFlowCharSet = 2056
SFlowCSIBM880 SFlowCharSet = 2057
SFlowCSIBM891 SFlowCharSet = 2058
SFlowCSIBM903 SFlowCharSet = 2059
SFlowCSIBBM904 SFlowCharSet = 2060
SFlowCSIBM905 SFlowCharSet = 2061
SFlowCSIBM918 SFlowCharSet = 2062
SFlowCSIBM1026 SFlowCharSet = 2063
SFlowCSIBMEBCDICATDE SFlowCharSet = 2064
SFlowCSEBCDICATDEA SFlowCharSet = 2065
SFlowCSEBCDICCAFR SFlowCharSet = 2066
SFlowCSEBCDICDKNO SFlowCharSet = 2067
SFlowCSEBCDICDKNOA SFlowCharSet = 2068
SFlowCSEBCDICFISE SFlowCharSet = 2069
SFlowCSEBCDICFISEA SFlowCharSet = 2070
SFlowCSEBCDICFR SFlowCharSet = 2071
SFlowCSEBCDICIT SFlowCharSet = 2072
SFlowCSEBCDICPT SFlowCharSet = 2073
SFlowCSEBCDICES SFlowCharSet = 2074
SFlowCSEBCDICESA SFlowCharSet = 2075
SFlowCSEBCDICESS SFlowCharSet = 2076
SFlowCSEBCDICUK SFlowCharSet = 2077
SFlowCSEBCDICUS SFlowCharSet = 2078
SFlowCSUnknown8BiT SFlowCharSet = 2079
SFlowCSMnemonic SFlowCharSet = 2080
SFlowCSMnem SFlowCharSet = 2081
SFlowCSVISCII SFlowCharSet = 2082
SFlowCSVIQR SFlowCharSet = 2083
SFlowCSKOI8R SFlowCharSet = 2084
SFlowCSHZGB2312 SFlowCharSet = 2085
SFlowCSIBM866 SFlowCharSet = 2086
SFlowCSPC775Baltic SFlowCharSet = 2087
SFlowCSKOI8U SFlowCharSet = 2088
SFlowCSIBM00858 SFlowCharSet = 2089
SFlowCSIBM00924 SFlowCharSet = 2090
SFlowCSIBM01140 SFlowCharSet = 2091
SFlowCSIBM01141 SFlowCharSet = 2092
SFlowCSIBM01142 SFlowCharSet = 2093
SFlowCSIBM01143 SFlowCharSet = 2094
SFlowCSIBM01144 SFlowCharSet = 2095
SFlowCSIBM01145 SFlowCharSet = 2096
SFlowCSIBM01146 SFlowCharSet = 2097
SFlowCSIBM01147 SFlowCharSet = 2098
SFlowCSIBM01148 SFlowCharSet = 2099
SFlowCSIBM01149 SFlowCharSet = 2100
SFlowCSBig5HKSCS SFlowCharSet = 2101
SFlowCSIBM1047 SFlowCharSet = 2102
SFlowCSPTCP154 SFlowCharSet = 2103
SFlowCSAmiga1251 SFlowCharSet = 2104
SFlowCSKOI7switched SFlowCharSet = 2105
SFlowCSBRF SFlowCharSet = 2106
SFlowCSTSCII SFlowCharSet = 2107
SFlowCSCP51932 SFlowCharSet = 2108
SFlowCSWindows874 SFlowCharSet = 2109
SFlowCSWindows1250 SFlowCharSet = 2250
SFlowCSWindows1251 SFlowCharSet = 2251
SFlowCSWindows1252 SFlowCharSet = 2252
SFlowCSWindows1253 SFlowCharSet = 2253
SFlowCSWindows1254 SFlowCharSet = 2254
SFlowCSWindows1255 SFlowCharSet = 2255
SFlowCSWindows1256 SFlowCharSet = 2256
SFlowCSWindows1257 SFlowCharSet = 2257
SFlowCSWindows1258 SFlowCharSet = 2258
SFlowCSTIS620 SFlowCharSet = 2259
SFlowCS50220 SFlowCharSet = 2260
SFlowCSreserved SFlowCharSet = 3000
)
func decodeExtendedUserFlow(data *[]byte) (SFlowExtendedUserFlow, error) {
eu := SFlowExtendedUserFlow{}
var fdf SFlowFlowDataFormat
var srcUserLen uint32
var srcUserLenWithPad int
var srcUserBytes []byte
var dstUserLen uint32
var dstUserLenWithPad int
var dstUserBytes []byte
*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
eu.EnterpriseID, eu.Format = fdf.decode()
*data, eu.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, eu.SourceCharSet = (*data)[4:], SFlowCharSet(binary.BigEndian.Uint32((*data)[:4]))
*data, srcUserLen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
srcUserLenWithPad = int(srcUserLen + ((4 - srcUserLen) % 4))
*data, srcUserBytes = (*data)[srcUserLenWithPad:], (*data)[:srcUserLenWithPad]
eu.SourceUserID = string(srcUserBytes[:srcUserLen])
*data, eu.DestinationCharSet = (*data)[4:], SFlowCharSet(binary.BigEndian.Uint32((*data)[:4]))
*data, dstUserLen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
dstUserLenWithPad = int(dstUserLen + ((4 - dstUserLen) % 4))
*data, dstUserBytes = (*data)[dstUserLenWithPad:], (*data)[:dstUserLenWithPad]
eu.DestinationUserID = string(dstUserBytes[:dstUserLen])
return eu, nil
}
// **************************************************
// Packet IP version 4 Record
// **************************************************
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Protocol |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Source IPv4 |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Destination IPv4 |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Source Port |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Destionation Port |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | TCP Flags |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | TOS |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowIpv4Record struct {
// The length of the IP packet excluding ower layer encapsulations
Length uint32
// IP Protocol type (for example, TCP = 6, UDP = 17)
Protocol uint32
// Source IP Address
IPSrc net.IP
// Destination IP Address
IPDst net.IP
// TCP/UDP source port number or equivalent
PortSrc uint32
// TCP/UDP destination port number or equivalent
PortDst uint32
// TCP flags
TCPFlags uint32
// IP type of service
TOS uint32
}
func decodeSFlowIpv4Record(data *[]byte) (SFlowIpv4Record, error) {
si := SFlowIpv4Record{}
*data, si.Length = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, si.Protocol = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, si.IPSrc = (*data)[4:], net.IP((*data)[:4])
*data, si.IPDst = (*data)[4:], net.IP((*data)[:4])
*data, si.PortSrc = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, si.PortDst = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, si.TCPFlags = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, si.TOS = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
return si, nil
}
// **************************************************
// Packet IP version 6 Record
// **************************************************
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Protocol |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Source IPv4 |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Destination IPv4 |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Source Port |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Destionation Port |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | TCP Flags |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Priority |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowIpv6Record struct {
// The length of the IP packet excluding ower layer encapsulations
Length uint32
// IP Protocol type (for example, TCP = 6, UDP = 17)
Protocol uint32
// Source IP Address
IPSrc net.IP
// Destination IP Address
IPDst net.IP
// TCP/UDP source port number or equivalent
PortSrc uint32
// TCP/UDP destination port number or equivalent
PortDst uint32
// TCP flags
TCPFlags uint32
// IP priority
Priority uint32
}
func decodeSFlowIpv6Record(data *[]byte) (SFlowIpv6Record, error) {
si := SFlowIpv6Record{}
*data, si.Length = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, si.Protocol = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, si.IPSrc = (*data)[16:], net.IP((*data)[:16])
*data, si.IPDst = (*data)[16:], net.IP((*data)[:16])
*data, si.PortSrc = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, si.PortDst = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, si.TCPFlags = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, si.Priority = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
return si, nil
}
// **************************************************
// Extended IPv4 Tunnel Egress
// **************************************************
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | record length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// / Packet IP version 4 Record /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowExtendedIpv4TunnelEgressRecord struct {
SFlowBaseFlowRecord
SFlowIpv4Record SFlowIpv4Record
}
func decodeExtendedIpv4TunnelEgress(data *[]byte) (SFlowExtendedIpv4TunnelEgressRecord, error) {
rec := SFlowExtendedIpv4TunnelEgressRecord{}
var fdf SFlowFlowDataFormat
*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
rec.EnterpriseID, rec.Format = fdf.decode()
*data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
rec.SFlowIpv4Record, _ = decodeSFlowIpv4Record(data)
return rec, nil
}
// **************************************************
// Extended IPv4 Tunnel Ingress
// **************************************************
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | record length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// / Packet IP version 4 Record /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowExtendedIpv4TunnelIngressRecord struct {
SFlowBaseFlowRecord
SFlowIpv4Record SFlowIpv4Record
}
func decodeExtendedIpv4TunnelIngress(data *[]byte) (SFlowExtendedIpv4TunnelIngressRecord, error) {
rec := SFlowExtendedIpv4TunnelIngressRecord{}
var fdf SFlowFlowDataFormat
*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
rec.EnterpriseID, rec.Format = fdf.decode()
*data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
rec.SFlowIpv4Record, _ = decodeSFlowIpv4Record(data)
return rec, nil
}
// **************************************************
// Extended IPv6 Tunnel Egress
// **************************************************
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | record length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// / Packet IP version 6 Record /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowExtendedIpv6TunnelEgressRecord struct {
SFlowBaseFlowRecord
SFlowIpv6Record
}
func decodeExtendedIpv6TunnelEgress(data *[]byte) (SFlowExtendedIpv6TunnelEgressRecord, error) {
rec := SFlowExtendedIpv6TunnelEgressRecord{}
var fdf SFlowFlowDataFormat
*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
rec.EnterpriseID, rec.Format = fdf.decode()
*data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
rec.SFlowIpv6Record, _ = decodeSFlowIpv6Record(data)
return rec, nil
}
// **************************************************
// Extended IPv6 Tunnel Ingress
// **************************************************
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | record length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// / Packet IP version 6 Record /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowExtendedIpv6TunnelIngressRecord struct {
SFlowBaseFlowRecord
SFlowIpv6Record
}
func decodeExtendedIpv6TunnelIngress(data *[]byte) (SFlowExtendedIpv6TunnelIngressRecord, error) {
rec := SFlowExtendedIpv6TunnelIngressRecord{}
var fdf SFlowFlowDataFormat
*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
rec.EnterpriseID, rec.Format = fdf.decode()
*data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
rec.SFlowIpv6Record, _ = decodeSFlowIpv6Record(data)
return rec, nil
}
// **************************************************
// Extended Decapsulate Egress
// **************************************************
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | record length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Inner Header Offset |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowExtendedDecapsulateEgressRecord struct {
SFlowBaseFlowRecord
InnerHeaderOffset uint32
}
func decodeExtendedDecapsulateEgress(data *[]byte) (SFlowExtendedDecapsulateEgressRecord, error) {
rec := SFlowExtendedDecapsulateEgressRecord{}
var fdf SFlowFlowDataFormat
*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
rec.EnterpriseID, rec.Format = fdf.decode()
*data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, rec.InnerHeaderOffset = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
return rec, nil
}
// **************************************************
// Extended Decapsulate Ingress
// **************************************************
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | record length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Inner Header Offset |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowExtendedDecapsulateIngressRecord struct {
SFlowBaseFlowRecord
InnerHeaderOffset uint32
}
func decodeExtendedDecapsulateIngress(data *[]byte) (SFlowExtendedDecapsulateIngressRecord, error) {
rec := SFlowExtendedDecapsulateIngressRecord{}
var fdf SFlowFlowDataFormat
*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
rec.EnterpriseID, rec.Format = fdf.decode()
*data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, rec.InnerHeaderOffset = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
return rec, nil
}
// **************************************************
// Extended VNI Egress
// **************************************************
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | record length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | VNI |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowExtendedVniEgressRecord struct {
SFlowBaseFlowRecord
VNI uint32
}
func decodeExtendedVniEgress(data *[]byte) (SFlowExtendedVniEgressRecord, error) {
rec := SFlowExtendedVniEgressRecord{}
var fdf SFlowFlowDataFormat
*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
rec.EnterpriseID, rec.Format = fdf.decode()
*data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, rec.VNI = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
return rec, nil
}
// **************************************************
// Extended VNI Ingress
// **************************************************
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | record length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | VNI |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowExtendedVniIngressRecord struct {
SFlowBaseFlowRecord
VNI uint32
}
func decodeExtendedVniIngress(data *[]byte) (SFlowExtendedVniIngressRecord, error) {
rec := SFlowExtendedVniIngressRecord{}
var fdf SFlowFlowDataFormat
*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
rec.EnterpriseID, rec.Format = fdf.decode()
*data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, rec.VNI = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
return rec, nil
}
// **************************************************
// Counter Record
// **************************************************
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | counter length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// / counter data /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowBaseCounterRecord struct {
EnterpriseID SFlowEnterpriseID
Format SFlowCounterRecordType
FlowDataLength uint32
}
func (bcr SFlowBaseCounterRecord) GetType() SFlowCounterRecordType {
switch bcr.Format {
case SFlowTypeGenericInterfaceCounters:
return SFlowTypeGenericInterfaceCounters
case SFlowTypeEthernetInterfaceCounters:
return SFlowTypeEthernetInterfaceCounters
case SFlowTypeTokenRingInterfaceCounters:
return SFlowTypeTokenRingInterfaceCounters
case SFlowType100BaseVGInterfaceCounters:
return SFlowType100BaseVGInterfaceCounters
case SFlowTypeVLANCounters:
return SFlowTypeVLANCounters
case SFlowTypeLACPCounters:
return SFlowTypeLACPCounters
case SFlowTypeProcessorCounters:
return SFlowTypeProcessorCounters
case SFlowTypeOpenflowPortCounters:
return SFlowTypeOpenflowPortCounters
case SFlowTypePORTNAMECounters:
return SFlowTypePORTNAMECounters
case SFLowTypeAPPRESOURCESCounters:
return SFLowTypeAPPRESOURCESCounters
case SFlowTypeOVSDPCounters:
return SFlowTypeOVSDPCounters
}
unrecognized := fmt.Sprint("Unrecognized counter record type:", bcr.Format)
panic(unrecognized)
}
// **************************************************
// Counter Record
// **************************************************
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | counter length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IfIndex |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IfType |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IfSpeed |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IfDirection |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IfStatus |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IFInOctets |
// | |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IfInUcastPkts |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IfInMulticastPkts |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IfInBroadcastPkts |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IfInDiscards |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | InInErrors |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IfInUnknownProtos |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IfOutOctets |
// | |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IfOutUcastPkts |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IfOutMulticastPkts |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IfOutBroadcastPkts |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IfOutDiscards |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IfOUtErrors |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | IfPromiscouousMode |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowGenericInterfaceCounters struct {
SFlowBaseCounterRecord
IfIndex uint32
IfType uint32
IfSpeed uint64
IfDirection uint32
IfStatus uint32
IfInOctets uint64
IfInUcastPkts uint32
IfInMulticastPkts uint32
IfInBroadcastPkts uint32
IfInDiscards uint32
IfInErrors uint32
IfInUnknownProtos uint32
IfOutOctets uint64
IfOutUcastPkts uint32
IfOutMulticastPkts uint32
IfOutBroadcastPkts uint32
IfOutDiscards uint32
IfOutErrors uint32
IfPromiscuousMode uint32
}
func decodeGenericInterfaceCounters(data *[]byte) (SFlowGenericInterfaceCounters, error) {
gic := SFlowGenericInterfaceCounters{}
var cdf SFlowCounterDataFormat
*data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
gic.EnterpriseID, gic.Format = cdf.decode()
*data, gic.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, gic.IfIndex = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, gic.IfType = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, gic.IfSpeed = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
*data, gic.IfDirection = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, gic.IfStatus = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, gic.IfInOctets = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
*data, gic.IfInUcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, gic.IfInMulticastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, gic.IfInBroadcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, gic.IfInDiscards = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, gic.IfInErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, gic.IfInUnknownProtos = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, gic.IfOutOctets = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
*data, gic.IfOutUcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, gic.IfOutMulticastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, gic.IfOutBroadcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, gic.IfOutDiscards = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, gic.IfOutErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, gic.IfPromiscuousMode = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
return gic, nil
}
// **************************************************
// Counter Record
// **************************************************
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | counter length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// / counter data /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowEthernetCounters struct {
SFlowBaseCounterRecord
AlignmentErrors uint32
FCSErrors uint32
SingleCollisionFrames uint32
MultipleCollisionFrames uint32
SQETestErrors uint32
DeferredTransmissions uint32
LateCollisions uint32
ExcessiveCollisions uint32
InternalMacTransmitErrors uint32
CarrierSenseErrors uint32
FrameTooLongs uint32
InternalMacReceiveErrors uint32
SymbolErrors uint32
}
func decodeEthernetCounters(data *[]byte) (SFlowEthernetCounters, error) {
ec := SFlowEthernetCounters{}
var cdf SFlowCounterDataFormat
*data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
ec.EnterpriseID, ec.Format = cdf.decode()
if len(*data) < 4 {
return SFlowEthernetCounters{}, errors.New("ethernet counters too small")
}
*data, ec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowEthernetCounters{}, errors.New("ethernet counters too small")
}
*data, ec.AlignmentErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowEthernetCounters{}, errors.New("ethernet counters too small")
}
*data, ec.FCSErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowEthernetCounters{}, errors.New("ethernet counters too small")
}
*data, ec.SingleCollisionFrames = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowEthernetCounters{}, errors.New("ethernet counters too small")
}
*data, ec.MultipleCollisionFrames = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowEthernetCounters{}, errors.New("ethernet counters too small")
}
*data, ec.SQETestErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowEthernetCounters{}, errors.New("ethernet counters too small")
}
*data, ec.DeferredTransmissions = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowEthernetCounters{}, errors.New("ethernet counters too small")
}
*data, ec.LateCollisions = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowEthernetCounters{}, errors.New("ethernet counters too small")
}
*data, ec.ExcessiveCollisions = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowEthernetCounters{}, errors.New("ethernet counters too small")
}
*data, ec.InternalMacTransmitErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowEthernetCounters{}, errors.New("ethernet counters too small")
}
*data, ec.CarrierSenseErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowEthernetCounters{}, errors.New("ethernet counters too small")
}
*data, ec.FrameTooLongs = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowEthernetCounters{}, errors.New("ethernet counters too small")
}
*data, ec.InternalMacReceiveErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
if len(*data) < 4 {
return SFlowEthernetCounters{}, errors.New("ethernet counters too small")
}
*data, ec.SymbolErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
return ec, nil
}
// VLAN Counter
type SFlowVLANCounters struct {
SFlowBaseCounterRecord
VlanID uint32
Octets uint64
UcastPkts uint32
MulticastPkts uint32
BroadcastPkts uint32
Discards uint32
}
func decodeVLANCounters(data *[]byte) (SFlowVLANCounters, error) {
vc := SFlowVLANCounters{}
var cdf SFlowCounterDataFormat
*data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
vc.EnterpriseID, vc.Format = cdf.decode()
vc.EnterpriseID, vc.Format = cdf.decode()
*data, vc.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, vc.VlanID = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, vc.Octets = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
*data, vc.UcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, vc.MulticastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, vc.BroadcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, vc.Discards = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
return vc, nil
}
//SFLLACPportState : SFlow LACP Port State (All(4) - 32 bit)
type SFLLACPPortState struct {
PortStateAll uint32
}
//LACPcounters : LACP SFlow Counters ( 64 Bytes )
type SFlowLACPCounters struct {
SFlowBaseCounterRecord
ActorSystemID net.HardwareAddr
PartnerSystemID net.HardwareAddr
AttachedAggID uint32
LacpPortState SFLLACPPortState
LACPDUsRx uint32
MarkerPDUsRx uint32
MarkerResponsePDUsRx uint32
UnknownRx uint32
IllegalRx uint32
LACPDUsTx uint32
MarkerPDUsTx uint32
MarkerResponsePDUsTx uint32
}
func decodeLACPCounters(data *[]byte) (SFlowLACPCounters, error) {
la := SFlowLACPCounters{}
var cdf SFlowCounterDataFormat
*data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
la.EnterpriseID, la.Format = cdf.decode()
*data, la.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, la.ActorSystemID = (*data)[6:], (*data)[:6]
*data = (*data)[2:] // remove padding
*data, la.PartnerSystemID = (*data)[6:], (*data)[:6]
*data = (*data)[2:] //remove padding
*data, la.AttachedAggID = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, la.LacpPortState.PortStateAll = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, la.LACPDUsRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, la.MarkerPDUsRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, la.MarkerResponsePDUsRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, la.UnknownRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, la.IllegalRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, la.LACPDUsTx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, la.MarkerPDUsTx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, la.MarkerResponsePDUsTx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
return la, nil
}
// **************************************************
// Processor Counter Record
// **************************************************
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | counter length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | FiveSecCpu |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | OneMinCpu |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | GiveMinCpu |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | TotalMemory |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | FreeMemory |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
type SFlowProcessorCounters struct {
SFlowBaseCounterRecord
FiveSecCpu uint32 // 5 second average CPU utilization
OneMinCpu uint32 // 1 minute average CPU utilization
FiveMinCpu uint32 // 5 minute average CPU utilization
TotalMemory uint64 // total memory (in bytes)
FreeMemory uint64 // free memory (in bytes)
}
func decodeProcessorCounters(data *[]byte) (SFlowProcessorCounters, error) {
pc := SFlowProcessorCounters{}
var cdf SFlowCounterDataFormat
var high32, low32 uint32
*data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
pc.EnterpriseID, pc.Format = cdf.decode()
*data, pc.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, pc.FiveSecCpu = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, pc.OneMinCpu = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, pc.FiveMinCpu = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, high32 = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, low32 = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
pc.TotalMemory = (uint64(high32) << 32) + uint64(low32)
*data, high32 = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, low32 = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
pc.FreeMemory = (uint64(high32)) + uint64(low32)
return pc, nil
}
// SFlowEthernetFrameFlowRecord give additional information
// about the sampled packet if it's available.
// An agent may or may not provide this information.
type SFlowEthernetFrameFlowRecord struct {
SFlowBaseFlowRecord
FrameLength uint32
SrcMac net.HardwareAddr
DstMac net.HardwareAddr
Type uint32
}
// Ethernet frame flow records have the following structure:
// 0 15 31
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 20 bit Interprise (0) |12 bit format |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | record length |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Source Mac Address |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Destination Mac Address |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Ethernet Packet Type |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
func decodeEthernetFrameFlowRecord(data *[]byte) (SFlowEthernetFrameFlowRecord, error) {
es := SFlowEthernetFrameFlowRecord{}
var fdf SFlowFlowDataFormat
*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
es.EnterpriseID, es.Format = fdf.decode()
*data, es.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, es.FrameLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, es.SrcMac = (*data)[8:], net.HardwareAddr((*data)[:6])
*data, es.DstMac = (*data)[8:], net.HardwareAddr((*data)[:6])
*data, es.Type = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
return es, nil
}
//SFlowOpenflowPortCounters : OVS-Sflow OpenFlow Port Counter ( 20 Bytes )
type SFlowOpenflowPortCounters struct {
SFlowBaseCounterRecord
DatapathID uint64
PortNo uint32
}
func decodeOpenflowportCounters(data *[]byte) (SFlowOpenflowPortCounters, error) {
ofp := SFlowOpenflowPortCounters{}
var cdf SFlowCounterDataFormat
*data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
ofp.EnterpriseID, ofp.Format = cdf.decode()
*data, ofp.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, ofp.DatapathID = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
*data, ofp.PortNo = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
return ofp, nil
}
//SFlowAppresourcesCounters : OVS_Sflow App Resources Counter ( 48 Bytes )
type SFlowAppresourcesCounters struct {
SFlowBaseCounterRecord
UserTime uint32
SystemTime uint32
MemUsed uint64
MemMax uint64
FdOpen uint32
FdMax uint32
ConnOpen uint32
ConnMax uint32
}
func decodeAppresourcesCounters(data *[]byte) (SFlowAppresourcesCounters, error) {
app := SFlowAppresourcesCounters{}
var cdf SFlowCounterDataFormat
*data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
app.EnterpriseID, app.Format = cdf.decode()
*data, app.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, app.UserTime = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, app.SystemTime = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, app.MemUsed = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
*data, app.MemMax = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
*data, app.FdOpen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, app.FdMax = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, app.ConnOpen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, app.ConnMax = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
return app, nil
}
//SFlowOVSDPCounters : OVS-Sflow DataPath Counter ( 32 Bytes )
type SFlowOVSDPCounters struct {
SFlowBaseCounterRecord
NHit uint32
NMissed uint32
NLost uint32
NMaskHit uint32
NFlows uint32
NMasks uint32
}
func decodeOVSDPCounters(data *[]byte) (SFlowOVSDPCounters, error) {
dp := SFlowOVSDPCounters{}
var cdf SFlowCounterDataFormat
*data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
dp.EnterpriseID, dp.Format = cdf.decode()
*data, dp.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, dp.NHit = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, dp.NMissed = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, dp.NLost = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, dp.NMaskHit = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, dp.NFlows = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
*data, dp.NMasks = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
return dp, nil
}
//SFlowPORTNAME : OVS-Sflow PORTNAME Counter Sampletype ( 20 Bytes )
type SFlowPORTNAME struct {
SFlowBaseCounterRecord
Len uint32
Str string
}
func decodeString(data *[]byte) (len uint32, str string) {
*data, len = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
str = string((*data)[:len])
if (len % 4) != 0 {
len += 4 - len%4
}
*data = (*data)[len:]
return
}
func decodePortnameCounters(data *[]byte) (SFlowPORTNAME, error) {
pn := SFlowPORTNAME{}
var cdf SFlowCounterDataFormat
*data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
pn.EnterpriseID, pn.Format = cdf.decode()
*data, pn.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
pn.Len, pn.Str = decodeString(data)
return pn, nil
}
// Copyright 2017 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"bytes"
"fmt"
"io"
"strconv"
"strings"
"github.com/google/gopacket"
)
// SIPVersion defines the different versions of the SIP Protocol
type SIPVersion uint8
// Represents all the versions of SIP protocol
const (
SIPVersion1 SIPVersion = 1
SIPVersion2 SIPVersion = 2
)
func (sv SIPVersion) String() string {
switch sv {
default:
// Defaulting to SIP/2.0
return "SIP/2.0"
case SIPVersion1:
return "SIP/1.0"
case SIPVersion2:
return "SIP/2.0"
}
}
// GetSIPVersion is used to get SIP version constant
func GetSIPVersion(version string) (SIPVersion, error) {
switch strings.ToUpper(version) {
case "SIP/1.0":
return SIPVersion1, nil
case "SIP/2.0":
return SIPVersion2, nil
default:
return 0, fmt.Errorf("Unknown SIP version: '%s'", version)
}
}
// SIPMethod defines the different methods of the SIP Protocol
// defined in the different RFC's
type SIPMethod uint16
// Here are all the SIP methods
const (
SIPMethodInvite SIPMethod = 1 // INVITE [RFC3261]
SIPMethodAck SIPMethod = 2 // ACK [RFC3261]
SIPMethodBye SIPMethod = 3 // BYE [RFC3261]
SIPMethodCancel SIPMethod = 4 // CANCEL [RFC3261]
SIPMethodOptions SIPMethod = 5 // OPTIONS [RFC3261]
SIPMethodRegister SIPMethod = 6 // REGISTER [RFC3261]
SIPMethodPrack SIPMethod = 7 // PRACK [RFC3262]
SIPMethodSubscribe SIPMethod = 8 // SUBSCRIBE [RFC6665]
SIPMethodNotify SIPMethod = 9 // NOTIFY [RFC6665]
SIPMethodPublish SIPMethod = 10 // PUBLISH [RFC3903]
SIPMethodInfo SIPMethod = 11 // INFO [RFC6086]
SIPMethodRefer SIPMethod = 12 // REFER [RFC3515]
SIPMethodMessage SIPMethod = 13 // MESSAGE [RFC3428]
SIPMethodUpdate SIPMethod = 14 // UPDATE [RFC3311]
SIPMethodPing SIPMethod = 15 // PING [https://tools.ietf.org/html/draft-fwmiller-ping-03]
)
func (sm SIPMethod) String() string {
switch sm {
default:
return "Unknown method"
case SIPMethodInvite:
return "INVITE"
case SIPMethodAck:
return "ACK"
case SIPMethodBye:
return "BYE"
case SIPMethodCancel:
return "CANCEL"
case SIPMethodOptions:
return "OPTIONS"
case SIPMethodRegister:
return "REGISTER"
case SIPMethodPrack:
return "PRACK"
case SIPMethodSubscribe:
return "SUBSCRIBE"
case SIPMethodNotify:
return "NOTIFY"
case SIPMethodPublish:
return "PUBLISH"
case SIPMethodInfo:
return "INFO"
case SIPMethodRefer:
return "REFER"
case SIPMethodMessage:
return "MESSAGE"
case SIPMethodUpdate:
return "UPDATE"
case SIPMethodPing:
return "PING"
}
}
// GetSIPMethod returns the constant of a SIP method
// from its string
func GetSIPMethod(method string) (SIPMethod, error) {
switch strings.ToUpper(method) {
case "INVITE":
return SIPMethodInvite, nil
case "ACK":
return SIPMethodAck, nil
case "BYE":
return SIPMethodBye, nil
case "CANCEL":
return SIPMethodCancel, nil
case "OPTIONS":
return SIPMethodOptions, nil
case "REGISTER":
return SIPMethodRegister, nil
case "PRACK":
return SIPMethodPrack, nil
case "SUBSCRIBE":
return SIPMethodSubscribe, nil
case "NOTIFY":
return SIPMethodNotify, nil
case "PUBLISH":
return SIPMethodPublish, nil
case "INFO":
return SIPMethodInfo, nil
case "REFER":
return SIPMethodRefer, nil
case "MESSAGE":
return SIPMethodMessage, nil
case "UPDATE":
return SIPMethodUpdate, nil
case "PING":
return SIPMethodPing, nil
default:
return 0, fmt.Errorf("Unknown SIP method: '%s'", method)
}
}
// Here is a correspondance between long header names and short
// as defined in rfc3261 in section 20
var compactSipHeadersCorrespondance = map[string]string{
"accept-contact": "a",
"allow-events": "u",
"call-id": "i",
"contact": "m",
"content-encoding": "e",
"content-length": "l",
"content-type": "c",
"event": "o",
"from": "f",
"identity": "y",
"refer-to": "r",
"referred-by": "b",
"reject-contact": "j",
"request-disposition": "d",
"session-expires": "x",
"subject": "s",
"supported": "k",
"to": "t",
"via": "v",
}
// SIP object will contains information about decoded SIP packet.
// -> The SIP Version
// -> The SIP Headers (in a map[string][]string because of multiple headers with the same name
// -> The SIP Method
// -> The SIP Response code (if it's a response)
// -> The SIP Status line (if it's a response)
// You can easily know the type of the packet with the IsResponse boolean
//
type SIP struct {
BaseLayer
// Base information
Version SIPVersion
Method SIPMethod
Headers map[string][]string
// Request
RequestURI string
// Response
IsResponse bool
ResponseCode int
ResponseStatus string
// Private fields
cseq int64
contentLength int64
lastHeaderParsed string
}
// decodeSIP decodes the byte slice into a SIP type. It also
// setups the application Layer in PacketBuilder.
func decodeSIP(data []byte, p gopacket.PacketBuilder) error {
s := NewSIP()
err := s.DecodeFromBytes(data, p)
if err != nil {
return err
}
p.AddLayer(s)
p.SetApplicationLayer(s)
return nil
}
// NewSIP instantiates a new empty SIP object
func NewSIP() *SIP {
s := new(SIP)
s.Headers = make(map[string][]string)
return s
}
// LayerType returns gopacket.LayerTypeSIP.
func (s *SIP) LayerType() gopacket.LayerType {
return LayerTypeSIP
}
// Payload returns the base layer payload
func (s *SIP) Payload() []byte {
return s.BaseLayer.Payload
}
// CanDecode returns the set of layer types that this DecodingLayer can decode
func (s *SIP) CanDecode() gopacket.LayerClass {
return LayerTypeSIP
}
// NextLayerType returns the layer type contained by this DecodingLayer
func (s *SIP) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
// DecodeFromBytes decodes the slice into the SIP struct.
func (s *SIP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
// Init some vars for parsing follow-up
var countLines int
var line []byte
var err error
var offset int
// Iterate on all lines of the SIP Headers
// and stop when we reach the SDP (aka when the new line
// is at index 0 of the remaining packet)
buffer := bytes.NewBuffer(data)
for {
// Read next line
line, err = buffer.ReadBytes(byte('\n'))
if err != nil {
if err == io.EOF {
if len(bytes.Trim(line, "\r\n")) > 0 {
df.SetTruncated()
}
break
} else {
return err
}
}
offset += len(line)
// Trim the new line delimiters
line = bytes.Trim(line, "\r\n")
// Empty line, we hit Body
if len(line) == 0 {
break
}
// First line is the SIP request/response line
// Other lines are headers
if countLines == 0 {
err = s.ParseFirstLine(line)
if err != nil {
return err
}
} else {
err = s.ParseHeader(line)
if err != nil {
return err
}
}
countLines++
}
s.BaseLayer = BaseLayer{Contents: data[:offset], Payload: data[offset:]}
return nil
}
// ParseFirstLine will compute the first line of a SIP packet.
// The first line will tell us if it's a request or a response.
//
// Examples of first line of SIP Prococol :
//
// Request : INVITE bob@example.com SIP/2.0
// Response : SIP/2.0 200 OK
// Response : SIP/2.0 501 Not Implemented
//
func (s *SIP) ParseFirstLine(firstLine []byte) error {
var err error
// Splits line by space
splits := strings.SplitN(string(firstLine), " ", 3)
// We must have at least 3 parts
if len(splits) < 3 {
return fmt.Errorf("invalid first SIP line: '%s'", string(firstLine))
}
// Determine the SIP packet type
if strings.HasPrefix(splits[0], "SIP") {
// --> Response
s.IsResponse = true
// Validate SIP Version
s.Version, err = GetSIPVersion(splits[0])
if err != nil {
return err
}
// Compute code
s.ResponseCode, err = strconv.Atoi(splits[1])
if err != nil {
return err
}
// Compute status line
s.ResponseStatus = splits[2]
} else {
// --> Request
// Validate method
s.Method, err = GetSIPMethod(splits[0])
if err != nil {
return err
}
s.RequestURI = splits[1]
// Validate SIP Version
s.Version, err = GetSIPVersion(splits[2])
if err != nil {
return err
}
}
return nil
}
// ParseHeader will parse a SIP Header
// SIP Headers are quite simple, there are colon separated name and value
// Headers can be spread over multiple lines
//
// Examples of header :
//
// CSeq: 1 REGISTER
// Via: SIP/2.0/UDP there.com:5060
// Authorization:Digest username="UserB",
// realm="MCI WorldCom SIP",
// nonce="1cec4341ae6cbe5a359ea9c8e88df84f", opaque="",
// uri="sip:ss2.wcom.com", response="71ba27c64bd01de719686aa4590d5824"
//
func (s *SIP) ParseHeader(header []byte) (err error) {
// Ignore empty headers
if len(header) == 0 {
return
}
// Check if this is the following of last header
// RFC 3261 - 7.3.1 - Header Field Format specify that following lines of
// multiline headers must begin by SP or TAB
if header[0] == '\t' || header[0] == ' ' {
header = bytes.TrimSpace(header)
s.Headers[s.lastHeaderParsed][len(s.Headers[s.lastHeaderParsed])-1] += fmt.Sprintf(" %s", string(header))
return
}
// Find the ':' to separate header name and value
index := bytes.Index(header, []byte(":"))
if index >= 0 {
headerName := strings.ToLower(string(bytes.Trim(header[:index], " ")))
headerValue := string(bytes.Trim(header[index+1:], " "))
// Add header to object
s.Headers[headerName] = append(s.Headers[headerName], headerValue)
s.lastHeaderParsed = headerName
// Compute specific headers
err = s.ParseSpecificHeaders(headerName, headerValue)
if err != nil {
return err
}
}
return nil
}
// ParseSpecificHeaders will parse some specific key values from
// specific headers like CSeq or Content-Length integer values
func (s *SIP) ParseSpecificHeaders(headerName string, headerValue string) (err error) {
switch headerName {
case "cseq":
// CSeq header value is formatted like that :
// CSeq: 123 INVITE
// We split the value to parse Cseq integer value, and method
splits := strings.Split(headerValue, " ")
if len(splits) > 1 {
// Parse Cseq
s.cseq, err = strconv.ParseInt(splits[0], 10, 64)
if err != nil {
return err
}
// Validate method
if s.IsResponse {
s.Method, err = GetSIPMethod(splits[1])
if err != nil {
return err
}
}
}
case "content-length":
// Parse Content-Length
s.contentLength, err = strconv.ParseInt(headerValue, 10, 64)
if err != nil {
return err
}
}
return nil
}
// GetAllHeaders will return the full headers of the
// current SIP packets in a map[string][]string
func (s *SIP) GetAllHeaders() map[string][]string {
return s.Headers
}
// GetHeader will return all the headers with
// the specified name.
func (s *SIP) GetHeader(headerName string) []string {
headerName = strings.ToLower(headerName)
h := make([]string, 0)
if _, ok := s.Headers[headerName]; ok {
return s.Headers[headerName]
}
compactHeader := compactSipHeadersCorrespondance[headerName]
if _, ok := s.Headers[compactHeader]; ok {
return s.Headers[compactHeader]
}
return h
}
// GetFirstHeader will return the first header with
// the specified name. If the current SIP packet has multiple
// headers with the same name, it returns the first.
func (s *SIP) GetFirstHeader(headerName string) string {
headers := s.GetHeader(headerName)
if len(headers) > 0 {
return headers[0]
}
return ""
}
//
// Some handy getters for most used SIP headers
//
// GetAuthorization will return the Authorization
// header of the current SIP packet
func (s *SIP) GetAuthorization() string {
return s.GetFirstHeader("Authorization")
}
// GetFrom will return the From
// header of the current SIP packet
func (s *SIP) GetFrom() string {
return s.GetFirstHeader("From")
}
// GetTo will return the To
// header of the current SIP packet
func (s *SIP) GetTo() string {
return s.GetFirstHeader("To")
}
// GetContact will return the Contact
// header of the current SIP packet
func (s *SIP) GetContact() string {
return s.GetFirstHeader("Contact")
}
// GetCallID will return the Call-ID
// header of the current SIP packet
func (s *SIP) GetCallID() string {
return s.GetFirstHeader("Call-ID")
}
// GetUserAgent will return the User-Agent
// header of the current SIP packet
func (s *SIP) GetUserAgent() string {
return s.GetFirstHeader("User-Agent")
}
// GetContentLength will return the parsed integer
// Content-Length header of the current SIP packet
func (s *SIP) GetContentLength() int64 {
return s.contentLength
}
// GetCSeq will return the parsed integer CSeq header
// header of the current SIP packet
func (s *SIP) GetCSeq() int64 {
return s.cseq
}
// Copyright 2017 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"net"
"github.com/google/gopacket"
)
type STPSwitchID struct {
Priority uint16 // Bridge priority
SysID uint16 // VLAN ID
HwAddr net.HardwareAddr
}
// STP decode spanning tree protocol packets to transport BPDU (bridge protocol data unit) message.
type STP struct {
BaseLayer
ProtocolID uint16
Version uint8
Type uint8
TC, TCA bool // TC: Topologie change ; TCA: Topologie change ack
RouteID, BridgeID STPSwitchID
Cost uint32
PortID uint16
MessageAge uint16
MaxAge uint16
HelloTime uint16
FDelay uint16
}
// LayerType returns gopacket.LayerTypeSTP.
func (s *STP) LayerType() gopacket.LayerType { return LayerTypeSTP }
// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (s *STP) CanDecode() gopacket.LayerClass {
return LayerTypeSTP
}
// DecodeFromBytes decodes the given bytes into this layer.
func (stp *STP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
stpLength := 35
if len(data) < stpLength {
df.SetTruncated()
return fmt.Errorf("STP length %d too short", len(data))
}
stp.ProtocolID = binary.BigEndian.Uint16(data[:2])
stp.Version = uint8(data[2])
stp.Type = uint8(data[3])
stp.TC = data[4]&0x01 != 0
stp.TCA = data[4]&0x80 != 0
stp.RouteID.Priority = binary.BigEndian.Uint16(data[5:7]) & 0xf000
stp.RouteID.SysID = binary.BigEndian.Uint16(data[5:7]) & 0x0fff
stp.RouteID.HwAddr = net.HardwareAddr(data[7:13])
stp.Cost = binary.BigEndian.Uint32(data[13:17])
stp.BridgeID.Priority = binary.BigEndian.Uint16(data[17:19]) & 0xf000
stp.BridgeID.SysID = binary.BigEndian.Uint16(data[17:19]) & 0x0fff
stp.BridgeID.HwAddr = net.HardwareAddr(data[19:25])
stp.PortID = binary.BigEndian.Uint16(data[25:27])
stp.MessageAge = binary.BigEndian.Uint16(data[27:29])
stp.MaxAge = binary.BigEndian.Uint16(data[29:31])
stp.HelloTime = binary.BigEndian.Uint16(data[31:33])
stp.FDelay = binary.BigEndian.Uint16(data[33:35])
stp.Contents = data[:stpLength]
stp.Payload = data[stpLength:]
return nil
}
// NextLayerType returns the layer type contained by this DecodingLayer.
func (stp *STP) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
// Check if the priority value is correct.
func checkPriority(prio uint16) (uint16, error) {
if prio == 0 {
return prio, errors.New("Invalid Priority value must be in the rage <4096-61440> with an increment of 4096")
}
if prio%4096 == 0 {
return prio, nil
} else {
return prio, errors.New("Invalid Priority value must be in the rage <4096-61440> with an increment of 4096")
}
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (s *STP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
var flags uint8 = 0x00
bytes, err := b.PrependBytes(35)
if err != nil {
return err
}
binary.BigEndian.PutUint16(bytes, s.ProtocolID)
bytes[2] = s.Version
bytes[3] = s.Type
if s.TC {
flags |= 0x01
}
if s.TCA {
flags |= 0x80
}
bytes[4] = flags
prioRoot, err := checkPriority(s.RouteID.Priority)
if err != nil {
panic(err)
}
if s.RouteID.SysID >= 4096 {
panic("Invalid VlanID value ..!")
}
binary.BigEndian.PutUint16(bytes[5:7], prioRoot|s.RouteID.SysID)
copy(bytes[7:13], s.RouteID.HwAddr)
binary.BigEndian.PutUint32(bytes[13:17], s.Cost)
prioBridge, err := checkPriority(s.BridgeID.Priority)
if err != nil {
panic(err)
}
if s.BridgeID.SysID >= 4096 {
panic("Invalid VlanID value ..!")
}
binary.BigEndian.PutUint16(bytes[17:19], prioBridge|s.BridgeID.SysID)
copy(bytes[19:25], s.BridgeID.HwAddr)
binary.BigEndian.PutUint16(bytes[25:27], s.PortID)
binary.BigEndian.PutUint16(bytes[27:29], s.MessageAge)
binary.BigEndian.PutUint16(bytes[29:31], s.MaxAge)
binary.BigEndian.PutUint16(bytes[31:33], s.HelloTime)
binary.BigEndian.PutUint16(bytes[33:35], s.FDelay)
return nil
}
func decodeSTP(data []byte, p gopacket.PacketBuilder) error {
stp := &STP{}
return decodingLayerDecoder(stp, data, p)
}
// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
"github.com/google/gopacket"
)
// TCP is the layer for TCP headers.
type TCP struct {
BaseLayer
SrcPort, DstPort TCPPort
Seq uint32
Ack uint32
DataOffset uint8
FIN, SYN, RST, PSH, ACK, URG, ECE, CWR, NS bool
Window uint16
Checksum uint16
Urgent uint16
sPort, dPort []byte
Options []TCPOption
Padding []byte
opts [4]TCPOption
tcpipchecksum
}
// TCPOptionKind represents a TCP option code.
type TCPOptionKind uint8
const (
TCPOptionKindEndList = 0
TCPOptionKindNop = 1
TCPOptionKindMSS = 2 // len = 4
TCPOptionKindWindowScale = 3 // len = 3
TCPOptionKindSACKPermitted = 4 // len = 2
TCPOptionKindSACK = 5 // len = n
TCPOptionKindEcho = 6 // len = 6, obsolete
TCPOptionKindEchoReply = 7 // len = 6, obsolete
TCPOptionKindTimestamps = 8 // len = 10
TCPOptionKindPartialOrderConnectionPermitted = 9 // len = 2, obsolete
TCPOptionKindPartialOrderServiceProfile = 10 // len = 3, obsolete
TCPOptionKindCC = 11 // obsolete
TCPOptionKindCCNew = 12 // obsolete
TCPOptionKindCCEcho = 13 // obsolete
TCPOptionKindAltChecksum = 14 // len = 3, obsolete
TCPOptionKindAltChecksumData = 15 // len = n, obsolete
)
func (k TCPOptionKind) String() string {
switch k {
case TCPOptionKindEndList:
return "EndList"
case TCPOptionKindNop:
return "NOP"
case TCPOptionKindMSS:
return "MSS"
case TCPOptionKindWindowScale:
return "WindowScale"
case TCPOptionKindSACKPermitted:
return "SACKPermitted"
case TCPOptionKindSACK:
return "SACK"
case TCPOptionKindEcho:
return "Echo"
case TCPOptionKindEchoReply:
return "EchoReply"
case TCPOptionKindTimestamps:
return "Timestamps"
case TCPOptionKindPartialOrderConnectionPermitted:
return "PartialOrderConnectionPermitted"
case TCPOptionKindPartialOrderServiceProfile:
return "PartialOrderServiceProfile"
case TCPOptionKindCC:
return "CC"
case TCPOptionKindCCNew:
return "CCNew"
case TCPOptionKindCCEcho:
return "CCEcho"
case TCPOptionKindAltChecksum:
return "AltChecksum"
case TCPOptionKindAltChecksumData:
return "AltChecksumData"
default:
return fmt.Sprintf("Unknown(%d)", k)
}
}
type TCPOption struct {
OptionType TCPOptionKind
OptionLength uint8
OptionData []byte
}
func (t TCPOption) String() string {
hd := hex.EncodeToString(t.OptionData)
if len(hd) > 0 {
hd = " 0x" + hd
}
switch t.OptionType {
case TCPOptionKindMSS:
if len(t.OptionData) >= 2 {
return fmt.Sprintf("TCPOption(%s:%v%s)",
t.OptionType,
binary.BigEndian.Uint16(t.OptionData),
hd)
}
case TCPOptionKindTimestamps:
if len(t.OptionData) == 8 {
return fmt.Sprintf("TCPOption(%s:%v/%v%s)",
t.OptionType,
binary.BigEndian.Uint32(t.OptionData[:4]),
binary.BigEndian.Uint32(t.OptionData[4:8]),
hd)
}
}
return fmt.Sprintf("TCPOption(%s:%s)", t.OptionType, hd)
}
// LayerType returns gopacket.LayerTypeTCP
func (t *TCP) LayerType() gopacket.LayerType { return LayerTypeTCP }
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (t *TCP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
var optionLength int
for _, o := range t.Options {
switch o.OptionType {
case 0, 1:
optionLength += 1
default:
optionLength += 2 + len(o.OptionData)
}
}
if opts.FixLengths {
if rem := optionLength % 4; rem != 0 {
t.Padding = lotsOfZeros[:4-rem]
}
t.DataOffset = uint8((len(t.Padding) + optionLength + 20) / 4)
}
bytes, err := b.PrependBytes(20 + optionLength + len(t.Padding))
if err != nil {
return err
}
binary.BigEndian.PutUint16(bytes, uint16(t.SrcPort))
binary.BigEndian.PutUint16(bytes[2:], uint16(t.DstPort))
binary.BigEndian.PutUint32(bytes[4:], t.Seq)
binary.BigEndian.PutUint32(bytes[8:], t.Ack)
binary.BigEndian.PutUint16(bytes[12:], t.flagsAndOffset())
binary.BigEndian.PutUint16(bytes[14:], t.Window)
binary.BigEndian.PutUint16(bytes[18:], t.Urgent)
start := 20
for _, o := range t.Options {
bytes[start] = byte(o.OptionType)
switch o.OptionType {
case 0, 1:
start++
default:
if opts.FixLengths {
o.OptionLength = uint8(len(o.OptionData) + 2)
}
bytes[start+1] = o.OptionLength
copy(bytes[start+2:start+len(o.OptionData)+2], o.OptionData)
start += len(o.OptionData) + 2
}
}
copy(bytes[start:], t.Padding)
if opts.ComputeChecksums {
// zero out checksum bytes in current serialization.
bytes[16] = 0
bytes[17] = 0
csum, err := t.computeChecksum(b.Bytes(), IPProtocolTCP)
if err != nil {
return err
}
t.Checksum = csum
}
binary.BigEndian.PutUint16(bytes[16:], t.Checksum)
return nil
}
func (t *TCP) ComputeChecksum() (uint16, error) {
return t.computeChecksum(append(t.Contents, t.Payload...), IPProtocolTCP)
}
func (t *TCP) flagsAndOffset() uint16 {
f := uint16(t.DataOffset) << 12
if t.FIN {
f |= 0x0001
}
if t.SYN {
f |= 0x0002
}
if t.RST {
f |= 0x0004
}
if t.PSH {
f |= 0x0008
}
if t.ACK {
f |= 0x0010
}
if t.URG {
f |= 0x0020
}
if t.ECE {
f |= 0x0040
}
if t.CWR {
f |= 0x0080
}
if t.NS {
f |= 0x0100
}
return f
}
func (tcp *TCP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 20 {
df.SetTruncated()
return fmt.Errorf("Invalid TCP header. Length %d less than 20", len(data))
}
tcp.SrcPort = TCPPort(binary.BigEndian.Uint16(data[0:2]))
tcp.sPort = data[0:2]
tcp.DstPort = TCPPort(binary.BigEndian.Uint16(data[2:4]))
tcp.dPort = data[2:4]
tcp.Seq = binary.BigEndian.Uint32(data[4:8])
tcp.Ack = binary.BigEndian.Uint32(data[8:12])
tcp.DataOffset = data[12] >> 4
tcp.FIN = data[13]&0x01 != 0
tcp.SYN = data[13]&0x02 != 0
tcp.RST = data[13]&0x04 != 0
tcp.PSH = data[13]&0x08 != 0
tcp.ACK = data[13]&0x10 != 0
tcp.URG = data[13]&0x20 != 0
tcp.ECE = data[13]&0x40 != 0
tcp.CWR = data[13]&0x80 != 0
tcp.NS = data[12]&0x01 != 0
tcp.Window = binary.BigEndian.Uint16(data[14:16])
tcp.Checksum = binary.BigEndian.Uint16(data[16:18])
tcp.Urgent = binary.BigEndian.Uint16(data[18:20])
if tcp.Options == nil {
// Pre-allocate to avoid allocating a slice.
tcp.Options = tcp.opts[:0]
} else {
tcp.Options = tcp.Options[:0]
}
tcp.Padding = tcp.Padding[:0]
if tcp.DataOffset < 5 {
return fmt.Errorf("Invalid TCP data offset %d < 5", tcp.DataOffset)
}
dataStart := int(tcp.DataOffset) * 4
if dataStart > len(data) {
df.SetTruncated()
tcp.Payload = nil
tcp.Contents = data
return errors.New("TCP data offset greater than packet length")
}
tcp.Contents = data[:dataStart]
tcp.Payload = data[dataStart:]
// From here on, data points just to the header options.
data = data[20:dataStart]
OPTIONS:
for len(data) > 0 {
tcp.Options = append(tcp.Options, TCPOption{OptionType: TCPOptionKind(data[0])})
opt := &tcp.Options[len(tcp.Options)-1]
switch opt.OptionType {
case TCPOptionKindEndList: // End of options
opt.OptionLength = 1
tcp.Padding = data[1:]
break OPTIONS
case TCPOptionKindNop: // 1 byte padding
opt.OptionLength = 1
default:
if len(data) < 2 {
df.SetTruncated()
return fmt.Errorf("Invalid TCP option length. Length %d less than 2", len(data))
}
opt.OptionLength = data[1]
if opt.OptionLength < 2 {
return fmt.Errorf("Invalid TCP option length %d < 2", opt.OptionLength)
} else if int(opt.OptionLength) > len(data) {
df.SetTruncated()
return fmt.Errorf("Invalid TCP option length %d exceeds remaining %d bytes", opt.OptionLength, len(data))
}
opt.OptionData = data[2:opt.OptionLength]
}
data = data[opt.OptionLength:]
}
return nil
}
func (t *TCP) CanDecode() gopacket.LayerClass {
return LayerTypeTCP
}
func (t *TCP) NextLayerType() gopacket.LayerType {
lt := t.DstPort.LayerType()
if lt == gopacket.LayerTypePayload {
lt = t.SrcPort.LayerType()
}
return lt
}
func decodeTCP(data []byte, p gopacket.PacketBuilder) error {
tcp := &TCP{}
err := tcp.DecodeFromBytes(data, p)
p.AddLayer(tcp)
p.SetTransportLayer(tcp)
if err != nil {
return err
}
if p.DecodeOptions().DecodeStreamsAsDatagrams {
return p.NextDecoder(tcp.NextLayerType())
} else {
return p.NextDecoder(gopacket.LayerTypePayload)
}
}
func (t *TCP) TransportFlow() gopacket.Flow {
return gopacket.NewFlow(EndpointTCPPort, t.sPort, t.dPort)
}
// For testing only
func (t *TCP) SetInternalPortsForTesting() {
t.sPort = make([]byte, 2)
t.dPort = make([]byte, 2)
binary.BigEndian.PutUint16(t.sPort, uint16(t.SrcPort))
binary.BigEndian.PutUint16(t.dPort, uint16(t.DstPort))
}
// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"errors"
"fmt"
"github.com/google/gopacket"
)
// Checksum computation for TCP/UDP.
type tcpipchecksum struct {
pseudoheader tcpipPseudoHeader
}
type tcpipPseudoHeader interface {
pseudoheaderChecksum() (uint32, error)
}
func (ip *IPv4) pseudoheaderChecksum() (csum uint32, err error) {
if err := ip.AddressTo4(); err != nil {
return 0, err
}
csum += (uint32(ip.SrcIP[0]) + uint32(ip.SrcIP[2])) << 8
csum += uint32(ip.SrcIP[1]) + uint32(ip.SrcIP[3])
csum += (uint32(ip.DstIP[0]) + uint32(ip.DstIP[2])) << 8
csum += uint32(ip.DstIP[1]) + uint32(ip.DstIP[3])
return csum, nil
}
func (ip *IPv6) pseudoheaderChecksum() (csum uint32, err error) {
if err := ip.AddressTo16(); err != nil {
return 0, err
}
for i := 0; i < 16; i += 2 {
csum += uint32(ip.SrcIP[i]) << 8
csum += uint32(ip.SrcIP[i+1])
csum += uint32(ip.DstIP[i]) << 8
csum += uint32(ip.DstIP[i+1])
}
return csum, nil
}
// Calculate the TCP/IP checksum defined in rfc1071. The passed-in csum is any
// initial checksum data that's already been computed.
func tcpipChecksum(data []byte, csum uint32) uint16 {
// to handle odd lengths, we loop to length - 1, incrementing by 2, then
// handle the last byte specifically by checking against the original
// length.
length := len(data) - 1
for i := 0; i < length; i += 2 {
// For our test packet, doing this manually is about 25% faster
// (740 ns vs. 1000ns) than doing it by calling binary.BigEndian.Uint16.
csum += uint32(data[i]) << 8
csum += uint32(data[i+1])
}
if len(data)%2 == 1 {
csum += uint32(data[length]) << 8
}
for csum > 0xffff {
csum = (csum >> 16) + (csum & 0xffff)
}
return ^uint16(csum)
}
// computeChecksum computes a TCP or UDP checksum. headerAndPayload is the
// serialized TCP or UDP header plus its payload, with the checksum zero'd
// out. headerProtocol is the IP protocol number of the upper-layer header.
func (c *tcpipchecksum) computeChecksum(headerAndPayload []byte, headerProtocol IPProtocol) (uint16, error) {
if c.pseudoheader == nil {
return 0, errors.New("TCP/IP layer 4 checksum cannot be computed without network layer... call SetNetworkLayerForChecksum to set which layer to use")
}
length := uint32(len(headerAndPayload))
csum, err := c.pseudoheader.pseudoheaderChecksum()
if err != nil {
return 0, err
}
csum += uint32(headerProtocol)
csum += length & 0xffff
csum += length >> 16
return tcpipChecksum(headerAndPayload, csum), nil
}
// SetNetworkLayerForChecksum tells this layer which network layer is wrapping it.
// This is needed for computing the checksum when serializing, since TCP/IP transport
// layer checksums depends on fields in the IPv4 or IPv6 layer that contains it.
// The passed in layer must be an *IPv4 or *IPv6.
func (i *tcpipchecksum) SetNetworkLayerForChecksum(l gopacket.NetworkLayer) error {
switch v := l.(type) {
case *IPv4:
i.pseudoheader = v
case *IPv6:
i.pseudoheader = v
default:
return fmt.Errorf("cannot use layer type %v for tcp checksum network layer", l.LayerType())
}
return nil
}
// Copyright 2018 The GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"github.com/google/gopacket"
)
// TLSType defines the type of data after the TLS Record
type TLSType uint8
// TLSType known values.
const (
TLSChangeCipherSpec TLSType = 20
TLSAlert TLSType = 21
TLSHandshake TLSType = 22
TLSApplicationData TLSType = 23
TLSUnknown TLSType = 255
)
// String shows the register type nicely formatted
func (tt TLSType) String() string {
switch tt {
default:
return "Unknown"
case TLSChangeCipherSpec:
return "Change Cipher Spec"
case TLSAlert:
return "Alert"
case TLSHandshake:
return "Handshake"
case TLSApplicationData:
return "Application Data"
}
}
// TLSVersion represents the TLS version in numeric format
type TLSVersion uint16
// Strings shows the TLS version nicely formatted
func (tv TLSVersion) String() string {
switch tv {
default:
return "Unknown"
case 0x0200:
return "SSL 2.0"
case 0x0300:
return "SSL 3.0"
case 0x0301:
return "TLS 1.0"
case 0x0302:
return "TLS 1.1"
case 0x0303:
return "TLS 1.2"
case 0x0304:
return "TLS 1.3"
}
}
// TLS is specified in RFC 5246
//
// TLS Record Protocol
// 0 1 2 3 4 5 6 7 8
// +--+--+--+--+--+--+--+--+
// | Content Type |
// +--+--+--+--+--+--+--+--+
// | Version (major) |
// +--+--+--+--+--+--+--+--+
// | Version (minor) |
// +--+--+--+--+--+--+--+--+
// | Length |
// +--+--+--+--+--+--+--+--+
// | Length |
// +--+--+--+--+--+--+--+--+
// TLS is actually a slide of TLSrecord structures
type TLS struct {
BaseLayer
// TLS Records
ChangeCipherSpec []TLSChangeCipherSpecRecord
Handshake []TLSHandshakeRecord
AppData []TLSAppDataRecord
Alert []TLSAlertRecord
}
// TLSRecordHeader contains all the information that each TLS Record types should have
type TLSRecordHeader struct {
ContentType TLSType
Version TLSVersion
Length uint16
}
// LayerType returns gopacket.LayerTypeTLS.
func (t *TLS) LayerType() gopacket.LayerType { return LayerTypeTLS }
// decodeTLS decodes the byte slice into a TLS type. It also
// setups the application Layer in PacketBuilder.
func decodeTLS(data []byte, p gopacket.PacketBuilder) error {
t := &TLS{}
err := t.DecodeFromBytes(data, p)
if err != nil {
return err
}
p.AddLayer(t)
p.SetApplicationLayer(t)
return nil
}
// DecodeFromBytes decodes the slice into the TLS struct.
func (t *TLS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
t.BaseLayer.Contents = data
t.BaseLayer.Payload = nil
t.ChangeCipherSpec = t.ChangeCipherSpec[:0]
t.Handshake = t.Handshake[:0]
t.AppData = t.AppData[:0]
t.Alert = t.Alert[:0]
return t.decodeTLSRecords(data, df)
}
func (t *TLS) decodeTLSRecords(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 5 {
df.SetTruncated()
return errors.New("TLS record too short")
}
// since there are no further layers, the baselayer's content is
// pointing to this layer
// TODO: Consider removing this
t.BaseLayer = BaseLayer{Contents: data[:len(data)]}
var h TLSRecordHeader
h.ContentType = TLSType(data[0])
h.Version = TLSVersion(binary.BigEndian.Uint16(data[1:3]))
h.Length = binary.BigEndian.Uint16(data[3:5])
if h.ContentType.String() == "Unknown" {
return errors.New("Unknown TLS record type")
}
hl := 5 // header length
tl := hl + int(h.Length)
if len(data) < tl {
df.SetTruncated()
return errors.New("TLS packet length mismatch")
}
switch h.ContentType {
default:
return errors.New("Unknown TLS record type")
case TLSChangeCipherSpec:
var r TLSChangeCipherSpecRecord
e := r.decodeFromBytes(h, data[hl:tl], df)
if e != nil {
return e
}
t.ChangeCipherSpec = append(t.ChangeCipherSpec, r)
case TLSAlert:
var r TLSAlertRecord
e := r.decodeFromBytes(h, data[hl:tl], df)
if e != nil {
return e
}
t.Alert = append(t.Alert, r)
case TLSHandshake:
var r TLSHandshakeRecord
e := r.decodeFromBytes(h, data[hl:tl], df)
if e != nil {
return e
}
t.Handshake = append(t.Handshake, r)
case TLSApplicationData:
var r TLSAppDataRecord
e := r.decodeFromBytes(h, data[hl:tl], df)
if e != nil {
return e
}
t.AppData = append(t.AppData, r)
}
if len(data) == tl {
return nil
}
return t.decodeTLSRecords(data[tl:len(data)], df)
}
// CanDecode implements gopacket.DecodingLayer.
func (t *TLS) CanDecode() gopacket.LayerClass {
return LayerTypeTLS
}
// NextLayerType implements gopacket.DecodingLayer.
func (t *TLS) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypeZero
}
// Payload returns nil, since TLS encrypted payload is inside TLSAppDataRecord
func (t *TLS) Payload() []byte {
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
func (t *TLS) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
totalLength := 0
for _, record := range t.ChangeCipherSpec {
if opts.FixLengths {
record.Length = 1
}
totalLength += 5 + 1 // length of header + record
}
for range t.Handshake {
totalLength += 5
// TODO
}
for _, record := range t.AppData {
if opts.FixLengths {
record.Length = uint16(len(record.Payload))
}
totalLength += 5 + len(record.Payload)
}
for _, record := range t.Alert {
if len(record.EncryptedMsg) == 0 {
if opts.FixLengths {
record.Length = 2
}
totalLength += 5 + 2
} else {
if opts.FixLengths {
record.Length = uint16(len(record.EncryptedMsg))
}
totalLength += 5 + len(record.EncryptedMsg)
}
}
data, err := b.PrependBytes(totalLength)
if err != nil {
return err
}
off := 0
for _, record := range t.ChangeCipherSpec {
off = encodeHeader(record.TLSRecordHeader, data, off)
data[off] = byte(record.Message)
off++
}
for _, record := range t.Handshake {
off = encodeHeader(record.TLSRecordHeader, data, off)
// TODO
}
for _, record := range t.AppData {
off = encodeHeader(record.TLSRecordHeader, data, off)
copy(data[off:], record.Payload)
off += len(record.Payload)
}
for _, record := range t.Alert {
off = encodeHeader(record.TLSRecordHeader, data, off)
if len(record.EncryptedMsg) == 0 {
data[off] = byte(record.Level)
data[off+1] = byte(record.Description)
off += 2
} else {
copy(data[off:], record.EncryptedMsg)
off += len(record.EncryptedMsg)
}
}
return nil
}
func encodeHeader(header TLSRecordHeader, data []byte, offset int) int {
data[offset] = byte(header.ContentType)
binary.BigEndian.PutUint16(data[offset+1:], uint16(header.Version))
binary.BigEndian.PutUint16(data[offset+3:], header.Length)
return offset + 5
}
// Copyright 2018 The GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"errors"
"fmt"
"github.com/google/gopacket"
)
// TLSAlertLevel defines the alert level data type
type TLSAlertLevel uint8
// TLSAlertDescr defines the alert descrption data type
type TLSAlertDescr uint8
const (
TLSAlertWarning TLSAlertLevel = 1
TLSAlertFatal TLSAlertLevel = 2
TLSAlertUnknownLevel TLSAlertLevel = 255
TLSAlertCloseNotify TLSAlertDescr = 0
TLSAlertUnexpectedMessage TLSAlertDescr = 10
TLSAlertBadRecordMac TLSAlertDescr = 20
TLSAlertDecryptionFailedRESERVED TLSAlertDescr = 21
TLSAlertRecordOverflow TLSAlertDescr = 22
TLSAlertDecompressionFailure TLSAlertDescr = 30
TLSAlertHandshakeFailure TLSAlertDescr = 40
TLSAlertNoCertificateRESERVED TLSAlertDescr = 41
TLSAlertBadCertificate TLSAlertDescr = 42
TLSAlertUnsupportedCertificate TLSAlertDescr = 43
TLSAlertCertificateRevoked TLSAlertDescr = 44
TLSAlertCertificateExpired TLSAlertDescr = 45
TLSAlertCertificateUnknown TLSAlertDescr = 46
TLSAlertIllegalParameter TLSAlertDescr = 47
TLSAlertUnknownCa TLSAlertDescr = 48
TLSAlertAccessDenied TLSAlertDescr = 49
TLSAlertDecodeError TLSAlertDescr = 50
TLSAlertDecryptError TLSAlertDescr = 51
TLSAlertExportRestrictionRESERVED TLSAlertDescr = 60
TLSAlertProtocolVersion TLSAlertDescr = 70
TLSAlertInsufficientSecurity TLSAlertDescr = 71
TLSAlertInternalError TLSAlertDescr = 80
TLSAlertUserCanceled TLSAlertDescr = 90
TLSAlertNoRenegotiation TLSAlertDescr = 100
TLSAlertUnsupportedExtension TLSAlertDescr = 110
TLSAlertUnknownDescription TLSAlertDescr = 255
)
// TLS Alert
// 0 1 2 3 4 5 6 7 8
// +--+--+--+--+--+--+--+--+
// | Level |
// +--+--+--+--+--+--+--+--+
// | Description |
// +--+--+--+--+--+--+--+--+
// TLSAlertRecord contains all the information that each Alert Record type should have
type TLSAlertRecord struct {
TLSRecordHeader
Level TLSAlertLevel
Description TLSAlertDescr
EncryptedMsg []byte
}
// DecodeFromBytes decodes the slice into the TLS struct.
func (t *TLSAlertRecord) decodeFromBytes(h TLSRecordHeader, data []byte, df gopacket.DecodeFeedback) error {
// TLS Record Header
t.ContentType = h.ContentType
t.Version = h.Version
t.Length = h.Length
if len(data) < 2 {
df.SetTruncated()
return errors.New("TLS Alert packet too short")
}
if t.Length == 2 {
t.Level = TLSAlertLevel(data[0])
t.Description = TLSAlertDescr(data[1])
} else {
t.Level = TLSAlertUnknownLevel
t.Description = TLSAlertUnknownDescription
t.EncryptedMsg = data
}
return nil
}
// Strings shows the TLS alert level nicely formatted
func (al TLSAlertLevel) String() string {
switch al {
default:
return fmt.Sprintf("Unknown(%d)", al)
case TLSAlertWarning:
return "Warning"
case TLSAlertFatal:
return "Fatal"
}
}
// Strings shows the TLS alert description nicely formatted
func (ad TLSAlertDescr) String() string {
switch ad {
default:
return "Unknown"
case TLSAlertCloseNotify:
return "close_notify"
case TLSAlertUnexpectedMessage:
return "unexpected_message"
case TLSAlertBadRecordMac:
return "bad_record_mac"
case TLSAlertDecryptionFailedRESERVED:
return "decryption_failed_RESERVED"
case TLSAlertRecordOverflow:
return "record_overflow"
case TLSAlertDecompressionFailure:
return "decompression_failure"
case TLSAlertHandshakeFailure:
return "handshake_failure"
case TLSAlertNoCertificateRESERVED:
return "no_certificate_RESERVED"
case TLSAlertBadCertificate:
return "bad_certificate"
case TLSAlertUnsupportedCertificate:
return "unsupported_certificate"
case TLSAlertCertificateRevoked:
return "certificate_revoked"
case TLSAlertCertificateExpired:
return "certificate_expired"
case TLSAlertCertificateUnknown:
return "certificate_unknown"
case TLSAlertIllegalParameter:
return "illegal_parameter"
case TLSAlertUnknownCa:
return "unknown_ca"
case TLSAlertAccessDenied:
return "access_denied"
case TLSAlertDecodeError:
return "decode_error"
case TLSAlertDecryptError:
return "decrypt_error"
case TLSAlertExportRestrictionRESERVED:
return "export_restriction_RESERVED"
case TLSAlertProtocolVersion:
return "protocol_version"
case TLSAlertInsufficientSecurity:
return "insufficient_security"
case TLSAlertInternalError:
return "internal_error"
case TLSAlertUserCanceled:
return "user_canceled"
case TLSAlertNoRenegotiation:
return "no_renegotiation"
case TLSAlertUnsupportedExtension:
return "unsupported_extension"
}
}
// Copyright 2018 The GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"errors"
"github.com/google/gopacket"
)
// TLSAppDataRecord contains all the information that each AppData Record types should have
type TLSAppDataRecord struct {
TLSRecordHeader
Payload []byte
}
// DecodeFromBytes decodes the slice into the TLS struct.
func (t *TLSAppDataRecord) decodeFromBytes(h TLSRecordHeader, data []byte, df gopacket.DecodeFeedback) error {
// TLS Record Header
t.ContentType = h.ContentType
t.Version = h.Version
t.Length = h.Length
if len(data) != int(t.Length) {
return errors.New("TLS Application Data length mismatch")
}
t.Payload = data
return nil
}
// Copyright 2018 The GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"errors"
"github.com/google/gopacket"
)
// TLSchangeCipherSpec defines the message value inside ChangeCipherSpec Record
type TLSchangeCipherSpec uint8
const (
TLSChangecipherspecMessage TLSchangeCipherSpec = 1
TLSChangecipherspecUnknown TLSchangeCipherSpec = 255
)
// TLS Change Cipher Spec
// 0 1 2 3 4 5 6 7 8
// +--+--+--+--+--+--+--+--+
// | Message |
// +--+--+--+--+--+--+--+--+
// TLSChangeCipherSpecRecord defines the type of data inside ChangeCipherSpec Record
type TLSChangeCipherSpecRecord struct {
TLSRecordHeader
Message TLSchangeCipherSpec
}
// DecodeFromBytes decodes the slice into the TLS struct.
func (t *TLSChangeCipherSpecRecord) decodeFromBytes(h TLSRecordHeader, data []byte, df gopacket.DecodeFeedback) error {
// TLS Record Header
t.ContentType = h.ContentType
t.Version = h.Version
t.Length = h.Length
if len(data) != 1 {
df.SetTruncated()
return errors.New("TLS Change Cipher Spec record incorrect length")
}
t.Message = TLSchangeCipherSpec(data[0])
if t.Message != TLSChangecipherspecMessage {
t.Message = TLSChangecipherspecUnknown
}
return nil
}
// String shows the message value nicely formatted
func (ccs TLSchangeCipherSpec) String() string {
switch ccs {
default:
return "Unknown"
case TLSChangecipherspecMessage:
return "Change Cipher Spec Message"
}
}
// Copyright 2018 The GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"github.com/google/gopacket"
)
// TLSHandshakeRecord defines the structure of a Handshare Record
type TLSHandshakeRecord struct {
TLSRecordHeader
}
// DecodeFromBytes decodes the slice into the TLS struct.
func (t *TLSHandshakeRecord) decodeFromBytes(h TLSRecordHeader, data []byte, df gopacket.DecodeFeedback) error {
// TLS Record Header
t.ContentType = h.ContentType
t.Version = h.Version
t.Length = h.Length
// TODO
return nil
}
// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"fmt"
"github.com/google/gopacket"
)
// UDP is the layer for UDP headers.
type UDP struct {
BaseLayer
SrcPort, DstPort UDPPort
Length uint16
Checksum uint16
sPort, dPort []byte
tcpipchecksum
}
// LayerType returns gopacket.LayerTypeUDP
func (u *UDP) LayerType() gopacket.LayerType { return LayerTypeUDP }
func (udp *UDP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 8 {
df.SetTruncated()
return fmt.Errorf("Invalid UDP header. Length %d less than 8", len(data))
}
udp.SrcPort = UDPPort(binary.BigEndian.Uint16(data[0:2]))
udp.sPort = data[0:2]
udp.DstPort = UDPPort(binary.BigEndian.Uint16(data[2:4]))
udp.dPort = data[2:4]
udp.Length = binary.BigEndian.Uint16(data[4:6])
udp.Checksum = binary.BigEndian.Uint16(data[6:8])
udp.BaseLayer = BaseLayer{Contents: data[:8]}
switch {
case udp.Length >= 8:
hlen := int(udp.Length)
if hlen > len(data) {
df.SetTruncated()
hlen = len(data)
}
udp.Payload = data[8:hlen]
case udp.Length == 0: // Jumbogram, use entire rest of data
udp.Payload = data[8:]
default:
return fmt.Errorf("UDP packet too small: %d bytes", udp.Length)
}
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (u *UDP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
var jumbo bool
payload := b.Bytes()
if _, ok := u.pseudoheader.(*IPv6); ok {
if len(payload)+8 > 65535 {
jumbo = true
}
}
bytes, err := b.PrependBytes(8)
if err != nil {
return err
}
binary.BigEndian.PutUint16(bytes, uint16(u.SrcPort))
binary.BigEndian.PutUint16(bytes[2:], uint16(u.DstPort))
if opts.FixLengths {
if jumbo {
u.Length = 0
} else {
u.Length = uint16(len(payload)) + 8
}
}
binary.BigEndian.PutUint16(bytes[4:], u.Length)
if opts.ComputeChecksums {
// zero out checksum bytes
bytes[6] = 0
bytes[7] = 0
csum, err := u.computeChecksum(b.Bytes(), IPProtocolUDP)
if err != nil {
return err
}
u.Checksum = csum
}
binary.BigEndian.PutUint16(bytes[6:], u.Checksum)
return nil
}
func (u *UDP) CanDecode() gopacket.LayerClass {
return LayerTypeUDP
}
// NextLayerType use the destination port to select the
// right next decoder. It tries first to decode via the
// destination port, then the source port.
func (u *UDP) NextLayerType() gopacket.LayerType {
if lt := u.DstPort.LayerType(); lt != gopacket.LayerTypePayload {
return lt
}
return u.SrcPort.LayerType()
}
func decodeUDP(data []byte, p gopacket.PacketBuilder) error {
udp := &UDP{}
err := udp.DecodeFromBytes(data, p)
p.AddLayer(udp)
p.SetTransportLayer(udp)
if err != nil {
return err
}
return p.NextDecoder(udp.NextLayerType())
}
func (u *UDP) TransportFlow() gopacket.Flow {
return gopacket.NewFlow(EndpointUDPPort, u.sPort, u.dPort)
}
// For testing only
func (u *UDP) SetInternalPortsForTesting() {
u.sPort = make([]byte, 2)
u.dPort = make([]byte, 2)
binary.BigEndian.PutUint16(u.sPort, uint16(u.SrcPort))
binary.BigEndian.PutUint16(u.dPort, uint16(u.DstPort))
}
// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"github.com/google/gopacket"
)
// UDPLite is the layer for UDP-Lite headers (rfc 3828).
type UDPLite struct {
BaseLayer
SrcPort, DstPort UDPLitePort
ChecksumCoverage uint16
Checksum uint16
sPort, dPort []byte
}
// LayerType returns gopacket.LayerTypeUDPLite
func (u *UDPLite) LayerType() gopacket.LayerType { return LayerTypeUDPLite }
func decodeUDPLite(data []byte, p gopacket.PacketBuilder) error {
udp := &UDPLite{
SrcPort: UDPLitePort(binary.BigEndian.Uint16(data[0:2])),
sPort: data[0:2],
DstPort: UDPLitePort(binary.BigEndian.Uint16(data[2:4])),
dPort: data[2:4],
ChecksumCoverage: binary.BigEndian.Uint16(data[4:6]),
Checksum: binary.BigEndian.Uint16(data[6:8]),
BaseLayer: BaseLayer{data[:8], data[8:]},
}
p.AddLayer(udp)
p.SetTransportLayer(udp)
return p.NextDecoder(gopacket.LayerTypePayload)
}
func (u *UDPLite) TransportFlow() gopacket.Flow {
return gopacket.NewFlow(EndpointUDPLitePort, u.sPort, u.dPort)
}
// Copyright 2014 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"github.com/google/gopacket"
)
type USBEventType uint8
const (
USBEventTypeSubmit USBEventType = 'S'
USBEventTypeComplete USBEventType = 'C'
USBEventTypeError USBEventType = 'E'
)
func (a USBEventType) String() string {
switch a {
case USBEventTypeSubmit:
return "SUBMIT"
case USBEventTypeComplete:
return "COMPLETE"
case USBEventTypeError:
return "ERROR"
default:
return "Unknown event type"
}
}
type USBRequestBlockSetupRequest uint8
const (
USBRequestBlockSetupRequestGetStatus USBRequestBlockSetupRequest = 0x00
USBRequestBlockSetupRequestClearFeature USBRequestBlockSetupRequest = 0x01
USBRequestBlockSetupRequestSetFeature USBRequestBlockSetupRequest = 0x03
USBRequestBlockSetupRequestSetAddress USBRequestBlockSetupRequest = 0x05
USBRequestBlockSetupRequestGetDescriptor USBRequestBlockSetupRequest = 0x06
USBRequestBlockSetupRequestSetDescriptor USBRequestBlockSetupRequest = 0x07
USBRequestBlockSetupRequestGetConfiguration USBRequestBlockSetupRequest = 0x08
USBRequestBlockSetupRequestSetConfiguration USBRequestBlockSetupRequest = 0x09
USBRequestBlockSetupRequestSetIdle USBRequestBlockSetupRequest = 0x0a
)
func (a USBRequestBlockSetupRequest) String() string {
switch a {
case USBRequestBlockSetupRequestGetStatus:
return "GET_STATUS"
case USBRequestBlockSetupRequestClearFeature:
return "CLEAR_FEATURE"
case USBRequestBlockSetupRequestSetFeature:
return "SET_FEATURE"
case USBRequestBlockSetupRequestSetAddress:
return "SET_ADDRESS"
case USBRequestBlockSetupRequestGetDescriptor:
return "GET_DESCRIPTOR"
case USBRequestBlockSetupRequestSetDescriptor:
return "SET_DESCRIPTOR"
case USBRequestBlockSetupRequestGetConfiguration:
return "GET_CONFIGURATION"
case USBRequestBlockSetupRequestSetConfiguration:
return "SET_CONFIGURATION"
case USBRequestBlockSetupRequestSetIdle:
return "SET_IDLE"
default:
return "UNKNOWN"
}
}
type USBTransportType uint8
const (
USBTransportTypeTransferIn USBTransportType = 0x80 // Indicates send or receive
USBTransportTypeIsochronous USBTransportType = 0x00 // Isochronous transfers occur continuously and periodically. They typically contain time sensitive information, such as an audio or video stream.
USBTransportTypeInterrupt USBTransportType = 0x01 // Interrupt transfers are typically non-periodic, small device "initiated" communication requiring bounded latency, such as pointing devices or keyboards.
USBTransportTypeControl USBTransportType = 0x02 // Control transfers are typically used for command and status operations.
USBTransportTypeBulk USBTransportType = 0x03 // Bulk transfers can be used for large bursty data, using all remaining available bandwidth, no guarantees on bandwidth or latency, such as file transfers.
)
type USBDirectionType uint8
const (
USBDirectionTypeUnknown USBDirectionType = iota
USBDirectionTypeIn
USBDirectionTypeOut
)
func (a USBDirectionType) String() string {
switch a {
case USBDirectionTypeIn:
return "In"
case USBDirectionTypeOut:
return "Out"
default:
return "Unknown direction type"
}
}
// The reference at http://www.beyondlogic.org/usbnutshell/usb1.shtml contains more information about the protocol.
type USB struct {
BaseLayer
ID uint64
EventType USBEventType
TransferType USBTransportType
Direction USBDirectionType
EndpointNumber uint8
DeviceAddress uint8
BusID uint16
TimestampSec int64
TimestampUsec int32
Setup bool
Data bool
Status int32
UrbLength uint32
UrbDataLength uint32
UrbInterval uint32
UrbStartFrame uint32
UrbCopyOfTransferFlags uint32
IsoNumDesc uint32
}
func (u *USB) LayerType() gopacket.LayerType { return LayerTypeUSB }
func (m *USB) NextLayerType() gopacket.LayerType {
if m.Setup {
return LayerTypeUSBRequestBlockSetup
} else if m.Data {
}
return m.TransferType.LayerType()
}
func decodeUSB(data []byte, p gopacket.PacketBuilder) error {
d := &USB{}
return decodingLayerDecoder(d, data, p)
}
func (m *USB) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 40 {
df.SetTruncated()
return errors.New("USB < 40 bytes")
}
m.ID = binary.LittleEndian.Uint64(data[0:8])
m.EventType = USBEventType(data[8])
m.TransferType = USBTransportType(data[9])
m.EndpointNumber = data[10] & 0x7f
if data[10]&uint8(USBTransportTypeTransferIn) > 0 {
m.Direction = USBDirectionTypeIn
} else {
m.Direction = USBDirectionTypeOut
}
m.DeviceAddress = data[11]
m.BusID = binary.LittleEndian.Uint16(data[12:14])
if uint(data[14]) == 0 {
m.Setup = true
}
if uint(data[15]) == 0 {
m.Data = true
}
m.TimestampSec = int64(binary.LittleEndian.Uint64(data[16:24]))
m.TimestampUsec = int32(binary.LittleEndian.Uint32(data[24:28]))
m.Status = int32(binary.LittleEndian.Uint32(data[28:32]))
m.UrbLength = binary.LittleEndian.Uint32(data[32:36])
m.UrbDataLength = binary.LittleEndian.Uint32(data[36:40])
m.Contents = data[:40]
m.Payload = data[40:]
if m.Setup {
m.Payload = data[40:]
} else if m.Data {
m.Payload = data[uint32(len(data))-m.UrbDataLength:]
}
// if 64 bit, dissect_linux_usb_pseudo_header_ext
if false {
m.UrbInterval = binary.LittleEndian.Uint32(data[40:44])
m.UrbStartFrame = binary.LittleEndian.Uint32(data[44:48])
m.UrbDataLength = binary.LittleEndian.Uint32(data[48:52])
m.IsoNumDesc = binary.LittleEndian.Uint32(data[52:56])
m.Contents = data[:56]
m.Payload = data[56:]
}
// crc5 or crc16
// eop (end of packet)
return nil
}
type USBRequestBlockSetup struct {
BaseLayer
RequestType uint8
Request USBRequestBlockSetupRequest
Value uint16
Index uint16
Length uint16
}
func (u *USBRequestBlockSetup) LayerType() gopacket.LayerType { return LayerTypeUSBRequestBlockSetup }
func (m *USBRequestBlockSetup) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
func (m *USBRequestBlockSetup) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
m.RequestType = data[0]
m.Request = USBRequestBlockSetupRequest(data[1])
m.Value = binary.LittleEndian.Uint16(data[2:4])
m.Index = binary.LittleEndian.Uint16(data[4:6])
m.Length = binary.LittleEndian.Uint16(data[6:8])
m.Contents = data[:8]
m.Payload = data[8:]
return nil
}
func decodeUSBRequestBlockSetup(data []byte, p gopacket.PacketBuilder) error {
d := &USBRequestBlockSetup{}
return decodingLayerDecoder(d, data, p)
}
type USBControl struct {
BaseLayer
}
func (u *USBControl) LayerType() gopacket.LayerType { return LayerTypeUSBControl }
func (m *USBControl) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
func (m *USBControl) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
m.Contents = data
return nil
}
func decodeUSBControl(data []byte, p gopacket.PacketBuilder) error {
d := &USBControl{}
return decodingLayerDecoder(d, data, p)
}
type USBInterrupt struct {
BaseLayer
}
func (u *USBInterrupt) LayerType() gopacket.LayerType { return LayerTypeUSBInterrupt }
func (m *USBInterrupt) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
func (m *USBInterrupt) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
m.Contents = data
return nil
}
func decodeUSBInterrupt(data []byte, p gopacket.PacketBuilder) error {
d := &USBInterrupt{}
return decodingLayerDecoder(d, data, p)
}
type USBBulk struct {
BaseLayer
}
func (u *USBBulk) LayerType() gopacket.LayerType { return LayerTypeUSBBulk }
func (m *USBBulk) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
func (m *USBBulk) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
m.Contents = data
return nil
}
func decodeUSBBulk(data []byte, p gopacket.PacketBuilder) error {
d := &USBBulk{}
return decodingLayerDecoder(d, data, p)
}
// Copyright 2016 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"net"
"github.com/google/gopacket"
)
/*
This layer provides decoding for Virtual Router Redundancy Protocol (VRRP) v2.
https://tools.ietf.org/html/rfc3768#section-5
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| Type | Virtual Rtr ID| Priority | Count IP Addrs|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Auth Type | Adver Int | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address (1) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| . |
| . |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address (n) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Authentication Data (1) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Authentication Data (2) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
type VRRPv2Type uint8
type VRRPv2AuthType uint8
const (
VRRPv2Advertisement VRRPv2Type = 0x01 // router advertisement
)
// String conversions for VRRP message types
func (v VRRPv2Type) String() string {
switch v {
case VRRPv2Advertisement:
return "VRRPv2 Advertisement"
default:
return ""
}
}
const (
VRRPv2AuthNoAuth VRRPv2AuthType = 0x00 // No Authentication
VRRPv2AuthReserved1 VRRPv2AuthType = 0x01 // Reserved field 1
VRRPv2AuthReserved2 VRRPv2AuthType = 0x02 // Reserved field 2
)
func (v VRRPv2AuthType) String() string {
switch v {
case VRRPv2AuthNoAuth:
return "No Authentication"
case VRRPv2AuthReserved1:
return "Reserved"
case VRRPv2AuthReserved2:
return "Reserved"
default:
return ""
}
}
// VRRPv2 represents an VRRP v2 message.
type VRRPv2 struct {
BaseLayer
Version uint8 // The version field specifies the VRRP protocol version of this packet (v2)
Type VRRPv2Type // The type field specifies the type of this VRRP packet. The only type defined in v2 is ADVERTISEMENT
VirtualRtrID uint8 // identifies the virtual router this packet is reporting status for
Priority uint8 // specifies the sending VRRP router's priority for the virtual router (100 = default)
CountIPAddr uint8 // The number of IP addresses contained in this VRRP advertisement.
AuthType VRRPv2AuthType // identifies the authentication method being utilized
AdverInt uint8 // The Advertisement interval indicates the time interval (in seconds) between ADVERTISEMENTS. The default is 1 second
Checksum uint16 // used to detect data corruption in the VRRP message.
IPAddress []net.IP // one or more IP addresses associated with the virtual router. Specified in the CountIPAddr field.
}
// LayerType returns LayerTypeVRRP for VRRP v2 message.
func (v *VRRPv2) LayerType() gopacket.LayerType { return LayerTypeVRRP }
func (v *VRRPv2) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
v.BaseLayer = BaseLayer{Contents: data[:len(data)]}
v.Version = data[0] >> 4 // high nibble == VRRP version. We're expecting v2
v.Type = VRRPv2Type(data[0] & 0x0F) // low nibble == VRRP type. Expecting 1 (advertisement)
if v.Type != 1 {
// rfc3768: A packet with unknown type MUST be discarded.
return errors.New("Unrecognized VRRPv2 type field.")
}
v.VirtualRtrID = data[1]
v.Priority = data[2]
v.CountIPAddr = data[3]
if v.CountIPAddr < 1 {
return errors.New("VRRPv2 number of IP addresses is not valid.")
}
v.AuthType = VRRPv2AuthType(data[4])
v.AdverInt = uint8(data[5])
v.Checksum = binary.BigEndian.Uint16(data[6:8])
// populate the IPAddress field. The number of addresses is specified in the v.CountIPAddr field
// offset references the starting byte containing the list of ip addresses
offset := 8
for i := uint8(0); i < v.CountIPAddr; i++ {
v.IPAddress = append(v.IPAddress, data[offset:offset+4])
offset += 4
}
// any trailing packets here may be authentication data and *should* be ignored in v2 as per RFC
//
// 5.3.10. Authentication Data
//
// The authentication string is currently only used to maintain
// backwards compatibility with RFC 2338. It SHOULD be set to zero on
// transmission and ignored on reception.
return nil
}
// CanDecode specifies the layer type in which we are attempting to unwrap.
func (v *VRRPv2) CanDecode() gopacket.LayerClass {
return LayerTypeVRRP
}
// NextLayerType specifies the next layer that should be decoded. VRRP does not contain any further payload, so we set to 0
func (v *VRRPv2) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypeZero
}
// The VRRP packet does not include payload data. Setting byte slice to nil
func (v *VRRPv2) Payload() []byte {
return nil
}
// decodeVRRP will parse VRRP v2
func decodeVRRP(data []byte, p gopacket.PacketBuilder) error {
if len(data) < 8 {
return errors.New("Not a valid VRRP packet. Packet length is too small.")
}
v := &VRRPv2{}
return decodingLayerDecoder(v, data, p)
}
// Copyright 2016 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package layers
import (
"encoding/binary"
"errors"
"fmt"
"github.com/google/gopacket"
)
// VXLAN is specifed in RFC 7348 https://tools.ietf.org/html/rfc7348
// G, D, A, Group Policy ID from https://tools.ietf.org/html/draft-smith-vxlan-group-policy-00
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// 0 8 16 24 32
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |G|R|R|R|I|R|R|R|R|D|R|R|A|R|R|R| Group Policy ID |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | 24 bit VXLAN Network Identifier | Reserved |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// VXLAN is a VXLAN packet header
type VXLAN struct {
BaseLayer
ValidIDFlag bool // 'I' bit per RFC 7348
VNI uint32 // 'VXLAN Network Identifier' 24 bits per RFC 7348
GBPExtension bool // 'G' bit per Group Policy https://tools.ietf.org/html/draft-smith-vxlan-group-policy-00
GBPDontLearn bool // 'D' bit per Group Policy
GBPApplied bool // 'A' bit per Group Policy
GBPGroupPolicyID uint16 // 'Group Policy ID' 16 bits per Group Policy
}
// LayerType returns LayerTypeVXLAN
func (vx *VXLAN) LayerType() gopacket.LayerType { return LayerTypeVXLAN }
// CanDecode returns the layer type this DecodingLayer can decode
func (vx *VXLAN) CanDecode() gopacket.LayerClass {
return LayerTypeVXLAN
}
// NextLayerType retuns the next layer we should see after vxlan
func (vx *VXLAN) NextLayerType() gopacket.LayerType {
return LayerTypeEthernet
}
// DecodeFromBytes takes a byte buffer and decodes
func (vx *VXLAN) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 8 {
return errors.New("vxlan packet too small")
}
// VNI is a 24bit number, Uint32 requires 32 bits
var buf [4]byte
copy(buf[1:], data[4:7])
// RFC 7348 https://tools.ietf.org/html/rfc7348
vx.ValidIDFlag = data[0]&0x08 > 0 // 'I' bit per RFC7348
vx.VNI = binary.BigEndian.Uint32(buf[:]) // VXLAN Network Identifier per RFC7348
// Group Based Policy https://tools.ietf.org/html/draft-smith-vxlan-group-policy-00
vx.GBPExtension = data[0]&0x80 > 0 // 'G' bit per the group policy draft
vx.GBPDontLearn = data[1]&0x40 > 0 // 'D' bit - the egress VTEP MUST NOT learn the source address of the encapsulated frame.
vx.GBPApplied = data[1]&0x80 > 0 // 'A' bit - indicates that the group policy has already been applied to this packet.
vx.GBPGroupPolicyID = binary.BigEndian.Uint16(data[2:4]) // Policy ID as per the group policy draft
// Layer information
const vxlanLength = 8
vx.Contents = data[:vxlanLength]
vx.Payload = data[vxlanLength:]
return nil
}
func decodeVXLAN(data []byte, p gopacket.PacketBuilder) error {
vx := &VXLAN{}
err := vx.DecodeFromBytes(data, p)
if err != nil {
return err
}
p.AddLayer(vx)
return p.NextDecoder(LinkTypeEthernet)
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (vx *VXLAN) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
bytes, err := b.PrependBytes(8)
if err != nil {
return err
}
// PrependBytes does not guarantee that bytes are zeroed. Setting flags via OR requires that they start off at zero
bytes[0] = 0
bytes[1] = 0
if vx.ValidIDFlag {
bytes[0] |= 0x08
}
if vx.GBPExtension {
bytes[0] |= 0x80
}
if vx.GBPDontLearn {
bytes[1] |= 0x40
}
if vx.GBPApplied {
bytes[1] |= 0x80
}
binary.BigEndian.PutUint16(bytes[2:4], vx.GBPGroupPolicyID)
if vx.VNI >= 1<<24 {
return fmt.Errorf("Virtual Network Identifier = %x exceeds max for 24-bit uint", vx.VNI)
}
binary.BigEndian.PutUint32(bytes[4:8], vx.VNI<<8)
return nil
}
// Copyright 2019 The GoPacket Authors. All rights reserved.
package gopacket
// Created by gen.go, don't edit manually
// Generated at 2019-06-18 11:37:31.308731293 +0600 +06 m=+0.000842599
// LayersDecoder returns DecodingLayerFunc for specified
// DecodingLayerContainer, LayerType value to start decoding with and
// some DecodeFeedback.
func LayersDecoder(dl DecodingLayerContainer, first LayerType, df DecodeFeedback) DecodingLayerFunc {
firstDec, ok := dl.Decoder(first)
if !ok {
return func([]byte, *[]LayerType) (LayerType, error) {
return first, nil
}
}
if dlc, ok := dl.(DecodingLayerSparse); ok {
return func(data []byte, decoded *[]LayerType) (LayerType, error) {
*decoded = (*decoded)[:0] // Truncated decoded layers.
typ := first
decoder := firstDec
for {
if err := decoder.DecodeFromBytes(data, df); err != nil {
return LayerTypeZero, err
}
*decoded = append(*decoded, typ)
typ = decoder.NextLayerType()
if data = decoder.LayerPayload(); len(data) == 0 {
break
}
if decoder, ok = dlc.Decoder(typ); !ok {
return typ, nil
}
}
return LayerTypeZero, nil
}
}
if dlc, ok := dl.(DecodingLayerArray); ok {
return func(data []byte, decoded *[]LayerType) (LayerType, error) {
*decoded = (*decoded)[:0] // Truncated decoded layers.
typ := first
decoder := firstDec
for {
if err := decoder.DecodeFromBytes(data, df); err != nil {
return LayerTypeZero, err
}
*decoded = append(*decoded, typ)
typ = decoder.NextLayerType()
if data = decoder.LayerPayload(); len(data) == 0 {
break
}
if decoder, ok = dlc.Decoder(typ); !ok {
return typ, nil
}
}
return LayerTypeZero, nil
}
}
if dlc, ok := dl.(DecodingLayerMap); ok {
return func(data []byte, decoded *[]LayerType) (LayerType, error) {
*decoded = (*decoded)[:0] // Truncated decoded layers.
typ := first
decoder := firstDec
for {
if err := decoder.DecodeFromBytes(data, df); err != nil {
return LayerTypeZero, err
}
*decoded = append(*decoded, typ)
typ = decoder.NextLayerType()
if data = decoder.LayerPayload(); len(data) == 0 {
break
}
if decoder, ok = dlc.Decoder(typ); !ok {
return typ, nil
}
}
return LayerTypeZero, nil
}
}
dlc := dl
return func(data []byte, decoded *[]LayerType) (LayerType, error) {
*decoded = (*decoded)[:0] // Truncated decoded layers.
typ := first
decoder := firstDec
for {
if err := decoder.DecodeFromBytes(data, df); err != nil {
return LayerTypeZero, err
}
*decoded = append(*decoded, typ)
typ = decoder.NextLayerType()
if data = decoder.LayerPayload(); len(data) == 0 {
break
}
if decoder, ok = dlc.Decoder(typ); !ok {
return typ, nil
}
}
return LayerTypeZero, nil
}
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package gopacket
import (
"fmt"
"strconv"
)
// LayerType is a unique identifier for each type of layer. This enumeration
// does not match with any externally available numbering scheme... it's solely
// usable/useful within this library as a means for requesting layer types
// (see Packet.Layer) and determining which types of layers have been decoded.
//
// New LayerTypes may be created by calling gopacket.RegisterLayerType.
type LayerType int64
// LayerTypeMetadata contains metadata associated with each LayerType.
type LayerTypeMetadata struct {
// Name is the string returned by each layer type's String method.
Name string
// Decoder is the decoder to use when the layer type is passed in as a
// Decoder.
Decoder Decoder
}
type layerTypeMetadata struct {
inUse bool
LayerTypeMetadata
}
// DecodersByLayerName maps layer names to decoders for those layers.
// This allows users to specify decoders by name to a program and have that
// program pick the correct decoder accordingly.
var DecodersByLayerName = map[string]Decoder{}
const maxLayerType = 2000
var ltMeta [maxLayerType]layerTypeMetadata
var ltMetaMap = map[LayerType]layerTypeMetadata{}
// RegisterLayerType creates a new layer type and registers it globally.
// The number passed in must be unique, or a runtime panic will occur. Numbers
// 0-999 are reserved for the gopacket library. Numbers 1000-1999 should be
// used for common application-specific types, and are very fast. Any other
// number (negative or >= 2000) may be used for uncommon application-specific
// types, and are somewhat slower (they require a map lookup over an array
// index).
func RegisterLayerType(num int, meta LayerTypeMetadata) LayerType {
if 0 <= num && num < maxLayerType {
if ltMeta[num].inUse {
panic("Layer type already exists")
}
} else {
if ltMetaMap[LayerType(num)].inUse {
panic("Layer type already exists")
}
}
return OverrideLayerType(num, meta)
}
// OverrideLayerType acts like RegisterLayerType, except that if the layer type
// has already been registered, it overrides the metadata with the passed-in
// metadata intead of panicing.
func OverrideLayerType(num int, meta LayerTypeMetadata) LayerType {
if 0 <= num && num < maxLayerType {
ltMeta[num] = layerTypeMetadata{
inUse: true,
LayerTypeMetadata: meta,
}
} else {
ltMetaMap[LayerType(num)] = layerTypeMetadata{
inUse: true,
LayerTypeMetadata: meta,
}
}
DecodersByLayerName[meta.Name] = meta.Decoder
return LayerType(num)
}
// Decode decodes the given data using the decoder registered with the layer
// type.
func (t LayerType) Decode(data []byte, c PacketBuilder) error {
var d Decoder
if 0 <= int(t) && int(t) < maxLayerType {
d = ltMeta[int(t)].Decoder
} else {
d = ltMetaMap[t].Decoder
}
if d != nil {
return d.Decode(data, c)
}
return fmt.Errorf("Layer type %v has no associated decoder", t)
}
// String returns the string associated with this layer type.
func (t LayerType) String() (s string) {
if 0 <= int(t) && int(t) < maxLayerType {
s = ltMeta[int(t)].Name
} else {
s = ltMetaMap[t].Name
}
if s == "" {
s = strconv.Itoa(int(t))
}
return
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package gopacket
import (
"bytes"
"encoding/hex"
"errors"
"fmt"
"io"
"net"
"os"
"reflect"
"runtime/debug"
"strings"
"syscall"
"time"
)
// CaptureInfo provides standardized information about a packet captured off
// the wire or read from a file.
type CaptureInfo struct {
// Timestamp is the time the packet was captured, if that is known.
Timestamp time.Time
// CaptureLength is the total number of bytes read off of the wire.
CaptureLength int
// Length is the size of the original packet. Should always be >=
// CaptureLength.
Length int
// InterfaceIndex
InterfaceIndex int
// The packet source can place ancillary data of various types here.
// For example, the afpacket source can report the VLAN of captured
// packets this way.
AncillaryData []interface{}
}
// PacketMetadata contains metadata for a packet.
type PacketMetadata struct {
CaptureInfo
// Truncated is true if packet decoding logic detects that there are fewer
// bytes in the packet than are detailed in various headers (for example, if
// the number of bytes in the IPv4 contents/payload is less than IPv4.Length).
// This is also set automatically for packets captured off the wire if
// CaptureInfo.CaptureLength < CaptureInfo.Length.
Truncated bool
}
// 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
// is broken into a number of Layers as it is decoded.
type Packet interface {
//// Functions for outputting the packet as a human-readable string:
//// ------------------------------------------------------------------
// String returns a human-readable string representation of the packet.
// It uses LayerString on each layer to output the layer.
String() string
// Dump returns a verbose human-readable string representation of the packet,
// including a hex dump of all layers. It uses LayerDump on each layer to
// output the layer.
Dump() string
//// Functions for accessing arbitrary packet layers:
//// ------------------------------------------------------------------
// Layers returns all layers in this packet, computing them as necessary
Layers() []Layer
// Layer returns the first layer in this packet of the given type, or nil
Layer(LayerType) Layer
// LayerClass returns the first layer in this packet of the given class,
// or nil.
LayerClass(LayerClass) Layer
//// Functions for accessing specific types of packet layers. These functions
//// return the first layer of each type found within the packet.
//// ------------------------------------------------------------------
// LinkLayer returns the first link layer in the packet
LinkLayer() LinkLayer
// NetworkLayer returns the first network layer in the packet
NetworkLayer() NetworkLayer
// TransportLayer returns the first transport layer in the packet
TransportLayer() TransportLayer
// ApplicationLayer returns the first application layer in the packet
ApplicationLayer() ApplicationLayer
// ErrorLayer is particularly useful, since it returns nil if the packet
// was fully decoded successfully, and non-nil if an error was encountered
// in decoding and the packet was only partially decoded. Thus, its output
// can be used to determine if the entire packet was able to be decoded.
ErrorLayer() ErrorLayer
//// Functions for accessing data specific to the packet:
//// ------------------------------------------------------------------
// Data returns the set of bytes that make up this entire packet.
Data() []byte
// Metadata returns packet metadata associated with this packet.
Metadata() *PacketMetadata
}
// packet contains all the information we need to fulfill the Packet interface,
// and its two "subclasses" (yes, no such thing in Go, bear with me),
// eagerPacket and lazyPacket, provide eager and lazy decoding logic around the
// various functions needed to access this information.
type packet struct {
// data contains the entire packet data for a packet
data []byte
// initialLayers is space for an initial set of layers already created inside
// the packet.
initialLayers [6]Layer
// layers contains each layer we've already decoded
layers []Layer
// last is the last layer added to the packet
last Layer
// metadata is the PacketMetadata for this packet
metadata PacketMetadata
decodeOptions DecodeOptions
// Pointers to the various important layers
link LinkLayer
network NetworkLayer
transport TransportLayer
application ApplicationLayer
failure ErrorLayer
}
func (p *packet) SetTruncated() {
p.metadata.Truncated = true
}
func (p *packet) SetLinkLayer(l LinkLayer) {
if p.link == nil {
p.link = l
}
}
func (p *packet) SetNetworkLayer(l NetworkLayer) {
if p.network == nil {
p.network = l
}
}
func (p *packet) SetTransportLayer(l TransportLayer) {
if p.transport == nil {
p.transport = l
}
}
func (p *packet) SetApplicationLayer(l ApplicationLayer) {
if p.application == nil {
p.application = l
}
}
func (p *packet) SetErrorLayer(l ErrorLayer) {
if p.failure == nil {
p.failure = l
}
}
func (p *packet) AddLayer(l Layer) {
p.layers = append(p.layers, l)
p.last = l
}
func (p *packet) DumpPacketData() {
fmt.Fprint(os.Stderr, p.packetDump())
os.Stderr.Sync()
}
func (p *packet) Metadata() *PacketMetadata {
return &p.metadata
}
func (p *packet) Data() []byte {
return p.data
}
func (p *packet) DecodeOptions() *DecodeOptions {
return &p.decodeOptions
}
func (p *packet) addFinalDecodeError(err error, stack []byte) {
fail := &DecodeFailure{err: err, stack: stack}
if p.last == nil {
fail.data = p.data
} else {
fail.data = p.last.LayerPayload()
}
p.AddLayer(fail)
p.SetErrorLayer(fail)
}
func (p *packet) recoverDecodeError() {
if !p.decodeOptions.SkipDecodeRecovery {
if r := recover(); r != nil {
p.addFinalDecodeError(fmt.Errorf("%v", r), debug.Stack())
}
}
}
// LayerString outputs an individual layer as a string. The layer is output
// in a single line, with no trailing newline. This function is specifically
// designed to do the right thing for most layers... it follows the following
// rules:
// * If the Layer has a String function, just output that.
// * Otherwise, output all exported fields in the layer, recursing into
// exported slices and structs.
// NOTE: This is NOT THE SAME AS fmt's "%#v". %#v will output both exported
// and unexported fields... many times packet layers contain unexported stuff
// that would just mess up the output of the layer, see for example the
// Payload layer and it's internal 'data' field, which contains a large byte
// array that would really mess up formatting.
func LayerString(l Layer) string {
return fmt.Sprintf("%v\t%s", l.LayerType(), layerString(reflect.ValueOf(l), false, false))
}
// Dumper dumps verbose information on a value. If a layer type implements
// Dumper, then its LayerDump() string will include the results in its output.
type Dumper interface {
Dump() string
}
// LayerDump outputs a very verbose string representation of a layer. Its
// output is a concatenation of LayerString(l) and hex.Dump(l.LayerContents()).
// It contains newlines and ends with a newline.
func LayerDump(l Layer) string {
var b bytes.Buffer
b.WriteString(LayerString(l))
b.WriteByte('\n')
if d, ok := l.(Dumper); ok {
dump := d.Dump()
if dump != "" {
b.WriteString(dump)
if dump[len(dump)-1] != '\n' {
b.WriteByte('\n')
}
}
}
b.WriteString(hex.Dump(l.LayerContents()))
return b.String()
}
// layerString outputs, recursively, a layer in a "smart" way. See docs for
// LayerString for more details.
//
// Params:
// i - value to write out
// anonymous: if we're currently recursing an anonymous member of a struct
// writeSpace: if we've already written a value in a struct, and need to
// write a space before writing more. This happens when we write various
// anonymous values, and need to keep writing more.
func layerString(v reflect.Value, anonymous bool, writeSpace bool) string {
// Let String() functions take precedence.
if v.CanInterface() {
if s, ok := v.Interface().(fmt.Stringer); ok {
return s.String()
}
}
// Reflect, and spit out all the exported fields as key=value.
switch v.Type().Kind() {
case reflect.Interface, reflect.Ptr:
if v.IsNil() {
return "nil"
}
r := v.Elem()
return layerString(r, anonymous, writeSpace)
case reflect.Struct:
var b bytes.Buffer
typ := v.Type()
if !anonymous {
b.WriteByte('{')
}
for i := 0; i < v.NumField(); i++ {
// Check if this is upper-case.
ftype := typ.Field(i)
f := v.Field(i)
if ftype.Anonymous {
anonStr := layerString(f, true, writeSpace)
writeSpace = writeSpace || anonStr != ""
b.WriteString(anonStr)
} else if ftype.PkgPath == "" { // exported
if writeSpace {
b.WriteByte(' ')
}
writeSpace = true
fmt.Fprintf(&b, "%s=%s", typ.Field(i).Name, layerString(f, false, writeSpace))
}
}
if !anonymous {
b.WriteByte('}')
}
return b.String()
case reflect.Slice:
var b bytes.Buffer
b.WriteByte('[')
if v.Len() > 4 {
fmt.Fprintf(&b, "..%d..", v.Len())
} else {
for j := 0; j < v.Len(); j++ {
if j != 0 {
b.WriteString(", ")
}
b.WriteString(layerString(v.Index(j), false, false))
}
}
b.WriteByte(']')
return b.String()
}
return fmt.Sprintf("%v", v.Interface())
}
const (
longBytesLength = 128
)
// LongBytesGoString returns a string representation of the byte slice shortened
// using the format '<type>{<truncated slice> ... (<n> bytes)}' if it
// exceeds a predetermined length. Can be used to avoid filling the display with
// very long byte strings.
func LongBytesGoString(buf []byte) string {
if len(buf) < longBytesLength {
return fmt.Sprintf("%#v", buf)
}
s := fmt.Sprintf("%#v", buf[:longBytesLength-1])
s = strings.TrimSuffix(s, "}")
return fmt.Sprintf("%s ... (%d bytes)}", s, len(buf))
}
func baseLayerString(value reflect.Value) string {
t := value.Type()
content := value.Field(0)
c := make([]byte, content.Len())
for i := range c {
c[i] = byte(content.Index(i).Uint())
}
payload := value.Field(1)
p := make([]byte, payload.Len())
for i := range p {
p[i] = byte(payload.Index(i).Uint())
}
return fmt.Sprintf("%s{Contents:%s, Payload:%s}", t.String(),
LongBytesGoString(c),
LongBytesGoString(p))
}
func layerGoString(i interface{}, b *bytes.Buffer) {
if s, ok := i.(fmt.GoStringer); ok {
b.WriteString(s.GoString())
return
}
var v reflect.Value
var ok bool
if v, ok = i.(reflect.Value); !ok {
v = reflect.ValueOf(i)
}
switch v.Kind() {
case reflect.Ptr, reflect.Interface:
if v.Kind() == reflect.Ptr {
b.WriteByte('&')
}
layerGoString(v.Elem().Interface(), b)
case reflect.Struct:
t := v.Type()
b.WriteString(t.String())
b.WriteByte('{')
for i := 0; i < v.NumField(); i++ {
if i > 0 {
b.WriteString(", ")
}
if t.Field(i).Name == "BaseLayer" {
fmt.Fprintf(b, "BaseLayer:%s", baseLayerString(v.Field(i)))
} else if v.Field(i).Kind() == reflect.Struct {
fmt.Fprintf(b, "%s:", t.Field(i).Name)
layerGoString(v.Field(i), b)
} else if v.Field(i).Kind() == reflect.Ptr {
b.WriteByte('&')
layerGoString(v.Field(i), b)
} else {
fmt.Fprintf(b, "%s:%#v", t.Field(i).Name, v.Field(i))
}
}
b.WriteByte('}')
default:
fmt.Fprintf(b, "%#v", i)
}
}
// LayerGoString returns a representation of the layer in Go syntax,
// taking care to shorten "very long" BaseLayer byte slices
func LayerGoString(l Layer) string {
b := new(bytes.Buffer)
layerGoString(l, b)
return b.String()
}
func (p *packet) packetString() string {
var b bytes.Buffer
fmt.Fprintf(&b, "PACKET: %d bytes", len(p.Data()))
if p.metadata.Truncated {
b.WriteString(", truncated")
}
if p.metadata.Length > 0 {
fmt.Fprintf(&b, ", wire length %d cap length %d", p.metadata.Length, p.metadata.CaptureLength)
}
if !p.metadata.Timestamp.IsZero() {
fmt.Fprintf(&b, " @ %v", p.metadata.Timestamp)
}
b.WriteByte('\n')
for i, l := range p.layers {
fmt.Fprintf(&b, "- Layer %d (%02d bytes) = %s\n", i+1, len(l.LayerContents()), LayerString(l))
}
return b.String()
}
func (p *packet) packetDump() string {
var b bytes.Buffer
fmt.Fprintf(&b, "-- FULL PACKET DATA (%d bytes) ------------------------------------\n%s", len(p.data), hex.Dump(p.data))
for i, l := range p.layers {
fmt.Fprintf(&b, "--- Layer %d ---\n%s", i+1, LayerDump(l))
}
return b.String()
}
// eagerPacket is a packet implementation that does eager decoding. Upon
// initial construction, it decodes all the layers it can from packet data.
// eagerPacket implements Packet and PacketBuilder.
type eagerPacket struct {
packet
}
var errNilDecoder = errors.New("NextDecoder passed nil decoder, probably an unsupported decode type")
func (p *eagerPacket) NextDecoder(next Decoder) error {
if next == nil {
return errNilDecoder
}
if p.last == nil {
return errors.New("NextDecoder called, but no layers added yet")
}
d := p.last.LayerPayload()
if len(d) == 0 {
return nil
}
// Since we're eager, immediately call the next decoder.
return next.Decode(d, p)
}
func (p *eagerPacket) initialDecode(dec Decoder) {
defer p.recoverDecodeError()
err := dec.Decode(p.data, p)
if err != nil {
p.addFinalDecodeError(err, nil)
}
}
func (p *eagerPacket) LinkLayer() LinkLayer {
return p.link
}
func (p *eagerPacket) NetworkLayer() NetworkLayer {
return p.network
}
func (p *eagerPacket) TransportLayer() TransportLayer {
return p.transport
}
func (p *eagerPacket) ApplicationLayer() ApplicationLayer {
return p.application
}
func (p *eagerPacket) ErrorLayer() ErrorLayer {
return p.failure
}
func (p *eagerPacket) Layers() []Layer {
return p.layers
}
func (p *eagerPacket) Layer(t LayerType) Layer {
for _, l := range p.layers {
if l.LayerType() == t {
return l
}
}
return nil
}
func (p *eagerPacket) LayerClass(lc LayerClass) Layer {
for _, l := range p.layers {
if lc.Contains(l.LayerType()) {
return l
}
}
return nil
}
func (p *eagerPacket) String() string { return p.packetString() }
func (p *eagerPacket) Dump() string { return p.packetDump() }
// lazyPacket does lazy decoding on its packet data. On construction it does
// no initial decoding. For each function call, it decodes only as many layers
// as are necessary to compute the return value for that function.
// lazyPacket implements Packet and PacketBuilder.
type lazyPacket struct {
packet
next Decoder
}
func (p *lazyPacket) NextDecoder(next Decoder) error {
if next == nil {
return errNilDecoder
}
p.next = next
return nil
}
func (p *lazyPacket) decodeNextLayer() {
if p.next == nil {
return
}
d := p.data
if p.last != nil {
d = p.last.LayerPayload()
}
next := p.next
p.next = nil
// We've just set p.next to nil, so if we see we have no data, this should be
// the final call we get to decodeNextLayer if we return here.
if len(d) == 0 {
return
}
defer p.recoverDecodeError()
err := next.Decode(d, p)
if err != nil {
p.addFinalDecodeError(err, nil)
}
}
func (p *lazyPacket) LinkLayer() LinkLayer {
for p.link == nil && p.next != nil {
p.decodeNextLayer()
}
return p.link
}
func (p *lazyPacket) NetworkLayer() NetworkLayer {
for p.network == nil && p.next != nil {
p.decodeNextLayer()
}
return p.network
}
func (p *lazyPacket) TransportLayer() TransportLayer {
for p.transport == nil && p.next != nil {
p.decodeNextLayer()
}
return p.transport
}
func (p *lazyPacket) ApplicationLayer() ApplicationLayer {
for p.application == nil && p.next != nil {
p.decodeNextLayer()
}
return p.application
}
func (p *lazyPacket) ErrorLayer() ErrorLayer {
for p.failure == nil && p.next != nil {
p.decodeNextLayer()
}
return p.failure
}
func (p *lazyPacket) Layers() []Layer {
for p.next != nil {
p.decodeNextLayer()
}
return p.layers
}
func (p *lazyPacket) Layer(t LayerType) Layer {
for _, l := range p.layers {
if l.LayerType() == t {
return l
}
}
numLayers := len(p.layers)
for p.next != nil {
p.decodeNextLayer()
for _, l := range p.layers[numLayers:] {
if l.LayerType() == t {
return l
}
}
numLayers = len(p.layers)
}
return nil
}
func (p *lazyPacket) LayerClass(lc LayerClass) Layer {
for _, l := range p.layers {
if lc.Contains(l.LayerType()) {
return l
}
}
numLayers := len(p.layers)
for p.next != nil {
p.decodeNextLayer()
for _, l := range p.layers[numLayers:] {
if lc.Contains(l.LayerType()) {
return l
}
}
numLayers = len(p.layers)
}
return nil
}
func (p *lazyPacket) String() string { p.Layers(); return p.packetString() }
func (p *lazyPacket) Dump() string { p.Layers(); return p.packetDump() }
// DecodeOptions tells gopacket how to decode a packet.
type DecodeOptions struct {
// Lazy decoding decodes the minimum number of layers needed to return data
// for a packet at each function call. Be careful using this with concurrent
// packet processors, as each call to packet.* could mutate the packet, and
// two concurrent function calls could interact poorly.
Lazy bool
// NoCopy decoding doesn't copy its input buffer into storage that's owned by
// the packet. If you can guarantee that the bytes underlying the slice
// passed into NewPacket aren't going to be modified, this can be faster. If
// there's any chance that those bytes WILL be changed, this will invalidate
// your packets.
NoCopy bool
// SkipDecodeRecovery skips over panic recovery during packet decoding.
// Normally, when packets decode, if a panic occurs, that panic is captured
// by a recover(), and a DecodeFailure layer is added to the packet detailing
// the issue. If this flag is set, panics are instead allowed to continue up
// the stack.
SkipDecodeRecovery bool
// DecodeStreamsAsDatagrams enables routing of application-level layers in the TCP
// decoder. If true, we should try to decode layers after TCP in single packets.
// This is disabled by default because the reassembly package drives the decoding
// of TCP payload data after reassembly.
DecodeStreamsAsDatagrams bool
}
// Default decoding provides the safest (but slowest) method for decoding
// packets. It eagerly processes all layers (so it's concurrency-safe) and it
// copies its input buffer upon creation of the packet (so the packet remains
// valid if the underlying slice is modified. Both of these take time,
// though, so beware. If you can guarantee that the packet will only be used
// by one goroutine at a time, set Lazy decoding. If you can guarantee that
// the underlying slice won't change, set NoCopy decoding.
var Default = DecodeOptions{}
// Lazy is a DecodeOptions with just Lazy set.
var Lazy = DecodeOptions{Lazy: true}
// NoCopy is a DecodeOptions with just NoCopy set.
var NoCopy = DecodeOptions{NoCopy: true}
// DecodeStreamsAsDatagrams is a DecodeOptions with just DecodeStreamsAsDatagrams set.
var DecodeStreamsAsDatagrams = DecodeOptions{DecodeStreamsAsDatagrams: true}
// NewPacket creates a new Packet object from a set of bytes. The
// firstLayerDecoder tells it how to interpret the first layer from the bytes,
// future layers will be generated from that first layer automatically.
func NewPacket(data []byte, firstLayerDecoder Decoder, options DecodeOptions) Packet {
if !options.NoCopy {
dataCopy := make([]byte, len(data))
copy(dataCopy, data)
data = dataCopy
}
if options.Lazy {
p := &lazyPacket{
packet: packet{data: data, decodeOptions: options},
next: firstLayerDecoder,
}
p.layers = p.initialLayers[:0]
// Crazy craziness:
// If the following return statemet is REMOVED, and Lazy is FALSE, then
// eager packet processing becomes 17% FASTER. No, there is no logical
// explanation for this. However, it's such a hacky micro-optimization that
// we really can't rely on it. It appears to have to do with the size the
// compiler guesses for this function's stack space, since one symptom is
// that with the return statement in place, we more than double calls to
// runtime.morestack/runtime.lessstack. We'll hope the compiler gets better
// over time and we get this optimization for free. Until then, we'll have
// to live with slower packet processing.
return p
}
p := &eagerPacket{
packet: packet{data: data, decodeOptions: options},
}
p.layers = p.initialLayers[:0]
p.initialDecode(firstLayerDecoder)
return p
}
// PacketDataSource is an interface for some source of packet data. Users may
// create their own implementations, or use the existing implementations in
// gopacket/pcap (libpcap, allows reading from live interfaces or from
// pcap files) or gopacket/pfring (PF_RING, allows reading from live
// interfaces).
type PacketDataSource interface {
// ReadPacketData returns the next packet available from this data source.
// It returns:
// data: The bytes of an individual packet.
// ci: Metadata about the capture
// err: An error encountered while reading packet data. If err != nil,
// then data/ci will be ignored.
ReadPacketData() (data []byte, ci CaptureInfo, err error)
}
// ConcatFinitePacketDataSources returns a PacketDataSource that wraps a set
// of internal PacketDataSources, each of which will stop with io.EOF after
// reading a finite number of packets. The returned PacketDataSource will
// return all packets from the first finite source, followed by all packets from
// the second, etc. Once all finite sources have returned io.EOF, the returned
// source will as well.
func ConcatFinitePacketDataSources(pds ...PacketDataSource) PacketDataSource {
c := concat(pds)
return &c
}
type concat []PacketDataSource
func (c *concat) ReadPacketData() (data []byte, ci CaptureInfo, err error) {
for len(*c) > 0 {
data, ci, err = (*c)[0].ReadPacketData()
if err == io.EOF {
*c = (*c)[1:]
continue
}
return
}
return nil, CaptureInfo{}, io.EOF
}
// ZeroCopyPacketDataSource is an interface to pull packet data from sources
// that allow data to be returned without copying to a user-controlled buffer.
// It's very similar to PacketDataSource, except that the caller must be more
// careful in how the returned buffer is handled.
type ZeroCopyPacketDataSource interface {
// ZeroCopyReadPacketData returns the next packet available from this data source.
// It returns:
// data: The bytes of an individual packet. Unlike with
// PacketDataSource's ReadPacketData, the slice returned here points
// to a buffer owned by the data source. In particular, the bytes in
// this buffer may be changed by future calls to
// ZeroCopyReadPacketData. Do not use the returned buffer after
// subsequent ZeroCopyReadPacketData calls.
// ci: Metadata about the capture
// err: An error encountered while reading packet data. If err != nil,
// then data/ci will be ignored.
ZeroCopyReadPacketData() (data []byte, ci CaptureInfo, err error)
}
// PacketSource reads in packets from a PacketDataSource, decodes them, and
// returns them.
//
// There are currently two different methods for reading packets in through
// a PacketSource:
//
// Reading With Packets Function
//
// This method is the most convenient and easiest to code, but lacks
// flexibility. Packets returns a 'chan Packet', then asynchronously writes
// packets into that channel. Packets uses a blocking channel, and closes
// it if an io.EOF is returned by the underlying PacketDataSource. All other
// PacketDataSource errors are ignored and discarded.
// for packet := range packetSource.Packets() {
// ...
// }
//
// Reading With NextPacket Function
//
// This method is the most flexible, and exposes errors that may be
// encountered by the underlying PacketDataSource. It's also the fastest
// in a tight loop, since it doesn't have the overhead of a channel
// read/write. However, it requires the user to handle errors, most
// importantly the io.EOF error in cases where packets are being read from
// a file.
// for {
// packet, err := packetSource.NextPacket()
// if err == io.EOF {
// break
// } else if err != nil {
// log.Println("Error:", err)
// continue
// }
// handlePacket(packet) // Do something with each packet.
// }
type PacketSource struct {
source PacketDataSource
decoder Decoder
// DecodeOptions is the set of options to use for decoding each piece
// of packet data. This can/should be changed by the user to reflect the
// way packets should be decoded.
DecodeOptions
c chan Packet
}
// NewPacketSource creates a packet data source.
func NewPacketSource(source PacketDataSource, decoder Decoder) *PacketSource {
return &PacketSource{
source: source,
decoder: decoder,
}
}
// NextPacket returns the next decoded packet from the PacketSource. On error,
// it returns a nil packet and a non-nil error.
func (p *PacketSource) NextPacket() (Packet, error) {
data, ci, err := p.source.ReadPacketData()
if err != nil {
return nil, err
}
packet := NewPacket(data, p.decoder, p.DecodeOptions)
m := packet.Metadata()
m.CaptureInfo = ci
m.Truncated = m.Truncated || ci.CaptureLength < ci.Length
return packet, nil
}
// packetsToChannel reads in all packets from the packet source and sends them
// to the given channel. This routine terminates when a non-temporary error
// is returned by NextPacket().
func (p *PacketSource) packetsToChannel() {
defer close(p.c)
for {
packet, err := p.NextPacket()
if err == nil {
p.c <- packet
continue
}
// Immediately retry for temporary network errors
if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
continue
}
// Immediately retry for EAGAIN
if err == syscall.EAGAIN {
continue
}
// Immediately break for known unrecoverable errors
if err == io.EOF || err == io.ErrUnexpectedEOF ||
err == io.ErrNoProgress || err == io.ErrClosedPipe || err == io.ErrShortBuffer ||
err == syscall.EBADF ||
strings.Contains(err.Error(), "use of closed file") {
break
}
// Sleep briefly and try again
time.Sleep(time.Millisecond * time.Duration(5))
}
}
// Packets returns a channel of packets, allowing easy iterating over
// packets. Packets will be asynchronously read in from the underlying
// PacketDataSource and written to the returned channel. If the underlying
// PacketDataSource returns an io.EOF error, the channel will be closed.
// If any other error is encountered, it is ignored.
//
// for packet := range packetSource.Packets() {
// handlePacket(packet) // Do something with each packet.
// }
//
// If called more than once, returns the same channel.
func (p *PacketSource) Packets() chan Packet {
if p.c == nil {
p.c = make(chan Packet, 1000)
go p.packetsToChannel()
}
return p.c
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package gopacket
import (
"fmt"
)
// A container for single LayerType->DecodingLayer mapping.
type decodingLayerElem struct {
typ LayerType
dec DecodingLayer
}
// DecodingLayer is an interface for packet layers that can decode themselves.
//
// The important part of DecodingLayer is that they decode themselves in-place.
// Calling DecodeFromBytes on a DecodingLayer totally resets the entire layer to
// the new state defined by the data passed in. A returned error leaves the
// DecodingLayer in an unknown intermediate state, thus its fields should not be
// trusted.
//
// Because the DecodingLayer is resetting its own fields, a call to
// DecodeFromBytes should normally not require any memory allocation.
type DecodingLayer interface {
// DecodeFromBytes resets the internal state of this layer to the state
// defined by the passed-in bytes. Slices in the DecodingLayer may
// reference the passed-in data, so care should be taken to copy it
// first should later modification of data be required before the
// DecodingLayer is discarded.
DecodeFromBytes(data []byte, df DecodeFeedback) error
// CanDecode returns the set of LayerTypes this DecodingLayer can
// decode. For Layers that are also DecodingLayers, this will most
// often be that Layer's LayerType().
CanDecode() LayerClass
// NextLayerType returns the LayerType which should be used to decode
// the LayerPayload.
NextLayerType() LayerType
// LayerPayload is the set of bytes remaining to decode after a call to
// DecodeFromBytes.
LayerPayload() []byte
}
// DecodingLayerFunc decodes given packet and stores decoded LayerType
// values into specified slice. Returns either first encountered
// unsupported LayerType value or decoding error. In case of success,
// returns (LayerTypeZero, nil).
type DecodingLayerFunc func([]byte, *[]LayerType) (LayerType, error)
// DecodingLayerContainer stores all DecodingLayer-s and serves as a
// searching tool for DecodingLayerParser.
type DecodingLayerContainer interface {
// Put adds new DecodingLayer to container. The new instance of
// the same DecodingLayerContainer is returned so it may be
// implemented as a value receiver.
Put(DecodingLayer) DecodingLayerContainer
// Decoder returns DecodingLayer to decode given LayerType and
// true if it was found. If no decoder found, return false.
Decoder(LayerType) (DecodingLayer, bool)
// LayersDecoder returns DecodingLayerFunc which decodes given
// packet, starting with specified LayerType and DecodeFeedback.
LayersDecoder(first LayerType, df DecodeFeedback) DecodingLayerFunc
}
// DecodingLayerSparse is a sparse array-based implementation of
// DecodingLayerContainer. Each DecodingLayer is addressed in an
// allocated slice by LayerType value itself. Though this is the
// fastest container it may be memory-consuming if used with big
// LayerType values.
type DecodingLayerSparse []DecodingLayer
// Put implements DecodingLayerContainer interface.
func (dl DecodingLayerSparse) Put(d DecodingLayer) DecodingLayerContainer {
maxLayerType := LayerType(len(dl) - 1)
for _, typ := range d.CanDecode().LayerTypes() {
if typ > maxLayerType {
maxLayerType = typ
}
}
if extra := maxLayerType - LayerType(len(dl)) + 1; extra > 0 {
dl = append(dl, make([]DecodingLayer, extra)...)
}
for _, typ := range d.CanDecode().LayerTypes() {
dl[typ] = d
}
return dl
}
// LayersDecoder implements DecodingLayerContainer interface.
func (dl DecodingLayerSparse) LayersDecoder(first LayerType, df DecodeFeedback) DecodingLayerFunc {
return LayersDecoder(dl, first, df)
}
// Decoder implements DecodingLayerContainer interface.
func (dl DecodingLayerSparse) Decoder(typ LayerType) (DecodingLayer, bool) {
if int64(typ) < int64(len(dl)) {
decoder := dl[typ]
return decoder, decoder != nil
}
return nil, false
}
// DecodingLayerArray is an array-based implementation of
// DecodingLayerContainer. Each DecodingLayer is searched linearly in
// an allocated slice in one-by-one fashion.
type DecodingLayerArray []decodingLayerElem
// Put implements DecodingLayerContainer interface.
func (dl DecodingLayerArray) Put(d DecodingLayer) DecodingLayerContainer {
TYPES:
for _, typ := range d.CanDecode().LayerTypes() {
for i := range dl {
if dl[i].typ == typ {
dl[i].dec = d
continue TYPES
}
}
dl = append(dl, decodingLayerElem{typ, d})
}
return dl
}
// Decoder implements DecodingLayerContainer interface.
func (dl DecodingLayerArray) Decoder(typ LayerType) (DecodingLayer, bool) {
for i := range dl {
if dl[i].typ == typ {
return dl[i].dec, true
}
}
return nil, false
}
// LayersDecoder implements DecodingLayerContainer interface.
func (dl DecodingLayerArray) LayersDecoder(first LayerType, df DecodeFeedback) DecodingLayerFunc {
return LayersDecoder(dl, first, df)
}
// DecodingLayerMap is an map-based implementation of
// DecodingLayerContainer. Each DecodingLayer is searched in a map
// hashed by LayerType value.
type DecodingLayerMap map[LayerType]DecodingLayer
// Put implements DecodingLayerContainer interface.
func (dl DecodingLayerMap) Put(d DecodingLayer) DecodingLayerContainer {
for _, typ := range d.CanDecode().LayerTypes() {
if dl == nil {
dl = make(map[LayerType]DecodingLayer)
}
dl[typ] = d
}
return dl
}
// Decoder implements DecodingLayerContainer interface.
func (dl DecodingLayerMap) Decoder(typ LayerType) (DecodingLayer, bool) {
d, ok := dl[typ]
return d, ok
}
// LayersDecoder implements DecodingLayerContainer interface.
func (dl DecodingLayerMap) LayersDecoder(first LayerType, df DecodeFeedback) DecodingLayerFunc {
return LayersDecoder(dl, first, df)
}
// Static code check.
var (
_ = []DecodingLayerContainer{
DecodingLayerSparse(nil),
DecodingLayerMap(nil),
DecodingLayerArray(nil),
}
)
// DecodingLayerParser parses a given set of layer types. See DecodeLayers for
// more information on how DecodingLayerParser should be used.
type DecodingLayerParser struct {
// DecodingLayerParserOptions is the set of options available to the
// user to define the parser's behavior.
DecodingLayerParserOptions
dlc DecodingLayerContainer
first LayerType
df DecodeFeedback
decodeFunc DecodingLayerFunc
// Truncated is set when a decode layer detects that the packet has been
// truncated.
Truncated bool
}
// AddDecodingLayer adds a decoding layer to the parser. This adds support for
// the decoding layer's CanDecode layers to the parser... should they be
// encountered, they'll be parsed.
func (l *DecodingLayerParser) AddDecodingLayer(d DecodingLayer) {
l.SetDecodingLayerContainer(l.dlc.Put(d))
}
// SetTruncated is used by DecodingLayers to set the Truncated boolean in the
// DecodingLayerParser. Users should simply read Truncated after calling
// DecodeLayers.
func (l *DecodingLayerParser) SetTruncated() {
l.Truncated = true
}
// NewDecodingLayerParser creates a new DecodingLayerParser and adds in all
// of the given DecodingLayers with AddDecodingLayer.
//
// Each call to DecodeLayers will attempt to decode the given bytes first by
// treating them as a 'first'-type layer, then by using NextLayerType on
// subsequently decoded layers to find the next relevant decoder. Should a
// deoder not be available for the layer type returned by NextLayerType,
// decoding will stop.
//
// NewDecodingLayerParser uses DecodingLayerMap container by
// default.
func NewDecodingLayerParser(first LayerType, decoders ...DecodingLayer) *DecodingLayerParser {
dlp := &DecodingLayerParser{first: first}
dlp.df = dlp // Cast this once to the interface
// default container
dlc := DecodingLayerContainer(DecodingLayerMap(make(map[LayerType]DecodingLayer)))
for _, d := range decoders {
dlc = dlc.Put(d)
}
dlp.SetDecodingLayerContainer(dlc)
return dlp
}
// SetDecodingLayerContainer specifies container with decoders. This
// call replaces all decoders already registered in given instance of
// DecodingLayerParser.
func (l *DecodingLayerParser) SetDecodingLayerContainer(dlc DecodingLayerContainer) {
l.dlc = dlc
l.decodeFunc = l.dlc.LayersDecoder(l.first, l.df)
}
// DecodeLayers decodes as many layers as possible from the given data. It
// initially treats the data as layer type 'typ', then uses NextLayerType on
// each subsequent decoded layer until it gets to a layer type it doesn't know
// how to parse.
//
// For each layer successfully decoded, DecodeLayers appends the layer type to
// the decoded slice. DecodeLayers truncates the 'decoded' slice initially, so
// there's no need to empty it yourself.
//
// This decoding method is about an order of magnitude faster than packet
// decoding, because it only decodes known layers that have already been
// allocated. This means it doesn't need to allocate each layer it returns...
// instead it overwrites the layers that already exist.
//
// Example usage:
// func main() {
// var eth layers.Ethernet
// var ip4 layers.IPv4
// var ip6 layers.IPv6
// var tcp layers.TCP
// var udp layers.UDP
// var payload gopacket.Payload
// parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, ð, &ip4, &ip6, &tcp, &udp, &payload)
// var source gopacket.PacketDataSource = getMyDataSource()
// decodedLayers := make([]gopacket.LayerType, 0, 10)
// for {
// data, _, err := source.ReadPacketData()
// if err != nil {
// fmt.Println("Error reading packet data: ", err)
// continue
// }
// fmt.Println("Decoding packet")
// err = parser.DecodeLayers(data, &decodedLayers)
// for _, typ := range decodedLayers {
// fmt.Println(" Successfully decoded layer type", typ)
// switch typ {
// case layers.LayerTypeEthernet:
// fmt.Println(" Eth ", eth.SrcMAC, eth.DstMAC)
// case layers.LayerTypeIPv4:
// fmt.Println(" IP4 ", ip4.SrcIP, ip4.DstIP)
// case layers.LayerTypeIPv6:
// fmt.Println(" IP6 ", ip6.SrcIP, ip6.DstIP)
// case layers.LayerTypeTCP:
// fmt.Println(" TCP ", tcp.SrcPort, tcp.DstPort)
// case layers.LayerTypeUDP:
// fmt.Println(" UDP ", udp.SrcPort, udp.DstPort)
// }
// }
// if decodedLayers.Truncated {
// fmt.Println(" Packet has been truncated")
// }
// if err != nil {
// fmt.Println(" Error encountered:", err)
// }
// }
// }
//
// If DecodeLayers is unable to decode the next layer type, it will return the
// error UnsupportedLayerType.
func (l *DecodingLayerParser) DecodeLayers(data []byte, decoded *[]LayerType) (err error) {
l.Truncated = false
if !l.IgnorePanic {
defer panicToError(&err)
}
typ, err := l.decodeFunc(data, decoded)
if typ != LayerTypeZero {
// no decoder
if l.IgnoreUnsupported {
return nil
}
return UnsupportedLayerType(typ)
}
return err
}
// UnsupportedLayerType is returned by DecodingLayerParser if DecodeLayers
// encounters a layer type that the DecodingLayerParser has no decoder for.
type UnsupportedLayerType LayerType
// Error implements the error interface, returning a string to say that the
// given layer type is unsupported.
func (e UnsupportedLayerType) Error() string {
return fmt.Sprintf("No decoder for layer type %v", LayerType(e))
}
func panicToError(e *error) {
if r := recover(); r != nil {
*e = fmt.Errorf("panic: %v", r)
}
}
// DecodingLayerParserOptions provides options to affect the behavior of a given
// DecodingLayerParser.
type DecodingLayerParserOptions struct {
// IgnorePanic determines whether a DecodingLayerParser should stop
// panics on its own (by returning them as an error from DecodeLayers)
// or should allow them to raise up the stack. Handling errors does add
// latency to the process of decoding layers, but is much safer for
// callers. IgnorePanic defaults to false, thus if the caller does
// nothing decode panics will be returned as errors.
IgnorePanic bool
// IgnoreUnsupported will stop parsing and return a nil error when it
// encounters a layer it doesn't have a parser for, instead of returning an
// UnsupportedLayerType error. If this is true, it's up to the caller to make
// sure that all expected layers have been parsed (by checking the decoded
// slice).
IgnoreUnsupported bool
}
// Copyright 2018 The GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package gopacket
import (
"fmt"
"math"
"time"
)
// TimestampResolution represents the resolution of timestamps in Base^Exponent.
type TimestampResolution struct {
Base, Exponent int
}
func (t TimestampResolution) String() string {
return fmt.Sprintf("%d^%d", t.Base, t.Exponent)
}
// ToDuration returns the smallest representable time difference as a time.Duration
func (t TimestampResolution) ToDuration() time.Duration {
if t.Base == 0 {
return 0
}
if t.Exponent == 0 {
return time.Second
}
switch t.Base {
case 10:
return time.Duration(math.Pow10(t.Exponent + 9))
case 2:
if t.Exponent < 0 {
return time.Second >> uint(-t.Exponent)
}
return time.Second << uint(t.Exponent)
default:
// this might loose precision
return time.Duration(float64(time.Second) * math.Pow(float64(t.Base), float64(t.Exponent)))
}
}
// TimestampResolutionInvalid represents an invalid timestamp resolution
var TimestampResolutionInvalid = TimestampResolution{}
// TimestampResolutionMillisecond is a resolution of 10^-3s
var TimestampResolutionMillisecond = TimestampResolution{10, -3}
// TimestampResolutionMicrosecond is a resolution of 10^-6s
var TimestampResolutionMicrosecond = TimestampResolution{10, -6}
// TimestampResolutionNanosecond is a resolution of 10^-9s
var TimestampResolutionNanosecond = TimestampResolution{10, -9}
// TimestampResolutionNTP is the resolution of NTP timestamps which is 2^-32 ≈ 233 picoseconds
var TimestampResolutionNTP = TimestampResolution{2, -32}
// TimestampResolutionCaptureInfo is the resolution used in CaptureInfo, which his currently nanosecond
var TimestampResolutionCaptureInfo = TimestampResolutionNanosecond
// PacketSourceResolution is an interface for packet data sources that
// support reporting the timestamp resolution of the aqcuired timestamps.
// Returned timestamps will always have NanosecondTimestampResolution due
// to the use of time.Time, but scaling might have occured if acquired
// timestamps have a different resolution.
type PacketSourceResolution interface {
// Resolution returns the timestamp resolution of acquired timestamps before scaling to NanosecondTimestampResolution.
Resolution() TimestampResolution
}
// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package gopacket
import (
"fmt"
)
// SerializableLayer allows its implementations to be written out as a set of bytes,
// so those bytes may be sent on the wire or otherwise used by the caller.
// SerializableLayer is implemented by certain Layer types, and can be encoded to
// bytes using the LayerWriter object.
type SerializableLayer interface {
// SerializeTo writes this layer to a slice, growing that slice if necessary
// to make it fit the layer's data.
// Args:
// b: SerializeBuffer to write this layer on to. When called, b.Bytes()
// is the payload this layer should wrap, if any. Note that this
// layer can either prepend itself (common), append itself
// (uncommon), or both (sometimes padding or footers are required at
// the end of packet data). It's also possible (though probably very
// rarely needed) to overwrite any bytes in the current payload.
// After this call, b.Bytes() should return the byte encoding of
// this layer wrapping the original b.Bytes() payload.
// opts: options to use while writing out data.
// Returns:
// error if a problem was encountered during encoding. If an error is
// returned, the bytes in data should be considered invalidated, and
// not used.
//
// SerializeTo calls SHOULD entirely ignore LayerContents and
// LayerPayload. It just serializes based on struct fields, neither
// modifying nor using contents/payload.
SerializeTo(b SerializeBuffer, opts SerializeOptions) error
// LayerType returns the type of the layer that is being serialized to the buffer
LayerType() LayerType
}
// SerializeOptions provides options for behaviors that SerializableLayers may want to
// implement.
type SerializeOptions struct {
// FixLengths determines whether, during serialization, layers should fix
// the values for any length field that depends on the payload.
FixLengths bool
// ComputeChecksums determines whether, during serialization, layers
// should recompute checksums based on their payloads.
ComputeChecksums bool
}
// SerializeBuffer is a helper used by gopacket for writing out packet layers.
// SerializeBuffer starts off as an empty []byte. Subsequent calls to PrependBytes
// return byte slices before the current Bytes(), AppendBytes returns byte
// slices after.
//
// Byte slices returned by PrependBytes/AppendBytes are NOT zero'd out, so if
// you want to make sure they're all zeros, set them as such.
//
// SerializeBuffer is specifically designed to handle packet writing, where unlike
// with normal writes it's easier to start writing at the inner-most layer and
// work out, meaning that we often need to prepend bytes. This runs counter to
// typical writes to byte slices using append(), where we only write at the end
// of the buffer.
//
// It can be reused via Clear. Note, however, that a Clear call will invalidate the
// byte slices returned by any previous Bytes() call (the same buffer is
// reused).
//
// 1) Reusing a write buffer is generally much faster than creating a new one,
// and with the default implementation it avoids additional memory allocations.
// 2) If a byte slice from a previous Bytes() call will continue to be used,
// it's better to create a new SerializeBuffer.
//
// The Clear method is specifically designed to minimize memory allocations for
// similar later workloads on the SerializeBuffer. IE: if you make a set of
// Prepend/Append calls, then clear, then make the same calls with the same
// sizes, the second round (and all future similar rounds) shouldn't allocate
// any new memory.
type SerializeBuffer interface {
// Bytes returns the contiguous set of bytes collected so far by Prepend/Append
// calls. The slice returned by Bytes will be modified by future Clear calls,
// so if you're planning on clearing this SerializeBuffer, you may want to copy
// Bytes somewhere safe first.
Bytes() []byte
// PrependBytes returns a set of bytes which prepends the current bytes in this
// buffer. These bytes start in an indeterminate state, so they should be
// overwritten by the caller. The caller must only call PrependBytes if they
// know they're going to immediately overwrite all bytes returned.
PrependBytes(num int) ([]byte, error)
// AppendBytes returns a set of bytes which appends the current bytes in this
// buffer. These bytes start in an indeterminate state, so they should be
// overwritten by the caller. The caller must only call AppendBytes if they
// know they're going to immediately overwrite all bytes returned.
AppendBytes(num int) ([]byte, error)
// Clear resets the SerializeBuffer to a new, empty buffer. After a call to clear,
// the byte slice returned by any previous call to Bytes() for this buffer
// should be considered invalidated.
Clear() error
// Layers returns all the Layers that have been successfully serialized into this buffer
// already.
Layers() []LayerType
// PushLayer adds the current Layer to the list of Layers that have been serialized
// into this buffer.
PushLayer(LayerType)
}
type serializeBuffer struct {
data []byte
start int
prepended, appended int
layers []LayerType
}
// NewSerializeBuffer creates a new instance of the default implementation of
// the SerializeBuffer interface.
func NewSerializeBuffer() SerializeBuffer {
return &serializeBuffer{}
}
// NewSerializeBufferExpectedSize creates a new buffer for serialization, optimized for an
// expected number of bytes prepended/appended. This tends to decrease the
// number of memory allocations made by the buffer during writes.
func NewSerializeBufferExpectedSize(expectedPrependLength, expectedAppendLength int) SerializeBuffer {
return &serializeBuffer{
data: make([]byte, expectedPrependLength, expectedPrependLength+expectedAppendLength),
start: expectedPrependLength,
prepended: expectedPrependLength,
appended: expectedAppendLength,
}
}
func (w *serializeBuffer) Bytes() []byte {
return w.data[w.start:]
}
func (w *serializeBuffer) PrependBytes(num int) ([]byte, error) {
if num < 0 {
panic("num < 0")
}
if w.start < num {
toPrepend := w.prepended
if toPrepend < num {
toPrepend = num
}
w.prepended += toPrepend
length := cap(w.data) + toPrepend
newData := make([]byte, length)
newStart := w.start + toPrepend
copy(newData[newStart:], w.data[w.start:])
w.start = newStart
w.data = newData[:toPrepend+len(w.data)]
}
w.start -= num
return w.data[w.start : w.start+num], nil
}
func (w *serializeBuffer) AppendBytes(num int) ([]byte, error) {
if num < 0 {
panic("num < 0")
}
initialLength := len(w.data)
if cap(w.data)-initialLength < num {
toAppend := w.appended
if toAppend < num {
toAppend = num
}
w.appended += toAppend
newData := make([]byte, cap(w.data)+toAppend)
copy(newData[w.start:], w.data[w.start:])
w.data = newData[:initialLength]
}
// Grow the buffer. We know it'll be under capacity given above.
w.data = w.data[:initialLength+num]
return w.data[initialLength:], nil
}
func (w *serializeBuffer) Clear() error {
w.start = w.prepended
w.data = w.data[:w.start]
w.layers = w.layers[:0]
return nil
}
func (w *serializeBuffer) Layers() []LayerType {
return w.layers
}
func (w *serializeBuffer) PushLayer(l LayerType) {
w.layers = append(w.layers, l)
}
// SerializeLayers clears the given write buffer, then writes all layers into it so
// they correctly wrap each other. Note that by clearing the buffer, it
// invalidates all slices previously returned by w.Bytes()
//
// Example:
// buf := gopacket.NewSerializeBuffer()
// opts := gopacket.SerializeOptions{}
// gopacket.SerializeLayers(buf, opts, a, b, c)
// firstPayload := buf.Bytes() // contains byte representation of a(b(c))
// gopacket.SerializeLayers(buf, opts, d, e, f)
// secondPayload := buf.Bytes() // contains byte representation of d(e(f)). firstPayload is now invalidated, since the SerializeLayers call Clears buf.
func SerializeLayers(w SerializeBuffer, opts SerializeOptions, layers ...SerializableLayer) error {
w.Clear()
for i := len(layers) - 1; i >= 0; i-- {
layer := layers[i]
err := layer.SerializeTo(w, opts)
if err != nil {
return err
}
w.PushLayer(layer.LayerType())
}
return nil
}
// SerializePacket is a convenience function that calls SerializeLayers
// on packet's Layers().
// It returns an error if one of the packet layers is not a SerializableLayer.
func SerializePacket(buf SerializeBuffer, opts SerializeOptions, packet Packet) error {
sls := []SerializableLayer{}
for _, layer := range packet.Layers() {
sl, ok := layer.(SerializableLayer)
if !ok {
return fmt.Errorf("layer %s is not serializable", layer.LayerType().String())
}
sls = append(sls, sl)
}
return SerializeLayers(buf, opts, sls...)
}