mirror of
https://github.com/SagerNet/sing.git
synced 2025-04-04 20:37:40 +03:00
Add pac support for mixed server
This commit is contained in:
parent
869224c157
commit
04917323e6
14 changed files with 277 additions and 55 deletions
|
@ -11,6 +11,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
@ -30,6 +31,7 @@ import (
|
||||||
"github.com/sagernet/sing/protocol/shadowsocks/shadowaead"
|
"github.com/sagernet/sing/protocol/shadowsocks/shadowaead"
|
||||||
"github.com/sagernet/sing/protocol/shadowsocks/shadowaead_2022"
|
"github.com/sagernet/sing/protocol/shadowsocks/shadowaead_2022"
|
||||||
"github.com/sagernet/sing/protocol/socks"
|
"github.com/sagernet/sing/protocol/socks"
|
||||||
|
"github.com/sagernet/sing/protocol/wapd"
|
||||||
"github.com/sagernet/sing/transport/mixed"
|
"github.com/sagernet/sing/transport/mixed"
|
||||||
"github.com/sagernet/sing/transport/system"
|
"github.com/sagernet/sing/transport/system"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
@ -52,6 +54,7 @@ type flags struct {
|
||||||
UseSystemRNG bool `json:"use_system_rng"`
|
UseSystemRNG bool `json:"use_system_rng"`
|
||||||
ReducedSaltEntropy bool `json:"reduced_salt_entropy"`
|
ReducedSaltEntropy bool `json:"reduced_salt_entropy"`
|
||||||
ConfigFile string
|
ConfigFile string
|
||||||
|
WAPD bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -88,6 +91,7 @@ Only available with Linux kernel > 3.7.0.`)
|
||||||
command.Flags().BoolVarP(&f.Verbose, "verbose", "v", true, "Enable verbose mode.")
|
command.Flags().BoolVarP(&f.Verbose, "verbose", "v", true, "Enable verbose mode.")
|
||||||
command.Flags().BoolVar(&f.UseSystemRNG, "use-system-rng", false, "Use system random number generator.")
|
command.Flags().BoolVar(&f.UseSystemRNG, "use-system-rng", false, "Use system random number generator.")
|
||||||
command.Flags().BoolVar(&f.ReducedSaltEntropy, "reduced-salt-entropy", false, "Remapping salt to printable chars.")
|
command.Flags().BoolVar(&f.ReducedSaltEntropy, "reduced-salt-entropy", false, "Remapping salt to printable chars.")
|
||||||
|
command.Flags().BoolVar(&f.WAPD, "wapd", false, "Listen WADP server.")
|
||||||
|
|
||||||
err := command.Execute()
|
err := command.Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -102,6 +106,7 @@ type LocalClient struct {
|
||||||
method shadowsocks.Method
|
method shadowsocks.Method
|
||||||
dialer net.Dialer
|
dialer net.Dialer
|
||||||
bypass string
|
bypass string
|
||||||
|
wapd *wapd.Listener
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLocalClient(f *flags) (*LocalClient, error) {
|
func NewLocalClient(f *flags) (*LocalClient, error) {
|
||||||
|
@ -247,6 +252,10 @@ func NewLocalClient(f *flags) (*LocalClient, error) {
|
||||||
|
|
||||||
client.Listener = mixed.NewListener(netip.AddrPortFrom(bind, f.LocalPort), nil, transproxyMode, client)
|
client.Listener = mixed.NewListener(netip.AddrPortFrom(bind, f.LocalPort), nil, transproxyMode, client)
|
||||||
|
|
||||||
|
if f.WAPD {
|
||||||
|
client.wapd = wapd.NewListener(netip.MustParseAddr("255.255.255.255"), "http://127.0.0.1:"+strconv.Itoa(int(f.LocalPort))+"/proxy.pac", client)
|
||||||
|
}
|
||||||
|
|
||||||
if f.Bypass != "" {
|
if f.Bypass != "" {
|
||||||
err := geoip.LoadMMDB("Country.mmdb")
|
err := geoip.LoadMMDB("Country.mmdb")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -373,6 +382,14 @@ func Run(cmd *cobra.Command, flags *flags) {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if client.wapd != nil {
|
||||||
|
err = client.wapd.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
logrus.Info("mixed server started at ", client.Listener.TCPListener.Addr())
|
logrus.Info("mixed server started at ", client.Listener.TCPListener.Addr())
|
||||||
|
|
||||||
osSignals := make(chan os.Signal, 1)
|
osSignals := make(chan os.Signal, 1)
|
||||||
|
@ -383,6 +400,7 @@ func Run(cmd *cobra.Command, flags *flags) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *LocalClient) HandleError(err error) {
|
func (c *LocalClient) HandleError(err error) {
|
||||||
|
common.Close(err)
|
||||||
if E.IsClosed(err) {
|
if E.IsClosed(err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/sagernet/sing"
|
"github.com/sagernet/sing"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
"github.com/sagernet/sing/common/redir"
|
"github.com/sagernet/sing/common/redir"
|
||||||
|
@ -133,6 +134,7 @@ func (c *localClient) NewPacketConnection(conn socks.PacketConn, _ M.Metadata) e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *localClient) OnError(err error) {
|
func (c *localClient) OnError(err error) {
|
||||||
|
common.Close(err)
|
||||||
if E.IsClosed(err) {
|
if E.IsClosed(err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,20 +96,33 @@ func Must1(_ any, err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Close(closers ...any) {
|
func Close(closers ...any) error {
|
||||||
|
var retErr error
|
||||||
for _, closer := range closers {
|
for _, closer := range closers {
|
||||||
if closer == nil {
|
if closer == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
var err error
|
||||||
switch c := closer.(type) {
|
switch c := closer.(type) {
|
||||||
case io.Closer:
|
case io.Closer:
|
||||||
c.Close()
|
err = c.Close()
|
||||||
}
|
}
|
||||||
switch c := closer.(type) {
|
switch c := closer.(type) {
|
||||||
case ReaderWithUpstream:
|
case ReaderWithUpstream:
|
||||||
Close(c.Upstream())
|
err = Close(c.Upstream())
|
||||||
case WriterWithUpstream:
|
case WriterWithUpstream:
|
||||||
Close(c.Upstream())
|
err = Close(c.Upstream())
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
retErr = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return retErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func CloseError(closer any, err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return Close(closer)
|
||||||
}
|
}
|
||||||
|
|
10
common/metadata/network.go
Normal file
10
common/metadata/network.go
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
package metadata
|
||||||
|
|
||||||
|
import "net/netip"
|
||||||
|
|
||||||
|
func NetworkFromNetAddr(network string, addr netip.Addr) string {
|
||||||
|
if addr.Is4() && (addr.IsUnspecified() || addr.IsGlobalUnicast() || addr.IsLinkLocalUnicast()) {
|
||||||
|
return network + "4"
|
||||||
|
}
|
||||||
|
return network
|
||||||
|
}
|
2
go.mod
2
go.mod
|
@ -3,6 +3,7 @@ module github.com/sagernet/sing
|
||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/insomniacslk/dhcp v0.0.0-20220405050111-12fbdcb11b41
|
||||||
github.com/klauspost/compress v1.15.1
|
github.com/klauspost/compress v1.15.1
|
||||||
github.com/openacid/low v0.1.21
|
github.com/openacid/low v0.1.21
|
||||||
github.com/oschwald/geoip2-golang v1.7.0
|
github.com/oschwald/geoip2-golang v1.7.0
|
||||||
|
@ -33,6 +34,7 @@ require (
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
|
||||||
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
|
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
)
|
)
|
||||||
|
|
55
go.sum
55
go.sum
|
@ -5,19 +5,41 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 h1:BS21ZUJ/B5X2UVUbczfmdWH7GapPWAhxcMsDnjJTU1E=
|
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 h1:BS21ZUJ/B5X2UVUbczfmdWH7GapPWAhxcMsDnjJTU1E=
|
||||||
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
|
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
|
||||||
|
github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
|
github.com/insomniacslk/dhcp v0.0.0-20220405050111-12fbdcb11b41 h1:Yg3n3AI7GoHnWt7dyjsLPU+TEuZfPAg0OdiA3MJUV6I=
|
||||||
|
github.com/insomniacslk/dhcp v0.0.0-20220405050111-12fbdcb11b41/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
|
||||||
|
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
|
||||||
|
github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
|
||||||
|
github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
|
||||||
|
github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A=
|
github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A=
|
||||||
github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
|
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
|
||||||
|
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
|
||||||
|
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
|
||||||
|
github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
|
||||||
|
github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
|
||||||
|
github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
|
||||||
|
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
github.com/openacid/errors v0.8.1/go.mod h1:GUQEJJOJE3W9skHm8E8Y4phdl2LLEN8iD7c5gcGgdx0=
|
github.com/openacid/errors v0.8.1/go.mod h1:GUQEJJOJE3W9skHm8E8Y4phdl2LLEN8iD7c5gcGgdx0=
|
||||||
github.com/openacid/low v0.1.21 h1:Tr2GNu4N/+rGRYdOsEHOE89cxUIaDViZbVmKz29uKGo=
|
github.com/openacid/low v0.1.21 h1:Tr2GNu4N/+rGRYdOsEHOE89cxUIaDViZbVmKz29uKGo=
|
||||||
|
@ -42,10 +64,13 @@ github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c h1:pqy40B3M
|
||||||
github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
|
github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
|
||||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
|
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
|
||||||
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
|
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
@ -54,21 +79,51 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
|
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
|
||||||
|
github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA=
|
||||||
|
github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
|
||||||
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
|
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
|
||||||
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI=
|
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI=
|
||||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
|
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
|
||||||
github.com/v2fly/v2ray-core/v5 v5.0.3 h1:2rnJ9vZbBQ7V4upWsoUVYGoqZl4grrx8SxOReKx+jjc=
|
github.com/v2fly/v2ray-core/v5 v5.0.3 h1:2rnJ9vZbBQ7V4upWsoUVYGoqZl4grrx8SxOReKx+jjc=
|
||||||
github.com/v2fly/v2ray-core/v5 v5.0.3/go.mod h1:zhDdsUJcNE8LcLRA3l7fEQ6QLuveD4/OLbQM2CceSHM=
|
github.com/v2fly/v2ray-core/v5 v5.0.3/go.mod h1:zhDdsUJcNE8LcLRA3l7fEQ6QLuveD4/OLbQM2CceSHM=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 h1:iU7T1X1J6yxDr0rda54sWGkHgOp5XJrqm79gcNlC2VM=
|
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 h1:iU7T1X1J6yxDr0rda54sWGkHgOp5XJrqm79gcNlC2VM=
|
||||||
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM=
|
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM=
|
||||||
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
|
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 h1:EN5+DfgmRMvRUrMGERW2gQl3Vc+Z7ZMnI/xdEpPSf0c=
|
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 h1:EN5+DfgmRMvRUrMGERW2gQl3Vc+Z7ZMnI/xdEpPSf0c=
|
||||||
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f h1:8w7RhxzTVgUzw/AH/9mUV5q0vMgy40SQRursCcfmkCw=
|
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f h1:8w7RhxzTVgUzw/AH/9mUV5q0vMgy40SQRursCcfmkCw=
|
||||||
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d h1:q4JksJ2n0fmbXC0Aj0eOs6E0AcPqnKglxWXWFqGD6x0=
|
golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d h1:q4JksJ2n0fmbXC0Aj0eOs6E0AcPqnKglxWXWFqGD6x0=
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
_ "unsafe"
|
_ "unsafe"
|
||||||
|
|
||||||
"github.com/sagernet/sing/common/auth"
|
"github.com/sagernet/sing/common/auth"
|
||||||
"github.com/sagernet/sing/common/buf"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
"github.com/sagernet/sing/transport/tcp"
|
"github.com/sagernet/sing/transport/tcp"
|
||||||
|
@ -22,14 +21,9 @@ type Handler interface {
|
||||||
tcp.Handler
|
tcp.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleConnection(conn *buf.BufferedConn, authenticator auth.Authenticator, handler Handler) error {
|
func HandleRequest(request *http.Request, conn net.Conn, authenticator auth.Authenticator, handler Handler, metadata M.Metadata) error {
|
||||||
var httpClient *http.Client
|
var httpClient *http.Client
|
||||||
for {
|
for {
|
||||||
request, err := readRequest(conn.Reader())
|
|
||||||
if err != nil {
|
|
||||||
return E.Cause(err, "read http request")
|
|
||||||
}
|
|
||||||
|
|
||||||
if authenticator != nil {
|
if authenticator != nil {
|
||||||
var authOk bool
|
var authOk bool
|
||||||
authorization := request.Header.Get("Proxy-Authorization")
|
authorization := request.Header.Get("Proxy-Authorization")
|
||||||
|
@ -39,7 +33,7 @@ func HandleConnection(conn *buf.BufferedConn, authenticator auth.Authenticator,
|
||||||
authOk = authenticator.Verify(userPswdArr[0], userPswdArr[1])
|
authOk = authenticator.Verify(userPswdArr[0], userPswdArr[1])
|
||||||
}
|
}
|
||||||
if !authOk {
|
if !authOk {
|
||||||
err = responseWith(request, http.StatusProxyAuthRequired).Write(conn)
|
err := responseWith(request, http.StatusProxyAuthRequired).Write(conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -61,9 +55,8 @@ func HandleConnection(conn *buf.BufferedConn, authenticator auth.Authenticator,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "write http response")
|
return E.Cause(err, "write http response")
|
||||||
}
|
}
|
||||||
return handler.NewConnection(conn, M.Metadata{
|
metadata.Destination = destination
|
||||||
Destination: destination,
|
return handler.NewConnection(conn, metadata)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
keepAlive := strings.TrimSpace(strings.ToLower(request.Header.Get("Proxy-Connection"))) == "keep-alive"
|
keepAlive := strings.TrimSpace(strings.ToLower(request.Header.Get("Proxy-Connection"))) == "keep-alive"
|
||||||
|
@ -101,11 +94,10 @@ func HandleConnection(conn *buf.BufferedConn, authenticator auth.Authenticator,
|
||||||
|
|
||||||
left, right := net.Pipe()
|
left, right := net.Pipe()
|
||||||
go func() {
|
go func() {
|
||||||
err = handler.NewConnection(right, M.Metadata{
|
metadata.Destination = destination
|
||||||
Destination: destination,
|
err = handler.NewConnection(right, metadata)
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handler.HandleError(err)
|
handler.HandleError(&tcp.Error{Conn: right, Cause: err})
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return left, nil
|
return left, nil
|
||||||
|
@ -137,11 +129,15 @@ func HandleConnection(conn *buf.BufferedConn, authenticator auth.Authenticator,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !keepAlive {
|
||||||
|
return conn.Close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname readRequest net/http.ReadRequest
|
//go:linkname ReadRequest net/http.ReadRequest
|
||||||
func readRequest(b *bufio.Reader) (req *http.Request, err error)
|
func ReadRequest(b *bufio.Reader) (req *http.Request, err error)
|
||||||
|
|
||||||
func removeHopByHopHeaders(header http.Header) {
|
func removeHopByHopHeaders(header http.Header) {
|
||||||
// Strip hop-by-hop header based on RFC:
|
// Strip hop-by-hop header based on RFC:
|
||||||
|
|
|
@ -35,7 +35,7 @@ func NewListener(bind netip.AddrPort, authenticator auth.Authenticator, handler
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Listener) NewConnection(conn net.Conn, metadata M.Metadata) error {
|
func (l *Listener) NewConnection(conn net.Conn, metadata M.Metadata) error {
|
||||||
return HandleConnection(conn, l.bindAddr, l.authenticator, l.handler)
|
return HandleConnection(conn, l.authenticator, l.bindAddr, l.handler, metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Listener) Start() error {
|
func (l *Listener) Start() error {
|
||||||
|
@ -50,7 +50,7 @@ func (l *Listener) HandleError(err error) {
|
||||||
l.handler.HandleError(err)
|
l.handler.HandleError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleConnection(conn net.Conn, bind netip.Addr, authenticator auth.Authenticator, handler Handler) error {
|
func HandleConnection(conn net.Conn, authenticator auth.Authenticator, bind netip.Addr, handler Handler, metadata M.Metadata) error {
|
||||||
authRequest, err := ReadAuthRequest(conn)
|
authRequest, err := ReadAuthRequest(conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "read socks auth request")
|
return E.Cause(err, "read socks auth request")
|
||||||
|
@ -72,7 +72,7 @@ func HandleConnection(conn net.Conn, bind netip.Addr, authenticator auth.Authent
|
||||||
}
|
}
|
||||||
err = WriteAuthResponse(conn, &AuthResponse{
|
err = WriteAuthResponse(conn, &AuthResponse{
|
||||||
Version: authRequest.Version,
|
Version: authRequest.Version,
|
||||||
Method: AuthTypeNotRequired,
|
Method: authMethod,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "write socks auth response")
|
return E.Cause(err, "write socks auth response")
|
||||||
|
@ -109,9 +109,8 @@ func HandleConnection(conn net.Conn, bind netip.Addr, authenticator auth.Authent
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "write socks response")
|
return E.Cause(err, "write socks response")
|
||||||
}
|
}
|
||||||
return handler.NewConnection(conn, M.Metadata{
|
metadata.Destination = request.Destination
|
||||||
Destination: request.Destination,
|
return handler.NewConnection(conn, metadata)
|
||||||
})
|
|
||||||
case CommandUDPAssociate:
|
case CommandUDPAssociate:
|
||||||
network := "udp"
|
network := "udp"
|
||||||
if bind.Is4() {
|
if bind.Is4() {
|
||||||
|
@ -130,15 +129,12 @@ func HandleConnection(conn net.Conn, bind netip.Addr, authenticator auth.Authent
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "write socks response")
|
return E.Cause(err, "write socks response")
|
||||||
}
|
}
|
||||||
|
metadata.Destination = request.Destination
|
||||||
go func() {
|
go func() {
|
||||||
err := handler.NewPacketConnection(NewPacketConn(conn, udpConn), M.Metadata{
|
err := handler.NewPacketConnection(NewPacketConn(conn, udpConn), metadata)
|
||||||
Source: M.AddrPortFromNetAddr(conn.RemoteAddr()),
|
|
||||||
Destination: request.Destination,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handler.HandleError(err)
|
handler.HandleError(err)
|
||||||
}
|
}
|
||||||
conn.Close()
|
|
||||||
}()
|
}()
|
||||||
return common.Error(io.Copy(io.Discard, conn))
|
return common.Error(io.Copy(io.Discard, conn))
|
||||||
default:
|
default:
|
||||||
|
|
52
protocol/wapd/listener.go
Normal file
52
protocol/wapd/listener.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package wapd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/netip"
|
||||||
|
|
||||||
|
"github.com/insomniacslk/dhcp/dhcpv4"
|
||||||
|
_ "github.com/insomniacslk/dhcp/dhcpv6"
|
||||||
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
"github.com/sagernet/sing/transport/udp"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Listener struct {
|
||||||
|
*udp.Listener
|
||||||
|
E.Handler
|
||||||
|
option dhcpv4.Option
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewListener(bind netip.Addr, proxyURL string, errorHandler E.Handler) *Listener {
|
||||||
|
l := &Listener{
|
||||||
|
Handler: errorHandler,
|
||||||
|
option: dhcpv4.Option{
|
||||||
|
Code: OptionCode,
|
||||||
|
Value: dhcpv4.String(fmt.Sprint(proxyURL)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
l.Listener = udp.NewUDPListener(netip.AddrPortFrom(bind, dhcpv4.ServerPort), l)
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Listener) NewPacket(packet *buf.Buffer, metadata M.Metadata) error {
|
||||||
|
request, err := dhcpv4.FromBytes(packet.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "bad dhcpv4 packet")
|
||||||
|
}
|
||||||
|
logrus.Trace("DHCPv4 request ", request)
|
||||||
|
if !request.IsOptionRequested(OptionCode) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
reply, err := dhcpv4.NewReplyFromRequest(request, dhcpv4.WithOption(l.option))
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "create response")
|
||||||
|
}
|
||||||
|
_, err = l.WriteTo(reply.ToBytes(), metadata.Source.UDPAddr())
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "write response")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
13
protocol/wapd/protocol.go
Normal file
13
protocol/wapd/protocol.go
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package wapd
|
||||||
|
|
||||||
|
var OptionCode = optionCode{}
|
||||||
|
|
||||||
|
type optionCode struct{}
|
||||||
|
|
||||||
|
func (C optionCode) Code() uint8 {
|
||||||
|
return 252
|
||||||
|
}
|
||||||
|
|
||||||
|
func (C optionCode) String() string {
|
||||||
|
return "Web Proxy Auto-Discovery Protocol"
|
||||||
|
}
|
|
@ -1,11 +1,17 @@
|
||||||
package mixed
|
package mixed
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
netHttp "net/http"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/auth"
|
"github.com/sagernet/sing/common/auth"
|
||||||
"github.com/sagernet/sing/common/buf"
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
"github.com/sagernet/sing/common/redir"
|
"github.com/sagernet/sing/common/redir"
|
||||||
"github.com/sagernet/sing/common/udpnat"
|
"github.com/sagernet/sing/common/udpnat"
|
||||||
|
@ -53,11 +59,40 @@ func (l *Listener) NewConnection(conn net.Conn, metadata M.Metadata) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
switch header[0] {
|
switch header[0] {
|
||||||
case socks.Version4, socks.Version5:
|
case socks.Version4:
|
||||||
return socks.HandleConnection(bufConn, l.bindAddr, l.authenticator, l.handler)
|
return E.New("socks4 request dropped (TODO)")
|
||||||
default:
|
case socks.Version5:
|
||||||
return http.HandleConnection(bufConn, l.authenticator, l.handler)
|
return socks.HandleConnection(bufConn, l.authenticator, l.bindAddr, l.handler, metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request, err := http.ReadRequest(bufConn.Reader())
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "read http request")
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.Method == "GET" && request.URL.Path == "/proxy.pac" {
|
||||||
|
content := newPAC(M.AddrPortFromNetAddr(conn.LocalAddr()))
|
||||||
|
response := &netHttp.Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
Status: netHttp.StatusText(200),
|
||||||
|
Proto: request.Proto,
|
||||||
|
ProtoMajor: request.ProtoMajor,
|
||||||
|
ProtoMinor: request.ProtoMinor,
|
||||||
|
Header: netHttp.Header{
|
||||||
|
"Content-Type": {"application/x-ns-proxy-autoconfig"},
|
||||||
|
"Server": {sing.VersionStr},
|
||||||
|
},
|
||||||
|
ContentLength: int64(len(content)),
|
||||||
|
Body: io.NopCloser(strings.NewReader(content)),
|
||||||
|
}
|
||||||
|
err = response.Write(bufConn)
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "write pac response")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.HandleRequest(request, bufConn, l.authenticator, l.handler, metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Listener) NewPacket(packet *buf.Buffer, metadata M.Metadata) error {
|
func (l *Listener) NewPacket(packet *buf.Buffer, metadata M.Metadata) error {
|
||||||
|
@ -80,9 +115,8 @@ func (l *Listener) Start() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Listener) Close() error {
|
func (l *Listener) Close() error {
|
||||||
l.TCPListener.Close()
|
return common.Close(
|
||||||
if l.UDPListener != nil {
|
l.TCPListener,
|
||||||
l.UDPListener.Close()
|
l.UDPListener,
|
||||||
}
|
)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
19
transport/mixed/pac.go
Normal file
19
transport/mixed/pac.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package mixed
|
||||||
|
|
||||||
|
import M "github.com/sagernet/sing/common/metadata"
|
||||||
|
|
||||||
|
/*func newPAC(proxyAddr *M.AddrPort) string {
|
||||||
|
return `
|
||||||
|
function FindProxyForURL(url, host) {
|
||||||
|
return "SOCKS5 ` + proxyAddr.String() + `;SOCKS ` + proxyAddr.String() + `; PROXY ` + proxyAddr.String() + `";
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func newPAC(proxyAddr *M.AddrPort) string {
|
||||||
|
// TODO: socks4 not supported
|
||||||
|
return `
|
||||||
|
function FindProxyForURL(url, host) {
|
||||||
|
return "SOCKS5 ` + proxyAddr.String() + `; PROXY ` + proxyAddr.String() + `";
|
||||||
|
}`
|
||||||
|
}
|
|
@ -23,6 +23,23 @@ type Listener struct {
|
||||||
*net.TCPListener
|
*net.TCPListener
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Error struct {
|
||||||
|
Conn net.Conn
|
||||||
|
Cause error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
return e.Cause.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Unwrap() error {
|
||||||
|
return e.Cause
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Close() error {
|
||||||
|
return common.Close(e.Conn)
|
||||||
|
}
|
||||||
|
|
||||||
func NewTCPListener(listen netip.AddrPort, handler Handler, options ...Option) *Listener {
|
func NewTCPListener(listen netip.AddrPort, handler Handler, options ...Option) *Listener {
|
||||||
listener := &Listener{
|
listener := &Listener{
|
||||||
bind: listen,
|
bind: listen,
|
||||||
|
@ -35,11 +52,7 @@ func NewTCPListener(listen netip.AddrPort, handler Handler, options ...Option) *
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Listener) Start() error {
|
func (l *Listener) Start() error {
|
||||||
network := "tcp"
|
tcpListener, err := net.ListenTCP(M.NetworkFromNetAddr("tcp", l.bind.Addr()), net.TCPAddrFromAddrPort(l.bind))
|
||||||
if l.bind.Addr() == netip.IPv4Unspecified() {
|
|
||||||
network = "tcp4"
|
|
||||||
}
|
|
||||||
tcpListener, err := net.ListenTCP(network, net.TCPAddrFromAddrPort(l.bind))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -73,7 +86,9 @@ func (l *Listener) loop() {
|
||||||
l.Close()
|
l.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var metadata M.Metadata
|
metadata := M.Metadata{
|
||||||
|
Source: M.AddrPortFromNetAddr(tcpConn.RemoteAddr()),
|
||||||
|
}
|
||||||
switch l.trans {
|
switch l.trans {
|
||||||
case redir.ModeRedirect:
|
case redir.ModeRedirect:
|
||||||
metadata.Destination, _ = redir.GetOriginalDestination(tcpConn)
|
metadata.Destination, _ = redir.GetOriginalDestination(tcpConn)
|
||||||
|
@ -86,9 +101,9 @@ func (l *Listener) loop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
err := l.handler.NewConnection(tcpConn, metadata)
|
hErr := l.handler.NewConnection(tcpConn, metadata)
|
||||||
if err != nil {
|
if hErr != nil {
|
||||||
l.handler.HandleError(err)
|
l.handler.HandleError(&Error{Conn: tcpConn, Cause: hErr})
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ type Handler interface {
|
||||||
type Listener struct {
|
type Listener struct {
|
||||||
*net.UDPConn
|
*net.UDPConn
|
||||||
handler Handler
|
handler Handler
|
||||||
|
network string
|
||||||
bind netip.AddrPort
|
bind netip.AddrPort
|
||||||
tproxy bool
|
tproxy bool
|
||||||
}
|
}
|
||||||
|
@ -35,11 +36,7 @@ func NewUDPListener(listen netip.AddrPort, handler Handler, options ...Option) *
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Listener) Start() error {
|
func (l *Listener) Start() error {
|
||||||
network := "udp"
|
udpConn, err := net.ListenUDP(M.NetworkFromNetAddr("udp", l.bind.Addr()), net.UDPAddrFromAddrPort(l.bind))
|
||||||
if l.bind.Addr() == netip.IPv4Unspecified() {
|
|
||||||
network = "udp4"
|
|
||||||
}
|
|
||||||
udpConn, err := net.ListenUDP(network, net.UDPAddrFromAddrPort(l.bind))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue