mirror of
https://github.com/p4gefau1t/trojan-go.git
synced 2026-10-19 16:15:38 +00:00
add http proxy, fix bugs
This commit is contained in:
+4
-4
@@ -11,19 +11,19 @@ type RewindReader struct {
|
||||
rawReader io.Reader
|
||||
buf []byte
|
||||
bufReadIdx int
|
||||
rewinded bool
|
||||
rewound bool
|
||||
buffering bool
|
||||
bufferSize int
|
||||
}
|
||||
|
||||
func (r *RewindReader) Read(p []byte) (int, error) {
|
||||
if r.rewinded {
|
||||
if r.rewound {
|
||||
if len(r.buf) > r.bufReadIdx {
|
||||
n := copy(p, r.buf[r.bufReadIdx:])
|
||||
r.bufReadIdx += n
|
||||
return n, nil
|
||||
}
|
||||
r.rewinded = false //all buffering content has been read
|
||||
r.rewound = false //all buffering content has been read
|
||||
}
|
||||
n, err := r.rawReader.Read(p)
|
||||
if r.buffering {
|
||||
@@ -62,7 +62,7 @@ func (r *RewindReader) Rewind() {
|
||||
if r.bufferSize == 0 {
|
||||
panic("has no buffer")
|
||||
}
|
||||
r.rewinded = true
|
||||
r.rewound = true
|
||||
r.bufReadIdx = 0
|
||||
}
|
||||
|
||||
|
||||
+21
-4
@@ -4,7 +4,8 @@ import (
|
||||
"context"
|
||||
"github.com/p4gefau1t/trojan-go/config"
|
||||
"github.com/p4gefau1t/trojan-go/proxy"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel/adapter"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel/http"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel/mux"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel/router"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel/shadowsocks"
|
||||
@@ -43,16 +44,32 @@ func GenerateClientTree(transportPlugin bool, muxEnabled bool, wsEnabled bool, s
|
||||
func init() {
|
||||
proxy.RegisterProxyCreator(Name, func(ctx context.Context) (*proxy.Proxy, error) {
|
||||
cfg := config.FromContext(ctx, Name).(*Config)
|
||||
serverStack := []string{socks.Name}
|
||||
|
||||
transportServer, err := transport.NewServer(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
root := &proxy.Node{
|
||||
Name: transport.Name,
|
||||
Next: make(map[string]*proxy.Node),
|
||||
IsEndpoint: false,
|
||||
Context: ctx,
|
||||
Server: transportServer,
|
||||
}
|
||||
|
||||
root.BuildNext(adapter.Name).BuildNext(http.Name).IsEndpoint = true
|
||||
root.BuildNext(adapter.Name).BuildNext(socks.Name).IsEndpoint = true
|
||||
|
||||
clientStack := GenerateClientTree(cfg.TransportPlugin.Enabled, cfg.Mux.Enabled, cfg.Websocket.Enabled, cfg.Shadowsocks.Enabled, cfg.Router.Enabled)
|
||||
c, err := proxy.CreateClientStack(ctx, clientStack)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s, err := proxy.CreateServerStack(ctx, serverStack)
|
||||
s := proxy.FindAllEndpoints(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proxy.NewProxy(ctx, []tunnel.Server{s}, c), nil
|
||||
return proxy.NewProxy(ctx, s, c), nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ const Name = "SERVER"
|
||||
func init() {
|
||||
proxy.RegisterProxyCreator(Name, func(ctx context.Context) (*proxy.Proxy, error) {
|
||||
cfg := config.FromContext(ctx, Name).(*client.Config)
|
||||
s, err := transport.NewServer(ctx, nil)
|
||||
transportServer, err := transport.NewServer(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -35,7 +35,7 @@ func init() {
|
||||
Next: make(map[string]*proxy.Node),
|
||||
IsEndpoint: false,
|
||||
Context: ctx,
|
||||
Server: s,
|
||||
Server: transportServer,
|
||||
}
|
||||
|
||||
if !cfg.TransportPlugin.Enabled {
|
||||
|
||||
@@ -23,6 +23,8 @@ import (
|
||||
_ "net/http/pprof"
|
||||
)
|
||||
|
||||
// test key and cert
|
||||
|
||||
var cert = `
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDZTCCAk0CFFphZh018B5iAD9F5fV4y0AlD0LxMA0GCSqGSIb3DQEBCwUAMG8x
|
||||
@@ -293,7 +295,7 @@ transport-plugin:
|
||||
enabled: true
|
||||
type: plaintext
|
||||
shadowsocks:
|
||||
enabled: false
|
||||
enabled: true
|
||||
method: AEAD_CHACHA20_POLY1305
|
||||
password: 12345678
|
||||
mux:
|
||||
@@ -316,7 +318,7 @@ transport-plugin:
|
||||
enabled: true
|
||||
type: plaintext
|
||||
shadowsocks:
|
||||
enabled: false
|
||||
enabled: true
|
||||
method: AEAD_CHACHA20_POLY1305
|
||||
password: 12345678
|
||||
websocket:
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
package adapter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/p4gefau1t/trojan-go/common"
|
||||
"github.com/p4gefau1t/trojan-go/log"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel/http"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel/socks"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel/transport"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
underlay tunnel.Server
|
||||
socksConn chan tunnel.Conn
|
||||
httpConn chan tunnel.Conn
|
||||
nextSocks bool
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func (s *Server) acceptConnLoop() {
|
||||
for {
|
||||
conn, err := s.underlay.AcceptConn(&Tunnel{})
|
||||
if err != nil {
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
log.Debug("exiting")
|
||||
return
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
rewindConn := common.NewRewindConn(conn)
|
||||
rewindConn.SetBufferSize(16)
|
||||
buf := [3]byte{}
|
||||
_, err = rewindConn.Read(buf[:])
|
||||
rewindConn.Rewind()
|
||||
rewindConn.StopBuffering()
|
||||
if err != nil {
|
||||
log.Error(common.NewError("failed to detect proxy protocol type").Base(err))
|
||||
continue
|
||||
}
|
||||
if buf[0] == 5 && s.nextSocks {
|
||||
log.Debug("socks5 connection")
|
||||
s.socksConn <- &transport.Conn{
|
||||
Conn: rewindConn,
|
||||
}
|
||||
} else {
|
||||
log.Debug("http connection")
|
||||
s.httpConn <- &transport.Conn{
|
||||
Conn: rewindConn,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) AcceptConn(overlay tunnel.Tunnel) (tunnel.Conn, error) {
|
||||
if _, ok := overlay.(*http.Tunnel); ok {
|
||||
select {
|
||||
case conn := <-s.httpConn:
|
||||
return conn, nil
|
||||
case <-s.ctx.Done():
|
||||
return nil, common.NewError("adapter closed")
|
||||
}
|
||||
} else if _, ok := overlay.(*socks.Tunnel); ok {
|
||||
s.nextSocks = true
|
||||
select {
|
||||
case conn := <-s.socksConn:
|
||||
return conn, nil
|
||||
case <-s.ctx.Done():
|
||||
return nil, common.NewError("adapter closed")
|
||||
}
|
||||
} else {
|
||||
panic("invalid overlay")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) AcceptPacket(tunnel.Tunnel) (tunnel.PacketConn, error) {
|
||||
// no packet conn available, but it's ok to stuck here
|
||||
<-s.ctx.Done()
|
||||
return nil, common.NewError("adapter server closed")
|
||||
}
|
||||
|
||||
func (s *Server) Close() error {
|
||||
s.cancel()
|
||||
return s.underlay.Close()
|
||||
}
|
||||
|
||||
func NewServer(ctx context.Context, underlay tunnel.Server) (*Server, error) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
server := &Server{
|
||||
underlay: underlay,
|
||||
socksConn: make(chan tunnel.Conn, 32),
|
||||
httpConn: make(chan tunnel.Conn, 32),
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
}
|
||||
go server.acceptConnLoop()
|
||||
return server, nil
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package adapter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel"
|
||||
)
|
||||
|
||||
const Name = "ADAPTER"
|
||||
|
||||
type Tunnel struct{}
|
||||
|
||||
func (t *Tunnel) Name() string {
|
||||
return Name
|
||||
}
|
||||
|
||||
func (t *Tunnel) NewClient(ctx context.Context, client tunnel.Client) (tunnel.Client, error) {
|
||||
panic("not supported")
|
||||
}
|
||||
|
||||
func (t *Tunnel) NewServer(ctx context.Context, server tunnel.Server) (tunnel.Server, error) {
|
||||
return NewServer(ctx, server)
|
||||
}
|
||||
|
||||
func init() {
|
||||
tunnel.RegisterTunnel(Name, &Tunnel{})
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package dokodemo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"github.com/p4gefau1t/trojan-go/common"
|
||||
"net"
|
||||
|
||||
"github.com/p4gefau1t/trojan-go/tunnel"
|
||||
@@ -58,15 +58,15 @@ func (c *PacketConn) ReadWithMetadata(p []byte) (int, *tunnel.Metadata, error) {
|
||||
n := copy(p, payload)
|
||||
return n, c.M, nil
|
||||
case <-c.Ctx.Done():
|
||||
return 0, nil, io.EOF
|
||||
return 0, nil, common.NewError("dokodemo packet conn closed")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *PacketConn) WriteWithMetadata(p []byte, m *tunnel.Metadata) (int, error) {
|
||||
select {
|
||||
case c.Output <- p:
|
||||
return len(p), nil
|
||||
case <-c.Ctx.Done():
|
||||
return 0, io.EOF
|
||||
return 0, common.NewError("dokodemo packet conn failed to write")
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/p4gefau1t/trojan-go/common"
|
||||
"github.com/p4gefau1t/trojan-go/config"
|
||||
"github.com/p4gefau1t/trojan-go/test/util"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel/transport"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHTTP(t *testing.T) {
|
||||
port := common.PickPort("tcp", "127.0.0.1")
|
||||
ctx := config.WithConfig(context.Background(), transport.Name, &transport.Config{
|
||||
LocalHost: "127.0.0.1",
|
||||
LocalPort: port,
|
||||
})
|
||||
|
||||
tcpServer, err := transport.NewServer(ctx, nil)
|
||||
common.Must(err)
|
||||
s, err := NewServer(ctx, tcpServer)
|
||||
common.Must(err)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
go func() {
|
||||
http.Get(fmt.Sprintf("http://127.0.0.1:%d", port))
|
||||
}()
|
||||
conn, err := s.AcceptConn(nil)
|
||||
common.Must(err)
|
||||
bufReader := bufio.NewReader(bufio.NewReader(conn))
|
||||
req, err := http.ReadRequest(bufReader)
|
||||
fmt.Println(req)
|
||||
ioutil.ReadAll(req.Body)
|
||||
req.Body.Close()
|
||||
resp := `HTTP/1.1 200 OK
|
||||
Date: Mon, 19 Jul 2004 16:18:20 GMT
|
||||
Server: Apache
|
||||
Last-Modified: Sat, 10 Jul 2004 17:29:19 GMT
|
||||
ETag: "1d0325-2470-40f0276f"
|
||||
Accept-Ranges: bytes
|
||||
Content-Length: 4
|
||||
Connection: close
|
||||
Content-Type: text/html
|
||||
|
||||
1234
|
||||
`
|
||||
_, err = conn.Write([]byte(resp))
|
||||
common.Must(err)
|
||||
buf := [100]byte{}
|
||||
_, err = conn.Read(buf[:])
|
||||
if err == nil {
|
||||
t.Fail()
|
||||
}
|
||||
conn.Close()
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("CONNECT", "https://google.com:443", nil)
|
||||
common.Must(err)
|
||||
conn1, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", port))
|
||||
common.Must(err)
|
||||
req.Write(conn1)
|
||||
|
||||
conn2, err := s.AcceptConn(nil)
|
||||
common.Must(err)
|
||||
|
||||
if conn2.Metadata().Port != 443 || conn2.Metadata().DomainName != "google.com" {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
connResp := "HTTP/1.1 200 Connection established\r\n\r\n"
|
||||
buf := make([]byte, len(connResp))
|
||||
conn1.Read(buf)
|
||||
if string(buf) != connResp {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if !util.CheckConn(conn1, conn2) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
conn1.Close()
|
||||
conn2.Close()
|
||||
s.Close()
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/p4gefau1t/trojan-go/common"
|
||||
"github.com/p4gefau1t/trojan-go/log"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ConnectConn struct {
|
||||
net.Conn
|
||||
metadata *tunnel.Metadata
|
||||
}
|
||||
|
||||
func (c *ConnectConn) Metadata() *tunnel.Metadata {
|
||||
return c.metadata
|
||||
}
|
||||
|
||||
type OtherConn struct {
|
||||
net.Conn
|
||||
metadata *tunnel.Metadata //fixed
|
||||
reqReader *io.PipeReader
|
||||
respWriter *io.PipeWriter
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func (c *OtherConn) Metadata() *tunnel.Metadata {
|
||||
return c.metadata
|
||||
}
|
||||
|
||||
func (c *OtherConn) Read(p []byte) (int, error) {
|
||||
n, err := c.reqReader.Read(p)
|
||||
if err == io.EOF {
|
||||
if n != 0 {
|
||||
panic("non zero")
|
||||
}
|
||||
select {
|
||||
case <-c.ctx.Done():
|
||||
return 0, common.NewError("http conn closed")
|
||||
}
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (c *OtherConn) Write(p []byte) (int, error) {
|
||||
return c.respWriter.Write(p)
|
||||
}
|
||||
|
||||
func (c *OtherConn) Close() error {
|
||||
c.cancel()
|
||||
c.reqReader.Close()
|
||||
c.respWriter.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
underlay tunnel.Server
|
||||
connChan chan tunnel.Conn
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func (s *Server) acceptLoop() {
|
||||
for {
|
||||
conn, err := s.underlay.AcceptConn(&Tunnel{})
|
||||
if err != nil {
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
log.Error(common.NewError("http closed"))
|
||||
return
|
||||
default:
|
||||
log.Error(common.NewError("http failed to accept connection").Base(err))
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
go func(conn net.Conn) {
|
||||
reqBufReader := bufio.NewReader(ioutil.NopCloser(conn))
|
||||
req, err := http.ReadRequest(reqBufReader)
|
||||
if err != nil {
|
||||
log.Error(common.NewError("not a valid http request").Base(err))
|
||||
return
|
||||
}
|
||||
if strings.ToUpper(req.Method) == "CONNECT" { // CONNECT
|
||||
addr, err := tunnel.NewAddressFromAddr("tcp", req.Host)
|
||||
if err != nil {
|
||||
log.Error(common.NewError("invalid http dest address").Base(err))
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
resp := fmt.Sprintf("HTTP/%d.%d 200 Connection established\r\n\r\n", req.ProtoMajor, req.ProtoMinor)
|
||||
_, err = conn.Write([]byte(resp))
|
||||
if err != nil {
|
||||
log.Error("http failed to respond connect request")
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
s.connChan <- &ConnectConn{
|
||||
Conn: conn,
|
||||
metadata: &tunnel.Metadata{
|
||||
Address: addr,
|
||||
},
|
||||
}
|
||||
} else { // GET, POST, PUT...
|
||||
defer conn.Close()
|
||||
for {
|
||||
ctx, cancel := context.WithCancel(s.ctx)
|
||||
reqReader, reqWriter := io.Pipe()
|
||||
respReader, respWriter := io.Pipe()
|
||||
var addr *tunnel.Address
|
||||
_, strPort, err := net.SplitHostPort(req.Host)
|
||||
if err != nil {
|
||||
if strPort == "" { //default port 80
|
||||
addr = tunnel.NewAddressFromHostPort("tcp", req.Host, 80)
|
||||
}
|
||||
} else {
|
||||
addr, err = tunnel.NewAddressFromAddr("tcp", req.Host)
|
||||
if err != nil {
|
||||
log.Error(common.NewError("invalid http dest address").Base(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
log.Debug("http dest", addr)
|
||||
newConn := &OtherConn{
|
||||
Conn: conn,
|
||||
metadata: &tunnel.Metadata{
|
||||
Address: addr,
|
||||
},
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
reqReader: reqReader,
|
||||
respWriter: respWriter,
|
||||
}
|
||||
s.connChan <- newConn // pass this http session connection to proxy.RelayConn
|
||||
|
||||
err = req.Write(reqWriter) // write request to the remote
|
||||
if err != nil {
|
||||
log.Error(common.NewError("http failed to write http request").Base(err))
|
||||
return
|
||||
}
|
||||
|
||||
respBufReader := bufio.NewReader(ioutil.NopCloser(respReader)) // read response from the remote
|
||||
resp, err := http.ReadResponse(respBufReader, req)
|
||||
if err != nil {
|
||||
log.Error(common.NewError("http failed to read http response").Base(err))
|
||||
return
|
||||
}
|
||||
err = resp.Write(conn) // send the response back to the local
|
||||
if err != nil {
|
||||
log.Error(common.NewError("http failed to write the response back").Base(err))
|
||||
return
|
||||
}
|
||||
newConn.Close()
|
||||
req.Body.Close()
|
||||
resp.Body.Close()
|
||||
|
||||
req, err = http.ReadRequest(reqBufReader) //read the next http request from local
|
||||
if err != nil {
|
||||
log.Error(common.NewError("http failed to the read request from local").Base(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}(conn)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) AcceptConn(tunnel.Tunnel) (tunnel.Conn, error) {
|
||||
select {
|
||||
case conn := <-s.connChan:
|
||||
return conn, nil
|
||||
case <-s.ctx.Done():
|
||||
return nil, common.NewError("http server closed")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) AcceptPacket(tunnel.Tunnel) (tunnel.PacketConn, error) {
|
||||
<-s.ctx.Done()
|
||||
return nil, common.NewError("http server closed")
|
||||
}
|
||||
|
||||
func (s *Server) Close() error {
|
||||
s.cancel()
|
||||
return s.underlay.Close()
|
||||
}
|
||||
|
||||
func NewServer(ctx context.Context, underlay tunnel.Server) (*Server, error) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
server := &Server{
|
||||
underlay: underlay,
|
||||
connChan: make(chan tunnel.Conn, 32),
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
}
|
||||
go server.acceptLoop()
|
||||
return server, nil
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel"
|
||||
)
|
||||
|
||||
const Name = "HTTP"
|
||||
|
||||
type Tunnel struct{}
|
||||
|
||||
func (t *Tunnel) Name() string {
|
||||
return Name
|
||||
}
|
||||
|
||||
func (t *Tunnel) NewClient(ctx context.Context, client tunnel.Client) (tunnel.Client, error) {
|
||||
panic("not supported")
|
||||
}
|
||||
|
||||
func (t *Tunnel) NewServer(ctx context.Context, server tunnel.Server) (tunnel.Server, error) {
|
||||
return NewServer(ctx, server)
|
||||
}
|
||||
|
||||
func init() {
|
||||
tunnel.RegisterTunnel(Name, &Tunnel{})
|
||||
}
|
||||
@@ -15,7 +15,7 @@ type Client struct {
|
||||
}
|
||||
|
||||
func (c *Client) DialConn(address *tunnel.Address, tunnel tunnel.Tunnel) (tunnel.Conn, error) {
|
||||
conn, err := c.underlay.DialConn(address, tunnel)
|
||||
conn, err := c.underlay.DialConn(address, &Tunnel{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ type Server struct {
|
||||
}
|
||||
|
||||
func (s *Server) AcceptConn(overlay tunnel.Tunnel) (tunnel.Conn, error) {
|
||||
conn, err := s.underlay.AcceptConn(overlay)
|
||||
conn, err := s.underlay.AcceptConn(&Tunnel{})
|
||||
if err != nil {
|
||||
return nil, common.NewError("shadowsocks failed to accept connection from underlying tunnel")
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@ package socks
|
||||
import "github.com/p4gefau1t/trojan-go/config"
|
||||
|
||||
type Config struct {
|
||||
LocalHost string `json:"local_addr" yaml:"local-addr"`
|
||||
LocalPort int `json:"local_port" yaml:"local-port"`
|
||||
UDPTimeout int `json:"udp_timeout" yaml:"udp-timeout"`
|
||||
UDPTimeout int `json:"udp_timeout" yaml:"udp-timeout"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
+16
-21
@@ -26,13 +26,13 @@ const (
|
||||
|
||||
// Server is a socks5 server
|
||||
type Server struct {
|
||||
connChan chan tunnel.Conn
|
||||
packetChan chan tunnel.PacketConn
|
||||
tcpListener net.Listener
|
||||
localHost string
|
||||
timeout time.Duration
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
connChan chan tunnel.Conn
|
||||
packetChan chan tunnel.PacketConn
|
||||
underlay tunnel.Server
|
||||
localHost string
|
||||
timeout time.Duration
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func (s *Server) AcceptConn(tunnel.Tunnel) (tunnel.Conn, error) {
|
||||
@@ -55,7 +55,7 @@ func (s *Server) AcceptPacket(tunnel.Tunnel) (tunnel.PacketConn, error) {
|
||||
|
||||
func (s *Server) Close() error {
|
||||
s.cancel()
|
||||
return s.tcpListener.Close()
|
||||
return s.underlay.Close()
|
||||
}
|
||||
|
||||
func (s *Server) handshake(conn net.Conn) (*Conn, error) {
|
||||
@@ -110,7 +110,7 @@ func (s *Server) associate(conn net.Conn, addr *tunnel.Address) error {
|
||||
|
||||
func (s *Server) acceptLoop() {
|
||||
for {
|
||||
conn, err := s.tcpListener.Accept()
|
||||
conn, err := s.underlay.AcceptConn(&Tunnel{})
|
||||
if err != nil {
|
||||
log.Error(common.NewError("socks5 accept err").Base(err))
|
||||
return
|
||||
@@ -134,6 +134,7 @@ func (s *Server) acceptLoop() {
|
||||
case Associate:
|
||||
defer newConn.Close()
|
||||
port := common.PickPort("udp", s.localHost)
|
||||
// TODO use underlying server
|
||||
associateAddr := tunnel.NewAddressFromHostPort("udp", s.localHost, port)
|
||||
l, err := net.ListenPacket("udp", associateAddr.String())
|
||||
if err != nil {
|
||||
@@ -160,22 +161,16 @@ func (s *Server) acceptLoop() {
|
||||
// NewServer create a socks server
|
||||
func NewServer(ctx context.Context, underlay tunnel.Server) (tunnel.Server, error) {
|
||||
cfg := config.FromContext(ctx, Name).(*Config)
|
||||
listenAddr := tunnel.NewAddressFromHostPort("tcp", cfg.LocalHost, cfg.LocalPort)
|
||||
l, err := net.Listen("tcp", listenAddr.String())
|
||||
if err != nil {
|
||||
return nil, common.NewError("socks5 failed to listen").Base(err)
|
||||
}
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
server := &Server{
|
||||
tcpListener: l,
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
connChan: make(chan tunnel.Conn, 32),
|
||||
packetChan: make(chan tunnel.PacketConn, 32),
|
||||
timeout: time.Duration(cfg.UDPTimeout) * time.Second,
|
||||
underlay: underlay,
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
connChan: make(chan tunnel.Conn, 32),
|
||||
packetChan: make(chan tunnel.PacketConn, 32),
|
||||
timeout: time.Duration(cfg.UDPTimeout) * time.Second,
|
||||
}
|
||||
go server.acceptLoop()
|
||||
log.Info("socks5 server is listening on tcp:", l.Addr().String())
|
||||
log.Debug("socks server created")
|
||||
return server, nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/p4gefau1t/trojan-go/config"
|
||||
"github.com/p4gefau1t/trojan-go/test/util"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel"
|
||||
"github.com/p4gefau1t/trojan-go/tunnel/transport"
|
||||
"golang.org/x/net/proxy"
|
||||
"net"
|
||||
"sync"
|
||||
@@ -16,12 +17,17 @@ import (
|
||||
|
||||
func TestSocks(t *testing.T) {
|
||||
port := common.PickPort("tcp", "127.0.0.1")
|
||||
ctx := config.WithConfig(context.Background(), Name, &Config{
|
||||
ctx := config.WithConfig(context.Background(), transport.Name, &transport.Config{
|
||||
LocalHost: "127.0.0.1",
|
||||
LocalPort: port,
|
||||
})
|
||||
ctx = config.WithConfig(ctx, Name, &Config{
|
||||
UDPTimeout: 30,
|
||||
})
|
||||
tcpServer, err := transport.NewServer(ctx, nil)
|
||||
common.Must(err)
|
||||
addr := tunnel.NewAddressFromHostPort("tcp", "127.0.0.1", port)
|
||||
s, err := NewServer(ctx, nil)
|
||||
s, err := NewServer(ctx, tcpServer)
|
||||
common.Must(err)
|
||||
socksClient, err := proxy.SOCKS5("tcp", addr.String(), nil, proxy.Direct)
|
||||
common.Must(err)
|
||||
|
||||
@@ -80,7 +80,7 @@ func (s *Server) acceptLoop() {
|
||||
|
||||
func (s *Server) AcceptConn(overlay tunnel.Tunnel) (tunnel.Conn, error) {
|
||||
// TODO fix import cycle
|
||||
if overlay != nil && overlay.Name() == "WEBSOCKET" {
|
||||
if overlay != nil && (overlay.Name() == "WEBSOCKET" || overlay.Name() == "HTTP") {
|
||||
s.nextHTTP = true
|
||||
select {
|
||||
case conn := <-s.wsChan:
|
||||
|
||||
Reference in New Issue
Block a user