Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions app/proxyman/inbound/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/proxy"
"github.com/xtls/xray-core/proxy/hysteria/account"
hyCtx "github.com/xtls/xray-core/proxy/hysteria/ctx"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tcp"
Expand Down Expand Up @@ -138,6 +140,13 @@ func (w *tcpWorker) Proxy() proxy.Inbound {

func (w *tcpWorker) Start() error {
ctx := context.Background()

type HysteriaInboundValidator interface{ HysteriaInboundValidator() *account.Validator }
if v, ok := w.proxy.(HysteriaInboundValidator); ok {
ctx = hyCtx.ContextWithRequireDatagram(ctx, true)
ctx = hyCtx.ContextWithValidator(ctx, v.HysteriaInboundValidator())
}

hub, err := internet.ListenTCP(ctx, w.address, w.port, w.stream, func(conn stat.Connection) {
go w.callback(conn)
})
Expand Down
32 changes: 32 additions & 0 deletions infra/conf/hysteria.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package conf
import (
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/proxy/hysteria"
"github.com/xtls/xray-core/proxy/hysteria/account"
"google.golang.org/protobuf/proto"
)

Expand All @@ -27,3 +29,33 @@ func (c *HysteriaClientConfig) Build() (proto.Message, error) {

return config, nil
}

type HysteriaUserConfig struct {
Auth string `json:"auth"`
Level uint32 `json:"level"`
Email string `json:"email"`
}

type HysteriaServerConfig struct {
Version int32 `json:"version"`
Users []*HysteriaUserConfig `json:"clients"`
}

func (c *HysteriaServerConfig) Build() (proto.Message, error) {
config := new(hysteria.ServerConfig)

if c.Users != nil {
for _, user := range c.Users {
account := &account.Account{
Auth: user.Auth,
}
config.Users = append(config.Users, &protocol.User{
Email: user.Email,
Level: user.Level,
Account: serial.ToTypedMessage(account),
})
}
}

return config, nil
}
44 changes: 42 additions & 2 deletions infra/conf/transport_internet.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,20 @@ type UdpHop struct {
Interval *Int32Range `json:"interval"`
}

type Masquerade struct {
Type string `json:"type"`

Dir string `json:"dir"`

Url string `json:"url"`
RewriteHost bool `json:"rewriteHost"`
Insecure bool `json:"insecure"`

Content string `json:"content"`
Headers map[string]string `json:"headers"`
StatusCode int32 `json:"statusCode"`
}

type HysteriaConfig struct {
Version int32 `json:"version"`
Auth string `json:"auth"`
Expand All @@ -523,6 +537,10 @@ type HysteriaConfig struct {
MaxIdleTimeout int64 `json:"maxIdleTimeout"`
KeepAlivePeriod int64 `json:"keepAlivePeriod"`
DisablePathMTUDiscovery bool `json:"disablePathMTUDiscovery"`
MaxIncomingStreams int64 `json:"maxIncomingStreams"`

UdpIdleTimeout int64 `json:"udpIdleTimeout"`
Masquerade Masquerade `json:"masquerade"`
}

func (c *HysteriaConfig) Build() (proto.Message, error) {
Expand Down Expand Up @@ -556,10 +574,10 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
}

if up > 0 && up < 65536 {
return nil, errors.New("Up must be at least 65536 Bps")
return nil, errors.New("Up must be at least 65536 bytes per second")
}
if down > 0 && down < 65536 {
return nil, errors.New("Down must be at least 65536 Bps")
return nil, errors.New("Down must be at least 65536 bytes per second")
}
if (inertvalMin != 0 && inertvalMin < 5) || (inertvalMax != 0 && inertvalMax < 5) {
return nil, errors.New("Interval must be at least 5")
Expand All @@ -583,6 +601,12 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
if c.KeepAlivePeriod != 0 && (c.KeepAlivePeriod < 2 || c.KeepAlivePeriod > 60) {
return nil, errors.New("KeepAlivePeriod must be between 2 and 60")
}
if c.MaxIncomingStreams != 0 && c.MaxIncomingStreams < 8 {
return nil, errors.New("MaxIncomingStreams must be at least 8")
}
if c.UdpIdleTimeout != 0 && (c.UdpIdleTimeout < 2 || c.UdpIdleTimeout > 600) {
return nil, errors.New("UdpIdleTimeout must be between 2 and 600")
}

config := &hysteria.Config{}
config.Version = c.Version
Expand All @@ -600,6 +624,16 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
config.MaxIdleTimeout = c.MaxIdleTimeout
config.KeepAlivePeriod = c.KeepAlivePeriod
config.DisablePathMtuDiscovery = c.DisablePathMTUDiscovery
config.MaxIncomingStreams = c.MaxIncomingStreams
config.UdpIdleTimeout = c.UdpIdleTimeout
config.MasqType = c.Masquerade.Type
config.MasqFile = c.Masquerade.Dir
config.MasqUrl = c.Masquerade.Url
config.MasqUrlRewriteHost = c.Masquerade.RewriteHost
config.MasqUrlInsecure = c.Masquerade.Insecure
config.MasqString = c.Masquerade.Content
config.MasqStringHeaders = c.Masquerade.Headers
config.MasqStringStatusCode = c.Masquerade.StatusCode

if config.InitStreamReceiveWindow == 0 {
config.InitStreamReceiveWindow = 8388608
Expand All @@ -619,6 +653,12 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
// if config.KeepAlivePeriod == 0 {
// config.KeepAlivePeriod = 10
// }
if config.MaxIncomingStreams == 0 {
config.MaxIncomingStreams = 1024
}
if config.UdpIdleTimeout == 0 {
config.UdpIdleTimeout = 60
}

return config, nil
}
Expand Down
1 change: 1 addition & 0 deletions infra/conf/xray.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ var (
"vmess": func() interface{} { return new(VMessInboundConfig) },
"trojan": func() interface{} { return new(TrojanServerConfig) },
"wireguard": func() interface{} { return &WireGuardConfig{IsClient: false} },
"hysteria": func() interface{} { return new(HysteriaServerConfig) },
"tun": func() interface{} { return new(TunConfig) },
}, "protocol", "settings")

Expand Down
129 changes: 129 additions & 0 deletions proxy/hysteria/account/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package account

import (
"sync"

"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/protocol"

"google.golang.org/protobuf/proto"
)

func (a *Account) AsAccount() (protocol.Account, error) {
return &MemoryAccount{
Auth: a.Auth,
}, nil
}

type MemoryAccount struct {
Auth string
}

func (a *MemoryAccount) Equals(another protocol.Account) bool {
if account, ok := another.(*MemoryAccount); ok {
return a.Auth == account.Auth
}
return false
}

func (a *MemoryAccount) ToProto() proto.Message {
return &Account{
Auth: a.Auth,
}
}

type Validator struct {
emails map[string]struct{}
users map[string]*protocol.MemoryUser

mutex sync.Mutex
}

func NewValidator() *Validator {
return &Validator{
emails: make(map[string]struct{}),
users: make(map[string]*protocol.MemoryUser),
}
}

func (v *Validator) Add(u *protocol.MemoryUser) error {
v.mutex.Lock()
defer v.mutex.Unlock()

if u.Email != "" {
if _, ok := v.emails[u.Email]; ok {
return errors.New("User ", u.Email, " already exists.")
}
v.emails[u.Email] = struct{}{}
}
v.users[u.Account.(*MemoryAccount).Auth] = u

return nil
}

func (v *Validator) Del(email string) error {
if email == "" {
return errors.New("Email must not be empty.")
}

v.mutex.Lock()
defer v.mutex.Unlock()

if _, ok := v.emails[email]; !ok {
return errors.New("User ", email, " not found.")
}
delete(v.emails, email)
for key, user := range v.users {
if user.Email == email {
delete(v.users, key)
break
}
}

return nil
}

func (v *Validator) Get(auth string) *protocol.MemoryUser {
v.mutex.Lock()
defer v.mutex.Unlock()

return v.users[auth]
}

func (v *Validator) GetByEmail(email string) *protocol.MemoryUser {
if email == "" {
return nil
}

v.mutex.Lock()
defer v.mutex.Unlock()

if _, ok := v.emails[email]; ok {
for _, user := range v.users {
if user.Email == email {
return user
}
}
}

return nil
}

func (v *Validator) GetAll() []*protocol.MemoryUser {
v.mutex.Lock()
defer v.mutex.Unlock()

var users = make([]*protocol.MemoryUser, 0, len(v.users))
for _, user := range v.users {
users = append(users, user)
}

return users
}

func (v *Validator) GetCount() int64 {
v.mutex.Lock()
defer v.mutex.Unlock()

return int64(len(v.users))
}
Loading