vppn/node/packets.go
2024-12-22 13:58:09 +01:00

182 lines
3.9 KiB
Go

package node
import (
"errors"
"net/netip"
"time"
"unsafe"
)
var (
errMalformedPacket = errors.New("malformed packet")
errUnknownPacketType = errors.New("unknown packet type")
)
const (
packetTypeSyn = iota + 1
packetTypeSynAck
packetTypeAck
packetTypePing
packetTypePong
packetTypeRelayed
)
// ----------------------------------------------------------------------------
type controlPacket struct {
SrcIP byte
RemoteAddr netip.AddrPort
Payload any
}
func (p *controlPacket) ParsePayload(buf []byte) (err error) {
switch buf[0] {
case packetTypePing:
p.Payload, err = parsePingPacket(buf)
case packetTypePong:
p.Payload, err = parsePongPacket(buf)
case packetTypeSyn:
p.Payload, err = parseSynPacket(buf)
case packetTypeSynAck:
p.Payload, err = parseSynAckPacket(buf)
case packetTypeAck:
p.Payload, err = parseAckPacket(buf)
default:
return errUnknownPacketType
}
return err
}
// ----------------------------------------------------------------------------
type synPacket struct {
TraceID uint64 // TraceID to match response w/ request.
SharedKey [32]byte // Our shared key.
ServerAddr netip.AddrPort // The address we're sending to.
RelayIP byte
}
func (p synPacket) Marshal(buf []byte) []byte {
return newBinWriter(buf).
Byte(packetTypeSyn).
Uint64(p.TraceID).
SharedKey(p.SharedKey).
AddrPort(p.ServerAddr).
Byte(p.RelayIP).
Build()
}
func parseSynPacket(buf []byte) (p synPacket, err error) {
err = newBinReader(buf[1:]).
Uint64(&p.TraceID).
SharedKey(&p.SharedKey).
AddrPort(&p.ServerAddr).
Byte(&p.RelayIP).
Error()
return
}
// ----------------------------------------------------------------------------
type synAckPacket struct {
TraceID uint64
}
func newSynAckPacket(traceID uint64) synAckPacket {
return synAckPacket{traceID}
}
func (p synAckPacket) Marshal(buf []byte) []byte {
return newBinWriter(buf).
Byte(packetTypeSynAck).
Uint64(p.TraceID).
Build()
}
func parseSynAckPacket(buf []byte) (p synAckPacket, err error) {
err = newBinReader(buf[1:]).
Uint64(&p.TraceID).
Error()
return
}
// ----------------------------------------------------------------------------
type ackPacket struct {
TraceID uint64
}
func (p ackPacket) Marshal(buf []byte) []byte {
return newBinWriter(buf).
Byte(packetTypeAck).
Uint64(p.TraceID).
Build()
}
func parseAckPacket(buf []byte) (p ackPacket, err error) {
err = newBinReader(buf[1:]).
Uint64(&p.TraceID).
Error()
return
}
// ----------------------------------------------------------------------------
// A pingPacket is sent from a node acting as a client, to a node acting
// as a server. It always contains the shared key the client is expecting
// to use for data encryption with the server.
type pingPacket struct {
SentAt int64 // UnixMilli. // Not used. Use traceID.
}
func newPingPacket() (pp pingPacket) {
pp.SentAt = time.Now().UnixMilli()
return
}
func (p pingPacket) Marshal(buf []byte) []byte {
return newBinWriter(buf).
Byte(packetTypePing).
Int64(p.SentAt).
Build()
}
func parsePingPacket(buf []byte) (p pingPacket, err error) {
err = newBinReader(buf[1:]).
Int64(&p.SentAt).
Error()
return
}
// ----------------------------------------------------------------------------
// A pongPacket is sent by a node in a server role in response to a pingPacket.
type pongPacket struct {
SentAt int64 // UnixMilli.
RecvdAt int64 // UnixMilli.
}
func newPongPacket(sentAt int64) (pp pongPacket) {
pp.SentAt = sentAt
pp.RecvdAt = time.Now().UnixMilli()
return
}
func (p pongPacket) Marshal(buf []byte) []byte {
buf = buf[:17]
buf[0] = packetTypePong
*(*uint64)(unsafe.Pointer(&buf[1])) = uint64(p.SentAt)
*(*uint64)(unsafe.Pointer(&buf[9])) = uint64(p.RecvdAt)
return buf
}
func parsePongPacket(buf []byte) (p pongPacket, err error) {
if len(buf) != 17 {
return p, errMalformedPacket
}
p.SentAt = *(*int64)(unsafe.Pointer(&buf[1]))
p.RecvdAt = *(*int64)(unsafe.Pointer(&buf[9]))
return
}