mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-22 08:31:30 +00:00
Add user rule item
This commit is contained in:
parent
cf845d946e
commit
d1e83882e5
|
@ -21,6 +21,7 @@ type InboundContext struct {
|
|||
Destination M.Socksaddr
|
||||
Domain string
|
||||
Protocol string
|
||||
User string
|
||||
Outbound string
|
||||
|
||||
// cache
|
||||
|
|
|
@ -1,111 +1,14 @@
|
|||
package settings
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"github.com/sagernet/sing/common/wininet"
|
||||
)
|
||||
|
||||
var (
|
||||
modwininet = windows.NewLazySystemDLL("settings.dll")
|
||||
procInternetSetOptionW = modwininet.NewProc("InternetSetOptionW")
|
||||
)
|
||||
|
||||
const (
|
||||
internetOptionPerConnectionOption = 75
|
||||
internetOptionSettingsChanged = 39
|
||||
internetOptionRefresh = 37
|
||||
internetOptionProxySettingsChanged = 95
|
||||
)
|
||||
|
||||
const (
|
||||
internetPerConnFlags = 1
|
||||
internetPerConnProxyServer = 2
|
||||
internetPerConnProxyBypass = 3
|
||||
internetPerConnAutoconfigUrl = 4
|
||||
internetPerConnAutodiscoveryFlags = 5
|
||||
internetPerConnAutoconfigSecondaryUrl = 6
|
||||
internetPerConnAutoconfigReloadDelayMins = 7
|
||||
internetPerConnAutoconfigLastDetectTime = 8
|
||||
internetPerConnAutoconfigLastDetectUrl = 9
|
||||
internetPerConnFlagsUi = 10
|
||||
internetOptionProxyUsername = 43
|
||||
internetOptionProxyPassword = 44
|
||||
)
|
||||
|
||||
const (
|
||||
proxyTypeDirect = 1
|
||||
proxyTypeProxy = 2
|
||||
proxyTypeAutoProxyUrl = 4
|
||||
proxyTypeAutoDetect = 8
|
||||
)
|
||||
|
||||
type internetPerConnOptionList struct {
|
||||
dwSize uint32
|
||||
pszConnection uintptr
|
||||
dwOptionCount uint32
|
||||
dwOptionError uint32
|
||||
pOptions uintptr
|
||||
}
|
||||
|
||||
type internetPerConnOption struct {
|
||||
dwOption uint32
|
||||
value [8]byte
|
||||
}
|
||||
|
||||
func internetSetOption(option uintptr, lpBuffer uintptr, dwBufferSize uintptr) error {
|
||||
r0, _, err := syscall.SyscallN(procInternetSetOptionW.Addr(), 0, option, lpBuffer, dwBufferSize)
|
||||
if r0 != 1 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setOptions(options ...internetPerConnOption) error {
|
||||
var optionList internetPerConnOptionList
|
||||
optionList.dwSize = uint32(unsafe.Sizeof(optionList))
|
||||
optionList.dwOptionCount = uint32(len(options))
|
||||
optionList.dwOptionError = 0
|
||||
optionList.pOptions = uintptr(unsafe.Pointer(&options[0]))
|
||||
err := internetSetOption(internetOptionPerConnectionOption, uintptr(unsafe.Pointer(&optionList)), uintptr(optionList.dwSize))
|
||||
if err != nil {
|
||||
return os.NewSyscallError("InternetSetOption(Direct)", err)
|
||||
}
|
||||
err = internetSetOption(internetOptionSettingsChanged, 0, 0)
|
||||
if err != nil {
|
||||
return os.NewSyscallError("InternetSetOption(SettingsChanged)", err)
|
||||
}
|
||||
err = internetSetOption(internetOptionProxySettingsChanged, 0, 0)
|
||||
if err != nil {
|
||||
return os.NewSyscallError("InternetSetOption(ProxySettingsChanged)", err)
|
||||
}
|
||||
err = internetSetOption(internetOptionRefresh, 0, 0)
|
||||
if err != nil {
|
||||
return os.NewSyscallError("InternetSetOption(Refresh)", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ClearSystemProxy() error {
|
||||
var flagsOption internetPerConnOption
|
||||
flagsOption.dwOption = internetPerConnFlags
|
||||
*((*uint32)(unsafe.Pointer(&flagsOption.value))) = proxyTypeDirect | proxyTypeAutoDetect
|
||||
return setOptions(flagsOption)
|
||||
return wininet.ClearSystemProxy()
|
||||
}
|
||||
|
||||
func SetSystemProxy(port uint16, mixed bool) error {
|
||||
var flagsOption internetPerConnOption
|
||||
flagsOption.dwOption = internetPerConnFlags
|
||||
*((*uint32)(unsafe.Pointer(&flagsOption.value))) = proxyTypeProxy | proxyTypeDirect
|
||||
var proxyOption internetPerConnOption
|
||||
proxyOption.dwOption = internetPerConnProxyServer
|
||||
*((*uintptr)(unsafe.Pointer(&proxyOption.value))) = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(F.ToString("http://127.0.0.1:", port))))
|
||||
var bypassOption internetPerConnOption
|
||||
bypassOption.dwOption = internetPerConnProxyBypass
|
||||
*((*uintptr)(unsafe.Pointer(&bypassOption.value))) = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr("local")))
|
||||
return setOptions(flagsOption, proxyOption, bypassOption)
|
||||
return wininet.SetSystemProxy(F.ToString("http://127.0.0.1:", port), "local")
|
||||
}
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
"mixed-in"
|
||||
],
|
||||
"network": "tcp",
|
||||
"user": [
|
||||
"usera",
|
||||
"userb"
|
||||
],
|
||||
"protocol": [
|
||||
"tls",
|
||||
"http",
|
||||
|
@ -80,6 +84,14 @@ Tags of [inbound](../inbound).
|
|||
|
||||
`tcp` or `udp`.
|
||||
|
||||
#### user
|
||||
|
||||
Username, see each inbound for details.
|
||||
|
||||
#### protocol
|
||||
|
||||
Sniffed protocol, see [Sniff](/configuration/route/sniff/) for details.
|
||||
|
||||
#### domain
|
||||
|
||||
Match full domain.
|
||||
|
|
|
@ -47,9 +47,7 @@ Enable tcp fast open for listener.
|
|||
|
||||
Enable sniffing.
|
||||
|
||||
Reads domain names for routing, supports HTTP TLS for TCP, QUIC for UDP.
|
||||
|
||||
This does not break zero copy, like splice.
|
||||
See [Sniff](/configuration/route/sniff/) for details.
|
||||
|
||||
#### sniff_override_destination
|
||||
|
||||
|
|
|
@ -51,9 +51,7 @@ Enable tcp fast open for listener.
|
|||
|
||||
Enable sniffing.
|
||||
|
||||
Reads domain names for routing, supports HTTP TLS for TCP, QUIC for UDP.
|
||||
|
||||
This does not break zero copy, like splice.
|
||||
See [Sniff](/configuration/route/sniff/) for details.
|
||||
|
||||
#### sniff_override_destination
|
||||
|
||||
|
|
|
@ -51,9 +51,7 @@ Enable tcp fast open for listener.
|
|||
|
||||
Enable sniffing.
|
||||
|
||||
Reads domain names for routing, supports HTTP TLS for TCP, QUIC for UDP.
|
||||
|
||||
This does not break zero copy, like splice.
|
||||
See [Sniff](/configuration/route/sniff/) for details.
|
||||
|
||||
#### sniff_override_destination
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
{
|
||||
"type": "redirect",
|
||||
"tag": "redirect-in",
|
||||
|
||||
"listen": "::",
|
||||
"listen_port": 5353,
|
||||
"sniff": false,
|
||||
|
@ -36,9 +37,7 @@ Listen port.
|
|||
|
||||
Enable sniffing.
|
||||
|
||||
Reads domain names for routing, supports HTTP TLS for TCP, QUIC for UDP.
|
||||
|
||||
This does not break zero copy, like splice.
|
||||
See [Sniff](/configuration/route/sniff/) for details.
|
||||
|
||||
#### sniff_override_destination
|
||||
|
||||
|
|
|
@ -47,9 +47,7 @@ Enable tcp fast open for listener.
|
|||
|
||||
Enable sniffing.
|
||||
|
||||
Reads domain names for routing, supports HTTP TLS for TCP, QUIC for UDP.
|
||||
|
||||
This does not break zero copy, like splice.
|
||||
See [Sniff](/configuration/route/sniff/) for details.
|
||||
|
||||
#### sniff_override_destination
|
||||
|
||||
|
|
|
@ -49,9 +49,7 @@ Enable tcp fast open for listener.
|
|||
|
||||
Enable sniffing.
|
||||
|
||||
Reads domain names for routing, supports HTTP TLS for TCP, QUIC for UDP.
|
||||
|
||||
This does not break zero copy, like splice.
|
||||
See [Sniff](/configuration/route/sniff/) for details.
|
||||
|
||||
#### sniff_override_destination
|
||||
|
||||
|
|
|
@ -40,9 +40,7 @@ Listen port.
|
|||
|
||||
Enable sniffing.
|
||||
|
||||
Reads domain names for routing, supports HTTP TLS for TCP, QUIC for UDP.
|
||||
|
||||
This does not break zero copy, like splice.
|
||||
See [Sniff](/configuration/route/sniff/) for details.
|
||||
|
||||
#### sniff_override_destination
|
||||
|
||||
|
|
|
@ -59,9 +59,7 @@ Hijack TCP/UDP DNS requests to the built-in DNS adapter.
|
|||
|
||||
Enable sniffing.
|
||||
|
||||
Reads domain names for routing, supports HTTP TLS for TCP, QUIC for UDP.
|
||||
|
||||
This does not break zero copy, like splice.
|
||||
See [Sniff](/configuration/route/sniff/) for details.
|
||||
|
||||
#### sniff_override_destination
|
||||
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
"mixed-in"
|
||||
],
|
||||
"network": "tcp",
|
||||
"user": [
|
||||
"usera",
|
||||
"userb"
|
||||
],
|
||||
"protocol": [
|
||||
"tls",
|
||||
"http",
|
||||
|
@ -79,6 +83,14 @@
|
|||
|
||||
Tags of [inbound](../inbound).
|
||||
|
||||
#### user
|
||||
|
||||
Username, see each inbound for details.
|
||||
|
||||
#### protocol
|
||||
|
||||
Sniffed protocol, see [Sniff](/configuration/route/sniff/) for details.
|
||||
|
||||
#### network
|
||||
|
||||
`tcp` or `udp`.
|
||||
|
|
10
docs/configuration/route/sniff.md
Normal file
10
docs/configuration/route/sniff.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
If enabled in the inbound, the protocol and domain name (if present) of by the connection can be sniffed.
|
||||
|
||||
#### Supported Protocols
|
||||
|
||||
| Network | Protocol | Domain Name |
|
||||
|:---------:|:----------:|:-------------:|
|
||||
| TCP | HTTP | Host |
|
||||
| TCP | TLS | Server Name |
|
||||
| UDP | QUIC | Server Name |
|
||||
| UDP | STUN | / |
|
4
go.mod
4
go.mod
|
@ -7,9 +7,9 @@ require (
|
|||
github.com/goccy/go-json v0.9.10
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
github.com/oschwald/maxminddb-golang v1.9.0
|
||||
github.com/sagernet/sing v0.0.0-20220716021830-bd79d31e3b10
|
||||
github.com/sagernet/sing v0.0.0-20220717063925-00f98eb6bc34
|
||||
github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619
|
||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220716012931-952ae62e05d7
|
||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220717063942-45a2ad9cd41f
|
||||
github.com/sagernet/sing-tun v0.0.0-20220717030718-f53aabff275f
|
||||
github.com/spf13/cobra v1.5.0
|
||||
github.com/stretchr/testify v1.8.0
|
||||
|
|
8
go.sum
8
go.sum
|
@ -25,12 +25,12 @@ github.com/oschwald/maxminddb-golang v1.9.0/go.mod h1:TK+s/Z2oZq0rSl4PSeAEoP0bgm
|
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagernet/sing v0.0.0-20220716021830-bd79d31e3b10 h1:CQSsVgvVT6KcYNQASP4jnPTg7epSxHGI3MS011LIXkA=
|
||||
github.com/sagernet/sing v0.0.0-20220716021830-bd79d31e3b10/go.mod h1:3ZmoGNg/nNJTyHAZFNRSPaXpNIwpDvyIiAUd0KIWV5c=
|
||||
github.com/sagernet/sing v0.0.0-20220717063925-00f98eb6bc34 h1:1kFruA2QzuH2R6txJXEDSasfdxzsjNyzC4Z1kZjMkHg=
|
||||
github.com/sagernet/sing v0.0.0-20220717063925-00f98eb6bc34/go.mod h1:GbtQfZSpmtD3cXeD1qX2LCMwY8dH+bnnInDTqd92IsM=
|
||||
github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619 h1:oHbOmq1WS0XaZmXp6WpxzyB2xeyRIA1/L8EJKuNntfY=
|
||||
github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619/go.mod h1:y2fpvoxukw3G7eApIZwkcpcG/NE4AB8pCQI0Qd8rMqk=
|
||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220716012931-952ae62e05d7 h1:7xQvlMSxNWphQ4t+7fHfR4OnkH23GukLIjImnM1CMLA=
|
||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220716012931-952ae62e05d7/go.mod h1:NtHwPOk1wEOPdjjsjtrYoaQuXtlDCrx0mrcWBrNE0sA=
|
||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220717063942-45a2ad9cd41f h1:F6yiuKbBoXgWiuoP7R0YA14pDEl3emxA1mL7M16Q7gc=
|
||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220717063942-45a2ad9cd41f/go.mod h1:cDrLwa3zwY8AaW6a4sjipn4xgdIr3CT8TPqSW6iFOi0=
|
||||
github.com/sagernet/sing-tun v0.0.0-20220717030718-f53aabff275f h1:o3YN4sFC7lQznAwutagPqBb23hal7MkgVq/VEvd7Vug=
|
||||
github.com/sagernet/sing-tun v0.0.0-20220717030718-f53aabff275f/go.mod h1:p7QbUBs2ejf6UQsiHyy1xGAWOk9JWQjZTHy8pOmkWmo=
|
||||
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common/auth"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/protocol/http"
|
||||
)
|
||||
|
||||
|
@ -40,5 +41,25 @@ func NewHTTP(ctx context.Context, router adapter.Router, logger log.ContextLogge
|
|||
}
|
||||
|
||||
func (h *HTTP) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||
return http.HandleConnection(ctx, conn, std_bufio.NewReader(conn), h.authenticator, h.upstreamHandler(metadata), M.Metadata{})
|
||||
return http.HandleConnection(ctx, conn, std_bufio.NewReader(conn), h.authenticator, h.upstreamUserHandler(metadata), M.Metadata{})
|
||||
}
|
||||
|
||||
func (a *myInboundAdapter) upstreamUserHandler(metadata adapter.InboundContext) adapter.UpstreamHandlerAdapter {
|
||||
return adapter.NewUpstreamHandler(metadata, a.newUserConnection, a.streamUserPacketConnection, a)
|
||||
}
|
||||
|
||||
func (a *myInboundAdapter) newUserConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||
user, loaded := auth.UserFromContext[string](ctx)
|
||||
if !loaded {
|
||||
a.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination)
|
||||
return a.router.RouteConnection(ctx, conn, metadata)
|
||||
}
|
||||
metadata.User = user
|
||||
a.logger.InfoContext(ctx, "[", user, "] inbound connection to ", metadata.Destination)
|
||||
return a.router.RouteConnection(ctx, conn, metadata)
|
||||
}
|
||||
|
||||
func (a *myInboundAdapter) streamUserPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||
a.logger.InfoContext(ctx, "inbound packet connection to ", metadata.Destination)
|
||||
return a.router.RoutePacketConnection(ctx, conn, metadata)
|
||||
}
|
||||
|
|
|
@ -52,8 +52,8 @@ func (h *Mixed) NewConnection(ctx context.Context, conn net.Conn, metadata adapt
|
|||
}
|
||||
switch headerType {
|
||||
case socks4.Version, socks5.Version:
|
||||
return socks.HandleConnection0(ctx, conn, headerType, h.authenticator, h.upstreamHandler(metadata), M.Metadata{})
|
||||
return socks.HandleConnection0(ctx, conn, headerType, h.authenticator, h.upstreamUserHandler(metadata), M.Metadata{})
|
||||
}
|
||||
reader := std_bufio.NewReader(bufio.NewCachedReader(conn, buf.As([]byte{headerType})))
|
||||
return http.HandleConnection(ctx, conn, reader, h.authenticator, h.upstreamHandler(metadata), M.Metadata{})
|
||||
return http.HandleConnection(ctx, conn, reader, h.authenticator, h.upstreamUserHandler(metadata), M.Metadata{})
|
||||
}
|
||||
|
|
|
@ -77,5 +77,17 @@ func (h *Shadowsocks) NewConnection(ctx context.Context, conn net.Conn, metadata
|
|||
}
|
||||
|
||||
func (h *Shadowsocks) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext) error {
|
||||
return h.service.NewPacket(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, buffer, adapter.UpstreamMetadata(metadata))
|
||||
return h.service.NewPacket(adapter.WithContext(ctx, &metadata), conn, buffer, adapter.UpstreamMetadata(metadata))
|
||||
}
|
||||
|
||||
func (h *Shadowsocks) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||
h.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination)
|
||||
return h.router.RouteConnection(ctx, conn, metadata)
|
||||
}
|
||||
|
||||
func (h *Shadowsocks) newPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||
ctx = log.ContextWithNewID(ctx)
|
||||
h.logger.InfoContext(ctx, "inbound packet connection from ", metadata.Source)
|
||||
h.logger.InfoContext(ctx, "inbound packet connection to ", metadata.Destination)
|
||||
return h.router.RoutePacketConnection(ctx, conn, metadata)
|
||||
}
|
||||
|
|
|
@ -3,14 +3,15 @@ package inbound
|
|||
import (
|
||||
"context"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-shadowsocks"
|
||||
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/auth"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
|
@ -72,24 +73,34 @@ func (h *ShadowsocksMulti) NewConnection(ctx context.Context, conn net.Conn, met
|
|||
}
|
||||
|
||||
func (h *ShadowsocksMulti) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext) error {
|
||||
return h.service.NewPacket(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, buffer, adapter.UpstreamMetadata(metadata))
|
||||
return h.service.NewPacket(adapter.WithContext(ctx, &metadata), conn, buffer, adapter.UpstreamMetadata(metadata))
|
||||
}
|
||||
|
||||
func (h *ShadowsocksMulti) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||
userCtx := ctx.(*shadowsocks.UserContext[int])
|
||||
user := h.users[userCtx.User].Name
|
||||
userIndex, loaded := auth.UserFromContext[int](ctx)
|
||||
if !loaded {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
user := h.users[userIndex].Name
|
||||
if user == "" {
|
||||
user = F.ToString(userCtx.User)
|
||||
user = F.ToString(userIndex)
|
||||
} else {
|
||||
metadata.User = user
|
||||
}
|
||||
h.logger.InfoContext(ctx, "[", user, "] inbound connection to ", metadata.Destination)
|
||||
return h.router.RouteConnection(ctx, conn, metadata)
|
||||
}
|
||||
|
||||
func (h *ShadowsocksMulti) newPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||
userCtx := ctx.(*shadowsocks.UserContext[int])
|
||||
user := h.users[userCtx.User].Name
|
||||
userIndex, loaded := auth.UserFromContext[int](ctx)
|
||||
if !loaded {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
user := h.users[userIndex].Name
|
||||
if user == "" {
|
||||
user = F.ToString(userCtx.User)
|
||||
user = F.ToString(userIndex)
|
||||
} else {
|
||||
metadata.User = user
|
||||
}
|
||||
ctx = log.ContextWithNewID(ctx)
|
||||
h.logger.InfoContext(ctx, "[", user, "] inbound packet connection from ", metadata.Source)
|
||||
|
|
|
@ -3,14 +3,15 @@ package inbound
|
|||
import (
|
||||
"context"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-shadowsocks"
|
||||
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/auth"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
|
@ -72,24 +73,34 @@ func (h *ShadowsocksRelay) NewConnection(ctx context.Context, conn net.Conn, met
|
|||
}
|
||||
|
||||
func (h *ShadowsocksRelay) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext) error {
|
||||
return h.service.NewPacket(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, buffer, adapter.UpstreamMetadata(metadata))
|
||||
return h.service.NewPacket(adapter.WithContext(ctx, &metadata), conn, buffer, adapter.UpstreamMetadata(metadata))
|
||||
}
|
||||
|
||||
func (h *ShadowsocksRelay) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||
userCtx := ctx.(*shadowsocks.UserContext[int])
|
||||
destination := h.destinations[userCtx.User].Name
|
||||
destinationIndex, loaded := auth.UserFromContext[int](ctx)
|
||||
if !loaded {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
destination := h.destinations[destinationIndex].Name
|
||||
if destination == "" {
|
||||
destination = F.ToString(userCtx.User)
|
||||
destination = F.ToString(destinationIndex)
|
||||
} else {
|
||||
metadata.User = destination
|
||||
}
|
||||
h.logger.InfoContext(ctx, "[", destination, "] inbound connection to ", metadata.Destination)
|
||||
return h.router.RouteConnection(ctx, conn, metadata)
|
||||
}
|
||||
|
||||
func (h *ShadowsocksRelay) newPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||
userCtx := ctx.(*shadowsocks.UserContext[int])
|
||||
destination := h.destinations[userCtx.User].Name
|
||||
destinationIndex, loaded := auth.UserFromContext[int](ctx)
|
||||
if !loaded {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
destination := h.destinations[destinationIndex].Name
|
||||
if destination == "" {
|
||||
destination = F.ToString(userCtx.User)
|
||||
destination = F.ToString(destinationIndex)
|
||||
} else {
|
||||
metadata.User = destination
|
||||
}
|
||||
ctx = log.ContextWithNewID(ctx)
|
||||
h.logger.InfoContext(ctx, "[", destination, "] inbound packet connection from ", metadata.Source)
|
||||
|
|
|
@ -38,5 +38,5 @@ func NewSocks(ctx context.Context, router adapter.Router, logger log.ContextLogg
|
|||
}
|
||||
|
||||
func (h *Socks) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||
return socks.HandleConnection(ctx, conn, h.authenticator, h.upstreamHandler(metadata), M.Metadata{})
|
||||
return socks.HandleConnection(ctx, conn, h.authenticator, h.upstreamUserHandler(metadata), M.Metadata{})
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ nav:
|
|||
- GeoIP: configuration/route/geoip.md
|
||||
- Geosite: configuration/route/geosite.md
|
||||
- Route Rule: configuration/route/rule.md
|
||||
- Protocol Sniff: configuration/route/sniff.md
|
||||
- Examples:
|
||||
- examples/index.md
|
||||
- Shadowsocks Server: examples/ss-server.md
|
||||
|
|
|
@ -91,6 +91,7 @@ func (r *DNSRule) UnmarshalJSON(bytes []byte) error {
|
|||
type DefaultDNSRule struct {
|
||||
Inbound Listable[string] `json:"inbound,omitempty"`
|
||||
Network string `json:"network,omitempty"`
|
||||
User Listable[string] `json:"user,omitempty"`
|
||||
Protocol Listable[string] `json:"protocol,omitempty"`
|
||||
Domain Listable[string] `json:"domain,omitempty"`
|
||||
DomainSuffix Listable[string] `json:"domain_suffix,omitempty"`
|
||||
|
@ -114,6 +115,7 @@ func (r DefaultDNSRule) IsValid() bool {
|
|||
func (r DefaultDNSRule) Equals(other DefaultDNSRule) bool {
|
||||
return common.ComparableSliceEquals(r.Inbound, other.Inbound) &&
|
||||
r.Network == other.Network &&
|
||||
common.ComparableSliceEquals(r.User, other.User) &&
|
||||
common.ComparableSliceEquals(r.Protocol, other.Protocol) &&
|
||||
common.ComparableSliceEquals(r.Domain, other.Domain) &&
|
||||
common.ComparableSliceEquals(r.DomainSuffix, other.DomainSuffix) &&
|
||||
|
|
|
@ -89,6 +89,7 @@ type DefaultRule struct {
|
|||
Inbound Listable[string] `json:"inbound,omitempty"`
|
||||
IPVersion int `json:"ip_version,omitempty"`
|
||||
Network string `json:"network,omitempty"`
|
||||
User Listable[string] `json:"user,omitempty"`
|
||||
Protocol Listable[string] `json:"protocol,omitempty"`
|
||||
Domain Listable[string] `json:"domain,omitempty"`
|
||||
DomainSuffix Listable[string] `json:"domain_suffix,omitempty"`
|
||||
|
@ -114,6 +115,7 @@ func (r DefaultRule) Equals(other DefaultRule) bool {
|
|||
return common.ComparableSliceEquals(r.Inbound, other.Inbound) &&
|
||||
r.IPVersion == other.IPVersion &&
|
||||
r.Network == other.Network &&
|
||||
common.ComparableSliceEquals(r.User, other.User) &&
|
||||
common.ComparableSliceEquals(r.Protocol, other.Protocol) &&
|
||||
common.ComparableSliceEquals(r.Domain, other.Domain) &&
|
||||
common.ComparableSliceEquals(r.DomainSuffix, other.DomainSuffix) &&
|
||||
|
|
|
@ -82,8 +82,13 @@ func NewDefaultRule(router adapter.Router, logger log.ContextLogger, options opt
|
|||
return nil, E.New("invalid network: ", options.Network)
|
||||
}
|
||||
}
|
||||
if len(options.User) > 0 {
|
||||
item := NewUserItem(options.User)
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.Protocol) > 0 {
|
||||
item := NewProtocolItem(options.Protocol)
|
||||
item := NewUserItem(options.Protocol)
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
|
|
@ -66,8 +66,13 @@ func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options
|
|||
return nil, E.New("invalid network: ", options.Network)
|
||||
}
|
||||
}
|
||||
if len(options.User) > 0 {
|
||||
item := NewUserItem(options.User)
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.Protocol) > 0 {
|
||||
item := NewProtocolItem(options.Protocol)
|
||||
item := NewUserItem(options.Protocol)
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
|
37
route/rule_user.go
Normal file
37
route/rule_user.go
Normal file
|
@ -0,0 +1,37 @@
|
|||
package route
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
)
|
||||
|
||||
var _ RuleItem = (*UserItem)(nil)
|
||||
|
||||
type UserItem struct {
|
||||
users []string
|
||||
userMap map[string]bool
|
||||
}
|
||||
|
||||
func NewUserItem(users []string) *UserItem {
|
||||
userMap := make(map[string]bool)
|
||||
for _, protocol := range users {
|
||||
userMap[protocol] = true
|
||||
}
|
||||
return &UserItem{
|
||||
users: users,
|
||||
userMap: userMap,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *UserItem) Match(metadata *adapter.InboundContext) bool {
|
||||
return r.userMap[metadata.User]
|
||||
}
|
||||
|
||||
func (r *UserItem) String() string {
|
||||
if len(r.users) == 1 {
|
||||
return F.ToString("user=", r.users[0])
|
||||
}
|
||||
return F.ToString("user=[", strings.Join(r.users, " "), "]")
|
||||
}
|
|
@ -46,15 +46,15 @@ func startInstance(t *testing.T, options option.Options) {
|
|||
|
||||
func testSuit(t *testing.T, clientPort uint16, testPort uint16) {
|
||||
dialer := socks.NewClient(N.SystemDialer, M.ParseSocksaddrHostPort("127.0.0.1", clientPort), socks.Version5, "", "")
|
||||
dialTCP := func() (net.Conn, error) {
|
||||
return dialer.DialContext(context.Background(), "tcp", M.ParseSocksaddrHostPort("127.0.0.1", testPort))
|
||||
dialTCP := func(port uint16) (net.Conn, error) {
|
||||
return dialer.DialContext(context.Background(), "tcp", M.ParseSocksaddrHostPort("127.0.0.1", port))
|
||||
}
|
||||
dialUDP := func() (net.PacketConn, error) {
|
||||
return dialer.ListenPacket(context.Background(), M.ParseSocksaddrHostPort("127.0.0.1", testPort))
|
||||
dialUDP := func(port uint16) (net.PacketConn, error) {
|
||||
return dialer.ListenPacket(context.Background(), M.ParseSocksaddrHostPort("127.0.0.1", port))
|
||||
}
|
||||
require.NoError(t, testPingPongWithConn(t, testPort, dialTCP))
|
||||
require.NoError(t, testLargeDataWithConn(t, testPort, dialTCP))
|
||||
require.NoError(t, testPingPongWithPacketConn(t, testPort, dialUDP))
|
||||
require.NoError(t, testLargeDataWithPacketConn(t, testPort, dialUDP))
|
||||
require.NoError(t, testPingPongWithConn(t, dialTCP))
|
||||
require.NoError(t, testLargeDataWithConn(t, dialTCP))
|
||||
require.NoError(t, testPingPongWithPacketConn(t, dialUDP))
|
||||
require.NoError(t, testLargeDataWithPacketConn(t, dialUDP))
|
||||
require.NoError(t, testPacketConnTimeout(t, dialUDP))
|
||||
}
|
||||
|
|
|
@ -152,14 +152,15 @@ func newLargeDataPair() (chan hashPair, chan hashPair, func(t *testing.T) error)
|
|||
return pingCh, pongCh, test
|
||||
}
|
||||
|
||||
func testPingPongWithConn(t *testing.T, port uint16, cc func() (net.Conn, error)) error {
|
||||
func testPingPongWithConn(t *testing.T, cc func(port uint16) (net.Conn, error)) error {
|
||||
port := mkPort(t)
|
||||
l, err := listen("tcp", ":"+F.ToString(port))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
c, err := cc()
|
||||
c, err := cc(port)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -198,7 +199,9 @@ func testPingPongWithConn(t *testing.T, port uint16, cc func() (net.Conn, error)
|
|||
return test(t)
|
||||
}
|
||||
|
||||
func testPingPongWithPacketConn(t *testing.T, port uint16, pcc func() (net.PacketConn, error)) error {
|
||||
func testPingPongWithPacketConn(t *testing.T, pcc func(port uint16) (net.PacketConn, error)) error {
|
||||
port := mkPort(t)
|
||||
|
||||
l, err := listenPacket("udp", ":"+F.ToString(port))
|
||||
require.NoError(t, err)
|
||||
defer l.Close()
|
||||
|
@ -219,7 +222,7 @@ func testPingPongWithPacketConn(t *testing.T, port uint16, pcc func() (net.Packe
|
|||
}
|
||||
}()
|
||||
|
||||
pc, err := pcc()
|
||||
pc, err := pcc(port)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -246,7 +249,8 @@ type hashPair struct {
|
|||
recvHash map[int][]byte
|
||||
}
|
||||
|
||||
func testLargeDataWithConn(t *testing.T, port uint16, cc func() (net.Conn, error)) error {
|
||||
func testLargeDataWithConn(t *testing.T, cc func(port uint16) (net.Conn, error)) error {
|
||||
port := mkPort(t)
|
||||
l, err := listen("tcp", ":"+F.ToString(port))
|
||||
require.NoError(t, err)
|
||||
defer l.Close()
|
||||
|
@ -275,7 +279,7 @@ func testLargeDataWithConn(t *testing.T, port uint16, cc func() (net.Conn, error
|
|||
return hashMap, nil
|
||||
}
|
||||
|
||||
c, err := cc()
|
||||
c, err := cc(port)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -343,7 +347,8 @@ func testLargeDataWithConn(t *testing.T, port uint16, cc func() (net.Conn, error
|
|||
return test(t)
|
||||
}
|
||||
|
||||
func testLargeDataWithPacketConn(t *testing.T, port uint16, pcc func() (net.PacketConn, error)) error {
|
||||
func testLargeDataWithPacketConn(t *testing.T, pcc func(port uint16) (net.PacketConn, error)) error {
|
||||
port := mkPort(t)
|
||||
l, err := listenPacket("udp", ":"+F.ToString(port))
|
||||
require.NoError(t, err)
|
||||
defer l.Close()
|
||||
|
@ -409,7 +414,7 @@ func testLargeDataWithPacketConn(t *testing.T, port uint16, pcc func() (net.Pack
|
|||
}
|
||||
}()
|
||||
|
||||
pc, err := pcc()
|
||||
pc, err := pcc(port)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -444,8 +449,8 @@ func testLargeDataWithPacketConn(t *testing.T, port uint16, pcc func() (net.Pack
|
|||
return test(t)
|
||||
}
|
||||
|
||||
func testPacketConnTimeout(t *testing.T, pcc func() (net.PacketConn, error)) error {
|
||||
pc, err := pcc()
|
||||
func testPacketConnTimeout(t *testing.T, pcc func(port uint16) (net.PacketConn, error)) error {
|
||||
pc, err := pcc(mkPort(t))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ go 1.18
|
|||
require (
|
||||
github.com/docker/docker v20.10.17+incompatible
|
||||
github.com/docker/go-connections v0.4.0
|
||||
github.com/sagernet/sing v0.0.0-20220716021830-bd79d31e3b10
|
||||
github.com/sagernet/sing v0.0.0-20220717063925-00f98eb6bc34
|
||||
github.com/sagernet/sing-box v0.0.0
|
||||
github.com/stretchr/testify v1.8.0
|
||||
golang.org/x/net v0.0.0-20220708220712-1185a9018129
|
||||
|
@ -33,7 +33,7 @@ require (
|
|||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619 // indirect
|
||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220716012931-952ae62e05d7 // indirect
|
||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220717063942-45a2ad9cd41f // indirect
|
||||
github.com/sagernet/sing-tun v0.0.0-20220717030718-f53aabff275f // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/vishvananda/netlink v1.1.0 // indirect
|
||||
|
|
|
@ -52,12 +52,12 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sagernet/sing v0.0.0-20220716021830-bd79d31e3b10 h1:CQSsVgvVT6KcYNQASP4jnPTg7epSxHGI3MS011LIXkA=
|
||||
github.com/sagernet/sing v0.0.0-20220716021830-bd79d31e3b10/go.mod h1:3ZmoGNg/nNJTyHAZFNRSPaXpNIwpDvyIiAUd0KIWV5c=
|
||||
github.com/sagernet/sing v0.0.0-20220717063925-00f98eb6bc34 h1:1kFruA2QzuH2R6txJXEDSasfdxzsjNyzC4Z1kZjMkHg=
|
||||
github.com/sagernet/sing v0.0.0-20220717063925-00f98eb6bc34/go.mod h1:GbtQfZSpmtD3cXeD1qX2LCMwY8dH+bnnInDTqd92IsM=
|
||||
github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619 h1:oHbOmq1WS0XaZmXp6WpxzyB2xeyRIA1/L8EJKuNntfY=
|
||||
github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619/go.mod h1:y2fpvoxukw3G7eApIZwkcpcG/NE4AB8pCQI0Qd8rMqk=
|
||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220716012931-952ae62e05d7 h1:7xQvlMSxNWphQ4t+7fHfR4OnkH23GukLIjImnM1CMLA=
|
||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220716012931-952ae62e05d7/go.mod h1:NtHwPOk1wEOPdjjsjtrYoaQuXtlDCrx0mrcWBrNE0sA=
|
||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220717063942-45a2ad9cd41f h1:F6yiuKbBoXgWiuoP7R0YA14pDEl3emxA1mL7M16Q7gc=
|
||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220717063942-45a2ad9cd41f/go.mod h1:cDrLwa3zwY8AaW6a4sjipn4xgdIr3CT8TPqSW6iFOi0=
|
||||
github.com/sagernet/sing-tun v0.0.0-20220717030718-f53aabff275f h1:o3YN4sFC7lQznAwutagPqBb23hal7MkgVq/VEvd7Vug=
|
||||
github.com/sagernet/sing-tun v0.0.0-20220717030718-f53aabff275f/go.mod h1:p7QbUBs2ejf6UQsiHyy1xGAWOk9JWQjZTHy8pOmkWmo=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
|
|
Loading…
Reference in a new issue