mirror of
https://github.com/weaveworks/scope.git
synced 2026-05-05 16:59:36 +00:00
We'd like to benefit from the memory reduction from: https://github.com/google/gopacket/pull/377 I just ran: $ gvt update github.com/google/gopacket Fixes: https://github.com/weaveworks/scope/issues/2905
510 lines
15 KiB
Go
510 lines
15 KiB
Go
// 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"
|
|
)
|
|
|
|
// 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 (
|
|
RouterLSAtype = 0x2001
|
|
NetworkLSAtype = 0x2002
|
|
InterAreaPrefixLSAtype = 0x2003
|
|
InterAreaRouterLSAtype = 0x2004
|
|
ASExternalLSAtype = 0x4005
|
|
NSSALSAtype = 0x2007
|
|
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
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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.
|
|
type LSAheader struct {
|
|
LSAge uint16
|
|
LSType uint16
|
|
LinkStateID uint32
|
|
AdvRouter uint32
|
|
LSSeqNumber uint32
|
|
LSChecksum uint16
|
|
Length uint16
|
|
}
|
|
|
|
// 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 uint16
|
|
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
|
|
}
|
|
|
|
// getLSAs parses the LSA information from the packet
|
|
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])
|
|
|
|
switch lstype {
|
|
case RouterLSAtype:
|
|
var routers []Router
|
|
var j uint32
|
|
for j = 24; j < uint32(lsalength); j += 16 {
|
|
router := Router{
|
|
Type: uint8(data[offset+j]),
|
|
Metric: binary.BigEndian.Uint16(data[offset+j+2 : offset+j+4]),
|
|
InterfaceID: binary.BigEndian.Uint32(data[offset+j+4 : offset+j+8]),
|
|
NeighborInterfaceID: binary.BigEndian.Uint32(data[offset+j+8 : offset+j+12]),
|
|
NeighborRouterID: binary.BigEndian.Uint32(data[offset+j+12 : offset+j+16]),
|
|
}
|
|
routers = append(routers, router)
|
|
}
|
|
content = RouterLSA{
|
|
Flags: uint8(data[offset+20]),
|
|
Options: binary.BigEndian.Uint32(data[offset+20:offset+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[offset+j:offset+j+4]))
|
|
}
|
|
content = NetworkLSA{
|
|
Options: binary.BigEndian.Uint32(data[offset+20:offset+24]) & 0x00FFFFFF,
|
|
AttachedRouter: routers,
|
|
}
|
|
case InterAreaPrefixLSAtype:
|
|
content = InterAreaPrefixLSA{
|
|
Metric: binary.BigEndian.Uint32(data[offset+20:offset+24]) & 0x00FFFFFF,
|
|
PrefixLength: uint8(data[offset+24]),
|
|
PrefixOptions: uint8(data[offset+25]),
|
|
AddressPrefix: data[offset+28 : offset+uint32(lsalength)],
|
|
}
|
|
case InterAreaRouterLSAtype:
|
|
content = InterAreaRouterLSA{
|
|
Options: binary.BigEndian.Uint32(data[offset+20:offset+24]) & 0x00FFFFFF,
|
|
Metric: binary.BigEndian.Uint32(data[offset+24:offset+28]) & 0x00FFFFFF,
|
|
DestinationRouterID: binary.BigEndian.Uint32(data[offset+28 : offset+32]),
|
|
}
|
|
case ASExternalLSAtype:
|
|
fallthrough
|
|
case NSSALSAtype:
|
|
|
|
flags := uint8(data[offset+20])
|
|
prefixLen := uint8(data[offset+24]) / 8
|
|
var forwardingAddress []byte
|
|
if (flags & 0x02) == 0x02 {
|
|
forwardingAddress = data[offset+28+uint32(prefixLen) : offset+28+uint32(prefixLen)+16]
|
|
}
|
|
content = ASExternalLSA{
|
|
Flags: flags,
|
|
Metric: binary.BigEndian.Uint32(data[offset+20:offset+24]) & 0x00FFFFFF,
|
|
PrefixLength: prefixLen,
|
|
PrefixOptions: uint8(data[offset+25]),
|
|
RefLSType: binary.BigEndian.Uint16(data[offset+26 : offset+28]),
|
|
AddressPrefix: data[offset+28 : offset+28+uint32(prefixLen)],
|
|
ForwardingAddress: forwardingAddress,
|
|
}
|
|
case LinkLSAtype:
|
|
var prefixes []Prefix
|
|
var prefixOffset uint32 = offset + 44
|
|
var j uint32
|
|
numOfPrefixes := binary.BigEndian.Uint32(data[offset+40 : offset+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[offset+20]),
|
|
Options: binary.BigEndian.Uint32(data[offset+20:offset+24]) & 0x00FFFFFF,
|
|
LinkLocalAddress: data[offset+24 : offset+40],
|
|
NumOfPrefixes: numOfPrefixes,
|
|
Prefixes: prefixes,
|
|
}
|
|
case IntraAreaPrefixLSAtype:
|
|
var prefixes []Prefix
|
|
var prefixOffset uint32 = offset + 32
|
|
var j uint16
|
|
numOfPrefixes := binary.BigEndian.Uint16(data[offset+20 : offset+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[offset+22 : offset+24]),
|
|
RefLinkStateID: binary.BigEndian.Uint32(data[offset+24 : offset+28]),
|
|
RefAdvRouter: binary.BigEndian.Uint32(data[offset+28 : offset+32]),
|
|
Prefixes: prefixes,
|
|
}
|
|
default:
|
|
return nil, fmt.Errorf("Unknown 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])
|
|
|
|
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: 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.")
|
|
}
|