add fake TCP transport
This commit is contained in:
parent
e8d5687d65
commit
c56e4aa7c2
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
203
ftcp.go
Normal 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
|
||||||
|
}
|
2
node.go
2
node.go
@ -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 = ""
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user