fix: patch old wan method

This commit is contained in:
mzz2017 2023-02-07 21:11:12 +08:00
parent 9f33ecf809
commit 45701f8559
10 changed files with 90 additions and 47 deletions

View File

@ -112,5 +112,6 @@ var (
)
const (
TproxyMark uint32 = 0x80000000
TproxyMark uint32 = 0x80000000
LoopbackIfIndex = 1
)

View File

@ -7,7 +7,6 @@ package control
import (
"context"
"encoding/hex"
"errors"
"fmt"
"github.com/cilium/ebpf"
@ -38,6 +37,7 @@ import (
type ControlPlane struct {
*ControlPlaneCore
deferFuncs []func() error
listenIp string
// TODO: add mutex?
outbounds []*outbound.DialerGroup
@ -193,16 +193,15 @@ retryLoadBpf:
_ = core.Close()
}
}()
// Bind to links. Binding should be advance of dialerGroups to avoid un-routable old connection.
for _, ifname := range lanInterface {
if err = core.BindLan(ifname); err != nil {
return nil, fmt.Errorf("BindLan: %v: %w", ifname, err)
if err = core.bindLan(ifname); err != nil {
return nil, fmt.Errorf("bindLan: %v: %w", ifname, err)
}
}
for _, ifname := range wanInterface {
if err = core.BindWan(ifname); err != nil {
return nil, fmt.Errorf("BindWan: %v: %w", ifname, err)
if err = core.bindWan(ifname); err != nil {
return nil, fmt.Errorf("bindWan: %v: %w", ifname, err)
}
}
@ -312,9 +311,14 @@ retryLoadBpf:
}
}
listenIp := "[::1]"
if len(wanInterface) > 0 {
listenIp = "0.0.0.0"
}
return &ControlPlane{
ControlPlaneCore: core,
deferFuncs: nil,
listenIp: listenIp,
outbounds: outbounds,
outboundName2Id: outboundName2Id,
SimulatedLpmTries: builder.SimulatedLpmTries,
@ -333,12 +337,13 @@ func (c *ControlPlane) ListenAndServe(port uint16) (err error) {
return dialer.TproxyControl(c)
},
}
tcpListener, err := listenConfig.Listen(context.TODO(), "tcp", "[::1]:"+strconv.Itoa(int(port)))
listenAddr := net.JoinHostPort(c.listenIp, strconv.Itoa(int(port)))
tcpListener, err := listenConfig.Listen(context.TODO(), "tcp", listenAddr)
if err != nil {
return fmt.Errorf("listenTCP: %w", err)
}
defer tcpListener.Close()
packetConn, err := listenConfig.ListenPacket(context.TODO(), "udp", "[::1]:"+strconv.Itoa(int(port)))
packetConn, err := listenConfig.ListenPacket(context.TODO(), "udp", listenAddr)
if err != nil {
return fmt.Errorf("listenUDP: %w", err)
}
@ -408,21 +413,30 @@ func (c *ControlPlane) ListenAndServe(port uint16) (err error) {
break
}
dst := RetrieveOriginalDest(oob[:oobn])
if !dst.IsValid() {
c.log.WithFields(logrus.Fields{
"source": src.String(),
"oob": hex.EncodeToString(oob[:oobn]),
}).Warnf("Failed to retrieve original dest")
continue
var newBuf []byte
outboundIndex, err := c.RetrieveOutboundIndex(src, dst, unix.IPPROTO_UDP)
if err != nil {
// WAN. Old method.
addrHdr, dataOffset, err := ParseAddrHdr(buf[:n])
if err != nil {
c.log.Warnf("No AddrPort presented")
continue
}
newBuf = pool.Get(n - dataOffset)
copy(newBuf, buf[dataOffset:n])
outboundIndex = consts.OutboundIndex(addrHdr.Outbound)
src = netip.AddrPortFrom(dst.Addr(), src.Port())
dst = addrHdr.Dest
} else {
newBuf = pool.Get(n)
copy(newBuf, buf[:n])
}
newBuf := pool.Get(n)
copy(newBuf, buf[:n])
go func(data []byte, src, dst netip.AddrPort) {
if e := c.handlePkt(newBuf, src, dst); e != nil {
go func(data []byte, src, dst netip.AddrPort, outboundIndex consts.OutboundIndex) {
if e := c.handlePkt(newBuf, src, dst, outboundIndex); e != nil {
c.log.Warnln("handlePkt:", e)
}
pool.Put(newBuf)
}(newBuf, src, dst)
}(newBuf, src, dst, outboundIndex)
}
}()
<-ctx.Done()

View File

@ -111,7 +111,7 @@ func getifParamsFromLink(link netlink.Link) (ifParams bpfIfParams, err error) {
return ifParams, nil
}
func (c *ControlPlaneCore) BindLan(ifname string) error {
func (c *ControlPlaneCore) bindLan(ifname string) error {
c.log.Infof("Bind to LAN: %v", ifname)
link, err := netlink.LinkByName(ifname)
if err != nil {
@ -123,7 +123,7 @@ func (c *ControlPlaneCore) BindLan(ifname string) error {
ip rule add fwmark 0x80000000/0x80000000 table 2023
ip route add local default dev lo table 2023
ip -6 rule add fwmark 0x80000000/0x80000000 table 2023
ip -6 route add local ::/0 dev lo table 2023
ip -6 route add local default dev lo table 2023
`).CombinedOutput(); err != nil {
return fmt.Errorf("%w: %v", err, string(bytes.TrimSpace(output)))
}
@ -132,7 +132,7 @@ func (c *ControlPlaneCore) BindLan(ifname string) error {
ip rule del fwmark 0x80000000/0x80000000 table 2023
ip route del local default dev lo table 2023
ip -6 rule del fwmark 0x80000000/0x80000000 table 2023
ip -6 route del local ::/0 dev lo table 2023
ip -6 route del local default dev lo table 2023
`).Run()
})
/// Insert an elem into IfindexParamsMap.
@ -208,12 +208,15 @@ func (c *ControlPlaneCore) BindLan(ifname string) error {
return nil
}
func (c *ControlPlaneCore) BindWan(ifname string) error {
func (c *ControlPlaneCore) bindWan(ifname string) error {
c.log.Infof("Bind to WAN: %v", ifname)
link, err := netlink.LinkByName(ifname)
if err != nil {
return err
}
if link.Attrs().Index == consts.LoopbackIfIndex {
return fmt.Errorf("cannot bind to loopback interface")
}
/// Insert an elem into IfindexParamsMap.
ifParams, err := getifParamsFromLink(link)
if err != nil {

View File

@ -18,6 +18,7 @@
// #define __DEBUG_ROUTING
// #define __PRINT_ROUTING_RESULT
// #define __PRINT_SETUP_PROCESS_CONNNECTION
// #define __REMOVE_BPF_PRINTK
#ifdef __REMOVE_BPF_PRINTK
@ -130,6 +131,8 @@ struct {
__type(key, struct tuples);
__type(value, __u32); // outbound
__uint(max_entries, MAX_DST_MAPPING_NUM);
/// NOTICE: It MUST be pinned.
__uint(pinning, LIBBPF_PIN_BY_NAME);
} routing_tuples_map SEC(".maps");
// Params:
@ -1197,6 +1200,7 @@ int tproxy_lan_ingress(struct __sk_buff *skb) {
ip -6 rule del fwmark 0x80000000/0x80000000 table 2023
ip -6 route del local ::/0 dev lo table 2023
*/
// Socket lookup and assign skb to existing socket connection.
struct bpf_sock_tuple tuple = {0};
__u32 tuple_size;
struct bpf_sock *sk;
@ -1204,7 +1208,6 @@ int tproxy_lan_ingress(struct __sk_buff *skb) {
__u32 flag[6] = {0};
void *l4hdr;
// Socket lookup and assign skb to existing socket connection.
if (ipversion == 4) {
tuple.ipv4.daddr = tuples.dst.ip[3];
tuple.ipv4.saddr = tuples.src.ip[3];
@ -1963,7 +1966,9 @@ static int __always_inline update_map_elem_by_cookie(const __u64 cookie) {
return ret;
}
#ifdef __PRINT_SETUP_PROCESS_CONNNECTION
bpf_printk("setup_mapping: %llu -> %s (%d)", cookie, val.pname, val.pid);
#endif
return 0;
}

View File

@ -41,7 +41,7 @@ func generate(output string) error {
Ebpf: structField.Tag.Get("ebpf"),
})
default:
return fmt.Errorf("unexpected prefix, should be TproxyWan or TproxyLan: %v", structField.Name)
return fmt.Errorf("unexpected program name which should begin with TproxyWan or TproxyLan, but get: %v", structField.Name)
}
}

View File

@ -9,9 +9,12 @@ import (
"fmt"
"github.com/mzz2017/softwind/pkg/zeroalloc/io"
"github.com/sirupsen/logrus"
"github.com/v2rayA/dae/common"
"github.com/v2rayA/dae/common/consts"
internal "github.com/v2rayA/dae/pkg/ebpf_internal"
"golang.org/x/sys/unix"
"net"
"net/netip"
"strings"
"time"
)
@ -20,12 +23,27 @@ func (c *ControlPlane) handleConn(lConn net.Conn) (err error) {
defer lConn.Close()
src := lConn.RemoteAddr().(*net.TCPAddr).AddrPort()
dst := lConn.LocalAddr().(*net.TCPAddr).AddrPort()
outboundIndex, _, err := c.RetrieveOutboundIndex(src, dst, unix.IPPROTO_TCP)
outboundIndex, err := c.RetrieveOutboundIndex(src, dst, unix.IPPROTO_TCP)
if err != nil {
return fmt.Errorf("RetrieveOutboundIndex: %w", err)
// WAN. Old method.
var value bpfIpPortOutbound
ip6 := src.Addr().As16()
if e := c.bpf.TcpDstMap.Lookup(bpfIpPort{
Ip: common.Ipv6ByteSliceToUint32Array(ip6[:]),
Port: internal.Htons(src.Port()),
}, &value); e != nil {
return fmt.Errorf("failed to retrieve target info %v: %v, %v", src.String(), err, e)
}
outboundIndex = consts.OutboundIndex(value.Outbound)
dstAddr, ok := netip.AddrFromSlice(common.Ipv6Uint32ArrayToByteSlice(value.Ip))
if !ok {
return fmt.Errorf("failed to parse dest ip: %v", value.Ip)
}
dst = netip.AddrPortFrom(dstAddr, internal.Htons(value.Port))
}
switch consts.OutboundIndex(outboundIndex) {
switch outboundIndex {
case consts.OutboundDirect:
case consts.OutboundControlPlaneDirect:
outboundIndex = consts.OutboundDirect

View File

@ -16,11 +16,11 @@ import (
"syscall"
)
func (c *ControlPlaneCore) RetrieveOutboundIndex(src, dst netip.AddrPort, l4proto uint8) (outboundIndex consts.OutboundIndex, tuples *bpfTuples, err error) {
func (c *ControlPlaneCore) RetrieveOutboundIndex(src, dst netip.AddrPort, l4proto uint8) (outboundIndex consts.OutboundIndex, err error) {
srcIp6 := src.Addr().As16()
dstIp6 := dst.Addr().As16()
tuples = &bpfTuples{
tuples := &bpfTuples{
Src: bpfIpPort{
Ip: common.Ipv6ByteSliceToUint32Array(srcIp6[:]),
Port: internal.Htons(src.Port()),
@ -34,12 +34,12 @@ func (c *ControlPlaneCore) RetrieveOutboundIndex(src, dst netip.AddrPort, l4prot
var _outboundIndex uint32
if err := c.bpf.RoutingTuplesMap.Lookup(tuples, &_outboundIndex); err != nil {
return 0, nil, fmt.Errorf("reading map: key [%v, %v, %v]: %w", src.String(), l4proto, dst.String(), err)
return 0, fmt.Errorf("reading map: key [%v, %v, %v]: %w", src.String(), l4proto, dst.String(), err)
}
if _outboundIndex > uint32(consts.OutboundLogicalMax) {
return 0, nil, fmt.Errorf("bad outbound index")
return 0, fmt.Errorf("bad outbound index")
}
return consts.OutboundIndex(_outboundIndex), tuples, nil
return consts.OutboundIndex(_outboundIndex), nil
}
func RetrieveOriginalDest(oob []byte) netip.AddrPort {
@ -55,7 +55,7 @@ func RetrieveOriginalDest(oob []byte) netip.AddrPort {
} else if msg.Header.Level == syscall.SOL_IPV6 && msg.Header.Type == unix.IPV6_RECVORIGDSTADDR {
ip := msg.Data[8:24]
port := binary.BigEndian.Uint16(msg.Data[2:4])
return netip.AddrPortFrom(netip.AddrFrom4(*(*[4]byte)(ip)), port)
return netip.AddrPortFrom(netip.AddrFrom16(*(*[16]byte)(ip)), port)
}
}
return netip.AddrPort{}

View File

@ -14,7 +14,6 @@ import (
"github.com/v2rayA/dae/common/consts"
"github.com/v2rayA/dae/component/outbound/dialer"
"golang.org/x/net/dns/dnsmessage"
"golang.org/x/sys/unix"
"net"
"net/netip"
"strings"
@ -123,11 +122,7 @@ func (c *ControlPlane) RelayToUDP(to netip.AddrPort, isDNS bool, dummyFrom *neti
}
}
func (c *ControlPlane) handlePkt(data []byte, src, dst netip.AddrPort) (err error) {
outboundIndex, _, err := c.RetrieveOutboundIndex(src, dst, unix.IPPROTO_UDP)
if err != nil {
return fmt.Errorf("RetrieveOutboundIndex: %w", err)
}
func (c *ControlPlane) handlePkt(data []byte, src, dst netip.AddrPort, outboundIndex consts.OutboundIndex) (err error) {
switch outboundIndex {
case consts.OutboundDirect:
case consts.OutboundControlPlaneDirect:

View File

@ -110,6 +110,13 @@ func bindAddr(fd uintptr, addrPort netip.AddrPort) error {
a6 := &syscall.SockaddrInet6{
Port: int(addrPort.Port()),
}
zone := addrPort.Addr().Zone()
if zone != "" {
//if link, e := netlink.LinkByName(zone); e == nil {
// a6.ZoneId = uint32(link.Attrs().Index)
//}
return fmt.Errorf("unsupported ipv6 zone")
}
a6.Addr = addr.As16()
sockAddr = a6
default:

View File

@ -3,7 +3,7 @@ lan=docker0
wan=wlp5s0
sudo tc qdisc add dev $lan clsact > /dev/null 2>&1
# sudo tc qdisc add dev $wan clsact > /dev/null 2>&1
sudo tc qdisc add dev $wan clsact > /dev/null 2>&1
set -ex
@ -13,11 +13,11 @@ sudo rm -rf /sys/fs/bpf/tc/globals/*
clang -O2 -g -Wall -Werror -c component/control/kern/tproxy.c -target bpf -D__TARGET_ARCH_x86 -o foo.o
sudo tc filter del dev $lan ingress
sudo tc filter del dev $lan egress
# sudo tc filter del dev $wan ingress
# sudo tc filter del dev $wan egress
sudo tc filter del dev $wan ingress
sudo tc filter del dev $wan egress
sudo tc filter add dev $lan ingress bpf direct-action obj foo.o sec tc/ingress
# sudo tc filter add dev $lan egress bpf direct-action obj foo.o sec tc/egress
# sudo tc filter add dev $wan ingress bpf direct-action obj foo.o sec tc/wan_ingress
# sudo tc filter add dev $wan egress bpf direct-action obj foo.o sec tc/wan_egress
sudo tc filter add dev $wan ingress bpf direct-action obj foo.o sec tc/wan_ingress
sudo tc filter add dev $wan egress bpf direct-action obj foo.o sec tc/wan_egress
exit 0