From 0bf9e464ffd742c04b9d33826f05ddd32388c904 Mon Sep 17 00:00:00 2001 From: mzz2017 <2017@duck.com> Date: Sat, 18 Feb 2023 14:55:42 +0800 Subject: [PATCH] Revert "optimize: no need for rule table for wan and reject TCP to tproxy" This reverts commit 7452abb158dd020f259f70b64c379e3296fe9397. --- common/consts/ebpf.go | 1 + control/control_plane.go | 3 + control/control_plane_core.go | 111 ++++++++++++++++++++++++++++++++++ control/kern/tproxy.c | 78 +++++++++++++----------- 4 files changed, 157 insertions(+), 36 deletions(-) diff --git a/common/consts/ebpf.go b/common/consts/ebpf.go index 8b424db..b82c364 100644 --- a/common/consts/ebpf.go +++ b/common/consts/ebpf.go @@ -125,6 +125,7 @@ var ( ) const ( + TproxyMark uint32 = 0x8000000 LoopbackIfIndex = 1 ) diff --git a/control/control_plane.go b/control/control_plane.go index f2fb18e..744885d 100644 --- a/control/control_plane.go +++ b/control/control_plane.go @@ -175,6 +175,9 @@ func NewControlPlane( } // Bind to LAN if len(global.LanInterface) > 0 { + if err = core.setupRoutingPolicy(); err != nil { + return nil, err + } for _, ifname := range global.LanInterface { if err = core.bindLan(ifname); err != nil { return nil, fmt.Errorf("bindLan: %v: %w", ifname, err) diff --git a/control/control_plane_core.go b/control/control_plane_core.go index 7ae5186..afc93f9 100644 --- a/control/control_plane_core.go +++ b/control/control_plane_core.go @@ -15,6 +15,7 @@ import ( internal "github.com/v2rayA/dae/pkg/ebpf_internal" "github.com/vishvananda/netlink" "golang.org/x/sys/unix" + "net" "os" "regexp" ) @@ -115,6 +116,116 @@ func (c *ControlPlaneCore) delQdisc(ifname string) error { return nil } +func (c *ControlPlaneCore) setupRoutingPolicy() (err error) { + /// Insert ip rule / ip route. + const table = 2023 + + /** ip table + ip route add local default dev lo table 2023 + ip -6 route add local default dev lo table 2023 + */ + routes := []netlink.Route{{ + Scope: unix.RT_SCOPE_HOST, + LinkIndex: consts.LoopbackIfIndex, + Dst: &net.IPNet{ + IP: []byte{0, 0, 0, 0}, + Mask: net.CIDRMask(0, 32), + }, + Table: table, + Type: unix.RTN_LOCAL, + }, { + Scope: unix.RT_SCOPE_HOST, + LinkIndex: consts.LoopbackIfIndex, + Dst: &net.IPNet{ + IP: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + Mask: net.CIDRMask(0, 128), + }, + Table: table, + Type: unix.RTN_LOCAL, + }} + cleanRoutes := func() error { + var errs error + for _, route := range routes { + if e := netlink.RouteDel(&route); e != nil { + if errs != nil { + errs = fmt.Errorf("%w; %v", errs, e) + } else { + errs = e + } + } + } + if errs != nil { + return fmt.Errorf("IpRouteDel(lo): %w", errs) + } + return nil + } +tryRouteAddAgain: + for _, route := range routes { + if err = netlink.RouteAdd(&route); err != nil { + if os.IsExist(err) { + _ = cleanRoutes() + goto tryRouteAddAgain + } + return fmt.Errorf("IpRouteAdd: %w", err) + } + } + c.deferFuncs = append(c.deferFuncs, cleanRoutes) + + /** ip rule + ip rule add fwmark 0x8000000/0x8000000 table 2023 + ip -6 rule add fwmark 0x8000000/0x8000000 table 2023 + */ + rules := []netlink.Rule{{ + SuppressIfgroup: -1, + SuppressPrefixlen: -1, + Priority: -1, + Goto: -1, + Flow: -1, + Family: unix.AF_INET, + Table: table, + Mark: int(consts.TproxyMark), + Mask: int(consts.TproxyMark), + }, { + SuppressIfgroup: -1, + SuppressPrefixlen: -1, + Priority: -1, + Goto: -1, + Flow: -1, + Family: unix.AF_INET6, + Table: table, + Mark: int(consts.TproxyMark), + Mask: int(consts.TproxyMark), + }} + cleanRules := func() error { + var errs error + for _, rule := range rules { + if e := netlink.RuleDel(&rule); e != nil { + if errs != nil { + errs = fmt.Errorf("%w; %v", errs, e) + } else { + errs = e + } + } + } + if errs != nil { + return fmt.Errorf("IpRuleDel: %w", errs) + } + return nil + } +tryRuleAddAgain: + for _, rule := range rules { + if err = netlink.RuleAdd(&rule); err != nil { + if os.IsExist(err) { + _ = cleanRules() + goto tryRuleAddAgain + } + return fmt.Errorf("IpRuleAdd: %w", err) + } + } + c.deferFuncs = append(c.deferFuncs, cleanRules) + return nil +} + func (c *ControlPlaneCore) bindLan(ifname string) error { c.log.Infof("Bind to LAN: %v", ifname) diff --git a/control/kern/tproxy.c b/control/kern/tproxy.c index b3488e4..4de449c 100644 --- a/control/kern/tproxy.c +++ b/control/kern/tproxy.c @@ -65,6 +65,8 @@ #define IS_WAN 0 #define IS_LAN 1 +#define TPROXY_MARK 0x8000000 + #define ESOCKTNOSUPPORT 94 /* Socket type not supported */ enum { BPF_F_CURRENT_NETNS = -1 }; @@ -1218,8 +1220,8 @@ int tproxy_lan_egress(struct __sk_buff *skb) { ori_src.ip, false, true))) { return TC_ACT_SHOT; } - if ((ret = rewrite_port(skb, l4proto, ihl, tuples.sport, ori_src.port, false, - true))) { + if ((ret = rewrite_port(skb, l4proto, ihl, tuples.sport, ori_src.port, + false, true))) { return TC_ACT_SHOT; } disable_l4_checksum(skb, l4proto, ihl); @@ -1326,8 +1328,8 @@ new_connection: bpf_htonl((ethh.h_source[2] << 24) + (ethh.h_source[3] << 16) + (ethh.h_source[4] << 8) + (ethh.h_source[5])), }; - if ((ret = routing(flag, l4hdr, tuples.sip.u6_addr32, tuples.dip.u6_addr32, - mac)) < 0) { + if ((ret = routing(flag, l4hdr, tuples.sip.u6_addr32, + tuples.dip.u6_addr32, mac)) < 0) { bpf_printk("shot routing: %d", ret); return TC_ACT_SHOT; } @@ -1394,10 +1396,7 @@ control_plane_tproxy: } assign: - if ((ret = bpf_skb_change_type(skb, 0))) { - bpf_printk("failed to change type"); - goto sk_shot; - } + skb->mark = TPROXY_MARK; ret = bpf_sk_assign(skb, sk, 0); bpf_sk_release(sk); if (ret) { @@ -1802,30 +1801,36 @@ int tproxy_wan_ingress(struct __sk_buff *skb) { __u16 tproxy_typ = bpf_ntohs(*(__u16 *)ðh.h_source[4]); if (*(__u32 *)ðh.h_source[0] != bpf_htonl(0x02000203) || tproxy_typ > 1) { // Check for security. Reject packets that is UDP and sent to tproxy port. - __be16 *tproxy_port = bpf_map_lookup_elem(¶m_map, &tproxy_port_key); - if (!tproxy_port) { - goto accept; - } - if (unlikely(*tproxy_port == tuples.dport)) { - struct bpf_sock_tuple tuple = {0}; - __u32 tuple_size; - - if (ipversion == 4) { - tuple.ipv4.daddr = tuples.dip.u6_addr32[3]; - tuple.ipv4.dport = tuples.dport; - tuple_size = sizeof(tuple.ipv4); - } else { - __builtin_memcpy(tuple.ipv6.daddr, &tuples.dip, IPV6_BYTE_LENGTH); - tuple.ipv6.dport = tuples.dport; - tuple_size = sizeof(tuple.ipv6); + if (l4proto == IPPROTO_UDP) { + __be16 *tproxy_port = bpf_map_lookup_elem(¶m_map, &tproxy_port_key); + if (!tproxy_port) { + goto accept; } + if (unlikely(*tproxy_port == tuples.dport)) { + struct bpf_sock_tuple tuple = {0}; + __u32 tuple_size; - struct bpf_sock *sk = - bpf_sk_lookup_udp(skb, &tuple, tuple_size, BPF_F_CURRENT_NETNS, 0); - if (sk) { - // Scope is host. - bpf_sk_release(sk); - return TC_ACT_SHOT; + if (ipversion == 4) { + tuple.ipv4.daddr = tuples.dip.u6_addr32[3]; + tuple.ipv4.saddr = tuples.sip.u6_addr32[3]; + tuple.ipv4.dport = tuples.dport; + tuple.ipv4.sport = tuples.sport; + tuple_size = sizeof(tuple.ipv4); + } else { + __builtin_memcpy(tuple.ipv6.daddr, &tuples.dip, IPV6_BYTE_LENGTH); + __builtin_memcpy(tuple.ipv6.saddr, &tuples.sip, IPV6_BYTE_LENGTH); + tuple.ipv6.dport = tuples.dport; + tuple.ipv6.sport = tuples.sport; + tuple_size = sizeof(tuple.ipv6); + } + + struct bpf_sock *sk = + bpf_sk_lookup_udp(skb, &tuple, tuple_size, BPF_F_CURRENT_NETNS, 0); + if (sk) { + // Scope is host. + bpf_sk_release(sk); + return TC_ACT_SHOT; + } } } accept: @@ -1900,15 +1905,16 @@ int tproxy_wan_ingress(struct __sk_buff *skb) { } // Rewrite udp src ip - if ((ret = rewrite_ip(skb, ipversion, IPPROTO_UDP, ihl, - tuples.sip.u6_addr32, ori_src.ip, false, true))) { + if ((ret = + rewrite_ip(skb, ipversion, IPPROTO_UDP, ihl, + tuples.sip.u6_addr32, ori_src.ip, false, true))) { bpf_printk("Shot IP: %d", ret); return TC_ACT_SHOT; } // Rewrite udp src port - if ((ret = rewrite_port(skb, IPPROTO_UDP, ihl, tuples.sport, ori_src.port, - false, true))) { + if ((ret = rewrite_port(skb, IPPROTO_UDP, ihl, tuples.sport, + ori_src.port, false, true))) { bpf_printk("Shot Port: %d", ret); return TC_ACT_SHOT; } @@ -1950,8 +1956,8 @@ int tproxy_wan_ingress(struct __sk_buff *skb) { } // Rewrite dst port. - if ((ret = rewrite_port(skb, l4proto, ihl, tuples.dport, *tproxy_port, true, - true))) { + if ((ret = rewrite_port(skb, l4proto, ihl, tuples.dport, *tproxy_port, + true, true))) { bpf_printk("Shot Port: %d", ret); return TC_ACT_SHOT; }