Updates 2.6.4

+ 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
+
This commit is contained in:
Toby Chui
2023-06-16 00:48:39 +08:00
parent a73a7944ec
commit 48dc85ea3e
27 changed files with 1425 additions and 174 deletions

100
src/mod/pathrule/handler.go Normal file
View File

@@ -0,0 +1,100 @@
package pathrule
import (
"encoding/json"
"net/http"
"strconv"
uuid "github.com/satori/go.uuid"
"imuslab.com/zoraxy/mod/utils"
)
/*
handler.go
This script handles pathblock api
*/
func (h *Handler) HandleListBlockingPath(w http.ResponseWriter, r *http.Request) {
js, _ := json.Marshal(h.BlockingPaths)
utils.SendJSONResponse(w, string(js))
}
func (h *Handler) HandleAddBlockingPath(w http.ResponseWriter, r *http.Request) {
matchingPath, err := utils.PostPara(r, "matchingPath")
if err != nil {
utils.SendErrorResponse(w, "invalid matching path given")
return
}
exactMatch, err := utils.PostPara(r, "exactMatch")
if err != nil {
utils.SendErrorResponse(w, "invalid exact match value given")
return
}
statusCodeString, err := utils.PostPara(r, "statusCode")
if err != nil {
utils.SendErrorResponse(w, "invalid status code given")
return
}
statusCode, err := strconv.Atoi(statusCodeString)
if err != nil {
utils.SendErrorResponse(w, "invalid status code given")
return
}
enabled, err := utils.PostPara(r, "enabled")
if err != nil {
utils.SendErrorResponse(w, "invalid enabled value given")
return
}
caseSensitive, err := utils.PostPara(r, "caseSensitive")
if err != nil {
utils.SendErrorResponse(w, "invalid case sensitive value given")
return
}
targetBlockingPath := BlockingPath{
UUID: uuid.NewV4().String(),
MatchingPath: matchingPath,
ExactMatch: exactMatch == "true",
StatusCode: statusCode,
CustomHeaders: http.Header{},
CustomHTML: []byte(""),
Enabled: enabled == "true",
CaseSenitive: caseSensitive == "true",
}
err = h.AddBlockingPath(&targetBlockingPath)
if err != nil {
utils.SendErrorResponse(w, err.Error())
return
}
utils.SendOK(w)
}
func (h *Handler) HandleRemoveBlockingPath(w http.ResponseWriter, r *http.Request) {
blockerUUID, err := utils.PostPara(r, "uuid")
if err != nil {
utils.SendErrorResponse(w, "invalid uuid given")
return
}
targetRule := h.GetPathBlockerFromUUID(blockerUUID)
if targetRule == nil {
//Not found
utils.SendErrorResponse(w, "target path blocker not found")
return
}
err = h.RemoveBlockingPathByUUID(blockerUUID)
if err != nil {
utils.SendErrorResponse(w, err.Error())
return
}
utils.SendOK(w)
}

View File

@@ -0,0 +1,175 @@
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
}