Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7948ab5

Browse files
committed
Implement port process inspection
1 parent 76d3a24 commit 7948ab5

File tree

5 files changed

+58
-10
lines changed

5 files changed

+58
-10
lines changed

agent/agent_test.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -192,10 +192,13 @@ func TestAgent_Stats_Magic(t *testing.T) {
192192
require.NoError(t, err)
193193
})
194194

195-
// This test name being "Jetbrains" is required to be a certain string.
196-
// It must match the regex check in the agent for Jetbrains.
197-
t.Run("Jetbrains", func(t *testing.T) {
195+
// This test name must contain the string checked for by the agent, since it
196+
// looks for this string in the process name.
197+
t.Run("TracksIdea.vendor.name=JetBrains", func(t *testing.T) {
198198
t.Parallel()
199+
if runtime.GOOS != "linux" {
200+
t.Skip("JetBrains tracking is only supported on Linux")
201+
}
199202
ctx := testutil.Context(t, testutil.WaitLong)
200203

201204
rl, err := net.Listen("tcp", "127.0.0.1:0")

agent/agentssh/agentssh.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ func NewServer(ctx context.Context, logger slog.Logger, prometheusRegistry *prom
113113
ChannelHandlers: map[string]ssh.ChannelHandler{
114114
"direct-tcpip": func(srv *ssh.Server, conn *gossh.ServerConn, newChan gossh.NewChannel, ctx ssh.Context) {
115115
// wrapper is designed to find and track jetbrains gateway connections.
116-
wrapped := NewChannelAcceptWatcher(s.logger, newChan, &s.connCountJetBrains)
116+
wrapped := NewChannelAcceptWatcher(ctx, s.logger, newChan, &s.connCountJetBrains)
117117
ssh.DirectTCPIPHandler(srv, conn, wrapped, ctx)
118118
},
119119
"[email protected]": directStreamLocalHandler,

agent/agentssh/jetbrainstrack.go

+22-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package agentssh
22

33
import (
4+
"strings"
45
"sync"
56

67
"cdr.dev/slog"
8+
"github.com/gliderlabs/ssh"
79
"go.uber.org/atomic"
810
gossh "golang.org/x/crypto/ssh"
911
)
@@ -21,17 +23,31 @@ type ChannelAcceptWatcher struct {
2123
jetbrainsCounter *atomic.Int64
2224
}
2325

24-
func NewChannelAcceptWatcher(logger slog.Logger, newChannel gossh.NewChannel, counter *atomic.Int64) gossh.NewChannel {
26+
func NewChannelAcceptWatcher(ctx ssh.Context, logger slog.Logger, newChannel gossh.NewChannel, counter *atomic.Int64) gossh.NewChannel {
2527
d := localForwardChannelData{}
2628
if err := gossh.Unmarshal(newChannel.ExtraData(), &d); err != nil {
27-
// If the data fails to unmarshal, do nothing
29+
// If the data fails to unmarshal, do nothing.
2830
return newChannel
2931
}
3032

31-
//if !jetbrains {
32-
// If this isn't jetbrains, then we don't need to do anything special.
33-
//return newChannel
34-
//}
33+
// If we do get a port, we should be able to get the matching PID and from
34+
// there look up the name
35+
name, err := getListeningPortProcessName(d.DestPort)
36+
if err != nil {
37+
logger.Warn(ctx, "port inspection failed",
38+
slog.F("destination_port", d.DestPort),
39+
slog.Error(err))
40+
return newChannel
41+
}
42+
43+
// If this isn't JetBrains, then we don't need to do anything special. We
44+
// attempt to match on something that appears unique to JetBrains software.
45+
if strings.Contains(strings.ToLower(name), "idea.vendor.name=jetbrains") {
46+
return newChannel
47+
}
48+
49+
logger.Debug(ctx, "discovered forwarded JetBrains process",
50+
slog.F("destination_port", d.DestPort))
3551

3652
return &ChannelAcceptWatcher{
3753
NewChannel: newChannel,
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//go:build linux || (windows && amd64)
2+
3+
package agentssh
4+
5+
import (
6+
"github.com/cakturk/go-netstat/netstat"
7+
)
8+
9+
func getListeningPortProcessName(port uint32) (string, error) {
10+
tabs, err := netstat.TCPSocks(func(s *netstat.SockTabEntry) bool {
11+
return s.LocalAddr != nil && uint32(s.LocalAddr.Port) == port
12+
})
13+
if err != nil {
14+
return "", err
15+
}
16+
if len(tabs) == 0 {
17+
return "", nil
18+
}
19+
return tabs[0].Process.Name, nil
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//go:build !linux && !(windows && amd64)
2+
3+
package agentssh
4+
5+
func getListeningPortProcessCmdline(port uint32) (string, error) {
6+
// We are not worrying about other platforms at the moment because Gateway
7+
// only supports Linux anyway.
8+
return "", nil
9+
}

0 commit comments

Comments
 (0)