// 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 ( RouterLSAtypeV2 = 0x1 RouterLSAtype = 0x2001 NetworkLSAtypeV2 = 0x2 NetworkLSAtype = 0x2002 SummaryLSANetworktypeV2 = 0x3 InterAreaPrefixLSAtype = 0x2003 SummaryLSAASBRtypeV2 = 0x4 InterAreaRouterLSAtype = 0x2004 ASExternalLSAtypeV2 = 0x5 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 } // 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 } // 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) { var content interface{} switch lstype { case RouterLSAtypeV2: var routers []RouterV2 links := binary.BigEndian.Uint16(data[22:24]) content = RouterLSAV2{ Flags: data[20], Links: links, Routers: routers, } 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 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.") }