Skip to content
This repository has been archived by the owner on Mar 17, 2024. It is now read-only.

Commit

Permalink
使用uuid作为特殊指令,避免0rtt时的探测攻击;新增Makefile
Browse files Browse the repository at this point in the history
新增的Makefile可以自动将版本号写入程序中。目前默认编译四种环境下的可执行文件
  • Loading branch information
e1732a364fed committed Mar 14, 2022
1 parent 7437968 commit 43f475e
Show file tree
Hide file tree
Showing 9 changed files with 228 additions and 58 deletions.
30 changes: 30 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
BUILD_VERSION := v1.0.2

prefix:=verysimple

cmd:=go build -trimpath -ldflags "-X 'main.Version=${BUILD_VERSION}' -s -w -buildid=" -o

all: win10 linux_amd64 linux_arm64 macos_arm64



linux_amd64:
GOARCH=amd64 GOOS=linux $(cmd) ${prefix}_linux_amd64_${BUILD_VERSION}

linux_arm64:
GOARCH=arm64 GOOS=linux $(cmd) ${prefix}_linux_arm64_${BUILD_VERSION}

#我只提供mac 的apple silicon版本.

macos_arm64:
GOARCH=arm64 GOOS=darwin $(cmd) ${prefix}_macos_${BUILD_VERSION}

win10:
GOARCH=amd64 GOOS=windows $(cmd) ${prefix}_win10_${BUILD_VERSION}.exe


clean:
rm -f ${prefix}_linux_amd64_${BUILD_VERSION}
rm -f ${prefix}_linux_arm64_${BUILD_VERSION}
rm -f ${prefix}_win10_${BUILD_VERSION}.exe
rm -f ${prefix}_macos_${BUILD_VERSION}
19 changes: 15 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ V2ray Simple, 建议读作 very simple (显然只适用于汉语母语者),

verysimple项目大大简化了 转发机制,能提高运行速度。本项目 转发流量时,关键代码直接放在main.go里!非常直白易懂

正式项目名称是v2ray simple(大小写、带不带连词符或下划线均可),平时可以直接用 verysimple 指代。直接在任何场合 用verysimple 这个名称都是可以的,但是项目名字要弄清楚,是 v2ray_simple
正式项目名称是v2ray simple(大小写、带不带连词符或下划线均可),平时可以直接用 verysimple 指代。直接在任何场合 用verysimple 这个名称都是可以的,但是项目名字要弄清楚,是 v2ray_simple。交流时可简称 "vs"。

规定,编译出的文件名必须是 verysimple开头.


## 特点
Expand Down Expand Up @@ -172,9 +174,9 @@ verysimple 继承 v2simple的一个优点,就是服务端的配置也可以用
版本号自己修改下即可

```sh
GOARCH=amd64 GOOS=linux go build -trimpath -ldflags "-s -w -buildid=" -o v2ray_simple_linux_amd64_v1.0.1
GOARCH=arm64 GOOS=linux go build -trimpath -ldflags "-s -w -buildid=" -o v2ray_simple_linux_arm64_v1.0.1
GOARCH=amd64 GOOS=windows go build -trimpath -ldflags "-s -w -buildid=" -o v2ray_simple_win10_v1.0.1.exe
GOARCH=amd64 GOOS=linux go build -trimpath -ldflags "-s -w -buildid=" -o v2ray_simple_linux_amd64_v1.0.2
GOARCH=arm64 GOOS=linux go build -trimpath -ldflags "-s -w -buildid=" -o v2ray_simple_linux_arm64_v1.0.2
GOARCH=amd64 GOOS=windows go build -trimpath -ldflags "-s -w -buildid=" -o v2ray_simple_win10_v1.0.2.exe
```

## 生成自签名证书
Expand Down Expand Up @@ -246,3 +248,12 @@ https://github.com/librespeed/speedtest-go

https://t.me/shadowrocket_unofficial


# 免责声明

MIT协议!我不负任何责任。本项目只是个代理项目,适合内网测试使用,以及适合阅读代码了解原理。

你如果用于任何其它目的,我不会帮助你。

我只会帮助研究理论的朋友。而且我不帮你你也没话说,MIT协议。

60 changes: 45 additions & 15 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"net"
"os"
"os/signal"
"runtime"
"strings"
"syscall"
"time"
Expand All @@ -25,8 +24,7 @@ import (
)

var (
version = "1.0.0"
desc = "v2ray_simple, a very simple implementation of V2Ray, 并且在某些地方试图走在v2ray前面"
desc = "v2ray_simple, a very simple implementation of V2Ray, 并且在某些地方试图走在v2ray前面"

configFileName string

Expand All @@ -50,8 +48,8 @@ func init() {
flag.StringVar(&uniqueTestDomain, "td", "", "test a single domain, like www.domain.com")
}

func printVersion() {
fmt.Printf("===============================\nv2ray_simple %v (%v), %v %v %v\n", version, desc, runtime.Version(), runtime.GOOS, runtime.GOARCH)
func printDesc() {
printVersion()
proxy.PrintAllServerNames()

proxy.PrintAllClientNames()
Expand Down Expand Up @@ -83,7 +81,7 @@ func loadConfig(fileName string) (*Config, error) {

func main() {

printVersion()
printDesc()

flag.Parse()

Expand Down Expand Up @@ -347,7 +345,14 @@ func handleNewIncomeConnection(localServer proxy.Server, remoteClient proxy.Clie
if tls_lazy_secure {
// 如果使用secure办法,则我们每次不能先拨号,而是要detect用户的首包后再拨号
// 这种情况只需要客户端操作, 此时我们wrc直接传入原始的 刚拨号好的 tcp连接,即 clientConn
tryRawCopy(true, client, realTargetAddr, clientConn, wlc, nil, true, nil)

// 而且为了避免黑客攻击或探测,我们要使用uuid作为特殊指令,此时需要 UserServer和 UserClient

if uc := client.(proxy.UserClient); uc != nil {
tryRawCopy(true, uc, nil, realTargetAddr, clientConn, wlc, nil, true, nil)

}

return

} else {
Expand Down Expand Up @@ -377,13 +382,25 @@ func handleNewIncomeConnection(localServer proxy.Server, remoteClient proxy.Clie
if tls_lazy_encrypt {
isclient := client.IsUseTLS()
if isclient {
tryRawCopy(false, nil, nil, wrc, wlc, baseLocalConn, true, clientEndRemoteClientTlsRawReadRecorder)

//必须是 UserClient
if userClient := client.(proxy.UserClient); userClient != nil {
tryRawCopy(false, userClient, nil, nil, wrc, wlc, baseLocalConn, true, clientEndRemoteClientTlsRawReadRecorder)
return
}

} else {
tryRawCopy(false, nil, nil, wrc, wlc, baseLocalConn, false, serverEndLocalServerTlsRawReadRecorder)

// 最新代码已经确认,使用uuid 作为 “特殊指令”,所以要求Server必须是一个 proxy.UserServer
// 否则将无法开启splice功能。这是为了防止0-rtt 探测

if userServer := localServer.(proxy.UserServer); userServer != nil {
tryRawCopy(false, nil, userServer, nil, wrc, wlc, baseLocalConn, false, serverEndLocalServerTlsRawReadRecorder)
return
}

}

return
}

/*
Expand All @@ -406,7 +423,7 @@ func handleNewIncomeConnection(localServer proxy.Server, remoteClient proxy.Clie
//和 xtls的splice 含义相同
// 我们内部先 使用 DetectConn进行过滤分析,然后再判断进化为splice 或者退化为普通拷贝
// 前两个参数仅用于 tls_lazy_secure
func tryRawCopy(useSecureMethod bool, proxy_client proxy.Client, clientAddr *proxy.Addr, wrc, wlc io.ReadWriter, localConn net.Conn, isclient bool, theRecorder *tlsLayer.Recorder) {
func tryRawCopy(useSecureMethod bool, proxy_client proxy.UserClient, proxy_server proxy.UserServer, clientAddr *proxy.Addr, wrc, wlc io.ReadWriter, localConn net.Conn, isclient bool, theRecorder *tlsLayer.Recorder) {

//如果用了 lazy_encrypt, 则不直接利用Copy,因为有两个阶段:判断阶段和直连阶段
// 在判断阶段,因为还没确定是否是 tls,所以是要继续用tls加密的,
Expand All @@ -424,6 +441,14 @@ func tryRawCopy(useSecureMethod bool, proxy_client proxy.Client, clientAddr *pro
wlcdc := wlc.(*tlsLayer.DetectConn)
wlccc_raw := wlcdc.RawConn

if isclient {
sc := []byte(proxy_client.GetUser().GetIdentityBytes())
wlcdc.R.SpecialCommandBytes = sc
wlcdc.W.SpecialCommandBytes = sc
} else {
wlcdc.R.UH = proxy_server
}

var rawWRC *net.TCPConn

if !useSecureMethod {
Expand Down Expand Up @@ -462,7 +487,7 @@ func tryRawCopy(useSecureMethod bool, proxy_client proxy.Client, clientAddr *pro
return
}
} else {
rawWRC = wrc.(*net.TCPConn)
rawWRC = wrc.(*net.TCPConn) //useSecureMethod的一定是客户端,此时就是直接给出原始连接
}

waitWRC_CreateChan := make(chan int)
Expand Down Expand Up @@ -491,7 +516,7 @@ func tryRawCopy(useSecureMethod bool, proxy_client proxy.Client, clientAddr *pro
checkCount++

if useSecureMethod && checkCount == 1 {
//此时还未dial,需要进行dial
//此时还未dial,需要进行dial; 仅限客户端

if tlsLayer.PDD {
log.Println(" 才开始Dial 服务端")
Expand Down Expand Up @@ -529,13 +554,13 @@ func tryRawCopy(useSecureMethod bool, proxy_client proxy.Client, clientAddr *pro

if isclient {

// 果是client,因为client是在Read时判断的 IsTLS,所以特殊指令实际上是要在这里发送
// 若是client,因为client是在Read时判断的 IsTLS,所以特殊指令实际上是要在这里发送

if tlsLayer.PDD {
log.Println("R 准备发送特殊命令, 以及保存的TLS内容", len(p[:n]))
}

wrc.Write(tlsLayer.SpecialCommand)
wrc.Write(wlcdc.R.SpecialCommandBytes)

//然后还要发送第一段FreeData

Expand All @@ -548,6 +573,11 @@ func tryRawCopy(useSecureMethod bool, proxy_client proxy.Client, clientAddr *pro

//theRecorder.DigestAll()

//这个瞬间,R是存放了 SpecialCommand了(即uuid),然而W还是没有的 ,
// 所以我们要先给W的SpecialCommand 赋值

wlcdc.W.SpecialCommandBytes = wlcdc.R.SpecialCommandBytes

rawBuf := theRecorder.GetLast()
bs := rawBuf.Bytes()

Expand Down
10 changes: 0 additions & 10 deletions proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,16 +101,6 @@ import (
"github.com/hahahrfool/v2ray_simple/tlsLayer"
)

type User interface {
GetIdentityStr() string //每个user唯一,通过比较这个string 即可 判断两个User 是否相等
}

type UserConn interface {
io.ReadWriter
User
GetProtocolVersion() int
}

// 给一个节点 提供 VSI中 第 5-7层 的支持
type ProxyCommon interface {
AddrStr() string //地址,在server就是监听地址,在client就是拨号地址
Expand Down
54 changes: 45 additions & 9 deletions proxy/id.go → proxy/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,60 @@ import (
"crypto/md5"
"encoding/hex"
"errors"
"io"
"strings"
)

type ID struct {
UUID [16]byte
CmdKey [16]byte
type User interface {
GetIdentityStr() string //每个user唯一,通过比较这个string 即可 判断两个User 是否相等

GetIdentityBytes() []byte
}

type UserClient interface {
Client
GetUser() User
}

func NewID(s string) (*ID, error) {
type UserContainer interface {
GetUserByStr(idStr string) User
GetUserByBytes(bs []byte) User

//tlsLayer.UserHaser
HasUserByBytes(bs []byte) bool
UserBytesLen() int
}

type UserServer interface {
Server
UserContainer
}

type UserConn interface {
io.ReadWriter
User
GetProtocolVersion() int
}

//一种专门用于v2ray协议族的 User
func (u V2rayUser) GetIdentityStr() string {
return UUIDToStr(u)
}

func (u V2rayUser) GetIdentityBytes() []byte {
return u[:]
}

//一种专门用于v2ray协议族的 结构 (vmess/vless), 实现 User 接口
type V2rayUser [16]byte

func NewV2rayUser(s string) (*V2rayUser, error) {
uuid, err := StrToUUID(s)
if err != nil {
return nil, err
}
id := &ID{
UUID: uuid,
}
copy(id.CmdKey[:], Get_cmdKey(uuid))
return id, nil

return (*V2rayUser)(&uuid), nil
}

func StrToUUID(s string) (uuid [16]byte, err error) {
Expand Down
12 changes: 8 additions & 4 deletions proxy/vless/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ func init() {
proxy.RegisterClient(Name, NewVlessClient)
}

//实现 proxy.UserClient
type Client struct {
proxy.ProxyCommonStruct

udpResponseChan chan *proxy.UDPAddrData

version int

user *proxy.ID
user *proxy.V2rayUser

is_CRUMFURS_established bool

Expand All @@ -39,7 +40,7 @@ type Client struct {
func NewVlessClient(url *url.URL) (proxy.Client, error) {
addr := url.Host
uuidStr := url.User.Username()
id, err := proxy.NewID(uuidStr)
id, err := proxy.NewV2rayUser(uuidStr)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -67,6 +68,9 @@ func NewVlessClient(url *url.URL) (proxy.Client, error) {

func (c *Client) Name() string { return Name }
func (c *Client) Version() int { return c.version }
func (c *Client) GetUser() proxy.User {
return c.user
}

func (c *Client) Handshake(underlay net.Conn, target *proxy.Addr) (io.ReadWriter, error) {
var err error
Expand Down Expand Up @@ -130,7 +134,7 @@ func (c *Client) Handshake(underlay net.Conn, target *proxy.Addr) (io.ReadWriter

return &UserConn{
Conn: underlay,
uuid: c.user.UUID,
uuid: *c.user,
version: c.version,
isUDP: target.IsUDP,
}, err
Expand Down Expand Up @@ -189,7 +193,7 @@ func (c *Client) getBufWithCmd(cmd byte) *bytes.Buffer {
v := c.version
buf := common.GetBuf()
buf.WriteByte(byte(v)) //version
buf.Write(c.user.UUID[:])
buf.Write(c.user[:])
if v == 0 {
buf.WriteByte(0) //addon length
}
Expand Down
Loading

0 comments on commit 43f475e

Please sign in to comment.