2023-01-23 18:54:21 +07:00
|
|
|
/*
|
|
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
* Copyright (c) since 2022, mzz2017 (mzz@tuta.io). All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package routing
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2023-01-24 23:31:20 +07:00
|
|
|
"github.com/v2rayA/dae/common"
|
2023-01-23 19:01:24 +07:00
|
|
|
"github.com/v2rayA/dae/common/consts"
|
2023-01-23 18:54:21 +07:00
|
|
|
"net/netip"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
2023-01-23 19:01:24 +07:00
|
|
|
var FakeOutbound_AND = consts.OutboundLogicalAnd.String()
|
2023-01-23 18:54:21 +07:00
|
|
|
|
|
|
|
type MatcherBuilder interface {
|
|
|
|
AddDomain(key string, values []string, outbound string)
|
|
|
|
AddIp(values []netip.Prefix, outbound string)
|
|
|
|
AddPort(values [][2]int, outbound string)
|
|
|
|
AddSource(values []netip.Prefix, outbound string)
|
|
|
|
AddSourcePort(values [][2]int, outbound string)
|
2023-01-24 23:31:20 +07:00
|
|
|
AddL4Proto(values consts.L4ProtoType, outbound string)
|
2023-01-23 19:01:24 +07:00
|
|
|
AddIpVersion(values consts.IpVersion, outbound string)
|
2023-01-23 18:54:21 +07:00
|
|
|
AddMac(values [][6]byte, outbound string)
|
|
|
|
AddFinal(outbound string)
|
|
|
|
AddAnyBefore(key string, values []string, outbound string)
|
|
|
|
AddAnyAfter(key string, values []string, outbound string)
|
|
|
|
Build() (err error)
|
|
|
|
}
|
|
|
|
|
|
|
|
func GroupParamValuesByKey(params []*Param) map[string][]string {
|
|
|
|
groups := make(map[string][]string)
|
|
|
|
for _, param := range params {
|
|
|
|
groups[param.Key] = append(groups[param.Key], param.Val)
|
|
|
|
}
|
|
|
|
return groups
|
|
|
|
}
|
|
|
|
|
|
|
|
func ParsePrefixes(values []string) (cidrs []netip.Prefix, err error) {
|
|
|
|
for _, value := range values {
|
|
|
|
toParse := value
|
|
|
|
if strings.LastIndexByte(value, '/') == -1 {
|
|
|
|
toParse += "/32"
|
|
|
|
}
|
|
|
|
prefix, err := netip.ParsePrefix(toParse)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("cannot parse %v: %w", value, err)
|
|
|
|
}
|
|
|
|
cidrs = append(cidrs, prefix)
|
|
|
|
}
|
|
|
|
return cidrs, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func ApplyMatcherBuilder(builder MatcherBuilder, rules []RoutingRule, finalOutbound string) (err error) {
|
|
|
|
for _, rule := range rules {
|
|
|
|
// rule is like: domain(domain:baidu.com) && port(443) -> proxy
|
|
|
|
for iFunc, f := range rule.AndFunctions {
|
|
|
|
// f is like: domain(domain:baidu.com)
|
|
|
|
paramValueGroups := GroupParamValuesByKey(f.Params)
|
|
|
|
for key, paramValueGroup := range paramValueGroups {
|
|
|
|
// Preprocess the outbound and pass FakeOutbound_AND to all but the last function.
|
|
|
|
outbound := FakeOutbound_AND
|
|
|
|
if iFunc == len(rule.AndFunctions)-1 {
|
|
|
|
outbound = rule.Outbound
|
|
|
|
}
|
|
|
|
builder.AddAnyBefore(key, paramValueGroup, outbound)
|
|
|
|
switch f.Name {
|
2023-01-24 23:31:20 +07:00
|
|
|
case consts.Function_Domain:
|
2023-01-23 18:54:21 +07:00
|
|
|
builder.AddDomain(key, paramValueGroup, outbound)
|
2023-01-24 23:31:20 +07:00
|
|
|
case consts.Function_Ip, consts.Function_SourceIp:
|
2023-01-23 18:54:21 +07:00
|
|
|
cidrs, err := ParsePrefixes(paramValueGroup)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-01-24 23:31:20 +07:00
|
|
|
if f.Name == consts.Function_Ip {
|
|
|
|
builder.AddIp(cidrs, outbound)
|
|
|
|
} else {
|
|
|
|
builder.AddSource(cidrs, outbound)
|
|
|
|
}
|
|
|
|
case consts.Function_Mac:
|
|
|
|
var macAddrs [][6]byte
|
|
|
|
for _, v := range paramValueGroup {
|
|
|
|
mac, err := common.ParseMac(v)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
macAddrs = append(macAddrs, mac)
|
|
|
|
}
|
|
|
|
builder.AddMac(macAddrs, outbound)
|
|
|
|
case consts.Function_Port, consts.Function_SourcePort:
|
|
|
|
var portRanges [][2]int
|
|
|
|
for _, v := range paramValueGroup {
|
|
|
|
portRange, err := common.ParsePortRange(v)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
portRanges = append(portRanges, portRange)
|
|
|
|
}
|
|
|
|
if f.Name == consts.Function_Port {
|
|
|
|
builder.AddPort(portRanges, outbound)
|
|
|
|
} else {
|
|
|
|
builder.AddSourcePort(portRanges, outbound)
|
|
|
|
}
|
|
|
|
case consts.Function_L4Proto:
|
|
|
|
var l4protoType consts.L4ProtoType
|
|
|
|
for _, v := range paramValueGroup {
|
|
|
|
switch v {
|
|
|
|
case "tcp":
|
|
|
|
l4protoType |= consts.L4ProtoType_TCP
|
|
|
|
case "udp":
|
|
|
|
l4protoType |= consts.L4ProtoType_UDP
|
|
|
|
}
|
|
|
|
}
|
|
|
|
builder.AddL4Proto(l4protoType, outbound)
|
|
|
|
case consts.Function_IpVersion:
|
|
|
|
var ipVersion consts.IpVersion
|
|
|
|
for _, v := range paramValueGroup {
|
|
|
|
switch v {
|
|
|
|
case "4":
|
|
|
|
ipVersion |= consts.IpVersion_4
|
|
|
|
case "6":
|
|
|
|
ipVersion |= consts.IpVersion_6
|
|
|
|
}
|
|
|
|
}
|
|
|
|
builder.AddIpVersion(ipVersion, outbound)
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("unsupported function name: %v", f.Name)
|
2023-01-23 18:54:21 +07:00
|
|
|
}
|
|
|
|
builder.AddAnyAfter(key, paramValueGroup, outbound)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
builder.AddAnyBefore("", nil, finalOutbound)
|
|
|
|
builder.AddFinal(finalOutbound)
|
|
|
|
builder.AddAnyAfter("", nil, finalOutbound)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type DefaultMatcherBuilder struct{}
|
|
|
|
|
|
|
|
func (d *DefaultMatcherBuilder) AddDomain(values []string, outbound string) {}
|
|
|
|
func (d *DefaultMatcherBuilder) AddIp(values []netip.Prefix, outbound string) {}
|
|
|
|
func (d *DefaultMatcherBuilder) AddPort(values [][2]int, outbound string) {}
|
|
|
|
func (d *DefaultMatcherBuilder) AddSource(values []netip.Prefix, outbound string) {}
|
|
|
|
func (d *DefaultMatcherBuilder) AddSourcePort(values [][2]int, outbound string) {}
|
2023-01-24 23:31:20 +07:00
|
|
|
func (d *DefaultMatcherBuilder) AddL4Proto(values consts.L4ProtoType, outbound string) {}
|
2023-01-23 19:01:24 +07:00
|
|
|
func (d *DefaultMatcherBuilder) AddIpVersion(values consts.IpVersion, outbound string) {}
|
2023-01-23 18:54:21 +07:00
|
|
|
func (d *DefaultMatcherBuilder) AddMac(values [][6]byte, outbound string) {}
|
|
|
|
func (d *DefaultMatcherBuilder) AddFinal(outbound string) {}
|
|
|
|
func (d *DefaultMatcherBuilder) AddAnyBefore(key string, values []string, outbound string) {}
|
|
|
|
func (d *DefaultMatcherBuilder) AddAnyAfter(key string, values []string, outbound string) {}
|
|
|
|
func (d *DefaultMatcherBuilder) Build() (err error) { return nil }
|