playit.gg go implementation #1

Open
Sirherobrine23 wants to merge 6 commits from breaked into main
37 changed files with 2165 additions and 1722 deletions
Showing only changes of commit de15644b41 - Show all commits

1
.gitignore vendored
View File

@ -21,3 +21,4 @@
# Go workspace file
go.work
main.go

View File

@ -3,7 +3,7 @@ package api
import (
"bytes"
"encoding/json"
"net"
"fmt"
"net/netip"
"github.com/google/uuid"
@ -15,18 +15,32 @@ type PortRange struct {
}
type AgentTunnel struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
IpNum uint16 `json:"ip_num"`
RegionNum uint16 `json:"region_num"`
Port PortRange `json:"port"`
Proto string `json:"proto"`
LocalIp net.IP `json:"local_ip"`
LocalPort uint16 `json:"local_port"`
TunnelType string `json:"tunnel_type"`
AssignedDomain string `json:"assigned_domain"`
CustomDomain string `json:"custom_domain"`
Disabled *any `json:"disabled"`
ID uuid.UUID `json:"id"`
Name string `json:"name"`
IpNum uint16 `json:"ip_num"`
RegionNum uint16 `json:"region_num"`
Port PortRange `json:"port"`
Proto string `json:"proto"`
LocalIp netip.Addr `json:"local_ip"`
LocalPort uint16 `json:"local_port"`
TunnelType string `json:"tunnel_type"`
AssignedDomain string `json:"assigned_domain"`
CustomDomain string `json:"custom_domain"`
Disabled *any `json:"disabled"`
}
func (tun *AgentTunnel) DestString() string {
return fmt.Sprintf("%s:%d", tun.LocalIp, tun.LocalPort)
}
func (tun *AgentTunnel) SourceString() string {
var addr string
if addr = tun.CustomDomain; addr == "" {
addr = tun.AssignedDomain
}
if tun.TunnelType == "minecraft-java" {
return addr
}
return fmt.Sprintf("%s:%d", addr, tun.Port.From)
}
type AgentPendingTunnel struct {

View File

@ -1,6 +1,7 @@
package network
import (
"encoding/binary"
"net/netip"
"sirherobrine23.org/playit-cloud/go-playit/api"
@ -13,4 +14,84 @@ type AddressValue[V any] struct {
type AddressLookup[Value any] interface {
Lookup(IP netip.Addr, Port uint16, Proto api.PortProto) *AddressValue[Value]
}
type MatchIP struct {
IPNumber uint64
RegionID *uint16
}
func (slef *MatchIP) Matches(ip netip.Addr) bool {
if ip.Is6() {
other := NewMatchIP(ip)
return slef.IPNumber == other.IPNumber && slef.RegionID == other.RegionID
}
octs := ip.As4()
if uint64(octs[3]) != slef.IPNumber {
return false
}
if slef.RegionID == nil {
return true
}
return RegionNumberV4(ip) == *slef.RegionID
}
func NewMatchIP(ip netip.Addr) MatchIP {
parts := ip.As16()
regionID := binary.BigEndian.Uint16([]byte{parts[6], parts[7]})
ipNumber := binary.BigEndian.Uint64([]byte{
parts[8],
parts[9],
parts[10],
parts[11],
parts[12],
parts[13],
parts[14],
parts[15],
})
info := MatchIP{IPNumber: ipNumber}
if regionID != 0 {
info.RegionID = new(uint16)
*info.RegionID = regionID
}
return info
}
func RegionNumberV4(ip netip.Addr) uint16 {
octs := ip.As4();
if octs[0] == 147 && octs[1] == 185 && octs[2] == 221 { /* 147.185.221.0/24 (1) */
return 1
} else if octs[0] == 209 && octs[1] == 25 && octs[2] >= 140 && octs[2] <= 143 { /* 209.25.140.0/22 (2 to 5) */
return uint16(2 + (octs[2] - 140))
} else if octs[0] == 23 && octs[1] == 133 && octs[2] == 216 { /* 23.133.216.0/24 (6) */
return 6
}
/* global IP */
return 0
}
type MappingOverride struct {
Proto api.PortProto
Port api.PortRange
LocalAddr netip.AddrPort
MatchIP MatchIP
}
type LookupWithOverrides []MappingOverride
func (look *LookupWithOverrides) Lookup(IP netip.Addr, Port uint16, Proto api.PortProto) *AddressValue[netip.AddrPort] {
for _, over := range *look {
if (over.Port.From <= Port && Port < over.Port.To) && (over.Proto == "both" || over.Proto == Proto) {
return &AddressValue[netip.AddrPort]{
Value: over.LocalAddr,
FromPort: over.Port.From,
ToPort: over.Port.To,
}
}
}
return &AddressValue[netip.AddrPort]{
Value: netip.AddrPortFrom(netip.IPv4Unspecified(), Port),
FromPort: Port,
ToPort: Port+1,
}
}

View File

@ -21,7 +21,7 @@ func asLocalMasked(ip uint32) uint32 {
return ip | 0x7F000000
}
func mapToLocalIP4(ip net.IP) net.IP {
func mapToLocalIP4(ip net.IP) netip.Addr {
var ipUint32 uint32
if ip.To4() != nil { // Check if it's already IPv4
ipUint32 = binary.BigEndian.Uint32(ip.To4())
@ -33,24 +33,22 @@ func mapToLocalIP4(ip net.IP) net.IP {
shuffle(binary.BigEndian.Uint32(bytes[12:16]))
}
return net.IPv4(
return netip.AddrFrom4([4]byte{
byte(asLocalMasked(ipUint32)>>24),
byte(asLocalMasked(ipUint32)>>16),
byte(asLocalMasked(ipUint32)>>8),
byte(asLocalMasked(ipUint32)),
)
})
}
func TcpSocket(SpecialLan bool, Peer, Host netip.AddrPort) (*net.TCPConn, error) {
isLoopback := Host.Addr().IsLoopback()
if isLoopback && SpecialLan {
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())
return nil, err
stream, err := net.DialTCP("tcp", net.TCPAddrFromAddrPort(netip.AddrPortFrom(mapToLocalIP4(Peer.Addr().AsSlice()), 0)), net.TCPAddrFromAddrPort(Host))
if err == nil {
return stream, nil
}
return stream, 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 bind connection to special local address to support IP based banning")
stream, err := net.DialTCP("tcp", nil, net.TCPAddrFromAddrPort(Host))
@ -66,20 +64,14 @@ func UdpSocket(SpecialLan bool, Peer, Host netip.AddrPort) (*net.UDPConn, error)
if isLoopback && SpecialLan {
local_ip := mapToLocalIP4(Peer.Addr().AsSlice());
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))
stream, err := net.ListenUDP("udp4", net.UDPAddrFromAddrPort(netip.AddrPortFrom(local_ip, local_port)))
if err != nil {
// 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))
stream, err = net.ListenUDP("udp4", net.UDPAddrFromAddrPort(netip.AddrPortFrom(local_ip, 0)))
if err != nil {
// 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())
stream, err = net.ListenUDP("udp4", nil)
}
}
return stream, nil
return stream, err
}
return net.DialUDP("udp", nil, net.UDPAddrFromAddrPort(Host))
}

View File

@ -105,7 +105,7 @@ func (self *UdpClients) ClientCount() int {
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"))
found := self.lookup.Lookup(flowDst.Addr(), flowDst.Port(), api.PortProto("udp"))
if found == nil {
return fmt.Errorf("could not find tunnel")
}
@ -116,8 +116,9 @@ func (self *UdpClients) ForwardPacket(Flow tunnel.UdpFlow, data []byte) error {
return client.SendLocal(flowDst.Port(), data)
}
}
self.udpClientsLocker.Lock()
defer self.udpClientsLocker.Unlock()
self.udpClientsLocker.Lock()
client, err := func() (*UdpClient, error) {
for kkey, client := range self.udpClients {
@ -128,23 +129,18 @@ func (self *UdpClients) ForwardPacket(Flow tunnel.UdpFlow, data []byte) error {
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(),
if Flow.IPSrc.Addr().Is4() {
clientAddr = netip.AddrPortFrom(Flow.IPSrc.Addr(), Flow.IPSrc.Port())
sendFlow = tunnel.UdpFlow{
IPSrc: netip.AddrPortFrom(Flow.IPDst.Addr(), found.FromPort),
IPDst: 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(),
},
clientAddr = netip.AddrPortFrom(Flow.IPSrc.Addr(), Flow.IPSrc.Port())
sendFlow = tunnel.UdpFlow{
IPSrc: netip.AddrPortFrom(Flow.IPDst.Addr(), found.FromPort),
IPDst: Flow.Src(),
Flow: sendFlow.Flow,
}
}

View File

@ -386,9 +386,6 @@ func (pong *Pong) ReadFrom(r io.Reader) error {
} else if err := enc.ReadOption(r, func(r io.Reader) (err error) {
pong.SessionExpireAt = new(time.Time)
*pong.SessionExpireAt = time.UnixMilli(enc.Read64(r)) // Fix set SessionExpireAt
// expAt := time.UnixMilli(enc.Read64(r)) // Fix set SessionExpireAt
// fmt.Printf("pong.SessionExpireAt: %s\n", expAt.String())
// pong.SessionExpireAt = &expAt
return nil
}); err != nil {
return err

107
runner/autorun.go Normal file
View File

@ -0,0 +1,107 @@
package runner
import (
"fmt"
"net/netip"
"sync"
"time"
"sirherobrine23.org/playit-cloud/go-playit/api"
"sirherobrine23.org/playit-cloud/go-playit/network"
)
type TunnelEntry struct {
PubAddress string
MatchIP network.MatchIP
PortType api.PortProto
FromPort, ToPort uint16
LocalStartAdress netip.AddrPort
}
type LocalLookup struct {
AdreessLock sync.Mutex
Adreess []TunnelEntry
}
func (look *LocalLookup) Lookup(IP netip.Addr, Port uint16, Proto api.PortProto) *network.AddressValue[netip.AddrPort] {
look.AdreessLock.Lock()
defer look.AdreessLock.Unlock()
for _, tunnel := range look.Adreess {
if tunnel.PortType != Proto && tunnel.PortType != "both" {
continue
} else if !tunnel.MatchIP.Matches(IP) {
continue
} else if tunnel.FromPort <= Port && Port < tunnel.ToPort {
return &network.AddressValue[netip.AddrPort]{
Value: tunnel.LocalStartAdress,
FromPort: tunnel.FromPort,
ToPort: tunnel.ToPort,
}
}
}
return nil
}
func (look *LocalLookup) Update(tunnels []api.AgentTunnel) {
entries := []TunnelEntry{}
for _, tunnel := range tunnels {
tun := TunnelEntry{
PortType: api.PortProto(tunnel.Proto),
FromPort: tunnel.Port.From,
ToPort: tunnel.Port.To,
LocalStartAdress: netip.AddrPortFrom(tunnel.LocalIp, tunnel.LocalPort),
MatchIP: network.MatchIP{IPNumber: uint64(tunnel.IpNum)},
}
if tunnel.RegionNum != 0 {
tun.MatchIP.RegionID = new(uint16)
*tun.MatchIP.RegionID = tunnel.RegionNum
}
entries = append(entries, tun)
}
look.AdreessLock.Lock()
defer look.AdreessLock.Unlock()
look.Adreess = entries
}
func Autorun(Api api.Api) error {
lookup := LocalLookup{Adreess: []TunnelEntry{}, AdreessLock: sync.Mutex{}}
tuns, err := Api.AgentInfo()
if err != nil {
return err
}
lookup.Update(tuns.Tunnels)
for _, tun := range tuns.Tunnels {
src, dst := tun.SourceString(), tun.DestString()
if tun.Disabled != nil {
fmt.Printf("%s -> %s (Disabled)\n", src, dst)
} else if tun.TunnelType != "" {
fmt.Printf("%s -> %s (%s)\n", src, dst, tun.TunnelType)
} else {
fmt.Printf("%s -> %s (Proto: %s, Port Count %d)\n", src, dst, tun.Proto, tun.Port.To - tun.Port.From)
}
}
var runner TunnelRunner
errorCount := 0
for {
runner, err = NewTunnelRunner(Api, &lookup)
if err == nil {
break
} else if errorCount++; errorCount > 5 {
return err
}
<-time.After(time.Second*2)
}
runing := runner.Run()
go func(){
for runner.KeepRunning.Load() {
if tuns, err = Api.AgentInfo(); err != nil {
<-time.After(time.Second*3)
continue
}
lookup.Update(tuns.Tunnels)
<-time.After(time.Second*3)
}
}()
defer runner.KeepRunning.Store(false)
return <- runing
}

View File

@ -3,6 +3,7 @@ package runner
import (
"fmt"
"io"
"net"
"net/netip"
"sync/atomic"
"time"
@ -25,7 +26,7 @@ func NewTunnelRunner(Api api.Api, Lookup network.AddressLookup[netip.AddrPort])
if err := tunnel.Setup(); err != nil {
return TunnelRunner{}, err
}
udp_clients := network.NewUdpClients(tunnel.UdpTunnel(), Lookup)
udp_clients := network.NewUdpClients(*tunnel.UdpTunnel(), Lookup)
var keep atomic.Bool
keep.Store(true)
return TunnelRunner{
@ -42,7 +43,7 @@ func (self *TunnelRunner) SetSpecialLan(setUse bool) {
self.UdpClients.UseSpecialLan = setUse
}
func (self *TunnelRunner) Run() {
func (self *TunnelRunner) Run() chan error {
end := make(chan error)
tunnel := self.Tunnel
go func() {
@ -54,33 +55,37 @@ func (self *TunnelRunner) Run() {
if _, err := tunnel.ReloadControlAddr(); err != nil {
}
}
fmt.Println("Reload")
fmt.Println("Reciving new connection")
if new_client := tunnel.Update(); new_client != nil {
fmt.Println("New TCP Client")
clients := self.TcpClients
found := self.Lookup.Lookup(new_client.ConnectAddr.Addr(), new_client.ConnectAddr.Port(), api.PortProto("tcp"))
if found == nil {
fmt.Println("could not find local address for connection")
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 {
var (
tunnel_conn *network.TcpClient
local_conn *net.TCPConn
err error
)
if tunnel_conn, err = self.TcpClients.Connect(*new_client); err != nil {
return
}
defer tunnel_conn.Stream.Close()
local_conn, err := network.TcpSocket(self.TcpClients.UseSpecialLAN, peerAddr, local_addr)
if err != nil {
defer tunnel_conn.Dropper.Drop()
if local_conn, err = network.TcpSocket(self.TcpClients.UseSpecialLAN, new_client.PeerAddr, netip.AddrPortFrom(found.Value.Addr(), (new_client.ConnectAddr.Port()-found.FromPort)+found.Value.Port())); err != nil {
return
}
defer local_conn.Close()
done := make(chan struct{})
defer close(done)
go func() {
io.Copy(&tunnel_conn.Stream, local_conn)
done <- struct{}{}
}()
go func() {
io.Copy(local_conn, &tunnel_conn.Stream)
done <- struct{}{}
@ -92,25 +97,27 @@ func (self *TunnelRunner) Run() {
}
}()
// udp_clients := self.UdpClients
// go func(){
// buffer := make([]byte, 2048)
// // had_success := false
// udp := tunnel.UdpTunnel()
// for self.KeepRunning.Load() {
// buffer := make([]byte, 2048)
// fmt.Println("udp rec")
// rx, err := udp.ReceiveFrom(buffer)
// fmt.Println(rx)
// if err != nil {
// fmt.Println(err)
// time.Sleep(time.Second)
// continue
// }
// if rx.ConfirmerdConnection {
// continue
// }
// d,_:=json.MarshalIndent(rx, "", " ")
// fmt.Printf("rx: %s\n", string(d))
// bytes, flow := rx.ReceivedPacket.Bytes, rx.ReceivedPacket.Flow
// if err := udp_clients.ForwardPacket(flow, buffer[:bytes]); err != nil {
// if err := self.UdpClients.ForwardPacket(flow, buffer[:bytes]); err != nil {
// panic(err)
// }
// }
// }()
<-end
return end
}

View File

@ -88,11 +88,9 @@ func (self *AuthenticatedControl) Authenticate() (AuthenticatedControl, error) {
func (self *AuthenticatedControl) RecvFeedMsg() (proto.ControlFeed, error) {
buff := make([]byte, 1024)
fmt.Println("RecvFeedMsg")
self.Conn.Udp.SetReadDeadline(*new(time.Time))
// self.Conn.Udp.SetReadDeadline(time.Now().Add(23_000_000_000))
// self.Conn.Udp.SetReadDeadline(*new(time.Time))
self.Conn.Udp.SetReadDeadline(*new(time.Time)) // Remove deadline
size, remote, err := self.Conn.Udp.ReadFromUDPAddrPort(buff)
fmt.Println("End RecvFeedMsg")
if err != nil {
return proto.ControlFeed{}, err
} else if remote.Compare(self.Conn.ControlAddr) != 0 {

View File

@ -3,7 +3,6 @@ package tunnel
import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"net"
"net/netip"
@ -137,8 +136,6 @@ func (self *ConnectedControl) Authenticate(Api api.Api) (AuthenticatedControl, e
if response := feed.Response; response != nil {
if response.RequestID != 10 {
d,_:=json.MarshalIndent(feed, "", " ")
fmt.Printf("Setup: %s\n", string(d))
continue
}
if content := response.Content; content.RequestQueued {

View File

@ -27,7 +27,7 @@ type SimpleTunnel struct {
api api.Api
controlAddr netip.AddrPort
controlChannel AuthenticatedControl
udpTunnel UdpTunnel
udpTunnel *UdpTunnel
lastKeepAlive, lastPing, lastPong, lastUdpAuth time.Time
lastControlTargets []netip.AddrPort
}
@ -39,8 +39,8 @@ func NewSimpleTunnel(Api api.Api) SimpleTunnel {
}
func (self *SimpleTunnel) Setup() error {
udpTunnel := UdpTunnel{}
if err := AssignUdpTunnel(&udpTunnel); err != nil {
udpTunnel := new(UdpTunnel)
if err := AssignUdpTunnel(udpTunnel); err != nil {
return err
}
@ -104,7 +104,7 @@ func (self *SimpleTunnel) UpdateControlAddr(connected ConnectedControl) (bool, e
return true, nil
}
func (self *SimpleTunnel) UdpTunnel() UdpTunnel {
func (self *SimpleTunnel) UdpTunnel() *UdpTunnel {
return self.udpTunnel
}
@ -119,59 +119,64 @@ func (self *SimpleTunnel) Update() *proto.NewClient {
}
now := time.Now()
if now.UnixMilli() - self.lastPing.UnixMilli() > 1_000 {
if now.UnixMilli()-self.lastPing.UnixMilli() > 1_000 {
self.lastPing = now
if err := self.controlChannel.SendPing(200, now); err != nil {}
if err := self.controlChannel.SendPing(200, now); err != nil {
}
}
if self.udpTunnel.RequiresAuth() {
if 5_000 < now.UnixMilli() - self.lastUdpAuth.UnixMilli() {
if 5_000 < now.UnixMilli()-self.lastUdpAuth.UnixMilli() {
self.lastUdpAuth = now
if err := self.controlChannel.SendSetupUdpChannel(9_000); err != nil {}
if err := self.controlChannel.SendSetupUdpChannel(9_000); err != nil {
}
}
} else if self.udpTunnel.RequireResend() {
if 1_000 < now.UnixMilli() - self.lastUdpAuth.UnixMilli() {
if 1_000 < now.UnixMilli()-self.lastUdpAuth.UnixMilli() {
self.lastUdpAuth = now
if _, err := self.udpTunnel.ResendToken(); err != nil {}
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 {
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 {}
if err := self.controlChannel.SendKeepAlive(100); err != nil {
}
if err := self.controlChannel.SendSetupUdpChannel(1); err != nil {
}
}
for range 30 {
feed, err := self.controlChannel.RecvFeedMsg()
if err != nil {
fmt.Println(err)
fmt.Printf("Update: %s", err.Error())
continue
}
d,_:=json.MarshalIndent(feed, "", " ")
fmt.Printf("SimTunne: %s\n", string(d))
d, _ := json.MarshalIndent(feed, "", " ")
fmt.Println(string(d))
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 {
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 {
fmt.Println("client ip changed", pong.ClientAddr.String(), self.controlChannel.Conn.Pong.ClientAddr.String())
}
// if pong.ClientAddr.Compare(self.controlChannel.Conn.Pong.ClientAddr) != 0 {
// fmt.Println("client ip changed", pong.ClientAddr.String(), self.controlChannel.Conn.Pong.ClientAddr.String())
// }
}
}
}
}
if self.lastPong.UnixMilli() != 0 && time.Now().UnixMilli() - self.lastPong.UnixMilli() > 6_000 {
if self.lastPong.UnixMilli() != 0 && time.Now().UnixMilli()-self.lastPong.UnixMilli() > 6_000 {
self.lastPong = time.UnixMilli(0)
self.controlChannel.SetExpired()
}
return nil
}
}

View File

@ -20,83 +20,51 @@ const (
V6_LEN int = 48
)
type UdpFlowBase struct {
Src, Dst netip.AddrPort
}
type UdpFlow struct {
V4 *UdpFlowBase
V6 *struct {
UdpFlowBase
Flow uint32
}
IPSrc, IPDst netip.AddrPort
Flow uint32
}
func (w *UdpFlow) Len() int {
if w.V4 == nil {
return V6_LEN
if w.IPSrc.Addr().Is4() {
return V4_LEN
}
return V4_LEN
return V6_LEN
}
func (w *UdpFlow) Src() netip.AddrPort {
if w.V4 == nil {
return w.V6.UdpFlowBase.Src
}
return w.V4.Src
return w.IPSrc
}
func (w *UdpFlow) Dst() netip.AddrPort {
if w.V4 == nil {
return w.V6.UdpFlowBase.Dst
}
return w.V4.Dst
return w.IPDst
}
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,
},
IPSrc: netip.AddrPortFrom(w.IPSrc.Addr(), port),
IPDst: w.IPSrc,
}
}
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 {
if err := enc.WriteBytes(writer, w.IPSrc.Addr().AsSlice()); err != nil {
return err
} else if err := enc.WriteBytes(writer, conn.Dst.Addr().AsSlice()); err != nil {
} else if err := enc.WriteBytes(writer, w.IPDst.Addr().AsSlice()); err != nil {
return err
} else if err := enc.WriteU16(writer, conn.Src.Port()); err != nil {
} else if err := enc.WriteU16(writer, w.IPSrc.Port()); err != nil {
return err
} else if err := enc.WriteU16(writer, conn.Dst.Port()); err != nil {
} else if err := enc.WriteU16(writer, w.IPDst.Port()); err != nil {
return err
}
if w.V4 != nil {
if err := enc.WriteU64(writer, REDIRECT_FLOW_4_FOOTER_ID_OLD); err != nil {
if w.IPSrc.Addr().Is6() {
if err := enc.WriteU32(writer, w.Flow); err != nil {
return err
} else if err := enc.WriteU64(writer, REDIRECT_FLOW_6_FOOTER_ID); 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 {
if err := enc.WriteU64(writer, REDIRECT_FLOW_4_FOOTER_ID_OLD); err != nil {
return err
}
}
@ -104,53 +72,55 @@ func (w *UdpFlow) WriteTo(writer io.Writer) error {
return nil
}
func FromTailUdpFlow(slice []byte) (*UdpFlow, uint64, error) {
func FromTailUdpFlow(slice []byte) (UdpFlow, uint64, error) {
if len(slice) < 8 {
return nil, 0, fmt.Errorf("not space to footer")
return UdpFlow{}, 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:
footer := binary.BigEndian.Uint64(slice[(len(slice)-8):])
if footer == REDIRECT_FLOW_4_FOOTER_ID || footer == REDIRECT_FLOW_4_FOOTER_ID_OLD || footer == (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")
return UdpFlow{}, 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))
reader := bytes.NewReader(slice[len(slice)-V4_LEN:])
return &UdpFlow{
V4: &UdpFlowBase{
Src: netip.AddrPortFrom(srcIP, src_port),
Dst: netip.AddrPortFrom(dstIP, dst_port),
},
}, 0, nil
case REDIRECT_FLOW_6_FOOTER_ID:
var err error
var src_ip, dst_ip []byte
if src_ip, err = enc.ReadByteN(reader, 4); err != nil {
return UdpFlow{}, 0, err
} else if dst_ip, err = enc.ReadByteN(reader, 4); err != nil {
return UdpFlow{}, 0, err
}
src_port, dst_port := enc.ReadU16(reader), enc.ReadU16(reader)
srcIP := netip.AddrFrom4([4]byte(src_ip))
dstIP := netip.AddrFrom4([4]byte(dst_ip))
var point UdpFlow
point.IPSrc = netip.AddrPortFrom(srcIP, src_port)
point.IPDst = netip.AddrPortFrom(dstIP, dst_port)
return point, 0, nil
} else if footer == REDIRECT_FLOW_6_FOOTER_ID {
if len(slice) < V6_LEN {
return nil, footer, fmt.Errorf("v6 not have space")
return UdpFlow{}, 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))
reader := bytes.NewReader(slice[len(slice)-V4_LEN:])
return &UdpFlow{
V6: &struct {
UdpFlowBase
Flow uint32
}{
UdpFlowBase{
Src: netip.AddrPortFrom(srcIP, src_port),
Dst: netip.AddrPortFrom(dstIP, dst_port),
},
flow,
},
}, 0, nil
var err error
var src_ip, dst_ip []byte
if src_ip, err = enc.ReadByteN(reader, 16); err != nil {
return UdpFlow{}, 0, err
} else if dst_ip, err = enc.ReadByteN(reader, 16); err != nil {
return UdpFlow{}, 0, err
}
src_port, dst_port, flow := enc.ReadU16(reader), enc.ReadU16(reader), enc.ReadU32(reader)
srcIP := netip.AddrFrom16([16]byte(src_ip))
dstIP := netip.AddrFrom16([16]byte(dst_ip))
var point UdpFlow
point.IPSrc = netip.AddrPortFrom(srcIP, src_port)
point.IPDst = netip.AddrPortFrom(dstIP, dst_port)
point.Flow = flow
return point, 0, nil
}
return nil, footer, nil
return UdpFlow{}, footer, fmt.Errorf("read fotter")
}

View File

@ -82,26 +82,26 @@ func (udp *UdpTunnel) RequiresAuth() bool {
return 5 < now_sec()-lastSend
}
func (udp *UdpTunnel) SetUdpTunnel(details proto.UdpChannelDetails) error {
func (udp *UdpTunnel) SetUdpTunnel(details *proto.UdpChannelDetails) error {
// LogDebug.Println("Updating Udp Tunnel")
{
udp.locker.Lock()
if current := udp.Details.Udp; current != nil {
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.locker.Lock()
if current := udp.Details.Udp; current != nil {
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
udp.locker.Unlock()
}
udp.Details.Udp = new(proto.UdpChannelDetails)
udp.Details.Udp.Token = details.Token
udp.Details.Udp.TunnelAddr = details.TunnelAddr
udp.locker.Unlock()
return udp.SendToken(&details)
return udp.SendToken(details)
}
func (udp *UdpTunnel) ResendToken() (bool, error) {
@ -175,12 +175,13 @@ func (Udp *UdpTunnel) GetToken() ([]byte, error) {
return lock.Udp.Token[:], nil
}
type UdpTunnelRxPacket struct {
Bytes uint64
Flow UdpFlow
}
type UdpTunnelRx struct {
ConfirmerdConnection bool
ReceivedPacket *struct {
Bytes uint64
Flow UdpFlow
}
ReceivedPacket UdpTunnelRxPacket
}
func (Udp *UdpTunnel) ReceiveFrom(buff []byte) (*UdpTunnelRx, error) {
@ -191,6 +192,8 @@ func (Udp *UdpTunnel) ReceiveFrom(buff []byte) (*UdpTunnelRx, error) {
if err != nil {
return nil, err
}
// udp.SetReadDeadline(time.Now().Add(time.Second * 2))
byteSize, remote, err := udp.ReadFromUDPAddrPort(buff)
if err != nil {
return nil, err
@ -203,36 +206,34 @@ func (Udp *UdpTunnel) ReceiveFrom(buff []byte) (*UdpTunnelRx, error) {
return nil, fmt.Errorf("got data from other source")
}
}
buff = buff[:byteSize]
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) {
var point UdpTunnelRx
if bytes.Equal(buff, token) {
// LogDebug.Println("udp session confirmed")
Udp.LastConfirm.Store(now_sec())
return &UdpTunnelRx{ConfirmerdConnection: true}, nil
}
if len(buff)+V6_LEN < byteSize {
point.ConfirmerdConnection = true
return &point, nil
} else if len(buff)+V6_LEN < byteSize {
return nil, fmt.Errorf("receive buffer too small")
}
footer, footerInt, err := FromTailUdpFlow(buff[byteSize:])
footer, footerInt, err := FromTailUdpFlow(buff)
if err != nil {
if footerInt == UDP_CHANNEL_ESTABLISH_ID {
actual := hex.EncodeToString(buff[byteSize:])
actual := hex.EncodeToString(buff)
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 nil, fmt.Errorf("failed to extract udp footer: %s, err: %s", hex.EncodeToString(buff), err.Error())
}
return &UdpTunnelRx{ReceivedPacket: &struct {
Bytes uint64
Flow UdpFlow
}{uint64(byteSize) - uint64(footer.Len()), *footer}}, nil
point.ReceivedPacket = UdpTunnelRxPacket{
uint64(byteSize - footer.Len()),
footer,
}
return &point, nil
}