Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions layers/tls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//
// 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 (
Expand Down
220 changes: 212 additions & 8 deletions layers/vrrp.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,18 @@ import (
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/

// VRRPv2Type is a VRRPv2 message
type VRRPv2Type uint8

// VRRPv2AuthType is a VRRPv2 auth message
type VRRPv2AuthType uint8

const (
// VRRPv2Advertisement is a message type
VRRPv2Advertisement VRRPv2Type = 0x01 // router advertisement
)

// String conversions for VRRP message types
// String conversions for VRRPv2 message types
func (v VRRPv2Type) String() string {
switch v {
case VRRPv2Advertisement:
Expand All @@ -54,12 +58,14 @@ func (v VRRPv2Type) String() string {
}
}

// VRRP authentication types
const (
VRRPv2AuthNoAuth VRRPv2AuthType = 0x00 // No Authentication
VRRPv2AuthReserved1 VRRPv2AuthType = 0x01 // Reserved field 1
VRRPv2AuthReserved2 VRRPv2AuthType = 0x02 // Reserved field 2
)

// String conversions for VRRPv2 authentication types
func (v VRRPv2AuthType) String() string {
switch v {
case VRRPv2AuthNoAuth:
Expand Down Expand Up @@ -90,6 +96,7 @@ type VRRPv2 struct {
// LayerType returns LayerTypeVRRP for VRRP v2 message.
func (v *VRRPv2) LayerType() gopacket.LayerType { return LayerTypeVRRP }

// DecodeFromBytes decodes the VRRPv2 layer from bytes
func (v *VRRPv2) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {

v.BaseLayer = BaseLayer{Contents: data[:len(data)]}
Expand All @@ -98,15 +105,15 @@ func (v *VRRPv2) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error
v.Type = VRRPv2Type(data[0] & 0x0F) // low nibble == VRRP type. Expecting 1 (advertisement)
if v.Type != 1 {
// rfc3768: A packet with unknown type MUST be discarded.
return errors.New("Unrecognized VRRPv2 type field.")
return errors.New("unrecognized VRRPv2 type field")
}

v.VirtualRtrID = data[1]
v.Priority = data[2]

v.CountIPAddr = data[3]
if v.CountIPAddr < 1 {
return errors.New("VRRPv2 number of IP addresses is not valid.")
return errors.New("the VRRPv2 number of IP addresses is not valid")
}

v.AuthType = VRRPv2AuthType(data[4])
Expand Down Expand Up @@ -141,16 +148,213 @@ func (v *VRRPv2) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypeZero
}

// The VRRP packet does not include payload data. Setting byte slice to nil
//Payload layer. The VRRP packet does not include payload data. Setting byte slice to nil
func (v *VRRPv2) Payload() []byte {
return nil
}

// decodeVRRP will parse VRRP v2
// https://tools.ietf.org/html/rfc5798#section-5
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |Version| Type | Virtual Rtr ID| Priority |Count IPvX Addr|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |(rsvd) | Max Adver Int | Checksum |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// + +
// | IPvX Address(es) |
// + +
// + +
// + +
// + +
// | |
// + +
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

// VRRPv3Type represents VRRP message type.
type VRRPv3Type uint8

const (
// VRRPv3Advertisement is the only supported VRRP message type
VRRPv3Advertisement VRRPv3Type = 0x01 // router advertisement
)

// VRRPv3 IANA assigned addresses
var (
VRRPDstIPv4 = net.IP{224, 0, 0, 18}
VRRPDstIPv6 = net.IP{
0xFF, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x12,
}

VRRPDstMACv4 = net.HardwareAddr{0x01, 0x00, 0x5e, 0x00, 0x00, 0x12}
VRRPDstMACv6 = net.HardwareAddr{0x33, 0x33, 0x00, 0x00, 0x00, 0x12}
)

// String conversions for message type.
func (v VRRPv3Type) String() string {
switch v {
case VRRPv3Advertisement:
return "VRRPv3 Advertisement"
default:
return ""
}
}

// VRRPv3 represent a VRRP v3 message structure.
type VRRPv3 struct {
BaseLayer
Version uint8 // The version field specifies the VRRP protocol version of this packet (v3)
Type VRRPv3Type // The type field specifies the type of this VRRP packet. The only type defined in v3 is ADVERTISEMENT
VirtualRtrID uint8 // identifies the virtual router this packet is reporting status for
Priority uint8 // specifies the sending VRRP router's priority for the virtual router (100 = default)
CountIPvXAddr uint8 // The number of IP addresses contained in this VRRP advertisement.
Rsvd uint8 // reserved
MaxAdverInt uint16 // The Advertisement interval indicates the time interval (in centiseconds) between ADVERTISEMENTS. The default is 1 second (100 centiseconds)
Checksum uint16 // used to detect data corruption in the VRRP message.
IPvXAddress []net.IP // one or more IPv4 or IPv6 addresses associated with the virtual router. Specified in the CountIPAddr field. Must not mix IPv4 with IPv6
tcpipchecksum
}

// LayerType returns LayerTypeVRRP.
func (v *VRRPv3) LayerType() gopacket.LayerType {
return LayerTypeVRRP
}

// DecodeFromBytes decodes a given data to a VRRPv3 message.
func (v *VRRPv3) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
v.BaseLayer = BaseLayer{Contents: data[:]}

v.Version = data[0] >> 4 // high nibble
if v.Version != 3 {
return errors.New("incorrect version number, should be 3")
}

v.Type = VRRPv3Type(data[0] & 0x0F) // low nibble
if v.Type != VRRPv3Advertisement {
return errors.New("unsupported VRRPv3 type field")
}

v.VirtualRtrID = data[1]

v.Priority = data[2]

v.CountIPvXAddr = data[3]
if v.CountIPvXAddr < 1 {
return errors.New("advertisement MUST have at least 1 address")
}

v.Rsvd = 0

v.MaxAdverInt = binary.BigEndian.Uint16([]byte{data[4] & 0x0F, data[5]})
v.Checksum = binary.BigEndian.Uint16(data[6:8])

offset := uint8(8)
addrSize := uint8(len(data[offset:])) / v.CountIPvXAddr
if addrSize != 4 && addrSize != 16 {
return errors.New("count field does not match neither IPv4 nor IPv6")
}
v.IPvXAddress = make([]net.IP, 0, v.CountIPvXAddr)
for i := uint8(0); i < v.CountIPvXAddr; i++ {
v.IPvXAddress = append(v.IPvXAddress, data[offset:offset+addrSize])
offset += addrSize
}

return nil
}

// CanDecode specifies the layer type in which we are attempting to unwrap
func (v *VRRPv3) CanDecode() gopacket.LayerClass {
return LayerTypeVRRP
}

// NextLayerType specifies the next layer that should be decoded. VRRP does not contain any payload, so we set to 0
func (v *VRRPv3) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypeZero
}

// Payload should return empty payload for VRRP
func (v *VRRPv3) Payload() []byte {
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 (v *VRRPv3) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
//calculate message size
offset := 8
if len(v.IPvXAddress) < 1 {
return errors.New("advertisement MUST have at least 1 address")
}
count := int(v.CountIPvXAddr)
if len(v.IPvXAddress) != count {
return errors.New("count value and given ip addresses mismatch")
}

var addrSize int
switch v.IPvXAddress[0].To4 {
case nil:
addrSize = 16
default:
addrSize = 4
}
bytes, err := b.PrependBytes(offset + addrSize*count)
if err != nil {
return err
}

bytes[0] = (v.Version << 4) + uint8(v.Type)
bytes[1] = v.VirtualRtrID
bytes[2] = v.Priority
bytes[3] = v.CountIPvXAddr

binary.BigEndian.PutUint16(bytes[4:6], v.MaxAdverInt)

for _, ip := range v.IPvXAddress {
switch addrSize {
case 4:
if copy(bytes[offset:offset+addrSize], ip.To4()) != addrSize {
return errors.New("illegal address")
}
case 16:
if copy(bytes[offset:offset+addrSize], ip) != addrSize {
return errors.New("illegal address")
}
}
offset += addrSize
}
bytes[6], bytes[7] = 0, 0

if opts.ComputeChecksums {
csum, err := v.computeChecksum(b.Bytes(), IPProtocolVRRP)
if err != nil {
return err
}
v.Checksum = csum
}

binary.BigEndian.PutUint16(bytes[6:8], v.Checksum)
return nil
}

// decodeVRRP will parse VRRP v2 or v3
func decodeVRRP(data []byte, p gopacket.PacketBuilder) error {
if len(data) < 8 {
return errors.New("Not a valid VRRP packet. Packet length is too small.")
return errors.New("not a valid VRRP packet. Packet length is too small")
}
v := &VRRPv2{}
return decodingLayerDecoder(v, data, p)
switch data[0] >> 4 {
case 2:
v := &VRRPv2{}
return decodingLayerDecoder(v, data, p)
case 3:
v := &VRRPv3{}
return decodingLayerDecoder(v, data, p)
}

return errors.New("unsupported VRRP version")
}
87 changes: 86 additions & 1 deletion layers/vrrp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
package layers

import (
"github.com/google/gopacket"
"bytes"
"net"
"testing"

"github.com/google/gopacket"
)

// vrrpPacketPriority100 is the packet:
Expand Down Expand Up @@ -53,3 +56,85 @@ func BenchmarkDecodeVRRPPacket0(b *testing.B) {
gopacket.NewPacket(vrrpPacketPriority100, LayerTypeEthernet, gopacket.NoCopy)
}
}

// vrrpv3PacketPriority100 is the following packet:
// 19:21:41.089249 IP (tos 0xc0, ttl 255, id 82, offset 0, flags [none], proto VRRP (112), length 40)
// 10.0.0.130 > 224.0.0.18: vrrp 10.0.0.130 > 224.0.0.18: VRRPv3, Advertisement, vrid 1, prio 100, intvl 100cs, length 20, addrs(3): 192.168.200.16,192.168.200.17,192.168.200.18
// 0x0000: 0100 5e00 0012 0050 5639 0a20 0800 45c0 ..^....PV9....E.
// 0x0010: 0028 0052 0000 ff70 cfbf 0a00 0082 e000 .(.R...p........
// 0x0020: 0012 3101 6403 0064 e54e c0a8 c810 c0a8 ..1.d..d.N......
// 0x0030: c811 c0a8 c812 ......
var vrrpv3PacketPriority100 = []byte{
0x01, 0x00, 0x5e, 0x00, 0x00, 0x12, 0x00, 0x50, 0x56, 0x39, 0x0a, 0x20, 0x08, 0x00, 0x45, 0xc0,
0x00, 0x28, 0x00, 0x52, 0x00, 0x00, 0xff, 0x70, 0xcf, 0xbf, 0x0a, 0x00, 0x00, 0x82, 0xe0, 0x00,
0x00, 0x12, 0x31, 0x01, 0x64, 0x03, 0x00, 0x64, 0xe5, 0x4e, 0xc0, 0xa8, 0xc8, 0x10, 0xc0, 0xa8,
0xc8, 0x11, 0xc0, 0xa8, 0xc8, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}

func TestVRRPPv3acketPacket0(t *testing.T) {
p := gopacket.NewPacket(vrrpv3PacketPriority100, LinkTypeEthernet, gopacket.Default)
if p.ErrorLayer() != nil {
t.Error("Failed to decode packet", p.ErrorLayer().Error())
}
checkLayers(p, []gopacket.LayerType{LayerTypeEthernet, LayerTypeIPv4, LayerTypeVRRP}, t)

// Version=3 Type=VRRPv3 Advertisement VirtualRtrID=1 Priority=100
vrrp, ok := p.Layer(LayerTypeVRRP).(*VRRPv3)
if !ok {
t.Errorf("failed to assert layer type")
}
if vrrp.Version != 3 {
t.Fatalf("Unable to decode VRRPv3 version. Received %d, expected %d", vrrp.Version, 3)
}

if vrrp.Type != 1 {
t.Fatalf("Unable to decode VRRPv3 type. Received %d, expected %d", vrrp.Type, 1)
}

if vrrp.Priority != 100 {
t.Fatalf("Unable to decode VRRPv3 priority. Received %d, expected %d", vrrp.Priority, 100)
}

if vrrp.Checksum != 0xe54e {
t.Fatalf("Unable to decode VRRPv3 checksum. Received %d, expected %d", vrrp.Checksum, 0xe54e)
}

if vrrp.MaxAdverInt != 100 {
t.Fatalf("Unable to decode VRRPv3 advertise interval. Received %d, expected %d", vrrp.MaxAdverInt, 100)
}

if vrrp.CountIPvXAddr != 3 {
t.Fatalf("Unable to decode VRRPv3 IP addresses count. Received %d, expected %d", vrrp.CountIPvXAddr, 3)
}

if len(vrrp.IPvXAddress) != 3 {
t.Fatalf("Decoded wrong number of IP address. Received %d, expected %d", len(vrrp.IPvXAddress), 3)
}

addresses := []net.IP{
net.IP{192, 168, 200, 16},
net.IP{192, 168, 200, 17},
net.IP{192, 168, 200, 18},
}
for i, ip := range vrrp.IPvXAddress {
if !bytes.Equal(ip, addresses[i]) {
t.Fatalf("Decoded wrong IP. Recieved %s, expected %s", ip, addresses[i])
}
}

}

func BenchmarkDecodeVRRPv3Packet0(b *testing.B) {
for i := 0; i < b.N; i++ {
gopacket.NewPacket(vrrpv3PacketPriority100, LayerTypeEthernet, gopacket.NoCopy)
}
}

func TestVRRPv3Serialize(t *testing.T) {
p := gopacket.NewPacket(vrrpv3PacketPriority100, LinkTypeEthernet, gopacket.Default)
p.Layer(LayerTypeVRRP).(*VRRPv3).SetNetworkLayerForChecksum(p.Layer(LayerTypeIPv4).(*IPv4))
if p.ErrorLayer() != nil {
t.Error("Failed to decode packet", p.ErrorLayer().Error())
}
testSerialization(t, p, vrrpv3PacketPriority100)
}
2 changes: 1 addition & 1 deletion routing/other.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
// +build !linux

// Package routing is currently only supported in Linux, but the build system requires a valid go file for all architectures.

package routing

// New returns new router
func New() (Router, error) {
panic("router only implemented in linux")
}