package vrrp
|
|
import (
|
"errors"
|
"fmt"
|
"net"
|
"unsafe"
|
)
|
|
type VRRPPacket struct {
|
Header [8]byte
|
IPAddress [][4]byte
|
Pshdr *PseudoHeader
|
}
|
|
type PseudoHeader struct {
|
Saddr net.IP
|
Daddr net.IP
|
Zero uint8
|
Protocol uint8
|
Len uint16
|
}
|
|
func (psh *PseudoHeader) ToBytes() []byte {
|
var octets = make([]byte, 36)
|
copy(octets, psh.Saddr)
|
copy(octets[16:], psh.Daddr)
|
copy(octets[32:], []byte{psh.Zero, psh.Protocol, byte(psh.Len >> 8), byte(psh.Len)})
|
return octets
|
}
|
|
func FromBytes(IPvXVersion byte, octets []byte) (*VRRPPacket, error) {
|
if len(octets) < 8 {
|
return nil, errors.New("faulty VRRP packet size")
|
}
|
var packet VRRPPacket
|
for index := 0; index < 8; index++ {
|
packet.Header[index] = octets[index]
|
}
|
//todo validate the number of IPvX addresses
|
var countofaddrs = int(packet.GetIPvXAddrCount())
|
switch IPvXVersion {
|
case 4:
|
case 6:
|
countofaddrs = countofaddrs * 4
|
default:
|
return nil, fmt.Errorf("faulty IPvX version %d", IPvXVersion)
|
}
|
//to compatible with VRRP v2 packet, ignore the auth info
|
if 8+countofaddrs*4 > len(octets) {
|
return nil, fmt.Errorf("The value of filed IPvXAddrCount doesn't match the length of octets")
|
}
|
for index := 0; index < countofaddrs; index++ {
|
var addr [4]byte
|
addr[0] = octets[8+4*index]
|
addr[1] = octets[8+4*index+1]
|
addr[2] = octets[8+4*index+2]
|
addr[3] = octets[8+4*index+3]
|
packet.IPAddress = append(packet.IPAddress, addr)
|
}
|
return &packet, nil
|
}
|
|
func (packet *VRRPPacket) GetIPvXAddr(version byte) (addrs []net.IP) {
|
switch version {
|
case 4:
|
for index := range packet.IPAddress {
|
addrs = append(addrs, net.IPv4(
|
packet.IPAddress[index][0],
|
packet.IPAddress[index][1],
|
packet.IPAddress[index][2],
|
packet.IPAddress[index][3]))
|
}
|
return addrs
|
case 6:
|
for index := 0; index < int(packet.GetIPvXAddrCount()); index++ {
|
var p = make(net.IP, net.IPv6len)
|
for i := 0; i < 4; i++ {
|
copy(p[4*i:], packet.IPAddress[index*4+i][:])
|
}
|
addrs = append(addrs, p)
|
}
|
return addrs
|
default:
|
return nil
|
}
|
}
|
|
func (packet *VRRPPacket) AddIPvXAddr(version byte, ip net.IP) {
|
switch version {
|
case 4:
|
packet.IPAddress = append(packet.IPAddress, [4]byte{ip[12], ip[13], ip[14], ip[15]})
|
packet.setIPvXAddrCount(packet.GetIPvXAddrCount() + 1)
|
//todo byte maybe overflow
|
case 6:
|
for index := 0; index < 4; index++ {
|
packet.IPAddress = append(packet.IPAddress, [4]byte{ip[index*4+0], ip[index*4+1], ip[index*4+2], ip[index*4+3]})
|
}
|
packet.setIPvXAddrCount(packet.GetIPvXAddrCount() + 1)
|
default:
|
panic("VRRPPacket.AddIPvXAddr: only support IPv4 and IPv6 address")
|
}
|
}
|
|
func (packet *VRRPPacket) GetVersion() byte {
|
return (packet.Header[0] & 240) >> 4
|
}
|
|
func (packet *VRRPPacket) SetVersion(Version VRRPVersion) {
|
packet.Header[0] = (packet.Header[0] & 15) | (byte(Version) << 4)
|
}
|
|
func (packet *VRRPPacket) GetType() byte {
|
return packet.Header[0] & 15
|
}
|
|
func (packet *VRRPPacket) SetType() {
|
packet.Header[0] = (packet.Header[0] & 240) | 1
|
}
|
|
func (packet *VRRPPacket) GetVirtualRouterID() byte {
|
return packet.Header[1]
|
}
|
|
func (packet *VRRPPacket) SetVirtualRouterID(VirtualRouterID byte) {
|
packet.Header[1] = VirtualRouterID
|
}
|
|
func (packet *VRRPPacket) GetPriority() byte {
|
return packet.Header[2]
|
}
|
|
func (packet *VRRPPacket) SetPriority(Priority byte) {
|
packet.Header[2] = Priority
|
}
|
|
func (packet *VRRPPacket) GetIPvXAddrCount() byte {
|
return packet.Header[3]
|
}
|
|
func (packet *VRRPPacket) setIPvXAddrCount(count byte) {
|
packet.Header[3] = count
|
}
|
|
func (packet *VRRPPacket) GetAdvertisementInterval() uint16 {
|
return uint16(packet.Header[4]&15)<<8 | uint16(packet.Header[5])
|
}
|
|
func (packet *VRRPPacket) SetAdvertisementInterval(interval uint16) {
|
packet.Header[4] = (packet.Header[4] & 240) | byte((interval>>8)&15)
|
packet.Header[5] = byte(interval)
|
}
|
|
func (packet *VRRPPacket) GetCheckSum() uint16 {
|
return uint16(packet.Header[6])<<8 | uint16(packet.Header[7])
|
}
|
|
func (packet *VRRPPacket) SetCheckSum(pshdr *PseudoHeader) {
|
var PointerAdd = func(ptr unsafe.Pointer, bytes int) unsafe.Pointer {
|
return unsafe.Pointer(uintptr(ptr) + uintptr(bytes))
|
}
|
var octets = pshdr.ToBytes()
|
octets = append(octets, packet.ToBytes()...)
|
var x = len(octets)
|
var ptr = unsafe.Pointer(&octets[0])
|
var sum uint32
|
for x > 1 {
|
sum = sum + uint32(*(*uint16)(ptr))
|
ptr = PointerAdd(ptr, 2)
|
x = x - 2
|
}
|
if x > 0 {
|
sum = sum + uint32(*((*uint8)(ptr)))
|
}
|
for (sum >> 16) > 0 {
|
sum = sum&65535 + sum>>16
|
}
|
sum = ^sum
|
packet.Header[7] = byte(sum >> 8)
|
packet.Header[6] = byte(sum)
|
}
|
|
func (packet *VRRPPacket) ValidateCheckSum(pshdr *PseudoHeader) bool {
|
var PointerAdd = func(ptr unsafe.Pointer, bytes int) unsafe.Pointer {
|
return unsafe.Pointer(uintptr(ptr) + uintptr(bytes))
|
}
|
var octets = pshdr.ToBytes()
|
octets = append(octets, packet.ToBytes()...)
|
var x = len(octets)
|
var ptr = unsafe.Pointer(&octets[0])
|
var sum uint32
|
for x > 1 {
|
sum = sum + uint32(*(*uint16)(ptr))
|
ptr = PointerAdd(ptr, 2)
|
x = x - 2
|
}
|
if x > 0 {
|
sum = sum + uint32(*((*uint8)(ptr)))
|
}
|
for (sum >> 16) > 0 {
|
sum = sum&65535 + sum>>16
|
}
|
if uint16(sum) == 65535 {
|
return true
|
} else {
|
return false
|
}
|
}
|
|
func (packet *VRRPPacket) ToBytes() []byte {
|
var payload = make([]byte, 8+len(packet.IPAddress)*4)
|
copy(payload, packet.Header[:])
|
for index := range packet.IPAddress {
|
copy(payload[8+index*4:], packet.IPAddress[index][:])
|
}
|
return payload
|
}
|