dae/component/routing/function_parser.go
2024-01-04 17:28:16 +08:00

159 lines
5.7 KiB
Go

/*
* SPDX-License-Identifier: AGPL-3.0-only
* Copyright (c) 2022-2024, daeuniverse Organization <dae@v2raya.org>
*/
package routing
import (
"encoding/binary"
"fmt"
"net/netip"
"strconv"
"strings"
"github.com/daeuniverse/dae/common"
"github.com/daeuniverse/dae/common/consts"
"github.com/daeuniverse/dae/pkg/config_parser"
"github.com/sirupsen/logrus"
"golang.org/x/exp/constraints"
)
type FunctionParser func(log *logrus.Logger, f *config_parser.Function, key string, paramValueGroup []string, overrideOutbound *Outbound) (err error)
// Preset function parser factories.
// PlainParserFactory is for style unity.
func PlainParserFactory(callback func(f *config_parser.Function, key string, paramValueGroup []string, overrideOutbound *Outbound) (err error)) FunctionParser {
return func(log *logrus.Logger, f *config_parser.Function, key string, paramValueGroup []string, overrideOutbound *Outbound) (err error) {
return callback(f, key, paramValueGroup, overrideOutbound)
}
}
// EmptyKeyPlainParserFactory only accepts function with empty key.
func EmptyKeyPlainParserFactory(callback func(f *config_parser.Function, values []string, overrideOutbound *Outbound) (err error)) FunctionParser {
return func(log *logrus.Logger, f *config_parser.Function, key string, paramValueGroup []string, overrideOutbound *Outbound) (err error) {
if key != "" {
return fmt.Errorf("this function cannot accept a key")
}
return callback(f, paramValueGroup, overrideOutbound)
}
}
func IpParserFactory(callback func(f *config_parser.Function, cidrs []netip.Prefix, overrideOutbound *Outbound) (err error)) FunctionParser {
return func(log *logrus.Logger, f *config_parser.Function, key string, paramValueGroup []string, overrideOutbound *Outbound) (err error) {
cidrs, err := parsePrefixes(paramValueGroup)
if err != nil {
return err
}
return callback(f, cidrs, overrideOutbound)
}
}
func MacParserFactory(callback func(f *config_parser.Function, macAddrs [][6]byte, overrideOutbound *Outbound) (err error)) FunctionParser {
return func(log *logrus.Logger, f *config_parser.Function, key string, paramValueGroup []string, overrideOutbound *Outbound) (err error) {
var macAddrs [][6]byte
for _, v := range paramValueGroup {
mac, err := common.ParseMac(v)
if err != nil {
return err
}
macAddrs = append(macAddrs, mac)
}
return callback(f, macAddrs, overrideOutbound)
}
}
func PortRangeParserFactory(callback func(f *config_parser.Function, portRanges [][2]uint16, overrideOutbound *Outbound) (err error)) FunctionParser {
return func(log *logrus.Logger, f *config_parser.Function, key string, paramValueGroup []string, overrideOutbound *Outbound) (err error) {
var portRanges [][2]uint16
for _, v := range paramValueGroup {
portRange, err := common.ParsePortRange(v)
if err != nil {
return err
}
portRanges = append(portRanges, portRange)
}
return callback(f, portRanges, overrideOutbound)
}
}
func L4ProtoParserFactory(callback func(f *config_parser.Function, l4protoType consts.L4ProtoType, overrideOutbound *Outbound) (err error)) FunctionParser {
return func(log *logrus.Logger, f *config_parser.Function, key string, paramValueGroup []string, overrideOutbound *Outbound) (err error) {
var l4protoType consts.L4ProtoType
for _, v := range paramValueGroup {
switch v {
case "tcp":
l4protoType |= consts.L4ProtoType_TCP
case "udp":
l4protoType |= consts.L4ProtoType_UDP
}
}
return callback(f, l4protoType, overrideOutbound)
}
}
func IpVersionParserFactory(callback func(f *config_parser.Function, ipVersion consts.IpVersionType, overrideOutbound *Outbound) (err error)) FunctionParser {
return func(log *logrus.Logger, f *config_parser.Function, key string, paramValueGroup []string, overrideOutbound *Outbound) (err error) {
var ipVersion consts.IpVersionType
for _, v := range paramValueGroup {
switch v {
case "4":
ipVersion |= consts.IpVersion_4
case "6":
ipVersion |= consts.IpVersion_6
}
}
return callback(f, ipVersion, overrideOutbound)
}
}
func ProcessNameParserFactory(callback func(f *config_parser.Function, procNames [][consts.TaskCommLen]byte, overrideOutbound *Outbound) (err error)) FunctionParser {
return func(log *logrus.Logger, f *config_parser.Function, key string, paramValueGroup []string, overrideOutbound *Outbound) (err error) {
var procNames [][consts.TaskCommLen]byte
for _, v := range paramValueGroup {
if len([]byte(v)) > consts.TaskCommLen {
log.Infof(`pname routing: trim "%v" to "%v" because it is too long.`, v, string([]byte(v)[:consts.TaskCommLen]))
}
procNames = append(procNames, toProcessName(v))
}
return callback(f, procNames, overrideOutbound)
}
}
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 toProcessName(processName string) (procName [consts.TaskCommLen]byte) {
n := []byte(processName)
copy(procName[:], n)
return procName
}
func UintParserFactory[T constraints.Unsigned](callback func(f *config_parser.Function, values []T, overrideOutbound *Outbound) (err error)) FunctionParser {
size := binary.Size(new(T))
return func(log *logrus.Logger, f *config_parser.Function, key string, paramValueGroup []string, overrideOutbound *Outbound) (err error) {
var values []T
for _, v := range paramValueGroup {
val, err := strconv.ParseUint(v, 0, 8*size)
if err != nil {
return fmt.Errorf("cannot parse %v: %w", v, err)
}
values = append(values, T(val))
}
return callback(f, values, overrideOutbound)
}
}