Merge branch 'master' into dev
# Conflicts: # go.mod # go.sum
This commit is contained in:
commit
423dd1e35d
12
api/api.go
12
api/api.go
@ -165,6 +165,18 @@ func registerConfig(config *gin.RouterGroup) {
|
||||
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)
|
||||
|
@ -144,7 +144,7 @@ func saveConfig(ctx *gin.Context) {
|
||||
if err != nil {
|
||||
writeError(ctx, &Error{
|
||||
statusCode: http.StatusInternalServerError,
|
||||
Code: 40005,
|
||||
Code: ErrCodeSaveConfigFailed,
|
||||
Msg: fmt.Sprintf("create file: %s", err.Error()),
|
||||
})
|
||||
return
|
||||
@ -154,8 +154,8 @@ func saveConfig(ctx *gin.Context) {
|
||||
if err := config.Global().Write(f, req.Format); err != nil {
|
||||
writeError(ctx, &Error{
|
||||
statusCode: http.StatusInternalServerError,
|
||||
Code: 40006,
|
||||
Msg: fmt.Sprintf("write: %s", err.Error()),
|
||||
Code: ErrCodeSaveConfigFailed,
|
||||
Msg: fmt.Sprintf("save config: %s", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-gost/x/config"
|
||||
@ -35,15 +37,22 @@ func createAdmission(ctx *gin.Context) {
|
||||
var req createAdmissionRequest
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if req.Data.Name == "" {
|
||||
writeError(ctx, ErrInvalid)
|
||||
name := strings.TrimSpace(req.Data.Name)
|
||||
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
|
||||
}
|
||||
|
||||
v := parser.ParseAdmission(&req.Data)
|
||||
|
||||
if err := registry.AdmissionRegistry().Register(req.Data.Name, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.AdmissionRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("admission %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
@ -87,25 +96,27 @@ func updateAdmission(ctx *gin.Context) {
|
||||
ctx.ShouldBindUri(&req)
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if !registry.AdmissionRegistry().IsRegistered(req.Admission) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Admission)
|
||||
|
||||
if !registry.AdmissionRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("admission %s not found", name)))
|
||||
return
|
||||
}
|
||||
|
||||
req.Data.Name = req.Admission
|
||||
req.Data.Name = name
|
||||
|
||||
v := parser.ParseAdmission(&req.Data)
|
||||
|
||||
registry.AdmissionRegistry().Unregister(req.Admission)
|
||||
registry.AdmissionRegistry().Unregister(name)
|
||||
|
||||
if err := registry.AdmissionRegistry().Register(req.Admission, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.AdmissionRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("admission %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
for i := range c.Admissions {
|
||||
if c.Admissions[i].Name == req.Admission {
|
||||
if c.Admissions[i].Name == name {
|
||||
c.Admissions[i] = &req.Data
|
||||
break
|
||||
}
|
||||
@ -145,17 +156,19 @@ func deleteAdmission(ctx *gin.Context) {
|
||||
var req deleteAdmissionRequest
|
||||
ctx.ShouldBindUri(&req)
|
||||
|
||||
if !registry.AdmissionRegistry().IsRegistered(req.Admission) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Admission)
|
||||
|
||||
if !registry.AdmissionRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("admission %s not found", name)))
|
||||
return
|
||||
}
|
||||
registry.AdmissionRegistry().Unregister(req.Admission)
|
||||
registry.AdmissionRegistry().Unregister(name)
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
admissiones := c.Admissions
|
||||
c.Admissions = nil
|
||||
for _, s := range admissiones {
|
||||
if s.Name == req.Admission {
|
||||
if s.Name == name {
|
||||
continue
|
||||
}
|
||||
c.Admissions = append(c.Admissions, s)
|
||||
|
@ -1,7 +1,9 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-gost/x/config"
|
||||
@ -35,14 +37,21 @@ func createAuther(ctx *gin.Context) {
|
||||
var req createAutherRequest
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if req.Data.Name == "" {
|
||||
writeError(ctx, ErrInvalid)
|
||||
name := strings.TrimSpace(req.Data.Name)
|
||||
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
|
||||
}
|
||||
|
||||
v := parser.ParseAuther(&req.Data)
|
||||
if err := registry.AutherRegistry().Register(req.Data.Name, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.AutherRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("auther %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
@ -86,24 +95,26 @@ func updateAuther(ctx *gin.Context) {
|
||||
ctx.ShouldBindUri(&req)
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if !registry.AutherRegistry().IsRegistered(req.Auther) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Auther)
|
||||
|
||||
if !registry.AutherRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("auther %s not found", name)))
|
||||
return
|
||||
}
|
||||
|
||||
req.Data.Name = req.Auther
|
||||
req.Data.Name = name
|
||||
|
||||
v := parser.ParseAuther(&req.Data)
|
||||
registry.AutherRegistry().Unregister(req.Auther)
|
||||
registry.AutherRegistry().Unregister(name)
|
||||
|
||||
if err := registry.AutherRegistry().Register(req.Auther, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.AutherRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("auther %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
for i := range c.Authers {
|
||||
if c.Authers[i].Name == req.Auther {
|
||||
if c.Authers[i].Name == name {
|
||||
c.Authers[i] = &req.Data
|
||||
break
|
||||
}
|
||||
@ -143,17 +154,19 @@ func deleteAuther(ctx *gin.Context) {
|
||||
var req deleteAutherRequest
|
||||
ctx.ShouldBindUri(&req)
|
||||
|
||||
if !registry.AutherRegistry().IsRegistered(req.Auther) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Auther)
|
||||
|
||||
if !registry.AutherRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("auther %s not found", name)))
|
||||
return
|
||||
}
|
||||
registry.AutherRegistry().Unregister(req.Auther)
|
||||
registry.AutherRegistry().Unregister(name)
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
authers := c.Authers
|
||||
c.Authers = nil
|
||||
for _, s := range authers {
|
||||
if s.Name == req.Auther {
|
||||
if s.Name == name {
|
||||
continue
|
||||
}
|
||||
c.Authers = append(c.Authers, s)
|
||||
|
@ -1,7 +1,9 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-gost/x/config"
|
||||
@ -35,15 +37,22 @@ func createBypass(ctx *gin.Context) {
|
||||
var req createBypassRequest
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if req.Data.Name == "" {
|
||||
writeError(ctx, ErrInvalid)
|
||||
name := strings.TrimSpace(req.Data.Name)
|
||||
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
|
||||
}
|
||||
|
||||
v := parser.ParseBypass(&req.Data)
|
||||
|
||||
if err := registry.BypassRegistry().Register(req.Data.Name, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.BypassRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("bypass %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
@ -87,25 +96,27 @@ func updateBypass(ctx *gin.Context) {
|
||||
ctx.ShouldBindUri(&req)
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if !registry.BypassRegistry().IsRegistered(req.Bypass) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Bypass)
|
||||
|
||||
if !registry.BypassRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("bypass %s not found", name)))
|
||||
return
|
||||
}
|
||||
|
||||
req.Data.Name = req.Bypass
|
||||
req.Data.Name = name
|
||||
|
||||
v := parser.ParseBypass(&req.Data)
|
||||
|
||||
registry.BypassRegistry().Unregister(req.Bypass)
|
||||
registry.BypassRegistry().Unregister(name)
|
||||
|
||||
if err := registry.BypassRegistry().Register(req.Bypass, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.BypassRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("bypass %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
for i := range c.Bypasses {
|
||||
if c.Bypasses[i].Name == req.Bypass {
|
||||
if c.Bypasses[i].Name == name {
|
||||
c.Bypasses[i] = &req.Data
|
||||
break
|
||||
}
|
||||
@ -145,17 +156,19 @@ func deleteBypass(ctx *gin.Context) {
|
||||
var req deleteBypassRequest
|
||||
ctx.ShouldBindUri(&req)
|
||||
|
||||
if !registry.BypassRegistry().IsRegistered(req.Bypass) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Bypass)
|
||||
|
||||
if !registry.BypassRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("bypass %s not found", name)))
|
||||
return
|
||||
}
|
||||
registry.BypassRegistry().Unregister(req.Bypass)
|
||||
registry.BypassRegistry().Unregister(name)
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
bypasses := c.Bypasses
|
||||
c.Bypasses = nil
|
||||
for _, s := range bypasses {
|
||||
if s.Name == req.Bypass {
|
||||
if s.Name == name {
|
||||
continue
|
||||
}
|
||||
c.Bypasses = append(c.Bypasses, s)
|
||||
|
@ -1,7 +1,9 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-gost/core/logger"
|
||||
@ -36,19 +38,26 @@ func createChain(ctx *gin.Context) {
|
||||
var req createChainRequest
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if req.Data.Name == "" {
|
||||
writeError(ctx, ErrInvalid)
|
||||
name := strings.TrimSpace(req.Data.Name)
|
||||
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
|
||||
}
|
||||
|
||||
v, err := parser.ParseChain(&req.Data, logger.Default())
|
||||
if err != nil {
|
||||
writeError(ctx, ErrCreate)
|
||||
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create chain %s failed: %s", name, err.Error())))
|
||||
return
|
||||
}
|
||||
|
||||
if err := registry.ChainRegistry().Register(req.Data.Name, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.ChainRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("chain %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
@ -93,29 +102,31 @@ func updateChain(ctx *gin.Context) {
|
||||
ctx.ShouldBindUri(&req)
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if !registry.ChainRegistry().IsRegistered(req.Chain) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Chain)
|
||||
|
||||
if !registry.ChainRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("chain %s not found", name)))
|
||||
return
|
||||
}
|
||||
|
||||
req.Data.Name = req.Chain
|
||||
req.Data.Name = name
|
||||
|
||||
v, err := parser.ParseChain(&req.Data, logger.Default())
|
||||
if err != nil {
|
||||
writeError(ctx, ErrCreate)
|
||||
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create chain %s failed: %s", name, err.Error())))
|
||||
return
|
||||
}
|
||||
|
||||
registry.ChainRegistry().Unregister(req.Chain)
|
||||
registry.ChainRegistry().Unregister(name)
|
||||
|
||||
if err := registry.ChainRegistry().Register(req.Chain, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.ChainRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("chain %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
for i := range c.Chains {
|
||||
if c.Chains[i].Name == req.Chain {
|
||||
if c.Chains[i].Name == name {
|
||||
c.Chains[i] = &req.Data
|
||||
break
|
||||
}
|
||||
@ -155,17 +166,19 @@ func deleteChain(ctx *gin.Context) {
|
||||
var req deleteChainRequest
|
||||
ctx.ShouldBindUri(&req)
|
||||
|
||||
if !registry.ChainRegistry().IsRegistered(req.Chain) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Chain)
|
||||
|
||||
if !registry.ChainRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("chain %s not found", name)))
|
||||
return
|
||||
}
|
||||
registry.ChainRegistry().Unregister(req.Chain)
|
||||
registry.ChainRegistry().Unregister(name)
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
chains := c.Chains
|
||||
c.Chains = nil
|
||||
for _, s := range chains {
|
||||
if s.Name == req.Chain {
|
||||
if s.Name == name {
|
||||
continue
|
||||
}
|
||||
c.Chains = append(c.Chains, s)
|
||||
|
@ -1,7 +1,9 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-gost/x/config"
|
||||
@ -35,15 +37,21 @@ func createConnLimiter(ctx *gin.Context) {
|
||||
var req createConnLimiterRequest
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if req.Data.Name == "" {
|
||||
writeError(ctx, ErrInvalid)
|
||||
name := strings.TrimSpace(req.Data.Name)
|
||||
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
|
||||
}
|
||||
|
||||
v := parser.ParseConnLimiter(&req.Data)
|
||||
|
||||
if err := registry.ConnLimiterRegistry().Register(req.Data.Name, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.ConnLimiterRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create limmiter %s failed: %s", name, err.Error())))
|
||||
return
|
||||
}
|
||||
|
||||
@ -87,25 +95,27 @@ func updateConnLimiter(ctx *gin.Context) {
|
||||
ctx.ShouldBindUri(&req)
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if !registry.ConnLimiterRegistry().IsRegistered(req.Limiter) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Limiter)
|
||||
|
||||
if !registry.ConnLimiterRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("limiter %s not found", name)))
|
||||
return
|
||||
}
|
||||
|
||||
req.Data.Name = req.Limiter
|
||||
req.Data.Name = name
|
||||
|
||||
v := parser.ParseConnLimiter(&req.Data)
|
||||
|
||||
registry.ConnLimiterRegistry().Unregister(req.Limiter)
|
||||
registry.ConnLimiterRegistry().Unregister(name)
|
||||
|
||||
if err := registry.ConnLimiterRegistry().Register(req.Limiter, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.ConnLimiterRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
for i := range c.CLimiters {
|
||||
if c.CLimiters[i].Name == req.Limiter {
|
||||
if c.CLimiters[i].Name == name {
|
||||
c.CLimiters[i] = &req.Data
|
||||
break
|
||||
}
|
||||
@ -145,17 +155,19 @@ func deleteConnLimiter(ctx *gin.Context) {
|
||||
var req deleteConnLimiterRequest
|
||||
ctx.ShouldBindUri(&req)
|
||||
|
||||
if !registry.ConnLimiterRegistry().IsRegistered(req.Limiter) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Limiter)
|
||||
|
||||
if !registry.ConnLimiterRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("limiter %s not found", name)))
|
||||
return
|
||||
}
|
||||
registry.ConnLimiterRegistry().Unregister(req.Limiter)
|
||||
registry.ConnLimiterRegistry().Unregister(name)
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
limiteres := c.CLimiters
|
||||
c.CLimiters = nil
|
||||
for _, s := range limiteres {
|
||||
if s.Name == req.Limiter {
|
||||
if s.Name == name {
|
||||
continue
|
||||
}
|
||||
c.CLimiters = append(c.CLimiters, s)
|
||||
|
@ -1,7 +1,9 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-gost/core/logger"
|
||||
@ -36,19 +38,26 @@ func createHop(ctx *gin.Context) {
|
||||
var req createHopRequest
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if req.Data.Name == "" {
|
||||
writeError(ctx, ErrInvalid)
|
||||
name := strings.TrimSpace(req.Data.Name)
|
||||
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
|
||||
}
|
||||
|
||||
v, err := parser.ParseHop(&req.Data, logger.Default())
|
||||
if err != nil {
|
||||
writeError(ctx, ErrCreate)
|
||||
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create hop %s failed: %s", name, err.Error())))
|
||||
return
|
||||
}
|
||||
|
||||
if err := registry.HopRegistry().Register(req.Data.Name, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.HopRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("hop %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
@ -93,29 +102,30 @@ func updateHop(ctx *gin.Context) {
|
||||
ctx.ShouldBindUri(&req)
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if !registry.HopRegistry().IsRegistered(req.Hop) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Hop)
|
||||
if !registry.HopRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("hop %s not found", name)))
|
||||
return
|
||||
}
|
||||
|
||||
req.Data.Name = req.Hop
|
||||
req.Data.Name = name
|
||||
|
||||
v, err := parser.ParseHop(&req.Data, logger.Default())
|
||||
if err != nil {
|
||||
writeError(ctx, ErrCreate)
|
||||
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create hop %s failed: %s", name, err.Error())))
|
||||
return
|
||||
}
|
||||
|
||||
registry.HopRegistry().Unregister(req.Hop)
|
||||
registry.HopRegistry().Unregister(name)
|
||||
|
||||
if err := registry.HopRegistry().Register(req.Hop, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.HopRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("hop %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
for i := range c.Hops {
|
||||
if c.Hops[i].Name == req.Hop {
|
||||
if c.Hops[i].Name == name {
|
||||
c.Hops[i] = &req.Data
|
||||
break
|
||||
}
|
||||
@ -155,17 +165,19 @@ func deleteHop(ctx *gin.Context) {
|
||||
var req deleteHopRequest
|
||||
ctx.ShouldBindUri(&req)
|
||||
|
||||
if !registry.HopRegistry().IsRegistered(req.Hop) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Hop)
|
||||
|
||||
if !registry.HopRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("hop %s not found", name)))
|
||||
return
|
||||
}
|
||||
registry.HopRegistry().Unregister(req.Hop)
|
||||
registry.HopRegistry().Unregister(name)
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
hops := c.Hops
|
||||
c.Hops = nil
|
||||
for _, s := range hops {
|
||||
if s.Name == req.Hop {
|
||||
if s.Name == name {
|
||||
continue
|
||||
}
|
||||
c.Hops = append(c.Hops, s)
|
||||
|
@ -1,7 +1,9 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-gost/x/config"
|
||||
@ -35,15 +37,22 @@ func createHosts(ctx *gin.Context) {
|
||||
var req createHostsRequest
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if req.Data.Name == "" {
|
||||
writeError(ctx, ErrInvalid)
|
||||
name := strings.TrimSpace(req.Data.Name)
|
||||
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
|
||||
}
|
||||
|
||||
v := parser.ParseHostMapper(&req.Data)
|
||||
|
||||
if err := registry.HostsRegistry().Register(req.Data.Name, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.HostsRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("hosts %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
@ -87,25 +96,27 @@ func updateHosts(ctx *gin.Context) {
|
||||
ctx.ShouldBindUri(&req)
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if !registry.HostsRegistry().IsRegistered(req.Hosts) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Hosts)
|
||||
|
||||
if !registry.HostsRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("hosts %s not found", name)))
|
||||
return
|
||||
}
|
||||
|
||||
req.Data.Name = req.Hosts
|
||||
req.Data.Name = name
|
||||
|
||||
v := parser.ParseHostMapper(&req.Data)
|
||||
|
||||
registry.HostsRegistry().Unregister(req.Hosts)
|
||||
registry.HostsRegistry().Unregister(name)
|
||||
|
||||
if err := registry.HostsRegistry().Register(req.Hosts, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.HostsRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("hosts %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
for i := range c.Hosts {
|
||||
if c.Hosts[i].Name == req.Hosts {
|
||||
if c.Hosts[i].Name == name {
|
||||
c.Hosts[i] = &req.Data
|
||||
break
|
||||
}
|
||||
@ -145,17 +156,19 @@ func deleteHosts(ctx *gin.Context) {
|
||||
var req deleteHostsRequest
|
||||
ctx.ShouldBindUri(&req)
|
||||
|
||||
if !registry.HostsRegistry().IsRegistered(req.Hosts) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Hosts)
|
||||
|
||||
if !registry.HostsRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("hosts %s not found", name)))
|
||||
return
|
||||
}
|
||||
registry.HostsRegistry().Unregister(req.Hosts)
|
||||
registry.HostsRegistry().Unregister(name)
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
hosts := c.Hosts
|
||||
c.Hosts = nil
|
||||
for _, s := range hosts {
|
||||
if s.Name == req.Hosts {
|
||||
if s.Name == name {
|
||||
continue
|
||||
}
|
||||
c.Hosts = append(c.Hosts, s)
|
||||
|
@ -1,7 +1,9 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-gost/x/config"
|
||||
@ -35,15 +37,22 @@ func createIngress(ctx *gin.Context) {
|
||||
var req createIngressRequest
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if req.Data.Name == "" {
|
||||
writeError(ctx, ErrInvalid)
|
||||
name := strings.TrimSpace(req.Data.Name)
|
||||
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
|
||||
}
|
||||
|
||||
v := parser.ParseIngress(&req.Data)
|
||||
|
||||
if err := registry.IngressRegistry().Register(req.Data.Name, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.IngressRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("ingress %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
@ -87,25 +96,27 @@ func updateIngress(ctx *gin.Context) {
|
||||
ctx.ShouldBindUri(&req)
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if !registry.IngressRegistry().IsRegistered(req.Ingress) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Ingress)
|
||||
|
||||
if !registry.IngressRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("ingress %s not found", name)))
|
||||
return
|
||||
}
|
||||
|
||||
req.Data.Name = req.Ingress
|
||||
req.Data.Name = name
|
||||
|
||||
v := parser.ParseIngress(&req.Data)
|
||||
|
||||
registry.IngressRegistry().Unregister(req.Ingress)
|
||||
registry.IngressRegistry().Unregister(name)
|
||||
|
||||
if err := registry.IngressRegistry().Register(req.Ingress, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.IngressRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("ingress %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
for i := range c.Ingresses {
|
||||
if c.Ingresses[i].Name == req.Ingress {
|
||||
if c.Ingresses[i].Name == name {
|
||||
c.Ingresses[i] = &req.Data
|
||||
break
|
||||
}
|
||||
@ -145,17 +156,19 @@ func deleteIngress(ctx *gin.Context) {
|
||||
var req deleteIngressRequest
|
||||
ctx.ShouldBindUri(&req)
|
||||
|
||||
if !registry.IngressRegistry().IsRegistered(req.Ingress) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Ingress)
|
||||
|
||||
if !registry.IngressRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("ingress %s not found", name)))
|
||||
return
|
||||
}
|
||||
registry.IngressRegistry().Unregister(req.Ingress)
|
||||
registry.IngressRegistry().Unregister(name)
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
ingresses := c.Ingresses
|
||||
c.Ingresses = nil
|
||||
for _, s := range ingresses {
|
||||
if s.Name == req.Ingress {
|
||||
if s.Name == name {
|
||||
continue
|
||||
}
|
||||
c.Ingresses = append(c.Ingresses, s)
|
||||
|
@ -1,7 +1,9 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-gost/x/config"
|
||||
@ -35,15 +37,22 @@ func createLimiter(ctx *gin.Context) {
|
||||
var req createLimiterRequest
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if req.Data.Name == "" {
|
||||
writeError(ctx, ErrInvalid)
|
||||
name := strings.TrimSpace(req.Data.Name)
|
||||
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
|
||||
}
|
||||
|
||||
v := parser.ParseTrafficLimiter(&req.Data)
|
||||
|
||||
if err := registry.TrafficLimiterRegistry().Register(req.Data.Name, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.TrafficLimiterRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
@ -87,25 +96,27 @@ func updateLimiter(ctx *gin.Context) {
|
||||
ctx.ShouldBindUri(&req)
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if !registry.TrafficLimiterRegistry().IsRegistered(req.Limiter) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Limiter)
|
||||
|
||||
if !registry.TrafficLimiterRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("limiter %s not found", name)))
|
||||
return
|
||||
}
|
||||
|
||||
req.Data.Name = req.Limiter
|
||||
req.Data.Name = name
|
||||
|
||||
v := parser.ParseTrafficLimiter(&req.Data)
|
||||
|
||||
registry.TrafficLimiterRegistry().Unregister(req.Limiter)
|
||||
registry.TrafficLimiterRegistry().Unregister(name)
|
||||
|
||||
if err := registry.TrafficLimiterRegistry().Register(req.Limiter, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.TrafficLimiterRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
for i := range c.Limiters {
|
||||
if c.Limiters[i].Name == req.Limiter {
|
||||
if c.Limiters[i].Name == name {
|
||||
c.Limiters[i] = &req.Data
|
||||
break
|
||||
}
|
||||
@ -145,17 +156,19 @@ func deleteLimiter(ctx *gin.Context) {
|
||||
var req deleteLimiterRequest
|
||||
ctx.ShouldBindUri(&req)
|
||||
|
||||
if !registry.TrafficLimiterRegistry().IsRegistered(req.Limiter) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Limiter)
|
||||
|
||||
if !registry.TrafficLimiterRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("limiter %s not found", name)))
|
||||
return
|
||||
}
|
||||
registry.TrafficLimiterRegistry().Unregister(req.Limiter)
|
||||
registry.TrafficLimiterRegistry().Unregister(name)
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
limiteres := c.Limiters
|
||||
c.Limiters = nil
|
||||
for _, s := range limiteres {
|
||||
if s.Name == req.Limiter {
|
||||
if s.Name == name {
|
||||
continue
|
||||
}
|
||||
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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-gost/x/config"
|
||||
@ -35,15 +37,22 @@ func createRateLimiter(ctx *gin.Context) {
|
||||
var req createRateLimiterRequest
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if req.Data.Name == "" {
|
||||
writeError(ctx, ErrInvalid)
|
||||
name := strings.TrimSpace(req.Data.Name)
|
||||
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
|
||||
}
|
||||
|
||||
v := parser.ParseRateLimiter(&req.Data)
|
||||
|
||||
if err := registry.RateLimiterRegistry().Register(req.Data.Name, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.RateLimiterRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
@ -87,25 +96,27 @@ func updateRateLimiter(ctx *gin.Context) {
|
||||
ctx.ShouldBindUri(&req)
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if !registry.RateLimiterRegistry().IsRegistered(req.Limiter) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Limiter)
|
||||
|
||||
if !registry.RateLimiterRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("limiter %s not found", name)))
|
||||
return
|
||||
}
|
||||
|
||||
req.Data.Name = req.Limiter
|
||||
req.Data.Name = name
|
||||
|
||||
v := parser.ParseRateLimiter(&req.Data)
|
||||
|
||||
registry.RateLimiterRegistry().Unregister(req.Limiter)
|
||||
registry.RateLimiterRegistry().Unregister(name)
|
||||
|
||||
if err := registry.RateLimiterRegistry().Register(req.Limiter, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.RateLimiterRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("limiter %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
for i := range c.RLimiters {
|
||||
if c.RLimiters[i].Name == req.Limiter {
|
||||
if c.RLimiters[i].Name == name {
|
||||
c.RLimiters[i] = &req.Data
|
||||
break
|
||||
}
|
||||
@ -145,17 +156,19 @@ func deleteRateLimiter(ctx *gin.Context) {
|
||||
var req deleteRateLimiterRequest
|
||||
ctx.ShouldBindUri(&req)
|
||||
|
||||
if !registry.RateLimiterRegistry().IsRegistered(req.Limiter) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Limiter)
|
||||
|
||||
if !registry.RateLimiterRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("limiter %s not found", name)))
|
||||
return
|
||||
}
|
||||
registry.RateLimiterRegistry().Unregister(req.Limiter)
|
||||
registry.RateLimiterRegistry().Unregister(name)
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
limiteres := c.RLimiters
|
||||
c.RLimiters = nil
|
||||
for _, s := range limiteres {
|
||||
if s.Name == req.Limiter {
|
||||
if s.Name == name {
|
||||
continue
|
||||
}
|
||||
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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-gost/x/config"
|
||||
@ -35,19 +37,26 @@ func createResolver(ctx *gin.Context) {
|
||||
var req createResolverRequest
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if req.Data.Name == "" {
|
||||
writeError(ctx, ErrInvalid)
|
||||
name := strings.TrimSpace(req.Data.Name)
|
||||
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
|
||||
}
|
||||
|
||||
v, err := parser.ParseResolver(&req.Data)
|
||||
if err != nil {
|
||||
writeError(ctx, ErrCreate)
|
||||
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create resolver %s failed: %s", name, err.Error())))
|
||||
return
|
||||
}
|
||||
|
||||
if err := registry.ResolverRegistry().Register(req.Data.Name, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.ResolverRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("resolver %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
@ -91,29 +100,31 @@ func updateResolver(ctx *gin.Context) {
|
||||
ctx.ShouldBindUri(&req)
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if !registry.ResolverRegistry().IsRegistered(req.Resolver) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Resolver)
|
||||
|
||||
if !registry.ResolverRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("resolver %s not found", name)))
|
||||
return
|
||||
}
|
||||
|
||||
req.Data.Name = req.Resolver
|
||||
req.Data.Name = name
|
||||
|
||||
v, err := parser.ParseResolver(&req.Data)
|
||||
if err != nil {
|
||||
writeError(ctx, ErrCreate)
|
||||
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create resolver %s failed: %s", name, err.Error())))
|
||||
return
|
||||
}
|
||||
|
||||
registry.ResolverRegistry().Unregister(req.Resolver)
|
||||
registry.ResolverRegistry().Unregister(name)
|
||||
|
||||
if err := registry.ResolverRegistry().Register(req.Resolver, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.ResolverRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("resolver %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
for i := range c.Resolvers {
|
||||
if c.Resolvers[i].Name == req.Resolver {
|
||||
if c.Resolvers[i].Name == name {
|
||||
c.Resolvers[i] = &req.Data
|
||||
break
|
||||
}
|
||||
@ -153,17 +164,19 @@ func deleteResolver(ctx *gin.Context) {
|
||||
var req deleteResolverRequest
|
||||
ctx.ShouldBindUri(&req)
|
||||
|
||||
if !registry.ResolverRegistry().IsRegistered(req.Resolver) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
name := strings.TrimSpace(req.Resolver)
|
||||
|
||||
if !registry.ResolverRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("resolver %s not found", name)))
|
||||
return
|
||||
}
|
||||
registry.ResolverRegistry().Unregister(req.Resolver)
|
||||
registry.ResolverRegistry().Unregister(name)
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
resolvers := c.Resolvers
|
||||
c.Resolvers = nil
|
||||
for _, s := range resolvers {
|
||||
if s.Name == req.Resolver {
|
||||
if s.Name == name {
|
||||
continue
|
||||
}
|
||||
c.Resolvers = append(c.Resolvers, s)
|
||||
|
@ -1,7 +1,9 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-gost/x/config"
|
||||
@ -35,15 +37,22 @@ func createRouter(ctx *gin.Context) {
|
||||
var req createRouterRequest
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if req.Data.Name == "" {
|
||||
writeError(ctx, ErrInvalid)
|
||||
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(req.Data.Name, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
if err := registry.RouterRegistry().Register(name, v); err != nil {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("router %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
@ -87,25 +96,27 @@ func updateRouter(ctx *gin.Context) {
|
||||
ctx.ShouldBindUri(&req)
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if !registry.RouterRegistry().IsRegistered(req.Router) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
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 = req.Router
|
||||
req.Data.Name = name
|
||||
|
||||
v := parser.ParseRouter(&req.Data)
|
||||
|
||||
registry.RouterRegistry().Unregister(req.Router)
|
||||
registry.RouterRegistry().Unregister(name)
|
||||
|
||||
if err := registry.RouterRegistry().Register(req.Router, v); err != nil {
|
||||
writeError(ctx, ErrDup)
|
||||
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 == req.Router {
|
||||
if c.Routers[i].Name == name {
|
||||
c.Routers[i] = &req.Data
|
||||
break
|
||||
}
|
||||
@ -145,17 +156,19 @@ func deleteRouter(ctx *gin.Context) {
|
||||
var req deleteRouterRequest
|
||||
ctx.ShouldBindUri(&req)
|
||||
|
||||
if !registry.RouterRegistry().IsRegistered(req.Router) {
|
||||
writeError(ctx, ErrNotFound)
|
||||
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(req.Router)
|
||||
registry.RouterRegistry().Unregister(name)
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
routeres := c.Routers
|
||||
c.Routers = nil
|
||||
for _, s := range routeres {
|
||||
if s.Name == req.Router {
|
||||
if s.Name == name {
|
||||
continue
|
||||
}
|
||||
c.Routers = append(c.Routers, s)
|
||||
|
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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-gost/x/config"
|
||||
@ -35,25 +37,27 @@ func createService(ctx *gin.Context) {
|
||||
var req createServiceRequest
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
if req.Data.Name == "" {
|
||||
writeError(ctx, ErrInvalid)
|
||||
name := strings.TrimSpace(req.Data.Name)
|
||||
if name == "" {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeInvalid, "service name is required"))
|
||||
return
|
||||
}
|
||||
req.Data.Name = name
|
||||
|
||||
if registry.ServiceRegistry().IsRegistered(req.Data.Name) {
|
||||
writeError(ctx, ErrDup)
|
||||
if registry.ServiceRegistry().IsRegistered(name) {
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("service %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
svc, err := parser.ParseService(&req.Data)
|
||||
if err != nil {
|
||||
writeError(ctx, ErrCreate)
|
||||
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create service %s failed: %s", name, err.Error())))
|
||||
return
|
||||
}
|
||||
|
||||
if err := registry.ServiceRegistry().Register(req.Data.Name, svc); err != nil {
|
||||
if err := registry.ServiceRegistry().Register(name, svc); err != nil {
|
||||
svc.Close()
|
||||
writeError(ctx, ErrDup)
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("service %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
@ -99,26 +103,28 @@ func updateService(ctx *gin.Context) {
|
||||
ctx.ShouldBindUri(&req)
|
||||
ctx.ShouldBindJSON(&req.Data)
|
||||
|
||||
old := registry.ServiceRegistry().Get(req.Service)
|
||||
name := strings.TrimSpace(req.Service)
|
||||
|
||||
old := registry.ServiceRegistry().Get(name)
|
||||
if old == nil {
|
||||
writeError(ctx, ErrNotFound)
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("service %s not found", name)))
|
||||
return
|
||||
}
|
||||
old.Close()
|
||||
|
||||
req.Data.Name = req.Service
|
||||
req.Data.Name = name
|
||||
|
||||
svc, err := parser.ParseService(&req.Data)
|
||||
if err != nil {
|
||||
writeError(ctx, ErrCreate)
|
||||
writeError(ctx, NewError(http.StatusInternalServerError, ErrCodeFailed, fmt.Sprintf("create service %s failed: %s", name, err.Error())))
|
||||
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()
|
||||
writeError(ctx, ErrDup)
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeDup, fmt.Sprintf("service %s already exists", name)))
|
||||
return
|
||||
}
|
||||
|
||||
@ -126,7 +132,7 @@ func updateService(ctx *gin.Context) {
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
for i := range c.Services {
|
||||
if c.Services[i].Name == req.Service {
|
||||
if c.Services[i].Name == name {
|
||||
c.Services[i] = &req.Data
|
||||
break
|
||||
}
|
||||
@ -166,20 +172,22 @@ func deleteService(ctx *gin.Context) {
|
||||
var req deleteServiceRequest
|
||||
ctx.ShouldBindUri(&req)
|
||||
|
||||
svc := registry.ServiceRegistry().Get(req.Service)
|
||||
name := strings.TrimSpace(req.Service)
|
||||
|
||||
svc := registry.ServiceRegistry().Get(name)
|
||||
if svc == nil {
|
||||
writeError(ctx, ErrNotFound)
|
||||
writeError(ctx, NewError(http.StatusBadRequest, ErrCodeNotFound, fmt.Sprintf("service %s not found", name)))
|
||||
return
|
||||
}
|
||||
|
||||
registry.ServiceRegistry().Unregister(req.Service)
|
||||
registry.ServiceRegistry().Unregister(name)
|
||||
svc.Close()
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
services := c.Services
|
||||
c.Services = nil
|
||||
for _, s := range services {
|
||||
if s.Name == req.Service {
|
||||
if s.Name == name {
|
||||
continue
|
||||
}
|
||||
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"}
|
||||
)
|
||||
|
||||
type ErrCode int
|
||||
|
||||
const (
|
||||
ErrCodeInvalid = 40001
|
||||
ErrCodeDup = 40002
|
||||
ErrCodeFailed = 40003
|
||||
ErrCodeNotFound = 40004
|
||||
ErrCodeSaveConfigFailed = 40005
|
||||
)
|
||||
|
||||
// Error is an api error.
|
||||
type Error struct {
|
||||
statusCode int
|
||||
@ -22,6 +32,14 @@ type Error struct {
|
||||
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 {
|
||||
b, _ := json.Marshal(e)
|
||||
return string(b)
|
||||
|
@ -37,7 +37,11 @@ func mwBasicAuth(auther auth.Authenticator) gin.HandlerFunc {
|
||||
u, p, _ := c.Request.BasicAuth()
|
||||
if _, ok := auther.Authenticate(c, u, p); !ok {
|
||||
c.Writer.Header().Set("WWW-Authenticate", "Basic")
|
||||
c.AbortWithStatus(http.StatusUnauthorized)
|
||||
c.JSON(http.StatusUnauthorized, Response{
|
||||
Code: http.StatusUnauthorized,
|
||||
Msg: "Unauthorized",
|
||||
})
|
||||
c.Abort()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
380
api/swagger.yaml
380
api/swagger.yaml
@ -188,8 +188,18 @@ definitions:
|
||||
x-go-name: Limiters
|
||||
log:
|
||||
$ref: '#/definitions/LogConfig'
|
||||
loggers:
|
||||
items:
|
||||
$ref: '#/definitions/LoggerConfig'
|
||||
type: array
|
||||
x-go-name: Loggers
|
||||
metrics:
|
||||
$ref: '#/definitions/MetricsConfig'
|
||||
observers:
|
||||
items:
|
||||
$ref: '#/definitions/ObserverConfig'
|
||||
type: array
|
||||
x-go-name: Observers
|
||||
profiling:
|
||||
$ref: '#/definitions/ProfilingConfig'
|
||||
recorders:
|
||||
@ -296,11 +306,18 @@ definitions:
|
||||
type: string
|
||||
type: array
|
||||
x-go-name: Bypasses
|
||||
filter:
|
||||
$ref: '#/definitions/NodeFilterConfig'
|
||||
host:
|
||||
description: DEPRECATED by filter.host
|
||||
type: string
|
||||
x-go-name: Host
|
||||
http:
|
||||
$ref: '#/definitions/HTTPNodeConfig'
|
||||
metadata:
|
||||
additionalProperties: {}
|
||||
type: object
|
||||
x-go-name: Metadata
|
||||
name:
|
||||
type: string
|
||||
x-go-name: Name
|
||||
@ -308,9 +325,11 @@ definitions:
|
||||
type: string
|
||||
x-go-name: Network
|
||||
path:
|
||||
description: DEPRECATED by filter.path
|
||||
type: string
|
||||
x-go-name: Path
|
||||
protocol:
|
||||
description: DEPRECATED by filter.protocol
|
||||
type: string
|
||||
x-go-name: Protocol
|
||||
tls:
|
||||
@ -319,7 +338,12 @@ definitions:
|
||||
x-go-package: github.com/go-gost/x/config
|
||||
ForwarderConfig:
|
||||
properties:
|
||||
hop:
|
||||
description: the referenced hop name
|
||||
type: string
|
||||
x-go-name: Hop
|
||||
name:
|
||||
description: DEPRECATED by hop field
|
||||
type: string
|
||||
x-go-name: Name
|
||||
nodes:
|
||||
@ -342,6 +366,8 @@ definitions:
|
||||
x-go-package: github.com/go-gost/x/config
|
||||
HTTPNodeConfig:
|
||||
properties:
|
||||
auth:
|
||||
$ref: '#/definitions/AuthConfig'
|
||||
header:
|
||||
additionalProperties:
|
||||
type: string
|
||||
@ -350,6 +376,11 @@ definitions:
|
||||
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:
|
||||
@ -361,6 +392,14 @@ definitions:
|
||||
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:
|
||||
properties:
|
||||
auth:
|
||||
@ -385,6 +424,9 @@ definitions:
|
||||
additionalProperties: {}
|
||||
type: object
|
||||
x-go-name: Metadata
|
||||
observer:
|
||||
type: string
|
||||
x-go-name: Observer
|
||||
retries:
|
||||
format: int64
|
||||
type: integer
|
||||
@ -615,6 +657,15 @@ definitions:
|
||||
x-go-name: MaxSize
|
||||
type: object
|
||||
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:
|
||||
properties:
|
||||
addr:
|
||||
@ -664,8 +715,6 @@ definitions:
|
||||
addr:
|
||||
type: string
|
||||
x-go-name: Addr
|
||||
auth:
|
||||
$ref: '#/definitions/AuthConfig'
|
||||
bypass:
|
||||
type: string
|
||||
x-go-name: Bypass
|
||||
@ -678,9 +727,8 @@ definitions:
|
||||
$ref: '#/definitions/ConnectorConfig'
|
||||
dialer:
|
||||
$ref: '#/definitions/DialerConfig'
|
||||
host:
|
||||
type: string
|
||||
x-go-name: Host
|
||||
filter:
|
||||
$ref: '#/definitions/NodeFilterConfig'
|
||||
hosts:
|
||||
type: string
|
||||
x-go-name: Hosts
|
||||
@ -699,12 +747,6 @@ definitions:
|
||||
network:
|
||||
type: string
|
||||
x-go-name: Network
|
||||
path:
|
||||
type: string
|
||||
x-go-name: Path
|
||||
protocol:
|
||||
type: string
|
||||
x-go-name: Protocol
|
||||
resolver:
|
||||
type: string
|
||||
x-go-name: Resolver
|
||||
@ -714,6 +756,28 @@ definitions:
|
||||
$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:
|
||||
@ -927,6 +991,14 @@ definitions:
|
||||
x-go-name: Limiter
|
||||
listener:
|
||||
$ref: '#/definitions/ListenerConfig'
|
||||
logger:
|
||||
type: string
|
||||
x-go-name: Logger
|
||||
loggers:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
x-go-name: Loggers
|
||||
metadata:
|
||||
additionalProperties: {}
|
||||
type: object
|
||||
@ -934,6 +1006,9 @@ definitions:
|
||||
name:
|
||||
type: string
|
||||
x-go-name: Name
|
||||
observer:
|
||||
type: string
|
||||
x-go-name: Observer
|
||||
recorders:
|
||||
items:
|
||||
$ref: '#/definitions/RecorderObject'
|
||||
@ -947,6 +1022,61 @@ definitions:
|
||||
x-go-name: RLimiter
|
||||
sockopts:
|
||||
$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
|
||||
x-go-package: github.com/go-gost/x/config
|
||||
SockOptsConfig:
|
||||
@ -1588,6 +1718,122 @@ paths:
|
||||
summary: Update limiter by name, the limiter must already exist.
|
||||
tags:
|
||||
- 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:
|
||||
post:
|
||||
operationId: createResolverRequest
|
||||
@ -1762,6 +2008,64 @@ paths:
|
||||
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:
|
||||
post:
|
||||
operationId: createServiceRequest
|
||||
@ -1877,12 +2181,24 @@ responses:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
createObserverResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
createRateLimiterResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
createRecorderResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
createResolverResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
@ -1895,6 +2211,12 @@ responses:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
createSDResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
createServiceResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
@ -1955,12 +2277,24 @@ responses:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
deleteObserverResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
deleteRateLimiterResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
deleteRecorderResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
deleteResolverResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
@ -1973,6 +2307,12 @@ responses:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
deleteSDResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
deleteServiceResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
@ -2045,12 +2385,24 @@ responses:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
updateObserverResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
updateRateLimiterResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
updateRecorderResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
updateResolverResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
@ -2063,6 +2415,12 @@ responses:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
updateSDResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
Data: {}
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
updateServiceResponse:
|
||||
description: successful operation.
|
||||
headers:
|
||||
|
@ -235,11 +235,17 @@ func (bp *localBypass) Contains(ctx context.Context, network, addr string, opts
|
||||
b := !bp.options.whitelist && matched ||
|
||||
bp.options.whitelist && !matched
|
||||
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
|
||||
}
|
||||
|
||||
func (p *localBypass) IsWhitelist() bool {
|
||||
return p.options.whitelist
|
||||
}
|
||||
|
||||
func (bp *localBypass) parseLine(s string) string {
|
||||
if n := strings.IndexByte(s, '#'); n >= 0 {
|
||||
s = s[:n]
|
||||
|
@ -75,3 +75,7 @@ func (p *grpcPlugin) Close() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) IsWhitelist() bool {
|
||||
return false
|
||||
}
|
||||
|
@ -96,3 +96,7 @@ func (p *httpPlugin) Contains(ctx context.Context, network, addr string, opts ..
|
||||
}
|
||||
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
|
||||
node = node.Copy()
|
||||
node.Options().Transport = tr
|
||||
rt = NewRoute()
|
||||
rt = NewRoute(ChainRouteOption(c))
|
||||
}
|
||||
|
||||
rt.addNode(node)
|
||||
|
@ -129,10 +129,11 @@ func (r *route) connect(ctx context.Context, logger logger.Logger) (conn net.Con
|
||||
metrics.Labels{"chain": name, "node": node.Name}); v != nil {
|
||||
v.Inc()
|
||||
}
|
||||
} else {
|
||||
if marker != nil {
|
||||
marker.Reset()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if marker != nil {
|
||||
marker.Reset()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
@ -297,9 +297,9 @@ type RedisRecorder struct {
|
||||
}
|
||||
|
||||
type RecorderObject struct {
|
||||
Name string `json:"name"`
|
||||
Record string `json:"record"`
|
||||
Metadata map[string]any
|
||||
Name string `json:"name"`
|
||||
Record string `json:"record"`
|
||||
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type LimiterConfig struct {
|
||||
@ -343,25 +343,32 @@ type HandlerConfig 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"`
|
||||
Nodes []*ForwardNodeConfig `json:"nodes"`
|
||||
}
|
||||
|
||||
type ForwardNodeConfig struct {
|
||||
Name string `yaml:",omitempty" json:"name,omitempty"`
|
||||
Addr string `yaml:",omitempty" json:"addr,omitempty"`
|
||||
Host string `yaml:",omitempty" json:"host,omitempty"`
|
||||
Network string `yaml:",omitempty" json:"network,omitempty"`
|
||||
Protocol string `yaml:",omitempty" json:"protocol,omitempty"`
|
||||
Path string `yaml:",omitempty" json:"path,omitempty"`
|
||||
Bypass string `yaml:",omitempty" json:"bypass,omitempty"`
|
||||
Bypasses []string `yaml:",omitempty" json:"bypasses,omitempty"`
|
||||
HTTP *HTTPNodeConfig `yaml:",omitempty" json:"http,omitempty"`
|
||||
TLS *TLSNodeConfig `yaml:",omitempty" json:"tls,omitempty"`
|
||||
// DEPRECATED by HTTP.Auth
|
||||
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
||||
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
||||
Name string `yaml:",omitempty" json:"name,omitempty"`
|
||||
Addr string `yaml:",omitempty" json:"addr,omitempty"`
|
||||
Network string `yaml:",omitempty" json:"network,omitempty"`
|
||||
Bypass string `yaml:",omitempty" json:"bypass,omitempty"`
|
||||
Bypasses []string `yaml:",omitempty" json:"bypasses,omitempty"`
|
||||
// DEPRECATED by filter.protocol
|
||||
Protocol string `yaml:",omitempty" json:"protocol,omitempty"`
|
||||
// DEPRECATED by filter.host
|
||||
Host string `yaml:",omitempty" json:"host,omitempty"`
|
||||
// DEPRECATED by filter.path
|
||||
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 {
|
||||
@ -369,11 +376,17 @@ type HTTPURLRewriteConfig struct {
|
||||
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 {
|
||||
Host string `yaml:",omitempty" json:"host,omitempty"`
|
||||
Header map[string]string `yaml:",omitempty" json:"header,omitempty"`
|
||||
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
||||
Rewrite []HTTPURLRewriteConfig `yaml:",omitempty" json:"rewrite,omitempty"`
|
||||
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
||||
}
|
||||
|
||||
type TLSNodeConfig struct {
|
||||
@ -477,24 +490,21 @@ type HopConfig struct {
|
||||
}
|
||||
|
||||
type NodeConfig struct {
|
||||
Name string `json:"name"`
|
||||
Addr string `yaml:",omitempty" json:"addr,omitempty"`
|
||||
Host string `yaml:",omitempty" json:"host,omitempty"`
|
||||
Network string `yaml:",omitempty" json:"network,omitempty"`
|
||||
Protocol string `yaml:",omitempty" json:"protocol,omitempty"`
|
||||
Path string `yaml:",omitempty" json:"path,omitempty"`
|
||||
Interface string `yaml:",omitempty" json:"interface,omitempty"`
|
||||
SockOpts *SockOptsConfig `yaml:"sockopts,omitempty" json:"sockopts,omitempty"`
|
||||
Bypass string `yaml:",omitempty" json:"bypass,omitempty"`
|
||||
Bypasses []string `yaml:",omitempty" json:"bypasses,omitempty"`
|
||||
Resolver string `yaml:",omitempty" json:"resolver,omitempty"`
|
||||
Hosts string `yaml:",omitempty" json:"hosts,omitempty"`
|
||||
Connector *ConnectorConfig `yaml:",omitempty" json:"connector,omitempty"`
|
||||
Dialer *DialerConfig `yaml:",omitempty" json:"dialer,omitempty"`
|
||||
HTTP *HTTPNodeConfig `yaml:",omitempty" json:"http,omitempty"`
|
||||
TLS *TLSNodeConfig `yaml:",omitempty" json:"tls,omitempty"`
|
||||
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
||||
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Addr string `yaml:",omitempty" json:"addr,omitempty"`
|
||||
Network string `yaml:",omitempty" json:"network,omitempty"`
|
||||
Bypass string `yaml:",omitempty" json:"bypass,omitempty"`
|
||||
Bypasses []string `yaml:",omitempty" json:"bypasses,omitempty"`
|
||||
Resolver string `yaml:",omitempty" json:"resolver,omitempty"`
|
||||
Hosts string `yaml:",omitempty" json:"hosts,omitempty"`
|
||||
Connector *ConnectorConfig `yaml:",omitempty" json:"connector,omitempty"`
|
||||
Dialer *DialerConfig `yaml:",omitempty" json:"dialer,omitempty"`
|
||||
Interface string `yaml:",omitempty" json:"interface,omitempty"`
|
||||
SockOpts *SockOptsConfig `yaml:"sockopts,omitempty" json:"sockopts,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 Config struct {
|
||||
|
@ -32,7 +32,7 @@ func ParseHop(cfg *config.HopConfig, log logger.Logger) (hop.Hop, error) {
|
||||
}
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
case plugin.HTTP:
|
||||
return hop_plugin.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
@ -67,15 +67,17 @@ func ParseHop(cfg *config.HopConfig, log logger.Logger) (hop.Hop, error) {
|
||||
}
|
||||
|
||||
if v.Connector == nil {
|
||||
v.Connector = &config.ConnectorConfig{
|
||||
Type: "http",
|
||||
}
|
||||
v.Connector = &config.ConnectorConfig{}
|
||||
}
|
||||
if strings.TrimSpace(v.Connector.Type) == "" {
|
||||
v.Connector.Type = "http"
|
||||
}
|
||||
|
||||
if v.Dialer == nil {
|
||||
v.Dialer = &config.DialerConfig{
|
||||
Type: "tcp",
|
||||
}
|
||||
v.Dialer = &config.DialerConfig{}
|
||||
}
|
||||
if strings.TrimSpace(v.Dialer.Type) == "" {
|
||||
v.Dialer.Type = "tcp"
|
||||
}
|
||||
|
||||
node, err := node_parser.ParseNode(cfg.Name, v, log)
|
||||
|
@ -147,46 +147,47 @@ func ParseNode(hop string, cfg *config.NodeConfig, log logger.Logger) (*chain.No
|
||||
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{
|
||||
chain.TransportNodeOption(tr),
|
||||
chain.BypassNodeOption(bypass.BypassGroup(bypass_parser.List(cfg.Bypass, cfg.Bypasses...)...)),
|
||||
chain.ResoloverNodeOption(registry.ResolverRegistry().Get(cfg.Resolver)),
|
||||
chain.HostMapperNodeOption(registry.HostsRegistry().Get(cfg.Hosts)),
|
||||
chain.MetadataNodeOption(nm),
|
||||
chain.HostNodeOption(host),
|
||||
chain.ProtocolNodeOption(cfg.Protocol),
|
||||
chain.PathNodeOption(cfg.Path),
|
||||
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 {
|
||||
settings := &chain.HTTPNodeSettings{
|
||||
Host: cfg.HTTP.Host,
|
||||
Header: cfg.HTTP.Header,
|
||||
}
|
||||
|
||||
auth := cfg.HTTP.Auth
|
||||
if auth == nil {
|
||||
auth = cfg.Auth
|
||||
}
|
||||
if auth != nil {
|
||||
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,
|
||||
"host": cfg.Host,
|
||||
"protocol": cfg.Protocol,
|
||||
"kind": "node",
|
||||
"node": cfg.Name,
|
||||
"addr": cfg.Addr,
|
||||
})),
|
||||
)
|
||||
}
|
||||
@ -200,6 +201,7 @@ func ParseNode(hop string, cfg *config.NodeConfig, log logger.Logger) (*chain.No
|
||||
}
|
||||
opts = append(opts, chain.HTTPNodeOption(settings))
|
||||
}
|
||||
|
||||
if cfg.TLS != nil {
|
||||
tlsCfg := &chain.TLSNodeSettings{
|
||||
ServerName: cfg.TLS.ServerName,
|
||||
|
@ -2,6 +2,8 @@ package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-gost/core/admission"
|
||||
"github.com/go-gost/core/auth"
|
||||
@ -34,14 +36,17 @@ import (
|
||||
|
||||
func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
if cfg.Listener == nil {
|
||||
cfg.Listener = &config.ListenerConfig{
|
||||
Type: "tcp",
|
||||
}
|
||||
cfg.Listener = &config.ListenerConfig{}
|
||||
}
|
||||
if strings.TrimSpace(cfg.Listener.Type) == "" {
|
||||
cfg.Listener.Type = "tcp"
|
||||
}
|
||||
|
||||
if cfg.Handler == nil {
|
||||
cfg.Handler = &config.HandlerConfig{
|
||||
Type: "auto",
|
||||
}
|
||||
cfg.Handler = &config.HandlerConfig{}
|
||||
}
|
||||
if strings.TrimSpace(cfg.Handler.Type) == "" {
|
||||
cfg.Handler.Type = "auto"
|
||||
}
|
||||
|
||||
log := logger.Default()
|
||||
@ -98,6 +103,7 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
var preUp, preDown, postUp, postDown []string
|
||||
var ignoreChain bool
|
||||
var pStats *stats.Stats
|
||||
var observePeriod time.Duration
|
||||
if cfg.Metadata != nil {
|
||||
md := metadata.NewMetadata(cfg.Metadata)
|
||||
ppv = mdutil.GetInt(md, parsing.MDKeyProxyProtocol)
|
||||
@ -118,6 +124,7 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
if mdutil.GetBool(md, parsing.MDKeyEnableStats) {
|
||||
pStats = &stats.Stats{}
|
||||
}
|
||||
observePeriod = mdutil.GetDuration(md, "observePeriod")
|
||||
}
|
||||
|
||||
listenOpts := []listener.Option{
|
||||
@ -143,7 +150,7 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
if rf := registry.ListenerRegistry().Get(cfg.Listener.Type); rf != nil {
|
||||
ln = rf(listenOpts...)
|
||||
} 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 {
|
||||
@ -230,7 +237,7 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
handler.ServiceOption(cfg.Name),
|
||||
)
|
||||
} 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 {
|
||||
@ -259,6 +266,7 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
xservice.RecordersOption(recorders...),
|
||||
xservice.StatsOption(pStats),
|
||||
xservice.ObserverOption(registry.ObserverRegistry().Get(cfg.Observer)),
|
||||
xservice.ObservePeriodOption(observePeriod),
|
||||
xservice.LoggerOption(serviceLogger),
|
||||
)
|
||||
|
||||
@ -271,6 +279,14 @@ func parseForwarder(cfg *config.ForwarderConfig, log logger.Logger) (hop.Hop, er
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
hopName := cfg.Hop
|
||||
if hopName == "" {
|
||||
hopName = cfg.Name
|
||||
}
|
||||
if hopName != "" {
|
||||
return registry.HopRegistry().Get(hopName), nil
|
||||
}
|
||||
|
||||
hc := config.HopConfig{
|
||||
Name: cfg.Name,
|
||||
Selector: cfg.Selector,
|
||||
@ -286,27 +302,42 @@ func parseForwarder(cfg *config.ForwarderConfig, log logger.Logger) (hop.Hop, er
|
||||
if i > 0 {
|
||||
name = fmt.Sprintf("%s-%d", node.Name, i)
|
||||
}
|
||||
|
||||
filter := node.Filter
|
||||
if filter == nil {
|
||||
if node.Protocol != "" || node.Host != "" || node.Path != "" {
|
||||
filter = &config.NodeFilterConfig{
|
||||
Protocol: node.Protocol,
|
||||
Host: node.Host,
|
||||
Path: node.Path,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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: name,
|
||||
Addr: addr,
|
||||
Host: node.Host,
|
||||
Network: node.Network,
|
||||
Protocol: node.Protocol,
|
||||
Path: node.Path,
|
||||
Bypass: node.Bypass,
|
||||
Bypasses: node.Bypasses,
|
||||
HTTP: node.HTTP,
|
||||
Filter: filter,
|
||||
HTTP: httpCfg,
|
||||
TLS: node.TLS,
|
||||
Auth: node.Auth,
|
||||
Metadata: node.Metadata,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(hc.Nodes) > 0 {
|
||||
return hop_parser.ParseHop(&hc, log)
|
||||
}
|
||||
return registry.HopRegistry().Get(hc.Name), nil
|
||||
return hop_parser.ParseHop(&hc, log)
|
||||
}
|
||||
|
||||
func chainGroup(name string, group *config.ChainGroupConfig) chain.Chainer {
|
||||
|
@ -70,6 +70,19 @@ func (d *http2Dialer) Dial(ctx context.Context, address string, opts ...dialer.D
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
{
|
||||
// Check whether the connection is established properly
|
||||
netd := options.NetDialer
|
||||
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{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: d.options.TLSConfig,
|
||||
@ -81,17 +94,16 @@ func (d *http2Dialer) Dial(ctx context.Context, address string, opts ...dialer.D
|
||||
return netd.Dial(ctx, network, addr)
|
||||
},
|
||||
ForceAttemptHTTP2: true,
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
MaxIdleConns: 16,
|
||||
IdleConnTimeout: 30 * time.Second,
|
||||
TLSHandshakeTimeout: 30 * time.Second,
|
||||
ExpectContinueTimeout: 15 * time.Second,
|
||||
},
|
||||
}
|
||||
d.clients[address] = client
|
||||
}
|
||||
|
||||
var c net.Conn
|
||||
c = &conn{
|
||||
var c net.Conn = &conn{
|
||||
localAddr: &net.TCPAddr{},
|
||||
remoteAddr: raddr,
|
||||
onClose: func() {
|
||||
|
@ -86,7 +86,7 @@ func (d *http3Dialer) Dial(ctx context.Context, addr string, opts ...dialer.Dial
|
||||
|
||||
return quic.DialEarly(context.Background(), udpConn.(net.PacketConn), udpAddr, tlsCfg, cfg)
|
||||
},
|
||||
QuicConfig: &quic.Config{
|
||||
QUICConfig: &quic.Config{
|
||||
KeepAlivePeriod: d.md.keepAlivePeriod,
|
||||
HandshakeIdleTimeout: d.md.handshakeTimeout,
|
||||
MaxIdleTimeout: d.md.maxIdleTimeout,
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
md "github.com/go-gost/core/metadata"
|
||||
"github.com/go-gost/x/registry"
|
||||
"github.com/quic-go/quic-go"
|
||||
"github.com/quic-go/quic-go/http3"
|
||||
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,
|
||||
header: d.md.header,
|
||||
dialer: &wt.Dialer{
|
||||
RoundTripper: &http3.RoundTripper{
|
||||
TLSClientConfig: d.options.TLSConfig,
|
||||
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)
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
TLSClientConfig: d.options.TLSConfig,
|
||||
DialAddr: 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)
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
udpConn, err := options.NetDialer.Dial(ctx, "udp", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
udpConn, err := options.NetDialer.Dial(ctx, "udp", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return quic.DialEarly(ctx, udpConn.(net.PacketConn), udpAddr, tlsCfg, cfg)
|
||||
},
|
||||
QuicConfig: &quic.Config{
|
||||
KeepAlivePeriod: d.md.keepAlivePeriod,
|
||||
HandshakeIdleTimeout: d.md.handshakeTimeout,
|
||||
MaxIdleTimeout: d.md.maxIdleTimeout,
|
||||
/*
|
||||
Versions: []quic.VersionNumber{
|
||||
quic.Version1,
|
||||
},
|
||||
*/
|
||||
MaxIncomingStreams: int64(d.md.maxStreams),
|
||||
},
|
||||
return quic.DialEarly(ctx, udpConn.(net.PacketConn), udpAddr, tlsCfg, cfg)
|
||||
},
|
||||
QUICConfig: &quic.Config{
|
||||
KeepAlivePeriod: d.md.keepAlivePeriod,
|
||||
HandshakeIdleTimeout: d.md.handshakeTimeout,
|
||||
MaxIdleTimeout: d.md.maxIdleTimeout,
|
||||
/*
|
||||
Versions: []quic.VersionNumber{
|
||||
quic.Version1,
|
||||
},
|
||||
*/
|
||||
MaxIncomingStreams: int64(d.md.maxStreams),
|
||||
EnableDatagrams: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -49,7 +49,12 @@ func (d *kcpDialer) parseMetadata(md mdata.Metadata) (err error) {
|
||||
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)
|
||||
return
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
type obfsHTTPConn struct {
|
||||
net.Conn
|
||||
host string
|
||||
path string
|
||||
rbuf bytes.Buffer
|
||||
wbuf bytes.Buffer
|
||||
headerDrained bool
|
||||
|
@ -2,6 +2,7 @@ package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
|
||||
"github.com/go-gost/core/dialer"
|
||||
@ -12,11 +13,13 @@ import (
|
||||
|
||||
func init() {
|
||||
registry.DialerRegistry().Register("ohttp", NewDialer)
|
||||
registry.DialerRegistry().Register("ohttps", NewDialer)
|
||||
}
|
||||
|
||||
type obfsHTTPDialer struct {
|
||||
md metadata
|
||||
logger logger.Logger
|
||||
tlsEnabled bool
|
||||
md metadata
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
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) {
|
||||
return d.parseMetadata(md)
|
||||
}
|
||||
@ -59,9 +74,16 @@ func (d *obfsHTTPDialer) Handshake(ctx context.Context, conn net.Conn, options .
|
||||
host = opts.Addr
|
||||
}
|
||||
|
||||
if d.tlsEnabled {
|
||||
conn = tls.Client(conn, &tls.Config{
|
||||
ServerName: host,
|
||||
})
|
||||
}
|
||||
|
||||
return &obfsHTTPConn{
|
||||
Conn: conn,
|
||||
host: host,
|
||||
path: d.md.path,
|
||||
header: d.md.header,
|
||||
logger: d.logger,
|
||||
}, nil
|
||||
|
@ -7,24 +7,29 @@ import (
|
||||
mdutil "github.com/go-gost/core/metadata/util"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultPath = "/"
|
||||
)
|
||||
|
||||
type metadata struct {
|
||||
host string
|
||||
path string
|
||||
header http.Header
|
||||
}
|
||||
|
||||
func (d *obfsHTTPDialer) parseMetadata(md mdata.Metadata) (err error) {
|
||||
const (
|
||||
header = "header"
|
||||
host = "host"
|
||||
)
|
||||
d.md.host = mdutil.GetString(md, "obfs.host", "host")
|
||||
d.md.path = mdutil.GetString(md, "obfs.path", "path")
|
||||
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{}
|
||||
for k, v := range m {
|
||||
h.Add(k, v)
|
||||
}
|
||||
d.md.header = h
|
||||
}
|
||||
d.md.host = mdutil.GetString(md, host)
|
||||
return
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
mdata "github.com/go-gost/core/metadata"
|
||||
mdutil "github.com/go-gost/core/metadata/util"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/zalando/go-keyring"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
@ -20,21 +23,35 @@ type metadata struct {
|
||||
|
||||
func (d *sshDialer) parseMetadata(md mdata.Metadata) (err error) {
|
||||
const (
|
||||
handshakeTimeout = "handshakeTimeout"
|
||||
privateKeyFile = "privateKeyFile"
|
||||
passphrase = "passphrase"
|
||||
handshakeTimeout = "handshakeTimeout"
|
||||
privateKeyFile = "privateKeyFile"
|
||||
passphrase = "passphrase"
|
||||
passphraseFromKeyring = "passphraseFromKeyring"
|
||||
)
|
||||
|
||||
if key := mdutil.GetString(md, privateKeyFile); key != "" {
|
||||
key, err = homedir.Expand(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := os.ReadFile(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if pp := mdutil.GetString(md, passphrase); pp != "" {
|
||||
d.md.signer, err = ssh.ParsePrivateKeyWithPassphrase(data, []byte(pp))
|
||||
var pp string
|
||||
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 {
|
||||
pp = mdutil.GetString(md, passphrase)
|
||||
}
|
||||
if pp == "" {
|
||||
d.md.signer, err = ssh.ParsePrivateKey(data)
|
||||
} else {
|
||||
d.md.signer, err = ssh.ParsePrivateKeyWithPassphrase(data, []byte(pp))
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1,11 +1,14 @@
|
||||
package sshd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
mdata "github.com/go-gost/core/metadata"
|
||||
mdutil "github.com/go-gost/core/metadata/util"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/zalando/go-keyring"
|
||||
"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 != "" {
|
||||
key, err = homedir.Expand(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := os.ReadFile(key)
|
||||
if err != nil {
|
||||
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 == "" {
|
||||
d.md.signer, err = ssh.ParsePrivateKey(data)
|
||||
} else {
|
||||
|
58
go.mod
58
go.mod
@ -1,13 +1,15 @@
|
||||
module github.com/go-gost/x
|
||||
|
||||
go 1.21
|
||||
go 1.22
|
||||
|
||||
toolchain go1.22.2
|
||||
|
||||
require (
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
|
||||
github.com/gin-contrib/cors v1.5.0
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/go-gost/core v0.0.0-20240131151724-a06608ccafbf
|
||||
github.com/go-gost/core v0.0.0-20240508132029-8d554ddcf77c
|
||||
github.com/go-gost/gosocks4 v0.0.1
|
||||
github.com/go-gost/gosocks5 v0.4.0
|
||||
github.com/go-gost/plugin v0.0.0-20240103125338-9c84e29cb81a
|
||||
@ -16,16 +18,16 @@ require (
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/gobwas/glob v0.2.3
|
||||
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.1
|
||||
github.com/miekg/dns v1.1.57
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/pion/dtls/v2 v2.2.6
|
||||
github.com/pires/go-proxyproto v0.7.0
|
||||
github.com/prometheus/client_golang v1.17.0
|
||||
github.com/quic-go/quic-go v0.40.1
|
||||
github.com/quic-go/webtransport-go v0.6.0
|
||||
github.com/refraction-networking/utls v1.5.4
|
||||
github.com/prometheus/client_golang v1.19.1
|
||||
github.com/quic-go/quic-go v0.45.0
|
||||
github.com/quic-go/webtransport-go v0.8.0
|
||||
github.com/rs/xid v1.3.0
|
||||
github.com/shadowsocks/go-shadowsocks2 v0.1.5
|
||||
github.com/shadowsocks/shadowsocks-go v0.0.0-20200409064450-3e585ff90601
|
||||
@ -37,25 +39,28 @@ require (
|
||||
github.com/xtaci/smux v1.5.24
|
||||
github.com/xtaci/tcpraw v1.2.25
|
||||
github.com/yl2chen/cidranger v1.0.2
|
||||
golang.org/x/crypto v0.17.0
|
||||
golang.org/x/net v0.19.0
|
||||
golang.org/x/sys v0.15.0
|
||||
github.com/zalando/go-keyring v0.2.4
|
||||
golang.org/x/crypto v0.24.0
|
||||
golang.org/x/net v0.26.0
|
||||
golang.org/x/sys v0.21.0
|
||||
golang.org/x/time v0.5.0
|
||||
golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478
|
||||
google.golang.org/grpc v1.59.0
|
||||
google.golang.org/protobuf v1.31.0
|
||||
google.golang.org/grpc v1.64.0
|
||||
google.golang.org/protobuf v1.34.2
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
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/bytedance/sonic v1.10.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // 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/danieljoos/wincred v1.2.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
@ -63,11 +68,11 @@ require (
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.16.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/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/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/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
||||
@ -75,21 +80,19 @@ require (
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // 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/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // 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/v2 v2.1.1 // indirect
|
||||
github.com/pion/logging v0.2.2 // indirect
|
||||
github.com/pion/transport/v2 v2.0.2 // indirect
|
||||
github.com/pion/udp/v2 v2.0.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/common v0.44.0 // indirect
|
||||
github.com/prometheus/procfs v0.11.1 // indirect
|
||||
github.com/prometheus/client_model v0.5.0 // indirect
|
||||
github.com/prometheus/common v0.48.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
@ -104,14 +107,15 @@ require (
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect
|
||||
go.uber.org/mock v0.3.0 // indirect
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/arch v0.6.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/tools v0.16.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 // indirect
|
||||
golang.org/x/mod v0.18.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/tools v0.22.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
)
|
||||
|
132
go.sum
132
go.sum
@ -4,6 +4,8 @@ github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmH
|
||||
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/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/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
@ -26,6 +28,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/coreos/go-iptables v0.5.0 h1:mw6SAibtHKZcNzAsOxjoHIG0gy5YFHhypWSSNc6EjbQ=
|
||||
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.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
@ -49,8 +53,8 @@ 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-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/go-gost/core v0.0.0-20240131151724-a06608ccafbf h1:akQ96Ibm+P7IftDluZPoMCzBzbLR/TjFu8Wpjy3H7hM=
|
||||
github.com/go-gost/core v0.0.0-20240131151724-a06608ccafbf/go.mod h1:ndkgWVYRLwupVaFFWv8ML1Nr8tD3xhHK245PLpUDg4E=
|
||||
github.com/go-gost/core v0.0.0-20240508132029-8d554ddcf77c h1:1ahtn+3bQB50at5ubWDOrA4yja8vWpWNrGSRaCztNWg=
|
||||
github.com/go-gost/core v0.0.0-20240508132029-8d554ddcf77c/go.mod h1:j08tDHkFzk7dfOeLhl3RWsASdf9YWWRfWBUQqbQvx3A=
|
||||
github.com/go-gost/gosocks4 v0.0.1 h1:+k1sec8HlELuQV7rWftIkmy8UijzUt2I6t+iMPlGB2s=
|
||||
github.com/go-gost/gosocks4 v0.0.1/go.mod h1:3B6L47HbU/qugDg4JnoFPHgJXE43Inz8Bah1QaN9qCc=
|
||||
github.com/go-gost/gosocks5 v0.4.0 h1:EIrOEkpJez4gwHrMa33frA+hHXJyevjp47thpMQsJzI=
|
||||
@ -61,8 +65,8 @@ github.com/go-gost/relay v0.5.0 h1:JG1tgy/KWiVXS0ukuVXvbM0kbYuJTWxYpJ5JwzsCf/c=
|
||||
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/go.mod h1:/9QfdewqmHdaE362Hv5nDaSWLx3pCmtD870d6GaquXs=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
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/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
@ -73,12 +77,14 @@ github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqR
|
||||
github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
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-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
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 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
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/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
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/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/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@ -90,25 +96,21 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
|
||||
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.2/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/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
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.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.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/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
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/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
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/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g=
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
@ -131,10 +133,10 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
|
||||
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@ -146,10 +148,10 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
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/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.12.0 h1:UIVDowFPwpg6yMUpPjGkYvf06K3RAiJXUhCxEwQVHRI=
|
||||
github.com/onsi/ginkgo/v2 v2.12.0/go.mod h1:ZNEzXISYlqpb8S36iN71ifqLi3vVD1rVJGvWRCJOUpQ=
|
||||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
||||
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
|
||||
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/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
|
||||
@ -169,24 +171,21 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
|
||||
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
|
||||
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.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM=
|
||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
|
||||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
|
||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
||||
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
|
||||
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
|
||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
||||
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
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/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/quic-go/quic-go v0.40.1 h1:X3AGzUNFs0jVuO3esAGnTfvdgvL4fq655WaOi1snv1Q=
|
||||
github.com/quic-go/quic-go v0.40.1/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c=
|
||||
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/quic-go/quic-go v0.45.0 h1:OHmkQGM37luZITyTSu6ff03HP/2IrwDX1ZFiNEhSFUE=
|
||||
github.com/quic-go/quic-go v0.45.0/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI=
|
||||
github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg=
|
||||
github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM=
|
||||
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/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
@ -217,11 +216,11 @@ github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
|
||||
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.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/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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
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.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
@ -256,8 +255,10 @@ github.com/xtaci/tcpraw v1.2.25/go.mod h1:dKyZ2V75s0cZ7cbgJYdxPvms7af0joIeOyx1Gg
|
||||
github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU=
|
||||
github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
|
||||
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
github.com/zalando/go-keyring v0.2.4 h1:wi2xxTqdiwMKbM6TWwi+uJCG/Tum2UV0jqaQhCa9/68=
|
||||
github.com/zalando/go-keyring v0.2.4/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
@ -270,19 +271,19 @@ golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 h1:+iq7lrkxmFNBM7xx+Rae2W6uyPfhPeDWD+n+JgppptE=
|
||||
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||
golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 h1:LoYXNGAShUG3m/ehNk4iFctuhGX/+R1ZpfJ4/ia80JM=
|
||||
golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
|
||||
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-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
|
||||
golang.org/x/mod v0.18.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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -294,16 +295,15 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
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.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
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-20181221193216-37e7f081c4d4/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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -317,22 +317,22 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.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-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.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.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@ -343,8 +343,8 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
|
||||
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
||||
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
|
||||
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@ -356,24 +356,22 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3 h1:9Xyg6I9IWQZhRVfCWjKK+l6kI0jHcPesVlMnT//aHNo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
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.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
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/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
|
||||
google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
|
||||
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-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.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
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=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
@ -148,7 +149,7 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt
|
||||
fields := map[string]any{
|
||||
"dst": addr,
|
||||
}
|
||||
if u, _, _ := h.basicProxyAuth(req.Header.Get("Proxy-Authorization"), log); u != "" {
|
||||
if u, _, _ := h.basicProxyAuth(req.Header.Get("Proxy-Authorization")); u != "" {
|
||||
fields["user"] = u
|
||||
}
|
||||
log = log.WithFields(fields)
|
||||
@ -222,26 +223,6 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt
|
||||
}
|
||||
defer cc.Close()
|
||||
|
||||
if req.Method == http.MethodConnect {
|
||||
resp.StatusCode = http.StatusOK
|
||||
resp.Status = "200 Connection established"
|
||||
|
||||
if log.IsLevelEnabled(logger.TraceLevel) {
|
||||
dump, _ := httputil.DumpResponse(resp, false)
|
||||
log.Trace(string(dump))
|
||||
}
|
||||
if err = resp.Write(conn); err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
req.Header.Del("Proxy-Connection")
|
||||
if err = req.Write(cc); err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
rw := traffic_wrapper.WrapReadWriter(h.options.Limiter, conn,
|
||||
traffic.NetworkOption(network),
|
||||
traffic.AddrOption(addr),
|
||||
@ -256,6 +237,22 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt
|
||||
rw = stats_wrapper.WrapReadWriter(rw, pstats)
|
||||
}
|
||||
|
||||
if req.Method != http.MethodConnect {
|
||||
return h.handleProxy(rw, cc, req, log)
|
||||
}
|
||||
|
||||
resp.StatusCode = http.StatusOK
|
||||
resp.Status = "200 Connection established"
|
||||
|
||||
if log.IsLevelEnabled(logger.TraceLevel) {
|
||||
dump, _ := httputil.DumpResponse(resp, false)
|
||||
log.Trace(string(dump))
|
||||
}
|
||||
if err = resp.Write(rw); err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
log.Infof("%s <-> %s", conn.RemoteAddr(), addr)
|
||||
netpkg.Transport(rw, cc)
|
||||
@ -266,6 +263,49 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *httpHandler) handleProxy(rw, cc io.ReadWriter, req *http.Request, log logger.Logger) (err error) {
|
||||
req.Header.Del("Proxy-Connection")
|
||||
|
||||
if err = req.Write(cc); err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
ch := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
ch <- netpkg.CopyBuffer(rw, cc, 32*1024)
|
||||
}()
|
||||
|
||||
for {
|
||||
err := func() error {
|
||||
req, err := http.ReadRequest(bufio.NewReader(rw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if log.IsLevelEnabled(logger.TraceLevel) {
|
||||
dump, _ := httputil.DumpRequest(req, false)
|
||||
log.Trace(string(dump))
|
||||
}
|
||||
|
||||
req.Header.Del("Proxy-Connection")
|
||||
|
||||
if err = req.Write(cc); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
ch <- err
|
||||
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return <-ch
|
||||
}
|
||||
|
||||
func (h *httpHandler) decodeServerName(s string) (string, error) {
|
||||
b, err := base64.RawURLEncoding.DecodeString(s)
|
||||
if err != nil {
|
||||
@ -284,7 +324,7 @@ func (h *httpHandler) decodeServerName(s string) (string, error) {
|
||||
return string(v), nil
|
||||
}
|
||||
|
||||
func (h *httpHandler) basicProxyAuth(proxyAuth string, log logger.Logger) (username, password string, ok bool) {
|
||||
func (h *httpHandler) basicProxyAuth(proxyAuth string) (username, password string, ok bool) {
|
||||
if proxyAuth == "" {
|
||||
return
|
||||
}
|
||||
@ -306,7 +346,7 @@ func (h *httpHandler) basicProxyAuth(proxyAuth string, log logger.Logger) (usern
|
||||
}
|
||||
|
||||
func (h *httpHandler) authenticate(ctx context.Context, conn net.Conn, req *http.Request, resp *http.Response, log logger.Logger) (id string, ok bool) {
|
||||
u, p, _ := h.basicProxyAuth(req.Header.Get("Proxy-Authorization"), log)
|
||||
u, p, _ := h.basicProxyAuth(req.Header.Get("Proxy-Authorization"))
|
||||
if h.options.Auther == nil {
|
||||
return "", true
|
||||
}
|
||||
@ -412,7 +452,11 @@ func (h *httpHandler) observeStats(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
d := h.md.observePeriod
|
||||
if d < time.Millisecond {
|
||||
d = 5 * time.Second
|
||||
}
|
||||
ticker := time.NewTicker(d)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
|
@ -3,6 +3,7 @@ package http
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
mdata "github.com/go-gost/core/metadata"
|
||||
mdutil "github.com/go-gost/core/metadata/util"
|
||||
@ -18,20 +19,11 @@ type metadata struct {
|
||||
header http.Header
|
||||
hash string
|
||||
authBasicRealm string
|
||||
observePeriod time.Duration
|
||||
}
|
||||
|
||||
func (h *httpHandler) parseMetadata(md mdata.Metadata) error {
|
||||
const (
|
||||
header = "header"
|
||||
probeResistKey = "probeResistance"
|
||||
probeResistKeyX = "probe_resist"
|
||||
knock = "knock"
|
||||
enableUDP = "udp"
|
||||
hash = "hash"
|
||||
authBasicRealm = "authBasicRealm"
|
||||
)
|
||||
|
||||
if m := mdutil.GetStringMapString(md, header); len(m) > 0 {
|
||||
if m := mdutil.GetStringMapString(md, "http.header", "header"); len(m) > 0 {
|
||||
hd := http.Header{}
|
||||
for k, v := range m {
|
||||
hd.Add(k, v)
|
||||
@ -39,22 +31,20 @@ func (h *httpHandler) parseMetadata(md mdata.Metadata) error {
|
||||
h.md.header = hd
|
||||
}
|
||||
|
||||
pr := mdutil.GetString(md, probeResistKey)
|
||||
if pr == "" {
|
||||
pr = mdutil.GetString(md, probeResistKeyX)
|
||||
}
|
||||
if pr != "" {
|
||||
if pr := mdutil.GetString(md, "probeResist", "probe_resist"); pr != "" {
|
||||
if ss := strings.SplitN(pr, ":", 2); len(ss) == 2 {
|
||||
h.md.probeResistance = &probeResistance{
|
||||
Type: ss[0],
|
||||
Value: ss[1],
|
||||
Knock: mdutil.GetString(md, knock),
|
||||
Knock: mdutil.GetString(md, "knock"),
|
||||
}
|
||||
}
|
||||
}
|
||||
h.md.enableUDP = mdutil.GetBool(md, enableUDP)
|
||||
h.md.hash = mdutil.GetString(md, hash)
|
||||
h.md.authBasicRealm = mdutil.GetString(md, authBasicRealm)
|
||||
h.md.enableUDP = mdutil.GetBool(md, "udp")
|
||||
h.md.hash = mdutil.GetString(md, "hash")
|
||||
h.md.authBasicRealm = mdutil.GetString(md, "authBasicRealm")
|
||||
|
||||
h.md.observePeriod = mdutil.GetDuration(md, "observePeriod")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -419,7 +419,11 @@ func (h *http2Handler) observeStats(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
d := h.md.observePeriod
|
||||
if d < time.Millisecond {
|
||||
d = 5 * time.Second
|
||||
}
|
||||
ticker := time.NewTicker(d)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
|
@ -3,6 +3,7 @@ package http2
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
mdata "github.com/go-gost/core/metadata"
|
||||
mdutil "github.com/go-gost/core/metadata/util"
|
||||
@ -17,19 +18,11 @@ type metadata struct {
|
||||
header http.Header
|
||||
hash string
|
||||
authBasicRealm string
|
||||
observePeriod time.Duration
|
||||
}
|
||||
|
||||
func (h *http2Handler) parseMetadata(md mdata.Metadata) error {
|
||||
const (
|
||||
header = "header"
|
||||
probeResistKey = "probeResistance"
|
||||
probeResistKeyX = "probe_resist"
|
||||
knock = "knock"
|
||||
hash = "hash"
|
||||
authBasicRealm = "authBasicRealm"
|
||||
)
|
||||
|
||||
if m := mdutil.GetStringMapString(md, header); len(m) > 0 {
|
||||
if m := mdutil.GetStringMapString(md, "http.header", "header"); len(m) > 0 {
|
||||
hd := http.Header{}
|
||||
for k, v := range m {
|
||||
hd.Add(k, v)
|
||||
@ -37,21 +30,19 @@ func (h *http2Handler) parseMetadata(md mdata.Metadata) error {
|
||||
h.md.header = hd
|
||||
}
|
||||
|
||||
pr := mdutil.GetString(md, probeResistKey)
|
||||
if pr == "" {
|
||||
pr = mdutil.GetString(md, probeResistKeyX)
|
||||
}
|
||||
if pr != "" {
|
||||
if pr := mdutil.GetString(md, "probeResist", "probe_resist"); pr != "" {
|
||||
if ss := strings.SplitN(pr, ":", 2); len(ss) == 2 {
|
||||
h.md.probeResistance = &probeResistance{
|
||||
Type: ss[0],
|
||||
Value: ss[1],
|
||||
Knock: mdutil.GetString(md, knock),
|
||||
Knock: mdutil.GetString(md, "knock"),
|
||||
}
|
||||
}
|
||||
}
|
||||
h.md.hash = mdutil.GetString(md, hash)
|
||||
h.md.authBasicRealm = mdutil.GetString(md, authBasicRealm)
|
||||
h.md.hash = mdutil.GetString(md, "hash")
|
||||
h.md.authBasicRealm = mdutil.GetString(md, "authBasicRealm")
|
||||
|
||||
h.md.observePeriod = mdutil.GetDuration(md, "observePeriod")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
64
handler/redirect/tcp/handler_darwin.go
Normal file
64
handler/redirect/tcp/handler_darwin.go
Normal file
@ -0,0 +1,64 @@
|
||||
package redirect
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (h *redirectHandler) getOriginalDstAddr(conn net.Conn) (addr net.Addr, err error) {
|
||||
host, port, err := localToRemote(conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
portNumber, _ := strconv.Atoi(port)
|
||||
addr = &net.TCPAddr{
|
||||
IP: net.ParseIP(host),
|
||||
Port: portNumber,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func localToRemote(clientConn net.Conn) (string, string, error) {
|
||||
host, port, err := net.SplitHostPort(clientConn.RemoteAddr().String())
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
out, err := exec.Command("sudo", "-n", "/sbin/pfctl", "-s", "state").Output()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
remoteAddr, remotePort, err := translatePfctlOutput(host, port, string(out))
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return remoteAddr, remotePort, err
|
||||
}
|
||||
|
||||
func translatePfctlOutput(address string, port, s string) (string, string, error) {
|
||||
// We may get an ipv4-mapped ipv6 address here, e.g. ::ffff:127.0.0.1.
|
||||
// Those still appear as "127.0.0.1" in the table, so we need to strip the prefix.
|
||||
// re := regexp.MustCompile(`^::ffff:((\d+\.\d+\.\d+\.\d+$))`)
|
||||
// strippedAddress := re.ReplaceAllString(address, "")
|
||||
strippedAddress := address
|
||||
|
||||
// ALL tcp 192.168.1.13:57474 -> 23.205.82.58:443 ESTABLISHED:ESTABLISHED
|
||||
spec := net.JoinHostPort(strippedAddress, port)
|
||||
|
||||
lines := strings.Split(s, "\n")
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, "ESTABLISHED:ESTABLISHED") {
|
||||
if strings.Contains(line, spec) {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) > 4 {
|
||||
return net.SplitHostPort(fields[4])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", "", fmt.Errorf("could not resolve original destination")
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
//go:build !linux
|
||||
//go:build !linux && !darwin
|
||||
|
||||
package redirect
|
||||
|
||||
@ -7,7 +7,7 @@ import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func (h *redirectHandler) getOriginalDstAddr(conn net.Conn) (addr net.Addr, err error) {
|
||||
func (h *redirectHandler) getOriginalDstAddr(_ net.Conn) (addr net.Addr, err error) {
|
||||
err = errors.New("TCP redirect is not available on non-linux platform")
|
||||
return
|
||||
}
|
||||
|
@ -204,7 +204,11 @@ func (h *relayHandler) observeStats(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
d := h.md.observePeriod
|
||||
if d < time.Millisecond {
|
||||
d = 5 * time.Second
|
||||
}
|
||||
ticker := time.NewTicker(d)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
|
@ -16,28 +16,21 @@ type metadata struct {
|
||||
noDelay bool
|
||||
hash string
|
||||
muxCfg *mux.Config
|
||||
observePeriod time.Duration
|
||||
}
|
||||
|
||||
func (h *relayHandler) parseMetadata(md mdata.Metadata) (err error) {
|
||||
const (
|
||||
readTimeout = "readTimeout"
|
||||
enableBind = "bind"
|
||||
udpBufferSize = "udpBufferSize"
|
||||
noDelay = "nodelay"
|
||||
hash = "hash"
|
||||
)
|
||||
h.md.readTimeout = mdutil.GetDuration(md, "readTimeout")
|
||||
h.md.enableBind = mdutil.GetBool(md, "bind")
|
||||
h.md.noDelay = mdutil.GetBool(md, "nodelay")
|
||||
|
||||
h.md.readTimeout = mdutil.GetDuration(md, readTimeout)
|
||||
h.md.enableBind = mdutil.GetBool(md, enableBind)
|
||||
h.md.noDelay = mdutil.GetBool(md, noDelay)
|
||||
|
||||
if bs := mdutil.GetInt(md, udpBufferSize); bs > 0 {
|
||||
if bs := mdutil.GetInt(md, "udpBufferSize"); bs > 0 {
|
||||
h.md.udpBufferSize = int(math.Min(math.Max(float64(bs), 512), 64*1024))
|
||||
} else {
|
||||
h.md.udpBufferSize = 4096
|
||||
}
|
||||
|
||||
h.md.hash = mdutil.GetString(md, hash)
|
||||
h.md.hash = mdutil.GetString(md, "hash")
|
||||
|
||||
h.md.muxCfg = &mux.Config{
|
||||
Version: mdutil.GetInt(md, "mux.version"),
|
||||
@ -49,5 +42,7 @@ func (h *relayHandler) parseMetadata(md mdata.Metadata) (err error) {
|
||||
MaxStreamBuffer: mdutil.GetInt(md, "mux.maxStreamBuffer"),
|
||||
}
|
||||
|
||||
h.md.observePeriod = mdutil.GetDuration(md, "observePeriod")
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -14,9 +14,9 @@ import (
|
||||
"github.com/go-gost/gosocks4"
|
||||
ctxvalue "github.com/go-gost/x/ctx"
|
||||
netpkg "github.com/go-gost/x/internal/net"
|
||||
stats_util "github.com/go-gost/x/internal/util/stats"
|
||||
"github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats_util "github.com/go-gost/x/internal/util/stats"
|
||||
"github.com/go-gost/x/stats"
|
||||
stats_wrapper "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
@ -218,7 +218,11 @@ func (h *socks4Handler) observeStats(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
d := h.md.observePeriod
|
||||
if d < time.Millisecond {
|
||||
d = 5 * time.Second
|
||||
}
|
||||
ticker := time.NewTicker(d)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
|
@ -8,17 +8,14 @@ import (
|
||||
)
|
||||
|
||||
type metadata struct {
|
||||
readTimeout time.Duration
|
||||
hash string
|
||||
readTimeout time.Duration
|
||||
hash string
|
||||
observePeriod time.Duration
|
||||
}
|
||||
|
||||
func (h *socks4Handler) parseMetadata(md mdata.Metadata) (err error) {
|
||||
const (
|
||||
readTimeout = "readTimeout"
|
||||
hash = "hash"
|
||||
)
|
||||
|
||||
h.md.readTimeout = mdutil.GetDuration(md, readTimeout)
|
||||
h.md.hash = mdutil.GetString(md, hash)
|
||||
h.md.readTimeout = mdutil.GetDuration(md, "readTimeout")
|
||||
h.md.hash = mdutil.GetString(md, "hash")
|
||||
h.md.observePeriod = mdutil.GetDuration(md, "observePeriod")
|
||||
return
|
||||
}
|
||||
|
@ -160,7 +160,11 @@ func (h *socks5Handler) observeStats(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
d := h.md.observePeriod
|
||||
if d < time.Millisecond {
|
||||
d = 5 * time.Second
|
||||
}
|
||||
ticker := time.NewTicker(d)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
|
@ -18,32 +18,23 @@ type metadata struct {
|
||||
compatibilityMode bool
|
||||
hash string
|
||||
muxCfg *mux.Config
|
||||
observePeriod time.Duration
|
||||
}
|
||||
|
||||
func (h *socks5Handler) parseMetadata(md mdata.Metadata) (err error) {
|
||||
const (
|
||||
readTimeout = "readTimeout"
|
||||
noTLS = "notls"
|
||||
enableBind = "bind"
|
||||
enableUDP = "udp"
|
||||
udpBufferSize = "udpBufferSize"
|
||||
compatibilityMode = "comp"
|
||||
hash = "hash"
|
||||
)
|
||||
h.md.readTimeout = mdutil.GetDuration(md, "readTimeout")
|
||||
h.md.noTLS = mdutil.GetBool(md, "notls")
|
||||
h.md.enableBind = mdutil.GetBool(md, "bind")
|
||||
h.md.enableUDP = mdutil.GetBool(md, "udp")
|
||||
|
||||
h.md.readTimeout = mdutil.GetDuration(md, readTimeout)
|
||||
h.md.noTLS = mdutil.GetBool(md, noTLS)
|
||||
h.md.enableBind = mdutil.GetBool(md, enableBind)
|
||||
h.md.enableUDP = mdutil.GetBool(md, enableUDP)
|
||||
|
||||
if bs := mdutil.GetInt(md, udpBufferSize); bs > 0 {
|
||||
if bs := mdutil.GetInt(md, "udpBufferSize"); bs > 0 {
|
||||
h.md.udpBufferSize = int(math.Min(math.Max(float64(bs), 512), 64*1024))
|
||||
} else {
|
||||
h.md.udpBufferSize = 4096
|
||||
}
|
||||
|
||||
h.md.compatibilityMode = mdutil.GetBool(md, compatibilityMode)
|
||||
h.md.hash = mdutil.GetString(md, hash)
|
||||
h.md.compatibilityMode = mdutil.GetBool(md, "comp")
|
||||
h.md.hash = mdutil.GetString(md, "hash")
|
||||
|
||||
h.md.muxCfg = &mux.Config{
|
||||
Version: mdutil.GetInt(md, "mux.version"),
|
||||
@ -55,5 +46,7 @@ func (h *socks5Handler) parseMetadata(md mdata.Metadata) (err error) {
|
||||
MaxStreamBuffer: mdutil.GetInt(md, "mux.maxStreamBuffer"),
|
||||
}
|
||||
|
||||
h.md.observePeriod = mdutil.GetDuration(md, "observePeriod")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ import (
|
||||
"github.com/go-gost/core/handler"
|
||||
"github.com/go-gost/core/hop"
|
||||
md "github.com/go-gost/core/metadata"
|
||||
"github.com/go-gost/core/router"
|
||||
tun_util "github.com/go-gost/x/internal/util/tun"
|
||||
"github.com/go-gost/x/registry"
|
||||
"github.com/songgao/water/waterutil"
|
||||
@ -109,23 +108,6 @@ func (h *tunHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler.
|
||||
return h.handleServer(ctx, conn, config, log)
|
||||
}
|
||||
|
||||
func (h *tunHandler) findRouteFor(ctx context.Context, dst net.IP, router router.Router) net.Addr {
|
||||
if v, ok := h.routes.Load(ipToTunRouteKey(dst)); ok {
|
||||
return v.(net.Addr)
|
||||
}
|
||||
|
||||
if router == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if route := router.GetRoute(ctx, dst); route != nil && route.Gateway != nil {
|
||||
if v, ok := h.routes.Load(ipToTunRouteKey(route.Gateway)); ok {
|
||||
return v.(net.Addr)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var mIPProts = map[waterutil.IPProtocol]string{
|
||||
waterutil.HOPOPT: "HOPOPT",
|
||||
waterutil.ICMP: "ICMP",
|
||||
|
@ -16,28 +16,23 @@ type metadata struct {
|
||||
bufferSize int
|
||||
keepAlivePeriod time.Duration
|
||||
passphrase string
|
||||
p2p bool
|
||||
}
|
||||
|
||||
func (h *tunHandler) parseMetadata(md mdata.Metadata) (err error) {
|
||||
const (
|
||||
bufferSize = "bufferSize"
|
||||
keepAlive = "keepAlive"
|
||||
keepAlivePeriod = "ttl"
|
||||
passphrase = "passphrase"
|
||||
)
|
||||
|
||||
h.md.bufferSize = mdutil.GetInt(md, bufferSize)
|
||||
h.md.bufferSize = mdutil.GetInt(md, "tun.bufsize", "bufsize", "buffersize")
|
||||
if h.md.bufferSize <= 0 {
|
||||
h.md.bufferSize = defaultBufferSize
|
||||
}
|
||||
|
||||
if mdutil.GetBool(md, keepAlive) {
|
||||
h.md.keepAlivePeriod = mdutil.GetDuration(md, keepAlivePeriod)
|
||||
if mdutil.GetBool(md, "tun.keepalive", "keepalive") {
|
||||
h.md.keepAlivePeriod = mdutil.GetDuration(md, "tun.ttl", "ttl")
|
||||
if h.md.keepAlivePeriod <= 0 {
|
||||
h.md.keepAlivePeriod = defaultKeepAlivePeriod
|
||||
}
|
||||
}
|
||||
|
||||
h.md.passphrase = mdutil.GetString(md, passphrase)
|
||||
h.md.passphrase = mdutil.GetString(md, "tun.token", "token", "passphrase")
|
||||
h.md.p2p = mdutil.GetBool(md, "tun.p2p", "p2p")
|
||||
return
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/go-gost/core/common/bufpool"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/router"
|
||||
tun_util "github.com/go-gost/x/internal/util/tun"
|
||||
"github.com/songgao/water/waterutil"
|
||||
"golang.org/x/net/ipv4"
|
||||
@ -203,11 +204,13 @@ func (h *tunHandler) transportServer(ctx context.Context, tun io.ReadWriter, con
|
||||
return nil
|
||||
}
|
||||
|
||||
if addr := h.findRouteFor(ctx, dst, config.Router); addr != nil {
|
||||
log.Debugf("find route: %s -> %s", dst, addr)
|
||||
if !h.md.p2p {
|
||||
if addr := h.findRouteFor(ctx, dst, config.Router); addr != nil {
|
||||
log.Debugf("find route: %s -> %s", dst, addr)
|
||||
|
||||
_, err := conn.WriteTo(b[:n], addr)
|
||||
return err
|
||||
_, err := conn.WriteTo(b[:n], addr)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := tun.Write(b[:n]); err != nil {
|
||||
@ -231,6 +234,9 @@ func (h *tunHandler) transportServer(ctx context.Context, tun io.ReadWriter, con
|
||||
}
|
||||
|
||||
func (h *tunHandler) updateRoute(ip net.IP, addr net.Addr, log logger.Logger) {
|
||||
if h.md.p2p {
|
||||
ip = net.IPv6zero
|
||||
}
|
||||
rkey := ipToTunRouteKey(ip)
|
||||
if actual, loaded := h.routes.LoadOrStore(rkey, addr); loaded {
|
||||
if actual.(net.Addr).String() != addr.String() {
|
||||
@ -242,3 +248,25 @@ func (h *tunHandler) updateRoute(ip net.IP, addr net.Addr, log logger.Logger) {
|
||||
log.Debugf("new route: %s -> %s", ip, addr)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *tunHandler) findRouteFor(ctx context.Context, dst net.IP, router router.Router) net.Addr {
|
||||
if h.md.p2p {
|
||||
dst = net.IPv6zero
|
||||
router = nil
|
||||
}
|
||||
|
||||
if v, ok := h.routes.Load(ipToTunRouteKey(dst)); ok {
|
||||
return v.(net.Addr)
|
||||
}
|
||||
|
||||
if router == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if route := router.GetRoute(ctx, dst); route != nil && route.Gateway != nil {
|
||||
if v, ok := h.routes.Load(ipToTunRouteKey(route.Gateway)); ok {
|
||||
return v.(net.Addr)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
66
hop/hop.go
66
hop/hop.go
@ -1,7 +1,6 @@
|
||||
package hop
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
@ -181,7 +180,11 @@ func (p *chainHop) filterByHost(host string, nodes ...*chain.Node) (filters []*c
|
||||
if node == nil {
|
||||
continue
|
||||
}
|
||||
vhost := node.Options().Host
|
||||
|
||||
var vhost string
|
||||
if filter := node.Options().Filter; filter != nil {
|
||||
vhost = filter.Host
|
||||
}
|
||||
if vhost == "" { // backup node
|
||||
if !found {
|
||||
filters = append(filters, node)
|
||||
@ -216,14 +219,18 @@ func (p *chainHop) filterByProtocol(protocol string, nodes ...*chain.Node) (filt
|
||||
continue
|
||||
}
|
||||
|
||||
if node.Options().Protocol == "" {
|
||||
var prot string
|
||||
if filter := node.Options().Filter; filter != nil {
|
||||
prot = filter.Protocol
|
||||
}
|
||||
if prot == "" {
|
||||
if !found {
|
||||
filters = append(filters, node)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if node.Options().Protocol == protocol {
|
||||
if prot == protocol {
|
||||
if !found {
|
||||
filters = nil
|
||||
}
|
||||
@ -244,19 +251,31 @@ func (p *chainHop) filterByPath(path string, nodes ...*chain.Node) (filters []*c
|
||||
p.options.logger.Debugf("filter by path: %s", path)
|
||||
|
||||
sort.SliceStable(nodes, func(i, j int) bool {
|
||||
return len(nodes[i].Options().Path) > len(nodes[j].Options().Path)
|
||||
filter1 := nodes[i].Options().Filter
|
||||
if filter1 == nil {
|
||||
return false
|
||||
}
|
||||
filter2 := nodes[j].Options().Filter
|
||||
if filter2 == nil {
|
||||
return true
|
||||
}
|
||||
return len(filter1.Path) > len(filter2.Path)
|
||||
})
|
||||
|
||||
found := false
|
||||
for _, node := range nodes {
|
||||
if node.Options().Path == "" {
|
||||
var pathFilter string
|
||||
if filter := node.Options().Filter; filter != nil {
|
||||
pathFilter = filter.Path
|
||||
}
|
||||
if pathFilter == "" {
|
||||
if !found {
|
||||
filters = append(filters, node)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(path, node.Options().Path) {
|
||||
if strings.HasPrefix(path, pathFilter) {
|
||||
if !found {
|
||||
filters = nil
|
||||
}
|
||||
@ -308,33 +327,30 @@ func (p *chainHop) reload(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
func (p *chainHop) load(ctx context.Context) (nodes []*chain.Node, err error) {
|
||||
if p.options.fileLoader != nil {
|
||||
r, er := p.options.fileLoader.Load(ctx)
|
||||
if loader := p.options.fileLoader; loader != nil {
|
||||
r, er := loader.Load(ctx)
|
||||
if er != nil {
|
||||
p.options.logger.Warnf("file loader: %v", er)
|
||||
}
|
||||
nodes, _ = p.parseNode(r)
|
||||
}
|
||||
|
||||
if p.options.redisLoader != nil {
|
||||
if lister, ok := p.options.redisLoader.(loader.Lister); ok {
|
||||
list, er := lister.List(ctx)
|
||||
if er != nil {
|
||||
p.options.logger.Warnf("redis loader: %v", er)
|
||||
}
|
||||
for _, s := range list {
|
||||
nl, _ := p.parseNode(bytes.NewReader([]byte(s)))
|
||||
nodes = append(nodes, nl...)
|
||||
}
|
||||
if loader := p.options.redisLoader; loader != nil {
|
||||
r, er := loader.Load(ctx)
|
||||
if er != nil {
|
||||
p.options.logger.Warnf("redis loader: %v", er)
|
||||
}
|
||||
ns, _ := p.parseNode(r)
|
||||
nodes = append(nodes, ns...)
|
||||
}
|
||||
if p.options.httpLoader != nil {
|
||||
r, er := p.options.httpLoader.Load(ctx)
|
||||
|
||||
if loader := p.options.httpLoader; loader != nil {
|
||||
r, er := loader.Load(ctx)
|
||||
if er != nil {
|
||||
p.options.logger.Warnf("http loader: %v", er)
|
||||
}
|
||||
if node, _ := p.parseNode(r); node != nil {
|
||||
nodes = append(nodes, node...)
|
||||
if ns, _ := p.parseNode(r); ns != nil {
|
||||
nodes = append(nodes, ns...)
|
||||
}
|
||||
}
|
||||
|
||||
@ -342,6 +358,10 @@ func (p *chainHop) load(ctx context.Context) (nodes []*chain.Node, err error) {
|
||||
}
|
||||
|
||||
func (p *chainHop) parseNode(r io.Reader) ([]*chain.Node, error) {
|
||||
if r == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var ncs []*config.NodeConfig
|
||||
if err := json.NewDecoder(r).Decode(&ncs); err != nil {
|
||||
return nil, err
|
||||
|
@ -94,6 +94,10 @@ func (p *grpcPlugin) Select(ctx context.Context, opts ...hop.SelectOption) *chai
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if p.conn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
|
@ -71,6 +71,10 @@ func (p *grpcPlugin) Lookup(ctx context.Context, network, host string, opts ...h
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if p.conn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
|
@ -82,6 +82,10 @@ func (p *grpcPlugin) SetRule(ctx context.Context, rule *ingress.Rule, opts ...in
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if p.conn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
|
@ -12,6 +12,11 @@ import (
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
const (
|
||||
GRPC string = "grpc"
|
||||
HTTP string = "http"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Token string
|
||||
TLSConfig *tls.Config
|
||||
|
@ -160,7 +160,7 @@ func NewHTTP3Server(addr string, quicConfig *quic.Config, opts ...ServerOption)
|
||||
http3Server: &http3.Server{
|
||||
Addr: addr,
|
||||
TLSConfig: options.tlsConfig,
|
||||
QuicConfig: quicConfig,
|
||||
QUICConfig: quicConfig,
|
||||
},
|
||||
cqueue: make(chan net.Conn, options.backlog),
|
||||
closed: make(chan struct{}),
|
||||
|
@ -95,6 +95,10 @@ func (p *grpcPlugin) Out(ctx context.Context, key string, opts ...traffic.Option
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if p.conn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ func (l *http3Listener) Init(md md.Metadata) (err error) {
|
||||
l.server = &http3.Server{
|
||||
Addr: l.options.Addr,
|
||||
TLSConfig: l.options.TLSConfig,
|
||||
QuicConfig: &quic.Config{
|
||||
QUICConfig: &quic.Config{
|
||||
KeepAlivePeriod: l.md.keepAlivePeriod,
|
||||
HandshakeIdleTimeout: l.md.handshakeTimeout,
|
||||
MaxIdleTimeout: l.md.maxIdleTimeout,
|
||||
|
@ -66,7 +66,7 @@ func (l *wtListener) Init(md md.Metadata) (err error) {
|
||||
H3: http3.Server{
|
||||
Addr: l.options.Addr,
|
||||
TLSConfig: l.options.TLSConfig,
|
||||
QuicConfig: &quic.Config{
|
||||
QUICConfig: &quic.Config{
|
||||
KeepAlivePeriod: l.md.keepAlivePeriod,
|
||||
HandshakeIdleTimeout: l.md.handshakeTimeout,
|
||||
MaxIdleTimeout: l.md.maxIdleTimeout,
|
||||
|
@ -52,7 +52,12 @@ func (l *kcpListener) parseMetadata(md mdata.Metadata) (err error) {
|
||||
l.md.config.KeepAlive = mdutil.GetInt(md, "kcp.keepalive")
|
||||
l.md.config.Interval = mdutil.GetInt(md, "kcp.interval")
|
||||
l.md.config.MTU = mdutil.GetInt(md, "kcp.mtu")
|
||||
l.md.config.SmuxVer = mdutil.GetInt(md, "kcp.smuxVer")
|
||||
l.md.config.RcvWnd = mdutil.GetInt(md, "kcp.rcvwnd")
|
||||
l.md.config.SndWnd = mdutil.GetInt(md, "kcp.sndwnd")
|
||||
l.md.config.SmuxVer = mdutil.GetInt(md, "kcp.smuxver")
|
||||
l.md.config.SmuxBuf = mdutil.GetInt(md, "kcp.smuxbuf")
|
||||
l.md.config.StreamBuf = mdutil.GetInt(md, "kcp.streambuf")
|
||||
l.md.config.NoComp = mdutil.GetBool(md, "kcp.nocomp")
|
||||
|
||||
l.md.backlog = mdutil.GetInt(md, backlog)
|
||||
if l.md.backlog <= 0 {
|
||||
|
9
listener/redirect/tcp/listener_darwin.go
Normal file
9
listener/redirect/tcp/listener_darwin.go
Normal file
@ -0,0 +1,9 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func (l *redirectListener) control(network, address string, c syscall.RawConn) error {
|
||||
return nil
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
//go:build !linux
|
||||
//go:build !linux && !darwin
|
||||
|
||||
package tcp
|
||||
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
mdata "github.com/go-gost/core/metadata"
|
||||
mdutil "github.com/go-gost/core/metadata/util"
|
||||
ssh_util "github.com/go-gost/x/internal/util/ssh"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
@ -29,6 +30,10 @@ func (l *sshListener) parseMetadata(md mdata.Metadata) (err error) {
|
||||
)
|
||||
|
||||
if key := mdutil.GetString(md, privateKeyFile); key != "" {
|
||||
key, err = homedir.Expand(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := os.ReadFile(key)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1,11 +1,14 @@
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
mdata "github.com/go-gost/core/metadata"
|
||||
mdutil "github.com/go-gost/core/metadata/util"
|
||||
ssh_util "github.com/go-gost/x/internal/util/ssh"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/zalando/go-keyring"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
@ -29,12 +32,24 @@ func (l *sshdListener) parseMetadata(md mdata.Metadata) (err error) {
|
||||
)
|
||||
|
||||
if key := mdutil.GetString(md, privateKeyFile); key != "" {
|
||||
key, err = homedir.Expand(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := os.ReadFile(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pp := mdutil.GetString(md, passphrase)
|
||||
var pp string
|
||||
if mdutil.GetBool(md, "passphraseFromKeyring") {
|
||||
pp, err = keyring.Get(fmt.Sprintf("SSH %s", key), l.options.Auth.Username())
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get secret(%s) from keyring: %w", key, err)
|
||||
}
|
||||
} else {
|
||||
pp = mdutil.GetString(md, passphrase)
|
||||
}
|
||||
if pp == "" {
|
||||
l.md.signer, err = ssh.ParsePrivateKey(data)
|
||||
} else {
|
||||
|
@ -33,6 +33,7 @@ func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) observer.Obs
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/observer"
|
||||
@ -58,6 +59,9 @@ func NewHTTPPlugin(name string, url string, opts ...plugin.Option) observer.Obse
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(url, "http") {
|
||||
url = "http://" + url
|
||||
}
|
||||
return &httpPlugin{
|
||||
url: url,
|
||||
client: plugin.NewHTTPClient(&options),
|
||||
|
@ -69,6 +69,10 @@ func (p *grpcPlugin) Record(ctx context.Context, b []byte, opts ...recorder.Reco
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if p.conn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
|
@ -37,3 +37,11 @@ func (w *bypassWrapper) Contains(ctx context.Context, network, addr string, opts
|
||||
}
|
||||
return bp.Contains(ctx, network, addr, opts...)
|
||||
}
|
||||
|
||||
func (p *bypassWrapper) IsWhitelist() bool {
|
||||
bp := p.r.get(p.name)
|
||||
if bp == nil {
|
||||
return false
|
||||
}
|
||||
return bp.IsWhitelist()
|
||||
}
|
||||
|
@ -70,6 +70,10 @@ func (p *grpcPlugin) Resolve(ctx context.Context, network, host string, opts ...
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if p.conn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
|
@ -63,6 +63,10 @@ func (p *grpcPlugin) GetRoute(ctx context.Context, dst net.IP, opts ...router.Op
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if p.conn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
|
@ -127,6 +127,10 @@ func (p *grpcPlugin) Get(ctx context.Context, name string) ([]*sd.Service, error
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if p.conn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
|
@ -24,15 +24,16 @@ import (
|
||||
)
|
||||
|
||||
type options struct {
|
||||
admission admission.Admission
|
||||
recorders []recorder.RecorderObject
|
||||
preUp []string
|
||||
postUp []string
|
||||
preDown []string
|
||||
postDown []string
|
||||
stats *stats.Stats
|
||||
observer observer.Observer
|
||||
logger logger.Logger
|
||||
admission admission.Admission
|
||||
recorders []recorder.RecorderObject
|
||||
preUp []string
|
||||
postUp []string
|
||||
preDown []string
|
||||
postDown []string
|
||||
stats *stats.Stats
|
||||
observer observer.Observer
|
||||
observePeriod time.Duration
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
type Option func(opts *options)
|
||||
@ -85,6 +86,12 @@ func ObserverOption(observer observer.Observer) Option {
|
||||
}
|
||||
}
|
||||
|
||||
func ObservePeriodOption(period time.Duration) Option {
|
||||
return func(opts *options) {
|
||||
opts.observePeriod = period
|
||||
}
|
||||
}
|
||||
|
||||
func LoggerOption(logger logger.Logger) Option {
|
||||
return func(opts *options) {
|
||||
opts.logger = logger
|
||||
@ -129,6 +136,10 @@ func (s *defaultService) Addr() net.Addr {
|
||||
func (s *defaultService) Serve() error {
|
||||
s.execCmds("post-up", s.options.postUp)
|
||||
s.setState(StateReady)
|
||||
s.status.addEvent(Event{
|
||||
Time: time.Now(),
|
||||
Message: fmt.Sprintf("service %s is listening on %s", s.name, s.listener.Addr()),
|
||||
})
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
@ -290,7 +301,12 @@ func (s *defaultService) observeStats(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
d := s.options.observePeriod
|
||||
if d < time.Millisecond {
|
||||
d = 5 * time.Second
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(d)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
|
@ -72,5 +72,8 @@ func (p *Status) addEvent(event Event) {
|
||||
}
|
||||
|
||||
func (p *Status) Stats() *stats.Stats {
|
||||
if p == nil {
|
||||
return nil
|
||||
}
|
||||
return p.stats
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user