Pndpd/pndp/packet.go

182 lines
4.1 KiB
Go
Raw Normal View History

2021-12-22 07:01:30 -05:00
package pndp
2021-12-20 14:53:42 -05:00
import (
2021-12-25 08:21:07 -05:00
"bytes"
2021-12-20 14:53:42 -05:00
"encoding/binary"
2021-12-21 06:00:28 -05:00
"errors"
2021-12-25 08:21:07 -05:00
"fmt"
2021-12-21 06:00:28 -05:00
"net"
2021-12-26 11:45:43 +01:00
"strings"
2021-12-20 14:53:42 -05:00
)
var emptyIpv6 = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
2021-12-22 07:01:30 -05:00
type payload interface {
2021-12-20 14:53:42 -05:00
constructPacket() ([]byte, int)
}
2021-12-22 07:01:30 -05:00
type ipv6Header struct {
2021-12-20 14:53:42 -05:00
protocol byte
srcIP []byte
dstIP []byte
payloadLen []byte
payload []byte
}
2021-12-22 07:01:30 -05:00
func newIpv6Header(srcIp []byte, dstIp []byte) (*ipv6Header, error) {
2021-12-21 06:00:28 -05:00
if len(dstIp) != 16 || len(srcIp) != 16 {
return nil, errors.New("malformed IP")
}
2021-12-22 07:01:30 -05:00
return &ipv6Header{dstIP: dstIp, srcIP: srcIp, protocol: 0x3a}, nil
2021-12-20 14:53:42 -05:00
}
2021-12-22 07:01:30 -05:00
func (h *ipv6Header) addPayload(payload payload) {
2021-12-20 14:53:42 -05:00
bPayload, checksumPos := payload.constructPacket()
bPayloadLen := make([]byte, 2)
binary.BigEndian.PutUint16(bPayloadLen, uint16(len(bPayload)))
h.payloadLen = bPayloadLen
if checksumPos > 0 {
bChecksum := make([]byte, 2)
binary.BigEndian.PutUint16(bChecksum, calculateChecksum(h, bPayload))
bPayload[checksumPos] = bChecksum[0]
bPayload[checksumPos+1] = bChecksum[1]
}
h.payload = bPayload
}
2021-12-22 07:01:30 -05:00
func (h *ipv6Header) constructPacket() []byte {
2021-12-20 14:53:42 -05:00
header := []byte{
0x60, // v6
0, // qos
0, // qos
0, // qos
2021-12-22 07:01:30 -05:00
h.payloadLen[0], // payload Length
h.payloadLen[1], // payload Length
2021-12-20 14:53:42 -05:00
h.protocol, // Protocol next header
0xff, // Hop limit
}
final := append(header, h.srcIP...)
final = append(final, h.dstIP...)
final = append(final, h.payload...)
return final
}
2021-12-22 07:01:30 -05:00
type ndpPayload struct {
packetType ndpType
2021-12-20 14:53:42 -05:00
answeringForIP []byte
mac []byte
}
2021-12-22 07:01:30 -05:00
func newNdpPacket(answeringForIP []byte, mac []byte, packetType ndpType) (*ndpPayload, error) {
2021-12-21 06:00:28 -05:00
if len(answeringForIP) != 16 || len(mac) != 6 {
return nil, errors.New("malformed IP")
}
2021-12-22 07:01:30 -05:00
return &ndpPayload{
2021-12-20 16:46:26 -05:00
packetType: packetType,
2021-12-20 14:53:42 -05:00
answeringForIP: answeringForIP,
mac: mac,
2021-12-21 06:00:28 -05:00
}, nil
2021-12-20 14:53:42 -05:00
}
2021-12-22 07:01:30 -05:00
func (p *ndpPayload) constructPacket() ([]byte, int) {
2021-12-20 16:46:26 -05:00
var protocol byte
var flags byte
2021-12-21 06:00:28 -05:00
var linkType byte
2021-12-22 07:01:30 -05:00
if p.packetType == ndp_SOL {
2021-12-20 16:46:26 -05:00
protocol = 0x87
flags = 0x0
2021-12-21 06:00:28 -05:00
linkType = 0x01
2021-12-20 16:46:26 -05:00
} else {
protocol = 0x88
flags = 0x60
2021-12-21 06:00:28 -05:00
linkType = 0x02
2021-12-20 16:46:26 -05:00
}
2021-12-20 14:53:42 -05:00
header := []byte{
2021-12-22 07:01:30 -05:00
protocol, // Type: ndpType
2021-12-20 16:46:26 -05:00
0x0, // Code
0x0, // Checksum filled in later
0x0, // Checksum filled in later
flags, // Flags (Solicited,Override)
0x0, // Reserved
0x0, // Reserved
0x0, // Reserved
2021-12-20 14:53:42 -05:00
}
final := append(header, p.answeringForIP...)
secondHeader := []byte{
2021-12-21 06:00:28 -05:00
linkType, // Type
0x01, // Length: 1 (8 bytes)
2021-12-20 14:53:42 -05:00
}
final = append(final, secondHeader...)
final = append(final, p.mac...)
return final, 2
}
2021-12-22 07:01:30 -05:00
func calculateChecksum(h *ipv6Header, payload []byte) uint16 {
2021-12-25 08:21:07 -05:00
if payload == nil {
return 0x0000
} else if len(payload) == 0 {
return 0x0000
}
2021-12-20 14:53:42 -05:00
sumPseudoHeader := checksumAddition(h.srcIP) + checksumAddition(h.dstIP) + checksumAddition([]byte{0x00, h.protocol}) + checksumAddition(h.payloadLen)
sumPayload := checksumAddition(payload)
sumTotal := sumPayload + sumPseudoHeader
for sumTotal>>16 > 0x0 {
sumTotal = (sumTotal & 0xffff) + (sumTotal >> 16)
}
return uint16(sumTotal) ^ 0xFFFF
}
func checksumAddition(b []byte) uint32 {
var sum uint32 = 0
for i := 0; i < len(b); i++ {
if i%2 == 0 {
2021-12-25 08:21:07 -05:00
if len(b)-1 == i {
2021-12-24 17:04:18 -05:00
sum += uint32(uint16(b[i])<<8 | uint16(0x0))
} else {
sum += uint32(uint16(b[i])<<8 | uint16(b[i+1]))
}
2021-12-20 14:53:42 -05:00
}
}
return sum
}
2021-12-21 06:00:28 -05:00
2021-12-25 08:21:07 -05:00
func checkPacketChecksum(scrip, dstip, payload []byte) bool {
v6, err := newIpv6Header(scrip, dstip)
if err != nil {
return false
}
packetsum := make([]byte, 2)
copy(packetsum, payload[2:4])
bPayloadLen := make([]byte, 2)
binary.BigEndian.PutUint16(bPayloadLen, uint16(len(payload)))
v6.payloadLen = bPayloadLen
payload[2] = 0x0
payload[3] = 0x0
bChecksum := make([]byte, 2)
binary.BigEndian.PutUint16(bChecksum, calculateChecksum(v6, payload))
if bytes.Equal(packetsum, bChecksum) {
if GlobalDebug {
fmt.Println("Verified received packet checksum")
}
return true
} else {
if GlobalDebug {
fmt.Println("Received packet checksum validation failed")
}
return false
}
}
2021-12-22 07:01:30 -05:00
func isIpv6(ip string) bool {
2021-12-21 06:00:28 -05:00
rip := net.ParseIP(ip)
2021-12-26 11:45:43 +01:00
return rip != nil && strings.Contains(ip, ":")
2021-12-21 06:00:28 -05:00
}