optimize: drop ipv6 send_redirects

This commit is contained in:
mzz2017
2023-02-26 13:36:38 +08:00
parent 27d77d2b42
commit e0cec1874a
5 changed files with 65 additions and 74 deletions

View File

@ -74,7 +74,6 @@ sudo tee /etc/sysctl.d/60-dae-$lan_ifname.conf << EOF
net.ipv4.conf.$lan_ifname.forwarding = 1 net.ipv4.conf.$lan_ifname.forwarding = 1
net.ipv6.conf.$lan_ifname.forwarding = 1 net.ipv6.conf.$lan_ifname.forwarding = 1
net.ipv4.conf.$lan_ifname.send_redirects = 0 net.ipv4.conf.$lan_ifname.send_redirects = 0
net.ipv6.conf.$lan_ifname.send_redirects = 0
EOF EOF
sudo sysctl --system sudo sysctl --system
``` ```

View File

@ -153,22 +153,6 @@ func NewControlPlane(
if err = bpf.ParamMap.Update(consts.ControlPlanePidKey, uint32(os.Getpid()), ebpf.UpdateAny); err != nil { if err = bpf.ParamMap.Update(consts.ControlPlanePidKey, uint32(os.Getpid()), ebpf.UpdateAny); err != nil {
return nil, err return nil, err
} }
// Write ip_proto to hdr_size mapping for IPv6 extension extraction (it is just for eBPF code insns optimization).
if err = bpf.IpprotoHdrsizeMap.Update(uint32(unix.IPPROTO_HOPOPTS), int32(-1), ebpf.UpdateAny); err != nil {
return nil, err
}
if err = bpf.IpprotoHdrsizeMap.Update(uint32(unix.IPPROTO_ROUTING), int32(-1), ebpf.UpdateAny); err != nil {
return nil, err
}
if err = bpf.IpprotoHdrsizeMap.Update(uint32(unix.IPPROTO_FRAGMENT), int32(4), ebpf.UpdateAny); err != nil {
return nil, err
}
if err = bpf.IpprotoHdrsizeMap.Update(uint32(unix.IPPROTO_TCP), int32(-2), ebpf.UpdateAny); err != nil {
return nil, err
}
if err = bpf.IpprotoHdrsizeMap.Update(uint32(unix.IPPROTO_UDP), int32(-2), ebpf.UpdateAny); err != nil {
return nil, err
}
/// Bind to links. Binding should be advance of dialerGroups to avoid un-routable old connection. /// Bind to links. Binding should be advance of dialerGroups to avoid un-routable old connection.
// Add clsact qdisc // Add clsact qdisc

View File

@ -9,6 +9,7 @@
#include "headers/if_ether_defs.h" #include "headers/if_ether_defs.h"
#include "headers/pkt_cls_defs.h" #include "headers/pkt_cls_defs.h"
#include "headers/socket_defs.h" #include "headers/socket_defs.h"
#include "headers/upai_in6_defs.h"
#include "headers/vmlinux.h" #include "headers/vmlinux.h"
#include "headers/bpf_core_read.h" #include "headers/bpf_core_read.h"
@ -217,15 +218,6 @@ struct {
__uint(max_entries, 2); __uint(max_entries, 2);
} l4proto_ipversion_map SEC(".maps"); } l4proto_ipversion_map SEC(".maps");
// IPPROTO to hdr_size
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, __u32);
__type(value, __s32);
__uint(max_entries, 5);
__uint(pinning, LIBBPF_PIN_BY_NAME);
} ipproto_hdrsize_map SEC(".maps");
// Interface Ips: // Interface Ips:
struct if_params { struct if_params {
bool rx_cksm_offload; bool rx_cksm_offload;
@ -543,13 +535,11 @@ static __always_inline int rewrite_port(struct __sk_buff *skb, __u8 proto,
return 0; return 0;
} }
static __always_inline int handle_ipv6_extensions(const struct __sk_buff *skb, static __always_inline int
__u32 offset, __u32 hdr, handle_ipv6_extensions(const struct __sk_buff *skb, __u32 offset, __u32 hdr,
struct tcphdr *tcph, struct icmp6hdr *icmp6h, struct tcphdr *tcph,
struct udphdr *udph, struct udphdr *udph, __u8 *ihl, __u8 *l4proto) {
__u8 *ihl, __u8 *l4proto) {
__u8 hdr_length = 0; __u8 hdr_length = 0;
__s32 *p_s32;
__u8 nexthdr = 0; __u8 nexthdr = 0;
*ihl = sizeof(struct ipv6hdr) / 4; *ihl = sizeof(struct ipv6hdr) / 4;
int ret; int ret;
@ -563,12 +553,20 @@ static __always_inline int handle_ipv6_extensions(const struct __sk_buff *skb,
return 1; return 1;
} }
// See control/control_plane.go. // See control/control_plane.go.
if (!(p_s32 = bpf_map_lookup_elem(&ipproto_hdrsize_map, &hdr))) {
return 1;
}
switch (*p_s32) { switch (hdr) {
case -1: case IPPROTO_ICMPV6:
*l4proto = hdr;
hdr_length = sizeof(struct icmp6hdr);
// Assume ICMPV6 as a level 4 protocol.
if ((ret = bpf_skb_load_bytes(skb, offset, icmp6h, hdr_length))) {
bpf_printk("not a valid IPv6 packet");
return -EFAULT;
}
return 0;
case IPPROTO_HOPOPTS:
case IPPROTO_ROUTING:
if ((ret = bpf_skb_load_bytes(skb, offset + 1, &hdr_length, if ((ret = bpf_skb_load_bytes(skb, offset + 1, &hdr_length,
sizeof(hdr_length)))) { sizeof(hdr_length)))) {
bpf_printk("not a valid IPv6 packet"); bpf_printk("not a valid IPv6 packet");
@ -580,13 +578,13 @@ static __always_inline int handle_ipv6_extensions(const struct __sk_buff *skb,
return -EFAULT; return -EFAULT;
} }
break; break;
case 4: case IPPROTO_FRAGMENT:
hdr_length = 4; hdr_length = 4;
goto special_n1; goto special_n1;
case -2: case IPPROTO_TCP:
case IPPROTO_UDP:
*l4proto = hdr; *l4proto = hdr;
if (hdr == IPPROTO_TCP) { if (hdr == IPPROTO_TCP) {
__builtin_memset(tcph, 0, sizeof(struct udphdr));
// Upper layer; // Upper layer;
if ((ret = bpf_skb_load_bytes(skb, offset, tcph, if ((ret = bpf_skb_load_bytes(skb, offset, tcph,
sizeof(struct tcphdr)))) { sizeof(struct tcphdr)))) {
@ -594,7 +592,6 @@ static __always_inline int handle_ipv6_extensions(const struct __sk_buff *skb,
return -EFAULT; return -EFAULT;
} }
} else if (hdr == IPPROTO_UDP) { } else if (hdr == IPPROTO_UDP) {
__builtin_memset(tcph, 0, sizeof(struct tcphdr));
// Upper layer; // Upper layer;
if ((ret = bpf_skb_load_bytes(skb, offset, udph, if ((ret = bpf_skb_load_bytes(skb, offset, udph,
sizeof(struct udphdr)))) { sizeof(struct udphdr)))) {
@ -616,11 +613,10 @@ static __always_inline int handle_ipv6_extensions(const struct __sk_buff *skb,
return 1; return 1;
} }
static __always_inline int static __always_inline int parse_transport(
parse_transport(const struct __sk_buff *skb, struct ethhdr *ethh, const struct __sk_buff *skb, struct ethhdr *ethh, struct iphdr *iph,
struct iphdr *iph, struct ipv6hdr *ipv6h, struct tcphdr *tcph, struct ipv6hdr *ipv6h, struct icmp6hdr *icmp6h, struct tcphdr *tcph,
struct udphdr *udph, __u8 *ihl, __u8 *ipversion, struct udphdr *udph, __u8 *ihl, __u8 *ipversion, __u8 *l4proto) {
__u8 *l4proto) {
__u32 offset = 0; __u32 offset = 0;
int ret; int ret;
@ -635,11 +631,15 @@ parse_transport(const struct __sk_buff *skb, struct ethhdr *ethh,
*ipversion = 0; *ipversion = 0;
*ihl = 0; *ihl = 0;
*l4proto = 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", eth->h_proto, // bpf_printk("parse_transport: h_proto: %u ? %u %u", eth->h_proto,
// bpf_htons(ETH_P_IP), bpf_htons(ETH_P_IPV6)); // bpf_htons(ETH_P_IP), bpf_htons(ETH_P_IPV6));
if (ethh->h_proto == bpf_htons(ETH_P_IP)) { if (ethh->h_proto == bpf_htons(ETH_P_IP)) {
__builtin_memset(ipv6h, 0, sizeof(struct ipv6hdr));
*ipversion = 4; *ipversion = 4;
if ((ret = bpf_skb_load_bytes(skb, offset, iph, sizeof(struct iphdr)))) { if ((ret = bpf_skb_load_bytes(skb, offset, iph, sizeof(struct iphdr)))) {
@ -651,14 +651,12 @@ parse_transport(const struct __sk_buff *skb, struct ethhdr *ethh,
// We only process TCP and UDP traffic. // We only process TCP and UDP traffic.
*l4proto = iph->protocol; *l4proto = iph->protocol;
if (iph->protocol == IPPROTO_TCP) { if (iph->protocol == IPPROTO_TCP) {
__builtin_memset(udph, 0, sizeof(struct udphdr));
if ((ret = if ((ret =
bpf_skb_load_bytes(skb, offset, tcph, sizeof(struct tcphdr)))) { bpf_skb_load_bytes(skb, offset, tcph, sizeof(struct tcphdr)))) {
// Not a complete tcphdr. // Not a complete tcphdr.
return -EFAULT; return -EFAULT;
} }
} else if (iph->protocol == IPPROTO_UDP) { } else if (iph->protocol == IPPROTO_UDP) {
__builtin_memset(tcph, 0, sizeof(struct tcphdr));
if ((ret = if ((ret =
bpf_skb_load_bytes(skb, offset, udph, sizeof(struct udphdr)))) { bpf_skb_load_bytes(skb, offset, udph, sizeof(struct udphdr)))) {
// Not a complete tcphdr. // Not a complete tcphdr.
@ -671,7 +669,6 @@ parse_transport(const struct __sk_buff *skb, struct ethhdr *ethh,
*ihl = iph->ihl; *ihl = iph->ihl;
return 0; return 0;
} else if (ethh->h_proto == bpf_htons(ETH_P_IPV6)) { } else if (ethh->h_proto == bpf_htons(ETH_P_IPV6)) {
__builtin_memset(iph, 0, sizeof(struct iphdr));
*ipversion = 6; *ipversion = 6;
if ((ret = if ((ret =
@ -682,8 +679,8 @@ parse_transport(const struct __sk_buff *skb, struct ethhdr *ethh,
offset += sizeof(struct ipv6hdr); offset += sizeof(struct ipv6hdr);
return handle_ipv6_extensions(skb, offset, ipv6h->nexthdr, tcph, udph, ihl, return handle_ipv6_extensions(skb, offset, ipv6h->nexthdr, icmp6h, tcph,
l4proto); udph, ihl, l4proto);
} else { } else {
return 1; return 1;
} }
@ -1164,18 +1161,28 @@ int tproxy_lan_egress(struct __sk_buff *skb) {
struct ethhdr ethh; struct ethhdr ethh;
struct iphdr iph; struct iphdr iph;
struct ipv6hdr ipv6h; struct ipv6hdr ipv6h;
struct icmp6hdr icmp6h;
struct tcphdr tcph; struct tcphdr tcph;
struct udphdr udph; struct udphdr udph;
__u8 ihl; __u8 ihl;
__u8 ipversion; __u8 ipversion;
__u8 l4proto; __u8 l4proto;
int ret = parse_transport(skb, &ethh, &iph, &ipv6h, &tcph, &udph, &ihl, int ret = parse_transport(skb, &ethh, &iph, &ipv6h, &icmp6h, &tcph, &udph,
&ipversion, &l4proto); &ihl, &ipversion, &l4proto);
if (ret) { if (ret) {
bpf_printk("parse_transport: %d", ret); bpf_printk("parse_transport: %d", ret);
return TC_ACT_OK; return TC_ACT_OK;
} }
if (l4proto != IPPROTO_UDP) { switch (l4proto) {
case IPPROTO_ICMPV6:
if (icmp6h.icmp6_type == 137) {
// REDIRECT (NDP)
return TC_ACT_SHOT;
}
return TC_ACT_PIPE;
case IPPROTO_UDP:
break;
default:
return TC_ACT_PIPE; return TC_ACT_PIPE;
} }
@ -1218,17 +1225,21 @@ int tproxy_lan_ingress(struct __sk_buff *skb) {
struct ethhdr ethh; struct ethhdr ethh;
struct iphdr iph; struct iphdr iph;
struct ipv6hdr ipv6h; struct ipv6hdr ipv6h;
struct icmp6hdr icmp6h;
struct tcphdr tcph; struct tcphdr tcph;
struct udphdr udph; struct udphdr udph;
__u8 ihl; __u8 ihl;
__u8 ipversion; __u8 ipversion;
__u8 l4proto; __u8 l4proto;
int ret = parse_transport(skb, &ethh, &iph, &ipv6h, &tcph, &udph, &ihl, int ret = parse_transport(skb, &ethh, &iph, &ipv6h, &icmp6h, &tcph, &udph,
&ipversion, &l4proto); &ihl, &ipversion, &l4proto);
if (ret) { if (ret) {
bpf_printk("parse_transport: %d", ret); bpf_printk("parse_transport: %d", ret);
return TC_ACT_OK; return TC_ACT_OK;
} }
if (l4proto == IPPROTO_ICMPV6) {
return TC_ACT_OK;
}
// Prepare five tuples. // Prepare five tuples.
struct tuples tuples; struct tuples tuples;
@ -1492,17 +1503,21 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
struct ethhdr ethh; struct ethhdr ethh;
struct iphdr iph; struct iphdr iph;
struct ipv6hdr ipv6h; struct ipv6hdr ipv6h;
struct icmp6hdr icmp6h;
struct tcphdr tcph; struct tcphdr tcph;
struct udphdr udph; struct udphdr udph;
__u8 ihl; __u8 ihl;
__u8 ipversion; __u8 ipversion;
__u8 l4proto; __u8 l4proto;
bool tcp_state_syn; bool tcp_state_syn;
int ret = parse_transport(skb, &ethh, &iph, &ipv6h, &tcph, &udph, &ihl, int ret = parse_transport(skb, &ethh, &iph, &ipv6h, &icmp6h, &tcph, &udph,
&ipversion, &l4proto); &ihl, &ipversion, &l4proto);
if (ret) { if (ret) {
return TC_ACT_OK; return TC_ACT_OK;
} }
if (l4proto == IPPROTO_ICMPV6) {
return TC_ACT_OK;
}
// Backup for further use. // Backup for further use.
struct tuples tuples; struct tuples tuples;
@ -1546,7 +1561,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
if (sk) { if (sk) {
// Not a tproxy WAN response. It is a tproxy LAN response. // Not a tproxy WAN response. It is a tproxy LAN response.
bpf_sk_release(sk); bpf_sk_release(sk);
return TC_ACT_OK; return TC_ACT_PIPE;
} }
} }
} }
@ -1812,16 +1827,20 @@ int tproxy_wan_ingress(struct __sk_buff *skb) {
struct ethhdr ethh; struct ethhdr ethh;
struct iphdr iph; struct iphdr iph;
struct ipv6hdr ipv6h; struct ipv6hdr ipv6h;
struct icmp6hdr icmp6h;
struct tcphdr tcph; struct tcphdr tcph;
struct udphdr udph; struct udphdr udph;
__u8 ihl; __u8 ihl;
__u8 ipversion; __u8 ipversion;
__u8 l4proto; __u8 l4proto;
int ret = parse_transport(skb, &ethh, &iph, &ipv6h, &tcph, &udph, &ihl, int ret = parse_transport(skb, &ethh, &iph, &ipv6h, &icmp6h, &tcph, &udph,
&ipversion, &l4proto); &ihl, &ipversion, &l4proto);
if (ret) { if (ret) {
return TC_ACT_OK; return TC_ACT_OK;
} }
if (l4proto == IPPROTO_ICMPV6) {
return TC_ACT_OK;
}
struct tuples tuples; struct tuples tuples;
get_tuples(&tuples, &iph, &ipv6h, &tcph, &udph, ipversion, l4proto); get_tuples(&tuples, &iph, &ipv6h, &tcph, &udph, ipversion, l4proto);

View File

@ -87,10 +87,6 @@ func checkIpforward(ifname string, ipversion consts.IpVersionStr) error {
path := fmt.Sprintf("/proc/sys/net/ipv%v/conf/%v/forwarding", ipversion, ifname) path := fmt.Sprintf("/proc/sys/net/ipv%v/conf/%v/forwarding", ipversion, ifname)
b, err := os.ReadFile(path) b, err := os.ReadFile(path)
if err != nil { if err != nil {
if os.IsNotExist(err) {
// Kernel does not support.
return nil
}
return err return err
} }
if bytes.Equal(bytes.TrimSpace(b), []byte("1")) { if bytes.Equal(bytes.TrimSpace(b), []byte("1")) {
@ -113,10 +109,6 @@ func checkSendRedirects(ifname string, ipversion consts.IpVersionStr) error {
path := fmt.Sprintf("/proc/sys/net/ipv%v/conf/%v/send_redirects", ipversion, ifname) path := fmt.Sprintf("/proc/sys/net/ipv%v/conf/%v/send_redirects", ipversion, ifname)
b, err := os.ReadFile(path) b, err := os.ReadFile(path)
if err != nil { if err != nil {
if os.IsNotExist(err) {
// Kernel does not support.
return nil
}
return err return err
} }
if bytes.Equal(bytes.TrimSpace(b), []byte("0")) { if bytes.Equal(bytes.TrimSpace(b), []byte("0")) {
@ -129,9 +121,6 @@ func CheckSendRedirects(ifname string) error {
if err := checkSendRedirects(ifname, consts.IpVersionStr_4); err != nil { if err := checkSendRedirects(ifname, consts.IpVersionStr_4); err != nil {
return err return err
} }
if err := checkSendRedirects(ifname, consts.IpVersionStr_6); err != nil {
return err
}
return nil return nil
} }