mirror of
https://github.com/daeuniverse/dae.git
synced 2025-07-20 20:59:55 +07:00
optimize: drop ipv6 send_redirects
This commit is contained in:
@ -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
|
||||||
```
|
```
|
||||||
|
@ -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
|
||||||
|
Submodule control/kern/headers updated: 99eb2ebd74...378c3c576e
@ -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, ðh, &iph, &ipv6h, &tcph, &udph, &ihl,
|
int ret = parse_transport(skb, ðh, &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, ðh, &iph, &ipv6h, &tcph, &udph, &ihl,
|
int ret = parse_transport(skb, ðh, &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, ðh, &iph, &ipv6h, &tcph, &udph, &ihl,
|
int ret = parse_transport(skb, ðh, &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, ðh, &iph, &ipv6h, &tcph, &udph, &ihl,
|
int ret = parse_transport(skb, ðh, &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);
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user