Skip to content

Commit fe85235

Browse files
committed
new dump_limit_size parameter: stop dumping records beyond this size. Bugfix: dumps now have the appropriate size and content.
1 parent 7cdb0f0 commit fe85235

File tree

5 files changed

+46
-14
lines changed

5 files changed

+46
-14
lines changed

cmd/sshproxy/recorder.go

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ import (
2323
"github.com/cea-hpc/sshproxy/pkg/utils"
2424
)
2525

26+
// Dup duplicates a []byte slice.
27+
func Dup(a []byte, n int) []byte {
28+
b := make([]byte, n)
29+
copy(b, a)
30+
return b
31+
}
32+
2633
// A Splitter reads from and/or writes to a file descriptor and sends a
2734
// record.Record struct to a channel for each read/write operation.
2835
type Splitter struct {
@@ -48,23 +55,25 @@ func (s *Splitter) Close() error {
4855
// its internal channel.
4956
func (s *Splitter) Read(p []byte) (int, error) {
5057
n, err := s.f.Read(p)
58+
pp := Dup(p, n)
5159
s.ch <- record.Record{
5260
Time: time.Now(),
5361
Fd: s.fd,
5462
Size: n,
55-
Data: p,
63+
Data: pp,
5664
}
5765
return n, err
5866
}
5967

6068
// Write implements the Writer Write method. It sends a copy of the written
6169
// slice to its internal channel.
6270
func (s *Splitter) Write(p []byte) (int, error) {
71+
pp := Dup(p, len(p))
6372
s.ch <- record.Record{
6473
Time: time.Now(),
6574
Fd: s.fd,
6675
Size: len(p),
67-
Data: p,
76+
Data: pp,
6877
}
6978
return s.f.Write(p)
7079
}
@@ -78,7 +87,7 @@ func (s *Splitter) Write(p []byte) (int, error) {
7887
// The file is a succession of serialized record.Record structs. See the
7988
// record.Record documentation for details on the format.
8089
type Recorder struct {
81-
Stdin, Stdout, Stderr io.ReadWriteCloser // standard input, output and error to be used instead of the standard file descriptors.
90+
Stdin, Stdout, Stderr io.ReadWriteCloser // standard input, output and error to be used instead of the standard file descriptors
8291
start time.Time // when the Recorder was started
8392
etcdStatsInterval time.Duration // interval at which bandwidth is updated in etcd
8493
logStatsInterval time.Duration // interval at which basic statistics of transferred bytes are logged
@@ -87,16 +96,17 @@ type Recorder struct {
8796
ch chan record.Record // channel to read record.Record structs
8897
conninfo *ConnInfo // specific SSH connection information
8998
command string // initial user command
90-
dumpfile string // path to filename where the raw records are dumped.
91-
writer *record.Writer // *record.Writer where the raw records are dumped.
99+
dumpfile string // path to filename where the raw records are dumped
100+
dumpLimitSize uint64 // number of bytes beyond which records are no longer dumped
101+
writer *record.Writer // *record.Writer where the raw records are dumped
92102
}
93103

94104
// NewRecorder returns a new Recorder struct.
95105
//
96106
// If dumpfile is not empty, the intercepted raw data will be written in this
97107
// file. Logging of basic statistics will be done every logStatsInterval seconds. Bandwidth will be updated in etcd every etcdStatsInterval seconds.
98108
// It will stop recording when the context is cancelled.
99-
func NewRecorder(conninfo *ConnInfo, dumpfile, command string, etcdStatsInterval time.Duration, logStatsInterval time.Duration) *Recorder {
109+
func NewRecorder(conninfo *ConnInfo, dumpfile, command string, etcdStatsInterval time.Duration, logStatsInterval time.Duration, dumpLimitSize uint64) *Recorder {
100110
ch := make(chan record.Record)
101111

102112
return &Recorder{
@@ -111,6 +121,7 @@ func NewRecorder(conninfo *ConnInfo, dumpfile, command string, etcdStatsInterval
111121
conninfo: conninfo,
112122
command: command,
113123
dumpfile: dumpfile,
124+
dumpLimitSize: dumpLimitSize,
114125
writer: nil,
115126
}
116127
}
@@ -246,6 +257,11 @@ func (r *Recorder) Run(ctx context.Context, cli *utils.Client, etcdPath string)
246257
r.totals[rec.Fd] += uint64(rec.Size)
247258
if r.writer != nil {
248259
r.dump(rec)
260+
if r.dumpLimitSize != 0 && r.totals[rec.Fd] > r.dumpLimitSize {
261+
fd.Close()
262+
fd = nil
263+
r.writer = nil
264+
}
249265
}
250266
case <-ctx.Done():
251267
return
@@ -258,6 +274,11 @@ func (r *Recorder) Run(ctx context.Context, cli *utils.Client, etcdPath string)
258274
r.totals[rec.Fd] += uint64(rec.Size)
259275
if r.writer != nil {
260276
r.dump(rec)
277+
if r.dumpLimitSize != 0 && r.totals[rec.Fd] > r.dumpLimitSize {
278+
fd.Close()
279+
fd = nil
280+
r.writer = nil
281+
}
261282
}
262283
case <-ctx.Done():
263284
return

cmd/sshproxy/sshproxy.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ func mainExitCode() int {
300300
log.Debugf("config.log = %s", config.Log)
301301
log.Debugf("config.check_interval = %s", config.CheckInterval.Duration())
302302
log.Debugf("config.dump = %s", config.Dump)
303+
log.Debugf("config.dump_limit_size = %d", config.DumpLimitSize)
303304
log.Debugf("config.etcd_stats_interval = %s", config.EtcdStatsInterval.Duration())
304305
log.Debugf("config.log_stats_interval = %s", config.LogStatsInterval.Duration())
305306
log.Debugf("config.etcd = %+v", config.Etcd)
@@ -437,11 +438,7 @@ func mainExitCode() int {
437438

438439
var recorder *Recorder
439440
if config.Dump != "" {
440-
if !interactiveCommand {
441-
// dont't dump non-interactive commands, but still log and update etcd
442-
config.Dump = "etcd"
443-
}
444-
recorder = NewRecorder(conninfo, config.Dump, originalCmd, config.EtcdStatsInterval.Duration(), config.LogStatsInterval.Duration())
441+
recorder = NewRecorder(conninfo, config.Dump, originalCmd, config.EtcdStatsInterval.Duration(), config.LogStatsInterval.Duration(), config.DumpLimitSize)
445442

446443
wg.Add(1)
447444
go func() {

config/sshproxy.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,12 @@
2828
# 'TCP:host:port' (the TCP is case sensitive), e.g. 'TCP:collector:5555'.
2929
#dump: ""
3030

31+
# Maximum size of a dump (bytes). Beyond the limit, records are no more dumped.
32+
# Defaults to 0 (no limit).
33+
#dump_limit_size: 0
34+
3135
# Interval at which basic statistics of transferred bytes are logged.
32-
# 0 by default, the string can contain a unit suffix such as 'h', 'm' and
36+
# "0" by default, the string can contain a unit suffix such as 'h', 'm' and
3337
# 's' (e.g. "2m30s"). These statistics are only available when the 'dump'
3438
# option is set.
3539
#log_stats_interval: "0"

doc/sshproxy.yaml.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ user needs to have the right to write in this directory. For example:
6363
It can also be a network address where to send dumps if specified as
6464
'TCP:host:port' (the TCP is case sensitive), e.g. 'TCP:collector:5555'.
6565

66+
*dump_limit_size*::
67+
an integer specifying the maximum size (bytes) of a dump. Beyond this
68+
size, records are no longer dumped. Defaults to 0 (no limit).
69+
6670
*log_stats_interval*::
6771
a string specifying the interval at which basic statistics of
6872
transferred bytes are logged. 0 by default. The string can contain a

pkg/utils/config.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ type Config struct {
2929
Log string
3030
CheckInterval Duration `yaml:"check_interval"` // Minimum interval between host checks
3131
Dump string
32+
DumpLimitSize uint64 `yaml:"dump_limit_size"`
3233
Etcd etcdConfig
3334
EtcdStatsInterval Duration `yaml:"etcd_stats_interval"`
3435
LogStatsInterval Duration `yaml:"log_stats_interval"`
@@ -75,8 +76,9 @@ type subConfig struct {
7576
Debug interface{}
7677
Log interface{}
7778
Dump interface{}
78-
EtcdStatsInterval interface{} `yaml:"stats_interval"`
79-
LogStatsInterval interface{} `yaml:"stats_interval"`
79+
DumpLimitSize interface{} `yaml:"dump_limit_size"`
80+
EtcdStatsInterval interface{} `yaml:"etcd_stats_interval"`
81+
LogStatsInterval interface{} `yaml:"log_stats_interval"`
8082
BgCommand interface{} `yaml:"bg_command"`
8183
Environment map[string]string
8284
Routes map[string]*RouteConfig
@@ -96,6 +98,10 @@ func parseSubConfig(config *Config, subconfig *subConfig) error {
9698
config.Dump = subconfig.Dump.(string)
9799
}
98100

101+
if subconfig.DumpLimitSize != nil {
102+
config.DumpLimitSize = subconfig.DumpLimitSize.(uint64)
103+
}
104+
99105
if subconfig.EtcdStatsInterval != nil {
100106
var err error
101107
config.EtcdStatsInterval, err = ParseDuration(subconfig.EtcdStatsInterval.(string))

0 commit comments

Comments
 (0)