This repository has been archived on 2024-07-06. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
go-playit/tunnel/simples_tunnel.go
Matheus Sampaio Queiroga a3c4994e66 Common
Signed-off-by: Matheus Sampaio Queiroga <srherobrine20@gmail.com>
2024-05-21 23:11:16 -03:00

214 lines
5.6 KiB
Go

package tunnel
import (
"encoding/json"
"fmt"
"net/netip"
"slices"
"time"
"sirherobrine23.org/playit-cloud/go-playit/api"
)
type SimplesTunnel struct {
ApiClaim api.Api
ControlAddr netip.AddrPort
ControlChannel *AuthenticatedControl
UdpTunnel UdpTunnel
LastKeepAlive uint64
LastPing uint64
LastPong uint64
LastUdpAuth uint64
lastControlTargets []netip.AddrPort
}
func ControlAddresses(Api api.Api) ([]netip.AddrPort, error) {
controls, err := Api.AgentRoutings(nil)
if err != nil {
return nil, err
}
addrs := []netip.AddrPort{}
for _, v := range append(controls.Targets6, controls.Targets4...) {
addrs = append(addrs, netip.AddrPortFrom(v, 5525))
}
return addrs, nil
}
func (Tun *SimplesTunnel) Setup() error {
if err := AssignUdpTunnel(&Tun.UdpTunnel); err != nil {
return err
}
addresses, err := ControlAddresses(Tun.ApiClaim)
if err != nil {
return err
}
setup, err := (&SetupFindSuitableChannel{Address: addresses}).Setup()
if err != nil {
return err
}
control_channel, err := setup.Authenticate(Tun.ApiClaim)
if err != nil {
return err
}
Tun.ControlAddr = setup.ControlAddr
Tun.ControlChannel = control_channel
return nil
}
func (Tun *SimplesTunnel) ReloadControlAddr() (bool, error) {
addresses, err := ControlAddresses(Tun.ApiClaim)
if err != nil {
return false, err
}
if slices.ContainsFunc(Tun.lastControlTargets, func(a netip.AddrPort) bool {
return !slices.ContainsFunc(addresses, func(b netip.AddrPort) bool {
return a.Compare(b) == 0
})
}) {
return false, nil
}
setup, err := (&SetupFindSuitableChannel{addresses}).Setup()
if err != nil {
return false, err
}
updated, err := Tun.UpdateControlAddr(*setup)
Tun.lastControlTargets = addresses
return updated, err
}
func (Tun *SimplesTunnel) UpdateControlAddr(conncted ConnectedControl) (ok bool, err error) {
if conncted.ControlAddr.Compare(Tun.ControlAddr) == 0 {
LogDebug.Println("not required Update control addr")
return
}
var controlChannel *AuthenticatedControl
controlChannel, err = conncted.Authenticate(Tun.ApiClaim)
if err != nil {
return
}
LogDebug.Printf("Update control address %s to %s\n", Tun.ControlAddr.String(), conncted.ControlAddr.String())
Tun.ControlChannel = controlChannel
Tun.ControlAddr = conncted.ControlAddr
Tun.LastPing = 0
Tun.LastKeepAlive = 0
Tun.LastUdpAuth = 0
Tun.UdpTunnel.InvalidateSession()
ok = true
return
}
func (Tun *SimplesTunnel) Update() (*NewClient, error) {
if Tun.ControlChannel.IsIspired() {
LogDebug.Println("Creating new controller channel...")
if err := Tun.ControlChannel.Authenticate(); err != nil {
LogDebug.Println(err)
time.Sleep(time.Second * 2)
return nil, nil
}
}
now := uint64(time.Now().UnixMilli())
if now-Tun.LastPing > 1_000 {
Tun.LastPing = now
if err := Tun.ControlChannel.SendPing(200, time.UnixMilli(int64(now))); err != nil {
LogDebug.Println("failed to send ping")
}
}
// d, _ := json.MarshalIndent(Tun, "", " ")
// LogDebug.Panicf(string(d))
if Tun.UdpTunnel.RequiresAuth() {
if 5_000 < now-Tun.LastUdpAuth {
Tun.LastUdpAuth = now
if err := Tun.ControlChannel.SendSetupUDPChannel(9000); err != nil {
LogDebug.Println("failed to send udp setup request to control")
LogDebug.Println(err)
}
}
} else if Tun.UdpTunnel.RequireResend() {
if 1_000 < now-Tun.LastUdpAuth {
Tun.LastUdpAuth = now
if _, err := Tun.UdpTunnel.ResendToken(); err != nil {
LogDebug.Println("failed to send udp auth request")
LogDebug.Println(err)
}
}
timeTillExpire := func(x, y uint64) uint64 {
if x > y {
return y
}
return x
}(uint64(Tun.ControlChannel.Registered.ExpiresAt.UnixMilli()), uint64(now))
if 10_000 < now-Tun.LastKeepAlive && timeTillExpire < 30_000 {
Tun.LastKeepAlive = now
LogDebug.Println("send KeepAlive")
if err := Tun.ControlChannel.SendKeepAlive(100); err != nil {
LogDebug.Println("failed to send KeepAlive")
LogDebug.Println(err)
}
if err := Tun.ControlChannel.SendSetupUDPChannel(1); err != nil {
LogDebug.Println("failed to send setup udp channel request")
LogDebug.Println(err)
}
}
timeout := 0
for range 30 {
if timeout >= 10 {
LogDebug.Println("feed recv timeout")
break
}
LogDebug.Println("RX Feed message")
men, err := Tun.ControlChannel.RecFeedMsg()
if err != nil {
timeout++
LogDebug.Printf("failed to parse response: %s\n", err.Error())
continue
}
if men.NewClient != nil {
return men.NewClient, nil
} else if men.Response != nil {
cont := men.Response.Content
if cont.UdpChannelDetails != nil {
LogDebug.Print("Response SetUdpTunnel")
if err := Tun.UdpTunnel.SetUdpTunnel(*men.Response.Content.UdpChannelDetails); err != nil {
timeout++
LogDebug.Print(err)
}
} else if cont.Pong != nil {
Tun.LastPong = uint64(time.Now().UnixMilli())
if cont.Pong.ClientAddr.Compare(Tun.ControlChannel.Conn.Pong.ClientAddr.AddrPort) != 0 {
LogDebug.Printf("Client IP changed: %q -> %q\n", cont.Pong.ClientAddr, Tun.ControlChannel.Conn.Pong.ClientAddr.AddrPort)
}
} else if cont.Unauthorized {
LogDebug.Panicln("unauthorized, check token or reload agent")
Tun.ControlChannel.ForceEpired = true
return nil, fmt.Errorf("unauthorized, check token or reload agent")
} else {
LogDebug.Printf("got response")
d , _ := json.MarshalIndent(men, "", " ")
LogDebug.Printf(string(d))
}
}
}
}
if Tun.LastPong != 0 && uint64(time.Now().UnixMilli())-Tun.LastPong > 6_000 {
LogDebug.Println("timeout waiting for pong")
Tun.LastPong = 0
Tun.ControlChannel.ForceEpired = true
}
return nil, nil
}