mirror of
https://github.com/daeuniverse/dae.git
synced 2025-02-02 04:14:31 +07:00
feat: support pname routing (just task command. fixme)
This commit is contained in:
parent
b788f03d4a
commit
460ef450a0
@ -10,6 +10,8 @@ const (
|
||||
BpfPinRoot = "/sys/fs/bpf"
|
||||
|
||||
AddrHdrSize = 20
|
||||
|
||||
TaskCommLen = 16
|
||||
)
|
||||
|
||||
type ParamKey uint32
|
||||
@ -33,15 +35,16 @@ const (
|
||||
type RoutingType uint8
|
||||
|
||||
const (
|
||||
RoutingType_DomainSet RoutingType = iota
|
||||
RoutingType_IpSet
|
||||
RoutingType_SourceIpSet
|
||||
RoutingType_Port
|
||||
RoutingType_SourcePort
|
||||
RoutingType_L4Proto
|
||||
RoutingType_IpVersion
|
||||
RoutingType_Mac
|
||||
RoutingType_Final
|
||||
MatchType_DomainSet RoutingType = iota
|
||||
MatchType_IpSet
|
||||
MatchType_SourceIpSet
|
||||
MatchType_Port
|
||||
MatchType_SourcePort
|
||||
MatchType_L4Proto
|
||||
MatchType_IpVersion
|
||||
MatchType_Mac
|
||||
MatchType_ProcessName
|
||||
MatchType_Final
|
||||
)
|
||||
|
||||
type OutboundIndex uint8
|
||||
|
@ -11,14 +11,15 @@ const (
|
||||
RoutingDomain_Suffix = "suffix"
|
||||
RoutingDomain_Regex = "regex"
|
||||
|
||||
Function_Domain = "domain"
|
||||
Function_Ip = "ip"
|
||||
Function_SourceIp = "sip"
|
||||
Function_Port = "port"
|
||||
Function_SourcePort = "sport"
|
||||
Function_Mac = "mac"
|
||||
Function_L4Proto = "l4proto"
|
||||
Function_IpVersion = "ipversion"
|
||||
Function_Domain = "domain"
|
||||
Function_Ip = "ip"
|
||||
Function_SourceIp = "sip"
|
||||
Function_Port = "port"
|
||||
Function_SourcePort = "sport"
|
||||
Function_L4Proto = "l4proto"
|
||||
Function_IpVersion = "ipversion"
|
||||
Function_Mac = "mac"
|
||||
Function_ProcessName = "pname"
|
||||
|
||||
Declaration_Final = "final"
|
||||
)
|
||||
|
@ -213,7 +213,7 @@ retryLoadBpf:
|
||||
}
|
||||
log.Debugf("RoutingA:\n%vfinal: %v\n", debugBuilder.String(), routingA.Final)
|
||||
}
|
||||
if err = routing.ApplyMatcherBuilder(builder, rules, routingA.Final); err != nil {
|
||||
if err = routing.ApplyMatcherBuilder(log, builder, rules, routingA.Final); err != nil {
|
||||
return nil, fmt.Errorf("ApplyMatcherBuilder: %w", err)
|
||||
}
|
||||
if err = builder.Build(); err != nil {
|
||||
|
@ -194,6 +194,7 @@ enum __attribute__((packed)) MatchType {
|
||||
MatchType_L4Proto,
|
||||
MatchType_IpVersion,
|
||||
MatchType_Mac,
|
||||
MatchType_ProcessName,
|
||||
MatchType_Final,
|
||||
};
|
||||
enum L4ProtoType {
|
||||
@ -228,6 +229,7 @@ struct match_set {
|
||||
struct port_range port_range;
|
||||
enum L4ProtoType l4proto_type;
|
||||
enum IpVersionType ip_version;
|
||||
__u32 pname[TASK_COMM_LEN / 4];
|
||||
};
|
||||
enum MatchType type;
|
||||
bool not ; // A subrule flag (this is not a match_set flag).
|
||||
@ -565,8 +567,8 @@ static __always_inline int get_tproxy_ip(__u8 ipversion, __u32 ifindex,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __always_inline int ip_is_host(bool ipversion, __u32 ifindex, __be32 ip[4],
|
||||
__be32 tproxy_ip[4]) {
|
||||
static __always_inline int ip_is_host(bool ipversion, __u32 ifindex,
|
||||
__be32 ip[4], __be32 tproxy_ip[4]) {
|
||||
if (tproxy_ip) {
|
||||
int ret;
|
||||
if ((ret = get_tproxy_ip(ipversion, ifindex, tproxy_ip))) {
|
||||
@ -807,11 +809,11 @@ static __always_inline int decap_after_udp_hdr(struct __sk_buff *skb,
|
||||
}
|
||||
|
||||
// Do not use __always_inline here because this function is too heavy.
|
||||
static int routing(__u32 flag[3], void *l4_hdr, __be32 saddr[4],
|
||||
static int routing(__u32 flag[6], void *l4_hdr, __be32 saddr[4],
|
||||
__be32 daddr[4], __be32 mac[4]) {
|
||||
#define _l4proto_type flag[0]
|
||||
#define _ipversion_type flag[1]
|
||||
#define _from_localhost flag[2]
|
||||
#define _pname &flag[2]
|
||||
|
||||
int ret;
|
||||
|
||||
@ -957,6 +959,10 @@ static int routing(__u32 flag[3], void *l4_hdr, __be32 saddr[4],
|
||||
if ((domain_routing->bitmap[i / 32] >> (i % 32)) & 1) {
|
||||
good_subrule = true;
|
||||
}
|
||||
} else if (match_set->type == MatchType_ProcessName) {
|
||||
if ((equal_ipv6_format(match_set->pname, _pname))){
|
||||
good_subrule = true;
|
||||
}
|
||||
} else if (match_set->type == MatchType_Final) {
|
||||
// bpf_printk("CHECK: hit final");
|
||||
good_subrule = true;
|
||||
@ -1005,7 +1011,7 @@ static int routing(__u32 flag[3], void *l4_hdr, __be32 saddr[4],
|
||||
return -EPERM;
|
||||
#undef _l4proto_type
|
||||
#undef _ipversion_type
|
||||
#undef _from_localhost
|
||||
#undef _pname
|
||||
}
|
||||
|
||||
// Do DNAT.
|
||||
@ -1027,7 +1033,6 @@ int tproxy_ingress(struct __sk_buff *skb) {
|
||||
bpf_printk("parse_transport: %d", ret);
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
|
||||
// Backup for further use.
|
||||
__be16 ipv4_tot_len = 0;
|
||||
@ -1085,13 +1090,12 @@ int tproxy_ingress(struct __sk_buff *skb) {
|
||||
if (unlikely(tcp_state_syn)) {
|
||||
// New TCP connection.
|
||||
// bpf_printk("[%X]New Connection", bpf_ntohl(tcph.seq));
|
||||
__u32 flag[3] = {L4ProtoType_TCP}; // TCP
|
||||
__u32 flag[6] = {L4ProtoType_TCP}; // TCP
|
||||
if (ipversion == 6) {
|
||||
flag[1] = IpVersionType_6;
|
||||
} else {
|
||||
flag[1] = IpVersionType_4;
|
||||
}
|
||||
flag[2] = false;
|
||||
__be32 mac[4] = {
|
||||
0,
|
||||
0,
|
||||
@ -1159,13 +1163,12 @@ int tproxy_ingress(struct __sk_buff *skb) {
|
||||
new_hdr.port = udph.dest;
|
||||
|
||||
// Routing. It decides if we redirect traffic to control plane.
|
||||
__u32 flag[3] = {L4ProtoType_UDP};
|
||||
__u32 flag[6] = {L4ProtoType_UDP};
|
||||
if (ipversion == 6) {
|
||||
flag[1] = IpVersionType_6;
|
||||
} else {
|
||||
flag[1] = IpVersionType_4;
|
||||
}
|
||||
flag[2] = false;
|
||||
__be32 mac[4] = {
|
||||
0,
|
||||
0,
|
||||
@ -1259,7 +1262,6 @@ int tproxy_egress(struct __sk_buff *skb) {
|
||||
if (ret) {
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
|
||||
// Parse saddr and daddr as ipv6 format.
|
||||
__be32 saddr[4];
|
||||
@ -1456,7 +1458,6 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
|
||||
if (ret) {
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
|
||||
__be16 sport;
|
||||
if (l4proto == IPPROTO_TCP) {
|
||||
@ -1566,13 +1567,15 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
|
||||
if (unlikely(tcp_state_syn)) {
|
||||
// New TCP connection.
|
||||
// bpf_printk("[%X]New Connection", bpf_ntohl(tcph.seq));
|
||||
__u32 flag[3] = {L4ProtoType_TCP}; // TCP
|
||||
__u32 flag[6] = {L4ProtoType_TCP}; // TCP
|
||||
if (ipversion == 6) {
|
||||
flag[1] = IpVersionType_6;
|
||||
} else {
|
||||
flag[1] = IpVersionType_4;
|
||||
}
|
||||
flag[2] = true;
|
||||
if (pid_pname) {
|
||||
__builtin_memcpy(&flag[2], pid_pname->pname, TASK_COMM_LEN);
|
||||
}
|
||||
__be32 mac[4] = {
|
||||
0,
|
||||
0,
|
||||
@ -1646,13 +1649,15 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
|
||||
new_hdr.port = udph.dest;
|
||||
|
||||
// Routing. It decides if we redirect traffic to control plane.
|
||||
__u32 flag[3] = {L4ProtoType_UDP};
|
||||
__u32 flag[6] = {L4ProtoType_UDP};
|
||||
if (ipversion == 6) {
|
||||
flag[1] = IpVersionType_6;
|
||||
} else {
|
||||
flag[1] = IpVersionType_4;
|
||||
}
|
||||
flag[2] = true;
|
||||
if (pid_pname) {
|
||||
__builtin_memcpy(&flag[2], pid_pname->pname, TASK_COMM_LEN);
|
||||
}
|
||||
__be32 mac[4] = {
|
||||
0,
|
||||
0,
|
||||
@ -1719,7 +1724,6 @@ int tproxy_wan_ingress(struct __sk_buff *skb) {
|
||||
if (ret) {
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
|
||||
// bpf_printk("bpf_ntohs(*(__u16 *)ðh.h_source[4]): %u",
|
||||
// bpf_ntohs(*(__u16 *)ðh.h_source[4]));
|
||||
@ -1857,8 +1861,8 @@ int tproxy_wan_ingress(struct __sk_buff *skb) {
|
||||
// bpf_printk("should send to: %pI6:%u", tproxy_ip,
|
||||
// bpf_ntohs(*tproxy_port));
|
||||
|
||||
if ((ret =
|
||||
rewrite_ip(skb, ipversion, l4proto, ihl, daddr, tproxy_ip, true))) {
|
||||
if ((ret = rewrite_ip(skb, ipversion, l4proto, ihl, daddr, tproxy_ip,
|
||||
true))) {
|
||||
bpf_printk("Shot IP: %d", ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"github.com/v2rayA/dae/pkg/config_parser"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type DomainSet struct {
|
||||
@ -74,7 +75,7 @@ func (b *RoutingMatcherBuilder) AddDomain(f *config_parser.Function, key string,
|
||||
Domains: values,
|
||||
})
|
||||
b.rules = append(b.rules, bpfMatchSet{
|
||||
Type: uint8(consts.RoutingType_DomainSet),
|
||||
Type: uint8(consts.MatchType_DomainSet),
|
||||
Not: f.Not,
|
||||
Outbound: b.OutboundToId(outbound),
|
||||
})
|
||||
@ -94,7 +95,7 @@ func (b *RoutingMatcherBuilder) AddSourceMac(f *config_parser.Function, macAddrs
|
||||
lpmTrieIndex := len(b.SimulatedLpmTries)
|
||||
b.SimulatedLpmTries = append(b.SimulatedLpmTries, values)
|
||||
b.rules = append(b.rules, bpfMatchSet{
|
||||
Type: uint8(consts.RoutingType_Mac),
|
||||
Type: uint8(consts.MatchType_Mac),
|
||||
Value: uint32(lpmTrieIndex),
|
||||
Not: f.Not,
|
||||
Outbound: b.OutboundToId(outbound),
|
||||
@ -109,7 +110,7 @@ func (b *RoutingMatcherBuilder) AddIp(f *config_parser.Function, values []netip.
|
||||
lpmTrieIndex := len(b.SimulatedLpmTries)
|
||||
b.SimulatedLpmTries = append(b.SimulatedLpmTries, values)
|
||||
b.rules = append(b.rules, bpfMatchSet{
|
||||
Type: uint8(consts.RoutingType_IpSet),
|
||||
Type: uint8(consts.MatchType_IpSet),
|
||||
Value: uint32(lpmTrieIndex),
|
||||
Not: f.Not,
|
||||
Outbound: b.OutboundToId(outbound),
|
||||
@ -123,7 +124,7 @@ func (b *RoutingMatcherBuilder) AddPort(f *config_parser.Function, values [][2]u
|
||||
outbound = _outbound
|
||||
}
|
||||
b.rules = append(b.rules, bpfMatchSet{
|
||||
Type: uint8(consts.RoutingType_Port),
|
||||
Type: uint8(consts.MatchType_Port),
|
||||
Value: _bpfPortRange{
|
||||
PortStart: value[0],
|
||||
PortEnd: value[1],
|
||||
@ -141,7 +142,7 @@ func (b *RoutingMatcherBuilder) AddSourceIp(f *config_parser.Function, values []
|
||||
lpmTrieIndex := len(b.SimulatedLpmTries)
|
||||
b.SimulatedLpmTries = append(b.SimulatedLpmTries, values)
|
||||
b.rules = append(b.rules, bpfMatchSet{
|
||||
Type: uint8(consts.RoutingType_SourceIpSet),
|
||||
Type: uint8(consts.MatchType_SourceIpSet),
|
||||
Value: uint32(lpmTrieIndex),
|
||||
Not: f.Not,
|
||||
Outbound: b.OutboundToId(outbound),
|
||||
@ -155,7 +156,7 @@ func (b *RoutingMatcherBuilder) AddSourcePort(f *config_parser.Function, values
|
||||
outbound = _outbound
|
||||
}
|
||||
b.rules = append(b.rules, bpfMatchSet{
|
||||
Type: uint8(consts.RoutingType_SourcePort),
|
||||
Type: uint8(consts.MatchType_SourcePort),
|
||||
Value: _bpfPortRange{
|
||||
PortStart: value[0],
|
||||
PortEnd: value[1],
|
||||
@ -171,7 +172,7 @@ func (b *RoutingMatcherBuilder) AddL4Proto(f *config_parser.Function, values con
|
||||
return
|
||||
}
|
||||
b.rules = append(b.rules, bpfMatchSet{
|
||||
Type: uint8(consts.RoutingType_L4Proto),
|
||||
Type: uint8(consts.MatchType_L4Proto),
|
||||
Value: uint32(values),
|
||||
Not: f.Not,
|
||||
Outbound: b.OutboundToId(outbound),
|
||||
@ -183,20 +184,36 @@ func (b *RoutingMatcherBuilder) AddIpVersion(f *config_parser.Function, values c
|
||||
return
|
||||
}
|
||||
b.rules = append(b.rules, bpfMatchSet{
|
||||
Type: uint8(consts.RoutingType_IpVersion),
|
||||
Type: uint8(consts.MatchType_IpVersion),
|
||||
Value: uint32(values),
|
||||
Not: f.Not,
|
||||
Outbound: b.OutboundToId(outbound),
|
||||
})
|
||||
}
|
||||
|
||||
func (b *RoutingMatcherBuilder) AddProcessName(f *config_parser.Function, values [][consts.TaskCommLen]byte, _outbound string) {
|
||||
for i, value := range values {
|
||||
outbound := routing.FakeOutbound_OR
|
||||
if i == len(values)-1 {
|
||||
outbound = _outbound
|
||||
}
|
||||
matchSet := bpfMatchSet{
|
||||
Type: uint8(consts.MatchType_ProcessName),
|
||||
Not: f.Not,
|
||||
Outbound: b.OutboundToId(outbound),
|
||||
}
|
||||
copy((*(*[16]byte)(unsafe.Pointer(&matchSet.Value)))[:], value[:])
|
||||
b.rules = append(b.rules, matchSet)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *RoutingMatcherBuilder) AddFinal(outbound string) {
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
b.Final = outbound
|
||||
b.rules = append(b.rules, bpfMatchSet{
|
||||
Type: uint8(consts.RoutingType_Final),
|
||||
Type: uint8(consts.MatchType_Final),
|
||||
Outbound: b.OutboundToId(outbound),
|
||||
})
|
||||
}
|
||||
@ -226,7 +243,7 @@ func (b *RoutingMatcherBuilder) Build() (err error) {
|
||||
}
|
||||
// Write routings.
|
||||
// Final rule MUST be the last.
|
||||
if b.rules[len(b.rules)-1].Type != uint8(consts.RoutingType_Final) {
|
||||
if b.rules[len(b.rules)-1].Type != uint8(consts.MatchType_Final) {
|
||||
b.err = fmt.Errorf("final rule MUST be the last")
|
||||
return b.err
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ type MatcherBuilder interface {
|
||||
AddL4Proto(f *config_parser.Function, values consts.L4ProtoType, outbound string)
|
||||
AddIpVersion(f *config_parser.Function, values consts.IpVersion, outbound string)
|
||||
AddSourceMac(f *config_parser.Function, values [][6]byte, outbound string)
|
||||
AddProcessName(f *config_parser.Function, values [][consts.TaskCommLen]byte, outbound string)
|
||||
AddFinal(outbound string)
|
||||
AddAnyBefore(f *config_parser.Function, key string, values []string, outbound string)
|
||||
AddAnyAfter(f *config_parser.Function, key string, values []string, outbound string)
|
||||
@ -59,9 +60,15 @@ func ParsePrefixes(values []string) (cidrs []netip.Prefix, err error) {
|
||||
return cidrs, nil
|
||||
}
|
||||
|
||||
func ApplyMatcherBuilder(builder MatcherBuilder, rules []*config_parser.RoutingRule, finalOutbound string) (err error) {
|
||||
func ToProcessName(processName string) (procName [consts.TaskCommLen]byte) {
|
||||
n := []byte(processName)
|
||||
copy(procName[:], n)
|
||||
return procName
|
||||
}
|
||||
|
||||
func ApplyMatcherBuilder(log *logrus.Logger, builder MatcherBuilder, rules []*config_parser.RoutingRule, finalOutbound string) (err error) {
|
||||
for _, rule := range rules {
|
||||
logrus.Debugln("[rule]", rule.String(true))
|
||||
log.Debugln("[rule]", rule.String(true))
|
||||
|
||||
// rule is like: domain(domain:baidu.com) && port(443) -> proxy
|
||||
for iFunc, f := range rule.AndFunctions {
|
||||
@ -84,7 +91,7 @@ func ApplyMatcherBuilder(builder MatcherBuilder, rules []*config_parser.RoutingR
|
||||
if f.Not {
|
||||
symNot = "!"
|
||||
}
|
||||
logrus.Debugf("\t%v%v(%v) -> %v", symNot, f.Name, key, outbound)
|
||||
log.Debugf("\t%v%v(%v) -> %v", symNot, f.Name, key, outbound)
|
||||
}
|
||||
|
||||
builder.AddAnyBefore(f, key, paramValueGroup, outbound)
|
||||
@ -147,6 +154,15 @@ func ApplyMatcherBuilder(builder MatcherBuilder, rules []*config_parser.RoutingR
|
||||
}
|
||||
}
|
||||
builder.AddIpVersion(f, ipVersion, outbound)
|
||||
case consts.Function_ProcessName:
|
||||
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))
|
||||
}
|
||||
builder.AddProcessName(f, procNames, outbound)
|
||||
default:
|
||||
return fmt.Errorf("unsupported function name: %v", f.Name)
|
||||
}
|
||||
@ -186,6 +202,8 @@ func (d *DefaultMatcherBuilder) AddSourceMac(f *config_parser.Function, values [
|
||||
func (d *DefaultMatcherBuilder) AddFinal(outbound string) {}
|
||||
func (d *DefaultMatcherBuilder) AddAnyBefore(f *config_parser.Function, key string, values []string, outbound string) {
|
||||
}
|
||||
func (d *DefaultMatcherBuilder) AddProcessName(f *config_parser.Function, values [][consts.TaskCommLen]byte, outbound string) {
|
||||
}
|
||||
func (d *DefaultMatcherBuilder) AddAnyAfter(f *config_parser.Function, key string, values []string, outbound string) {
|
||||
}
|
||||
func (d *DefaultMatcherBuilder) Build() (err error) { return nil }
|
||||
|
@ -16,7 +16,7 @@ type Global struct {
|
||||
TproxyPort uint16 `mapstructure:"tproxy_port" default:"12345"`
|
||||
CheckUrl string `mapstructure:"check_url" default:"https://connectivitycheck.gstatic.com/generate_204"`
|
||||
CheckInterval time.Duration `mapstructure:"check_interval" default:"15s"`
|
||||
DnsUpstream string `mapstructure:"dns_upstream" default:"208.67.222.222:5353"`
|
||||
DnsUpstream string `mapstructure:"dns_upstream" default:"1.1.1.1:53"`
|
||||
LanInterface string `mapstructure:"lan_interface"`
|
||||
WanInterface string `mapstructure:"wan_interface"`
|
||||
}
|
||||
|
@ -48,6 +48,9 @@ group {
|
||||
|
||||
routing {
|
||||
# See routing.md for full examples.
|
||||
ip(1.1.1.1) && port(53) -> my_group
|
||||
pname(firefox) && domain(ip.sb) -> direct
|
||||
pname(curl) && domain(ip.sb) -> my_group
|
||||
|
||||
ip(geoip:private) -> direct
|
||||
ip(geoip:cn) -> direct
|
||||
|
@ -34,9 +34,6 @@ port(10080-30000) -> direct
|
||||
sport(38563) -> direct
|
||||
sport(10080-30000) -> direct
|
||||
|
||||
# Source MAC rule
|
||||
mac('02:42:ac:11:00:02') -> direct
|
||||
|
||||
# Level 4 protocol rule:
|
||||
l4proto(tcp) -> my_group
|
||||
l4proto(udp) -> direct
|
||||
@ -45,6 +42,12 @@ l4proto(udp) -> direct
|
||||
ipversion(4) -> block
|
||||
ipversion(6) -> ipv6_group
|
||||
|
||||
# Source MAC rule
|
||||
mac('02:42:ac:11:00:02') -> direct
|
||||
|
||||
# Process Name rule (Only support local process)
|
||||
pname(curl) -> direct
|
||||
|
||||
# Multiple domains rule
|
||||
domain(keyword: google, suffix: www.twitter.com, suffix: v2raya.org) -> my_group
|
||||
# Multiple IP rule
|
||||
|
Loading…
Reference in New Issue
Block a user