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/setup.go
Matheus Sampaio Queiroga a3c4994e66 Common
Signed-off-by: Matheus Sampaio Queiroga <srherobrine20@gmail.com>
2024-05-21 23:11:16 -03:00

191 lines
4.9 KiB
Go

package tunnel
import (
"bytes"
"encoding/hex"
"fmt"
"net"
"net/netip"
"time"
"sirherobrine23.org/playit-cloud/go-playit/api"
)
type SetupFindSuitableChannel struct {
Address []netip.AddrPort
}
func (Setup *SetupFindSuitableChannel) Setup() (*ConnectedControl, error) {
for _, Addr := range Setup.Address {
network := "udp6"
if Addr.Addr().Is4() && !Addr.Addr().Is4In6() {
network = "udp4"
}
conn, err := net.ListenUDP(network, nil)
if err != nil {
fmt.Println(err.Error())
continue
}
for range 3 {
// Make initial ping
buffer := bytes.NewBuffer([]byte{})
if err = (&ControlRpcMessage[*ControlRequest]{
RequestID: 1,
Content: &ControlRequest{
Ping: &Ping{
Now: time.Now(),
CurrentPing: nil,
SessionID: nil,
},
},
}).WriteTo(buffer); err != nil {
conn.Close()
return nil, err
}
// Write initial ping
_, err = conn.WriteToUDP(buffer.Bytes(), net.UDPAddrFromAddrPort(Addr))
if err != nil {
conn.Close()
break
}
for range 5 {
buff := make([]byte, 2048)
if err = conn.SetReadDeadline(time.Now().Add(time.Millisecond * 5)); err != nil {
return nil, err
}
bytesSize, peer, err := conn.ReadFrom(buff)
if err != nil {
if netErr, isNet := err.(net.Error); isNet {
if netErr.Timeout() {
continue
}
}
return nil, err
} else if peer.String() != Addr.String() {
continue
}
buff = buff[:bytesSize]
var feed ControlFeed
if err := feed.ReadFrom(bytes.NewReader(buff)); err != nil {
return nil, err
} else if feed.Response == nil {
return nil, fmt.Errorf("unexpected control feed")
}
msg := feed.Response
if msg.RequestID != 1 {
continue
} else if msg.Content.Pong == nil {
return nil, fmt.Errorf("expected pong got other response")
}
return &ConnectedControl{
ControlAddr: Addr,
Udp: conn,
Pong: msg.Content.Pong,
}, nil
}
}
}
return nil, fmt.Errorf("cannot make UDP tunnel to playit controller, check you internet conenction")
}
type ConnectedControl struct {
ControlAddr netip.AddrPort
Udp *net.UDPConn
Pong *Pong
}
func (Control *ConnectedControl) Authenticate(Api api.Api) (*AuthenticatedControl, error) {
if !Control.Pong.ClientAddr.AddrPort.IsValid() {
return nil, fmt.Errorf("invalid pong Client address")
} else if !Control.Pong.TunnelAddr.AddrPort.IsValid() {
return nil, fmt.Errorf("invalid pong Tunnel address")
}
LogDebug.Println("Registring agent proto")
tk, err := Api.ProtoRegisterRegister(Control.Pong.ClientAddr.AddrPort, Control.Pong.TunnelAddr.AddrPort)
if err != nil {
LogDebug.Println("failed to sign and register")
return nil, err
}
tkBytes, err := hex.DecodeString(tk)
if err != nil {
return nil, err
}
for range 5 {
buffer := bytes.NewBuffer([]byte{})
if err := (&ControlRpcMessage[*RawSlice]{
RequestID: 10,
Content: &RawSlice{
Buff: tkBytes,
},
}).WriteTo(buffer); err != nil {
return nil, err
}
_, err := Control.Udp.WriteTo(buffer.Bytes(), net.UDPAddrFromAddrPort(Control.ControlAddr))
if err != nil {
return nil, err
}
for range 5 {
reciver := append(buffer.Bytes(), make([]byte, 1024)...)
Control.Udp.SetReadDeadline(time.Now().Add(time.Millisecond * 5))
recSize, remote, err := Control.Udp.ReadFrom(reciver)
if err != nil {
if errNet, isNet := err.(net.Error); isNet {
if errNet.Timeout() {
LogDebug.Println("Timeout")
break
}
}
return nil, err
} else if remote.String() != Control.ControlAddr.String() {
LogDebug.Println("got response not from tunnel server")
continue
}
feed := &ControlFeed{}
if err = feed.ReadFrom(bytes.NewReader(reciver[:recSize])); err != nil {
LogDebug.Println("failed to read response from tunnel")
return nil, err
} else if feed.Response.RequestID != 10 {
LogDebug.Println("got response for different request")
continue
} else if feed.Response == nil || feed.Response.Content == nil {
LogDebug.Println("feed response or Response content is empty")
return nil, fmt.Errorf("cannot get response")
}
controlRes := feed.Response.Content
if controlRes.RequestQueued {
LogDebug.Println("register queued, waiting 1s")
time.Sleep(time.Second)
continue
} else if controlRes.InvalidSignature {
return nil, fmt.Errorf("register return invalid signature")
} else if controlRes.Unauthorized {
return nil, fmt.Errorf("unauthorized")
} else if controlRes.AgentRegistered != nil {
return &AuthenticatedControl{
ApiClient: Api,
Conn: *Control,
LastPong: *Control.Pong,
CurrentPing: nil,
Registered: *controlRes.AgentRegistered,
Buff: reciver[recSize:],
ForceEpired: false,
}, nil
}
LogDebug.Println("expected AgentRegistered but got something else")
}
}
return nil, fmt.Errorf("failed1 to connect agent")
}