mirror of
https://github.com/cmz0228/hysteria-dev.git
synced 2025-08-07 01:41:48 +00:00
ACL entry
This commit is contained in:
111
pkg/acl/entry.go
Normal file
111
pkg/acl/entry.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package acl
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Action byte
|
||||
|
||||
const (
|
||||
ActionDirect = Action(iota)
|
||||
ActionProxy
|
||||
ActionBlock
|
||||
ActionHijack
|
||||
)
|
||||
|
||||
type Entry struct {
|
||||
Net *net.IPNet
|
||||
Domain string
|
||||
Suffix bool
|
||||
All bool
|
||||
Action Action
|
||||
ActionArg string
|
||||
}
|
||||
|
||||
// Format: action cond_type cond arg
|
||||
// Examples:
|
||||
// proxy domain-suffix google.com
|
||||
// block ip 8.8.8.8
|
||||
// hijack cidr 192.168.1.1/24 127.0.0.1
|
||||
func ParseEntry(s string) (Entry, error) {
|
||||
fields := strings.Fields(s)
|
||||
if len(fields) < 2 {
|
||||
return Entry{}, fmt.Errorf("expecting at least 2 fields, got %d", len(fields))
|
||||
}
|
||||
args := fields[1:]
|
||||
if len(args) == 1 {
|
||||
// Make sure there are at least 2 args
|
||||
args = append(args, "")
|
||||
}
|
||||
ipNet, domain, suffix, all, err := parseCond(args[0], args[1])
|
||||
if err != nil {
|
||||
return Entry{}, err
|
||||
}
|
||||
e := Entry{
|
||||
Net: ipNet,
|
||||
Domain: domain,
|
||||
Suffix: suffix,
|
||||
All: all,
|
||||
}
|
||||
switch strings.ToLower(fields[0]) {
|
||||
case "direct":
|
||||
e.Action = ActionDirect
|
||||
case "proxy":
|
||||
e.Action = ActionProxy
|
||||
case "block":
|
||||
e.Action = ActionBlock
|
||||
case "hijack":
|
||||
if len(args) < 3 {
|
||||
return Entry{}, fmt.Errorf("no hijack destination for %s %s", args[0], args[1])
|
||||
}
|
||||
e.Action = ActionHijack
|
||||
e.ActionArg = args[2]
|
||||
default:
|
||||
return Entry{}, fmt.Errorf("invalid action %s", fields[0])
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func parseCond(typ, cond string) (*net.IPNet, string, bool, bool, error) {
|
||||
switch strings.ToLower(typ) {
|
||||
case "domain":
|
||||
if len(cond) == 0 {
|
||||
return nil, "", false, false, errors.New("empty domain")
|
||||
}
|
||||
return nil, cond, false, false, nil
|
||||
case "domain-suffix":
|
||||
if len(cond) == 0 {
|
||||
return nil, "", false, false, errors.New("empty domain suffix")
|
||||
}
|
||||
return nil, cond, true, false, nil
|
||||
case "cidr":
|
||||
_, ipNet, err := net.ParseCIDR(cond)
|
||||
if err != nil {
|
||||
return nil, "", false, false, err
|
||||
}
|
||||
return ipNet, "", false, false, nil
|
||||
case "ip":
|
||||
ip := net.ParseIP(cond)
|
||||
if ip == nil {
|
||||
return nil, "", false, false, fmt.Errorf("invalid ip %s", cond)
|
||||
}
|
||||
if ip.To4() != nil {
|
||||
return &net.IPNet{
|
||||
IP: ip,
|
||||
Mask: net.CIDRMask(32, 32),
|
||||
}, "", false, false, nil
|
||||
} else {
|
||||
return &net.IPNet{
|
||||
IP: ip,
|
||||
Mask: net.CIDRMask(128, 128),
|
||||
}, "", false, false, nil
|
||||
}
|
||||
case "all":
|
||||
return nil, "", false, true, nil
|
||||
default:
|
||||
return nil, "", false, false, fmt.Errorf("invalid condition type %s", typ)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user