├── .gitignore ├── Gopkg.lock ├── Gopkg.toml ├── README.md ├── cmd ├── fioc │ └── main.go └── fiod │ └── main.go ├── http.go ├── pkg ├── bufpool │ └── bufpool.go ├── socks5 │ └── socks5.go ├── srtp │ ├── srtp.go │ └── srtp_test.go └── transfer │ └── transfer.go └── quic.go /.gitignore: -------------------------------------------------------------------------------- 1 | cmd/fiod/fiod -------------------------------------------------------------------------------- /Gopkg.lock: -------------------------------------------------------------------------------- 1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 2 | 3 | 4 | [[projects]] 5 | branch = "master" 6 | name = "github.com/aead/chacha20" 7 | packages = [ 8 | ".", 9 | "chacha" 10 | ] 11 | revision = "e2538746bfea853aaa589feb8ec46bd46ee78f86" 12 | 13 | [[projects]] 14 | branch = "master" 15 | name = "github.com/bifurcation/mint" 16 | packages = [ 17 | ".", 18 | "syntax" 19 | ] 20 | revision = "198357931e6129b810c9c77c12e0dd754846170c" 21 | 22 | [[projects]] 23 | branch = "master" 24 | name = "github.com/cheekybits/genny" 25 | packages = ["generic"] 26 | revision = "9127e812e1e9e501ce899a18121d316ecb52e4ba" 27 | 28 | [[projects]] 29 | branch = "master" 30 | name = "github.com/elazarl/goproxy" 31 | packages = ["."] 32 | revision = "a96fa3a318260eab29abaf32f7128c9eb07fb073" 33 | 34 | [[projects]] 35 | branch = "master" 36 | name = "github.com/golang/snappy" 37 | packages = ["."] 38 | revision = "553a641470496b2327abcac10b36396bd98e45c9" 39 | 40 | [[projects]] 41 | branch = "master" 42 | name = "github.com/hashicorp/golang-lru" 43 | packages = [ 44 | ".", 45 | "simplelru" 46 | ] 47 | revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3" 48 | 49 | [[projects]] 50 | branch = "master" 51 | name = "github.com/lucas-clemente/aes12" 52 | packages = ["."] 53 | revision = "cd47fb39b79f867c6e4e5cd39cf7abd799f71670" 54 | 55 | [[projects]] 56 | branch = "master" 57 | name = "github.com/lucas-clemente/quic-go" 58 | packages = [ 59 | ".", 60 | "internal/ackhandler", 61 | "internal/congestion", 62 | "internal/crypto", 63 | "internal/flowcontrol", 64 | "internal/handshake", 65 | "internal/protocol", 66 | "internal/utils", 67 | "internal/wire", 68 | "qerr" 69 | ] 70 | revision = "240896a4dd6fc56c42698bb0855166858c47fa27" 71 | 72 | [[projects]] 73 | branch = "master" 74 | name = "github.com/lucas-clemente/quic-go-certificates" 75 | packages = ["."] 76 | revision = "d2f86524cced5186554df90d92529757d22c1cb6" 77 | 78 | [[projects]] 79 | name = "github.com/pkg/errors" 80 | packages = ["."] 81 | revision = "645ef00459ed84a119197bfb8d8205042c6df63d" 82 | version = "v0.8.0" 83 | 84 | [[projects]] 85 | branch = "master" 86 | name = "golang.org/x/crypto" 87 | packages = [ 88 | "curve25519", 89 | "hkdf" 90 | ] 91 | revision = "2d027ae1dddd4694d54f7a8b6cbe78dca8720226" 92 | 93 | [[projects]] 94 | branch = "master" 95 | name = "golang.org/x/net" 96 | packages = [ 97 | "context", 98 | "internal/socks", 99 | "proxy" 100 | ] 101 | revision = "f73e4c9ed3b7ebdd5f699a16a880c2b1994e50dd" 102 | 103 | [[projects]] 104 | branch = "master" 105 | name = "golang.org/x/sync" 106 | packages = [ 107 | "errgroup", 108 | "singleflight" 109 | ] 110 | revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca" 111 | 112 | [[projects]] 113 | branch = "master" 114 | name = "golang.org/x/sys" 115 | packages = ["cpu"] 116 | revision = "7dfd1290c7917b7ba22824b9d24954ab3002fe24" 117 | 118 | [solve-meta] 119 | analyzer-name = "dep" 120 | analyzer-version = 1 121 | inputs-digest = "6fc68a9f2fb7c00f862399645449fcfa0e7e1b3e541cd9594f7d3d1e2c12705f" 122 | solver-name = "gps-cdcl" 123 | solver-version = 1 124 | -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | # Gopkg.toml example 2 | # 3 | # Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md 4 | # for detailed Gopkg.toml documentation. 5 | # 6 | # required = ["github.com/user/thing/cmd/thing"] 7 | # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] 8 | # 9 | # [[constraint]] 10 | # name = "github.com/user/project" 11 | # version = "1.0.0" 12 | # 13 | # [[constraint]] 14 | # name = "github.com/user/project2" 15 | # branch = "dev" 16 | # source = "github.com/myfork/project2" 17 | # 18 | # [[override]] 19 | # name = "github.com/x/y" 20 | # version = "2.4.0" 21 | # 22 | # [prune] 23 | # non-go = false 24 | # go-tests = true 25 | # unused-packages = true 26 | 27 | 28 | [[constraint]] 29 | name = "github.com/elazarl/goproxy" 30 | branch = "master" 31 | 32 | [[constraint]] 33 | branch = "master" 34 | name = "github.com/golang/snappy" 35 | 36 | [[constraint]] 37 | branch = "master" 38 | name = "github.com/lucas-clemente/quic-go" 39 | 40 | [[constraint]] 41 | name = "github.com/pkg/errors" 42 | version = "0.8.0" 43 | 44 | [[constraint]] 45 | branch = "master" 46 | name = "golang.org/x/net" 47 | 48 | [[constraint]] 49 | branch = "master" 50 | name = "golang.org/x/sync" 51 | 52 | [prune] 53 | go-tests = true 54 | unused-packages = true 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A QUIC based Proxy!(Just a toy) 2 | 3 | # Usage 4 | 5 | ## Install 6 | 7 | ``` 8 | # client peer 9 | go get -u -v github.com/freedomio/fio-go/cmd/fioc 10 | # server peer 11 | wget -O fiod https://github.com/freedomio/fio-go/releases/download/0.0.3/fiod 12 | chmod +x fiod 13 | # or with golang envrionment on you server computer 14 | go get -u -v github.com/freedomio/fio-go/cmd/fiod 15 | ``` 16 | 17 | ### Run 18 | 19 | ``` 20 | # On your server computer 21 | fiod -l :9093 22 | # On your pc 23 | fioc -l 127.0.0.1:8987(socks5 proxy listen) -r your_server_ip:9093 -lh 127.0.0.1:8988(http proxy listen) 24 | ``` 25 | 26 | Enjoy it! -------------------------------------------------------------------------------- /cmd/fioc/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "log" 6 | 7 | "github.com/freedomio/fio-go" 8 | ) 9 | 10 | var listenAddr = flag.String("l", "127.0.0.1:8087", "socks5 listen address") 11 | var httpLisAddr = flag.String("lh", "127.0.0.1:8887", "http listen address") 12 | var remoteAddr = flag.String("r", "8.8.8.8:8087", "remote address") 13 | 14 | type combine struct { 15 | httpProxy *fio.Http 16 | quicClient *fio.QUICClient 17 | } 18 | 19 | func newCombine(listenAddr, httpLisAddr, remoteAddr string) (*combine, error) { 20 | quicClient, err := fio.NewQUICClient(listenAddr, remoteAddr, nil, nil) 21 | if err != nil { 22 | return nil, err 23 | } 24 | httpProxy, err := fio.NewHttp(httpLisAddr, quicClient) 25 | if err != nil { 26 | return nil, err 27 | } 28 | return &combine{ 29 | httpProxy: httpProxy, 30 | quicClient: quicClient, 31 | }, nil 32 | } 33 | 34 | func (c *combine) run() { 35 | go c.httpProxy.Run() 36 | c.quicClient.Run() 37 | } 38 | 39 | func main() { 40 | flag.Parse() 41 | client, err := newCombine(*listenAddr, *httpLisAddr, *remoteAddr) 42 | if err != nil { 43 | panic(err) 44 | } 45 | log.Println("start client") 46 | client.run() 47 | } 48 | -------------------------------------------------------------------------------- /cmd/fiod/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | 6 | "github.com/freedomio/fio-go" 7 | ) 8 | 9 | var listenAddr = flag.String("l", "127.0.0.1:8087", "listen address") 10 | 11 | func main() { 12 | flag.Parse() 13 | server, err := fio.NewQUICServer(*listenAddr, nil, nil) 14 | if err != nil { 15 | panic(err) 16 | } 17 | server.Run() 18 | } 19 | -------------------------------------------------------------------------------- /http.go: -------------------------------------------------------------------------------- 1 | package fio 2 | 3 | import ( 4 | "log" 5 | "net" 6 | "net/http" 7 | 8 | "github.com/elazarl/goproxy" 9 | xproxy "golang.org/x/net/proxy" 10 | ) 11 | 12 | type quicForward struct { 13 | session *quicSession 14 | } 15 | 16 | func (f *quicForward) Dial(network, addr string) (c net.Conn, err error) { 17 | return f.session.OpenConnSync() 18 | } 19 | 20 | type Http struct { 21 | server *http.Server 22 | client *QUICClient 23 | } 24 | 25 | func NewHttp(listenAddr string, client *QUICClient) (*Http, error) { 26 | socks5Dailer, err := xproxy.SOCKS5("tcp", "0.0.0.0:0", nil, &quicForward{session: client.session}) 27 | if err != nil { 28 | return nil, err 29 | } 30 | httpProxy := goproxy.NewProxyHttpServer() 31 | httpProxy.ConnectDial = socks5Dailer.Dial 32 | return &Http{ 33 | server: &http.Server{Addr: listenAddr, Handler: httpProxy}, 34 | client: client, 35 | }, nil 36 | } 37 | 38 | func (h *Http) Run() { 39 | if err := h.server.ListenAndServe(); err != nil { 40 | log.Println(err) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /pkg/bufpool/bufpool.go: -------------------------------------------------------------------------------- 1 | package bufpool 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | var bufPool sync.Pool 8 | var bufCap = 2 * 1024 9 | 10 | // Acquire the buffer from pool. 11 | func Acquire() *[]byte { 12 | return bufPool.Get().(*[]byte) 13 | } 14 | 15 | // Giveback the buffer to pool. 16 | func Giveback(buf *[]byte) { 17 | if cap(*buf) != bufCap { 18 | panic("Giveback called with packet of wrong size!") 19 | } 20 | bufPool.Put(buf) 21 | } 22 | 23 | func init() { 24 | bufPool.New = func() interface{} { 25 | b := make([]byte, bufCap) 26 | return &b 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pkg/socks5/socks5.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "io" 7 | "net" 8 | "strconv" 9 | 10 | "github.com/pkg/errors" 11 | ) 12 | 13 | const ( 14 | socks5Version = 0x05 15 | authNone = 0x00 16 | cmdTCPConnect = 0x01 17 | 18 | atypeIPV4 = 0x01 19 | atypeDomain = 0x03 20 | atypeIPV6 = 0x04 21 | ) 22 | 23 | func format(format string) string { 24 | return fmt.Sprintf("socks5: %s", format) 25 | } 26 | 27 | // Socks5 valid socks5 protocol in server side. 28 | func Socks5(rw io.ReadWriter, buf []byte) (string, error) { 29 | _, err := io.ReadAtLeast(rw, buf, 1) 30 | if err != nil { 31 | return "", errors.Wrap(err, format("read version error")) 32 | } 33 | version := buf[0] 34 | if version != socks5Version { 35 | return "", errors.Errorf(format("unsupport version: %d"), version) 36 | } 37 | _, err = rw.Write([]byte{socks5Version, authNone}) 38 | if err != nil { 39 | return "", errors.Wrap(err, format("write method error")) 40 | } 41 | // read request infomation. 42 | _, err = io.ReadAtLeast(rw, buf, 5) 43 | if err != nil { 44 | return "", errors.Wrap(err, format("read request infomation error")) 45 | } 46 | if buf[1] != cmdTCPConnect { 47 | return "", errors.Errorf(format("unsupport cmd: %d"), buf[1]) 48 | } 49 | 50 | atype := buf[3] 51 | var host string 52 | var port uint16 53 | var hostEnd int 54 | switch atype { 55 | case atypeIPV4: 56 | hostEnd = 4 + net.IPv4len 57 | host = net.IP(buf[4:hostEnd]).String() 58 | case atypeDomain: 59 | hostEnd = int(buf[4]) + 5 60 | host = string(buf[5:hostEnd]) 61 | case atypeIPV6: 62 | hostEnd = 4 + net.IPv6len 63 | host = net.IP(buf[4:hostEnd]).String() 64 | default: 65 | return "", errors.Errorf(format("unsupport address type: %d"), atype) 66 | } 67 | port = binary.BigEndian.Uint16(buf[hostEnd : hostEnd+2]) 68 | _, err = rw.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x43}) 69 | if err != nil { 70 | return "", errors.Wrap(err, format("write response error")) 71 | } 72 | return net.JoinHostPort(host, strconv.Itoa(int(port))), nil 73 | } 74 | -------------------------------------------------------------------------------- /pkg/srtp/srtp.go: -------------------------------------------------------------------------------- 1 | package srtp 2 | 3 | import ( 4 | "encoding/binary" 5 | "math/rand" 6 | "net" 7 | ) 8 | 9 | // SRTP fake SRTP header. 10 | type SRTP struct { 11 | net.PacketConn 12 | header uint16 13 | number uint16 14 | } 15 | 16 | // WriteTo PacketConn WriteTo implement. 17 | func (s *SRTP) WriteTo(b []byte, addr net.Addr) (int, error) { 18 | s.number++ 19 | header := make([]byte, 4) 20 | binary.BigEndian.PutUint16(header[0:2], s.number) 21 | binary.BigEndian.PutUint16(header[2:4], s.number) 22 | n, err := s.PacketConn.WriteTo(append(header, b...), addr) 23 | return n - 4, err 24 | } 25 | 26 | // ReadFrom PacketConn ReadFrom implement. 27 | func (s *SRTP) ReadFrom(b []byte) (int, net.Addr, error) { 28 | n, addr, err := s.PacketConn.ReadFrom(b) 29 | b = b[4:] 30 | return n - 4, addr, err 31 | } 32 | 33 | // New returns a new SRTP instance based on the given config. 34 | func New(conn net.PacketConn) *SRTP { 35 | return &SRTP{ 36 | PacketConn: conn, 37 | header: 0xB5E8, 38 | number: uint16(rand.Intn(65536)), 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /pkg/srtp/srtp_test.go: -------------------------------------------------------------------------------- 1 | package srtp 2 | 3 | import "testing" 4 | 5 | func Test(t *testing.T) { 6 | } 7 | -------------------------------------------------------------------------------- /pkg/transfer/transfer.go: -------------------------------------------------------------------------------- 1 | package transfer 2 | 3 | import ( 4 | "io" 5 | 6 | "golang.org/x/sync/errgroup" 7 | ) 8 | 9 | // TransferBuffer between two io stream with provided buffers. 10 | func TransferBuffer(dst, src io.ReadWriter, buf1, buf2 []byte) error { 11 | var eg errgroup.Group 12 | eg.Go(func() error { 13 | _, err := io.CopyBuffer(dst, src, buf1) 14 | return err 15 | }) 16 | eg.Go(func() error { 17 | _, err := io.CopyBuffer(src, dst, buf2) 18 | return err 19 | }) 20 | return eg.Wait() 21 | } 22 | -------------------------------------------------------------------------------- /quic.go: -------------------------------------------------------------------------------- 1 | package fio 2 | 3 | import ( 4 | "crypto/rand" 5 | "crypto/rsa" 6 | "crypto/tls" 7 | "crypto/x509" 8 | "encoding/pem" 9 | "io" 10 | "log" 11 | "math/big" 12 | "net" 13 | "time" 14 | 15 | "github.com/freedomio/fio-go/pkg/bufpool" 16 | "github.com/freedomio/fio-go/pkg/socks5" 17 | "github.com/freedomio/fio-go/pkg/transfer" 18 | "github.com/lucas-clemente/quic-go" 19 | "golang.org/x/sync/singleflight" 20 | ) 21 | 22 | var defaultQuicCfg = &quic.Config{ 23 | IdleTimeout: time.Minute * 10, 24 | MaxIncomingStreams: 65535, 25 | MaxReceiveStreamFlowControlWindow: 100 * (1 << 20), 26 | MaxReceiveConnectionFlowControlWindow: 1000 * (1 << 20), 27 | } 28 | 29 | // Setup a bare-bones TLS config for the server 30 | func generateTLSConfig() *tls.Config { 31 | key, err := rsa.GenerateKey(rand.Reader, 1024) 32 | if err != nil { 33 | panic(err) 34 | } 35 | template := x509.Certificate{SerialNumber: big.NewInt(1)} 36 | certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key) 37 | if err != nil { 38 | panic(err) 39 | } 40 | keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}) 41 | certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) 42 | 43 | tlsCert, err := tls.X509KeyPair(certPEM, keyPEM) 44 | if err != nil { 45 | panic(err) 46 | } 47 | return &tls.Config{Certificates: []tls.Certificate{tlsCert}} 48 | } 49 | 50 | type quicConn struct { 51 | quic.Stream 52 | laddr net.Addr 53 | raddr net.Addr 54 | } 55 | 56 | func (c *quicConn) LocalAddr() net.Addr { 57 | return c.laddr 58 | } 59 | 60 | func (c *quicConn) RemoteAddr() net.Addr { 61 | return c.laddr 62 | } 63 | 64 | type quicSession struct { 65 | quic.Session 66 | } 67 | 68 | func (s *quicSession) OpenConnSync() (*quicConn, error) { 69 | stream, err := s.OpenStreamSync() 70 | if err != nil { 71 | return nil, err 72 | } 73 | return &quicConn{ 74 | Stream: stream, 75 | laddr: s.LocalAddr(), 76 | raddr: s.RemoteAddr(), 77 | }, nil 78 | } 79 | 80 | func (s *quicSession) AcceptConn() (*quicConn, error) { 81 | stream, err := s.AcceptStream() 82 | if err != nil { 83 | return nil, err 84 | } 85 | return &quicConn{ 86 | Stream: stream, 87 | laddr: s.LocalAddr(), 88 | raddr: s.RemoteAddr(), 89 | }, nil 90 | } 91 | 92 | type QUICClient struct { 93 | quicRemoteAddr string 94 | tlsCfg *tls.Config 95 | quicCfg *quic.Config 96 | session *quicSession 97 | lis net.Listener 98 | sf singleflight.Group 99 | } 100 | 101 | func NewQUICClient(listenAddr, quicRemoteAddr string, tlsCfg *tls.Config, quicCfg *quic.Config) (*QUICClient, error) { 102 | if tlsCfg == nil { 103 | tlsCfg = &tls.Config{InsecureSkipVerify: true} 104 | } 105 | if quicCfg == nil { 106 | quicCfg = defaultQuicCfg 107 | } 108 | lis, err := net.Listen("tcp", listenAddr) 109 | if err != nil { 110 | return nil, err 111 | } 112 | 113 | c := &QUICClient{ 114 | quicCfg: quicCfg, 115 | tlsCfg: tlsCfg, 116 | quicRemoteAddr: quicRemoteAddr, 117 | lis: lis, 118 | } 119 | c.connect() 120 | return c, nil 121 | } 122 | 123 | func (c *QUICClient) dail() error { 124 | udpAddr, err := net.ResolveUDPAddr("udp", c.quicRemoteAddr) 125 | if err != nil { 126 | return err 127 | } 128 | udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0}) 129 | if err != nil { 130 | return err 131 | } 132 | session, err := quic.Dial(udpConn, udpAddr, c.quicRemoteAddr, c.tlsCfg, c.quicCfg) 133 | if err != nil { 134 | return err 135 | } 136 | c.session = &quicSession{Session: session} 137 | return nil 138 | } 139 | 140 | func (c *QUICClient) connect() { 141 | c.sf.Do("connect", func() (interface{}, error) { 142 | for { 143 | err := c.dail() 144 | if err != nil { 145 | log.Println("dial quic server error: ", err) 146 | time.Sleep(3 * time.Second) 147 | continue 148 | } 149 | return nil, nil 150 | } 151 | }) 152 | } 153 | 154 | func (c *QUICClient) Run() { 155 | for { 156 | conn, err := c.lis.Accept() 157 | if err != nil { 158 | log.Println("tcp accept error: ", err) 159 | continue 160 | } 161 | go c.handleConn(conn) 162 | } 163 | } 164 | 165 | func (c *QUICClient) openConnSync() *quicConn { 166 | for { 167 | conn, err := c.session.OpenConnSync() 168 | if err != nil { 169 | log.Printf("open conn error: %v\n reconnecting...", err) 170 | c.connect() 171 | continue 172 | } 173 | return conn 174 | } 175 | } 176 | 177 | func (c *QUICClient) handleConn(in net.Conn) { 178 | defer in.Close() 179 | 180 | conn := c.openConnSync() 181 | defer conn.Close() 182 | 183 | buf1 := bufpool.Acquire() 184 | buf2 := bufpool.Acquire() 185 | 186 | err := transfer.TransferBuffer(conn, in, *buf1, *buf2) 187 | if err != nil { 188 | log.Println("transfer error: ", err) 189 | } 190 | bufpool.Giveback(buf1) 191 | bufpool.Giveback(buf2) 192 | } 193 | 194 | type QUICServer struct { 195 | lis quic.Listener 196 | } 197 | 198 | func NewQUICServer(listenAddr string, tlsCfg *tls.Config, quicCfg *quic.Config) (*QUICServer, error) { 199 | if tlsCfg == nil { 200 | tlsCfg = generateTLSConfig() 201 | } 202 | if quicCfg == nil { 203 | quicCfg = defaultQuicCfg 204 | } 205 | udpAddr, err := net.ResolveUDPAddr("udp", listenAddr) 206 | if err != nil { 207 | return nil, err 208 | } 209 | conn, err := net.ListenUDP("udp", udpAddr) 210 | if err != nil { 211 | return nil, err 212 | } 213 | lis, err := quic.Listen(conn, tlsCfg, quicCfg) 214 | if err != nil { 215 | return nil, err 216 | } 217 | return &QUICServer{ 218 | lis: lis, 219 | }, nil 220 | } 221 | 222 | func (s *QUICServer) Run() { 223 | for { 224 | session, err := s.lis.Accept() 225 | if err != nil { 226 | log.Println("session accpet error: ", err) 227 | continue 228 | } 229 | log.Println("new session from: ", session.RemoteAddr()) 230 | go s.handleSession(&quicSession{Session: session}) 231 | } 232 | } 233 | 234 | func (s *QUICServer) handleSession(session *quicSession) { 235 | for { 236 | conn, err := session.AcceptConn() 237 | if err != nil { 238 | log.Printf("stream accept error: %v finish session: %s\n", err, session.RemoteAddr()) 239 | return 240 | } 241 | go s.handleConn(conn) 242 | } 243 | } 244 | 245 | func (s *QUICServer) handleConn(in io.ReadWriteCloser) { 246 | defer in.Close() 247 | 248 | buf1 := bufpool.Acquire() 249 | defer bufpool.Giveback(buf1) 250 | addr, err := socks5.Socks5(in, *buf1) 251 | if err != nil { 252 | log.Println("parse socks5 error: ", err) 253 | return 254 | } 255 | log.Println("new request to: ", addr) 256 | tcpAddr, err := net.ResolveTCPAddr("tcp", addr) 257 | if err != nil { 258 | log.Println("resolve tpc address error: ", err) 259 | return 260 | } 261 | remote, err := net.DialTCP("tcp", nil, tcpAddr) 262 | if err != nil { 263 | log.Println("dial to remote error: ", err) 264 | return 265 | } 266 | defer remote.Close() 267 | 268 | buf2 := bufpool.Acquire() 269 | 270 | err = transfer.TransferBuffer(remote, in, *buf1, *buf2) 271 | if err != nil { 272 | log.Println("transfer error: ", err) 273 | } 274 | bufpool.Giveback(buf2) 275 | } 276 | --------------------------------------------------------------------------------