feat: add legacy IP access filtering

This commit is contained in:
OpenClaw Agent
2026-09-21 13:20:29 +08:00
parent 3175b06295
commit 8a82e48507
2 changed files with 79 additions and 2 deletions
+1 -1
View File
@@ -63,7 +63,7 @@ func main() {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
srv := &api.Server{Store: storage.Local{Root: root}, Auth: mgr, Sessions: map[string]*auth.Account{}, WebDAVRoot: root} srv := &api.Server{Store: storage.Local{Root: root}, Auth: mgr, Sessions: map[string]*auth.Account{}, WebDAVRoot: root, Allow: cfg.Allow}
addr := ":" + itoa(cfg.Port) addr := ":" + itoa(cfg.Port)
log.Printf("chfs-ng listening on %s root=%s", addr, filepath.Clean(root)) log.Printf("chfs-ng listening on %s root=%s", addr, filepath.Clean(root))
if cfg.SSLCert != "" && cfg.SSLKey != "" { if cfg.SSLCert != "" && cfg.SSLKey != "" {
+78 -1
View File
@@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"io" "io"
"mime/multipart" "mime/multipart"
"net"
"net/http" "net/http"
"path" "path"
"path/filepath" "path/filepath"
@@ -22,6 +23,7 @@ type Server struct {
Auth *auth.Manager Auth *auth.Manager
Sessions map[string]*auth.Account Sessions map[string]*auth.Account
WebDAVRoot string WebDAVRoot string
Allow string
} }
type fileInfo struct { type fileInfo struct {
Name string `json:"name"` Name string `json:"name"`
@@ -53,7 +55,7 @@ func (s *Server) Handler() http.Handler {
mux.HandleFunc("/chfs/shared", s.shared) mux.HandleFunc("/chfs/shared", s.shared)
mux.HandleFunc("/chfs/preview", s.preview) mux.HandleFunc("/chfs/preview", s.preview)
mux.HandleFunc("/", s.fileHandler) mux.HandleFunc("/", s.fileHandler)
return mux return s.ipFilter(mux)
} }
func account(r *http.Request, s *Server) *auth.Account { func account(r *http.Request, s *Server) *auth.Account {
if c, e := r.Cookie("chfs_token"); e == nil { if c, e := r.Cookie("chfs_token"); e == nil {
@@ -509,3 +511,78 @@ func (s *Server) webdav(w http.ResponseWriter, r *http.Request) {
h := &webdav.Handler{FileSystem: webdav.LocalFileSystem(s.WebDAVRoot)} h := &webdav.Handler{FileSystem: webdav.LocalFileSystem(s.WebDAVRoot)}
h.ServeHTTP(w, r) h.ServeHTTP(w, r)
} }
func (s *Server) ipFilter(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if s.Allow != "" && !allowedIP(s.Allow, clientIP(r)) {
http.Error(w, "forbidden", http.StatusForbidden)
return
}
next.ServeHTTP(w, r)
})
}
func clientIP(r *http.Request) net.IP {
host, _, err := net.SplitHostPort(r.RemoteAddr)
if err == nil {
return net.ParseIP(host)
}
return net.ParseIP(r.RemoteAddr)
}
func allowedIP(rule string, ip net.IP) bool {
if ip == nil {
return false
}
rule = strings.TrimSpace(rule)
black := false
if strings.HasPrefix(strings.ToLower(rule), "not(") && strings.HasSuffix(rule, ")") {
black = true
rule = strings.TrimSpace(rule[4 : len(rule)-1])
}
matched := false
for _, item := range strings.Split(rule, ",") {
item = strings.TrimSpace(item)
if item == "" {
continue
}
if ipInItem(ip, item) {
matched = true
break
}
}
if black {
return !matched
}
return matched
}
func ipInItem(ip net.IP, item string) bool {
if strings.Contains(item, "-") {
parts := strings.SplitN(item, "-", 2)
lo, hi := net.ParseIP(strings.TrimSpace(parts[0])), net.ParseIP(strings.TrimSpace(parts[1]))
if lo == nil || hi == nil {
return false
}
v := ip.To4()
l := lo.To4()
h := hi.To4()
if v == nil || l == nil || h == nil {
return false
}
return bytesCompare(v, l) >= 0 && bytesCompare(v, h) <= 0
}
return ip.Equal(net.ParseIP(item))
}
func bytesCompare(a, b net.IP) int {
for i := range a {
if a[i] < b[i] {
return -1
}
if a[i] > b[i] {
return 1
}
}
return 0
}