Files
gin-contrib/limit/limit.go
T
2024-04-02 15:13:13 +03:00

62 lines
1.5 KiB
Go

package limit
import (
"log"
"net"
"strings"
"git.company.lan/gopkg/gin"
)
// CIDR is a middleware that check given CIDR rules and return 403 Forbidden when user is not coming from allowed source.
// CIDRs accepts a list of CIDRs, separated by comma. (e.g. 127.0.0.1/32, ::1/128 )
func New(CIDRs string, opts ...Option) gin.HandlerFunc {
l := &Limit{
handler: func(c *gin.Context, remoteAddr, CIDRs string) bool {
log.Println("[LIMIT] Request from [" + remoteAddr + "] is not allow to access `" + c.Request.RequestURI + "`, only allow from: [" + CIDRs + "]")
return true
},
}
for _, opt := range opts {
opt(l)
}
return func(c *gin.Context) {
remoteAddr := c.ClientIP()
// parse it into IP type
remoteIP := net.ParseIP(remoteAddr)
// split CIDRs by comma, and we are going check them one by one
cidrSlices := strings.Split(CIDRs, ",")
// under of CIDR we were in
var matchCount uint
// go over each CIDR and do the tests
for _, cidr := range cidrSlices {
// remove unwanted spaces
cidr = strings.TrimSpace(cidr)
// try to parse the CIDR
_, cidrIPNet, err := net.ParseCIDR(cidr)
if err != nil {
_ = c.AbortWithError(500, err)
return
}
// This is the core of this middleware, it ask current CIDR network range to test if current IP is in
if cidrIPNet.Contains(remoteIP) {
matchCount = matchCount + 1
}
}
// if no CIDR ranges contains our IP
if matchCount == 0 && l.handler(c, remoteAddr, CIDRs) {
c.AbortWithStatus(403)
}
}
}