mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-22 08:31:30 +00:00
Add set_system_proxy option for windows
This commit is contained in:
parent
e7d557fd9e
commit
238afda9da
13
common/wininet/wininet_stub.go
Normal file
13
common/wininet/wininet_stub.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
//go:build !windows
|
||||
|
||||
package wininet
|
||||
|
||||
import "os"
|
||||
|
||||
func ClearSystemProxy() error {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
|
||||
func SetSystemProxy(proxy string, bypass string) error {
|
||||
return os.ErrInvalid
|
||||
}
|
109
common/wininet/wininet_windows.go
Normal file
109
common/wininet/wininet_windows.go
Normal file
|
@ -0,0 +1,109 @@
|
|||
package wininet
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
modwininet = windows.NewLazySystemDLL("wininet.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)
|
||||
}
|
||||
|
||||
func SetSystemProxy(proxy string, bypass string) 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(proxy)))
|
||||
var bypassOption internetPerConnOption
|
||||
bypassOption.dwOption = internetPerConnProxyBypass
|
||||
*((*uintptr)(unsafe.Pointer(&bypassOption.value))) = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(bypass)))
|
||||
return setOptions(flagsOption, proxyOption, bypassOption)
|
||||
}
|
|
@ -9,6 +9,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/wininet"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
|
@ -16,6 +17,7 @@ import (
|
|||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
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"
|
||||
|
||||
|
@ -36,6 +38,10 @@ type myInboundAdapter struct {
|
|||
packetHandler adapter.PacketHandler
|
||||
packetUpstream any
|
||||
|
||||
// http mixed
|
||||
|
||||
setSystemProxy bool
|
||||
|
||||
// internal
|
||||
|
||||
tcpListener *net.TCPListener
|
||||
|
@ -88,14 +94,24 @@ func (a *myInboundAdapter) Start() error {
|
|||
go a.loopUDPOut()
|
||||
a.logger.Info("udp server started at ", udpConn.LocalAddr())
|
||||
}
|
||||
if a.setSystemProxy {
|
||||
err := wininet.SetSystemProxy(F.ToString("http://127.0.0.1:", M.SocksaddrFromNet(a.tcpListener.Addr()).Port), "local")
|
||||
if err != nil {
|
||||
return E.Cause(err, "set system proxy")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *myInboundAdapter) Close() error {
|
||||
return common.Close(
|
||||
var err error
|
||||
if a.setSystemProxy {
|
||||
err = wininet.ClearSystemProxy()
|
||||
}
|
||||
return E.Errors(err, common.Close(
|
||||
common.PtrOrNil(a.tcpListener),
|
||||
common.PtrOrNil(a.udpConn),
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
func (a *myInboundAdapter) upstreamHandler(metadata adapter.InboundContext) adapter.UpstreamHandlerAdapter {
|
||||
|
|
|
@ -21,16 +21,17 @@ type HTTP struct {
|
|||
authenticator auth.Authenticator
|
||||
}
|
||||
|
||||
func NewHTTP(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SimpleInboundOptions) *HTTP {
|
||||
func NewHTTP(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HTTPMixedInboundOptions) *HTTP {
|
||||
inbound := &HTTP{
|
||||
myInboundAdapter{
|
||||
protocol: C.TypeHTTP,
|
||||
network: []string{C.NetworkTCP},
|
||||
ctx: ctx,
|
||||
router: router,
|
||||
logger: logger,
|
||||
tag: tag,
|
||||
listenOptions: options.ListenOptions,
|
||||
protocol: C.TypeHTTP,
|
||||
network: []string{C.NetworkTCP},
|
||||
ctx: ctx,
|
||||
router: router,
|
||||
logger: logger,
|
||||
tag: tag,
|
||||
listenOptions: options.ListenOptions,
|
||||
setSystemProxy: options.SetSystemProxy,
|
||||
},
|
||||
auth.NewAuthenticator(options.Users),
|
||||
}
|
||||
|
|
|
@ -27,16 +27,17 @@ type Mixed struct {
|
|||
authenticator auth.Authenticator
|
||||
}
|
||||
|
||||
func NewMixed(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SimpleInboundOptions) *Mixed {
|
||||
func NewMixed(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HTTPMixedInboundOptions) *Mixed {
|
||||
inbound := &Mixed{
|
||||
myInboundAdapter{
|
||||
protocol: C.TypeMixed,
|
||||
network: []string{C.NetworkTCP},
|
||||
ctx: ctx,
|
||||
router: router,
|
||||
logger: logger,
|
||||
tag: tag,
|
||||
listenOptions: options.ListenOptions,
|
||||
protocol: C.TypeMixed,
|
||||
network: []string{C.NetworkTCP},
|
||||
ctx: ctx,
|
||||
router: router,
|
||||
logger: logger,
|
||||
tag: tag,
|
||||
listenOptions: options.ListenOptions,
|
||||
setSystemProxy: options.SetSystemProxy,
|
||||
},
|
||||
auth.NewAuthenticator(options.Users),
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ type Socks struct {
|
|||
authenticator auth.Authenticator
|
||||
}
|
||||
|
||||
func NewSocks(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SimpleInboundOptions) *Socks {
|
||||
func NewSocks(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SocksInboundOptions) *Socks {
|
||||
inbound := &Socks{
|
||||
myInboundAdapter{
|
||||
protocol: C.TypeSocks,
|
||||
|
|
|
@ -42,26 +42,30 @@ func (f Formatter) Format(ctx context.Context, level Level, tag string, message
|
|||
id, hasId = IDFromContext(ctx)
|
||||
}
|
||||
if hasId {
|
||||
var color aurora.Color
|
||||
color = aurora.Color(uint8(id))
|
||||
color %= 215
|
||||
row := uint(color / 36)
|
||||
column := uint(color % 36)
|
||||
if !f.DisableColors {
|
||||
var color aurora.Color
|
||||
color = aurora.Color(uint8(id))
|
||||
color %= 215
|
||||
row := uint(color / 36)
|
||||
column := uint(color % 36)
|
||||
|
||||
var r, g, b float32
|
||||
r = float32(row * 51)
|
||||
g = float32(column / 6 * 51)
|
||||
b = float32((column % 6) * 51)
|
||||
luma := 0.2126*r + 0.7152*g + 0.0722*b
|
||||
if luma < 60 {
|
||||
row = 5 - row
|
||||
column = 35 - column
|
||||
color = aurora.Color(row*36 + column)
|
||||
var r, g, b float32
|
||||
r = float32(row * 51)
|
||||
g = float32(column / 6 * 51)
|
||||
b = float32((column % 6) * 51)
|
||||
luma := 0.2126*r + 0.7152*g + 0.0722*b
|
||||
if luma < 60 {
|
||||
row = 5 - row
|
||||
column = 35 - column
|
||||
color = aurora.Color(row*36 + column)
|
||||
}
|
||||
color += 16
|
||||
color = color << 16
|
||||
color |= 1 << 14
|
||||
message = F.ToString("[", aurora.Colorize(id, color).String(), "] ", message)
|
||||
} else {
|
||||
message = F.ToString("[", id, "] ", message)
|
||||
}
|
||||
color += 16
|
||||
color = color << 16
|
||||
color |= 1 << 14
|
||||
message = F.ToString("[", aurora.Colorize(id, color).String(), "] ", message)
|
||||
}
|
||||
switch {
|
||||
case f.DisableTimestamp:
|
||||
|
|
|
@ -13,9 +13,9 @@ type _Inbound struct {
|
|||
Type string `json:"type"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
DirectOptions DirectInboundOptions `json:"-"`
|
||||
SocksOptions SimpleInboundOptions `json:"-"`
|
||||
HTTPOptions SimpleInboundOptions `json:"-"`
|
||||
MixedOptions SimpleInboundOptions `json:"-"`
|
||||
SocksOptions SocksInboundOptions `json:"-"`
|
||||
HTTPOptions HTTPMixedInboundOptions `json:"-"`
|
||||
MixedOptions HTTPMixedInboundOptions `json:"-"`
|
||||
ShadowsocksOptions ShadowsocksInboundOptions `json:"-"`
|
||||
TunOptions TunInboundOptions `json:"-"`
|
||||
}
|
||||
|
@ -97,16 +97,28 @@ type ListenOptions struct {
|
|||
InboundOptions
|
||||
}
|
||||
|
||||
type SimpleInboundOptions struct {
|
||||
type SocksInboundOptions struct {
|
||||
ListenOptions
|
||||
Users []auth.User `json:"users,omitempty"`
|
||||
}
|
||||
|
||||
func (o SimpleInboundOptions) Equals(other SimpleInboundOptions) bool {
|
||||
func (o SocksInboundOptions) Equals(other SocksInboundOptions) bool {
|
||||
return o.ListenOptions == other.ListenOptions &&
|
||||
common.ComparableSliceEquals(o.Users, other.Users)
|
||||
}
|
||||
|
||||
type HTTPMixedInboundOptions struct {
|
||||
ListenOptions
|
||||
Users []auth.User `json:"users,omitempty"`
|
||||
SetSystemProxy bool `json:"set_system_proxy,omitempty"`
|
||||
}
|
||||
|
||||
func (o HTTPMixedInboundOptions) Equals(other HTTPMixedInboundOptions) bool {
|
||||
return o.ListenOptions == other.ListenOptions &&
|
||||
common.ComparableSliceEquals(o.Users, other.Users) &&
|
||||
o.SetSystemProxy == other.SetSystemProxy
|
||||
}
|
||||
|
||||
type DirectInboundOptions struct {
|
||||
ListenOptions
|
||||
Network NetworkList `json:"network,omitempty"`
|
||||
|
|
|
@ -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-20220712060558-029ab1ce4f91
|
||||
github.com/sagernet/sing v0.0.0-20220714062657-6685f65aac21
|
||||
github.com/sagernet/sing-box v0.0.0
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/stretchr/testify v1.8.0
|
||||
|
|
|
@ -52,8 +52,8 @@ 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-20220712060558-029ab1ce4f91 h1:fYsRChEViZHDvrOLp7fbswYCH3txaVyAl1zB0cnSNlc=
|
||||
github.com/sagernet/sing v0.0.0-20220712060558-029ab1ce4f91/go.mod h1:3ZmoGNg/nNJTyHAZFNRSPaXpNIwpDvyIiAUd0KIWV5c=
|
||||
github.com/sagernet/sing v0.0.0-20220714062657-6685f65aac21 h1:PaX9VR0gVUagiRHwp9imiVZ9VW169WoEyToJg3UCKBI=
|
||||
github.com/sagernet/sing v0.0.0-20220714062657-6685f65aac21/go.mod h1:wbwi++q4pI7qbFYMbteUOakZUBdc4NmL+OQ08C3hTqc=
|
||||
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-20220701084835-2208da1d8649 h1:whNDUGOAX5GPZkSy4G3Gv9QyIgk5SXRyjkRuP7ohF8k=
|
||||
|
|
|
@ -93,7 +93,7 @@ func testShadowsocksOutboundWithShadowsocksRust(t *testing.T, method string, pas
|
|||
Inbounds: []option.Inbound{
|
||||
{
|
||||
Type: C.TypeMixed,
|
||||
MixedOptions: option.SimpleInboundOptions{
|
||||
MixedOptions: option.HTTPMixedInboundOptions{
|
||||
ListenOptions: option.ListenOptions{
|
||||
Listen: option.ListenAddress(netip.IPv4Unspecified()),
|
||||
ListenPort: clientPort,
|
||||
|
@ -131,7 +131,7 @@ func testShadowsocksSelf(t *testing.T, method string, password string) {
|
|||
{
|
||||
Type: C.TypeMixed,
|
||||
Tag: "mixed-in",
|
||||
MixedOptions: option.SimpleInboundOptions{
|
||||
MixedOptions: option.HTTPMixedInboundOptions{
|
||||
ListenOptions: option.ListenOptions{
|
||||
Listen: option.ListenAddress(netip.IPv4Unspecified()),
|
||||
ListenPort: clientPort,
|
||||
|
|
Loading…
Reference in a new issue