You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
2.2 KiB

2 weeks ago
package socks5
import (
"net"
"strconv"
"strings"
)
// SimpleRule 简单访问规则
type SimpleRule struct {
action string // allow, deny
networks []*net.IPNet
ports []int
}
// NewRule 创建访问规则
func NewRule(config RuleConfig) Rule {
rule := &SimpleRule{
action: strings.ToLower(config.Action),
ports: config.Ports,
}
// 解析IP网段
for _, ipStr := range config.IPs {
if !strings.Contains(ipStr, "/") {
// 单个IP,添加适当的子网掩码
if strings.Contains(ipStr, ":") {
ipStr += "/128" // IPv6
} else {
ipStr += "/32" // IPv4
}
}
_, network, err := net.ParseCIDR(ipStr)
if err != nil {
// 如果解析失败,尝试作为单个IP处理
ip := net.ParseIP(ipStr)
if ip != nil {
if ip.To4() != nil {
_, network, _ = net.ParseCIDR(ip.String() + "/32")
} else {
_, network, _ = net.ParseCIDR(ip.String() + "/128")
}
}
}
if network != nil {
rule.networks = append(rule.networks, network)
}
}
return rule
}
// Allow 检查是否允许访问
func (r *SimpleRule) Allow(addr net.Addr) bool {
// 解析地址
var ip net.IP
var port int
switch a := addr.(type) {
case *net.IPAddr:
ip = a.IP
case *net.TCPAddr:
ip = a.IP
port = a.Port
case *net.UDPAddr:
ip = a.IP
port = a.Port
default:
// 尝试从字符串解析
host, portStr, err := net.SplitHostPort(addr.String())
if err != nil {
return r.action == "allow" // 默认策略
}
ip = net.ParseIP(host)
if p, err := strconv.Atoi(portStr); err == nil {
port = p
}
}
if ip == nil {
return r.action == "allow" // 默认策略
}
// 检查IP是否匹配
ipMatches := len(r.networks) == 0 // 如果没有指定网段,默认匹配
for _, network := range r.networks {
if network.Contains(ip) {
ipMatches = true
break
}
}
// 检查端口是否匹配
portMatches := len(r.ports) == 0 // 如果没有指定端口,默认匹配
for _, p := range r.ports {
if p == port {
portMatches = true
break
}
}
// 根据规则类型返回结果
matches := ipMatches && portMatches
switch r.action {
case "allow":
return matches
case "deny":
return !matches
default:
return true // 默认允许
}
}