playit.gg go implementation #1
203
enc/enc.go
Normal file
203
enc/enc.go
Normal file
@ -0,0 +1,203 @@
|
||||
package enc
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/netip"
|
||||
)
|
||||
|
||||
func ReadU8(r io.Reader) uint8 {
|
||||
var d uint8
|
||||
err := binary.Read(r, binary.BigEndian, d)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
func ReadU16(r io.Reader) uint16 {
|
||||
var d uint16
|
||||
err := binary.Read(r, binary.BigEndian, d)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
func ReadU32(r io.Reader) uint32 {
|
||||
var d uint32
|
||||
err := binary.Read(r, binary.BigEndian, d)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
func ReadU64(r io.Reader) uint64 {
|
||||
var d uint64
|
||||
err := binary.Read(r, binary.BigEndian, d)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func WriteU8(w io.Writer, d uint8) error {
|
||||
return binary.Write(w, binary.BigEndian, d)
|
||||
}
|
||||
func WriteU16(w io.Writer, d uint16) error {
|
||||
return binary.Write(w, binary.BigEndian, d)
|
||||
}
|
||||
func WriteU32(w io.Writer, d uint32) error {
|
||||
return binary.Write(w, binary.BigEndian, d)
|
||||
}
|
||||
func WriteU64(w io.Writer, d uint64) error {
|
||||
return binary.Write(w, binary.BigEndian, d)
|
||||
}
|
||||
|
||||
func Read8(r io.Reader) int8 {
|
||||
var d int8
|
||||
err := binary.Read(r, binary.BigEndian, d)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
func Read16(r io.Reader) int16 {
|
||||
var d int16
|
||||
err := binary.Read(r, binary.BigEndian, d)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
func Read32(r io.Reader) int32 {
|
||||
var d int32
|
||||
err := binary.Read(r, binary.BigEndian, d)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
func Read64(r io.Reader) int64 {
|
||||
var d int64
|
||||
err := binary.Read(r, binary.BigEndian, d)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
func Write8(w io.Writer, d int8) error {
|
||||
return binary.Write(w, binary.BigEndian, d)
|
||||
}
|
||||
func Write16(w io.Writer, d int16) error {
|
||||
return binary.Write(w, binary.BigEndian, d)
|
||||
}
|
||||
func Write32(w io.Writer, d int32) error {
|
||||
return binary.Write(w, binary.BigEndian, d)
|
||||
}
|
||||
func Write64(w io.Writer, d int64) error {
|
||||
return binary.Write(w, binary.BigEndian, d)
|
||||
}
|
||||
|
||||
func ReadByteN(r io.Reader, size int) (buff []byte, err error) {
|
||||
buff = make([]byte, size)
|
||||
for index := range buff {
|
||||
if err = binary.Read(r, binary.BigEndian, &buff[index]); err != nil {
|
||||
buff = buff[:index]
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
func WriteBytes(w io.Writer, buff []byte) error {
|
||||
return binary.Write(w, binary.BigEndian, buff)
|
||||
}
|
||||
|
||||
func AddrWrite(w io.Writer, addr netip.Addr) error {
|
||||
if addr.Is6() {
|
||||
if err := WriteU8(w, 6); err != nil {
|
||||
return err
|
||||
} else if err = WriteBytes(w, addr.AsSlice()); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := WriteU8(w, 4); err != nil {
|
||||
return err
|
||||
} else if err = WriteBytes(w, addr.AsSlice()); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func AddrRead(r io.Reader) (addr netip.Addr, err error) {
|
||||
var buff []byte
|
||||
switch ReadU8(r) {
|
||||
case 4:
|
||||
if buff, err = ReadByteN(r, 4); err != nil {
|
||||
return
|
||||
}
|
||||
addr = netip.AddrFrom4([4]byte(buff))
|
||||
return
|
||||
case 6:
|
||||
if buff, err = ReadByteN(r, 16); err != nil {
|
||||
return
|
||||
}
|
||||
netip.AddrFrom16([16]byte(buff))
|
||||
return
|
||||
}
|
||||
err = fmt.Errorf("connet get ip type")
|
||||
return
|
||||
}
|
||||
|
||||
func AddrPortRead(r io.Reader) (netip.AddrPort, error) {
|
||||
switch ReadU8(r) {
|
||||
case 4:
|
||||
buff, err := ReadByteN(r, 4)
|
||||
if err != nil {
|
||||
return netip.AddrPort{}, err
|
||||
}
|
||||
return netip.AddrPortFrom(netip.AddrFrom4([4]byte(buff)), ReadU16(r)), nil
|
||||
case 6:
|
||||
buff, err := ReadByteN(r, 16)
|
||||
if err != nil {
|
||||
return netip.AddrPort{}, err
|
||||
}
|
||||
return netip.AddrPortFrom(netip.AddrFrom16([16]byte(buff)), ReadU16(r)), nil
|
||||
}
|
||||
return netip.AddrPort{}, fmt.Errorf("connet get ip type")
|
||||
}
|
||||
func AddrPortWrite(w io.Writer, addr netip.AddrPort) error {
|
||||
if !addr.IsValid() {
|
||||
return fmt.Errorf("invalid ip address")
|
||||
} else if addr.Addr().Is6() {
|
||||
if err := WriteU8(w, 6); err != nil {
|
||||
return err
|
||||
} else if err = binary.Write(w, binary.BigEndian, addr.Addr().AsSlice()); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := WriteU8(w, 4); err != nil {
|
||||
return err
|
||||
} else if err = binary.Write(w, binary.BigEndian, addr.Addr().AsSlice()); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func WriteOption(w io.Writer, d any, callback func(w io.Writer) (err error)) error {
|
||||
if d == nil {
|
||||
return WriteU8(w, 0)
|
||||
} else if err := WriteU8(w, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
return callback(w)
|
||||
}
|
||||
func ReadOption(r io.Reader, callback func(r io.Reader) (err error)) error {
|
||||
switch ReadU8(r) {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
return callback(r)
|
||||
}
|
||||
return fmt.Errorf("invalid Option value")
|
||||
}
|
16
network/address_lookup.go
Normal file
16
network/address_lookup.go
Normal file
@ -0,0 +1,16 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
|
||||
"sirherobrine23.org/playit-cloud/go-playit/api"
|
||||
)
|
||||
|
||||
type AddressValue[V any] struct {
|
||||
Value V
|
||||
FromPort, ToPort uint16
|
||||
}
|
||||
|
||||
type AddressLookup[Value any] interface {
|
||||
Lookup(IP netip.Addr, Port uint16, Proto api.PortProto) *AddressValue[Value]
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package tunnel
|
||||
package network
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
@ -47,15 +47,15 @@ func TcpSocket(SpecialLan bool, Peer, Host netip.AddrPort) (*net.TCPConn, error)
|
||||
local_ip := mapToLocalIP4(Peer.Addr().AsSlice());
|
||||
stream, err := net.DialTCP("tcp4", net.TCPAddrFromAddrPort(netip.AddrPortFrom(netip.AddrFrom4([4]byte(local_ip.To4())), 0)), net.TCPAddrFromAddrPort(Host))
|
||||
if err != nil {
|
||||
logDebug.Printf("Failed to establish connection using special lan %s for flow %s -> %s\n", local_ip, Peer.String(), Host.String())
|
||||
// logDebug.Printf("Failed to establish connection using special lan %s for flow %s -> %s\n", local_ip, Peer.String(), Host.String())
|
||||
return nil, err
|
||||
}
|
||||
return stream, nil
|
||||
}
|
||||
logDebug.Printf("Failed to bind connection to special local address to support IP based banning")
|
||||
// logDebug.Printf("Failed to bind connection to special local address to support IP based banning")
|
||||
stream, err := net.DialTCP("tcp", nil, net.TCPAddrFromAddrPort(Host))
|
||||
if err != nil {
|
||||
logDebug.Printf("Failed to establish connection for flow %s -> %s. Is your server running? %q", Peer.String(), Host.String(), err.Error())
|
||||
// logDebug.Printf("Failed to establish connection for flow %s -> %s. Is your server running? %q", Peer.String(), Host.String(), err.Error())
|
||||
return nil, err
|
||||
}
|
||||
return stream, nil
|
||||
@ -68,15 +68,15 @@ func UdpSocket(SpecialLan bool, Peer, Host netip.AddrPort) (*net.UDPConn, error)
|
||||
local_port := 40000 + (Peer.Port() % 24000);
|
||||
stream, err := net.DialUDP("udp4", net.UDPAddrFromAddrPort(netip.AddrPortFrom(netip.AddrFrom16([16]byte(local_ip)), local_port)), net.UDPAddrFromAddrPort(Host))
|
||||
if err != nil {
|
||||
logDebug.Printf("Failed to bind UDP port to %d to have connections survive agent restart: %s", local_port, err.Error())
|
||||
// logDebug.Printf("Failed to bind UDP port to %d to have connections survive agent restart: %s", local_port, err.Error())
|
||||
stream, err = net.DialUDP("udp4", net.UDPAddrFromAddrPort(netip.AddrPortFrom(netip.AddrFrom16([16]byte(local_ip)), 0)), net.UDPAddrFromAddrPort(Host))
|
||||
if err != nil {
|
||||
err2 := err
|
||||
// err2 := err
|
||||
stream, err = net.DialUDP("udp4", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logDebug.Printf("Failed to bind UDP to special local address, in-game ip banning will not work: %s", err2.Error())
|
||||
// logDebug.Printf("Failed to bind UDP to special local address, in-game ip banning will not work: %s", err2.Error())
|
||||
}
|
||||
}
|
||||
return stream, nil
|
98
network/tcp_clients.go
Normal file
98
network/tcp_clients.go
Normal file
@ -0,0 +1,98 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
|
||||
"sirherobrine23.org/playit-cloud/go-playit/tunnel"
|
||||
"sirherobrine23.org/playit-cloud/go-playit/proto"
|
||||
)
|
||||
|
||||
type ActiveClients struct {
|
||||
locked sync.Mutex
|
||||
// active: Arc<RwLock<HashMap<(SocketAddr, SocketAddr), NewClient>>>,
|
||||
active map[[2]netip.AddrPort]proto.NewClient
|
||||
}
|
||||
|
||||
func NewActiveClients() ActiveClients {
|
||||
return ActiveClients{
|
||||
locked: sync.Mutex{},
|
||||
active: make(map[[2]netip.AddrPort]proto.NewClient),
|
||||
}
|
||||
}
|
||||
|
||||
func (clients *ActiveClients) Len() int {
|
||||
return len(clients.active)
|
||||
}
|
||||
|
||||
func (clients *ActiveClients) GetClients() []proto.NewClient {
|
||||
clientsArr := []proto.NewClient{}
|
||||
for _, cl := range clients.active {
|
||||
clientsArr = append(clientsArr, cl)
|
||||
}
|
||||
return clientsArr
|
||||
}
|
||||
|
||||
func (clients *ActiveClients) AddNew(client proto.NewClient) *Dropper {
|
||||
clients.locked.Lock()
|
||||
defer clients.locked.Unlock()
|
||||
for actClient := range clients.active {
|
||||
if client.PeerAddr.Compare(actClient[0]) == 0 && client.ConnectAddr.Compare(actClient[1]) == 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
key := [2]netip.AddrPort{client.PeerAddr, client.ConnectAddr}
|
||||
clients.active[key] = client
|
||||
return &Dropper{key, *clients}
|
||||
}
|
||||
|
||||
type Dropper struct {
|
||||
key [2]netip.AddrPort
|
||||
inner ActiveClients
|
||||
}
|
||||
|
||||
func (dr *Dropper) Drop() {
|
||||
PeerAddr, ConnectAddr := dr.key[0], dr.key[1]
|
||||
dr.inner.locked.Lock()
|
||||
defer dr.inner.locked.Unlock()
|
||||
for client := range dr.inner.active {
|
||||
if client[0].Compare(PeerAddr) == 0 && client[1].Compare(ConnectAddr) == 0 {
|
||||
delete(dr.inner.active, client)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewTcpClients() TcpClients {
|
||||
return TcpClients{NewActiveClients(), true}
|
||||
}
|
||||
|
||||
type TcpClients struct {
|
||||
active ActiveClients
|
||||
UseSpecialLAN bool
|
||||
}
|
||||
|
||||
func (tcp *TcpClients) ActiveClients() ActiveClients {
|
||||
return tcp.active
|
||||
}
|
||||
|
||||
func (tcp *TcpClients) Connect(newClient proto.NewClient) (*TcpClient, error) {
|
||||
claimInstruction := newClient.ClaimInstructions
|
||||
droppe := tcp.active.AddNew(newClient)
|
||||
if droppe == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
stream, err := (&tunnel.TcpTunnel{claimInstruction}).Connect()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &TcpClient{*stream, *droppe}, nil
|
||||
}
|
||||
|
||||
type TcpClient struct {
|
||||
Stream net.TCPConn
|
||||
Dropper Dropper
|
||||
}
|
175
network/udp_clients.go
Normal file
175
network/udp_clients.go
Normal file
@ -0,0 +1,175 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"sirherobrine23.org/playit-cloud/go-playit/api"
|
||||
"sirherobrine23.org/playit-cloud/go-playit/tunnel"
|
||||
)
|
||||
|
||||
type UdpClient struct {
|
||||
clientKey ClientKey
|
||||
sendFlow tunnel.UdpFlow
|
||||
udpTunnel tunnel.UdpTunnel
|
||||
localUdp net.UDPConn
|
||||
localStartAddr netip.AddrPort
|
||||
tunnelFromPort uint16
|
||||
tunnelToPort uint16
|
||||
udpClientsLock sync.Mutex
|
||||
udpClients map[ClientKey]UdpClient
|
||||
lastActivity atomic.Uint32
|
||||
}
|
||||
|
||||
func (self *UdpClient) SendLocal(dstPort uint16, data []byte) error {
|
||||
portOffset := dstPort - self.tunnelFromPort
|
||||
self.lastActivity.Store(uint32(time.Now().UnixMilli() / 1_000))
|
||||
if portOffset == 0 {
|
||||
_, err := self.localUdp.WriteToUDP(data, net.UDPAddrFromAddrPort(self.localStartAddr))
|
||||
return err
|
||||
}
|
||||
_, err := self.localUdp.WriteToUDP(data, net.UDPAddrFromAddrPort(netip.AddrPortFrom(self.localStartAddr.Addr(), self.localStartAddr.Port()+portOffset)))
|
||||
return err
|
||||
}
|
||||
|
||||
type HostToTunnelForwarder struct{ UdpClient }
|
||||
|
||||
func (self *HostToTunnelForwarder) Run() {
|
||||
buffer := make([]byte, 2048)
|
||||
for {
|
||||
buffer = make([]byte, 2048)
|
||||
self.localUdp.SetReadDeadline(time.Now().Add(time.Second * 30))
|
||||
size, source, err := self.localUdp.ReadFromUDPAddrPort(buffer)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
break
|
||||
} else if source.Addr().Compare(self.localStartAddr.Addr()) != 0 {
|
||||
// "dropping packet from different unexpected source"
|
||||
continue
|
||||
}
|
||||
|
||||
portCount := self.tunnelToPort - self.tunnelFromPort
|
||||
localFrom := self.localStartAddr.Port()
|
||||
localTo := localFrom + portCount
|
||||
if source.Port() < localFrom || localTo <= source.Port() {
|
||||
// "dropping packet outside of expected port range"
|
||||
continue
|
||||
}
|
||||
buffer = buffer[:size]
|
||||
portOffset := source.Port() - localFrom
|
||||
flow := self.sendFlow.WithSrcPort(self.tunnelFromPort + portOffset)
|
||||
if _, err = self.udpTunnel.Send(buffer, flow); err != nil {
|
||||
// "failed to send packet to through tunnel"
|
||||
}
|
||||
}
|
||||
|
||||
self.UdpClient.udpClientsLock.Lock()
|
||||
if _, is := self.UdpClient.udpClients[self.clientKey]; is {
|
||||
// if !reflect.DeepEqual(v, self) {} else {}
|
||||
delete(self.UdpClient.udpClients, self.clientKey)
|
||||
}
|
||||
self.UdpClient.udpClientsLock.Unlock()
|
||||
}
|
||||
|
||||
type ClientKey struct {
|
||||
ClientAddr, TunnelAddr netip.AddrPort
|
||||
}
|
||||
|
||||
type UdpClients struct {
|
||||
udpTunnel tunnel.UdpTunnel
|
||||
lookup AddressLookup[netip.AddrPort]
|
||||
udpClientsLocker sync.Mutex
|
||||
udpClients map[ClientKey]UdpClient
|
||||
UseSpecialLan bool
|
||||
}
|
||||
|
||||
func NewUdpClients(Tunnel tunnel.UdpTunnel, Lookup AddressLookup[netip.AddrPort]) UdpClients {
|
||||
return UdpClients{
|
||||
udpTunnel: Tunnel,
|
||||
lookup: Lookup,
|
||||
udpClientsLocker: sync.Mutex{},
|
||||
udpClients: make(map[ClientKey]UdpClient),
|
||||
UseSpecialLan: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *UdpClients) ClientCount() int {
|
||||
return len(self.udpClients)
|
||||
}
|
||||
|
||||
func (self *UdpClients) ForwardPacket(Flow tunnel.UdpFlow, data []byte) error {
|
||||
flowDst := Flow.Dst()
|
||||
found := self.lookup.Lookup(flowDst.Addr(), Flow.Dst().Port(), api.PortProto("udp"))
|
||||
if found == nil {
|
||||
return fmt.Errorf("could not find tunnel")
|
||||
}
|
||||
|
||||
key := ClientKey{ClientAddr: Flow.Src(), TunnelAddr: netip.AddrPortFrom(flowDst.Addr(), found.FromPort)}
|
||||
for kkey, client := range self.udpClients {
|
||||
if reflect.DeepEqual(kkey, key) {
|
||||
return client.SendLocal(flowDst.Port(), data)
|
||||
}
|
||||
}
|
||||
self.udpClientsLocker.Lock()
|
||||
defer self.udpClientsLocker.Unlock()
|
||||
|
||||
client, err := func() (*UdpClient, error) {
|
||||
for kkey, client := range self.udpClients {
|
||||
if reflect.DeepEqual(kkey, key) {
|
||||
return &client, nil
|
||||
}
|
||||
}
|
||||
localAddr := found.Value
|
||||
var sendFlow tunnel.UdpFlow
|
||||
var clientAddr netip.AddrPort
|
||||
if Flow.V4 != nil {
|
||||
clientAddr = netip.AddrPortFrom(Flow.V4.Src.Addr(), Flow.V4.Src.Port())
|
||||
sendFlow.V4 = &tunnel.UdpFlowBase{
|
||||
Src: netip.AddrPortFrom(Flow.V4.Dst.Addr(), found.FromPort),
|
||||
Dst: Flow.Src(),
|
||||
}
|
||||
} else {
|
||||
clientAddr = netip.AddrPortFrom(Flow.V6.Src.Addr(), Flow.V6.Src.Port())
|
||||
sendFlow.V6 = &struct {
|
||||
tunnel.UdpFlowBase
|
||||
Flow uint32
|
||||
}{
|
||||
Flow: sendFlow.V6.Flow,
|
||||
UdpFlowBase: tunnel.UdpFlowBase{
|
||||
Src: netip.AddrPortFrom(Flow.V6.Dst.Addr(), found.FromPort),
|
||||
Dst: Flow.Src(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
usock, err := UdpSocket(self.UseSpecialLan, clientAddr, localAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client := UdpClient{
|
||||
clientKey: key,
|
||||
sendFlow: sendFlow,
|
||||
localUdp: *usock,
|
||||
udpTunnel: self.udpTunnel,
|
||||
localStartAddr: localAddr,
|
||||
tunnelFromPort: found.FromPort,
|
||||
tunnelToPort: found.ToPort,
|
||||
udpClients: self.udpClients,
|
||||
lastActivity: atomic.Uint32{},
|
||||
}
|
||||
|
||||
self.udpClients[key] = client
|
||||
go (&HostToTunnelForwarder{client}).Run()
|
||||
return &client, nil
|
||||
}()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return client.SendLocal(flowDst.Port(), data)
|
||||
}
|
103
proto/control_feed.go
Normal file
103
proto/control_feed.go
Normal file
@ -0,0 +1,103 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/netip"
|
||||
|
||||
"sirherobrine23.org/playit-cloud/go-playit/enc"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrFeedRead error = fmt.Errorf("invalid controlFeed id")
|
||||
)
|
||||
|
||||
type ControlFeed struct {
|
||||
Response *ControlRpcMessage[*ControlResponse]
|
||||
NewClient *NewClient
|
||||
}
|
||||
|
||||
func (Feed *ControlFeed) ReadFrom(r io.Reader) error {
|
||||
id := enc.ReadU32(r)
|
||||
if id == 1 {
|
||||
Feed.Response = new(ControlRpcMessage[*ControlResponse])
|
||||
Feed.Response.Content = new(ControlResponse)
|
||||
return Feed.Response.ReadFrom(r)
|
||||
} else if id == 2 {
|
||||
Feed.NewClient = &NewClient{}
|
||||
return Feed.NewClient.ReadFrom(r)
|
||||
}
|
||||
return ErrFeedRead
|
||||
}
|
||||
func (Feed *ControlFeed) WriteTo(w io.Writer) error {
|
||||
if Feed.Response != nil {
|
||||
if err := enc.WriteU32(w, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
return Feed.Response.WriteTo(w)
|
||||
} else if Feed.NewClient != nil {
|
||||
if err := enc.WriteU32(w, 2); err != nil {
|
||||
return err
|
||||
}
|
||||
return Feed.NewClient.WriteTo(w)
|
||||
}
|
||||
return fmt.Errorf("set Response or NewClient")
|
||||
}
|
||||
|
||||
type NewClient struct {
|
||||
ConnectAddr netip.AddrPort
|
||||
PeerAddr netip.AddrPort
|
||||
ClaimInstructions ClaimInstructions
|
||||
TunnelServerId uint64
|
||||
DataCenterId uint32
|
||||
}
|
||||
|
||||
func (client *NewClient) ReadFrom(r io.Reader) error {
|
||||
var err error
|
||||
if client.ConnectAddr, err = enc.AddrPortRead(r); err != nil {
|
||||
return err
|
||||
} else if client.PeerAddr, err = enc.AddrPortRead(r); err != nil {
|
||||
return err
|
||||
} else if err = client.ClaimInstructions.ReadFrom(r); err != nil {
|
||||
return err
|
||||
}
|
||||
client.TunnelServerId, client.DataCenterId = enc.ReadU64(r), enc.ReadU32(r)
|
||||
return nil
|
||||
}
|
||||
func (client *NewClient) WriteTo(w io.Writer) error {
|
||||
if err := enc.AddrPortWrite(w, client.ConnectAddr); err != nil {
|
||||
return err
|
||||
} else if err := enc.AddrPortWrite(w, client.PeerAddr); err != nil {
|
||||
return err
|
||||
} else if err := client.ClaimInstructions.WriteTo(w); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteU64(w, client.TunnelServerId); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteU32(w, client.DataCenterId); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ClaimInstructions struct {
|
||||
Address netip.AddrPort
|
||||
Token []byte
|
||||
}
|
||||
|
||||
func (claim *ClaimInstructions) ReadFrom(r io.Reader) (err error) {
|
||||
if claim.Address, err = enc.AddrPortRead(r); err != nil {
|
||||
return err
|
||||
}
|
||||
claim.Token, err = enc.ReadByteN(r, int(enc.ReadU64(r)))
|
||||
return
|
||||
}
|
||||
func (claim *ClaimInstructions) WriteTo(w io.Writer) error {
|
||||
if err := enc.AddrPortWrite(w, claim.Address); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteU64(w, uint64(len(claim.Token))); err != nil {
|
||||
return err
|
||||
} else if err = enc.WriteBytes(w, claim.Token); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
394
proto/control_messages.go
Normal file
394
proto/control_messages.go
Normal file
@ -0,0 +1,394 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"sirherobrine23.org/playit-cloud/go-playit/enc"
|
||||
)
|
||||
|
||||
type ControlRequest struct {
|
||||
Ping *Ping
|
||||
AgentRegister *AgentRegister
|
||||
AgentKeepAlive *AgentSessionId
|
||||
SetupUdpChannel *AgentSessionId
|
||||
AgentCheckPortMapping *AgentCheckPortMapping
|
||||
}
|
||||
|
||||
func (Control *ControlRequest) WriteTo(w io.Writer) error {
|
||||
if Control.Ping != nil {
|
||||
if err := enc.WriteU32(w, 6); err != nil {
|
||||
return err
|
||||
}
|
||||
return Control.Ping.WriteTo(w)
|
||||
} else if Control.AgentRegister != nil {
|
||||
if err := enc.WriteU32(w, 2); err != nil {
|
||||
return err
|
||||
}
|
||||
return Control.AgentRegister.WriteTo(w)
|
||||
} else if Control.AgentKeepAlive != nil {
|
||||
if err := enc.WriteU32(w, 3); err != nil {
|
||||
return err
|
||||
}
|
||||
return Control.AgentKeepAlive.WriteTo(w)
|
||||
} else if Control.SetupUdpChannel != nil {
|
||||
if err := enc.WriteU32(w, 4); err != nil {
|
||||
return err
|
||||
}
|
||||
return Control.SetupUdpChannel.WriteTo(w)
|
||||
} else if Control.AgentCheckPortMapping != nil {
|
||||
if err := enc.WriteU32(w, 5); err != nil {
|
||||
return err
|
||||
}
|
||||
return Control.AgentCheckPortMapping.WriteTo(w)
|
||||
}
|
||||
return fmt.Errorf("set ControlRequest")
|
||||
}
|
||||
func (Control *ControlRequest) ReadFrom(r io.Reader) error {
|
||||
switch enc.ReadU32(r) {
|
||||
case 1:
|
||||
Control.Ping = new(Ping)
|
||||
return Control.Ping.ReadFrom(r)
|
||||
case 2:
|
||||
Control.AgentRegister = new(AgentRegister)
|
||||
return Control.AgentRegister.ReadFrom(r)
|
||||
case 3:
|
||||
Control.AgentKeepAlive = new(AgentSessionId)
|
||||
return Control.AgentKeepAlive.ReadFrom(r)
|
||||
case 4:
|
||||
Control.SetupUdpChannel = new(AgentSessionId)
|
||||
return Control.SetupUdpChannel.ReadFrom(r)
|
||||
case 5:
|
||||
Control.AgentCheckPortMapping = new(AgentCheckPortMapping)
|
||||
return Control.AgentCheckPortMapping.ReadFrom(r)
|
||||
}
|
||||
return fmt.Errorf("invalid ControlRequest id")
|
||||
}
|
||||
|
||||
type AgentCheckPortMapping struct {
|
||||
AgentSessionId AgentSessionId
|
||||
PortRange PortRange
|
||||
}
|
||||
|
||||
func (Agent *AgentCheckPortMapping) WriteTo(w io.Writer) error {
|
||||
if err := Agent.AgentSessionId.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
return Agent.PortRange.WriteTo(w)
|
||||
}
|
||||
func (Agent *AgentCheckPortMapping) ReadFrom(r io.Reader) error {
|
||||
if err := Agent.AgentSessionId.ReadFrom(r); err != nil {
|
||||
return err
|
||||
}
|
||||
return Agent.AgentSessionId.ReadFrom(r)
|
||||
}
|
||||
|
||||
type Ping struct {
|
||||
Now time.Time
|
||||
CurrentPing *uint64
|
||||
SessionId *AgentSessionId
|
||||
}
|
||||
|
||||
func (ping *Ping) WriteTo(w io.Writer) error {
|
||||
if err := enc.WriteU64(w, uint64(ping.Now.UnixMilli())); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteOption(w, ping.CurrentPing, func(w io.Writer) error {
|
||||
return enc.WriteU64(w, *ping.CurrentPing)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteOption(w, ping.SessionId, ping.SessionId.WriteTo); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (ping *Ping) ReadFrom(r io.Reader) error {
|
||||
ping.Now = time.UnixMilli(int64(enc.ReadU64(r)))
|
||||
if err := enc.ReadOption(r, func(r io.Reader) error {
|
||||
*ping.CurrentPing = enc.ReadU64(r)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := enc.ReadOption(r, func(r io.Reader) error {
|
||||
return ping.SessionId.ReadFrom(r)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type AgentRegister struct {
|
||||
AccountID, AgentId, AgentVersion, Timestamp uint64
|
||||
ClientAddr, TunnelAddr netip.AddrPort
|
||||
Signature [32]byte
|
||||
}
|
||||
|
||||
func (agent *AgentRegister) writePlain() *bytes.Buffer {
|
||||
buff := new(bytes.Buffer)
|
||||
enc.WriteU64(buff, agent.AccountID)
|
||||
enc.WriteU64(buff, agent.AgentId)
|
||||
enc.WriteU64(buff, agent.AgentVersion)
|
||||
enc.WriteU64(buff, agent.Timestamp)
|
||||
enc.AddrPortWrite(buff, agent.ClientAddr)
|
||||
enc.AddrPortWrite(buff, agent.TunnelAddr)
|
||||
return buff
|
||||
}
|
||||
func (agent *AgentRegister) UpdateSignature(hmac HmacSha256) {
|
||||
agent.Signature = hmac.Sign(agent.writePlain().Bytes())
|
||||
}
|
||||
func (agent *AgentRegister) VerifySignature(hmac HmacSha256) bool {
|
||||
return hmac.Verify(agent.writePlain().Bytes(), agent.Signature[:])
|
||||
}
|
||||
|
||||
func (AgentReg *AgentRegister) WriteTo(w io.Writer) error {
|
||||
if err := enc.WriteU64(w, AgentReg.AccountID); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteU64(w, AgentReg.AgentId); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteU64(w, AgentReg.AgentVersion); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteU64(w, AgentReg.Timestamp); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.AddrPortWrite(w, AgentReg.ClientAddr); err != nil {
|
||||
return err
|
||||
} else if err := enc.AddrPortWrite(w, AgentReg.TunnelAddr); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write(AgentReg.Signature[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (AgentReg *AgentRegister) ReadFrom(r io.Reader) error {
|
||||
AgentReg.AccountID, AgentReg.AccountID, AgentReg.AgentVersion, AgentReg.Timestamp = enc.ReadU64(r), enc.ReadU64(r), enc.ReadU64(r), enc.ReadU64(r)
|
||||
var err error
|
||||
if AgentReg.ClientAddr, err = enc.AddrPortRead(r); err != nil {
|
||||
return err
|
||||
} else if AgentReg.TunnelAddr, err = enc.AddrPortRead(r); err != nil {
|
||||
return err
|
||||
}
|
||||
AgentReg.Signature = [32]byte(make([]byte, 32))
|
||||
if n, _ := r.Read(AgentReg.Signature[:]); n != 32 {
|
||||
return fmt.Errorf("missing signature")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ControlResponse struct {
|
||||
InvalidSignature, Unauthorized, RequestQueued, TryAgainLater bool
|
||||
Pong *Pong
|
||||
AgentRegistered *AgentRegistered
|
||||
AgentPortMapping *AgentPortMapping
|
||||
UdpChannelDetails *UdpChannelDetails
|
||||
}
|
||||
|
||||
func (Control *ControlResponse) WriteTo(w io.Writer) error {
|
||||
if Control.Pong != nil {
|
||||
if err := enc.WriteU32(w, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
return Control.Pong.WriteTo(w)
|
||||
} else if Control.InvalidSignature {
|
||||
return enc.WriteU32(w, 2)
|
||||
} else if Control.Unauthorized {
|
||||
return enc.WriteU32(w, 3)
|
||||
} else if Control.RequestQueued {
|
||||
return enc.WriteU32(w, 4)
|
||||
} else if Control.TryAgainLater {
|
||||
return enc.WriteU32(w, 5)
|
||||
} else if Control.AgentRegistered != nil {
|
||||
if err := enc.WriteU32(w, 6); err != nil {
|
||||
return err
|
||||
}
|
||||
return Control.AgentRegistered.WriteTo(w)
|
||||
} else if Control.AgentPortMapping != nil {
|
||||
if err := enc.WriteU32(w, 7); err != nil {
|
||||
return err
|
||||
}
|
||||
return Control.AgentPortMapping.WriteTo(w)
|
||||
} else if Control.UdpChannelDetails != nil {
|
||||
if err := enc.WriteU32(w, 8); err != nil {
|
||||
return err
|
||||
}
|
||||
return Control.UdpChannelDetails.WriteTo(w)
|
||||
}
|
||||
return fmt.Errorf("insert any options to write")
|
||||
}
|
||||
func (Control *ControlResponse) ReadFrom(r io.Reader) error {
|
||||
switch enc.ReadU32(r) {
|
||||
case 1:
|
||||
Control.Pong = new(Pong)
|
||||
return Control.Pong.ReadFrom(r)
|
||||
case 2:
|
||||
Control.InvalidSignature = true
|
||||
return nil
|
||||
case 3:
|
||||
Control.Unauthorized = true
|
||||
return nil
|
||||
case 4:
|
||||
Control.RequestQueued = true
|
||||
return nil
|
||||
case 5:
|
||||
Control.TryAgainLater = true
|
||||
return nil
|
||||
case 6:
|
||||
Control.AgentRegistered = new(AgentRegistered)
|
||||
return Control.AgentRegistered.ReadFrom(r)
|
||||
case 7:
|
||||
Control.AgentPortMapping = new(AgentPortMapping)
|
||||
return Control.AgentPortMapping.ReadFrom(r)
|
||||
case 8:
|
||||
Control.UdpChannelDetails = new(UdpChannelDetails)
|
||||
return Control.UdpChannelDetails.ReadFrom(r)
|
||||
}
|
||||
return fmt.Errorf("invalid ControlResponse id")
|
||||
}
|
||||
|
||||
type AgentPortMapping struct {
|
||||
Range PortRange
|
||||
Found *AgentPortMappingFound
|
||||
}
|
||||
|
||||
func (Agent *AgentPortMapping) WriteTo(w io.Writer) error {
|
||||
if err := Agent.Range.WriteTo(w); err != nil {
|
||||
return err
|
||||
} else if err := Agent.Found.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (Agent *AgentPortMapping) ReadFrom(r io.Reader) error {
|
||||
if err := Agent.Range.ReadFrom(r); err != nil {
|
||||
return err
|
||||
} else if err := Agent.Found.ReadFrom(r); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type AgentPortMappingFound struct {
|
||||
ToAgent *AgentSessionId
|
||||
}
|
||||
|
||||
func (Agent *AgentPortMappingFound) WriteTo(w io.Writer) error {
|
||||
if Agent.ToAgent != nil {
|
||||
if err := enc.WriteU32(w, 1); err != nil {
|
||||
return err
|
||||
} else if err := Agent.ToAgent.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (Agent *AgentPortMappingFound) ReadFrom(r io.Reader) error {
|
||||
if enc.ReadU32(r) == 1 {
|
||||
Agent.ToAgent = new(AgentSessionId)
|
||||
return Agent.ToAgent.ReadFrom(r)
|
||||
}
|
||||
return fmt.Errorf("unknown AgentPortMappingFound id")
|
||||
}
|
||||
|
||||
type UdpChannelDetails struct {
|
||||
TunnelAddr netip.AddrPort
|
||||
Token []byte
|
||||
}
|
||||
|
||||
func (UdpChannel *UdpChannelDetails) WriteTo(w io.Writer) error {
|
||||
if err := enc.AddrPortWrite(w, UdpChannel.TunnelAddr); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteU64(w, uint64(len(UdpChannel.Token))); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteBytes(w, UdpChannel.Token); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (UdpChannel *UdpChannelDetails) ReadFrom(r io.Reader) error {
|
||||
var err error
|
||||
if UdpChannel.TunnelAddr, err = enc.AddrPortRead(r); err != nil {
|
||||
return err
|
||||
} else if UdpChannel.Token, err = enc.ReadByteN(r, int(enc.ReadU64(r))); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Pong struct {
|
||||
RequestNow, ServerNow time.Time
|
||||
ServerId uint64
|
||||
DataCenterId uint32
|
||||
ClientAddr, TunnelAddr netip.AddrPort
|
||||
SessionExpireAt *time.Time
|
||||
}
|
||||
|
||||
func (pong *Pong) WriteTo(w io.Writer) error {
|
||||
if err := enc.Write64(w, pong.RequestNow.UnixMilli()); err != nil {
|
||||
return err
|
||||
} else if err := enc.Write64(w, pong.ServerNow.UnixMilli()); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteU64(w, pong.ServerId); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteU32(w, pong.DataCenterId); err != nil {
|
||||
return err
|
||||
} else if err := enc.AddrPortWrite(w, pong.ClientAddr); err != nil {
|
||||
return err
|
||||
} else if err := enc.AddrPortWrite(w, pong.TunnelAddr); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteOption(w, pong.SessionExpireAt, func(w io.Writer) (err error) {
|
||||
return enc.Write64(w, pong.SessionExpireAt.UnixMilli())
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (pong *Pong) ReadFrom(r io.Reader) error {
|
||||
pong.RequestNow = time.UnixMilli(enc.Read64(r))
|
||||
pong.ServerNow = time.UnixMilli(enc.Read64(r))
|
||||
pong.ServerId = enc.ReadU64(r)
|
||||
pong.DataCenterId = enc.ReadU32(r)
|
||||
var err error
|
||||
if pong.ClientAddr, err = enc.AddrPortRead(r); err != nil {
|
||||
return err
|
||||
} else if pong.TunnelAddr, err = enc.AddrPortRead(r); err != nil {
|
||||
return err
|
||||
} else if err := enc.ReadOption(r, func(r io.Reader) (err error) {
|
||||
pong.SessionExpireAt = new(time.Time)
|
||||
d, err := time.UnixMilli(enc.Read64(r)).MarshalBinary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return pong.SessionExpireAt.UnmarshalBinary(d)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type AgentRegistered struct {
|
||||
Id AgentSessionId
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
|
||||
func (agent *AgentRegistered) WriteTo(w io.Writer) error {
|
||||
if err := agent.Id.WriteTo(w); err != nil {
|
||||
return err
|
||||
} else if err := enc.Write64(w, agent.ExpiresAt.UnixMilli()); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (agent *AgentRegistered) ReadFrom(r io.Reader) error {
|
||||
if err := agent.Id.ReadFrom(r); err != nil {
|
||||
return err
|
||||
}
|
||||
agent.ExpiresAt = time.UnixMilli(enc.Read64(r))
|
||||
return nil
|
||||
}
|
10
proto/encoding.go
Normal file
10
proto/encoding.go
Normal file
@ -0,0 +1,10 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
type MessageEncoding interface {
|
||||
ReadFrom(r io.Reader) error
|
||||
WriteTo(w io.Writer) error
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package tunnel
|
||||
package proto
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
87
proto/lib.go
Normal file
87
proto/lib.go
Normal file
@ -0,0 +1,87 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/netip"
|
||||
|
||||
"sirherobrine23.org/playit-cloud/go-playit/enc"
|
||||
)
|
||||
|
||||
type AgentSessionId struct {
|
||||
SessionID, AccountID, AgentID uint64
|
||||
}
|
||||
|
||||
type PortRange struct {
|
||||
IP netip.Addr
|
||||
PortStart, PortEnd uint16
|
||||
PortProto PortProto
|
||||
}
|
||||
|
||||
type PortProto string
|
||||
|
||||
func (AgentSession *AgentSessionId) WriteTo(w io.Writer) error {
|
||||
if err := enc.WriteU64(w, AgentSession.SessionID); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteU64(w, AgentSession.AccountID); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteU64(w, AgentSession.AgentID); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (AgentSession *AgentSessionId) ReadFrom(r io.Reader) error {
|
||||
AgentSession.SessionID, AgentSession.AccountID, AgentSession.AgentID = enc.ReadU64(r), enc.ReadU64(r), enc.ReadU64(r)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (portRange *PortRange) WriteTo(w io.Writer) error {
|
||||
if err := enc.AddrWrite(w, portRange.IP); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteU16(w, portRange.PortStart); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteU16(w, portRange.PortEnd); err != nil {
|
||||
return err
|
||||
} else if err := portRange.PortProto.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (portRange *PortRange) ReadFrom(r io.Reader) error {
|
||||
var err error
|
||||
portRange.IP, err = enc.AddrRead(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
portRange.PortStart, portRange.PortEnd = enc.ReadU16(r), enc.ReadU16(r)
|
||||
portRange.PortProto = PortProto("")
|
||||
if err := portRange.PortProto.ReadFrom(r); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (proto PortProto) WriteTo(w io.Writer) error {
|
||||
switch proto {
|
||||
case "tcp":
|
||||
return enc.WriteU8(w, 1)
|
||||
case "udp":
|
||||
return enc.WriteU8(w, 2)
|
||||
case "both":
|
||||
return enc.WriteU8(w, 3)
|
||||
}
|
||||
return fmt.Errorf("invalid port proto")
|
||||
}
|
||||
func (proto PortProto) ReadFrom(r io.Reader) error {
|
||||
switch enc.ReadU8(r) {
|
||||
case 1:
|
||||
proto = PortProto("tcp")
|
||||
case 2:
|
||||
proto = PortProto("udp")
|
||||
case 3:
|
||||
proto = PortProto("both")
|
||||
default:
|
||||
return fmt.Errorf("invalid port proto")
|
||||
}
|
||||
return nil
|
||||
}
|
21
proto/raw_slice.go
Normal file
21
proto/raw_slice.go
Normal file
@ -0,0 +1,21 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
type RawSlice []byte
|
||||
|
||||
func (buff RawSlice) ReadFrom(r io.Reader) error {
|
||||
return fmt.Errorf("cannot read for RawSlice")
|
||||
}
|
||||
func (buff RawSlice) WriteTo(w io.Writer) error {
|
||||
size, err := w.Write(buff)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if size != len(buff) {
|
||||
return fmt.Errorf("not enough space to write raw slice")
|
||||
}
|
||||
return nil
|
||||
}
|
28
proto/rpc.go
Normal file
28
proto/rpc.go
Normal file
@ -0,0 +1,28 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
type ControlRpcMessage[T MessageEncoding] struct {
|
||||
RequestID uint64
|
||||
Content T // Convert with .(*type)
|
||||
}
|
||||
|
||||
func (rpc *ControlRpcMessage[T]) WriteTo(w io.Writer) error {
|
||||
if err := binary.Write(w, binary.BigEndian, rpc.RequestID); err != nil {
|
||||
return err
|
||||
} else if err = rpc.Content.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (rpc *ControlRpcMessage[T]) ReadFrom(r io.Reader) error {
|
||||
if err := binary.Read(r, binary.BigEndian, &rpc.RequestID); err != nil {
|
||||
return err
|
||||
} else if err = rpc.Content.ReadFrom(r); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package tunnel
|
||||
package proto
|
||||
|
||||
import (
|
||||
"log"
|
||||
@ -6,4 +6,4 @@ import (
|
||||
)
|
||||
|
||||
// Write log and show in terminal to debug
|
||||
var logDebug *log.Logger = log.New(os.Stderr, "plait.gg", log.Ltime|log.Ldate)
|
||||
var logDebug *log.Logger = log.New(os.Stderr, "plait.gg", log.Ltime|log.Ldate)
|
113
runner/tunnel_runner.go
Normal file
113
runner/tunnel_runner.go
Normal file
@ -0,0 +1,113 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/netip"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"sirherobrine23.org/playit-cloud/go-playit/api"
|
||||
"sirherobrine23.org/playit-cloud/go-playit/network"
|
||||
"sirherobrine23.org/playit-cloud/go-playit/tunnel"
|
||||
)
|
||||
|
||||
type TunnelRunner struct {
|
||||
Lookup network.AddressLookup[netip.AddrPort]
|
||||
Tunnel tunnel.SimpleTunnel
|
||||
UdpClients network.UdpClients
|
||||
TcpClients network.TcpClients
|
||||
KeepRunning atomic.Bool
|
||||
}
|
||||
|
||||
func NewTunnelRunner(Api api.Api, Lookup network.AddressLookup[netip.AddrPort]) (TunnelRunner, error) {
|
||||
tunnel := tunnel.NewSimpleTunnel(Api)
|
||||
if err := tunnel.Setup(); err != nil {
|
||||
return TunnelRunner{}, err
|
||||
}
|
||||
udp_clients := network.NewUdpClients(tunnel.UdpTunnel(), Lookup)
|
||||
var keep atomic.Bool
|
||||
keep.Store(true)
|
||||
return TunnelRunner{
|
||||
Lookup: Lookup,
|
||||
Tunnel: tunnel,
|
||||
UdpClients: udp_clients,
|
||||
TcpClients: network.NewTcpClients(),
|
||||
KeepRunning: keep,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (self *TunnelRunner) SetSpecialLan(setUse bool) {
|
||||
self.TcpClients.UseSpecialLAN = setUse
|
||||
self.UdpClients.UseSpecialLan = setUse
|
||||
}
|
||||
|
||||
func (self *TunnelRunner) Run() {
|
||||
end := make(chan error)
|
||||
tunnel := self.Tunnel
|
||||
udp := tunnel.UdpTunnel()
|
||||
go func() {
|
||||
lastControlUpdate := time.Now().UnixMilli()
|
||||
for self.KeepRunning.Load() {
|
||||
now := time.Now().UnixMilli()
|
||||
if 30_000 < time.Now().UnixMilli()-lastControlUpdate {
|
||||
lastControlUpdate = now
|
||||
if _, err := tunnel.ReloadControlAddr(); err != nil {
|
||||
}
|
||||
}
|
||||
if new_client := tunnel.Update(); new_client != nil {
|
||||
clients := self.TcpClients
|
||||
found := self.Lookup.Lookup(new_client.ConnectAddr.Addr(), new_client.ConnectAddr.Port(), api.PortProto("tcp"))
|
||||
if found == nil {
|
||||
continue
|
||||
}
|
||||
local_addr := netip.AddrPortFrom(found.Value.Addr(), (new_client.ConnectAddr.Port()-found.FromPort)+found.Value.Port())
|
||||
go func() {
|
||||
peerAddr := new_client.PeerAddr
|
||||
tunnel_conn, err := clients.Connect(*new_client)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer tunnel_conn.Stream.Close()
|
||||
local_conn, err := network.TcpSocket(self.TcpClients.UseSpecialLAN, peerAddr, local_addr)
|
||||
if err != nil {
|
||||
|
||||
}
|
||||
defer local_conn.Close()
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
io.Copy(&tunnel_conn.Stream, local_conn)
|
||||
done <- struct{}{}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
io.Copy(local_conn, &tunnel_conn.Stream)
|
||||
done <- struct{}{}
|
||||
}()
|
||||
<-done
|
||||
<-done
|
||||
}()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
udp_clients := self.UdpClients
|
||||
go func(){
|
||||
buffer := make([]byte, 2048)
|
||||
// had_success := false
|
||||
for self.KeepRunning.Load() {
|
||||
rx, err := udp.ReceiveFrom(buffer)
|
||||
if err != nil {
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
if rx.ConfirmerdConnection {
|
||||
continue
|
||||
}
|
||||
bytes, flow := rx.ReceivedPacket.Bytes, rx.ReceivedPacket.Flow
|
||||
if err := udp_clients.ForwardPacket(flow, buffer[:bytes]); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
<-end
|
||||
}
|
178
tunnel/binary.go
178
tunnel/binary.go
@ -1,178 +0,0 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/netip"
|
||||
)
|
||||
|
||||
func readU8(r io.Reader) uint8 {
|
||||
var d uint8
|
||||
err := binary.Read(r, binary.BigEndian, d)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
func readU16(r io.Reader) uint16 {
|
||||
var d uint16
|
||||
err := binary.Read(r, binary.BigEndian, d)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
func readU32(r io.Reader) uint32 {
|
||||
var d uint32
|
||||
err := binary.Read(r, binary.BigEndian, d)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
func readU64(r io.Reader) uint64 {
|
||||
var d uint64
|
||||
err := binary.Read(r, binary.BigEndian, d)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func writeU8(w io.Writer, d uint8) (int64, error) {
|
||||
return 1, binary.Write(w, binary.BigEndian, d)
|
||||
}
|
||||
func writeU16(w io.Writer, d uint16) (int64, error) {
|
||||
return 2, binary.Write(w, binary.BigEndian, d)
|
||||
}
|
||||
func writeU32(w io.Writer, d uint32) (int64, error) {
|
||||
return 4, binary.Write(w, binary.BigEndian, d)
|
||||
}
|
||||
func writeU64(w io.Writer, d uint64) (int64, error) {
|
||||
return 8, binary.Write(w, binary.BigEndian, d)
|
||||
}
|
||||
|
||||
func readByteN(r io.Reader, size int) (buff []byte, err error) {
|
||||
buff = make([]byte, size)
|
||||
for index := range buff {
|
||||
if err = binary.Read(r, binary.BigEndian, &buff[index]); err != nil {
|
||||
buff = buff[:index]
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
func writeBytes(w io.Writer, buff []byte) (n int64, err error) {
|
||||
n = int64(len(buff))
|
||||
err = binary.Write(w, binary.BigEndian, buff)
|
||||
return
|
||||
}
|
||||
|
||||
func addrWrite(w io.Writer, addr netip.Addr) (n int64, err error) {
|
||||
if addr.Is6() {
|
||||
if _, err = writeU8(w, 6); err != nil {
|
||||
n = 0
|
||||
return
|
||||
} else if _, err = writeBytes(w, addr.AsSlice()); err != nil {
|
||||
n = 1
|
||||
return
|
||||
}
|
||||
n = 17
|
||||
return
|
||||
}
|
||||
if _, err = writeU8(w, 4); err != nil {
|
||||
n = 0
|
||||
return
|
||||
} else if _, err = writeBytes(w, addr.AsSlice()); err != nil {
|
||||
n = 1
|
||||
return
|
||||
}
|
||||
n = 5
|
||||
return
|
||||
}
|
||||
func addrRead(r io.Reader) (addr netip.Addr, n int64, err error) {
|
||||
var buff []byte
|
||||
n = 1
|
||||
switch readU8(r) {
|
||||
case 4:
|
||||
buff, err = readByteN(r, 4)
|
||||
n += int64(len(buff))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
addr = netip.AddrFrom4([4]byte(buff))
|
||||
return
|
||||
case 6:
|
||||
buff, err = readByteN(r, 16)
|
||||
n += int64(len(buff))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
netip.AddrFrom16([16]byte(buff))
|
||||
return
|
||||
}
|
||||
err = fmt.Errorf("connet get ip type")
|
||||
return
|
||||
}
|
||||
|
||||
func addrPortRead(r io.Reader) (netip.AddrPort, int64, error) {
|
||||
switch readU8(r) {
|
||||
case 4:
|
||||
buff, err := readByteN(r, 4)
|
||||
if err != nil {
|
||||
return netip.AddrPort{}, int64(len(buff)), err
|
||||
}
|
||||
return netip.AddrPortFrom(netip.AddrFrom4([4]byte(buff)), readU16(r)), 6, nil
|
||||
case 6:
|
||||
buff, err := readByteN(r, 16)
|
||||
if err != nil {
|
||||
return netip.AddrPort{}, int64(len(buff)), err
|
||||
}
|
||||
return netip.AddrPortFrom(netip.AddrFrom16([16]byte(buff)), readU16(r)), 19, nil
|
||||
}
|
||||
return netip.AddrPort{}, 1, fmt.Errorf("connet get ip type")
|
||||
}
|
||||
func addrPortWrite(w io.Writer, addr netip.AddrPort) (n int64, err error) {
|
||||
if !addr.IsValid() {
|
||||
return 0, fmt.Errorf("invalid ip address")
|
||||
} else if addr.Addr().Is6() {
|
||||
if _, err = writeU8(w, 6); err != nil {
|
||||
return 0, err
|
||||
} else if err = binary.Write(w, binary.BigEndian, addr.Addr().AsSlice()); err != nil {
|
||||
return 1, err
|
||||
}
|
||||
n = 18
|
||||
return
|
||||
}
|
||||
if _, err = writeU8(w, 4); err != nil {
|
||||
return 0, err
|
||||
} else if err = binary.Write(w, binary.BigEndian, addr.Addr().AsSlice()); err != nil {
|
||||
return 1, err
|
||||
}
|
||||
n = 5
|
||||
return
|
||||
}
|
||||
|
||||
func writeOption(w io.Writer, d any, callback func(w io.Writer) (n int64, err error)) (n int64, err error) {
|
||||
if d == nil {
|
||||
return writeU8(w, 0)
|
||||
}
|
||||
n, err = writeU8(w, 1)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n2, err2 := callback(w)
|
||||
return n + n2, err2
|
||||
}
|
||||
func readOption(r io.Reader, callback func(r io.Reader) (n int64, err error)) (n int64, err error) {
|
||||
n = 1
|
||||
switch readU8(r) {
|
||||
case 0:
|
||||
return 1, nil
|
||||
case 1:
|
||||
n2, err := callback(r)
|
||||
return n + n2, err
|
||||
}
|
||||
return 1, fmt.Errorf("invalid Option value")
|
||||
}
|
118
tunnel/control.go
Normal file
118
tunnel/control.go
Normal file
@ -0,0 +1,118 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"sirherobrine23.org/playit-cloud/go-playit/api"
|
||||
"sirherobrine23.org/playit-cloud/go-playit/proto"
|
||||
)
|
||||
|
||||
type AuthenticatedControl struct {
|
||||
Api api.Api
|
||||
Conn ConnectedControl
|
||||
LastPong proto.Pong
|
||||
Registered proto.AgentRegistered
|
||||
buffer *bytes.Buffer
|
||||
ForceExpire bool
|
||||
CurrentPing *uint64
|
||||
}
|
||||
|
||||
func (self *AuthenticatedControl) SendKeepAlive(requestId uint64) error {
|
||||
return self.Send(proto.ControlRpcMessage[*proto.ControlRequest]{
|
||||
requestId,
|
||||
&proto.ControlRequest{
|
||||
AgentKeepAlive: &self.Registered.Id,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (self *AuthenticatedControl) SendSetupUdpChannel(requestId uint64) error {
|
||||
return self.Send(proto.ControlRpcMessage[*proto.ControlRequest]{
|
||||
requestId,
|
||||
&proto.ControlRequest{
|
||||
SetupUdpChannel: &self.Registered.Id,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (self *AuthenticatedControl) SendPing(requestId uint64, Now time.Time) error {
|
||||
return self.Send(proto.ControlRpcMessage[*proto.ControlRequest]{
|
||||
requestId,
|
||||
&proto.ControlRequest{
|
||||
Ping: &proto.Ping{Now, self.CurrentPing, &self.Registered.Id},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (self *AuthenticatedControl) GetExpireAt() time.Time {
|
||||
return self.Registered.ExpiresAt
|
||||
}
|
||||
|
||||
func (self *AuthenticatedControl) IsExpired() bool {
|
||||
return self.ForceExpire || self.LastPong.SessionExpireAt == nil || self.FlowChanged()
|
||||
}
|
||||
|
||||
func (self *AuthenticatedControl) SetExpired() {
|
||||
self.ForceExpire = true
|
||||
}
|
||||
|
||||
func (self *AuthenticatedControl) FlowChanged() bool {
|
||||
return self.Conn.Pong.ClientAddr.Compare(self.LastPong.ClientAddr) != 0
|
||||
}
|
||||
|
||||
func (self *AuthenticatedControl) Send(req proto.ControlRpcMessage[*proto.ControlRequest]) error {
|
||||
self.buffer.Reset()
|
||||
if err := req.WriteTo(self.buffer); err != nil {
|
||||
return err
|
||||
} else if _, err := self.Conn.Udp.WriteTo(self.buffer.Bytes(), net.UDPAddrFromAddrPort(self.Conn.ControlAddr)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *AuthenticatedControl) IntoRequireAuth() ConnectedControl {
|
||||
return ConnectedControl{
|
||||
ControlAddr: self.Conn.ControlAddr,
|
||||
Udp: self.Conn.Udp,
|
||||
Pong: self.LastPong,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *AuthenticatedControl) Authenticate() error {
|
||||
conn := self.IntoRequireAuth()
|
||||
var err error
|
||||
if *self, err = conn.Authenticate(self.Api); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *AuthenticatedControl) RecvFeedMsg() (proto.ControlFeed, error) {
|
||||
buff := make([]byte, 1024)
|
||||
size, remote, err := self.Conn.Udp.ReadFromUDPAddrPort(buff)
|
||||
self.buffer.Reset()
|
||||
self.buffer.Write(buff[:size])
|
||||
if err != nil {
|
||||
return proto.ControlFeed{}, err
|
||||
} else if remote.Compare(self.Conn.ControlAddr) != 0 {
|
||||
return proto.ControlFeed{}, fmt.Errorf("invalid remote, expected %q got %q", remote.String(), self.Conn.ControlAddr.String())
|
||||
}
|
||||
feed := proto.ControlFeed{}
|
||||
if err := feed.ReadFrom(self.buffer); err != nil {
|
||||
return proto.ControlFeed{}, err
|
||||
}
|
||||
if feed.Response != nil {
|
||||
res := feed.Response
|
||||
if registered := res.Content.AgentRegistered; registered != nil {
|
||||
self.Registered = *registered
|
||||
}
|
||||
if pong := res.Content.Pong; pong != nil {
|
||||
*self.CurrentPing = uint64(time.Now().UnixMilli() - pong.RequestNow.UnixMilli())
|
||||
self.LastPong = *pong
|
||||
}
|
||||
}
|
||||
return feed, nil
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/netip"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrFeedRead error = fmt.Errorf("invalid controlFeed id")
|
||||
)
|
||||
|
||||
type ControlFeed struct {
|
||||
Response *ControlRpcMessage[*ControlResponse]
|
||||
NewClient *NewClient
|
||||
}
|
||||
|
||||
func (Feed *ControlFeed) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
id := readU32(r)
|
||||
if id == 1 {
|
||||
Feed.Response = new(ControlRpcMessage[*ControlResponse])
|
||||
Feed.Response.Content = new(ControlResponse)
|
||||
n, err = Feed.Response.ReadFrom(r)
|
||||
n += 4
|
||||
return
|
||||
} else if id == 2 {
|
||||
Feed.NewClient = &NewClient{}
|
||||
n, err = Feed.NewClient.ReadFrom(r)
|
||||
n += 4
|
||||
return
|
||||
}
|
||||
return 4, ErrFeedRead
|
||||
}
|
||||
func (Feed *ControlFeed) WriteTo(w io.Writer) (n int64, err error) {
|
||||
if Feed.Response != nil {
|
||||
if err := writeU32(w, 1); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
n, err = Feed.Response.WriteTo(w)
|
||||
n += 4
|
||||
return
|
||||
} else if Feed.NewClient != nil {
|
||||
if err := writeU32(w, 2); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
n, err = Feed.NewClient.WriteTo(w)
|
||||
n += 4
|
||||
return
|
||||
}
|
||||
return 0, fmt.Errorf("")
|
||||
}
|
||||
|
||||
type NewClient struct {
|
||||
ConnectAddr netip.AddrPort
|
||||
PeerAddr netip.AddrPort
|
||||
ClaimInstructions ClaimInstructions
|
||||
TunnelServerId uint64
|
||||
DataCenterId uint32
|
||||
}
|
||||
|
||||
func (client *NewClient) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
client.ConnectAddr, n, err = addrPortRead(r)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
n2 := n
|
||||
client.PeerAddr, n, err = addrPortRead(r)
|
||||
if err != nil {
|
||||
return n2 + n, err
|
||||
}
|
||||
|
||||
n3 := n2 + n
|
||||
n, err = client.ClaimInstructions.ReadFrom(r);
|
||||
if err != nil {
|
||||
return n3 + n, err
|
||||
}
|
||||
n+=n3 + 8 + 4
|
||||
client.TunnelServerId, client.DataCenterId = readU64(r), readU32(r)
|
||||
return
|
||||
}
|
||||
func (client *NewClient) WriteTo(w io.Writer) (n int64, err error) {
|
||||
n, err = addrPortWrite(w, client.ConnectAddr)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
n2 := n
|
||||
n, err = addrPortWrite(w, client.PeerAddr)
|
||||
if err != nil {
|
||||
return n+n2, err
|
||||
}
|
||||
n3:= n+n2
|
||||
if n, err = client.ClaimInstructions.WriteTo(w); err != nil {
|
||||
return n + n3, err
|
||||
}
|
||||
|
||||
n4 := n + n3
|
||||
if err = writeU64(w, client.TunnelServerId); err != nil {
|
||||
return n4, err
|
||||
}
|
||||
n4 += 8
|
||||
if err = writeU32(w, client.DataCenterId); err != nil {
|
||||
return n4, err
|
||||
}
|
||||
n = n4+8
|
||||
return
|
||||
}
|
||||
|
||||
type ClaimInstructions struct {
|
||||
Address netip.AddrPort
|
||||
Token []byte
|
||||
}
|
||||
|
||||
func (claim *ClaimInstructions) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
claim.Address, n, err = addrPortRead(r)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
claim.Token, err = readByteN(r, int(readU64(r)))
|
||||
n += int64(len(claim.Token)) + 8
|
||||
return
|
||||
}
|
||||
func (claim *ClaimInstructions) WriteTo(w io.Writer) (n int64, err error) {
|
||||
n, err = addrPortWrite(w, claim.Address)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
if err = writeU64(w, uint64(len(claim.Token))); err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
n2 := 8 + n
|
||||
n, err = writeBytes(w, claim.Token)
|
||||
if err != nil {
|
||||
return n2, err
|
||||
}
|
||||
n = n2 + n
|
||||
return
|
||||
}
|
@ -1,394 +0,0 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/netip"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ControlRequest struct {
|
||||
Ping *Ping
|
||||
AgentRegister *AgentRegister
|
||||
AgentKeepAlive *AgentSessionId
|
||||
SetupUdpChannel *AgentSessionId
|
||||
AgentCheckPortMapping *AgentCheckPortMapping
|
||||
}
|
||||
|
||||
func (Control *ControlRequest) WriteTo(w io.Writer) (n int64, err error) {
|
||||
if Control.Ping != nil {
|
||||
n, err = writeU32(w, 6)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n2 := n
|
||||
n, err = Control.Ping.WriteTo(w)
|
||||
if err != nil {
|
||||
return n2, err
|
||||
}
|
||||
n += n2
|
||||
return
|
||||
} else if Control.AgentRegister != nil {
|
||||
n, err = writeU32(w, 2)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n2 := n
|
||||
n, err = Control.AgentRegister.WriteTo(w)
|
||||
if err != nil {
|
||||
return n2, err
|
||||
}
|
||||
n += n2
|
||||
return
|
||||
} else if Control.AgentKeepAlive != nil {
|
||||
n, err = writeU32(w, 3)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n2 := n
|
||||
n, err = Control.AgentKeepAlive.WriteTo(w)
|
||||
if err != nil {
|
||||
return n2, err
|
||||
}
|
||||
n += n2
|
||||
return
|
||||
} else if Control.SetupUdpChannel != nil {
|
||||
n, err = writeU32(w, 4)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n2 := n
|
||||
n, err = Control.SetupUdpChannel.WriteTo(w)
|
||||
if err != nil {
|
||||
return n2, err
|
||||
}
|
||||
n += n2
|
||||
return
|
||||
} else if Control.AgentCheckPortMapping != nil {
|
||||
n, err = writeU32(w, 5)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n2 := n
|
||||
n, err = Control.AgentCheckPortMapping.WriteTo(w)
|
||||
if err != nil {
|
||||
return n2, err
|
||||
}
|
||||
n += n2
|
||||
return
|
||||
}
|
||||
err = fmt.Errorf("set ControlRequest")
|
||||
return
|
||||
}
|
||||
func (Control *ControlRequest) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
n = 1
|
||||
switch readU32(r) {
|
||||
case 1:
|
||||
Control.Ping = new(Ping)
|
||||
np, err := Control.Ping.ReadFrom(r)
|
||||
return np + n, err
|
||||
case 2:
|
||||
Control.AgentRegister = new(AgentRegister)
|
||||
np, err := Control.AgentRegister.ReadFrom(r)
|
||||
return np + n, err
|
||||
case 3:
|
||||
Control.AgentKeepAlive = new(AgentSessionId)
|
||||
np, err := Control.AgentKeepAlive.ReadFrom(r)
|
||||
return np + n, err
|
||||
case 4:
|
||||
Control.SetupUdpChannel = new(AgentSessionId)
|
||||
np, err := Control.SetupUdpChannel.ReadFrom(r)
|
||||
return np + n, err
|
||||
case 5:
|
||||
Control.AgentCheckPortMapping = new(AgentCheckPortMapping)
|
||||
np, err := Control.AgentCheckPortMapping.ReadFrom(r)
|
||||
return np + n, err
|
||||
}
|
||||
err = fmt.Errorf("invalid ControlRequest id")
|
||||
return
|
||||
}
|
||||
|
||||
type AgentCheckPortMapping struct {
|
||||
AgentSessionId AgentSessionId
|
||||
PortRange PortRange
|
||||
}
|
||||
|
||||
func (Agent *AgentCheckPortMapping) WriteTo(w io.Writer) (n int64, err error) {
|
||||
n, err = Agent.AgentSessionId.WriteTo(w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n2 := n
|
||||
n, err = Agent.PortRange.WriteTo(w)
|
||||
return n + n2, err
|
||||
}
|
||||
func (Agent *AgentCheckPortMapping) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
n, err = Agent.AgentSessionId.ReadFrom(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n2 := n
|
||||
n, err = Agent.AgentSessionId.ReadFrom(r)
|
||||
return n + n2, err
|
||||
}
|
||||
|
||||
type Ping struct {
|
||||
Now time.Time
|
||||
CurrentPing *time.Time
|
||||
SessionId *AgentSessionId
|
||||
}
|
||||
|
||||
func (ping *Ping) WriteTo(w io.Writer) (n int64, err error) {
|
||||
n, err = writeU64(w, uint64(ping.Now.UnixMilli()))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n2 := n
|
||||
if n, err = writeOption(w, ping.CurrentPing, func(w io.Writer) (int64, error) {
|
||||
return writeU64(w, uint64(ping.CurrentPing.UnixMilli()))
|
||||
}); err != nil {
|
||||
n = n2
|
||||
return
|
||||
}
|
||||
n += n2
|
||||
if n, err = writeOption(w, ping.SessionId, ping.SessionId.WriteTo); err != nil {
|
||||
n = n2
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
func (ping *Ping) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
ping.Now = time.UnixMilli(int64(readU64(r)))
|
||||
n, err = readOption(r, func(r io.Reader) (n int64, err error) {
|
||||
ping.CurrentPing = new(time.Time)
|
||||
d, _ := time.UnixMilli(int64(readU64(r))).MarshalBinary()
|
||||
ping.CurrentPing.UnmarshalBinary(d)
|
||||
return 8, nil
|
||||
})
|
||||
n += 8
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n, err = readOption(r, func(r io.Reader) (n int64, err error) {
|
||||
return ping.SessionId.ReadFrom(r)
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type AgentRegister struct {
|
||||
AccountID, AgentId, AgentVersion, Timestamp uint64
|
||||
ClientAddr, TunnelAddr netip.AddrPort
|
||||
Signature [32]byte
|
||||
}
|
||||
|
||||
func (agent *AgentRegister) writePlain() *bytes.Buffer {
|
||||
buff := new(bytes.Buffer)
|
||||
writeU64(buff, agent.AccountID)
|
||||
writeU64(buff, agent.AgentId)
|
||||
writeU64(buff, agent.AgentVersion)
|
||||
writeU64(buff, agent.Timestamp)
|
||||
addrPortWrite(buff, agent.ClientAddr)
|
||||
addrPortWrite(buff, agent.TunnelAddr)
|
||||
return buff
|
||||
}
|
||||
func (agent *AgentRegister) UpdateSignature(hmac HmacSha256) {
|
||||
agent.Signature = hmac.Sign(agent.writePlain().Bytes())
|
||||
}
|
||||
func (agent *AgentRegister) VerifySignature(hmac HmacSha256) bool {
|
||||
return hmac.Verify(agent.writePlain().Bytes(), agent.Signature[:])
|
||||
}
|
||||
|
||||
func (AgentReg *AgentRegister) WriteTo(w io.Writer) (n int64, err error) {
|
||||
if _, err := writeU64(w, AgentReg.AccountID); err != nil {
|
||||
return 0, err
|
||||
} else if _, err := writeU64(w, AgentReg.AgentId); err != nil {
|
||||
return 0, err
|
||||
} else if _, err := writeU64(w, AgentReg.AgentVersion); err != nil {
|
||||
return 0, err
|
||||
} else if _, err := writeU64(w, AgentReg.Timestamp); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
n = 8 * 4
|
||||
if n2, err := addrPortWrite(w, AgentReg.ClientAddr); err != nil {
|
||||
return n, err
|
||||
} else if n3, err := addrPortWrite(w, AgentReg.TunnelAddr); err != nil {
|
||||
return n + n2, err
|
||||
} else {
|
||||
n += n3
|
||||
}
|
||||
if n4, err := w.Write(AgentReg.Signature[:]); err != nil {
|
||||
return n, err
|
||||
} else {
|
||||
n += int64(n4)
|
||||
}
|
||||
return
|
||||
}
|
||||
func (AgentReg *AgentRegister) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
AgentReg.AccountID, AgentReg.AccountID, AgentReg.AgentVersion, AgentReg.Timestamp = readU64(r), readU64(r), readU64(r), readU64(r)
|
||||
if AgentReg.ClientAddr, n, err = addrPortRead(r); err != nil {
|
||||
return
|
||||
} else if AgentReg.TunnelAddr, n, err = addrPortRead(r); err != nil {
|
||||
return
|
||||
}
|
||||
AgentReg.Signature = [32]byte(make([]byte, 32))
|
||||
if n2, _ := r.Read(AgentReg.Signature[:]); n != 32 {
|
||||
return int64(n2), fmt.Errorf("missing signature")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type ControlResponse struct {
|
||||
InvalidSignature, Unauthorized, RequestQueued, TryAgainLater bool
|
||||
Pong *Pong
|
||||
AgentRegistered *AgentRegistered
|
||||
AgentPortMapping *AgentPortMapping
|
||||
UdpChannelDetails *UdpChannelDetails
|
||||
}
|
||||
|
||||
func (Control *ControlResponse) WriteTo(w io.Writer) (n int64, err error) {
|
||||
defer func() {
|
||||
if err == nil {
|
||||
n += 4
|
||||
}
|
||||
}()
|
||||
if Control.Pong != nil {
|
||||
writeU32(w, 1)
|
||||
n, err = Control.Pong.WriteTo(w)
|
||||
return
|
||||
} else if Control.InvalidSignature {
|
||||
return writeU32(w, 2)
|
||||
} else if Control.Unauthorized {
|
||||
return writeU32(w, 3)
|
||||
} else if Control.RequestQueued {
|
||||
return writeU32(w, 4)
|
||||
} else if Control.TryAgainLater {
|
||||
return writeU32(w, 5)
|
||||
} else if Control.AgentRegistered != nil {
|
||||
writeU32(w, 6)
|
||||
return Control.AgentRegistered.WriteTo(w)
|
||||
} else if Control.AgentPortMapping != nil {
|
||||
writeU32(w, 7)
|
||||
return Control.AgentPortMapping.WriteTo(w)
|
||||
} else if Control.UdpChannelDetails != nil {
|
||||
writeU32(w, 8)
|
||||
return Control.UdpChannelDetails.WriteTo(w)
|
||||
} else {
|
||||
err = fmt.Errorf("insert any options to write")
|
||||
}
|
||||
return
|
||||
}
|
||||
func (Control *ControlResponse) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
defer func() {
|
||||
if err == nil {
|
||||
n += 4
|
||||
}
|
||||
}()
|
||||
switch readU32(r) {
|
||||
case 1:
|
||||
Control.Pong = &Pong{}
|
||||
return Control.Pong.ReadFrom(r)
|
||||
case 2:
|
||||
Control.InvalidSignature = true
|
||||
return
|
||||
case 3:
|
||||
Control.Unauthorized = true
|
||||
return
|
||||
case 4:
|
||||
Control.RequestQueued = true
|
||||
return
|
||||
case 5:
|
||||
Control.TryAgainLater = true
|
||||
return
|
||||
case 6:
|
||||
Control.AgentRegistered = &AgentRegistered{}
|
||||
return Control.AgentRegistered.ReadFrom(r)
|
||||
case 7:
|
||||
Control.AgentPortMapping = &AgentPortMapping{}
|
||||
return Control.AgentPortMapping.ReadFrom(r)
|
||||
case 8:
|
||||
Control.UdpChannelDetails = &UdpChannelDetails{}
|
||||
return Control.UdpChannelDetails.ReadFrom(r)
|
||||
default:
|
||||
err = fmt.Errorf("invalid ControlResponse id")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type AgentPortMapping struct {
|
||||
Range PortRange
|
||||
Found *AgentPortMappingFound
|
||||
}
|
||||
|
||||
func (Agent *AgentPortMapping) WriteTo(w io.Writer) (n int64, err error) {
|
||||
Agent.Range.WriteTo(w)
|
||||
Agent.Found.WriteTo(w)
|
||||
return
|
||||
}
|
||||
func (Agent *AgentPortMapping) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
Agent.Range.ReadFrom(r)
|
||||
Agent.Found.ReadFrom(r)
|
||||
return
|
||||
}
|
||||
|
||||
type AgentPortMappingFound struct {
|
||||
ToAgent *AgentSessionId
|
||||
}
|
||||
|
||||
func (Agent *AgentPortMappingFound) WriteTo(w io.Writer) (n int64, err error) {
|
||||
if Agent.ToAgent != nil {
|
||||
writeU32(w, 1)
|
||||
Agent.ToAgent.WriteTo(w)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
func (Agent *AgentPortMappingFound) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
if readU32(r) == 1 {
|
||||
defer func() { n += 4 }()
|
||||
Agent.ToAgent = new(AgentSessionId)
|
||||
return Agent.ToAgent.ReadFrom(r)
|
||||
}
|
||||
return 4, fmt.Errorf("unknown AgentPortMappingFound id")
|
||||
}
|
||||
|
||||
type UdpChannelDetails struct {
|
||||
TunnelAddr netip.AddrPort
|
||||
Token []byte
|
||||
}
|
||||
|
||||
func (UdpChannel *UdpChannelDetails) WriteTo(w io.Writer) (n int64, err error) {
|
||||
addrPortWrite(w, UdpChannel.TunnelAddr)
|
||||
writeU64(w, uint64(len(UdpChannel.Token)))
|
||||
writeBytes(w, UdpChannel.Token)
|
||||
return
|
||||
}
|
||||
func (UdpChannel *UdpChannelDetails) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
UdpChannel.TunnelAddr, _, _ = addrPortRead(r)
|
||||
UdpChannel.Token, _ = readByteN(r, int(readU64(r)))
|
||||
return
|
||||
}
|
||||
|
||||
type Pong struct {
|
||||
RequestNow, ServerNow time.Time
|
||||
ServerId uint64
|
||||
DataCenterId uint32
|
||||
ClientAddr, TunnelAddr netip.AddrPort
|
||||
SessionExpireAt *time.Time
|
||||
}
|
||||
|
||||
func (pong *Pong) WriteTo(w io.Writer) (n int64, err error) {
|
||||
|
||||
}
|
||||
func (pong *Pong) ReadFrom(r io.Reader) (n int64, err error) {}
|
||||
|
||||
type AgentRegistered struct {
|
||||
Id AgentSessionId
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
|
||||
func (agent *AgentRegistered) WriteTo(w io.Writer) (n int64, err error) {}
|
||||
func (agent *AgentRegistered) ReadFrom(r io.Reader) (n int64, err error) {}
|
@ -1,97 +0,0 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/netip"
|
||||
)
|
||||
|
||||
type AgentSessionId struct {
|
||||
SessionID, AccountID, AgentID uint64
|
||||
}
|
||||
|
||||
type PortRange struct {
|
||||
IP netip.Addr
|
||||
PortStart, PortEnd uint16
|
||||
PortProto PortProto
|
||||
}
|
||||
|
||||
type PortProto string
|
||||
|
||||
func (AgentSession *AgentSessionId) WriteTo(w io.Writer) (int64, error) {
|
||||
if _, err := writeU64(w, AgentSession.SessionID); err != nil {
|
||||
return 0, err
|
||||
} else if _, err = writeU64(w, AgentSession.AccountID); err != nil {
|
||||
return 8, err
|
||||
} else if _, err = writeU64(w, AgentSession.AgentID); err != nil {
|
||||
return 16, err
|
||||
}
|
||||
return 24, nil
|
||||
}
|
||||
func (AgentSession *AgentSessionId) ReadFrom(r io.Reader) (int64, error) {
|
||||
AgentSession.SessionID, AgentSession.AccountID, AgentSession.AgentID = readU64(r), readU64(r), readU64(r)
|
||||
return 24, nil
|
||||
}
|
||||
|
||||
func (portRange *PortRange) WriteTo(w io.Writer) (int64, error) {
|
||||
var len int64 = 4
|
||||
sizeIP, err := addrWrite(w, portRange.IP)
|
||||
if err != nil {
|
||||
return len, err
|
||||
}
|
||||
len += sizeIP
|
||||
if _, err = writeU16(w, portRange.PortStart); err != nil {
|
||||
return len, err
|
||||
} else if _, err = writeU16(w, portRange.PortEnd); err != nil {
|
||||
return len, err
|
||||
}
|
||||
protoSize, err := portRange.PortProto.WriteTo(w)
|
||||
if err != nil {
|
||||
return len, err
|
||||
}
|
||||
return len + protoSize, nil
|
||||
}
|
||||
func (portRange *PortRange) ReadFrom(r io.Reader) (int64, error) {
|
||||
var (
|
||||
ipSize int64
|
||||
err error
|
||||
)
|
||||
portRange.IP, ipSize, err = addrRead(r)
|
||||
if err != nil {
|
||||
return ipSize, err
|
||||
}
|
||||
|
||||
ipSize += 4
|
||||
portRange.PortStart, portRange.PortEnd = readU16(r), readU16(r)
|
||||
|
||||
portRange.PortProto = PortProto("")
|
||||
protoSize, err := portRange.PortProto.ReadFrom(r)
|
||||
if err != nil {
|
||||
return ipSize, err
|
||||
}
|
||||
return ipSize + protoSize, nil
|
||||
}
|
||||
|
||||
func (proto PortProto) WriteTo(w io.Writer) (int64, error) {
|
||||
switch proto {
|
||||
case "tcp":
|
||||
return writeU8(w, 1)
|
||||
case "udp":
|
||||
return writeU8(w, 2)
|
||||
case "both":
|
||||
return writeU8(w, 3)
|
||||
}
|
||||
return 0, fmt.Errorf("invalid port proto")
|
||||
}
|
||||
func (proto PortProto) ReadFrom(r io.Reader) (int64, error) {
|
||||
switch readU8(r) {
|
||||
case 1:
|
||||
proto = PortProto("tcp")
|
||||
case 2:
|
||||
proto = PortProto("udp")
|
||||
case 3:
|
||||
proto = PortProto("both")
|
||||
default: return 0, fmt.Errorf("invalid port proto")
|
||||
}
|
||||
return 1, nil
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
type MessageEncoding interface {
|
||||
io.ReaderFrom
|
||||
io.WriterTo
|
||||
}
|
||||
|
||||
type ControlRpcMessage[T MessageEncoding] struct {
|
||||
RequestID uint64
|
||||
Content T // Convert with .(*type)
|
||||
}
|
||||
|
||||
func (rpc *ControlRpcMessage[T]) WriteTo(w io.Writer) (n int64, err error) {
|
||||
if err = binary.Write(w, binary.BigEndian, rpc.RequestID); err != nil {
|
||||
return 0, err
|
||||
} else if n, err = rpc.Content.WriteTo(w); err != nil {
|
||||
return 8, err
|
||||
}
|
||||
n += 8
|
||||
return
|
||||
}
|
||||
func (rpc *ControlRpcMessage[T]) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
if err = binary.Read(r, binary.BigEndian, &rpc.RequestID); err != nil {
|
||||
n = 0
|
||||
return n, err
|
||||
} else if n, err = rpc.Content.ReadFrom(r); err != nil {
|
||||
return 8, err
|
||||
}
|
||||
n += 8
|
||||
return
|
||||
}
|
159
tunnel/setup.go
Normal file
159
tunnel/setup.go
Normal file
@ -0,0 +1,159 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"sirherobrine23.org/playit-cloud/go-playit/api"
|
||||
"sirherobrine23.org/playit-cloud/go-playit/proto"
|
||||
)
|
||||
|
||||
type SetupFindSuitableChannel struct {
|
||||
options []netip.AddrPort
|
||||
}
|
||||
|
||||
func (self *SetupFindSuitableChannel) Setup() (ConnectedControl, error) {
|
||||
for _, addr := range self.options {
|
||||
var (
|
||||
err error
|
||||
socket *net.UDPConn
|
||||
)
|
||||
isIPv6 := addr.Addr().Is6()
|
||||
if isIPv6 {
|
||||
if socket, err = net.ListenUDP("udp6", nil); err != nil {
|
||||
continue // Next address to listen
|
||||
}
|
||||
} else {
|
||||
if socket, err = net.ListenUDP("udp4", nil); err != nil {
|
||||
continue // Next address to listen
|
||||
}
|
||||
}
|
||||
var attempts int
|
||||
if attempts = 3; isIPv6 {
|
||||
attempts = 1
|
||||
}
|
||||
for range attempts {
|
||||
buffer := new(bytes.Buffer)
|
||||
if err = (&proto.ControlRpcMessage[*proto.ControlRequest]{
|
||||
RequestID: 1,
|
||||
Content: &proto.ControlRequest{
|
||||
Ping: &proto.Ping{
|
||||
Now: time.Now(),
|
||||
CurrentPing: nil,
|
||||
SessionId: nil,
|
||||
},
|
||||
},
|
||||
}).WriteTo(buffer); err != nil {
|
||||
return ConnectedControl{}, err
|
||||
} else if _, err = socket.WriteTo(buffer.Bytes(), net.UDPAddrFromAddrPort(addr)); err != nil {
|
||||
return ConnectedControl{}, fmt.Errorf("failed to send initial ping: %s", err.Error())
|
||||
}
|
||||
buffer.Reset()
|
||||
var waits int
|
||||
if waits = 5; isIPv6 {
|
||||
waits = 3
|
||||
}
|
||||
for range waits {
|
||||
buff := make([]byte, 1024)
|
||||
socket.SetReadDeadline(time.Now().Add(time.Millisecond * 5))
|
||||
size, peer, err := socket.ReadFromUDPAddrPort(buff)
|
||||
if err != nil {
|
||||
continue
|
||||
} else if peer.Compare(addr) != 0 {
|
||||
continue
|
||||
}
|
||||
buffer = bytes.NewBuffer(buff[:size])
|
||||
feed := proto.ControlFeed{}
|
||||
if err := feed.ReadFrom(buffer); err != nil {
|
||||
continue
|
||||
} else if feed.Response != nil {
|
||||
continue
|
||||
} else if feed.Response.RequestID != 1 {
|
||||
continue
|
||||
} else if feed.Response.Content.Pong != nil {
|
||||
continue
|
||||
}
|
||||
return ConnectedControl{addr, *socket, *feed.Response.Content.Pong}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return ConnectedControl{}, fmt.Errorf("failed to connect")
|
||||
}
|
||||
|
||||
type ConnectedControl struct {
|
||||
ControlAddr netip.AddrPort
|
||||
Udp net.UDPConn
|
||||
Pong proto.Pong
|
||||
}
|
||||
|
||||
func (self *ConnectedControl) Authenticate(Api api.Api) (AuthenticatedControl, error) {
|
||||
key, err := Api.ProtoRegisterRegister(self.Pong.ClientAddr, self.Pong.TunnelAddr)
|
||||
if err != nil {
|
||||
return AuthenticatedControl{}, err
|
||||
}
|
||||
keyBytes, err := hex.DecodeString(key)
|
||||
if err != nil {
|
||||
return AuthenticatedControl{}, err
|
||||
}
|
||||
for range 5 {
|
||||
buffer := new(bytes.Buffer)
|
||||
if err := (&proto.ControlRpcMessage[proto.RawSlice]{
|
||||
RequestID: 10,
|
||||
Content: proto.RawSlice(keyBytes),
|
||||
}).WriteTo(buffer); err != nil {
|
||||
return AuthenticatedControl{}, err
|
||||
} else if _, err := self.Udp.WriteTo(buffer.Bytes(), net.UDPAddrFromAddrPort(self.ControlAddr)); err != nil {
|
||||
return AuthenticatedControl{}, err
|
||||
}
|
||||
for range 5 {
|
||||
buff := make([]byte, 1024)
|
||||
size, remote, err := self.Udp.ReadFromUDPAddrPort(buff)
|
||||
if err != nil {
|
||||
break
|
||||
} else if self.ControlAddr.Compare(remote) != 0 {
|
||||
continue
|
||||
}
|
||||
buffer.Reset()
|
||||
buffer.Write(buff[:size]) // Write only reader data
|
||||
var feed proto.ControlFeed
|
||||
if err := feed.ReadFrom(buffer); err != nil {
|
||||
continue
|
||||
} else if response := feed.Response; response != nil {
|
||||
if response.RequestID != 10 {
|
||||
continue
|
||||
}
|
||||
if content := response.Content; content.RequestQueued {
|
||||
time.Sleep(time.Second) // Sleep to wait register
|
||||
break
|
||||
} else if content.InvalidSignature {
|
||||
return AuthenticatedControl{}, fmt.Errorf("invalid signature")
|
||||
} else if content.Unauthorized {
|
||||
return AuthenticatedControl{}, fmt.Errorf("unauthorized")
|
||||
} else if registered := content.AgentRegistered; registered != nil {
|
||||
// secret_key,
|
||||
// api_client: api,
|
||||
// conn: self,
|
||||
// last_pong: pong,
|
||||
// registered,
|
||||
// buffer,
|
||||
// current_ping: None,
|
||||
// force_expired: false,
|
||||
return AuthenticatedControl{
|
||||
Api: Api,
|
||||
Conn: *self,
|
||||
LastPong: self.Pong,
|
||||
Registered: *registered,
|
||||
buffer: buffer,
|
||||
CurrentPing: nil,
|
||||
ForceExpire: false,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return AuthenticatedControl{}, fmt.Errorf("failed to connect")
|
||||
}
|
170
tunnel/simple_tunnel.go
Normal file
170
tunnel/simple_tunnel.go
Normal file
@ -0,0 +1,170 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"sirherobrine23.org/playit-cloud/go-playit/api"
|
||||
"sirherobrine23.org/playit-cloud/go-playit/proto"
|
||||
)
|
||||
|
||||
func getControlAddresses(api api.Api) ([]netip.AddrPort, error) {
|
||||
routing, err := api.AgentRoutings(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addresses := []netip.AddrPort{}
|
||||
for _, ip6 := range append(routing.Targets6, routing.Targets4...) {
|
||||
addresses = append(addresses, netip.AddrPortFrom(ip6, 5525))
|
||||
}
|
||||
return addresses, nil
|
||||
}
|
||||
|
||||
type SimpleTunnel struct {
|
||||
api api.Api
|
||||
controlAddr netip.AddrPort
|
||||
controlChannel AuthenticatedControl
|
||||
udpTunnel UdpTunnel
|
||||
lastKeepAlive, lastPing, lastPong, lastUdpAuth time.Time
|
||||
lastControlTargets []netip.AddrPort
|
||||
}
|
||||
|
||||
func NewSimpleTunnel(Api api.Api) SimpleTunnel {
|
||||
return SimpleTunnel{
|
||||
api: Api,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SimpleTunnel) Setup() error {
|
||||
udpTunnel := UdpTunnel{}
|
||||
if err := AssignUdpTunnel(&udpTunnel); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addresses, err := getControlAddresses(self.api)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
setup, err := (&SetupFindSuitableChannel{addresses}).Setup()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
controlChannel, err := setup.Authenticate(self.api)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.lastControlTargets = addresses
|
||||
self.controlAddr = setup.ControlAddr
|
||||
self.controlChannel = controlChannel
|
||||
self.udpTunnel = udpTunnel
|
||||
self.lastKeepAlive = time.UnixMilli(0)
|
||||
self.lastPing = time.UnixMilli(0)
|
||||
self.lastPong = time.UnixMilli(0)
|
||||
self.lastUdpAuth = time.UnixMilli(0)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SimpleTunnel) ReloadControlAddr() (bool, error) {
|
||||
addresses, err := getControlAddresses(self.api)
|
||||
if err != nil {
|
||||
return false, err
|
||||
} else if slices.ContainsFunc(self.lastControlTargets, func(e1 netip.AddrPort) bool {
|
||||
return !slices.Contains(addresses, e1)
|
||||
}) {
|
||||
return false, nil
|
||||
}
|
||||
setup, err := (&SetupFindSuitableChannel{addresses}).Setup()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
updated, err := self.UpdateControlAddr(setup)
|
||||
if err == nil {
|
||||
self.lastControlTargets = addresses
|
||||
}
|
||||
return updated, err
|
||||
}
|
||||
func (self *SimpleTunnel) UpdateControlAddr(connected ConnectedControl) (bool, error) {
|
||||
newControlAddr := connected.ControlAddr
|
||||
if self.controlAddr.Compare(newControlAddr) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
controlChannel, err := connected.Authenticate(self.api)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
self.controlChannel = controlChannel
|
||||
self.controlAddr = newControlAddr
|
||||
self.lastPing, self.lastKeepAlive, self.lastUdpAuth = time.UnixMilli(0), time.UnixMilli(0), time.UnixMilli(0)
|
||||
self.udpTunnel.InvalidateSession()
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (self *SimpleTunnel) UdpTunnel() UdpTunnel {
|
||||
return self.udpTunnel
|
||||
}
|
||||
|
||||
func (self *SimpleTunnel) Update() *proto.NewClient {
|
||||
if self.controlChannel.IsExpired() {
|
||||
if err := self.controlChannel.Authenticate(); err != nil {
|
||||
time.Sleep(time.Second * 2)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
if now.UnixMilli() - self.lastPing.UnixMilli() > 1_000 {
|
||||
self.lastPing = now
|
||||
if err := self.controlChannel.SendPing(200, now); err != nil {}
|
||||
}
|
||||
if self.udpTunnel.RequiresAuth() {
|
||||
if 5_000 < now.UnixMilli() - self.lastUdpAuth.UnixMilli() {
|
||||
self.lastUdpAuth = now
|
||||
if err := self.controlChannel.SendSetupUdpChannel(9_000); err != nil {}
|
||||
}
|
||||
} else if self.udpTunnel.RequireResend() {
|
||||
if 1_000 < now.UnixMilli() - self.lastUdpAuth.UnixMilli() {
|
||||
self.lastUdpAuth = now
|
||||
if _, err := self.udpTunnel.ResendToken(); err != nil {}
|
||||
}
|
||||
}
|
||||
|
||||
timeTillExpire := max(self.controlChannel.GetExpireAt().UnixMilli(), now.UnixMilli()) - now.UnixMilli()
|
||||
if 10_000 < now.UnixMilli() - self.lastKeepAlive.UnixMilli() && timeTillExpire < 30_000 {
|
||||
self.lastKeepAlive = now
|
||||
if err := self.controlChannel.SendKeepAlive(100); err != nil {}
|
||||
if err := self.controlChannel.SendSetupUdpChannel(1); err != nil {}
|
||||
}
|
||||
timeout := 0
|
||||
for range 30 {
|
||||
feed, err := self.controlChannel.RecvFeedMsg()
|
||||
if err != nil {
|
||||
continue
|
||||
} else if newClient := feed.NewClient; newClient != nil {
|
||||
return newClient
|
||||
} else if msg := feed.Response; msg != nil {
|
||||
if content := msg.Content; content != nil {
|
||||
if details := content.UdpChannelDetails; details != nil {
|
||||
if err := self.udpTunnel.SetUdpTunnel(*details); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else if content.Unauthorized {
|
||||
self.controlChannel.SetExpired()
|
||||
} else if pong := content.Pong; pong != nil {
|
||||
self.lastPong = time.Now()
|
||||
if pong.ClientAddr.Compare(self.controlChannel.Conn.Pong.ClientAddr) != 0 {}
|
||||
}
|
||||
}
|
||||
}
|
||||
if timeout++; timeout >= 10 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if self.lastPong.UnixMilli() != 0 && time.Now().UnixMilli() - self.lastPong.UnixMilli() > 6_000 {
|
||||
self.lastPong = time.UnixMilli(0)
|
||||
self.controlChannel.SetExpired()
|
||||
}
|
||||
return nil
|
||||
}
|
37
tunnel/tcp_tunnel.go
Normal file
37
tunnel/tcp_tunnel.go
Normal file
@ -0,0 +1,37 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"sirherobrine23.org/playit-cloud/go-playit/proto"
|
||||
)
|
||||
|
||||
type TcpTunnel struct {
|
||||
ClaimInstruction proto.ClaimInstructions
|
||||
}
|
||||
|
||||
func (tcpTunnel *TcpTunnel) Connect() (*net.TCPConn, error) {
|
||||
conn, err := net.DialTCP("tcp", nil, net.TCPAddrFromAddrPort(tcpTunnel.ClaimInstruction.Address))
|
||||
if err != nil {
|
||||
if conn != nil {
|
||||
conn.Close()
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
_, err = conn.Write(tcpTunnel.ClaimInstruction.Token)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
buff := make([]byte, 8)
|
||||
size, err := conn.Read(buff)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
} else if size != 8 {
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("invalid response reader size")
|
||||
}
|
||||
return conn, nil
|
||||
}
|
156
tunnel/udp_proto.go
Normal file
156
tunnel/udp_proto.go
Normal file
@ -0,0 +1,156 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/netip"
|
||||
|
||||
"sirherobrine23.org/playit-cloud/go-playit/enc"
|
||||
)
|
||||
|
||||
const (
|
||||
REDIRECT_FLOW_4_FOOTER_ID_OLD uint64 = 0x5cb867cf788173b2
|
||||
REDIRECT_FLOW_4_FOOTER_ID uint64 = 0x4448474f48414344
|
||||
REDIRECT_FLOW_6_FOOTER_ID uint64 = 0x6668676f68616366
|
||||
UDP_CHANNEL_ESTABLISH_ID uint64 = 0xd01fe6830ddce781
|
||||
|
||||
V4_LEN int = 20
|
||||
V6_LEN int = 48
|
||||
)
|
||||
|
||||
type UdpFlowBase struct {
|
||||
Src, Dst netip.AddrPort
|
||||
}
|
||||
|
||||
type UdpFlow struct {
|
||||
V4 *UdpFlowBase
|
||||
V6 *struct {
|
||||
UdpFlowBase
|
||||
Flow uint32
|
||||
}
|
||||
}
|
||||
|
||||
func (w *UdpFlow) Len() int {
|
||||
if w.V4 == nil {
|
||||
return V6_LEN
|
||||
}
|
||||
return V4_LEN
|
||||
}
|
||||
|
||||
func (w *UdpFlow) Src() netip.AddrPort {
|
||||
if w.V4 == nil {
|
||||
return w.V6.UdpFlowBase.Src
|
||||
}
|
||||
return w.V4.Src
|
||||
}
|
||||
func (w *UdpFlow) Dst() netip.AddrPort {
|
||||
if w.V4 == nil {
|
||||
return w.V6.UdpFlowBase.Dst
|
||||
}
|
||||
return w.V4.Dst
|
||||
}
|
||||
|
||||
func (w *UdpFlow) WithSrcPort(port uint16) UdpFlow {
|
||||
if w.V4 == nil {
|
||||
return UdpFlow{
|
||||
V6: &struct{UdpFlowBase; Flow uint32}{
|
||||
Flow: w.V6.Flow,
|
||||
UdpFlowBase: UdpFlowBase{
|
||||
Src: netip.AddrPortFrom(w.V6.Src.Addr(), port),
|
||||
Dst: w.V6.Src,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
return UdpFlow{
|
||||
V4: &UdpFlowBase{
|
||||
Src: netip.AddrPortFrom(w.V4.Src.Addr(), port),
|
||||
Dst: w.V4.Dst,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (w *UdpFlow) WriteTo(writer io.Writer) error {
|
||||
var conn UdpFlowBase
|
||||
if w.V4 != nil {
|
||||
conn = *w.V4
|
||||
} else {
|
||||
conn = w.V6.UdpFlowBase
|
||||
}
|
||||
if err := enc.WriteBytes(writer, conn.Src.Addr().AsSlice()); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteBytes(writer, conn.Dst.Addr().AsSlice()); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteU16(writer, conn.Src.Port()); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteU16(writer, conn.Dst.Port()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if w.V4 != nil {
|
||||
if err := enc.WriteU64(writer, REDIRECT_FLOW_4_FOOTER_ID_OLD); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := enc.WriteU32(writer, w.V6.Flow); err != nil {
|
||||
return err
|
||||
} else if err := enc.WriteU64(writer, REDIRECT_FLOW_6_FOOTER_ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func FromTailUdpFlow(slice []byte) (*UdpFlow, uint64, error) {
|
||||
if len(slice) < 8 {
|
||||
return nil, 0, fmt.Errorf("not space to footer")
|
||||
}
|
||||
footer := binary.BigEndian.Uint64(slice[len(slice)-8:])
|
||||
switch footer {
|
||||
case REDIRECT_FLOW_4_FOOTER_ID | REDIRECT_FLOW_4_FOOTER_ID_OLD:
|
||||
if len(slice) < V4_LEN {
|
||||
return nil, 0, fmt.Errorf("v4 not have space")
|
||||
}
|
||||
slice = slice[len(slice)-V4_LEN:]
|
||||
src_ip, _ := enc.ReadByteN(bytes.NewReader(slice), 4)
|
||||
srcIP, _ := netip.AddrFromSlice(src_ip)
|
||||
dst_ip, _ := enc.ReadByteN(bytes.NewReader(slice), 4)
|
||||
dstIP, _ := netip.AddrFromSlice(dst_ip)
|
||||
src_port, dst_port := enc.ReadU16(bytes.NewReader(slice)), enc.ReadU16(bytes.NewReader(slice))
|
||||
|
||||
return &UdpFlow{
|
||||
V4: &UdpFlowBase{
|
||||
Src: netip.AddrPortFrom(srcIP, src_port),
|
||||
Dst: netip.AddrPortFrom(dstIP, dst_port),
|
||||
},
|
||||
}, 0, nil
|
||||
case REDIRECT_FLOW_6_FOOTER_ID:
|
||||
if len(slice) < V6_LEN {
|
||||
return nil, footer, fmt.Errorf("v6 not have space")
|
||||
}
|
||||
slice = slice[len(slice)-V6_LEN:]
|
||||
src_ip, _ := enc.ReadByteN(bytes.NewReader(slice), 16)
|
||||
srcIP, _ := netip.AddrFromSlice(src_ip)
|
||||
dst_ip, _ := enc.ReadByteN(bytes.NewReader(slice), 16)
|
||||
dstIP, _ := netip.AddrFromSlice(dst_ip)
|
||||
src_port, dst_port := enc.ReadU16(bytes.NewReader(slice)), enc.ReadU16(bytes.NewReader(slice))
|
||||
flow := enc.ReadU32(bytes.NewReader(slice))
|
||||
|
||||
return &UdpFlow{
|
||||
V6: &struct {
|
||||
UdpFlowBase
|
||||
Flow uint32
|
||||
}{
|
||||
UdpFlowBase{
|
||||
Src: netip.AddrPortFrom(srcIP, src_port),
|
||||
Dst: netip.AddrPortFrom(dstIP, dst_port),
|
||||
},
|
||||
flow,
|
||||
},
|
||||
}, 0, nil
|
||||
}
|
||||
return nil, footer, nil
|
||||
}
|
223
tunnel/udp_tunnel.go
Normal file
223
tunnel/udp_tunnel.go
Normal file
@ -0,0 +1,223 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"slices"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"sirherobrine23.org/playit-cloud/go-playit/proto"
|
||||
)
|
||||
|
||||
type UdpTunnel struct {
|
||||
Udp4 *net.UDPConn
|
||||
Udp6 *net.UDPConn
|
||||
locker sync.Mutex
|
||||
Details ChannelDetails
|
||||
LastConfirm atomic.Uint32
|
||||
LastSend atomic.Uint32
|
||||
}
|
||||
|
||||
type ChannelDetails struct {
|
||||
Udp *proto.UdpChannelDetails
|
||||
AddrHistory []netip.AddrPort
|
||||
}
|
||||
|
||||
func AssignUdpTunnel(tunUdp *UdpTunnel) error {
|
||||
// LogDebug.Println("Assign UDP Tunnel IPv4")
|
||||
udp4, err := net.ListenUDP("udp4", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tunUdp.Udp4 = udp4
|
||||
// IPv6 opcional
|
||||
// LogDebug.Println("Assign UDP Tunnel IPv6")
|
||||
if tunUdp.Udp6, err = net.ListenUDP("udp6", nil); err != nil {
|
||||
// LogDebug.Println("Cannot listen IPv6 Udp Tunnel")
|
||||
tunUdp.Udp6 = nil
|
||||
err = nil
|
||||
}
|
||||
|
||||
tunUdp.Details = ChannelDetails{
|
||||
AddrHistory: []netip.AddrPort{},
|
||||
Udp: nil,
|
||||
}
|
||||
|
||||
tunUdp.LastConfirm = atomic.Uint32{}
|
||||
tunUdp.LastSend = atomic.Uint32{}
|
||||
tunUdp.LastConfirm.Store(0)
|
||||
tunUdp.LastSend.Store(0)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (udp *UdpTunnel) IsSetup() bool {
|
||||
return udp.Details.Udp != nil
|
||||
}
|
||||
|
||||
func (udp *UdpTunnel) InvalidateSession() {
|
||||
udp.LastConfirm.Store(0)
|
||||
udp.LastSend.Store(0)
|
||||
}
|
||||
|
||||
func now_sec() uint32 {
|
||||
return uint32(time.Now().UnixMilli()) / 1_000
|
||||
}
|
||||
|
||||
func (udp *UdpTunnel) RequireResend() bool {
|
||||
last_confirm := udp.LastConfirm.Load()
|
||||
/* send token every 10 seconds */
|
||||
return 10 < now_sec()-last_confirm
|
||||
}
|
||||
|
||||
func (udp *UdpTunnel) RequiresAuth() bool {
|
||||
lastConf, lastSend := udp.LastConfirm.Load(), udp.LastSend.Load()
|
||||
if lastSend < lastConf {
|
||||
return false
|
||||
}
|
||||
return 5 < now_sec()-lastSend
|
||||
}
|
||||
|
||||
func (udp *UdpTunnel) SetUdpTunnel(details proto.UdpChannelDetails) error {
|
||||
// LogDebug.Println("Updating Udp Tunnel")
|
||||
udp.locker.Lock()
|
||||
defer udp.locker.Unlock()
|
||||
if udp.Details.Udp != nil {
|
||||
current := udp.Details.Udp
|
||||
if bytes.Equal(current.Token, details.Token) && current.TunnelAddr.Compare(details.TunnelAddr) == 0 {
|
||||
udp.locker.Unlock()
|
||||
return nil
|
||||
}
|
||||
if current.TunnelAddr.Compare(details.TunnelAddr) != 0 {
|
||||
// LogDebug.Println("changed udp tunner addr")
|
||||
oldAddr := current.TunnelAddr
|
||||
udp.Details.AddrHistory = append(udp.Details.AddrHistory, oldAddr)
|
||||
}
|
||||
udp.Details.Udp = &details
|
||||
}
|
||||
|
||||
return udp.SendToken(&details)
|
||||
}
|
||||
|
||||
func (udp *UdpTunnel) ResendToken() (bool, error) {
|
||||
lock := udp.Details
|
||||
if lock.Udp == nil {
|
||||
return false, nil
|
||||
} else if err := udp.SendToken(lock.Udp); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (udp *UdpTunnel) SendToken(details *proto.UdpChannelDetails) error {
|
||||
if details.TunnelAddr.Addr().Is4() {
|
||||
udp.Udp4.WriteToUDPAddrPort(details.Token, details.TunnelAddr)
|
||||
} else {
|
||||
if udp.Udp6 == nil {
|
||||
return fmt.Errorf("ipv6 not supported")
|
||||
}
|
||||
udp.Udp6.WriteToUDPAddrPort(details.Token, details.TunnelAddr)
|
||||
}
|
||||
// LogDebug.Printf("send udp session token (len=%d) to %s\n", len(details.Token), details.TunnelAddr.AddrPort.String())
|
||||
udp.LastSend.Store(now_sec())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (udp *UdpTunnel) GetSock() (*net.UDPConn, *netip.AddrPort, error) {
|
||||
lock := udp.Details
|
||||
if lock.Udp == nil {
|
||||
// LogDebug.Println("udp tunnel not connected")
|
||||
return nil, nil, fmt.Errorf("udp tunnel not connected")
|
||||
} else if lock.Udp.TunnelAddr.Addr().Is4() {
|
||||
return udp.Udp4, &lock.Udp.TunnelAddr, nil
|
||||
} else if udp.Udp6 == nil {
|
||||
// LogDebug.Println("ipv6 not setup")
|
||||
return nil, nil, fmt.Errorf("ipv6 not setup")
|
||||
}
|
||||
return udp.Udp6, &lock.Udp.TunnelAddr, nil
|
||||
}
|
||||
|
||||
func (Udp *UdpTunnel) Send(data []byte, Flow UdpFlow) (int, error) {
|
||||
buff := bytes.NewBuffer([]byte{})
|
||||
if err := Flow.WriteTo(buff); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
socket, addr, err := Udp.GetSock()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return socket.WriteToUDPAddrPort(append(data, buff.Bytes()...), *addr)
|
||||
}
|
||||
|
||||
func (Udp *UdpTunnel) GetToken() ([]byte, error) {
|
||||
lock := Udp.Details
|
||||
if lock.Udp == nil {
|
||||
return nil, fmt.Errorf("udp tunnel not connected")
|
||||
}
|
||||
return lock.Udp.Token[:], nil
|
||||
}
|
||||
|
||||
type UdpTunnelRx struct {
|
||||
ConfirmerdConnection bool
|
||||
ReceivedPacket *struct {
|
||||
Bytes uint64
|
||||
Flow UdpFlow
|
||||
}
|
||||
}
|
||||
|
||||
func (Udp *UdpTunnel) ReceiveFrom(buff []byte) (*UdpTunnelRx, error) {
|
||||
udp, tunnelAddr, err := Udp.GetSock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
byteSize, remote, err := udp.ReadFromUDPAddrPort(buff)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tunnelAddr.Compare(remote) != 0 {
|
||||
lock := Udp.Details
|
||||
if !slices.ContainsFunc(lock.AddrHistory, func(a netip.AddrPort) bool {
|
||||
return a.Compare(remote) == 0
|
||||
}) {
|
||||
return nil, fmt.Errorf("got data from other source")
|
||||
}
|
||||
}
|
||||
token, err := Udp.GetToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// LogDebug.Println("Check token")
|
||||
// LogDebug.Println(buff)
|
||||
// LogDebug.Println(token)
|
||||
// LogDebug.Println("end check token")
|
||||
if bytes.Equal(buff[:byteSize], token) {
|
||||
// LogDebug.Println("udp session confirmed")
|
||||
Udp.LastConfirm.Store(now_sec())
|
||||
return &UdpTunnelRx{ConfirmerdConnection: true}, nil
|
||||
}
|
||||
|
||||
if len(buff)+V6_LEN < byteSize {
|
||||
return nil, fmt.Errorf("receive buffer too small")
|
||||
}
|
||||
|
||||
footer, footerInt, err := FromTailUdpFlow(buff[byteSize:])
|
||||
if err != nil {
|
||||
if footerInt == UDP_CHANNEL_ESTABLISH_ID {
|
||||
actual := hex.EncodeToString(buff[byteSize:])
|
||||
expected := hex.EncodeToString(token)
|
||||
return nil, fmt.Errorf("unexpected UDP establish packet, actual: %s, expected: %s", actual, expected)
|
||||
}
|
||||
return nil, fmt.Errorf("failed to extract udp footer: %s, err: %s", hex.EncodeToString(buff[byteSize:]), err.Error())
|
||||
}
|
||||
return &UdpTunnelRx{ReceivedPacket: &struct {
|
||||
Bytes uint64
|
||||
Flow UdpFlow
|
||||
}{uint64(byteSize) - uint64(footer.Len()), *footer}}, nil
|
||||
}
|
Reference in New Issue
Block a user