Compare commits
103 Commits
34b9e3b16e
...
dev
Author | SHA1 | Date | |
---|---|---|---|
490e6b40f5 | |||
bc0d6953bc | |||
22e522e933 | |||
5e8a8a4b4d | |||
fa16373d66 | |||
1a776dc759 | |||
12ef82e41f | |||
3656ba9315 | |||
f73960ad36 | |||
c0a80400d2 | |||
2a75be91b0 | |||
4a4c64cc66 | |||
f2e32080e4 | |||
59b99a5b44 | |||
c1d0887a9b | |||
96f4d7bf5c | |||
949c98adc0 | |||
13c9e3ba97 | |||
3c1985e980 | |||
22537ff0d2 | |||
b583e29a56 | |||
ba2a83a51d | |||
74dc03bd66 | |||
b99292bed8 | |||
f9bfca76ed | |||
2ae0462822 | |||
423dd1e35d | |||
15f28c667a | |||
9bae597cbb | |||
6d819a0c06 | |||
784e4b2b01 | |||
e793b2743b | |||
ce60160cd7 | |||
118ee91c95 | |||
754b2fdeac | |||
40f709880d | |||
332a3a1cd0 | |||
f2a5089c29 | |||
55058573d6 | |||
41b5e62207 | |||
766ce7fdaa | |||
254875cd30 | |||
66104cd079 | |||
871afeeb6d | |||
c3b133a2de | |||
68f9690494 | |||
c35a79b2c9 | |||
a2ab48c423 | |||
902e24e7e8 | |||
d26bf4f05c | |||
5ea88aa5cf | |||
77a8f28edc | |||
7bf0537243 | |||
6ba22b0935 | |||
7da8b2a710 | |||
d9b7585856 | |||
63ad7f2354 | |||
25dcf536c6 | |||
3d2a7b7d3b | |||
5cc2c3de82 | |||
5ee7746aab | |||
3616a0d8a4 | |||
b5b39de62c | |||
43d37d0a5f | |||
8bdd7ee172 | |||
a618998b36 | |||
bb1a9908d4 | |||
01168e9846 | |||
53aab11764 | |||
c04c28e1fd | |||
936954ecf2 | |||
262ac0e9a5 | |||
c959fc2f73 | |||
4e1a70ec6d | |||
e1ae379048 | |||
1117723913 | |||
590a6ae6ff | |||
9fa95cc8b3 | |||
40e9a8ce7b | |||
4a1b225d2c | |||
c4b95b180e | |||
cc07ccb276 | |||
f847fa533e | |||
b1390dda1c | |||
8ef341dc88 | |||
94f8afdf45 | |||
6ea815eb36 | |||
ee80eedac3 | |||
7cc1ef436f | |||
116c7b51fe | |||
9be710dc19 | |||
e8be8d625a | |||
c87faa2017 | |||
79c15f2c37 | |||
44064e4dd1 | |||
c95edd6ed3 | |||
74639e9c4e | |||
88cc6ff4d5 | |||
330631fd79 | |||
42a4ccb24c | |||
2c82233b4f | |||
a465210bd6 | |||
f5a20fd0fc |
67
admission/plugin/grpc.go
Normal file
67
admission/plugin/grpc.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package admission
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/go-gost/core/admission"
|
||||||
|
"github.com/go-gost/core/logger"
|
||||||
|
"github.com/go-gost/plugin/admission/proto"
|
||||||
|
"github.com/go-gost/x/internal/plugin"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type grpcPlugin struct {
|
||||||
|
conn grpc.ClientConnInterface
|
||||||
|
client proto.AdmissionClient
|
||||||
|
log logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGRPCPlugin creates an Admission plugin based on gRPC.
|
||||||
|
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) admission.Admission {
|
||||||
|
var options plugin.Options
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
log := logger.Default().WithFields(map[string]any{
|
||||||
|
"kind": "admission",
|
||||||
|
"admission": name,
|
||||||
|
})
|
||||||
|
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p := &grpcPlugin{
|
||||||
|
conn: conn,
|
||||||
|
log: log,
|
||||||
|
}
|
||||||
|
if conn != nil {
|
||||||
|
p.client = proto.NewAdmissionClient(conn)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *grpcPlugin) Admit(ctx context.Context, addr string, opts ...admission.Option) bool {
|
||||||
|
if p.client == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := p.client.Admit(ctx,
|
||||||
|
&proto.AdmissionRequest{
|
||||||
|
Addr: addr,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
p.log.Error(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return r.Ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *grpcPlugin) Close() error {
|
||||||
|
if closer, ok := p.conn.(io.Closer); ok {
|
||||||
|
return closer.Close()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -4,71 +4,13 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/go-gost/core/admission"
|
"github.com/go-gost/core/admission"
|
||||||
"github.com/go-gost/core/logger"
|
"github.com/go-gost/core/logger"
|
||||||
"github.com/go-gost/plugin/admission/proto"
|
|
||||||
"github.com/go-gost/x/internal/plugin"
|
"github.com/go-gost/x/internal/plugin"
|
||||||
"google.golang.org/grpc"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type grpcPlugin struct {
|
|
||||||
conn grpc.ClientConnInterface
|
|
||||||
client proto.AdmissionClient
|
|
||||||
log logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewGRPCPlugin creates an Admission plugin based on gRPC.
|
|
||||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) admission.Admission {
|
|
||||||
var options plugin.Options
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(&options)
|
|
||||||
}
|
|
||||||
|
|
||||||
log := logger.Default().WithFields(map[string]any{
|
|
||||||
"kind": "admission",
|
|
||||||
"admission": name,
|
|
||||||
})
|
|
||||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
p := &grpcPlugin{
|
|
||||||
conn: conn,
|
|
||||||
log: log,
|
|
||||||
}
|
|
||||||
if conn != nil {
|
|
||||||
p.client = proto.NewAdmissionClient(conn)
|
|
||||||
}
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *grpcPlugin) Admit(ctx context.Context, addr string, opts ...admission.Option) bool {
|
|
||||||
if p.client == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
r, err := p.client.Admit(ctx,
|
|
||||||
&proto.AdmissionRequest{
|
|
||||||
Addr: addr,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
p.log.Error(err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return r.Ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *grpcPlugin) Close() error {
|
|
||||||
if closer, ok := p.conn.(io.Closer); ok {
|
|
||||||
return closer.Close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type httpPluginRequest struct {
|
type httpPluginRequest struct {
|
||||||
Addr string `json:"addr"`
|
Addr string `json:"addr"`
|
||||||
}
|
}
|
176
api/api.go
176
api/api.go
@ -2,6 +2,13 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-contrib/cors"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-gost/core/auth"
|
||||||
|
"github.com/go-gost/core/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -13,3 +20,172 @@ type Response struct {
|
|||||||
Code int `json:"code,omitempty"`
|
Code int `json:"code,omitempty"`
|
||||||
Msg string `json:"msg,omitempty"`
|
Msg string `json:"msg,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type options struct {
|
||||||
|
accessLog bool
|
||||||
|
pathPrefix string
|
||||||
|
auther auth.Authenticator
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option func(*options)
|
||||||
|
|
||||||
|
func PathPrefixOption(pathPrefix string) Option {
|
||||||
|
return func(o *options) {
|
||||||
|
o.pathPrefix = pathPrefix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AccessLogOption(enable bool) Option {
|
||||||
|
return func(o *options) {
|
||||||
|
o.accessLog = enable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AutherOption(auther auth.Authenticator) Option {
|
||||||
|
return func(o *options) {
|
||||||
|
o.auther = auther
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type server struct {
|
||||||
|
s *http.Server
|
||||||
|
ln net.Listener
|
||||||
|
cclose chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(addr string, opts ...Option) (service.Service, error) {
|
||||||
|
ln, err := net.Listen("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var options options
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
gin.SetMode(gin.ReleaseMode)
|
||||||
|
|
||||||
|
r := gin.New()
|
||||||
|
r.Use(
|
||||||
|
cors.New((cors.Config{
|
||||||
|
AllowAllOrigins: true,
|
||||||
|
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
||||||
|
AllowHeaders: []string{"*"},
|
||||||
|
AllowPrivateNetwork: true,
|
||||||
|
})),
|
||||||
|
gin.Recovery(),
|
||||||
|
)
|
||||||
|
if options.accessLog {
|
||||||
|
r.Use(mwLogger())
|
||||||
|
}
|
||||||
|
|
||||||
|
router := r.Group("")
|
||||||
|
if options.pathPrefix != "" {
|
||||||
|
router = router.Group(options.pathPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
router.StaticFS("/docs", http.FS(swaggerDoc))
|
||||||
|
|
||||||
|
config := router.Group("/config")
|
||||||
|
config.Use(mwBasicAuth(options.auther))
|
||||||
|
registerConfig(config)
|
||||||
|
|
||||||
|
return &server{
|
||||||
|
s: &http.Server{
|
||||||
|
Handler: r,
|
||||||
|
},
|
||||||
|
ln: ln,
|
||||||
|
cclose: make(chan struct{}),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) Serve() error {
|
||||||
|
return s.s.Serve(s.ln)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) Addr() net.Addr {
|
||||||
|
return s.ln.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) Close() error {
|
||||||
|
return s.s.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) IsClosed() bool {
|
||||||
|
select {
|
||||||
|
case <-s.cclose:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerConfig(config *gin.RouterGroup) {
|
||||||
|
config.GET("", getConfig)
|
||||||
|
config.POST("", saveConfig)
|
||||||
|
|
||||||
|
config.POST("/services", createService)
|
||||||
|
config.PUT("/services/:service", updateService)
|
||||||
|
config.DELETE("/services/:service", deleteService)
|
||||||
|
|
||||||
|
config.POST("/chains", createChain)
|
||||||
|
config.PUT("/chains/:chain", updateChain)
|
||||||
|
config.DELETE("/chains/:chain", deleteChain)
|
||||||
|
|
||||||
|
config.POST("/hops", createHop)
|
||||||
|
config.PUT("/hops/:hop", updateHop)
|
||||||
|
config.DELETE("/hops/:hop", deleteHop)
|
||||||
|
|
||||||
|
config.POST("/authers", createAuther)
|
||||||
|
config.PUT("/authers/:auther", updateAuther)
|
||||||
|
config.DELETE("/authers/:auther", deleteAuther)
|
||||||
|
|
||||||
|
config.POST("/admissions", createAdmission)
|
||||||
|
config.PUT("/admissions/:admission", updateAdmission)
|
||||||
|
config.DELETE("/admissions/:admission", deleteAdmission)
|
||||||
|
|
||||||
|
config.POST("/bypasses", createBypass)
|
||||||
|
config.PUT("/bypasses/:bypass", updateBypass)
|
||||||
|
config.DELETE("/bypasses/:bypass", deleteBypass)
|
||||||
|
|
||||||
|
config.POST("/resolvers", createResolver)
|
||||||
|
config.PUT("/resolvers/:resolver", updateResolver)
|
||||||
|
config.DELETE("/resolvers/:resolver", deleteResolver)
|
||||||
|
|
||||||
|
config.POST("/hosts", createHosts)
|
||||||
|
config.PUT("/hosts/:hosts", updateHosts)
|
||||||
|
config.DELETE("/hosts/:hosts", deleteHosts)
|
||||||
|
|
||||||
|
config.POST("/ingresses", createIngress)
|
||||||
|
config.PUT("/ingresses/:ingress", updateIngress)
|
||||||
|
config.DELETE("/ingresses/:ingress", deleteIngress)
|
||||||
|
|
||||||
|
config.POST("/routers", createRouter)
|
||||||
|
config.PUT("/routers/:router", updateRouter)
|
||||||
|
config.DELETE("/routers/:router", deleteRouter)
|
||||||
|
|
||||||
|
config.POST("/observers", createObserver)
|
||||||
|
config.PUT("/observers/:observer", updateObserver)
|
||||||
|
config.DELETE("/observers/:observer", deleteObserver)
|
||||||
|
|
||||||
|
config.POST("/recorders", createRecorder)
|
||||||
|
config.PUT("/recorders/:recorder", updateRecorder)
|
||||||
|
config.DELETE("/recorders/:recorder", deleteRecorder)
|
||||||
|
|
||||||
|
config.POST("/sds", createSD)
|
||||||
|
config.PUT("/sds/:sd", updateSD)
|
||||||
|
config.DELETE("/sds/:sd", deleteSD)
|
||||||
|
|
||||||
|
config.POST("/limiters", createLimiter)
|
||||||
|
config.PUT("/limiters/:limiter", updateLimiter)
|
||||||
|
config.DELETE("/limiters/:limiter", deleteLimiter)
|
||||||
|
|
||||||
|
config.POST("/climiters", createConnLimiter)
|
||||||
|
config.PUT("/climiters/:limiter", updateConnLimiter)
|
||||||
|
config.DELETE("/climiters/:limiter", deleteConnLimiter)
|
||||||
|
|
||||||
|
config.POST("/rlimiters", createRateLimiter)
|
||||||
|
config.PUT("/rlimiters/:limiter", updateRateLimiter)
|
||||||
|
config.DELETE("/rlimiters/:limiter", deleteRateLimiter)
|
||||||
|
}
|
||||||
|
@ -7,9 +7,16 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-gost/core/observer/stats"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
|
"github.com/go-gost/x/registry"
|
||||||
|
"github.com/go-gost/x/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type serviceStatus interface {
|
||||||
|
Status() *service.Status
|
||||||
|
}
|
||||||
|
|
||||||
// swagger:parameters getConfigRequest
|
// swagger:parameters getConfigRequest
|
||||||
type getConfigRequest struct {
|
type getConfigRequest struct {
|
||||||
// output format, one of yaml|json, default is json.
|
// output format, one of yaml|json, default is json.
|
||||||
@ -37,6 +44,40 @@ func getConfig(ctx *gin.Context) {
|
|||||||
var req getConfigRequest
|
var req getConfigRequest
|
||||||
ctx.ShouldBindQuery(&req)
|
ctx.ShouldBindQuery(&req)
|
||||||
|
|
||||||
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
|
for _, svc := range c.Services {
|
||||||
|
if svc == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s := registry.ServiceRegistry().Get(svc.Name)
|
||||||
|
ss, ok := s.(serviceStatus)
|
||||||
|
if ok && ss != nil {
|
||||||
|
status := ss.Status()
|
||||||
|
svc.Status = &config.ServiceStatus{
|
||||||
|
CreateTime: status.CreateTime().Unix(),
|
||||||
|
State: string(status.State()),
|
||||||
|
}
|
||||||
|
if st := status.Stats(); st != nil {
|
||||||
|
svc.Status.Stats = &config.ServiceStats{
|
||||||
|
TotalConns: st.Get(stats.KindTotalConns),
|
||||||
|
CurrentConns: st.Get(stats.KindCurrentConns),
|
||||||
|
TotalErrs: st.Get(stats.KindTotalErrs),
|
||||||
|
InputBytes: st.Get(stats.KindInputBytes),
|
||||||
|
OutputBytes: st.Get(stats.KindOutputBytes),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, ev := range status.Events() {
|
||||||
|
if !ev.Time.IsZero() {
|
||||||
|
svc.Status.Events = append(svc.Status.Events, config.ServiceEvent{
|
||||||
|
Time: ev.Time.Unix(),
|
||||||
|
Msg: ev.Message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
var resp getConfigResponse
|
var resp getConfigResponse
|
||||||
resp.Config = config.Global()
|
resp.Config = config.Global()
|
||||||
|
|
||||||
@ -62,6 +103,9 @@ type saveConfigRequest struct {
|
|||||||
// output format, one of yaml|json, default is yaml.
|
// output format, one of yaml|json, default is yaml.
|
||||||
// in: query
|
// in: query
|
||||||
Format string `form:"format" json:"format"`
|
Format string `form:"format" json:"format"`
|
||||||
|
// file path, default is gost.yaml|gost.json in current working directory.
|
||||||
|
// in: query
|
||||||
|
Path string `form:"path" json:"path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// successful operation.
|
// successful operation.
|
||||||
@ -92,11 +136,15 @@ func saveConfig(ctx *gin.Context) {
|
|||||||
req.Format = "yaml"
|
req.Format = "yaml"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.Path != "" {
|
||||||
|
file = req.Path
|
||||||
|
}
|
||||||
|
|
||||||
f, err := os.Create(file)
|
f, err := os.Create(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(ctx, &Error{
|
writeError(ctx, &Error{
|
||||||
statusCode: http.StatusInternalServerError,
|
statusCode: http.StatusInternalServerError,
|
||||||
Code: 40005,
|
Code: ErrCodeSaveConfigFailed,
|
||||||
Msg: fmt.Sprintf("create file: %s", err.Error()),
|
Msg: fmt.Sprintf("create file: %s", err.Error()),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@ -106,8 +154,8 @@ func saveConfig(ctx *gin.Context) {
|
|||||||
if err := config.Global().Write(f, req.Format); err != nil {
|
if err := config.Global().Write(f, req.Format); err != nil {
|
||||||
writeError(ctx, &Error{
|
writeError(ctx, &Error{
|
||||||
statusCode: http.StatusInternalServerError,
|
statusCode: http.StatusInternalServerError,
|
||||||
Code: 40006,
|
Code: ErrCodeSaveConfigFailed,
|
||||||
Msg: fmt.Sprintf("write: %s", err.Error()),
|
Msg: fmt.Sprintf("save config: %s", err.Error()),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
@ -35,15 +37,22 @@ func createAdmission(ctx *gin.Context) {
|
|||||||
var req createAdmissionRequest
|
var req createAdmissionRequest
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if req.Data.Name == "" {
|
name := strings.TrimSpace(req.Data.Name)
|
||||||
writeError(ctx, ErrInvalid)
|
if name == "" {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "admission name is required"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
if registry.AdmissionRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("admission %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
v := parser.ParseAdmission(&req.Data)
|
v := parser.ParseAdmission(&req.Data)
|
||||||
|
|
||||||
if err := registry.AdmissionRegistry().Register(req.Data.Name, v); err != nil {
|
if err := registry.AdmissionRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("admission %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,25 +96,27 @@ func updateAdmission(ctx *gin.Context) {
|
|||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if !registry.AdmissionRegistry().IsRegistered(req.Admission) {
|
name := strings.TrimSpace(req.Admission)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.AdmissionRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("admission %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Data.Name = req.Admission
|
req.Data.Name = name
|
||||||
|
|
||||||
v := parser.ParseAdmission(&req.Data)
|
v := parser.ParseAdmission(&req.Data)
|
||||||
|
|
||||||
registry.AdmissionRegistry().Unregister(req.Admission)
|
registry.AdmissionRegistry().Unregister(name)
|
||||||
|
|
||||||
if err := registry.AdmissionRegistry().Register(req.Admission, v); err != nil {
|
if err := registry.AdmissionRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("admission %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
for i := range c.Admissions {
|
for i := range c.Admissions {
|
||||||
if c.Admissions[i].Name == req.Admission {
|
if c.Admissions[i].Name == name {
|
||||||
c.Admissions[i] = &req.Data
|
c.Admissions[i] = &req.Data
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -145,17 +156,19 @@ func deleteAdmission(ctx *gin.Context) {
|
|||||||
var req deleteAdmissionRequest
|
var req deleteAdmissionRequest
|
||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
if !registry.AdmissionRegistry().IsRegistered(req.Admission) {
|
name := strings.TrimSpace(req.Admission)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.AdmissionRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("admission %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
registry.AdmissionRegistry().Unregister(req.Admission)
|
registry.AdmissionRegistry().Unregister(name)
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
admissiones := c.Admissions
|
admissiones := c.Admissions
|
||||||
c.Admissions = nil
|
c.Admissions = nil
|
||||||
for _, s := range admissiones {
|
for _, s := range admissiones {
|
||||||
if s.Name == req.Admission {
|
if s.Name == name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.Admissions = append(c.Admissions, s)
|
c.Admissions = append(c.Admissions, s)
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
@ -35,14 +37,21 @@ func createAuther(ctx *gin.Context) {
|
|||||||
var req createAutherRequest
|
var req createAutherRequest
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if req.Data.Name == "" {
|
name := strings.TrimSpace(req.Data.Name)
|
||||||
writeError(ctx, ErrInvalid)
|
if name == "" {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "auther name is required"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
if registry.AutherRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("auther %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
v := parser.ParseAuther(&req.Data)
|
v := parser.ParseAuther(&req.Data)
|
||||||
if err := registry.AutherRegistry().Register(req.Data.Name, v); err != nil {
|
if err := registry.AutherRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("auther %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,24 +95,26 @@ func updateAuther(ctx *gin.Context) {
|
|||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if !registry.AutherRegistry().IsRegistered(req.Auther) {
|
name := strings.TrimSpace(req.Auther)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.AutherRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("auther %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Data.Name = req.Auther
|
req.Data.Name = name
|
||||||
|
|
||||||
v := parser.ParseAuther(&req.Data)
|
v := parser.ParseAuther(&req.Data)
|
||||||
registry.AutherRegistry().Unregister(req.Auther)
|
registry.AutherRegistry().Unregister(name)
|
||||||
|
|
||||||
if err := registry.AutherRegistry().Register(req.Auther, v); err != nil {
|
if err := registry.AutherRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("auther %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
for i := range c.Authers {
|
for i := range c.Authers {
|
||||||
if c.Authers[i].Name == req.Auther {
|
if c.Authers[i].Name == name {
|
||||||
c.Authers[i] = &req.Data
|
c.Authers[i] = &req.Data
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -143,17 +154,19 @@ func deleteAuther(ctx *gin.Context) {
|
|||||||
var req deleteAutherRequest
|
var req deleteAutherRequest
|
||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
if !registry.AutherRegistry().IsRegistered(req.Auther) {
|
name := strings.TrimSpace(req.Auther)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.AutherRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("auther %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
registry.AutherRegistry().Unregister(req.Auther)
|
registry.AutherRegistry().Unregister(name)
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
authers := c.Authers
|
authers := c.Authers
|
||||||
c.Authers = nil
|
c.Authers = nil
|
||||||
for _, s := range authers {
|
for _, s := range authers {
|
||||||
if s.Name == req.Auther {
|
if s.Name == name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.Authers = append(c.Authers, s)
|
c.Authers = append(c.Authers, s)
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
@ -35,15 +37,22 @@ func createBypass(ctx *gin.Context) {
|
|||||||
var req createBypassRequest
|
var req createBypassRequest
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if req.Data.Name == "" {
|
name := strings.TrimSpace(req.Data.Name)
|
||||||
writeError(ctx, ErrInvalid)
|
if name == "" {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "bypass name is required"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
if registry.BypassRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("bypass %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
v := parser.ParseBypass(&req.Data)
|
v := parser.ParseBypass(&req.Data)
|
||||||
|
|
||||||
if err := registry.BypassRegistry().Register(req.Data.Name, v); err != nil {
|
if err := registry.BypassRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("bypass %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,25 +96,27 @@ func updateBypass(ctx *gin.Context) {
|
|||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if !registry.BypassRegistry().IsRegistered(req.Bypass) {
|
name := strings.TrimSpace(req.Bypass)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.BypassRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("bypass %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Data.Name = req.Bypass
|
req.Data.Name = name
|
||||||
|
|
||||||
v := parser.ParseBypass(&req.Data)
|
v := parser.ParseBypass(&req.Data)
|
||||||
|
|
||||||
registry.BypassRegistry().Unregister(req.Bypass)
|
registry.BypassRegistry().Unregister(name)
|
||||||
|
|
||||||
if err := registry.BypassRegistry().Register(req.Bypass, v); err != nil {
|
if err := registry.BypassRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("bypass %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
for i := range c.Bypasses {
|
for i := range c.Bypasses {
|
||||||
if c.Bypasses[i].Name == req.Bypass {
|
if c.Bypasses[i].Name == name {
|
||||||
c.Bypasses[i] = &req.Data
|
c.Bypasses[i] = &req.Data
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -145,17 +156,19 @@ func deleteBypass(ctx *gin.Context) {
|
|||||||
var req deleteBypassRequest
|
var req deleteBypassRequest
|
||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
if !registry.BypassRegistry().IsRegistered(req.Bypass) {
|
name := strings.TrimSpace(req.Bypass)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.BypassRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("bypass %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
registry.BypassRegistry().Unregister(req.Bypass)
|
registry.BypassRegistry().Unregister(name)
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
bypasses := c.Bypasses
|
bypasses := c.Bypasses
|
||||||
c.Bypasses = nil
|
c.Bypasses = nil
|
||||||
for _, s := range bypasses {
|
for _, s := range bypasses {
|
||||||
if s.Name == req.Bypass {
|
if s.Name == name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.Bypasses = append(c.Bypasses, s)
|
c.Bypasses = append(c.Bypasses, s)
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-gost/core/logger"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
parser "github.com/go-gost/x/config/parsing/chain"
|
parser "github.com/go-gost/x/config/parsing/chain"
|
||||||
"github.com/go-gost/x/registry"
|
"github.com/go-gost/x/registry"
|
||||||
@ -35,19 +38,26 @@ func createChain(ctx *gin.Context) {
|
|||||||
var req createChainRequest
|
var req createChainRequest
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if req.Data.Name == "" {
|
name := strings.TrimSpace(req.Data.Name)
|
||||||
writeError(ctx, ErrInvalid)
|
if name == "" {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "chain name is required"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
if registry.ChainRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("chain %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err := parser.ParseChain(&req.Data)
|
v, err := parser.ParseChain(&req.Data, logger.Default())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(ctx, ErrCreate)
|
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create chain %s failed: %s", name, err.Error())))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := registry.ChainRegistry().Register(req.Data.Name, v); err != nil {
|
if err := registry.ChainRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("chain %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,29 +102,31 @@ func updateChain(ctx *gin.Context) {
|
|||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if !registry.ChainRegistry().IsRegistered(req.Chain) {
|
name := strings.TrimSpace(req.Chain)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.ChainRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("chain %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Data.Name = req.Chain
|
req.Data.Name = name
|
||||||
|
|
||||||
v, err := parser.ParseChain(&req.Data)
|
v, err := parser.ParseChain(&req.Data, logger.Default())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(ctx, ErrCreate)
|
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create chain %s failed: %s", name, err.Error())))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.ChainRegistry().Unregister(req.Chain)
|
registry.ChainRegistry().Unregister(name)
|
||||||
|
|
||||||
if err := registry.ChainRegistry().Register(req.Chain, v); err != nil {
|
if err := registry.ChainRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("chain %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
for i := range c.Chains {
|
for i := range c.Chains {
|
||||||
if c.Chains[i].Name == req.Chain {
|
if c.Chains[i].Name == name {
|
||||||
c.Chains[i] = &req.Data
|
c.Chains[i] = &req.Data
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -154,17 +166,19 @@ func deleteChain(ctx *gin.Context) {
|
|||||||
var req deleteChainRequest
|
var req deleteChainRequest
|
||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
if !registry.ChainRegistry().IsRegistered(req.Chain) {
|
name := strings.TrimSpace(req.Chain)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.ChainRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("chain %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
registry.ChainRegistry().Unregister(req.Chain)
|
registry.ChainRegistry().Unregister(name)
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
chains := c.Chains
|
chains := c.Chains
|
||||||
c.Chains = nil
|
c.Chains = nil
|
||||||
for _, s := range chains {
|
for _, s := range chains {
|
||||||
if s.Name == req.Chain {
|
if s.Name == name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.Chains = append(c.Chains, s)
|
c.Chains = append(c.Chains, s)
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
@ -35,15 +37,21 @@ func createConnLimiter(ctx *gin.Context) {
|
|||||||
var req createConnLimiterRequest
|
var req createConnLimiterRequest
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if req.Data.Name == "" {
|
name := strings.TrimSpace(req.Data.Name)
|
||||||
writeError(ctx, ErrInvalid)
|
if name == "" {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "limiter name is required"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
if registry.ConnLimiterRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
v := parser.ParseConnLimiter(&req.Data)
|
v := parser.ParseConnLimiter(&req.Data)
|
||||||
|
if err := registry.ConnLimiterRegistry().Register(name, v); err != nil {
|
||||||
if err := registry.ConnLimiterRegistry().Register(req.Data.Name, v); err != nil {
|
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create limmiter %s failed: %s", name, err.Error())))
|
||||||
writeError(ctx, ErrDup)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,25 +95,27 @@ func updateConnLimiter(ctx *gin.Context) {
|
|||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if !registry.ConnLimiterRegistry().IsRegistered(req.Limiter) {
|
name := strings.TrimSpace(req.Limiter)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.ConnLimiterRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("limiter %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Data.Name = req.Limiter
|
req.Data.Name = name
|
||||||
|
|
||||||
v := parser.ParseConnLimiter(&req.Data)
|
v := parser.ParseConnLimiter(&req.Data)
|
||||||
|
|
||||||
registry.ConnLimiterRegistry().Unregister(req.Limiter)
|
registry.ConnLimiterRegistry().Unregister(name)
|
||||||
|
|
||||||
if err := registry.ConnLimiterRegistry().Register(req.Limiter, v); err != nil {
|
if err := registry.ConnLimiterRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
for i := range c.CLimiters {
|
for i := range c.CLimiters {
|
||||||
if c.CLimiters[i].Name == req.Limiter {
|
if c.CLimiters[i].Name == name {
|
||||||
c.CLimiters[i] = &req.Data
|
c.CLimiters[i] = &req.Data
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -145,17 +155,19 @@ func deleteConnLimiter(ctx *gin.Context) {
|
|||||||
var req deleteConnLimiterRequest
|
var req deleteConnLimiterRequest
|
||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
if !registry.ConnLimiterRegistry().IsRegistered(req.Limiter) {
|
name := strings.TrimSpace(req.Limiter)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.ConnLimiterRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("limiter %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
registry.ConnLimiterRegistry().Unregister(req.Limiter)
|
registry.ConnLimiterRegistry().Unregister(name)
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
limiteres := c.CLimiters
|
limiteres := c.CLimiters
|
||||||
c.CLimiters = nil
|
c.CLimiters = nil
|
||||||
for _, s := range limiteres {
|
for _, s := range limiteres {
|
||||||
if s.Name == req.Limiter {
|
if s.Name == name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.CLimiters = append(c.CLimiters, s)
|
c.CLimiters = append(c.CLimiters, s)
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-gost/core/logger"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
parser "github.com/go-gost/x/config/parsing/hop"
|
parser "github.com/go-gost/x/config/parsing/hop"
|
||||||
"github.com/go-gost/x/registry"
|
"github.com/go-gost/x/registry"
|
||||||
@ -35,19 +38,26 @@ func createHop(ctx *gin.Context) {
|
|||||||
var req createHopRequest
|
var req createHopRequest
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if req.Data.Name == "" {
|
name := strings.TrimSpace(req.Data.Name)
|
||||||
writeError(ctx, ErrInvalid)
|
if name == "" {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "hop name is required"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
if registry.HopRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("hop %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err := parser.ParseHop(&req.Data)
|
v, err := parser.ParseHop(&req.Data, logger.Default())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(ctx, ErrCreate)
|
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create hop %s failed: %s", name, err.Error())))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := registry.HopRegistry().Register(req.Data.Name, v); err != nil {
|
if err := registry.HopRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("hop %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,29 +102,30 @@ func updateHop(ctx *gin.Context) {
|
|||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if !registry.HopRegistry().IsRegistered(req.Hop) {
|
name := strings.TrimSpace(req.Hop)
|
||||||
writeError(ctx, ErrNotFound)
|
if !registry.HopRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("hop %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Data.Name = req.Hop
|
req.Data.Name = name
|
||||||
|
|
||||||
v, err := parser.ParseHop(&req.Data)
|
v, err := parser.ParseHop(&req.Data, logger.Default())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(ctx, ErrCreate)
|
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create hop %s failed: %s", name, err.Error())))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.HopRegistry().Unregister(req.Hop)
|
registry.HopRegistry().Unregister(name)
|
||||||
|
|
||||||
if err := registry.HopRegistry().Register(req.Hop, v); err != nil {
|
if err := registry.HopRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("hop %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
for i := range c.Hops {
|
for i := range c.Hops {
|
||||||
if c.Hops[i].Name == req.Hop {
|
if c.Hops[i].Name == name {
|
||||||
c.Hops[i] = &req.Data
|
c.Hops[i] = &req.Data
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -154,17 +165,19 @@ func deleteHop(ctx *gin.Context) {
|
|||||||
var req deleteHopRequest
|
var req deleteHopRequest
|
||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
if !registry.HopRegistry().IsRegistered(req.Hop) {
|
name := strings.TrimSpace(req.Hop)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.HopRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("hop %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
registry.HopRegistry().Unregister(req.Hop)
|
registry.HopRegistry().Unregister(name)
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
hops := c.Hops
|
hops := c.Hops
|
||||||
c.Hops = nil
|
c.Hops = nil
|
||||||
for _, s := range hops {
|
for _, s := range hops {
|
||||||
if s.Name == req.Hop {
|
if s.Name == name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.Hops = append(c.Hops, s)
|
c.Hops = append(c.Hops, s)
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
@ -35,15 +37,22 @@ func createHosts(ctx *gin.Context) {
|
|||||||
var req createHostsRequest
|
var req createHostsRequest
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if req.Data.Name == "" {
|
name := strings.TrimSpace(req.Data.Name)
|
||||||
writeError(ctx, ErrInvalid)
|
if name == "" {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "hosts name is required"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
if registry.HostsRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("hosts %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
v := parser.ParseHostMapper(&req.Data)
|
v := parser.ParseHostMapper(&req.Data)
|
||||||
|
|
||||||
if err := registry.HostsRegistry().Register(req.Data.Name, v); err != nil {
|
if err := registry.HostsRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("hosts %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,25 +96,27 @@ func updateHosts(ctx *gin.Context) {
|
|||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if !registry.HostsRegistry().IsRegistered(req.Hosts) {
|
name := strings.TrimSpace(req.Hosts)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.HostsRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("hosts %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Data.Name = req.Hosts
|
req.Data.Name = name
|
||||||
|
|
||||||
v := parser.ParseHostMapper(&req.Data)
|
v := parser.ParseHostMapper(&req.Data)
|
||||||
|
|
||||||
registry.HostsRegistry().Unregister(req.Hosts)
|
registry.HostsRegistry().Unregister(name)
|
||||||
|
|
||||||
if err := registry.HostsRegistry().Register(req.Hosts, v); err != nil {
|
if err := registry.HostsRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("hosts %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
for i := range c.Hosts {
|
for i := range c.Hosts {
|
||||||
if c.Hosts[i].Name == req.Hosts {
|
if c.Hosts[i].Name == name {
|
||||||
c.Hosts[i] = &req.Data
|
c.Hosts[i] = &req.Data
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -145,17 +156,19 @@ func deleteHosts(ctx *gin.Context) {
|
|||||||
var req deleteHostsRequest
|
var req deleteHostsRequest
|
||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
if !registry.HostsRegistry().IsRegistered(req.Hosts) {
|
name := strings.TrimSpace(req.Hosts)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.HostsRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("hosts %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
registry.HostsRegistry().Unregister(req.Hosts)
|
registry.HostsRegistry().Unregister(name)
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
hosts := c.Hosts
|
hosts := c.Hosts
|
||||||
c.Hosts = nil
|
c.Hosts = nil
|
||||||
for _, s := range hosts {
|
for _, s := range hosts {
|
||||||
if s.Name == req.Hosts {
|
if s.Name == name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.Hosts = append(c.Hosts, s)
|
c.Hosts = append(c.Hosts, s)
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
@ -35,15 +37,22 @@ func createIngress(ctx *gin.Context) {
|
|||||||
var req createIngressRequest
|
var req createIngressRequest
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if req.Data.Name == "" {
|
name := strings.TrimSpace(req.Data.Name)
|
||||||
writeError(ctx, ErrInvalid)
|
if name == "" {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "ingress name is required"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
if registry.IngressRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("ingress %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
v := parser.ParseIngress(&req.Data)
|
v := parser.ParseIngress(&req.Data)
|
||||||
|
|
||||||
if err := registry.IngressRegistry().Register(req.Data.Name, v); err != nil {
|
if err := registry.IngressRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("ingress %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,25 +96,27 @@ func updateIngress(ctx *gin.Context) {
|
|||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if !registry.IngressRegistry().IsRegistered(req.Ingress) {
|
name := strings.TrimSpace(req.Ingress)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.IngressRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("ingress %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Data.Name = req.Ingress
|
req.Data.Name = name
|
||||||
|
|
||||||
v := parser.ParseIngress(&req.Data)
|
v := parser.ParseIngress(&req.Data)
|
||||||
|
|
||||||
registry.IngressRegistry().Unregister(req.Ingress)
|
registry.IngressRegistry().Unregister(name)
|
||||||
|
|
||||||
if err := registry.IngressRegistry().Register(req.Ingress, v); err != nil {
|
if err := registry.IngressRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("ingress %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
for i := range c.Ingresses {
|
for i := range c.Ingresses {
|
||||||
if c.Ingresses[i].Name == req.Ingress {
|
if c.Ingresses[i].Name == name {
|
||||||
c.Ingresses[i] = &req.Data
|
c.Ingresses[i] = &req.Data
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -145,17 +156,19 @@ func deleteIngress(ctx *gin.Context) {
|
|||||||
var req deleteIngressRequest
|
var req deleteIngressRequest
|
||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
if !registry.IngressRegistry().IsRegistered(req.Ingress) {
|
name := strings.TrimSpace(req.Ingress)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.IngressRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("ingress %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
registry.IngressRegistry().Unregister(req.Ingress)
|
registry.IngressRegistry().Unregister(name)
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
ingresses := c.Ingresses
|
ingresses := c.Ingresses
|
||||||
c.Ingresses = nil
|
c.Ingresses = nil
|
||||||
for _, s := range ingresses {
|
for _, s := range ingresses {
|
||||||
if s.Name == req.Ingress {
|
if s.Name == name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.Ingresses = append(c.Ingresses, s)
|
c.Ingresses = append(c.Ingresses, s)
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
@ -35,15 +37,22 @@ func createLimiter(ctx *gin.Context) {
|
|||||||
var req createLimiterRequest
|
var req createLimiterRequest
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if req.Data.Name == "" {
|
name := strings.TrimSpace(req.Data.Name)
|
||||||
writeError(ctx, ErrInvalid)
|
if name == "" {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "limiter name is required"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
if registry.TrafficLimiterRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
v := parser.ParseTrafficLimiter(&req.Data)
|
v := parser.ParseTrafficLimiter(&req.Data)
|
||||||
|
|
||||||
if err := registry.TrafficLimiterRegistry().Register(req.Data.Name, v); err != nil {
|
if err := registry.TrafficLimiterRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,25 +96,27 @@ func updateLimiter(ctx *gin.Context) {
|
|||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if !registry.TrafficLimiterRegistry().IsRegistered(req.Limiter) {
|
name := strings.TrimSpace(req.Limiter)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.TrafficLimiterRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("limiter %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Data.Name = req.Limiter
|
req.Data.Name = name
|
||||||
|
|
||||||
v := parser.ParseTrafficLimiter(&req.Data)
|
v := parser.ParseTrafficLimiter(&req.Data)
|
||||||
|
|
||||||
registry.TrafficLimiterRegistry().Unregister(req.Limiter)
|
registry.TrafficLimiterRegistry().Unregister(name)
|
||||||
|
|
||||||
if err := registry.TrafficLimiterRegistry().Register(req.Limiter, v); err != nil {
|
if err := registry.TrafficLimiterRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
for i := range c.Limiters {
|
for i := range c.Limiters {
|
||||||
if c.Limiters[i].Name == req.Limiter {
|
if c.Limiters[i].Name == name {
|
||||||
c.Limiters[i] = &req.Data
|
c.Limiters[i] = &req.Data
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -145,17 +156,19 @@ func deleteLimiter(ctx *gin.Context) {
|
|||||||
var req deleteLimiterRequest
|
var req deleteLimiterRequest
|
||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
if !registry.TrafficLimiterRegistry().IsRegistered(req.Limiter) {
|
name := strings.TrimSpace(req.Limiter)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.TrafficLimiterRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("limiter %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
registry.TrafficLimiterRegistry().Unregister(req.Limiter)
|
registry.TrafficLimiterRegistry().Unregister(name)
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
limiteres := c.Limiters
|
limiteres := c.Limiters
|
||||||
c.Limiters = nil
|
c.Limiters = nil
|
||||||
for _, s := range limiteres {
|
for _, s := range limiteres {
|
||||||
if s.Name == req.Limiter {
|
if s.Name == name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.Limiters = append(c.Limiters, s)
|
c.Limiters = append(c.Limiters, s)
|
||||||
|
182
api/config_observer.go
Normal file
182
api/config_observer.go
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-gost/x/config"
|
||||||
|
parser "github.com/go-gost/x/config/parsing/observer"
|
||||||
|
"github.com/go-gost/x/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// swagger:parameters createObserverRequest
|
||||||
|
type createObserverRequest struct {
|
||||||
|
// in: body
|
||||||
|
Data config.ObserverConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response createObserverResponse
|
||||||
|
type createObserverResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func createObserver(ctx *gin.Context) {
|
||||||
|
// swagger:route POST /config/observers Observer createObserverRequest
|
||||||
|
//
|
||||||
|
// Create a new observer, the name of the observer must be unique in observer list.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: createObserverResponse
|
||||||
|
|
||||||
|
var req createObserverRequest
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
name := strings.TrimSpace(req.Data.Name)
|
||||||
|
if name == "" {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "observer name is required"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
if registry.ObserverRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("observer %s already exists", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v := parser.ParseObserver(&req.Data)
|
||||||
|
|
||||||
|
if err := registry.ObserverRegistry().Register(name, v); err != nil {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("observer %s already exists", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
|
c.Observers = append(c.Observers, &req.Data)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters updateObserverRequest
|
||||||
|
type updateObserverRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Observer string `uri:"observer" json:"observer"`
|
||||||
|
// in: body
|
||||||
|
Data config.ObserverConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response updateObserverResponse
|
||||||
|
type updateObserverResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateObserver(ctx *gin.Context) {
|
||||||
|
// swagger:route PUT /config/observers/{observer} Observer updateObserverRequest
|
||||||
|
//
|
||||||
|
// Update observer by name, the observer must already exist.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: updateObserverResponse
|
||||||
|
|
||||||
|
var req updateObserverRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
name := strings.TrimSpace(req.Observer)
|
||||||
|
|
||||||
|
if !registry.ObserverRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("observer %s not found", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
v := parser.ParseObserver(&req.Data)
|
||||||
|
|
||||||
|
registry.ObserverRegistry().Unregister(name)
|
||||||
|
|
||||||
|
if err := registry.ObserverRegistry().Register(name, v); err != nil {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("observer %s already exists", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
|
for i := range c.Observers {
|
||||||
|
if c.Observers[i].Name == name {
|
||||||
|
c.Observers[i] = &req.Data
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters deleteObserverRequest
|
||||||
|
type deleteObserverRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Observer string `uri:"observer" json:"observer"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response deleteObserverResponse
|
||||||
|
type deleteObserverResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteObserver(ctx *gin.Context) {
|
||||||
|
// swagger:route DELETE /config/observers/{observer} Observer deleteObserverRequest
|
||||||
|
//
|
||||||
|
// Delete observer by name.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: deleteObserverResponse
|
||||||
|
|
||||||
|
var req deleteObserverRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
|
name := strings.TrimSpace(req.Observer)
|
||||||
|
|
||||||
|
if !registry.ObserverRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("observer %s not found", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
registry.ObserverRegistry().Unregister(name)
|
||||||
|
|
||||||
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
|
observers := c.Observers
|
||||||
|
c.Observers = nil
|
||||||
|
for _, s := range observers {
|
||||||
|
if s.Name == name {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c.Observers = append(c.Observers, s)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
@ -35,15 +37,22 @@ func createRateLimiter(ctx *gin.Context) {
|
|||||||
var req createRateLimiterRequest
|
var req createRateLimiterRequest
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if req.Data.Name == "" {
|
name := strings.TrimSpace(req.Data.Name)
|
||||||
writeError(ctx, ErrInvalid)
|
if name == "" {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "limiter name is required"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
if registry.RateLimiterRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
v := parser.ParseRateLimiter(&req.Data)
|
v := parser.ParseRateLimiter(&req.Data)
|
||||||
|
|
||||||
if err := registry.RateLimiterRegistry().Register(req.Data.Name, v); err != nil {
|
if err := registry.RateLimiterRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,25 +96,27 @@ func updateRateLimiter(ctx *gin.Context) {
|
|||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if !registry.RateLimiterRegistry().IsRegistered(req.Limiter) {
|
name := strings.TrimSpace(req.Limiter)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.RateLimiterRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("limiter %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Data.Name = req.Limiter
|
req.Data.Name = name
|
||||||
|
|
||||||
v := parser.ParseRateLimiter(&req.Data)
|
v := parser.ParseRateLimiter(&req.Data)
|
||||||
|
|
||||||
registry.RateLimiterRegistry().Unregister(req.Limiter)
|
registry.RateLimiterRegistry().Unregister(name)
|
||||||
|
|
||||||
if err := registry.RateLimiterRegistry().Register(req.Limiter, v); err != nil {
|
if err := registry.RateLimiterRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
for i := range c.RLimiters {
|
for i := range c.RLimiters {
|
||||||
if c.RLimiters[i].Name == req.Limiter {
|
if c.RLimiters[i].Name == name {
|
||||||
c.RLimiters[i] = &req.Data
|
c.RLimiters[i] = &req.Data
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -145,17 +156,19 @@ func deleteRateLimiter(ctx *gin.Context) {
|
|||||||
var req deleteRateLimiterRequest
|
var req deleteRateLimiterRequest
|
||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
if !registry.RateLimiterRegistry().IsRegistered(req.Limiter) {
|
name := strings.TrimSpace(req.Limiter)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.RateLimiterRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("limiter %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
registry.RateLimiterRegistry().Unregister(req.Limiter)
|
registry.RateLimiterRegistry().Unregister(name)
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
limiteres := c.RLimiters
|
limiteres := c.RLimiters
|
||||||
c.RLimiters = nil
|
c.RLimiters = nil
|
||||||
for _, s := range limiteres {
|
for _, s := range limiteres {
|
||||||
if s.Name == req.Limiter {
|
if s.Name == name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.RLimiters = append(c.RLimiters, s)
|
c.RLimiters = append(c.RLimiters, s)
|
||||||
|
181
api/config_recorder.go
Normal file
181
api/config_recorder.go
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-gost/x/config"
|
||||||
|
parser "github.com/go-gost/x/config/parsing/recorder"
|
||||||
|
"github.com/go-gost/x/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// swagger:parameters createRecorderRequest
|
||||||
|
type createRecorderRequest struct {
|
||||||
|
// in: body
|
||||||
|
Data config.RecorderConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response createRecorderResponse
|
||||||
|
type createRecorderResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func createRecorder(ctx *gin.Context) {
|
||||||
|
// swagger:route POST /config/recorders Recorder createRecorderRequest
|
||||||
|
//
|
||||||
|
// Create a new recorder, the name of the recorder must be unique in recorder list.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: createRecorderResponse
|
||||||
|
|
||||||
|
var req createRecorderRequest
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
name := strings.TrimSpace(req.Data.Name)
|
||||||
|
if name == "" {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "recorder name is required"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
if registry.RecorderRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("recorder %s already exists", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v := parser.ParseRecorder(&req.Data)
|
||||||
|
|
||||||
|
if err := registry.RecorderRegistry().Register(name, v); err != nil {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("recorder %s already exists", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
|
c.Recorders = append(c.Recorders, &req.Data)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters updateRecorderRequest
|
||||||
|
type updateRecorderRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Recorder string `uri:"recorder" json:"recorder"`
|
||||||
|
// in: body
|
||||||
|
Data config.RecorderConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response updateRecorderResponse
|
||||||
|
type updateRecorderResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateRecorder(ctx *gin.Context) {
|
||||||
|
// swagger:route PUT /config/recorders/{recorder} Recorder updateRecorderRequest
|
||||||
|
//
|
||||||
|
// Update recorder by name, the recorder must already exist.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: updateRecorderResponse
|
||||||
|
|
||||||
|
var req updateRecorderRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
name := strings.TrimSpace(req.Recorder)
|
||||||
|
|
||||||
|
if !registry.RecorderRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("recorder %s not found", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
v := parser.ParseRecorder(&req.Data)
|
||||||
|
|
||||||
|
registry.RecorderRegistry().Unregister(name)
|
||||||
|
|
||||||
|
if err := registry.RecorderRegistry().Register(name, v); err != nil {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("recorder %s already exists", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
|
for i := range c.Recorders {
|
||||||
|
if c.Recorders[i].Name == name {
|
||||||
|
c.Recorders[i] = &req.Data
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters deleteRecorderRequest
|
||||||
|
type deleteRecorderRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Recorder string `uri:"recorder" json:"recorder"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response deleteRecorderResponse
|
||||||
|
type deleteRecorderResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteRecorder(ctx *gin.Context) {
|
||||||
|
// swagger:route DELETE /config/recorders/{recorder} Recorder deleteRecorderRequest
|
||||||
|
//
|
||||||
|
// Delete recorder by name.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: deleteRecorderResponse
|
||||||
|
|
||||||
|
var req deleteRecorderRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
|
name := strings.TrimSpace(req.Recorder)
|
||||||
|
|
||||||
|
if !registry.RecorderRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("recorder %s not found", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
registry.RecorderRegistry().Unregister(name)
|
||||||
|
|
||||||
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
|
recorders := c.Recorders
|
||||||
|
c.Recorders = nil
|
||||||
|
for _, s := range recorders {
|
||||||
|
if s.Name == name {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c.Recorders = append(c.Recorders, s)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
@ -35,19 +37,26 @@ func createResolver(ctx *gin.Context) {
|
|||||||
var req createResolverRequest
|
var req createResolverRequest
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if req.Data.Name == "" {
|
name := strings.TrimSpace(req.Data.Name)
|
||||||
writeError(ctx, ErrInvalid)
|
if name == "" {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "resolver name is required"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
if registry.ResolverRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("resolver %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err := parser.ParseResolver(&req.Data)
|
v, err := parser.ParseResolver(&req.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(ctx, ErrCreate)
|
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create resolver %s failed: %s", name, err.Error())))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := registry.ResolverRegistry().Register(req.Data.Name, v); err != nil {
|
if err := registry.ResolverRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("resolver %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,29 +100,31 @@ func updateResolver(ctx *gin.Context) {
|
|||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if !registry.ResolverRegistry().IsRegistered(req.Resolver) {
|
name := strings.TrimSpace(req.Resolver)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.ResolverRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("resolver %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Data.Name = req.Resolver
|
req.Data.Name = name
|
||||||
|
|
||||||
v, err := parser.ParseResolver(&req.Data)
|
v, err := parser.ParseResolver(&req.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(ctx, ErrCreate)
|
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create resolver %s failed: %s", name, err.Error())))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.ResolverRegistry().Unregister(req.Resolver)
|
registry.ResolverRegistry().Unregister(name)
|
||||||
|
|
||||||
if err := registry.ResolverRegistry().Register(req.Resolver, v); err != nil {
|
if err := registry.ResolverRegistry().Register(name, v); err != nil {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("resolver %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
for i := range c.Resolvers {
|
for i := range c.Resolvers {
|
||||||
if c.Resolvers[i].Name == req.Resolver {
|
if c.Resolvers[i].Name == name {
|
||||||
c.Resolvers[i] = &req.Data
|
c.Resolvers[i] = &req.Data
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -153,17 +164,19 @@ func deleteResolver(ctx *gin.Context) {
|
|||||||
var req deleteResolverRequest
|
var req deleteResolverRequest
|
||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
if !registry.ResolverRegistry().IsRegistered(req.Resolver) {
|
name := strings.TrimSpace(req.Resolver)
|
||||||
writeError(ctx, ErrNotFound)
|
|
||||||
|
if !registry.ResolverRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("resolver %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
registry.ResolverRegistry().Unregister(req.Resolver)
|
registry.ResolverRegistry().Unregister(name)
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
resolvers := c.Resolvers
|
resolvers := c.Resolvers
|
||||||
c.Resolvers = nil
|
c.Resolvers = nil
|
||||||
for _, s := range resolvers {
|
for _, s := range resolvers {
|
||||||
if s.Name == req.Resolver {
|
if s.Name == name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.Resolvers = append(c.Resolvers, s)
|
c.Resolvers = append(c.Resolvers, s)
|
||||||
|
182
api/config_router.go
Normal file
182
api/config_router.go
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-gost/x/config"
|
||||||
|
parser "github.com/go-gost/x/config/parsing/router"
|
||||||
|
"github.com/go-gost/x/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// swagger:parameters createRouterRequest
|
||||||
|
type createRouterRequest struct {
|
||||||
|
// in: body
|
||||||
|
Data config.RouterConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response createRouterResponse
|
||||||
|
type createRouterResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func createRouter(ctx *gin.Context) {
|
||||||
|
// swagger:route POST /config/routers Router createRouterRequest
|
||||||
|
//
|
||||||
|
// Create a new router, the name of the router must be unique in router list.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: createRouterResponse
|
||||||
|
|
||||||
|
var req createRouterRequest
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
name := strings.TrimSpace(req.Data.Name)
|
||||||
|
if name == "" {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "router name is required"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
if registry.RouterRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("router %s already exists", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v := parser.ParseRouter(&req.Data)
|
||||||
|
|
||||||
|
if err := registry.RouterRegistry().Register(name, v); err != nil {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("router %s already exists", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
|
c.Routers = append(c.Routers, &req.Data)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters updateRouterRequest
|
||||||
|
type updateRouterRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Router string `uri:"router" json:"router"`
|
||||||
|
// in: body
|
||||||
|
Data config.RouterConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response updateRouterResponse
|
||||||
|
type updateRouterResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateRouter(ctx *gin.Context) {
|
||||||
|
// swagger:route PUT /config/routers/{router} Router updateRouterRequest
|
||||||
|
//
|
||||||
|
// Update router by name, the router must already exist.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: updateRouterResponse
|
||||||
|
|
||||||
|
var req updateRouterRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
name := strings.TrimSpace(req.Router)
|
||||||
|
|
||||||
|
if !registry.RouterRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("router %s not found", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
v := parser.ParseRouter(&req.Data)
|
||||||
|
|
||||||
|
registry.RouterRegistry().Unregister(name)
|
||||||
|
|
||||||
|
if err := registry.RouterRegistry().Register(name, v); err != nil {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("router %s already exists", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
|
for i := range c.Routers {
|
||||||
|
if c.Routers[i].Name == name {
|
||||||
|
c.Routers[i] = &req.Data
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters deleteRouterRequest
|
||||||
|
type deleteRouterRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Router string `uri:"router" json:"router"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response deleteRouterResponse
|
||||||
|
type deleteRouterResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteRouter(ctx *gin.Context) {
|
||||||
|
// swagger:route DELETE /config/routers/{router} Router deleteRouterRequest
|
||||||
|
//
|
||||||
|
// Delete router by name.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: deleteRouterResponse
|
||||||
|
|
||||||
|
var req deleteRouterRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
|
name := strings.TrimSpace(req.Router)
|
||||||
|
|
||||||
|
if !registry.RouterRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("router %s not found", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
registry.RouterRegistry().Unregister(name)
|
||||||
|
|
||||||
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
|
routeres := c.Routers
|
||||||
|
c.Routers = nil
|
||||||
|
for _, s := range routeres {
|
||||||
|
if s.Name == name {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c.Routers = append(c.Routers, s)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
182
api/config_sd.go
Normal file
182
api/config_sd.go
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-gost/x/config"
|
||||||
|
parser "github.com/go-gost/x/config/parsing/sd"
|
||||||
|
"github.com/go-gost/x/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// swagger:parameters createSDRequest
|
||||||
|
type createSDRequest struct {
|
||||||
|
// in: body
|
||||||
|
Data config.SDConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response createSDResponse
|
||||||
|
type createSDResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSD(ctx *gin.Context) {
|
||||||
|
// swagger:route POST /config/sds SD createSDRequest
|
||||||
|
//
|
||||||
|
// Create a new SD, the name of the SD must be unique in SD list.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: createSDResponse
|
||||||
|
|
||||||
|
var req createSDRequest
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
name := strings.TrimSpace(req.Data.Name)
|
||||||
|
if name == "" {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "sd name is required"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
if registry.SDRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("sd %s already exists", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v := parser.ParseSD(&req.Data)
|
||||||
|
|
||||||
|
if err := registry.SDRegistry().Register(name, v); err != nil {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("sd %s already exists", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
|
c.SDs = append(c.SDs, &req.Data)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters updateSDRequest
|
||||||
|
type updateSDRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
SD string `uri:"sd" json:"sd"`
|
||||||
|
// in: body
|
||||||
|
Data config.SDConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response updateSDResponse
|
||||||
|
type updateSDResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateSD(ctx *gin.Context) {
|
||||||
|
// swagger:route PUT /config/sds/{sd} SD updateSDRequest
|
||||||
|
//
|
||||||
|
// Update SD by name, the SD must already exist.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: updateSDResponse
|
||||||
|
|
||||||
|
var req updateSDRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
name := strings.TrimSpace(req.SD)
|
||||||
|
|
||||||
|
if !registry.SDRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("sd %s not found", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
|
v := parser.ParseSD(&req.Data)
|
||||||
|
|
||||||
|
registry.SDRegistry().Unregister(name)
|
||||||
|
|
||||||
|
if err := registry.SDRegistry().Register(name, v); err != nil {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("sd %s already exists", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
|
for i := range c.SDs {
|
||||||
|
if c.SDs[i].Name == name {
|
||||||
|
c.SDs[i] = &req.Data
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters deleteSDRequest
|
||||||
|
type deleteSDRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
SD string `uri:"sd" json:"sd"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response deleteSDResponse
|
||||||
|
type deleteSDResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteSD(ctx *gin.Context) {
|
||||||
|
// swagger:route DELETE /config/sds/{sd} SD deleteSDRequest
|
||||||
|
//
|
||||||
|
// Delete SD by name.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: deleteSDResponse
|
||||||
|
|
||||||
|
var req deleteSDRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
|
name := strings.TrimSpace(req.SD)
|
||||||
|
|
||||||
|
if !registry.SDRegistry().IsRegistered(name) {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("sd %s not found", name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
registry.SDRegistry().Unregister(name)
|
||||||
|
|
||||||
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
|
sds := c.SDs
|
||||||
|
c.SDs = nil
|
||||||
|
for _, s := range sds {
|
||||||
|
if s.Name == name {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c.SDs = append(c.SDs, s)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
@ -35,25 +37,27 @@ func createService(ctx *gin.Context) {
|
|||||||
var req createServiceRequest
|
var req createServiceRequest
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
if req.Data.Name == "" {
|
name := strings.TrimSpace(req.Data.Name)
|
||||||
writeError(ctx, ErrInvalid)
|
if name == "" {
|
||||||
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "service name is required"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
req.Data.Name = name
|
||||||
|
|
||||||
if registry.ServiceRegistry().IsRegistered(req.Data.Name) {
|
if registry.ServiceRegistry().IsRegistered(name) {
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("service %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
svc, err := parser.ParseService(&req.Data)
|
svc, err := parser.ParseService(&req.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(ctx, ErrCreate)
|
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create service %s failed: %s", name, err.Error())))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := registry.ServiceRegistry().Register(req.Data.Name, svc); err != nil {
|
if err := registry.ServiceRegistry().Register(name, svc); err != nil {
|
||||||
svc.Close()
|
svc.Close()
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("service %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,26 +103,28 @@ func updateService(ctx *gin.Context) {
|
|||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
ctx.ShouldBindJSON(&req.Data)
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
old := registry.ServiceRegistry().Get(req.Service)
|
name := strings.TrimSpace(req.Service)
|
||||||
|
|
||||||
|
old := registry.ServiceRegistry().Get(name)
|
||||||
if old == nil {
|
if old == nil {
|
||||||
writeError(ctx, ErrNotFound)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("service %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
old.Close()
|
old.Close()
|
||||||
|
|
||||||
req.Data.Name = req.Service
|
req.Data.Name = name
|
||||||
|
|
||||||
svc, err := parser.ParseService(&req.Data)
|
svc, err := parser.ParseService(&req.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(ctx, ErrCreate)
|
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create service %s failed: %s", name, err.Error())))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.ServiceRegistry().Unregister(req.Service)
|
registry.ServiceRegistry().Unregister(name)
|
||||||
|
|
||||||
if err := registry.ServiceRegistry().Register(req.Service, svc); err != nil {
|
if err := registry.ServiceRegistry().Register(name, svc); err != nil {
|
||||||
svc.Close()
|
svc.Close()
|
||||||
writeError(ctx, ErrDup)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("service %s already exists", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +132,7 @@ func updateService(ctx *gin.Context) {
|
|||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
for i := range c.Services {
|
for i := range c.Services {
|
||||||
if c.Services[i].Name == req.Service {
|
if c.Services[i].Name == name {
|
||||||
c.Services[i] = &req.Data
|
c.Services[i] = &req.Data
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -166,20 +172,22 @@ func deleteService(ctx *gin.Context) {
|
|||||||
var req deleteServiceRequest
|
var req deleteServiceRequest
|
||||||
ctx.ShouldBindUri(&req)
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
svc := registry.ServiceRegistry().Get(req.Service)
|
name := strings.TrimSpace(req.Service)
|
||||||
|
|
||||||
|
svc := registry.ServiceRegistry().Get(name)
|
||||||
if svc == nil {
|
if svc == nil {
|
||||||
writeError(ctx, ErrNotFound)
|
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("service %s not found", name)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.ServiceRegistry().Unregister(req.Service)
|
registry.ServiceRegistry().Unregister(name)
|
||||||
svc.Close()
|
svc.Close()
|
||||||
|
|
||||||
config.OnUpdate(func(c *config.Config) error {
|
config.OnUpdate(func(c *config.Config) error {
|
||||||
services := c.Services
|
services := c.Services
|
||||||
c.Services = nil
|
c.Services = nil
|
||||||
for _, s := range services {
|
for _, s := range services {
|
||||||
if s.Name == req.Service {
|
if s.Name == name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.Services = append(c.Services, s)
|
c.Services = append(c.Services, s)
|
||||||
|
18
api/error.go
18
api/error.go
@ -15,6 +15,16 @@ var (
|
|||||||
ErrSave = &Error{statusCode: http.StatusInternalServerError, Code: 40005, Msg: "save config failed"}
|
ErrSave = &Error{statusCode: http.StatusInternalServerError, Code: 40005, Msg: "save config failed"}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ErrCode int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ErrCodeInvalid = 40001
|
||||||
|
ErrCodeDup = 40002
|
||||||
|
ErrCodeFailed = 40003
|
||||||
|
ErrCodeNotFound = 40004
|
||||||
|
ErrCodeSaveConfigFailed = 40005
|
||||||
|
)
|
||||||
|
|
||||||
// Error is an api error.
|
// Error is an api error.
|
||||||
type Error struct {
|
type Error struct {
|
||||||
statusCode int
|
statusCode int
|
||||||
@ -22,6 +32,14 @@ type Error struct {
|
|||||||
Msg string `json:"msg"`
|
Msg string `json:"msg"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewError(status, code int, msg string) error {
|
||||||
|
return &Error{
|
||||||
|
statusCode: status,
|
||||||
|
Code: code,
|
||||||
|
Msg: msg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (e *Error) Error() string {
|
func (e *Error) Error() string {
|
||||||
b, _ := json.Marshal(e)
|
b, _ := json.Marshal(e)
|
||||||
return string(b)
|
return string(b)
|
||||||
|
@ -36,7 +36,12 @@ func mwBasicAuth(auther auth.Authenticator) gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
u, p, _ := c.Request.BasicAuth()
|
u, p, _ := c.Request.BasicAuth()
|
||||||
if _, ok := auther.Authenticate(c, u, p); !ok {
|
if _, ok := auther.Authenticate(c, u, p); !ok {
|
||||||
c.AbortWithStatus(http.StatusUnauthorized)
|
c.Writer.Header().Set("WWW-Authenticate", "Basic")
|
||||||
|
c.JSON(http.StatusUnauthorized, Response{
|
||||||
|
Code: http.StatusUnauthorized,
|
||||||
|
Msg: "Unauthorized",
|
||||||
|
})
|
||||||
|
c.Abort()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
152
api/service.go
152
api/service.go
@ -1,152 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/gin-contrib/cors"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/go-gost/core/auth"
|
|
||||||
"github.com/go-gost/core/service"
|
|
||||||
)
|
|
||||||
|
|
||||||
type options struct {
|
|
||||||
accessLog bool
|
|
||||||
pathPrefix string
|
|
||||||
auther auth.Authenticator
|
|
||||||
}
|
|
||||||
|
|
||||||
type Option func(*options)
|
|
||||||
|
|
||||||
func PathPrefixOption(pathPrefix string) Option {
|
|
||||||
return func(o *options) {
|
|
||||||
o.pathPrefix = pathPrefix
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func AccessLogOption(enable bool) Option {
|
|
||||||
return func(o *options) {
|
|
||||||
o.accessLog = enable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func AutherOption(auther auth.Authenticator) Option {
|
|
||||||
return func(o *options) {
|
|
||||||
o.auther = auther
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type server struct {
|
|
||||||
s *http.Server
|
|
||||||
ln net.Listener
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewService(addr string, opts ...Option) (service.Service, error) {
|
|
||||||
ln, err := net.Listen("tcp", addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var options options
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(&options)
|
|
||||||
}
|
|
||||||
|
|
||||||
gin.SetMode(gin.ReleaseMode)
|
|
||||||
|
|
||||||
r := gin.New()
|
|
||||||
r.Use(
|
|
||||||
cors.New((cors.Config{
|
|
||||||
AllowAllOrigins: true,
|
|
||||||
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
|
||||||
AllowHeaders: []string{"*"},
|
|
||||||
})),
|
|
||||||
gin.Recovery(),
|
|
||||||
)
|
|
||||||
if options.accessLog {
|
|
||||||
r.Use(mwLogger())
|
|
||||||
}
|
|
||||||
|
|
||||||
router := r.Group("")
|
|
||||||
if options.pathPrefix != "" {
|
|
||||||
router = router.Group(options.pathPrefix)
|
|
||||||
}
|
|
||||||
|
|
||||||
router.StaticFS("/docs", http.FS(swaggerDoc))
|
|
||||||
|
|
||||||
config := router.Group("/config")
|
|
||||||
config.Use(mwBasicAuth(options.auther))
|
|
||||||
registerConfig(config)
|
|
||||||
|
|
||||||
return &server{
|
|
||||||
s: &http.Server{
|
|
||||||
Handler: r,
|
|
||||||
},
|
|
||||||
ln: ln,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *server) Serve() error {
|
|
||||||
return s.s.Serve(s.ln)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *server) Addr() net.Addr {
|
|
||||||
return s.ln.Addr()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *server) Close() error {
|
|
||||||
return s.s.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func registerConfig(config *gin.RouterGroup) {
|
|
||||||
config.GET("", getConfig)
|
|
||||||
config.POST("", saveConfig)
|
|
||||||
|
|
||||||
config.POST("/services", createService)
|
|
||||||
config.PUT("/services/:service", updateService)
|
|
||||||
config.DELETE("/services/:service", deleteService)
|
|
||||||
|
|
||||||
config.POST("/chains", createChain)
|
|
||||||
config.PUT("/chains/:chain", updateChain)
|
|
||||||
config.DELETE("/chains/:chain", deleteChain)
|
|
||||||
|
|
||||||
config.POST("/hops", createHop)
|
|
||||||
config.PUT("/hops/:hop", updateHop)
|
|
||||||
config.DELETE("/hops/:hop", deleteHop)
|
|
||||||
|
|
||||||
config.POST("/authers", createAuther)
|
|
||||||
config.PUT("/authers/:auther", updateAuther)
|
|
||||||
config.DELETE("/authers/:auther", deleteAuther)
|
|
||||||
|
|
||||||
config.POST("/admissions", createAdmission)
|
|
||||||
config.PUT("/admissions/:admission", updateAdmission)
|
|
||||||
config.DELETE("/admissions/:admission", deleteAdmission)
|
|
||||||
|
|
||||||
config.POST("/bypasses", createBypass)
|
|
||||||
config.PUT("/bypasses/:bypass", updateBypass)
|
|
||||||
config.DELETE("/bypasses/:bypass", deleteBypass)
|
|
||||||
|
|
||||||
config.POST("/resolvers", createResolver)
|
|
||||||
config.PUT("/resolvers/:resolver", updateResolver)
|
|
||||||
config.DELETE("/resolvers/:resolver", deleteResolver)
|
|
||||||
|
|
||||||
config.POST("/hosts", createHosts)
|
|
||||||
config.PUT("/hosts/:hosts", updateHosts)
|
|
||||||
config.DELETE("/hosts/:hosts", deleteHosts)
|
|
||||||
|
|
||||||
config.POST("/ingresses", createIngress)
|
|
||||||
config.PUT("/ingresses/:ingress", updateIngress)
|
|
||||||
config.DELETE("/ingresses/:ingress", deleteIngress)
|
|
||||||
|
|
||||||
config.POST("/limiters", createLimiter)
|
|
||||||
config.PUT("/limiters/:limiter", updateLimiter)
|
|
||||||
config.DELETE("/limiters/:limiter", deleteLimiter)
|
|
||||||
|
|
||||||
config.POST("/climiters", createConnLimiter)
|
|
||||||
config.PUT("/climiters/:limiter", updateConnLimiter)
|
|
||||||
config.DELETE("/climiters/:limiter", deleteConnLimiter)
|
|
||||||
|
|
||||||
config.POST("/rlimiters", createRateLimiter)
|
|
||||||
config.PUT("/rlimiters/:limiter", updateRateLimiter)
|
|
||||||
config.DELETE("/rlimiters/:limiter", deleteRateLimiter)
|
|
||||||
}
|
|
657
api/swagger.yaml
657
api/swagger.yaml
@ -34,6 +34,8 @@ definitions:
|
|||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Name
|
x-go-name: Name
|
||||||
|
plugin:
|
||||||
|
$ref: '#/definitions/PluginConfig'
|
||||||
redis:
|
redis:
|
||||||
$ref: '#/definitions/RedisLoader'
|
$ref: '#/definitions/RedisLoader'
|
||||||
reload:
|
reload:
|
||||||
@ -71,6 +73,8 @@ definitions:
|
|||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Name
|
x-go-name: Name
|
||||||
|
plugin:
|
||||||
|
$ref: '#/definitions/PluginConfig'
|
||||||
redis:
|
redis:
|
||||||
$ref: '#/definitions/RedisLoader'
|
$ref: '#/definitions/RedisLoader'
|
||||||
reload:
|
reload:
|
||||||
@ -91,6 +95,8 @@ definitions:
|
|||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Name
|
x-go-name: Name
|
||||||
|
plugin:
|
||||||
|
$ref: '#/definitions/PluginConfig'
|
||||||
redis:
|
redis:
|
||||||
$ref: '#/definitions/RedisLoader'
|
$ref: '#/definitions/RedisLoader'
|
||||||
reload:
|
reload:
|
||||||
@ -107,9 +113,6 @@ definitions:
|
|||||||
ChainConfig:
|
ChainConfig:
|
||||||
properties:
|
properties:
|
||||||
hops:
|
hops:
|
||||||
description: |-
|
|
||||||
REMOVED since beta.6
|
|
||||||
Selector *SelectorConfig `yaml:",omitempty" json:"selector,omitempty"`
|
|
||||||
items:
|
items:
|
||||||
$ref: '#/definitions/HopConfig'
|
$ref: '#/definitions/HopConfig'
|
||||||
type: array
|
type: array
|
||||||
@ -185,8 +188,18 @@ definitions:
|
|||||||
x-go-name: Limiters
|
x-go-name: Limiters
|
||||||
log:
|
log:
|
||||||
$ref: '#/definitions/LogConfig'
|
$ref: '#/definitions/LogConfig'
|
||||||
|
loggers:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/LoggerConfig'
|
||||||
|
type: array
|
||||||
|
x-go-name: Loggers
|
||||||
metrics:
|
metrics:
|
||||||
$ref: '#/definitions/MetricsConfig'
|
$ref: '#/definitions/MetricsConfig'
|
||||||
|
observers:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/ObserverConfig'
|
||||||
|
type: array
|
||||||
|
x-go-name: Observers
|
||||||
profiling:
|
profiling:
|
||||||
$ref: '#/definitions/ProfilingConfig'
|
$ref: '#/definitions/ProfilingConfig'
|
||||||
recorders:
|
recorders:
|
||||||
@ -204,6 +217,16 @@ definitions:
|
|||||||
$ref: '#/definitions/LimiterConfig'
|
$ref: '#/definitions/LimiterConfig'
|
||||||
type: array
|
type: array
|
||||||
x-go-name: RLimiters
|
x-go-name: RLimiters
|
||||||
|
routers:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/RouterConfig'
|
||||||
|
type: array
|
||||||
|
x-go-name: Routers
|
||||||
|
sds:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/SDConfig'
|
||||||
|
type: array
|
||||||
|
x-go-name: SDs
|
||||||
services:
|
services:
|
||||||
items:
|
items:
|
||||||
$ref: '#/definitions/ServiceConfig'
|
$ref: '#/definitions/ServiceConfig'
|
||||||
@ -273,6 +296,8 @@ definitions:
|
|||||||
addr:
|
addr:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Addr
|
x-go-name: Addr
|
||||||
|
auth:
|
||||||
|
$ref: '#/definitions/AuthConfig'
|
||||||
bypass:
|
bypass:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Bypass
|
x-go-name: Bypass
|
||||||
@ -281,20 +306,44 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
x-go-name: Bypasses
|
x-go-name: Bypasses
|
||||||
|
filter:
|
||||||
|
$ref: '#/definitions/NodeFilterConfig'
|
||||||
host:
|
host:
|
||||||
|
description: DEPRECATED by filter.host
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Host
|
x-go-name: Host
|
||||||
|
http:
|
||||||
|
$ref: '#/definitions/HTTPNodeConfig'
|
||||||
|
metadata:
|
||||||
|
additionalProperties: {}
|
||||||
|
type: object
|
||||||
|
x-go-name: Metadata
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Name
|
x-go-name: Name
|
||||||
|
network:
|
||||||
|
type: string
|
||||||
|
x-go-name: Network
|
||||||
|
path:
|
||||||
|
description: DEPRECATED by filter.path
|
||||||
|
type: string
|
||||||
|
x-go-name: Path
|
||||||
protocol:
|
protocol:
|
||||||
|
description: DEPRECATED by filter.protocol
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Protocol
|
x-go-name: Protocol
|
||||||
|
tls:
|
||||||
|
$ref: '#/definitions/TLSNodeConfig'
|
||||||
type: object
|
type: object
|
||||||
x-go-package: github.com/go-gost/x/config
|
x-go-package: github.com/go-gost/x/config
|
||||||
ForwarderConfig:
|
ForwarderConfig:
|
||||||
properties:
|
properties:
|
||||||
|
hop:
|
||||||
|
description: the referenced hop name
|
||||||
|
type: string
|
||||||
|
x-go-name: Hop
|
||||||
name:
|
name:
|
||||||
|
description: DEPRECATED by hop field
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Name
|
x-go-name: Name
|
||||||
nodes:
|
nodes:
|
||||||
@ -304,12 +353,6 @@ definitions:
|
|||||||
x-go-name: Nodes
|
x-go-name: Nodes
|
||||||
selector:
|
selector:
|
||||||
$ref: '#/definitions/SelectorConfig'
|
$ref: '#/definitions/SelectorConfig'
|
||||||
targets:
|
|
||||||
description: DEPRECATED by nodes since beta.4
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
x-go-name: Targets
|
|
||||||
type: object
|
type: object
|
||||||
x-go-package: github.com/go-gost/x/config
|
x-go-package: github.com/go-gost/x/config
|
||||||
HTTPLoader:
|
HTTPLoader:
|
||||||
@ -321,6 +364,42 @@ definitions:
|
|||||||
x-go-name: URL
|
x-go-name: URL
|
||||||
type: object
|
type: object
|
||||||
x-go-package: github.com/go-gost/x/config
|
x-go-package: github.com/go-gost/x/config
|
||||||
|
HTTPNodeConfig:
|
||||||
|
properties:
|
||||||
|
auth:
|
||||||
|
$ref: '#/definitions/AuthConfig'
|
||||||
|
header:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
x-go-name: Header
|
||||||
|
host:
|
||||||
|
type: string
|
||||||
|
x-go-name: Host
|
||||||
|
rewrite:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/HTTPURLRewriteConfig'
|
||||||
|
type: array
|
||||||
|
x-go-name: Rewrite
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/go-gost/x/config
|
||||||
|
HTTPRecorder:
|
||||||
|
properties:
|
||||||
|
timeout:
|
||||||
|
$ref: '#/definitions/Duration'
|
||||||
|
url:
|
||||||
|
type: string
|
||||||
|
x-go-name: URL
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/go-gost/x/config
|
||||||
|
HTTPURLRewriteConfig:
|
||||||
|
properties:
|
||||||
|
Match:
|
||||||
|
type: string
|
||||||
|
Replacement:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/go-gost/x/config
|
||||||
HandlerConfig:
|
HandlerConfig:
|
||||||
properties:
|
properties:
|
||||||
auth:
|
auth:
|
||||||
@ -338,13 +417,16 @@ definitions:
|
|||||||
x-go-name: Chain
|
x-go-name: Chain
|
||||||
chainGroup:
|
chainGroup:
|
||||||
$ref: '#/definitions/ChainGroupConfig'
|
$ref: '#/definitions/ChainGroupConfig'
|
||||||
ingress:
|
limiter:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Ingress
|
x-go-name: Limiter
|
||||||
metadata:
|
metadata:
|
||||||
additionalProperties: {}
|
additionalProperties: {}
|
||||||
type: object
|
type: object
|
||||||
x-go-name: Metadata
|
x-go-name: Metadata
|
||||||
|
observer:
|
||||||
|
type: string
|
||||||
|
x-go-name: Observer
|
||||||
retries:
|
retries:
|
||||||
format: int64
|
format: int64
|
||||||
type: integer
|
type: integer
|
||||||
@ -366,9 +448,13 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
x-go-name: Bypasses
|
x-go-name: Bypasses
|
||||||
|
file:
|
||||||
|
$ref: '#/definitions/FileLoader'
|
||||||
hosts:
|
hosts:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Hosts
|
x-go-name: Hosts
|
||||||
|
http:
|
||||||
|
$ref: '#/definitions/HTTPLoader'
|
||||||
interface:
|
interface:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Interface
|
x-go-name: Interface
|
||||||
@ -380,6 +466,12 @@ definitions:
|
|||||||
$ref: '#/definitions/NodeConfig'
|
$ref: '#/definitions/NodeConfig'
|
||||||
type: array
|
type: array
|
||||||
x-go-name: Nodes
|
x-go-name: Nodes
|
||||||
|
plugin:
|
||||||
|
$ref: '#/definitions/PluginConfig'
|
||||||
|
redis:
|
||||||
|
$ref: '#/definitions/RedisLoader'
|
||||||
|
reload:
|
||||||
|
$ref: '#/definitions/Duration'
|
||||||
resolver:
|
resolver:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Resolver
|
x-go-name: Resolver
|
||||||
@ -418,6 +510,8 @@ definitions:
|
|||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Name
|
x-go-name: Name
|
||||||
|
plugin:
|
||||||
|
$ref: '#/definitions/PluginConfig'
|
||||||
redis:
|
redis:
|
||||||
$ref: '#/definitions/RedisLoader'
|
$ref: '#/definitions/RedisLoader'
|
||||||
reload:
|
reload:
|
||||||
@ -433,6 +527,8 @@ definitions:
|
|||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Name
|
x-go-name: Name
|
||||||
|
plugin:
|
||||||
|
$ref: '#/definitions/PluginConfig'
|
||||||
redis:
|
redis:
|
||||||
$ref: '#/definitions/RedisLoader'
|
$ref: '#/definitions/RedisLoader'
|
||||||
reload:
|
reload:
|
||||||
@ -468,6 +564,8 @@ definitions:
|
|||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Name
|
x-go-name: Name
|
||||||
|
plugin:
|
||||||
|
$ref: '#/definitions/PluginConfig'
|
||||||
redis:
|
redis:
|
||||||
$ref: '#/definitions/RedisLoader'
|
$ref: '#/definitions/RedisLoader'
|
||||||
reload:
|
reload:
|
||||||
@ -559,11 +657,25 @@ definitions:
|
|||||||
x-go-name: MaxSize
|
x-go-name: MaxSize
|
||||||
type: object
|
type: object
|
||||||
x-go-package: github.com/go-gost/x/config
|
x-go-package: github.com/go-gost/x/config
|
||||||
|
LoggerConfig:
|
||||||
|
properties:
|
||||||
|
log:
|
||||||
|
$ref: '#/definitions/LogConfig'
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
x-go-name: Name
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/go-gost/x/config
|
||||||
MetricsConfig:
|
MetricsConfig:
|
||||||
properties:
|
properties:
|
||||||
addr:
|
addr:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Addr
|
x-go-name: Addr
|
||||||
|
auth:
|
||||||
|
$ref: '#/definitions/AuthConfig'
|
||||||
|
auther:
|
||||||
|
type: string
|
||||||
|
x-go-name: Auther
|
||||||
path:
|
path:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Path
|
x-go-name: Path
|
||||||
@ -574,6 +686,9 @@ definitions:
|
|||||||
addr:
|
addr:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Addr
|
x-go-name: Addr
|
||||||
|
async:
|
||||||
|
type: boolean
|
||||||
|
x-go-name: Async
|
||||||
chain:
|
chain:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Chain
|
x-go-name: Chain
|
||||||
@ -583,6 +698,9 @@ definitions:
|
|||||||
hostname:
|
hostname:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Hostname
|
x-go-name: Hostname
|
||||||
|
only:
|
||||||
|
type: string
|
||||||
|
x-go-name: Only
|
||||||
prefer:
|
prefer:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Prefer
|
x-go-name: Prefer
|
||||||
@ -609,12 +727,13 @@ definitions:
|
|||||||
$ref: '#/definitions/ConnectorConfig'
|
$ref: '#/definitions/ConnectorConfig'
|
||||||
dialer:
|
dialer:
|
||||||
$ref: '#/definitions/DialerConfig'
|
$ref: '#/definitions/DialerConfig'
|
||||||
host:
|
filter:
|
||||||
type: string
|
$ref: '#/definitions/NodeFilterConfig'
|
||||||
x-go-name: Host
|
|
||||||
hosts:
|
hosts:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Hosts
|
x-go-name: Hosts
|
||||||
|
http:
|
||||||
|
$ref: '#/definitions/HTTPNodeConfig'
|
||||||
interface:
|
interface:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Interface
|
x-go-name: Interface
|
||||||
@ -625,14 +744,55 @@ definitions:
|
|||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Name
|
x-go-name: Name
|
||||||
protocol:
|
network:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Protocol
|
x-go-name: Network
|
||||||
resolver:
|
resolver:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Resolver
|
x-go-name: Resolver
|
||||||
sockopts:
|
sockopts:
|
||||||
$ref: '#/definitions/SockOptsConfig'
|
$ref: '#/definitions/SockOptsConfig'
|
||||||
|
tls:
|
||||||
|
$ref: '#/definitions/TLSNodeConfig'
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/go-gost/x/config
|
||||||
|
NodeFilterConfig:
|
||||||
|
properties:
|
||||||
|
host:
|
||||||
|
type: string
|
||||||
|
x-go-name: Host
|
||||||
|
path:
|
||||||
|
type: string
|
||||||
|
x-go-name: Path
|
||||||
|
protocol:
|
||||||
|
type: string
|
||||||
|
x-go-name: Protocol
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/go-gost/x/config
|
||||||
|
ObserverConfig:
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
x-go-name: Name
|
||||||
|
plugin:
|
||||||
|
$ref: '#/definitions/PluginConfig'
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/go-gost/x/config
|
||||||
|
PluginConfig:
|
||||||
|
properties:
|
||||||
|
addr:
|
||||||
|
type: string
|
||||||
|
x-go-name: Addr
|
||||||
|
timeout:
|
||||||
|
$ref: '#/definitions/Duration'
|
||||||
|
tls:
|
||||||
|
$ref: '#/definitions/TLSConfig'
|
||||||
|
token:
|
||||||
|
type: string
|
||||||
|
x-go-name: Token
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
x-go-name: Type
|
||||||
type: object
|
type: object
|
||||||
x-go-package: github.com/go-gost/x/config
|
x-go-package: github.com/go-gost/x/config
|
||||||
ProfilingConfig:
|
ProfilingConfig:
|
||||||
@ -646,15 +806,24 @@ definitions:
|
|||||||
properties:
|
properties:
|
||||||
file:
|
file:
|
||||||
$ref: '#/definitions/FileRecorder'
|
$ref: '#/definitions/FileRecorder'
|
||||||
|
http:
|
||||||
|
$ref: '#/definitions/HTTPRecorder'
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Name
|
x-go-name: Name
|
||||||
|
plugin:
|
||||||
|
$ref: '#/definitions/PluginConfig'
|
||||||
redis:
|
redis:
|
||||||
$ref: '#/definitions/RedisRecorder'
|
$ref: '#/definitions/RedisRecorder'
|
||||||
|
tcp:
|
||||||
|
$ref: '#/definitions/TCPRecorder'
|
||||||
type: object
|
type: object
|
||||||
x-go-package: github.com/go-gost/x/config
|
x-go-package: github.com/go-gost/x/config
|
||||||
RecorderObject:
|
RecorderObject:
|
||||||
properties:
|
properties:
|
||||||
|
Metadata:
|
||||||
|
additionalProperties: {}
|
||||||
|
type: object
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Name
|
x-go-name: Name
|
||||||
@ -713,6 +882,8 @@ definitions:
|
|||||||
$ref: '#/definitions/NameserverConfig'
|
$ref: '#/definitions/NameserverConfig'
|
||||||
type: array
|
type: array
|
||||||
x-go-name: Nameservers
|
x-go-name: Nameservers
|
||||||
|
plugin:
|
||||||
|
$ref: '#/definitions/PluginConfig'
|
||||||
type: object
|
type: object
|
||||||
x-go-package: github.com/go-gost/x/config
|
x-go-package: github.com/go-gost/x/config
|
||||||
Response:
|
Response:
|
||||||
@ -726,6 +897,47 @@ definitions:
|
|||||||
x-go-name: Msg
|
x-go-name: Msg
|
||||||
type: object
|
type: object
|
||||||
x-go-package: github.com/go-gost/x/api
|
x-go-package: github.com/go-gost/x/api
|
||||||
|
RouterConfig:
|
||||||
|
properties:
|
||||||
|
file:
|
||||||
|
$ref: '#/definitions/FileLoader'
|
||||||
|
http:
|
||||||
|
$ref: '#/definitions/HTTPLoader'
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
x-go-name: Name
|
||||||
|
plugin:
|
||||||
|
$ref: '#/definitions/PluginConfig'
|
||||||
|
redis:
|
||||||
|
$ref: '#/definitions/RedisLoader'
|
||||||
|
reload:
|
||||||
|
$ref: '#/definitions/Duration'
|
||||||
|
routes:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/RouterRouteConfig'
|
||||||
|
type: array
|
||||||
|
x-go-name: Routes
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/go-gost/x/config
|
||||||
|
RouterRouteConfig:
|
||||||
|
properties:
|
||||||
|
gateway:
|
||||||
|
type: string
|
||||||
|
x-go-name: Gateway
|
||||||
|
net:
|
||||||
|
type: string
|
||||||
|
x-go-name: Net
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/go-gost/x/config
|
||||||
|
SDConfig:
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
x-go-name: Name
|
||||||
|
plugin:
|
||||||
|
$ref: '#/definitions/PluginConfig'
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/go-gost/x/config
|
||||||
SelectorConfig:
|
SelectorConfig:
|
||||||
properties:
|
properties:
|
||||||
failTimeout:
|
failTimeout:
|
||||||
@ -779,6 +991,14 @@ definitions:
|
|||||||
x-go-name: Limiter
|
x-go-name: Limiter
|
||||||
listener:
|
listener:
|
||||||
$ref: '#/definitions/ListenerConfig'
|
$ref: '#/definitions/ListenerConfig'
|
||||||
|
logger:
|
||||||
|
type: string
|
||||||
|
x-go-name: Logger
|
||||||
|
loggers:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
x-go-name: Loggers
|
||||||
metadata:
|
metadata:
|
||||||
additionalProperties: {}
|
additionalProperties: {}
|
||||||
type: object
|
type: object
|
||||||
@ -786,6 +1006,9 @@ definitions:
|
|||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Name
|
x-go-name: Name
|
||||||
|
observer:
|
||||||
|
type: string
|
||||||
|
x-go-name: Observer
|
||||||
recorders:
|
recorders:
|
||||||
items:
|
items:
|
||||||
$ref: '#/definitions/RecorderObject'
|
$ref: '#/definitions/RecorderObject'
|
||||||
@ -799,6 +1022,61 @@ definitions:
|
|||||||
x-go-name: RLimiter
|
x-go-name: RLimiter
|
||||||
sockopts:
|
sockopts:
|
||||||
$ref: '#/definitions/SockOptsConfig'
|
$ref: '#/definitions/SockOptsConfig'
|
||||||
|
status:
|
||||||
|
$ref: '#/definitions/ServiceStatus'
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/go-gost/x/config
|
||||||
|
ServiceEvent:
|
||||||
|
properties:
|
||||||
|
msg:
|
||||||
|
type: string
|
||||||
|
x-go-name: Msg
|
||||||
|
time:
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
x-go-name: Time
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/go-gost/x/config
|
||||||
|
ServiceStats:
|
||||||
|
properties:
|
||||||
|
currentConns:
|
||||||
|
format: uint64
|
||||||
|
type: integer
|
||||||
|
x-go-name: CurrentConns
|
||||||
|
inputBytes:
|
||||||
|
format: uint64
|
||||||
|
type: integer
|
||||||
|
x-go-name: InputBytes
|
||||||
|
outputBytes:
|
||||||
|
format: uint64
|
||||||
|
type: integer
|
||||||
|
x-go-name: OutputBytes
|
||||||
|
totalConns:
|
||||||
|
format: uint64
|
||||||
|
type: integer
|
||||||
|
x-go-name: TotalConns
|
||||||
|
totalErrs:
|
||||||
|
format: uint64
|
||||||
|
type: integer
|
||||||
|
x-go-name: TotalErrs
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/go-gost/x/config
|
||||||
|
ServiceStatus:
|
||||||
|
properties:
|
||||||
|
createTime:
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
x-go-name: CreateTime
|
||||||
|
events:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/ServiceEvent'
|
||||||
|
type: array
|
||||||
|
x-go-name: Events
|
||||||
|
state:
|
||||||
|
type: string
|
||||||
|
x-go-name: State
|
||||||
|
stats:
|
||||||
|
$ref: '#/definitions/ServiceStats'
|
||||||
type: object
|
type: object
|
||||||
x-go-package: github.com/go-gost/x/config
|
x-go-package: github.com/go-gost/x/config
|
||||||
SockOptsConfig:
|
SockOptsConfig:
|
||||||
@ -809,6 +1087,15 @@ definitions:
|
|||||||
x-go-name: Mark
|
x-go-name: Mark
|
||||||
type: object
|
type: object
|
||||||
x-go-package: github.com/go-gost/x/config
|
x-go-package: github.com/go-gost/x/config
|
||||||
|
TCPRecorder:
|
||||||
|
properties:
|
||||||
|
addr:
|
||||||
|
type: string
|
||||||
|
x-go-name: Addr
|
||||||
|
timeout:
|
||||||
|
$ref: '#/definitions/Duration'
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/go-gost/x/config
|
||||||
TLSConfig:
|
TLSConfig:
|
||||||
properties:
|
properties:
|
||||||
caFile:
|
caFile:
|
||||||
@ -823,6 +1110,8 @@ definitions:
|
|||||||
keyFile:
|
keyFile:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: KeyFile
|
x-go-name: KeyFile
|
||||||
|
options:
|
||||||
|
$ref: '#/definitions/TLSOptions'
|
||||||
organization:
|
organization:
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Organization
|
x-go-name: Organization
|
||||||
@ -836,6 +1125,33 @@ definitions:
|
|||||||
$ref: '#/definitions/Duration'
|
$ref: '#/definitions/Duration'
|
||||||
type: object
|
type: object
|
||||||
x-go-package: github.com/go-gost/x/config
|
x-go-package: github.com/go-gost/x/config
|
||||||
|
TLSNodeConfig:
|
||||||
|
properties:
|
||||||
|
options:
|
||||||
|
$ref: '#/definitions/TLSOptions'
|
||||||
|
secure:
|
||||||
|
type: boolean
|
||||||
|
x-go-name: Secure
|
||||||
|
serverName:
|
||||||
|
type: string
|
||||||
|
x-go-name: ServerName
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/go-gost/x/config
|
||||||
|
TLSOptions:
|
||||||
|
properties:
|
||||||
|
cipherSuites:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
x-go-name: CipherSuites
|
||||||
|
maxVersion:
|
||||||
|
type: string
|
||||||
|
x-go-name: MaxVersion
|
||||||
|
minVersion:
|
||||||
|
type: string
|
||||||
|
x-go-name: MinVersion
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/go-gost/x/config
|
||||||
info:
|
info:
|
||||||
title: Documentation of Web API.
|
title: Documentation of Web API.
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
@ -866,6 +1182,11 @@ paths:
|
|||||||
name: format
|
name: format
|
||||||
type: string
|
type: string
|
||||||
x-go-name: Format
|
x-go-name: Format
|
||||||
|
- description: file path, default is gost.yaml|gost.json in current working directory.
|
||||||
|
in: query
|
||||||
|
name: path
|
||||||
|
type: string
|
||||||
|
x-go-name: Path
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
$ref: '#/responses/saveConfigResponse'
|
$ref: '#/responses/saveConfigResponse'
|
||||||
@ -1397,6 +1718,122 @@ paths:
|
|||||||
summary: Update limiter by name, the limiter must already exist.
|
summary: Update limiter by name, the limiter must already exist.
|
||||||
tags:
|
tags:
|
||||||
- Limiter
|
- Limiter
|
||||||
|
/config/observers:
|
||||||
|
post:
|
||||||
|
operationId: createObserverRequest
|
||||||
|
parameters:
|
||||||
|
- in: body
|
||||||
|
name: data
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ObserverConfig'
|
||||||
|
x-go-name: Data
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
$ref: '#/responses/createObserverResponse'
|
||||||
|
security:
|
||||||
|
- basicAuth:
|
||||||
|
- '[]'
|
||||||
|
summary: Create a new observer, the name of the observer must be unique in observer list.
|
||||||
|
tags:
|
||||||
|
- Observer
|
||||||
|
/config/observers/{observer}:
|
||||||
|
delete:
|
||||||
|
operationId: deleteObserverRequest
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: observer
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
x-go-name: Observer
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
$ref: '#/responses/deleteObserverResponse'
|
||||||
|
security:
|
||||||
|
- basicAuth:
|
||||||
|
- '[]'
|
||||||
|
summary: Delete observer by name.
|
||||||
|
tags:
|
||||||
|
- Observer
|
||||||
|
put:
|
||||||
|
operationId: updateObserverRequest
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: observer
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
x-go-name: Observer
|
||||||
|
- in: body
|
||||||
|
name: data
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ObserverConfig'
|
||||||
|
x-go-name: Data
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
$ref: '#/responses/updateObserverResponse'
|
||||||
|
security:
|
||||||
|
- basicAuth:
|
||||||
|
- '[]'
|
||||||
|
summary: Update observer by name, the observer must already exist.
|
||||||
|
tags:
|
||||||
|
- Observer
|
||||||
|
/config/recorders:
|
||||||
|
post:
|
||||||
|
operationId: createRecorderRequest
|
||||||
|
parameters:
|
||||||
|
- in: body
|
||||||
|
name: data
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/RecorderConfig'
|
||||||
|
x-go-name: Data
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
$ref: '#/responses/createRecorderResponse'
|
||||||
|
security:
|
||||||
|
- basicAuth:
|
||||||
|
- '[]'
|
||||||
|
summary: Create a new recorder, the name of the recorder must be unique in recorder list.
|
||||||
|
tags:
|
||||||
|
- Recorder
|
||||||
|
/config/recorders/{recorder}:
|
||||||
|
delete:
|
||||||
|
operationId: deleteRecorderRequest
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: recorder
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
x-go-name: Recorder
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
$ref: '#/responses/deleteRecorderResponse'
|
||||||
|
security:
|
||||||
|
- basicAuth:
|
||||||
|
- '[]'
|
||||||
|
summary: Delete recorder by name.
|
||||||
|
tags:
|
||||||
|
- Recorder
|
||||||
|
put:
|
||||||
|
operationId: updateRecorderRequest
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: recorder
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
x-go-name: Recorder
|
||||||
|
- in: body
|
||||||
|
name: data
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/RecorderConfig'
|
||||||
|
x-go-name: Data
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
$ref: '#/responses/updateRecorderResponse'
|
||||||
|
security:
|
||||||
|
- basicAuth:
|
||||||
|
- '[]'
|
||||||
|
summary: Update recorder by name, the recorder must already exist.
|
||||||
|
tags:
|
||||||
|
- Recorder
|
||||||
/config/resolvers:
|
/config/resolvers:
|
||||||
post:
|
post:
|
||||||
operationId: createResolverRequest
|
operationId: createResolverRequest
|
||||||
@ -1513,6 +1950,122 @@ paths:
|
|||||||
summary: Update rate limiter by name, the limiter must already exist.
|
summary: Update rate limiter by name, the limiter must already exist.
|
||||||
tags:
|
tags:
|
||||||
- Limiter
|
- Limiter
|
||||||
|
/config/routers:
|
||||||
|
post:
|
||||||
|
operationId: createRouterRequest
|
||||||
|
parameters:
|
||||||
|
- in: body
|
||||||
|
name: data
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/RouterConfig'
|
||||||
|
x-go-name: Data
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
$ref: '#/responses/createRouterResponse'
|
||||||
|
security:
|
||||||
|
- basicAuth:
|
||||||
|
- '[]'
|
||||||
|
summary: Create a new router, the name of the router must be unique in router list.
|
||||||
|
tags:
|
||||||
|
- Router
|
||||||
|
/config/routers/{router}:
|
||||||
|
delete:
|
||||||
|
operationId: deleteRouterRequest
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: router
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
x-go-name: Router
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
$ref: '#/responses/deleteRouterResponse'
|
||||||
|
security:
|
||||||
|
- basicAuth:
|
||||||
|
- '[]'
|
||||||
|
summary: Delete router by name.
|
||||||
|
tags:
|
||||||
|
- Router
|
||||||
|
put:
|
||||||
|
operationId: updateRouterRequest
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: router
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
x-go-name: Router
|
||||||
|
- in: body
|
||||||
|
name: data
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/RouterConfig'
|
||||||
|
x-go-name: Data
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
$ref: '#/responses/updateRouterResponse'
|
||||||
|
security:
|
||||||
|
- basicAuth:
|
||||||
|
- '[]'
|
||||||
|
summary: Update router by name, the router must already exist.
|
||||||
|
tags:
|
||||||
|
- Router
|
||||||
|
/config/sds:
|
||||||
|
post:
|
||||||
|
operationId: createSDRequest
|
||||||
|
parameters:
|
||||||
|
- in: body
|
||||||
|
name: data
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/SDConfig'
|
||||||
|
x-go-name: Data
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
$ref: '#/responses/createSDResponse'
|
||||||
|
security:
|
||||||
|
- basicAuth:
|
||||||
|
- '[]'
|
||||||
|
summary: Create a new SD, the name of the SD must be unique in SD list.
|
||||||
|
tags:
|
||||||
|
- SD
|
||||||
|
/config/sds/{sd}:
|
||||||
|
delete:
|
||||||
|
operationId: deleteSDRequest
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: sd
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
x-go-name: SD
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
$ref: '#/responses/deleteSDResponse'
|
||||||
|
security:
|
||||||
|
- basicAuth:
|
||||||
|
- '[]'
|
||||||
|
summary: Delete SD by name.
|
||||||
|
tags:
|
||||||
|
- SD
|
||||||
|
put:
|
||||||
|
operationId: updateSDRequest
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: sd
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
x-go-name: SD
|
||||||
|
- in: body
|
||||||
|
name: data
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/SDConfig'
|
||||||
|
x-go-name: Data
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
$ref: '#/responses/updateSDResponse'
|
||||||
|
security:
|
||||||
|
- basicAuth:
|
||||||
|
- '[]'
|
||||||
|
summary: Update SD by name, the SD must already exist.
|
||||||
|
tags:
|
||||||
|
- SD
|
||||||
/config/services:
|
/config/services:
|
||||||
post:
|
post:
|
||||||
operationId: createServiceRequest
|
operationId: createServiceRequest
|
||||||
@ -1628,18 +2181,42 @@ responses:
|
|||||||
Data: {}
|
Data: {}
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/Response'
|
$ref: '#/definitions/Response'
|
||||||
|
createObserverResponse:
|
||||||
|
description: successful operation.
|
||||||
|
headers:
|
||||||
|
Data: {}
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Response'
|
||||||
createRateLimiterResponse:
|
createRateLimiterResponse:
|
||||||
description: successful operation.
|
description: successful operation.
|
||||||
headers:
|
headers:
|
||||||
Data: {}
|
Data: {}
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/Response'
|
$ref: '#/definitions/Response'
|
||||||
|
createRecorderResponse:
|
||||||
|
description: successful operation.
|
||||||
|
headers:
|
||||||
|
Data: {}
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Response'
|
||||||
createResolverResponse:
|
createResolverResponse:
|
||||||
description: successful operation.
|
description: successful operation.
|
||||||
headers:
|
headers:
|
||||||
Data: {}
|
Data: {}
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/Response'
|
$ref: '#/definitions/Response'
|
||||||
|
createRouterResponse:
|
||||||
|
description: successful operation.
|
||||||
|
headers:
|
||||||
|
Data: {}
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Response'
|
||||||
|
createSDResponse:
|
||||||
|
description: successful operation.
|
||||||
|
headers:
|
||||||
|
Data: {}
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Response'
|
||||||
createServiceResponse:
|
createServiceResponse:
|
||||||
description: successful operation.
|
description: successful operation.
|
||||||
headers:
|
headers:
|
||||||
@ -1700,18 +2277,42 @@ responses:
|
|||||||
Data: {}
|
Data: {}
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/Response'
|
$ref: '#/definitions/Response'
|
||||||
|
deleteObserverResponse:
|
||||||
|
description: successful operation.
|
||||||
|
headers:
|
||||||
|
Data: {}
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Response'
|
||||||
deleteRateLimiterResponse:
|
deleteRateLimiterResponse:
|
||||||
description: successful operation.
|
description: successful operation.
|
||||||
headers:
|
headers:
|
||||||
Data: {}
|
Data: {}
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/Response'
|
$ref: '#/definitions/Response'
|
||||||
|
deleteRecorderResponse:
|
||||||
|
description: successful operation.
|
||||||
|
headers:
|
||||||
|
Data: {}
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Response'
|
||||||
deleteResolverResponse:
|
deleteResolverResponse:
|
||||||
description: successful operation.
|
description: successful operation.
|
||||||
headers:
|
headers:
|
||||||
Data: {}
|
Data: {}
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/Response'
|
$ref: '#/definitions/Response'
|
||||||
|
deleteRouterResponse:
|
||||||
|
description: successful operation.
|
||||||
|
headers:
|
||||||
|
Data: {}
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Response'
|
||||||
|
deleteSDResponse:
|
||||||
|
description: successful operation.
|
||||||
|
headers:
|
||||||
|
Data: {}
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Response'
|
||||||
deleteServiceResponse:
|
deleteServiceResponse:
|
||||||
description: successful operation.
|
description: successful operation.
|
||||||
headers:
|
headers:
|
||||||
@ -1784,18 +2385,42 @@ responses:
|
|||||||
Data: {}
|
Data: {}
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/Response'
|
$ref: '#/definitions/Response'
|
||||||
|
updateObserverResponse:
|
||||||
|
description: successful operation.
|
||||||
|
headers:
|
||||||
|
Data: {}
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Response'
|
||||||
updateRateLimiterResponse:
|
updateRateLimiterResponse:
|
||||||
description: successful operation.
|
description: successful operation.
|
||||||
headers:
|
headers:
|
||||||
Data: {}
|
Data: {}
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/Response'
|
$ref: '#/definitions/Response'
|
||||||
|
updateRecorderResponse:
|
||||||
|
description: successful operation.
|
||||||
|
headers:
|
||||||
|
Data: {}
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Response'
|
||||||
updateResolverResponse:
|
updateResolverResponse:
|
||||||
description: successful operation.
|
description: successful operation.
|
||||||
headers:
|
headers:
|
||||||
Data: {}
|
Data: {}
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/Response'
|
$ref: '#/definitions/Response'
|
||||||
|
updateRouterResponse:
|
||||||
|
description: successful operation.
|
||||||
|
headers:
|
||||||
|
Data: {}
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Response'
|
||||||
|
updateSDResponse:
|
||||||
|
description: successful operation.
|
||||||
|
headers:
|
||||||
|
Data: {}
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Response'
|
||||||
updateServiceResponse:
|
updateServiceResponse:
|
||||||
description: successful operation.
|
description: successful operation.
|
||||||
headers:
|
headers:
|
||||||
|
@ -110,7 +110,7 @@ func (p *authenticator) Authenticate(ctx context.Context, user, password string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
v, ok := p.kvs[user]
|
v, ok := p.kvs[user]
|
||||||
return "", ok && (v == "" || password == v)
|
return user, ok && (v == "" || password == v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *authenticator) periodReload(ctx context.Context) error {
|
func (p *authenticator) periodReload(ctx context.Context) error {
|
||||||
@ -145,6 +145,8 @@ func (p *authenticator) reload(ctx context.Context) (err error) {
|
|||||||
kvs[k] = v
|
kvs[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.options.logger.Debugf("load items %d", len(m))
|
||||||
|
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
@ -206,7 +208,6 @@ func (p *authenticator) load(ctx context.Context) (m map[string]string, err erro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.options.logger.Debugf("load items %d", len(m))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
72
auth/plugin/grpc.go
Normal file
72
auth/plugin/grpc.go
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/go-gost/core/auth"
|
||||||
|
"github.com/go-gost/core/logger"
|
||||||
|
"github.com/go-gost/plugin/auth/proto"
|
||||||
|
ctxvalue "github.com/go-gost/x/ctx"
|
||||||
|
"github.com/go-gost/x/internal/plugin"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type grpcPlugin struct {
|
||||||
|
conn grpc.ClientConnInterface
|
||||||
|
client proto.AuthenticatorClient
|
||||||
|
log logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGRPCPlugin creates an Authenticator plugin based on gRPC.
|
||||||
|
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) auth.Authenticator {
|
||||||
|
var options plugin.Options
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
log := logger.Default().WithFields(map[string]any{
|
||||||
|
"kind": "auther",
|
||||||
|
"auther": name,
|
||||||
|
})
|
||||||
|
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p := &grpcPlugin{
|
||||||
|
conn: conn,
|
||||||
|
log: log,
|
||||||
|
}
|
||||||
|
|
||||||
|
if conn != nil {
|
||||||
|
p.client = proto.NewAuthenticatorClient(conn)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authenticate checks the validity of the provided user-password pair.
|
||||||
|
func (p *grpcPlugin) Authenticate(ctx context.Context, user, password string, opts ...auth.Option) (string, bool) {
|
||||||
|
if p.client == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := p.client.Authenticate(ctx,
|
||||||
|
&proto.AuthenticateRequest{
|
||||||
|
Username: user,
|
||||||
|
Password: password,
|
||||||
|
Client: string(ctxvalue.ClientAddrFromContext(ctx)),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
p.log.Error(err)
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return r.Id, r.Ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *grpcPlugin) Close() error {
|
||||||
|
if closer, ok := p.conn.(io.Closer); ok {
|
||||||
|
return closer.Close()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -4,76 +4,14 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/go-gost/core/auth"
|
"github.com/go-gost/core/auth"
|
||||||
"github.com/go-gost/core/logger"
|
"github.com/go-gost/core/logger"
|
||||||
"github.com/go-gost/plugin/auth/proto"
|
ctxvalue "github.com/go-gost/x/ctx"
|
||||||
"github.com/go-gost/x/internal/plugin"
|
"github.com/go-gost/x/internal/plugin"
|
||||||
auth_util "github.com/go-gost/x/internal/util/auth"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type grpcPlugin struct {
|
|
||||||
conn grpc.ClientConnInterface
|
|
||||||
client proto.AuthenticatorClient
|
|
||||||
log logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewGRPCPlugin creates an Authenticator plugin based on gRPC.
|
|
||||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) auth.Authenticator {
|
|
||||||
var options plugin.Options
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(&options)
|
|
||||||
}
|
|
||||||
|
|
||||||
log := logger.Default().WithFields(map[string]any{
|
|
||||||
"kind": "auther",
|
|
||||||
"auther": name,
|
|
||||||
})
|
|
||||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
p := &grpcPlugin{
|
|
||||||
conn: conn,
|
|
||||||
log: log,
|
|
||||||
}
|
|
||||||
|
|
||||||
if conn != nil {
|
|
||||||
p.client = proto.NewAuthenticatorClient(conn)
|
|
||||||
}
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Authenticate checks the validity of the provided user-password pair.
|
|
||||||
func (p *grpcPlugin) Authenticate(ctx context.Context, user, password string, opts ...auth.Option) (string, bool) {
|
|
||||||
if p.client == nil {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
r, err := p.client.Authenticate(ctx,
|
|
||||||
&proto.AuthenticateRequest{
|
|
||||||
Username: user,
|
|
||||||
Password: password,
|
|
||||||
Client: string(auth_util.ClientAddrFromContext(ctx)),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
p.log.Error(err)
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
return r.Id, r.Ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *grpcPlugin) Close() error {
|
|
||||||
if closer, ok := p.conn.(io.Closer); ok {
|
|
||||||
return closer.Close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type httpPluginRequest struct {
|
type httpPluginRequest struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
@ -118,7 +56,7 @@ func (p *httpPlugin) Authenticate(ctx context.Context, user, password string, op
|
|||||||
rb := httpPluginRequest{
|
rb := httpPluginRequest{
|
||||||
Username: user,
|
Username: user,
|
||||||
Password: password,
|
Password: password,
|
||||||
Client: string(auth_util.ClientAddrFromContext(ctx)),
|
Client: string(ctxvalue.ClientAddrFromContext(ctx)),
|
||||||
}
|
}
|
||||||
v, err := json.Marshal(&rb)
|
v, err := json.Marshal(&rb)
|
||||||
if err != nil {
|
if err != nil {
|
@ -130,6 +130,7 @@ func (bp *localBypass) reload(ctx context.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
patterns := append(bp.options.matchers, v...)
|
patterns := append(bp.options.matchers, v...)
|
||||||
|
bp.options.logger.Debugf("load items %d", len(patterns))
|
||||||
|
|
||||||
var addrs []string
|
var addrs []string
|
||||||
var inets []*net.IPNet
|
var inets []*net.IPNet
|
||||||
@ -205,7 +206,6 @@ func (bp *localBypass) load(ctx context.Context) (patterns []string, err error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bp.options.logger.Debugf("load items %d", len(patterns))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,11 +235,17 @@ func (bp *localBypass) Contains(ctx context.Context, network, addr string, opts
|
|||||||
b := !bp.options.whitelist && matched ||
|
b := !bp.options.whitelist && matched ||
|
||||||
bp.options.whitelist && !matched
|
bp.options.whitelist && !matched
|
||||||
if b {
|
if b {
|
||||||
bp.options.logger.Debugf("bypass: %s", addr)
|
bp.options.logger.Debugf("bypass: %s, whitelist: %t", addr, bp.options.whitelist)
|
||||||
|
} else {
|
||||||
|
bp.options.logger.Debugf("pass: %s, whitelist: %t", addr, bp.options.whitelist)
|
||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *localBypass) IsWhitelist() bool {
|
||||||
|
return p.options.whitelist
|
||||||
|
}
|
||||||
|
|
||||||
func (bp *localBypass) parseLine(s string) string {
|
func (bp *localBypass) parseLine(s string) string {
|
||||||
if n := strings.IndexByte(s, '#'); n >= 0 {
|
if n := strings.IndexByte(s, '#'); n >= 0 {
|
||||||
s = s[:n]
|
s = s[:n]
|
||||||
|
81
bypass/plugin/grpc.go
Normal file
81
bypass/plugin/grpc.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package bypass
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/go-gost/core/bypass"
|
||||||
|
"github.com/go-gost/core/logger"
|
||||||
|
"github.com/go-gost/plugin/bypass/proto"
|
||||||
|
ctxvalue "github.com/go-gost/x/ctx"
|
||||||
|
"github.com/go-gost/x/internal/plugin"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type grpcPlugin struct {
|
||||||
|
conn grpc.ClientConnInterface
|
||||||
|
client proto.BypassClient
|
||||||
|
log logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGRPCPlugin creates a Bypass plugin based on gRPC.
|
||||||
|
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) bypass.Bypass {
|
||||||
|
var options plugin.Options
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
log := logger.Default().WithFields(map[string]any{
|
||||||
|
"kind": "bypass",
|
||||||
|
"bypass": name,
|
||||||
|
})
|
||||||
|
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p := &grpcPlugin{
|
||||||
|
conn: conn,
|
||||||
|
log: log,
|
||||||
|
}
|
||||||
|
if conn != nil {
|
||||||
|
p.client = proto.NewBypassClient(conn)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *grpcPlugin) Contains(ctx context.Context, network, addr string, opts ...bypass.Option) bool {
|
||||||
|
if p.client == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
var options bypass.Options
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := p.client.Bypass(ctx,
|
||||||
|
&proto.BypassRequest{
|
||||||
|
Network: network,
|
||||||
|
Addr: addr,
|
||||||
|
Client: string(ctxvalue.ClientIDFromContext(ctx)),
|
||||||
|
Host: options.Host,
|
||||||
|
Path: options.Path,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
p.log.Error(err)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return r.Ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *grpcPlugin) Close() error {
|
||||||
|
if closer, ok := p.conn.(io.Closer); ok {
|
||||||
|
return closer.Close()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *grpcPlugin) IsWhitelist() bool {
|
||||||
|
return false
|
||||||
|
}
|
@ -4,81 +4,14 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/go-gost/core/bypass"
|
"github.com/go-gost/core/bypass"
|
||||||
"github.com/go-gost/core/logger"
|
"github.com/go-gost/core/logger"
|
||||||
"github.com/go-gost/plugin/bypass/proto"
|
ctxvalue "github.com/go-gost/x/ctx"
|
||||||
"github.com/go-gost/x/internal/plugin"
|
"github.com/go-gost/x/internal/plugin"
|
||||||
auth_util "github.com/go-gost/x/internal/util/auth"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type grpcPlugin struct {
|
|
||||||
conn grpc.ClientConnInterface
|
|
||||||
client proto.BypassClient
|
|
||||||
log logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewGRPCPlugin creates a Bypass plugin based on gRPC.
|
|
||||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) bypass.Bypass {
|
|
||||||
var options plugin.Options
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(&options)
|
|
||||||
}
|
|
||||||
|
|
||||||
log := logger.Default().WithFields(map[string]any{
|
|
||||||
"kind": "bypass",
|
|
||||||
"bypass": name,
|
|
||||||
})
|
|
||||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
p := &grpcPlugin{
|
|
||||||
conn: conn,
|
|
||||||
log: log,
|
|
||||||
}
|
|
||||||
if conn != nil {
|
|
||||||
p.client = proto.NewBypassClient(conn)
|
|
||||||
}
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *grpcPlugin) Contains(ctx context.Context, network, addr string, opts ...bypass.Option) bool {
|
|
||||||
if p.client == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
var options bypass.Options
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(&options)
|
|
||||||
}
|
|
||||||
|
|
||||||
r, err := p.client.Bypass(ctx,
|
|
||||||
&proto.BypassRequest{
|
|
||||||
Network: network,
|
|
||||||
Addr: addr,
|
|
||||||
Client: string(auth_util.IDFromContext(ctx)),
|
|
||||||
Host: options.Host,
|
|
||||||
Path: options.Path,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
p.log.Error(err)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return r.Ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *grpcPlugin) Close() error {
|
|
||||||
if closer, ok := p.conn.(io.Closer); ok {
|
|
||||||
return closer.Close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type httpPluginRequest struct {
|
type httpPluginRequest struct {
|
||||||
Network string `json:"network"`
|
Network string `json:"network"`
|
||||||
Addr string `json:"addr"`
|
Addr string `json:"addr"`
|
||||||
@ -129,7 +62,7 @@ func (p *httpPlugin) Contains(ctx context.Context, network, addr string, opts ..
|
|||||||
rb := httpPluginRequest{
|
rb := httpPluginRequest{
|
||||||
Network: network,
|
Network: network,
|
||||||
Addr: addr,
|
Addr: addr,
|
||||||
Client: string(auth_util.IDFromContext(ctx)),
|
Client: string(ctxvalue.ClientIDFromContext(ctx)),
|
||||||
Host: options.Host,
|
Host: options.Host,
|
||||||
Path: options.Path,
|
Path: options.Path,
|
||||||
}
|
}
|
||||||
@ -163,3 +96,7 @@ func (p *httpPlugin) Contains(ctx context.Context, network, addr string, opts ..
|
|||||||
}
|
}
|
||||||
return res.OK
|
return res.OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *httpPlugin) IsWhitelist() bool {
|
||||||
|
return false
|
||||||
|
}
|
@ -104,7 +104,7 @@ func (c *Chain) Route(ctx context.Context, network, address string, opts ...chai
|
|||||||
tr.Options().Route = rt
|
tr.Options().Route = rt
|
||||||
node = node.Copy()
|
node = node.Copy()
|
||||||
node.Options().Transport = tr
|
node.Options().Transport = tr
|
||||||
rt = NewRoute()
|
rt = NewRoute(ChainRouteOption(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.addNode(node)
|
rt.addNode(node)
|
||||||
|
114
chain/route.go
114
chain/route.go
@ -2,6 +2,8 @@ package chain
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -10,9 +12,86 @@ import (
|
|||||||
"github.com/go-gost/core/logger"
|
"github.com/go-gost/core/logger"
|
||||||
"github.com/go-gost/core/metrics"
|
"github.com/go-gost/core/metrics"
|
||||||
"github.com/go-gost/core/selector"
|
"github.com/go-gost/core/selector"
|
||||||
|
xnet "github.com/go-gost/x/internal/net"
|
||||||
|
"github.com/go-gost/x/internal/net/dialer"
|
||||||
|
"github.com/go-gost/x/internal/net/udp"
|
||||||
xmetrics "github.com/go-gost/x/metrics"
|
xmetrics "github.com/go-gost/x/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrEmptyRoute = errors.New("empty route")
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
DefaultRoute chain.Route = &defaultRoute{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// defaultRoute is a Route without nodes.
|
||||||
|
type defaultRoute struct{}
|
||||||
|
|
||||||
|
func (*defaultRoute) Dial(ctx context.Context, network, address string, opts ...chain.DialOption) (net.Conn, error) {
|
||||||
|
var options chain.DialOptions
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
netd := dialer.Dialer{
|
||||||
|
Interface: options.Interface,
|
||||||
|
Netns: options.Netns,
|
||||||
|
Logger: options.Logger,
|
||||||
|
}
|
||||||
|
if options.SockOpts != nil {
|
||||||
|
netd.Mark = options.SockOpts.Mark
|
||||||
|
}
|
||||||
|
|
||||||
|
return netd.Dial(ctx, network, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*defaultRoute) Bind(ctx context.Context, network, address string, opts ...chain.BindOption) (net.Listener, error) {
|
||||||
|
var options chain.BindOptions
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch network {
|
||||||
|
case "tcp", "tcp4", "tcp6":
|
||||||
|
addr, err := net.ResolveTCPAddr(network, address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return net.ListenTCP(network, addr)
|
||||||
|
case "udp", "udp4", "udp6":
|
||||||
|
addr, err := net.ResolveUDPAddr(network, address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conn, err := net.ListenUDP(network, addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
logger := logger.Default().WithFields(map[string]any{
|
||||||
|
"network": network,
|
||||||
|
"address": address,
|
||||||
|
})
|
||||||
|
ln := udp.NewListener(conn, &udp.ListenConfig{
|
||||||
|
Backlog: options.Backlog,
|
||||||
|
ReadQueueSize: options.UDPDataQueueSize,
|
||||||
|
ReadBufferSize: options.UDPDataBufferSize,
|
||||||
|
TTL: options.UDPConnTTL,
|
||||||
|
Keepalive: true,
|
||||||
|
Logger: logger,
|
||||||
|
})
|
||||||
|
return ln, err
|
||||||
|
default:
|
||||||
|
err := fmt.Errorf("network %s unsupported", network)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *defaultRoute) Nodes() []*chain.Node {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type RouteOptions struct {
|
type RouteOptions struct {
|
||||||
Chain chain.Chainer
|
Chain chain.Chainer
|
||||||
}
|
}
|
||||||
@ -25,12 +104,12 @@ func ChainRouteOption(c chain.Chainer) RouteOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type route struct {
|
type chainRoute struct {
|
||||||
nodes []*chain.Node
|
nodes []*chain.Node
|
||||||
options RouteOptions
|
options RouteOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRoute(opts ...RouteOption) *route {
|
func NewRoute(opts ...RouteOption) *chainRoute {
|
||||||
var options RouteOptions
|
var options RouteOptions
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
if opt != nil {
|
if opt != nil {
|
||||||
@ -38,18 +117,18 @@ func NewRoute(opts ...RouteOption) *route {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &route{
|
return &chainRoute{
|
||||||
options: options,
|
options: options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *route) addNode(nodes ...*chain.Node) {
|
func (r *chainRoute) addNode(nodes ...*chain.Node) {
|
||||||
r.nodes = append(r.nodes, nodes...)
|
r.nodes = append(r.nodes, nodes...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *route) Dial(ctx context.Context, network, address string, opts ...chain.DialOption) (net.Conn, error) {
|
func (r *chainRoute) Dial(ctx context.Context, network, address string, opts ...chain.DialOption) (net.Conn, error) {
|
||||||
if len(r.Nodes()) == 0 {
|
if len(r.Nodes()) == 0 {
|
||||||
return chain.DefaultRoute.Dial(ctx, network, address, opts...)
|
return DefaultRoute.Dial(ctx, network, address, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
var options chain.DialOptions
|
var options chain.DialOptions
|
||||||
@ -73,9 +152,9 @@ func (r *route) Dial(ctx context.Context, network, address string, opts ...chain
|
|||||||
return cc, nil
|
return cc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *route) Bind(ctx context.Context, network, address string, opts ...chain.BindOption) (net.Listener, error) {
|
func (r *chainRoute) Bind(ctx context.Context, network, address string, opts ...chain.BindOption) (net.Listener, error) {
|
||||||
if len(r.Nodes()) == 0 {
|
if len(r.Nodes()) == 0 {
|
||||||
return chain.DefaultRoute.Bind(ctx, network, address, opts...)
|
return DefaultRoute.Bind(ctx, network, address, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
var options chain.BindOptions
|
var options chain.BindOptions
|
||||||
@ -106,7 +185,7 @@ func (r *route) Bind(ctx context.Context, network, address string, opts ...chain
|
|||||||
return ln, nil
|
return ln, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *route) connect(ctx context.Context, logger logger.Logger) (conn net.Conn, err error) {
|
func (r *chainRoute) connect(ctx context.Context, logger logger.Logger) (conn net.Conn, err error) {
|
||||||
network := "ip"
|
network := "ip"
|
||||||
node := r.nodes[0]
|
node := r.nodes[0]
|
||||||
|
|
||||||
@ -129,15 +208,16 @@ func (r *route) connect(ctx context.Context, logger logger.Logger) (conn net.Con
|
|||||||
metrics.Labels{"chain": name, "node": node.Name}); v != nil {
|
metrics.Labels{"chain": name, "node": node.Name}); v != nil {
|
||||||
v.Inc()
|
v.Inc()
|
||||||
}
|
}
|
||||||
} else {
|
return
|
||||||
if marker != nil {
|
}
|
||||||
marker.Reset()
|
|
||||||
}
|
if marker != nil {
|
||||||
|
marker.Reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
addr, err := chain.Resolve(ctx, network, node.Addr, node.Options().Resolver, node.Options().HostMapper, logger)
|
addr, err := xnet.Resolve(ctx, network, node.Addr, node.Options().Resolver, node.Options().HostMapper, logger)
|
||||||
marker := node.Marker()
|
marker := node.Marker()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if marker != nil {
|
if marker != nil {
|
||||||
@ -181,7 +261,7 @@ func (r *route) connect(ctx context.Context, logger logger.Logger) (conn net.Con
|
|||||||
preNode := node
|
preNode := node
|
||||||
for _, node := range r.nodes[1:] {
|
for _, node := range r.nodes[1:] {
|
||||||
marker := node.Marker()
|
marker := node.Marker()
|
||||||
addr, err = chain.Resolve(ctx, network, node.Addr, node.Options().Resolver, node.Options().HostMapper, logger)
|
addr, err = xnet.Resolve(ctx, network, node.Addr, node.Options().Resolver, node.Options().HostMapper, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cn.Close()
|
cn.Close()
|
||||||
if marker != nil {
|
if marker != nil {
|
||||||
@ -217,14 +297,14 @@ func (r *route) connect(ctx context.Context, logger logger.Logger) (conn net.Con
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *route) getNode(index int) *chain.Node {
|
func (r *chainRoute) getNode(index int) *chain.Node {
|
||||||
if r == nil || len(r.Nodes()) == 0 || index < 0 || index >= len(r.Nodes()) {
|
if r == nil || len(r.Nodes()) == 0 || index < 0 || index >= len(r.Nodes()) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return r.nodes[index]
|
return r.nodes[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *route) Nodes() []*chain.Node {
|
func (r *chainRoute) Nodes() []*chain.Node {
|
||||||
if r != nil {
|
if r != nil {
|
||||||
return r.nodes
|
return r.nodes
|
||||||
}
|
}
|
||||||
|
207
chain/router.go
Normal file
207
chain/router.go
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
package chain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-gost/core/chain"
|
||||||
|
"github.com/go-gost/core/logger"
|
||||||
|
"github.com/go-gost/core/recorder"
|
||||||
|
xnet "github.com/go-gost/x/internal/net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Router struct {
|
||||||
|
options chain.RouterOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRouter(opts ...chain.RouterOption) *Router {
|
||||||
|
r := &Router{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
if opt != nil {
|
||||||
|
opt(&r.options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r.options.Timeout == 0 {
|
||||||
|
r.options.Timeout = 15 * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.options.Logger == nil {
|
||||||
|
r.options.Logger = logger.Default().WithFields(map[string]any{"kind": "router"})
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Router) Options() *chain.RouterOptions {
|
||||||
|
if r == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &r.options
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Router) Dial(ctx context.Context, network, address string) (conn net.Conn, err error) {
|
||||||
|
host := address
|
||||||
|
if h, _, _ := net.SplitHostPort(address); h != "" {
|
||||||
|
host = h
|
||||||
|
}
|
||||||
|
r.record(ctx, recorder.RecorderServiceRouterDialAddress, []byte(host))
|
||||||
|
|
||||||
|
conn, err = r.dial(ctx, network, address)
|
||||||
|
if err != nil {
|
||||||
|
r.record(ctx, recorder.RecorderServiceRouterDialAddressError, []byte(host))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if network == "udp" || network == "udp4" || network == "udp6" {
|
||||||
|
if _, ok := conn.(net.PacketConn); !ok {
|
||||||
|
return &packetConn{conn}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Router) record(ctx context.Context, name string, data []byte) error {
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rec := range r.options.Recorders {
|
||||||
|
if rec.Record == name {
|
||||||
|
err := rec.Recorder.Record(ctx, data)
|
||||||
|
if err != nil {
|
||||||
|
r.options.Logger.Errorf("record %s: %v", name, err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Router) dial(ctx context.Context, network, address string) (conn net.Conn, err error) {
|
||||||
|
count := r.options.Retries + 1
|
||||||
|
if count <= 0 {
|
||||||
|
count = 1
|
||||||
|
}
|
||||||
|
r.options.Logger.Debugf("dial %s/%s", address, network)
|
||||||
|
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
ctx := ctx
|
||||||
|
if r.options.Timeout > 0 {
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
ctx, cancel = context.WithTimeout(ctx, r.options.Timeout)
|
||||||
|
defer cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
var ipAddr string
|
||||||
|
ipAddr, err = xnet.Resolve(ctx, "ip", address, r.options.Resolver, r.options.HostMapper, r.options.Logger)
|
||||||
|
if err != nil {
|
||||||
|
r.options.Logger.Error(err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
var route chain.Route
|
||||||
|
if r.options.Chain != nil {
|
||||||
|
route = r.options.Chain.Route(ctx, network, ipAddr, chain.WithHostRouteOption(address))
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.options.Logger.IsLevelEnabled(logger.DebugLevel) {
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
for _, node := range routePath(route) {
|
||||||
|
fmt.Fprintf(&buf, "%s@%s > ", node.Name, node.Addr)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&buf, "%s", ipAddr)
|
||||||
|
r.options.Logger.Debugf("route(retry=%d) %s", i, buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if route == nil {
|
||||||
|
route = DefaultRoute
|
||||||
|
}
|
||||||
|
conn, err = route.Dial(ctx, network, ipAddr,
|
||||||
|
chain.InterfaceDialOption(r.options.IfceName),
|
||||||
|
chain.NetnsDialOption(r.options.Netns),
|
||||||
|
chain.SockOptsDialOption(r.options.SockOpts),
|
||||||
|
chain.LoggerDialOption(r.options.Logger),
|
||||||
|
)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
r.options.Logger.Errorf("route(retry=%d) %s", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Router) Bind(ctx context.Context, network, address string, opts ...chain.BindOption) (ln net.Listener, err error) {
|
||||||
|
count := r.options.Retries + 1
|
||||||
|
if count <= 0 {
|
||||||
|
count = 1
|
||||||
|
}
|
||||||
|
r.options.Logger.Debugf("bind on %s/%s", address, network)
|
||||||
|
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
ctx := ctx
|
||||||
|
if r.options.Timeout > 0 {
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
ctx, cancel = context.WithTimeout(ctx, r.options.Timeout)
|
||||||
|
defer cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
var route chain.Route
|
||||||
|
if r.options.Chain != nil {
|
||||||
|
route = r.options.Chain.Route(ctx, network, address)
|
||||||
|
if route == nil || len(route.Nodes()) == 0 {
|
||||||
|
err = ErrEmptyRoute
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.options.Logger.IsLevelEnabled(logger.DebugLevel) {
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
for _, node := range routePath(route) {
|
||||||
|
fmt.Fprintf(&buf, "%s@%s > ", node.Name, node.Addr)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&buf, "%s", address)
|
||||||
|
r.options.Logger.Debugf("route(retry=%d) %s", i, buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if route == nil {
|
||||||
|
route = DefaultRoute
|
||||||
|
}
|
||||||
|
ln, err = route.Bind(ctx, network, address, opts...)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
r.options.Logger.Errorf("route(retry=%d) %s", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func routePath(route chain.Route) (path []*chain.Node) {
|
||||||
|
if route == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, node := range route.Nodes() {
|
||||||
|
if tr := node.Options().Transport; tr != nil {
|
||||||
|
path = append(path, routePath(tr.Options().Route)...)
|
||||||
|
}
|
||||||
|
path = append(path, node)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type packetConn struct {
|
||||||
|
net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *packetConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
|
||||||
|
n, err = c.Read(b)
|
||||||
|
addr = c.Conn.RemoteAddr()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *packetConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
||||||
|
return c.Write(b)
|
||||||
|
}
|
106
chain/transport.go
Normal file
106
chain/transport.go
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
package chain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/go-gost/core/chain"
|
||||||
|
"github.com/go-gost/core/connector"
|
||||||
|
"github.com/go-gost/core/dialer"
|
||||||
|
net_dialer "github.com/go-gost/x/internal/net/dialer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Transport struct {
|
||||||
|
dialer dialer.Dialer
|
||||||
|
connector connector.Connector
|
||||||
|
options chain.TransportOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTransport(d dialer.Dialer, c connector.Connector, opts ...chain.TransportOption) *Transport {
|
||||||
|
tr := &Transport{
|
||||||
|
dialer: d,
|
||||||
|
connector: c,
|
||||||
|
}
|
||||||
|
for _, opt := range opts {
|
||||||
|
if opt != nil {
|
||||||
|
opt(&tr.options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr *Transport) Dial(ctx context.Context, addr string) (net.Conn, error) {
|
||||||
|
netd := &net_dialer.Dialer{
|
||||||
|
Interface: tr.options.IfceName,
|
||||||
|
Netns: tr.options.Netns,
|
||||||
|
}
|
||||||
|
if tr.options.SockOpts != nil {
|
||||||
|
netd.Mark = tr.options.SockOpts.Mark
|
||||||
|
}
|
||||||
|
if tr.options.Route != nil && len(tr.options.Route.Nodes()) > 0 {
|
||||||
|
netd.DialFunc = func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
return tr.options.Route.Dial(ctx, network, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
opts := []dialer.DialOption{
|
||||||
|
dialer.HostDialOption(tr.options.Addr),
|
||||||
|
dialer.NetDialerDialOption(netd),
|
||||||
|
}
|
||||||
|
return tr.dialer.Dial(ctx, addr, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr *Transport) Handshake(ctx context.Context, conn net.Conn) (net.Conn, error) {
|
||||||
|
var err error
|
||||||
|
if hs, ok := tr.dialer.(dialer.Handshaker); ok {
|
||||||
|
conn, err = hs.Handshake(ctx, conn,
|
||||||
|
dialer.AddrHandshakeOption(tr.options.Addr))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hs, ok := tr.connector.(connector.Handshaker); ok {
|
||||||
|
return hs.Handshake(ctx, conn)
|
||||||
|
}
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr *Transport) Connect(ctx context.Context, conn net.Conn, network, address string) (net.Conn, error) {
|
||||||
|
netd := &net_dialer.Dialer{
|
||||||
|
Interface: tr.options.IfceName,
|
||||||
|
Netns: tr.options.Netns,
|
||||||
|
}
|
||||||
|
if tr.options.SockOpts != nil {
|
||||||
|
netd.Mark = tr.options.SockOpts.Mark
|
||||||
|
}
|
||||||
|
return tr.connector.Connect(ctx, conn, network, address,
|
||||||
|
connector.DialerConnectOption(netd),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr *Transport) Bind(ctx context.Context, conn net.Conn, network, address string, opts ...connector.BindOption) (net.Listener, error) {
|
||||||
|
if binder, ok := tr.connector.(connector.Binder); ok {
|
||||||
|
return binder.Bind(ctx, conn, network, address, opts...)
|
||||||
|
}
|
||||||
|
return nil, connector.ErrBindUnsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr *Transport) Multiplex() bool {
|
||||||
|
if mux, ok := tr.dialer.(dialer.Multiplexer); ok {
|
||||||
|
return mux.Multiplex()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr *Transport) Options() *chain.TransportOptions {
|
||||||
|
if tr != nil {
|
||||||
|
return &tr.options
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr *Transport) Copy() chain.Transporter {
|
||||||
|
tr2 := &Transport{}
|
||||||
|
*tr2 = *tr
|
||||||
|
return tr
|
||||||
|
}
|
682
config/cmd/cmd.go
Normal file
682
config/cmd/cmd.go
Normal file
@ -0,0 +1,682 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
mdutil "github.com/go-gost/core/metadata/util"
|
||||||
|
"github.com/go-gost/x/config"
|
||||||
|
xnet "github.com/go-gost/x/internal/net"
|
||||||
|
"github.com/go-gost/x/limiter/conn"
|
||||||
|
"github.com/go-gost/x/limiter/traffic"
|
||||||
|
mdx "github.com/go-gost/x/metadata"
|
||||||
|
"github.com/go-gost/x/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidCmd = errors.New("invalid cmd")
|
||||||
|
ErrInvalidNode = errors.New("invalid node")
|
||||||
|
)
|
||||||
|
|
||||||
|
func BuildConfigFromCmd(serviceList, nodeList []string) (*config.Config, error) {
|
||||||
|
namePrefix := ""
|
||||||
|
cfg := &config.Config{}
|
||||||
|
|
||||||
|
var chain *config.ChainConfig
|
||||||
|
if len(nodeList) > 0 {
|
||||||
|
chain = &config.ChainConfig{
|
||||||
|
Name: fmt.Sprintf("%schain-0", namePrefix),
|
||||||
|
}
|
||||||
|
cfg.Chains = append(cfg.Chains, chain)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, node := range nodeList {
|
||||||
|
url, err := Norm(node)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeConfig, err := buildNodeConfig(url)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nodeConfig.Name = fmt.Sprintf("%snode-0", namePrefix)
|
||||||
|
|
||||||
|
var nodes []*config.NodeConfig
|
||||||
|
for _, host := range strings.Split(nodeConfig.Addr, ",") {
|
||||||
|
if host == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
nodeCfg := &config.NodeConfig{}
|
||||||
|
*nodeCfg = *nodeConfig
|
||||||
|
nodeCfg.Name = fmt.Sprintf("%snode-%d", namePrefix, len(nodes))
|
||||||
|
nodeCfg.Addr = host
|
||||||
|
nodes = append(nodes, nodeCfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
m := map[string]any{}
|
||||||
|
for k, v := range url.Query() {
|
||||||
|
if len(v) > 0 {
|
||||||
|
m[k] = v[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
md := mdx.NewMetadata(m)
|
||||||
|
|
||||||
|
hopConfig := &config.HopConfig{
|
||||||
|
Name: fmt.Sprintf("%shop-%d", namePrefix, i),
|
||||||
|
Selector: parseSelector(m),
|
||||||
|
Nodes: nodes,
|
||||||
|
Metadata: m,
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := mdutil.GetString(md, "bypass"); v != "" {
|
||||||
|
bypassCfg := &config.BypassConfig{
|
||||||
|
Name: fmt.Sprintf("%sbypass-%d", namePrefix, len(cfg.Bypasses)),
|
||||||
|
}
|
||||||
|
if v[0] == '~' {
|
||||||
|
bypassCfg.Whitelist = true
|
||||||
|
v = v[1:]
|
||||||
|
}
|
||||||
|
for _, s := range strings.Split(v, ",") {
|
||||||
|
if s == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
bypassCfg.Matchers = append(bypassCfg.Matchers, s)
|
||||||
|
}
|
||||||
|
hopConfig.Bypass = bypassCfg.Name
|
||||||
|
cfg.Bypasses = append(cfg.Bypasses, bypassCfg)
|
||||||
|
delete(m, "bypass")
|
||||||
|
}
|
||||||
|
if v := mdutil.GetString(md, "resolver"); v != "" {
|
||||||
|
resolverCfg := &config.ResolverConfig{
|
||||||
|
Name: fmt.Sprintf("%sresolver-%d", namePrefix, len(cfg.Resolvers)),
|
||||||
|
}
|
||||||
|
for _, rs := range strings.Split(v, ",") {
|
||||||
|
if rs == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
resolverCfg.Nameservers = append(
|
||||||
|
resolverCfg.Nameservers,
|
||||||
|
&config.NameserverConfig{
|
||||||
|
Addr: rs,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
hopConfig.Resolver = resolverCfg.Name
|
||||||
|
cfg.Resolvers = append(cfg.Resolvers, resolverCfg)
|
||||||
|
delete(m, "resolver")
|
||||||
|
}
|
||||||
|
if v := mdutil.GetString(md, "hosts"); v != "" {
|
||||||
|
hostsCfg := &config.HostsConfig{
|
||||||
|
Name: fmt.Sprintf("%shosts-%d", namePrefix, len(cfg.Hosts)),
|
||||||
|
}
|
||||||
|
for _, s := range strings.Split(v, ",") {
|
||||||
|
ss := strings.SplitN(s, ":", 2)
|
||||||
|
if len(ss) != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
hostsCfg.Mappings = append(
|
||||||
|
hostsCfg.Mappings,
|
||||||
|
&config.HostMappingConfig{
|
||||||
|
Hostname: ss[0],
|
||||||
|
IP: ss[1],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
hopConfig.Hosts = hostsCfg.Name
|
||||||
|
cfg.Hosts = append(cfg.Hosts, hostsCfg)
|
||||||
|
delete(m, "hosts")
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := mdutil.GetString(md, "interface"); v != "" {
|
||||||
|
hopConfig.Interface = v
|
||||||
|
delete(m, "interface")
|
||||||
|
}
|
||||||
|
if v := mdutil.GetInt(md, "so_mark"); v > 0 {
|
||||||
|
hopConfig.SockOpts = &config.SockOptsConfig{
|
||||||
|
Mark: v,
|
||||||
|
}
|
||||||
|
delete(m, "so_mark")
|
||||||
|
}
|
||||||
|
|
||||||
|
chain.Hops = append(chain.Hops, hopConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
var services []*config.ServiceConfig
|
||||||
|
for _, svc := range serviceList {
|
||||||
|
svc = strings.TrimSpace(svc)
|
||||||
|
if svc == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if svc[0] == ':' || !strings.Contains(svc, "://") {
|
||||||
|
svc = "auto://" + svc
|
||||||
|
}
|
||||||
|
|
||||||
|
host, svc := cutHost(svc)
|
||||||
|
|
||||||
|
url, err := Norm(svc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
url.Host = host
|
||||||
|
|
||||||
|
svcs, err := buildServiceConfig(url)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
services = append(services, svcs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, service := range services {
|
||||||
|
service.Name = fmt.Sprintf("%sservice-%d", namePrefix, i)
|
||||||
|
if chain != nil {
|
||||||
|
if service.Listener.Type == "rtcp" || service.Listener.Type == "rudp" {
|
||||||
|
service.Listener.Chain = chain.Name
|
||||||
|
} else {
|
||||||
|
service.Handler.Chain = chain.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cfg.Services = append(cfg.Services, service)
|
||||||
|
|
||||||
|
mh := service.Handler.Metadata
|
||||||
|
md := mdx.NewMetadata(mh)
|
||||||
|
if v := mdutil.GetInt(md, "retries"); v > 0 {
|
||||||
|
service.Handler.Retries = v
|
||||||
|
delete(mh, "retries")
|
||||||
|
}
|
||||||
|
if v := mdutil.GetString(md, "admission"); v != "" {
|
||||||
|
admCfg := &config.AdmissionConfig{
|
||||||
|
Name: fmt.Sprintf("%sadmission-%d", namePrefix, len(cfg.Admissions)),
|
||||||
|
}
|
||||||
|
if v[0] == '~' {
|
||||||
|
admCfg.Whitelist = true
|
||||||
|
v = v[1:]
|
||||||
|
}
|
||||||
|
for _, s := range strings.Split(v, ",") {
|
||||||
|
if s == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
admCfg.Matchers = append(admCfg.Matchers, s)
|
||||||
|
}
|
||||||
|
service.Admission = admCfg.Name
|
||||||
|
cfg.Admissions = append(cfg.Admissions, admCfg)
|
||||||
|
delete(mh, "admission")
|
||||||
|
}
|
||||||
|
if v := mdutil.GetString(md, "bypass"); v != "" {
|
||||||
|
bypassCfg := &config.BypassConfig{
|
||||||
|
Name: fmt.Sprintf("%sbypass-%d", namePrefix, len(cfg.Bypasses)),
|
||||||
|
}
|
||||||
|
if v[0] == '~' {
|
||||||
|
bypassCfg.Whitelist = true
|
||||||
|
v = v[1:]
|
||||||
|
}
|
||||||
|
for _, s := range strings.Split(v, ",") {
|
||||||
|
if s == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
bypassCfg.Matchers = append(bypassCfg.Matchers, s)
|
||||||
|
}
|
||||||
|
service.Bypass = bypassCfg.Name
|
||||||
|
cfg.Bypasses = append(cfg.Bypasses, bypassCfg)
|
||||||
|
delete(mh, "bypass")
|
||||||
|
}
|
||||||
|
if v := mdutil.GetString(md, "resolver"); v != "" {
|
||||||
|
resolverCfg := &config.ResolverConfig{
|
||||||
|
Name: fmt.Sprintf("%sresolver-%d", namePrefix, len(cfg.Resolvers)),
|
||||||
|
}
|
||||||
|
for _, rs := range strings.Split(v, ",") {
|
||||||
|
if rs == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
resolverCfg.Nameservers = append(
|
||||||
|
resolverCfg.Nameservers,
|
||||||
|
&config.NameserverConfig{
|
||||||
|
Addr: rs,
|
||||||
|
Prefer: mdutil.GetString(md, "prefer"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
service.Resolver = resolverCfg.Name
|
||||||
|
cfg.Resolvers = append(cfg.Resolvers, resolverCfg)
|
||||||
|
delete(mh, "resolver")
|
||||||
|
}
|
||||||
|
if v := mdutil.GetString(md, "hosts"); v != "" {
|
||||||
|
hostsCfg := &config.HostsConfig{
|
||||||
|
Name: fmt.Sprintf("%shosts-%d", namePrefix, len(cfg.Hosts)),
|
||||||
|
}
|
||||||
|
for _, s := range strings.Split(v, ",") {
|
||||||
|
ss := strings.SplitN(s, ":", 2)
|
||||||
|
if len(ss) != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
hostsCfg.Mappings = append(
|
||||||
|
hostsCfg.Mappings,
|
||||||
|
&config.HostMappingConfig{
|
||||||
|
Hostname: ss[0],
|
||||||
|
IP: ss[1],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
service.Hosts = hostsCfg.Name
|
||||||
|
cfg.Hosts = append(cfg.Hosts, hostsCfg)
|
||||||
|
delete(mh, "hosts")
|
||||||
|
}
|
||||||
|
|
||||||
|
in := mdutil.GetString(md, "limiter.in")
|
||||||
|
out := mdutil.GetString(md, "limiter.out")
|
||||||
|
cin := mdutil.GetString(md, "limiter.conn.in")
|
||||||
|
cout := mdutil.GetString(md, "limiter.conn.out")
|
||||||
|
if in != "" || cin != "" || out != "" || cout != "" {
|
||||||
|
limiter := &config.LimiterConfig{
|
||||||
|
Name: fmt.Sprintf("%slimiter-%d", namePrefix, len(cfg.Limiters)),
|
||||||
|
}
|
||||||
|
if in != "" || out != "" {
|
||||||
|
limiter.Limits = append(limiter.Limits,
|
||||||
|
fmt.Sprintf("%s %s %s", traffic.GlobalLimitKey, in, out))
|
||||||
|
}
|
||||||
|
if cin != "" || cout != "" {
|
||||||
|
limiter.Limits = append(limiter.Limits,
|
||||||
|
fmt.Sprintf("%s %s %s", traffic.ConnLimitKey, cin, cout))
|
||||||
|
}
|
||||||
|
service.Limiter = limiter.Name
|
||||||
|
cfg.Limiters = append(cfg.Limiters, limiter)
|
||||||
|
delete(mh, "limiter.in")
|
||||||
|
delete(mh, "limiter.out")
|
||||||
|
delete(mh, "limiter.conn.in")
|
||||||
|
delete(mh, "limiter.conn.out")
|
||||||
|
}
|
||||||
|
|
||||||
|
if climit := mdutil.GetInt(md, "climiter"); climit > 0 {
|
||||||
|
limiter := &config.LimiterConfig{
|
||||||
|
Name: fmt.Sprintf("%sclimiter-%d", namePrefix, len(cfg.CLimiters)),
|
||||||
|
Limits: []string{fmt.Sprintf("%s %d", conn.GlobalLimitKey, climit)},
|
||||||
|
}
|
||||||
|
service.CLimiter = limiter.Name
|
||||||
|
cfg.CLimiters = append(cfg.CLimiters, limiter)
|
||||||
|
delete(mh, "climiter")
|
||||||
|
}
|
||||||
|
|
||||||
|
if rlimit := mdutil.GetFloat(md, "rlimiter"); rlimit > 0 {
|
||||||
|
limiter := &config.LimiterConfig{
|
||||||
|
Name: fmt.Sprintf("%srlimiter-%d", namePrefix, len(cfg.RLimiters)),
|
||||||
|
Limits: []string{fmt.Sprintf("%s %s", conn.GlobalLimitKey, strconv.FormatFloat(rlimit, 'f', -1, 64))},
|
||||||
|
}
|
||||||
|
service.RLimiter = limiter.Name
|
||||||
|
cfg.RLimiters = append(cfg.RLimiters, limiter)
|
||||||
|
delete(mh, "rlimiter")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func cutHost(s string) (host, remain string) {
|
||||||
|
if s == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
n := strings.IndexByte(s, ':')
|
||||||
|
start := n + 3
|
||||||
|
end := strings.IndexAny(s[start:], "/?")
|
||||||
|
if end < 0 {
|
||||||
|
end = len(s)
|
||||||
|
} else {
|
||||||
|
end += start
|
||||||
|
}
|
||||||
|
// auth info
|
||||||
|
if n = strings.LastIndexByte(s[start:end], '@'); n >= 0 {
|
||||||
|
start += (n + 1)
|
||||||
|
}
|
||||||
|
host = s[start:end]
|
||||||
|
|
||||||
|
remain = s[:start] + s[end:]
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildServiceConfig(url *url.URL) ([]*config.ServiceConfig, error) {
|
||||||
|
namePrefix := ""
|
||||||
|
if v := os.Getenv("_GOST_ID"); v != "" {
|
||||||
|
namePrefix = fmt.Sprintf("go-%s@", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
var handler, listener string
|
||||||
|
schemes := strings.Split(url.Scheme, "+")
|
||||||
|
if len(schemes) == 1 {
|
||||||
|
handler = schemes[0]
|
||||||
|
listener = schemes[0]
|
||||||
|
}
|
||||||
|
if len(schemes) == 2 {
|
||||||
|
handler = schemes[0]
|
||||||
|
listener = schemes[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs := xnet.AddrPortRange(url.Host).Addrs()
|
||||||
|
if len(addrs) == 0 {
|
||||||
|
addrs = append(addrs, url.Host)
|
||||||
|
}
|
||||||
|
|
||||||
|
var services []*config.ServiceConfig
|
||||||
|
for _, addr := range addrs {
|
||||||
|
services = append(services, &config.ServiceConfig{
|
||||||
|
Addr: addr,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if h := registry.HandlerRegistry().Get(handler); h == nil {
|
||||||
|
handler = "auto"
|
||||||
|
}
|
||||||
|
if ln := registry.ListenerRegistry().Get(listener); ln == nil {
|
||||||
|
listener = "tcp"
|
||||||
|
if handler == "ssu" {
|
||||||
|
listener = "udp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var nodes []*config.ForwardNodeConfig
|
||||||
|
// forward mode
|
||||||
|
if remotes := strings.Trim(url.EscapedPath(), "/"); remotes != "" {
|
||||||
|
i := 0
|
||||||
|
for _, addr := range strings.Split(remotes, ",") {
|
||||||
|
addrs := xnet.AddrPortRange(addr).Addrs()
|
||||||
|
if len(addrs) == 0 {
|
||||||
|
addrs = append(addrs, addr)
|
||||||
|
}
|
||||||
|
for _, adr := range addrs {
|
||||||
|
nodes = append(nodes, &config.ForwardNodeConfig{
|
||||||
|
Name: fmt.Sprintf("%starget-%d", namePrefix, i),
|
||||||
|
Addr: adr,
|
||||||
|
})
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if handler != "relay" {
|
||||||
|
if listener == "tcp" || listener == "udp" ||
|
||||||
|
listener == "rtcp" || listener == "rudp" ||
|
||||||
|
listener == "tun" || listener == "tap" ||
|
||||||
|
listener == "dns" || listener == "unix" ||
|
||||||
|
listener == "serial" {
|
||||||
|
handler = listener
|
||||||
|
} else {
|
||||||
|
handler = "forward"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(nodes) > 0 {
|
||||||
|
if len(services) == 1 {
|
||||||
|
services[0].Forwarder = &config.ForwarderConfig{
|
||||||
|
Nodes: nodes,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i, svc := range services {
|
||||||
|
if len(nodes) == 1 {
|
||||||
|
svc.Forwarder = &config.ForwarderConfig{
|
||||||
|
Nodes: nodes,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if i < len(nodes) {
|
||||||
|
svc.Forwarder = &config.ForwarderConfig{
|
||||||
|
Nodes: []*config.ForwardNodeConfig{nodes[i]},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var auth *config.AuthConfig
|
||||||
|
if url.User != nil {
|
||||||
|
auth = &config.AuthConfig{
|
||||||
|
Username: url.User.Username(),
|
||||||
|
}
|
||||||
|
auth.Password, _ = url.User.Password()
|
||||||
|
}
|
||||||
|
|
||||||
|
m := map[string]any{}
|
||||||
|
for k, v := range url.Query() {
|
||||||
|
if len(v) > 0 {
|
||||||
|
m[k] = v[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
md := mdx.NewMetadata(m)
|
||||||
|
|
||||||
|
if sa := mdutil.GetString(md, "auth"); sa != "" {
|
||||||
|
au, err := parseAuthFromCmd(sa)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
auth = au
|
||||||
|
}
|
||||||
|
delete(m, "auth")
|
||||||
|
|
||||||
|
tlsConfig := &config.TLSConfig{
|
||||||
|
CertFile: mdutil.GetString(md, "tls.certFile", "certFile", "cert"),
|
||||||
|
KeyFile: mdutil.GetString(md, "tls.keyFile", "keyFile", "key"),
|
||||||
|
CAFile: mdutil.GetString(md, "tls.caFile", "caFile", "ca"),
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(m, "tls.certFile")
|
||||||
|
delete(m, "certFile")
|
||||||
|
delete(m, "cert")
|
||||||
|
delete(m, "tls.keyFile")
|
||||||
|
delete(m, "keyFile")
|
||||||
|
delete(m, "key")
|
||||||
|
delete(m, "tls.caFile")
|
||||||
|
delete(m, "caFile")
|
||||||
|
delete(m, "ca")
|
||||||
|
|
||||||
|
if tlsConfig.CertFile == "" {
|
||||||
|
tlsConfig = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := mdutil.GetString(md, "dns"); v != "" {
|
||||||
|
md.Set("dns", strings.Split(v, ","))
|
||||||
|
}
|
||||||
|
|
||||||
|
selector := parseSelector(m)
|
||||||
|
handlerCfg := &config.HandlerConfig{
|
||||||
|
Type: handler,
|
||||||
|
Auth: auth,
|
||||||
|
Metadata: m,
|
||||||
|
}
|
||||||
|
listenerCfg := &config.ListenerConfig{
|
||||||
|
Type: listener,
|
||||||
|
TLS: tlsConfig,
|
||||||
|
Metadata: m,
|
||||||
|
}
|
||||||
|
if listenerCfg.Type == "ssh" || listenerCfg.Type == "sshd" {
|
||||||
|
handlerCfg.Auth = nil
|
||||||
|
listenerCfg.Auth = auth
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, svc := range services {
|
||||||
|
if svc.Forwarder != nil {
|
||||||
|
svc.Forwarder.Selector = selector
|
||||||
|
}
|
||||||
|
svc.Handler = handlerCfg
|
||||||
|
svc.Listener = listenerCfg
|
||||||
|
svc.Metadata = m
|
||||||
|
}
|
||||||
|
|
||||||
|
return services, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildNodeConfig(url *url.URL) (*config.NodeConfig, error) {
|
||||||
|
var connector, dialer string
|
||||||
|
schemes := strings.Split(url.Scheme, "+")
|
||||||
|
if len(schemes) == 1 {
|
||||||
|
connector = schemes[0]
|
||||||
|
dialer = schemes[0]
|
||||||
|
}
|
||||||
|
if len(schemes) == 2 {
|
||||||
|
connector = schemes[0]
|
||||||
|
dialer = schemes[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
m := map[string]any{}
|
||||||
|
for k, v := range url.Query() {
|
||||||
|
if len(v) > 0 {
|
||||||
|
m[k] = v[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
md := mdx.NewMetadata(m)
|
||||||
|
|
||||||
|
node := &config.NodeConfig{
|
||||||
|
Addr: url.Host,
|
||||||
|
Metadata: m,
|
||||||
|
}
|
||||||
|
|
||||||
|
if c := registry.ConnectorRegistry().Get(connector); c == nil {
|
||||||
|
connector = "http"
|
||||||
|
}
|
||||||
|
if d := registry.DialerRegistry().Get(dialer); d == nil {
|
||||||
|
dialer = "tcp"
|
||||||
|
if connector == "ssu" {
|
||||||
|
dialer = "udp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var auth *config.AuthConfig
|
||||||
|
if url.User != nil {
|
||||||
|
auth = &config.AuthConfig{
|
||||||
|
Username: url.User.Username(),
|
||||||
|
}
|
||||||
|
auth.Password, _ = url.User.Password()
|
||||||
|
}
|
||||||
|
|
||||||
|
if sauth := mdutil.GetString(md, "auth"); sauth != "" && auth == nil {
|
||||||
|
au, err := parseAuthFromCmd(sauth)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
auth = au
|
||||||
|
}
|
||||||
|
delete(m, "auth")
|
||||||
|
|
||||||
|
tlsConfig := &config.TLSConfig{
|
||||||
|
CertFile: mdutil.GetString(md, "tls.certFile", "certFile", "cert"),
|
||||||
|
KeyFile: mdutil.GetString(md, "tls.keyFile", "keyFile", "key"),
|
||||||
|
CAFile: mdutil.GetString(md, "tls.caFile", "caFile", "ca"),
|
||||||
|
Secure: mdutil.GetBool(md, "tls.secure", "secure"),
|
||||||
|
ServerName: mdutil.GetString(md, "tls.servername", "servername"),
|
||||||
|
}
|
||||||
|
if tlsConfig.ServerName == "" {
|
||||||
|
tlsConfig.ServerName = url.Hostname()
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(m, "tls.certFile")
|
||||||
|
delete(m, "certFile")
|
||||||
|
delete(m, "cert")
|
||||||
|
delete(m, "tls.keyFile")
|
||||||
|
delete(m, "keyFile")
|
||||||
|
delete(m, "key")
|
||||||
|
delete(m, "tls.caFile")
|
||||||
|
delete(m, "caFile")
|
||||||
|
delete(m, "ca")
|
||||||
|
delete(m, "tls.secure")
|
||||||
|
delete(m, "secure")
|
||||||
|
delete(m, "tls.servername")
|
||||||
|
delete(m, "serverName")
|
||||||
|
|
||||||
|
if !tlsConfig.Secure && tlsConfig.CertFile == "" && tlsConfig.CAFile == "" && tlsConfig.ServerName == "" {
|
||||||
|
tlsConfig = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
node.Connector = &config.ConnectorConfig{
|
||||||
|
Type: connector,
|
||||||
|
Auth: auth,
|
||||||
|
Metadata: m,
|
||||||
|
}
|
||||||
|
node.Dialer = &config.DialerConfig{
|
||||||
|
Type: dialer,
|
||||||
|
TLS: tlsConfig,
|
||||||
|
Metadata: m,
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.Dialer.Type == "ssh" || node.Dialer.Type == "sshd" {
|
||||||
|
node.Connector.Auth = nil
|
||||||
|
node.Dialer.Auth = auth
|
||||||
|
}
|
||||||
|
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Norm(s string) (*url.URL, error) {
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
if s == "" {
|
||||||
|
return nil, ErrInvalidCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
if s[0] == ':' || !strings.Contains(s, "://") {
|
||||||
|
s = "auto://" + s
|
||||||
|
}
|
||||||
|
|
||||||
|
url, err := url.Parse(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if url.Scheme == "https" {
|
||||||
|
url.Scheme = "http+tls"
|
||||||
|
}
|
||||||
|
|
||||||
|
return url, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseAuthFromCmd(sa string) (*config.AuthConfig, error) {
|
||||||
|
v, err := base64.StdEncoding.DecodeString(sa)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cs := string(v)
|
||||||
|
n := strings.IndexByte(cs, ':')
|
||||||
|
if n < 0 {
|
||||||
|
return &config.AuthConfig{
|
||||||
|
Username: cs,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &config.AuthConfig{
|
||||||
|
Username: cs[:n],
|
||||||
|
Password: cs[n+1:],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseSelector(m map[string]any) *config.SelectorConfig {
|
||||||
|
md := mdx.NewMetadata(m)
|
||||||
|
strategy := mdutil.GetString(md, "strategy")
|
||||||
|
maxFails := mdutil.GetInt(md, "maxFails", "max_fails")
|
||||||
|
failTimeout := mdutil.GetDuration(md, "failTimeout", "fail_timeout")
|
||||||
|
if strategy == "" && maxFails <= 0 && failTimeout <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if strategy == "" {
|
||||||
|
strategy = "round"
|
||||||
|
}
|
||||||
|
if maxFails <= 0 {
|
||||||
|
maxFails = 1
|
||||||
|
}
|
||||||
|
if failTimeout <= 0 {
|
||||||
|
failTimeout = 30 * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(m, "strategy")
|
||||||
|
delete(m, "maxFails")
|
||||||
|
delete(m, "max_fails")
|
||||||
|
delete(m, "failTimeout")
|
||||||
|
delete(m, "fail_timeout")
|
||||||
|
|
||||||
|
return &config.SelectorConfig{
|
||||||
|
Strategy: strategy,
|
||||||
|
MaxFails: maxFails,
|
||||||
|
FailTimeout: failTimeout,
|
||||||
|
}
|
||||||
|
}
|
159
config/config.go
159
config/config.go
@ -79,6 +79,11 @@ type LogRotationConfig struct {
|
|||||||
Compress bool `yaml:"compress,omitempty" json:"compress,omitempty"`
|
Compress bool `yaml:"compress,omitempty" json:"compress,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LoggerConfig struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Log *LogConfig `yaml:",omitempty" json:"log,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type ProfilingConfig struct {
|
type ProfilingConfig struct {
|
||||||
Addr string `json:"addr"`
|
Addr string `json:"addr"`
|
||||||
}
|
}
|
||||||
@ -244,6 +249,21 @@ type SDConfig struct {
|
|||||||
Plugin *PluginConfig `yaml:",omitempty" json:"plugin,omitempty"`
|
Plugin *PluginConfig `yaml:",omitempty" json:"plugin,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RouterRouteConfig struct {
|
||||||
|
Net string `json:"net"`
|
||||||
|
Gateway string `json:"gateway"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RouterConfig struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Routes []*RouterRouteConfig `yaml:",omitempty" json:"routes,omitempty"`
|
||||||
|
Reload time.Duration `yaml:",omitempty" json:"reload,omitempty"`
|
||||||
|
File *FileLoader `yaml:",omitempty" json:"file,omitempty"`
|
||||||
|
Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"`
|
||||||
|
HTTP *HTTPLoader `yaml:"http,omitempty" json:"http,omitempty"`
|
||||||
|
Plugin *PluginConfig `yaml:",omitempty" json:"plugin,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
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"`
|
||||||
@ -277,9 +297,9 @@ 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
|
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LimiterConfig struct {
|
type LimiterConfig struct {
|
||||||
@ -289,6 +309,12 @@ type LimiterConfig struct {
|
|||||||
File *FileLoader `yaml:",omitempty" json:"file,omitempty"`
|
File *FileLoader `yaml:",omitempty" json:"file,omitempty"`
|
||||||
Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"`
|
Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"`
|
||||||
HTTP *HTTPLoader `yaml:"http,omitempty" json:"http,omitempty"`
|
HTTP *HTTPLoader `yaml:"http,omitempty" json:"http,omitempty"`
|
||||||
|
Plugin *PluginConfig `yaml:",omitempty" json:"plugin,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ObserverConfig struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Plugin *PluginConfig `yaml:",omitempty" json:"plugin,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListenerConfig struct {
|
type ListenerConfig struct {
|
||||||
@ -311,33 +337,69 @@ type HandlerConfig struct {
|
|||||||
Authers []string `yaml:",omitempty" json:"authers,omitempty"`
|
Authers []string `yaml:",omitempty" json:"authers,omitempty"`
|
||||||
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
||||||
TLS *TLSConfig `yaml:",omitempty" json:"tls,omitempty"`
|
TLS *TLSConfig `yaml:",omitempty" json:"tls,omitempty"`
|
||||||
Ingress string `yaml:",omitempty" json:"ingress,omitempty"`
|
Limiter string `yaml:",omitempty" json:"limiter,omitempty"`
|
||||||
|
Observer string `yaml:",omitempty" json:"observer,omitempty"`
|
||||||
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ForwarderConfig struct {
|
type ForwarderConfig struct {
|
||||||
Name string `yaml:",omitempty" json:"name,omitempty"`
|
// DEPRECATED by hop field
|
||||||
|
Name string `yaml:",omitempty" json:"name,omitempty"`
|
||||||
|
// the referenced hop name
|
||||||
|
Hop string `yaml:",omitempty" json:"hop,omitempty"`
|
||||||
Selector *SelectorConfig `yaml:",omitempty" json:"selector,omitempty"`
|
Selector *SelectorConfig `yaml:",omitempty" json:"selector,omitempty"`
|
||||||
Nodes []*ForwardNodeConfig `json:"nodes"`
|
Nodes []*ForwardNodeConfig `json:"nodes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ForwardNodeConfig struct {
|
type ForwardNodeConfig struct {
|
||||||
Name string `yaml:",omitempty" json:"name,omitempty"`
|
Name string `yaml:",omitempty" json:"name,omitempty"`
|
||||||
Addr string `yaml:",omitempty" json:"addr,omitempty"`
|
Addr string `yaml:",omitempty" json:"addr,omitempty"`
|
||||||
Host string `yaml:",omitempty" json:"host,omitempty"`
|
Network string `yaml:",omitempty" json:"network,omitempty"`
|
||||||
Network string `yaml:",omitempty" json:"network,omitempty"`
|
Bypass string `yaml:",omitempty" json:"bypass,omitempty"`
|
||||||
Protocol string `yaml:",omitempty" json:"protocol,omitempty"`
|
Bypasses []string `yaml:",omitempty" json:"bypasses,omitempty"`
|
||||||
Path string `yaml:",omitempty" json:"path,omitempty"`
|
// DEPRECATED by filter.protocol
|
||||||
Bypass string `yaml:",omitempty" json:"bypass,omitempty"`
|
Protocol string `yaml:",omitempty" json:"protocol,omitempty"`
|
||||||
Bypasses []string `yaml:",omitempty" json:"bypasses,omitempty"`
|
// DEPRECATED by filter.host
|
||||||
HTTP *HTTPNodeConfig `yaml:",omitempty" json:"http,omitempty"`
|
Host string `yaml:",omitempty" json:"host,omitempty"`
|
||||||
TLS *TLSNodeConfig `yaml:",omitempty" json:"tls,omitempty"`
|
// DEPRECATED by filter.path
|
||||||
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
Path string `yaml:",omitempty" json:"path,omitempty"`
|
||||||
|
// DEPRECATED by http.auth
|
||||||
|
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
||||||
|
Filter *NodeFilterConfig `yaml:",omitempty" json:"filter,omitempty"`
|
||||||
|
HTTP *HTTPNodeConfig `yaml:",omitempty" json:"http,omitempty"`
|
||||||
|
TLS *TLSNodeConfig `yaml:",omitempty" json:"tls,omitempty"`
|
||||||
|
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HTTPURLRewriteConfig struct {
|
||||||
|
Match string
|
||||||
|
Replacement string
|
||||||
|
}
|
||||||
|
|
||||||
|
type HTTPBodyRewriteConfig struct {
|
||||||
|
// filter by MIME types
|
||||||
|
Type string
|
||||||
|
Match string
|
||||||
|
Replacement string
|
||||||
|
}
|
||||||
|
|
||||||
|
type NodeFilterConfig struct {
|
||||||
|
Host string `yaml:",omitempty" json:"host,omitempty"`
|
||||||
|
Protocol string `yaml:",omitempty" json:"protocol,omitempty"`
|
||||||
|
Path string `yaml:",omitempty" json:"path,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type HTTPNodeConfig struct {
|
type HTTPNodeConfig struct {
|
||||||
Host string `yaml:",omitempty" json:"host,omitempty"`
|
// rewrite host header
|
||||||
|
Host string `yaml:",omitempty" json:"host,omitempty"`
|
||||||
|
// additional request header
|
||||||
Header map[string]string `yaml:",omitempty" json:"header,omitempty"`
|
Header map[string]string `yaml:",omitempty" json:"header,omitempty"`
|
||||||
|
// rewrite URL
|
||||||
|
Rewrite []HTTPURLRewriteConfig `yaml:",omitempty" json:"rewrite,omitempty"`
|
||||||
|
// rewrite response body
|
||||||
|
RewriteBody []HTTPBodyRewriteConfig `yaml:"rewriteBody,omitempty" json:"rewriteBody,omitempty"`
|
||||||
|
// HTTP basic auth
|
||||||
|
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TLSNodeConfig struct {
|
type TLSNodeConfig struct {
|
||||||
@ -380,11 +442,36 @@ type ServiceConfig struct {
|
|||||||
Limiter string `yaml:",omitempty" json:"limiter,omitempty"`
|
Limiter string `yaml:",omitempty" json:"limiter,omitempty"`
|
||||||
CLimiter string `yaml:"climiter,omitempty" json:"climiter,omitempty"`
|
CLimiter string `yaml:"climiter,omitempty" json:"climiter,omitempty"`
|
||||||
RLimiter string `yaml:"rlimiter,omitempty" json:"rlimiter,omitempty"`
|
RLimiter string `yaml:"rlimiter,omitempty" json:"rlimiter,omitempty"`
|
||||||
|
Logger string `yaml:",omitempty" json:"logger,omitempty"`
|
||||||
|
Loggers []string `yaml:",omitempty" json:"loggers,omitempty"`
|
||||||
|
Observer string `yaml:",omitempty" json:"observer,omitempty"`
|
||||||
Recorders []*RecorderObject `yaml:",omitempty" json:"recorders,omitempty"`
|
Recorders []*RecorderObject `yaml:",omitempty" json:"recorders,omitempty"`
|
||||||
Handler *HandlerConfig `yaml:",omitempty" json:"handler,omitempty"`
|
Handler *HandlerConfig `yaml:",omitempty" json:"handler,omitempty"`
|
||||||
Listener *ListenerConfig `yaml:",omitempty" json:"listener,omitempty"`
|
Listener *ListenerConfig `yaml:",omitempty" json:"listener,omitempty"`
|
||||||
Forwarder *ForwarderConfig `yaml:",omitempty" json:"forwarder,omitempty"`
|
Forwarder *ForwarderConfig `yaml:",omitempty" json:"forwarder,omitempty"`
|
||||||
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
||||||
|
// service status, read-only
|
||||||
|
Status *ServiceStatus `yaml:",omitempty" json:"status,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceStatus struct {
|
||||||
|
CreateTime int64 `yaml:"createTime" json:"createTime"`
|
||||||
|
State string `yaml:"state" json:"state"`
|
||||||
|
Events []ServiceEvent `yaml:",omitempty" json:"events,omitempty"`
|
||||||
|
Stats *ServiceStats `yaml:",omitempty" json:"stats,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceEvent struct {
|
||||||
|
Time int64 `yaml:"time" json:"time"`
|
||||||
|
Msg string `yaml:"msg" json:"msg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceStats struct {
|
||||||
|
TotalConns uint64 `yaml:"totalConns" json:"totalConns"`
|
||||||
|
CurrentConns uint64 `yaml:"currentConns" json:"currentConns"`
|
||||||
|
TotalErrs uint64 `yaml:"totalErrs" json:"totalErrs"`
|
||||||
|
InputBytes uint64 `yaml:"inputBytes" json:"inputBytes"`
|
||||||
|
OutputBytes uint64 `yaml:"outputBytes" json:"outputBytes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChainConfig struct {
|
type ChainConfig struct {
|
||||||
@ -413,27 +500,26 @@ type HopConfig struct {
|
|||||||
Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"`
|
Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"`
|
||||||
HTTP *HTTPLoader `yaml:"http,omitempty" json:"http,omitempty"`
|
HTTP *HTTPLoader `yaml:"http,omitempty" json:"http,omitempty"`
|
||||||
Plugin *PluginConfig `yaml:",omitempty" json:"plugin,omitempty"`
|
Plugin *PluginConfig `yaml:",omitempty" json:"plugin,omitempty"`
|
||||||
|
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type NodeConfig struct {
|
type NodeConfig struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Addr string `yaml:",omitempty" json:"addr,omitempty"`
|
Addr string `yaml:",omitempty" json:"addr,omitempty"`
|
||||||
Host string `yaml:",omitempty" json:"host,omitempty"`
|
Network string `yaml:",omitempty" json:"network,omitempty"`
|
||||||
Network string `yaml:",omitempty" json:"network,omitempty"`
|
Bypass string `yaml:",omitempty" json:"bypass,omitempty"`
|
||||||
Protocol string `yaml:",omitempty" json:"protocol,omitempty"`
|
Bypasses []string `yaml:",omitempty" json:"bypasses,omitempty"`
|
||||||
Path string `yaml:",omitempty" json:"path,omitempty"`
|
Resolver string `yaml:",omitempty" json:"resolver,omitempty"`
|
||||||
Interface string `yaml:",omitempty" json:"interface,omitempty"`
|
Hosts string `yaml:",omitempty" json:"hosts,omitempty"`
|
||||||
SockOpts *SockOptsConfig `yaml:"sockopts,omitempty" json:"sockopts,omitempty"`
|
Connector *ConnectorConfig `yaml:",omitempty" json:"connector,omitempty"`
|
||||||
Bypass string `yaml:",omitempty" json:"bypass,omitempty"`
|
Dialer *DialerConfig `yaml:",omitempty" json:"dialer,omitempty"`
|
||||||
Bypasses []string `yaml:",omitempty" json:"bypasses,omitempty"`
|
Interface string `yaml:",omitempty" json:"interface,omitempty"`
|
||||||
Resolver string `yaml:",omitempty" json:"resolver,omitempty"`
|
Netns string `yaml:",omitempty" json:"netns,omitempty"`
|
||||||
Hosts string `yaml:",omitempty" json:"hosts,omitempty"`
|
SockOpts *SockOptsConfig `yaml:"sockopts,omitempty" json:"sockopts,omitempty"`
|
||||||
Connector *ConnectorConfig `yaml:",omitempty" json:"connector,omitempty"`
|
Filter *NodeFilterConfig `yaml:",omitempty" json:"filter,omitempty"`
|
||||||
Dialer *DialerConfig `yaml:",omitempty" json:"dialer,omitempty"`
|
HTTP *HTTPNodeConfig `yaml:",omitempty" json:"http,omitempty"`
|
||||||
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
TLS *TLSNodeConfig `yaml:",omitempty" json:"tls,omitempty"`
|
||||||
HTTP *HTTPNodeConfig `yaml:",omitempty" json:"http,omitempty"`
|
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
||||||
TLS *TLSNodeConfig `yaml:",omitempty" json:"tls,omitempty"`
|
|
||||||
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@ -446,11 +532,14 @@ type Config struct {
|
|||||||
Resolvers []*ResolverConfig `yaml:",omitempty" json:"resolvers,omitempty"`
|
Resolvers []*ResolverConfig `yaml:",omitempty" json:"resolvers,omitempty"`
|
||||||
Hosts []*HostsConfig `yaml:",omitempty" json:"hosts,omitempty"`
|
Hosts []*HostsConfig `yaml:",omitempty" json:"hosts,omitempty"`
|
||||||
Ingresses []*IngressConfig `yaml:",omitempty" json:"ingresses,omitempty"`
|
Ingresses []*IngressConfig `yaml:",omitempty" json:"ingresses,omitempty"`
|
||||||
|
Routers []*RouterConfig `yaml:",omitempty" json:"routers,omitempty"`
|
||||||
SDs []*SDConfig `yaml:"sds,omitempty" json:"sds,omitempty"`
|
SDs []*SDConfig `yaml:"sds,omitempty" json:"sds,omitempty"`
|
||||||
Recorders []*RecorderConfig `yaml:",omitempty" json:"recorders,omitempty"`
|
Recorders []*RecorderConfig `yaml:",omitempty" json:"recorders,omitempty"`
|
||||||
Limiters []*LimiterConfig `yaml:",omitempty" json:"limiters,omitempty"`
|
Limiters []*LimiterConfig `yaml:",omitempty" json:"limiters,omitempty"`
|
||||||
CLimiters []*LimiterConfig `yaml:"climiters,omitempty" json:"climiters,omitempty"`
|
CLimiters []*LimiterConfig `yaml:"climiters,omitempty" json:"climiters,omitempty"`
|
||||||
RLimiters []*LimiterConfig `yaml:"rlimiters,omitempty" json:"rlimiters,omitempty"`
|
RLimiters []*LimiterConfig `yaml:"rlimiters,omitempty" json:"rlimiters,omitempty"`
|
||||||
|
Observers []*ObserverConfig `yaml:",omitempty" json:"observers,omitempty"`
|
||||||
|
Loggers []*LoggerConfig `yaml:",omitempty" json:"loggers,omitempty"`
|
||||||
TLS *TLSConfig `yaml:",omitempty" json:"tls,omitempty"`
|
TLS *TLSConfig `yaml:",omitempty" json:"tls,omitempty"`
|
||||||
Log *LogConfig `yaml:",omitempty" json:"log,omitempty"`
|
Log *LogConfig `yaml:",omitempty" json:"log,omitempty"`
|
||||||
Profiling *ProfilingConfig `yaml:",omitempty" json:"profiling,omitempty"`
|
Profiling *ProfilingConfig `yaml:",omitempty" json:"profiling,omitempty"`
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/go-gost/core/admission"
|
"github.com/go-gost/core/admission"
|
||||||
"github.com/go-gost/core/logger"
|
"github.com/go-gost/core/logger"
|
||||||
xadmission "github.com/go-gost/x/admission"
|
xadmission "github.com/go-gost/x/admission"
|
||||||
|
admission_plugin "github.com/go-gost/x/admission/plugin"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
"github.com/go-gost/x/internal/loader"
|
"github.com/go-gost/x/internal/loader"
|
||||||
"github.com/go-gost/x/internal/plugin"
|
"github.com/go-gost/x/internal/plugin"
|
||||||
@ -28,13 +29,13 @@ func ParseAdmission(cfg *config.AdmissionConfig) admission.Admission {
|
|||||||
}
|
}
|
||||||
switch strings.ToLower(cfg.Plugin.Type) {
|
switch strings.ToLower(cfg.Plugin.Type) {
|
||||||
case "http":
|
case "http":
|
||||||
return xadmission.NewHTTPPlugin(
|
return admission_plugin.NewHTTPPlugin(
|
||||||
cfg.Name, cfg.Plugin.Addr,
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
plugin.TLSConfigOption(tlsCfg),
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
return xadmission.NewGRPCPlugin(
|
return admission_plugin.NewGRPCPlugin(
|
||||||
cfg.Name, cfg.Plugin.Addr,
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
plugin.TokenOption(cfg.Plugin.Token),
|
plugin.TokenOption(cfg.Plugin.Token),
|
||||||
plugin.TLSConfigOption(tlsCfg),
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/go-gost/core/auth"
|
"github.com/go-gost/core/auth"
|
||||||
"github.com/go-gost/core/logger"
|
"github.com/go-gost/core/logger"
|
||||||
xauth "github.com/go-gost/x/auth"
|
xauth "github.com/go-gost/x/auth"
|
||||||
|
auth_plugin "github.com/go-gost/x/auth/plugin"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
"github.com/go-gost/x/internal/loader"
|
"github.com/go-gost/x/internal/loader"
|
||||||
"github.com/go-gost/x/internal/plugin"
|
"github.com/go-gost/x/internal/plugin"
|
||||||
@ -28,13 +29,13 @@ func ParseAuther(cfg *config.AutherConfig) auth.Authenticator {
|
|||||||
}
|
}
|
||||||
switch cfg.Plugin.Type {
|
switch cfg.Plugin.Type {
|
||||||
case "http":
|
case "http":
|
||||||
return xauth.NewHTTPPlugin(
|
return auth_plugin.NewHTTPPlugin(
|
||||||
cfg.Name, cfg.Plugin.Addr,
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
plugin.TLSConfigOption(tlsCfg),
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
return xauth.NewGRPCPlugin(
|
return auth_plugin.NewGRPCPlugin(
|
||||||
cfg.Name, cfg.Plugin.Addr,
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
plugin.TokenOption(cfg.Plugin.Token),
|
plugin.TokenOption(cfg.Plugin.Token),
|
||||||
plugin.TLSConfigOption(tlsCfg),
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/go-gost/core/bypass"
|
"github.com/go-gost/core/bypass"
|
||||||
"github.com/go-gost/core/logger"
|
"github.com/go-gost/core/logger"
|
||||||
xbypass "github.com/go-gost/x/bypass"
|
xbypass "github.com/go-gost/x/bypass"
|
||||||
|
bypass_plugin "github.com/go-gost/x/bypass/plugin"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
"github.com/go-gost/x/internal/loader"
|
"github.com/go-gost/x/internal/loader"
|
||||||
"github.com/go-gost/x/internal/plugin"
|
"github.com/go-gost/x/internal/plugin"
|
||||||
@ -28,13 +29,13 @@ func ParseBypass(cfg *config.BypassConfig) bypass.Bypass {
|
|||||||
}
|
}
|
||||||
switch strings.ToLower(cfg.Plugin.Type) {
|
switch strings.ToLower(cfg.Plugin.Type) {
|
||||||
case "http":
|
case "http":
|
||||||
return xbypass.NewHTTPPlugin(
|
return bypass_plugin.NewHTTPPlugin(
|
||||||
cfg.Name, cfg.Plugin.Addr,
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
plugin.TLSConfigOption(tlsCfg),
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
return xbypass.NewGRPCPlugin(
|
return bypass_plugin.NewGRPCPlugin(
|
||||||
cfg.Name, cfg.Plugin.Addr,
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
plugin.TokenOption(cfg.Plugin.Token),
|
plugin.TokenOption(cfg.Plugin.Token),
|
||||||
plugin.TLSConfigOption(tlsCfg),
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
|
@ -12,12 +12,12 @@ import (
|
|||||||
"github.com/go-gost/x/registry"
|
"github.com/go-gost/x/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseChain(cfg *config.ChainConfig) (chain.Chainer, error) {
|
func ParseChain(cfg *config.ChainConfig, log logger.Logger) (chain.Chainer, error) {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
chainLogger := logger.Default().WithFields(map[string]any{
|
chainLogger := log.WithFields(map[string]any{
|
||||||
"kind": "chain",
|
"kind": "chain",
|
||||||
"chain": cfg.Name,
|
"chain": cfg.Name,
|
||||||
})
|
})
|
||||||
@ -37,7 +37,7 @@ func ParseChain(cfg *config.ChainConfig) (chain.Chainer, error) {
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
if ch.Nodes != nil || ch.Plugin != nil {
|
if ch.Nodes != nil || ch.Plugin != nil {
|
||||||
if hop, err = hop_parser.ParseHop(ch); err != nil {
|
if hop, err = hop_parser.ParseHop(ch, log); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -8,16 +8,20 @@ import (
|
|||||||
"github.com/go-gost/core/chain"
|
"github.com/go-gost/core/chain"
|
||||||
"github.com/go-gost/core/hop"
|
"github.com/go-gost/core/hop"
|
||||||
"github.com/go-gost/core/logger"
|
"github.com/go-gost/core/logger"
|
||||||
|
mdutil "github.com/go-gost/core/metadata/util"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
|
"github.com/go-gost/x/config/parsing"
|
||||||
bypass_parser "github.com/go-gost/x/config/parsing/bypass"
|
bypass_parser "github.com/go-gost/x/config/parsing/bypass"
|
||||||
node_parser "github.com/go-gost/x/config/parsing/node"
|
node_parser "github.com/go-gost/x/config/parsing/node"
|
||||||
selector_parser "github.com/go-gost/x/config/parsing/selector"
|
selector_parser "github.com/go-gost/x/config/parsing/selector"
|
||||||
xhop "github.com/go-gost/x/hop"
|
xhop "github.com/go-gost/x/hop"
|
||||||
|
hop_plugin "github.com/go-gost/x/hop/plugin"
|
||||||
"github.com/go-gost/x/internal/loader"
|
"github.com/go-gost/x/internal/loader"
|
||||||
"github.com/go-gost/x/internal/plugin"
|
"github.com/go-gost/x/internal/plugin"
|
||||||
|
"github.com/go-gost/x/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseHop(cfg *config.HopConfig) (hop.Hop, error) {
|
func ParseHop(cfg *config.HopConfig, log logger.Logger) (hop.Hop, error) {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -31,14 +35,14 @@ func ParseHop(cfg *config.HopConfig) (hop.Hop, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch strings.ToLower(cfg.Plugin.Type) {
|
switch strings.ToLower(cfg.Plugin.Type) {
|
||||||
case "http":
|
case plugin.HTTP:
|
||||||
return xhop.NewHTTPPlugin(
|
return hop_plugin.NewHTTPPlugin(
|
||||||
cfg.Name, cfg.Plugin.Addr,
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
plugin.TLSConfigOption(tlsCfg),
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||||
), nil
|
), nil
|
||||||
default:
|
default:
|
||||||
return xhop.NewGRPCPlugin(
|
return hop_plugin.NewGRPCPlugin(
|
||||||
cfg.Name, cfg.Plugin.Addr,
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
plugin.TokenOption(cfg.Plugin.Token),
|
plugin.TokenOption(cfg.Plugin.Token),
|
||||||
plugin.TLSConfigOption(tlsCfg),
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
@ -46,6 +50,16 @@ func ParseHop(cfg *config.HopConfig) (hop.Hop, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ifce := cfg.Interface
|
||||||
|
var netns string
|
||||||
|
if cfg.Metadata != nil {
|
||||||
|
md := metadata.NewMetadata(cfg.Metadata)
|
||||||
|
if v := mdutil.GetString(md, parsing.MDKeyInterface); v != "" {
|
||||||
|
ifce = v
|
||||||
|
}
|
||||||
|
netns = mdutil.GetString(md, "netns")
|
||||||
|
}
|
||||||
|
|
||||||
var nodes []*chain.Node
|
var nodes []*chain.Node
|
||||||
for _, v := range cfg.Nodes {
|
for _, v := range cfg.Nodes {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
@ -59,25 +73,31 @@ func ParseHop(cfg *config.HopConfig) (hop.Hop, error) {
|
|||||||
v.Hosts = cfg.Hosts
|
v.Hosts = cfg.Hosts
|
||||||
}
|
}
|
||||||
if v.Interface == "" {
|
if v.Interface == "" {
|
||||||
v.Interface = cfg.Interface
|
v.Interface = ifce
|
||||||
}
|
}
|
||||||
|
if v.Netns == "" {
|
||||||
|
v.Netns = netns
|
||||||
|
}
|
||||||
|
|
||||||
if v.SockOpts == nil {
|
if v.SockOpts == nil {
|
||||||
v.SockOpts = cfg.SockOpts
|
v.SockOpts = cfg.SockOpts
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.Connector == nil {
|
if v.Connector == nil {
|
||||||
v.Connector = &config.ConnectorConfig{
|
v.Connector = &config.ConnectorConfig{}
|
||||||
Type: "http",
|
}
|
||||||
}
|
if strings.TrimSpace(v.Connector.Type) == "" {
|
||||||
|
v.Connector.Type = "http"
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.Dialer == nil {
|
if v.Dialer == nil {
|
||||||
v.Dialer = &config.DialerConfig{
|
v.Dialer = &config.DialerConfig{}
|
||||||
Type: "tcp",
|
}
|
||||||
}
|
if strings.TrimSpace(v.Dialer.Type) == "" {
|
||||||
|
v.Dialer.Type = "tcp"
|
||||||
}
|
}
|
||||||
|
|
||||||
node, err := node_parser.ParseNode(cfg.Name, v)
|
node, err := node_parser.ParseNode(cfg.Name, v, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -97,7 +117,7 @@ func ParseHop(cfg *config.HopConfig) (hop.Hop, error) {
|
|||||||
xhop.SelectorOption(sel),
|
xhop.SelectorOption(sel),
|
||||||
xhop.BypassOption(bypass.BypassGroup(bypass_parser.List(cfg.Bypass, cfg.Bypasses...)...)),
|
xhop.BypassOption(bypass.BypassGroup(bypass_parser.List(cfg.Bypass, cfg.Bypasses...)...)),
|
||||||
xhop.ReloadPeriodOption(cfg.Reload),
|
xhop.ReloadPeriodOption(cfg.Reload),
|
||||||
xhop.LoggerOption(logger.Default().WithFields(map[string]any{
|
xhop.LoggerOption(log.WithFields(map[string]any{
|
||||||
"kind": "hop",
|
"kind": "hop",
|
||||||
"hop": cfg.Name,
|
"hop": cfg.Name,
|
||||||
})),
|
})),
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/go-gost/core/logger"
|
"github.com/go-gost/core/logger"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
xhosts "github.com/go-gost/x/hosts"
|
xhosts "github.com/go-gost/x/hosts"
|
||||||
|
hosts_plugin "github.com/go-gost/x/hosts/plugin"
|
||||||
"github.com/go-gost/x/internal/loader"
|
"github.com/go-gost/x/internal/loader"
|
||||||
"github.com/go-gost/x/internal/plugin"
|
"github.com/go-gost/x/internal/plugin"
|
||||||
)
|
)
|
||||||
@ -28,13 +29,13 @@ func ParseHostMapper(cfg *config.HostsConfig) hosts.HostMapper {
|
|||||||
}
|
}
|
||||||
switch strings.ToLower(cfg.Plugin.Type) {
|
switch strings.ToLower(cfg.Plugin.Type) {
|
||||||
case "http":
|
case "http":
|
||||||
return xhosts.NewHTTPPlugin(
|
return hosts_plugin.NewHTTPPlugin(
|
||||||
cfg.Name, cfg.Plugin.Addr,
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
plugin.TLSConfigOption(tlsCfg),
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
return xhosts.NewGRPCPlugin(
|
return hosts_plugin.NewGRPCPlugin(
|
||||||
cfg.Name, cfg.Plugin.Addr,
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
plugin.TokenOption(cfg.Plugin.Token),
|
plugin.TokenOption(cfg.Plugin.Token),
|
||||||
plugin.TLSConfigOption(tlsCfg),
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/go-gost/core/logger"
|
"github.com/go-gost/core/logger"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
xingress "github.com/go-gost/x/ingress"
|
xingress "github.com/go-gost/x/ingress"
|
||||||
|
ingress_plugin "github.com/go-gost/x/ingress/plugin"
|
||||||
"github.com/go-gost/x/internal/loader"
|
"github.com/go-gost/x/internal/loader"
|
||||||
"github.com/go-gost/x/internal/plugin"
|
"github.com/go-gost/x/internal/plugin"
|
||||||
)
|
)
|
||||||
@ -27,13 +28,13 @@ func ParseIngress(cfg *config.IngressConfig) ingress.Ingress {
|
|||||||
}
|
}
|
||||||
switch strings.ToLower(cfg.Plugin.Type) {
|
switch strings.ToLower(cfg.Plugin.Type) {
|
||||||
case "http":
|
case "http":
|
||||||
return xingress.NewHTTPPlugin(
|
return ingress_plugin.NewHTTPPlugin(
|
||||||
cfg.Name, cfg.Plugin.Addr,
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
plugin.TLSConfigOption(tlsCfg),
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
return xingress.NewGRPCPlugin(
|
return ingress_plugin.NewGRPCPlugin(
|
||||||
cfg.Name, cfg.Plugin.Addr,
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
plugin.TokenOption(cfg.Plugin.Token),
|
plugin.TokenOption(cfg.Plugin.Token),
|
||||||
plugin.TLSConfigOption(tlsCfg),
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
@ -41,13 +42,13 @@ func ParseIngress(cfg *config.IngressConfig) ingress.Ingress {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var rules []xingress.Rule
|
var rules []*ingress.Rule
|
||||||
for _, rule := range cfg.Rules {
|
for _, rule := range cfg.Rules {
|
||||||
if rule.Hostname == "" || rule.Endpoint == "" {
|
if rule.Hostname == "" || rule.Endpoint == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
rules = append(rules, xingress.Rule{
|
rules = append(rules, &ingress.Rule{
|
||||||
Hostname: rule.Hostname,
|
Hostname: rule.Hostname,
|
||||||
Endpoint: rule.Endpoint,
|
Endpoint: rule.Endpoint,
|
||||||
})
|
})
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
package limiter
|
package limiter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/go-gost/core/limiter/conn"
|
"github.com/go-gost/core/limiter/conn"
|
||||||
"github.com/go-gost/core/limiter/rate"
|
"github.com/go-gost/core/limiter/rate"
|
||||||
"github.com/go-gost/core/limiter/traffic"
|
"github.com/go-gost/core/limiter/traffic"
|
||||||
"github.com/go-gost/core/logger"
|
"github.com/go-gost/core/logger"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
"github.com/go-gost/x/internal/loader"
|
"github.com/go-gost/x/internal/loader"
|
||||||
|
"github.com/go-gost/x/internal/plugin"
|
||||||
xconn "github.com/go-gost/x/limiter/conn"
|
xconn "github.com/go-gost/x/limiter/conn"
|
||||||
xrate "github.com/go-gost/x/limiter/rate"
|
xrate "github.com/go-gost/x/limiter/rate"
|
||||||
xtraffic "github.com/go-gost/x/limiter/traffic"
|
xtraffic "github.com/go-gost/x/limiter/traffic"
|
||||||
|
traffic_plugin "github.com/go-gost/x/limiter/traffic/plugin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseTrafficLimiter(cfg *config.LimiterConfig) (lim traffic.TrafficLimiter) {
|
func ParseTrafficLimiter(cfg *config.LimiterConfig) (lim traffic.TrafficLimiter) {
|
||||||
@ -17,6 +22,30 @@ func ParseTrafficLimiter(cfg *config.LimiterConfig) (lim traffic.TrafficLimiter)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.Plugin != nil {
|
||||||
|
var tlsCfg *tls.Config
|
||||||
|
if cfg.Plugin.TLS != nil {
|
||||||
|
tlsCfg = &tls.Config{
|
||||||
|
ServerName: cfg.Plugin.TLS.ServerName,
|
||||||
|
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch strings.ToLower(cfg.Plugin.Type) {
|
||||||
|
case "http":
|
||||||
|
return traffic_plugin.NewHTTPPlugin(
|
||||||
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
|
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
return traffic_plugin.NewGRPCPlugin(
|
||||||
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
|
plugin.TokenOption(cfg.Plugin.Token),
|
||||||
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var opts []xtraffic.Option
|
var opts []xtraffic.Option
|
||||||
|
|
||||||
if cfg.File != nil && cfg.File.Path != "" {
|
if cfg.File != nil && cfg.File.Path != "" {
|
||||||
|
70
config/parsing/logger/parse.go
Normal file
70
config/parsing/logger/parse.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/go-gost/core/logger"
|
||||||
|
"github.com/go-gost/x/config"
|
||||||
|
xlogger "github.com/go-gost/x/logger"
|
||||||
|
"github.com/go-gost/x/registry"
|
||||||
|
"gopkg.in/natefinch/lumberjack.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ParseLogger(cfg *config.LoggerConfig) logger.Logger {
|
||||||
|
if cfg == nil || cfg.Log == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
opts := []xlogger.Option{
|
||||||
|
xlogger.NameOption(cfg.Name),
|
||||||
|
xlogger.FormatOption(logger.LogFormat(cfg.Log.Format)),
|
||||||
|
xlogger.LevelOption(logger.LogLevel(cfg.Log.Level)),
|
||||||
|
}
|
||||||
|
|
||||||
|
var out io.Writer = os.Stderr
|
||||||
|
switch cfg.Log.Output {
|
||||||
|
case "none", "null":
|
||||||
|
return xlogger.Nop()
|
||||||
|
case "stdout":
|
||||||
|
out = os.Stdout
|
||||||
|
case "stderr", "":
|
||||||
|
out = os.Stderr
|
||||||
|
default:
|
||||||
|
if cfg.Log.Rotation != nil {
|
||||||
|
out = &lumberjack.Logger{
|
||||||
|
Filename: cfg.Log.Output,
|
||||||
|
MaxSize: cfg.Log.Rotation.MaxSize,
|
||||||
|
MaxAge: cfg.Log.Rotation.MaxAge,
|
||||||
|
MaxBackups: cfg.Log.Rotation.MaxBackups,
|
||||||
|
LocalTime: cfg.Log.Rotation.LocalTime,
|
||||||
|
Compress: cfg.Log.Rotation.Compress,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
os.MkdirAll(filepath.Dir(cfg.Log.Output), 0755)
|
||||||
|
f, err := os.OpenFile(cfg.Log.Output, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||||
|
if err != nil {
|
||||||
|
logger.Default().Warn(err)
|
||||||
|
} else {
|
||||||
|
out = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
opts = append(opts, xlogger.OutputOption(out))
|
||||||
|
|
||||||
|
return xlogger.NewLogger(opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func List(name string, names ...string) []logger.Logger {
|
||||||
|
var loggers []logger.Logger
|
||||||
|
if adm := registry.LoggerRegistry().Get(name); adm != nil {
|
||||||
|
loggers = append(loggers, adm)
|
||||||
|
}
|
||||||
|
for _, s := range names {
|
||||||
|
if lg := registry.LoggerRegistry().Get(s); lg != nil {
|
||||||
|
loggers = append(loggers, lg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return loggers
|
||||||
|
}
|
@ -3,8 +3,8 @@ package node
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-gost/core/bypass"
|
"github.com/go-gost/core/bypass"
|
||||||
"github.com/go-gost/core/chain"
|
"github.com/go-gost/core/chain"
|
||||||
@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/go-gost/core/metadata"
|
"github.com/go-gost/core/metadata"
|
||||||
mdutil "github.com/go-gost/core/metadata/util"
|
mdutil "github.com/go-gost/core/metadata/util"
|
||||||
xauth "github.com/go-gost/x/auth"
|
xauth "github.com/go-gost/x/auth"
|
||||||
|
xchain "github.com/go-gost/x/chain"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
"github.com/go-gost/x/config/parsing"
|
"github.com/go-gost/x/config/parsing"
|
||||||
auth_parser "github.com/go-gost/x/config/parsing/auth"
|
auth_parser "github.com/go-gost/x/config/parsing/auth"
|
||||||
@ -23,7 +24,7 @@ import (
|
|||||||
"github.com/go-gost/x/registry"
|
"github.com/go-gost/x/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseNode(hop string, cfg *config.NodeConfig) (*chain.Node, error) {
|
func ParseNode(hop string, cfg *config.NodeConfig, log logger.Logger) (*chain.Node, error) {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -40,7 +41,7 @@ func ParseNode(hop string, cfg *config.NodeConfig) (*chain.Node, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeLogger := logger.Default().WithFields(map[string]any{
|
nodeLogger := log.WithFields(map[string]any{
|
||||||
"hop": hop,
|
"hop": hop,
|
||||||
"kind": "node",
|
"kind": "node",
|
||||||
"node": cfg.Name,
|
"node": cfg.Name,
|
||||||
@ -139,40 +140,77 @@ func ParseNode(hop string, cfg *config.NodeConfig) (*chain.Node, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tr := chain.NewTransport(d, cr,
|
tr := xchain.NewTransport(d, cr,
|
||||||
chain.AddrTransportOption(cfg.Addr),
|
chain.AddrTransportOption(cfg.Addr),
|
||||||
chain.InterfaceTransportOption(cfg.Interface),
|
chain.InterfaceTransportOption(cfg.Interface),
|
||||||
|
chain.NetnsTransportOption(cfg.Netns),
|
||||||
chain.SockOptsTransportOption(sockOpts),
|
chain.SockOptsTransportOption(sockOpts),
|
||||||
chain.TimeoutTransportOption(10*time.Second),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// convert *.example.com to .example.com
|
|
||||||
// convert *example.com to example.com
|
|
||||||
host := cfg.Host
|
|
||||||
if strings.HasPrefix(host, "*") {
|
|
||||||
host = host[1:]
|
|
||||||
if !strings.HasPrefix(host, ".") {
|
|
||||||
host = "." + host
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
opts := []chain.NodeOption{
|
opts := []chain.NodeOption{
|
||||||
chain.TransportNodeOption(tr),
|
chain.TransportNodeOption(tr),
|
||||||
chain.BypassNodeOption(bypass.BypassGroup(bypass_parser.List(cfg.Bypass, cfg.Bypasses...)...)),
|
chain.BypassNodeOption(bypass.BypassGroup(bypass_parser.List(cfg.Bypass, cfg.Bypasses...)...)),
|
||||||
chain.ResoloverNodeOption(registry.ResolverRegistry().Get(cfg.Resolver)),
|
chain.ResoloverNodeOption(registry.ResolverRegistry().Get(cfg.Resolver)),
|
||||||
chain.HostMapperNodeOption(registry.HostsRegistry().Get(cfg.Hosts)),
|
chain.HostMapperNodeOption(registry.HostsRegistry().Get(cfg.Hosts)),
|
||||||
chain.MetadataNodeOption(nm),
|
chain.MetadataNodeOption(nm),
|
||||||
chain.HostNodeOption(host),
|
|
||||||
chain.ProtocolNodeOption(cfg.Protocol),
|
|
||||||
chain.PathNodeOption(cfg.Path),
|
|
||||||
chain.NetworkNodeOption(cfg.Network),
|
chain.NetworkNodeOption(cfg.Network),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if filter := cfg.Filter; filter != nil {
|
||||||
|
// convert *.example.com to .example.com
|
||||||
|
// convert *example.com to example.com
|
||||||
|
host := filter.Host
|
||||||
|
if strings.HasPrefix(host, "*") {
|
||||||
|
host = host[1:]
|
||||||
|
if !strings.HasPrefix(host, ".") {
|
||||||
|
host = "." + host
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settings := &chain.NodeFilterSettings{
|
||||||
|
Protocol: filter.Protocol,
|
||||||
|
Host: host,
|
||||||
|
Path: filter.Path,
|
||||||
|
}
|
||||||
|
opts = append(opts, chain.NodeFilterOption(settings))
|
||||||
|
}
|
||||||
|
|
||||||
if cfg.HTTP != nil {
|
if cfg.HTTP != nil {
|
||||||
opts = append(opts, chain.HTTPNodeOption(&chain.HTTPNodeSettings{
|
settings := &chain.HTTPNodeSettings{
|
||||||
Host: cfg.HTTP.Host,
|
Host: cfg.HTTP.Host,
|
||||||
Header: cfg.HTTP.Header,
|
Header: cfg.HTTP.Header,
|
||||||
}))
|
}
|
||||||
|
|
||||||
|
if auth := cfg.HTTP.Auth; auth != nil && auth.Username != "" {
|
||||||
|
settings.Auther = xauth.NewAuthenticator(
|
||||||
|
xauth.AuthsOption(map[string]string{auth.Username: auth.Password}),
|
||||||
|
xauth.LoggerOption(log.WithFields(map[string]any{
|
||||||
|
"kind": "node",
|
||||||
|
"node": cfg.Name,
|
||||||
|
"addr": cfg.Addr,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
for _, v := range cfg.HTTP.Rewrite {
|
||||||
|
if pattern, _ := regexp.Compile(v.Match); pattern != nil {
|
||||||
|
settings.RewriteURL = append(settings.RewriteURL, chain.HTTPURLRewriteSetting{
|
||||||
|
Pattern: pattern,
|
||||||
|
Replacement: v.Replacement,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, v := range cfg.HTTP.RewriteBody {
|
||||||
|
if pattern, _ := regexp.Compile(v.Match); pattern != nil {
|
||||||
|
settings.RewriteBody = append(settings.RewriteBody, chain.HTTPBodyRewriteSettings{
|
||||||
|
Type: v.Type,
|
||||||
|
Pattern: pattern,
|
||||||
|
Replacement: []byte(v.Replacement),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
opts = append(opts, chain.HTTPNodeOption(settings))
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.TLS != nil {
|
if cfg.TLS != nil {
|
||||||
tlsCfg := &chain.TLSNodeSettings{
|
tlsCfg := &chain.TLSNodeSettings{
|
||||||
ServerName: cfg.TLS.ServerName,
|
ServerName: cfg.TLS.ServerName,
|
||||||
@ -185,18 +223,5 @@ func ParseNode(hop string, cfg *config.NodeConfig) (*chain.Node, error) {
|
|||||||
}
|
}
|
||||||
opts = append(opts, chain.TLSNodeOption(tlsCfg))
|
opts = append(opts, chain.TLSNodeOption(tlsCfg))
|
||||||
}
|
}
|
||||||
if cfg.Auth != nil {
|
|
||||||
opts = append(opts, chain.AutherNodeOption(
|
|
||||||
xauth.NewAuthenticator(
|
|
||||||
xauth.AuthsOption(map[string]string{cfg.Auth.Username: cfg.Auth.Password}),
|
|
||||||
xauth.LoggerOption(logger.Default().WithFields(map[string]any{
|
|
||||||
"kind": "node",
|
|
||||||
"node": cfg.Name,
|
|
||||||
"addr": cfg.Addr,
|
|
||||||
"host": cfg.Host,
|
|
||||||
"protocol": cfg.Protocol,
|
|
||||||
})),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
return chain.NewNode(cfg.Name, cfg.Addr, opts...), nil
|
return chain.NewNode(cfg.Name, cfg.Addr, opts...), nil
|
||||||
}
|
}
|
||||||
|
39
config/parsing/observer/parse.go
Normal file
39
config/parsing/observer/parse.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package observer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-gost/core/observer"
|
||||||
|
"github.com/go-gost/x/config"
|
||||||
|
"github.com/go-gost/x/internal/plugin"
|
||||||
|
observer_plugin "github.com/go-gost/x/observer/plugin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ParseObserver(cfg *config.ObserverConfig) observer.Observer {
|
||||||
|
if cfg == nil || cfg.Plugin == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var tlsCfg *tls.Config
|
||||||
|
if cfg.Plugin.TLS != nil {
|
||||||
|
tlsCfg = &tls.Config{
|
||||||
|
ServerName: cfg.Plugin.TLS.ServerName,
|
||||||
|
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch strings.ToLower(cfg.Plugin.Type) {
|
||||||
|
case "http":
|
||||||
|
return observer_plugin.NewHTTPPlugin(
|
||||||
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
|
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
return observer_plugin.NewGRPCPlugin(
|
||||||
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
|
plugin.TokenOption(cfg.Plugin.Token),
|
||||||
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ const (
|
|||||||
MDKeyPostUp = "postUp"
|
MDKeyPostUp = "postUp"
|
||||||
MDKeyPostDown = "postDown"
|
MDKeyPostDown = "postDown"
|
||||||
MDKeyIgnoreChain = "ignoreChain"
|
MDKeyIgnoreChain = "ignoreChain"
|
||||||
|
MDKeyEnableStats = "enableStats"
|
||||||
|
|
||||||
MDKeyRecorderDirection = "direction"
|
MDKeyRecorderDirection = "direction"
|
||||||
MDKeyRecorderTimestampFormat = "timeStampFormat"
|
MDKeyRecorderTimestampFormat = "timeStampFormat"
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
"github.com/go-gost/x/internal/plugin"
|
"github.com/go-gost/x/internal/plugin"
|
||||||
xrecorder "github.com/go-gost/x/recorder"
|
xrecorder "github.com/go-gost/x/recorder"
|
||||||
|
recorder_plugin "github.com/go-gost/x/recorder/plugin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseRecorder(cfg *config.RecorderConfig) (r recorder.Recorder) {
|
func ParseRecorder(cfg *config.RecorderConfig) (r recorder.Recorder) {
|
||||||
@ -25,13 +26,13 @@ func ParseRecorder(cfg *config.RecorderConfig) (r recorder.Recorder) {
|
|||||||
}
|
}
|
||||||
switch strings.ToLower(cfg.Plugin.Type) {
|
switch strings.ToLower(cfg.Plugin.Type) {
|
||||||
case "http":
|
case "http":
|
||||||
return xrecorder.NewHTTPPlugin(
|
return recorder_plugin.NewHTTPPlugin(
|
||||||
cfg.Name, cfg.Plugin.Addr,
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
plugin.TLSConfigOption(tlsCfg),
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
return xrecorder.NewGRPCPlugin(
|
return recorder_plugin.NewGRPCPlugin(
|
||||||
cfg.Name, cfg.Plugin.Addr,
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
plugin.TokenOption(cfg.Plugin.Token),
|
plugin.TokenOption(cfg.Plugin.Token),
|
||||||
plugin.TLSConfigOption(tlsCfg),
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/go-gost/x/internal/plugin"
|
"github.com/go-gost/x/internal/plugin"
|
||||||
"github.com/go-gost/x/registry"
|
"github.com/go-gost/x/registry"
|
||||||
xresolver "github.com/go-gost/x/resolver"
|
xresolver "github.com/go-gost/x/resolver"
|
||||||
|
resolver_plugin "github.com/go-gost/x/resolver/plugin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseResolver(cfg *config.ResolverConfig) (resolver.Resolver, error) {
|
func ParseResolver(cfg *config.ResolverConfig) (resolver.Resolver, error) {
|
||||||
@ -28,13 +29,13 @@ func ParseResolver(cfg *config.ResolverConfig) (resolver.Resolver, error) {
|
|||||||
}
|
}
|
||||||
switch strings.ToLower(cfg.Plugin.Type) {
|
switch strings.ToLower(cfg.Plugin.Type) {
|
||||||
case "http":
|
case "http":
|
||||||
return xresolver.NewHTTPPlugin(
|
return resolver_plugin.NewHTTPPlugin(
|
||||||
cfg.Name, cfg.Plugin.Addr,
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
plugin.TLSConfigOption(tlsCfg),
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||||
), nil
|
), nil
|
||||||
default:
|
default:
|
||||||
return xresolver.NewGRPCPlugin(
|
return resolver_plugin.NewGRPCPlugin(
|
||||||
cfg.Name, cfg.Plugin.Addr,
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
plugin.TokenOption(cfg.Plugin.Token),
|
plugin.TokenOption(cfg.Plugin.Token),
|
||||||
plugin.TLSConfigOption(tlsCfg),
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
|
105
config/parsing/router/parse.go
Normal file
105
config/parsing/router/parse.go
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-gost/core/logger"
|
||||||
|
"github.com/go-gost/core/router"
|
||||||
|
"github.com/go-gost/x/config"
|
||||||
|
"github.com/go-gost/x/internal/loader"
|
||||||
|
"github.com/go-gost/x/internal/plugin"
|
||||||
|
xrouter "github.com/go-gost/x/router"
|
||||||
|
router_plugin "github.com/go-gost/x/router/plugin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ParseRouter(cfg *config.RouterConfig) router.Router {
|
||||||
|
if cfg == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Plugin != nil {
|
||||||
|
var tlsCfg *tls.Config
|
||||||
|
if cfg.Plugin.TLS != nil {
|
||||||
|
tlsCfg = &tls.Config{
|
||||||
|
ServerName: cfg.Plugin.TLS.ServerName,
|
||||||
|
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch strings.ToLower(cfg.Plugin.Type) {
|
||||||
|
case "http":
|
||||||
|
return router_plugin.NewHTTPPlugin(
|
||||||
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
|
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
return router_plugin.NewGRPCPlugin(
|
||||||
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
|
plugin.TokenOption(cfg.Plugin.Token),
|
||||||
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var routes []*router.Route
|
||||||
|
for _, route := range cfg.Routes {
|
||||||
|
_, ipNet, _ := net.ParseCIDR(route.Net)
|
||||||
|
if ipNet == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
gw := net.ParseIP(route.Gateway)
|
||||||
|
if gw == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
routes = append(routes, &router.Route{
|
||||||
|
Net: ipNet,
|
||||||
|
Gateway: gw,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
opts := []xrouter.Option{
|
||||||
|
xrouter.RoutesOption(routes),
|
||||||
|
xrouter.ReloadPeriodOption(cfg.Reload),
|
||||||
|
xrouter.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||||
|
"kind": "router",
|
||||||
|
"router": cfg.Name,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
if cfg.File != nil && cfg.File.Path != "" {
|
||||||
|
opts = append(opts, xrouter.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
|
||||||
|
}
|
||||||
|
if cfg.Redis != nil && cfg.Redis.Addr != "" {
|
||||||
|
switch cfg.Redis.Type {
|
||||||
|
case "list": // rediss list
|
||||||
|
opts = append(opts, xrouter.RedisLoaderOption(loader.RedisListLoader(
|
||||||
|
cfg.Redis.Addr,
|
||||||
|
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||||
|
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||||
|
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||||
|
)))
|
||||||
|
case "set": // redis set
|
||||||
|
opts = append(opts, xrouter.RedisLoaderOption(loader.RedisSetLoader(
|
||||||
|
cfg.Redis.Addr,
|
||||||
|
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||||
|
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||||
|
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||||
|
)))
|
||||||
|
default: // redis hash
|
||||||
|
opts = append(opts, xrouter.RedisLoaderOption(loader.RedisHashLoader(
|
||||||
|
cfg.Redis.Addr,
|
||||||
|
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||||
|
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||||
|
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||||
|
opts = append(opts, xrouter.HTTPLoaderOption(loader.HTTPLoader(
|
||||||
|
cfg.HTTP.URL,
|
||||||
|
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
return xrouter.NewRouter(opts...)
|
||||||
|
}
|
@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/go-gost/core/sd"
|
"github.com/go-gost/core/sd"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
"github.com/go-gost/x/internal/plugin"
|
"github.com/go-gost/x/internal/plugin"
|
||||||
xsd "github.com/go-gost/x/sd"
|
sd_plugin "github.com/go-gost/x/sd/plugin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseSD(cfg *config.SDConfig) sd.SD {
|
func ParseSD(cfg *config.SDConfig) sd.SD {
|
||||||
@ -24,13 +24,13 @@ func ParseSD(cfg *config.SDConfig) sd.SD {
|
|||||||
}
|
}
|
||||||
switch strings.ToLower(cfg.Plugin.Type) {
|
switch strings.ToLower(cfg.Plugin.Type) {
|
||||||
case "http":
|
case "http":
|
||||||
return xsd.NewHTTPPlugin(
|
return sd_plugin.NewHTTPPlugin(
|
||||||
cfg.Name, cfg.Plugin.Addr,
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
plugin.TLSConfigOption(tlsCfg),
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
return xsd.NewGRPCPlugin(
|
return sd_plugin.NewGRPCPlugin(
|
||||||
cfg.Name, cfg.Plugin.Addr,
|
cfg.Name, cfg.Plugin.Addr,
|
||||||
plugin.TokenOption(cfg.Plugin.Token),
|
plugin.TokenOption(cfg.Plugin.Token),
|
||||||
plugin.TLSConfigOption(tlsCfg),
|
plugin.TLSConfigOption(tlsCfg),
|
||||||
|
@ -2,6 +2,9 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/go-gost/core/admission"
|
"github.com/go-gost/core/admission"
|
||||||
"github.com/go-gost/core/auth"
|
"github.com/go-gost/core/auth"
|
||||||
@ -12,6 +15,7 @@ import (
|
|||||||
"github.com/go-gost/core/listener"
|
"github.com/go-gost/core/listener"
|
||||||
"github.com/go-gost/core/logger"
|
"github.com/go-gost/core/logger"
|
||||||
mdutil "github.com/go-gost/core/metadata/util"
|
mdutil "github.com/go-gost/core/metadata/util"
|
||||||
|
"github.com/go-gost/core/observer/stats"
|
||||||
"github.com/go-gost/core/recorder"
|
"github.com/go-gost/core/recorder"
|
||||||
"github.com/go-gost/core/selector"
|
"github.com/go-gost/core/selector"
|
||||||
"github.com/go-gost/core/service"
|
"github.com/go-gost/core/service"
|
||||||
@ -22,43 +26,49 @@ import (
|
|||||||
auth_parser "github.com/go-gost/x/config/parsing/auth"
|
auth_parser "github.com/go-gost/x/config/parsing/auth"
|
||||||
bypass_parser "github.com/go-gost/x/config/parsing/bypass"
|
bypass_parser "github.com/go-gost/x/config/parsing/bypass"
|
||||||
hop_parser "github.com/go-gost/x/config/parsing/hop"
|
hop_parser "github.com/go-gost/x/config/parsing/hop"
|
||||||
|
logger_parser "github.com/go-gost/x/config/parsing/logger"
|
||||||
selector_parser "github.com/go-gost/x/config/parsing/selector"
|
selector_parser "github.com/go-gost/x/config/parsing/selector"
|
||||||
xnet "github.com/go-gost/x/internal/net"
|
|
||||||
tls_util "github.com/go-gost/x/internal/util/tls"
|
tls_util "github.com/go-gost/x/internal/util/tls"
|
||||||
"github.com/go-gost/x/metadata"
|
"github.com/go-gost/x/metadata"
|
||||||
"github.com/go-gost/x/registry"
|
"github.com/go-gost/x/registry"
|
||||||
xservice "github.com/go-gost/x/service"
|
xservice "github.com/go-gost/x/service"
|
||||||
|
"github.com/vishvananda/netns"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||||
if cfg.Listener == nil {
|
if cfg.Listener == nil {
|
||||||
cfg.Listener = &config.ListenerConfig{
|
cfg.Listener = &config.ListenerConfig{}
|
||||||
Type: "tcp",
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if strings.TrimSpace(cfg.Listener.Type) == "" {
|
||||||
|
cfg.Listener.Type = "tcp"
|
||||||
|
}
|
||||||
|
|
||||||
if cfg.Handler == nil {
|
if cfg.Handler == nil {
|
||||||
cfg.Handler = &config.HandlerConfig{
|
cfg.Handler = &config.HandlerConfig{}
|
||||||
Type: "auto",
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
serviceLogger := logger.Default().WithFields(map[string]any{
|
if strings.TrimSpace(cfg.Handler.Type) == "" {
|
||||||
|
cfg.Handler.Type = "auto"
|
||||||
|
}
|
||||||
|
|
||||||
|
log := logger.Default()
|
||||||
|
if loggers := logger_parser.List(cfg.Logger, cfg.Loggers...); len(loggers) > 0 {
|
||||||
|
log = logger.LoggerGroup(loggers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceLogger := log.WithFields(map[string]any{
|
||||||
"kind": "service",
|
"kind": "service",
|
||||||
"service": cfg.Name,
|
"service": cfg.Name,
|
||||||
"listener": cfg.Listener.Type,
|
"listener": cfg.Listener.Type,
|
||||||
"handler": cfg.Handler.Type,
|
"handler": cfg.Handler.Type,
|
||||||
})
|
})
|
||||||
|
|
||||||
listenerLogger := serviceLogger.WithFields(map[string]any{
|
|
||||||
"kind": "listener",
|
|
||||||
})
|
|
||||||
|
|
||||||
tlsCfg := cfg.Listener.TLS
|
tlsCfg := cfg.Listener.TLS
|
||||||
if tlsCfg == nil {
|
if tlsCfg == nil {
|
||||||
tlsCfg = &config.TLSConfig{}
|
tlsCfg = &config.TLSConfig{}
|
||||||
}
|
}
|
||||||
tlsConfig, err := tls_util.LoadServerConfig(tlsCfg)
|
tlsConfig, err := tls_util.LoadServerConfig(tlsCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
listenerLogger.Error(err)
|
serviceLogger.Error(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if tlsConfig == nil {
|
if tlsConfig == nil {
|
||||||
@ -89,6 +99,10 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
|||||||
ifce := cfg.Interface
|
ifce := cfg.Interface
|
||||||
var preUp, preDown, postUp, postDown []string
|
var preUp, preDown, postUp, postDown []string
|
||||||
var ignoreChain bool
|
var ignoreChain bool
|
||||||
|
var pStats *stats.Stats
|
||||||
|
var observePeriod time.Duration
|
||||||
|
var netnsIn, netnsOut string
|
||||||
|
var dialTimeout time.Duration
|
||||||
if cfg.Metadata != nil {
|
if cfg.Metadata != nil {
|
||||||
md := metadata.NewMetadata(cfg.Metadata)
|
md := metadata.NewMetadata(cfg.Metadata)
|
||||||
ppv = mdutil.GetInt(md, parsing.MDKeyProxyProtocol)
|
ppv = mdutil.GetInt(md, parsing.MDKeyProxyProtocol)
|
||||||
@ -105,31 +119,83 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
|||||||
postUp = mdutil.GetStrings(md, parsing.MDKeyPostUp)
|
postUp = mdutil.GetStrings(md, parsing.MDKeyPostUp)
|
||||||
postDown = mdutil.GetStrings(md, parsing.MDKeyPostDown)
|
postDown = mdutil.GetStrings(md, parsing.MDKeyPostDown)
|
||||||
ignoreChain = mdutil.GetBool(md, parsing.MDKeyIgnoreChain)
|
ignoreChain = mdutil.GetBool(md, parsing.MDKeyIgnoreChain)
|
||||||
|
|
||||||
|
if mdutil.GetBool(md, parsing.MDKeyEnableStats) {
|
||||||
|
pStats = &stats.Stats{}
|
||||||
|
}
|
||||||
|
observePeriod = mdutil.GetDuration(md, "observePeriod")
|
||||||
|
netnsIn = mdutil.GetString(md, "netns")
|
||||||
|
netnsOut = mdutil.GetString(md, "netns.out")
|
||||||
|
dialTimeout = mdutil.GetDuration(md, "dialTimeout")
|
||||||
|
}
|
||||||
|
|
||||||
|
listenerLogger := serviceLogger.WithFields(map[string]any{
|
||||||
|
"kind": "listener",
|
||||||
|
})
|
||||||
|
|
||||||
|
routerOpts := []chain.RouterOption{
|
||||||
|
chain.TimeoutRouterOption(dialTimeout),
|
||||||
|
chain.InterfaceRouterOption(ifce),
|
||||||
|
chain.NetnsRouterOption(netnsOut),
|
||||||
|
chain.SockOptsRouterOption(sockOpts),
|
||||||
|
chain.ResolverRouterOption(registry.ResolverRegistry().Get(cfg.Resolver)),
|
||||||
|
chain.HostMapperRouterOption(registry.HostsRegistry().Get(cfg.Hosts)),
|
||||||
|
chain.LoggerRouterOption(listenerLogger),
|
||||||
|
}
|
||||||
|
if !ignoreChain {
|
||||||
|
routerOpts = append(routerOpts,
|
||||||
|
chain.ChainRouterOption(chainGroup(cfg.Listener.Chain, cfg.Listener.ChainGroup)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
listenOpts := []listener.Option{
|
listenOpts := []listener.Option{
|
||||||
listener.AddrOption(cfg.Addr),
|
listener.AddrOption(cfg.Addr),
|
||||||
|
listener.RouterOption(xchain.NewRouter(routerOpts...)),
|
||||||
listener.AutherOption(auther),
|
listener.AutherOption(auther),
|
||||||
listener.AuthOption(auth_parser.Info(cfg.Listener.Auth)),
|
listener.AuthOption(auth_parser.Info(cfg.Listener.Auth)),
|
||||||
listener.TLSConfigOption(tlsConfig),
|
listener.TLSConfigOption(tlsConfig),
|
||||||
listener.AdmissionOption(admission.AdmissionGroup(admissions...)),
|
listener.AdmissionOption(admission.AdmissionGroup(admissions...)),
|
||||||
listener.TrafficLimiterOption(registry.TrafficLimiterRegistry().Get(cfg.Limiter)),
|
listener.TrafficLimiterOption(registry.TrafficLimiterRegistry().Get(cfg.Limiter)),
|
||||||
listener.ConnLimiterOption(registry.ConnLimiterRegistry().Get(cfg.CLimiter)),
|
listener.ConnLimiterOption(registry.ConnLimiterRegistry().Get(cfg.CLimiter)),
|
||||||
listener.LoggerOption(listenerLogger),
|
|
||||||
listener.ServiceOption(cfg.Name),
|
listener.ServiceOption(cfg.Name),
|
||||||
listener.ProxyProtocolOption(ppv),
|
listener.ProxyProtocolOption(ppv),
|
||||||
|
listener.StatsOption(pStats),
|
||||||
|
listener.NetnsOption(netnsIn),
|
||||||
|
listener.LoggerOption(listenerLogger),
|
||||||
}
|
}
|
||||||
if !ignoreChain {
|
|
||||||
listenOpts = append(listenOpts,
|
if netnsIn != "" {
|
||||||
listener.ChainOption(chainGroup(cfg.Listener.Chain, cfg.Listener.ChainGroup)),
|
runtime.LockOSThread()
|
||||||
)
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
originNs, err := netns.Get()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("netns.Get(): %v", err)
|
||||||
|
}
|
||||||
|
defer netns.Set(originNs)
|
||||||
|
|
||||||
|
var ns netns.NsHandle
|
||||||
|
|
||||||
|
if strings.HasPrefix(netnsIn, "/") {
|
||||||
|
ns, err = netns.GetFromPath(netnsIn)
|
||||||
|
} else {
|
||||||
|
ns, err = netns.GetFromName(netnsIn)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("netns.Get(%s): %v", netnsIn, err)
|
||||||
|
}
|
||||||
|
defer ns.Close()
|
||||||
|
|
||||||
|
if err := netns.Set(ns); err != nil {
|
||||||
|
return nil, fmt.Errorf("netns.Set(%s): %v", netnsIn, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var ln listener.Listener
|
var ln listener.Listener
|
||||||
if rf := registry.ListenerRegistry().Get(cfg.Listener.Type); rf != nil {
|
if rf := registry.ListenerRegistry().Get(cfg.Listener.Type); rf != nil {
|
||||||
ln = rf(listenOpts...)
|
ln = rf(listenOpts...)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unregistered listener: %s", cfg.Listener.Type)
|
return nil, fmt.Errorf("unknown listener: %s", cfg.Listener.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Listener.Metadata == nil {
|
if cfg.Listener.Metadata == nil {
|
||||||
@ -184,10 +250,11 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
routerOpts := []chain.RouterOption{
|
routerOpts = []chain.RouterOption{
|
||||||
chain.RetriesRouterOption(cfg.Handler.Retries),
|
chain.RetriesRouterOption(cfg.Handler.Retries),
|
||||||
// chain.TimeoutRouterOption(10*time.Second),
|
chain.TimeoutRouterOption(dialTimeout),
|
||||||
chain.InterfaceRouterOption(ifce),
|
chain.InterfaceRouterOption(ifce),
|
||||||
|
chain.NetnsRouterOption(netnsOut),
|
||||||
chain.SockOptsRouterOption(sockOpts),
|
chain.SockOptsRouterOption(sockOpts),
|
||||||
chain.ResolverRouterOption(registry.ResolverRegistry().Get(cfg.Resolver)),
|
chain.ResolverRouterOption(registry.ResolverRegistry().Get(cfg.Resolver)),
|
||||||
chain.HostMapperRouterOption(registry.HostsRegistry().Get(cfg.Hosts)),
|
chain.HostMapperRouterOption(registry.HostsRegistry().Get(cfg.Hosts)),
|
||||||
@ -199,26 +266,28 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
|||||||
chain.ChainRouterOption(chainGroup(cfg.Handler.Chain, cfg.Handler.ChainGroup)),
|
chain.ChainRouterOption(chainGroup(cfg.Handler.Chain, cfg.Handler.ChainGroup)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
router := chain.NewRouter(routerOpts...)
|
|
||||||
|
|
||||||
var h handler.Handler
|
var h handler.Handler
|
||||||
if rf := registry.HandlerRegistry().Get(cfg.Handler.Type); rf != nil {
|
if rf := registry.HandlerRegistry().Get(cfg.Handler.Type); rf != nil {
|
||||||
h = rf(
|
h = rf(
|
||||||
handler.RouterOption(router),
|
handler.RouterOption(xchain.NewRouter(routerOpts...)),
|
||||||
handler.AutherOption(auther),
|
handler.AutherOption(auther),
|
||||||
handler.AuthOption(auth_parser.Info(cfg.Handler.Auth)),
|
handler.AuthOption(auth_parser.Info(cfg.Handler.Auth)),
|
||||||
handler.BypassOption(bypass.BypassGroup(bypass_parser.List(cfg.Bypass, cfg.Bypasses...)...)),
|
handler.BypassOption(bypass.BypassGroup(bypass_parser.List(cfg.Bypass, cfg.Bypasses...)...)),
|
||||||
handler.TLSConfigOption(tlsConfig),
|
handler.TLSConfigOption(tlsConfig),
|
||||||
handler.RateLimiterOption(registry.RateLimiterRegistry().Get(cfg.RLimiter)),
|
handler.RateLimiterOption(registry.RateLimiterRegistry().Get(cfg.RLimiter)),
|
||||||
|
handler.TrafficLimiterOption(registry.TrafficLimiterRegistry().Get(cfg.Handler.Limiter)),
|
||||||
|
handler.ObserverOption(registry.ObserverRegistry().Get(cfg.Handler.Observer)),
|
||||||
handler.LoggerOption(handlerLogger),
|
handler.LoggerOption(handlerLogger),
|
||||||
handler.ServiceOption(cfg.Name),
|
handler.ServiceOption(cfg.Name),
|
||||||
|
handler.NetnsOption(netnsIn),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unregistered handler: %s", cfg.Handler.Type)
|
return nil, fmt.Errorf("unknown handler: %s", cfg.Handler.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
if forwarder, ok := h.(handler.Forwarder); ok {
|
if forwarder, ok := h.(handler.Forwarder); ok {
|
||||||
hop, err := parseForwarder(cfg.Forwarder)
|
hop, err := parseForwarder(cfg.Forwarder, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -241,6 +310,9 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
|||||||
xservice.PostUpOption(postUp),
|
xservice.PostUpOption(postUp),
|
||||||
xservice.PostDownOption(postDown),
|
xservice.PostDownOption(postDown),
|
||||||
xservice.RecordersOption(recorders...),
|
xservice.RecordersOption(recorders...),
|
||||||
|
xservice.StatsOption(pStats),
|
||||||
|
xservice.ObserverOption(registry.ObserverRegistry().Get(cfg.Observer)),
|
||||||
|
xservice.ObservePeriodOption(observePeriod),
|
||||||
xservice.LoggerOption(serviceLogger),
|
xservice.LoggerOption(serviceLogger),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -248,46 +320,61 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
|||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseForwarder(cfg *config.ForwarderConfig) (hop.Hop, error) {
|
func parseForwarder(cfg *config.ForwarderConfig, log logger.Logger) (hop.Hop, error) {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hopName := cfg.Hop
|
||||||
|
if hopName == "" {
|
||||||
|
hopName = cfg.Name
|
||||||
|
}
|
||||||
|
if hopName != "" {
|
||||||
|
return registry.HopRegistry().Get(hopName), nil
|
||||||
|
}
|
||||||
|
|
||||||
hc := config.HopConfig{
|
hc := config.HopConfig{
|
||||||
Name: cfg.Name,
|
Name: cfg.Name,
|
||||||
Selector: cfg.Selector,
|
Selector: cfg.Selector,
|
||||||
}
|
}
|
||||||
for _, node := range cfg.Nodes {
|
for _, node := range cfg.Nodes {
|
||||||
if node != nil {
|
if node == nil {
|
||||||
addrs := xnet.AddrPortRange(node.Addr).Addrs()
|
continue
|
||||||
if len(addrs) == 0 {
|
}
|
||||||
addrs = append(addrs, node.Addr)
|
|
||||||
}
|
filter := node.Filter
|
||||||
for i, addr := range addrs {
|
if filter == nil {
|
||||||
name := node.Name
|
if node.Protocol != "" || node.Host != "" || node.Path != "" {
|
||||||
if i > 0 {
|
filter = &config.NodeFilterConfig{
|
||||||
name = fmt.Sprintf("%s-%d", node.Name, i)
|
|
||||||
}
|
|
||||||
hc.Nodes = append(hc.Nodes, &config.NodeConfig{
|
|
||||||
Name: name,
|
|
||||||
Addr: addr,
|
|
||||||
Host: node.Host,
|
|
||||||
Network: node.Network,
|
|
||||||
Protocol: node.Protocol,
|
Protocol: node.Protocol,
|
||||||
|
Host: node.Host,
|
||||||
Path: node.Path,
|
Path: node.Path,
|
||||||
Bypass: node.Bypass,
|
}
|
||||||
Bypasses: node.Bypasses,
|
|
||||||
HTTP: node.HTTP,
|
|
||||||
TLS: node.TLS,
|
|
||||||
Auth: node.Auth,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
httpCfg := node.HTTP
|
||||||
|
if node.Auth != nil {
|
||||||
|
if httpCfg == nil {
|
||||||
|
httpCfg = &config.HTTPNodeConfig{}
|
||||||
|
}
|
||||||
|
if httpCfg.Auth == nil {
|
||||||
|
httpCfg.Auth = node.Auth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hc.Nodes = append(hc.Nodes, &config.NodeConfig{
|
||||||
|
Name: node.Name,
|
||||||
|
Addr: node.Addr,
|
||||||
|
Network: node.Network,
|
||||||
|
Bypass: node.Bypass,
|
||||||
|
Bypasses: node.Bypasses,
|
||||||
|
Filter: filter,
|
||||||
|
HTTP: httpCfg,
|
||||||
|
TLS: node.TLS,
|
||||||
|
Metadata: node.Metadata,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if len(hc.Nodes) > 0 {
|
return hop_parser.ParseHop(&hc, log)
|
||||||
return hop_parser.ParseHop(&hc)
|
|
||||||
}
|
|
||||||
return registry.HopRegistry().Get(hc.Name), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func chainGroup(name string, group *config.ChainGroupConfig) chain.Chainer {
|
func chainGroup(name string, group *config.ChainGroupConfig) chain.Chainer {
|
||||||
|
@ -39,14 +39,22 @@ func (c *directConnector) Connect(ctx context.Context, _ net.Conn, network, addr
|
|||||||
opt(&cOpts)
|
opt(&cOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := cOpts.NetDialer.Dial(ctx, network, address)
|
conn, err := cOpts.Dialer.Dial(ctx, network, address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var localAddr, remoteAddr string
|
||||||
|
if addr := conn.LocalAddr(); addr != nil {
|
||||||
|
localAddr = addr.String()
|
||||||
|
}
|
||||||
|
if addr := conn.RemoteAddr(); addr != nil {
|
||||||
|
remoteAddr = addr.String()
|
||||||
|
}
|
||||||
|
|
||||||
log := c.options.Logger.WithFields(map[string]any{
|
log := c.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": remoteAddr,
|
||||||
"local": conn.LocalAddr().String(),
|
"local": localAddr,
|
||||||
"network": network,
|
"network": network,
|
||||||
"address": address,
|
"address": address,
|
||||||
})
|
})
|
||||||
|
@ -6,10 +6,10 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/go-gost/core/common/net/udp"
|
|
||||||
"github.com/go-gost/core/connector"
|
"github.com/go-gost/core/connector"
|
||||||
"github.com/go-gost/core/logger"
|
"github.com/go-gost/core/logger"
|
||||||
"github.com/go-gost/relay"
|
"github.com/go-gost/relay"
|
||||||
|
"github.com/go-gost/x/internal/net/udp"
|
||||||
"github.com/go-gost/x/internal/util/mux"
|
"github.com/go-gost/x/internal/util/mux"
|
||||||
relay_util "github.com/go-gost/x/internal/util/relay"
|
relay_util "github.com/go-gost/x/internal/util/relay"
|
||||||
)
|
)
|
||||||
@ -73,7 +73,7 @@ func (c *relayConnector) bindUDP(ctx context.Context, conn net.Conn, network, ad
|
|||||||
ReadQueueSize: opts.UDPDataQueueSize,
|
ReadQueueSize: opts.UDPDataQueueSize,
|
||||||
ReadBufferSize: opts.UDPDataBufferSize,
|
ReadBufferSize: opts.UDPDataBufferSize,
|
||||||
TTL: opts.UDPConnTTL,
|
TTL: opts.UDPConnTTL,
|
||||||
KeepAlive: true,
|
Keepalive: true,
|
||||||
Logger: log,
|
Logger: log,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/go-gost/core/common/bufpool"
|
"github.com/go-gost/core/common/bufpool"
|
||||||
mdata "github.com/go-gost/core/metadata"
|
mdata "github.com/go-gost/core/metadata"
|
||||||
"github.com/go-gost/relay"
|
"github.com/go-gost/relay"
|
||||||
|
xrelay "github.com/go-gost/x/internal/util/relay"
|
||||||
)
|
)
|
||||||
|
|
||||||
type tcpConn struct {
|
type tcpConn struct {
|
||||||
@ -129,7 +130,7 @@ func readResponse(r io.Reader) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if resp.Status != relay.StatusOK {
|
if resp.Status != relay.StatusOK {
|
||||||
err = fmt.Errorf("status %d", resp.Status)
|
err = fmt.Errorf("%d %s", resp.Status, xrelay.StatusText(resp.Status))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -223,16 +224,3 @@ func (c *bindUDPConn) RemoteAddr() net.Addr {
|
|||||||
func (c *bindUDPConn) Metadata() mdata.Metadata {
|
func (c *bindUDPConn) Metadata() mdata.Metadata {
|
||||||
return c.md
|
return c.md
|
||||||
}
|
}
|
||||||
|
|
||||||
type bindAddr struct {
|
|
||||||
network string
|
|
||||||
addr string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *bindAddr) Network() string {
|
|
||||||
return p.network
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *bindAddr) String() string {
|
|
||||||
return p.addr
|
|
||||||
}
|
|
||||||
|
@ -5,10 +5,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/go-gost/core/common/net/udp"
|
|
||||||
"github.com/go-gost/core/connector"
|
"github.com/go-gost/core/connector"
|
||||||
"github.com/go-gost/core/logger"
|
"github.com/go-gost/core/logger"
|
||||||
"github.com/go-gost/gosocks5"
|
"github.com/go-gost/gosocks5"
|
||||||
|
"github.com/go-gost/x/internal/net/udp"
|
||||||
"github.com/go-gost/x/internal/util/mux"
|
"github.com/go-gost/x/internal/util/mux"
|
||||||
"github.com/go-gost/x/internal/util/socks"
|
"github.com/go-gost/x/internal/util/socks"
|
||||||
)
|
)
|
||||||
@ -87,7 +87,7 @@ func (c *socks5Connector) bindUDP(ctx context.Context, conn net.Conn, network, a
|
|||||||
ReadQueueSize: opts.UDPDataQueueSize,
|
ReadQueueSize: opts.UDPDataQueueSize,
|
||||||
ReadBufferSize: opts.UDPDataBufferSize,
|
ReadBufferSize: opts.UDPDataBufferSize,
|
||||||
TTL: opts.UDPConnTTL,
|
TTL: opts.UDPConnTTL,
|
||||||
KeepAlive: true,
|
Keepalive: true,
|
||||||
Logger: log,
|
Logger: log,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -69,6 +69,10 @@ func (c *udpRelayConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
|||||||
if err = socksAddr.ParseFrom(addr.String()); err != nil {
|
if err = socksAddr.ParseFrom(addr.String()); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if socksAddr.Host == "" {
|
||||||
|
socksAddr.Type = gosocks5.AddrIPv4
|
||||||
|
socksAddr.Host = "127.0.0.1"
|
||||||
|
}
|
||||||
|
|
||||||
header := gosocks5.UDPHeader{
|
header := gosocks5.UDPHeader{
|
||||||
Addr: &socksAddr,
|
Addr: &socksAddr,
|
||||||
|
@ -130,6 +130,10 @@ func (c *socks5Connector) Connect(ctx context.Context, conn net.Conn, network, a
|
|||||||
log.Error(err)
|
log.Error(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if addr.Host == "" {
|
||||||
|
addr.Type = gosocks5.AddrIPv4
|
||||||
|
addr.Host = "127.0.0.1"
|
||||||
|
}
|
||||||
|
|
||||||
req := gosocks5.NewRequest(gosocks5.CmdConnect, &addr)
|
req := gosocks5.NewRequest(gosocks5.CmdConnect, &addr)
|
||||||
log.Trace(req)
|
log.Trace(req)
|
||||||
@ -201,16 +205,22 @@ func (c *socks5Connector) relayUDP(ctx context.Context, conn net.Conn, addr net.
|
|||||||
}
|
}
|
||||||
log.Trace(reply)
|
log.Trace(reply)
|
||||||
|
|
||||||
log.Debugf("bind on: %v", reply.Addr)
|
|
||||||
|
|
||||||
if reply.Rep != gosocks5.Succeeded {
|
if reply.Rep != gosocks5.Succeeded {
|
||||||
return nil, errors.New("get socks5 UDP tunnel failure")
|
return nil, errors.New("get socks5 UDP tunnel failure")
|
||||||
}
|
}
|
||||||
|
|
||||||
cc, err := opts.NetDialer.Dial(ctx, "udp", reply.Addr.String())
|
log.Debugf("bind on: %v", reply.Addr)
|
||||||
|
|
||||||
|
cc, err := opts.Dialer.Dial(ctx, "udp", reply.Addr.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
c.options.Logger.Error(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
log.Debugf("%s <- %s -> %s", cc.LocalAddr(), cc.RemoteAddr(), addr)
|
||||||
|
|
||||||
|
if c.md.udpTimeout > 0 {
|
||||||
|
cc.SetReadDeadline(time.Now().Add(c.md.udpTimeout))
|
||||||
|
}
|
||||||
|
|
||||||
return &udpRelayConn{
|
return &udpRelayConn{
|
||||||
udpConn: cc.(*net.UDPConn),
|
udpConn: cc.(*net.UDPConn),
|
||||||
|
@ -17,24 +17,19 @@ type metadata struct {
|
|||||||
noTLS bool
|
noTLS bool
|
||||||
relay string
|
relay string
|
||||||
udpBufferSize int
|
udpBufferSize int
|
||||||
|
udpTimeout time.Duration
|
||||||
muxCfg *mux.Config
|
muxCfg *mux.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *socks5Connector) parseMetadata(md mdata.Metadata) (err error) {
|
func (c *socks5Connector) parseMetadata(md mdata.Metadata) (err error) {
|
||||||
const (
|
c.md.connectTimeout = mdutil.GetDuration(md, "timeout")
|
||||||
connectTimeout = "timeout"
|
c.md.noTLS = mdutil.GetBool(md, "notls")
|
||||||
noTLS = "notls"
|
c.md.relay = mdutil.GetString(md, "relay")
|
||||||
relay = "relay"
|
c.md.udpBufferSize = mdutil.GetInt(md, "udp.bufferSize", "udpBufferSize")
|
||||||
udpBufferSize = "udpBufferSize"
|
|
||||||
)
|
|
||||||
|
|
||||||
c.md.connectTimeout = mdutil.GetDuration(md, connectTimeout)
|
|
||||||
c.md.noTLS = mdutil.GetBool(md, noTLS)
|
|
||||||
c.md.relay = mdutil.GetString(md, relay)
|
|
||||||
c.md.udpBufferSize = mdutil.GetInt(md, udpBufferSize)
|
|
||||||
if c.md.udpBufferSize <= 0 {
|
if c.md.udpBufferSize <= 0 {
|
||||||
c.md.udpBufferSize = defaultUDPBufferSize
|
c.md.udpBufferSize = defaultUDPBufferSize
|
||||||
}
|
}
|
||||||
|
c.md.udpTimeout = mdutil.GetDuration(md, "udp.timeout")
|
||||||
|
|
||||||
c.md.muxCfg = &mux.Config{
|
c.md.muxCfg = &mux.Config{
|
||||||
Version: mdutil.GetInt(md, "mux.version"),
|
Version: mdutil.GetInt(md, "mux.version"),
|
||||||
|
@ -27,7 +27,8 @@ func (c *tunnelConnector) Bind(ctx context.Context, conn net.Conn, network, addr
|
|||||||
"endpoint": endpoint,
|
"endpoint": endpoint,
|
||||||
"tunnel": c.md.tunnelID.String(),
|
"tunnel": c.md.tunnelID.String(),
|
||||||
})
|
})
|
||||||
log.Infof("create tunnel on %s/%s OK, tunnel=%s, connector=%s", addr, network, c.md.tunnelID.String(), cid)
|
log.Infof("create tunnel on %s/%s OK, tunnel=%s, connector=%s, weight=%d",
|
||||||
|
addr, network, c.md.tunnelID.String(), cid, cid.Weight())
|
||||||
|
|
||||||
session, err := mux.ServerSession(conn, c.md.muxCfg)
|
session, err := mux.ServerSession(conn, c.md.muxCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -72,7 +73,7 @@ func (c *tunnelConnector) initTunnel(conn net.Conn, network, address string) (ad
|
|||||||
req.Features = append(req.Features, af) // dst address
|
req.Features = append(req.Features, af) // dst address
|
||||||
|
|
||||||
req.Features = append(req.Features, &relay.TunnelFeature{
|
req.Features = append(req.Features, &relay.TunnelFeature{
|
||||||
ID: c.md.tunnelID.ID(),
|
ID: c.md.tunnelID,
|
||||||
})
|
})
|
||||||
if _, err = req.WriteTo(conn); err != nil {
|
if _, err = req.WriteTo(conn); err != nil {
|
||||||
return
|
return
|
||||||
@ -100,7 +101,7 @@ func (c *tunnelConnector) initTunnel(conn net.Conn, network, address string) (ad
|
|||||||
}
|
}
|
||||||
case relay.FeatureTunnel:
|
case relay.FeatureTunnel:
|
||||||
if feature, _ := f.(*relay.TunnelFeature); feature != nil {
|
if feature, _ := f.(*relay.TunnelFeature); feature != nil {
|
||||||
cid = relay.NewConnectorID(feature.ID[:])
|
cid = feature.ID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,67 +1,24 @@
|
|||||||
package tunnel
|
package tunnel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/go-gost/core/common/bufpool"
|
"github.com/go-gost/core/common/bufpool"
|
||||||
mdata "github.com/go-gost/core/metadata"
|
mdata "github.com/go-gost/core/metadata"
|
||||||
"github.com/go-gost/relay"
|
"github.com/go-gost/relay"
|
||||||
|
xrelay "github.com/go-gost/x/internal/util/relay"
|
||||||
)
|
)
|
||||||
|
|
||||||
type tcpConn struct {
|
|
||||||
net.Conn
|
|
||||||
wbuf *bytes.Buffer
|
|
||||||
once sync.Once
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *tcpConn) Read(b []byte) (n int, err error) {
|
|
||||||
c.once.Do(func() {
|
|
||||||
if c.wbuf != nil {
|
|
||||||
err = readResponse(c.Conn)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return c.Conn.Read(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *tcpConn) Write(b []byte) (n int, err error) {
|
|
||||||
n = len(b) // force byte length consistent
|
|
||||||
if c.wbuf != nil && c.wbuf.Len() > 0 {
|
|
||||||
c.wbuf.Write(b) // append the data to the cached header
|
|
||||||
_, err = c.Conn.Write(c.wbuf.Bytes())
|
|
||||||
c.wbuf.Reset()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err = c.Conn.Write(b)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type udpConn struct {
|
type udpConn struct {
|
||||||
net.Conn
|
net.Conn
|
||||||
wbuf *bytes.Buffer
|
|
||||||
once sync.Once
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *udpConn) Read(b []byte) (n int, err error) {
|
func (c *udpConn) Read(b []byte) (n int, err error) {
|
||||||
c.once.Do(func() {
|
|
||||||
if c.wbuf != nil {
|
|
||||||
err = readResponse(c.Conn)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var bb [2]byte
|
var bb [2]byte
|
||||||
_, err = io.ReadFull(c.Conn, bb[:])
|
_, err = io.ReadFull(c.Conn, bb[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -88,14 +45,6 @@ func (c *udpConn) Write(b []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
n = len(b)
|
n = len(b)
|
||||||
if c.wbuf != nil && c.wbuf.Len() > 0 {
|
|
||||||
var bb [2]byte
|
|
||||||
binary.BigEndian.PutUint16(bb[:], uint16(len(b)))
|
|
||||||
c.wbuf.Write(bb[:])
|
|
||||||
c.wbuf.Write(b) // append the data to the cached header
|
|
||||||
_, err = c.wbuf.WriteTo(c.Conn)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var bb [2]byte
|
var bb [2]byte
|
||||||
binary.BigEndian.PutUint16(bb[:], uint16(len(b)))
|
binary.BigEndian.PutUint16(bb[:], uint16(len(b)))
|
||||||
@ -119,7 +68,7 @@ func readResponse(r io.Reader) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if resp.Status != relay.StatusOK {
|
if resp.Status != relay.StatusOK {
|
||||||
err = fmt.Errorf("status %d", resp.Status)
|
err = fmt.Errorf("%d %s", resp.Status, xrelay.StatusText(resp.Status))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package tunnel
|
package tunnel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
@ -10,7 +9,7 @@ import (
|
|||||||
"github.com/go-gost/core/connector"
|
"github.com/go-gost/core/connector"
|
||||||
md "github.com/go-gost/core/metadata"
|
md "github.com/go-gost/core/metadata"
|
||||||
"github.com/go-gost/relay"
|
"github.com/go-gost/relay"
|
||||||
auth_util "github.com/go-gost/x/internal/util/auth"
|
ctxvalue "github.com/go-gost/x/ctx"
|
||||||
"github.com/go-gost/x/registry"
|
"github.com/go-gost/x/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -74,7 +73,7 @@ func (c *tunnelConnector) Connect(ctx context.Context, conn net.Conn, network, a
|
|||||||
}
|
}
|
||||||
|
|
||||||
srcAddr := conn.LocalAddr().String()
|
srcAddr := conn.LocalAddr().String()
|
||||||
if v := auth_util.ClientAddrFromContext(ctx); v != "" {
|
if v := ctxvalue.ClientAddrFromContext(ctx); v != "" {
|
||||||
srcAddr = string(v)
|
srcAddr = string(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,42 +86,23 @@ func (c *tunnelConnector) Connect(ctx context.Context, conn net.Conn, network, a
|
|||||||
req.Features = append(req.Features, af) // dst address
|
req.Features = append(req.Features, af) // dst address
|
||||||
|
|
||||||
req.Features = append(req.Features, &relay.TunnelFeature{
|
req.Features = append(req.Features, &relay.TunnelFeature{
|
||||||
ID: c.md.tunnelID.ID(),
|
ID: c.md.tunnelID,
|
||||||
})
|
})
|
||||||
|
|
||||||
if c.md.noDelay {
|
if _, err := req.WriteTo(conn); err != nil {
|
||||||
if _, err := req.WriteTo(conn); err != nil {
|
return nil, err
|
||||||
return nil, err
|
}
|
||||||
}
|
// drain the response
|
||||||
// drain the response
|
if err := readResponse(conn); err != nil {
|
||||||
if err := readResponse(conn); err != nil {
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch network {
|
switch network {
|
||||||
case "tcp", "tcp4", "tcp6":
|
case "tcp", "tcp4", "tcp6":
|
||||||
if !c.md.noDelay {
|
|
||||||
cc := &tcpConn{
|
|
||||||
Conn: conn,
|
|
||||||
wbuf: &bytes.Buffer{},
|
|
||||||
}
|
|
||||||
if _, err := req.WriteTo(cc.wbuf); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
conn = cc
|
|
||||||
}
|
|
||||||
case "udp", "udp4", "udp6":
|
case "udp", "udp4", "udp6":
|
||||||
cc := &udpConn{
|
conn = &udpConn{
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
}
|
}
|
||||||
if !c.md.noDelay {
|
|
||||||
cc.wbuf = &bytes.Buffer{}
|
|
||||||
if _, err := req.WriteTo(cc.wbuf); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
conn = cc
|
|
||||||
default:
|
default:
|
||||||
err := fmt.Errorf("network %s is unsupported", network)
|
err := fmt.Errorf("network %s is unsupported", network)
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
@ -18,13 +18,11 @@ var (
|
|||||||
type metadata struct {
|
type metadata struct {
|
||||||
connectTimeout time.Duration
|
connectTimeout time.Duration
|
||||||
tunnelID relay.TunnelID
|
tunnelID relay.TunnelID
|
||||||
noDelay bool
|
|
||||||
muxCfg *mux.Config
|
muxCfg *mux.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *tunnelConnector) parseMetadata(md mdata.Metadata) (err error) {
|
func (c *tunnelConnector) parseMetadata(md mdata.Metadata) (err error) {
|
||||||
c.md.connectTimeout = mdutil.GetDuration(md, "connectTimeout")
|
c.md.connectTimeout = mdutil.GetDuration(md, "connectTimeout")
|
||||||
c.md.noDelay = mdutil.GetBool(md, "nodelay")
|
|
||||||
|
|
||||||
if s := mdutil.GetString(md, "tunnelID", "tunnel.id"); s != "" {
|
if s := mdutil.GetString(md, "tunnelID", "tunnel.id"); s != "" {
|
||||||
uuid, err := uuid.Parse(s)
|
uuid, err := uuid.Parse(s)
|
||||||
@ -42,6 +40,10 @@ func (c *tunnelConnector) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
c.md.tunnelID = relay.NewTunnelID(uuid[:])
|
c.md.tunnelID = relay.NewTunnelID(uuid[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if weight := mdutil.GetInt(md, "tunnel.weight"); weight > 0 {
|
||||||
|
c.md.tunnelID = c.md.tunnelID.SetWeight(uint8(weight))
|
||||||
|
}
|
||||||
|
|
||||||
c.md.muxCfg = &mux.Config{
|
c.md.muxCfg = &mux.Config{
|
||||||
Version: mdutil.GetInt(md, "mux.version"),
|
Version: mdutil.GetInt(md, "mux.version"),
|
||||||
KeepAliveInterval: mdutil.GetDuration(md, "mux.keepaliveInterval"),
|
KeepAliveInterval: mdutil.GetDuration(md, "mux.keepaliveInterval"),
|
||||||
|
76
ctx/value.go
Normal file
76
ctx/value.go
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
package ctx
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// clientAddrKey saves the client address.
|
||||||
|
type clientAddrKey struct{}
|
||||||
|
|
||||||
|
type ClientAddr string
|
||||||
|
|
||||||
|
var (
|
||||||
|
keyClientAddr clientAddrKey
|
||||||
|
)
|
||||||
|
|
||||||
|
func ContextWithClientAddr(ctx context.Context, addr ClientAddr) context.Context {
|
||||||
|
return context.WithValue(ctx, keyClientAddr, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClientAddrFromContext(ctx context.Context) ClientAddr {
|
||||||
|
v, _ := ctx.Value(keyClientAddr).(ClientAddr)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// sidKey saves the session ID.
|
||||||
|
type sidKey struct{}
|
||||||
|
type Sid string
|
||||||
|
|
||||||
|
var (
|
||||||
|
keySid sidKey
|
||||||
|
)
|
||||||
|
|
||||||
|
func ContextWithSid(ctx context.Context, sid Sid) context.Context {
|
||||||
|
return context.WithValue(ctx, keySid, sid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SidFromContext(ctx context.Context) Sid {
|
||||||
|
v, _ := ctx.Value(keySid).(Sid)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// hashKey saves the hash source for Selector.
|
||||||
|
type hashKey struct{}
|
||||||
|
|
||||||
|
type Hash struct {
|
||||||
|
Source string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
clientHashKey = &hashKey{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func ContextWithHash(ctx context.Context, hash *Hash) context.Context {
|
||||||
|
return context.WithValue(ctx, clientHashKey, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HashFromContext(ctx context.Context) *Hash {
|
||||||
|
if v, _ := ctx.Value(clientHashKey).(*Hash); v != nil {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type clientIDKey struct{}
|
||||||
|
type ClientID string
|
||||||
|
|
||||||
|
var (
|
||||||
|
keyClientID = &clientIDKey{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func ContextWithClientID(ctx context.Context, clientID ClientID) context.Context {
|
||||||
|
return context.WithValue(ctx, keyClientID, clientID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClientIDFromContext(ctx context.Context) ClientID {
|
||||||
|
v, _ := ctx.Value(keyClientID).(ClientID)
|
||||||
|
return v
|
||||||
|
}
|
@ -45,7 +45,7 @@ func (d *dtlsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO
|
|||||||
opt(&options)
|
opt(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := options.NetDialer.Dial(ctx, "udp", addr)
|
conn, err := options.Dialer.Dial(ctx, "udp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -71,14 +71,13 @@ func (d *grpcDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO
|
|||||||
grpcOpts := []grpc.DialOption{
|
grpcOpts := []grpc.DialOption{
|
||||||
// grpc.WithBlock(),
|
// grpc.WithBlock(),
|
||||||
grpc.WithContextDialer(func(c context.Context, s string) (net.Conn, error) {
|
grpc.WithContextDialer(func(c context.Context, s string) (net.Conn, error) {
|
||||||
return options.NetDialer.Dial(c, "tcp", s)
|
return options.Dialer.Dial(c, "tcp", s)
|
||||||
}),
|
}),
|
||||||
grpc.WithAuthority(host),
|
grpc.WithAuthority(host),
|
||||||
grpc.WithConnectParams(grpc.ConnectParams{
|
grpc.WithConnectParams(grpc.ConnectParams{
|
||||||
Backoff: backoff.DefaultConfig,
|
Backoff: backoff.DefaultConfig,
|
||||||
MinConnectTimeout: d.md.minConnectTimeout,
|
MinConnectTimeout: d.md.minConnectTimeout,
|
||||||
}),
|
}),
|
||||||
grpc.FailOnNonTempDialError(true),
|
|
||||||
}
|
}
|
||||||
if !d.md.insecure {
|
if !d.md.insecure {
|
||||||
grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(credentials.NewTLS(d.options.TLSConfig)))
|
grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(credentials.NewTLS(d.options.TLSConfig)))
|
||||||
@ -94,7 +93,7 @@ func (d *grpcDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
cc, err := grpc.DialContext(ctx, addr, grpcOpts...)
|
cc, err := grpc.NewClient(addr, grpcOpts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.options.Logger.Error(err)
|
d.options.Logger.Error(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -7,10 +7,10 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
net_dialer "github.com/go-gost/core/common/net/dialer"
|
|
||||||
"github.com/go-gost/core/dialer"
|
"github.com/go-gost/core/dialer"
|
||||||
"github.com/go-gost/core/logger"
|
"github.com/go-gost/core/logger"
|
||||||
md "github.com/go-gost/core/metadata"
|
md "github.com/go-gost/core/metadata"
|
||||||
|
net_dialer "github.com/go-gost/x/internal/net/dialer"
|
||||||
mdx "github.com/go-gost/x/metadata"
|
mdx "github.com/go-gost/x/metadata"
|
||||||
"github.com/go-gost/x/registry"
|
"github.com/go-gost/x/registry"
|
||||||
)
|
)
|
||||||
@ -70,28 +70,40 @@ func (d *http2Dialer) Dial(ctx context.Context, address string, opts ...dialer.D
|
|||||||
opt(&options)
|
opt(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Check whether the connection is established properly
|
||||||
|
netd := options.Dialer
|
||||||
|
if netd == nil {
|
||||||
|
netd = net_dialer.DefaultNetDialer
|
||||||
|
}
|
||||||
|
conn, err := netd.Dial(ctx, "tcp", address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
client = &http.Client{
|
client = &http.Client{
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
TLSClientConfig: d.options.TLSConfig,
|
TLSClientConfig: d.options.TLSConfig,
|
||||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
netd := options.NetDialer
|
netd := options.Dialer
|
||||||
if netd == nil {
|
if netd == nil {
|
||||||
netd = net_dialer.DefaultNetDialer
|
netd = net_dialer.DefaultNetDialer
|
||||||
}
|
}
|
||||||
return netd.Dial(ctx, network, addr)
|
return netd.Dial(ctx, network, addr)
|
||||||
},
|
},
|
||||||
ForceAttemptHTTP2: true,
|
ForceAttemptHTTP2: true,
|
||||||
MaxIdleConns: 100,
|
MaxIdleConns: 16,
|
||||||
IdleConnTimeout: 90 * time.Second,
|
IdleConnTimeout: 30 * time.Second,
|
||||||
TLSHandshakeTimeout: 10 * time.Second,
|
TLSHandshakeTimeout: 30 * time.Second,
|
||||||
ExpectContinueTimeout: 1 * time.Second,
|
ExpectContinueTimeout: 15 * time.Second,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
d.clients[address] = client
|
d.clients[address] = client
|
||||||
}
|
}
|
||||||
|
|
||||||
var c net.Conn
|
var c net.Conn = &conn{
|
||||||
c = &conn{
|
|
||||||
localAddr: &net.TCPAddr{},
|
localAddr: &net.TCPAddr{},
|
||||||
remoteAddr: raddr,
|
remoteAddr: raddr,
|
||||||
onClose: func() {
|
onClose: func() {
|
||||||
|
@ -94,14 +94,14 @@ func (d *h2Dialer) Dial(ctx context.Context, address string, opts ...dialer.Dial
|
|||||||
client.Transport = &http2.Transport{
|
client.Transport = &http2.Transport{
|
||||||
AllowHTTP: true,
|
AllowHTTP: true,
|
||||||
DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
|
DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||||
return options.NetDialer.Dial(ctx, network, addr)
|
return options.Dialer.Dial(ctx, network, addr)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
client.Transport = &http.Transport{
|
client.Transport = &http.Transport{
|
||||||
TLSClientConfig: d.options.TLSConfig,
|
TLSClientConfig: d.options.TLSConfig,
|
||||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
return options.NetDialer.Dial(ctx, network, addr)
|
return options.Dialer.Dial(ctx, network, addr)
|
||||||
},
|
},
|
||||||
ForceAttemptHTTP2: true,
|
ForceAttemptHTTP2: true,
|
||||||
MaxIdleConns: 100,
|
MaxIdleConns: 100,
|
||||||
|
@ -79,14 +79,14 @@ func (d *http3Dialer) Dial(ctx context.Context, addr string, opts ...dialer.Dial
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
udpConn, err := options.NetDialer.Dial(ctx, "udp", "")
|
udpConn, err := options.Dialer.Dial(ctx, "udp", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return quic.DialEarly(context.Background(), udpConn.(net.PacketConn), udpAddr, tlsCfg, cfg)
|
return quic.DialEarly(context.Background(), udpConn.(net.PacketConn), udpAddr, tlsCfg, cfg)
|
||||||
},
|
},
|
||||||
QuicConfig: &quic.Config{
|
QUICConfig: &quic.Config{
|
||||||
KeepAlivePeriod: d.md.keepAlivePeriod,
|
KeepAlivePeriod: d.md.keepAlivePeriod,
|
||||||
HandshakeIdleTimeout: d.md.handshakeTimeout,
|
HandshakeIdleTimeout: d.md.handshakeTimeout,
|
||||||
MaxIdleTimeout: d.md.maxIdleTimeout,
|
MaxIdleTimeout: d.md.maxIdleTimeout,
|
||||||
|
@ -50,7 +50,7 @@ func (d *http3Dialer) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
d.md.host = mdutil.GetString(md, "host")
|
d.md.host = mdutil.GetString(md, "host")
|
||||||
if !md.IsExists(keepAlive) || mdutil.GetBool(md, keepAlive) {
|
if md == nil || !md.IsExists(keepAlive) || mdutil.GetBool(md, keepAlive) {
|
||||||
d.md.keepAlivePeriod = mdutil.GetDuration(md, keepAlivePeriod)
|
d.md.keepAlivePeriod = mdutil.GetDuration(md, keepAlivePeriod)
|
||||||
if d.md.keepAlivePeriod <= 0 {
|
if d.md.keepAlivePeriod <= 0 {
|
||||||
d.md.keepAlivePeriod = 10 * time.Second
|
d.md.keepAlivePeriod = 10 * time.Second
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
md "github.com/go-gost/core/metadata"
|
md "github.com/go-gost/core/metadata"
|
||||||
"github.com/go-gost/x/registry"
|
"github.com/go-gost/x/registry"
|
||||||
"github.com/quic-go/quic-go"
|
"github.com/quic-go/quic-go"
|
||||||
"github.com/quic-go/quic-go/http3"
|
|
||||||
wt "github.com/quic-go/webtransport-go"
|
wt "github.com/quic-go/webtransport-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -74,33 +73,32 @@ func (d *wtDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOpt
|
|||||||
path: d.md.path,
|
path: d.md.path,
|
||||||
header: d.md.header,
|
header: d.md.header,
|
||||||
dialer: &wt.Dialer{
|
dialer: &wt.Dialer{
|
||||||
RoundTripper: &http3.RoundTripper{
|
TLSClientConfig: d.options.TLSConfig,
|
||||||
TLSClientConfig: d.options.TLSConfig,
|
DialAddr: func(ctx context.Context, adr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
|
||||||
Dial: func(ctx context.Context, adr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
|
// d.options.Logger.Infof("dial: %s, %s, %s", addr, adr, host)
|
||||||
// d.options.Logger.Infof("dial: %s, %s, %s", addr, adr, host)
|
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||||
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, err
|
||||||
return nil, err
|
}
|
||||||
}
|
|
||||||
|
|
||||||
udpConn, err := options.NetDialer.Dial(ctx, "udp", "")
|
udpConn, err := options.Dialer.Dial(ctx, "udp", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return quic.DialEarly(ctx, udpConn.(net.PacketConn), udpAddr, tlsCfg, cfg)
|
return quic.DialEarly(ctx, udpConn.(net.PacketConn), udpAddr, tlsCfg, cfg)
|
||||||
},
|
},
|
||||||
QuicConfig: &quic.Config{
|
QUICConfig: &quic.Config{
|
||||||
KeepAlivePeriod: d.md.keepAlivePeriod,
|
KeepAlivePeriod: d.md.keepAlivePeriod,
|
||||||
HandshakeIdleTimeout: d.md.handshakeTimeout,
|
HandshakeIdleTimeout: d.md.handshakeTimeout,
|
||||||
MaxIdleTimeout: d.md.maxIdleTimeout,
|
MaxIdleTimeout: d.md.maxIdleTimeout,
|
||||||
/*
|
/*
|
||||||
Versions: []quic.VersionNumber{
|
Versions: []quic.VersionNumber{
|
||||||
quic.Version1,
|
quic.Version1,
|
||||||
},
|
},
|
||||||
*/
|
*/
|
||||||
MaxIncomingStreams: int64(d.md.maxStreams),
|
MaxIncomingStreams: int64(d.md.maxStreams),
|
||||||
},
|
EnableDatagrams: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ func (d *wtDialer) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
d.md.path = defaultPath
|
d.md.path = defaultPath
|
||||||
}
|
}
|
||||||
|
|
||||||
if !md.IsExists(keepAlive) || mdutil.GetBool(md, keepAlive) {
|
if md == nil || !md.IsExists(keepAlive) || mdutil.GetBool(md, keepAlive) {
|
||||||
d.md.keepAlivePeriod = mdutil.GetDuration(md, keepAlivePeriod)
|
d.md.keepAlivePeriod = mdutil.GetDuration(md, keepAlivePeriod)
|
||||||
if d.md.keepAlivePeriod <= 0 {
|
if d.md.keepAlivePeriod <= 0 {
|
||||||
d.md.keepAlivePeriod = 10 * time.Second
|
d.md.keepAlivePeriod = 10 * time.Second
|
||||||
|
@ -19,9 +19,11 @@ import (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.DialerRegistry().Register("icmp", NewDialer)
|
registry.DialerRegistry().Register("icmp", NewDialer)
|
||||||
|
registry.DialerRegistry().Register("icmp6", NewDialer6)
|
||||||
}
|
}
|
||||||
|
|
||||||
type icmpDialer struct {
|
type icmpDialer struct {
|
||||||
|
ip6 bool
|
||||||
sessions map[string]*quicSession
|
sessions map[string]*quicSession
|
||||||
sessionMutex sync.Mutex
|
sessionMutex sync.Mutex
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
@ -42,6 +44,19 @@ func NewDialer(opts ...dialer.Option) dialer.Dialer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewDialer6(opts ...dialer.Option) dialer.Dialer {
|
||||||
|
options := dialer.Options{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &icmpDialer{
|
||||||
|
ip6: true,
|
||||||
|
sessions: make(map[string]*quicSession),
|
||||||
|
logger: options.Logger,
|
||||||
|
options: options,
|
||||||
|
}
|
||||||
|
}
|
||||||
func (d *icmpDialer) Init(md md.Metadata) (err error) {
|
func (d *icmpDialer) Init(md md.Metadata) (err error) {
|
||||||
if err = d.parseMetadata(md); err != nil {
|
if err = d.parseMetadata(md); err != nil {
|
||||||
return
|
return
|
||||||
@ -71,7 +86,11 @@ func (d *icmpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO
|
|||||||
}
|
}
|
||||||
|
|
||||||
var pc net.PacketConn
|
var pc net.PacketConn
|
||||||
pc, err = icmp.ListenPacket("ip4:icmp", "")
|
if d.ip6 {
|
||||||
|
pc, err = icmp.ListenPacket("ip6:ipv6-icmp", "")
|
||||||
|
} else {
|
||||||
|
pc, err = icmp.ListenPacket("ip4:icmp", "")
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -81,7 +100,7 @@ func (d *icmpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO
|
|||||||
id = rand.New(rand.NewSource(time.Now().UnixNano())).Intn(math.MaxUint16) + 1
|
id = rand.New(rand.NewSource(time.Now().UnixNano())).Intn(math.MaxUint16) + 1
|
||||||
raddr.Port = id
|
raddr.Port = id
|
||||||
}
|
}
|
||||||
pc = icmp_pkg.ClientConn(pc, id)
|
pc = icmp_pkg.ClientConn(d.ip6, pc, id)
|
||||||
|
|
||||||
session, err = d.initSession(ctx, raddr, pc)
|
session, err = d.initSession(ctx, raddr, pc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -115,7 +134,7 @@ func (d *icmpDialer) initSession(ctx context.Context, addr net.Addr, conn net.Pa
|
|||||||
}
|
}
|
||||||
|
|
||||||
tlsCfg := d.options.TLSConfig
|
tlsCfg := d.options.TLSConfig
|
||||||
tlsCfg.NextProtos = []string{"http/3", "quic/v1"}
|
tlsCfg.NextProtos = []string{"h3", "quic/v1"}
|
||||||
|
|
||||||
session, err := quic.DialEarly(ctx, conn, addr, tlsCfg, quicConfig)
|
session, err := quic.DialEarly(ctx, conn, addr, tlsCfg, quicConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -14,21 +14,14 @@ type metadata struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *icmpDialer) parseMetadata(md mdata.Metadata) (err error) {
|
func (d *icmpDialer) parseMetadata(md mdata.Metadata) (err error) {
|
||||||
const (
|
if mdutil.GetBool(md, "keepalive") {
|
||||||
keepAlive = "keepAlive"
|
d.md.keepAlivePeriod = mdutil.GetDuration(md, "ttl")
|
||||||
keepAlivePeriod = "ttl"
|
|
||||||
handshakeTimeout = "handshakeTimeout"
|
|
||||||
maxIdleTimeout = "maxIdleTimeout"
|
|
||||||
)
|
|
||||||
|
|
||||||
if mdutil.GetBool(md, keepAlive) {
|
|
||||||
d.md.keepAlivePeriod = mdutil.GetDuration(md, keepAlivePeriod)
|
|
||||||
if d.md.keepAlivePeriod <= 0 {
|
if d.md.keepAlivePeriod <= 0 {
|
||||||
d.md.keepAlivePeriod = 10 * time.Second
|
d.md.keepAlivePeriod = 10 * time.Second
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
d.md.handshakeTimeout = mdutil.GetDuration(md, handshakeTimeout)
|
d.md.handshakeTimeout = mdutil.GetDuration(md, "handshakeTimeout")
|
||||||
d.md.maxIdleTimeout = mdutil.GetDuration(md, maxIdleTimeout)
|
d.md.maxIdleTimeout = mdutil.GetDuration(md, "maxIdleTimeout")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ func (d *kcpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp
|
|||||||
PacketConn: pc,
|
PacketConn: pc,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c, err := options.NetDialer.Dial(ctx, "udp", "")
|
c, err := options.Dialer.Dial(ctx, "udp", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -149,7 +149,9 @@ func (d *kcpDialer) initSession(ctx context.Context, addr net.Addr, conn net.Pac
|
|||||||
smuxConfig.Version = config.SmuxVer
|
smuxConfig.Version = config.SmuxVer
|
||||||
smuxConfig.MaxReceiveBuffer = config.SmuxBuf
|
smuxConfig.MaxReceiveBuffer = config.SmuxBuf
|
||||||
smuxConfig.MaxStreamBuffer = config.StreamBuf
|
smuxConfig.MaxStreamBuffer = config.StreamBuf
|
||||||
smuxConfig.KeepAliveInterval = time.Duration(config.KeepAlive) * time.Second
|
if config.KeepAlive > 0 {
|
||||||
|
smuxConfig.KeepAliveInterval = time.Duration(config.KeepAlive) * time.Second
|
||||||
|
}
|
||||||
var cc net.Conn = kcpconn
|
var cc net.Conn = kcpconn
|
||||||
if !config.NoComp {
|
if !config.NoComp {
|
||||||
cc = kcp_util.CompStreamConn(kcpconn)
|
cc = kcp_util.CompStreamConn(kcpconn)
|
||||||
|
@ -21,14 +21,14 @@ func (d *kcpDialer) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
handshakeTimeout = "handshakeTimeout"
|
handshakeTimeout = "handshakeTimeout"
|
||||||
)
|
)
|
||||||
|
|
||||||
if file := mdutil.GetString(md, configFile); file != "" {
|
if file := mdutil.GetString(md, "kcp.configFile", "configFile", "c"); file != "" {
|
||||||
d.md.config, err = kcp_util.ParseFromFile(file)
|
d.md.config, err = kcp_util.ParseFromFile(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if m := mdutil.GetStringMap(md, config); len(m) > 0 {
|
if m := mdutil.GetStringMap(md, "kcp.config", "config"); len(m) > 0 {
|
||||||
b, err := json.Marshal(m)
|
b, err := json.Marshal(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -42,6 +42,19 @@ func (d *kcpDialer) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
if d.md.config == nil {
|
if d.md.config == nil {
|
||||||
d.md.config = kcp_util.DefaultConfig
|
d.md.config = kcp_util.DefaultConfig
|
||||||
}
|
}
|
||||||
|
d.md.config.TCP = mdutil.GetBool(md, "kcp.tcp", "tcp")
|
||||||
|
d.md.config.Key = mdutil.GetString(md, "kcp.key")
|
||||||
|
d.md.config.Crypt = mdutil.GetString(md, "kcp.crypt")
|
||||||
|
d.md.config.Mode = mdutil.GetString(md, "kcp.mode")
|
||||||
|
d.md.config.KeepAlive = mdutil.GetInt(md, "kcp.keepalive")
|
||||||
|
d.md.config.Interval = mdutil.GetInt(md, "kcp.interval")
|
||||||
|
d.md.config.MTU = mdutil.GetInt(md, "kcp.mtu")
|
||||||
|
d.md.config.RcvWnd = mdutil.GetInt(md, "kcp.rcvwnd")
|
||||||
|
d.md.config.SndWnd = mdutil.GetInt(md, "kcp.sndwnd")
|
||||||
|
d.md.config.SmuxVer = mdutil.GetInt(md, "kcp.smuxver")
|
||||||
|
d.md.config.SmuxBuf = mdutil.GetInt(md, "kcp.smuxbuf")
|
||||||
|
d.md.config.StreamBuf = mdutil.GetInt(md, "kcp.streambuf")
|
||||||
|
d.md.config.NoComp = mdutil.GetBool(md, "kcp.nocomp")
|
||||||
|
|
||||||
d.md.handshakeTimeout = mdutil.GetDuration(md, handshakeTimeout)
|
d.md.handshakeTimeout = mdutil.GetDuration(md, handshakeTimeout)
|
||||||
return
|
return
|
||||||
|
@ -67,7 +67,7 @@ func (d *mtcpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO
|
|||||||
opt(&options)
|
opt(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err = options.NetDialer.Dial(ctx, "tcp", addr)
|
conn, err = options.Dialer.Dial(ctx, "tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ func (d *mtlsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO
|
|||||||
opt(&options)
|
opt(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err = options.NetDialer.Dial(ctx, "tcp", addr)
|
conn, err = options.Dialer.Dial(ctx, "tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ func (d *mwsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp
|
|||||||
opt(&options)
|
opt(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err = options.NetDialer.Dial(ctx, "tcp", addr)
|
conn, err = options.Dialer.Dial(ctx, "tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
type obfsHTTPConn struct {
|
type obfsHTTPConn struct {
|
||||||
net.Conn
|
net.Conn
|
||||||
host string
|
host string
|
||||||
|
path string
|
||||||
rbuf bytes.Buffer
|
rbuf bytes.Buffer
|
||||||
wbuf bytes.Buffer
|
wbuf bytes.Buffer
|
||||||
headerDrained bool
|
headerDrained bool
|
||||||
|
@ -2,6 +2,7 @@ package http
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/go-gost/core/dialer"
|
"github.com/go-gost/core/dialer"
|
||||||
@ -12,11 +13,13 @@ import (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.DialerRegistry().Register("ohttp", NewDialer)
|
registry.DialerRegistry().Register("ohttp", NewDialer)
|
||||||
|
registry.DialerRegistry().Register("ohttps", NewDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type obfsHTTPDialer struct {
|
type obfsHTTPDialer struct {
|
||||||
md metadata
|
tlsEnabled bool
|
||||||
logger logger.Logger
|
md metadata
|
||||||
|
logger logger.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDialer(opts ...dialer.Option) dialer.Dialer {
|
func NewDialer(opts ...dialer.Option) dialer.Dialer {
|
||||||
@ -30,6 +33,18 @@ func NewDialer(opts ...dialer.Option) dialer.Dialer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewTLSDialer(opts ...dialer.Option) dialer.Dialer {
|
||||||
|
options := &dialer.Options{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &obfsHTTPDialer{
|
||||||
|
tlsEnabled: true,
|
||||||
|
logger: options.Logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (d *obfsHTTPDialer) Init(md md.Metadata) (err error) {
|
func (d *obfsHTTPDialer) Init(md md.Metadata) (err error) {
|
||||||
return d.parseMetadata(md)
|
return d.parseMetadata(md)
|
||||||
}
|
}
|
||||||
@ -40,7 +55,7 @@ func (d *obfsHTTPDialer) Dial(ctx context.Context, addr string, opts ...dialer.D
|
|||||||
opt(options)
|
opt(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := options.NetDialer.Dial(ctx, "tcp", addr)
|
conn, err := options.Dialer.Dial(ctx, "tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.logger.Error(err)
|
d.logger.Error(err)
|
||||||
}
|
}
|
||||||
@ -59,9 +74,16 @@ func (d *obfsHTTPDialer) Handshake(ctx context.Context, conn net.Conn, options .
|
|||||||
host = opts.Addr
|
host = opts.Addr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if d.tlsEnabled {
|
||||||
|
conn = tls.Client(conn, &tls.Config{
|
||||||
|
ServerName: host,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return &obfsHTTPConn{
|
return &obfsHTTPConn{
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
host: host,
|
host: host,
|
||||||
|
path: d.md.path,
|
||||||
header: d.md.header,
|
header: d.md.header,
|
||||||
logger: d.logger,
|
logger: d.logger,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -7,24 +7,29 @@ import (
|
|||||||
mdutil "github.com/go-gost/core/metadata/util"
|
mdutil "github.com/go-gost/core/metadata/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultPath = "/"
|
||||||
|
)
|
||||||
|
|
||||||
type metadata struct {
|
type metadata struct {
|
||||||
host string
|
host string
|
||||||
|
path string
|
||||||
header http.Header
|
header http.Header
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *obfsHTTPDialer) parseMetadata(md mdata.Metadata) (err error) {
|
func (d *obfsHTTPDialer) parseMetadata(md mdata.Metadata) (err error) {
|
||||||
const (
|
d.md.host = mdutil.GetString(md, "obfs.host", "host")
|
||||||
header = "header"
|
d.md.path = mdutil.GetString(md, "obfs.path", "path")
|
||||||
host = "host"
|
if d.md.path == "" {
|
||||||
)
|
d.md.path = defaultPath
|
||||||
|
}
|
||||||
|
|
||||||
if m := mdutil.GetStringMapString(md, header); len(m) > 0 {
|
if m := mdutil.GetStringMapString(md, "obfs.header", "header"); len(m) > 0 {
|
||||||
h := http.Header{}
|
h := http.Header{}
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
h.Add(k, v)
|
h.Add(k, v)
|
||||||
}
|
}
|
||||||
d.md.header = h
|
d.md.header = h
|
||||||
}
|
}
|
||||||
d.md.host = mdutil.GetString(md, host)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ func (d *obfsTLSDialer) Dial(ctx context.Context, addr string, opts ...dialer.Di
|
|||||||
opt(options)
|
opt(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := options.NetDialer.Dial(ctx, "tcp", addr)
|
conn, err := options.Dialer.Dial(ctx, "tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.logger.Error(err)
|
d.logger.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ func (d *phtDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp
|
|||||||
tr := &http.Transport{
|
tr := &http.Transport{
|
||||||
// Proxy: http.ProxyFromEnvironment,
|
// Proxy: http.ProxyFromEnvironment,
|
||||||
DialContext: func(ctx context.Context, network, adr string) (net.Conn, error) {
|
DialContext: func(ctx context.Context, network, adr string) (net.Conn, error) {
|
||||||
return options.NetDialer.Dial(ctx, network, addr)
|
return options.Dialer.Dial(ctx, network, addr)
|
||||||
},
|
},
|
||||||
ForceAttemptHTTP2: true,
|
ForceAttemptHTTP2: true,
|
||||||
MaxIdleConns: 100,
|
MaxIdleConns: 100,
|
||||||
|
@ -67,7 +67,7 @@ func (d *quicDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO
|
|||||||
opt(options)
|
opt(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := options.NetDialer.Dial(ctx, "udp", "")
|
c, err := options.Dialer.Dial(ctx, "udp", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -114,7 +114,7 @@ func (d *quicDialer) initSession(ctx context.Context, addr net.Addr, conn net.Pa
|
|||||||
}
|
}
|
||||||
|
|
||||||
tlsCfg := d.options.TLSConfig
|
tlsCfg := d.options.TLSConfig
|
||||||
tlsCfg.NextProtos = []string{"http/3", "quic/v1"}
|
tlsCfg.NextProtos = []string{"h3", "quic/v1"}
|
||||||
|
|
||||||
session, err := quic.DialEarly(ctx, conn, addr, tlsCfg, quicConfig)
|
session, err := quic.DialEarly(ctx, conn, addr, tlsCfg, quicConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -31,7 +31,7 @@ func (d *quicDialer) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
d.md.cipherKey = []byte(key)
|
d.md.cipherKey = []byte(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !md.IsExists(keepAlive) || mdutil.GetBool(md, keepAlive) {
|
if md == nil || !md.IsExists(keepAlive) || mdutil.GetBool(md, keepAlive) {
|
||||||
d.md.keepAlivePeriod = mdutil.GetDuration(md, keepAlivePeriod)
|
d.md.keepAlivePeriod = mdutil.GetDuration(md, keepAlivePeriod)
|
||||||
if d.md.keepAlivePeriod <= 0 {
|
if d.md.keepAlivePeriod <= 0 {
|
||||||
d.md.keepAlivePeriod = 10 * time.Second
|
d.md.keepAlivePeriod = 10 * time.Second
|
||||||
|
@ -64,7 +64,7 @@ func (d *sshDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp
|
|||||||
opt(&options)
|
opt(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err = options.NetDialer.Dial(ctx, "tcp", addr)
|
conn, err = options.Dialer.Dial(ctx, "tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
package ssh
|
package ssh
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
mdata "github.com/go-gost/core/metadata"
|
mdata "github.com/go-gost/core/metadata"
|
||||||
mdutil "github.com/go-gost/core/metadata/util"
|
mdutil "github.com/go-gost/core/metadata/util"
|
||||||
|
"github.com/mitchellh/go-homedir"
|
||||||
|
"github.com/zalando/go-keyring"
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -20,21 +23,35 @@ type metadata struct {
|
|||||||
|
|
||||||
func (d *sshDialer) parseMetadata(md mdata.Metadata) (err error) {
|
func (d *sshDialer) parseMetadata(md mdata.Metadata) (err error) {
|
||||||
const (
|
const (
|
||||||
handshakeTimeout = "handshakeTimeout"
|
handshakeTimeout = "handshakeTimeout"
|
||||||
privateKeyFile = "privateKeyFile"
|
privateKeyFile = "privateKeyFile"
|
||||||
passphrase = "passphrase"
|
passphrase = "passphrase"
|
||||||
|
passphraseFromKeyring = "passphraseFromKeyring"
|
||||||
)
|
)
|
||||||
|
|
||||||
if key := mdutil.GetString(md, privateKeyFile); key != "" {
|
if key := mdutil.GetString(md, privateKeyFile); key != "" {
|
||||||
|
key, err = homedir.Expand(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
data, err := os.ReadFile(key)
|
data, err := os.ReadFile(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if pp := mdutil.GetString(md, passphrase); pp != "" {
|
var pp string
|
||||||
d.md.signer, err = ssh.ParsePrivateKeyWithPassphrase(data, []byte(pp))
|
if mdutil.GetBool(md, passphraseFromKeyring) {
|
||||||
|
pp, err = keyring.Get(fmt.Sprintf("SSH %s", key), d.options.Auth.Username())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to get secret(%s) from keyring: %w", key, err)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
pp = mdutil.GetString(md, passphrase)
|
||||||
|
}
|
||||||
|
if pp == "" {
|
||||||
d.md.signer, err = ssh.ParsePrivateKey(data)
|
d.md.signer, err = ssh.ParsePrivateKey(data)
|
||||||
|
} else {
|
||||||
|
d.md.signer, err = ssh.ParsePrivateKeyWithPassphrase(data, []byte(pp))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -64,7 +64,7 @@ func (d *sshdDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO
|
|||||||
opt(&options)
|
opt(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err = options.NetDialer.Dial(ctx, "tcp", addr)
|
conn, err = options.Dialer.Dial(ctx, "tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
package sshd
|
package sshd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
mdata "github.com/go-gost/core/metadata"
|
mdata "github.com/go-gost/core/metadata"
|
||||||
mdutil "github.com/go-gost/core/metadata/util"
|
mdutil "github.com/go-gost/core/metadata/util"
|
||||||
|
"github.com/mitchellh/go-homedir"
|
||||||
|
"github.com/zalando/go-keyring"
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,12 +29,24 @@ func (d *sshdDialer) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if key := mdutil.GetString(md, privateKeyFile); key != "" {
|
if key := mdutil.GetString(md, privateKeyFile); key != "" {
|
||||||
|
key, err = homedir.Expand(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
data, err := os.ReadFile(key)
|
data, err := os.ReadFile(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
pp := mdutil.GetString(md, passphrase)
|
var pp string
|
||||||
|
if mdutil.GetBool(md, "passphraseFromKeyring") {
|
||||||
|
pp, err = keyring.Get(fmt.Sprintf("SSH %s", key), key)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to get secret(%s) from keyring: %w", key, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pp = mdutil.GetString(md, passphrase)
|
||||||
|
}
|
||||||
if pp == "" {
|
if pp == "" {
|
||||||
d.md.signer, err = ssh.ParsePrivateKey(data)
|
d.md.signer, err = ssh.ParsePrivateKey(data)
|
||||||
} else {
|
} else {
|
||||||
|
@ -40,7 +40,7 @@ func (d *tcpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp
|
|||||||
opt(&options)
|
opt(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := options.NetDialer.Dial(ctx, "tcp", addr)
|
conn, err := options.Dialer.Dial(ctx, "tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.logger.Error(err)
|
d.logger.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ func (d *tlsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp
|
|||||||
opt(&options)
|
opt(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := options.NetDialer.Dial(ctx, "tcp", addr)
|
conn, err := options.Dialer.Dial(ctx, "tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.logger.Error(err)
|
d.logger.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ func (d *udpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp
|
|||||||
opt(&options)
|
opt(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := options.NetDialer.Dial(ctx, "udp", addr)
|
c, err := options.Dialer.Dial(ctx, "udp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
48
dialer/wg/dialer.go
Normal file
48
dialer/wg/dialer.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package wg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/go-gost/core/dialer"
|
||||||
|
"github.com/go-gost/core/logger"
|
||||||
|
md "github.com/go-gost/core/metadata"
|
||||||
|
"github.com/go-gost/x/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.DialerRegistry().Register("wg", NewDialer)
|
||||||
|
}
|
||||||
|
|
||||||
|
type wgDialer struct {
|
||||||
|
md metadata
|
||||||
|
logger logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDialer(opts ...dialer.Option) dialer.Dialer {
|
||||||
|
options := &dialer.Options{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &wgDialer{
|
||||||
|
logger: options.Logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *wgDialer) Init(md md.Metadata) (err error) {
|
||||||
|
return d.parseMetadata(md)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *wgDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (net.Conn, error) {
|
||||||
|
var options dialer.DialOptions
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := options.Dialer.Dial(ctx, "tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
d.logger.Error(err)
|
||||||
|
}
|
||||||
|
return conn, err
|
||||||
|
}
|
23
dialer/wg/metadata.go
Normal file
23
dialer/wg/metadata.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package wg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
md "github.com/go-gost/core/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
dialTimeout = "dialTimeout"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultDialTimeout = 5 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
type metadata struct {
|
||||||
|
dialTimeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *wgDialer) parseMetadata(md md.Metadata) (err error) {
|
||||||
|
return
|
||||||
|
}
|
@ -59,7 +59,7 @@ func (d *wsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOpt
|
|||||||
opt(&options)
|
opt(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := options.NetDialer.Dial(ctx, "tcp", addr)
|
conn, err := options.Dialer.Dial(ctx, "tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.options.Logger.Error(err)
|
d.options.Logger.Error(err)
|
||||||
}
|
}
|
||||||
|
127
go.mod
127
go.mod
@ -1,116 +1,121 @@
|
|||||||
module github.com/go-gost/x
|
module github.com/go-gost/x
|
||||||
|
|
||||||
go 1.21
|
go 1.22
|
||||||
|
|
||||||
|
toolchain go1.22.2
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137
|
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137
|
||||||
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.6.0
|
||||||
github.com/gin-gonic/gin v1.9.1
|
github.com/gin-gonic/gin v1.9.1
|
||||||
github.com/go-gost/core v0.0.0-20231113123850-a916f0401649
|
github.com/go-gost/core v0.1.1
|
||||||
github.com/go-gost/gosocks4 v0.0.1
|
github.com/go-gost/gosocks4 v0.0.1
|
||||||
github.com/go-gost/gosocks5 v0.4.0
|
github.com/go-gost/gosocks5 v0.4.2
|
||||||
github.com/go-gost/plugin v0.0.0-20231109123346-0ae4157b9d25
|
github.com/go-gost/plugin v0.0.0-20240103125338-9c84e29cb81a
|
||||||
github.com/go-gost/relay v0.4.1-0.20230916134211-828f314ddfe7
|
github.com/go-gost/relay v0.5.0
|
||||||
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451
|
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451
|
||||||
github.com/go-redis/redis/v8 v8.11.5
|
github.com/go-redis/redis/v8 v8.11.5
|
||||||
github.com/gobwas/glob v0.2.3
|
github.com/gobwas/glob v0.2.3
|
||||||
github.com/golang/snappy v0.0.4
|
github.com/golang/snappy v0.0.4
|
||||||
github.com/google/uuid v1.4.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/gorilla/websocket v1.5.0
|
github.com/gorilla/websocket v1.5.1
|
||||||
github.com/miekg/dns v1.1.56
|
github.com/miekg/dns v1.1.61
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
github.com/pion/dtls/v2 v2.2.6
|
github.com/pion/dtls/v2 v2.2.6
|
||||||
github.com/pires/go-proxyproto v0.7.0
|
github.com/pires/go-proxyproto v0.7.0
|
||||||
github.com/prometheus/client_golang v1.17.0
|
github.com/prometheus/client_golang v1.19.1
|
||||||
github.com/quic-go/quic-go v0.39.0
|
github.com/quic-go/quic-go v0.45.0
|
||||||
github.com/quic-go/webtransport-go v0.6.0
|
github.com/quic-go/webtransport-go v0.8.0
|
||||||
github.com/refraction-networking/utls v1.5.4
|
|
||||||
github.com/rs/xid v1.3.0
|
github.com/rs/xid v1.3.0
|
||||||
github.com/shadowsocks/go-shadowsocks2 v0.1.5
|
github.com/shadowsocks/go-shadowsocks2 v0.1.5
|
||||||
github.com/shadowsocks/shadowsocks-go v0.0.0-20200409064450-3e585ff90601
|
github.com/shadowsocks/shadowsocks-go v0.0.0-20200409064450-3e585ff90601
|
||||||
github.com/sirupsen/logrus v1.8.1
|
github.com/sirupsen/logrus v1.8.1
|
||||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
|
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
|
||||||
github.com/spf13/viper v1.14.0
|
github.com/spf13/viper v1.18.2
|
||||||
github.com/vishvananda/netlink v1.1.0
|
github.com/vishvananda/netlink v1.1.0
|
||||||
github.com/xtaci/kcp-go/v5 v5.6.1
|
github.com/vishvananda/netns v0.0.4
|
||||||
|
github.com/xtaci/kcp-go/v5 v5.6.5
|
||||||
github.com/xtaci/smux v1.5.24
|
github.com/xtaci/smux v1.5.24
|
||||||
github.com/xtaci/tcpraw v1.2.25
|
github.com/xtaci/tcpraw v1.2.25
|
||||||
github.com/yl2chen/cidranger v1.0.2
|
github.com/yl2chen/cidranger v1.0.2
|
||||||
golang.org/x/crypto v0.14.0
|
github.com/zalando/go-keyring v0.2.4
|
||||||
golang.org/x/net v0.17.0
|
golang.org/x/crypto v0.25.0
|
||||||
golang.org/x/sys v0.13.0
|
golang.org/x/net v0.27.0
|
||||||
golang.org/x/time v0.3.0
|
golang.org/x/sys v0.22.0
|
||||||
|
golang.org/x/time v0.5.0
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478
|
golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478
|
||||||
google.golang.org/grpc v1.59.0
|
google.golang.org/grpc v1.65.0
|
||||||
google.golang.org/protobuf v1.31.0
|
google.golang.org/protobuf v1.34.2
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
|
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
|
||||||
|
github.com/alessio/shellescape v1.4.1 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/bytedance/sonic v1.9.1 // indirect
|
github.com/bytedance/sonic v1.11.2 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||||
|
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
||||||
github.com/coreos/go-iptables v0.5.0 // indirect
|
github.com/coreos/go-iptables v0.5.0 // indirect
|
||||||
|
github.com/danieljoos/wincred v1.2.0 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
github.com/go-playground/validator/v10 v10.19.0 // indirect
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||||
github.com/google/gopacket v1.1.19 // indirect
|
github.com/google/gopacket v1.1.19 // indirect
|
||||||
github.com/google/pprof v0.0.0-20230912144702-c363fe2c2ed8 // indirect
|
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/cpuid v1.3.1 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
github.com/klauspost/reedsolomon v1.11.8 // indirect
|
||||||
github.com/klauspost/reedsolomon v1.9.9 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/leodido/go-urn v1.2.4 // indirect
|
|
||||||
github.com/magiconair/properties v1.8.7 // indirect
|
github.com/magiconair/properties v1.8.7 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104 // indirect
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/onsi/ginkgo/v2 v2.12.0 // indirect
|
github.com/onsi/ginkgo/v2 v2.19.0 // indirect
|
||||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
|
||||||
github.com/pion/logging v0.2.2 // indirect
|
github.com/pion/logging v0.2.2 // indirect
|
||||||
github.com/pion/transport/v2 v2.0.2 // indirect
|
github.com/pion/transport/v2 v2.0.2 // indirect
|
||||||
github.com/pion/udp/v2 v2.0.1 // indirect
|
github.com/pion/udp/v2 v2.0.1 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
|
github.com/prometheus/client_model v0.5.0 // indirect
|
||||||
github.com/prometheus/common v0.44.0 // indirect
|
github.com/prometheus/common v0.48.0 // indirect
|
||||||
github.com/prometheus/procfs v0.11.1 // indirect
|
github.com/prometheus/procfs v0.12.0 // indirect
|
||||||
github.com/quic-go/qpack v0.4.0 // indirect
|
github.com/quic-go/qpack v0.4.0 // indirect
|
||||||
github.com/quic-go/qtls-go1-20 v0.3.4 // indirect
|
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||||
github.com/spf13/afero v1.9.3 // indirect
|
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||||
github.com/spf13/cast v1.5.0 // indirect
|
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||||
|
github.com/spf13/afero v1.11.0 // indirect
|
||||||
|
github.com/spf13/cast v1.6.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/subosito/gotenv v1.4.1 // indirect
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
github.com/templexxx/cpu v0.0.7 // indirect
|
github.com/templexxx/cpu v0.1.0 // indirect
|
||||||
github.com/templexxx/xorsimd v0.4.1 // indirect
|
github.com/templexxx/xorsimd v0.4.2 // indirect
|
||||||
github.com/tjfoc/gmsm v1.3.2 // indirect
|
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect
|
go.uber.org/mock v0.4.0 // indirect
|
||||||
go.uber.org/mock v0.3.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.7.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 // indirect
|
||||||
golang.org/x/mod v0.12.0 // indirect
|
golang.org/x/mod v0.19.0 // indirect
|
||||||
golang.org/x/text v0.13.0 // indirect
|
golang.org/x/sync v0.7.0 // indirect
|
||||||
golang.org/x/tools v0.13.0 // indirect
|
golang.org/x/text v0.16.0 // indirect
|
||||||
|
golang.org/x/tools v0.23.0 // indirect
|
||||||
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
|
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
|
||||||
)
|
)
|
||||||
|
654
go.sum
654
go.sum
@ -1,267 +1,161 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
|
||||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
|
||||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
|
||||||
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
|
||||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
|
||||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
|
||||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
|
||||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
|
||||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
|
||||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
|
||||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
|
||||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
|
||||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
|
||||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
|
||||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
|
||||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
|
||||||
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
|
|
||||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
|
||||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
|
||||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
|
||||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
|
||||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
|
||||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
|
||||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
|
||||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
|
||||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
|
||||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
|
||||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
|
||||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
|
||||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
|
||||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
|
||||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
|
||||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
|
||||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
|
||||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
|
||||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
||||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
|
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
|
||||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
|
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
|
||||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||||
|
github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0=
|
||||||
|
github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ=
|
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||||
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
|
||||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
github.com/bytedance/sonic v1.11.2 h1:ywfwo0a/3j9HR8wsYGWsIWl2mvRsI950HyoxiBERw5A=
|
||||||
|
github.com/bytedance/sonic v1.11.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||||
|
github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=
|
||||||
|
github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
|
||||||
github.com/coreos/go-iptables v0.5.0 h1:mw6SAibtHKZcNzAsOxjoHIG0gy5YFHhypWSSNc6EjbQ=
|
github.com/coreos/go-iptables v0.5.0 h1:mw6SAibtHKZcNzAsOxjoHIG0gy5YFHhypWSSNc6EjbQ=
|
||||||
github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
|
github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
|
||||||
|
github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE=
|
||||||
|
github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
|
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
|
||||||
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
|
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
|
||||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||||
github.com/gin-contrib/cors v1.3.1 h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA=
|
github.com/gin-contrib/cors v1.6.0 h1:0Z7D/bVhE6ja07lI8CTjTonp6SB07o8bNuFyRbsBUQg=
|
||||||
github.com/gin-contrib/cors v1.3.1/go.mod h1:jjEJ4268OPZUcU7k9Pm653S7lXUGcqMADzFA61xsmDk=
|
github.com/gin-contrib/cors v1.6.0/go.mod h1:cI+h6iOAyxKRtUtC6iF/Si1KSFvGm/gK+kshxlCi8ro=
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
|
|
||||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-gost/core v0.1.1 h1:8joR9KJYBvpurNu3i0zqN9orQthVzOjhtT4STumwNF0=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gost/core v0.1.1/go.mod h1:WGI43jOka7FAsSAwi/fSMaqxdR+E339ycb4NBGlFr6A=
|
||||||
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-20231109123312-8e4fc06cf1b7 h1:sDsPtmP51qf8zN/RbZZj/3vNLCoH0sdvpIRwV6TfzvY=
|
|
||||||
github.com/go-gost/core v0.0.0-20231109123312-8e4fc06cf1b7/go.mod h1:ndkgWVYRLwupVaFFWv8ML1Nr8tD3xhHK245PLpUDg4E=
|
|
||||||
github.com/go-gost/core v0.0.0-20231113123850-a916f0401649 h1:14iGAk7cqc+aDWtsuY6CWpP0lvC54pA5Izjeh5FdQNs=
|
|
||||||
github.com/go-gost/core v0.0.0-20231113123850-a916f0401649/go.mod h1:ndkgWVYRLwupVaFFWv8ML1Nr8tD3xhHK245PLpUDg4E=
|
|
||||||
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.4.0 h1:EIrOEkpJez4gwHrMa33frA+hHXJyevjp47thpMQsJzI=
|
github.com/go-gost/gosocks5 v0.4.2 h1:IianxHTkACPqCwiOAT3MHoMdSUl+SEPSRu1ikawC1Pc=
|
||||||
github.com/go-gost/gosocks5 v0.4.0/go.mod h1:1G6I7HP7VFVxveGkoK8mnprnJqSqJjdcASKsdUn4Pp4=
|
github.com/go-gost/gosocks5 v0.4.2/go.mod h1:1G6I7HP7VFVxveGkoK8mnprnJqSqJjdcASKsdUn4Pp4=
|
||||||
github.com/go-gost/plugin v0.0.0-20231109123346-0ae4157b9d25 h1:sOarC0xAJij4VtEhkJRng5okZW23KlXprxhb5XFZ+pw=
|
github.com/go-gost/plugin v0.0.0-20240103125338-9c84e29cb81a h1:ME7P1Brcg4C640DSPqlvQr7JuvvQfJ8QpmS3yCFlK3A=
|
||||||
github.com/go-gost/plugin v0.0.0-20231109123346-0ae4157b9d25/go.mod h1:qXr2Zm9Ex2ATqnWuNUzVZqySPMnuIihvblYZt4MlZLw=
|
github.com/go-gost/plugin v0.0.0-20240103125338-9c84e29cb81a/go.mod h1:qXr2Zm9Ex2ATqnWuNUzVZqySPMnuIihvblYZt4MlZLw=
|
||||||
github.com/go-gost/relay v0.4.1-0.20230916134211-828f314ddfe7 h1:qAG1OyjvdA5h221CfFSS3J359V3d2E7dJWyP29QoDSI=
|
github.com/go-gost/relay v0.5.0 h1:JG1tgy/KWiVXS0ukuVXvbM0kbYuJTWxYpJ5JwzsCf/c=
|
||||||
github.com/go-gost/relay v0.4.1-0.20230916134211-828f314ddfe7/go.mod h1:lcX+23LCQ3khIeASBo+tJ/WbwXFO32/N5YN6ucuYTG8=
|
github.com/go-gost/relay v0.5.0/go.mod h1:lcX+23LCQ3khIeASBo+tJ/WbwXFO32/N5YN6ucuYTG8=
|
||||||
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451 h1:xj8gUZGYO3nb5+6Bjw9+tsFkA9sYynrOvDvvC4uDV2I=
|
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451 h1:xj8gUZGYO3nb5+6Bjw9+tsFkA9sYynrOvDvvC4uDV2I=
|
||||||
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451/go.mod h1:/9QfdewqmHdaE362Hv5nDaSWLx3pCmtD870d6GaquXs=
|
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451/go.mod h1:/9QfdewqmHdaE362Hv5nDaSWLx3pCmtD870d6GaquXs=
|
||||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
|
||||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
|
|
||||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4=
|
||||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
|
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||||
|
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
|
||||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
|
||||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
|
||||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
|
||||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
|
||||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
|
||||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
|
||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
|
||||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g=
|
||||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
|
||||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
|
||||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
|
||||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
|
||||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/google/pprof v0.0.0-20230912144702-c363fe2c2ed8 h1:gpptm606MZYGaMHMsB4Srmb6EbW/IVHnt04rcMXnkBQ=
|
|
||||||
github.com/google/pprof v0.0.0-20230912144702-c363fe2c2ed8/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
|
||||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
|
||||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
|
||||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
|
||||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
|
||||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
|
||||||
github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
|
||||||
github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s=
|
|
||||||
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
github.com/klauspost/reedsolomon v1.9.9 h1:qCL7LZlv17xMixl55nq2/Oa1Y86nfO8EqDfv2GHND54=
|
github.com/klauspost/reedsolomon v1.11.8 h1:s8RpUW5TK4hjr+djiOpbZJB4ksx+TdYbRH7vHQpwPOY=
|
||||||
github.com/klauspost/reedsolomon v1.9.9/go.mod h1:O7yFFHiQwDR6b2t63KPUpccPtNdp5ADgh1gg4fd12wo=
|
github.com/klauspost/reedsolomon v1.11.8/go.mod h1:4bXRN+cVzMdml6ti7qLouuYi32KHJ5MGv0Qd8a47h6A=
|
||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
|
||||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY=
|
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104 h1:ULR/QWMgcgRiZLUjSSJMU+fW+RDMstRdmnDWj9Q+AsA=
|
|
||||||
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104/go.mod h1:wqKykBG2QzQDJEzvRkcS8x6MiSJkF52hXZsXcjaB3ls=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
github.com/onsi/ginkgo/v2 v2.12.0 h1:UIVDowFPwpg6yMUpPjGkYvf06K3RAiJXUhCxEwQVHRI=
|
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
|
||||||
github.com/onsi/ginkgo/v2 v2.12.0/go.mod h1:ZNEzXISYlqpb8S36iN71ifqLi3vVD1rVJGvWRCJOUpQ=
|
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
||||||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
|
||||||
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
|
||||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
|
||||||
github.com/pion/dtls/v2 v2.2.6 h1:yXMxKr0Skd+Ub6A8UqXTRLSywskx93ooMRHsQUtd+Z4=
|
github.com/pion/dtls/v2 v2.2.6 h1:yXMxKr0Skd+Ub6A8UqXTRLSywskx93ooMRHsQUtd+Z4=
|
||||||
github.com/pion/dtls/v2 v2.2.6/go.mod h1:t8fWJCIquY5rlQZwA2yWxUS1+OCrAdXrhVKXB5oD/wY=
|
github.com/pion/dtls/v2 v2.2.6/go.mod h1:t8fWJCIquY5rlQZwA2yWxUS1+OCrAdXrhVKXB5oD/wY=
|
||||||
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
||||||
@ -274,34 +168,34 @@ github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwy
|
|||||||
github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
|
github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
||||||
|
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM=
|
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
|
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
|
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
||||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||||
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
|
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||||
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
|
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||||
github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg=
|
github.com/quic-go/quic-go v0.45.0 h1:OHmkQGM37luZITyTSu6ff03HP/2IrwDX1ZFiNEhSFUE=
|
||||||
github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
github.com/quic-go/quic-go v0.45.0/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI=
|
||||||
github.com/quic-go/quic-go v0.39.0 h1:AgP40iThFMY0bj8jGxROhw3S0FMGa8ryqsmi9tBH3So=
|
github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg=
|
||||||
github.com/quic-go/quic-go v0.39.0/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q=
|
github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM=
|
||||||
github.com/quic-go/webtransport-go v0.6.0 h1:CvNsKqc4W2HljHJnoT+rMmbRJybShZ0YPFDD3NxaZLY=
|
|
||||||
github.com/quic-go/webtransport-go v0.6.0/go.mod h1:9KjU4AEBqEQidGHNDkZrb8CAa1abRaosM2yGOyiikEc=
|
|
||||||
github.com/refraction-networking/utls v1.5.4/go.mod h1:SPuDbBmgLGp8s+HLNc83FuavwZCFoMmExj+ltUHiHUw=
|
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
|
||||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||||
github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4=
|
github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4=
|
||||||
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
|
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||||
|
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||||
github.com/shadowsocks/go-shadowsocks2 v0.1.5 h1:PDSQv9y2S85Fl7VBeOMF9StzeXZyK1HakRm86CUbr28=
|
github.com/shadowsocks/go-shadowsocks2 v0.1.5 h1:PDSQv9y2S85Fl7VBeOMF9StzeXZyK1HakRm86CUbr28=
|
||||||
github.com/shadowsocks/go-shadowsocks2 v0.1.5/go.mod h1:AGGpIoek4HRno4xzyFiAtLHkOpcoznZEkAccaI/rplM=
|
github.com/shadowsocks/go-shadowsocks2 v0.1.5/go.mod h1:AGGpIoek4HRno4xzyFiAtLHkOpcoznZEkAccaI/rplM=
|
||||||
github.com/shadowsocks/shadowsocks-go v0.0.0-20200409064450-3e585ff90601 h1:XU9hik0exChEmY92ALW4l9WnDodxLVS9yOSNh2SizaQ=
|
github.com/shadowsocks/shadowsocks-go v0.0.0-20200409064450-3e585ff90601 h1:XU9hik0exChEmY92ALW4l9WnDodxLVS9yOSNh2SizaQ=
|
||||||
@ -310,52 +204,48 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE
|
|||||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8=
|
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8=
|
||||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
|
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
|
||||||
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
|
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||||
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
|
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||||
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU=
|
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
|
||||||
github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As=
|
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||||
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
github.com/templexxx/cpu v0.1.0 h1:wVM+WIJP2nYaxVxqgHPD4wGA2aJ9rvrQRV8CvFzNb40=
|
||||||
github.com/templexxx/cpu v0.0.1/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk=
|
github.com/templexxx/cpu v0.1.0/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk=
|
||||||
github.com/templexxx/cpu v0.0.7 h1:pUEZn8JBy/w5yzdYWgx+0m0xL9uk6j4K91C5kOViAzo=
|
github.com/templexxx/xorsimd v0.4.2 h1:ocZZ+Nvu65LGHmCLZ7OoCtg8Fx8jnHKK37SjvngUoVI=
|
||||||
github.com/templexxx/cpu v0.0.7/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk=
|
github.com/templexxx/xorsimd v0.4.2/go.mod h1:HgwaPoDREdi6OnULpSfxhzaiiSUY4Fi3JPn1wpt28NI=
|
||||||
github.com/templexxx/xorsimd v0.4.1 h1:iUZcywbOYDRAZUasAs2eSCUW8eobuZDy0I9FJiORkVg=
|
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||||
github.com/templexxx/xorsimd v0.4.1/go.mod h1:W+ffZz8jJMH2SXwuKu9WhygqBMbFnp14G2fqEr8qaNo=
|
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||||
github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM=
|
|
||||||
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
|
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
|
||||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
|
||||||
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
|
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
|
||||||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
||||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k=
|
|
||||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
|
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
|
||||||
github.com/xtaci/kcp-go/v5 v5.6.1 h1:Pwn0aoeNSPF9dTS7IgiPXn0HEtaIlVb6y5UKWPsx8bI=
|
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||||
github.com/xtaci/kcp-go/v5 v5.6.1/go.mod h1:W3kVPyNYwZ06p79dNwFWQOVFrdcBpDBsdyvK8moQrYo=
|
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||||
|
github.com/xtaci/kcp-go/v5 v5.6.5 h1:oxGZNobj3OddrLzwdJYnR/waNgwrL98u02u0DWNHE3k=
|
||||||
|
github.com/xtaci/kcp-go/v5 v5.6.5/go.mod h1:Qy3Zf2tWTdFdEs0E8JvhrX+39r5UDZoYac8anvud7/Q=
|
||||||
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=
|
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=
|
||||||
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
|
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
|
||||||
github.com/xtaci/smux v1.5.24 h1:77emW9dtnOxxOQ5ltR+8BbsX1kzcOxQ5gB+aaV9hXOY=
|
github.com/xtaci/smux v1.5.24 h1:77emW9dtnOxxOQ5ltR+8BbsX1kzcOxQ5gB+aaV9hXOY=
|
||||||
@ -364,384 +254,138 @@ github.com/xtaci/tcpraw v1.2.25 h1:VDlqo0op17JeXBM6e2G9ocCNLOJcw9mZbobMbJjo0vk=
|
|||||||
github.com/xtaci/tcpraw v1.2.25/go.mod h1:dKyZ2V75s0cZ7cbgJYdxPvms7af0joIeOyx1GgJQbLk=
|
github.com/xtaci/tcpraw v1.2.25/go.mod h1:dKyZ2V75s0cZ7cbgJYdxPvms7af0joIeOyx1GgJQbLk=
|
||||||
github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU=
|
github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU=
|
||||||
github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g=
|
github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
github.com/zalando/go-keyring v0.2.4 h1:wi2xxTqdiwMKbM6TWwi+uJCG/Tum2UV0jqaQhCa9/68=
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
github.com/zalando/go-keyring v0.2.4/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk=
|
||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
|
|
||||||
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
|
||||||
golang.org/x/arch v0.0.0-20190909030613-46d78d1859ac/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
|
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
|
||||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
|
||||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
||||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 h1:LoYXNGAShUG3m/ehNk4iFctuhGX/+R1ZpfJ4/ia80JM=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
|
||||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
|
||||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
|
||||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
|
||||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
|
||||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
|
||||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
|
||||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
|
||||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
|
||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
|
||||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
|
||||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
|
||||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
||||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
|
||||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
|
||||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
|
||||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
|
||||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
|
||||||
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
|
||||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
|
||||||
golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
|
||||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
|
||||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
|
||||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
|
||||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY=
|
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY=
|
||||||
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478 h1:vDy//hdR+GnROE3OdYbQKt9rdtNdHkDtONvpRwmls/0=
|
golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478 h1:vDy//hdR+GnROE3OdYbQKt9rdtNdHkDtONvpRwmls/0=
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U=
|
golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U=
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
|
||||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
|
||||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
|
||||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
|
||||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
|
||||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
|
||||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
|
||||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
|
||||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
|
||||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
|
||||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
|
||||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
|
||||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
|
||||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
|
||||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
|
||||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
|
||||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
|
||||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
|
||||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
|
||||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
|
||||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
|
||||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
|
||||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
|
||||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
|
||||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
|
||||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
|
||||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
|
||||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
|
||||||
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
|
|
||||||
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
|
||||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
|
||||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|
||||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
|
||||||
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
|
||||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
|
||||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
|
||||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
|
||||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
md "github.com/go-gost/core/metadata"
|
md "github.com/go-gost/core/metadata"
|
||||||
"github.com/go-gost/gosocks4"
|
"github.com/go-gost/gosocks4"
|
||||||
"github.com/go-gost/gosocks5"
|
"github.com/go-gost/gosocks5"
|
||||||
|
ctxvalue "github.com/go-gost/x/ctx"
|
||||||
netpkg "github.com/go-gost/x/internal/net"
|
netpkg "github.com/go-gost/x/internal/net"
|
||||||
"github.com/go-gost/x/registry"
|
"github.com/go-gost/x/registry"
|
||||||
)
|
)
|
||||||
@ -79,6 +80,7 @@ func (h *autoHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler
|
|||||||
log := h.options.Logger.WithFields(map[string]any{
|
log := h.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
|
"sid": ctxvalue.SidFromContext(ctx),
|
||||||
})
|
})
|
||||||
|
|
||||||
if log.IsLevelEnabled(logger.DebugLevel) {
|
if log.IsLevelEnabled(logger.DebugLevel) {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user