add recorder for serial handler
This commit is contained in:
parent
a623232cc1
commit
a743862f23
@ -229,6 +229,8 @@ type IngressConfig struct {
|
|||||||
type RecorderConfig struct {
|
type RecorderConfig struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
File *FileRecorder `yaml:",omitempty" json:"file,omitempty"`
|
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"`
|
Redis *RedisRecorder `yaml:",omitempty" json:"redis,omitempty"`
|
||||||
Plugin *PluginConfig `yaml:",omitempty" json:"plugin,omitempty"`
|
Plugin *PluginConfig `yaml:",omitempty" json:"plugin,omitempty"`
|
||||||
}
|
}
|
||||||
@ -238,6 +240,16 @@ type FileRecorder struct {
|
|||||||
Sep string `yaml:",omitempty" json:"sep,omitempty"`
|
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 {
|
type RedisRecorder struct {
|
||||||
Addr string `json:"addr"`
|
Addr string `json:"addr"`
|
||||||
DB int `yaml:",omitempty" json:"db,omitempty"`
|
DB int `yaml:",omitempty" json:"db,omitempty"`
|
||||||
@ -249,6 +261,7 @@ type RedisRecorder struct {
|
|||||||
type RecorderObject struct {
|
type RecorderObject struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Record string `json:"record"`
|
Record string `json:"record"`
|
||||||
|
Metadata map[string]any
|
||||||
}
|
}
|
||||||
|
|
||||||
type LimiterConfig struct {
|
type LimiterConfig struct {
|
||||||
|
@ -49,6 +49,10 @@ const (
|
|||||||
mdKeyPostUp = "postUp"
|
mdKeyPostUp = "postUp"
|
||||||
mdKeyPostDown = "postDown"
|
mdKeyPostDown = "postDown"
|
||||||
mdKeyIgnoreChain = "ignoreChain"
|
mdKeyIgnoreChain = "ignoreChain"
|
||||||
|
|
||||||
|
mdKeyRecorderDirection = "direction"
|
||||||
|
mdKeyRecorderTimestampFormat = "timeStampFormat"
|
||||||
|
mdKeyRecorderHexdump = "hexdump"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseAuther(cfg *config.AutherConfig) auth.Authenticator {
|
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 &&
|
if cfg.Redis != nil &&
|
||||||
cfg.Redis.Addr != "" &&
|
cfg.Redis.Addr != "" &&
|
||||||
cfg.Redis.Key != "" {
|
cfg.Redis.Key != "" {
|
||||||
|
@ -167,9 +167,15 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
|||||||
|
|
||||||
var recorders []recorder.RecorderObject
|
var recorders []recorder.RecorderObject
|
||||||
for _, r := range cfg.Recorders {
|
for _, r := range cfg.Recorders {
|
||||||
|
md := metadata.NewMetadata(r.Metadata)
|
||||||
recorders = append(recorders, recorder.RecorderObject{
|
recorders = append(recorders, recorder.RecorderObject{
|
||||||
Recorder: registry.RecorderRegistry().Get(r.Name),
|
Recorder: registry.RecorderRegistry().Get(r.Name),
|
||||||
Record: r.Record,
|
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/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
|
||||||
github.com/gin-contrib/cors v1.3.1
|
github.com/gin-contrib/cors v1.3.1
|
||||||
github.com/gin-gonic/gin v1.9.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/gosocks4 v0.0.1
|
||||||
github.com/go-gost/gosocks5 v0.3.1-0.20211109033403-d894d75b7f09
|
github.com/go-gost/gosocks5 v0.3.1-0.20211109033403-d894d75b7f09
|
||||||
github.com/go-gost/plugin v0.0.0-20230418123101-d221a4ec9a98
|
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 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-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-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-20230918131208-c258a114c40b h1:kqALaNXbbYyKFlcLj3ODsuvzplRxypnJOhMINSiM8sk=
|
||||||
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/go.mod h1:db6lBY+DkC3ct4OJfclsKnQwQmcv1B9NnMnpI2MNUwY=
|
||||||
github.com/go-gost/gosocks4 v0.0.1 h1:+k1sec8HlELuQV7rWftIkmy8UijzUt2I6t+iMPlGB2s=
|
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/gosocks4 v0.0.1/go.mod h1:3B6L47HbU/qugDg4JnoFPHgJXE43Inz8Bah1QaN9qCc=
|
||||||
github.com/go-gost/gosocks5 v0.3.1-0.20211109033403-d894d75b7f09 h1:A95M6UWcfZgOuJkQ7QLfG0Hs5peWIUSysCDNz4pfe04=
|
github.com/go-gost/gosocks5 v0.3.1-0.20211109033403-d894d75b7f09 h1:A95M6UWcfZgOuJkQ7QLfG0Hs5peWIUSysCDNz4pfe04=
|
||||||
|
@ -12,33 +12,52 @@ import (
|
|||||||
|
|
||||||
type recorderConn struct {
|
type recorderConn struct {
|
||||||
net.Conn
|
net.Conn
|
||||||
recorder recorder.Recorder
|
recorder recorder.RecorderObject
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *recorderConn) Read(b []byte) (n int, err error) {
|
func (c *recorderConn) Read(b []byte) (n int, err error) {
|
||||||
n, err = c.Conn.Read(b)
|
n, err = c.Conn.Read(b)
|
||||||
|
|
||||||
if n > 0 && c.recorder != nil {
|
if n > 0 && c.recorder.Recorder != nil {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
if c.recorder.Options != nil && c.recorder.Options.Direction {
|
||||||
buf.WriteByte('>')
|
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')
|
buf.WriteByte('\n')
|
||||||
|
}
|
||||||
|
if c.recorder.Options != nil && c.recorder.Options.Hexdump {
|
||||||
buf.WriteString(hex.Dump(b[:n]))
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *recorderConn) Write(b []byte) (int, error) {
|
func (c *recorderConn) Write(b []byte) (int, error) {
|
||||||
if c.recorder != nil {
|
if c.recorder.Recorder != nil {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
if c.recorder.Options != nil && c.recorder.Options.Direction {
|
||||||
buf.WriteByte('<')
|
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')
|
buf.WriteByte('\n')
|
||||||
|
}
|
||||||
|
if c.recorder.Options != nil && c.recorder.Options.Hexdump {
|
||||||
buf.WriteString(hex.Dump(b))
|
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)
|
return c.Conn.Write(b)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ type serialHandler struct {
|
|||||||
router *chain.Router
|
router *chain.Router
|
||||||
md metadata
|
md metadata
|
||||||
options handler.Options
|
options handler.Options
|
||||||
recorder recorder.Recorder
|
recorder recorder.RecorderObject
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandler(opts ...handler.Option) handler.Handler {
|
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 {
|
if opts := h.router.Options(); opts != nil {
|
||||||
for _, ro := range opts.Recorders {
|
for _, ro := range opts.Recorders {
|
||||||
if ro.Record == xrecorder.RecorderServiceHandlerSerial {
|
if ro.Record == xrecorder.RecorderServiceHandlerSerial {
|
||||||
h.recorder = ro.Recorder
|
h.recorder = ro
|
||||||
break
|
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)
|
log.Debugf("%s >> %s", conn.LocalAddr(), target.Addr)
|
||||||
|
|
||||||
if h.recorder != nil {
|
|
||||||
conn = &recorderConn{
|
conn = &recorderConn{
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
recorder: h.recorder,
|
recorder: h.recorder,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// serial port
|
// serial port
|
||||||
if _, _, err := net.SplitHostPort(target.Addr); err != nil {
|
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