mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-06-06 07:37:21 +02:00

+ Added force TLS v1.2 above toggle + Added trace route + Added ICMP ping + Added special routing rules module for up-coming acme integration + Fixed IPv6 check bug in black/whitelist + Optimized UI for TCP Proxy +
176 lines
4.6 KiB
Go
176 lines
4.6 KiB
Go
package pathrule
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"imuslab.com/zoraxy/mod/utils"
|
|
)
|
|
|
|
/*
|
|
Pathblock.go
|
|
|
|
This script block off some of the specific pathname in access
|
|
For example, this module can help you block request for a particular
|
|
apache directory or functional endpoints like /.well-known/ when you
|
|
are not using it
|
|
*/
|
|
|
|
type Options struct {
|
|
ConfigFolder string //The folder to store the path blocking config files
|
|
}
|
|
|
|
type BlockingPath struct {
|
|
UUID string
|
|
MatchingPath string
|
|
ExactMatch bool
|
|
StatusCode int
|
|
CustomHeaders http.Header
|
|
CustomHTML []byte
|
|
Enabled bool
|
|
CaseSenitive bool
|
|
}
|
|
|
|
type Handler struct {
|
|
Options *Options
|
|
BlockingPaths []*BlockingPath
|
|
}
|
|
|
|
// Create a new path blocker handler
|
|
func NewPathBlocker(options *Options) *Handler {
|
|
//Create folder if not exists
|
|
if !utils.FileExists(options.ConfigFolder) {
|
|
os.Mkdir(options.ConfigFolder, 0775)
|
|
}
|
|
|
|
//Load the configs from file
|
|
//TODO
|
|
|
|
return &Handler{
|
|
Options: options,
|
|
BlockingPaths: []*BlockingPath{},
|
|
}
|
|
}
|
|
|
|
func (h *Handler) ListBlockingPath() []*BlockingPath {
|
|
return h.BlockingPaths
|
|
}
|
|
|
|
// Get the blocker from matching path (path match, ignore tailing slash)
|
|
func (h *Handler) GetPathBlockerFromMatchingPath(matchingPath string) *BlockingPath {
|
|
for _, blocker := range h.BlockingPaths {
|
|
if blocker.MatchingPath == matchingPath {
|
|
return blocker
|
|
} else if strings.TrimSuffix(blocker.MatchingPath, "/") == strings.TrimSuffix(matchingPath, "/") {
|
|
return blocker
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (h *Handler) GetPathBlockerFromUUID(UUID string) *BlockingPath {
|
|
for _, blocker := range h.BlockingPaths {
|
|
if blocker.UUID == UUID {
|
|
return blocker
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (h *Handler) AddBlockingPath(pathBlocker *BlockingPath) error {
|
|
//Check if the blocker exists
|
|
blockerPath := pathBlocker.MatchingPath
|
|
targetBlocker := h.GetPathBlockerFromMatchingPath(blockerPath)
|
|
if targetBlocker != nil {
|
|
//Blocker with the same matching path already exists
|
|
return errors.New("path blocker with the same path already exists")
|
|
}
|
|
|
|
h.BlockingPaths = append(h.BlockingPaths, pathBlocker)
|
|
|
|
//Write the new config to file
|
|
return h.SaveBlockerToFile(pathBlocker)
|
|
}
|
|
|
|
func (h *Handler) RemoveBlockingPathByUUID(uuid string) error {
|
|
newBlockingList := []*BlockingPath{}
|
|
for _, thisBlocker := range h.BlockingPaths {
|
|
if thisBlocker.UUID != uuid {
|
|
newBlockingList = append(newBlockingList, thisBlocker)
|
|
}
|
|
}
|
|
|
|
if len(h.BlockingPaths) == len(newBlockingList) {
|
|
//Nothing is removed
|
|
return errors.New("given matching path blocker not exists")
|
|
}
|
|
|
|
h.BlockingPaths = newBlockingList
|
|
|
|
return h.RemoveBlockerFromFile(uuid)
|
|
}
|
|
|
|
func (h *Handler) SaveBlockerToFile(pathBlocker *BlockingPath) error {
|
|
saveFilename := filepath.Join(h.Options.ConfigFolder, pathBlocker.UUID)
|
|
js, _ := json.MarshalIndent(pathBlocker, "", " ")
|
|
return os.WriteFile(saveFilename, js, 0775)
|
|
}
|
|
|
|
func (h *Handler) RemoveBlockerFromFile(uuid string) error {
|
|
expectedConfigFile := filepath.Join(h.Options.ConfigFolder, uuid)
|
|
if !utils.FileExists(expectedConfigFile) {
|
|
return errors.New("config file not found on disk")
|
|
}
|
|
|
|
return os.Remove(expectedConfigFile)
|
|
}
|
|
|
|
// Get all the matching blockers for the given URL path
|
|
// return all the path blockers and the max length matching rule
|
|
func (h *Handler) GetMatchingBlockers(urlPath string) ([]*BlockingPath, *BlockingPath) {
|
|
urlPath = strings.TrimSuffix(urlPath, "/")
|
|
matchingBlockers := []*BlockingPath{}
|
|
var longestMatchingPrefix *BlockingPath = nil
|
|
for _, thisBlocker := range h.BlockingPaths {
|
|
if thisBlocker.Enabled == false {
|
|
//This blocker is not enabled. Ignore this
|
|
continue
|
|
}
|
|
|
|
incomingURLPath := urlPath
|
|
matchingPath := strings.TrimSuffix(thisBlocker.MatchingPath, "/")
|
|
|
|
if !thisBlocker.CaseSenitive {
|
|
//This is not case sensitive
|
|
incomingURLPath = strings.ToLower(incomingURLPath)
|
|
matchingPath = strings.ToLower(matchingPath)
|
|
}
|
|
|
|
if matchingPath == incomingURLPath {
|
|
//This blocker have exact url path match
|
|
matchingBlockers = append(matchingBlockers, thisBlocker)
|
|
if longestMatchingPrefix == nil || len(thisBlocker.MatchingPath) > len(longestMatchingPrefix.MatchingPath) {
|
|
longestMatchingPrefix = thisBlocker
|
|
}
|
|
continue
|
|
}
|
|
|
|
if !thisBlocker.ExactMatch && strings.HasPrefix(incomingURLPath, matchingPath) {
|
|
//This blocker have prefix url match
|
|
matchingBlockers = append(matchingBlockers, thisBlocker)
|
|
if longestMatchingPrefix == nil || len(thisBlocker.MatchingPath) > len(longestMatchingPrefix.MatchingPath) {
|
|
longestMatchingPrefix = thisBlocker
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
|
|
return matchingBlockers, longestMatchingPrefix
|
|
}
|