playit.gg go implementation #1
1
.gitignore
vendored
1
.gitignore
vendored
@ -21,3 +21,4 @@
|
||||
# Go workspace file
|
||||
go.work
|
||||
|
||||
main.go
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
@ -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))
|
||||
}
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
107
runner/autorun.go
Normal 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
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user