Skip to content

Commit

Permalink
feat: support ToS routing rule (daeuniverse#292)
Browse files Browse the repository at this point in the history
  • Loading branch information
mzz2017 authored Aug 19, 2023
1 parent c784eba commit 7273be6
Show file tree
Hide file tree
Showing 14 changed files with 110 additions and 28 deletions.
45 changes: 22 additions & 23 deletions cmd/honk.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,26 @@
* Copyright (c) 2022-2023, daeuniverse Organization <[email protected]>
*/

package cmd
package cmd

import (
"fmt"
"os"

"github.com/spf13/cobra"
)

var (
honkCmd = &cobra.Command{
Use: "honk",
Short: "Let dae call for you.",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Honk! Honk! Honk! This is dae!")
os.Exit(0)
},
}
)

func init() {
rootCmd.AddCommand(honkCmd)
}

import (
"fmt"
"os"

"github.com/spf13/cobra"
)

var (
honkCmd = &cobra.Command{
Use: "honk",
Short: "Let dae call for you.",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Honk! Honk! Honk! This is dae!")
os.Exit(0)
},
}
)

func init() {
rootCmd.AddCommand(honkCmd)
}
1 change: 1 addition & 0 deletions common/consts/ebpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const (
MatchType_IpVersion
MatchType_Mac
MatchType_ProcessName
MatchType_Tos
MatchType_Fallback
MatchType_MustRules

Expand Down
1 change: 1 addition & 0 deletions common/consts/routing.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const (
Function_IpVersion = "ipversion"
Function_Mac = "mac"
Function_ProcessName = "pname"
Function_Tos = "tos"

Function_QName = "qname"
Function_QType = "qtype"
Expand Down
23 changes: 21 additions & 2 deletions component/routing/function_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@
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"
"net/netip"
"strings"
"golang.org/x/exp/constraints"
)

type FunctionParser func(log *logrus.Logger, f *config_parser.Function, key string, paramValueGroup []string, overrideOutbound *Outbound) (err error)
Expand Down Expand Up @@ -137,3 +141,18 @@ func toProcessName(processName string) (procName [consts.TaskCommLen]byte) {
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, 10, 8*size)
if err != nil {
return fmt.Errorf("cannot parse %v: %w", v, err)
}
values = append(values, T(val))
}
return callback(f, values, overrideOutbound)
}
}
1 change: 1 addition & 0 deletions control/dns_control.go
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,7 @@ func (c *DnsController) dialSend(invokingDepth int, req *udpRequest, data []byte
"_qname": qname,
"qtype": qtype,
"pid": req.routingResult.Pid,
"tos": req.routingResult.Tos,
"pname": ProcessName2String(req.routingResult.Pname[:]),
"mac": Mac2String(req.routingResult.Mac[:]),
}
Expand Down
23 changes: 22 additions & 1 deletion control/kern/tproxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ struct routing_result {
__u8 outbound;
__u8 pname[TASK_COMM_LEN];
__u32 pid;
__u8 tos;
};

struct dst_routing_result {
Expand All @@ -155,6 +156,7 @@ struct tuples {
__u16 sport;
__u16 dport;
__u8 l4proto;
__u8 tos;
};

struct {
Expand Down Expand Up @@ -282,6 +284,7 @@ enum __attribute__((packed)) MatchType {
MatchType_IpVersion,
MatchType_Mac,
MatchType_ProcessName,
MatchType_Tos,
MatchType_Fallback,
};
enum L4ProtoType {
Expand Down Expand Up @@ -317,6 +320,7 @@ struct match_set {
enum L4ProtoType l4proto_type;
enum IpVersionType ip_version;
__u32 pname[TASK_COMM_LEN / 4];
__u8 tos;
};
bool not ; // A subrule flag (this is not a match_set flag).
enum MatchType type;
Expand Down Expand Up @@ -380,9 +384,13 @@ get_tuples(const struct __sk_buff *skb, struct tuples *tuples,
tuples->dip.u6_addr32[2] = bpf_htonl(0x0000ffff);
tuples->dip.u6_addr32[3] = iph->daddr;

tuples->tos = iph->tos;

} else {
__builtin_memcpy(&tuples->dip, &ipv6h->daddr, IPV6_BYTE_LENGTH);
__builtin_memcpy(&tuples->sip, &ipv6h->saddr, IPV6_BYTE_LENGTH);

tuples->tos = ipv6h->priority;
}
if (l4proto == IPPROTO_TCP) {
tuples->sport = tcph->source;
Expand Down Expand Up @@ -969,6 +977,7 @@ route(const __u32 flag[6], const void *l4hdr, const __be32 saddr[4],
#define _ipversion_type flag[1]
#define _pname &flag[2]
#define _is_wan flag[2]
#define _tos flag[3]

int ret;
struct lpm_key lpm_key_instance, *lpm_key;
Expand Down Expand Up @@ -1123,6 +1132,11 @@ route(const __u32 flag[6], const void *l4hdr, const __be32 saddr[4],
isdns_must_goodsubrule_badrule |= 0b10;
}
break;
case MatchType_Tos:
if (_tos == match_set->tos) {
isdns_must_goodsubrule_badrule |= 0b10;
}
break;
case MatchType_Fallback:
#ifdef __DEBUG_ROUTING
bpf_printk("CHECK: hit fallback");
Expand Down Expand Up @@ -1200,6 +1214,7 @@ route(const __u32 flag[6], const void *l4hdr, const __be32 saddr[4],
#undef _ipversion_type
#undef _pname
#undef _is_wan
#undef _tos
}

static bool __always_inline is_not_to_lan(void *_ori_src) {
Expand Down Expand Up @@ -1394,6 +1409,7 @@ int tproxy_lan_ingress(struct __sk_buff *skb) {
} else {
flag[1] = IpVersionType_6;
}
flag[3] = tuples.tos;
__be32 mac[4] = {
0,
0,
Expand All @@ -1411,6 +1427,7 @@ int tproxy_lan_ingress(struct __sk_buff *skb) {
routing_result.outbound = s64_ret;
routing_result.mark = s64_ret >> 8;
routing_result.must = (s64_ret >> 40) & 1;
routing_result.tos = tuples.tos;
__builtin_memcpy(routing_result.mac, ethh.h_source,
sizeof(routing_result.mac));
/// NOTICE: No pid pname info for LAN packet.
Expand Down Expand Up @@ -1685,6 +1702,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
} else {
flag[1] = IpVersionType_6;
}
flag[3] = tuples.tos;
if (pid_is_control_plane(skb, &pid_pname)) {
// From control plane. Direct.
return TC_ACT_OK;
Expand All @@ -1706,7 +1724,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
return TC_ACT_SHOT;
}

outbound = s64_ret;
outbound = s64_ret & 0xff;
mark = s64_ret >> 8;
must = (s64_ret >> 40) & 1;

Expand Down Expand Up @@ -1763,6 +1781,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
routing_info.routing_result.outbound = outbound;
routing_info.routing_result.mark = mark;
routing_info.routing_result.must = must;
routing_info.routing_result.tos = tuples.tos;
__builtin_memcpy(routing_info.routing_result.mac, ethh.h_source,
sizeof(ethh.h_source));
if (pid_pname) {
Expand Down Expand Up @@ -1796,6 +1815,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
} else {
flag[1] = IpVersionType_6;
}
flag[3] = tuples.tos;
struct pid_pname *pid_pname;
if (pid_is_control_plane(skb, &pid_pname)) {
// From control plane. Direct.
Expand Down Expand Up @@ -1826,6 +1846,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
new_hdr.routing_result.outbound = s64_ret;
new_hdr.routing_result.mark = s64_ret >> 8;
new_hdr.routing_result.must = (s64_ret >> 40) & 1;
new_hdr.routing_result.tos = tuples.tos;
__builtin_memcpy(new_hdr.routing_result.mac, ethh.h_source,
sizeof(ethh.h_source));
if (pid_pname) {
Expand Down
27 changes: 26 additions & 1 deletion control/routing_matcher_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ package control
import (
"encoding/binary"
"fmt"
"github.com/daeuniverse/dae/pkg/trie"
"net/netip"
"strconv"

"github.com/daeuniverse/dae/pkg/trie"

"github.com/cilium/ebpf"
"github.com/daeuniverse/dae/common"
"github.com/daeuniverse/dae/common/consts"
Expand Down Expand Up @@ -43,6 +44,7 @@ func NewRoutingMatcherBuilder(log *logrus.Logger, rules []*config_parser.Routing
rulesBuilder.RegisterFunctionParser(consts.Function_L4Proto, routing.L4ProtoParserFactory(b.addL4Proto))
rulesBuilder.RegisterFunctionParser(consts.Function_Mac, routing.MacParserFactory(b.addSourceMac))
rulesBuilder.RegisterFunctionParser(consts.Function_ProcessName, routing.ProcessNameParserFactory(b.addProcessName))
rulesBuilder.RegisterFunctionParser(consts.Function_Tos, routing.UintParserFactory(b.addTos))
rulesBuilder.RegisterFunctionParser(consts.Function_IpVersion, routing.IpVersionParserFactory(b.addIpVersion))
if err = rulesBuilder.Apply(rules); err != nil {
return nil, err
Expand Down Expand Up @@ -274,6 +276,29 @@ func (b *RoutingMatcherBuilder) addProcessName(f *config_parser.Function, values
return nil
}

func (b *RoutingMatcherBuilder) addTos(f *config_parser.Function, values []uint8, outbound *routing.Outbound) (err error) {
for i, value := range values {
outboundName := consts.OutboundLogicalOr.String()
if i == len(values)-1 {
outboundName = outbound.Name
}
outboundId, err := b.outboundToId(outboundName)
if err != nil {
return err
}
matchSet := bpfMatchSet{
Type: uint8(consts.MatchType_Tos),
Not: f.Not,
Outbound: outboundId,
Mark: outbound.Mark,
Must: outbound.Must,
}
matchSet.Value[0] = value
b.rules = append(b.rules, matchSet)
}
return nil
}

func (b *RoutingMatcherBuilder) addFallback(fallbackOutbound config.FunctionOrString) (err error) {
outbound, err := routing.ParseOutbound(config.FunctionOrStringToFunction(fallbackOutbound))
if err != nil {
Expand Down
7 changes: 6 additions & 1 deletion control/routing_matcher_userspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ package control
import (
"encoding/binary"
"fmt"
"github.com/daeuniverse/dae/pkg/trie"
"net"
"net/netip"

"github.com/daeuniverse/dae/common/consts"
"github.com/daeuniverse/dae/component/routing"
"github.com/daeuniverse/dae/pkg/trie"
)

type RoutingMatcher struct {
Expand All @@ -33,6 +33,7 @@ func (m *RoutingMatcher) Match(
l4proto consts.L4ProtoType,
domain string,
processName [16]uint8,
tos uint8,
mac []byte,
) (outboundIndex consts.OutboundIndex, mark uint32, must bool, err error) {
if len(sourceAddr) != net.IPv6len || len(destAddr) != net.IPv6len || len(mac) != net.IPv6len {
Expand Down Expand Up @@ -92,6 +93,10 @@ func (m *RoutingMatcher) Match(
if processName[0] != 0 && match.Value == processName {
goodSubrule = true
}
case consts.MatchType_Tos:
if tos == match.Value[0] {
goodSubrule = true
}
case consts.MatchType_Fallback:
goodSubrule = true
default:
Expand Down
1 change: 1 addition & 0 deletions control/tcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ func (c *ControlPlane) RouteDialTcp(p *RouteDialParam) (conn netproxy.Conn, err
"sniffed": domain,
"ip": RefineAddrPortToShow(dst),
"pid": routingResult.Pid,
"tos": routingResult.Tos,
"pname": ProcessName2String(routingResult.Pname[:]),
"mac": Mac2String(routingResult.Mac[:]),
}).Infof("%v <-> %v", RefineSourceToShow(src, dst.Addr(), consts.LanWanFlag_NotApplicable), dialTarget)
Expand Down
2 changes: 2 additions & 0 deletions control/udp.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ getNew:
"to": realDst.String(),
"domain": domain,
"pid": routingResult.Pid,
"tos": routingResult.Tos,
"pname": ProcessName2String(routingResult.Pname[:]),
"mac": Mac2String(routingResult.Mac[:]),
"from": realSrc.String(),
Expand All @@ -298,6 +299,7 @@ getNew:
"domain": domain,
"ip": RefineAddrPortToShow(realDst),
"pid": routingResult.Pid,
"tos": routingResult.Tos,
"pname": ProcessName2String(routingResult.Pname[:]),
"mac": Mac2String(routingResult.Mac[:]),
}
Expand Down
1 change: 1 addition & 0 deletions control/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func (c *ControlPlane) Route(src, dst netip.AddrPort, domain string, l4proto con
l4proto,
domain,
routingResult.Pname,
routingResult.Tos,
append([]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, routingResult.Mac[:]...),
); err != nil {
return 0, 0, false, err
Expand Down
3 changes: 3 additions & 0 deletions docs/en/configuration/routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ mac('02:42:ac:11:00:02') -> direct
### Process Name rule (only support localhost process when binding to WAN)
pname(curl) -> direct

### ToS rule (match ToS/DSCP; is useful for BT bypass)
tos(4) -> direct

### Multiple domains rule
domain(keyword: google, suffix: www.twitter.com, suffix: v2raya.org) -> my_group
### Multiple IP rule
Expand Down
3 changes: 3 additions & 0 deletions docs/zh/configuration/routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ mac('02:42:ac:11:00:02') -> direct
### 进程名称规则(绑定WAN时仅支持本机进程)
pname(curl) -> direct

### ToS规则(匹配 ToS 和 DSCP,可用于绕过 BT)
tos(4) -> direct

### 多个域名规则
domain(keyword: google, suffix: www.twitter.com, suffix: v2raya.org) -> my_group
### 多个IP规则
Expand Down
File renamed without changes.

0 comments on commit 7273be6

Please sign in to comment.