mirror of
https://github.com/daeuniverse/dae.git
synced 2025-02-22 04:29:38 +07:00
feat: support real process name traffic split (#6)
This commit is contained in:
parent
0793534f72
commit
b117dfa7d5
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
@ -92,6 +92,7 @@ jobs:
|
||||
|
||||
- name: Get project dependencies
|
||||
run: |
|
||||
git submodule update --init --recursive
|
||||
go mod download
|
||||
|
||||
- name: Build dae
|
||||
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "component/control/kern/headers"]
|
||||
path = component/control/kern/headers
|
||||
url = https://github.com/v2rayA/dae_bpf_headers
|
33
README.md
33
README.md
@ -4,7 +4,7 @@
|
||||
|
||||
***dae***, means goose, is a lightweight and high-performance transparent proxy solution.
|
||||
|
||||
In order to improve the traffic diversion performance as much as possible, dae runs the transparent proxy and traffic diversion suite in the linux kernel by eBPF. Therefore, we have the opportunity to make the direct traffic bypass the forwarding by proxy application and achieve true direct traffic through. Under such a magic trick, there is almost no performance loss and additional resource consumption for direct traffic.
|
||||
In order to improve the traffic split performance as much as possible, dae runs the transparent proxy and traffic split suite in the linux kernel by eBPF. Therefore, we have the opportunity to make the direct traffic bypass the forwarding by proxy application and achieve true direct traffic through. Under such a magic trick, there is almost no performance loss and additional resource consumption for direct traffic.
|
||||
|
||||
As a successor of [v2rayA](https://github.com/v2rayA/v2rayA), dae abandoned v2ray-core to meet the needs of users more freely.
|
||||
|
||||
@ -43,16 +43,45 @@ Note that if you bind dae to LAN only, dae only provide network service for traf
|
||||
|
||||
You need bind dae to WAN interface, if you want dae to provide network service for local programs.
|
||||
|
||||
This feature requires kernel version of the machine >= 5.2.
|
||||
This feature requires kernel version of the machine >= 5.7.
|
||||
|
||||
Note that if you bind dae to WAN only, dae only provide network service for local programs and not impact traffic coming in from other interfaces.
|
||||
|
||||
### Kernel Configuration Item
|
||||
|
||||
Usually, mainstream desktop distributions have these items turned on. But in order to reduce kernel size, some items are turned off by default on embedded device distributions like OpenWRT, Armbian, etc.
|
||||
|
||||
Use following commands to check the kernel configuration items on your machine.
|
||||
|
||||
```shell
|
||||
zcat /proc/config.gz || cat /boot/config || cat /boot/config-$(uname -r)
|
||||
```
|
||||
|
||||
**Bind to LAN**
|
||||
|
||||
```
|
||||
CONFIG_DEBUG_INFO_BTF
|
||||
```
|
||||
|
||||
**Bind to WAN**:
|
||||
|
||||
```
|
||||
CONFIG_DEBUG_INFO_BTF
|
||||
```
|
||||
|
||||
Check them using command like:
|
||||
|
||||
```shell
|
||||
(zcat /proc/config.gz || cat /boot/config || cat /boot/config-$(uname -r)) | grep 'CONFIG_DEBUG_INFO_BTF='
|
||||
```
|
||||
|
||||
## TODO
|
||||
|
||||
1. Check dns upstream and source loop (whether upstream is also a client of us) and remind the user to add sip rule.
|
||||
1. Domain routing performance optimization.
|
||||
1. DisableL4Checksum by link.
|
||||
1. Handle the case that nodes do not support UDP.
|
||||
1. Handle the case that nodes do not support IPv6.
|
||||
1. L4Checksum problem.
|
||||
1. MACv2 extension extraction.
|
||||
1. ...
|
||||
|
@ -98,4 +98,4 @@ const (
|
||||
|
||||
var BasicFeatureVersion = internal.Version{5, 2, 0}
|
||||
var FtraceFeatureVersion = internal.Version{5, 5, 0}
|
||||
var CgGetPidFeatureVersion = internal.Version{5, 7, 0}
|
||||
var CgSocketCookieFeatureVersion = internal.Version{5, 7, 0}
|
||||
|
@ -29,11 +29,19 @@ type _bpfPortRange struct {
|
||||
PortEnd uint16
|
||||
}
|
||||
|
||||
func (r _bpfPortRange) Encode() uint32 {
|
||||
var b [4]byte
|
||||
binary.BigEndian.PutUint16(b[:2], r.PortStart)
|
||||
binary.BigEndian.PutUint16(b[2:], r.PortEnd)
|
||||
return binary.BigEndian.Uint32(b[:])
|
||||
type _bpfMatchSet struct {
|
||||
// TODO: Need sync with C code.
|
||||
Value [16]byte
|
||||
Type uint8
|
||||
Not bool
|
||||
Outbound uint8
|
||||
_ [1]byte
|
||||
}
|
||||
|
||||
func (r _bpfPortRange) Encode() (b [16]byte) {
|
||||
binary.LittleEndian.PutUint16(b[:2], r.PortStart)
|
||||
binary.LittleEndian.PutUint16(b[2:], r.PortEnd)
|
||||
return b
|
||||
}
|
||||
|
||||
func (o *bpfObjects) newLpmMap(keys []_bpfLpmKey, values []uint32) (m *ebpf.Map, err error) {
|
||||
|
@ -69,6 +69,10 @@ func NewControlPlane(
|
||||
if kernelVersion.Less(consts.BasicFeatureVersion) {
|
||||
return nil, fmt.Errorf("your kernel version %v does not satisfy basic requirement; expect >=%v", c.kernelVersion.String(), consts.BasicFeatureVersion.String())
|
||||
}
|
||||
if len(wanInterface) > 0 && kernelVersion.Less(consts.CgSocketCookieFeatureVersion) {
|
||||
return nil, fmt.Errorf("your kernel version %v does not support bind to WAN; expect >=%v; remove wan_interface in config file and try again", kernelVersion.String(),
|
||||
consts.CgSocketCookieFeatureVersion.String())
|
||||
}
|
||||
|
||||
// Allow the current process to lock memory for eBPF resources.
|
||||
if err = rlimit.RemoveMemlock(); err != nil {
|
||||
@ -83,7 +87,8 @@ func NewControlPlane(
|
||||
var ProgramOptions ebpf.ProgramOptions
|
||||
if log.IsLevelEnabled(logrus.TraceLevel) {
|
||||
ProgramOptions = ebpf.ProgramOptions{
|
||||
LogLevel: ebpf.LogLevelInstruction | ebpf.LogLevelStats,
|
||||
LogLevel: ebpf.LogLevelBranch | ebpf.LogLevelStats,
|
||||
//LogLevel: ebpf.LogLevelInstruction | ebpf.LogLevelStats,
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,7 +97,7 @@ func NewControlPlane(
|
||||
if len(lanInterface) > 0 && len(wanInterface) == 0 {
|
||||
// Only bind LAN.
|
||||
obj = &bpfObjectsLan{}
|
||||
} else if len(wanInterface) == 0 && len(wanInterface) > 0 {
|
||||
} else if len(lanInterface) == 0 && len(wanInterface) > 0 {
|
||||
// Only bind to WAN.
|
||||
// Trick. Replace the beams with rotten timbers.
|
||||
obj = &bpfObjectsWan{}
|
||||
|
@ -164,10 +164,6 @@ func (c *ControlPlaneCore) BindLan(ifname string) error {
|
||||
}
|
||||
|
||||
func (c *ControlPlaneCore) BindWan(ifname string) error {
|
||||
if c.kernelVersion.Less(consts.BasicFeatureVersion) {
|
||||
return fmt.Errorf("your kernel version %v does not support bind to WAN; expect >=%v; remove wan_interface in config file and try again", c.kernelVersion.String(), consts.CgGetPidFeatureVersion.String())
|
||||
}
|
||||
|
||||
c.log.Infof("Bind to WAN: %v", ifname)
|
||||
link, err := netlink.LinkByName(ifname)
|
||||
if err != nil {
|
||||
|
1
component/control/kern/headers
Submodule
1
component/control/kern/headers
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 372c3cc61d2d907b89ebdfb7bec180a09cd28169
|
@ -3,20 +3,17 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
#include <asm-generic/errno-base.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/pkt_cls.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
#include <stdbool.h>
|
||||
#include "headers/if_ether_defs.h"
|
||||
#include "headers/pkt_cls_defs.h"
|
||||
#include "headers/socket_defs.h"
|
||||
#include "headers/vmlinux.h"
|
||||
|
||||
#include <asm-generic/errno-base.h>
|
||||
|
||||
#include <bpf/bpf_core_read.h>
|
||||
#include <bpf/bpf_endian.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
|
||||
// #define __DEBUG_ROUTING
|
||||
// #define __PRINT_ROUTING_RESULT
|
||||
@ -53,6 +50,8 @@
|
||||
#define MAX_DST_MAPPING_NUM (65536 * 2)
|
||||
#define MAX_SRC_PID_PNAME_MAPPING_NUM (65536)
|
||||
#define IPV6_MAX_EXTENSIONS 4
|
||||
#define MAX_ARG_LEN_TO_PROBE 192
|
||||
#define MAX_ARG_SCANNER_BUFFER_SIZE (TASK_COMM_LEN * 4)
|
||||
|
||||
#define OUTBOUND_DIRECT 0
|
||||
#define OUTBOUND_BLOCK 1
|
||||
@ -229,6 +228,7 @@ struct port_range {
|
||||
*/
|
||||
struct match_set {
|
||||
union {
|
||||
/// NOTICE: MUST sync with component/control/bpf_utils.go.
|
||||
__u32 __value; // Placeholder for bpf2go.
|
||||
|
||||
__u32 index;
|
||||
@ -827,13 +827,13 @@ routing(const __u32 flag[6], const void *l4_hdr, const __be32 saddr[4],
|
||||
|
||||
/// TODO: BPF_MAP_UPDATE_BATCH ?
|
||||
__u32 key = MatchType_L4Proto;
|
||||
if ((ret = bpf_map_update_elem(&l4proto_ipversion_map, &key, &_l4proto_type,
|
||||
BPF_ANY))) {
|
||||
if (unlikely((ret = bpf_map_update_elem(&l4proto_ipversion_map, &key,
|
||||
&_l4proto_type, BPF_ANY)))) {
|
||||
return ret;
|
||||
};
|
||||
key = MatchType_IpVersion;
|
||||
if ((ret = bpf_map_update_elem(&l4proto_ipversion_map, &key, &_ipversion_type,
|
||||
BPF_ANY))) {
|
||||
if (unlikely((ret = bpf_map_update_elem(&l4proto_ipversion_map, &key,
|
||||
&_ipversion_type, BPF_ANY)))) {
|
||||
return ret;
|
||||
};
|
||||
|
||||
@ -849,11 +849,13 @@ routing(const __u32 flag[6], const void *l4_hdr, const __be32 saddr[4],
|
||||
}
|
||||
|
||||
key = MatchType_SourcePort;
|
||||
if ((ret = bpf_map_update_elem(&h_port_map, &key, &h_sport, BPF_ANY))) {
|
||||
if (unlikely(
|
||||
(ret = bpf_map_update_elem(&h_port_map, &key, &h_sport, BPF_ANY)))) {
|
||||
return ret;
|
||||
};
|
||||
key = MatchType_Port;
|
||||
if ((ret = bpf_map_update_elem(&h_port_map, &key, &h_dport, BPF_ANY))) {
|
||||
if (unlikely(
|
||||
(ret = bpf_map_update_elem(&h_port_map, &key, &h_dport, BPF_ANY)))) {
|
||||
return ret;
|
||||
};
|
||||
|
||||
@ -862,7 +864,7 @@ routing(const __u32 flag[6], const void *l4_hdr, const __be32 saddr[4],
|
||||
if (h_dport == 53 && _l4proto_type == L4ProtoType_UDP) {
|
||||
struct ip_port *upstream =
|
||||
bpf_map_lookup_elem(&dns_upstream_map, &zero_key);
|
||||
if (!upstream) {
|
||||
if (unlikely(!upstream)) {
|
||||
return -EFAULT;
|
||||
}
|
||||
h_dport = bpf_ntohs(upstream->port);
|
||||
@ -875,21 +877,21 @@ routing(const __u32 flag[6], const void *l4_hdr, const __be32 saddr[4],
|
||||
__builtin_memcpy(lpm_key_instance.data, daddr, IPV6_BYTE_LENGTH);
|
||||
// bpf_printk("mac: %pI6", mac);
|
||||
key = MatchType_IpSet;
|
||||
if ((ret = bpf_map_update_elem(&lpm_key_map, &key, &lpm_key_instance,
|
||||
BPF_ANY))) {
|
||||
if (unlikely((ret = bpf_map_update_elem(&lpm_key_map, &key, &lpm_key_instance,
|
||||
BPF_ANY)))) {
|
||||
return ret;
|
||||
};
|
||||
__builtin_memcpy(lpm_key_instance.data, saddr, IPV6_BYTE_LENGTH);
|
||||
key = MatchType_SourceIpSet;
|
||||
if ((ret = bpf_map_update_elem(&lpm_key_map, &key, &lpm_key_instance,
|
||||
BPF_ANY))) {
|
||||
if (unlikely((ret = bpf_map_update_elem(&lpm_key_map, &key, &lpm_key_instance,
|
||||
BPF_ANY)))) {
|
||||
return ret;
|
||||
};
|
||||
if (!_is_wan) {
|
||||
__builtin_memcpy(lpm_key_instance.data, mac, IPV6_BYTE_LENGTH);
|
||||
key = MatchType_Mac;
|
||||
if ((ret = bpf_map_update_elem(&lpm_key_map, &key, &lpm_key_instance,
|
||||
BPF_ANY))) {
|
||||
if (unlikely((ret = bpf_map_update_elem(&lpm_key_map, &key,
|
||||
&lpm_key_instance, BPF_ANY)))) {
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
@ -909,7 +911,7 @@ routing(const __u32 flag[6], const void *l4_hdr, const __be32 saddr[4],
|
||||
for (__u32 i = 0; i < MAX_MATCH_SET_LEN; i++) {
|
||||
__u32 k = i; // Clone to pass code checker.
|
||||
match_set = bpf_map_lookup_elem(&routing_map, &k);
|
||||
if (!match_set) {
|
||||
if (unlikely(!match_set)) {
|
||||
return -EFAULT;
|
||||
}
|
||||
if (bad_rule || good_subrule) {
|
||||
@ -980,8 +982,8 @@ routing(const __u32 flag[6], const void *l4_hdr, const __be32 saddr[4],
|
||||
if ((domain_routing->bitmap[i / 32] >> (i % 32)) & 1) {
|
||||
good_subrule = true;
|
||||
}
|
||||
} else if (_is_wan && match_set->type == MatchType_ProcessName) {
|
||||
if ((equal_ipv6_format(match_set->pname, _pname))) {
|
||||
} else if (match_set->type == MatchType_ProcessName) {
|
||||
if (_is_wan && equal_ipv6_format(match_set->pname, _pname)) {
|
||||
good_subrule = true;
|
||||
}
|
||||
} else if (match_set->type == MatchType_Final) {
|
||||
@ -1298,7 +1300,7 @@ static __always_inline bool pid_is_control_plane(struct __sk_buff *skb,
|
||||
if (p) {
|
||||
*p = NULL;
|
||||
}
|
||||
if ((skb->mark & 0x80) == 0x80) {
|
||||
if ((skb->mark & 0x100) == 0x100) {
|
||||
bpf_printk("No pid_pname found. But it should not happen");
|
||||
/*
|
||||
if (l4proto == IPPROTO_TCP) {
|
||||
@ -1934,7 +1936,7 @@ int tproxy_wan_ingress(struct __sk_buff *skb) {
|
||||
}
|
||||
|
||||
static int __always_inline update_map_elem_by_cookie(const __u64 cookie) {
|
||||
if (!cookie) {
|
||||
if (unlikely(!cookie)) {
|
||||
bpf_printk("zero cookie");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1943,15 +1945,67 @@ static int __always_inline update_map_elem_by_cookie(const __u64 cookie) {
|
||||
// Build value.
|
||||
struct pid_pname val;
|
||||
__builtin_memset(&val, 0, sizeof(struct pid_pname));
|
||||
val.pid = bpf_get_current_pid_tgid() >> 32;
|
||||
// struct task_struct *t = (void *)bpf_get_current_task();
|
||||
if ((ret = bpf_get_current_comm(val.pname, sizeof(val.pname)))) {
|
||||
return ret;
|
||||
char buf[MAX_ARG_SCANNER_BUFFER_SIZE] = {0};
|
||||
struct task_struct *current = (void *)bpf_get_current_task();
|
||||
unsigned long arg_start = BPF_CORE_READ(current, mm, arg_start);
|
||||
unsigned long arg_end = BPF_CORE_READ(current, mm, arg_end);
|
||||
unsigned long arg_len = arg_end - arg_start;
|
||||
if (arg_len > MAX_ARG_LEN_TO_PROBE) {
|
||||
arg_len = MAX_ARG_LEN_TO_PROBE;
|
||||
}
|
||||
|
||||
/**
|
||||
For string like: /usr/lib/sddm/sddm-helper --socket /tmp/sddm-auth1
|
||||
We extract "sddm-helper" from it.
|
||||
*/
|
||||
unsigned long loc, j;
|
||||
unsigned long last_slash = -1;
|
||||
#pragma unroll
|
||||
for (loc = 0, j = 0; j < MAX_ARG_LEN_TO_PROBE;
|
||||
++j, loc = ((loc + 1) & (MAX_ARG_SCANNER_BUFFER_SIZE - 1))) {
|
||||
// volatile unsigned long k = j; // Cheat to unroll.
|
||||
// if (arg_start + k >= arg_end) {
|
||||
if (unlikely(arg_start + j >= arg_end)) {
|
||||
break;
|
||||
}
|
||||
if (unlikely(loc == 0)) {
|
||||
/// WANRING: Do NOT use bpf_core_read_user_str, it will bring terminator
|
||||
/// 0.
|
||||
// __builtin_memset(&buf, 0, MAX_ARG_SCANNER_BUFFER_SIZE);
|
||||
unsigned long to_read = arg_end - (arg_start + j);
|
||||
if (to_read >= MAX_ARG_SCANNER_BUFFER_SIZE) {
|
||||
to_read = MAX_ARG_SCANNER_BUFFER_SIZE;
|
||||
} else {
|
||||
buf[to_read] = 0;
|
||||
}
|
||||
if ((ret = bpf_core_read_user(&buf, to_read, arg_start + j))) {
|
||||
bpf_printk("failed to read process name: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (unlikely(buf[loc] == '/')) {
|
||||
last_slash = j;
|
||||
} else if (unlikely(buf[loc] == ' ' || buf[loc] == 0)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
++last_slash;
|
||||
unsigned long length_cpy = j - last_slash;
|
||||
if (length_cpy > TASK_COMM_LEN) {
|
||||
length_cpy = TASK_COMM_LEN;
|
||||
}
|
||||
if ((ret = bpf_core_read_user(&val.pname, length_cpy,
|
||||
arg_start + last_slash))) {
|
||||
bpf_printk("failed to read process name: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
val.pid = BPF_CORE_READ(current, tgid);
|
||||
// bpf_printk("a start_end: %lu %lu", arg_start, arg_end);
|
||||
// bpf_printk("b start_end: %lu %lu", arg_start + last_slash, arg_start + j);
|
||||
|
||||
// Update map.
|
||||
if ((ret =
|
||||
bpf_map_update_elem(&cookie_pid_map, &cookie, &val, BPF_NOEXIST))) {
|
||||
if (unlikely(ret = bpf_map_update_elem(&cookie_pid_map, &cookie, &val,
|
||||
BPF_NOEXIST))) {
|
||||
// bpf_printk("setup_mapping_from_sk: failed update map: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
@ -1970,7 +2024,7 @@ int tproxy_wan_cg_sock_create(struct bpf_sock *sk) {
|
||||
SEC("cgroup/sock_release")
|
||||
int tproxy_wan_cg_sock_release(struct bpf_sock *sk) {
|
||||
__u64 cookie = bpf_get_socket_cookie(sk);
|
||||
if (!cookie) {
|
||||
if (unlikely(!cookie)) {
|
||||
bpf_printk("zero cookie");
|
||||
return 1;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
package control
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/cilium/ebpf"
|
||||
"github.com/v2rayA/dae/common"
|
||||
@ -14,7 +15,6 @@ import (
|
||||
"github.com/v2rayA/dae/pkg/config_parser"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type DomainSet struct {
|
||||
@ -27,7 +27,7 @@ type RoutingMatcherBuilder struct {
|
||||
*routing.DefaultMatcherBuilder
|
||||
outboundName2Id map[string]uint8
|
||||
bpf *bpfObjects
|
||||
rules []bpfMatchSet
|
||||
rules []_bpfMatchSet
|
||||
SimulatedLpmTries [][]netip.Prefix
|
||||
SimulatedDomainSet []DomainSet
|
||||
Final string
|
||||
@ -74,7 +74,7 @@ func (b *RoutingMatcherBuilder) AddDomain(f *config_parser.Function, key string,
|
||||
RuleIndex: len(b.rules),
|
||||
Domains: values,
|
||||
})
|
||||
b.rules = append(b.rules, bpfMatchSet{
|
||||
b.rules = append(b.rules, _bpfMatchSet{
|
||||
Type: uint8(consts.MatchType_DomainSet),
|
||||
Not: f.Not,
|
||||
Outbound: b.OutboundToId(outbound),
|
||||
@ -94,12 +94,14 @@ 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{
|
||||
set := _bpfMatchSet{
|
||||
Value: [16]byte{},
|
||||
Type: uint8(consts.MatchType_Mac),
|
||||
Value: uint32(lpmTrieIndex),
|
||||
Not: f.Not,
|
||||
Outbound: b.OutboundToId(outbound),
|
||||
})
|
||||
}
|
||||
binary.LittleEndian.PutUint32(set.Value[:], uint32(lpmTrieIndex))
|
||||
b.rules = append(b.rules, set)
|
||||
|
||||
}
|
||||
|
||||
@ -109,12 +111,14 @@ 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{
|
||||
set := _bpfMatchSet{
|
||||
Value: [16]byte{},
|
||||
Type: uint8(consts.MatchType_IpSet),
|
||||
Value: uint32(lpmTrieIndex),
|
||||
Not: f.Not,
|
||||
Outbound: b.OutboundToId(outbound),
|
||||
})
|
||||
}
|
||||
binary.LittleEndian.PutUint32(set.Value[:], uint32(lpmTrieIndex))
|
||||
b.rules = append(b.rules, set)
|
||||
}
|
||||
|
||||
func (b *RoutingMatcherBuilder) AddPort(f *config_parser.Function, values [][2]uint16, _outbound string) {
|
||||
@ -123,7 +127,7 @@ func (b *RoutingMatcherBuilder) AddPort(f *config_parser.Function, values [][2]u
|
||||
if i == len(values)-1 {
|
||||
outbound = _outbound
|
||||
}
|
||||
b.rules = append(b.rules, bpfMatchSet{
|
||||
b.rules = append(b.rules, _bpfMatchSet{
|
||||
Type: uint8(consts.MatchType_Port),
|
||||
Value: _bpfPortRange{
|
||||
PortStart: value[0],
|
||||
@ -141,12 +145,14 @@ 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{
|
||||
set := _bpfMatchSet{
|
||||
Value: [16]byte{},
|
||||
Type: uint8(consts.MatchType_SourceIpSet),
|
||||
Value: uint32(lpmTrieIndex),
|
||||
Not: f.Not,
|
||||
Outbound: b.OutboundToId(outbound),
|
||||
})
|
||||
}
|
||||
binary.LittleEndian.PutUint32(set.Value[:], uint32(lpmTrieIndex))
|
||||
b.rules = append(b.rules, set)
|
||||
}
|
||||
|
||||
func (b *RoutingMatcherBuilder) AddSourcePort(f *config_parser.Function, values [][2]uint16, _outbound string) {
|
||||
@ -155,7 +161,7 @@ func (b *RoutingMatcherBuilder) AddSourcePort(f *config_parser.Function, values
|
||||
if i == len(values)-1 {
|
||||
outbound = _outbound
|
||||
}
|
||||
b.rules = append(b.rules, bpfMatchSet{
|
||||
b.rules = append(b.rules, _bpfMatchSet{
|
||||
Type: uint8(consts.MatchType_SourcePort),
|
||||
Value: _bpfPortRange{
|
||||
PortStart: value[0],
|
||||
@ -171,9 +177,9 @@ func (b *RoutingMatcherBuilder) AddL4Proto(f *config_parser.Function, values con
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
b.rules = append(b.rules, bpfMatchSet{
|
||||
b.rules = append(b.rules, _bpfMatchSet{
|
||||
Value: [16]byte{byte(values)},
|
||||
Type: uint8(consts.MatchType_L4Proto),
|
||||
Value: uint32(values),
|
||||
Not: f.Not,
|
||||
Outbound: b.OutboundToId(outbound),
|
||||
})
|
||||
@ -183,9 +189,9 @@ func (b *RoutingMatcherBuilder) AddIpVersion(f *config_parser.Function, values c
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
b.rules = append(b.rules, bpfMatchSet{
|
||||
b.rules = append(b.rules, _bpfMatchSet{
|
||||
Value: [16]byte{byte(values)},
|
||||
Type: uint8(consts.MatchType_IpVersion),
|
||||
Value: uint32(values),
|
||||
Not: f.Not,
|
||||
Outbound: b.OutboundToId(outbound),
|
||||
})
|
||||
@ -197,12 +203,12 @@ func (b *RoutingMatcherBuilder) AddProcessName(f *config_parser.Function, values
|
||||
if i == len(values)-1 {
|
||||
outbound = _outbound
|
||||
}
|
||||
matchSet := bpfMatchSet{
|
||||
matchSet := _bpfMatchSet{
|
||||
Type: uint8(consts.MatchType_ProcessName),
|
||||
Not: f.Not,
|
||||
Outbound: b.OutboundToId(outbound),
|
||||
}
|
||||
copy((*(*[16]byte)(unsafe.Pointer(&matchSet.Value)))[:], value[:])
|
||||
copy(matchSet.Value[:], value[:])
|
||||
b.rules = append(b.rules, matchSet)
|
||||
}
|
||||
}
|
||||
@ -212,7 +218,7 @@ func (b *RoutingMatcherBuilder) AddFinal(outbound string) {
|
||||
return
|
||||
}
|
||||
b.Final = outbound
|
||||
b.rules = append(b.rules, bpfMatchSet{
|
||||
b.rules = append(b.rules, _bpfMatchSet{
|
||||
Type: uint8(consts.MatchType_Final),
|
||||
Outbound: b.OutboundToId(outbound),
|
||||
})
|
||||
|
@ -106,7 +106,7 @@ func init() {
|
||||
func SoMarkControl(c syscall.RawConn) error {
|
||||
return c.Control(func(fd uintptr) {
|
||||
//TODO: force to set 0xff. any chances to customize this value?
|
||||
err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, fwmarkIoctl, 0x80)
|
||||
err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, fwmarkIoctl, 0x100)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -65,7 +65,8 @@ routing {
|
||||
# See routing.md for full examples.
|
||||
|
||||
ip(1.1.1.1) && port(53) -> my_group
|
||||
pname(firefox) && domain(ip.sb) -> direct # pname like firefox not works yet [ FIXME ]
|
||||
|
||||
pname(firefox) && domain(ip.sb) -> direct
|
||||
pname(curl) && domain(ip.sb) -> my_group
|
||||
|
||||
ip(geoip:private) -> direct
|
||||
|
@ -45,7 +45,7 @@ ipversion(6) -> ipv6_group
|
||||
# Source MAC rule
|
||||
mac('02:42:ac:11:00:02') -> direct
|
||||
|
||||
# Process Name rule (Only support local process)
|
||||
# Process Name rule (only support local process)
|
||||
pname(curl) -> direct
|
||||
|
||||
# Multiple domains rule
|
||||
|
Loading…
Reference in New Issue
Block a user