Skip to content

Commit

Permalink
feat: 增加 Hysteria 节点支持
Browse files Browse the repository at this point in the history
  • Loading branch information
nitezs committed Mar 9, 2024
1 parent d8a81e4 commit 68269fd
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 5 deletions.
6 changes: 6 additions & 0 deletions model/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ type Proxy struct {
CustomCA string `yaml:"ca,omitempty"`
CustomCAString string `yaml:"ca-str,omitempty"`
CWND int `yaml:"cwnd,omitempty"`
Auth string `yaml:"auth,omitempty"`
ReceiveWindowConn int `yaml:"recv-window-conn,omitempty"`
ReceiveWindow int `yaml:"recv-window,omitempty"`
DisableMTUDiscovery bool `yaml:"disable-mtu-discovery,omitempty"`
FastOpen bool `yaml:"fast-open,omitempty"`
HopInterval int `yaml:"hop-interval,omitempty"`
}

func (p Proxy) MarshalYAML() (interface{}, error) {
Expand Down
53 changes: 53 additions & 0 deletions model/proxy_hysteria.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package model

type Hysteria struct {
Type string `yaml:"type"`
Name string `yaml:"name"`
Server string `yaml:"server"`
Port int `yaml:"port,omitempty"`
Ports string `yaml:"ports,omitempty"`
Protocol string `yaml:"protocol,omitempty"`
ObfsProtocol string `yaml:"obfs-protocol,omitempty"` // compatible with Stash
Up string `yaml:"up"`
UpSpeed int `yaml:"up-speed,omitempty"` // compatible with Stash
Down string `yaml:"down"`
DownSpeed int `yaml:"down-speed,omitempty"` // compatible with Stash
Auth string `yaml:"auth,omitempty"`
AuthString string `yaml:"auth-str,omitempty"`
Obfs string `yaml:"obfs,omitempty"`
SNI string `yaml:"sni,omitempty"`
SkipCertVerify bool `yaml:"skip-cert-verify,omitempty"`
Fingerprint string `yaml:"fingerprint,omitempty"`
ALPN []string `yaml:"alpn,omitempty"`
CustomCA string `yaml:"ca,omitempty"`
CustomCAString string `yaml:"ca-str,omitempty"`
ReceiveWindowConn int `yaml:"recv-window-conn,omitempty"`
ReceiveWindow int `yaml:"recv-window,omitempty"`
DisableMTUDiscovery bool `yaml:"disable-mtu-discovery,omitempty"`
FastOpen bool `yaml:"fast-open,omitempty"`
HopInterval int `yaml:"hop-interval,omitempty"`
}

func ProxyToHysteria(p Proxy) Hysteria {
return Hysteria{
Type: "hysteria",
Name: p.Name,
Server: p.Server,
Port: p.Port,
Up: p.Up,
Down: p.Down,
Auth: p.Auth,
Obfs: p.Obfs,
SNI: p.Sni,
SkipCertVerify: p.SkipCertVerify,
Fingerprint: p.Fingerprint,
ALPN: p.Alpn,
CustomCA: p.CustomCA,
CustomCAString: p.CustomCAString,
ReceiveWindowConn: p.ReceiveWindowConn,
ReceiveWindow: p.ReceiveWindow,
DisableMTUDiscovery: p.DisableMTUDiscovery,
FastOpen: p.FastOpen,
HopInterval: p.HopInterval,
}
}
79 changes: 79 additions & 0 deletions parser/hysteria.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package parser

import (
"errors"
"net/url"
"strconv"
"strings"
"sub2clash/model"
)

//hysteria://host:port?protocol=udp&auth=123456&peer=sni.domain&insecure=1&upmbps=100&downmbps=100&alpn=hysteria&obfs=xplus&obfsParam=123456#remarks
//
//- host: hostname or IP address of the server to connect to (required)
//- port: port of the server to connect to (required)
//- protocol: protocol to use ("udp", "wechat-video", "faketcp") (optional, default: "udp")
//- auth: authentication payload (string) (optional)
//- peer: SNI for TLS (optional)
//- insecure: ignore certificate errors (optional)
//- upmbps: upstream bandwidth in Mbps (required)
//- downmbps: downstream bandwidth in Mbps (required)
//- alpn: QUIC ALPN (optional)
//- obfs: Obfuscation mode (optional, empty or "xplus")
//- obfsParam: Obfuscation password (optional)
//- remarks: remarks (optional)

func ParseHysteria(proxy string) (model.Proxy, error) {
// 判断是否以 hysteria:// 开头
if !strings.HasPrefix(proxy, "hysteria://") {
return model.Proxy{}, errors.New("invalid hysteria Url")
}
// 分割
parts := strings.SplitN(strings.TrimPrefix(proxy, "hysteria://"), "?", 2)
serverInfo := strings.SplitN(parts[0], ":", 2)
if len(serverInfo) != 2 {
return model.Proxy{}, errors.New("invalid hysteria Url")
}
params, err := url.ParseQuery(parts[1])
if err != nil {
return model.Proxy{}, errors.New("invalid hysteria Url")
}
host := serverInfo[0]
port, err := strconv.Atoi(serverInfo[1])
if err != nil {
return model.Proxy{}, errors.New("invalid hysteria Url")
}
protocol := params.Get("protocol")
auth := params.Get("auth")
peer := params.Get("peer")
insecure := params.Get("insecure")
upmbps := params.Get("upmbps")
downmbps := params.Get("downmbps")
alpn := params.Get("alpn")
obfs := params.Get("obfs")
obfsParam := params.Get("obfsParam")
remarks := ""
if strings.Contains(parts[1], "#") {
r := strings.Split(parts[1], "#")
remarks = r[len(r)-1]
} else {
remarks = serverInfo[0] + ":" + serverInfo[1]
}
// 返回结果
result := model.Proxy{
Type: "hysteria",
Name: remarks,
Server: host,
Port: port,
Up: upmbps,
Down: downmbps,
Auth: auth,
Obfs: obfs,
Sni: peer,
SkipCertVerify: insecure == "1",
Alpn: strings.Split(alpn, ","),
ObfsParam: obfsParam,
Protocol: protocol,
}
return result, nil
}
7 changes: 3 additions & 4 deletions parser/hysteria2.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@ import (
"sub2clash/model"
)

// hysteria2://[email protected]/?insecure=1&obfs=salamander&obfs-password=gawrgura&pinSHA256=deadbeef&sni=real.example.com

func ParseHysteria2(proxy string) (model.Proxy, error) {
// 判断是否以 hysteria2:// 开头
if !strings.HasPrefix(proxy, "hysteria2://") {
if !strings.HasPrefix(proxy, "hysteria2://") && !strings.HasPrefix(proxy, "hy2://") {
return model.Proxy{}, errors.New("invalid hysteria2 Url")
}
// 分割
parts := strings.SplitN(strings.TrimPrefix(proxy, "hysteria2://"), "@", 2)
if len(parts) != 2 {
return model.Proxy{}, errors.New("invalid hysteria2 Url")
}
// 分割
serverInfo := strings.SplitN(parts[1], "/?", 2)
serverAndPort := strings.SplitN(serverInfo[0], ":", 2)
Expand Down
5 changes: 4 additions & 1 deletion utils/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,12 @@ func ParseProxy(proxies ...string) []model.Proxy {
if strings.HasPrefix(proxy, "ssr://") {
proxyItem, err = parser.ParseShadowsocksR(proxy)
}
if strings.HasPrefix(proxy, "hysteria2://") {
if strings.HasPrefix(proxy, "hysteria2://") || strings.HasPrefix(proxy, "hy2://") {
proxyItem, err = parser.ParseHysteria2(proxy)
}
if strings.HasPrefix(proxy, "hysteria://") {
proxyItem, err = parser.ParseHysteria(proxy)
}
if err == nil {
result = append(result, proxyItem)
} else {
Expand Down

0 comments on commit 68269fd

Please sign in to comment.