修订文档; 添加shadowsocks协议支持;目前仅支持传输tcp

This commit is contained in:
e1732a364fed
2000-01-01 00:00:00 +00:00
parent 699627612f
commit ec1ed3e8a5
12 changed files with 530 additions and 4 deletions

12
examples/ss.client.toml Normal file
View File

@@ -0,0 +1,12 @@
[[listen]]
protocol = "socks5"
host = "127.0.0.1"
port = 10800
[[dial]]
protocol = "shadowsocks"
uuid = "method:AES-128-GCM\npass:iloveverysimple" # chacha20-ietf-poly1305,AES-128-GCM, AES-256-GCM, 大小写均可在macm1 上测试 应该是 aes 更快
host = "127.0.0.1"
port = 4434
#network = "udp" # 我们默认依然是在tcp上传输 ss协议的。如果是在udp上传输的话因为暴力发包是很容易丢包的

6
examples/ss.server.toml Normal file
View File

@@ -0,0 +1,6 @@
[[listen]]
protocol = "shadowsocks"
uuid = "method:AES-128-GCM\npass:iloveverysimple"
host = "127.0.0.1"
port = 4434
#network = "udp"

7
go.mod
View File

@@ -29,6 +29,11 @@ require (
google.golang.org/protobuf v1.28.0
)
require (
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
)
require (
github.com/cheekybits/genny v1.0.0 // indirect
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
@@ -42,6 +47,8 @@ require (
github.com/marten-seemann/qtls-go1-18 v0.1.1 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/shadowsocks/go-shadowsocks2 v0.1.5
github.com/shadowsocks/shadowsocks-go v0.0.0-20200409064450-3e585ff90601
go.uber.org/multierr v1.8.0 // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/text v0.3.7 // indirect

11
go.sum
View File

@@ -10,6 +10,8 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ=
@@ -176,9 +178,15 @@ github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7q
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/refraction-networking/utls v1.1.0 h1:dKXJwSqni/t5csYJ+aQcEgqB7AMWYi6EUc9u3bEmjX0=
github.com/refraction-networking/utls v1.1.0/go.mod h1:tz9gX959MEFfFN5whTIocCLUG57WiILqtdVxI8c6Wj0=
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shadowsocks/go-shadowsocks2 v0.1.5 h1:PDSQv9y2S85Fl7VBeOMF9StzeXZyK1HakRm86CUbr28=
github.com/shadowsocks/go-shadowsocks2 v0.1.5/go.mod h1:AGGpIoek4HRno4xzyFiAtLHkOpcoznZEkAccaI/rplM=
github.com/shadowsocks/shadowsocks-go v0.0.0-20200409064450-3e585ff90601 h1:XU9hik0exChEmY92ALW4l9WnDodxLVS9yOSNh2SizaQ=
github.com/shadowsocks/shadowsocks-go v0.0.0-20200409064450-3e585ff90601/go.mod h1:mttDPaeLm87u74HMrP+n2tugXvIKWcwff/cqSX0lehY=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
@@ -241,6 +249,7 @@ golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f h1:OeJjE6G4dgCY4PIXvIRQbE8+RX+uXZyGhUy/ksMGJoc=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -298,6 +307,7 @@ golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -315,6 +325,7 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@@ -53,7 +53,7 @@ func (zw *iicsZapWriter) Write(fields ...zapcore.Field) {
//一个贯穿转发流程的关键结构,简称iics
type incomingInserverConnState struct {
id uint32 //6位数字(十进制), 用于标识每一个连接.
id uint32 //十进制固定6位随机数, 用于标识每一个连接.
// 在多路复用的情况下, 可能产生多个 IncomingInserverConnState
// 共用一个 baseLocalConn, 但是 wrappedConn 各不相同。

View File

@@ -25,6 +25,7 @@ import (
_ "github.com/e1732a364fed/v2ray_simple/advLayer/ws"
_ "github.com/e1732a364fed/v2ray_simple/proxy/dokodemo"
_ "github.com/e1732a364fed/v2ray_simple/proxy/shadowsocks"
_ "github.com/e1732a364fed/v2ray_simple/proxy/simplesocks"
_ "github.com/e1732a364fed/v2ray_simple/proxy/socks5http"
_ "github.com/e1732a364fed/v2ray_simple/proxy/trojan"

View File

@@ -0,0 +1,98 @@
package shadowsocks
import (
"io"
"net"
"net/url"
"github.com/e1732a364fed/v2ray_simple/netLayer"
"github.com/e1732a364fed/v2ray_simple/proxy"
"github.com/e1732a364fed/v2ray_simple/utils"
"github.com/shadowsocks/go-shadowsocks2/core"
)
func init() {
proxy.RegisterClient(Name, ClientCreator{})
}
type ClientCreator struct{}
func (ClientCreator) NewClientFromURL(url *url.URL) (proxy.Client, error) {
var mp MethodPass
if mp.InitWithUrl(url) {
return newClient(mp), nil
}
return nil, utils.ErrNilOrWrongParameter
}
func (ClientCreator) NewClient(dc *proxy.DialConf) (proxy.Client, error) {
uuidStr := dc.Uuid
var mp MethodPass
if mp.InitWithStr(uuidStr) {
return newClient(mp), nil
}
return nil, utils.ErrNilOrWrongParameter
}
type Client struct {
proxy.Base
utils.UserPass
cipher core.Cipher
}
func newClient(mp MethodPass) *Client {
return &Client{
cipher: initShadowCipher(mp),
}
}
func (*Client) Name() string {
return Name
}
func (c *Client) Handshake(underlay net.Conn, firstPayload []byte, target netLayer.Addr) (conn io.ReadWriteCloser, err error) {
conn = c.cipher.StreamConn(underlay)
buf := utils.GetBuf()
defer utils.PutBuf(buf)
abs, atype := target.AddressBytes()
buf.WriteByte(netLayer.ATypeToSocks5Standard(atype))
buf.Write(abs)
buf.WriteByte(byte(target.Port >> 8))
buf.WriteByte(byte(target.Port << 8 >> 8))
if len(firstPayload) > 0 {
buf.Write(firstPayload)
}
_, err = conn.Write(buf.Bytes())
return
}
func (c *Client) EstablishUDPChannel(underlay net.Conn, firstPayload []byte, target netLayer.Addr) (mc netLayer.MsgConn, err error) {
pc, ok := underlay.(net.PacketConn)
if ok {
if c.cipher != nil {
pc = c.cipher.PacketConn(pc)
}
mc = &shadowUDPPacketConn{
PacketConn: pc,
raddr: underlay.RemoteAddr(),
taddr: target.ToUDPAddr(),
}
if firstPayload != nil {
err = mc.WriteMsgTo(firstPayload, target)
}
return
}
return nil, utils.ErrNotImplemented
}

View File

@@ -0,0 +1,99 @@
package shadowsocks
import (
"bytes"
"io"
"net"
"net/url"
"github.com/e1732a364fed/v2ray_simple/netLayer"
"github.com/e1732a364fed/v2ray_simple/proxy"
"github.com/e1732a364fed/v2ray_simple/utils"
"github.com/shadowsocks/go-shadowsocks2/core"
)
func init() {
proxy.RegisterServer(Name, &ServerCreator{})
}
type ServerCreator struct{}
func (ServerCreator) NewServer(lc *proxy.ListenConf) (proxy.Server, error) {
uuidStr := lc.Uuid
var mp MethodPass
if mp.InitWithStr(uuidStr) {
return newServer(mp), nil
}
return nil, utils.ErrNilOrWrongParameter
}
func (ServerCreator) NewServerFromURL(url *url.URL) (proxy.Server, error) {
var mp MethodPass
if mp.InitWithUrl(url) {
return newServer(mp), nil
}
return nil, utils.ErrNilOrWrongParameter
}
type Server struct {
proxy.Base
*utils.MultiUserMap
cipher core.Cipher
}
func newServer(info MethodPass) *Server {
return &Server{
cipher: initShadowCipher(info),
}
}
func (*Server) Name() string {
return Name
}
func (s *Server) Handshake(underlay net.Conn) (result net.Conn, msgConn netLayer.MsgConn, targetAddr netLayer.Addr, returnErr error) {
result = s.cipher.StreamConn(underlay)
readbs := utils.GetBytes(utils.MTU)
wholeReadLen, err := result.Read(readbs)
if err != nil {
returnErr = utils.ErrInErr{ErrDesc: "read underlay failed", ErrDetail: err, Data: wholeReadLen}
return
}
readbuf := bytes.NewBuffer(readbs[:wholeReadLen])
goto realPart
errorPart:
//所返回的 buffer 必须包含所有数据,而 bytes.Buffer 是不支持回退的,所以只能重新 New
returnErr = &utils.ErrBuffer{
Err: returnErr,
Buf: bytes.NewBuffer(readbs[:wholeReadLen]),
}
return
realPart:
targetAddr, err = GetAddrFrom(readbuf)
if err != nil {
returnErr = err
goto errorPart
}
result = &netLayer.IOWrapper{
Reader: &utils.ReadWrapper{
Reader: result,
OptionalReader: io.MultiReader(readbuf, result),
RemainFirstBufLen: readbuf.Len(),
},
Writer: result,
}
return
}

View File

@@ -0,0 +1,214 @@
/*
Package shadowsocks implements shadowsocks protocol.
Reference
https://github.com/shadowsocks/shadowsocks-org/wiki/Protocol
https://github.com/shadowsocks/shadowsocks-org/wiki/AEAD-Ciphers
我参考gost的实现。gost中Connector就相当于 clientHandler就相当于 Server
但是发现似乎没法一个server同时处理tcp和udp 也就是说,只能预先指定服务端要处理的协议;
而且我看ss的标准也没有提及哪一项 可以指定 tcp/udp
总之没搞懂。目前我们ss只支持单传输层协议。
另外本包是普通的ss AEAD Ciphers 不过似乎它还是有问题。所以还要以后研究ss-2022
https://github.com/shadowsocks/shadowsocks-org/issues/183
关于ss-2022
https://github.com/shadowsocks/shadowsocks-org/issues/196
*/
package shadowsocks
import (
"errors"
"net"
"net/url"
"strings"
"github.com/e1732a364fed/v2ray_simple/netLayer"
"github.com/e1732a364fed/v2ray_simple/utils"
"github.com/shadowsocks/go-shadowsocks2/core"
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
"go.uber.org/zap"
)
const Name = "shadowsocks"
const (
ATypIP4 = 0x1
ATypDomain = 0x3
ATypIP6 = 0x4
)
//implements core.Cipher
type shadowCipher struct {
cipher *ss.Cipher
}
func (c *shadowCipher) StreamConn(conn net.Conn) net.Conn {
return ss.NewConn(conn, c.cipher.Copy())
}
func (c *shadowCipher) PacketConn(conn net.PacketConn) net.PacketConn {
return ss.NewSecurePacketConn(conn, c.cipher.Copy())
}
func initShadowCipher(info MethodPass) (cipher core.Cipher) {
var method, password = info.Method, info.Password
//根据 https://github.com/shadowsocks/shadowsocks-org/wiki/SIP002-URI-Scheme
if method == "" || password == "" {
return
}
cp, _ := ss.NewCipher(method, password)
if cp != nil {
cipher = &shadowCipher{cipher: cp}
}
if cipher == nil {
var err error
cipher, err = core.PickCipher(strings.ToUpper(method), nil, password)
if err != nil {
if ce := utils.CanLogErr("ss initShadowCipher err"); ce != nil {
ce.Write(zap.Error(err))
}
return
}
}
return
}
//依照shadowsocks协议的格式读取 地址的域名、ip、port信息 (same as socks5 and trojan)
func GetAddrFrom(buf utils.ByteReader) (addr netLayer.Addr, err error) {
var b1 byte
b1, err = buf.ReadByte()
if err != nil {
return
}
switch b1 {
case ATypDomain:
var b2 byte
b2, err = buf.ReadByte()
if err != nil {
return
}
if b2 == 0 {
err = errors.New("got ATypDomain but domain lenth is marked to be 0")
return
}
bs := utils.GetBytes(int(b2))
var n int
n, err = buf.Read(bs)
if err != nil {
return
}
if n != int(b2) {
err = utils.ErrShortRead
return
}
addr.Name = string(bs[:n])
case ATypIP4:
bs := make([]byte, 4)
var n int
n, err = buf.Read(bs)
if err != nil {
return
}
if n != 4 {
err = utils.ErrShortRead
return
}
addr.IP = bs
case ATypIP6:
bs := make([]byte, net.IPv6len)
var n int
n, err = buf.Read(bs)
if err != nil {
return
}
if n != 4 {
err = utils.ErrShortRead
return
}
addr.IP = bs
default:
err = utils.ErrInErr{ErrDesc: "shadowsocks GetAddrFrom err", ErrDetail: utils.ErrInvalidData, Data: b1}
return
}
pb1, err := buf.ReadByte()
if err != nil {
return
}
pb2, err := buf.ReadByte()
if err != nil {
return
}
port := uint16(pb1)<<8 + uint16(pb2)
if port == 0 {
err = utils.ErrInErr{ErrDesc: "shadowsocks GetAddrFrom, port is zero, which is bad", ErrDetail: utils.ErrInvalidData}
return
}
addr.Port = int(port)
return
}
type MethodPass struct {
Method, Password string
}
//require "user" and "pass" field. return true if both not empty.
func (ph *MethodPass) InitWithUrl(u *url.URL) bool {
ph.Method = u.Query().Get("method")
ph.Password = u.Query().Get("pass")
return len(ph.Method) > 0 && len(ph.Password) > 0
}
//uuid: "method:xxxx\npass:xxxx"
func (ph *MethodPass) InitWithStr(str string) (ok bool) {
str = strings.TrimSuffix(str, "\n")
strs := strings.SplitN(str, "\n", 2)
if len(strs) != 2 {
return
}
var potentialMethod, potentialPass string
ustrs := strings.SplitN(strs[0], ":", 2)
if ustrs[0] != "method" {
return
}
potentialMethod = ustrs[1]
pstrs := strings.SplitN(strs[1], ":", 2)
if pstrs[0] != "pass" {
return
}
potentialPass = pstrs[1]
if potentialMethod != "" && potentialPass != "" {
ph.Method = potentialMethod
ph.Password = potentialPass
}
ok = true
return
}

78
proxy/shadowsocks/udp.go Normal file
View File

@@ -0,0 +1,78 @@
package shadowsocks
import (
"bytes"
"net"
"github.com/e1732a364fed/v2ray_simple/netLayer"
"github.com/e1732a364fed/v2ray_simple/utils"
)
type shadowUDPPacketConn struct {
net.PacketConn
raddr net.Addr
taddr net.Addr
handshakeBuf *bytes.Buffer
}
func (c *shadowUDPPacketConn) CloseConnWithRaddr(raddr netLayer.Addr) error {
return c.PacketConn.Close()
}
func (c *shadowUDPPacketConn) Fullcone() bool {
return true
}
func (c *shadowUDPPacketConn) ReadMsgFrom() (bs []byte, targetAddr netLayer.Addr, err error) {
buf := utils.GetPacket()
var n int
n, _, err = c.PacketConn.ReadFrom(buf)
if err != nil {
return
}
readbuf := bytes.NewBuffer(buf[:n])
targetAddr, err = GetAddrFrom(readbuf)
if err != nil {
return
}
bs = readbuf.Bytes()
return
}
func (c *shadowUDPPacketConn) WriteMsgTo(bs []byte, addr netLayer.Addr) (err error) {
var buf *bytes.Buffer
if c.handshakeBuf != nil {
buf = c.handshakeBuf
c.handshakeBuf = nil
} else {
buf = utils.GetBuf()
}
abs, atype := addr.AddressBytes()
atype = netLayer.ATypeToSocks5Standard(atype)
buf.WriteByte(atype)
buf.Write(abs)
buf.WriteByte(byte(addr.Port >> 8))
buf.WriteByte(byte(addr.Port << 8 >> 8))
buf.WriteByte(byte(len(bs) >> 8))
buf.WriteByte(byte(len(bs) << 8 >> 8))
buf.Write(bs)
_, err = c.PacketConn.WriteTo(buf.Bytes(), c.raddr)
utils.PutBuf(buf)
return err
}

View File

@@ -16,8 +16,8 @@ https://datatracker.ietf.org/doc/html/rfc1929
Off Topic
总体而言vless/vmess/trojan协议借鉴了socks5有不少类似的地方。
所以制作代理, 有必要学习socks5标准。
纵观各种代理协议vless/vmess/trojan/shadowsocks协议 都借鉴了socks5有不少类似的地方。
所以 制作代理, 有必要学习socks5标准。
*/
package socks5

View File

@@ -35,7 +35,7 @@ func ListenTproxy(lc proxy.LesserConf, defaultOutClientForThis proxy.Client, rou
if ce := utils.CanLogErr("TProxy startLoopUDP DialWithOpt failed"); ce != nil {
ce.Write(zap.Error(err))
}
return nil
return
}
udpConn := uconn.(*net.UDPConn)