mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-12-24 13:27:56 +08:00
修订文档; 添加shadowsocks协议支持;目前仅支持传输tcp
This commit is contained in:
12
examples/ss.client.toml
Normal file
12
examples/ss.client.toml
Normal 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
6
examples/ss.server.toml
Normal 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
7
go.mod
@@ -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
11
go.sum
@@ -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=
|
||||
|
||||
2
iics.go
2
iics.go
@@ -53,7 +53,7 @@ func (zw *iicsZapWriter) Write(fields ...zapcore.Field) {
|
||||
|
||||
//一个贯穿转发流程的关键结构,简称iics
|
||||
type incomingInserverConnState struct {
|
||||
id uint32 //6位数字(十进制), 用于标识每一个连接.
|
||||
id uint32 //十进制固定6位随机数, 用于标识每一个连接.
|
||||
|
||||
// 在多路复用的情况下, 可能产生多个 IncomingInserverConnState,
|
||||
// 共用一个 baseLocalConn, 但是 wrappedConn 各不相同。
|
||||
|
||||
1
main.go
1
main.go
@@ -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"
|
||||
|
||||
98
proxy/shadowsocks/client.go
Normal file
98
proxy/shadowsocks/client.go
Normal 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
|
||||
}
|
||||
99
proxy/shadowsocks/server.go
Normal file
99
proxy/shadowsocks/server.go
Normal 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
|
||||
}
|
||||
214
proxy/shadowsocks/shadowsocks.go
Normal file
214
proxy/shadowsocks/shadowsocks.go
Normal 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就相当于 client,Handler就相当于 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
78
proxy/shadowsocks/udp.go
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user