diff options
| author | MHSanaei <ho3ein.sanaei@gmail.com> | 2026-04-20 17:05:27 +0300 |
|---|---|---|
| committer | MHSanaei <ho3ein.sanaei@gmail.com> | 2026-04-20 17:05:27 +0300 |
| commit | ae5ad505d04fa347eb96a0d2bfb54ff541c3b709 (patch) | |
| tree | 54a8088e98e15868238be54b063bb051ab84fcb0 /sub | |
| parent | c188056f64be268dda8f7c16e23f7ef9c90d014f (diff) | |
add hysteria inbound
Co-Authored-By: Alireza Ahmadi <alireza7@gmail.com>
Diffstat (limited to 'sub')
| -rw-r--r-- | sub/subJsonService.go | 45 | ||||
| -rw-r--r-- | sub/subService.go | 68 |
2 files changed, 112 insertions, 1 deletions
diff --git a/sub/subJsonService.go b/sub/subJsonService.go index 05552fe8..7ce93e22 100644 --- a/sub/subJsonService.go +++ b/sub/subJsonService.go @@ -194,6 +194,8 @@ func (s *SubJsonService) getConfig(inbound *model.Inbound, client model.Client, newOutbounds = append(newOutbounds, s.genVless(inbound, streamSettings, client)) case "trojan", "shadowsocks": newOutbounds = append(newOutbounds, s.genServer(inbound, streamSettings, client)) + case "hysteria": + newOutbounds = append(newOutbounds, s.genHy(inbound, newStream, client)) } newOutbounds = append(newOutbounds, s.defaultOutbounds...) @@ -389,6 +391,49 @@ func (s *SubJsonService) genServer(inbound *model.Inbound, streamSettings json_u return result } +func (s *SubJsonService) genHy(inbound *model.Inbound, newStream map[string]any, client model.Client) json_util.RawMessage { + outbound := Outbound{} + + outbound.Protocol = string(inbound.Protocol) + outbound.Tag = "proxy" + + if s.mux != "" { + outbound.Mux = json_util.RawMessage(s.mux) + } + + var settings, stream map[string]any + json.Unmarshal([]byte(inbound.Settings), &settings) + version, _ := settings["version"].(float64) + outbound.Settings = map[string]any{ + "version": int(version), + "address": inbound.Listen, + "port": inbound.Port, + } + + json.Unmarshal([]byte(inbound.StreamSettings), &stream) + hyStream := stream["hysteriaSettings"].(map[string]any) + outHyStream := map[string]any{ + "version": int(version), + "auth": client.Auth, + } + if udpIdleTimeout, ok := hyStream["udpIdleTimeout"].(float64); ok { + outHyStream["udpIdleTimeout"] = int(udpIdleTimeout) + } + newStream["hysteriaSettings"] = outHyStream + + if finalmask, ok := hyStream["finalmask"].(map[string]any); ok { + newStream["finalmask"] = finalmask + } + + newStream["network"] = "hysteria" + newStream["security"] = "tls" + + outbound.StreamSettings, _ = json.MarshalIndent(newStream, "", " ") + + result, _ := json.MarshalIndent(outbound, "", " ") + return result +} + type Outbound struct { Protocol string `json:"protocol"` Tag string `json:"tag"` diff --git a/sub/subService.go b/sub/subService.go index b6422dd4..a4d38485 100644 --- a/sub/subService.go +++ b/sub/subService.go @@ -120,7 +120,7 @@ func (s *SubService) getInboundsBySubId(subId string) ([]*model.Inbound, error) FROM inbounds, JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client WHERE - protocol in ('vmess','vless','trojan','shadowsocks') + protocol in ('vmess','vless','trojan','shadowsocks','hysteria') AND JSON_EXTRACT(client.value, '$.subId') = ? AND enable = ? )`, subId, true).Find(&inbounds).Error if err != nil { @@ -171,6 +171,8 @@ func (s *SubService) getLink(inbound *model.Inbound, email string) string { return s.genTrojanLink(inbound, email) case "shadowsocks": return s.genShadowsocksLink(inbound, email) + case "hysteria": + return s.genHysteriaLink(inbound, email) } return "" } @@ -885,6 +887,70 @@ func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) st return url.String() } +func (s *SubService) genHysteriaLink(inbound *model.Inbound, email string) string { + address := s.address + if inbound.Protocol != model.Hysteria { + return "" + } + var stream map[string]interface{} + json.Unmarshal([]byte(inbound.StreamSettings), &stream) + clients, _ := s.inboundService.GetClients(inbound) + clientIndex := -1 + for i, client := range clients { + if client.Email == email { + clientIndex = i + break + } + } + auth := clients[clientIndex].Auth + port := inbound.Port + params := make(map[string]string) + + params["security"] = "tls" + tlsSetting, _ := stream["tlsSettings"].(map[string]interface{}) + alpns, _ := tlsSetting["alpn"].([]interface{}) + var alpn []string + for _, a := range alpns { + alpn = append(alpn, a.(string)) + } + if len(alpn) > 0 { + params["alpn"] = strings.Join(alpn, ",") + } + if sniValue, ok := searchKey(tlsSetting, "serverName"); ok { + params["sni"], _ = sniValue.(string) + } + + tlsSettings, _ := searchKey(tlsSetting, "settings") + if tlsSetting != nil { + if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok { + params["fp"], _ = fpValue.(string) + } + if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok { + if insecure.(bool) { + params["insecure"] = "1" + } + } + } + + var settings map[string]interface{} + json.Unmarshal([]byte(inbound.Settings), &settings) + version, _ := settings["version"].(float64) + protocol := "hysteria2" + if int(version) == 1 { + protocol = "hysteria" + } + + link := fmt.Sprintf("%s://%s@%s:%d", protocol, auth, address, port) + url, _ := url.Parse(link) + q := url.Query() + for k, v := range params { + q.Add(k, v) + } + url.RawQuery = q.Encode() + url.Fragment = s.genRemark(inbound, email, "") + return url.String() +} + func (s *SubService) genRemark(inbound *model.Inbound, email string, extra string) string { separationChar := string(s.remarkModel[0]) orderChars := s.remarkModel[1:] |
