Skip to content

Commit

Permalink
chore: alignment capability for vmess inbound
Browse files Browse the repository at this point in the history
  • Loading branch information
wwqgtxx committed Feb 4, 2025
1 parent 0ac6c3b commit a440f64
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 132 deletions.
8 changes: 8 additions & 0 deletions docs/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1146,6 +1146,14 @@ listeners:
# 下面两项如果填写则开启 tls(需要同时填写)
# certificate: ./server.crt
# private-key: ./server.key
# 如果填写reality-config则开启reality(注意不可与certificate和private-key同时填写)
# reality-config:
# dest: test.com:443
# private-key: jNXHt1yRo0vDuchQlIP6Z0ZvjT3KtzVI-T4E7RoLJS0 # 可由 mihomo generate reality-keypair 命令生成
# short-id:
# - 0123456789abcdef
# server-names:
# - test.com

- name: tuic-in-1
type: tuic
Expand Down
16 changes: 4 additions & 12 deletions listener/config/vless.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package config

import (
"github.com/metacubex/mihomo/listener/sing"

"encoding/json"

"github.com/metacubex/mihomo/listener/reality"
"github.com/metacubex/mihomo/listener/sing"
)

type VlessUser struct {
Expand All @@ -19,20 +20,11 @@ type VlessServer struct {
WsPath string
Certificate string
PrivateKey string
RealityConfig RealityConfig
RealityConfig reality.Config
MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"`
}

func (t VlessServer) String() string {
b, _ := json.Marshal(t)
return string(b)
}

type RealityConfig struct {
Dest string
PrivateKey string
ShortID []string
ServerNames []string
MaxTimeDifference int
Proxy string
}
20 changes: 11 additions & 9 deletions listener/config/vmess.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package config

import (
"github.com/metacubex/mihomo/listener/sing"

"encoding/json"

"github.com/metacubex/mihomo/listener/reality"
"github.com/metacubex/mihomo/listener/sing"
)

type VmessUser struct {
Expand All @@ -13,13 +14,14 @@ type VmessUser struct {
}

type VmessServer struct {
Enable bool
Listen string
Users []VmessUser
WsPath string
Certificate string
PrivateKey string
MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"`
Enable bool
Listen string
Users []VmessUser
WsPath string
Certificate string
PrivateKey string
RealityConfig reality.Config
MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"`
}

func (t VmessServer) String() string {
Expand Down
23 changes: 23 additions & 0 deletions listener/inbound/reality.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package inbound

import "github.com/metacubex/mihomo/listener/reality"

type RealityConfig struct {
Dest string `inbound:"dest"`
PrivateKey string `inbound:"private-key"`
ShortID []string `inbound:"short-id"`
ServerNames []string `inbound:"server-names"`
MaxTimeDifference int `inbound:"max-time-difference,omitempty"`
Proxy string `inbound:"proxy,omitempty"`
}

func (c RealityConfig) Build() reality.Config {
return reality.Config{
Dest: c.Dest,
PrivateKey: c.PrivateKey,
ShortID: c.ShortID,
ServerNames: c.ServerNames,
MaxTimeDifference: c.MaxTimeDifference,
Proxy: c.Proxy,
}
}
20 changes: 0 additions & 20 deletions listener/inbound/vless.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,6 @@ type VlessUser struct {
Flow string `inbound:"flow,omitempty"`
}

type RealityConfig struct {
Dest string `inbound:"dest"`
PrivateKey string `inbound:"private-key"`
ShortID []string `inbound:"short-id"`
ServerNames []string `inbound:"server-names"`
MaxTimeDifference int `inbound:"max-time-difference,omitempty"`
Proxy string `inbound:"proxy,omitempty"`
}

func (c RealityConfig) Build() LC.RealityConfig {
return LC.RealityConfig{
Dest: c.Dest,
PrivateKey: c.PrivateKey,
ShortID: c.ShortID,
ServerNames: c.ServerNames,
MaxTimeDifference: c.MaxTimeDifference,
Proxy: c.Proxy,
}
}

func (o VlessOption) Equal(config C.InboundConfig) bool {
return optionToString(o) == optionToString(config)
}
Expand Down
26 changes: 14 additions & 12 deletions listener/inbound/vmess.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import (

type VmessOption struct {
BaseOption
Users []VmessUser `inbound:"users"`
WsPath string `inbound:"ws-path,omitempty"`
Certificate string `inbound:"certificate,omitempty"`
PrivateKey string `inbound:"private-key,omitempty"`
MuxOption MuxOption `inbound:"mux-option,omitempty"`
Users []VmessUser `inbound:"users"`
WsPath string `inbound:"ws-path,omitempty"`
Certificate string `inbound:"certificate,omitempty"`
PrivateKey string `inbound:"private-key,omitempty"`
RealityConfig RealityConfig `inbound:"reality-config,omitempty"`
MuxOption MuxOption `inbound:"mux-option,omitempty"`
}

type VmessUser struct {
Expand Down Expand Up @@ -50,13 +51,14 @@ func NewVmess(options *VmessOption) (*Vmess, error) {
Base: base,
config: options,
vs: LC.VmessServer{
Enable: true,
Listen: base.RawAddress(),
Users: users,
WsPath: options.WsPath,
Certificate: options.Certificate,
PrivateKey: options.PrivateKey,
MuxOption: options.MuxOption.Build(),
Enable: true,
Listen: base.RawAddress(),
Users: users,
WsPath: options.WsPath,
Certificate: options.Certificate,
PrivateKey: options.PrivateKey,
RealityConfig: options.RealityConfig.Build(),
MuxOption: options.MuxOption.Build(),
},
}, nil
}
Expand Down
104 changes: 104 additions & 0 deletions listener/reality/reality.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package reality

import (
"context"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"net"
"time"

"github.com/metacubex/mihomo/listener/inner"
"github.com/metacubex/mihomo/ntp"

"github.com/sagernet/reality"
)

type Conn = reality.Conn

type Config struct {
Dest string
PrivateKey string
ShortID []string
ServerNames []string
MaxTimeDifference int
Proxy string
}

func (c Config) Build() (*Builder, error) {
realityConfig := &reality.Config{}
realityConfig.SessionTicketsDisabled = true
realityConfig.Type = "tcp"
realityConfig.Dest = c.Dest
realityConfig.Time = ntp.Now
realityConfig.ServerNames = make(map[string]bool)
for _, it := range c.ServerNames {
realityConfig.ServerNames[it] = true
}
privateKey, err := base64.RawURLEncoding.DecodeString(c.PrivateKey)
if err != nil {
return nil, fmt.Errorf("decode private key: %w", err)
}
if len(privateKey) != 32 {
return nil, errors.New("invalid private key")
}
realityConfig.PrivateKey = privateKey

realityConfig.MaxTimeDiff = time.Duration(c.MaxTimeDifference) * time.Microsecond

realityConfig.ShortIds = make(map[[8]byte]bool)
for i, shortIDString := range c.ShortID {
var shortID [8]byte
decodedLen, err := hex.Decode(shortID[:], []byte(shortIDString))
if err != nil {
return nil, fmt.Errorf("decode short_id[%d] '%s': %w", i, shortIDString, err)
}
if decodedLen > 8 {
return nil, fmt.Errorf("invalid short_id[%d]: %s", i, shortIDString)
}
realityConfig.ShortIds[shortID] = true
}

realityConfig.DialContext = func(ctx context.Context, network, address string) (net.Conn, error) {
return inner.HandleTcp(address, c.Proxy)
}

return &Builder{realityConfig}, nil
}

type Builder struct {
realityConfig *reality.Config
}

func (b Builder) NewListener(l net.Listener) net.Listener {
l = reality.NewListener(l, b.realityConfig)
// Due to low implementation quality, the reality server intercepted half close and caused memory leaks.
// We fixed it by calling Close() directly.
l = realityListenerWrapper{l}
return l
}

type realityConnWrapper struct {
*reality.Conn
}

func (c realityConnWrapper) Upstream() any {
return c.Conn
}

func (c realityConnWrapper) CloseWrite() error {
return c.Close()
}

type realityListenerWrapper struct {
net.Listener
}

func (l realityListenerWrapper) Accept() (net.Conn, error) {
c, err := l.Listener.Accept()
if err != nil {
return nil, err
}
return realityConnWrapper{c.(*reality.Conn)}, nil
}
Loading

0 comments on commit a440f64

Please sign in to comment.