mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2024-11-14 21:31:16 +08:00
Chore: adjust VLESS
This commit is contained in:
parent
131e9d38b6
commit
b3ea2ff8b6
14
README.md
14
README.md
@ -132,14 +132,24 @@ Support outbound transport protocol `VLESS`.
|
||||
The XTLS only support TCP transport by the XRAY-CORE.
|
||||
```yaml
|
||||
proxies:
|
||||
- name: "vless-tcp"
|
||||
- name: "vless-tls"
|
||||
type: vless
|
||||
server: server
|
||||
port: 443
|
||||
uuid: uuid
|
||||
network: tcp
|
||||
servername: example.com
|
||||
# flow: xtls-rprx-direct # xtls-rprx-origin # enable XTLS
|
||||
udp: true
|
||||
# skip-cert-verify: true
|
||||
- name: "vless-xtls"
|
||||
type: vless
|
||||
server: server
|
||||
port: 443
|
||||
uuid: uuid
|
||||
network: tcp
|
||||
servername: example.com
|
||||
flow: xtls-rprx-direct # or xtls-rprx-origin
|
||||
# flow-show: true # print the XTLS direct log
|
||||
# udp: true
|
||||
# skip-cert-verify: true
|
||||
```
|
||||
|
@ -6,9 +6,11 @@ import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
"github.com/Dreamacro/clash/component/resolver"
|
||||
@ -20,6 +22,11 @@ import (
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
const (
|
||||
// max packet length
|
||||
maxLength = 1024 << 3
|
||||
)
|
||||
|
||||
type Vless struct {
|
||||
*Base
|
||||
client *vless.Client
|
||||
@ -39,7 +46,6 @@ type VlessOption struct {
|
||||
UUID string `proxy:"uuid"`
|
||||
Flow string `proxy:"flow,omitempty"`
|
||||
FlowShow bool `proxy:"flow-show,omitempty"`
|
||||
TLS bool `proxy:"tls,omitempty"`
|
||||
UDP bool `proxy:"udp,omitempty"`
|
||||
Network string `proxy:"network,omitempty"`
|
||||
HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"`
|
||||
@ -80,9 +86,9 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
wsOpts.Headers = header
|
||||
}
|
||||
|
||||
if v.option.TLS {
|
||||
wsOpts.TLS = true
|
||||
wsOpts.TLSConfig = &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
ServerName: host,
|
||||
InsecureSkipVerify: v.option.SkipCertVerify,
|
||||
NextProtos: []string{"http/1.1"},
|
||||
@ -92,7 +98,7 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
} else if host := wsOpts.Headers.Get("Host"); host != "" {
|
||||
wsOpts.TLSConfig.ServerName = host
|
||||
}
|
||||
}
|
||||
|
||||
c, err = vmess.StreamWebsocketConn(c, wsOpts)
|
||||
case "http":
|
||||
// readability first, so just copy default TLS logic
|
||||
@ -160,7 +166,7 @@ func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error)
|
||||
|
||||
return vless.StreamXTLSConn(conn, &xtlsOpts)
|
||||
|
||||
} else if v.option.TLS {
|
||||
} else {
|
||||
tlsOpts := vmess.TLSConfig{
|
||||
Host: host,
|
||||
SkipCertVerify: v.option.SkipCertVerify,
|
||||
@ -176,8 +182,6 @@ func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error)
|
||||
|
||||
return vmess.StreamTLSConn(conn, &tlsOpts)
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (v *Vless) isXTLSEnabled() bool {
|
||||
@ -284,28 +288,95 @@ type vlessPacketConn struct {
|
||||
net.Conn
|
||||
rAddr net.Addr
|
||||
cache [2]byte
|
||||
remain int
|
||||
mux sync.Mutex
|
||||
}
|
||||
|
||||
func (uc *vlessPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
||||
binary.BigEndian.PutUint16(uc.cache[:], uint16(len(b)))
|
||||
_, _ = uc.Conn.Write(uc.cache[:])
|
||||
return uc.Conn.Write(b)
|
||||
}
|
||||
|
||||
func (uc *vlessPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||||
n, err := uc.Conn.Read(uc.cache[:])
|
||||
if err != nil {
|
||||
return n, uc.rAddr, err
|
||||
func (vc *vlessPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
||||
total := len(b)
|
||||
if total == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
n, err = uc.Conn.Read(b)
|
||||
return n, uc.rAddr, err
|
||||
|
||||
if total < maxLength {
|
||||
return vc.writePacket(b)
|
||||
}
|
||||
|
||||
offset := 0
|
||||
for {
|
||||
cursor := offset + maxLength
|
||||
if cursor > total {
|
||||
cursor = total
|
||||
}
|
||||
|
||||
n, err := vc.writePacket(b[offset:cursor])
|
||||
if err != nil {
|
||||
return offset + n, err
|
||||
}
|
||||
|
||||
offset = cursor
|
||||
if offset == total {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return total, nil
|
||||
}
|
||||
|
||||
func (vc *vlessPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||||
vc.mux.Lock()
|
||||
defer vc.mux.Unlock()
|
||||
|
||||
if vc.remain != 0 {
|
||||
length := len(b)
|
||||
if length > vc.remain {
|
||||
length = vc.remain
|
||||
}
|
||||
|
||||
n, err := vc.Conn.Read(b[:length])
|
||||
if err != nil {
|
||||
return 0, vc.rAddr, err
|
||||
}
|
||||
|
||||
vc.remain -= n
|
||||
|
||||
return n, vc.rAddr, nil
|
||||
}
|
||||
|
||||
if _, err := vc.Conn.Read(b[:2]); err != nil {
|
||||
return 0, vc.rAddr, err
|
||||
}
|
||||
|
||||
total := int(binary.BigEndian.Uint16(b[:2]))
|
||||
if total == 0 {
|
||||
return 0, vc.rAddr, nil
|
||||
}
|
||||
|
||||
length := len(b)
|
||||
if length > total {
|
||||
length = total
|
||||
}
|
||||
|
||||
if _, err := io.ReadFull(vc.Conn, b[:length]); err != nil {
|
||||
return 0, vc.rAddr, errors.New("read packet error")
|
||||
}
|
||||
|
||||
vc.remain = total - length
|
||||
|
||||
return length, vc.rAddr, nil
|
||||
}
|
||||
|
||||
func (vc *vlessPacketConn) writePacket(payload []byte) (int, error) {
|
||||
binary.BigEndian.PutUint16(vc.cache[:], uint16(len(payload)))
|
||||
|
||||
if _, err := vc.Conn.Write(vc.cache[:]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return vc.Conn.Write(payload)
|
||||
}
|
||||
|
||||
func NewVless(option VlessOption) (*Vless, error) {
|
||||
if !option.TLS {
|
||||
return nil, fmt.Errorf("TLS must be true with vless")
|
||||
}
|
||||
|
||||
var addons *vless.Addons
|
||||
if option.Network != "ws" && len(option.Flow) >= 16 {
|
||||
option.Flow = option.Flow[:16]
|
||||
@ -315,7 +386,7 @@ func NewVless(option VlessOption) (*Vless, error) {
|
||||
Flow: option.Flow,
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported vless flow type: %s", option.Flow)
|
||||
return nil, fmt.Errorf("unsupported xtls flow type: %s", option.Flow)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,6 @@ func (t *TUN) Write(packet []byte) (int, error) {
|
||||
return t.nt.Write(packet, t.offset)
|
||||
}
|
||||
|
||||
_ = t.cache[:t.offset]
|
||||
packet = append(t.cache[:t.offset], packet...)
|
||||
|
||||
return t.nt.Write(packet, t.offset)
|
||||
|
35
test/config/vless-ws.json
Normal file
35
test/config/vless-ws.json
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"inbounds": [
|
||||
{
|
||||
"port": 10002,
|
||||
"listen": "0.0.0.0",
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"clients": [
|
||||
{
|
||||
"id": "b831381d-6324-4d53-ad4f-8cda48b30811",
|
||||
"level": 0,
|
||||
"email": "ws@example.com"
|
||||
}
|
||||
]
|
||||
},
|
||||
"streamSettings": {
|
||||
"network": "ws",
|
||||
"security": "tls",
|
||||
"tlsSettings": {
|
||||
"certificates": [
|
||||
{
|
||||
"certificateFile": "/etc/ssl/v2ray/fullchain.pem",
|
||||
"keyFile": "/etc/ssl/v2ray/privkey.pem"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom"
|
||||
}
|
||||
]
|
||||
}
|
@ -8,9 +8,9 @@
|
||||
"clients": [
|
||||
{
|
||||
"id": "b831381d-6324-4d53-ad4f-8cda48b30811",
|
||||
"email": "xtls@example.com",
|
||||
"flow": "xtls-rprx-direct",
|
||||
"level": 0,
|
||||
"email": "love@example.com"
|
||||
"level": 0
|
||||
}
|
||||
],
|
||||
"decryption": "none"
|
||||
|
@ -37,7 +37,6 @@ func TestClash_VlessTLS(t *testing.T) {
|
||||
Server: localIP.String(),
|
||||
Port: 10002,
|
||||
UUID: "b831381d-6324-4d53-ad4f-8cda48b30811",
|
||||
TLS: true,
|
||||
SkipCertVerify: true,
|
||||
ServerName: "example.org",
|
||||
UDP: true,
|
||||
@ -75,7 +74,6 @@ func TestClash_VlessXTLS(t *testing.T) {
|
||||
Server: localIP.String(),
|
||||
Port: 10002,
|
||||
UUID: "b831381d-6324-4d53-ad4f-8cda48b30811",
|
||||
TLS: true,
|
||||
SkipCertVerify: true,
|
||||
ServerName: "example.org",
|
||||
UDP: true,
|
||||
@ -89,3 +87,41 @@ func TestClash_VlessXTLS(t *testing.T) {
|
||||
time.Sleep(waitTime)
|
||||
testSuit(t, proxy)
|
||||
}
|
||||
|
||||
func TestClash_VlessWS(t *testing.T) {
|
||||
cfg := &container.Config{
|
||||
Image: ImageVmess,
|
||||
ExposedPorts: defaultExposedPorts,
|
||||
}
|
||||
hostCfg := &container.HostConfig{
|
||||
PortBindings: defaultPortBindings,
|
||||
Binds: []string{
|
||||
fmt.Sprintf("%s:/etc/v2ray/config.json", C.Path.Resolve("vless-ws.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, "vless-ws")
|
||||
if err != nil {
|
||||
assert.FailNow(t, err.Error())
|
||||
}
|
||||
defer cleanContainer(id)
|
||||
|
||||
proxy, err := outbound.NewVless(outbound.VlessOption{
|
||||
Name: "vless",
|
||||
Server: localIP.String(),
|
||||
Port: 10002,
|
||||
UUID: "b831381d-6324-4d53-ad4f-8cda48b30811",
|
||||
SkipCertVerify: true,
|
||||
ServerName: "example.org",
|
||||
Network: "ws",
|
||||
UDP: true,
|
||||
})
|
||||
if err != nil {
|
||||
assert.FailNow(t, err.Error())
|
||||
}
|
||||
|
||||
time.Sleep(waitTime)
|
||||
testSuit(t, proxy)
|
||||
}
|
||||
|
@ -35,15 +35,6 @@ type DstAddr struct {
|
||||
Port uint
|
||||
}
|
||||
|
||||
// Config of vless
|
||||
type Config struct {
|
||||
UUID string
|
||||
AlterID uint16
|
||||
Security string
|
||||
Port string
|
||||
HostName string
|
||||
}
|
||||
|
||||
// Client is vless connection generator
|
||||
type Client struct {
|
||||
uuid *uuid.UUID
|
||||
|
Loading…
Reference in New Issue
Block a user