Skip to content

Commit

Permalink
feat: Support REALITY protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
H1JK committed Mar 8, 2023
1 parent 1e6f0f2 commit 76a8fe3
Show file tree
Hide file tree
Showing 9 changed files with 304 additions and 55 deletions.
41 changes: 41 additions & 0 deletions adapter/outbound/reality.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package outbound

import (
"encoding/base64"
"encoding/hex"
"errors"

tlsC "github.com/Dreamacro/clash/component/tls"

"golang.org/x/crypto/curve25519"
)

type RealityOptions struct {
ServerName string `proxy:"server-name"`
PublicKey string `proxy:"public-key"`
ShortID string `proxy:"short-id"`
}

func (o RealityOptions) Parse() (*tlsC.RealityConfig, error) {
if o.PublicKey != "" || o.ServerName != "" {
if o.PublicKey != "" && o.ServerName != "" {
config := new(tlsC.RealityConfig)

n, err := base64.RawURLEncoding.Decode(config.PublicKey[:], []byte(o.PublicKey))
if err != nil || n != curve25519.ScalarSize {
return nil, errors.New("invalid REALITY public key")
}

config.ShortID, err = hex.DecodeString(o.ShortID)
if err != nil {
return nil, errors.New("invalid REALITY short ID")
}

config.ServerName = o.ServerName

return config, nil
}
return nil, errors.New("invalid REALITY protocol option")
}
return nil, nil
}
37 changes: 22 additions & 15 deletions adapter/outbound/trojan.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,22 @@ type Trojan struct {

type TrojanOption struct {
BasicOption
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
Password string `proxy:"password"`
ALPN []string `proxy:"alpn,omitempty"`
SNI string `proxy:"sni,omitempty"`
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
Fingerprint string `proxy:"fingerprint,omitempty"`
UDP bool `proxy:"udp,omitempty"`
Network string `proxy:"network,omitempty"`
GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
WSOpts WSOptions `proxy:"ws-opts,omitempty"`
Flow string `proxy:"flow,omitempty"`
FlowShow bool `proxy:"flow-show,omitempty"`
ClientFingerprint string `proxy:"client-fingerprint,omitempty"`
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
Password string `proxy:"password"`
ALPN []string `proxy:"alpn,omitempty"`
SNI string `proxy:"sni,omitempty"`
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
Fingerprint string `proxy:"fingerprint,omitempty"`
UDP bool `proxy:"udp,omitempty"`
Network string `proxy:"network,omitempty"`
RealityOpts RealityOptions `proxy:"reality-opts,omitempty"`
GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
WSOpts WSOptions `proxy:"ws-opts,omitempty"`
Flow string `proxy:"flow,omitempty"`
FlowShow bool `proxy:"flow-show,omitempty"`
ClientFingerprint string `proxy:"client-fingerprint,omitempty"`
}

func (t *Trojan) plainStream(c net.Conn) (net.Conn, error) {
Expand Down Expand Up @@ -244,6 +245,12 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
tOption.ServerName = option.SNI
}

var err error
tOption.Reality, err = option.RealityOpts.Parse()
if err != nil {
return nil, err
}

t := &Trojan{
Base: &Base{
name: option.Name,
Expand Down
9 changes: 8 additions & 1 deletion adapter/outbound/vless.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ type Vless struct {
gunTLSConfig *tls.Config
gunConfig *gun.Config
transport *gun.TransportWrap

realityConfig *tlsC.RealityConfig
}

type VlessOption struct {
Expand All @@ -57,6 +59,7 @@ type VlessOption struct {
XUDP bool `proxy:"xudp,omitempty"`
PacketEncoding string `proxy:"packet-encoding,omitempty"`
Network string `proxy:"network,omitempty"`
RealityOpts RealityOptions `proxy:"reality-opts,omitempty"`
HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"`
HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"`
GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
Expand All @@ -78,7 +81,6 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {

switch v.option.Network {
case "ws":

host, port, _ := net.SplitHostPort(v.addr)
wsOpts := &vmess.WebsocketConfig{
Host: host,
Expand Down Expand Up @@ -190,6 +192,7 @@ func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error)
SkipCertVerify: v.option.SkipCertVerify,
FingerPrint: v.option.Fingerprint,
ClientFingerprint: v.option.ClientFingerprint,
Reality: v.realityConfig,
}

if isH2 {
Expand Down Expand Up @@ -554,7 +557,11 @@ func NewVless(option VlessOption) (*Vless, error) {
v.gunConfig = gunConfig

v.transport = gun.NewHTTP2Client(dialFn, tlsConfig, v.option.ClientFingerprint)
}

v.realityConfig, err = v.option.RealityOpts.Parse()
if err != nil {
return nil, err
}

return v, nil
Expand Down
57 changes: 33 additions & 24 deletions adapter/outbound/vmess.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,32 +35,35 @@ type Vmess struct {
gunTLSConfig *tls.Config
gunConfig *gun.Config
transport *gun.TransportWrap

realityConfig *tlsC.RealityConfig
}

type VmessOption struct {
BasicOption
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
UUID string `proxy:"uuid"`
AlterID int `proxy:"alterId"`
Cipher string `proxy:"cipher"`
UDP bool `proxy:"udp,omitempty"`
Network string `proxy:"network,omitempty"`
TLS bool `proxy:"tls,omitempty"`
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
Fingerprint string `proxy:"fingerprint,omitempty"`
ServerName string `proxy:"servername,omitempty"`
HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"`
HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"`
GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
WSOpts WSOptions `proxy:"ws-opts,omitempty"`
PacketAddr bool `proxy:"packet-addr,omitempty"`
XUDP bool `proxy:"xudp,omitempty"`
PacketEncoding string `proxy:"packet-encoding,omitempty"`
GlobalPadding bool `proxy:"global-padding,omitempty"`
AuthenticatedLength bool `proxy:"authenticated-length,omitempty"`
ClientFingerprint string `proxy:"client-fingerprint,omitempty"`
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
UUID string `proxy:"uuid"`
AlterID int `proxy:"alterId"`
Cipher string `proxy:"cipher"`
UDP bool `proxy:"udp,omitempty"`
Network string `proxy:"network,omitempty"`
TLS bool `proxy:"tls,omitempty"`
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
Fingerprint string `proxy:"fingerprint,omitempty"`
ServerName string `proxy:"servername,omitempty"`
RealityOpts RealityOptions `proxy:"reality-opts,omitempty"`
HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"`
HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"`
GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
WSOpts WSOptions `proxy:"ws-opts,omitempty"`
PacketAddr bool `proxy:"packet-addr,omitempty"`
XUDP bool `proxy:"xudp,omitempty"`
PacketEncoding string `proxy:"packet-encoding,omitempty"`
GlobalPadding bool `proxy:"global-padding,omitempty"`
AuthenticatedLength bool `proxy:"authenticated-length,omitempty"`
ClientFingerprint string `proxy:"client-fingerprint,omitempty"`
}

type HTTPOptions struct {
Expand Down Expand Up @@ -95,7 +98,6 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {

switch v.option.Network {
case "ws":

host, port, _ := net.SplitHostPort(v.addr)
wsOpts := &clashVMess.WebsocketConfig{
Host: host,
Expand Down Expand Up @@ -144,12 +146,12 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
Host: host,
SkipCertVerify: v.option.SkipCertVerify,
ClientFingerprint: v.option.ClientFingerprint,
Reality: v.realityConfig,
}

if v.option.ServerName != "" {
tlsOpts.Host = v.option.ServerName
}

c, err = clashVMess.StreamTLSConn(c, tlsOpts)
if err != nil {
return nil, err
Expand All @@ -172,6 +174,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
SkipCertVerify: v.option.SkipCertVerify,
NextProtos: []string{"h2"},
ClientFingerprint: v.option.ClientFingerprint,
Reality: v.realityConfig,
}

if v.option.ServerName != "" {
Expand Down Expand Up @@ -199,6 +202,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
Host: host,
SkipCertVerify: v.option.SkipCertVerify,
ClientFingerprint: v.option.ClientFingerprint,
Reality: v.realityConfig,
}

if v.option.ServerName != "" {
Expand Down Expand Up @@ -452,8 +456,13 @@ func NewVmess(option VmessOption) (*Vmess, error) {
v.gunConfig = gunConfig

v.transport = gun.NewHTTP2Client(dialFn, tlsConfig, v.option.ClientFingerprint)
}

v.realityConfig, err = v.option.RealityOpts.Parse()
if err != nil {
return nil, err
}

return v, nil
}

Expand Down
Loading

0 comments on commit 76a8fe3

Please sign in to comment.