replace xnet.Transport by xnet.Pipe

This commit is contained in:
ginuerzh
2025-07-28 20:52:15 +08:00
parent 35a049fb03
commit 208d18125c
52 changed files with 468 additions and 104 deletions
-4
View File
@@ -193,7 +193,3 @@ func (r *IPRange) Parse(s string) error {
func (r *IPRange) Contains(addr netip.Addr) bool {
return !(addr.Less(r.Min) || r.Max.Less(addr))
}
type ClientAddr interface {
ClientAddr() net.Addr
}
+4 -4
View File
@@ -135,7 +135,7 @@ func (d *Dialer) dialOnce(ctx context.Context, network, addr, ifceName string, i
}
err = sc.Control(func(fd uintptr) {
if ifceName != "" {
if err := bindDevice(network, fd, ifceName); err != nil {
if err := bindDevice(network, addr, fd, ifceName); err != nil {
log.Warnf("bind device: %v", err)
}
}
@@ -159,13 +159,13 @@ func (d *Dialer) dialOnce(ctx context.Context, network, addr, ifceName string, i
Control: func(network, address string, c syscall.RawConn) error {
return c.Control(func(fd uintptr) {
if ifceName != "" {
if err := bindDevice(network, fd, ifceName); err != nil {
log.Warnf("bind device: %v", err)
if err := bindDevice(network, address, fd, ifceName); err != nil {
log.Warnf("%s/%s bind device: %v", address, network, err)
}
}
if d.Mark != 0 {
if err := setMark(fd, d.Mark); err != nil {
log.Warnf("set mark: %v", err)
log.Warnf("%s/%s set mark: %v", address, network, err)
}
}
})
+8 -3
View File
@@ -7,18 +7,23 @@ import (
"golang.org/x/sys/unix"
)
func bindDevice(network string, fd uintptr, ifceName string) error {
func bindDevice(network, address string, fd uintptr, ifceName string) error {
if ifceName == "" {
return nil
}
host, _, _ := net.SplitHostPort(address)
if ip := net.ParseIP(host); ip != nil && !ip.IsGlobalUnicast() {
return nil
}
ifce, err := net.InterfaceByName(ifceName)
if err == nil {
if err != nil {
return err
}
switch network {
case "tcp", "tcp4", "udp4":
case "tcp", "tcp4", "udp", "udp4":
return unix.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BOUND_IF, ifce.Index)
case "tcp6", "udp6":
return unix.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BOUND_IF, ifce.Index)
+16
View File
@@ -0,0 +1,16 @@
package dialer
import (
"golang.org/x/sys/unix"
)
func bindDevice(network, address string, fd uintptr, ifceName string) error {
return nil
}
func setMark(fd uintptr, mark int) error {
if mark != 0 {
return nil
}
return unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_USER_COOKIE, mark)
}
+9 -1
View File
@@ -1,13 +1,21 @@
package dialer
import (
"net"
"golang.org/x/sys/unix"
)
func bindDevice(network string, fd uintptr, ifceName string) error {
func bindDevice(network, address string, fd uintptr, ifceName string) error {
if ifceName == "" {
return nil
}
host, _, _ := net.SplitHostPort(address)
if ip := net.ParseIP(host); ip != nil && !ip.IsGlobalUnicast() {
return nil
}
return unix.BindToDevice(int(fd), ifceName)
}
+16
View File
@@ -0,0 +1,16 @@
package dialer
import (
"golang.org/x/sys/unix"
)
func bindDevice(network, address string, fd uintptr, ifceName string) error {
return nil
}
func setMark(fd uintptr, mark int) error {
if mark != 0 {
return nil
}
return unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RTABLE, mark)
}
+2 -2
View File
@@ -1,8 +1,8 @@
//go:build !linux && !windows && !darwin
//go:build !unix && !windows
package dialer
func bindDevice(network string, fd uintptr, ifceName string) error {
func bindDevice(network, address string, fd uintptr, ifceName string) error {
return nil
}
+16 -4
View File
@@ -13,21 +13,33 @@ const (
IPV6_UNICAST_IF = 31
)
func bindDevice(network string, fd uintptr, ifceName string) error {
func bindDevice(network, address string, fd uintptr, ifceName string) error {
if ifceName == "" {
return nil
}
host, _, _ := net.SplitHostPort(address)
ip := net.ParseIP(host)
if ip != nil && !ip.IsGlobalUnicast() {
return nil
}
ifce, err := net.InterfaceByName(ifceName)
if err == nil {
if err != nil {
return err
}
switch network {
case "tcp", "tcp4", "udp4":
case "tcp", "tcp4", "udp", "udp4":
return bindSocketToInterface4(windows.Handle(fd), uint32(ifce.Index))
case "tcp6", "udp6":
return bindSocketToInterface6(windows.Handle(fd), uint32(ifce.Index))
err = bindSocketToInterface6(windows.Handle(fd), uint32(ifce.Index))
if network == "udp6" && ip == nil {
// The underlying IP net maybe IPv4 even if the `network` param is `udp6`,
// so we should bind socket to interface4 at the same time.
err = bindSocketToInterface4(windows.Handle(fd), uint32(ifce.Index))
}
return err
}
return nil
+19
View File
@@ -9,6 +9,7 @@ import (
"strings"
"syscall"
xio "github.com/go-gost/x/internal/io"
"github.com/vishvananda/netns"
)
@@ -25,6 +26,10 @@ type RemoteAddr interface {
RemoteAddr() net.Addr
}
type ClientAddr interface {
ClientAddr() net.Addr
}
// tcpraw.TCPConn
type SetDSCP interface {
SetDSCP(int) error
@@ -119,3 +124,17 @@ func (c *readWriteConn) Read(p []byte) (int, error) {
func (c *readWriteConn) Write(p []byte) (int, error) {
return c.w.Write(p)
}
func (c *readWriteConn) CloseRead() error {
if sc, ok := c.Conn.(xio.CloseRead); ok {
return sc.CloseRead()
}
return nil
}
func (c *readWriteConn) CloseWrite() error {
if sc, ok := c.Conn.(xio.CloseWrite); ok {
return sc.CloseWrite()
}
return nil
}
+76
View File
@@ -0,0 +1,76 @@
package net
import (
"context"
"io"
"sync"
"time"
"github.com/go-gost/core/common/bufpool"
xio "github.com/go-gost/x/internal/io"
)
const (
// tcpWaitTimeout implements a TCP half-close timeout.
tcpWaitTimeout = 30 * time.Second
)
func Pipe(ctx context.Context, rw1, rw2 io.ReadWriter) error {
wg := sync.WaitGroup{}
wg.Add(2)
ch := make(chan error, 2)
go func() {
defer wg.Done()
if err := pipeBuffer(rw1, rw2, bufferSize/2); err != nil {
ch <- err
}
}()
go func() {
defer wg.Done()
if err := pipeBuffer(rw2, rw1, bufferSize/2); err != nil {
ch <- err
}
}()
done := make(chan struct{})
go func() {
wg.Wait()
close(done)
}()
select {
case <-done:
case <-ctx.Done():
return nil
}
select {
case err := <-ch:
return err
default:
}
return nil
}
func pipeBuffer(dst io.ReadWriter, src io.ReadWriter, bufferSize int) error {
buf := bufpool.Get(bufferSize)
defer bufpool.Put(buf)
_, err := io.CopyBuffer(dst, src, buf)
// Do the upload/download side TCP half-close.
if cr, ok := src.(xio.CloseRead); ok {
cr.CloseRead()
}
if cw, ok := dst.(xio.CloseWrite); ok {
cw.CloseWrite()
}
// Set TCP half-close timeout.
xio.SetReadDeadline(dst, time.Now().Add(tcpWaitTimeout))
return err
}