Feature: support vmess 'zero' security (#2513)
This commit is contained in:
parent
58732ee8b1
commit
81b1e9f931
35
test/config/vmess-ws-tls-zero.json
Normal file
35
test/config/vmess-ws-tls-zero.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"inbounds": [
|
||||||
|
{
|
||||||
|
"port": 10002,
|
||||||
|
"listen": "0.0.0.0",
|
||||||
|
"protocol": "vmess",
|
||||||
|
"settings": {
|
||||||
|
"clients": [
|
||||||
|
{
|
||||||
|
"id": "b831381d-6324-4d53-ad4f-8cda48b30811",
|
||||||
|
"alterId": 0,
|
||||||
|
"security": "zero"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"streamSettings": {
|
||||||
|
"network": "ws",
|
||||||
|
"security": "tls",
|
||||||
|
"tlsSettings": {
|
||||||
|
"certificates": [
|
||||||
|
{
|
||||||
|
"certificateFile": "/etc/ssl/v2ray/fullchain.pem",
|
||||||
|
"keyFile": "/etc/ssl/v2ray/privkey.pem"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outbounds": [
|
||||||
|
{
|
||||||
|
"protocol": "freedom"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -18,6 +18,8 @@ func TestClash_Vmess(t *testing.T) {
|
|||||||
cfg := &container.Config{
|
cfg := &container.Config{
|
||||||
Image: ImageVmess,
|
Image: ImageVmess,
|
||||||
ExposedPorts: defaultExposedPorts,
|
ExposedPorts: defaultExposedPorts,
|
||||||
|
Entrypoint: []string{"/usr/bin/v2ray"},
|
||||||
|
Cmd: []string{"run", "-c", "/etc/v2ray/config.json"},
|
||||||
}
|
}
|
||||||
hostCfg := &container.HostConfig{
|
hostCfg := &container.HostConfig{
|
||||||
PortBindings: defaultPortBindings,
|
PortBindings: defaultPortBindings,
|
||||||
@ -49,6 +51,8 @@ func TestClash_VmessTLS(t *testing.T) {
|
|||||||
cfg := &container.Config{
|
cfg := &container.Config{
|
||||||
Image: ImageVmess,
|
Image: ImageVmess,
|
||||||
ExposedPorts: defaultExposedPorts,
|
ExposedPorts: defaultExposedPorts,
|
||||||
|
Entrypoint: []string{"/usr/bin/v2ray"},
|
||||||
|
Cmd: []string{"run", "-c", "/etc/v2ray/config.json"},
|
||||||
}
|
}
|
||||||
hostCfg := &container.HostConfig{
|
hostCfg := &container.HostConfig{
|
||||||
PortBindings: defaultPortBindings,
|
PortBindings: defaultPortBindings,
|
||||||
@ -86,6 +90,8 @@ func TestClash_VmessHTTP2(t *testing.T) {
|
|||||||
cfg := &container.Config{
|
cfg := &container.Config{
|
||||||
Image: ImageVmess,
|
Image: ImageVmess,
|
||||||
ExposedPorts: defaultExposedPorts,
|
ExposedPorts: defaultExposedPorts,
|
||||||
|
Entrypoint: []string{"/usr/bin/v2ray"},
|
||||||
|
Cmd: []string{"run", "-c", "/etc/v2ray/config.json"},
|
||||||
}
|
}
|
||||||
hostCfg := &container.HostConfig{
|
hostCfg := &container.HostConfig{
|
||||||
PortBindings: defaultPortBindings,
|
PortBindings: defaultPortBindings,
|
||||||
@ -128,6 +134,8 @@ func TestClash_VmessHTTP(t *testing.T) {
|
|||||||
cfg := &container.Config{
|
cfg := &container.Config{
|
||||||
Image: ImageVmess,
|
Image: ImageVmess,
|
||||||
ExposedPorts: defaultExposedPorts,
|
ExposedPorts: defaultExposedPorts,
|
||||||
|
Entrypoint: []string{"/usr/bin/v2ray"},
|
||||||
|
Cmd: []string{"run", "-c", "/etc/v2ray/config.json"},
|
||||||
}
|
}
|
||||||
hostCfg := &container.HostConfig{
|
hostCfg := &container.HostConfig{
|
||||||
PortBindings: defaultPortBindings,
|
PortBindings: defaultPortBindings,
|
||||||
@ -178,6 +186,8 @@ func TestClash_VmessWebsocket(t *testing.T) {
|
|||||||
cfg := &container.Config{
|
cfg := &container.Config{
|
||||||
Image: ImageVmess,
|
Image: ImageVmess,
|
||||||
ExposedPorts: defaultExposedPorts,
|
ExposedPorts: defaultExposedPorts,
|
||||||
|
Entrypoint: []string{"/usr/bin/v2ray"},
|
||||||
|
Cmd: []string{"run", "-c", "/etc/v2ray/config.json"},
|
||||||
}
|
}
|
||||||
hostCfg := &container.HostConfig{
|
hostCfg := &container.HostConfig{
|
||||||
PortBindings: defaultPortBindings,
|
PortBindings: defaultPortBindings,
|
||||||
@ -211,6 +221,8 @@ func TestClash_VmessWebsocketTLS(t *testing.T) {
|
|||||||
cfg := &container.Config{
|
cfg := &container.Config{
|
||||||
Image: ImageVmess,
|
Image: ImageVmess,
|
||||||
ExposedPorts: defaultExposedPorts,
|
ExposedPorts: defaultExposedPorts,
|
||||||
|
Entrypoint: []string{"/usr/bin/v2ray"},
|
||||||
|
Cmd: []string{"run", "-c", "/etc/v2ray/config.json"},
|
||||||
}
|
}
|
||||||
hostCfg := &container.HostConfig{
|
hostCfg := &container.HostConfig{
|
||||||
PortBindings: defaultPortBindings,
|
PortBindings: defaultPortBindings,
|
||||||
@ -221,7 +233,7 @@ func TestClash_VmessWebsocketTLS(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := startContainer(cfg, hostCfg, "vmess-ws")
|
id, err := startContainer(cfg, hostCfg, "vmess-ws-tls")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
cleanContainer(id)
|
cleanContainer(id)
|
||||||
@ -244,10 +256,51 @@ func TestClash_VmessWebsocketTLS(t *testing.T) {
|
|||||||
testSuit(t, proxy)
|
testSuit(t, proxy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestClash_VmessWebsocketTLSZero(t *testing.T) {
|
||||||
|
cfg := &container.Config{
|
||||||
|
Image: ImageVmess,
|
||||||
|
ExposedPorts: defaultExposedPorts,
|
||||||
|
Entrypoint: []string{"/usr/bin/v2ray"},
|
||||||
|
Cmd: []string{"run", "-c", "/etc/v2ray/config.json"},
|
||||||
|
}
|
||||||
|
hostCfg := &container.HostConfig{
|
||||||
|
PortBindings: defaultPortBindings,
|
||||||
|
Binds: []string{
|
||||||
|
fmt.Sprintf("%s:/etc/v2ray/config.json", C.Path.Resolve("vmess-ws-tls-zero.json")),
|
||||||
|
fmt.Sprintf("%s:/etc/ssl/v2ray/fullchain.pem", C.Path.Resolve("example.org.pem")),
|
||||||
|
fmt.Sprintf("%s:/etc/ssl/v2ray/privkey.pem", C.Path.Resolve("example.org-key.pem")),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := startContainer(cfg, hostCfg, "vmess-ws-tls-zero")
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Cleanup(func() {
|
||||||
|
cleanContainer(id)
|
||||||
|
})
|
||||||
|
|
||||||
|
proxy, err := outbound.NewVmess(outbound.VmessOption{
|
||||||
|
Name: "vmess",
|
||||||
|
Server: localIP.String(),
|
||||||
|
Port: 10002,
|
||||||
|
UUID: "b831381d-6324-4d53-ad4f-8cda48b30811",
|
||||||
|
Cipher: "zero",
|
||||||
|
Network: "ws",
|
||||||
|
TLS: true,
|
||||||
|
SkipCertVerify: true,
|
||||||
|
UDP: true,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
time.Sleep(waitTime)
|
||||||
|
testSuit(t, proxy)
|
||||||
|
}
|
||||||
|
|
||||||
func TestClash_VmessGrpc(t *testing.T) {
|
func TestClash_VmessGrpc(t *testing.T) {
|
||||||
cfg := &container.Config{
|
cfg := &container.Config{
|
||||||
Image: ImageVmess,
|
Image: ImageVmess,
|
||||||
ExposedPorts: defaultExposedPorts,
|
ExposedPorts: defaultExposedPorts,
|
||||||
|
Entrypoint: []string{"/usr/bin/v2ray"},
|
||||||
|
Cmd: []string{"run", "-c", "/etc/v2ray/config.json"},
|
||||||
}
|
}
|
||||||
hostCfg := &container.HostConfig{
|
hostCfg := &container.HostConfig{
|
||||||
PortBindings: defaultPortBindings,
|
PortBindings: defaultPortBindings,
|
||||||
@ -289,6 +342,8 @@ func TestClash_VmessWebsocket0RTT(t *testing.T) {
|
|||||||
cfg := &container.Config{
|
cfg := &container.Config{
|
||||||
Image: ImageVmess,
|
Image: ImageVmess,
|
||||||
ExposedPorts: defaultExposedPorts,
|
ExposedPorts: defaultExposedPorts,
|
||||||
|
Entrypoint: []string{"/usr/bin/v2ray"},
|
||||||
|
Cmd: []string{"run", "-c", "/etc/v2ray/config.json"},
|
||||||
}
|
}
|
||||||
hostCfg := &container.HostConfig{
|
hostCfg := &container.HostConfig{
|
||||||
PortBindings: defaultPortBindings,
|
PortBindings: defaultPortBindings,
|
||||||
@ -366,6 +421,8 @@ func Benchmark_Vmess(b *testing.B) {
|
|||||||
cfg := &container.Config{
|
cfg := &container.Config{
|
||||||
Image: ImageVmess,
|
Image: ImageVmess,
|
||||||
ExposedPorts: defaultExposedPorts,
|
ExposedPorts: defaultExposedPorts,
|
||||||
|
Entrypoint: []string{"/usr/bin/v2ray"},
|
||||||
|
Cmd: []string{"run", "-c", "/etc/v2ray/config.json"},
|
||||||
}
|
}
|
||||||
hostCfg := &container.HostConfig{
|
hostCfg := &container.HostConfig{
|
||||||
PortBindings: defaultPortBindings,
|
PortBindings: defaultPortBindings,
|
||||||
|
@ -35,6 +35,7 @@ type Conn struct {
|
|||||||
respBodyKey []byte
|
respBodyKey []byte
|
||||||
respV byte
|
respV byte
|
||||||
security byte
|
security byte
|
||||||
|
option byte
|
||||||
isAead bool
|
isAead bool
|
||||||
|
|
||||||
received bool
|
received bool
|
||||||
@ -74,7 +75,7 @@ func (vc *Conn) sendRequest() error {
|
|||||||
buf.Write(vc.reqBodyIV[:])
|
buf.Write(vc.reqBodyIV[:])
|
||||||
buf.Write(vc.reqBodyKey[:])
|
buf.Write(vc.reqBodyKey[:])
|
||||||
buf.WriteByte(vc.respV)
|
buf.WriteByte(vc.respV)
|
||||||
buf.WriteByte(OptionChunkStream)
|
buf.WriteByte(vc.option)
|
||||||
|
|
||||||
p := rand.Intn(16)
|
p := rand.Intn(16)
|
||||||
// P Sec Reserve Cmd
|
// P Sec Reserve Cmd
|
||||||
@ -206,6 +207,7 @@ func newConn(conn net.Conn, id *ID, dst *DstAddr, security Security, isAead bool
|
|||||||
copy(reqBodyIV[:], randBytes[:16])
|
copy(reqBodyIV[:], randBytes[:16])
|
||||||
copy(reqBodyKey[:], randBytes[16:32])
|
copy(reqBodyKey[:], randBytes[16:32])
|
||||||
respV := randBytes[32]
|
respV := randBytes[32]
|
||||||
|
option := OptionChunkStream
|
||||||
|
|
||||||
var (
|
var (
|
||||||
respBodyKey []byte
|
respBodyKey []byte
|
||||||
@ -227,6 +229,16 @@ func newConn(conn net.Conn, id *ID, dst *DstAddr, security Security, isAead bool
|
|||||||
var writer io.Writer
|
var writer io.Writer
|
||||||
var reader io.Reader
|
var reader io.Reader
|
||||||
switch security {
|
switch security {
|
||||||
|
case SecurityZero:
|
||||||
|
security = SecurityNone
|
||||||
|
if !dst.UDP {
|
||||||
|
reader = conn
|
||||||
|
writer = conn
|
||||||
|
option = 0
|
||||||
|
} else {
|
||||||
|
reader = newChunkReader(conn)
|
||||||
|
writer = newChunkWriter(conn)
|
||||||
|
}
|
||||||
case SecurityNone:
|
case SecurityNone:
|
||||||
reader = newChunkReader(conn)
|
reader = newChunkReader(conn)
|
||||||
writer = newChunkWriter(conn)
|
writer = newChunkWriter(conn)
|
||||||
@ -267,6 +279,7 @@ func newConn(conn net.Conn, id *ID, dst *DstAddr, security Security, isAead bool
|
|||||||
reader: reader,
|
reader: reader,
|
||||||
writer: writer,
|
writer: writer,
|
||||||
security: security,
|
security: security,
|
||||||
|
option: option,
|
||||||
isAead: isAead,
|
isAead: isAead,
|
||||||
}
|
}
|
||||||
if err := c.sendRequest(); err != nil {
|
if err := c.sendRequest(); err != nil {
|
||||||
|
@ -26,15 +26,9 @@ const (
|
|||||||
SecurityAES128GCM Security = 3
|
SecurityAES128GCM Security = 3
|
||||||
SecurityCHACHA20POLY1305 Security = 4
|
SecurityCHACHA20POLY1305 Security = 4
|
||||||
SecurityNone Security = 5
|
SecurityNone Security = 5
|
||||||
|
SecurityZero Security = 6
|
||||||
)
|
)
|
||||||
|
|
||||||
// CipherMapping return
|
|
||||||
var CipherMapping = map[string]byte{
|
|
||||||
"none": SecurityNone,
|
|
||||||
"aes-128-gcm": SecurityAES128GCM,
|
|
||||||
"chacha20-poly1305": SecurityCHACHA20POLY1305,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command types
|
// Command types
|
||||||
const (
|
const (
|
||||||
CommandTCP byte = 1
|
CommandTCP byte = 1
|
||||||
@ -95,6 +89,8 @@ func NewClient(config Config) (*Client, error) {
|
|||||||
security = SecurityCHACHA20POLY1305
|
security = SecurityCHACHA20POLY1305
|
||||||
case "none":
|
case "none":
|
||||||
security = SecurityNone
|
security = SecurityNone
|
||||||
|
case "zero":
|
||||||
|
security = SecurityZero
|
||||||
case "auto":
|
case "auto":
|
||||||
security = SecurityCHACHA20POLY1305
|
security = SecurityCHACHA20POLY1305
|
||||||
if runtime.GOARCH == "amd64" || runtime.GOARCH == "s390x" || runtime.GOARCH == "arm64" {
|
if runtime.GOARCH == "amd64" || runtime.GOARCH == "s390x" || runtime.GOARCH == "arm64" {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user