mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-25 10:01:30 +00:00
Accept HTTP1 in naive inbound
This commit is contained in:
parent
c9b7acd22c
commit
9edfe7d9d3
2
Makefile
2
Makefile
|
@ -57,7 +57,7 @@ test:
|
|||
@go test -v . && \
|
||||
pushd test && \
|
||||
go mod tidy && \
|
||||
go test -v -tags '$(TAGS)' . && \
|
||||
go test -v -tags with_quic,with_wireguard,with_grpc . && \
|
||||
popd
|
||||
|
||||
clean:
|
||||
|
|
|
@ -212,6 +212,15 @@ func (a *myInboundAdapter) injectTCP(conn net.Conn) {
|
|||
}
|
||||
}
|
||||
|
||||
func (a *myInboundAdapter) routeTCP(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) {
|
||||
a.logger.InfoContext(ctx, "inbound connection from ", metadata.Source)
|
||||
hErr := a.newConnection(ctx, conn, metadata)
|
||||
if hErr != nil {
|
||||
conn.Close()
|
||||
a.NewError(ctx, E.Cause(hErr, "process connection from ", metadata.Source))
|
||||
}
|
||||
}
|
||||
|
||||
func (a *myInboundAdapter) loopUDPIn() {
|
||||
defer close(a.packetOutboundClosed)
|
||||
_buffer := buf.StackNewPacket()
|
||||
|
|
355
inbound/naive.go
355
inbound/naive.go
|
@ -2,13 +2,13 @@ package inbound
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -17,13 +17,11 @@ import (
|
|||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-dns"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/auth"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/rw"
|
||||
|
@ -32,12 +30,7 @@ import (
|
|||
var _ adapter.Inbound = (*Naive)(nil)
|
||||
|
||||
type Naive struct {
|
||||
ctx context.Context
|
||||
router adapter.Router
|
||||
logger log.ContextLogger
|
||||
tag string
|
||||
listenOptions option.ListenOptions
|
||||
network []string
|
||||
myInboundAdapter
|
||||
authenticator auth.Authenticator
|
||||
tlsConfig *TLSConfig
|
||||
httpServer *http.Server
|
||||
|
@ -46,76 +39,69 @@ type Naive struct {
|
|||
|
||||
func NewNaive(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.NaiveInboundOptions) (*Naive, error) {
|
||||
inbound := &Naive{
|
||||
ctx: ctx,
|
||||
router: router,
|
||||
logger: logger,
|
||||
tag: tag,
|
||||
listenOptions: options.ListenOptions,
|
||||
network: options.Network.Build(),
|
||||
myInboundAdapter: myInboundAdapter{
|
||||
protocol: C.TypeNaive,
|
||||
network: options.Network.Build(),
|
||||
ctx: ctx,
|
||||
router: router,
|
||||
logger: logger,
|
||||
tag: tag,
|
||||
listenOptions: options.ListenOptions,
|
||||
},
|
||||
authenticator: auth.NewAuthenticator(options.Users),
|
||||
}
|
||||
if options.TLS == nil || !options.TLS.Enabled {
|
||||
return nil, C.ErrTLSRequired
|
||||
if common.Contains(inbound.network, N.NetworkUDP) {
|
||||
if options.TLS == nil || !options.TLS.Enabled {
|
||||
return nil, E.New("TLS is required for QUIC server")
|
||||
}
|
||||
}
|
||||
if len(options.Users) == 0 {
|
||||
return nil, E.New("missing users")
|
||||
}
|
||||
tlsConfig, err := NewTLSConfig(ctx, logger, common.PtrValueOrDefault(options.TLS))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if options.TLS != nil {
|
||||
tlsConfig, err := NewTLSConfig(ctx, logger, common.PtrValueOrDefault(options.TLS))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
inbound.tlsConfig = tlsConfig
|
||||
}
|
||||
inbound.tlsConfig = tlsConfig
|
||||
return inbound, nil
|
||||
}
|
||||
|
||||
func (n *Naive) Type() string {
|
||||
return C.TypeNaive
|
||||
}
|
||||
|
||||
func (n *Naive) Tag() string {
|
||||
return n.tag
|
||||
}
|
||||
|
||||
func (n *Naive) Start() error {
|
||||
err := n.tlsConfig.Start()
|
||||
if err != nil {
|
||||
return E.Cause(err, "create TLS config")
|
||||
}
|
||||
|
||||
var listenAddr string
|
||||
if nAddr := netip.Addr(n.listenOptions.Listen); nAddr.IsValid() {
|
||||
if n.listenOptions.ListenPort != 0 {
|
||||
listenAddr = M.SocksaddrFrom(netip.Addr(n.listenOptions.Listen), n.listenOptions.ListenPort).String()
|
||||
} else {
|
||||
listenAddr = net.JoinHostPort(nAddr.String(), ":https")
|
||||
var tlsConfig *tls.Config
|
||||
if n.tlsConfig != nil {
|
||||
err := n.tlsConfig.Start()
|
||||
if err != nil {
|
||||
return E.Cause(err, "create TLS config")
|
||||
}
|
||||
} else if n.listenOptions.ListenPort != 0 {
|
||||
listenAddr = ":" + F.ToString(n.listenOptions.ListenPort)
|
||||
} else {
|
||||
listenAddr = ":https"
|
||||
tlsConfig = n.tlsConfig.Config()
|
||||
}
|
||||
|
||||
if common.Contains(n.network, N.NetworkTCP) {
|
||||
n.httpServer = &http.Server{
|
||||
Handler: n,
|
||||
TLSConfig: n.tlsConfig.Config(),
|
||||
}
|
||||
tcpListener, err := net.Listen(M.NetworkFromNetAddr("tcp", netip.Addr(n.listenOptions.Listen)), listenAddr)
|
||||
tcpListener, err := n.ListenTCP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n.logger.Info("tcp server started at ", tcpListener.Addr())
|
||||
n.httpServer = &http.Server{
|
||||
Handler: n,
|
||||
TLSConfig: tlsConfig,
|
||||
}
|
||||
go func() {
|
||||
sErr := n.httpServer.ServeTLS(tcpListener, "", "")
|
||||
if sErr == http.ErrServerClosed {
|
||||
} else if sErr != nil {
|
||||
var sErr error
|
||||
if tlsConfig != nil {
|
||||
sErr = n.httpServer.ServeTLS(tcpListener, "", "")
|
||||
} else {
|
||||
sErr = n.httpServer.Serve(tcpListener)
|
||||
}
|
||||
if sErr != nil && !E.IsClosedOrCanceled(sErr) {
|
||||
n.logger.Error("http server serve error: ", sErr)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if common.Contains(n.network, N.NetworkUDP) {
|
||||
err = n.configureHTTP3Listener(listenAddr)
|
||||
err := n.configureHTTP3Listener()
|
||||
if !C.QUIC_AVAILABLE && len(n.network) > 1 {
|
||||
log.Warn(E.Cause(err, "naive http3 disabled"))
|
||||
} else if err != nil {
|
||||
|
@ -128,6 +114,7 @@ func (n *Naive) Start() error {
|
|||
|
||||
func (n *Naive) Close() error {
|
||||
return common.Close(
|
||||
&n.myInboundAdapter,
|
||||
common.PtrOrNil(n.httpServer),
|
||||
n.h3Server,
|
||||
common.PtrOrNil(n.tlsConfig),
|
||||
|
@ -137,12 +124,12 @@ func (n *Naive) Close() error {
|
|||
func (n *Naive) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||
ctx := log.ContextWithNewID(request.Context())
|
||||
if request.Method != "CONNECT" {
|
||||
n.logger.ErrorContext(ctx, "bad request: not connect")
|
||||
rejectHTTP(writer, http.StatusBadRequest)
|
||||
n.badRequest(ctx, request, E.New("not CONNECT request"))
|
||||
return
|
||||
} else if request.Header.Get("Padding") == "" {
|
||||
n.logger.ErrorContext(ctx, "bad request: missing padding")
|
||||
rejectHTTP(writer, http.StatusBadRequest)
|
||||
n.badRequest(ctx, request, E.New("missing naive padding"))
|
||||
return
|
||||
}
|
||||
var authOk bool
|
||||
|
@ -156,46 +143,41 @@ func (n *Naive) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
|||
}
|
||||
}
|
||||
if !authOk {
|
||||
n.logger.ErrorContext(ctx, "bad request: authorization failed")
|
||||
rejectHTTP(writer, http.StatusProxyAuthRequired)
|
||||
n.badRequest(ctx, request, E.New("authorization failed"))
|
||||
return
|
||||
}
|
||||
writer.Header().Set("Padding", generateNaivePaddingHeader())
|
||||
writer.WriteHeader(http.StatusOK)
|
||||
writer.(http.Flusher).Flush()
|
||||
|
||||
if request.ProtoMajor == 1 {
|
||||
n.logger.ErrorContext(ctx, "bad request: http1")
|
||||
rejectHTTP(writer, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
hostPort := request.URL.Host
|
||||
if hostPort == "" {
|
||||
hostPort = request.Host
|
||||
}
|
||||
source := M.ParseSocksaddr(request.RemoteAddr)
|
||||
destination := M.ParseSocksaddr(hostPort)
|
||||
n.newConnection(ctx, &naivePaddingConn{reader: request.Body, writer: writer, flusher: writer.(http.Flusher)}, source, destination)
|
||||
|
||||
if hijacker, isHijacker := writer.(http.Hijacker); isHijacker {
|
||||
conn, _, err := hijacker.Hijack()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n.newConnection(ctx, &naiveH1Conn{Conn: conn}, source, destination)
|
||||
} else {
|
||||
n.newConnection(ctx, &naiveH2Conn{reader: request.Body, writer: writer, flusher: writer.(http.Flusher)}, source, destination)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Naive) newConnection(ctx context.Context, conn net.Conn, source, destination M.Socksaddr) {
|
||||
var metadata adapter.InboundContext
|
||||
metadata.Inbound = n.tag
|
||||
metadata.InboundType = C.TypeNaive
|
||||
metadata.SniffEnabled = n.listenOptions.SniffEnabled
|
||||
metadata.SniffOverrideDestination = n.listenOptions.SniffOverrideDestination
|
||||
metadata.DomainStrategy = dns.DomainStrategy(n.listenOptions.DomainStrategy)
|
||||
metadata.Network = N.NetworkTCP
|
||||
metadata := n.createMetadata(conn)
|
||||
metadata.Source = source
|
||||
metadata.Destination = destination
|
||||
n.logger.InfoContext(ctx, "inbound connection from ", metadata.Source)
|
||||
n.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination)
|
||||
hErr := n.router.RouteConnection(ctx, conn, metadata)
|
||||
if hErr != nil {
|
||||
conn.Close()
|
||||
NewError(n.logger, ctx, E.Cause(hErr, "process connection from ", metadata.Source))
|
||||
}
|
||||
n.routeTCP(ctx, conn, metadata)
|
||||
}
|
||||
|
||||
func (n *Naive) badRequest(ctx context.Context, request *http.Request, err error) {
|
||||
n.NewError(ctx, E.Cause(err, "process connection from ", request.RemoteAddr))
|
||||
}
|
||||
|
||||
func rejectHTTP(writer http.ResponseWriter, statusCode int) {
|
||||
|
@ -232,9 +214,174 @@ func generateNaivePaddingHeader() string {
|
|||
|
||||
const kFirstPaddings = 8
|
||||
|
||||
var _ net.Conn = (*naivePaddingConn)(nil)
|
||||
type naiveH1Conn struct {
|
||||
net.Conn
|
||||
readPadding int
|
||||
writePadding int
|
||||
readRemaining int
|
||||
paddingRemaining int
|
||||
}
|
||||
|
||||
type naivePaddingConn struct {
|
||||
func (c *naiveH1Conn) Read(p []byte) (n int, err error) {
|
||||
n, err = c.read(p)
|
||||
return n, wrapHttpError(err)
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) read(p []byte) (n int, err error) {
|
||||
if c.readRemaining > 0 {
|
||||
if len(p) > c.readRemaining {
|
||||
p = p[:c.readRemaining]
|
||||
}
|
||||
n, err = c.Conn.Read(p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.readRemaining -= n
|
||||
return
|
||||
}
|
||||
if c.paddingRemaining > 0 {
|
||||
err = rw.SkipN(c.Conn, c.paddingRemaining)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.readRemaining = 0
|
||||
}
|
||||
if c.readPadding < kFirstPaddings {
|
||||
paddingHdr := p[:3]
|
||||
_, err = io.ReadFull(c.Conn, paddingHdr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
originalDataSize := int(binary.BigEndian.Uint16(paddingHdr[:2]))
|
||||
paddingSize := int(paddingHdr[2])
|
||||
if len(p) > originalDataSize {
|
||||
p = p[:originalDataSize]
|
||||
}
|
||||
n, err = c.Conn.Read(p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.readPadding++
|
||||
c.readRemaining = originalDataSize - n
|
||||
c.paddingRemaining = paddingSize
|
||||
return
|
||||
}
|
||||
return c.Conn.Read(p)
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) Write(p []byte) (n int, err error) {
|
||||
for pLen := len(p); pLen > 0; {
|
||||
var data []byte
|
||||
if pLen > 65535 {
|
||||
data = p[:65535]
|
||||
p = p[65535:]
|
||||
pLen -= 65535
|
||||
} else {
|
||||
data = p
|
||||
pLen = 0
|
||||
}
|
||||
var writeN int
|
||||
writeN, err = c.write(data)
|
||||
n += writeN
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return n, wrapHttpError(err)
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) write(p []byte) (n int, err error) {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
paddingSize := rand.Intn(256)
|
||||
|
||||
_buffer := buf.StackNewSize(3 + len(p) + paddingSize)
|
||||
defer common.KeepAlive(_buffer)
|
||||
buffer := common.Dup(_buffer)
|
||||
defer buffer.Release()
|
||||
header := buffer.Extend(3)
|
||||
binary.BigEndian.PutUint16(header, uint16(len(p)))
|
||||
header[2] = byte(paddingSize)
|
||||
|
||||
common.Must1(buffer.Write(p))
|
||||
_, err = c.Conn.Write(buffer.Bytes())
|
||||
if err == nil {
|
||||
n = len(p)
|
||||
}
|
||||
c.writePadding++
|
||||
return
|
||||
}
|
||||
return c.Conn.Write(p)
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) FrontHeadroom() int {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
return 3
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) RearHeadroom() int {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
return 255
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) WriterMTU() int {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
return 65535
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) WriteBuffer(buffer *buf.Buffer) error {
|
||||
defer buffer.Release()
|
||||
if c.writePadding < kFirstPaddings {
|
||||
bufferLen := buffer.Len()
|
||||
if bufferLen > 65535 {
|
||||
return common.Error(c.Write(buffer.Bytes()))
|
||||
}
|
||||
paddingSize := rand.Intn(256)
|
||||
header := buffer.ExtendHeader(3)
|
||||
binary.BigEndian.PutUint16(header, uint16(bufferLen))
|
||||
header[2] = byte(paddingSize)
|
||||
buffer.Extend(paddingSize)
|
||||
c.writePadding++
|
||||
}
|
||||
return wrapHttpError(common.Error(c.Conn.Write(buffer.Bytes())))
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) WriteTo(w io.Writer) (n int64, err error) {
|
||||
if c.readPadding < kFirstPaddings {
|
||||
n, err = bufio.WriteToN(c, w, kFirstPaddings-c.readPadding)
|
||||
} else {
|
||||
n, err = bufio.Copy(w, c.Conn)
|
||||
}
|
||||
return n, wrapHttpError(err)
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
n, err = bufio.ReadFromN(c, r, kFirstPaddings-c.writePadding)
|
||||
} else {
|
||||
n, err = bufio.Copy(c.Conn, r)
|
||||
}
|
||||
return n, wrapHttpError(err)
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) Upstream() any {
|
||||
return c.Conn
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) ReaderReplaceable() bool {
|
||||
return c.readRemaining == kFirstPaddings
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) WriterReplaceable() bool {
|
||||
return c.writePadding == kFirstPaddings
|
||||
}
|
||||
|
||||
type naiveH2Conn struct {
|
||||
reader io.Reader
|
||||
writer io.Writer
|
||||
flusher http.Flusher
|
||||
|
@ -245,12 +392,12 @@ type naivePaddingConn struct {
|
|||
paddingRemaining int
|
||||
}
|
||||
|
||||
func (c *naivePaddingConn) Read(p []byte) (n int, err error) {
|
||||
func (c *naiveH2Conn) Read(p []byte) (n int, err error) {
|
||||
n, err = c.read(p)
|
||||
return n, wrapHttpError(err)
|
||||
}
|
||||
|
||||
func (c *naivePaddingConn) read(p []byte) (n int, err error) {
|
||||
func (c *naiveH2Conn) read(p []byte) (n int, err error) {
|
||||
if c.readRemaining > 0 {
|
||||
if len(p) > c.readRemaining {
|
||||
p = p[:c.readRemaining]
|
||||
|
@ -292,7 +439,7 @@ func (c *naivePaddingConn) read(p []byte) (n int, err error) {
|
|||
return c.reader.Read(p)
|
||||
}
|
||||
|
||||
func (c *naivePaddingConn) Write(p []byte) (n int, err error) {
|
||||
func (c *naiveH2Conn) Write(p []byte) (n int, err error) {
|
||||
for pLen := len(p); pLen > 0; {
|
||||
var data []byte
|
||||
if pLen > 65535 {
|
||||
|
@ -316,7 +463,7 @@ func (c *naivePaddingConn) Write(p []byte) (n int, err error) {
|
|||
return n, wrapHttpError(err)
|
||||
}
|
||||
|
||||
func (c *naivePaddingConn) write(p []byte) (n int, err error) {
|
||||
func (c *naiveH2Conn) write(p []byte) (n int, err error) {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
paddingSize := rand.Intn(256)
|
||||
|
||||
|
@ -339,28 +486,28 @@ func (c *naivePaddingConn) write(p []byte) (n int, err error) {
|
|||
return c.writer.Write(p)
|
||||
}
|
||||
|
||||
func (c *naivePaddingConn) FrontHeadroom() int {
|
||||
func (c *naiveH2Conn) FrontHeadroom() int {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
return 3
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *naivePaddingConn) RearHeadroom() int {
|
||||
func (c *naiveH2Conn) RearHeadroom() int {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
return 255
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *naivePaddingConn) WriterMTU() int {
|
||||
func (c *naiveH2Conn) WriterMTU() int {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
return 65535
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *naivePaddingConn) WriteBuffer(buffer *buf.Buffer) error {
|
||||
func (c *naiveH2Conn) WriteBuffer(buffer *buf.Buffer) error {
|
||||
defer buffer.Release()
|
||||
if c.writePadding < kFirstPaddings {
|
||||
bufferLen := buffer.Len()
|
||||
|
@ -381,7 +528,7 @@ func (c *naivePaddingConn) WriteBuffer(buffer *buf.Buffer) error {
|
|||
return wrapHttpError(err)
|
||||
}
|
||||
|
||||
func (c *naivePaddingConn) WriteTo(w io.Writer) (n int64, err error) {
|
||||
func (c *naiveH2Conn) WriteTo(w io.Writer) (n int64, err error) {
|
||||
if c.readPadding < kFirstPaddings {
|
||||
n, err = bufio.WriteToN(c, w, kFirstPaddings-c.readPadding)
|
||||
} else {
|
||||
|
@ -390,7 +537,7 @@ func (c *naivePaddingConn) WriteTo(w io.Writer) (n int64, err error) {
|
|||
return n, wrapHttpError(err)
|
||||
}
|
||||
|
||||
func (c *naivePaddingConn) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
func (c *naiveH2Conn) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
n, err = bufio.ReadFromN(c, r, kFirstPaddings-c.writePadding)
|
||||
} else {
|
||||
|
@ -399,33 +546,49 @@ func (c *naivePaddingConn) ReadFrom(r io.Reader) (n int64, err error) {
|
|||
return n, wrapHttpError(err)
|
||||
}
|
||||
|
||||
func (c *naivePaddingConn) Close() error {
|
||||
func (c *naiveH2Conn) Close() error {
|
||||
return common.Close(
|
||||
c.reader,
|
||||
c.writer,
|
||||
)
|
||||
}
|
||||
|
||||
func (c *naivePaddingConn) LocalAddr() net.Addr {
|
||||
func (c *naiveH2Conn) LocalAddr() net.Addr {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *naivePaddingConn) RemoteAddr() net.Addr {
|
||||
func (c *naiveH2Conn) RemoteAddr() net.Addr {
|
||||
return c.rAddr
|
||||
}
|
||||
|
||||
func (c *naivePaddingConn) SetDeadline(t time.Time) error {
|
||||
func (c *naiveH2Conn) SetDeadline(t time.Time) error {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
|
||||
func (c *naivePaddingConn) SetReadDeadline(t time.Time) error {
|
||||
func (c *naiveH2Conn) SetReadDeadline(t time.Time) error {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
|
||||
func (c *naivePaddingConn) SetWriteDeadline(t time.Time) error {
|
||||
func (c *naiveH2Conn) SetWriteDeadline(t time.Time) error {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) UpstreamReader() any {
|
||||
return c.reader
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) UpstreamWriter() any {
|
||||
return c.writer
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) ReaderReplaceable() bool {
|
||||
return c.readRemaining == kFirstPaddings
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) WriterReplaceable() bool {
|
||||
return c.writePadding == kFirstPaddings
|
||||
}
|
||||
|
||||
func wrapHttpError(err error) error {
|
||||
if err == nil {
|
||||
return err
|
||||
|
|
|
@ -3,34 +3,26 @@
|
|||
package inbound
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/sagernet/quic-go"
|
||||
"github.com/sagernet/quic-go/http3"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
|
||||
func (n *Naive) configureHTTP3Listener(listenAddr string) error {
|
||||
func (n *Naive) configureHTTP3Listener() error {
|
||||
h3Server := &http3.Server{
|
||||
Port: int(n.listenOptions.ListenPort),
|
||||
TLSConfig: n.tlsConfig.Config(),
|
||||
Handler: n,
|
||||
}
|
||||
|
||||
udpListener, err := net.ListenPacket(M.NetworkFromNetAddr("udp", netip.Addr(n.listenOptions.Listen)), listenAddr)
|
||||
udpConn, err := n.ListenUDP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n.logger.Info("udp server started at ", udpListener.LocalAddr())
|
||||
|
||||
go func() {
|
||||
sErr := h3Server.Serve(udpListener)
|
||||
if sErr == quic.ErrServerClosed {
|
||||
udpListener.Close()
|
||||
return
|
||||
} else if sErr != nil {
|
||||
sErr := h3Server.Serve(udpConn)
|
||||
udpConn.Close()
|
||||
if sErr != nil && !E.IsClosedOrCanceled(sErr) {
|
||||
n.logger.Error("http3 server serve error: ", sErr)
|
||||
}
|
||||
}()
|
||||
|
|
|
@ -6,6 +6,6 @@ import (
|
|||
C "github.com/sagernet/sing-box/constant"
|
||||
)
|
||||
|
||||
func (n *Naive) configureHTTP3Listener(listenAddr string) error {
|
||||
func (n *Naive) configureHTTP3Listener() error {
|
||||
return C.ErrQUICNotIncluded
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ const (
|
|||
ImageNaive = "pocat/naiveproxy:client"
|
||||
ImageBoringTun = "ghcr.io/ntkme/boringtun:edge"
|
||||
ImageHysteria = "tobyxdd/hysteria:latest"
|
||||
ImageNginx = "nginx:stable"
|
||||
)
|
||||
|
||||
var allImages = []string{
|
||||
|
@ -45,6 +46,7 @@ var allImages = []string{
|
|||
ImageNaive,
|
||||
ImageBoringTun,
|
||||
ImageHysteria,
|
||||
// ImageNginx,
|
||||
}
|
||||
|
||||
var localIP = netip.MustParseAddr("127.0.0.1")
|
||||
|
|
22
test/config/naive-nginx.conf
Normal file
22
test/config/naive-nginx.conf
Normal file
|
@ -0,0 +1,22 @@
|
|||
server {
|
||||
listen 10000 ssl http2;
|
||||
listen [::]:10000 ssl http2;
|
||||
|
||||
server_name example.org;
|
||||
ssl_certificate /etc/nginx/cert.pem;
|
||||
ssl_certificate_key /etc/nginx/key.pem;
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
|
||||
ssl_session_tickets off;
|
||||
|
||||
# modern configuration
|
||||
ssl_protocols TLSv1.3;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
|
||||
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:10003;
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ func TestHysteriaSelf(t *testing.T) {
|
|||
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
|
||||
startInstance(t, option.Options{
|
||||
Log: &option.LogOptions{
|
||||
Level: "trace",
|
||||
Level: "error",
|
||||
},
|
||||
Inbounds: []option.Inbound{
|
||||
{
|
||||
|
@ -93,7 +93,7 @@ func TestHysteriaInbound(t *testing.T) {
|
|||
caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
|
||||
startInstance(t, option.Options{
|
||||
Log: &option.LogOptions{
|
||||
Level: "trace",
|
||||
Level: "error",
|
||||
},
|
||||
Inbounds: []option.Inbound{
|
||||
{
|
||||
|
@ -146,7 +146,7 @@ func TestHysteriaOutbound(t *testing.T) {
|
|||
})
|
||||
startInstance(t, option.Options{
|
||||
Log: &option.LogOptions{
|
||||
Level: "trace",
|
||||
Level: "error",
|
||||
},
|
||||
Inbounds: []option.Inbound{
|
||||
{
|
||||
|
|
|
@ -10,6 +10,55 @@ import (
|
|||
"github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
// FIXME: nginx do not support CONNECT
|
||||
func _TestNaiveInboundWithNingx(t *testing.T) {
|
||||
caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
|
||||
startInstance(t, option.Options{
|
||||
Log: &option.LogOptions{
|
||||
Level: "trace",
|
||||
},
|
||||
Inbounds: []option.Inbound{
|
||||
{
|
||||
Type: C.TypeNaive,
|
||||
NaiveOptions: option.NaiveInboundOptions{
|
||||
ListenOptions: option.ListenOptions{
|
||||
Listen: option.ListenAddress(netip.IPv4Unspecified()),
|
||||
ListenPort: otherPort,
|
||||
},
|
||||
Users: []auth.User{
|
||||
{
|
||||
Username: "sekai",
|
||||
Password: "password",
|
||||
},
|
||||
},
|
||||
Network: network.NetworkTCP,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
startDockerContainer(t, DockerOptions{
|
||||
Image: ImageNginx,
|
||||
Ports: []uint16{serverPort, otherPort},
|
||||
Bind: map[string]string{
|
||||
"naive-nginx.conf": "/etc/nginx/conf.d/naive.conf",
|
||||
certPem: "/etc/nginx/cert.pem",
|
||||
keyPem: "/etc/nginx/key.pem",
|
||||
},
|
||||
})
|
||||
startDockerContainer(t, DockerOptions{
|
||||
Image: ImageNaive,
|
||||
Ports: []uint16{serverPort, clientPort},
|
||||
Bind: map[string]string{
|
||||
"naive.json": "/etc/naiveproxy/config.json",
|
||||
caPem: "/etc/naiveproxy/ca.pem",
|
||||
},
|
||||
Env: []string{
|
||||
"SSL_CERT_FILE=/etc/naiveproxy/ca.pem",
|
||||
},
|
||||
})
|
||||
testTCP(t, clientPort, testPort)
|
||||
}
|
||||
|
||||
func TestNaiveInbound(t *testing.T) {
|
||||
caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
|
||||
startInstance(t, option.Options{
|
||||
|
|
|
@ -18,6 +18,7 @@ const (
|
|||
serverPort uint16 = 10000 + iota
|
||||
clientPort
|
||||
testPort
|
||||
otherPort
|
||||
)
|
||||
|
||||
func TestShadowsocks(t *testing.T) {
|
||||
|
@ -199,7 +200,7 @@ func TestShadowsocksUoT(t *testing.T) {
|
|||
password := mkBase64(t, 16)
|
||||
startInstance(t, option.Options{
|
||||
Log: &option.LogOptions{
|
||||
Level: "trace",
|
||||
Level: "error",
|
||||
},
|
||||
Inbounds: []option.Inbound{
|
||||
{
|
||||
|
|
|
@ -310,7 +310,7 @@ func testV2RayTransportNOTLSSelf(t *testing.T, transport *option.V2RayTransportO
|
|||
require.NoError(t, err)
|
||||
startInstance(t, option.Options{
|
||||
Log: &option.LogOptions{
|
||||
Level: "trace",
|
||||
Level: "error",
|
||||
},
|
||||
Inbounds: []option.Inbound{
|
||||
{
|
||||
|
|
|
@ -22,7 +22,7 @@ func TestWireGuard(t *testing.T) {
|
|||
time.Sleep(5 * time.Second)
|
||||
startInstance(t, option.Options{
|
||||
Log: &option.LogOptions{
|
||||
Level: "trace",
|
||||
Level: "error",
|
||||
},
|
||||
Inbounds: []option.Inbound{
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue