2024-03-10 15:13:42 -04:00
|
|
|
package parser
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"net/url"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
2024-03-20 12:02:38 -04:00
|
|
|
"sub2sing-box/model"
|
2024-03-10 15:13:42 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
//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)
|
|
|
|
|
2024-03-20 12:02:38 -04:00
|
|
|
func ParseHysteria(proxy string) (model.Outbound, error) {
|
2024-03-10 15:13:42 -04:00
|
|
|
if !strings.HasPrefix(proxy, "hysteria://") {
|
2024-03-20 12:02:38 -04:00
|
|
|
return model.Outbound{}, errors.New("invalid hysteria Url")
|
2024-03-10 15:13:42 -04:00
|
|
|
}
|
|
|
|
parts := strings.SplitN(strings.TrimPrefix(proxy, "hysteria://"), "?", 2)
|
|
|
|
serverInfo := strings.SplitN(parts[0], ":", 2)
|
|
|
|
if len(serverInfo) != 2 {
|
2024-03-20 12:02:38 -04:00
|
|
|
return model.Outbound{}, errors.New("invalid hysteria Url")
|
2024-03-10 15:13:42 -04:00
|
|
|
}
|
|
|
|
params, err := url.ParseQuery(parts[1])
|
|
|
|
if err != nil {
|
2024-03-20 12:02:38 -04:00
|
|
|
return model.Outbound{}, errors.New("invalid hysteria Url")
|
2024-03-10 15:13:42 -04:00
|
|
|
}
|
|
|
|
host := serverInfo[0]
|
|
|
|
port, err := strconv.Atoi(serverInfo[1])
|
|
|
|
if err != nil {
|
2024-03-20 12:02:38 -04:00
|
|
|
return model.Outbound{}, errors.New("invalid hysteria Url")
|
2024-03-10 15:13:42 -04:00
|
|
|
}
|
|
|
|
protocol := params.Get("protocol")
|
|
|
|
auth := params.Get("auth")
|
|
|
|
// peer := params.Get("peer")
|
|
|
|
insecure := params.Get("insecure")
|
|
|
|
upmbps := params.Get("upmbps")
|
|
|
|
downmbps := params.Get("downmbps")
|
|
|
|
obfs := params.Get("obfs")
|
|
|
|
// obfsParam := params.Get("obfsParam")
|
2024-03-11 12:13:59 -04:00
|
|
|
var alpn []string
|
|
|
|
if params.Get("alpn") != "" {
|
|
|
|
alpn = strings.Split(params.Get("alpn"), ",")
|
|
|
|
} else {
|
|
|
|
alpn = nil
|
|
|
|
}
|
2024-03-10 15:13:42 -04:00
|
|
|
remarks := ""
|
|
|
|
if strings.Contains(parts[1], "#") {
|
|
|
|
r := strings.Split(parts[1], "#")
|
|
|
|
remarks = r[len(r)-1]
|
|
|
|
} else {
|
|
|
|
remarks = serverInfo[0] + ":" + serverInfo[1]
|
|
|
|
}
|
|
|
|
insecureBool, err := strconv.ParseBool(insecure)
|
|
|
|
if err != nil {
|
2024-03-20 12:02:38 -04:00
|
|
|
return model.Outbound{}, errors.New("invalid hysteria Url")
|
2024-03-10 15:13:42 -04:00
|
|
|
}
|
2024-03-20 12:02:38 -04:00
|
|
|
result := model.Outbound{
|
2024-03-10 15:13:42 -04:00
|
|
|
Type: "hysteria",
|
2024-03-11 09:00:13 -04:00
|
|
|
Tag: remarks,
|
2024-03-20 12:02:38 -04:00
|
|
|
HysteriaOptions: model.HysteriaOutboundOptions{
|
|
|
|
ServerOptions: model.ServerOptions{
|
|
|
|
Server: host,
|
|
|
|
ServerPort: uint16(port),
|
|
|
|
},
|
|
|
|
Up: upmbps,
|
|
|
|
Down: downmbps,
|
|
|
|
Auth: []byte(auth),
|
|
|
|
Obfs: obfs,
|
|
|
|
Network: protocol,
|
|
|
|
OutboundTLSOptionsContainer: model.OutboundTLSOptionsContainer{
|
|
|
|
TLS: &model.OutboundTLSOptions{
|
|
|
|
Enabled: true,
|
|
|
|
Insecure: insecureBool,
|
|
|
|
ALPN: alpn,
|
|
|
|
},
|
2024-03-10 15:13:42 -04:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
return result, nil
|
|
|
|
}
|