From c6557ce207f7acc61d73c42af7ceeed73b6d3038 Mon Sep 17 00:00:00 2001 From: mzz <2017@duck.com> Date: Sun, 20 Aug 2023 23:43:33 +0800 Subject: [PATCH] refactor/fix: match dscp instead of tos (#294) Co-authored-by: dae-bot[bot] <136105375+dae-bot[bot]@users.noreply.github.com> --- cmd/honk.go | 2 +- common/consts/ebpf.go | 2 +- common/consts/routing.go | 2 +- component/routing/function_parser.go | 2 +- control/control_plane.go | 1 + control/dns_control.go | 2 +- control/kern/tproxy.c | 218 ++++++++++++++------------- control/routing_matcher_builder.go | 6 +- control/routing_matcher_userspace.go | 2 +- control/tcp.go | 7 +- control/udp.go | 4 +- control/utils.go | 4 +- docs/en/configuration/routing.md | 4 +- docs/zh/configuration/routing.md | 4 +- go.mod | 6 +- go.sum | 12 +- 16 files changed, 150 insertions(+), 128 deletions(-) diff --git a/cmd/honk.go b/cmd/honk.go index 80688ef..5b70c56 100644 --- a/cmd/honk.go +++ b/cmd/honk.go @@ -31,4 +31,4 @@ var ( func init() { rootCmd.AddCommand(honkCmd) -} \ No newline at end of file +} diff --git a/common/consts/ebpf.go b/common/consts/ebpf.go index d57e183..c8a2691 100644 --- a/common/consts/ebpf.go +++ b/common/consts/ebpf.go @@ -52,7 +52,7 @@ const ( MatchType_IpVersion MatchType_Mac MatchType_ProcessName - MatchType_Tos + MatchType_Dscp MatchType_Fallback MatchType_MustRules diff --git a/common/consts/routing.go b/common/consts/routing.go index 60395fd..786e182 100644 --- a/common/consts/routing.go +++ b/common/consts/routing.go @@ -22,7 +22,7 @@ const ( Function_IpVersion = "ipversion" Function_Mac = "mac" Function_ProcessName = "pname" - Function_Tos = "tos" + Function_Dscp = "dscp" Function_QName = "qname" Function_QType = "qtype" diff --git a/component/routing/function_parser.go b/component/routing/function_parser.go index e6c8902..9ab3970 100644 --- a/component/routing/function_parser.go +++ b/component/routing/function_parser.go @@ -147,7 +147,7 @@ func UintParserFactory[T constraints.Unsigned](callback func(f *config_parser.Fu 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) + val, err := strconv.ParseUint(v, 0, 8*size) if err != nil { return fmt.Errorf("cannot parse %v: %w", v, err) } diff --git a/control/control_plane.go b/control/control_plane.go index 5bd9eea..00f2384 100644 --- a/control/control_plane.go +++ b/control/control_plane.go @@ -757,6 +757,7 @@ func (c *ControlPlane) Serve(readyChan chan<- bool, listener *Listener) (err err Outbound: uint8(consts.OutboundControlPlaneRouting), Pname: [16]uint8{}, Pid: 0, + Dscp: 0, } realDst = pktDst goto destRetrieved diff --git a/control/dns_control.go b/control/dns_control.go index 452dff0..a0787fe 100644 --- a/control/dns_control.go +++ b/control/dns_control.go @@ -729,7 +729,7 @@ func (c *DnsController) dialSend(invokingDepth int, req *udpRequest, data []byte "_qname": qname, "qtype": qtype, "pid": req.routingResult.Pid, - "tos": req.routingResult.Tos, + "dscp": req.routingResult.Dscp, "pname": ProcessName2String(req.routingResult.Pname[:]), "mac": Mac2String(req.routingResult.Mac[:]), } diff --git a/control/kern/tproxy.c b/control/kern/tproxy.c index b6c933b..1c0e97e 100644 --- a/control/kern/tproxy.c +++ b/control/kern/tproxy.c @@ -140,7 +140,7 @@ struct routing_result { __u8 outbound; __u8 pname[TASK_COMM_LEN]; __u32 pid; - __u8 tos; + __u8 dscp; }; struct dst_routing_result { @@ -150,13 +150,17 @@ struct dst_routing_result { struct routing_result routing_result; }; -struct tuples { +struct tuples_key { union ip6 sip; union ip6 dip; __u16 sport; __u16 dport; __u8 l4proto; - __u8 tos; +}; + +struct tuples { + struct tuples_key five; + __u8 dscp; }; struct { @@ -185,7 +189,7 @@ struct { struct { __uint(type, BPF_MAP_TYPE_LRU_HASH); - __type(key, struct tuples); + __type(key, struct tuples_key); __type(value, struct routing_result); // outbound __uint(max_entries, MAX_DST_MAPPING_NUM); /// NOTICE: It MUST be pinned. @@ -284,7 +288,7 @@ enum __attribute__((packed)) MatchType { MatchType_IpVersion, MatchType_Mac, MatchType_ProcessName, - MatchType_Tos, + MatchType_Dscp, MatchType_Fallback, }; enum L4ProtoType { @@ -320,7 +324,7 @@ struct match_set { enum L4ProtoType l4proto_type; enum IpVersionType ip_version; __u32 pname[TASK_COMM_LEN / 4]; - __u8 tos; + __u8 dscp; }; bool not ; // A subrule flag (this is not a match_set flag). enum MatchType type; @@ -370,34 +374,40 @@ struct { // Functions: +static __always_inline __u8 ipv4_get_dscp(const struct iphdr *iph) { + return (iph->tos & 0xfc) >> 2; +} +static __always_inline __u8 ipv6_get_dscp(const struct ipv6hdr *ipv6h) { + return (ipv6h->priority << 2) + (ipv6h->flow_lbl[0] >> 6); +} static void __always_inline get_tuples(const struct __sk_buff *skb, struct tuples *tuples, const struct iphdr *iph, const struct ipv6hdr *ipv6h, const struct tcphdr *tcph, const struct udphdr *udph, __u8 l4proto) { __builtin_memset(tuples, 0, sizeof(*tuples)); - tuples->l4proto = l4proto; + tuples->five.l4proto = l4proto; if (skb->protocol == bpf_htons(ETH_P_IP)) { - tuples->sip.u6_addr32[2] = bpf_htonl(0x0000ffff); - tuples->sip.u6_addr32[3] = iph->saddr; + tuples->five.sip.u6_addr32[2] = bpf_htonl(0x0000ffff); + tuples->five.sip.u6_addr32[3] = iph->saddr; - tuples->dip.u6_addr32[2] = bpf_htonl(0x0000ffff); - tuples->dip.u6_addr32[3] = iph->daddr; + tuples->five.dip.u6_addr32[2] = bpf_htonl(0x0000ffff); + tuples->five.dip.u6_addr32[3] = iph->daddr; - tuples->tos = iph->tos; + tuples->dscp = ipv4_get_dscp(iph); } else { - __builtin_memcpy(&tuples->dip, &ipv6h->daddr, IPV6_BYTE_LENGTH); - __builtin_memcpy(&tuples->sip, &ipv6h->saddr, IPV6_BYTE_LENGTH); + __builtin_memcpy(&tuples->five.dip, &ipv6h->daddr, IPV6_BYTE_LENGTH); + __builtin_memcpy(&tuples->five.sip, &ipv6h->saddr, IPV6_BYTE_LENGTH); - tuples->tos = ipv6h->priority; + tuples->dscp = ipv6_get_dscp(ipv6h); } if (l4proto == IPPROTO_TCP) { - tuples->sport = tcph->source; - tuples->dport = tcph->dest; + tuples->five.sport = tcph->source; + tuples->five.dport = tcph->dest; } else { - tuples->sport = udph->source; - tuples->dport = udph->dest; + tuples->five.sport = udph->source; + tuples->five.dport = udph->dest; } } @@ -971,13 +981,13 @@ decap_after_udp_hdr(struct __sk_buff *skb, __u32 eth_h_len, __u8 ihl, // Do not use __always_inline here because this function is too heavy. // low -> high: outbound(8b) mark(32b) unused(23b) sign(1b) static __s64 __attribute__((noinline)) -route(const __u32 flag[6], const void *l4hdr, const __be32 saddr[4], +route(const __u32 flag[8], const void *l4hdr, const __be32 saddr[4], const __be32 daddr[4], const __be32 mac[4]) { #define _l4proto_type flag[0] #define _ipversion_type flag[1] #define _pname &flag[2] #define _is_wan flag[2] -#define _tos flag[3] +#define _dscp flag[6] int ret; struct lpm_key lpm_key_instance, *lpm_key; @@ -1132,8 +1142,8 @@ 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) { + case MatchType_Dscp: + if (_dscp == match_set->dscp) { isdns_must_goodsubrule_badrule |= 0b10; } break; @@ -1214,7 +1224,7 @@ route(const __u32 flag[6], const void *l4hdr, const __be32 saddr[4], #undef _ipversion_type #undef _pname #undef _is_wan -#undef _tos +#undef _dscp } static bool __always_inline is_not_to_lan(void *_ori_src) { @@ -1283,7 +1293,7 @@ int tproxy_lan_egress(struct __sk_buff *skb) { } struct tuples tuples; get_tuples(skb, &tuples, &iph, &ipv6h, &tcph, &udph, l4proto); - if (*tproxy_port != tuples.sport) { + if (*tproxy_port != tuples.five.sport) { return TC_ACT_PIPE; } @@ -1297,17 +1307,17 @@ int tproxy_lan_egress(struct __sk_buff *skb) { if (is_not_to_lan(&ori_src)) { return TC_ACT_PIPE; } - if ((ret = rewrite_ip(skb, eth_h_len, l4proto, ihl, tuples.sip.u6_addr32, + if ((ret = rewrite_ip(skb, eth_h_len, l4proto, ihl, tuples.five.sip.u6_addr32, ori_src.ip, false, true))) { return TC_ACT_SHOT; } - if ((ret = rewrite_port(skb, eth_h_len, l4proto, ihl, tuples.sport, + if ((ret = rewrite_port(skb, eth_h_len, l4proto, ihl, tuples.five.sport, ori_src.port, false, true))) { return TC_ACT_SHOT; } disable_l4_checksum(skb, eth_h_len, l4proto, ihl); - // bpf_printk("from %pI6 to %pI6", tuples.sip, ori_src.ip); - // bpf_printk("from %u to %u", bpf_ntohs(tuples.sport), + // bpf_printk("from %pI6 to %pI6", tuples.five.sip, ori_src.ip); + // bpf_printk("from %u to %u", bpf_ntohs(tuples.five.sport), // bpf_ntohs(ori_src.port)); return TC_ACT_OK; } @@ -1356,20 +1366,20 @@ int tproxy_lan_ingress(struct __sk_buff *skb) { __u32 tuple_size; struct bpf_sock *sk; bool is_old_conn = false; - __u32 flag[6]; + __u32 flag[8]; void *l4hdr; if (skb->protocol == bpf_htons(ETH_P_IP)) { - tuple.ipv4.daddr = tuples.dip.u6_addr32[3]; - tuple.ipv4.saddr = tuples.sip.u6_addr32[3]; - tuple.ipv4.dport = tuples.dport; - tuple.ipv4.sport = tuples.sport; + tuple.ipv4.daddr = tuples.five.dip.u6_addr32[3]; + tuple.ipv4.saddr = tuples.five.sip.u6_addr32[3]; + tuple.ipv4.dport = tuples.five.dport; + tuple.ipv4.sport = tuples.five.sport; tuple_size = sizeof(tuple.ipv4); } else { - __builtin_memcpy(tuple.ipv6.daddr, &tuples.dip, IPV6_BYTE_LENGTH); - __builtin_memcpy(tuple.ipv6.saddr, &tuples.sip, IPV6_BYTE_LENGTH); - tuple.ipv6.dport = tuples.dport; - tuple.ipv6.sport = tuples.sport; + __builtin_memcpy(tuple.ipv6.daddr, &tuples.five.dip, IPV6_BYTE_LENGTH); + __builtin_memcpy(tuple.ipv6.saddr, &tuples.five.sip, IPV6_BYTE_LENGTH); + tuple.ipv6.dport = tuples.five.dport; + tuple.ipv6.sport = tuples.five.sport; tuple_size = sizeof(tuple.ipv6); } @@ -1409,7 +1419,7 @@ new_connection: } else { flag[1] = IpVersionType_6; } - flag[3] = tuples.tos; + flag[6] = tuples.dscp; __be32 mac[4] = { 0, 0, @@ -1418,8 +1428,8 @@ new_connection: (ethh.h_source[4] << 8) + (ethh.h_source[5])), }; __s64 s64_ret; - if ((s64_ret = route(flag, l4hdr, tuples.sip.u6_addr32, tuples.dip.u6_addr32, - mac)) < 0) { + if ((s64_ret = route(flag, l4hdr, tuples.five.sip.u6_addr32, + tuples.five.dip.u6_addr32, mac)) < 0) { bpf_printk("shot routing: %d", s64_ret); return TC_ACT_SHOT; } @@ -1427,7 +1437,7 @@ new_connection: routing_result.outbound = s64_ret; routing_result.mark = s64_ret >> 8; routing_result.must = (s64_ret >> 40) & 1; - routing_result.tos = tuples.tos; + routing_result.dscp = tuples.dscp; __builtin_memcpy(routing_result.mac, ethh.h_source, sizeof(routing_result.mac)); /// NOTICE: No pid pname info for LAN packet. @@ -1441,19 +1451,19 @@ new_connection: // } // Save routing result. - if ((ret = bpf_map_update_elem(&routing_tuples_map, &tuples, &routing_result, - BPF_ANY))) { + if ((ret = bpf_map_update_elem(&routing_tuples_map, &tuples.five, + &routing_result, BPF_ANY))) { bpf_printk("shot save routing result: %d", ret); return TC_ACT_SHOT; } #if defined(__DEBUG_ROUTING) || defined(__PRINT_ROUTING_RESULT) if (l4proto == IPPROTO_TCP) { bpf_printk("tcp(lan): outbound: %u, target: %pI6:%u", ret, - tuples.dip.u6_addr32, bpf_ntohs(tuples.dport)); + tuples.five.dip.u6_addr32, bpf_ntohs(tuples.five.dport)); } else { bpf_printk("udp(lan): outbound: %u, target: %pI6:%u", - routing_result.outbound, tuples.dip.u6_addr32, - bpf_ntohs(tuples.dport)); + routing_result.outbound, tuples.five.dip.u6_addr32, + bpf_ntohs(tuples.five.dport)); } #endif if (routing_result.outbound == OUTBOUND_DIRECT) { @@ -1471,7 +1481,7 @@ new_connection: __u32 *alive; alive = bpf_map_lookup_elem(&outbound_connectivity_map, &q); if (alive && *alive == 0 && - !(l4proto == IPPROTO_UDP && tuples.dport == bpf_htons(53))) { + !(l4proto == IPPROTO_UDP && tuples.five.dport == bpf_htons(53))) { // Outbound is not alive. Dns is an exception. goto block; } @@ -1623,7 +1633,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) { if (!tproxy_port) { return TC_ACT_OK; } - bool tproxy_response = *tproxy_port == tuples.sport; + bool tproxy_response = *tproxy_port == tuples.five.sport; // Double check to avoid conflicts when binding wan and lan to the same // interface. if (tproxy_response && l4proto == IPPROTO_TCP) { @@ -1638,16 +1648,16 @@ int tproxy_wan_egress(struct __sk_buff *skb) { struct bpf_sock_tuple tuple = {0}; __u32 tuple_size; if (skb->protocol == bpf_htons(ETH_P_IP)) { - tuple.ipv4.daddr = tuples.dip.u6_addr32[3]; - tuple.ipv4.saddr = tuples.sip.u6_addr32[3]; - tuple.ipv4.dport = tuples.dport; - tuple.ipv4.sport = tuples.sport; + tuple.ipv4.daddr = tuples.five.dip.u6_addr32[3]; + tuple.ipv4.saddr = tuples.five.sip.u6_addr32[3]; + tuple.ipv4.dport = tuples.five.dport; + tuple.ipv4.sport = tuples.five.sport; tuple_size = sizeof(tuple.ipv4); } else { - __builtin_memcpy(tuple.ipv6.daddr, &tuples.dip, IPV6_BYTE_LENGTH); - __builtin_memcpy(tuple.ipv6.saddr, &tuples.sip, IPV6_BYTE_LENGTH); - tuple.ipv6.dport = tuples.dport; - tuple.ipv6.sport = tuples.sport; + __builtin_memcpy(tuple.ipv6.daddr, &tuples.five.dip, IPV6_BYTE_LENGTH); + __builtin_memcpy(tuple.ipv6.saddr, &tuples.five.sip, IPV6_BYTE_LENGTH); + tuple.ipv6.dport = tuples.five.dport; + tuple.ipv6.sport = tuples.five.sport; tuple_size = sizeof(tuple.ipv6); } struct bpf_sock *sk = @@ -1664,8 +1674,8 @@ int tproxy_wan_egress(struct __sk_buff *skb) { // Packets from tproxy port. // We need to redirect it to original port. - // bpf_printk("tproxy_response: %pI6:%u", tuples.dip.u6_addr32, - // bpf_ntohs(tuples.dport)); + // bpf_printk("tproxy_response: %pI6:%u", tuples.five.dip.u6_addr32, + // bpf_ntohs(tuples.five.dport)); // Write mac. if ((ret = bpf_skb_store_bytes(skb, offsetof(struct ethhdr, h_dest), @@ -1687,7 +1697,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) { __builtin_memset(&key_src, 0, sizeof(key_src)); // Use daddr as key in WAN because tproxy (control plane) also lookups the // map element using income client ip (that is daddr). - __builtin_memcpy(&key_src.ip, &tuples.dip, IPV6_BYTE_LENGTH); + __builtin_memcpy(&key_src.ip, &tuples.five.dip, IPV6_BYTE_LENGTH); key_src.port = tcph.source; __u8 outbound; bool must; @@ -1696,18 +1706,19 @@ 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[6] = {L4ProtoType_TCP}; // TCP + __u32 flag[8] = {L4ProtoType_TCP}; // TCP if (skb->protocol == bpf_htons(ETH_P_IP)) { flag[1] = IpVersionType_4; } else { flag[1] = IpVersionType_6; } - flag[3] = tuples.tos; + flag[6] = tuples.dscp; if (pid_is_control_plane(skb, &pid_pname)) { // From control plane. Direct. return TC_ACT_OK; } if (pid_pname) { + // 2, 3, 4, 5 __builtin_memcpy(&flag[2], pid_pname->pname, TASK_COMM_LEN); } __be32 mac[4] = { @@ -1718,8 +1729,8 @@ int tproxy_wan_egress(struct __sk_buff *skb) { (ethh.h_source[4] << 8) + (ethh.h_source[5])), }; __s64 s64_ret; - if ((s64_ret = route(flag, &tcph, tuples.sip.u6_addr32, - tuples.dip.u6_addr32, mac)) < 0) { + if ((s64_ret = route(flag, &tcph, tuples.five.sip.u6_addr32, + tuples.five.dip.u6_addr32, mac)) < 0) { bpf_printk("shot routing: %d", s64_ret); return TC_ACT_SHOT; } @@ -1731,10 +1742,10 @@ int tproxy_wan_egress(struct __sk_buff *skb) { #if defined(__DEBUG_ROUTING) || defined(__PRINT_ROUTING_RESULT) // Print only new connection. __u32 pid = pid_pname ? pid_pname->pid : 0; - bpf_printk("tcp(wan): from %pI6:%u [PID %u]", tuples.sip.u6_addr32, - bpf_ntohs(tuples.sport), pid); + bpf_printk("tcp(wan): from %pI6:%u [PID %u]", tuples.five.sip.u6_addr32, + bpf_ntohs(tuples.five.sport), pid); bpf_printk("tcp(wan): outbound: %u, %pI6:%u", outbound, - tuples.dip.u6_addr32, bpf_ntohs(tuples.dport)); + tuples.five.dip.u6_addr32, bpf_ntohs(tuples.five.dport)); #endif } else { // bpf_printk("[%X]Old Connection", bpf_ntohl(tcph.seq)); @@ -1768,7 +1779,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) { __u32 *alive; alive = bpf_map_lookup_elem(&outbound_connectivity_map, &q); if (alive && *alive == 0 && - !(l4proto == IPPROTO_UDP && tuples.dport == bpf_htons(53))) { + !(l4proto == IPPROTO_UDP && tuples.five.dport == bpf_htons(53))) { // Outbound is not alive. Dns is an exception. return TC_ACT_SHOT; } @@ -1776,12 +1787,12 @@ int tproxy_wan_egress(struct __sk_buff *skb) { if (unlikely(tcp_state_syn)) { struct dst_routing_result routing_info; __builtin_memset(&routing_info, 0, sizeof(routing_info)); - __builtin_memcpy(routing_info.ip, &tuples.dip, IPV6_BYTE_LENGTH); + __builtin_memcpy(routing_info.ip, &tuples.five.dip, IPV6_BYTE_LENGTH); routing_info.port = tcph.dest; 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; + routing_info.routing_result.dscp = tuples.dscp; __builtin_memcpy(routing_info.routing_result.mac, ethh.h_source, sizeof(ethh.h_source)); if (pid_pname) { @@ -1809,19 +1820,20 @@ int tproxy_wan_egress(struct __sk_buff *skb) { } else if (l4proto == IPPROTO_UDP) { // Routing. It decides if we redirect traffic to control plane. - __u32 flag[6] = {L4ProtoType_UDP}; + __u32 flag[8] = {L4ProtoType_UDP}; if (skb->protocol == bpf_htons(ETH_P_IP)) { flag[1] = IpVersionType_4; } else { flag[1] = IpVersionType_6; } - flag[3] = tuples.tos; + flag[6] = tuples.dscp; struct pid_pname *pid_pname; if (pid_is_control_plane(skb, &pid_pname)) { // From control plane. Direct. return TC_ACT_OK; } if (pid_pname) { + // 2, 3, 4, 5 __builtin_memcpy(&flag[2], pid_pname->pname, TASK_COMM_LEN); } __be32 mac[4] = { @@ -1832,21 +1844,21 @@ int tproxy_wan_egress(struct __sk_buff *skb) { (ethh.h_source[4] << 8) + (ethh.h_source[5])), }; __s64 s64_ret; - if ((s64_ret = route(flag, &udph, tuples.sip.u6_addr32, - tuples.dip.u6_addr32, mac)) < 0) { + if ((s64_ret = route(flag, &udph, tuples.five.sip.u6_addr32, + tuples.five.dip.u6_addr32, mac)) < 0) { bpf_printk("shot routing: %d", s64_ret); return TC_ACT_SHOT; } // Construct new hdr to encap. struct dst_routing_result new_hdr; __builtin_memset(&new_hdr, 0, sizeof(new_hdr)); - __builtin_memcpy(new_hdr.ip, &tuples.dip, IPV6_BYTE_LENGTH); + __builtin_memcpy(new_hdr.ip, &tuples.five.dip, IPV6_BYTE_LENGTH); new_hdr.port = udph.dest; new_hdr.recognize = RECOGNIZE; 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; + new_hdr.routing_result.dscp = tuples.dscp; __builtin_memcpy(new_hdr.routing_result.mac, ethh.h_source, sizeof(ethh.h_source)); if (pid_pname) { @@ -1856,11 +1868,11 @@ int tproxy_wan_egress(struct __sk_buff *skb) { } #if defined(__DEBUG_ROUTING) || defined(__PRINT_ROUTING_RESULT) __u32 pid = pid_pname ? pid_pname->pid : 0; - bpf_printk("udp(wan): from %pI6:%u [PID %u]", tuples.sip.u6_addr32, - bpf_ntohs(tuples.sport), pid); + bpf_printk("udp(wan): from %pI6:%u [PID %u]", tuples.five.sip.u6_addr32, + bpf_ntohs(tuples.five.sport), pid); bpf_printk("udp(wan): outbound: %u, %pI6:%u", - new_hdr.routing_result.outbound, tuples.dip.u6_addr32, - bpf_ntohs(tuples.dport)); + new_hdr.routing_result.outbound, tuples.five.dip.u6_addr32, + bpf_ntohs(tuples.five.dport)); #endif if (new_hdr.routing_result.outbound == OUTBOUND_DIRECT && @@ -1883,7 +1895,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) { __u32 *alive; alive = bpf_map_lookup_elem(&outbound_connectivity_map, &q); if (alive && *alive == 0 && - !(l4proto == IPPROTO_UDP && tuples.dport == bpf_htons(53))) { + !(l4proto == IPPROTO_UDP && tuples.five.dport == bpf_htons(53))) { // Outbound is not alive. Dns is an exception. return TC_ACT_SHOT; } @@ -1972,17 +1984,17 @@ int tproxy_wan_ingress(struct __sk_buff *skb) { if (!tproxy_port) { goto accept; } - if (unlikely(*tproxy_port == tuples.dport)) { + if (unlikely(*tproxy_port == tuples.five.dport)) { struct bpf_sock_tuple tuple = {0}; __u32 tuple_size; if (skb->protocol == bpf_htons(ETH_P_IP)) { - tuple.ipv4.daddr = tuples.dip.u6_addr32[3]; - tuple.ipv4.dport = tuples.dport; + tuple.ipv4.daddr = tuples.five.dip.u6_addr32[3]; + tuple.ipv4.dport = tuples.five.dport; tuple_size = sizeof(tuple.ipv4); } else { - __builtin_memcpy(tuple.ipv6.daddr, &tuples.dip, IPV6_BYTE_LENGTH); - tuple.ipv6.dport = tuples.dport; + __builtin_memcpy(tuple.ipv6.daddr, &tuples.five.dip, IPV6_BYTE_LENGTH); + tuple.ipv6.dport = tuples.five.dport; tuple_size = sizeof(tuple.ipv6); } @@ -2027,7 +2039,7 @@ int tproxy_wan_ingress(struct __sk_buff *skb) { __builtin_memset(&key_dst, 0, sizeof(key_dst)); // Use daddr as key in WAN because tproxy (control plane) also lookups the // map element using income client ip (that is daddr). - __builtin_memcpy(&key_dst.ip, &tuples.dip, IPV6_BYTE_LENGTH); + __builtin_memcpy(&key_dst.ip, &tuples.five.dip, IPV6_BYTE_LENGTH); key_dst.port = tcph.dest; struct dst_routing_result *original_dst = bpf_map_lookup_elem(&tcp_dst_map, &key_dst); @@ -2039,13 +2051,14 @@ int tproxy_wan_ingress(struct __sk_buff *skb) { // Rewrite sip and sport. if ((ret = rewrite_ip(skb, eth_h_len, IPPROTO_TCP, ihl, - tuples.sip.u6_addr32, original_dst->ip, false, + tuples.five.sip.u6_addr32, original_dst->ip, false, true))) { bpf_printk("Shot IP: %d", ret); return TC_ACT_SHOT; } - if ((ret = rewrite_port(skb, eth_h_len, IPPROTO_TCP, ihl, tuples.sport, - original_dst->port, false, true))) { + if ((ret = + rewrite_port(skb, eth_h_len, IPPROTO_TCP, ihl, tuples.five.sport, + original_dst->port, false, true))) { bpf_printk("Shot Port: %d", ret); return TC_ACT_SHOT; } @@ -2068,14 +2081,15 @@ int tproxy_wan_ingress(struct __sk_buff *skb) { // Rewrite udp src ip if ((ret = rewrite_ip(skb, eth_h_len, IPPROTO_UDP, ihl, - tuples.sip.u6_addr32, ori_src.ip, false, true))) { + tuples.five.sip.u6_addr32, ori_src.ip, false, + true))) { bpf_printk("Shot IP: %d", ret); return TC_ACT_SHOT; } // Rewrite udp src port - if ((ret = rewrite_port(skb, eth_h_len, IPPROTO_UDP, ihl, tuples.sport, - ori_src.port, false, true))) { + if ((ret = rewrite_port(skb, eth_h_len, IPPROTO_UDP, ihl, + tuples.five.sport, ori_src.port, false, true))) { bpf_printk("Shot Port: %d", ret); return TC_ACT_SHOT; } @@ -2091,8 +2105,9 @@ int tproxy_wan_ingress(struct __sk_buff *skb) { // } } // Rewrite dip to host ip. - if ((ret = rewrite_ip(skb, eth_h_len, l4proto, ihl, tuples.dip.u6_addr32, - tuples.sip.u6_addr32, true, true))) { + if ((ret = + rewrite_ip(skb, eth_h_len, l4proto, ihl, tuples.five.dip.u6_addr32, + tuples.five.sip.u6_addr32, true, true))) { bpf_printk("Shot IP: %d", ret); return TC_ACT_SHOT; } @@ -2101,7 +2116,7 @@ int tproxy_wan_ingress(struct __sk_buff *skb) { // Get tproxy ip and port. // saddr should be tproxy ip. - __be32 *tproxy_ip = tuples.sip.u6_addr32; + __be32 *tproxy_ip = tuples.five.sip.u6_addr32; // __builtin_memcpy(tproxy_ip, saddr, sizeof(tproxy_ip)); __be16 *tproxy_port = bpf_map_lookup_elem(¶m_map, &tproxy_port_key); if (!tproxy_port) { @@ -2110,14 +2125,14 @@ 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, eth_h_len, l4proto, ihl, tuples.dip.u6_addr32, - tproxy_ip, true, true))) { + if ((ret = rewrite_ip(skb, eth_h_len, l4proto, ihl, + tuples.five.dip.u6_addr32, tproxy_ip, true, true))) { bpf_printk("Shot IP: %d", ret); return TC_ACT_SHOT; } // Rewrite dst port. - if ((ret = rewrite_port(skb, eth_h_len, l4proto, ihl, tuples.dport, + if ((ret = rewrite_port(skb, eth_h_len, l4proto, ihl, tuples.five.dport, *tproxy_port, true, true))) { bpf_printk("Shot Port: %d", ret); return TC_ACT_SHOT; @@ -2125,8 +2140,9 @@ int tproxy_wan_ingress(struct __sk_buff *skb) { // (1) Use daddr as saddr to pass NIC verification. Notice that we do not // modify the so tproxy will send packet to it. - if ((ret = rewrite_ip(skb, eth_h_len, l4proto, ihl, tuples.sip.u6_addr32, - tuples.dip.u6_addr32, false, true))) { + if ((ret = + rewrite_ip(skb, eth_h_len, l4proto, ihl, tuples.five.sip.u6_addr32, + tuples.five.dip.u6_addr32, false, true))) { bpf_printk("Shot IP: %d", ret); return TC_ACT_SHOT; } diff --git a/control/routing_matcher_builder.go b/control/routing_matcher_builder.go index 06a8da1..85b8a12 100644 --- a/control/routing_matcher_builder.go +++ b/control/routing_matcher_builder.go @@ -44,7 +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_Dscp, routing.UintParserFactory(b.addDscp)) rulesBuilder.RegisterFunctionParser(consts.Function_IpVersion, routing.IpVersionParserFactory(b.addIpVersion)) if err = rulesBuilder.Apply(rules); err != nil { return nil, err @@ -276,7 +276,7 @@ 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) { +func (b *RoutingMatcherBuilder) addDscp(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 { @@ -287,7 +287,7 @@ func (b *RoutingMatcherBuilder) addTos(f *config_parser.Function, values []uint8 return err } matchSet := bpfMatchSet{ - Type: uint8(consts.MatchType_Tos), + Type: uint8(consts.MatchType_Dscp), Not: f.Not, Outbound: outboundId, Mark: outbound.Mark, diff --git a/control/routing_matcher_userspace.go b/control/routing_matcher_userspace.go index a1f36c2..7250bc1 100644 --- a/control/routing_matcher_userspace.go +++ b/control/routing_matcher_userspace.go @@ -93,7 +93,7 @@ func (m *RoutingMatcher) Match( if processName[0] != 0 && match.Value == processName { goodSubrule = true } - case consts.MatchType_Tos: + case consts.MatchType_Dscp: if tos == match.Value[0] { goodSubrule = true } diff --git a/control/tcp.go b/control/tcp.go index c9f43c4..ee6be13 100644 --- a/control/tcp.go +++ b/control/tcp.go @@ -83,6 +83,7 @@ destRetrieved: Domain: domain, Mac: routingResult.Mac, ProcessName: routingResult.Pname, + Dscp: routingResult.Dscp, Src: src, Dest: dst, Mark: routingResult.Mark, @@ -110,6 +111,7 @@ type RouteDialParam struct { Outbound consts.OutboundIndex Domain string Mac [6]uint8 + Dscp uint8 ProcessName [16]uint8 Src netip.AddrPort Dest netip.AddrPort @@ -119,9 +121,12 @@ type RouteDialParam struct { func (c *ControlPlane) RouteDialTcp(p *RouteDialParam) (conn netproxy.Conn, err error) { routingResult := &bpfRoutingResult{ Mark: p.Mark, + Must: 0, Mac: p.Mac, Outbound: uint8(p.Outbound), Pname: p.ProcessName, + Pid: 0, + Dscp: p.Dscp, } outboundIndex := consts.OutboundIndex(routingResult.Outbound) domain := p.Domain @@ -182,7 +187,7 @@ func (c *ControlPlane) RouteDialTcp(p *RouteDialParam) (conn netproxy.Conn, err "sniffed": domain, "ip": RefineAddrPortToShow(dst), "pid": routingResult.Pid, - "tos": routingResult.Tos, + "dscp": routingResult.Dscp, "pname": ProcessName2String(routingResult.Pname[:]), "mac": Mac2String(routingResult.Mac[:]), }).Infof("%v <-> %v", RefineSourceToShow(src, dst.Addr(), consts.LanWanFlag_NotApplicable), dialTarget) diff --git a/control/udp.go b/control/udp.go index a3a1f8e..27593f2 100644 --- a/control/udp.go +++ b/control/udp.go @@ -274,7 +274,7 @@ getNew: "to": realDst.String(), "domain": domain, "pid": routingResult.Pid, - "tos": routingResult.Tos, + "dscp": routingResult.Dscp, "pname": ProcessName2String(routingResult.Pname[:]), "mac": Mac2String(routingResult.Mac[:]), "from": realSrc.String(), @@ -299,7 +299,7 @@ getNew: "domain": domain, "ip": RefineAddrPortToShow(realDst), "pid": routingResult.Pid, - "tos": routingResult.Tos, + "dscp": routingResult.Dscp, "pname": ProcessName2String(routingResult.Pname[:]), "mac": Mac2String(routingResult.Mac[:]), } diff --git a/control/utils.go b/control/utils.go index 49c46eb..9fbd099 100644 --- a/control/utils.go +++ b/control/utils.go @@ -37,7 +37,7 @@ func (c *ControlPlane) Route(src, dst netip.AddrPort, domain string, l4proto con l4proto, domain, routingResult.Pname, - routingResult.Tos, + routingResult.Dscp, append([]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, routingResult.Mac[:]...), ); err != nil { return 0, 0, false, err @@ -50,7 +50,7 @@ func (c *controlPlaneCore) RetrieveRoutingResult(src, dst netip.AddrPort, l4prot srcIp6 := src.Addr().As16() dstIp6 := dst.Addr().As16() - tuples := &bpfTuples{ + tuples := &bpfTuplesKey{ Sip: struct{ U6Addr8 [16]uint8 }{U6Addr8: srcIp6}, Sport: common.Htons(src.Port()), Dip: struct{ U6Addr8 [16]uint8 }{U6Addr8: dstIp6}, diff --git a/docs/en/configuration/routing.md b/docs/en/configuration/routing.md index 6286295..d3af7bd 100644 --- a/docs/en/configuration/routing.md +++ b/docs/en/configuration/routing.md @@ -55,8 +55,8 @@ 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 +### DSCP rule (match DSCP; is useful for BT bypass). See https://github.com/daeuniverse/dae/discussions/295 +dscp(0x4) -> direct ### Multiple domains rule domain(keyword: google, suffix: www.twitter.com, suffix: v2raya.org) -> my_group diff --git a/docs/zh/configuration/routing.md b/docs/zh/configuration/routing.md index 0114f98..e20b31a 100644 --- a/docs/zh/configuration/routing.md +++ b/docs/zh/configuration/routing.md @@ -55,8 +55,8 @@ mac('02:42:ac:11:00:02') -> direct ### 进程名称规则(绑定WAN时仅支持本机进程) pname(curl) -> direct -### ToS规则(匹配 ToS 和 DSCP,可用于绕过 BT) -tos(4) -> direct +### DSCP规则(匹配 DSCP,可用于绕过 BT),见 https://github.com/daeuniverse/dae/discussions/295 +dscp(0x4) -> direct ### 多个域名规则 domain(keyword: google, suffix: www.twitter.com, suffix: v2raya.org) -> my_group diff --git a/go.mod b/go.mod index 4069e91..c923ab5 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/bits-and-blooms/bloom/v3 v3.5.0 github.com/cilium/ebpf v0.11.0 github.com/daeuniverse/dae-config-dist/go/dae_config v0.0.0-20230604120805-1c27619b592d - github.com/daeuniverse/softwind v0.0.0-20230809141237-cbe650b0e27c + github.com/daeuniverse/softwind v0.0.0-20230820153831-295ddb4d7a68 github.com/gorilla/websocket v1.5.0 github.com/json-iterator/go v1.1.12 github.com/miekg/dns v1.1.55 @@ -34,7 +34,7 @@ require ( github.com/golang/mock v1.6.0 // indirect github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect github.com/klauspost/compress v1.16.7 // indirect - github.com/mzz2017/quic-go v0.0.0-20230809140948-2ea096492e36 // indirect + github.com/mzz2017/quic-go v0.0.0-20230820052354-b1f9b30e2593 // indirect github.com/onsi/ginkgo/v2 v2.11.0 // indirect github.com/quic-go/qtls-go1-20 v0.3.1 // indirect golang.org/x/mod v0.12.0 // indirect @@ -67,7 +67,7 @@ require ( gitlab.com/yawning/chacha20.git v0.0.0-20230427033715-7877545b1b37 // indirect golang.org/x/term v0.10.0 // indirect golang.org/x/text v0.11.0 // indirect - google.golang.org/grpc v1.56.2 // indirect + google.golang.org/grpc v1.57.0 // indirect ) // replace github.com/daeuniverse/softwind => ../softwind diff --git a/go.sum b/go.sum index aefa017..bf33677 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,8 @@ github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUg github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/daeuniverse/dae-config-dist/go/dae_config v0.0.0-20230604120805-1c27619b592d h1:hnC39MjR7xt5kZjrKlef7DXKFDkiX8MIcDXYC/6Jf9Q= github.com/daeuniverse/dae-config-dist/go/dae_config v0.0.0-20230604120805-1c27619b592d/go.mod h1:VGWGgv7pCP5WGyHGUyb9+nq/gW0yBm+i/GfCNATOJ1M= -github.com/daeuniverse/softwind v0.0.0-20230809141237-cbe650b0e27c h1:CWSa7Jnmuz8pWjMi31wxbSC+cPDzk9eZ5UClZMC2uIc= -github.com/daeuniverse/softwind v0.0.0-20230809141237-cbe650b0e27c/go.mod h1:fL1IT5Qi5oZsrZwq38b4HYQH5AFe8XofpuukHQByTbM= +github.com/daeuniverse/softwind v0.0.0-20230820153831-295ddb4d7a68 h1:bEA1Y9Vzoppg3FEcE5YQwHY2mjX5hwK24n4oEM2dGD4= +github.com/daeuniverse/softwind v0.0.0-20230820153831-295ddb4d7a68/go.mod h1:msDwqsQcevrfE1YNMfREU1It2LJCYptgvdwhuQ194UY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -91,8 +91,8 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/mzz2017/disk-bloom v1.0.1 h1:rEF9MiXd9qMW3ibRpqcerLXULoTgRlM21yqqJl1B90M= github.com/mzz2017/disk-bloom v1.0.1/go.mod h1:JLHETtUu44Z6iBmsqzkOtFlRvXSlKnxjwiBRDapizDI= -github.com/mzz2017/quic-go v0.0.0-20230809140948-2ea096492e36 h1:ikWpUK6uyLmECHFDL/ZU3KA86l7eqIpDf3L46GA42jI= -github.com/mzz2017/quic-go v0.0.0-20230809140948-2ea096492e36/go.mod h1:DBA25b2LoPhrfSzOPE8KcDOicysx00qvvnqe0BpA8DQ= +github.com/mzz2017/quic-go v0.0.0-20230820052354-b1f9b30e2593 h1:WfhfXZs6AIZo1DhVoeExDIxDmT35tZJ0OaGgUKzPIgU= +github.com/mzz2017/quic-go v0.0.0-20230820052354-b1f9b30e2593/go.mod h1:DBA25b2LoPhrfSzOPE8KcDOicysx00qvvnqe0BpA8DQ= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -210,8 +210,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130 h1:2FZP5XuJY9zQyGM5N0rtovnoXjiMUEIUMvw0m9wlpLc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o= -google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= -google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=