178 lines
3.9 KiB
Go
178 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)
|
|
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.
|
|
Direct bool // True if this is request isn't relayed.
|
|
}
|
|
|
|
func (p synPacket) Marshal(buf []byte) []byte {
|
|
return newBinWriter(buf).
|
|
Byte(packetTypeSyn).
|
|
Uint64(p.TraceID).
|
|
SharedKey(p.SharedKey).
|
|
AddrPort(p.ServerAddr).
|
|
Bool(p.Direct).
|
|
Build()
|
|
}
|
|
|
|
func parseSynPacket(buf []byte) (p synPacket, err error) {
|
|
err = newBinReader(buf[1:]).
|
|
Uint64(&p.TraceID).
|
|
SharedKey(&p.SharedKey).
|
|
AddrPort(&p.ServerAddr).
|
|
Bool(&p.Direct).
|
|
Error()
|
|
return
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
type synAckPacket struct {
|
|
TraceID uint64
|
|
}
|
|
|
|
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(packetTypeSynAck).
|
|
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.
|
|
SharedKey [32]byte
|
|
}
|
|
|
|
func newPingPacket(sharedKey [32]byte) (pp pingPacket) {
|
|
pp.SentAt = time.Now().UnixMilli()
|
|
pp.SharedKey = sharedKey
|
|
return
|
|
}
|
|
|
|
func (p pingPacket) Marshal(buf []byte) []byte {
|
|
return newBinWriter(buf).
|
|
Byte(packetTypePing).
|
|
Int64(p.SentAt).
|
|
SharedKey(p.SharedKey).
|
|
Build()
|
|
}
|
|
|
|
func parsePingPacket(buf []byte) (p pingPacket, err error) {
|
|
err = newBinReader(buf[1:]).
|
|
Int64(&p.SentAt).
|
|
SharedKey(&p.SharedKey).
|
|
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
|
|
}
|