2026-04-06 00:20:51 -05:00

999 lines
28 KiB
Go

package server
import (
"AdaptixServer/core/eventing"
"AdaptixServer/core/utils/krypt"
"AdaptixServer/core/utils/logs"
"AdaptixServer/core/utils/proxy"
"AdaptixServer/core/utils/safe"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"math/rand/v2"
"net"
"strconv"
"sync"
"time"
"github.com/Adaptix-Framework/axc2"
"github.com/gorilla/websocket"
)
func (ts *Teamserver) TsTunnelList() (string, error) {
tunnels := ts.TunnelManager.ListTunnels()
jsonTunnel, err := json.Marshal(tunnels)
if err != nil {
return "", err
}
return string(jsonTunnel), nil
}
func (ts *Teamserver) TsTunnelClientStart(AgentId string, Listen bool, Type int, Info string, Lhost string, Lport int, Client string, Thost string, Tport int, AuthUser string, AuthPass string) (string, error) {
var (
taskId string
tunnelId string
err error
)
value, ok := ts.Agents.Get(AgentId)
if !ok {
return "", fmt.Errorf("agent '%v' does not exist", AgentId)
}
agent, ok := value.(*Agent)
if !ok {
return "", fmt.Errorf("invalid agent type for '%v'", AgentId)
}
if agent.Active == false {
return "", fmt.Errorf("agent '%v' not active", AgentId)
}
commandline := ""
message := ""
switch Type {
case adaptix.TUNNEL_TYPE_SOCKS4:
if Listen {
commandline = fmt.Sprintf("[from browser] socks4 start %v:%v", Lhost, Lport)
message = fmt.Sprintf("SOCKS4 server started on '%v:%v'", Lhost, Lport)
} else {
commandline = fmt.Sprintf("[from browser] socks4 (client) start %v:%v", Lhost, Lport)
message = fmt.Sprintf("SOCKS4 server started on (client '%v') '%v:%v'", Client, Lhost, Lport)
}
case adaptix.TUNNEL_TYPE_SOCKS5:
if Listen {
commandline = fmt.Sprintf("[from browser] socks5 start %v:%v", Lhost, Lport)
message = fmt.Sprintf("SOCKS5 server started on '%v:%v'", Lhost, Lport)
} else {
commandline = fmt.Sprintf("[from browser] socks5 (client) start %v:%v", Lhost, Lport)
message = fmt.Sprintf("SOCKS5 server started on (client '%v') '%v:%v'", Client, Lhost, Lport)
}
case adaptix.TUNNEL_TYPE_SOCKS5_AUTH:
if Listen {
commandline = fmt.Sprintf("[from browser] socks5 start %v:%v -auth %v %v", Lhost, Lport, AuthUser, AuthPass)
message = fmt.Sprintf("SOCKS5 (with Auth) server started on '%v:%v'", Lhost, Lport)
} else {
commandline = fmt.Sprintf("[from browser] socks5 (client) start %v:%v -auth %v %v", Lhost, Lport, AuthUser, AuthPass)
message = fmt.Sprintf("SOCKS5 (with Auth) server started on (client '%v') '%v:%v'", Client, Lhost, Lport)
}
case adaptix.TUNNEL_TYPE_LOCAL_PORT:
if Listen {
commandline = fmt.Sprintf("[from browser] local_port_fwd start %v:%v %v:%v", Lhost, Lport, Thost, Tport)
message = fmt.Sprintf("Started local port forwarding on %v:%v to %v:%v", Lhost, Lport, Thost, Tport)
} else {
commandline = fmt.Sprintf("[from browser] local_port_fwd (client) start on %v:%v %v:%v", Lhost, Lport, Thost, Tport)
message = fmt.Sprintf("Started local port forwarding on (client '%v') %v:%v to %v:%v", Client, Lhost, Lport, Thost, Tport)
}
case adaptix.TUNNEL_TYPE_REVERSE:
if Listen {
commandline = fmt.Sprintf("[from browser] reverse_port_fwd start %v %v:%v", Lport, Thost, Tport)
message = fmt.Sprintf("Starting reverse port forwarding %v to %v:%v", Lport, Thost, Tport)
} else {
}
default:
return "", errors.New("unknown tunnel type")
}
if Listen {
tunnelId, err = ts.TsTunnelCreate(AgentId, Type, Info, Lhost, Lport, "", Thost, Tport, AuthUser, AuthPass)
if err != nil {
return "", err
}
taskId, err = ts.TsTunnelStart(tunnelId)
if err != nil {
return "", err
}
} else {
tunnelId, err = ts.TsTunnelCreate(AgentId, Type, Info, Lhost, Lport, Client, Thost, Tport, AuthUser, AuthPass)
if err != nil {
return "", err
}
tunnel, ok := ts.TunnelManager.GetTunnel(tunnelId)
if !ok {
return "", ErrTunnelNotFound
}
tunnel.Active = true
tunnel.TaskId, _ = krypt.GenerateUID(8)
taskId = tunnel.TaskId
packet := CreateSpTunnelCreate(tunnel.Data)
ts.TsSyncAllClientsWithCategory(packet, SyncCategoryTunnels)
ts.TsNotifyTunnelAdd(tunnel)
}
taskData := adaptix.TaskData{
TaskId: taskId,
Type: adaptix.TASK_TYPE_TUNNEL,
Sync: true,
Message: message,
MessageType: CONSOLE_OUT_SUCCESS,
ClearText: "",
}
ts.TsTaskCreate(AgentId, commandline, Client, taskData)
return tunnelId, nil
}
type TunnelChannelData struct {
TunnelId string `json:"tunnel_id"`
ChannelId string `json:"channel_id"`
Mode string `json:"mode,omitempty"`
Host string `json:"host,omitempty"`
Port string `json:"port,omitempty"`
}
func (ts *Teamserver) TsTunnelClientNewChannel(TunnelData string, wsconn *websocket.Conn) error {
var td TunnelChannelData
if err := json.Unmarshal([]byte(TunnelData), &td); err != nil {
return errors.New("invalid tunnel data")
}
tunnel, ok := ts.TunnelManager.GetTunnel(td.TunnelId)
if !ok {
return ErrTunnelNotFound
}
agent, err := ts.getAgent(tunnel.Data.AgentId)
if err != nil {
return ErrAgentNotFound
}
cid, err := strconv.ParseInt(td.ChannelId, 16, 64)
if err != nil {
return errors.New("channelId not supported")
}
port := 0
if tunnel.Type == adaptix.TUNNEL_TYPE_SOCKS4 || tunnel.Type == adaptix.TUNNEL_TYPE_SOCKS5 || tunnel.Type == adaptix.TUNNEL_TYPE_SOCKS5_AUTH {
port, err = strconv.Atoi(td.Port)
if err != nil {
return errors.New("Invalid port number")
}
if port < 1 || port > 65535 {
return errors.New("Invalid port number")
}
if td.Host == "" {
return errors.New("Invalid host")
}
}
if tunnel.Type == adaptix.TUNNEL_TYPE_SOCKS5 || tunnel.Type == adaptix.TUNNEL_TYPE_SOCKS5_AUTH {
if td.Mode != "tcp" && td.Mode != "udp" {
return errors.New("invalid td.Mode")
}
}
go handleTunChannelCreateClient(ts.TunnelManager, agent, tunnel, wsconn, int(cid), td.Host, port, td.Mode)
return nil
}
func (ts *Teamserver) TsTunnelClientSetInfo(TunnelId string, Info string) error {
tunnel, ok := ts.TunnelManager.GetTunnel(TunnelId)
if !ok {
return ErrTunnelNotFound
}
tunnel.Data.Info = Info
packet := CreateSpTunnelEdit(tunnel.Data)
ts.TsSyncStateWithCategory(packet, "tunnel:"+tunnel.Data.TunnelId, SyncCategoryTunnels)
return nil
}
func (ts *Teamserver) TsTunnelClientStop(TunnelId string, Client string) error {
tunnel, ok := ts.TunnelManager.GetTunnel(TunnelId)
if !ok {
return ErrTunnelNotFound
}
if tunnel.Data.Client == "" {
_ = ts.TsTunnelStop(TunnelId)
return nil
}
if tunnel.Data.Client == Client {
tunnel, ok = ts.TunnelManager.DeleteTunnel(TunnelId)
if !ok {
return ErrTunnelNotFound
}
ts.TunnelManager.CloseAllChannels(tunnel)
packet := CreateSpTunnelDelete(tunnel.Data)
ts.TsSyncAllClientsWithCategory(packet, SyncCategoryTunnels)
taskData := adaptix.TaskData{
TaskId: tunnel.TaskId,
Completed: true,
FinishDate: time.Now().Unix(),
}
ts.TsTaskUpdate(tunnel.Data.AgentId, taskData)
return nil
}
return errors.New("The tunnel is running on another client's side, you are not allowed to perform this operation.")
}
/// Tunnel Start
func (ts *Teamserver) TsTunnelStart(TunnelId string) (string, error) {
tunnel, ok := ts.TunnelManager.GetTunnel(TunnelId)
if !ok {
return "", ErrTunnelNotFound
}
agent, err := ts.getAgent(tunnel.Data.AgentId)
if err != nil {
return "", ErrAgentNotFound
}
port, _ := strconv.Atoi(tunnel.Data.Port)
// --- PRE HOOK ---
preEvent := &eventing.EventDataTunnelStart{
AgentId: tunnel.Data.AgentId,
TunnelId: TunnelId,
TunnelType: tunnel.Type,
Port: port,
Info: tunnel.Data.Info,
}
if !ts.EventManager.Emit(eventing.EventTunnelStart, eventing.HookPre, preEvent) {
if preEvent.Error != nil {
return "", preEvent.Error
}
return "", fmt.Errorf("operation cancelled by hook")
}
// ----------------
if tunnel.Type == adaptix.TUNNEL_TYPE_REVERSE {
id, _ := strconv.ParseInt(TunnelId, 16, 64)
port, err := strconv.Atoi(tunnel.Data.Port)
if err != nil {
return "", fmt.Errorf("invalid port: %v", err)
}
taskData := tunnel.Callbacks.Reverse(int(id), port)
tunnelManageTask(agent, taskData)
} else {
address := tunnel.Data.Interface + ":" + tunnel.Data.Port
listener, listenErr := net.Listen("tcp", address)
if listenErr != nil {
ts.TunnelManager.DeleteTunnel(TunnelId)
return "", listenErr
}
tunnel.listener = listener
go func(l net.Listener, tm *TunnelManager) {
for {
conn, acceptErr := l.Accept()
if acceptErr != nil {
return
}
go handleTunChannelCreate(tm, agent, tunnel, conn)
}
}(tunnel.listener, ts.TunnelManager)
}
tunnel.Active = true
tunnel.TaskId, _ = krypt.GenerateUID(8)
packet := CreateSpTunnelCreate(tunnel.Data)
ts.TsSyncAllClientsWithCategory(packet, SyncCategoryTunnels)
ts.TsNotifyTunnelAdd(tunnel)
// --- POST HOOK ---
postEvent := &eventing.EventDataTunnelStart{
AgentId: tunnel.Data.AgentId,
TunnelId: TunnelId,
TunnelType: tunnel.Type,
Port: port,
Info: tunnel.Data.Info,
}
ts.EventManager.EmitAsync(eventing.EventTunnelStart, postEvent)
// -----------------
return tunnel.TaskId, nil
}
func (ts *Teamserver) TsTunnelCreate(AgentId string, Type int, Info string, Lhost string, Lport int, Client string, Thost string, Tport int, AuthUser string, AuthPass string) (string, error) {
agent, err := ts.getAgent(AgentId)
if err != nil {
return "", ErrAgentNotFound
}
agentData := agent.GetData()
if Info == "" && Type == adaptix.TUNNEL_TYPE_SOCKS5_AUTH {
Info = fmt.Sprintf("Creds %s:%s", AuthUser, AuthPass)
}
tunnelData := adaptix.TunnelData{
AgentId: agentData.Id,
Computer: agentData.Computer,
Username: agentData.Username,
Process: agentData.Process,
Info: Info,
Client: Client,
}
lport := strconv.Itoa(Lport)
tport := strconv.Itoa(Tport)
switch Type {
case adaptix.TUNNEL_TYPE_SOCKS4:
tunnelData.Type = "SOCKS4 proxy"
tunnelData.TunnelId = fmt.Sprintf("%08x", krypt.CRC32([]byte(Client+agentData.Id+"socks"+lport)))
tunnelData.Interface = Lhost
tunnelData.Port = lport
case adaptix.TUNNEL_TYPE_SOCKS5:
tunnelData.Type = "SOCKS5 proxy"
tunnelData.TunnelId = fmt.Sprintf("%08x", krypt.CRC32([]byte(Client+agentData.Id+"socks"+lport)))
tunnelData.Interface = Lhost
tunnelData.Port = lport
case adaptix.TUNNEL_TYPE_SOCKS5_AUTH:
tunnelData.Type = "SOCKS5 Auth proxy"
tunnelData.TunnelId = fmt.Sprintf("%08x", krypt.CRC32([]byte(Client+agentData.Id+"socks"+lport)))
tunnelData.Interface = Lhost
tunnelData.Port = lport
tunnelData.AuthUser = AuthUser
tunnelData.AuthPass = AuthPass
case adaptix.TUNNEL_TYPE_LOCAL_PORT:
tunnelData.Type = "Local port forward"
tunnelData.TunnelId = fmt.Sprintf("%08x", krypt.CRC32([]byte(Client+agentData.Id+"lportfwd"+lport)))
tunnelData.Interface = Lhost
tunnelData.Port = lport
tunnelData.Fhost = Thost
tunnelData.Fport = tport
case adaptix.TUNNEL_TYPE_REVERSE:
tunnelData.Type = "Reverse port forward"
tunnelData.TunnelId = fmt.Sprintf("%08x", krypt.CRC32([]byte(Client+agentData.Id+"rportfwd"+lport)))
tunnelData.Port = lport
tunnelData.Fhost = Thost
tunnelData.Fport = tport
default:
return "", errors.New("invalid tunnel type")
}
if existingTunnel, ok := ts.TunnelManager.GetTunnel(tunnelData.TunnelId); ok {
if existingTunnel.Active {
return "", ErrTunnelAlreadyActive
}
ts.TunnelManager.DeleteTunnel(tunnelData.TunnelId)
}
tunnel := &Tunnel{
connections: safe.NewMap(),
Data: tunnelData,
Type: Type,
Active: false,
Callbacks: agent.TunnelCallbacks(),
}
ts.TunnelManager.PutTunnel(tunnel)
return tunnel.Data.TunnelId, nil
}
func (ts *Teamserver) TsTunnelCreateSocks4(AgentId string, Info string, Lhost string, Lport int) (string, error) {
return ts.TsTunnelCreate(AgentId, adaptix.TUNNEL_TYPE_SOCKS4, Info, Lhost, Lport, "", "", 0, "", "")
}
func (ts *Teamserver) TsTunnelCreateSocks5(AgentId string, Info string, Lhost string, Lport int, UseAuth bool, Username string, Password string) (string, error) {
if UseAuth {
return ts.TsTunnelCreate(AgentId, adaptix.TUNNEL_TYPE_SOCKS5_AUTH, Info, Lhost, Lport, "", "", 0, Username, Password)
}
return ts.TsTunnelCreate(AgentId, adaptix.TUNNEL_TYPE_SOCKS5, Info, Lhost, Lport, "", "", 0, "", "")
}
func (ts *Teamserver) TsTunnelCreateLportfwd(AgentId string, Info string, Lhost string, Lport int, Thost string, Tport int) (string, error) {
return ts.TsTunnelCreate(AgentId, adaptix.TUNNEL_TYPE_LOCAL_PORT, Info, Lhost, Lport, "", Thost, Tport, "", "")
}
func (ts *Teamserver) TsTunnelCreateRportfwd(AgentId string, Info string, Lport int, Thost string, Tport int) (string, error) {
return ts.TsTunnelCreate(AgentId, adaptix.TUNNEL_TYPE_REVERSE, Info, "", Lport, "", Thost, Tport, "", "")
}
func (ts *Teamserver) TsTunnelUpdateRportfwd(tunnelId int, result bool) (string, string, error) {
tunId := fmt.Sprintf("%08x", tunnelId)
if result {
tunnel, ok := ts.TunnelManager.GetTunnel(tunId)
if ok {
packet := CreateSpTunnelCreate(tunnel.Data)
ts.TsSyncAllClientsWithCategory(packet, SyncCategoryTunnels)
ts.TsNotifyTunnelAdd(tunnel)
message := fmt.Sprintf("Reverse port forward '%s' to '%s:%s'", tunnel.Data.Port, tunnel.Data.Fhost, tunnel.Data.Fport)
return tunnel.TaskId, message, nil
}
} else {
tunnel, ok := ts.TunnelManager.DeleteTunnel(tunId)
if ok {
taskData := adaptix.TaskData{
TaskId: tunnel.TaskId,
MessageType: CONSOLE_OUT_ERROR,
Message: "Reverse port forward failed",
FinishDate: time.Now().Unix(),
Completed: true,
}
ts.TsTaskUpdate(tunnel.Data.AgentId, taskData)
return tunnel.TaskId, "", errors.New("reverse port forward failed")
}
}
return "", "", errors.New("tunnel not found")
}
/// Tunnel Stop
func (ts *Teamserver) TsTunnelStop(TunnelId string) error {
tunnel, ok := ts.TunnelManager.GetTunnel(TunnelId)
if !ok {
return ErrTunnelNotFound
}
port, _ := strconv.Atoi(tunnel.Data.Port)
// --- PRE HOOK ---
preEvent := &eventing.EventDataTunnelStop{
AgentId: tunnel.Data.AgentId,
TunnelId: TunnelId,
TunnelType: tunnel.Type,
Port: port,
}
if !ts.EventManager.Emit(eventing.EventTunnelStop, eventing.HookPre, preEvent) {
if preEvent.Error != nil {
return preEvent.Error
}
return fmt.Errorf("operation cancelled by hook")
}
// ----------------
tunnel, ok = ts.TunnelManager.DeleteTunnel(TunnelId)
if !ok {
return ErrTunnelNotFound
}
if tunnel.listener != nil {
_ = tunnel.listener.Close()
}
ts.TunnelManager.CloseAllChannels(tunnel)
packet := CreateSpTunnelDelete(tunnel.Data)
ts.TsSyncAllClientsWithCategory(packet, SyncCategoryTunnels)
taskData := adaptix.TaskData{
TaskId: tunnel.TaskId,
Completed: true,
FinishDate: time.Now().Unix(),
}
ts.TsTaskUpdate(tunnel.Data.AgentId, taskData)
ts.TsNotifyTunnelRemove(tunnel)
// --- POST HOOK ---
postEvent := &eventing.EventDataTunnelStop{
AgentId: tunnel.Data.AgentId,
TunnelId: TunnelId,
TunnelType: tunnel.Type,
Port: port,
}
ts.EventManager.EmitAsync(eventing.EventTunnelStop, postEvent)
// -----------------
return nil
}
func (ts *Teamserver) TsTunnelStopSocks(AgentId string, Port int) {
port := strconv.Itoa(Port)
id := krypt.CRC32([]byte(AgentId + "socks" + port))
TunnelId := fmt.Sprintf("%08x", id)
_ = ts.TsTunnelStop(TunnelId)
}
func (ts *Teamserver) TsTunnelStopLportfwd(AgentId string, Port int) {
port := strconv.Itoa(Port)
id := krypt.CRC32([]byte(AgentId + "lportfwd" + port))
TunnelId := fmt.Sprintf("%08x", id)
_ = ts.TsTunnelStop(TunnelId)
}
func (ts *Teamserver) TsTunnelStopRportfwd(AgentId string, Port int) {
port := strconv.Itoa(Port)
id := krypt.CRC32([]byte(AgentId + "rportfwd" + port))
TunnelId := fmt.Sprintf("%08x", id)
tunnel, ok := ts.TunnelManager.GetTunnel(TunnelId)
if !ok {
return
}
agent, err := ts.getAgent(tunnel.Data.AgentId)
if err != nil {
return
}
rawTaskData := tunnel.Callbacks.Close(int(id))
tunnelManageTask(agent, rawTaskData)
_ = ts.TsTunnelStop(TunnelId)
}
/// Connection
func (ts *Teamserver) TsTunnelChannelExists(channelId int) bool {
_, ok := ts.TunnelManager.GetChannelByIdOnly(channelId)
return ok
}
func (ts *Teamserver) TsTunnelGetPipe(AgentId string, channelId int) (*io.PipeReader, *io.PipeWriter, error) {
return ts.TunnelManager.GetChannelPipesByIdOnly(channelId)
}
func (ts *Teamserver) TsTunnelConnectionData(channelId int, data []byte) {
ts.TunnelManager.WriteToChannelByIdOnly(channelId, data)
}
func (ts *Teamserver) TsTunnelConnectionResume(AgentId string, channelId int, ioDirect bool) {
agent, err := ts.getAgent(AgentId)
if err != nil {
return
}
entry, ok := ts.TunnelManager.GetChannelByIdOnly(channelId)
if !ok {
return
}
tunnel := entry.Tunnel
tunChannel := entry.Channel
if tunnel.Data.Client == "" {
if tunChannel.conn != nil {
if tunnel.Type == adaptix.TUNNEL_TYPE_SOCKS5 || tunnel.Type == adaptix.TUNNEL_TYPE_SOCKS5_AUTH {
proxy.ReplySocks5StatusConn(tunChannel.conn, adaptix.SOCKS5_SUCCESS)
} else if tunnel.Type == adaptix.TUNNEL_TYPE_SOCKS4 {
proxy.ReplySocks4StatusConn(tunChannel.conn, true)
}
relaySocketToTunnel(ts.TunnelManager, agent, tunnel, tunChannel, ioDirect)
} else {
logs.Debug("", "[ERROR] tunChannel.conn is nil in relaySocketToTunnel")
}
} else {
if tunChannel.wsconn != nil {
if tunnel.Type == adaptix.TUNNEL_TYPE_SOCKS5 || tunnel.Type == adaptix.TUNNEL_TYPE_SOCKS5_AUTH {
proxy.ReplySocks5StatusWs(tunChannel.wsconn, adaptix.SOCKS5_SUCCESS)
} else if tunnel.Type == adaptix.TUNNEL_TYPE_SOCKS4 {
proxy.ReplySocks4StatusWs(tunChannel.wsconn, true)
}
relayWebsocketToTunnel(ts.TunnelManager, agent, tunnel, tunChannel, ioDirect)
} else {
logs.Debug("", "[ERROR] tunChannel.wsconn is nil in relayWebsocketToTunnel")
}
}
}
func (ts *Teamserver) TsTunnelConnectionClose(channelId int, writeOnly bool) {
ts.TunnelManager.CloseChannelByIdOnly(channelId, writeOnly)
}
func (ts *Teamserver) TsTunnelPause(channelId int) {
ts.TunnelManager.PauseChannel(channelId)
}
func (ts *Teamserver) TsTunnelResume(channelId int) {
ts.TunnelManager.ResumeChannel(channelId)
}
func (ts *Teamserver) TsTunnelConnectionHalt(channelId int, errorCode byte) {
entry, ok := ts.TunnelManager.GetChannelByIdOnly(channelId)
if !ok {
return
}
tunnel := entry.Tunnel
tunChannel := entry.Channel
if tunnel.Data.Client == "" {
if tunChannel.conn != nil {
if tunnel.Type == adaptix.TUNNEL_TYPE_SOCKS5 || tunnel.Type == adaptix.TUNNEL_TYPE_SOCKS5_AUTH {
if errorCode < 1 || errorCode > 8 {
errorCode = adaptix.SOCKS5_CONNECTION_REFUSED
}
proxy.ReplySocks5StatusConn(tunChannel.conn, errorCode)
} else if tunnel.Type == adaptix.TUNNEL_TYPE_SOCKS4 {
proxy.ReplySocks4StatusConn(tunChannel.conn, false)
}
}
} else {
if tunChannel.wsconn != nil {
if tunnel.Type == adaptix.TUNNEL_TYPE_SOCKS5 || tunnel.Type == adaptix.TUNNEL_TYPE_SOCKS5_AUTH {
if errorCode < 1 || errorCode > 8 {
errorCode = adaptix.SOCKS5_CONNECTION_REFUSED
}
proxy.ReplySocks5StatusWs(tunChannel.wsconn, errorCode)
} else if tunnel.Type == adaptix.TUNNEL_TYPE_SOCKS4 {
proxy.ReplySocks4StatusWs(tunChannel.wsconn, false)
}
}
}
ts.TunnelManager.CloseChannelByIdOnly(channelId, false)
}
func (ts *Teamserver) TsTunnelConnectionAccept(tunnelId int, channelId int) {
tunId := fmt.Sprintf("%08x", tunnelId)
tunnel, ok := ts.TunnelManager.GetTunnel(tunId)
if !ok {
return
}
agent, err := ts.getAgent(tunnel.Data.AgentId)
if err != nil {
return
}
if tunnel.Data.Client == "" {
handlerReverseAccept(ts.TunnelManager, agent, tunnel, channelId)
} else {
// TODO: reverse proxy to client
}
}
/// handlers
func handleTunChannelCreate(tm *TunnelManager, agent *Agent, tunnel *Tunnel, conn net.Conn) {
channelId := 0
for i := 0; i < 32; i++ {
cid := int(rand.Uint32())
if cid == 0 {
continue
}
if !tm.ChannelExistsInTunnel(tunnel, cid) {
channelId = cid
break
}
}
if channelId == 0 {
_ = conn.Close()
return
}
stc := NewSafeTunnelChannel(tm, channelId, conn, nil, "TCP")
tunChannel := stc.TunnelChannel
var taskData adaptix.TaskData
switch tunnel.Type {
case adaptix.TUNNEL_TYPE_SOCKS4:
proxySock, err := proxy.CheckSocks4(conn)
if err != nil {
logs.Debug("", "[ERROR] Socks4 proxy error: %v", err)
tm.closeChannelInternal(tunnel, tunChannel)
return
}
taskData = tunnel.Callbacks.ConnectTCP(tunChannel.channelId, proxySock.SocksType, proxySock.AddressType, proxySock.Address, proxySock.Port)
case adaptix.TUNNEL_TYPE_SOCKS5:
proxySock, err := proxy.CheckSocks5(conn, false, "", "")
if err != nil {
logs.Debug("", "[ERROR] Socks5 proxy error: %v", err)
tm.closeChannelInternal(tunnel, tunChannel)
return
}
if proxySock.SocksCommand == 3 {
taskData = tunnel.Callbacks.ConnectUDP(tunChannel.channelId, proxySock.SocksType, proxySock.AddressType, proxySock.Address, proxySock.Port)
tunChannel.protocol = "UDP"
} else {
taskData = tunnel.Callbacks.ConnectTCP(tunChannel.channelId, proxySock.SocksType, proxySock.AddressType, proxySock.Address, proxySock.Port)
}
case adaptix.TUNNEL_TYPE_SOCKS5_AUTH:
proxySock, err := proxy.CheckSocks5(conn, true, tunnel.Data.AuthUser, tunnel.Data.AuthPass)
if err != nil {
logs.Debug("", "Socks5 proxy error: %v", err)
tm.closeChannelInternal(tunnel, tunChannel)
return
}
if proxySock.SocksCommand == 3 {
taskData = tunnel.Callbacks.ConnectUDP(tunChannel.channelId, proxySock.SocksType, proxySock.AddressType, proxySock.Address, proxySock.Port)
tunChannel.protocol = "UDP"
} else {
taskData = tunnel.Callbacks.ConnectTCP(tunChannel.channelId, proxySock.SocksType, proxySock.AddressType, proxySock.Address, proxySock.Port)
}
case adaptix.TUNNEL_TYPE_LOCAL_PORT:
tport, _ := strconv.Atoi(tunnel.Data.Fport)
taskData = tunnel.Callbacks.ConnectTCP(tunChannel.channelId, adaptix.TUNNEL_TYPE_LOCAL_PORT, adaptix.ADDRESS_TYPE_IPV4, tunnel.Data.Fhost, tport)
default:
tm.closeChannelInternal(tunnel, tunChannel)
return
}
tunnelManageTask(agent, taskData)
tm.RegisterChannel(tunnel.Data.TunnelId, tunnel, tunChannel)
}
func handleTunChannelCreateClient(tm *TunnelManager, agent *Agent, tunnel *Tunnel, wsconn *websocket.Conn, channelId int, targetAddress string, targetPort int, protocol string) {
stc := NewSafeTunnelChannel(tm, channelId, nil, wsconn, "TCP")
tunChannel := stc.TunnelChannel
addressType := proxy.DetectAddrType(targetAddress)
var taskData adaptix.TaskData
switch tunnel.Type {
case adaptix.TUNNEL_TYPE_SOCKS4:
taskData = tunnel.Callbacks.ConnectTCP(tunChannel.channelId, adaptix.TUNNEL_TYPE_SOCKS4, addressType, targetAddress, targetPort)
case adaptix.TUNNEL_TYPE_SOCKS5:
if protocol == "udp" {
taskData = tunnel.Callbacks.ConnectUDP(tunChannel.channelId, adaptix.TUNNEL_TYPE_SOCKS5, addressType, targetAddress, targetPort)
tunChannel.protocol = "UDP"
} else {
taskData = tunnel.Callbacks.ConnectTCP(tunChannel.channelId, adaptix.TUNNEL_TYPE_SOCKS5, addressType, targetAddress, targetPort)
}
case adaptix.TUNNEL_TYPE_SOCKS5_AUTH:
if protocol == "udp" {
taskData = tunnel.Callbacks.ConnectUDP(tunChannel.channelId, adaptix.TUNNEL_TYPE_SOCKS5, addressType, targetAddress, targetPort)
tunChannel.protocol = "UDP"
} else {
taskData = tunnel.Callbacks.ConnectTCP(tunChannel.channelId, adaptix.TUNNEL_TYPE_SOCKS5, addressType, targetAddress, targetPort)
}
case adaptix.TUNNEL_TYPE_LOCAL_PORT:
tport, _ := strconv.Atoi(tunnel.Data.Fport)
taskData = tunnel.Callbacks.ConnectTCP(tunChannel.channelId, adaptix.TUNNEL_TYPE_LOCAL_PORT, addressType, tunnel.Data.Fhost, tport)
default:
tm.closeChannelInternal(tunnel, tunChannel)
return
}
tunnelManageTask(agent, taskData)
tm.RegisterChannel(tunnel.Data.TunnelId, tunnel, tunChannel)
}
func handlerReverseAccept(tm *TunnelManager, agent *Agent, tunnel *Tunnel, channelId int) {
target := tunnel.Data.Fhost + ":" + tunnel.Data.Fport
fwdConn, err := net.Dial("tcp", target)
if err != nil {
rawTaskData := tunnel.Callbacks.Close(channelId)
tunnelManageTask(agent, rawTaskData)
return
}
stc := NewSafeTunnelChannel(tm, channelId, fwdConn, nil, "TCP")
tunChannel := stc.TunnelChannel
tm.RegisterChannel(tunnel.Data.TunnelId, tunnel, tunChannel)
relaySocketToTunnel(tm, agent, tunnel, tunChannel, false)
}
/// process socket
func tunnelManageTask(agent *Agent, taskData adaptix.TaskData) {
taskData.AgentId = agent.GetData().Id
if taskData.TaskId == "" {
taskData.TaskId, _ = krypt.GenerateUID(8)
}
agent.HostedTunnelTasks.Push(taskData)
}
func relayPipeToTaskData(agent *Agent, channelId int, taskData adaptix.TaskData) {
if taskData.TaskId == "" {
taskData.TaskId, _ = krypt.GenerateUID(8)
}
taskData.AgentId = agent.GetData().Id
agent.HostedTunnelTasks.Push(taskData)
}
func relaySocketToTunnel(tm *TunnelManager, agent *Agent, tunnel *Tunnel, tunChannel *TunnelChannel, direct bool) {
var taskData adaptix.TaskData
ctx, cancel := context.WithCancel(context.Background())
tunnelId := tunnel.Data.TunnelId
var once sync.Once
finish := func() {
once.Do(func() {
cancel()
tm.CloseChannel(tunnelId, tunChannel.channelId)
taskData = tunnel.Callbacks.Close(tunChannel.channelId)
tunnelManageTask(agent, taskData)
})
}
go func() {
if direct {
defer finish()
}
if tunChannel.pwSrv == nil || tunChannel.conn == nil {
logs.Debug("", "[ERROR relaySocketToTunnel] pwSrv or conn == nil — copy (pwSrv <- conn)")
return
}
buf := tm.GetBuffer()
defer tm.PutBuffer(buf)
_, _ = io.CopyBuffer(tunChannel.pwSrv, tunChannel.conn, buf)
_ = tunChannel.pwSrv.Close()
}()
if !direct {
go func() {
defer finish()
buf := tm.GetBuffer()
defer tm.PutBuffer(buf)
backoff := time.Duration(1) * time.Millisecond
const maxBackoff = 50 * time.Millisecond
const minBackoff = 1 * time.Millisecond
for {
select {
case <-ctx.Done():
return
default:
if tunChannel.paused.Load() {
time.Sleep(backoff)
if backoff < maxBackoff {
backoff *= 2
}
continue
}
if agent.HostedTunnelTasks != nil && agent.HostedTunnelTasks.Len() > 128 {
time.Sleep(backoff)
if backoff < maxBackoff {
backoff *= 2
}
continue
}
n, err := tunChannel.prSrv.Read(buf)
if n > 0 {
backoff = minBackoff
var td adaptix.TaskData
if tunChannel.protocol == "UDP" {
td = tunnel.Callbacks.WriteUDP(tunChannel.channelId, buf[:n])
} else {
td = tunnel.Callbacks.WriteTCP(tunChannel.channelId, buf[:n])
}
relayPipeToTaskData(agent, tunChannel.channelId, td)
}
if err != nil {
return
}
}
}
}()
}
}
func relayWebsocketToTunnel(tm *TunnelManager, agent *Agent, tunnel *Tunnel, tunChannel *TunnelChannel, direct bool) {
ctx, cancel := context.WithCancel(context.Background())
tunnelId := tunnel.Data.TunnelId
var once sync.Once
finish := func() {
once.Do(func() {
cancel()
tm.CloseChannel(tunnelId, tunChannel.channelId)
taskData := tunnel.Callbacks.Close(tunChannel.channelId)
tunnelManageTask(agent, taskData)
})
}
go func() {
if direct {
defer finish()
}
if tunChannel.wsconn == nil || tunChannel.pwSrv == nil {
return
}
for {
_, msg, err := tunChannel.wsconn.ReadMessage()
if err != nil {
break
}
if _, err := tunChannel.pwSrv.Write(msg); err != nil {
break
}
}
_ = tunChannel.pwSrv.Close()
}()
if !direct {
go func() {
defer finish()
buf := tm.GetBuffer()
defer tm.PutBuffer(buf)
backoff := time.Duration(1) * time.Millisecond
const maxBackoff = 50 * time.Millisecond
const minBackoff = 1 * time.Millisecond
for {
select {
case <-ctx.Done():
return
default:
if tunChannel.paused.Load() {
time.Sleep(backoff)
if backoff < maxBackoff {
backoff *= 2
}
continue
}
if agent.HostedTunnelTasks != nil && agent.HostedTunnelTasks.Len() > 128 {
time.Sleep(backoff)
if backoff < maxBackoff {
backoff *= 2
}
continue
}
n, err := tunChannel.prSrv.Read(buf)
if n > 0 {
backoff = minBackoff
var td adaptix.TaskData
if tunChannel.protocol == "UDP" {
td = tunnel.Callbacks.WriteUDP(tunChannel.channelId, buf[:n])
} else {
td = tunnel.Callbacks.WriteTCP(tunChannel.channelId, buf[:n])
}
relayPipeToTaskData(agent, tunChannel.channelId, td)
}
if err != nil {
return
}
}
}
}()
}
}