@@ -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.
2835type Splitter struct {
@@ -48,23 +55,25 @@ func (s *Splitter) Close() error {
4855// its internal channel.
4956func (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.
6270func (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.
8089type 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
0 commit comments