Matteo Scandolo | a6a3aee | 2019-11-26 13:30:14 -0700 | [diff] [blame] | 1 | // Copyright 2012 Google, Inc. All rights reserved. |
| 2 | // |
| 3 | // Use of this source code is governed by a BSD-style license |
| 4 | // that can be found in the LICENSE file in the root of the source |
| 5 | // tree. |
| 6 | |
| 7 | package layers |
| 8 | |
| 9 | import ( |
| 10 | "encoding/binary" |
| 11 | "errors" |
| 12 | "github.com/google/gopacket" |
| 13 | ) |
| 14 | |
| 15 | // MPLS is the MPLS packet header. |
| 16 | type MPLS struct { |
| 17 | BaseLayer |
| 18 | Label uint32 |
| 19 | TrafficClass uint8 |
| 20 | StackBottom bool |
| 21 | TTL uint8 |
| 22 | } |
| 23 | |
| 24 | // LayerType returns gopacket.LayerTypeMPLS. |
| 25 | func (m *MPLS) LayerType() gopacket.LayerType { return LayerTypeMPLS } |
| 26 | |
| 27 | // ProtocolGuessingDecoder attempts to guess the protocol of the bytes it's |
| 28 | // given, then decode the packet accordingly. Its algorithm for guessing is: |
| 29 | // If the packet starts with byte 0x45-0x4F: IPv4 |
| 30 | // If the packet starts with byte 0x60-0x6F: IPv6 |
| 31 | // Otherwise: Error |
| 32 | // See draft-hsmit-isis-aal5mux-00.txt for more detail on this approach. |
| 33 | type ProtocolGuessingDecoder struct{} |
| 34 | |
| 35 | func (ProtocolGuessingDecoder) Decode(data []byte, p gopacket.PacketBuilder) error { |
| 36 | switch data[0] { |
| 37 | // 0x40 | header_len, where header_len is at least 5. |
| 38 | case 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f: |
| 39 | return decodeIPv4(data, p) |
| 40 | // IPv6 can start with any byte whose first 4 bits are 0x6. |
| 41 | case 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f: |
| 42 | return decodeIPv6(data, p) |
| 43 | } |
| 44 | return errors.New("Unable to guess protocol of packet data") |
| 45 | } |
| 46 | |
| 47 | // MPLSPayloadDecoder is the decoder used to data encapsulated by each MPLS |
| 48 | // layer. MPLS contains no type information, so we have to explicitly decide |
| 49 | // which decoder to use. This is initially set to ProtocolGuessingDecoder, our |
| 50 | // simple attempt at guessing protocols based on the first few bytes of data |
| 51 | // available to us. However, if you know that in your environment MPLS always |
| 52 | // encapsulates a specific protocol, you may reset this. |
| 53 | var MPLSPayloadDecoder gopacket.Decoder = ProtocolGuessingDecoder{} |
| 54 | |
| 55 | func decodeMPLS(data []byte, p gopacket.PacketBuilder) error { |
| 56 | decoded := binary.BigEndian.Uint32(data[:4]) |
| 57 | mpls := &MPLS{ |
| 58 | Label: decoded >> 12, |
| 59 | TrafficClass: uint8(decoded>>9) & 0x7, |
| 60 | StackBottom: decoded&0x100 != 0, |
| 61 | TTL: uint8(decoded), |
| 62 | BaseLayer: BaseLayer{data[:4], data[4:]}, |
| 63 | } |
| 64 | p.AddLayer(mpls) |
| 65 | if mpls.StackBottom { |
| 66 | return p.NextDecoder(MPLSPayloadDecoder) |
| 67 | } |
| 68 | return p.NextDecoder(gopacket.DecodeFunc(decodeMPLS)) |
| 69 | } |
| 70 | |
| 71 | // SerializeTo writes the serialized form of this layer into the |
| 72 | // SerializationBuffer, implementing gopacket.SerializableLayer. |
| 73 | // See the docs for gopacket.SerializableLayer for more info. |
| 74 | func (m *MPLS) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { |
| 75 | bytes, err := b.PrependBytes(4) |
| 76 | if err != nil { |
| 77 | return err |
| 78 | } |
| 79 | encoded := m.Label << 12 |
| 80 | encoded |= uint32(m.TrafficClass) << 9 |
| 81 | encoded |= uint32(m.TTL) |
| 82 | if m.StackBottom { |
| 83 | encoded |= 0x100 |
| 84 | } |
| 85 | binary.BigEndian.PutUint32(bytes, encoded) |
| 86 | return nil |
| 87 | } |