mirror of
https://github.com/yusing/godoxy.git
synced 2025-06-01 09:32:35 +02:00

Some checks are pending
Docker Image CI (socket-proxy) / build (push) Waiting to run
* refactor: simplify io code and make utils module independent * fix(docker): agent and socket-proxy docker event flushing with modified reverse proxy handler * refactor: remove unused code * refactor: remove the use of logging module in most code * refactor: streamline domain mismatch check in certState function * tweak: use ecdsa p-256 for autocert * fix(tests): update health check tests for invalid host and add case for port in host * feat(acme): custom acme directory * refactor: code refactor and improved context and error handling * tweak: optimize memory usage under load * fix(oidc): restore old user matching behavior * docs: add ChatGPT assistant to README --------- Co-authored-by: yusing <yusing@6uo.me>
82 lines
2.1 KiB
Go
82 lines
2.1 KiB
Go
package middleware
|
|
|
|
import (
|
|
"net"
|
|
"net/http"
|
|
|
|
"github.com/go-playground/validator/v10"
|
|
gphttp "github.com/yusing/go-proxy/internal/net/gphttp"
|
|
"github.com/yusing/go-proxy/internal/net/types"
|
|
"github.com/yusing/go-proxy/internal/serialization"
|
|
F "github.com/yusing/go-proxy/internal/utils/functional"
|
|
)
|
|
|
|
type (
|
|
cidrWhitelist struct {
|
|
CIDRWhitelistOpts
|
|
Tracer
|
|
cachedAddr F.Map[string, bool] // cache for trusted IPs
|
|
}
|
|
CIDRWhitelistOpts struct {
|
|
Allow []*types.CIDR `validate:"min=1"`
|
|
StatusCode int `json:"status_code" aliases:"status" validate:"omitempty,status_code"`
|
|
Message string
|
|
}
|
|
)
|
|
|
|
var (
|
|
CIDRWhiteList = NewMiddleware[cidrWhitelist]()
|
|
cidrWhitelistDefaults = CIDRWhitelistOpts{
|
|
Allow: []*types.CIDR{},
|
|
StatusCode: http.StatusForbidden,
|
|
Message: "IP not allowed",
|
|
}
|
|
)
|
|
|
|
func init() {
|
|
serialization.MustRegisterValidation("status_code", func(fl validator.FieldLevel) bool {
|
|
statusCode := fl.Field().Int()
|
|
return gphttp.IsStatusCodeValid(int(statusCode))
|
|
})
|
|
}
|
|
|
|
// setup implements MiddlewareWithSetup.
|
|
func (wl *cidrWhitelist) setup() {
|
|
wl.CIDRWhitelistOpts = cidrWhitelistDefaults
|
|
wl.cachedAddr = F.NewMapOf[string, bool]()
|
|
}
|
|
|
|
// before implements RequestModifier.
|
|
func (wl *cidrWhitelist) before(w http.ResponseWriter, r *http.Request) bool {
|
|
return wl.checkIP(w, r)
|
|
}
|
|
|
|
// checkIP checks if the IP address is allowed.
|
|
func (wl *cidrWhitelist) checkIP(w http.ResponseWriter, r *http.Request) bool {
|
|
var allow, ok bool
|
|
if allow, ok = wl.cachedAddr.Load(r.RemoteAddr); !ok {
|
|
ipStr, _, err := net.SplitHostPort(r.RemoteAddr)
|
|
if err != nil {
|
|
ipStr = r.RemoteAddr
|
|
}
|
|
ip := net.ParseIP(ipStr)
|
|
for _, cidr := range wl.Allow {
|
|
if cidr.Contains(ip) {
|
|
wl.cachedAddr.Store(r.RemoteAddr, true)
|
|
allow = true
|
|
wl.AddTracef("client %s is allowed", ipStr).With("allowed CIDR", cidr)
|
|
break
|
|
}
|
|
}
|
|
if !allow {
|
|
wl.cachedAddr.Store(r.RemoteAddr, false)
|
|
wl.AddTracef("client %s is forbidden", ipStr).With("allowed CIDRs", wl.Allow)
|
|
}
|
|
}
|
|
if !allow {
|
|
http.Error(w, wl.Message, wl.StatusCode)
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|