added cidr_whitelist middleware

This commit is contained in:
yusing 2024-10-02 01:20:25 +08:00
parent ed887a5cfc
commit e8c3e4c75f
2 changed files with 106 additions and 1 deletions

View file

@ -12,7 +12,7 @@
- [Real IP](#real-ip) - [Real IP](#real-ip)
- [Custom](#custom) - [Custom](#custom)
- [Cloudflare](#cloudflare) - [Cloudflare](#cloudflare)
- [Modify request or response](#modify-request-or-response) - [CIDR Whitelist](#cidr-whitelist)
- [Set headers](#set-headers) - [Set headers](#set-headers)
- [Add headers](#add-headers) - [Add headers](#add-headers)
- [Hide headers](#hide-headers) - [Hide headers](#hide-headers)
@ -147,6 +147,8 @@ location / {
} }
``` ```
[🔼Back to top](#table-of-content)
#### Cloudflare #### Cloudflare
This is a preset for Cloudflare This is a preset for Cloudflare
@ -169,6 +171,28 @@ app1:
[🔼Back to top](#table-of-content) [🔼Back to top](#table-of-content)
### CIDR Whitelist
```yaml
# docker labels
proxy.app1.middlewares.cidr_whitelist.allow: |
- 10.0.0.0/8
- 192.168.0.0/16
# optional (default: 403)
proxy.app1.middlewares.cidr_whitelist.status_code: 403
# optional (default: "IP not allowed")
proxy.app1.middlewares.cidr_whitelist.message: "IP not allowed"
# include file
app1:
middlewares:
whitelist:
cidr:
- 10.0.0.0/8
- 192.168.0.0/16
status_code: 403 # default
message: "IP not allowed" # default
### Modify request or response ### Modify request or response
```yaml ```yaml
@ -365,6 +389,8 @@ You may use them with `<middleware_name>@file`
See [example](../internal/net/http/middleware/test_data/middleware_compose.yml) See [example](../internal/net/http/middleware/test_data/middleware_compose.yml)
[🔼Back to top](#table-of-content)
## Examples ## Examples
### Authentik (untested, experimental) ### Authentik (untested, experimental)

View file

@ -0,0 +1,79 @@
package middleware
import (
"net"
"net/http"
D "github.com/yusing/go-proxy/internal/docker"
E "github.com/yusing/go-proxy/internal/error"
"github.com/yusing/go-proxy/internal/types"
)
type cidrWhitelist struct {
*cidrWhitelistOpts
m *Middleware
}
type cidrWhitelistOpts struct {
Allow []*types.CIDR
StatusCode int
Message string
trustedAddr map[string]struct{} // cache for trusted IPs
}
var CIDRWhiteList = &cidrWhitelist{
m: &Middleware{
labelParserMap: D.ValueParserMap{
"allow": D.YamlStringListParser,
"statusCode": D.IntParser,
},
},
}
var cidrWhitelistDefaults = func() *cidrWhitelistOpts {
return &cidrWhitelistOpts{
Allow: []*types.CIDR{},
StatusCode: http.StatusForbidden,
Message: "IP not allowed",
trustedAddr: make(map[string]struct{}),
}
}
func NewCIDRWhitelist(opts OptionsRaw) (*Middleware, E.NestedError) {
wl := new(cidrWhitelist)
wl.m = &Middleware{
impl: wl,
before: wl.checkIP,
}
wl.cidrWhitelistOpts = cidrWhitelistDefaults()
err := Deserialize(opts, wl.cidrWhitelistOpts)
if err != nil {
return nil, err
}
if len(wl.cidrWhitelistOpts.Allow) == 0 {
return nil, E.Missing("allow range")
}
return wl.m, nil
}
func (wl *cidrWhitelist) checkIP(next http.Handler, w ResponseWriter, r *Request) {
var ok bool
if _, ok = wl.trustedAddr[r.RemoteAddr]; !ok {
ip := net.IP(r.RemoteAddr)
for _, cidr := range wl.cidrWhitelistOpts.Allow {
if cidr.Contains(ip) {
wl.trustedAddr[r.RemoteAddr] = struct{}{}
ok = true
break
}
}
}
if !ok {
w.WriteHeader(wl.StatusCode)
w.Write([]byte(wl.Message))
return
}
next.ServeHTTP(w, r)
}