add recorder for serial handler
This commit is contained in:
parent
a623232cc1
commit
a743862f23
@ -229,6 +229,8 @@ type IngressConfig struct {
|
||||
type RecorderConfig struct {
|
||||
Name string `json:"name"`
|
||||
File *FileRecorder `yaml:",omitempty" json:"file,omitempty"`
|
||||
TCP *TCPRecorder `yaml:"tcp,omitempty" json:"tcp,omitempty"`
|
||||
HTTP *HTTPRecorder `yaml:"http,omitempty" json:"http,omitempty"`
|
||||
Redis *RedisRecorder `yaml:",omitempty" json:"redis,omitempty"`
|
||||
Plugin *PluginConfig `yaml:",omitempty" json:"plugin,omitempty"`
|
||||
}
|
||||
@ -238,6 +240,16 @@ type FileRecorder struct {
|
||||
Sep string `yaml:",omitempty" json:"sep,omitempty"`
|
||||
}
|
||||
|
||||
type TCPRecorder struct {
|
||||
Addr string `json:"addr"`
|
||||
Timeout time.Duration `json:"timeout"`
|
||||
}
|
||||
|
||||
type HTTPRecorder struct {
|
||||
URL string `json:"url" yaml:"url"`
|
||||
Timeout time.Duration `json:"timeout"`
|
||||
}
|
||||
|
||||
type RedisRecorder struct {
|
||||
Addr string `json:"addr"`
|
||||
DB int `yaml:",omitempty" json:"db,omitempty"`
|
||||
@ -249,6 +261,7 @@ type RedisRecorder struct {
|
||||
type RecorderObject struct {
|
||||
Name string `json:"name"`
|
||||
Record string `json:"record"`
|
||||
Metadata map[string]any
|
||||
}
|
||||
|
||||
type LimiterConfig struct {
|
||||
|
@ -49,6 +49,10 @@ const (
|
||||
mdKeyPostUp = "postUp"
|
||||
mdKeyPostDown = "postDown"
|
||||
mdKeyIgnoreChain = "ignoreChain"
|
||||
|
||||
mdKeyRecorderDirection = "direction"
|
||||
mdKeyRecorderTimestampFormat = "timeStampFormat"
|
||||
mdKeyRecorderHexdump = "hexdump"
|
||||
)
|
||||
|
||||
func ParseAuther(cfg *config.AutherConfig) auth.Authenticator {
|
||||
@ -492,6 +496,14 @@ func ParseRecorder(cfg *config.RecorderConfig) (r recorder.Recorder) {
|
||||
)
|
||||
}
|
||||
|
||||
if cfg.TCP != nil && cfg.TCP.Addr != "" {
|
||||
return xrecorder.TCPRecorder(cfg.TCP.Addr, xrecorder.TimeoutTCPRecorderOption(cfg.TCP.Timeout))
|
||||
}
|
||||
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
return xrecorder.HTTPRecorder(cfg.HTTP.URL, xrecorder.TimeoutHTTPRecorderOption(cfg.HTTP.Timeout))
|
||||
}
|
||||
|
||||
if cfg.Redis != nil &&
|
||||
cfg.Redis.Addr != "" &&
|
||||
cfg.Redis.Key != "" {
|
||||
|
@ -167,9 +167,15 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
|
||||
var recorders []recorder.RecorderObject
|
||||
for _, r := range cfg.Recorders {
|
||||
md := metadata.NewMetadata(r.Metadata)
|
||||
recorders = append(recorders, recorder.RecorderObject{
|
||||
Recorder: registry.RecorderRegistry().Get(r.Name),
|
||||
Record: r.Record,
|
||||
Options: &recorder.Options{
|
||||
Direction: mdutil.GetBool(md, mdKeyRecorderDirection),
|
||||
TimestampFormat: mdutil.GetString(md, mdKeyRecorderTimestampFormat),
|
||||
Hexdump: mdutil.GetBool(md, mdKeyRecorderHexdump),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
2
go.mod
2
go.mod
@ -7,7 +7,7 @@ require (
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
|
||||
github.com/gin-contrib/cors v1.3.1
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/go-gost/core v0.0.0-20230916134612-801f835e9ac1
|
||||
github.com/go-gost/core v0.0.0-20230918131208-c258a114c40b
|
||||
github.com/go-gost/gosocks4 v0.0.1
|
||||
github.com/go-gost/gosocks5 v0.3.1-0.20211109033403-d894d75b7f09
|
||||
github.com/go-gost/plugin v0.0.0-20230418123101-d221a4ec9a98
|
||||
|
4
go.sum
4
go.sum
@ -99,8 +99,8 @@ github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SU
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gost/core v0.0.0-20230916134612-801f835e9ac1 h1:2B5ir4WZUv5EI+5sKsvSP6GDbrvx/b2+/BnQDPFV1Kg=
|
||||
github.com/go-gost/core v0.0.0-20230916134612-801f835e9ac1/go.mod h1:db6lBY+DkC3ct4OJfclsKnQwQmcv1B9NnMnpI2MNUwY=
|
||||
github.com/go-gost/core v0.0.0-20230918131208-c258a114c40b h1:kqALaNXbbYyKFlcLj3ODsuvzplRxypnJOhMINSiM8sk=
|
||||
github.com/go-gost/core v0.0.0-20230918131208-c258a114c40b/go.mod h1:db6lBY+DkC3ct4OJfclsKnQwQmcv1B9NnMnpI2MNUwY=
|
||||
github.com/go-gost/gosocks4 v0.0.1 h1:+k1sec8HlELuQV7rWftIkmy8UijzUt2I6t+iMPlGB2s=
|
||||
github.com/go-gost/gosocks4 v0.0.1/go.mod h1:3B6L47HbU/qugDg4JnoFPHgJXE43Inz8Bah1QaN9qCc=
|
||||
github.com/go-gost/gosocks5 v0.3.1-0.20211109033403-d894d75b7f09 h1:A95M6UWcfZgOuJkQ7QLfG0Hs5peWIUSysCDNz4pfe04=
|
||||
|
@ -12,33 +12,52 @@ import (
|
||||
|
||||
type recorderConn struct {
|
||||
net.Conn
|
||||
recorder recorder.Recorder
|
||||
recorder recorder.RecorderObject
|
||||
}
|
||||
|
||||
func (c *recorderConn) Read(b []byte) (n int, err error) {
|
||||
n, err = c.Conn.Read(b)
|
||||
|
||||
if n > 0 && c.recorder != nil {
|
||||
if n > 0 && c.recorder.Recorder != nil {
|
||||
var buf bytes.Buffer
|
||||
if c.recorder.Options != nil && c.recorder.Options.Direction {
|
||||
buf.WriteByte('>')
|
||||
buf.WriteString(time.Now().Format("2006-01-02 15:04:05.000"))
|
||||
}
|
||||
if c.recorder.Options != nil && c.recorder.Options.TimestampFormat != "" {
|
||||
buf.WriteString(time.Now().Format(c.recorder.Options.TimestampFormat))
|
||||
}
|
||||
if buf.Len() > 0 {
|
||||
buf.WriteByte('\n')
|
||||
}
|
||||
if c.recorder.Options != nil && c.recorder.Options.Hexdump {
|
||||
buf.WriteString(hex.Dump(b[:n]))
|
||||
c.recorder.Record(context.Background(), buf.Bytes())
|
||||
} else {
|
||||
buf.Write(b[:n])
|
||||
}
|
||||
c.recorder.Recorder.Record(context.Background(), buf.Bytes())
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *recorderConn) Write(b []byte) (int, error) {
|
||||
if c.recorder != nil {
|
||||
if c.recorder.Recorder != nil {
|
||||
var buf bytes.Buffer
|
||||
if c.recorder.Options != nil && c.recorder.Options.Direction {
|
||||
buf.WriteByte('<')
|
||||
buf.WriteString(time.Now().Format("2006-01-02 15:04:05.000"))
|
||||
}
|
||||
if c.recorder.Options != nil && c.recorder.Options.TimestampFormat != "" {
|
||||
buf.WriteString(time.Now().Format(c.recorder.Options.TimestampFormat))
|
||||
}
|
||||
if buf.Len() > 0 {
|
||||
buf.WriteByte('\n')
|
||||
}
|
||||
if c.recorder.Options != nil && c.recorder.Options.Hexdump {
|
||||
buf.WriteString(hex.Dump(b))
|
||||
c.recorder.Record(context.Background(), buf.Bytes())
|
||||
} else {
|
||||
buf.Write(b)
|
||||
}
|
||||
c.recorder.Recorder.Record(context.Background(), buf.Bytes())
|
||||
}
|
||||
return c.Conn.Write(b)
|
||||
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ type serialHandler struct {
|
||||
router *chain.Router
|
||||
md metadata
|
||||
options handler.Options
|
||||
recorder recorder.Recorder
|
||||
recorder recorder.RecorderObject
|
||||
}
|
||||
|
||||
func NewHandler(opts ...handler.Option) handler.Handler {
|
||||
@ -54,7 +54,7 @@ func (h *serialHandler) Init(md md.Metadata) (err error) {
|
||||
if opts := h.router.Options(); opts != nil {
|
||||
for _, ro := range opts.Recorders {
|
||||
if ro.Record == xrecorder.RecorderServiceHandlerSerial {
|
||||
h.recorder = ro.Recorder
|
||||
h.recorder = ro
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -96,12 +96,10 @@ func (h *serialHandler) Handle(ctx context.Context, conn net.Conn, opts ...handl
|
||||
|
||||
log.Debugf("%s >> %s", conn.LocalAddr(), target.Addr)
|
||||
|
||||
if h.recorder != nil {
|
||||
conn = &recorderConn{
|
||||
Conn: conn,
|
||||
recorder: h.recorder,
|
||||
}
|
||||
}
|
||||
|
||||
// serial port
|
||||
if _, _, err := net.SplitHostPort(target.Addr); err != nil {
|
||||
|
62
recorder/http.go
Normal file
62
recorder/http.go
Normal file
@ -0,0 +1,62 @@
|
||||
package recorder
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-gost/core/recorder"
|
||||
)
|
||||
|
||||
type httpRecorderOptions struct {
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
type HTTPRecorderOption func(opts *httpRecorderOptions)
|
||||
|
||||
func TimeoutHTTPRecorderOption(timeout time.Duration) HTTPRecorderOption {
|
||||
return func(opts *httpRecorderOptions) {
|
||||
opts.timeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
type httpRecorder struct {
|
||||
url string
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
// HTTPRecorder records data to HTTP service.
|
||||
func HTTPRecorder(url string, opts ...HTTPRecorderOption) recorder.Recorder {
|
||||
var options httpRecorderOptions
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
return &httpRecorder{
|
||||
url: url,
|
||||
httpClient: &http.Client{
|
||||
Timeout: options.timeout,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (r *httpRecorder) Record(ctx context.Context, b []byte) error {
|
||||
req, err := http.NewRequest(http.MethodPost, r.url, bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := r.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("%d %s", resp.StatusCode, resp.Status)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
52
recorder/tcp.go
Normal file
52
recorder/tcp.go
Normal file
@ -0,0 +1,52 @@
|
||||
package recorder
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/go-gost/core/recorder"
|
||||
)
|
||||
|
||||
type tcpRecorderOptions struct {
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
type TCPRecorderOption func(opts *tcpRecorderOptions)
|
||||
|
||||
func TimeoutTCPRecorderOption(timeout time.Duration) TCPRecorderOption {
|
||||
return func(opts *tcpRecorderOptions) {
|
||||
opts.timeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
type tcpRecorder struct {
|
||||
addr string
|
||||
dialer *net.Dialer
|
||||
}
|
||||
|
||||
// TCPRecorder records data to TCP service.
|
||||
func TCPRecorder(addr string, opts ...TCPRecorderOption) recorder.Recorder {
|
||||
var options tcpRecorderOptions
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
return &tcpRecorder{
|
||||
addr: addr,
|
||||
dialer: &net.Dialer{
|
||||
Timeout: options.timeout,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (r *tcpRecorder) Record(ctx context.Context, b []byte) error {
|
||||
c, err := r.dialer.DialContext(ctx, "tcp", r.addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
_, err = c.Write(b)
|
||||
return err
|
||||
}
|
Loading…
Reference in New Issue
Block a user