Skip to content

Commit f61cd39

Browse files
authored
Refactored rsyslog plugin (#4658)
We now use the same code for forwarding logs to syslog: 1. Syslog now uses octet counting transport 2. Syslog log forwarding now works on Windows as well.
1 parent c531fbe commit f61cd39

File tree

9 files changed

+234
-85
lines changed

9 files changed

+234
-85
lines changed

api/events_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88

99
"github.com/Velocidex/ordereddict"
1010
errors "github.com/go-errors/errors"
11-
"github.com/golang/protobuf/proto"
1211
"github.com/stretchr/testify/suite"
1312
acl_proto "www.velocidex.com/golang/velociraptor/acls/proto"
1413
actions_proto "www.velocidex.com/golang/velociraptor/actions/proto"
@@ -36,6 +35,8 @@ var (
3635
name: Server.Audit.Logs
3736
type: SERVER_EVENT
3837
`}
38+
39+
FALSE = false
3940
)
4041

4142
// Tests the public API endpoints
@@ -338,7 +339,7 @@ func (self *GeneralAPITest) TestVFSGetBufferSparse() {
338339
buf, err = client.VFSGetBuffer(self.Ctx, &api_proto.VFSFileBuffer{
339340
Components: filename.Components(),
340341
Length: 100,
341-
Padding: proto.Bool(false),
342+
Padding: &FALSE,
342343
})
343344
assert.NoError(self.T(), err)
344345
assert.Equal(self.T(), string(buf.Data), "HelloWorld")

logging/logging.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
1818
package logging
1919

2020
import (
21+
"context"
2122
"fmt"
2223
"io"
2324
"io/ioutil"
@@ -116,7 +117,7 @@ func InitLogging(config_obj *config_proto.Config) error {
116117
new_manager.contexts[component] = logger
117118
}
118119

119-
err := maybeAddRemoteSyslog(config_obj, new_manager)
120+
err := maybeAddRemoteSyslog(context.Background(), config_obj, new_manager)
120121
if err != nil {
121122
return err
122123
}
Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
//go:build !windows
2-
// +build !windows
3-
41
package logging
52

63
import (
7-
"log/syslog"
4+
"context"
5+
"fmt"
86
"strings"
7+
"time"
98

10-
lSyslog "github.com/sirupsen/logrus/hooks/syslog"
119
config_proto "www.velocidex.com/golang/velociraptor/config/proto"
10+
"www.velocidex.com/golang/velociraptor/utils/syslog"
1211
)
1312

1413
func maybeAddRemoteSyslog(
14+
ctx context.Context,
1515
config_obj *config_proto.Config, manager *LogManager) error {
1616

1717
if config_obj.Logging == nil ||
@@ -58,11 +58,11 @@ func maybeAddRemoteSyslog(
5858
Prelog("<green>Will connect to syslog server %v over %v</>",
5959
server, protocol)
6060

61-
hook, err := lSyslog.NewSyslogHook(
62-
protocol, server, syslog.LOG_INFO, "")
61+
connect_timeout := time.Minute
62+
hook, err := syslog.NewHook(ctx, config_obj.Client, protocol, server,
63+
"", connect_timeout)
6364
if err != nil {
64-
Prelog("While connecting to Syslog %v: %v", server, err)
65-
return err
65+
return fmt.Errorf("While connecting to Syslog Server: %w", err)
6666
}
6767

6868
for k := range components {

logging/syslog_windows.go

Lines changed: 0 additions & 12 deletions
This file was deleted.

utils/syslog/api.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Provides an implementation of a syslog logger
2+
3+
package syslog
4+
5+
import (
6+
"context"
7+
"io"
8+
"time"
9+
10+
"github.com/sirupsen/logrus"
11+
"github.com/sirupsen/logrus/hooks/writer"
12+
config_proto "www.velocidex.com/golang/velociraptor/config/proto"
13+
"www.velocidex.com/golang/velociraptor/utils"
14+
)
15+
16+
var (
17+
Factory func(ctx context.Context,
18+
config_obj *config_proto.ClientConfig,
19+
network, raddr string,
20+
root_certs string,
21+
connectTimeout time.Duration) (io.Writer, error) = nil
22+
)
23+
24+
func NewHook(ctx context.Context,
25+
config_obj *config_proto.ClientConfig,
26+
network, raddr string,
27+
root_certs string,
28+
connectTimeout time.Duration) (logrus.Hook, error) {
29+
if Factory == nil {
30+
return nil, utils.Wrap(utils.NotImplementedError, "Syslog factory not initialized")
31+
}
32+
33+
writer_fd, err := Factory(ctx, config_obj, network, raddr, root_certs, connectTimeout)
34+
if err != nil {
35+
return nil, err
36+
}
37+
38+
return &writer.Hook{
39+
Writer: writer_fd,
40+
LogLevels: []logrus.Level{
41+
logrus.PanicLevel,
42+
logrus.FatalLevel,
43+
logrus.ErrorLevel,
44+
logrus.WarnLevel,
45+
logrus.InfoLevel,
46+
},
47+
}, nil
48+
}

vql/tools/rsyslog/cache.go

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,80 @@
11
package rsyslog
22

33
import (
4+
"context"
45
"time"
56

6-
"github.com/Velocidex/ttlcache/v2"
7+
config_proto "www.velocidex.com/golang/velociraptor/config/proto"
8+
vql_subsystem "www.velocidex.com/golang/velociraptor/vql"
9+
"www.velocidex.com/golang/vfilter"
10+
)
11+
12+
const (
13+
SYSLOG_POOL_TAG = "$SYSLOG"
714
)
815

916
type connectionPool struct {
10-
lru *ttlcache.Cache // map[string]*Logger
17+
ctx context.Context
18+
loggers map[string]*Logger
19+
}
20+
21+
// Get a new Logger for the specified address
22+
func (self *connectionPool) Dial(
23+
config_obj *config_proto.ClientConfig,
24+
network, raddr string,
25+
root_certs string,
26+
connectTimeout time.Duration) (*Logger, error) {
27+
28+
// Check if the connection is already in the pool
29+
existing, ok := self.loggers[raddr]
30+
if ok {
31+
return existing, nil
32+
}
33+
34+
// No logger found, make a new one.
35+
res := &Logger{
36+
ctx: self.ctx,
37+
config_obj: config_obj,
38+
network: network,
39+
raddr: raddr,
40+
root_certs: root_certs,
41+
connectTimeout: connectTimeout,
42+
messageQueue: make(chan string, 1000),
43+
}
44+
45+
err := res.Connect()
46+
if err != nil {
47+
return nil, err
48+
}
49+
50+
go res.Start()
51+
52+
self.loggers[raddr] = res
53+
54+
return res, nil
1155
}
1256

13-
func NewConnectionPool() *connectionPool {
14-
self := &connectionPool{
15-
lru: ttlcache.NewCache(),
57+
// A pool manages access to several syslog loggers. The pool's life
58+
// span is managed using the ctx.
59+
func NewConnectionPool(ctx context.Context) *connectionPool {
60+
return &connectionPool{
61+
ctx: ctx,
62+
loggers: make(map[string]*Logger),
1663
}
64+
}
1765

18-
_ = self.lru.SetTTL(time.Minute)
19-
self.lru.SetCacheSizeLimit(10)
20-
self.lru.SetExpirationCallback(func(key string, value interface{}) error {
21-
logger, ok := value.(*Logger)
66+
// Get a pool stored in the scope for the lifetime of the query.
67+
func GetPool(ctx context.Context, scope vfilter.Scope) *connectionPool {
68+
pool_any := vql_subsystem.CacheGet(scope, SYSLOG_POOL_TAG)
69+
if pool_any != nil {
70+
pool, ok := pool_any.(*connectionPool)
2271
if ok {
23-
logger.Close()
72+
return pool
2473
}
25-
return nil
26-
})
74+
}
75+
76+
pool := NewConnectionPool(ctx)
77+
vql_subsystem.CacheSet(scope, SYSLOG_POOL_TAG, pool)
2778

28-
return self
79+
return pool
2980
}

0 commit comments

Comments
 (0)