sing-box/inbound/naive.go

643 lines
15 KiB
Go
Raw Normal View History

2022-08-10 12:19:16 +00:00
package inbound
import (
"context"
"encoding/base64"
"encoding/binary"
"io"
"math/rand"
"net"
"net/http"
"os"
"strings"
"time"
"github.com/sagernet/sing-box/adapter"
2022-09-09 10:45:10 +00:00
"github.com/sagernet/sing-box/common/tls"
2022-08-10 12:19:16 +00:00
C "github.com/sagernet/sing-box/constant"
2022-09-14 04:46:02 +00:00
"github.com/sagernet/sing-box/include"
2022-08-10 12:19:16 +00:00
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/auth"
"github.com/sagernet/sing/common/buf"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/rw"
2022-08-23 11:44:40 +00:00
sHttp "github.com/sagernet/sing/protocol/http"
2022-08-10 12:19:16 +00:00
)
var _ adapter.Inbound = (*Naive)(nil)
type Naive struct {
2022-08-23 05:22:03 +00:00
myInboundAdapter
2022-08-10 12:19:16 +00:00
authenticator auth.Authenticator
2022-09-09 10:45:10 +00:00
tlsConfig tls.ServerConfig
2022-08-10 12:19:16 +00:00
httpServer *http.Server
h3Server any
}
func NewNaive(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.NaiveInboundOptions) (*Naive, error) {
inbound := &Naive{
2022-08-23 05:22:03 +00:00
myInboundAdapter: myInboundAdapter{
protocol: C.TypeNaive,
network: options.Network.Build(),
ctx: ctx,
router: router,
logger: logger,
tag: tag,
listenOptions: options.ListenOptions,
},
2022-08-10 12:19:16 +00:00
authenticator: auth.NewAuthenticator(options.Users),
}
2022-08-23 05:22:03 +00:00
if common.Contains(inbound.network, N.NetworkUDP) {
if options.TLS == nil || !options.TLS.Enabled {
return nil, E.New("TLS is required for QUIC server")
}
2022-08-10 12:19:16 +00:00
}
if len(options.Users) == 0 {
return nil, E.New("missing users")
2022-08-10 12:19:16 +00:00
}
2022-08-23 05:22:03 +00:00
if options.TLS != nil {
2023-02-21 06:53:00 +00:00
tlsConfig, err := tls.NewServer(ctx, router, logger, common.PtrValueOrDefault(options.TLS))
2022-08-23 05:22:03 +00:00
if err != nil {
return nil, err
}
inbound.tlsConfig = tlsConfig
2022-08-10 12:19:16 +00:00
}
return inbound, nil
}
func (n *Naive) Start() error {
2022-09-09 10:45:10 +00:00
var tlsConfig *tls.STDConfig
2022-08-23 05:22:03 +00:00
if n.tlsConfig != nil {
err := n.tlsConfig.Start()
if err != nil {
return E.Cause(err, "create TLS config")
2022-08-10 12:19:16 +00:00
}
2022-09-09 10:45:10 +00:00
tlsConfig, err = n.tlsConfig.Config()
if err != nil {
return err
}
2022-08-10 12:19:16 +00:00
}
if common.Contains(n.network, N.NetworkTCP) {
2022-08-23 05:22:03 +00:00
tcpListener, err := n.ListenTCP()
2022-08-10 12:19:16 +00:00
if err != nil {
return err
}
2022-08-23 05:22:03 +00:00
n.httpServer = &http.Server{
Handler: n,
TLSConfig: tlsConfig,
2023-04-08 10:46:35 +00:00
BaseContext: func(listener net.Listener) context.Context {
return n.ctx
},
2022-08-23 05:22:03 +00:00
}
2022-08-10 12:19:16 +00:00
go func() {
2022-08-23 05:22:03 +00:00
var sErr error
if tlsConfig != nil {
sErr = n.httpServer.ServeTLS(tcpListener, "", "")
} else {
sErr = n.httpServer.Serve(tcpListener)
}
if sErr != nil && !E.IsClosedOrCanceled(sErr) {
2022-08-10 12:19:16 +00:00
n.logger.Error("http server serve error: ", sErr)
}
}()
}
if common.Contains(n.network, N.NetworkUDP) {
2022-08-23 05:22:03 +00:00
err := n.configureHTTP3Listener()
2022-09-14 04:46:02 +00:00
if !include.WithQUIC && len(n.network) > 1 {
2022-08-10 12:19:16 +00:00
log.Warn(E.Cause(err, "naive http3 disabled"))
} else if err != nil {
return err
}
}
return nil
}
func (n *Naive) Close() error {
return common.Close(
2022-08-23 05:22:03 +00:00
&n.myInboundAdapter,
2022-08-10 12:19:16 +00:00
common.PtrOrNil(n.httpServer),
n.h3Server,
2022-09-09 10:45:10 +00:00
n.tlsConfig,
2022-08-10 12:19:16 +00:00
)
}
func (n *Naive) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
ctx := log.ContextWithNewID(request.Context())
if request.Method != "CONNECT" {
rejectHTTP(writer, http.StatusBadRequest)
2022-08-23 05:22:03 +00:00
n.badRequest(ctx, request, E.New("not CONNECT request"))
2022-08-10 12:19:16 +00:00
return
} else if request.Header.Get("Padding") == "" {
rejectHTTP(writer, http.StatusBadRequest)
2022-08-23 05:22:03 +00:00
n.badRequest(ctx, request, E.New("missing naive padding"))
2022-08-10 12:19:16 +00:00
return
}
var authOk bool
2023-01-19 02:47:22 +00:00
var userName string
2022-08-10 12:19:16 +00:00
authorization := request.Header.Get("Proxy-Authorization")
if strings.HasPrefix(authorization, "BASIC ") || strings.HasPrefix(authorization, "Basic ") {
userPassword, _ := base64.URLEncoding.DecodeString(authorization[6:])
userPswdArr := strings.SplitN(string(userPassword), ":", 2)
2023-01-19 02:47:22 +00:00
userName = userPswdArr[0]
2022-08-10 12:19:16 +00:00
authOk = n.authenticator.Verify(userPswdArr[0], userPswdArr[1])
}
if !authOk {
rejectHTTP(writer, http.StatusProxyAuthRequired)
2022-08-23 05:22:03 +00:00
n.badRequest(ctx, request, E.New("authorization failed"))
2022-08-10 12:19:16 +00:00
return
}
writer.Header().Set("Padding", generateNaivePaddingHeader())
writer.WriteHeader(http.StatusOK)
writer.(http.Flusher).Flush()
hostPort := request.URL.Host
if hostPort == "" {
hostPort = request.Host
}
2022-08-23 11:44:40 +00:00
source := sHttp.SourceAddress(request)
2022-08-10 12:19:16 +00:00
destination := M.ParseSocksaddr(hostPort)
2022-08-23 05:22:03 +00:00
if hijacker, isHijacker := writer.(http.Hijacker); isHijacker {
conn, _, err := hijacker.Hijack()
if err != nil {
2022-08-24 02:21:56 +00:00
n.badRequest(ctx, request, E.New("hijack failed"))
2022-08-23 05:22:03 +00:00
return
}
2023-01-19 02:47:22 +00:00
n.newConnection(ctx, &naiveH1Conn{Conn: conn}, userName, source, destination)
2022-08-23 05:22:03 +00:00
} else {
2023-01-19 02:47:22 +00:00
n.newConnection(ctx, &naiveH2Conn{reader: request.Body, writer: writer, flusher: writer.(http.Flusher)}, userName, source, destination)
2022-08-23 05:22:03 +00:00
}
2022-08-10 12:19:16 +00:00
}
2023-01-19 02:47:22 +00:00
func (n *Naive) newConnection(ctx context.Context, conn net.Conn, userName string, source, destination M.Socksaddr) {
if userName != "" {
n.logger.InfoContext(ctx, "[", userName, "] inbound connection from ", source)
n.logger.InfoContext(ctx, "[", userName, "] inbound connection to ", destination)
} else {
n.logger.InfoContext(ctx, "inbound connection from ", source)
n.logger.InfoContext(ctx, "inbound connection to ", destination)
}
hErr := n.router.RouteConnection(ctx, conn, n.createMetadata(conn, adapter.InboundContext{
2022-08-23 11:44:40 +00:00
Source: source,
Destination: destination,
2023-01-19 02:47:22 +00:00
User: userName,
2022-08-23 11:44:40 +00:00
}))
2023-01-19 02:47:22 +00:00
if hErr != nil {
conn.Close()
n.NewError(ctx, E.Cause(hErr, "process connection from ", source))
}
2022-08-23 05:22:03 +00:00
}
func (n *Naive) badRequest(ctx context.Context, request *http.Request, err error) {
n.NewError(ctx, E.Cause(err, "process connection from ", request.RemoteAddr))
2022-08-10 12:19:16 +00:00
}
func rejectHTTP(writer http.ResponseWriter, statusCode int) {
hijacker, ok := writer.(http.Hijacker)
if !ok {
writer.WriteHeader(statusCode)
return
}
conn, _, err := hijacker.Hijack()
if err != nil {
writer.WriteHeader(statusCode)
return
}
if tcpConn, isTCP := common.Cast[*net.TCPConn](conn); isTCP {
tcpConn.SetLinger(0)
}
conn.Close()
}
func generateNaivePaddingHeader() string {
paddingLen := rand.Intn(32) + 30
padding := make([]byte, paddingLen)
bits := rand.Uint64()
for i := 0; i < 16; i++ {
// Codes that won't be Huffman coded.
padding[i] = "!#$()+<>?@[]^`{}"[bits&15]
bits >>= 4
}
for i := 16; i < paddingLen; i++ {
padding[i] = '~'
}
return string(padding)
}
const kFirstPaddings = 8
2022-08-23 05:22:03 +00:00
type naiveH1Conn struct {
net.Conn
readPadding int
writePadding int
readRemaining int
paddingRemaining int
}
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
}
2022-08-24 02:21:56 +00:00
c.paddingRemaining = 0
2022-08-23 05:22:03 +00:00
}
if c.readPadding < kFirstPaddings {
2022-10-18 09:52:52 +00:00
var paddingHdr []byte
if len(p) >= 3 {
paddingHdr = p[:3]
} else {
_paddingHdr := make([]byte, 3)
defer common.KeepAlive(_paddingHdr)
paddingHdr = common.Dup(_paddingHdr)
}
2022-08-23 05:22:03 +00:00
_, 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())))
}
2022-08-10 12:19:16 +00:00
2022-08-24 02:21:56 +00:00
// FIXME
/*func (c *naiveH1Conn) WriteTo(w io.Writer) (n int64, err error) {
2022-08-23 05:22:03 +00:00
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)
2022-09-07 04:28:41 +00:00
}
2022-08-23 05:22:03 +00:00
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)
}
2022-09-07 04:28:41 +00:00
*/
2022-08-23 05:22:03 +00:00
func (c *naiveH1Conn) Upstream() any {
return c.Conn
}
func (c *naiveH1Conn) ReaderReplaceable() bool {
2022-09-07 04:28:41 +00:00
return c.readPadding == kFirstPaddings
2022-08-23 05:22:03 +00:00
}
func (c *naiveH1Conn) WriterReplaceable() bool {
return c.writePadding == kFirstPaddings
}
type naiveH2Conn struct {
2022-08-10 12:19:16 +00:00
reader io.Reader
writer io.Writer
flusher http.Flusher
rAddr net.Addr
readPadding int
writePadding int
readRemaining int
paddingRemaining int
}
2022-08-23 05:22:03 +00:00
func (c *naiveH2Conn) Read(p []byte) (n int, err error) {
2022-08-10 12:19:16 +00:00
n, err = c.read(p)
2022-08-22 04:02:16 +00:00
return n, wrapHttpError(err)
2022-08-10 12:19:16 +00:00
}
2022-08-23 05:22:03 +00:00
func (c *naiveH2Conn) read(p []byte) (n int, err error) {
2022-08-10 12:19:16 +00:00
if c.readRemaining > 0 {
if len(p) > c.readRemaining {
p = p[:c.readRemaining]
}
2022-08-22 04:02:16 +00:00
n, err = c.reader.Read(p)
2022-08-10 12:19:16 +00:00
if err != nil {
return
}
c.readRemaining -= n
return
}
if c.paddingRemaining > 0 {
err = rw.SkipN(c.reader, c.paddingRemaining)
if err != nil {
return
}
2022-08-24 02:21:56 +00:00
c.paddingRemaining = 0
2022-08-10 12:19:16 +00:00
}
if c.readPadding < kFirstPaddings {
2022-10-18 09:52:52 +00:00
var paddingHdr []byte
if len(p) >= 3 {
paddingHdr = p[:3]
} else {
_paddingHdr := make([]byte, 3)
defer common.KeepAlive(_paddingHdr)
paddingHdr = common.Dup(_paddingHdr)
}
2022-08-10 12:19:16 +00:00
_, err = io.ReadFull(c.reader, 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.reader.Read(p)
if err != nil {
return
}
c.readPadding++
c.readRemaining = originalDataSize - n
c.paddingRemaining = paddingSize
return
}
return c.reader.Read(p)
}
2022-08-23 05:22:03 +00:00
func (c *naiveH2Conn) Write(p []byte) (n int, err error) {
2022-08-22 04:02:16 +00:00
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
}
}
2022-08-10 12:19:16 +00:00
if err == nil {
c.flusher.Flush()
}
2022-08-22 04:02:16 +00:00
return n, wrapHttpError(err)
2022-08-10 12:19:16 +00:00
}
2022-08-23 05:22:03 +00:00
func (c *naiveH2Conn) write(p []byte) (n int, err error) {
2022-08-10 12:19:16 +00:00
if c.writePadding < kFirstPaddings {
paddingSize := rand.Intn(256)
2022-08-22 04:02:16 +00:00
_buffer := buf.StackNewSize(3 + len(p) + paddingSize)
defer common.KeepAlive(_buffer)
2022-08-10 12:19:16 +00:00
buffer := common.Dup(_buffer)
2022-08-22 04:02:16 +00:00
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.writer.Write(buffer.Bytes())
if err == nil {
n = len(p)
2022-08-10 12:19:16 +00:00
}
c.writePadding++
2022-08-22 04:02:16 +00:00
return
2022-08-10 12:19:16 +00:00
}
return c.writer.Write(p)
}
2022-08-23 05:22:03 +00:00
func (c *naiveH2Conn) FrontHeadroom() int {
2022-08-11 15:59:22 +00:00
if c.writePadding < kFirstPaddings {
2022-08-22 04:02:16 +00:00
return 3
}
return 0
}
2022-08-23 05:22:03 +00:00
func (c *naiveH2Conn) RearHeadroom() int {
2022-08-22 04:02:16 +00:00
if c.writePadding < kFirstPaddings {
return 255
}
return 0
}
2022-08-23 05:22:03 +00:00
func (c *naiveH2Conn) WriterMTU() int {
2022-08-22 04:02:16 +00:00
if c.writePadding < kFirstPaddings {
return 65535
2022-08-11 15:59:22 +00:00
}
return 0
}
2022-08-23 05:22:03 +00:00
func (c *naiveH2Conn) WriteBuffer(buffer *buf.Buffer) error {
2022-08-10 12:19:16 +00:00
defer buffer.Release()
if c.writePadding < kFirstPaddings {
bufferLen := buffer.Len()
2022-08-22 04:02:16 +00:00
if bufferLen > 65535 {
return common.Error(c.Write(buffer.Bytes()))
}
2022-08-10 12:19:16 +00:00
paddingSize := rand.Intn(256)
header := buffer.ExtendHeader(3)
binary.BigEndian.PutUint16(header, uint16(bufferLen))
header[2] = byte(paddingSize)
buffer.Extend(paddingSize)
c.writePadding++
}
err := common.Error(c.writer.Write(buffer.Bytes()))
if err == nil {
c.flusher.Flush()
}
return wrapHttpError(err)
}
2022-08-24 02:21:56 +00:00
// FIXME
/*func (c *naiveH2Conn) WriteTo(w io.Writer) (n int64, err error) {
2022-08-10 12:19:16 +00:00
if c.readPadding < kFirstPaddings {
2022-08-22 04:02:16 +00:00
n, err = bufio.WriteToN(c, w, kFirstPaddings-c.readPadding)
} else {
n, err = bufio.Copy(w, c.reader)
2022-08-10 12:19:16 +00:00
}
2022-08-22 04:02:16 +00:00
return n, wrapHttpError(err)
2022-09-07 04:28:41 +00:00
}
2022-08-10 12:19:16 +00:00
2022-08-23 05:22:03 +00:00
func (c *naiveH2Conn) ReadFrom(r io.Reader) (n int64, err error) {
2022-08-10 12:19:16 +00:00
if c.writePadding < kFirstPaddings {
2022-08-22 04:02:16 +00:00
n, err = bufio.ReadFromN(c, r, kFirstPaddings-c.writePadding)
} else {
n, err = bufio.Copy(c.writer, r)
2022-08-10 12:19:16 +00:00
}
2022-08-22 04:02:16 +00:00
return n, wrapHttpError(err)
2022-09-07 04:28:41 +00:00
}*/
2022-08-10 12:19:16 +00:00
2022-08-23 05:22:03 +00:00
func (c *naiveH2Conn) Close() error {
2022-08-10 12:19:16 +00:00
return common.Close(
c.reader,
c.writer,
)
}
2022-08-23 05:22:03 +00:00
func (c *naiveH2Conn) LocalAddr() net.Addr {
2022-08-10 12:19:16 +00:00
return nil
}
2022-08-23 05:22:03 +00:00
func (c *naiveH2Conn) RemoteAddr() net.Addr {
2022-08-10 12:19:16 +00:00
return c.rAddr
}
2022-08-23 05:22:03 +00:00
func (c *naiveH2Conn) SetDeadline(t time.Time) error {
2022-08-10 12:19:16 +00:00
return os.ErrInvalid
}
2022-08-23 05:22:03 +00:00
func (c *naiveH2Conn) SetReadDeadline(t time.Time) error {
2022-08-10 12:19:16 +00:00
return os.ErrInvalid
}
2022-08-23 05:22:03 +00:00
func (c *naiveH2Conn) SetWriteDeadline(t time.Time) error {
2022-08-10 12:19:16 +00:00
return os.ErrInvalid
}
2022-08-23 05:22:03 +00:00
func (c *naiveH2Conn) UpstreamReader() any {
return c.reader
}
func (c *naiveH2Conn) UpstreamWriter() any {
return c.writer
}
func (c *naiveH2Conn) ReaderReplaceable() bool {
2022-09-07 04:28:41 +00:00
return c.readPadding == kFirstPaddings
2022-08-23 05:22:03 +00:00
}
func (c *naiveH2Conn) WriterReplaceable() bool {
return c.writePadding == kFirstPaddings
}
2022-08-10 12:19:16 +00:00
func wrapHttpError(err error) error {
if err == nil {
return err
}
2022-08-22 04:02:16 +00:00
if strings.Contains(err.Error(), "client disconnected") {
return net.ErrClosed
}
if strings.Contains(err.Error(), "body closed by handler") {
2022-08-10 12:19:16 +00:00
return net.ErrClosed
}
2022-08-25 02:56:57 +00:00
if strings.Contains(err.Error(), "canceled with error code 268") {
return io.EOF
}
2022-08-10 12:19:16 +00:00
return err
}