diff --git a/src/internal/netfilter/firewall.go b/src/internal/netfilter/firewall.go index 5f9ef7b..e48f437 100644 --- a/src/internal/netfilter/firewall.go +++ b/src/internal/netfilter/firewall.go @@ -155,6 +155,16 @@ func (f *Firewall) AddTproxyRoute(fwmark, routeTable string) error { return fmt.Errorf("cmd.Run: %w", err) } + cmd = exec.Command("ip", "-6", "rule", "add", "fwmark", fwmark, "table", routeTable) + if err := cmd.Run(); err != nil { + slog.Warn("ip -6 rule add", slog.String("error", err.Error())) + } + + cmd = exec.Command("ip", "-6", "route", "add", "local", "::/0", "dev", "lo", "table", routeTable) + if err := cmd.Run(); err != nil { + slog.Warn("ip -6 route add", slog.String("error", err.Error())) + } + return nil } @@ -165,6 +175,12 @@ func (f *Firewall) DeleteTproxyRoute(fwmark, routeTable string) error { cmd = exec.Command("ip", "route", "flush", "table", routeTable) _ = cmd.Run() + cmd = exec.Command("ip", "-6", "rule", "del", "fwmark", fwmark, "table", routeTable) + _ = cmd.Run() + + cmd = exec.Command("ip", "-6", "route", "flush", "table", routeTable) + _ = cmd.Run() + return nil } diff --git a/src/internal/server/base/tcp_linux.go b/src/internal/server/base/tcp_linux.go index 59e2154..03eeebc 100644 --- a/src/internal/server/base/tcp_linux.go +++ b/src/internal/server/base/tcp_linux.go @@ -3,10 +3,13 @@ package base import ( + "encoding/binary" "errors" "fmt" + "log/slog" "net" "syscall" + "unsafe" "golang.org/x/sys/unix" ) @@ -37,18 +40,43 @@ func GetOriginalDstAddr(conn net.Conn) (addr string, err error) { return "", errors.New("GetConnFD connection is not *net.TCPConn") } - file, err := tcpConn.File() + rawConn, err := tcpConn.SyscallConn() if err != nil { - return "", fmt.Errorf("tcpConn.File: %v", err) - } - defer file.Close() - - raw, err := unix.GetsockoptIPv6Mreq(int(file.Fd()), unix.SOL_IP, unix.SO_ORIGINAL_DST) - if err != nil { - return "", fmt.Errorf("unix.GetsockoptIPv6Mreq: %v", err) + return "", fmt.Errorf("SyscallConn: %v", err) } - ip := net.IPv4(raw.Multiaddr[4], raw.Multiaddr[5], raw.Multiaddr[6], raw.Multiaddr[7]) - port := uint16(raw.Multiaddr[2])<<8 + uint16(raw.Multiaddr[3]) - return fmt.Sprintf("%s:%d", ip.String(), port), nil + var originalAddr string + err = rawConn.Control(func(fd uintptr) { + level := syscall.IPPROTO_IP + if conn.RemoteAddr().String()[0] == '[' { + level = syscall.IPPROTO_IPV6 + } + + addr, err := syscall.GetsockoptIPv6MTUInfo(int(fd), level, unix.SO_ORIGINAL_DST) + if err != nil { + slog.Warn("unix.GetsockoptIPv6MTUInfo", "error", err) + return + } + + var ip net.IP + if level == syscall.IPPROTO_IPV6 { + ip = net.IP(addr.Addr.Addr[:]) + } else { + ipBytes := (*[4]byte)(unsafe.Pointer(&addr.Addr.Flowinfo))[:4] + ip = net.IPv4(ipBytes[0], ipBytes[1], ipBytes[2], ipBytes[3]) + } + + port := binary.BigEndian.Uint16((*[2]byte)(unsafe.Pointer(&addr.Addr.Port))[:2]) + + if level == syscall.IPPROTO_IPV6 { + originalAddr = fmt.Sprintf("[%s]:%d", ip.String(), port) + } else { + originalAddr = fmt.Sprintf("%s:%d", ip.String(), port) + } + }) + if err != nil { + return "", fmt.Errorf("rawConn.Control: %v", err) + } + + return originalAddr, nil } diff --git a/src/internal/server/tproxy/nftables.go b/src/internal/server/tproxy/nftables.go index 61320a4..e088d85 100644 --- a/src/internal/server/tproxy/nftables.go +++ b/src/internal/server/tproxy/nftables.go @@ -96,6 +96,16 @@ func (s *Server) NftSetTproxy(tx *knftables.Transaction, table *knftables.Table) "counter accept", ), }) + tx.Add(&knftables.Rule{ + Chain: sidecar.Name, + Rule: knftables.Concat( + "meta l4proto tcp", + "mark", s.tproxyFwMark, + "mark set 7894", + fmt.Sprintf("tproxy ip6 to [::1]:%d", s.Cfg.Port), + "counter accept", + ), + }) } prerouting := &knftables.Chain{ @@ -175,6 +185,15 @@ func (s *Server) NftSetTproxy(tx *knftables.Transaction, table *knftables.Table) "counter accept", ), }) + tx.Add(&knftables.Rule{ + Chain: prerouting.Name, + Rule: knftables.Concat( + "meta l4proto tcp", + "mark", s.tproxyFwMark, + fmt.Sprintf("tproxy ip6 to [::1]:%d", s.Cfg.Port), + "counter accept", + ), + }) // default less hit. sc. tx.Add(&knftables.Rule{ @@ -186,6 +205,15 @@ func (s *Server) NftSetTproxy(tx *knftables.Transaction, table *knftables.Table) "counter accept", ), }) + tx.Add(&knftables.Rule{ + Chain: prerouting.Name, + Rule: knftables.Concat( + "meta l4proto tcp", + "mark set", s.tproxyFwMark, + fmt.Sprintf("tproxy ip6 to [::1]:%d", s.Cfg.Port), + "counter accept", + ), + }) output := &knftables.Chain{ Name: "OUTPUT",