replace xnet.Transport by xnet.Pipe
This commit is contained in:
@@ -5,6 +5,14 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type CloseRead interface {
|
||||
CloseRead() error
|
||||
}
|
||||
|
||||
type CloseWrite interface {
|
||||
CloseWrite() error
|
||||
}
|
||||
|
||||
type readWriter struct {
|
||||
io.Reader
|
||||
io.Writer
|
||||
@@ -17,6 +25,20 @@ func NewReadWriter(r io.Reader, w io.Writer) io.ReadWriter {
|
||||
}
|
||||
}
|
||||
|
||||
func (rw *readWriter) CloseRead() error {
|
||||
if sc, ok := rw.Writer.(CloseRead); ok {
|
||||
return sc.CloseRead()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rw *readWriter) CloseWrite() error {
|
||||
if sc, ok := rw.Writer.(CloseWrite); ok {
|
||||
return sc.CloseWrite()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type readWriteCloser struct {
|
||||
io.Reader
|
||||
io.Writer
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -602,7 +602,8 @@ func (h *Sniffer) handleUpgradeResponse(ctx context.Context, rw io.ReadWriter, c
|
||||
return h.sniffingWebsocketFrame(ctx, rw, cc, ro, log)
|
||||
}
|
||||
|
||||
return xnet.Transport(rw, cc)
|
||||
// return xnet.Transport(rw, cc)
|
||||
return xnet.Pipe(ctx, rw, cc)
|
||||
}
|
||||
|
||||
func (h *Sniffer) sniffingWebsocketFrame(ctx context.Context, rw, cc io.ReadWriter, ro *xrecorder.HandlerRecorderObject, log logger.Logger) error {
|
||||
@@ -861,7 +862,8 @@ func (h *Sniffer) HandleTLS(ctx context.Context, conn net.Conn, opts ...HandleOp
|
||||
}
|
||||
|
||||
log.Infof("%s <-> %s", ro.RemoteAddr, ro.Host)
|
||||
xnet.Transport(conn, cc)
|
||||
// xnet.Transport(conn, cc)
|
||||
xnet.Pipe(ctx, conn, cc)
|
||||
log.WithFields(map[string]any{
|
||||
"duration": time.Since(ro.Time),
|
||||
}).Infof("%s >-< %s", ro.RemoteAddr, ro.Host)
|
||||
|
||||
@@ -449,7 +449,8 @@ func (h *Sniffer) handleUpgradeResponse(ctx context.Context, rw io.ReadWriter, c
|
||||
return h.sniffingWebsocketFrame(ctx, rw, cc, ro, log)
|
||||
}
|
||||
|
||||
return xnet.Transport(rw, cc)
|
||||
// return xnet.Transport(rw, cc)
|
||||
return xnet.Pipe(ctx, rw, cc)
|
||||
}
|
||||
|
||||
func (h *Sniffer) sniffingWebsocketFrame(ctx context.Context, rw, cc io.ReadWriter, ro *xrecorder.HandlerRecorderObject, log logger.Logger) error {
|
||||
@@ -663,7 +664,8 @@ func (h *Sniffer) HandleTLS(ctx context.Context, conn net.Conn, opts ...HandleOp
|
||||
}
|
||||
|
||||
log.Infof("%s <-> %s", ro.RemoteAddr, ro.Host)
|
||||
xnet.Transport(conn, cc)
|
||||
// xnet.Transport(conn, cc)
|
||||
xnet.Pipe(ctx, conn, cc)
|
||||
log.WithFields(map[string]any{
|
||||
"duration": time.Since(ro.Time),
|
||||
}).Infof("%s >-< %s", ro.RemoteAddr, ro.Host)
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"net"
|
||||
|
||||
xio "github.com/go-gost/x/internal/io"
|
||||
"github.com/shadowsocks/go-shadowsocks2/core"
|
||||
)
|
||||
|
||||
@@ -40,3 +41,17 @@ func (c *shadowConn) Write(b []byte) (n int, err error) {
|
||||
_, err = c.Conn.Write(b)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *shadowConn) CloseRead() error {
|
||||
if sc, ok := c.Conn.(xio.CloseRead); ok {
|
||||
return sc.CloseRead()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *shadowConn) CloseWrite() error {
|
||||
if sc, ok := c.Conn.(xio.CloseWrite); ok {
|
||||
return sc.CloseWrite()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user