| // 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.") |
| } |