From 00f1df66966c51f8a2a96475b3cd287e1bd3113f Mon Sep 17 00:00:00 2001 From: Markson Hon <50002150+MarksonHon@users.noreply.github.com> Date: Thu, 8 Aug 2024 00:58:26 +0800 Subject: [PATCH 01/16] fix(cmd/run.go): always check whether network online (#588) --- cmd/run.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/run.go b/cmd/run.go index a642079300..7e808c6a94 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -325,7 +325,7 @@ func newControlPlane(log *logrus.Logger, bpf interface{}, dnsCache map[string]*c } // Resolve subscriptions to nodes. resolvingfailed := false - if !conf.Global.DisableWaitingNetwork && len(conf.Subscription) > 0 { + if !conf.Global.DisableWaitingNetwork { epo := 5 * time.Second client := http.Client{ Transport: &http.Transport{ From 817e448d9e81f799f4cdc280f0b717baa9ea07ff Mon Sep 17 00:00:00 2001 From: 536wfr <4860575@qq.com> Date: Wed, 14 Aug 2024 21:42:35 +0800 Subject: [PATCH 02/16] chore(example.dae): add hy2 in comments (#605) --- example.dae | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/example.dae b/example.dae index 3f581cd1a0..e2ceeb12af 100644 --- a/example.dae +++ b/example.dae @@ -111,13 +111,14 @@ subscription { # Nodes defined here will be merged as a part of the global node pool. node { # Add your node links here. - # Support socks5, http, https, ss, ssr, vmess, vless, trojan, tuic, juicity, etc. + # Support socks5, http, https, ss, ssr, vmess, vless, trojan, tuic, juicity, hysteria2, etc. # Full support list: https://github.com/daeuniverse/dae/blob/main/docs/en/proxy-protocols.md 'socks5://localhost:1080' mylink: 'ss://LINK' node1: 'vmess://LINK' node2: 'vless://LINK' chains: 'tuic://LINK -> vmess://LINK' + hysteria2: 'hysteria2://password@server-ip:port/?sni=domain' } # See https://github.com/daeuniverse/dae/blob/main/docs/en/configuration/dns.md for full examples. From 5d473f9fb736e2e9d54cc1229fe684568ae76c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sumire=20=28=E8=8F=AB=29?= <151038614+sumire88@users.noreply.github.com> Date: Tue, 20 Aug 2024 23:18:36 -0400 Subject: [PATCH 03/16] chore(changelogs): add v0.7.1 release changelogs (#609) --- CHANGELOGS.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOGS.md b/CHANGELOGS.md index 58fab77455..a95be06716 100644 --- a/CHANGELOGS.md +++ b/CHANGELOGS.md @@ -14,8 +14,9 @@ curl --silent "https://api.github.com/repos/daeuniverse/dae/releases" | jq -r '. +- [v0.7.1 (Latest)](#v071-latest) - [v0.8.0rc1 (Pre-release)](#v080rc1-pre-release) -- [v0.7.0 (Latest)](#v070-latest) +- [v0.7.0](#v070) - [v0.6.0](#v060) - [v0.5.1](#v051) - [v0.5.0](#v050) @@ -41,6 +42,18 @@ curl --silent "https://api.github.com/repos/daeuniverse/dae/releases" | jq -r '. - [v0.1.0](#v010) +### v0.7.1 (Latest) + +> Release date: 2024/08/21 + +#### Bug Fixes + +- fix(cmd/run.go): always check whether network online (#588) +- fix(udp_task_pool): panic: close of closed channel (#570) +- fix: unknown tls implementation (#569) + +#### Bug Fixes + ### v0.8.0rc1 (Pre-release) > Release date: 2024/07/22 @@ -78,7 +91,7 @@ curl --silent "https://api.github.com/repos/daeuniverse/dae/releases" | jq -r '. **Full Changelog**: https://github.com/daeuniverse/dae/compare/v0.7.0...v0.8.0rc1 -### v0.7.0 (Latest) +### v0.7.0 > Release date: 2024/07/21 From 00d569f2988868efe2471b2da08c3538c21d3287 Mon Sep 17 00:00:00 2001 From: "./gray" Date: Sat, 24 Aug 2024 14:52:56 +0800 Subject: [PATCH 04/16] optimize(bpf): Alternative way to avoid parsing packet at dae0 (#600) --- control/kern/tproxy.c | 330 ++++++++++++++++++++---------------------- 1 file changed, 159 insertions(+), 171 deletions(-) diff --git a/control/kern/tproxy.c b/control/kern/tproxy.c index 63b32d88f7..1efcb70fa2 100644 --- a/control/kern/tproxy.c +++ b/control/kern/tproxy.c @@ -126,7 +126,6 @@ union ip6 { struct redirect_tuple { union ip6 sip; union ip6 dip; - __u8 l4proto; }; struct redirect_entry { @@ -413,16 +412,14 @@ static __always_inline __u8 ipv6_get_dscp(const struct ipv6hdr *ipv6h) } static __always_inline void -get_tuples(struct __sk_buff *skb, struct tuples *tuples, - const void *l3hdr, const void *l4hdr, - __u16 l3proto, __u8 l4proto) +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->five.l4proto = l4proto; - if (l3proto == bpf_htons(ETH_P_IP)) { - struct iphdr *iph = (struct iphdr *)l3hdr; - + if (skb->protocol == bpf_htons(ETH_P_IP)) { tuples->five.sip.u6_addr32[2] = bpf_htonl(0x0000ffff); tuples->five.sip.u6_addr32[3] = iph->saddr; @@ -432,8 +429,6 @@ get_tuples(struct __sk_buff *skb, struct tuples *tuples, tuples->dscp = ipv4_get_dscp(iph); } else { - struct ipv6hdr *ipv6h = (struct ipv6hdr *)l3hdr; - __builtin_memcpy(&tuples->five.dip, &ipv6h->daddr, IPV6_BYTE_LENGTH); __builtin_memcpy(&tuples->five.sip, &ipv6h->saddr, @@ -442,13 +437,9 @@ get_tuples(struct __sk_buff *skb, struct tuples *tuples, tuples->dscp = ipv6_get_dscp(ipv6h); } if (l4proto == IPPROTO_TCP) { - struct tcphdr *tcph = (struct tcphdr *)l4hdr; - tuples->five.sport = tcph->source; tuples->five.dport = tcph->dest; } else { - struct udphdr *udph = (struct udphdr *)l4hdr; - tuples->five.sport = udph->source; tuples->five.dport = udph->dest; } @@ -467,13 +458,14 @@ static __always_inline bool equal16(const __be32 x[4], const __be32 y[4]) } static __always_inline int -handle_ipv6_extensions(void *data, void *data_end, - __u32 offset, __u32 hdr, - void **l4hdr, __u8 *ihl, __u8 *l4proto) +handle_ipv6_extensions(const struct __sk_buff *skb, __u32 offset, __u32 hdr, + struct icmp6hdr *icmp6h, struct tcphdr *tcph, + struct udphdr *udph, __u8 *ihl, __u8 *l4proto) { __u8 hdr_length = 0; __u8 nexthdr = 0; *ihl = sizeof(struct ipv6hdr) / 4; + int ret; // We only process TCP and UDP traffic. // Unroll can give less instructions but more memory consumption when loading. @@ -493,48 +485,53 @@ handle_ipv6_extensions(void *data, void *data_end, *l4proto = hdr; hdr_length = sizeof(struct icmp6hdr); // Assume ICMPV6 as a level 4 protocol. - *l4hdr = data + offset; - if (*l4hdr + hdr_length > data_end) + ret = bpf_skb_load_bytes(skb, offset, icmp6h, + hdr_length); + if (ret) { + bpf_printk("not a valid IPv6 packet"); return -EFAULT; - + } return 0; case IPPROTO_HOPOPTS: case IPPROTO_ROUTING: - *l4hdr = data + offset; - struct ipv6_opt_hdr *opt_hdr = (struct ipv6_opt_hdr *)*l4hdr; - - if (opt_hdr + 1 > (struct ipv6_opt_hdr *)data_end) + ret = bpf_skb_load_bytes(skb, offset + 1, &hdr_length, + sizeof(hdr_length)); + if (ret) { + bpf_printk("not a valid IPv6 packet"); return -EFAULT; + } - hdr_length = opt_hdr->hdrlen; - nexthdr = opt_hdr->nexthdr; - +special_n1: + ret = bpf_skb_load_bytes(skb, offset, &nexthdr, + sizeof(nexthdr)); + if (ret) { + bpf_printk("not a valid IPv6 packet"); + return -EFAULT; + } break; case IPPROTO_FRAGMENT: hdr_length = 4; - *l4hdr = data + offset; - opt_hdr = (struct ipv6_opt_hdr *)*l4hdr; - if (opt_hdr + 1 > (struct ipv6_opt_hdr *)data_end) - return -EFAULT; - - nexthdr = opt_hdr->nexthdr; - - break; + goto special_n1; case IPPROTO_TCP: case IPPROTO_UDP: *l4proto = hdr; if (hdr == IPPROTO_TCP) { // Upper layer; - *l4hdr = data + offset; - if (*l4hdr + sizeof(struct tcphdr) > data_end) + ret = bpf_skb_load_bytes(skb, offset, tcph, + sizeof(struct tcphdr)); + if (ret) { + bpf_printk("not a valid IPv6 packet"); return -EFAULT; - + } } else if (hdr == IPPROTO_UDP) { // Upper layer; - *l4hdr = data + offset; - if (*l4hdr + sizeof(struct udphdr) > data_end) + ret = bpf_skb_load_bytes(skb, offset, udph, + sizeof(struct udphdr)); + if (ret) { + bpf_printk("not a valid IPv6 packet"); return -EFAULT; + } } else { // Unknown hdr. bpf_printk("Unexpected hdr."); @@ -552,43 +549,44 @@ handle_ipv6_extensions(void *data, void *data_end, } static __always_inline int -parse_transport(struct __sk_buff *skb, __u32 link_h_len, - struct ethhdr *ethh, void **l3hdr, void **l4hdr, - __u8 *ihl, __u16 *l3proto, __u8 *l4proto) +parse_transport(const struct __sk_buff *skb, __u32 link_h_len, + struct ethhdr *ethh, struct iphdr *iph, struct ipv6hdr *ipv6h, + struct icmp6hdr *icmp6h, struct tcphdr *tcph, + struct udphdr *udph, __u8 *ihl, __u8 *l4proto) { __u32 offset = 0; - - if (bpf_skb_pull_data(skb, skb->len)) - return -EFAULT; - - void *data = (void *)(long)skb->data; - void *data_end = (void *)(long)skb->data_end; + int ret; if (link_h_len == ETH_HLEN) { - if (bpf_skb_load_bytes(skb, 0, ethh, sizeof(*ethh))) + ret = bpf_skb_load_bytes(skb, offset, ethh, + sizeof(struct ethhdr)); + if (ret) { + bpf_printk("not ethernet packet"); return 1; - + } // Skip ethhdr for next hdr. offset += sizeof(struct ethhdr); - *l3proto = ethh->h_proto; } else { - *l3proto = skb->protocol; + __builtin_memset(ethh, 0, sizeof(struct ethhdr)); ethh->h_proto = skb->protocol; } *ihl = 0; *l4proto = 0; + __builtin_memset(iph, 0, sizeof(struct iphdr)); + __builtin_memset(ipv6h, 0, sizeof(struct ipv6hdr)); + __builtin_memset(icmp6h, 0, sizeof(struct icmp6hdr)); + __builtin_memset(tcph, 0, sizeof(struct tcphdr)); + __builtin_memset(udph, 0, sizeof(struct udphdr)); // bpf_printk("parse_transport: h_proto: %u ? %u %u", ethh->h_proto, // bpf_htons(ETH_P_IP), // bpf_htons(ETH_P_IPV6)); - if (*l3proto == bpf_htons(ETH_P_IP)) { - *l3hdr = data + offset; - struct iphdr *iph = (struct iphdr *)*l3hdr; - - if (iph + 1 > (struct iphdr *)data_end) + if (ethh->h_proto == bpf_htons(ETH_P_IP)) { + ret = bpf_skb_load_bytes(skb, offset, iph, + sizeof(struct iphdr)); + if (ret) return -EFAULT; - // Skip ipv4hdr and options for next hdr. offset += iph->ihl * 4; @@ -596,31 +594,38 @@ parse_transport(struct __sk_buff *skb, __u32 link_h_len, *l4proto = iph->protocol; switch (iph->protocol) { case IPPROTO_TCP: { - *l4hdr = data + offset; - if (*l4hdr + sizeof(struct tcphdr) > data_end) + ret = bpf_skb_load_bytes(skb, offset, tcph, + sizeof(struct tcphdr)); + if (ret) { + // Not a complete tcphdr. return -EFAULT; + } } break; case IPPROTO_UDP: { - *l4hdr = data + offset; - if (*l4hdr + sizeof(struct udphdr) > data_end) + ret = bpf_skb_load_bytes(skb, offset, udph, + sizeof(struct udphdr)); + if (ret) { + // Not a complete udphdr. return -EFAULT; + } } break; default: return 1; } *ihl = iph->ihl; return 0; - } else if (*l3proto == bpf_htons(ETH_P_IPV6)) { - *l3hdr = data + offset; - struct ipv6hdr *ipv6h = (struct ipv6hdr *)*l3hdr; - - if (ipv6h + 1 > (struct ipv6hdr *)data_end) + } else if (ethh->h_proto == bpf_htons(ETH_P_IPV6)) { + ret = bpf_skb_load_bytes(skb, offset, ipv6h, + sizeof(struct ipv6hdr)); + if (ret) { + bpf_printk("not a valid IPv6 packet"); return -EFAULT; + } offset += sizeof(struct ipv6hdr); - return handle_ipv6_extensions(data, data_end, offset, ipv6h->nexthdr, - l4hdr, ihl, l4proto); + return handle_ipv6_extensions(skb, offset, ipv6h->nexthdr, + icmp6h, tcph, udph, ihl, l4proto); } else { /// EXPECTED: Maybe ICMP, MPLS, etc. // bpf_printk("IP but not supported packet: protocol is %u", @@ -931,11 +936,24 @@ static __always_inline int assign_listener(struct __sk_buff *skb, __u8 l4proto) static __always_inline void prep_redirect_to_control_plane( struct __sk_buff *skb, __u32 link_h_len, struct tuples *tuples, - __u16 l3proto, __u8 l4proto, struct ethhdr *ethh, __u8 from_wan, bool tcp_state_syn) + __u8 l4proto, struct ethhdr *ethh, __u8 from_wan, struct tcphdr *tcph) { + /* Redirect from L3 dev to L2 dev, e.g. wg0 -> veth */ + if (!link_h_len) { + __u16 l3proto = skb->protocol; + + bpf_skb_change_head(skb, sizeof(struct ethhdr), 0); + bpf_skb_store_bytes(skb, offsetof(struct ethhdr, h_proto), + &l3proto, sizeof(l3proto), 0); + } + + bpf_skb_store_bytes(skb, offsetof(struct ethhdr, h_dest), + (void *)&PARAM.dae0peer_mac, sizeof(ethh->h_dest), + 0); + struct redirect_tuple redirect_tuple = {}; - if (l3proto == bpf_htons(ETH_P_IP)) { + if (skb->protocol == bpf_htons(ETH_P_IP)) { redirect_tuple.sip.u6_addr32[3] = tuples->five.sip.u6_addr32[3]; redirect_tuple.dip.u6_addr32[3] = tuples->five.dip.u6_addr32[3]; } else { @@ -944,7 +962,6 @@ static __always_inline void prep_redirect_to_control_plane( __builtin_memcpy(&redirect_tuple.dip, &tuples->five.dip, IPV6_BYTE_LENGTH); } - redirect_tuple.l4proto = l4proto; struct redirect_entry redirect_entry = {}; redirect_entry.ifindex = skb->ifindex; @@ -958,22 +975,8 @@ static __always_inline void prep_redirect_to_control_plane( skb->cb[0] = TPROXY_MARK; skb->cb[1] = 0; - if ((l4proto == IPPROTO_TCP && tcp_state_syn) || - l4proto == IPPROTO_UDP) + if ((l4proto == IPPROTO_TCP && tcph->syn) || l4proto == IPPROTO_UDP) skb->cb[1] = l4proto; - - /* Redirect from L3 dev to L2 dev, e.g. wg0 -> veth */ - if (!link_h_len) { - __u16 l3proto = skb->protocol; - - bpf_skb_change_head(skb, sizeof(struct ethhdr), 0); - bpf_skb_store_bytes(skb, offsetof(struct ethhdr, h_proto), - &l3proto, sizeof(l3proto), 0); - } - - bpf_skb_store_bytes(skb, offsetof(struct ethhdr, h_dest), - (void *)&PARAM.dae0peer_mac, sizeof(ethh->h_dest), - 0); } SEC("tc/egress") @@ -982,28 +985,27 @@ int tproxy_lan_egress(struct __sk_buff *skb) if (skb->ingress_ifindex != NOWHERE_IFINDEX) return TC_ACT_PIPE; - struct ethhdr ethh = {}; - void *l3hdr; - void *l4hdr; + struct ethhdr ethh; + struct iphdr iph; + struct ipv6hdr ipv6h; + struct icmp6hdr icmp6h; + struct tcphdr tcph; + struct udphdr udph; __u8 ihl; __u8 l4proto; - __u16 l3proto; __u32 link_h_len; if (get_link_h_len(skb->ifindex, &link_h_len)) return TC_ACT_OK; - int ret = parse_transport(skb, link_h_len, - ðh, &l3hdr, &l4hdr, - &ihl, &l3proto, &l4proto); + int ret = parse_transport(skb, link_h_len, ðh, &iph, &ipv6h, &icmp6h, + &tcph, &udph, &ihl, &l4proto); if (ret) { bpf_printk("parse_transport: %d", ret); return TC_ACT_OK; } - if (l4proto == IPPROTO_ICMPV6) { - struct icmp6hdr *icmp6h = (struct icmp6hdr *)l4hdr; - - if (icmp6h->icmp6_type == NDP_REDIRECT) - return TC_ACT_SHOT; + if (l4proto == IPPROTO_ICMPV6 && icmp6h.icmp6_type == NDP_REDIRECT) { + // REDIRECT (NDP) + return TC_ACT_SHOT; } return TC_ACT_PIPE; } @@ -1011,20 +1013,20 @@ int tproxy_lan_egress(struct __sk_buff *skb) SEC("tc/ingress") int tproxy_lan_ingress(struct __sk_buff *skb) { - struct ethhdr ethh = {}; - void *l3hdr; - void *l4hdr; + struct ethhdr ethh; + struct iphdr iph; + struct ipv6hdr ipv6h; + struct icmp6hdr icmp6h; + struct tcphdr tcph; + struct udphdr udph; __u8 ihl; __u8 l4proto; - __u16 l3proto; __u32 link_h_len; if (get_link_h_len(skb->ifindex, &link_h_len)) return TC_ACT_OK; - bool tcp_state_syn = false; - int ret = parse_transport(skb, link_h_len, - ðh, &l3hdr, &l4hdr, - &ihl, &l3proto, &l4proto); + int ret = parse_transport(skb, link_h_len, ðh, &iph, &ipv6h, &icmp6h, + &tcph, &udph, &ihl, &l4proto); if (ret) { bpf_printk("parse_transport: %d", ret); return TC_ACT_OK; @@ -1035,7 +1037,7 @@ int tproxy_lan_ingress(struct __sk_buff *skb) // Prepare five tuples. struct tuples tuples; - get_tuples(skb, &tuples, l3hdr, l4hdr, l3proto, l4proto); + get_tuples(skb, &tuples, &iph, &ipv6h, &tcph, &udph, l4proto); /* * ip rule add fwmark 0x8000000/0x8000000 table 2023 @@ -1053,8 +1055,9 @@ int tproxy_lan_ingress(struct __sk_buff *skb) __u32 tuple_size; struct bpf_sock *sk; __u32 flag[8]; + void *l4hdr; - if (l3proto == bpf_htons(ETH_P_IP)) { + if (skb->protocol == bpf_htons(ETH_P_IP)) { tuple.ipv4.daddr = tuples.five.dip.u6_addr32[3]; tuple.ipv4.saddr = tuples.five.sip.u6_addr32[3]; tuple.ipv4.dport = tuples.five.dport; @@ -1072,10 +1075,7 @@ int tproxy_lan_ingress(struct __sk_buff *skb) if (l4proto == IPPROTO_TCP) { // TCP. - struct tcphdr *tcph = (struct tcphdr *)l4hdr; - - tcp_state_syn = tcph->syn && !tcph->ack; - if (tcp_state_syn) + if (tcph.syn && !tcph.ack) goto new_connection; sk = bpf_skc_lookup_tcp(skb, &tuple, tuple_size, @@ -1093,16 +1093,18 @@ int tproxy_lan_ingress(struct __sk_buff *skb) new_connection: __builtin_memset(flag, 0, sizeof(flag)); if (l4proto == IPPROTO_TCP) { - if (!tcp_state_syn) { + if (!(tcph.syn && !tcph.ack)) { // Not a new TCP connection. // Perhaps single-arm. return TC_ACT_OK; } + l4hdr = &tcph; flag[0] = L4ProtoType_TCP; } else { + l4hdr = &udph; flag[0] = L4ProtoType_UDP; } - if (l3proto == bpf_htons(ETH_P_IP)) + if (skb->protocol == bpf_htons(ETH_P_IP)) flag[1] = IpVersionType_4; else flag[1] = IpVersionType_6; @@ -1171,7 +1173,7 @@ int tproxy_lan_ingress(struct __sk_buff *skb) struct outbound_connectivity_query q = { 0 }; q.outbound = routing_result.outbound; - q.ipversion = l3proto == bpf_htons(ETH_P_IP) ? 4 : 6; + q.ipversion = skb->protocol == bpf_htons(ETH_P_IP) ? 4 : 6; q.l4proto = l4proto; __u32 *alive; @@ -1184,8 +1186,8 @@ int tproxy_lan_ingress(struct __sk_buff *skb) // Assign to control plane. control_plane: - prep_redirect_to_control_plane(skb, link_h_len, &tuples, l3proto, l4proto, ðh, - 0, tcp_state_syn); + prep_redirect_to_control_plane(skb, link_h_len, &tuples, l4proto, ðh, + 0, &tcph); return bpf_redirect(PARAM.dae0_ifindex, 0); direct: @@ -1304,19 +1306,20 @@ refresh_udp_conn_state_timer(struct tuples_key *key, bool is_egress) SEC("tc/wan_ingress") int tproxy_wan_ingress(struct __sk_buff *skb) { - struct ethhdr ethh = {}; - void *l3hdr; - void *l4hdr; + struct ethhdr ethh; + struct iphdr iph; + struct ipv6hdr ipv6h; + struct icmp6hdr icmp6h; + struct tcphdr tcph; + struct udphdr udph; __u8 ihl; __u8 l4proto; - __u16 l3proto; __u32 link_h_len; if (get_link_h_len(skb->ifindex, &link_h_len)) return TC_ACT_OK; - int ret = parse_transport(skb, link_h_len, - ðh, &l3hdr, &l4hdr, - &ihl, &l3proto, &l4proto); + int ret = parse_transport(skb, link_h_len, ðh, &iph, &ipv6h, &icmp6h, + &tcph, &udph, &ihl, &l4proto); if (ret) return TC_ACT_OK; if (l4proto != IPPROTO_UDP) @@ -1325,7 +1328,7 @@ int tproxy_wan_ingress(struct __sk_buff *skb) struct tuples tuples; struct tuples_key reversed_tuples_key; - get_tuples(skb, &tuples, l3hdr, l4hdr, l3proto, l4proto); + get_tuples(skb, &tuples, &iph, &ipv6h, &tcph, &udph, l4proto); copy_reversed_tuples(&tuples.five, &reversed_tuples_key); if (!refresh_udp_conn_state_timer(&reversed_tuples_key, false)) @@ -1346,20 +1349,21 @@ int tproxy_wan_egress(struct __sk_buff *skb) // return TC_ACT_OK; // } - struct ethhdr ethh = {}; - void *l3hdr; - void *l4hdr; + struct ethhdr ethh; + struct iphdr iph; + struct ipv6hdr ipv6h; + struct icmp6hdr icmp6h; + struct tcphdr tcph; + struct udphdr udph; __u8 ihl; __u8 l4proto; - __u16 l3proto; __u32 link_h_len; if (get_link_h_len(skb->ifindex, &link_h_len)) return TC_ACT_OK; - bool tcp_state_syn = false; - int ret = parse_transport(skb, link_h_len, - ðh, &l3hdr, &l4hdr, - &ihl, &l3proto, &l4proto); + bool tcp_state_syn; + int ret = parse_transport(skb, link_h_len, ðh, &iph, &ipv6h, &icmp6h, + &tcph, &udph, &ihl, &l4proto); if (ret) return TC_ACT_OK; if (l4proto == IPPROTO_ICMPV6) @@ -1368,14 +1372,12 @@ int tproxy_wan_egress(struct __sk_buff *skb) // Backup for further use. struct tuples tuples; - get_tuples(skb, &tuples, l3hdr, l4hdr, l3proto, l4proto); + get_tuples(skb, &tuples, &iph, &ipv6h, &tcph, &udph, l4proto); // Normal packets. if (l4proto == IPPROTO_TCP) { // Backup for further use. - struct tcphdr *tcph = (struct tcphdr *)l4hdr; - - tcp_state_syn = tcph->syn && !tcph->ack; + tcp_state_syn = tcph.syn && !tcph.ack; __u8 outbound; bool must; __u32 mark; @@ -1386,7 +1388,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) // bpf_printk("[%X]New Connection", bpf_ntohl(tcph.seq)); __u32 flag[8] = { L4ProtoType_TCP }; // TCP - if (l3proto == bpf_htons(ETH_P_IP)) + if (skb->protocol == bpf_htons(ETH_P_IP)) flag[1] = IpVersionType_4; else flag[1] = IpVersionType_6; @@ -1412,7 +1414,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) }; __s64 s64_ret; - s64_ret = route(flag, l4hdr, tuples.five.sip.u6_addr32, + s64_ret = route(flag, &tcph, tuples.five.sip.u6_addr32, tuples.five.dip.u6_addr32, mac); if (s64_ret < 0) { bpf_printk("shot routing: %d", s64_ret); @@ -1464,7 +1466,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) struct outbound_connectivity_query q = { 0 }; q.outbound = outbound; - q.ipversion = l3proto == bpf_htons(ETH_P_IP) ? 4 : 6; + q.ipversion = skb->protocol == bpf_htons(ETH_P_IP) ? 4 : 6; q.l4proto = l4proto; __u32 *alive; @@ -1499,7 +1501,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) // Routing. It decides if we redirect traffic to control plane. __u32 flag[8] = { L4ProtoType_UDP }; - if (l3proto == bpf_htons(ETH_P_IP)) + if (skb->protocol == bpf_htons(ETH_P_IP)) flag[1] = IpVersionType_4; else flag[1] = IpVersionType_6; @@ -1537,7 +1539,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) }; __s64 s64_ret; - s64_ret = route(flag, l4hdr, tuples.five.sip.u6_addr32, + s64_ret = route(flag, &udph, tuples.five.sip.u6_addr32, tuples.five.dip.u6_addr32, mac); if (s64_ret < 0) { bpf_printk("shot routing: %d", s64_ret); @@ -1587,7 +1589,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) struct outbound_connectivity_query q = { 0 }; q.outbound = routing_result.outbound; - q.ipversion = l3proto == bpf_htons(ETH_P_IP) ? 4 : 6; + q.ipversion = skb->protocol == bpf_htons(ETH_P_IP) ? 4 : 6; q.l4proto = l4proto; __u32 *alive; @@ -1600,8 +1602,8 @@ int tproxy_wan_egress(struct __sk_buff *skb) } } - prep_redirect_to_control_plane(skb, link_h_len, &tuples, l3proto, l4proto, ðh, - 1, tcp_state_syn); + prep_redirect_to_control_plane(skb, link_h_len, &tuples, l4proto, ðh, + 1, &tcph); return bpf_redirect(PARAM.dae0_ifindex, 0); } @@ -1633,36 +1635,22 @@ int tproxy_dae0peer_ingress(struct __sk_buff *skb) SEC("tc/dae0_ingress") int tproxy_dae0_ingress(struct __sk_buff *skb) { - struct ethhdr ethh = {}; - void *l3hdr; - void *l4hdr; - __u8 ihl; - __u8 l4proto; - __u16 l3proto; - __u32 link_h_len = 14; - - int ret = parse_transport(skb, link_h_len, - ðh, &l3hdr, &l4hdr, - &ihl, &l3proto, &l4proto); - if (ret) - return TC_ACT_OK; - struct tuples tuples; - - get_tuples(skb, &tuples, l3hdr, l4hdr, l3proto, l4proto); - // reverse the tuple! struct redirect_tuple redirect_tuple = {}; - if (l3proto == bpf_htons(ETH_P_IP)) { - redirect_tuple.sip.u6_addr32[3] = tuples.five.dip.u6_addr32[3]; - redirect_tuple.dip.u6_addr32[3] = tuples.five.sip.u6_addr32[3]; + if (skb->protocol == bpf_htons(ETH_P_IP)) { + bpf_skb_load_bytes(skb, ETH_HLEN + offsetof(struct iphdr, daddr), + &redirect_tuple.sip.u6_addr32[3], + sizeof(redirect_tuple.sip.u6_addr32[3])); + bpf_skb_load_bytes(skb, ETH_HLEN + offsetof(struct iphdr, saddr), + &redirect_tuple.dip.u6_addr32[3], + sizeof(redirect_tuple.dip.u6_addr32[3])); } else { - __builtin_memcpy(&redirect_tuple.sip, &tuples.five.dip, - IPV6_BYTE_LENGTH); - __builtin_memcpy(&redirect_tuple.dip, &tuples.five.sip, - IPV6_BYTE_LENGTH); + bpf_skb_load_bytes(skb, ETH_HLEN + offsetof(struct ipv6hdr, daddr), + &redirect_tuple.sip, sizeof(redirect_tuple.sip)); + bpf_skb_load_bytes(skb, ETH_HLEN + offsetof(struct ipv6hdr, saddr), + &redirect_tuple.dip, sizeof(redirect_tuple.dip)); } - redirect_tuple.l4proto = l4proto; struct redirect_entry *redirect_entry = bpf_map_lookup_elem(&redirect_track, &redirect_tuple); From ee272f72c6c9fe30d56d2159c151126ee6d39867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sumire=20=28=E8=8F=AB=29?= <151038614+sumire88@users.noreply.github.com> Date: Mon, 26 Aug 2024 08:36:08 -0400 Subject: [PATCH 05/16] ci: add trigger-downstream-flake-sync workflow (#612) --- .../trigger-downstream-flake-sync.yml | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .github/workflows/trigger-downstream-flake-sync.yml diff --git a/.github/workflows/trigger-downstream-flake-sync.yml b/.github/workflows/trigger-downstream-flake-sync.yml new file mode 100644 index 0000000000..640092dbb9 --- /dev/null +++ b/.github/workflows/trigger-downstream-flake-sync.yml @@ -0,0 +1,49 @@ +# _ +# __| | __ _ ___ +# / _` |/ _` |/ _ \ +# | (_| | (_| | __/ +# \__,_|\__,_|\___| +# +# Copyright (C) 2024 @daeuniverse +# +# This is a open-source software, liscensed under the AGPL-3.0 License. +# See /License for more information. + +--- +name: Trigger downstream sync workflow + +on: + workflow_dispatch: + push: + branches: + - 'main' + +env: + DOWNSTREAM_REPO: flake.nix + WORKFLOW_BRANCH: unstable + WORKFLOW_FILE: sync-upstream.yml + +jobs: + dispatch-downstream-workflow: + runs-on: ubuntu-latest + steps: + - name: Generate GitHub auth token + # https://github.com/tibdex/github-app-token + id: generate_token + uses: tibdex/github-app-token@v2.1.0 + with: + app_id: ${{ secrets.GH_APP_ID }} + private_key: ${{ secrets.GH_APP_PRIVATE_KEY }} + + - name: Dispatch + uses: convictional/trigger-workflow-and-wait@v1.6.5 + with: + owner: ${{ github.repository_owner }} + repo: ${{ env.DOWNSTREAM_REPO }} + github_token: ${{ steps.generate_token.outputs.token }} + workflow_file_name: ${{ env.WORKFLOW_FILE }} + ref: ${{ env.WORKFLOW_BRANCH }} + client_payload: '{"project":"${{ env.DOWNSTREAM_REPO }}","branch":"${{ env.WORKFLOW_BRANCH }}"}' + trigger_workflow: true + propagate_failure: false + wait_workflow: false From 0fd25ad5b0f6e1ff492715ef0d1a34125fbc2498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sumire=20=28=E8=8F=AB=29?= <151038614+sumire88@users.noreply.github.com> Date: Mon, 26 Aug 2024 09:20:29 -0400 Subject: [PATCH 06/16] ci/fix(trigger-downstream-flake-sync): update dispatch target (#613) --- .github/workflows/trigger-downstream-flake-sync.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/trigger-downstream-flake-sync.yml b/.github/workflows/trigger-downstream-flake-sync.yml index 640092dbb9..2a16174168 100644 --- a/.github/workflows/trigger-downstream-flake-sync.yml +++ b/.github/workflows/trigger-downstream-flake-sync.yml @@ -43,7 +43,7 @@ jobs: github_token: ${{ steps.generate_token.outputs.token }} workflow_file_name: ${{ env.WORKFLOW_FILE }} ref: ${{ env.WORKFLOW_BRANCH }} - client_payload: '{"project":"${{ env.DOWNSTREAM_REPO }}","branch":"${{ env.WORKFLOW_BRANCH }}"}' + client_payload: '{"project":"dae","branch":"${{ env.WORKFLOW_BRANCH }}"}' trigger_workflow: true propagate_failure: false wait_workflow: false From 18b657083f36510bed9af4dbfec89de4dce2e382 Mon Sep 17 00:00:00 2001 From: ston Date: Tue, 27 Aug 2024 09:48:10 +0800 Subject: [PATCH 07/16] docs: update persistent script (#603) --- docs/en/user-guide/persistent-subscription.md | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/docs/en/user-guide/persistent-subscription.md b/docs/en/user-guide/persistent-subscription.md index eba4176324..bffaf07f7b 100644 --- a/docs/en/user-guide/persistent-subscription.md +++ b/docs/en/user-guide/persistent-subscription.md @@ -21,23 +21,34 @@ We assume that your dae configuration file is stored in `/usr/local/etc/dae/` . cd /usr/local/etc/dae || exit 1 version="$(dae --version | head -n 1 | sed 's/dae version //')" UA="dae/${version} (like v2rayA/1.0 WebRequestHelper) (like v2rayN/1.0 WebRequestHelper)" +fail=false + while IFS=':' read -r name url do - curl -fL -A "$UA" "$url" -o "${name}.sub.new" - if [[ $? -eq 0 ]]; then - mv "${name}.sub.new" "${name}.sub" - chmod 0600 "${name}.sub" - echo "Downloaded $name" - else - rm "${name}.sub.new" - echo "Failed to download $name" - fi + curl --retry 3 --retry-delay 5 -fL -A "$UA" "$url" -o "${name}.sub.new" + if [[ $? -eq 0 ]]; then + mv "${name}.sub.new" "${name}.sub" + chmod 0600 "${name}.sub" + echo "Downloaded $name" + else + if [ -f "${name}.sub.new" ]; then + rm "${name}.sub.new" + fi + fail=true + echo "Failed to download $name" + fi done < sublist dae reload + +if $fail; then + echo "Failed to update some subs" + exit 2 +fi ``` You need to give it proper permission: + ```sh chmod +x /usr/local/bin/update-dae-subs.sh ``` @@ -71,6 +82,7 @@ After=network-online.target [Service] Type=oneshot ExecStart=/usr/local/bin/update-dae-subs.sh +Restart=on-failure ``` ## Configurations From c5b596c293fdceddc47e4ba6870d058fcbcedc9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=8B=E9=87=8E=E3=81=8B=E3=81=88=E3=81=A7?= Date: Tue, 27 Aug 2024 09:49:51 +0800 Subject: [PATCH 08/16] feat: add MPTCP support (#601) --- cmd/run.go | 4 ++-- common/utils.go | 5 +++-- component/outbound/dialer/connectivity_check.go | 10 ++++++---- config/config.go | 1 + config/desc.go | 1 + control/control_plane.go | 11 +++++++---- control/dns_control.go | 5 +++-- control/tcp.go | 2 +- control/udp.go | 2 +- example.dae | 4 ++++ go.mod | 7 +++---- go.sum | 15 +++------------ 12 files changed, 35 insertions(+), 32 deletions(-) diff --git a/cmd/run.go b/cmd/run.go index 7e808c6a94..f7dde16e62 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -331,7 +331,7 @@ func newControlPlane(log *logrus.Logger, bpf interface{}, dnsCache map[string]*c Transport: &http.Transport{ DialContext: func(ctx context.Context, network, addr string) (c net.Conn, err error) { cd := netproxy.ContextDialerConverter{Dialer: direct.SymmetricDirect} - conn, err := cd.DialContext(ctx, common.MagicNetwork("tcp", conf.Global.SoMarkFromDae), addr) + conn, err := cd.DialContext(ctx, common.MagicNetwork("tcp", conf.Global.SoMarkFromDae, conf.Global.Mptcp), addr) if err != nil { return nil, err } @@ -373,7 +373,7 @@ func newControlPlane(log *logrus.Logger, bpf interface{}, dnsCache map[string]*c Transport: &http.Transport{ DialContext: func(ctx context.Context, network, addr string) (c net.Conn, err error) { cd := netproxy.ContextDialerConverter{Dialer: direct.SymmetricDirect} - conn, err := cd.DialContext(ctx, common.MagicNetwork("tcp", conf.Global.SoMarkFromDae), addr) + conn, err := cd.DialContext(ctx, common.MagicNetwork("tcp", conf.Global.SoMarkFromDae, conf.Global.Mptcp), addr) if err != nil { return nil, err } diff --git a/common/utils.go b/common/utils.go index 350195b675..0d9ce794f2 100644 --- a/common/utils.go +++ b/common/utils.go @@ -469,13 +469,14 @@ nextLink: return Deduplicate(defaultIfs), nil } -func MagicNetwork(network string, mark uint32) string { - if mark == 0 { +func MagicNetwork(network string, mark uint32, mptcp bool) string { + if mark == 0 && !mptcp { return network } else { return netproxy.MagicNetwork{ Network: network, Mark: mark, + Mptcp: mptcp, }.Encode() } } diff --git a/component/outbound/dialer/connectivity_check.go b/component/outbound/dialer/connectivity_check.go index 3cb8f1e0bb..9e478a6666 100644 --- a/component/outbound/dialer/connectivity_check.go +++ b/component/outbound/dialer/connectivity_check.go @@ -282,8 +282,10 @@ func (d *Dialer) ActivateCheck() { func (d *Dialer) aliveBackground() { cycle := d.CheckInterval var tcpSomark uint32 + var mptcp bool if network, err := netproxy.ParseMagicNetwork(d.TcpCheckOptionRaw.ResolverNetwork); err == nil { tcpSomark = network.Mark + mptcp = network.Mptcp } tcp4CheckOpt := &CheckOption{ networkType: &NetworkType{ @@ -304,7 +306,7 @@ func (d *Dialer) aliveBackground() { }).Debugln("Skip check due to no DNS record.") return false, nil } - return d.HttpCheck(ctx, opt.Url, opt.Ip4, opt.Method, tcpSomark) + return d.HttpCheck(ctx, opt.Url, opt.Ip4, opt.Method, tcpSomark, mptcp) }, } tcp6CheckOpt := &CheckOption{ @@ -326,7 +328,7 @@ func (d *Dialer) aliveBackground() { }).Debugln("Skip check due to no DNS record.") return false, nil } - return d.HttpCheck(ctx, opt.Url, opt.Ip6, opt.Method, tcpSomark) + return d.HttpCheck(ctx, opt.Url, opt.Ip6, opt.Method, tcpSomark, mptcp) }, } tcpNetwork := netproxy.MagicNetwork{ @@ -580,7 +582,7 @@ func (d *Dialer) Check(opts *CheckOption) (ok bool, err error) { return ok, err } -func (d *Dialer) HttpCheck(ctx context.Context, u *netutils.URL, ip netip.Addr, method string, soMark uint32) (ok bool, err error) { +func (d *Dialer) HttpCheck(ctx context.Context, u *netutils.URL, ip netip.Addr, method string, soMark uint32, mptcp bool) (ok bool, err error) { // HTTP(S) check. if method == "" { method = http.MethodGet @@ -590,7 +592,7 @@ func (d *Dialer) HttpCheck(ctx context.Context, u *netutils.URL, ip netip.Addr, Transport: &http.Transport{ DialContext: func(ctx context.Context, network, addr string) (c net.Conn, err error) { // Force to dial "ip". - conn, err := cd.DialContext(ctx, common.MagicNetwork("tcp", soMark), net.JoinHostPort(ip.String(), u.Port())) + conn, err := cd.DialContext(ctx, common.MagicNetwork("tcp", soMark, mptcp), net.JoinHostPort(ip.String(), u.Port())) if err != nil { return nil, err } diff --git a/config/config.go b/config/config.go index 0c21515173..873278d701 100644 --- a/config/config.go +++ b/config/config.go @@ -42,6 +42,7 @@ type Global struct { TlsImplementation string `mapstructure:"tls_implementation" default:"tls"` UtlsImitate string `mapstructure:"utls_imitate" default:"chrome_auto"` PprofPort uint16 `mapstructure:"pprof_port" default:"0"` + Mptcp bool `mapstructure:"mptcp" default:"false"` } type Utls struct { diff --git a/config/desc.go b/config/desc.go index fad148a4e7..2440527cbc 100644 --- a/config/desc.go +++ b/config/desc.go @@ -57,6 +57,7 @@ var GlobalDesc = Desc{ "sniffing_timeout": "Timeout to waiting for first data sending for sniffing. It is always 0 if dial_mode is ip. Set it higher is useful in high latency LAN network.", "tls_implementation": "TLS implementation. \"tls\" is to use Go's crypto/tls. \"utls\" is to use uTLS, which can imitate browser's Client Hello.", "utls_imitate": "The Client Hello ID for uTLS to imitate. This takes effect only if tls_implementation is utls. See more: https://github.com/daeuniverse/dae/blob/331fa23c16/component/outbound/transport/tls/utls.go#L17", + "mptcp": "Enable Multipath TCP. If is true, dae will try to use MPTCP to connect all nodes, but it will only take effects when the node supports MPTCP. It can use for load balance and failover to multiple interfaces and IPs.", } var DnsDesc = Desc{ diff --git a/control/control_plane.go b/control/control_plane.go index 0e640f0904..5cc190853c 100644 --- a/control/control_plane.go +++ b/control/control_plane.go @@ -75,6 +75,7 @@ type ControlPlane struct { sniffingTimeout time.Duration tproxyPortProtect bool soMarkFromDae uint32 + mptcp bool } func NewControlPlane( @@ -261,8 +262,8 @@ func NewControlPlane( TlsImplementation: global.TlsImplementation, UtlsImitate: global.UtlsImitate}, Log: log, - TcpCheckOptionRaw: dialer.TcpCheckOptionRaw{Raw: global.TcpCheckUrl, Log: log, ResolverNetwork: common.MagicNetwork("udp", global.SoMarkFromDae), Method: global.TcpCheckHttpMethod}, - CheckDnsOptionRaw: dialer.CheckDnsOptionRaw{Raw: global.UdpCheckDns, ResolverNetwork: common.MagicNetwork("udp", global.SoMarkFromDae), Somark: global.SoMarkFromDae}, + TcpCheckOptionRaw: dialer.TcpCheckOptionRaw{Raw: global.TcpCheckUrl, Log: log, ResolverNetwork: common.MagicNetwork("udp", global.SoMarkFromDae, global.Mptcp), Method: global.TcpCheckHttpMethod}, + CheckDnsOptionRaw: dialer.CheckDnsOptionRaw{Raw: global.UdpCheckDns, ResolverNetwork: common.MagicNetwork("udp", global.SoMarkFromDae, global.Mptcp), Somark: global.SoMarkFromDae}, CheckInterval: global.CheckInterval, CheckTolerance: global.CheckTolerance, CheckDnsTcp: true, @@ -395,6 +396,7 @@ func NewControlPlane( sniffingTimeout: sniffingTimeout, tproxyPortProtect: global.TproxyPortProtect, soMarkFromDae: global.SoMarkFromDae, + mptcp: global.Mptcp, } defer func() { if err != nil { @@ -407,7 +409,7 @@ func NewControlPlane( Logger: log, LocationFinder: locationFinder, UpstreamReadyCallback: plane.dnsUpstreamReadyCallback, - UpstreamResolverNetwork: common.MagicNetwork("udp", global.SoMarkFromDae), + UpstreamResolverNetwork: common.MagicNetwork("udp", global.SoMarkFromDae, global.Mptcp), }) if err != nil { return nil, err @@ -620,7 +622,7 @@ func (c *ControlPlane) ChooseDialTarget(outbound consts.OutboundIndex, dst netip // TODO: use DNS controller and re-route by control plane. systemDns, err := netutils.SystemDns() if err == nil { - if ip46, err := netutils.ResolveIp46(ctx, direct.SymmetricDirect, systemDns, domain, common.MagicNetwork("udp", c.soMarkFromDae), true); err == nil && (ip46.Ip4.IsValid() || ip46.Ip6.IsValid()) { + if ip46, err := netutils.ResolveIp46(ctx, direct.SymmetricDirect, systemDns, domain, common.MagicNetwork("udp", c.soMarkFromDae, c.mptcp), true); err == nil && (ip46.Ip4.IsValid() || ip46.Ip6.IsValid()) { // Has A/AAAA records. It is a real domain. dialMode = consts.DialMode_Domain // Add it to real-domain set. @@ -938,6 +940,7 @@ func (c *ControlPlane) chooseBestDnsDialer( bestOutbound: bestOutbound, bestTarget: bestTarget, mark: dialMark, + mptcp: c.mptcp, }, nil } diff --git a/control/dns_control.go b/control/dns_control.go index 6ff705452c..8b41c309d2 100644 --- a/control/dns_control.go +++ b/control/dns_control.go @@ -344,6 +344,7 @@ type dialArgument struct { bestOutbound *outbound.DialerGroup bestTarget netip.AddrPort mark uint32 + mptcp bool } func (c *DnsController) Handle_(dnsMessage *dnsmessage.Msg, req *udpRequest) (err error) { @@ -570,7 +571,7 @@ func (c *DnsController) dialSend(invokingDepth int, req *udpRequest, data []byte // TODO: connection pool. conn, err = bestContextDialer.DialContext( ctxDial, - common.MagicNetwork("udp", dialArgument.mark), + common.MagicNetwork("udp", dialArgument.mark, dialArgument.mptcp), dialArgument.bestTarget.String(), ) if err != nil { @@ -633,7 +634,7 @@ func (c *DnsController) dialSend(invokingDepth int, req *udpRequest, data []byte case consts.L4ProtoStr_TCP: // We can block here because we are in a coroutine. - conn, err = bestContextDialer.DialContext(ctxDial, common.MagicNetwork("tcp", dialArgument.mark), dialArgument.bestTarget.String()) + conn, err = bestContextDialer.DialContext(ctxDial, common.MagicNetwork("tcp", dialArgument.mark, dialArgument.mptcp), dialArgument.bestTarget.String()) if err != nil { return fmt.Errorf("failed to dial proxy to tcp: %w", err) } diff --git a/control/tcp.go b/control/tcp.go index dd99cd052f..9796a8e4bd 100644 --- a/control/tcp.go +++ b/control/tcp.go @@ -165,7 +165,7 @@ func (c *ControlPlane) RouteDialTcp(p *RouteDialParam) (conn netproxy.Conn, err cd := netproxy.ContextDialerConverter{ Dialer: d, } - return cd.DialContext(ctx, common.MagicNetwork("tcp", routingResult.Mark), dialTarget) + return cd.DialContext(ctx, common.MagicNetwork("tcp", routingResult.Mark, c.mptcp), dialTarget) } type WriteCloser interface { diff --git a/control/udp.go b/control/udp.go index 638ce93a3d..5f3b459685 100644 --- a/control/udp.go +++ b/control/udp.go @@ -250,7 +250,7 @@ getNew: Target: dialTarget, Dialer: dialerForNew, Outbound: outbound, - Network: common.MagicNetwork("udp", routingResult.Mark), + Network: common.MagicNetwork("udp", routingResult.Mark, c.mptcp), SniffedDomain: domain, }, nil }, diff --git a/example.dae b/example.dae index e2ceeb12af..e1814e2b86 100644 --- a/example.dae +++ b/example.dae @@ -96,6 +96,10 @@ global { # The Client Hello ID for uTLS to imitate. This takes effect only if tls_implementation is utls. # See more: https://github.com/daeuniverse/dae/blob/331fa23c16/component/outbound/transport/tls/utls.go#L17 utls_imitate: chrome_auto + + # Multipath TCP (MPTCP) support. If is true, dae will try to use MPTCP to connect all nodes, but it will only take + # effects when the node supports MPTCP. It can use for load balance and failover to multiple interfaces and IPs. + mptcp: false } # Subscriptions defined here will be resolved as nodes and merged as a part of the global node pool. diff --git a/go.mod b/go.mod index 7e393173d9..405e731c05 100644 --- a/go.mod +++ b/go.mod @@ -8,13 +8,15 @@ require ( github.com/bits-and-blooms/bloom/v3 v3.5.0 github.com/cilium/ebpf v0.12.3 github.com/daeuniverse/dae-config-dist/go/dae_config v0.0.0-20230604120805-1c27619b592d - github.com/daeuniverse/outbound v0.0.0-20240628165628-7c0c217530ea + github.com/daeuniverse/outbound v0.0.0-20240807173909-1bac5b52e542 github.com/fsnotify/fsnotify v1.7.0 github.com/json-iterator/go v1.1.12 + github.com/mholt/archiver/v3 v3.5.1 github.com/miekg/dns v1.1.55 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 github.com/okzk/sdnotify v0.0.0-20180710141335-d9becc38acbd github.com/safchain/ethtool v0.3.0 + github.com/shirou/gopsutil/v4 v4.24.5 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 github.com/v2rayA/ahocorasick-domain v0.0.0-20231231085011-99ceb8ef3208 @@ -43,14 +45,11 @@ require ( github.com/gorilla/websocket v1.5.0 // indirect github.com/klauspost/compress v1.17.4 // indirect github.com/klauspost/pgzip v1.2.5 // indirect - github.com/mholt/archiver/v3 v3.5.1 // indirect github.com/nwaples/rardecode v1.1.0 // indirect github.com/onsi/ginkgo/v2 v2.11.0 // indirect github.com/pierrec/lz4/v4 v4.1.2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/shirou/gopsutil/v4 v4.24.5 // indirect - github.com/stretchr/testify v1.9.0 // indirect github.com/ulikunitz/xz v0.5.9 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect diff --git a/go.sum b/go.sum index d35af8738d..db7bec1642 100644 --- a/go.sum +++ b/go.sum @@ -23,8 +23,8 @@ github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBS 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/outbound v0.0.0-20240628165628-7c0c217530ea h1:mQwAcoKHR/AVsajoEpP/NSYL8nBTuP+kw7l2+xWM4xE= -github.com/daeuniverse/outbound v0.0.0-20240628165628-7c0c217530ea/go.mod h1:z0vJ5ZlLErX8WTruVeOuGr+1KOhSFcaPzEhZMAYfPdA= +github.com/daeuniverse/outbound v0.0.0-20240807173909-1bac5b52e542 h1:hL3E0XKvBvVmjNJrRDsI7SnmZmiery12f6/7b+kBILw= +github.com/daeuniverse/outbound v0.0.0-20240807173909-1bac5b52e542/go.mod h1:z0vJ5ZlLErX8WTruVeOuGr+1KOhSFcaPzEhZMAYfPdA= github.com/daeuniverse/quic-go v0.0.0-20240413031024-943f218e0810 h1:YtEYouFaNrg9sV9vf3UabvKShKn6sD0QaCdOxCwaF3g= github.com/daeuniverse/quic-go v0.0.0-20240413031024-943f218e0810/go.mod h1:61o2uZUGLrlv1i+oO2rx9sVX0vbf8cHzdSHt7h6lMnM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -77,9 +77,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 h1:n6vlPhxsA+BW/XsS5+uqi7GyzaLa5MH7qlSLBZtRdiA= github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= @@ -166,17 +165,11 @@ github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRM github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg= @@ -244,8 +237,6 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= From c8856614c52913e944a01465ed239e228aea0508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AF=A5ID=E6=9A=82=E6=97=A0=E6=98=B5=E7=A7=B0?= Date: Tue, 3 Sep 2024 18:38:21 +0800 Subject: [PATCH 09/16] feat: support ipip tunnel as lan/wan interface (#615) --- control/control_plane_core.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control/control_plane_core.go b/control/control_plane_core.go index ab84170c41..40b907ded0 100644 --- a/control/control_plane_core.go +++ b/control/control_plane_core.go @@ -142,7 +142,7 @@ func (c *controlPlaneCore) mapLinkType(ifname string) error { } var linkHdrLen uint32 switch link.Attrs().EncapType { - case "none": + case "none", "ipip": linkHdrLen = consts.LinkHdrLen_None case "ether": linkHdrLen = consts.LinkHdrLen_Ethernet From 9f04adfe161e2a4b94e8b0569e8f7e165fc8fa4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A5=9E=E6=A5=BD=E5=9D=82=C2=B7=E5=96=B5?= Date: Sun, 8 Sep 2024 22:13:06 +0800 Subject: [PATCH 10/16] feat: allow group override global node connectivity check (#623) Co-authored-by: mzz2017 <2017@duck.com> --- .../outbound/dialer/connectivity_check.go | 13 ++++ component/outbound/dialer/dialer.go | 25 ++++++++ config/config.go | 6 ++ config/desc.go | 5 ++ control/control_plane.go | 60 ++++++++++++++----- example.dae | 20 +++++++ 6 files changed, 115 insertions(+), 14 deletions(-) diff --git a/component/outbound/dialer/connectivity_check.go b/component/outbound/dialer/connectivity_check.go index 9e478a6666..4d330e38b3 100644 --- a/component/outbound/dialer/connectivity_check.go +++ b/component/outbound/dialer/connectivity_check.go @@ -19,6 +19,7 @@ import ( "strings" "sync" "time" + "unsafe" "github.com/daeuniverse/dae/common" @@ -452,6 +453,18 @@ func (d *Dialer) aliveBackground() { } } }() + var unused int + for _, opt := range CheckOpts { + if len(d.mustGetCollection(opt.networkType).AliveDialerSetSet) == 0 { + unused++ + } + } + if unused == len(CheckOpts) { + d.Log.WithField("dialer", d.Property().Name). + WithField("p", unsafe.Pointer(d)). + Traceln("cleaned up due to unused") + return + } var wg sync.WaitGroup for range d.checkCh { for _, opt := range CheckOpts { diff --git a/component/outbound/dialer/dialer.go b/component/outbound/dialer/dialer.go index 5d08706084..5be577cec0 100644 --- a/component/outbound/dialer/dialer.go +++ b/component/outbound/dialer/dialer.go @@ -10,7 +10,10 @@ import ( "fmt" "sync" "time" + "unsafe" + "github.com/daeuniverse/dae/common" + "github.com/daeuniverse/dae/config" D "github.com/daeuniverse/outbound/dialer" "github.com/daeuniverse/outbound/netproxy" "github.com/sirupsen/logrus" @@ -60,6 +63,21 @@ type Property struct { type AliveDialerSetSet map[*AliveDialerSet]int +func NewGlobalOption(global *config.Global, log *logrus.Logger) *GlobalOption { + return &GlobalOption{ + ExtraOption: D.ExtraOption{ + AllowInsecure: global.AllowInsecure, + TlsImplementation: global.TlsImplementation, + UtlsImitate: global.UtlsImitate}, + Log: log, + TcpCheckOptionRaw: TcpCheckOptionRaw{Raw: global.TcpCheckUrl, Log: log, ResolverNetwork: common.MagicNetwork("udp", global.SoMarkFromDae, global.Mptcp), Method: global.TcpCheckHttpMethod}, + CheckDnsOptionRaw: CheckDnsOptionRaw{Raw: global.UdpCheckDns, ResolverNetwork: common.MagicNetwork("udp", global.SoMarkFromDae, global.Mptcp), Somark: global.SoMarkFromDae}, + CheckInterval: global.CheckInterval, + CheckTolerance: global.CheckTolerance, + CheckDnsTcp: true, + } +} + // NewDialer is for register in general. func NewDialer(dialer netproxy.Dialer, option *GlobalOption, iOption InstanceOption, property *Property) *Dialer { var collections [6]*collection @@ -80,9 +98,16 @@ func NewDialer(dialer netproxy.Dialer, option *GlobalOption, iOption InstanceOpt ctx: ctx, cancel: cancel, } + option.Log.WithField("dialer", d.Property().Name). + WithField("p", unsafe.Pointer(d)). + Traceln("NewDialer") return d } +func (d *Dialer) Clone() *Dialer { + return NewDialer(d.Dialer, d.GlobalOption, d.InstanceOption, d.property) +} + func (d *Dialer) Close() error { d.cancel() d.tickerMu.Lock() diff --git a/config/config.go b/config/config.go index 873278d701..85c2434bc8 100644 --- a/config/config.go +++ b/config/config.go @@ -89,6 +89,12 @@ type Group struct { Filter [][]*config_parser.Function `mapstructure:"filter" repeatable:""` FilterAnnotation [][]*config_parser.Param `mapstructure:"_"` Policy FunctionListOrString `mapstructure:"policy" required:""` + + TcpCheckUrl []string `mapstructure:"tcp_check_url"` + TcpCheckHttpMethod string `mapstructure:"tcp_check_http_method"` + UdpCheckDns []string `mapstructure:"udp_check_dns"` + CheckInterval time.Duration `mapstructure:"check_interval"` + CheckTolerance time.Duration `mapstructure:"check_tolerance"` } type DnsRequestRouting struct { diff --git a/config/desc.go b/config/desc.go index 2440527cbc..121bf6cbac 100644 --- a/config/desc.go +++ b/config/desc.go @@ -85,4 +85,9 @@ min: Select node by the latency of last check. min_avg10: Select node by the average of latencies of last 10 checks. min_moving_avg: Select node by the moving average of latencies of checks, which means more recent latencies have higher weight. `, + "tcp_check_url": "Override global config.", + "tcp_check_http_method": "Override global config.", + "udp_check_dns": "Override global config.", + "check_interval": "Override global config.", + "check_tolerance": "Override global config.", } diff --git a/control/control_plane.go b/control/control_plane.go index 5cc190853c..5da9691841 100644 --- a/control/control_plane.go +++ b/control/control_plane.go @@ -33,7 +33,6 @@ import ( "github.com/daeuniverse/dae/config" "github.com/daeuniverse/dae/pkg/config_parser" internal "github.com/daeuniverse/dae/pkg/ebpf_internal" - D "github.com/daeuniverse/outbound/dialer" "github.com/daeuniverse/outbound/pool" "github.com/daeuniverse/outbound/protocol/direct" "github.com/daeuniverse/outbound/transport/grpc" @@ -256,18 +255,7 @@ func NewControlPlane( if global.AllowInsecure { log.Warnln("AllowInsecure is enabled, but it is not recommended. Please make sure you have to turn it on.") } - option := &dialer.GlobalOption{ - ExtraOption: D.ExtraOption{ - AllowInsecure: global.AllowInsecure, - TlsImplementation: global.TlsImplementation, - UtlsImitate: global.UtlsImitate}, - Log: log, - TcpCheckOptionRaw: dialer.TcpCheckOptionRaw{Raw: global.TcpCheckUrl, Log: log, ResolverNetwork: common.MagicNetwork("udp", global.SoMarkFromDae, global.Mptcp), Method: global.TcpCheckHttpMethod}, - CheckDnsOptionRaw: dialer.CheckDnsOptionRaw{Raw: global.UdpCheckDns, ResolverNetwork: common.MagicNetwork("udp", global.SoMarkFromDae, global.Mptcp), Somark: global.SoMarkFromDae}, - CheckInterval: global.CheckInterval, - CheckTolerance: global.CheckTolerance, - CheckDnsTcp: true, - } + option := dialer.NewGlobalOption(global, log) // Dial mode. dialMode, err := consts.ParseDialMode(global.DialMode) @@ -323,8 +311,22 @@ func NewControlPlane( if len(dialers) == 0 { log.Infoln("\t") } + groupOption, err := ParseGroupOverrideOption(group, *global, log) + finalOption := option + if err == nil && groupOption != nil { + newDialers := make([]*dialer.Dialer, 0) + for _, d := range dialers { + newDialer := d.Clone() + deferFuncs = append(deferFuncs, newDialer.Close) + newDialer.GlobalOption = groupOption + newDialers = append(newDialers, newDialer) + } + log.Infof(`Group "%v"'s check option has been override.`, group.Name) + dialers = newDialers + finalOption = groupOption + } // Create dialer group and append it to outbounds. - dialerGroup := outbound.NewDialerGroup(option, group.Name, dialers, annos, *policy, + dialerGroup := outbound.NewDialerGroup(finalOption, group.Name, dialers, annos, *policy, core.outboundAliveChangeCallback(uint8(len(outbounds)), disableKernelAliveCallback)) outbounds = append(outbounds, dialerGroup) } @@ -515,6 +517,36 @@ func ParseFixedDomainTtl(ks []config.KeyableString) (map[string]int, error) { return m, nil } +func ParseGroupOverrideOption(group config.Group, global config.Global, log *logrus.Logger) (*dialer.GlobalOption, error) { + result := global + changed := false + if group.TcpCheckUrl != nil { + result.TcpCheckUrl = group.TcpCheckUrl + changed = true + } + if group.TcpCheckHttpMethod != "" { + result.TcpCheckHttpMethod = group.TcpCheckHttpMethod + changed = true + } + if group.UdpCheckDns != nil { + result.UdpCheckDns = group.UdpCheckDns + changed = true + } + if group.CheckInterval != 0 { + result.CheckInterval = group.CheckInterval + changed = true + } + if group.CheckTolerance != 0 { + result.CheckTolerance = group.CheckTolerance + changed = true + } + if changed { + option := dialer.NewGlobalOption(&result, log) + return option, nil + } + return nil, nil +} + // EjectBpf will resect bpf from destroying life-cycle of control plane. func (c *ControlPlane) EjectBpf() *bpfObjects { return c.core.EjectBpf() diff --git a/example.dae b/example.dae index e1814e2b86..b894c35f8e 100644 --- a/example.dae +++ b/example.dae @@ -40,6 +40,7 @@ global { auto_config_kernel_parameter: true ##### Node connectivity check. + # These options, as defaults, are effective when no definition is given in the group. # Host of URL should have both IPv4 and IPv6 if you have double stack in local. # First is URL, others are IP addresses if given. @@ -213,6 +214,24 @@ group { # Select the node with min average of the last 10 latencies from the group for every connection. policy: min_avg10 } + + steam { + # Filter nodes from the global node pool defined by the subscription and node section above. + filter: subtag(my_sub) && !name(keyword: 'ExpireAt:') + # Select the node with min moving average of latencies from the group for every connection. + policy: min_moving_avg + + # Override tcp_check_url in global. + tcp_check_url: 'http://test.steampowered.com' + # Override tcp_check_http_method in global + #tcp_check_http_method: HEAD + # Override udp_check_dns in global + #udp_check_dns: 'dns.google.com:53,8.8.8.8,2001:4860:4860::8888' + # Override check_interval in global + #check_interval: 30s + # Override check_tolerance in global + #check_tolerance: 50ms + } } # See https://github.com/daeuniverse/dae/blob/main/docs/en/configuration/routing.md for full examples. @@ -238,6 +257,7 @@ routing { l4proto(udp) && dport(443) -> block dip(geoip:cn) -> direct domain(geosite:cn) -> direct + fallback: my_group } From d8fad755979e87fdb448eead497a650a18a23cf1 Mon Sep 17 00:00:00 2001 From: mzz <2017@duck.com> Date: Thu, 12 Sep 2024 12:50:33 +0800 Subject: [PATCH 11/16] feat(dialer): support reality (without udp support) (#573) --- control/tcp.go | 2 ++ go.mod | 18 +++++++++--------- go.sum | 40 ++++++++++++++++++++-------------------- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/control/tcp.go b/control/tcp.go index 9796a8e4bd..acdb14bfc5 100644 --- a/control/tcp.go +++ b/control/tcp.go @@ -65,6 +65,8 @@ func (c *ControlPlane) handleConn(lConn net.Conn) (err error) { switch { case strings.HasSuffix(err.Error(), "write: broken pipe"), strings.HasSuffix(err.Error(), "i/o timeout"), + strings.HasPrefix(err.Error(), "EOF"), + strings.HasSuffix(err.Error(), "connection reset by peer"), strings.HasSuffix(err.Error(), "canceled by local with error code 0"), strings.HasSuffix(err.Error(), "canceled by remote with error code 0"): return nil // ignore diff --git a/go.mod b/go.mod index 405e731c05..efac4b5acf 100644 --- a/go.mod +++ b/go.mod @@ -8,11 +8,11 @@ require ( github.com/bits-and-blooms/bloom/v3 v3.5.0 github.com/cilium/ebpf v0.12.3 github.com/daeuniverse/dae-config-dist/go/dae_config v0.0.0-20230604120805-1c27619b592d - github.com/daeuniverse/outbound v0.0.0-20240807173909-1bac5b52e542 + github.com/daeuniverse/outbound v0.0.0-20240911144232-d470a59233a5 github.com/fsnotify/fsnotify v1.7.0 github.com/json-iterator/go v1.1.12 github.com/mholt/archiver/v3 v3.5.1 - github.com/miekg/dns v1.1.55 + github.com/miekg/dns v1.1.58 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 github.com/okzk/sdnotify v0.0.0-20180710141335-d9becc38acbd github.com/safchain/ethtool v0.3.0 @@ -23,10 +23,10 @@ require ( github.com/vishvananda/netlink v1.1.0 github.com/vishvananda/netns v0.0.4 github.com/x-cray/logrus-prefixed-formatter v0.5.2 - golang.org/x/crypto v0.18.0 - golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691 + golang.org/x/crypto v0.21.0 + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 golang.org/x/sys v0.20.0 - google.golang.org/protobuf v1.31.0 + google.golang.org/protobuf v1.33.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) @@ -54,9 +54,9 @@ require ( github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.uber.org/mock v0.4.0 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.20.0 // indirect - golang.org/x/tools v0.11.0 // indirect + golang.org/x/mod v0.15.0 // indirect + golang.org/x/net v0.22.0 // indirect + golang.org/x/tools v0.18.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 // indirect ) @@ -82,7 +82,7 @@ require ( github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb // indirect github.com/spf13/pflag v1.0.5 // indirect gitlab.com/yawning/chacha20.git v0.0.0-20230427033715-7877545b1b37 // indirect - golang.org/x/term v0.16.0 // indirect + golang.org/x/term v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/grpc v1.57.0 // indirect ) diff --git a/go.sum b/go.sum index db7bec1642..9ce53b8557 100644 --- a/go.sum +++ b/go.sum @@ -23,8 +23,8 @@ github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBS 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/outbound v0.0.0-20240807173909-1bac5b52e542 h1:hL3E0XKvBvVmjNJrRDsI7SnmZmiery12f6/7b+kBILw= -github.com/daeuniverse/outbound v0.0.0-20240807173909-1bac5b52e542/go.mod h1:z0vJ5ZlLErX8WTruVeOuGr+1KOhSFcaPzEhZMAYfPdA= +github.com/daeuniverse/outbound v0.0.0-20240911144232-d470a59233a5 h1:L450vqT1TO+Ygzd8buBMna8d4/0asT0q74qitGTWSl4= +github.com/daeuniverse/outbound v0.0.0-20240911144232-d470a59233a5/go.mod h1:0dkFMC58MVUWMB19jwQuXEg1G16uAIAtdAU7v+yWXYs= github.com/daeuniverse/quic-go v0.0.0-20240413031024-943f218e0810 h1:YtEYouFaNrg9sV9vf3UabvKShKn6sD0QaCdOxCwaF3g= github.com/daeuniverse/quic-go v0.0.0-20240413031024-943f218e0810/go.mod h1:61o2uZUGLrlv1i+oO2rx9sVX0vbf8cHzdSHt7h6lMnM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -111,8 +111,8 @@ github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQ github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo= github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= -github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= -github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= +github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -199,25 +199,25 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691 h1:/yRP+0AN7mf5DkD3BAI6TOFnd51gEoDEb8o35jIFtgw= -golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -239,8 +239,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= @@ -250,8 +250,8 @@ golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= -golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= +golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= +golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -268,8 +268,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= From 9701f5a37798b9fe99dedac9948c325d45d47e40 Mon Sep 17 00:00:00 2001 From: Integral Date: Thu, 12 Sep 2024 13:02:19 +0000 Subject: [PATCH 12/16] docs: add reality tcp support to proxy-protocols (#627) --- docs/en/proxy-protocols.md | 1 + docs/zh/proxy-protocols.md | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/en/proxy-protocols.md b/docs/en/proxy-protocols.md index a9a19c6944..e1abf77ed9 100644 --- a/docs/en/proxy-protocols.md +++ b/docs/en/proxy-protocols.md @@ -20,6 +20,7 @@ - [x] TCP - [x] WS - [x] TLS + - [x] Reality (**Experimental, TCP Only**) - [x] gRPC - [x] Meek - [x] HTTPUpgrade diff --git a/docs/zh/proxy-protocols.md b/docs/zh/proxy-protocols.md index 9d9e3b3dd9..5127bf6916 100644 --- a/docs/zh/proxy-protocols.md +++ b/docs/zh/proxy-protocols.md @@ -20,6 +20,7 @@ - [x] TCP - [x] WS - [x] TLS + - [x] Reality (**实验性,目前仅支持 TCP**) - [x] gRPC - [x] Meek - [x] HTTPUpgrade From e637d666e09abad01dcbd4ded11eb283b11e2d27 Mon Sep 17 00:00:00 2001 From: Integral Date: Fri, 13 Sep 2024 14:39:33 +0000 Subject: [PATCH 13/16] optimize: replace c arithmetic operators with bitwise ones (#628) --- control/kern/tproxy.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/control/kern/tproxy.c b/control/kern/tproxy.c index 1efcb70fa2..c7b2a43a38 100644 --- a/control/kern/tproxy.c +++ b/control/kern/tproxy.c @@ -408,7 +408,7 @@ static __always_inline __u8 ipv4_get_dscp(const struct iphdr *iph) static __always_inline __u8 ipv6_get_dscp(const struct ipv6hdr *ipv6h) { - return (ipv6h->priority << 2) + (ipv6h->flow_lbl[0] >> 6); + return (ipv6h->priority << 2) | (ipv6h->flow_lbl[0] >> 6); } static __always_inline void @@ -1112,9 +1112,9 @@ int tproxy_lan_ingress(struct __sk_buff *skb) __be32 mac[4] = { 0, 0, - bpf_htonl((ethh.h_source[0] << 8) + (ethh.h_source[1])), - bpf_htonl((ethh.h_source[2] << 24) + (ethh.h_source[3] << 16) + - (ethh.h_source[4] << 8) + (ethh.h_source[5])), + bpf_htonl((ethh.h_source[0] << 8) | (ethh.h_source[1])), + bpf_htonl((ethh.h_source[2] << 24) | (ethh.h_source[3] << 16) | + (ethh.h_source[4] << 8) | (ethh.h_source[5])), }; __s64 s64_ret; @@ -1405,11 +1405,11 @@ int tproxy_wan_egress(struct __sk_buff *skb) __be32 mac[4] = { 0, 0, - bpf_htonl((ethh.h_source[0] << 8) + + bpf_htonl((ethh.h_source[0] << 8) | (ethh.h_source[1])), - bpf_htonl((ethh.h_source[2] << 24) + - (ethh.h_source[3] << 16) + - (ethh.h_source[4] << 8) + + bpf_htonl((ethh.h_source[2] << 24) | + (ethh.h_source[3] << 16) | + (ethh.h_source[4] << 8) | (ethh.h_source[5])), }; __s64 s64_ret; @@ -1532,10 +1532,10 @@ int tproxy_wan_egress(struct __sk_buff *skb) __be32 mac[4] = { 0, 0, - bpf_htonl((ethh.h_source[0] << 8) + (ethh.h_source[1])), - bpf_htonl((ethh.h_source[2] << 24) + - (ethh.h_source[3] << 16) + - (ethh.h_source[4] << 8) + (ethh.h_source[5])), + bpf_htonl((ethh.h_source[0] << 8) | (ethh.h_source[1])), + bpf_htonl((ethh.h_source[2] << 24) | + (ethh.h_source[3] << 16) | + (ethh.h_source[4] << 8) | (ethh.h_source[5])), }; __s64 s64_ret; From 8255400fe28fa8538319e9a08b8a51daddea674d Mon Sep 17 00:00:00 2001 From: Integral Date: Fri, 13 Sep 2024 16:41:45 +0000 Subject: [PATCH 14/16] refactor: improve code readability of struct initialization (#633) --- control/kern/tproxy.c | 111 +++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/control/kern/tproxy.c b/control/kern/tproxy.c index c7b2a43a38..0f3099da68 100644 --- a/control/kern/tproxy.c +++ b/control/kern/tproxy.c @@ -962,10 +962,9 @@ static __always_inline void prep_redirect_to_control_plane( __builtin_memcpy(&redirect_tuple.dip, &tuples->five.dip, IPV6_BYTE_LENGTH); } - struct redirect_entry redirect_entry = {}; + struct redirect_entry redirect_entry = { .ifindex = skb->ifindex, + .from_wan = from_wan }; - redirect_entry.ifindex = skb->ifindex; - redirect_entry.from_wan = from_wan; __builtin_memcpy(redirect_entry.smac, ethh->h_source, sizeof(ethh->h_source)); __builtin_memcpy(redirect_entry.dmac, ethh->h_dest, @@ -1124,12 +1123,11 @@ int tproxy_lan_ingress(struct __sk_buff *skb) bpf_printk("shot routing: %d", s64_ret); return TC_ACT_SHOT; } - struct routing_result routing_result = { 0 }; + struct routing_result routing_result = { .outbound = s64_ret, + .mark = s64_ret >> 8, + .must = (s64_ret >> 40) & 1, + .dscp = tuples.dscp }; - routing_result.outbound = s64_ret; - routing_result.mark = s64_ret >> 8; - routing_result.must = (s64_ret >> 40) & 1; - 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. @@ -1170,11 +1168,12 @@ int tproxy_lan_ingress(struct __sk_buff *skb) } // Check outbound connectivity in specific ipversion and l4proto. - struct outbound_connectivity_query q = { 0 }; + struct outbound_connectivity_query q = { + .outbound = routing_result.outbound, + .ipversion = skb->protocol == bpf_htons(ETH_P_IP) ? 4 : 6, + .l4proto = l4proto + }; - q.outbound = routing_result.outbound; - q.ipversion = skb->protocol == bpf_htons(ETH_P_IP) ? 4 : 6; - q.l4proto = l4proto; __u32 *alive; alive = bpf_map_lookup_elem(&outbound_connectivity_map, &q); @@ -1272,13 +1271,11 @@ refresh_udp_conn_state_timer(struct tuples_key *key, bool is_egress) { struct udp_conn_state *old_conn_state = bpf_map_lookup_elem(&udp_conn_state_map, key); - struct udp_conn_state new_conn_state = { 0 }; + struct udp_conn_state new_conn_state = { + .is_egress = old_conn_state ? old_conn_state->is_egress : + is_egress + }; - if (old_conn_state) - new_conn_state.is_egress = - old_conn_state->is_egress; // Keep the value. - else - new_conn_state.is_egress = is_egress; long ret = bpf_map_update_elem(&udp_conn_state_map, key, &new_conn_state, BPF_ANY); if (unlikely(ret)) @@ -1463,11 +1460,13 @@ int tproxy_wan_egress(struct __sk_buff *skb) // Rewrite to control plane. // Check outbound connectivity in specific ipversion and l4proto. - struct outbound_connectivity_query q = { 0 }; + struct outbound_connectivity_query q = { + .outbound = outbound, + .ipversion = skb->protocol == bpf_htons(ETH_P_IP) ? 4 : + 6, + .l4proto = l4proto + }; - q.outbound = outbound; - q.ipversion = skb->protocol == bpf_htons(ETH_P_IP) ? 4 : 6; - q.l4proto = l4proto; __u32 *alive; alive = bpf_map_lookup_elem(&outbound_connectivity_map, &q); @@ -1479,12 +1478,13 @@ int tproxy_wan_egress(struct __sk_buff *skb) } if (unlikely(tcp_state_syn)) { - struct routing_result routing_result = {}; + struct routing_result routing_result = { + .outbound = outbound, + .mark = mark, + .must = must, + .dscp = tuples.dscp + }; - routing_result.outbound = outbound; - routing_result.mark = mark; - routing_result.must = must; - routing_result.dscp = tuples.dscp; __builtin_memcpy(routing_result.mac, ethh.h_source, sizeof(ethh.h_source)); if (pid_pname) { @@ -1546,12 +1546,13 @@ int tproxy_wan_egress(struct __sk_buff *skb) return TC_ACT_SHOT; } // Construct new hdr to encap. - struct routing_result routing_result = {}; + struct routing_result routing_result = { + .outbound = s64_ret, + .mark = s64_ret >> 8, + .must = (s64_ret >> 40) & 1, + .dscp = tuples.dscp + }; - routing_result.outbound = s64_ret; - routing_result.mark = s64_ret >> 8; - routing_result.must = (s64_ret >> 40) & 1; - routing_result.dscp = tuples.dscp; __builtin_memcpy(routing_result.mac, ethh.h_source, sizeof(ethh.h_source)); if (pid_pname) { @@ -1586,11 +1587,13 @@ int tproxy_wan_egress(struct __sk_buff *skb) // Rewrite to control plane. // Check outbound connectivity in specific ipversion and l4proto. - struct outbound_connectivity_query q = { 0 }; + struct outbound_connectivity_query q = { + .outbound = routing_result.outbound, + .ipversion = skb->protocol == bpf_htons(ETH_P_IP) ? 4 : + 6, + .l4proto = l4proto + }; - q.outbound = routing_result.outbound; - q.ipversion = skb->protocol == bpf_htons(ETH_P_IP) ? 4 : 6; - q.l4proto = l4proto; __u32 *alive; alive = bpf_map_lookup_elem(&outbound_connectivity_map, &q); @@ -1766,9 +1769,9 @@ static __always_inline int update_map_elem_by_cookie(const __u64 cookie) ret = _update_map_elem_by_cookie(cookie); if (ret) { // Fallback to only write pid to avoid loop due to packets sent by dae. - struct pid_pname val = { 0 }; + struct pid_pname val = { .pid = bpf_get_current_pid_tgid() >> + 32 }; - val.pid = bpf_get_current_pid_tgid() >> 32; __u32(*pname)[TASK_COMM_LEN] = bpf_map_lookup_elem(&tgid_pname_map, &val.pid); if (pname) { @@ -1844,11 +1847,12 @@ int local_tcp_sockops(struct bpf_sock_ops *skops) if (pid == 0) return 0; - struct tuples_key tuple = {}; + struct tuples_key tuple = { + .l4proto = IPPROTO_TCP, + .sport = bpf_htonl(skops->local_port) >> 16, + .dport = skops->remote_port >> 16, + }; - tuple.l4proto = IPPROTO_TCP; - tuple.sport = bpf_htonl(skops->local_port) >> 16; - tuple.dport = skops->remote_port >> 16; if (skops->family == AF_INET) { tuple.sip.u6_addr32[2] = bpf_htonl(0x0000ffff); tuple.sip.u6_addr32[3] = skops->local_ip4; @@ -1870,17 +1874,14 @@ int local_tcp_sockops(struct bpf_sock_ops *skops) switch (skops->op) { case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: // dae sockets { - struct tuples_key rev_tuple = {}; + struct tuples_key rev_tuple = { .l4proto = IPPROTO_TCP, + .sport = tuple.dport, + .dport = tuple.sport }; - rev_tuple.l4proto = IPPROTO_TCP; - rev_tuple.sport = tuple.dport; - rev_tuple.dport = tuple.sport; __builtin_memcpy(&rev_tuple.sip, &tuple.dip, IPV6_BYTE_LENGTH); __builtin_memcpy(&rev_tuple.dip, &tuple.sip, IPV6_BYTE_LENGTH); - struct routing_result *routing_result; - - routing_result = + struct routing_result *routing_result = bpf_map_lookup_elem(&routing_tuples_map, &rev_tuple); if (!routing_result || !routing_result->pid) break; @@ -1896,9 +1897,7 @@ int local_tcp_sockops(struct bpf_sock_ops *skops) case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: // local client sockets { - struct routing_result *routing_result; - - routing_result = + struct routing_result *routing_result = bpf_map_lookup_elem(&routing_tuples_map, &tuple); if (!routing_result || !routing_result->pid) break; @@ -1922,11 +1921,11 @@ int local_tcp_sockops(struct bpf_sock_ops *skops) SEC("sk_msg/fast_redirect") int sk_msg_fast_redirect(struct sk_msg_md *msg) { - struct tuples_key rev_tuple = {}; + struct tuples_key rev_tuple = { .l4proto = IPPROTO_TCP, + .sport = msg->remote_port >> 16, + .dport = bpf_htonl(msg->local_port) >> + 16 }; - rev_tuple.l4proto = IPPROTO_TCP; - rev_tuple.sport = msg->remote_port >> 16; - rev_tuple.dport = bpf_htonl(msg->local_port) >> 16; if (msg->family == AF_INET) { rev_tuple.sip.u6_addr32[2] = bpf_htonl(0x0000ffff); rev_tuple.sip.u6_addr32[3] = msg->remote_ip4; From 903b59541787de3f1738e00d85f817914e0e8867 Mon Sep 17 00:00:00 2001 From: Integral Date: Sat, 14 Sep 2024 05:26:09 +0000 Subject: [PATCH 15/16] refactor: remove redundant assignments (#634) --- control/kern/tproxy.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/control/kern/tproxy.c b/control/kern/tproxy.c index 0f3099da68..aa1d9e235a 100644 --- a/control/kern/tproxy.c +++ b/control/kern/tproxy.c @@ -302,14 +302,14 @@ enum __attribute__((packed)) MatchType { enum L4ProtoType { L4ProtoType_TCP = 1, - L4ProtoType_UDP = 2, - L4ProtoType_X = 3, + L4ProtoType_UDP, + L4ProtoType_X, }; enum IpVersionType { IpVersionType_4 = 1, - IpVersionType_6 = 2, - IpVersionType_X = 3, + IpVersionType_6, + IpVersionType_X, }; struct port_range { @@ -1285,15 +1285,15 @@ refresh_udp_conn_state_timer(struct tuples_key *key, bool is_egress) if (unlikely(!value)) return NULL; - if ((ret = bpf_timer_init(&value->timer, &udp_conn_state_map, - CLOCK_MONOTONIC))) + if ((bpf_timer_init(&value->timer, &udp_conn_state_map, + CLOCK_MONOTONIC))) goto retn; - if ((ret = bpf_timer_set_callback(&value->timer, - refresh_udp_conn_state_timer_cb))) + if ((bpf_timer_set_callback(&value->timer, + refresh_udp_conn_state_timer_cb))) goto retn; - if ((ret = bpf_timer_start(&value->timer, TIMEOUT_UDP_CONN_STATE, 0))) + if ((bpf_timer_start(&value->timer, TIMEOUT_UDP_CONN_STATE, 0))) goto retn; retn: @@ -1710,7 +1710,7 @@ static __always_inline int _update_map_elem_by_cookie(const __u64 cookie) // __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) + if (to_read > MAX_ARG_SCANNER_BUFFER_SIZE) to_read = MAX_ARG_SCANNER_BUFFER_SIZE; else buf[to_read] = 0; From 3b2ae3add3d74b95a32c53fb6ad8c411790354cb Mon Sep 17 00:00:00 2001 From: mzz <2017@duck.com> Date: Tue, 17 Sep 2024 22:47:49 +0800 Subject: [PATCH 16/16] patch: revert: refactor: improve code readability of struct initialization (#637) --- control/kern/tproxy.c | 111 +++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 55 deletions(-) diff --git a/control/kern/tproxy.c b/control/kern/tproxy.c index aa1d9e235a..81bfa8d45a 100644 --- a/control/kern/tproxy.c +++ b/control/kern/tproxy.c @@ -962,9 +962,10 @@ static __always_inline void prep_redirect_to_control_plane( __builtin_memcpy(&redirect_tuple.dip, &tuples->five.dip, IPV6_BYTE_LENGTH); } - struct redirect_entry redirect_entry = { .ifindex = skb->ifindex, - .from_wan = from_wan }; + struct redirect_entry redirect_entry = {}; + redirect_entry.ifindex = skb->ifindex; + redirect_entry.from_wan = from_wan; __builtin_memcpy(redirect_entry.smac, ethh->h_source, sizeof(ethh->h_source)); __builtin_memcpy(redirect_entry.dmac, ethh->h_dest, @@ -1123,11 +1124,12 @@ int tproxy_lan_ingress(struct __sk_buff *skb) bpf_printk("shot routing: %d", s64_ret); return TC_ACT_SHOT; } - struct routing_result routing_result = { .outbound = s64_ret, - .mark = s64_ret >> 8, - .must = (s64_ret >> 40) & 1, - .dscp = tuples.dscp }; + struct routing_result routing_result = { 0 }; + routing_result.outbound = s64_ret; + routing_result.mark = s64_ret >> 8; + routing_result.must = (s64_ret >> 40) & 1; + 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. @@ -1168,12 +1170,11 @@ int tproxy_lan_ingress(struct __sk_buff *skb) } // Check outbound connectivity in specific ipversion and l4proto. - struct outbound_connectivity_query q = { - .outbound = routing_result.outbound, - .ipversion = skb->protocol == bpf_htons(ETH_P_IP) ? 4 : 6, - .l4proto = l4proto - }; + struct outbound_connectivity_query q = { 0 }; + q.outbound = routing_result.outbound; + q.ipversion = skb->protocol == bpf_htons(ETH_P_IP) ? 4 : 6; + q.l4proto = l4proto; __u32 *alive; alive = bpf_map_lookup_elem(&outbound_connectivity_map, &q); @@ -1271,11 +1272,13 @@ refresh_udp_conn_state_timer(struct tuples_key *key, bool is_egress) { struct udp_conn_state *old_conn_state = bpf_map_lookup_elem(&udp_conn_state_map, key); - struct udp_conn_state new_conn_state = { - .is_egress = old_conn_state ? old_conn_state->is_egress : - is_egress - }; + struct udp_conn_state new_conn_state = { 0 }; + if (old_conn_state) + new_conn_state.is_egress = + old_conn_state->is_egress; // Keep the value. + else + new_conn_state.is_egress = is_egress; long ret = bpf_map_update_elem(&udp_conn_state_map, key, &new_conn_state, BPF_ANY); if (unlikely(ret)) @@ -1460,13 +1463,11 @@ int tproxy_wan_egress(struct __sk_buff *skb) // Rewrite to control plane. // Check outbound connectivity in specific ipversion and l4proto. - struct outbound_connectivity_query q = { - .outbound = outbound, - .ipversion = skb->protocol == bpf_htons(ETH_P_IP) ? 4 : - 6, - .l4proto = l4proto - }; + struct outbound_connectivity_query q = { 0 }; + q.outbound = outbound; + q.ipversion = skb->protocol == bpf_htons(ETH_P_IP) ? 4 : 6; + q.l4proto = l4proto; __u32 *alive; alive = bpf_map_lookup_elem(&outbound_connectivity_map, &q); @@ -1478,13 +1479,12 @@ int tproxy_wan_egress(struct __sk_buff *skb) } if (unlikely(tcp_state_syn)) { - struct routing_result routing_result = { - .outbound = outbound, - .mark = mark, - .must = must, - .dscp = tuples.dscp - }; + struct routing_result routing_result = {}; + routing_result.outbound = outbound; + routing_result.mark = mark; + routing_result.must = must; + routing_result.dscp = tuples.dscp; __builtin_memcpy(routing_result.mac, ethh.h_source, sizeof(ethh.h_source)); if (pid_pname) { @@ -1546,13 +1546,12 @@ int tproxy_wan_egress(struct __sk_buff *skb) return TC_ACT_SHOT; } // Construct new hdr to encap. - struct routing_result routing_result = { - .outbound = s64_ret, - .mark = s64_ret >> 8, - .must = (s64_ret >> 40) & 1, - .dscp = tuples.dscp - }; + struct routing_result routing_result = {}; + routing_result.outbound = s64_ret; + routing_result.mark = s64_ret >> 8; + routing_result.must = (s64_ret >> 40) & 1; + routing_result.dscp = tuples.dscp; __builtin_memcpy(routing_result.mac, ethh.h_source, sizeof(ethh.h_source)); if (pid_pname) { @@ -1587,13 +1586,11 @@ int tproxy_wan_egress(struct __sk_buff *skb) // Rewrite to control plane. // Check outbound connectivity in specific ipversion and l4proto. - struct outbound_connectivity_query q = { - .outbound = routing_result.outbound, - .ipversion = skb->protocol == bpf_htons(ETH_P_IP) ? 4 : - 6, - .l4proto = l4proto - }; + struct outbound_connectivity_query q = { 0 }; + q.outbound = routing_result.outbound; + q.ipversion = skb->protocol == bpf_htons(ETH_P_IP) ? 4 : 6; + q.l4proto = l4proto; __u32 *alive; alive = bpf_map_lookup_elem(&outbound_connectivity_map, &q); @@ -1769,9 +1766,9 @@ static __always_inline int update_map_elem_by_cookie(const __u64 cookie) ret = _update_map_elem_by_cookie(cookie); if (ret) { // Fallback to only write pid to avoid loop due to packets sent by dae. - struct pid_pname val = { .pid = bpf_get_current_pid_tgid() >> - 32 }; + struct pid_pname val = { 0 }; + val.pid = bpf_get_current_pid_tgid() >> 32; __u32(*pname)[TASK_COMM_LEN] = bpf_map_lookup_elem(&tgid_pname_map, &val.pid); if (pname) { @@ -1847,12 +1844,11 @@ int local_tcp_sockops(struct bpf_sock_ops *skops) if (pid == 0) return 0; - struct tuples_key tuple = { - .l4proto = IPPROTO_TCP, - .sport = bpf_htonl(skops->local_port) >> 16, - .dport = skops->remote_port >> 16, - }; + struct tuples_key tuple = {}; + tuple.l4proto = IPPROTO_TCP; + tuple.sport = bpf_htonl(skops->local_port) >> 16; + tuple.dport = skops->remote_port >> 16; if (skops->family == AF_INET) { tuple.sip.u6_addr32[2] = bpf_htonl(0x0000ffff); tuple.sip.u6_addr32[3] = skops->local_ip4; @@ -1874,14 +1870,17 @@ int local_tcp_sockops(struct bpf_sock_ops *skops) switch (skops->op) { case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: // dae sockets { - struct tuples_key rev_tuple = { .l4proto = IPPROTO_TCP, - .sport = tuple.dport, - .dport = tuple.sport }; + struct tuples_key rev_tuple = {}; + rev_tuple.l4proto = IPPROTO_TCP; + rev_tuple.sport = tuple.dport; + rev_tuple.dport = tuple.sport; __builtin_memcpy(&rev_tuple.sip, &tuple.dip, IPV6_BYTE_LENGTH); __builtin_memcpy(&rev_tuple.dip, &tuple.sip, IPV6_BYTE_LENGTH); - struct routing_result *routing_result = + struct routing_result *routing_result; + + routing_result = bpf_map_lookup_elem(&routing_tuples_map, &rev_tuple); if (!routing_result || !routing_result->pid) break; @@ -1897,7 +1896,9 @@ int local_tcp_sockops(struct bpf_sock_ops *skops) case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: // local client sockets { - struct routing_result *routing_result = + struct routing_result *routing_result; + + routing_result = bpf_map_lookup_elem(&routing_tuples_map, &tuple); if (!routing_result || !routing_result->pid) break; @@ -1921,11 +1922,11 @@ int local_tcp_sockops(struct bpf_sock_ops *skops) SEC("sk_msg/fast_redirect") int sk_msg_fast_redirect(struct sk_msg_md *msg) { - struct tuples_key rev_tuple = { .l4proto = IPPROTO_TCP, - .sport = msg->remote_port >> 16, - .dport = bpf_htonl(msg->local_port) >> - 16 }; + struct tuples_key rev_tuple = {}; + rev_tuple.l4proto = IPPROTO_TCP; + rev_tuple.sport = msg->remote_port >> 16; + rev_tuple.dport = bpf_htonl(msg->local_port) >> 16; if (msg->family == AF_INET) { rev_tuple.sip.u6_addr32[2] = bpf_htonl(0x0000ffff); rev_tuple.sip.u6_addr32[3] = msg->remote_ip4;