mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-29 03:51:31 +00:00
hysteria2: Add more masquerade options
This commit is contained in:
parent
54bbda65c9
commit
d9d8567178
7
constant/hysteria2.go
Normal file
7
constant/hysteria2.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package constant
|
||||
|
||||
const (
|
||||
Hysterai2MasqueradeTypeFile = "file"
|
||||
Hysterai2MasqueradeTypeProxy = "proxy"
|
||||
Hysterai2MasqueradeTypeString = "string"
|
||||
)
|
|
@ -4,8 +4,8 @@
|
|||
{
|
||||
"type": "hysteria2",
|
||||
"tag": "hy2-in",
|
||||
...
|
||||
// Listen Fields
|
||||
|
||||
... // Listen Fields
|
||||
|
||||
"up_mbps": 100,
|
||||
"down_mbps": 100,
|
||||
|
@ -21,7 +21,7 @@
|
|||
],
|
||||
"ignore_client_bandwidth": false,
|
||||
"tls": {},
|
||||
"masquerade": "",
|
||||
"masquerade": "", // or {}
|
||||
"brutal_debug": false
|
||||
}
|
||||
```
|
||||
|
@ -79,14 +79,54 @@ TLS configuration, see [TLS](/configuration/shared/tls/#inbound).
|
|||
|
||||
#### masquerade
|
||||
|
||||
HTTP3 server behavior when authentication fails.
|
||||
HTTP3 server behavior (URL string configuration) when authentication fails.
|
||||
|
||||
| Scheme | Example | Description |
|
||||
|--------------|-------------------------|--------------------|
|
||||
| `file` | `file:///var/www` | As a file server |
|
||||
| `http/https` | `http://127.0.0.1:8080` | As a reverse proxy |
|
||||
|
||||
A 404 page will be returned if empty.
|
||||
Conflict with `masquerade.type`.
|
||||
|
||||
A 404 page will be returned if masquerade is not configured.
|
||||
|
||||
#### masquerade.type
|
||||
|
||||
HTTP3 server behavior (Object configuration) when authentication fails.
|
||||
|
||||
| Type | Description | Fields |
|
||||
|----------|-----------------------------|-------------------------------------|
|
||||
| `file` | As a file server | `file` |
|
||||
| `proxy` | As a reverse proxy | `url`, `rewrite_host` |
|
||||
| `string` | Reply with a fixed response | `status_code`, `headers`, `content` |
|
||||
|
||||
Conflict with `masquerade`.
|
||||
|
||||
A 404 page will be returned if masquerade is not configured.
|
||||
|
||||
#### masquerade.file
|
||||
|
||||
File server root directory.
|
||||
|
||||
#### masquerade.url
|
||||
|
||||
Reverse proxy target URL.
|
||||
|
||||
#### masquerade.rewrite_host
|
||||
|
||||
Rewrite the `Host` header to the target URL.
|
||||
|
||||
#### masquerade.status_code
|
||||
|
||||
Fixed response status code.
|
||||
|
||||
#### masquerade.headers
|
||||
|
||||
Fixed response headers.
|
||||
|
||||
#### masquerade.content
|
||||
|
||||
Fixed response content.
|
||||
|
||||
#### brutal_debug
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
{
|
||||
"type": "hysteria2",
|
||||
"tag": "hy2-in",
|
||||
...
|
||||
// 监听字段
|
||||
|
||||
... // 监听字段
|
||||
|
||||
"up_mbps": 100,
|
||||
"down_mbps": 100,
|
||||
|
@ -21,7 +21,7 @@
|
|||
],
|
||||
"ignore_client_bandwidth": false,
|
||||
"tls": {},
|
||||
"masquerade": "",
|
||||
"masquerade": "", // 或 {}
|
||||
"brutal_debug": false
|
||||
}
|
||||
```
|
||||
|
@ -76,14 +76,54 @@ TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。
|
|||
|
||||
#### masquerade
|
||||
|
||||
HTTP3 服务器认证失败时的行为。
|
||||
HTTP3 服务器认证失败时的行为 (URL 字符串配置)。
|
||||
|
||||
| Scheme | 示例 | 描述 |
|
||||
|--------------|-------------------------|---------|
|
||||
| `file` | `file:///var/www` | 作为文件服务器 |
|
||||
| `http/https` | `http://127.0.0.1:8080` | 作为反向代理 |
|
||||
|
||||
如果为空,则返回 404 页。
|
||||
如果 masquerade 未配置,则返回 404 页。
|
||||
|
||||
与 `masquerade.type` 冲突。
|
||||
|
||||
#### masquerade.type
|
||||
|
||||
HTTP3 服务器认证失败时的行为 (对象配置)。
|
||||
|
||||
| Type | 描述 | 字段 |
|
||||
|----------|---------|-------------------------------------|
|
||||
| `file` | 作为文件服务器 | `file` |
|
||||
| `proxy` | 作为反向代理 | `url`, `rewrite_host` |
|
||||
| `string` | 返回固定响应 | `status_code`, `headers`, `content` |
|
||||
|
||||
如果 masquerade 未配置,则返回 404 页。
|
||||
|
||||
与 `masquerade` 冲突。
|
||||
|
||||
#### masquerade.file
|
||||
|
||||
文件服务器根目录。
|
||||
|
||||
#### masquerade.url
|
||||
|
||||
反向代理目标 URL。
|
||||
|
||||
#### masquerade.rewrite_host
|
||||
|
||||
重写请求头中的 Host 字段到目标 URL。
|
||||
|
||||
#### masquerade.status_code
|
||||
|
||||
固定响应状态码。
|
||||
|
||||
#### masquerade.headers
|
||||
|
||||
固定响应头。
|
||||
|
||||
#### masquerade.content
|
||||
|
||||
固定响应内容。
|
||||
|
||||
#### brutal_debug
|
||||
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
package option
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/json"
|
||||
"github.com/sagernet/sing/common/json/badjson"
|
||||
"github.com/sagernet/sing/common/json/badoption"
|
||||
)
|
||||
|
||||
type Hysteria2InboundOptions struct {
|
||||
ListenOptions
|
||||
UpMbps int `json:"up_mbps,omitempty"`
|
||||
|
@ -8,8 +18,8 @@ type Hysteria2InboundOptions struct {
|
|||
Users []Hysteria2User `json:"users,omitempty"`
|
||||
IgnoreClientBandwidth bool `json:"ignore_client_bandwidth,omitempty"`
|
||||
InboundTLSOptionsContainer
|
||||
Masquerade string `json:"masquerade,omitempty"`
|
||||
BrutalDebug bool `json:"brutal_debug,omitempty"`
|
||||
Masquerade *Hysteria2Masquerade `json:"masquerade,omitempty"`
|
||||
BrutalDebug bool `json:"brutal_debug,omitempty"`
|
||||
}
|
||||
|
||||
type Hysteria2Obfs struct {
|
||||
|
@ -22,6 +32,82 @@ type Hysteria2User struct {
|
|||
Password string `json:"password,omitempty"`
|
||||
}
|
||||
|
||||
type _Hysteria2Masquerade struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
FileOptions Hysteria2MasqueradeFile `json:"-"`
|
||||
ProxyOptions Hysteria2MasqueradeProxy `json:"-"`
|
||||
StringOptions Hysteria2MasqueradeString `json:"-"`
|
||||
}
|
||||
|
||||
type Hysteria2Masquerade _Hysteria2Masquerade
|
||||
|
||||
func (m Hysteria2Masquerade) MarshalJSON() ([]byte, error) {
|
||||
var v any
|
||||
switch m.Type {
|
||||
case C.Hysterai2MasqueradeTypeFile:
|
||||
v = m.FileOptions
|
||||
case C.Hysterai2MasqueradeTypeProxy:
|
||||
v = m.ProxyOptions
|
||||
case C.Hysterai2MasqueradeTypeString:
|
||||
v = m.StringOptions
|
||||
default:
|
||||
return nil, E.New("unknown masquerade type: ", m.Type)
|
||||
}
|
||||
return badjson.MarshallObjects((_Hysteria2Masquerade)(m), v)
|
||||
}
|
||||
|
||||
func (m *Hysteria2Masquerade) UnmarshalJSON(bytes []byte) error {
|
||||
var urlString string
|
||||
err := json.Unmarshal(bytes, &urlString)
|
||||
if err == nil {
|
||||
masqueradeURL, err := url.Parse(urlString)
|
||||
if err != nil {
|
||||
return E.Cause(err, "invalid masquerade URL")
|
||||
}
|
||||
switch masqueradeURL.Scheme {
|
||||
case "file":
|
||||
m.Type = C.Hysterai2MasqueradeTypeFile
|
||||
m.FileOptions.Directory = masqueradeURL.Path
|
||||
case "http", "https":
|
||||
m.Type = C.Hysterai2MasqueradeTypeProxy
|
||||
m.ProxyOptions.URL = urlString
|
||||
default:
|
||||
return E.New("unknown masquerade URL scheme: ", masqueradeURL.Scheme)
|
||||
}
|
||||
}
|
||||
err = json.Unmarshal(bytes, (*_Hysteria2Masquerade)(m))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var v any
|
||||
switch m.Type {
|
||||
case C.Hysterai2MasqueradeTypeFile:
|
||||
v = &m.FileOptions
|
||||
case C.Hysterai2MasqueradeTypeProxy:
|
||||
v = &m.ProxyOptions
|
||||
case C.Hysterai2MasqueradeTypeString:
|
||||
v = &m.StringOptions
|
||||
default:
|
||||
return E.New("unknown masquerade type: ", m.Type)
|
||||
}
|
||||
return badjson.UnmarshallExcluded(bytes, (*_Hysteria2Masquerade)(m), v)
|
||||
}
|
||||
|
||||
type Hysteria2MasqueradeFile struct {
|
||||
Directory string `json:"directory"`
|
||||
}
|
||||
|
||||
type Hysteria2MasqueradeProxy struct {
|
||||
URL string `json:"url"`
|
||||
RewriteHost bool `json:"rewrite_host,omitempty"`
|
||||
}
|
||||
|
||||
type Hysteria2MasqueradeString struct {
|
||||
StatusCode int `json:"status_code,omitempty"`
|
||||
Headers badoption.HTTPHeader `json:"headers,omitempty"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
type Hysteria2OutboundOptions struct {
|
||||
DialerOptions
|
||||
ServerOptions
|
||||
|
|
|
@ -60,26 +60,40 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
|||
}
|
||||
}
|
||||
var masqueradeHandler http.Handler
|
||||
if options.Masquerade != "" {
|
||||
masqueradeURL, err := url.Parse(options.Masquerade)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "parse masquerade URL")
|
||||
}
|
||||
switch masqueradeURL.Scheme {
|
||||
case "file":
|
||||
masqueradeHandler = http.FileServer(http.Dir(masqueradeURL.Path))
|
||||
case "http", "https":
|
||||
if options.Masquerade != nil && options.Masquerade.Type != "" {
|
||||
switch options.Masquerade.Type {
|
||||
case C.Hysterai2MasqueradeTypeFile:
|
||||
masqueradeHandler = http.FileServer(http.Dir(options.Masquerade.FileOptions.Directory))
|
||||
case C.Hysterai2MasqueradeTypeProxy:
|
||||
masqueradeURL, err := url.Parse(options.Masquerade.ProxyOptions.URL)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "parse masquerade URL")
|
||||
}
|
||||
masqueradeHandler = &httputil.ReverseProxy{
|
||||
Rewrite: func(r *httputil.ProxyRequest) {
|
||||
r.SetURL(masqueradeURL)
|
||||
r.Out.Host = r.In.Host
|
||||
if !options.Masquerade.ProxyOptions.RewriteHost {
|
||||
r.Out.Host = r.In.Host
|
||||
}
|
||||
},
|
||||
ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {
|
||||
w.WriteHeader(http.StatusBadGateway)
|
||||
},
|
||||
}
|
||||
case C.Hysterai2MasqueradeTypeString:
|
||||
masqueradeHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if options.Masquerade.StringOptions.StatusCode != 0 {
|
||||
w.WriteHeader(options.Masquerade.StringOptions.StatusCode)
|
||||
}
|
||||
for key, values := range options.Masquerade.StringOptions.Headers {
|
||||
for _, value := range values {
|
||||
w.Header().Add(key, value)
|
||||
}
|
||||
}
|
||||
w.Write([]byte(options.Masquerade.StringOptions.Content))
|
||||
})
|
||||
default:
|
||||
return nil, E.New("unknown masquerade URL scheme: ", masqueradeURL.Scheme)
|
||||
return nil, E.New("unknown masquerade type: ", options.Masquerade.Type)
|
||||
}
|
||||
}
|
||||
inbound := &Inbound{
|
||||
|
|
Loading…
Reference in a new issue