blob: 9c5e7d246fa33662f4a6421ebdb4c058c94a0d84 [file] [log] [blame]
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -07001// 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
7package layers
8
9import (
10 "encoding/binary"
11
12 "github.com/google/gopacket"
13)
14
15// GRE is a Generic Routing Encapsulation header.
16type GRE struct {
17 BaseLayer
18 ChecksumPresent, RoutingPresent, KeyPresent, SeqPresent, StrictSourceRoute, AckPresent bool
19 RecursionControl, Flags, Version uint8
20 Protocol EthernetType
21 Checksum, Offset uint16
22 Key, Seq, Ack uint32
23 *GRERouting
24}
25
26// GRERouting is GRE routing information, present if the RoutingPresent flag is
27// set.
28type GRERouting struct {
29 AddressFamily uint16
30 SREOffset, SRELength uint8
31 RoutingInformation []byte
32 Next *GRERouting
33}
34
35// LayerType returns gopacket.LayerTypeGRE.
36func (g *GRE) LayerType() gopacket.LayerType { return LayerTypeGRE }
37
38// DecodeFromBytes decodes the given bytes into this layer.
39func (g *GRE) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
40 g.ChecksumPresent = data[0]&0x80 != 0
41 g.RoutingPresent = data[0]&0x40 != 0
42 g.KeyPresent = data[0]&0x20 != 0
43 g.SeqPresent = data[0]&0x10 != 0
44 g.StrictSourceRoute = data[0]&0x08 != 0
45 g.AckPresent = data[1]&0x80 != 0
46 g.RecursionControl = data[0] & 0x7
47 g.Flags = data[1] >> 3
48 g.Version = data[1] & 0x7
49 g.Protocol = EthernetType(binary.BigEndian.Uint16(data[2:4]))
50 offset := 4
51 if g.ChecksumPresent || g.RoutingPresent {
52 g.Checksum = binary.BigEndian.Uint16(data[offset : offset+2])
53 g.Offset = binary.BigEndian.Uint16(data[offset+2 : offset+4])
54 offset += 4
55 }
56 if g.KeyPresent {
57 g.Key = binary.BigEndian.Uint32(data[offset : offset+4])
58 offset += 4
59 }
60 if g.SeqPresent {
61 g.Seq = binary.BigEndian.Uint32(data[offset : offset+4])
62 offset += 4
63 }
64 if g.RoutingPresent {
65 tail := &g.GRERouting
66 for {
67 sre := &GRERouting{
68 AddressFamily: binary.BigEndian.Uint16(data[offset : offset+2]),
69 SREOffset: data[offset+2],
70 SRELength: data[offset+3],
71 }
72 sre.RoutingInformation = data[offset+4 : offset+4+int(sre.SRELength)]
73 offset += 4 + int(sre.SRELength)
74 if sre.AddressFamily == 0 && sre.SRELength == 0 {
75 break
76 }
77 (*tail) = sre
78 tail = &sre.Next
79 }
80 }
81 if g.AckPresent {
82 g.Ack = binary.BigEndian.Uint32(data[offset : offset+4])
83 offset += 4
84 }
85 g.BaseLayer = BaseLayer{data[:offset], data[offset:]}
86 return nil
87}
88
89// SerializeTo writes the serialized form of this layer into the SerializationBuffer,
90// implementing gopacket.SerializableLayer. See the docs for gopacket.SerializableLayer for more info.
91func (g *GRE) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
92 size := 4
93 if g.ChecksumPresent || g.RoutingPresent {
94 size += 4
95 }
96 if g.KeyPresent {
97 size += 4
98 }
99 if g.SeqPresent {
100 size += 4
101 }
102 if g.RoutingPresent {
103 r := g.GRERouting
104 for r != nil {
105 size += 4 + int(r.SRELength)
106 r = r.Next
107 }
108 size += 4
109 }
110 if g.AckPresent {
111 size += 4
112 }
113 buf, err := b.PrependBytes(size)
114 if err != nil {
115 return err
116 }
117 // Reset any potentially dirty memory in the first 2 bytes, as these use OR to set flags.
118 buf[0] = 0
119 buf[1] = 0
120 if g.ChecksumPresent {
121 buf[0] |= 0x80
122 }
123 if g.RoutingPresent {
124 buf[0] |= 0x40
125 }
126 if g.KeyPresent {
127 buf[0] |= 0x20
128 }
129 if g.SeqPresent {
130 buf[0] |= 0x10
131 }
132 if g.StrictSourceRoute {
133 buf[0] |= 0x08
134 }
135 if g.AckPresent {
136 buf[1] |= 0x80
137 }
138 buf[0] |= g.RecursionControl
139 buf[1] |= g.Flags << 3
140 buf[1] |= g.Version
141 binary.BigEndian.PutUint16(buf[2:4], uint16(g.Protocol))
142 offset := 4
143 if g.ChecksumPresent || g.RoutingPresent {
144 // Don't write the checksum value yet, as we may need to compute it,
145 // which requires the entire header be complete.
146 // Instead we zeroize the memory in case it is dirty.
147 buf[offset] = 0
148 buf[offset+1] = 0
149 binary.BigEndian.PutUint16(buf[offset+2:offset+4], g.Offset)
150 offset += 4
151 }
152 if g.KeyPresent {
153 binary.BigEndian.PutUint32(buf[offset:offset+4], g.Key)
154 offset += 4
155 }
156 if g.SeqPresent {
157 binary.BigEndian.PutUint32(buf[offset:offset+4], g.Seq)
158 offset += 4
159 }
160 if g.RoutingPresent {
161 sre := g.GRERouting
162 for sre != nil {
163 binary.BigEndian.PutUint16(buf[offset:offset+2], sre.AddressFamily)
164 buf[offset+2] = sre.SREOffset
165 buf[offset+3] = sre.SRELength
166 copy(buf[offset+4:offset+4+int(sre.SRELength)], sre.RoutingInformation)
167 offset += 4 + int(sre.SRELength)
168 sre = sre.Next
169 }
170 // Terminate routing field with a "NULL" SRE.
171 binary.BigEndian.PutUint32(buf[offset:offset+4], 0)
172 }
173 if g.AckPresent {
174 binary.BigEndian.PutUint32(buf[offset:offset+4], g.Ack)
175 offset += 4
176 }
177 if g.ChecksumPresent {
178 if opts.ComputeChecksums {
179 g.Checksum = tcpipChecksum(b.Bytes(), 0)
180 }
181
182 binary.BigEndian.PutUint16(buf[4:6], g.Checksum)
183 }
184 return nil
185}
186
187// CanDecode returns the set of layer types that this DecodingLayer can decode.
188func (g *GRE) CanDecode() gopacket.LayerClass {
189 return LayerTypeGRE
190}
191
192// NextLayerType returns the layer type contained by this DecodingLayer.
193func (g *GRE) NextLayerType() gopacket.LayerType {
194 return g.Protocol.LayerType()
195}
196
197func decodeGRE(data []byte, p gopacket.PacketBuilder) error {
198 g := &GRE{}
199 return decodingLayerDecoder(g, data, p)
200}