add fake TCP transport

This commit is contained in:
ginuerzh 2020-01-11 15:36:18 +08:00
parent e8d5687d65
commit c56e4aa7c2
4 changed files with 217 additions and 1 deletions

View File

@ -171,6 +171,8 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
case "ohttp": case "ohttp":
host = node.Get("host") host = node.Get("host")
tr = gost.ObfsHTTPTransporter() tr = gost.ObfsHTTPTransporter()
case "ftcp":
tr = gost.FakeTCPTransporter()
default: default:
tr = gost.TCPTransporter() tr = gost.TCPTransporter()
} }
@ -411,6 +413,15 @@ func (r *route) GenRouters() ([]router, error) {
Gateway: node.Get("gw"), Gateway: node.Get("gw"),
} }
ln, err = gost.TapListener(cfg) ln, err = gost.TapListener(cfg)
case "ftcp":
ln, err = gost.FakeTCPListener(
node.Addr,
&gost.FakeTCPListenConfig{
TTL: ttl,
Backlog: node.GetInt("backlog"),
QueueSize: node.GetInt("queue"),
},
)
default: default:
ln, err = gost.TCPListener(node.Addr) ln, err = gost.TCPListener(node.Addr)
} }

View File

@ -534,7 +534,7 @@ func (c *udpServerConn) Write(b []byte) (n int, err error) {
if n > 0 { if n > 0 {
if Debug { if Debug {
log.Logf("[udp] %s <<< %s : length %d", c.RemoteAddr(), c.LocalAddr(), n) log.Logf("[udp] %s <<< %s : length %d", c.raddr, c.LocalAddr(), n)
} }
select { select {

203
ftcp.go Normal file
View File

@ -0,0 +1,203 @@
package gost
import (
"errors"
"net"
"time"
"github.com/go-log/log"
"github.com/xtaci/tcpraw"
)
type fakeTCPTransporter struct{}
// FakeTCPTransporter creates a Transporter that is used by fake tcp client.
func FakeTCPTransporter() Transporter {
return &fakeTCPTransporter{}
}
func (tr *fakeTCPTransporter) Dial(addr string, options ...DialOption) (conn net.Conn, err error) {
opts := &DialOptions{}
for _, option := range options {
option(opts)
}
raddr, er := net.ResolveTCPAddr("tcp", addr)
if er != nil {
return nil, er
}
c, err := tcpraw.Dial("tcp", addr)
if err != nil {
return
}
conn = &fakeTCPConn{
raddr: raddr,
PacketConn: c,
}
return conn, nil
}
func (tr *fakeTCPTransporter) Handshake(conn net.Conn, options ...HandshakeOption) (net.Conn, error) {
return conn, nil
}
func (tr *fakeTCPTransporter) Multiplex() bool {
return false
}
type FakeTCPListenConfig struct {
TTL time.Duration
Backlog int
QueueSize int
}
type fakeTCPListener struct {
ln net.PacketConn
connChan chan net.Conn
errChan chan error
connMap udpConnMap
config *FakeTCPListenConfig
}
// FakeTCPListener creates a Listener for fake TCP server.
func FakeTCPListener(addr string, cfg *FakeTCPListenConfig) (Listener, error) {
ln, err := tcpraw.Listen("tcp", addr)
if err != nil {
return nil, err
}
if cfg == nil {
cfg = &FakeTCPListenConfig{}
}
backlog := cfg.Backlog
if backlog <= 0 {
backlog = defaultBacklog
}
l := &fakeTCPListener{
ln: ln,
connChan: make(chan net.Conn, backlog),
errChan: make(chan error, 1),
config: cfg,
}
go l.listenLoop()
return l, nil
}
func (l *fakeTCPListener) listenLoop() {
for {
b := make([]byte, mediumBufferSize)
n, raddr, err := l.ln.ReadFrom(b)
if err != nil {
log.Logf("[ftcp] peer -> %s : %s", l.Addr(), err)
l.Close()
l.errChan <- err
close(l.errChan)
return
}
conn, ok := l.connMap.Get(raddr.String())
if !ok {
cc := &fakeTCPConn{
raddr: raddr,
PacketConn: l.ln,
}
conn = newUDPServerConn(cc, raddr, l.config.TTL, l.config.QueueSize)
conn.onClose = func() {
l.connMap.Delete(raddr.String())
log.Logf("[ftcp] %s closed (%d)", raddr, l.connMap.Size())
}
select {
case l.connChan <- conn:
l.connMap.Set(raddr.String(), conn)
log.Logf("[ftcp] %s -> %s (%d)", raddr, l.Addr(), l.connMap.Size())
default:
conn.Close()
log.Logf("[ftcp] %s - %s: connection queue is full (%d)", raddr, l.Addr(), cap(l.connChan))
}
}
select {
case conn.rChan <- b[:n]:
if Debug {
log.Logf("[ftcp] %s >>> %s : length %d", raddr, l.Addr(), n)
}
default:
log.Logf("[ftcp] %s -> %s : recv queue is full (%d)", raddr, l.Addr(), cap(conn.rChan))
}
}
}
func (l *fakeTCPListener) Accept() (conn net.Conn, err error) {
var ok bool
select {
case conn = <-l.connChan:
case err, ok = <-l.errChan:
if !ok {
err = errors.New("accpet on closed listener")
}
}
return
}
func (l *fakeTCPListener) Addr() net.Addr {
return l.ln.LocalAddr()
}
func (l *fakeTCPListener) Close() error {
err := l.ln.Close()
l.connMap.Range(func(k interface{}, v *udpServerConn) bool {
v.Close()
return true
})
return err
}
type fakeTCPConn struct {
mss int
raddr net.Addr
net.PacketConn
}
func (c *fakeTCPConn) Read(b []byte) (n int, err error) {
n, _, err = c.ReadFrom(b)
return
}
func (c *fakeTCPConn) Write(b []byte) (n int, err error) {
return c.WriteTo(b, c.raddr)
}
func (c *fakeTCPConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
mss := c.mss
if mss <= 0 {
mss = 1460
}
for {
if len(b) == 0 {
break
}
var nn int
if len(b) <= mss {
nn, err = c.PacketConn.WriteTo(b, addr)
n += nn
break
}
nn, err = c.PacketConn.WriteTo(b[:mss], addr)
n += nn
if err != nil {
break
}
b = b[mss:]
}
return
}
func (c *fakeTCPConn) RemoteAddr() net.Addr {
return c.raddr
}

View File

@ -83,6 +83,7 @@ func ParseNode(s string) (node Node, err error) {
case "rtcp", "rudp": // rtcp and rudp are for remote port forwarding case "rtcp", "rudp": // rtcp and rudp are for remote port forwarding
case "ohttp": // obfs-http case "ohttp": // obfs-http
case "tun", "tap": // tun/tap device case "tun", "tap": // tun/tap device
case "ftcp": // fake TCP
default: default:
node.Transport = "tcp" node.Transport = "tcp"
} }
@ -95,6 +96,7 @@ func ParseNode(s string) (node Node, err error) {
case "direct", "remote", "forward": // forwarding case "direct", "remote", "forward": // forwarding
case "redirect": // TCP transparent proxy case "redirect": // TCP transparent proxy
case "tun", "tap": // tun/tap device case "tun", "tap": // tun/tap device
case "ftcp": // fake TCP
default: default:
node.Protocol = "" node.Protocol = ""
} }