// Copyright 2012 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" "github.com/google/gopacket" ) // GRE is a Generic Routing Encapsulation header. type GRE struct { BaseLayer ChecksumPresent, RoutingPresent, KeyPresent, SeqPresent, StrictSourceRoute bool RecursionControl, Flags, Version uint8 Protocol EthernetType Checksum, Offset uint16 Key, Seq uint32 *GRERouting } // GRERouting is GRE routing information, present if the RoutingPresent flag is // set. type GRERouting struct { AddressFamily uint16 SREOffset, SRELength uint8 RoutingInformation []byte Next *GRERouting } // LayerType returns gopacket.LayerTypeGRE. func (g *GRE) LayerType() gopacket.LayerType { return LayerTypeGRE } // DecodeFromBytes decodes the given bytes into this layer. func (g *GRE) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { g.ChecksumPresent = data[0]&0x80 != 0 g.RoutingPresent = data[0]&0x40 != 0 g.KeyPresent = data[0]&0x20 != 0 g.SeqPresent = data[0]&0x10 != 0 g.StrictSourceRoute = data[0]&0x08 != 0 g.RecursionControl = data[0] & 0x7 g.Flags = data[1] >> 3 g.Version = data[1] & 0x7 g.Protocol = EthernetType(binary.BigEndian.Uint16(data[2:4])) offset := 4 if g.ChecksumPresent || g.RoutingPresent { g.Checksum = binary.BigEndian.Uint16(data[offset : offset+2]) g.Offset = binary.BigEndian.Uint16(data[offset+2 : offset+4]) offset += 4 } if g.KeyPresent { g.Key = binary.BigEndian.Uint32(data[offset : offset+4]) offset += 4 } if g.SeqPresent { g.Seq = binary.BigEndian.Uint32(data[offset : offset+4]) offset += 4 } if g.RoutingPresent { tail := &g.GRERouting for { sre := &GRERouting{ AddressFamily: binary.BigEndian.Uint16(data[offset : offset+2]), SREOffset: data[offset+2], SRELength: data[offset+3], } sre.RoutingInformation = data[offset+4 : offset+4+int(sre.SRELength)] offset += 4 + int(sre.SRELength) if sre.AddressFamily == 0 && sre.SRELength == 0 { break } (*tail) = sre tail = &sre.Next } } g.BaseLayer = BaseLayer{data[:offset], data[offset:]} return nil } // SerializeTo writes the serialized form of this layer into the SerializationBuffer, // implementing gopacket.SerializableLayer. See the docs for gopacket.SerializableLayer for more info. func (g *GRE) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { size := 4 if g.ChecksumPresent || g.RoutingPresent { size += 4 } if g.KeyPresent { size += 4 } if g.SeqPresent { size += 4 } if g.RoutingPresent { r := g.GRERouting for r != nil { size += 4 + int(r.SRELength) r = r.Next } size += 4 } buf, err := b.PrependBytes(size) if err != nil { return err } // Reset any potentially dirty memory in the first 2 bytes, as these use OR to set flags. buf[0] = 0 buf[1] = 0 if g.ChecksumPresent { buf[0] |= 0x80 } if g.RoutingPresent { buf[0] |= 0x40 } if g.KeyPresent { buf[0] |= 0x20 } if g.SeqPresent { buf[0] |= 0x10 } if g.StrictSourceRoute { buf[0] |= 0x08 } buf[0] |= g.RecursionControl buf[1] |= g.Flags << 3 buf[1] |= g.Version binary.BigEndian.PutUint16(buf[2:4], uint16(g.Protocol)) offset := 4 if g.ChecksumPresent || g.RoutingPresent { // Don't write the checksum value yet, as we may need to compute it, // which requires the entire header be complete. // Instead we zeroize the memory in case it is dirty. buf[offset] = 0 buf[offset+1] = 0 binary.BigEndian.PutUint16(buf[offset+2:offset+4], g.Offset) offset += 4 } if g.KeyPresent { binary.BigEndian.PutUint32(buf[offset:offset+4], g.Key) offset += 4 } if g.SeqPresent { binary.BigEndian.PutUint32(buf[offset:offset+4], g.Seq) offset += 4 } if g.RoutingPresent { sre := g.GRERouting for sre != nil { binary.BigEndian.PutUint16(buf[offset:offset+2], sre.AddressFamily) buf[offset+2] = sre.SREOffset buf[offset+3] = sre.SRELength copy(buf[offset+4:offset+4+int(sre.SRELength)], sre.RoutingInformation) offset += 4 + int(sre.SRELength) sre = sre.Next } // Terminate routing field with a "NULL" SRE. binary.BigEndian.PutUint32(buf[offset:offset+4], 0) } if g.ChecksumPresent { if opts.ComputeChecksums { g.Checksum = tcpipChecksum(b.Bytes(), 0) } binary.BigEndian.PutUint16(buf[4:6], g.Checksum) } return nil } // CanDecode returns the set of layer types that this DecodingLayer can decode. func (g *GRE) CanDecode() gopacket.LayerClass { return LayerTypeGRE } // NextLayerType returns the layer type contained by this DecodingLayer. func (g *GRE) NextLayerType() gopacket.LayerType { return g.Protocol.LayerType() } func decodeGRE(data []byte, p gopacket.PacketBuilder) error { g := &GRE{} return decodingLayerDecoder(g, data, p) }