mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-07-26 08:55:35 +03:00
Add new admin panel, failover, dns fallback, providers, limiters. Update XHTTP
This commit is contained in:
@@ -3,7 +3,6 @@ package xhttp
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
@@ -13,8 +12,10 @@ import (
|
||||
"sync"
|
||||
|
||||
common "github.com/sagernet/sing-box/common/xray"
|
||||
"github.com/sagernet/sing-box/common/xray/buf"
|
||||
"github.com/sagernet/sing-box/common/xray/signal/done"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
|
||||
// interface to abstract between use of browser dialer, vs net/http
|
||||
@@ -24,8 +25,8 @@ type DialerClient interface {
|
||||
// ctx, url, sessionId, body, uploadOnly
|
||||
OpenStream(context.Context, string, string, io.Reader, bool) (io.ReadCloser, net.Addr, net.Addr, error)
|
||||
|
||||
// ctx, url, sessionId, seqStr, body, contentLength
|
||||
PostPacket(context.Context, string, string, string, io.Reader, int64) error
|
||||
// ctx, url, sessionId, seqStr, payload
|
||||
PostPacket(context.Context, string, string, string, buf.MultiBuffer) error
|
||||
}
|
||||
|
||||
// implements xhttp.DialerClient in terms of direct network connections
|
||||
@@ -60,30 +61,7 @@ func (c *DefaultDialerClient) OpenStream(ctx context.Context, url string, sessio
|
||||
method = c.options.GetNormalizedUplinkHTTPMethod() // stream-up/one
|
||||
}
|
||||
req, _ := http.NewRequestWithContext(context.WithoutCancel(ctx), method, url, body)
|
||||
req.Header = c.options.GetRequestHeader()
|
||||
length := int(c.options.GetNormalizedXPaddingBytes().Rand())
|
||||
config := XPaddingConfig{Length: length}
|
||||
if c.options.XPaddingObfsMode {
|
||||
config.Placement = XPaddingPlacement{
|
||||
Placement: c.options.XPaddingPlacement,
|
||||
Key: c.options.XPaddingKey,
|
||||
Header: c.options.XPaddingHeader,
|
||||
RawURL: url,
|
||||
}
|
||||
config.Method = PaddingMethod(c.options.XPaddingMethod)
|
||||
} else {
|
||||
config.Placement = XPaddingPlacement{
|
||||
Placement: option.PlacementQueryInHeader,
|
||||
Key: "x_padding",
|
||||
Header: "Referer",
|
||||
RawURL: url,
|
||||
}
|
||||
}
|
||||
ApplyXPaddingToRequest(req, config)
|
||||
ApplyMetaToRequest(c.options, req, sessionId, "")
|
||||
if method == c.options.GetNormalizedUplinkHTTPMethod() && !c.options.NoGRPCHeader {
|
||||
req.Header.Set("Content-Type", "application/grpc")
|
||||
}
|
||||
FillStreamRequest(req, sessionId, "", c.options)
|
||||
wrc = &WaitReadCloser{Wait: make(chan struct{})}
|
||||
go func() {
|
||||
resp, err := c.client.Do(req)
|
||||
@@ -107,76 +85,13 @@ func (c *DefaultDialerClient) OpenStream(ctx context.Context, url string, sessio
|
||||
return
|
||||
}
|
||||
|
||||
func (c *DefaultDialerClient) PostPacket(ctx context.Context, url string, sessionId string, seqStr string, body io.Reader, contentLength int64) error {
|
||||
var encodedData string
|
||||
dataPlacement := c.options.GetNormalizedUplinkDataPlacement()
|
||||
if dataPlacement != option.PlacementBody {
|
||||
data, err := io.ReadAll(body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
encodedData = base64.RawURLEncoding.EncodeToString(data)
|
||||
body = nil
|
||||
contentLength = 0
|
||||
}
|
||||
func (c *DefaultDialerClient) PostPacket(ctx context.Context, url string, sessionId string, seqStr string, payload buf.MultiBuffer) error {
|
||||
method := c.options.GetNormalizedUplinkHTTPMethod()
|
||||
req, err := http.NewRequestWithContext(context.WithoutCancel(ctx), method, url, body)
|
||||
req, err := http.NewRequestWithContext(context.WithoutCancel(ctx), method, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.ContentLength = contentLength
|
||||
req.Header = c.options.GetRequestHeader()
|
||||
if dataPlacement != option.PlacementBody {
|
||||
key := c.options.UplinkDataKey
|
||||
chunkSize := int(c.options.UplinkChunkSize)
|
||||
switch dataPlacement {
|
||||
case option.PlacementHeader:
|
||||
for i := 0; i < len(encodedData); i += chunkSize {
|
||||
end := i + chunkSize
|
||||
if end > len(encodedData) {
|
||||
end = len(encodedData)
|
||||
}
|
||||
chunk := encodedData[i:end]
|
||||
headerKey := fmt.Sprintf("%s-%d", key, i/chunkSize)
|
||||
req.Header.Set(headerKey, chunk)
|
||||
}
|
||||
|
||||
req.Header.Set(key+"-Length", fmt.Sprintf("%d", len(encodedData)))
|
||||
req.Header.Set(key+"-Upstream", "1")
|
||||
case option.PlacementCookie:
|
||||
for i := 0; i < len(encodedData); i += chunkSize {
|
||||
end := i + chunkSize
|
||||
if end > len(encodedData) {
|
||||
end = len(encodedData)
|
||||
}
|
||||
chunk := encodedData[i:end]
|
||||
cookieName := fmt.Sprintf("%s_%d", key, i/chunkSize)
|
||||
req.AddCookie(&http.Cookie{Name: cookieName, Value: chunk})
|
||||
}
|
||||
|
||||
req.AddCookie(&http.Cookie{Name: key + "_upstream", Value: "1"})
|
||||
}
|
||||
}
|
||||
length := int(c.options.GetNormalizedXPaddingBytes().Rand())
|
||||
config := XPaddingConfig{Length: length}
|
||||
if c.options.XPaddingObfsMode {
|
||||
config.Placement = XPaddingPlacement{
|
||||
Placement: c.options.XPaddingPlacement,
|
||||
Key: c.options.XPaddingKey,
|
||||
Header: c.options.XPaddingHeader,
|
||||
RawURL: url,
|
||||
}
|
||||
config.Method = PaddingMethod(c.options.XPaddingMethod)
|
||||
} else {
|
||||
config.Placement = XPaddingPlacement{
|
||||
Placement: option.PlacementQueryInHeader,
|
||||
Key: "x_padding",
|
||||
Header: "Referer",
|
||||
RawURL: url,
|
||||
}
|
||||
}
|
||||
ApplyXPaddingToRequest(req, config)
|
||||
ApplyMetaToRequest(c.options, req, sessionId, seqStr)
|
||||
FillPacketRequest(req, sessionId, seqStr, payload, c.options)
|
||||
if c.httpVersion != "1.1" {
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
@@ -185,12 +100,16 @@ func (c *DefaultDialerClient) PostPacket(ctx context.Context, url string, sessio
|
||||
}
|
||||
io.Copy(io.Discard, resp.Body)
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != 200 {
|
||||
return E.New("bad status code: ", resp.Status)
|
||||
}
|
||||
} else {
|
||||
// stringify the entire HTTP/1.1 request so it can be
|
||||
// safely retried. if instead req.Write is called multiple
|
||||
// times, the body is already drained after the first
|
||||
// request
|
||||
requestBuff := new(bytes.Buffer)
|
||||
requestBuff.Grow(512 + int(req.ContentLength))
|
||||
common.Must(req.Write(requestBuff))
|
||||
var uploadConn any
|
||||
var h1UploadConn *H1Conn
|
||||
|
||||
Reference in New Issue
Block a user