62 lines
1.5 KiB
Go
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)
|
|
}
|
|
}
|
|
}
|