Skip to content

Commit 30606f4

Browse files
author
Nicolas Chatelain
committed
WIP: session and recovery
1 parent 97ed394 commit 30606f4

File tree

6 files changed

+97
-61
lines changed

6 files changed

+97
-61
lines changed

cmd/proxy/app/app.go

Lines changed: 80 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ var ListenerList map[int]controller.Listener
2727
var ListenerListMutex sync.Mutex
2828
var ProxyController *controller.Controller
2929

30+
// CurrentAgentID points to the selected agent in the UI (when running session)
31+
var CurrentAgentID int
32+
33+
// Store AgentIDs
34+
var AgentCounter int
35+
3036
var (
3137
ErrInvalidAgent = errors.New("please, select an agent using the session command")
3238
ErrAlreadyRunning = errors.New("already running")
@@ -35,21 +41,76 @@ var (
3541

3642
func RegisterAgent(agent *controller.LigoloAgent) error {
3743
AgentListMutex.Lock()
38-
AgentList[agent.Id] = agent
39-
AgentListMutex.Unlock()
44+
defer AgentListMutex.Unlock()
45+
46+
for _, registeredAgents := range AgentList {
47+
if agent.SessionID == registeredAgents.SessionID {
48+
logrus.Infof("Recovered an agent: %s", registeredAgents.Name)
49+
registeredAgents.Session = agent.Session
50+
if registeredAgents.Running {
51+
go StartTunnel(registeredAgents, registeredAgents.Interface)
52+
}
53+
return nil
54+
}
55+
}
56+
AgentCounter++
57+
AgentList[AgentCounter] = agent
4058
return nil
4159
}
4260

4361
func UnregisterAgent(agent *controller.LigoloAgent) error {
44-
AgentListMutex.Lock()
62+
/*AgentListMutex.Lock()
4563
delete(AgentList, agent.Id)
46-
AgentListMutex.Unlock()
64+
AgentListMutex.Unlock()*/
4765
return nil
4866
}
4967

68+
func StartTunnel(agent *controller.LigoloAgent, tunName string) {
69+
logrus.Infof("Starting tunnel to %s", agent.Name)
70+
ligoloStack, err := proxy.NewLigoloTunnel(netstack.StackSettings{
71+
TunName: tunName,
72+
MaxInflight: 4096,
73+
})
74+
if err != nil {
75+
logrus.Error("Unable to create tunnel, err:", err)
76+
return
77+
}
78+
ifName, err := ligoloStack.GetStack().Interface().Name()
79+
if err != nil {
80+
logrus.Warn("unable to get interface name, err:", err)
81+
ifName = tunName
82+
}
83+
agent.Interface = ifName
84+
agent.Running = true
85+
86+
ctx, cancelTunnel := context.WithCancel(context.Background())
87+
go ligoloStack.HandleSession(agent.Session, ctx)
88+
89+
for {
90+
select {
91+
case <-agent.CloseChan: // User stopped
92+
logrus.Infof("Closing tunnel to %s...", agent.Name)
93+
cancelTunnel()
94+
return
95+
case <-agent.Session.CloseChan(): // Agent closed
96+
logrus.Warnf("Lost tunnel connection with agent %s!", agent.Name)
97+
//agent.Running = false
98+
//agent.Session = nil
99+
100+
if currentAgent, ok := AgentList[CurrentAgentID]; ok {
101+
if currentAgent.SessionID == agent.SessionID {
102+
App.SetDefaultPrompt()
103+
agent.Session = nil
104+
}
105+
}
106+
107+
cancelTunnel()
108+
return
109+
}
110+
}
111+
}
112+
50113
func Run() {
51-
// CurrentAgent points to the selected agent in the UI (when running session)
52-
var CurrentAgentID int
53114
// AgentList contains all the connected agents
54115
AgentList = make(map[int]*controller.LigoloAgent)
55116
// ListenerList contains all listener relays
@@ -61,7 +122,13 @@ func Run() {
61122
Usage: "session",
62123
Run: func(c *grumble.Context) error {
63124
AgentListMutex.Lock()
64-
if len(AgentList) == 0 {
125+
sessionCount := 0
126+
for _, agent := range AgentList {
127+
if agent.Session != nil && !agent.Session.IsClosed() {
128+
sessionCount += 1
129+
}
130+
}
131+
if sessionCount == 0 {
65132
AgentListMutex.Unlock()
66133
return errors.New("no sessions available")
67134
}
@@ -72,7 +139,9 @@ func Run() {
72139
Options: func() (out []string) {
73140
AgentListMutex.Lock()
74141
for id, agent := range AgentList {
75-
out = append(out, fmt.Sprintf("%d - %s", id, agent.String()))
142+
if agent.Session != nil && !agent.Session.IsClosed() {
143+
out = append(out, fmt.Sprintf("%d - %s", id, agent.String()))
144+
}
76145
}
77146
AgentListMutex.Unlock()
78147
return
@@ -194,48 +263,8 @@ func Run() {
194263
}
195264
}
196265

197-
go func() {
198-
logrus.Infof("Starting tunnel to %s", CurrentAgent.Name)
199-
ligoloStack, err := proxy.NewLigoloTunnel(netstack.StackSettings{
200-
TunName: c.Flags.String("tun"),
201-
MaxInflight: 4096,
202-
})
203-
if err != nil {
204-
logrus.Error("Unable to create tunnel, err:", err)
205-
return
206-
}
207-
ifName, err := ligoloStack.GetStack().Interface().Name()
208-
if err != nil {
209-
logrus.Warn("unable to get interface name, err:", err)
210-
ifName = c.Flags.String("tun")
211-
}
212-
CurrentAgent.Interface = ifName
213-
CurrentAgent.Running = true
214-
215-
ctx, cancelTunnel := context.WithCancel(context.Background())
216-
go ligoloStack.HandleSession(CurrentAgent.Session, ctx)
266+
go StartTunnel(CurrentAgent, c.Flags.String("tun"))
217267

218-
for {
219-
select {
220-
case <-CurrentAgent.CloseChan: // User stopped
221-
logrus.Infof("Closing tunnel to %s...", CurrentAgent.Name)
222-
cancelTunnel()
223-
return
224-
case <-CurrentAgent.Session.CloseChan(): // Agent closed
225-
logrus.Warnf("Lost connection with agent %s!", CurrentAgent.Name)
226-
// Connection lost, we need to delete the Agent from the list
227-
AgentListMutex.Lock()
228-
delete(AgentList, CurrentAgent.Id)
229-
AgentListMutex.Unlock()
230-
if CurrentAgent.Id == CurrentAgent.Id {
231-
App.SetDefaultPrompt()
232-
CurrentAgent.Session = nil
233-
}
234-
cancelTunnel()
235-
return
236-
}
237-
}
238-
}()
239268
return nil
240269
},
241270
})
@@ -252,10 +281,10 @@ func Run() {
252281

253282
AgentListMutex.Lock()
254283

255-
for _, agent := range AgentList {
284+
for id, agent := range AgentList {
256285

257286
if agent.Running {
258-
t.AppendRow(table.Row{agent.Id, agent.Name, agent.Interface})
287+
t.AppendRow(table.Row{id, agent.Name, agent.Interface})
259288
}
260289
}
261290
AgentListMutex.Unlock()

cmd/proxy/main.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,6 @@ func main() {
120120
select {
121121
case <-agent.Session.CloseChan(): // Agent closed
122122
logrus.Warnf("Lost ligolo-ng connection with agent %s!", agent.Name)
123-
if err := app.UnregisterAgent(agent); err != nil {
124-
logrus.Errorf("could not unregister agent: %s", err.Error())
125-
}
126123
return
127124
}
128125
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ require (
1616
)
1717

1818
require (
19+
github.com/google/uuid v1.3.0
1920
github.com/nicocha30/gvisor-ligolo v0.0.0-20230726075806-989fa2c0a413
2021
github.com/vishvananda/netlink v1.1.1-0.20211118161826-650dca95af54
2122
golang.org/x/sys v0.21.0
@@ -29,7 +30,6 @@ require (
2930
github.com/desertbit/readline v1.5.1 // indirect
3031
github.com/fatih/color v1.13.0 // indirect
3132
github.com/google/btree v1.1.2 // indirect
32-
github.com/google/uuid v1.3.0 // indirect
3333
github.com/hashicorp/errwrap v1.1.0 // indirect
3434
github.com/hashicorp/go-multierror v1.1.1 // indirect
3535
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect

pkg/agent/handler.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"github.com/google/uuid"
78
"net"
89
"os"
910
"os/user"
@@ -21,10 +22,13 @@ var listenerConntrack map[int32]net.Conn
2122
var listenerMap map[int32]interface{}
2223
var connTrackID int32
2324
var listenerID int32
25+
var sessionID string
2426

2527
func init() {
2628
listenerConntrack = make(map[int32]net.Conn)
2729
listenerMap = make(map[int32]interface{})
30+
id := uuid.New()
31+
sessionID = id.String()
2832
}
2933

3034
// Listener is the base class implementing listener sockets for Ligolo
@@ -171,6 +175,7 @@ func HandleConn(conn net.Conn) {
171175
infoResponse := protocol.InfoReplyPacket{
172176
Name: fmt.Sprintf("%s@%s", username, hostname),
173177
Interfaces: protocol.NewNetInterfaces(netifaces),
178+
SessionID: sessionID,
174179
}
175180

176181
if err := encoder.Encode(protocol.Envelope{

pkg/controller/agent.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,13 @@ import (
77
"net"
88
)
99

10-
var AgentCounter = 0
1110
var ListenerCounter = 0
1211

1312
type LigoloAgent struct {
14-
Id int
1513
Name string
1614
Network []protocol.NetInterface
1715
Session *yamux.Session
16+
SessionID string
1817
CloseChan chan bool
1918
Interface string
2019
Running bool
@@ -31,11 +30,16 @@ type Listener struct {
3130
}
3231

3332
func (l Listener) String() string {
34-
return fmt.Sprintf("#%d [%s] (%s) [Agent] %s => [Proxy] %s", l.Agent.Id, l.Agent.Name, l.Network, l.ListenerAddr, l.RedirectAddr)
33+
return fmt.Sprintf("[%s] (%s) [Agent] %s => [Proxy] %s", l.Agent.Name, l.Network, l.ListenerAddr, l.RedirectAddr)
3534
}
3635

3736
func (la *LigoloAgent) String() string {
38-
return fmt.Sprintf("#%d - %s - %s", la.Id, la.Name, la.Session.RemoteAddr())
37+
raddr := "Disconnected"
38+
if la.Session != nil {
39+
raddr = la.Session.RemoteAddr().String()
40+
}
41+
42+
return fmt.Sprintf("%s - %s - %s", la.Name, raddr, la.SessionID)
3943
}
4044

4145
func NewAgent(session *yamux.Session) (*LigoloAgent, error) {
@@ -62,12 +66,12 @@ func NewAgent(session *yamux.Session) (*LigoloAgent, error) {
6266

6367
response := protocolDecoder.Envelope.Payload
6468
reply := response.(protocol.InfoReplyPacket)
65-
AgentCounter++
69+
6670
return &LigoloAgent{
67-
Id: AgentCounter,
6871
Name: reply.Name,
6972
Network: reply.Interfaces,
7073
Session: session,
74+
SessionID: reply.SessionID,
7175
CloseChan: make(chan bool),
7276
}, nil
7377
}

pkg/protocol/packets.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type InfoRequestPacket struct {
4747
type InfoReplyPacket struct {
4848
Name string
4949
Interfaces []NetInterface
50+
SessionID string
5051
}
5152

5253
// ListenerSockRequestPacket is used by the proxy when relaying a listener socket

0 commit comments

Comments
 (0)