(ctx ssh.Context, logger slog.Logger, reportConnection reportConnectionFunc, newChannel gossh.NewChannel, counter *atomic.Int64)
| 35 | } |
| 36 | |
| 37 | func NewJetbrainsChannelWatcher(ctx ssh.Context, logger slog.Logger, reportConnection reportConnectionFunc, newChannel gossh.NewChannel, counter *atomic.Int64) gossh.NewChannel { |
| 38 | d := localForwardChannelData{} |
| 39 | if err := gossh.Unmarshal(newChannel.ExtraData(), &d); err != nil { |
| 40 | // If the data fails to unmarshal, do nothing. |
| 41 | logger.Warn(ctx, "failed to unmarshal port forward data", slog.Error(err)) |
| 42 | return newChannel |
| 43 | } |
| 44 | |
| 45 | // If we do get a port, we should be able to get the matching PID and from |
| 46 | // there look up the invocation. |
| 47 | cmdline, err := getListeningPortProcessCmdline(d.DestPort) |
| 48 | if err != nil { |
| 49 | logger.Warn(ctx, "failed to inspect port", |
| 50 | slog.F("destination_port", d.DestPort), |
| 51 | slog.Error(err)) |
| 52 | return newChannel |
| 53 | } |
| 54 | |
| 55 | // If this is not JetBrains, then we do not need to do anything special. We |
| 56 | // attempt to match on something that appears unique to JetBrains software. |
| 57 | if !isJetbrainsProcess(cmdline) { |
| 58 | return newChannel |
| 59 | } |
| 60 | |
| 61 | logger.Debug(ctx, "discovered forwarded JetBrains process", |
| 62 | slog.F("destination_port", d.DestPort)) |
| 63 | |
| 64 | return &JetbrainsChannelWatcher{ |
| 65 | NewChannel: newChannel, |
| 66 | jetbrainsCounter: counter, |
| 67 | logger: logger.With(slog.F("destination_port", d.DestPort)), |
| 68 | originAddr: d.OriginAddr, |
| 69 | reportConnection: reportConnection, |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | func (w *JetbrainsChannelWatcher) Accept() (gossh.Channel, <-chan *gossh.Request, error) { |
| 74 | disconnected := w.reportConnection(uuid.New(), MagicSessionTypeJetBrains, w.originAddr) |
no test coverage detected