mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-23 09:01:30 +00:00
WTF is this
This commit is contained in:
parent
eaa8e2dc70
commit
050b429485
|
@ -4,14 +4,13 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/urltest"
|
"github.com/sagernet/sing-box/common/urltest"
|
||||||
"github.com/sagernet/sing-dns"
|
"github.com/sagernet/sing-dns"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/varbin"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ClashServer interface {
|
type ClashServer interface {
|
||||||
|
@ -56,16 +55,15 @@ func (s *SavedRuleSet) MarshalBinary() ([]byte, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = rw.WriteUVariant(&buffer, uint64(len(s.Content)))
|
err = varbin.Write(&buffer, binary.BigEndian, s.Content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
buffer.Write(s.Content)
|
|
||||||
err = binary.Write(&buffer, binary.BigEndian, s.LastUpdated.Unix())
|
err = binary.Write(&buffer, binary.BigEndian, s.LastUpdated.Unix())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = rw.WriteVString(&buffer, s.LastEtag)
|
err = varbin.Write(&buffer, binary.BigEndian, s.LastEtag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -79,12 +77,7 @@ func (s *SavedRuleSet) UnmarshalBinary(data []byte) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
contentLen, err := rw.ReadUVariant(reader)
|
err = varbin.Read(reader, binary.BigEndian, &s.Content)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s.Content = make([]byte, contentLen)
|
|
||||||
_, err = io.ReadFull(reader, s.Content)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -94,7 +87,7 @@ func (s *SavedRuleSet) UnmarshalBinary(data []byte) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.LastUpdated = time.Unix(lastUpdated, 0)
|
s.LastUpdated = time.Unix(lastUpdated, 0)
|
||||||
s.LastEtag, err = rw.ReadVString(reader)
|
err = varbin.Read(reader, binary.BigEndian, &s.LastEtag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ type Router interface {
|
||||||
DefaultInterface() string
|
DefaultInterface() string
|
||||||
AutoDetectInterface() bool
|
AutoDetectInterface() bool
|
||||||
AutoDetectInterfaceFunc() control.Func
|
AutoDetectInterfaceFunc() control.Func
|
||||||
DefaultMark() int
|
DefaultMark() uint32
|
||||||
NetworkMonitor() tun.NetworkUpdateMonitor
|
NetworkMonitor() tun.NetworkUpdateMonitor
|
||||||
InterfaceMonitor() tun.DefaultInterfaceMonitor
|
InterfaceMonitor() tun.DefaultInterfaceMonitor
|
||||||
PackageManager() tun.PackageManager
|
PackageManager() tun.PackageManager
|
||||||
|
|
|
@ -45,7 +45,9 @@ func (s *Box) startOutbounds() error {
|
||||||
}
|
}
|
||||||
started[outboundTag] = true
|
started[outboundTag] = true
|
||||||
canContinue = true
|
canContinue = true
|
||||||
if starter, isStarter := outboundToStart.(common.Starter); isStarter {
|
if starter, isStarter := outboundToStart.(interface {
|
||||||
|
Start() error
|
||||||
|
}); isStarter {
|
||||||
monitor.Start("initialize outbound/", outboundToStart.Type(), "[", outboundTag, "]")
|
monitor.Start("initialize outbound/", outboundToStart.Type(), "[", outboundTag, "]")
|
||||||
err := starter.Start()
|
err := starter.Start()
|
||||||
monitor.Finish()
|
monitor.Finish()
|
||||||
|
|
|
@ -93,7 +93,7 @@ func buildAndroid() {
|
||||||
|
|
||||||
const name = "libbox.aar"
|
const name = "libbox.aar"
|
||||||
copyPath := filepath.Join("..", "sing-box-for-android", "app", "libs")
|
copyPath := filepath.Join("..", "sing-box-for-android", "app", "libs")
|
||||||
if rw.FileExists(copyPath) {
|
if rw.IsDir(copyPath) {
|
||||||
copyPath, _ = filepath.Abs(copyPath)
|
copyPath, _ = filepath.Abs(copyPath)
|
||||||
err = rw.CopyFile(name, filepath.Join(copyPath, name))
|
err = rw.CopyFile(name, filepath.Join(copyPath, name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -134,7 +134,7 @@ func buildiOS() {
|
||||||
}
|
}
|
||||||
|
|
||||||
copyPath := filepath.Join("..", "sing-box-for-apple")
|
copyPath := filepath.Join("..", "sing-box-for-apple")
|
||||||
if rw.FileExists(copyPath) {
|
if rw.IsDir(copyPath) {
|
||||||
targetDir := filepath.Join(copyPath, "Libbox.xcframework")
|
targetDir := filepath.Join(copyPath, "Libbox.xcframework")
|
||||||
targetDir, _ = filepath.Abs(targetDir)
|
targetDir, _ = filepath.Abs(targetDir)
|
||||||
os.RemoveAll(targetDir)
|
os.RemoveAll(targetDir)
|
||||||
|
|
|
@ -30,7 +30,7 @@ func FindSDK() {
|
||||||
}
|
}
|
||||||
for _, path := range searchPath {
|
for _, path := range searchPath {
|
||||||
path = os.ExpandEnv(path)
|
path = os.ExpandEnv(path)
|
||||||
if rw.FileExists(filepath.Join(path, "licenses", "android-sdk-license")) {
|
if rw.IsFile(filepath.Join(path, "licenses", "android-sdk-license")) {
|
||||||
androidSDKPath = path
|
androidSDKPath = path
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ func FindSDK() {
|
||||||
func findNDK() bool {
|
func findNDK() bool {
|
||||||
const fixedVersion = "26.2.11394342"
|
const fixedVersion = "26.2.11394342"
|
||||||
const versionFile = "source.properties"
|
const versionFile = "source.properties"
|
||||||
if fixedPath := filepath.Join(androidSDKPath, "ndk", fixedVersion); rw.FileExists(filepath.Join(fixedPath, versionFile)) {
|
if fixedPath := filepath.Join(androidSDKPath, "ndk", fixedVersion); rw.IsFile(filepath.Join(fixedPath, versionFile)) {
|
||||||
androidNDKPath = fixedPath
|
androidNDKPath = fixedPath
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ func findNDK() bool {
|
||||||
})
|
})
|
||||||
for _, versionName := range versionNames {
|
for _, versionName := range versionNames {
|
||||||
currentNDKPath := filepath.Join(androidSDKPath, "ndk", versionName)
|
currentNDKPath := filepath.Join(androidSDKPath, "ndk", versionName)
|
||||||
if rw.FileExists(filepath.Join(androidSDKPath, versionFile)) {
|
if rw.IsFile(filepath.Join(androidSDKPath, versionFile)) {
|
||||||
androidNDKPath = currentNDKPath
|
androidNDKPath = currentNDKPath
|
||||||
log.Warn("reproducibility warning: using NDK version " + versionName + " instead of " + fixedVersion)
|
log.Warn("reproducibility warning: using NDK version " + versionName + " instead of " + fixedVersion)
|
||||||
return true
|
return true
|
||||||
|
@ -100,11 +100,11 @@ var GoBinPath string
|
||||||
func FindMobile() {
|
func FindMobile() {
|
||||||
goBin := filepath.Join(build.Default.GOPATH, "bin")
|
goBin := filepath.Join(build.Default.GOPATH, "bin")
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
if !rw.FileExists(filepath.Join(goBin, "gobind.exe")) {
|
if !rw.IsFile(filepath.Join(goBin, "gobind.exe")) {
|
||||||
log.Fatal("missing gomobile installation")
|
log.Fatal("missing gomobile installation")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !rw.FileExists(filepath.Join(goBin, "gobind")) {
|
if !rw.IsFile(filepath.Join(goBin, "gobind")) {
|
||||||
log.Fatal("missing gomobile installation")
|
log.Fatal("missing gomobile installation")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,11 @@ func merge(outputPath string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = rw.WriteFile(outputPath, buffer.Bytes())
|
err = rw.MkdirParent(outputPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = os.WriteFile(outputPath, buffer.Bytes(), 0o644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,7 @@ func readConfigAndMerge() (option.Options, error) {
|
||||||
}
|
}
|
||||||
var mergedMessage json.RawMessage
|
var mergedMessage json.RawMessage
|
||||||
for _, options := range optionsList {
|
for _, options := range optionsList {
|
||||||
mergedMessage, err = badjson.MergeJSON(options.options.RawMessage, mergedMessage)
|
mergedMessage, err = badjson.MergeJSON(options.options.RawMessage, mergedMessage, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return option.Options{}, E.Cause(err, "merge config at ", options.path)
|
return option.Options{}, E.Cause(err, "merge config at ", options.path)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,22 @@
|
||||||
package geosite
|
package geosite
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/binary"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/varbin"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Reader struct {
|
type Reader struct {
|
||||||
|
access sync.Mutex
|
||||||
reader io.ReadSeeker
|
reader io.ReadSeeker
|
||||||
|
bufferedReader *bufio.Reader
|
||||||
|
metadataIndex int64
|
||||||
domainIndex map[string]int
|
domainIndex map[string]int
|
||||||
domainLength map[string]int
|
domainLength map[string]int
|
||||||
}
|
}
|
||||||
|
@ -34,15 +41,23 @@ func Open(path string) (*Reader, []string, error) {
|
||||||
return reader, codes, nil
|
return reader, codes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type geositeMetadata struct {
|
||||||
|
Code string
|
||||||
|
Index uint64
|
||||||
|
Length uint64
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Reader) readMetadata() error {
|
func (r *Reader) readMetadata() error {
|
||||||
version, err := rw.ReadByte(r.reader)
|
counter := &readCounter{Reader: r.reader}
|
||||||
|
reader := bufio.NewReader(counter)
|
||||||
|
version, err := reader.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if version != 0 {
|
if version != 0 {
|
||||||
return E.New("unknown version")
|
return E.New("unknown version")
|
||||||
}
|
}
|
||||||
entryLength, err := rw.ReadUVariant(r.reader)
|
entryLength, err := binary.ReadUvarint(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -55,16 +70,16 @@ func (r *Reader) readMetadata() error {
|
||||||
codeIndex uint64
|
codeIndex uint64
|
||||||
codeLength uint64
|
codeLength uint64
|
||||||
)
|
)
|
||||||
code, err = rw.ReadVString(r.reader)
|
code, err = varbin.ReadValue[string](reader, binary.BigEndian)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
keys[i] = code
|
keys[i] = code
|
||||||
codeIndex, err = rw.ReadUVariant(r.reader)
|
codeIndex, err = binary.ReadUvarint(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
codeLength, err = rw.ReadUVariant(r.reader)
|
codeLength, err = binary.ReadUvarint(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -73,6 +88,8 @@ func (r *Reader) readMetadata() error {
|
||||||
}
|
}
|
||||||
r.domainIndex = domainIndex
|
r.domainIndex = domainIndex
|
||||||
r.domainLength = domainLength
|
r.domainLength = domainLength
|
||||||
|
r.metadataIndex = counter.count - int64(reader.Buffered())
|
||||||
|
r.bufferedReader = reader
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,31 +98,32 @@ func (r *Reader) Read(code string) ([]Item, error) {
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil, E.New("code ", code, " not exists!")
|
return nil, E.New("code ", code, " not exists!")
|
||||||
}
|
}
|
||||||
_, err := r.reader.Seek(int64(index), io.SeekCurrent)
|
_, err := r.reader.Seek(r.metadataIndex+int64(index), io.SeekStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
counter := &rw.ReadCounter{Reader: r.reader}
|
r.bufferedReader.Reset(r.reader)
|
||||||
domain := make([]Item, r.domainLength[code])
|
itemList := make([]Item, r.domainLength[code])
|
||||||
for i := range domain {
|
err = varbin.Read(r.bufferedReader, binary.BigEndian, &itemList)
|
||||||
var (
|
|
||||||
item Item
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
item.Type, err = rw.ReadByte(counter)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
item.Value, err = rw.ReadVString(counter)
|
return itemList, nil
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
domain[i] = item
|
|
||||||
}
|
|
||||||
_, err = r.reader.Seek(int64(-index)-counter.Count(), io.SeekCurrent)
|
|
||||||
return domain, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Reader) Upstream() any {
|
func (r *Reader) Upstream() any {
|
||||||
return r.reader
|
return r.reader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type readCounter struct {
|
||||||
|
io.Reader
|
||||||
|
count int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *readCounter) Read(p []byte) (n int, err error) {
|
||||||
|
n, err = r.Reader.Read(p)
|
||||||
|
if n > 0 {
|
||||||
|
atomic.AddInt64(&r.count, int64(n))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -2,13 +2,13 @@ package geosite
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"encoding/binary"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/varbin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Write(writer io.Writer, domains map[string][]Item) error {
|
func Write(writer varbin.Writer, domains map[string][]Item) error {
|
||||||
keys := make([]string, 0, len(domains))
|
keys := make([]string, 0, len(domains))
|
||||||
for code := range domains {
|
for code := range domains {
|
||||||
keys = append(keys, code)
|
keys = append(keys, code)
|
||||||
|
@ -19,35 +19,32 @@ func Write(writer io.Writer, domains map[string][]Item) error {
|
||||||
index := make(map[string]int)
|
index := make(map[string]int)
|
||||||
for _, code := range keys {
|
for _, code := range keys {
|
||||||
index[code] = content.Len()
|
index[code] = content.Len()
|
||||||
for _, domain := range domains[code] {
|
err := varbin.Write(content, binary.BigEndian, domains[code])
|
||||||
content.WriteByte(domain.Type)
|
|
||||||
err := rw.WriteVString(content, domain.Value)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
err := rw.WriteByte(writer, 0)
|
err := writer.WriteByte(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = rw.WriteUVariant(writer, uint64(len(keys)))
|
_, err = varbin.WriteUvarint(writer, uint64(len(keys)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, code := range keys {
|
for _, code := range keys {
|
||||||
err = rw.WriteVString(writer, code)
|
err = varbin.Write(writer, binary.BigEndian, code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = rw.WriteUVariant(writer, uint64(index[code]))
|
_, err = varbin.WriteUvarint(writer, uint64(index[code]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = rw.WriteUVariant(writer, uint64(len(domains[code])))
|
_, err = varbin.WriteUvarint(writer, uint64(len(domains[code])))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package srs
|
package srs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"compress/zlib"
|
"compress/zlib"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
"io"
|
||||||
|
@ -11,7 +12,7 @@ import (
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/domain"
|
"github.com/sagernet/sing/common/domain"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/varbin"
|
||||||
|
|
||||||
"go4.org/netipx"
|
"go4.org/netipx"
|
||||||
)
|
)
|
||||||
|
@ -38,7 +39,7 @@ const (
|
||||||
ruleItemFinal uint8 = 0xFF
|
ruleItemFinal uint8 = 0xFF
|
||||||
)
|
)
|
||||||
|
|
||||||
func Read(reader io.Reader, recovery bool) (ruleSet option.PlainRuleSet, err error) {
|
func Read(reader io.Reader, recover bool) (ruleSet option.PlainRuleSet, err error) {
|
||||||
var magicBytes [3]byte
|
var magicBytes [3]byte
|
||||||
_, err = io.ReadFull(reader, magicBytes[:])
|
_, err = io.ReadFull(reader, magicBytes[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -60,13 +61,14 @@ func Read(reader io.Reader, recovery bool) (ruleSet option.PlainRuleSet, err err
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
length, err := rw.ReadUVariant(zReader)
|
bReader := bufio.NewReader(zReader)
|
||||||
|
length, err := binary.ReadUvarint(bReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ruleSet.Rules = make([]option.HeadlessRule, length)
|
ruleSet.Rules = make([]option.HeadlessRule, length)
|
||||||
for i := uint64(0); i < length; i++ {
|
for i := uint64(0); i < length; i++ {
|
||||||
ruleSet.Rules[i], err = readRule(zReader, recovery)
|
ruleSet.Rules[i], err = readRule(bReader, recover)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = E.Cause(err, "read rule[", i, "]")
|
err = E.Cause(err, "read rule[", i, "]")
|
||||||
return
|
return
|
||||||
|
@ -88,20 +90,25 @@ func Write(writer io.Writer, ruleSet option.PlainRuleSet) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = rw.WriteUVariant(zWriter, uint64(len(ruleSet.Rules)))
|
bWriter := bufio.NewWriter(zWriter)
|
||||||
|
_, err = varbin.WriteUvarint(bWriter, uint64(len(ruleSet.Rules)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, rule := range ruleSet.Rules {
|
for _, rule := range ruleSet.Rules {
|
||||||
err = writeRule(zWriter, rule)
|
err = writeRule(bWriter, rule)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
err = bWriter.Flush()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return zWriter.Close()
|
return zWriter.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func readRule(reader io.Reader, recovery bool) (rule option.HeadlessRule, err error) {
|
func readRule(reader varbin.Reader, recover bool) (rule option.HeadlessRule, err error) {
|
||||||
var ruleType uint8
|
var ruleType uint8
|
||||||
err = binary.Read(reader, binary.BigEndian, &ruleType)
|
err = binary.Read(reader, binary.BigEndian, &ruleType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -110,17 +117,17 @@ func readRule(reader io.Reader, recovery bool) (rule option.HeadlessRule, err er
|
||||||
switch ruleType {
|
switch ruleType {
|
||||||
case 0:
|
case 0:
|
||||||
rule.Type = C.RuleTypeDefault
|
rule.Type = C.RuleTypeDefault
|
||||||
rule.DefaultOptions, err = readDefaultRule(reader, recovery)
|
rule.DefaultOptions, err = readDefaultRule(reader, recover)
|
||||||
case 1:
|
case 1:
|
||||||
rule.Type = C.RuleTypeLogical
|
rule.Type = C.RuleTypeLogical
|
||||||
rule.LogicalOptions, err = readLogicalRule(reader, recovery)
|
rule.LogicalOptions, err = readLogicalRule(reader, recover)
|
||||||
default:
|
default:
|
||||||
err = E.New("unknown rule type: ", ruleType)
|
err = E.New("unknown rule type: ", ruleType)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeRule(writer io.Writer, rule option.HeadlessRule) error {
|
func writeRule(writer varbin.Writer, rule option.HeadlessRule) error {
|
||||||
switch rule.Type {
|
switch rule.Type {
|
||||||
case C.RuleTypeDefault:
|
case C.RuleTypeDefault:
|
||||||
return writeDefaultRule(writer, rule.DefaultOptions)
|
return writeDefaultRule(writer, rule.DefaultOptions)
|
||||||
|
@ -131,7 +138,7 @@ func writeRule(writer io.Writer, rule option.HeadlessRule) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func readDefaultRule(reader io.Reader, recovery bool) (rule option.DefaultHeadlessRule, err error) {
|
func readDefaultRule(reader varbin.Reader, recover bool) (rule option.DefaultHeadlessRule, err error) {
|
||||||
var lastItemType uint8
|
var lastItemType uint8
|
||||||
for {
|
for {
|
||||||
var itemType uint8
|
var itemType uint8
|
||||||
|
@ -158,6 +165,9 @@ func readDefaultRule(reader io.Reader, recovery bool) (rule option.DefaultHeadle
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rule.DomainMatcher = matcher
|
rule.DomainMatcher = matcher
|
||||||
|
if recover {
|
||||||
|
rule.Domain, rule.DomainSuffix = matcher.Dump()
|
||||||
|
}
|
||||||
case ruleItemDomainKeyword:
|
case ruleItemDomainKeyword:
|
||||||
rule.DomainKeyword, err = readRuleItemString(reader)
|
rule.DomainKeyword, err = readRuleItemString(reader)
|
||||||
case ruleItemDomainRegex:
|
case ruleItemDomainRegex:
|
||||||
|
@ -167,7 +177,7 @@ func readDefaultRule(reader io.Reader, recovery bool) (rule option.DefaultHeadle
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if recovery {
|
if recover {
|
||||||
rule.SourceIPCIDR = common.Map(rule.SourceIPSet.Prefixes(), netip.Prefix.String)
|
rule.SourceIPCIDR = common.Map(rule.SourceIPSet.Prefixes(), netip.Prefix.String)
|
||||||
}
|
}
|
||||||
case ruleItemIPCIDR:
|
case ruleItemIPCIDR:
|
||||||
|
@ -175,7 +185,7 @@ func readDefaultRule(reader io.Reader, recovery bool) (rule option.DefaultHeadle
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if recovery {
|
if recover {
|
||||||
rule.IPCIDR = common.Map(rule.IPSet.Prefixes(), netip.Prefix.String)
|
rule.IPCIDR = common.Map(rule.IPSet.Prefixes(), netip.Prefix.String)
|
||||||
}
|
}
|
||||||
case ruleItemSourcePort:
|
case ruleItemSourcePort:
|
||||||
|
@ -209,7 +219,7 @@ func readDefaultRule(reader io.Reader, recovery bool) (rule option.DefaultHeadle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeDefaultRule(writer io.Writer, rule option.DefaultHeadlessRule) error {
|
func writeDefaultRule(writer varbin.Writer, rule option.DefaultHeadlessRule) error {
|
||||||
err := binary.Write(writer, binary.BigEndian, uint8(0))
|
err := binary.Write(writer, binary.BigEndian, uint8(0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -327,73 +337,31 @@ func writeDefaultRule(writer io.Writer, rule option.DefaultHeadlessRule) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readRuleItemString(reader io.Reader) ([]string, error) {
|
func readRuleItemString(reader varbin.Reader) ([]string, error) {
|
||||||
length, err := rw.ReadUVariant(reader)
|
return varbin.ReadValue[[]string](reader, binary.BigEndian)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
value := make([]string, length)
|
|
||||||
for i := uint64(0); i < length; i++ {
|
|
||||||
value[i], err = rw.ReadVString(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeRuleItemString(writer io.Writer, itemType uint8, value []string) error {
|
func writeRuleItemString(writer varbin.Writer, itemType uint8, value []string) error {
|
||||||
err := binary.Write(writer, binary.BigEndian, itemType)
|
err := writer.WriteByte(itemType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = rw.WriteUVariant(writer, uint64(len(value)))
|
return varbin.Write(writer, binary.BigEndian, value)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, item := range value {
|
|
||||||
err = rw.WriteVString(writer, item)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func readRuleItemUint16(reader io.Reader) ([]uint16, error) {
|
func readRuleItemUint16(reader varbin.Reader) ([]uint16, error) {
|
||||||
length, err := rw.ReadUVariant(reader)
|
return varbin.ReadValue[[]uint16](reader, binary.BigEndian)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
value := make([]uint16, length)
|
|
||||||
for i := uint64(0); i < length; i++ {
|
|
||||||
err = binary.Read(reader, binary.BigEndian, &value[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeRuleItemUint16(writer io.Writer, itemType uint8, value []uint16) error {
|
func writeRuleItemUint16(writer varbin.Writer, itemType uint8, value []uint16) error {
|
||||||
err := binary.Write(writer, binary.BigEndian, itemType)
|
err := writer.WriteByte(itemType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = rw.WriteUVariant(writer, uint64(len(value)))
|
return varbin.Write(writer, binary.BigEndian, value)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, item := range value {
|
|
||||||
err = binary.Write(writer, binary.BigEndian, item)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeRuleItemCIDR(writer io.Writer, itemType uint8, value []string) error {
|
func writeRuleItemCIDR(writer varbin.Writer, itemType uint8, value []string) error {
|
||||||
var builder netipx.IPSetBuilder
|
var builder netipx.IPSetBuilder
|
||||||
for i, prefixString := range value {
|
for i, prefixString := range value {
|
||||||
prefix, err := netip.ParsePrefix(prefixString)
|
prefix, err := netip.ParsePrefix(prefixString)
|
||||||
|
@ -419,9 +387,8 @@ func writeRuleItemCIDR(writer io.Writer, itemType uint8, value []string) error {
|
||||||
return writeIPSet(writer, ipSet)
|
return writeIPSet(writer, ipSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func readLogicalRule(reader io.Reader, recovery bool) (logicalRule option.LogicalHeadlessRule, err error) {
|
func readLogicalRule(reader varbin.Reader, recovery bool) (logicalRule option.LogicalHeadlessRule, err error) {
|
||||||
var mode uint8
|
mode, err := reader.ReadByte()
|
||||||
err = binary.Read(reader, binary.BigEndian, &mode)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -434,7 +401,7 @@ func readLogicalRule(reader io.Reader, recovery bool) (logicalRule option.Logica
|
||||||
err = E.New("unknown logical mode: ", mode)
|
err = E.New("unknown logical mode: ", mode)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
length, err := rw.ReadUVariant(reader)
|
length, err := binary.ReadUvarint(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -453,7 +420,7 @@ func readLogicalRule(reader io.Reader, recovery bool) (logicalRule option.Logica
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeLogicalRule(writer io.Writer, logicalRule option.LogicalHeadlessRule) error {
|
func writeLogicalRule(writer varbin.Writer, logicalRule option.LogicalHeadlessRule) error {
|
||||||
err := binary.Write(writer, binary.BigEndian, uint8(1))
|
err := binary.Write(writer, binary.BigEndian, uint8(1))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -469,7 +436,7 @@ func writeLogicalRule(writer io.Writer, logicalRule option.LogicalHeadlessRule)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = rw.WriteUVariant(writer, uint64(len(logicalRule.Rules)))
|
_, err = varbin.WriteUvarint(writer, uint64(len(logicalRule.Rules)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,13 @@ package srs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"os"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
"github.com/sagernet/sing/common/varbin"
|
||||||
|
|
||||||
"go4.org/netipx"
|
"go4.org/netipx"
|
||||||
)
|
)
|
||||||
|
@ -20,94 +22,57 @@ type myIPRange struct {
|
||||||
to netip.Addr
|
to netip.Addr
|
||||||
}
|
}
|
||||||
|
|
||||||
func readIPSet(reader io.Reader) (*netipx.IPSet, error) {
|
type myIPRangeData struct {
|
||||||
var version uint8
|
From []byte
|
||||||
err := binary.Read(reader, binary.BigEndian, &version)
|
To []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func readIPSet(reader varbin.Reader) (*netipx.IPSet, error) {
|
||||||
|
version, err := reader.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if version != 1 {
|
||||||
|
return nil, os.ErrInvalid
|
||||||
|
}
|
||||||
|
// WTF why using uint64 here
|
||||||
var length uint64
|
var length uint64
|
||||||
err = binary.Read(reader, binary.BigEndian, &length)
|
err = binary.Read(reader, binary.BigEndian, &length)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
ranges := make([]myIPRangeData, length)
|
||||||
|
err = varbin.Read(reader, binary.BigEndian, &ranges)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
mySet := &myIPSet{
|
mySet := &myIPSet{
|
||||||
rr: make([]myIPRange, length),
|
rr: make([]myIPRange, len(ranges)),
|
||||||
}
|
}
|
||||||
for i := uint64(0); i < length; i++ {
|
for i, rangeData := range ranges {
|
||||||
var (
|
mySet.rr[i].from = M.AddrFromIP(rangeData.From)
|
||||||
fromLen uint64
|
mySet.rr[i].to = M.AddrFromIP(rangeData.To)
|
||||||
toLen uint64
|
|
||||||
fromAddr netip.Addr
|
|
||||||
toAddr netip.Addr
|
|
||||||
)
|
|
||||||
fromLen, err = rw.ReadUVariant(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
fromBytes := make([]byte, fromLen)
|
|
||||||
_, err = io.ReadFull(reader, fromBytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = fromAddr.UnmarshalBinary(fromBytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
toLen, err = rw.ReadUVariant(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
toBytes := make([]byte, toLen)
|
|
||||||
_, err = io.ReadFull(reader, toBytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = toAddr.UnmarshalBinary(toBytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mySet.rr[i] = myIPRange{fromAddr, toAddr}
|
|
||||||
}
|
}
|
||||||
return (*netipx.IPSet)(unsafe.Pointer(mySet)), nil
|
return (*netipx.IPSet)(unsafe.Pointer(mySet)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeIPSet(writer io.Writer, set *netipx.IPSet) error {
|
func writeIPSet(writer varbin.Writer, set *netipx.IPSet) error {
|
||||||
err := binary.Write(writer, binary.BigEndian, uint8(1))
|
err := writer.WriteByte(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
mySet := (*myIPSet)(unsafe.Pointer(set))
|
dataList := common.Map((*myIPSet)(unsafe.Pointer(set)).rr, func(rr myIPRange) myIPRangeData {
|
||||||
err = binary.Write(writer, binary.BigEndian, uint64(len(mySet.rr)))
|
return myIPRangeData{
|
||||||
|
From: rr.from.AsSlice(),
|
||||||
|
To: rr.to.AsSlice(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
err = binary.Write(writer, binary.BigEndian, uint64(len(dataList)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, rr := range mySet.rr {
|
for _, data := range dataList {
|
||||||
var (
|
err = varbin.Write(writer, binary.BigEndian, data)
|
||||||
fromBinary []byte
|
|
||||||
toBinary []byte
|
|
||||||
)
|
|
||||||
fromBinary, err = rr.from.MarshalBinary()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = rw.WriteUVariant(writer, uint64(len(fromBinary)))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = writer.Write(fromBinary)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
toBinary, err = rr.to.MarshalBinary()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = rw.WriteUVariant(writer, uint64(len(toBinary)))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = writer.Write(toBinary)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,14 +13,14 @@ var resourcePaths []string
|
||||||
|
|
||||||
func FindPath(name string) (string, bool) {
|
func FindPath(name string) (string, bool) {
|
||||||
name = os.ExpandEnv(name)
|
name = os.ExpandEnv(name)
|
||||||
if rw.FileExists(name) {
|
if rw.IsFile(name) {
|
||||||
return name, true
|
return name, true
|
||||||
}
|
}
|
||||||
for _, dir := range resourcePaths {
|
for _, dir := range resourcePaths {
|
||||||
if path := filepath.Join(dir, dirName, name); rw.FileExists(path) {
|
if path := filepath.Join(dir, dirName, name); rw.IsFile(path) {
|
||||||
return path, true
|
return path, true
|
||||||
}
|
}
|
||||||
if path := filepath.Join(dir, name); rw.FileExists(path) {
|
if path := filepath.Join(dir, name); rw.IsFile(path) {
|
||||||
return path, true
|
return path, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/experimental/clashapi"
|
"github.com/sagernet/sing-box/experimental/clashapi"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/varbin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *CommandClient) SetClashMode(newMode string) error {
|
func (c *CommandClient) SetClashMode(newMode string) error {
|
||||||
|
@ -22,7 +22,7 @@ func (c *CommandClient) SetClashMode(newMode string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = rw.WriteVString(conn, newMode)
|
err = varbin.Write(conn, binary.BigEndian, newMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ func (c *CommandClient) SetClashMode(newMode string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommandServer) handleSetClashMode(conn net.Conn) error {
|
func (s *CommandServer) handleSetClashMode(conn net.Conn) error {
|
||||||
newMode, err := rw.ReadVString(conn)
|
newMode, err := varbin.ReadValue[string](conn, binary.BigEndian)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ func (c *CommandClient) handleModeConn(conn net.Conn) {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
newMode, err := rw.ReadVString(conn)
|
newMode, err := varbin.ReadValue[string](conn, binary.BigEndian)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.handler.Disconnected(err.Error())
|
c.handler.Disconnected(err.Error())
|
||||||
return
|
return
|
||||||
|
@ -80,7 +80,7 @@ func (s *CommandServer) handleModeConn(conn net.Conn) error {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-s.modeUpdate:
|
case <-s.modeUpdate:
|
||||||
err = rw.WriteVString(conn, clashServer.Mode())
|
err = varbin.Write(conn, binary.BigEndian, clashServer.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -101,12 +101,12 @@ func readClashModeList(reader io.Reader) (modeList []string, currentMode string,
|
||||||
}
|
}
|
||||||
modeList = make([]string, modeListLength)
|
modeList = make([]string, modeListLength)
|
||||||
for i := 0; i < int(modeListLength); i++ {
|
for i := 0; i < int(modeListLength); i++ {
|
||||||
modeList[i], err = rw.ReadVString(reader)
|
modeList[i], err = varbin.ReadValue[string](reader, binary.BigEndian)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentMode, err = rw.ReadVString(reader)
|
currentMode, err = varbin.ReadValue[string](reader, binary.BigEndian)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,12 +118,12 @@ func writeClashModeList(writer io.Writer, clashServer adapter.ClashServer) error
|
||||||
}
|
}
|
||||||
if len(modeList) > 0 {
|
if len(modeList) > 0 {
|
||||||
for _, mode := range modeList {
|
for _, mode := range modeList {
|
||||||
err = rw.WriteVString(writer, mode)
|
err = varbin.Write(writer, binary.BigEndian, mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = rw.WriteVString(writer, clashServer.Mode())
|
err = varbin.Write(writer, binary.BigEndian, clashServer.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/sagernet/sing-box/experimental/clashapi"
|
"github.com/sagernet/sing-box/experimental/clashapi"
|
||||||
"github.com/sagernet/sing/common/binary"
|
"github.com/sagernet/sing/common/binary"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/varbin"
|
||||||
|
|
||||||
"github.com/gofrs/uuid/v5"
|
"github.com/gofrs/uuid/v5"
|
||||||
)
|
)
|
||||||
|
@ -18,7 +19,7 @@ func (c *CommandClient) CloseConnection(connId string) error {
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
writer := bufio.NewWriter(conn)
|
writer := bufio.NewWriter(conn)
|
||||||
err = binary.WriteData(writer, binary.BigEndian, connId)
|
err = varbin.Write(writer, binary.BigEndian, connId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -32,7 +33,7 @@ func (c *CommandClient) CloseConnection(connId string) error {
|
||||||
func (s *CommandServer) handleCloseConnection(conn net.Conn) error {
|
func (s *CommandServer) handleCloseConnection(conn net.Conn) error {
|
||||||
reader := bufio.NewReader(conn)
|
reader := bufio.NewReader(conn)
|
||||||
var connId string
|
var connId string
|
||||||
err := binary.ReadData(reader, binary.BigEndian, &connId)
|
err := varbin.Read(reader, binary.BigEndian, &connId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "read connection id")
|
return E.Cause(err, "read connection id")
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/sagernet/sing/common/binary"
|
"github.com/sagernet/sing/common/binary"
|
||||||
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/varbin"
|
||||||
|
|
||||||
"github.com/gofrs/uuid/v5"
|
"github.com/gofrs/uuid/v5"
|
||||||
)
|
)
|
||||||
|
@ -19,13 +20,17 @@ import (
|
||||||
func (c *CommandClient) handleConnectionsConn(conn net.Conn) {
|
func (c *CommandClient) handleConnectionsConn(conn net.Conn) {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
reader := bufio.NewReader(conn)
|
reader := bufio.NewReader(conn)
|
||||||
var connections Connections
|
var (
|
||||||
|
rawConnections []Connection
|
||||||
|
connections Connections
|
||||||
|
)
|
||||||
for {
|
for {
|
||||||
err := binary.ReadData(reader, binary.BigEndian, &connections.connections)
|
err := varbin.Read(reader, binary.BigEndian, &rawConnections)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.handler.Disconnected(err.Error())
|
c.handler.Disconnected(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
connections.input = rawConnections
|
||||||
c.handler.WriteConnections(&connections)
|
c.handler.WriteConnections(&connections)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,7 +74,7 @@ func (s *CommandServer) handleConnectionsConn(conn net.Conn) error {
|
||||||
for _, connection := range trafficManager.ClosedConnections() {
|
for _, connection := range trafficManager.ClosedConnections() {
|
||||||
outConnections = append(outConnections, newConnection(connections, connection, true))
|
outConnections = append(outConnections, newConnection(connections, connection, true))
|
||||||
}
|
}
|
||||||
err = binary.WriteData(writer, binary.BigEndian, outConnections)
|
err = varbin.Write(writer, binary.BigEndian, outConnections)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -92,33 +97,32 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Connections struct {
|
type Connections struct {
|
||||||
connections []Connection
|
input []Connection
|
||||||
filteredConnections []Connection
|
filtered []Connection
|
||||||
outConnections *[]Connection
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Connections) FilterState(state int32) {
|
func (c *Connections) FilterState(state int32) {
|
||||||
c.filteredConnections = c.filteredConnections[:0]
|
c.filtered = c.filtered[:0]
|
||||||
switch state {
|
switch state {
|
||||||
case ConnectionStateAll:
|
case ConnectionStateAll:
|
||||||
c.filteredConnections = append(c.filteredConnections, c.connections...)
|
c.filtered = append(c.filtered, c.input...)
|
||||||
case ConnectionStateActive:
|
case ConnectionStateActive:
|
||||||
for _, connection := range c.connections {
|
for _, connection := range c.input {
|
||||||
if connection.ClosedAt == 0 {
|
if connection.ClosedAt == 0 {
|
||||||
c.filteredConnections = append(c.filteredConnections, connection)
|
c.filtered = append(c.filtered, connection)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case ConnectionStateClosed:
|
case ConnectionStateClosed:
|
||||||
for _, connection := range c.connections {
|
for _, connection := range c.input {
|
||||||
if connection.ClosedAt != 0 {
|
if connection.ClosedAt != 0 {
|
||||||
c.filteredConnections = append(c.filteredConnections, connection)
|
c.filtered = append(c.filtered, connection)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Connections) SortByDate() {
|
func (c *Connections) SortByDate() {
|
||||||
slices.SortStableFunc(c.filteredConnections, func(x, y Connection) int {
|
slices.SortStableFunc(c.filtered, func(x, y Connection) int {
|
||||||
if x.CreatedAt < y.CreatedAt {
|
if x.CreatedAt < y.CreatedAt {
|
||||||
return 1
|
return 1
|
||||||
} else if x.CreatedAt > y.CreatedAt {
|
} else if x.CreatedAt > y.CreatedAt {
|
||||||
|
@ -130,7 +134,7 @@ func (c *Connections) SortByDate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Connections) SortByTraffic() {
|
func (c *Connections) SortByTraffic() {
|
||||||
slices.SortStableFunc(c.filteredConnections, func(x, y Connection) int {
|
slices.SortStableFunc(c.filtered, func(x, y Connection) int {
|
||||||
xTraffic := x.Uplink + x.Downlink
|
xTraffic := x.Uplink + x.Downlink
|
||||||
yTraffic := y.Uplink + y.Downlink
|
yTraffic := y.Uplink + y.Downlink
|
||||||
if xTraffic < yTraffic {
|
if xTraffic < yTraffic {
|
||||||
|
@ -144,7 +148,7 @@ func (c *Connections) SortByTraffic() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Connections) SortByTrafficTotal() {
|
func (c *Connections) SortByTrafficTotal() {
|
||||||
slices.SortStableFunc(c.filteredConnections, func(x, y Connection) int {
|
slices.SortStableFunc(c.filtered, func(x, y Connection) int {
|
||||||
xTraffic := x.UplinkTotal + x.DownlinkTotal
|
xTraffic := x.UplinkTotal + x.DownlinkTotal
|
||||||
yTraffic := y.UplinkTotal + y.DownlinkTotal
|
yTraffic := y.UplinkTotal + y.DownlinkTotal
|
||||||
if xTraffic < yTraffic {
|
if xTraffic < yTraffic {
|
||||||
|
@ -158,7 +162,7 @@ func (c *Connections) SortByTrafficTotal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Connections) Iterator() ConnectionIterator {
|
func (c *Connections) Iterator() ConnectionIterator {
|
||||||
return newPtrIterator(c.filteredConnections)
|
return newPtrIterator(c.filtered)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Connection struct {
|
type Connection struct {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
@ -10,7 +11,7 @@ import (
|
||||||
"github.com/sagernet/sing-box/common/urltest"
|
"github.com/sagernet/sing-box/common/urltest"
|
||||||
"github.com/sagernet/sing-box/outbound"
|
"github.com/sagernet/sing-box/outbound"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/varbin"
|
||||||
"github.com/sagernet/sing/service"
|
"github.com/sagernet/sing/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -36,19 +37,24 @@ func (s *CommandServer) handleGroupConn(conn net.Conn) error {
|
||||||
ticker := time.NewTicker(time.Duration(interval))
|
ticker := time.NewTicker(time.Duration(interval))
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
ctx := connKeepAlive(conn)
|
ctx := connKeepAlive(conn)
|
||||||
|
writer := bufio.NewWriter(conn)
|
||||||
for {
|
for {
|
||||||
service := s.service
|
service := s.service
|
||||||
if service != nil {
|
if service != nil {
|
||||||
err := writeGroups(conn, service)
|
err = writeGroups(writer, service)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err := binary.Write(conn, binary.BigEndian, uint16(0))
|
err = binary.Write(writer, binary.BigEndian, uint16(0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
err = writer.Flush()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
|
@ -68,11 +74,11 @@ type OutboundGroup struct {
|
||||||
Selectable bool
|
Selectable bool
|
||||||
Selected string
|
Selected string
|
||||||
IsExpand bool
|
IsExpand bool
|
||||||
items []*OutboundGroupItem
|
ItemList []*OutboundGroupItem
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *OutboundGroup) GetItems() OutboundGroupItemIterator {
|
func (g *OutboundGroup) GetItems() OutboundGroupItemIterator {
|
||||||
return newIterator(g.items)
|
return newIterator(g.ItemList)
|
||||||
}
|
}
|
||||||
|
|
||||||
type OutboundGroupIterator interface {
|
type OutboundGroupIterator interface {
|
||||||
|
@ -93,73 +99,10 @@ type OutboundGroupItemIterator interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
func readGroups(reader io.Reader) (OutboundGroupIterator, error) {
|
func readGroups(reader io.Reader) (OutboundGroupIterator, error) {
|
||||||
var groupLength uint16
|
groups, err := varbin.ReadValue[[]*OutboundGroup](reader, binary.BigEndian)
|
||||||
err := binary.Read(reader, binary.BigEndian, &groupLength)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
groups := make([]*OutboundGroup, 0, groupLength)
|
|
||||||
for i := 0; i < int(groupLength); i++ {
|
|
||||||
var group OutboundGroup
|
|
||||||
group.Tag, err = rw.ReadVString(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
group.Type, err = rw.ReadVString(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = binary.Read(reader, binary.BigEndian, &group.Selectable)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
group.Selected, err = rw.ReadVString(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = binary.Read(reader, binary.BigEndian, &group.IsExpand)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var itemLength uint16
|
|
||||||
err = binary.Read(reader, binary.BigEndian, &itemLength)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
group.items = make([]*OutboundGroupItem, itemLength)
|
|
||||||
for j := 0; j < int(itemLength); j++ {
|
|
||||||
var item OutboundGroupItem
|
|
||||||
item.Tag, err = rw.ReadVString(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
item.Type, err = rw.ReadVString(reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = binary.Read(reader, binary.BigEndian, &item.URLTestTime)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = binary.Read(reader, binary.BigEndian, &item.URLTestDelay)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
group.items[j] = &item
|
|
||||||
}
|
|
||||||
groups = append(groups, &group)
|
|
||||||
}
|
|
||||||
return newIterator(groups), nil
|
return newIterator(groups), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,63 +142,14 @@ func writeGroups(writer io.Writer, boxService *BoxService) error {
|
||||||
item.URLTestTime = history.Time.Unix()
|
item.URLTestTime = history.Time.Unix()
|
||||||
item.URLTestDelay = int32(history.Delay)
|
item.URLTestDelay = int32(history.Delay)
|
||||||
}
|
}
|
||||||
group.items = append(group.items, &item)
|
group.ItemList = append(group.ItemList, &item)
|
||||||
}
|
}
|
||||||
if len(group.items) < 2 {
|
if len(group.ItemList) < 2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
groups = append(groups, group)
|
groups = append(groups, group)
|
||||||
}
|
}
|
||||||
|
return varbin.Write(writer, binary.BigEndian, groups)
|
||||||
err := binary.Write(writer, binary.BigEndian, uint16(len(groups)))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, group := range groups {
|
|
||||||
err = rw.WriteVString(writer, group.Tag)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = rw.WriteVString(writer, group.Type)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = binary.Write(writer, binary.BigEndian, group.Selectable)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = rw.WriteVString(writer, group.Selected)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = binary.Write(writer, binary.BigEndian, group.IsExpand)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = binary.Write(writer, binary.BigEndian, uint16(len(group.items)))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, item := range group.items {
|
|
||||||
err = rw.WriteVString(writer, item.Tag)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = rw.WriteVString(writer, item.Type)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = binary.Write(writer, binary.BigEndian, item.URLTestTime)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = binary.Write(writer, binary.BigEndian, item.URLTestDelay)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CommandClient) SetGroupExpand(groupTag string, isExpand bool) error {
|
func (c *CommandClient) SetGroupExpand(groupTag string, isExpand bool) error {
|
||||||
|
@ -268,7 +162,7 @@ func (c *CommandClient) SetGroupExpand(groupTag string, isExpand bool) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = rw.WriteVString(conn, groupTag)
|
err = varbin.Write(conn, binary.BigEndian, groupTag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -280,7 +174,7 @@ func (c *CommandClient) SetGroupExpand(groupTag string, isExpand bool) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommandServer) handleSetGroupExpand(conn net.Conn) error {
|
func (s *CommandServer) handleSetGroupExpand(conn net.Conn) error {
|
||||||
groupTag, err := rw.ReadVString(conn)
|
groupTag, err := varbin.ReadValue[string](conn, binary.BigEndian)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,19 @@ import (
|
||||||
|
|
||||||
"github.com/sagernet/sing/common/binary"
|
"github.com/sagernet/sing/common/binary"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/varbin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (s *CommandServer) ResetLog() {
|
||||||
|
s.access.Lock()
|
||||||
|
defer s.access.Unlock()
|
||||||
|
s.savedLines.Init()
|
||||||
|
select {
|
||||||
|
case s.logReset <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *CommandServer) WriteMessage(message string) {
|
func (s *CommandServer) WriteMessage(message string) {
|
||||||
s.subscriber.Emit(message)
|
s.subscriber.Emit(message)
|
||||||
s.access.Lock()
|
s.access.Lock()
|
||||||
|
@ -21,26 +32,6 @@ func (s *CommandServer) WriteMessage(message string) {
|
||||||
s.access.Unlock()
|
s.access.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeLog(writer *bufio.Writer, messages []string) error {
|
|
||||||
err := binary.Write(writer, binary.BigEndian, uint8(0))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = binary.WriteData(writer, binary.BigEndian, messages)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return writer.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeClearLog(writer *bufio.Writer) error {
|
|
||||||
err := binary.Write(writer, binary.BigEndian, uint8(1))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return writer.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CommandServer) handleLogConn(conn net.Conn) error {
|
func (s *CommandServer) handleLogConn(conn net.Conn) error {
|
||||||
var (
|
var (
|
||||||
interval int64
|
interval int64
|
||||||
|
@ -67,8 +58,24 @@ func (s *CommandServer) handleLogConn(conn net.Conn) error {
|
||||||
}
|
}
|
||||||
defer s.observer.UnSubscribe(subscription)
|
defer s.observer.UnSubscribe(subscription)
|
||||||
writer := bufio.NewWriter(conn)
|
writer := bufio.NewWriter(conn)
|
||||||
|
select {
|
||||||
|
case <-s.logReset:
|
||||||
|
err = writer.WriteByte(1)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = writer.Flush()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
if len(savedLines) > 0 {
|
if len(savedLines) > 0 {
|
||||||
err = writeLog(writer, savedLines)
|
err = writer.WriteByte(0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = varbin.Write(writer, binary.BigEndian, savedLines)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -76,11 +83,15 @@ func (s *CommandServer) handleLogConn(conn net.Conn) error {
|
||||||
ctx := connKeepAlive(conn)
|
ctx := connKeepAlive(conn)
|
||||||
var logLines []string
|
var logLines []string
|
||||||
for {
|
for {
|
||||||
|
err = writer.Flush()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
case <-s.logReset:
|
case <-s.logReset:
|
||||||
err = writeClearLog(writer)
|
err = writer.WriteByte(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -99,7 +110,11 @@ func (s *CommandServer) handleLogConn(conn net.Conn) error {
|
||||||
break loopLogs
|
break loopLogs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = writeLog(writer, logLines)
|
err = writer.WriteByte(0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = varbin.Write(writer, binary.BigEndian, logLines)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -110,8 +125,7 @@ func (s *CommandServer) handleLogConn(conn net.Conn) error {
|
||||||
func (c *CommandClient) handleLogConn(conn net.Conn) {
|
func (c *CommandClient) handleLogConn(conn net.Conn) {
|
||||||
reader := bufio.NewReader(conn)
|
reader := bufio.NewReader(conn)
|
||||||
for {
|
for {
|
||||||
var messageType uint8
|
messageType, err := reader.ReadByte()
|
||||||
err := binary.Read(reader, binary.BigEndian, &messageType)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.handler.Disconnected(err.Error())
|
c.handler.Disconnected(err.Error())
|
||||||
return
|
return
|
||||||
|
@ -119,7 +133,7 @@ func (c *CommandClient) handleLogConn(conn net.Conn) {
|
||||||
var messages []string
|
var messages []string
|
||||||
switch messageType {
|
switch messageType {
|
||||||
case 0:
|
case 0:
|
||||||
err = binary.ReadData(reader, binary.BigEndian, &messages)
|
err = varbin.Read(reader, binary.BigEndian, &messages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.handler.Disconnected(err.Error())
|
c.handler.Disconnected(err.Error())
|
||||||
return
|
return
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/varbin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *CommandClient) ServiceReload() error {
|
func (c *CommandClient) ServiceReload() error {
|
||||||
|
@ -24,7 +24,7 @@ func (c *CommandClient) ServiceReload() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if hasError {
|
if hasError {
|
||||||
errorMessage, err := rw.ReadVString(conn)
|
errorMessage, err := varbin.ReadValue[string](conn, binary.BigEndian)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ func (s *CommandServer) handleServiceReload(conn net.Conn) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if rErr != nil {
|
if rErr != nil {
|
||||||
return rw.WriteVString(conn, rErr.Error())
|
return varbin.Write(conn, binary.BigEndian, rErr.Error())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ func (c *CommandClient) ServiceClose() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if hasError {
|
if hasError {
|
||||||
errorMessage, err := rw.ReadVString(conn)
|
errorMessage, err := varbin.ReadValue[string](conn, binary.BigEndian)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ func (s *CommandServer) handleServiceClose(conn net.Conn) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if rErr != nil {
|
if rErr != nil {
|
||||||
return rw.WriteVString(conn, rErr.Error())
|
return varbin.Write(conn, binary.BigEndian, rErr.Error())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/outbound"
|
"github.com/sagernet/sing-box/outbound"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/varbin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *CommandClient) SelectOutbound(groupTag string, outboundTag string) error {
|
func (c *CommandClient) SelectOutbound(groupTag string, outboundTag string) error {
|
||||||
|
@ -19,11 +19,11 @@ func (c *CommandClient) SelectOutbound(groupTag string, outboundTag string) erro
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = rw.WriteVString(conn, groupTag)
|
err = varbin.Write(conn, binary.BigEndian, groupTag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = rw.WriteVString(conn, outboundTag)
|
err = varbin.Write(conn, binary.BigEndian, outboundTag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -31,11 +31,11 @@ func (c *CommandClient) SelectOutbound(groupTag string, outboundTag string) erro
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommandServer) handleSelectOutbound(conn net.Conn) error {
|
func (s *CommandServer) handleSelectOutbound(conn net.Conn) error {
|
||||||
groupTag, err := rw.ReadVString(conn)
|
groupTag, err := varbin.ReadValue[string](conn, binary.BigEndian)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
outboundTag, err := rw.ReadVString(conn)
|
outboundTag, err := varbin.ReadValue[string](conn, binary.BigEndian)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,14 +66,6 @@ func (s *CommandServer) SetService(newService *BoxService) {
|
||||||
s.notifyURLTestUpdate()
|
s.notifyURLTestUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommandServer) ResetLog() {
|
|
||||||
s.savedLines.Init()
|
|
||||||
select {
|
|
||||||
case s.logReset <- struct{}{}:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CommandServer) notifyURLTestUpdate() {
|
func (s *CommandServer) notifyURLTestUpdate() {
|
||||||
select {
|
select {
|
||||||
case s.urlTestUpdate <- struct{}{}:
|
case s.urlTestUpdate <- struct{}{}:
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/varbin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func readError(reader io.Reader) error {
|
func readError(reader io.Reader) error {
|
||||||
|
@ -15,7 +15,7 @@ func readError(reader io.Reader) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if hasError {
|
if hasError {
|
||||||
errorMessage, err := rw.ReadVString(reader)
|
errorMessage, err := varbin.ReadValue[string](reader, binary.BigEndian)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ func writeError(writer io.Writer, wErr error) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if wErr != nil {
|
if wErr != nil {
|
||||||
err = rw.WriteVString(writer, wErr.Error())
|
err = varbin.Write(writer, binary.BigEndian, wErr.Error())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/batch"
|
"github.com/sagernet/sing/common/batch"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/varbin"
|
||||||
"github.com/sagernet/sing/service"
|
"github.com/sagernet/sing/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ func (c *CommandClient) URLTest(groupTag string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = rw.WriteVString(conn, groupTag)
|
err = varbin.Write(conn, binary.BigEndian, groupTag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ func (c *CommandClient) URLTest(groupTag string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommandServer) handleURLTest(conn net.Conn) error {
|
func (s *CommandServer) handleURLTest(conn net.Conn) error {
|
||||||
groupTag, err := rw.ReadVString(conn)
|
groupTag, err := varbin.ReadValue[string](conn, binary.BigEndian)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
|
||||||
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/varbin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func EncodeChunkedMessage(data []byte) []byte {
|
func EncodeChunkedMessage(data []byte) []byte {
|
||||||
|
@ -35,13 +35,13 @@ type ErrorMessage struct {
|
||||||
func (e *ErrorMessage) Encode() []byte {
|
func (e *ErrorMessage) Encode() []byte {
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
buffer.WriteByte(MessageTypeError)
|
buffer.WriteByte(MessageTypeError)
|
||||||
rw.WriteVString(&buffer, e.Message)
|
varbin.Write(&buffer, binary.BigEndian, e.Message)
|
||||||
return buffer.Bytes()
|
return buffer.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeErrorMessage(data []byte) (*ErrorMessage, error) {
|
func DecodeErrorMessage(data []byte) (*ErrorMessage, error) {
|
||||||
reader := bytes.NewReader(data)
|
reader := bytes.NewReader(data)
|
||||||
messageType, err := rw.ReadByte(reader)
|
messageType, err := reader.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ func DecodeErrorMessage(data []byte) (*ErrorMessage, error) {
|
||||||
return nil, E.New("invalid message")
|
return nil, E.New("invalid message")
|
||||||
}
|
}
|
||||||
var message ErrorMessage
|
var message ErrorMessage
|
||||||
message.Message, err = rw.ReadVString(reader)
|
message.Message, err = varbin.ReadValue[string](reader, binary.BigEndian)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ func (e *ProfileEncoder) Encode() []byte {
|
||||||
binary.Write(&buffer, binary.BigEndian, uint16(len(e.profiles)))
|
binary.Write(&buffer, binary.BigEndian, uint16(len(e.profiles)))
|
||||||
for _, preview := range e.profiles {
|
for _, preview := range e.profiles {
|
||||||
binary.Write(&buffer, binary.BigEndian, preview.ProfileID)
|
binary.Write(&buffer, binary.BigEndian, preview.ProfileID)
|
||||||
rw.WriteVString(&buffer, preview.Name)
|
varbin.Write(&buffer, binary.BigEndian, preview.Name)
|
||||||
binary.Write(&buffer, binary.BigEndian, preview.Type)
|
binary.Write(&buffer, binary.BigEndian, preview.Type)
|
||||||
}
|
}
|
||||||
return buffer.Bytes()
|
return buffer.Bytes()
|
||||||
|
@ -117,7 +117,7 @@ func (d *ProfileDecoder) Decode(data []byte) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
profile.Name, err = rw.ReadVString(reader)
|
profile.Name, err = varbin.ReadValue[string](reader, binary.BigEndian)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ func (r *ProfileContentRequest) Encode() []byte {
|
||||||
|
|
||||||
func DecodeProfileContentRequest(data []byte) (*ProfileContentRequest, error) {
|
func DecodeProfileContentRequest(data []byte) (*ProfileContentRequest, error) {
|
||||||
reader := bytes.NewReader(data)
|
reader := bytes.NewReader(data)
|
||||||
messageType, err := rw.ReadByte(reader)
|
messageType, err := reader.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -176,12 +176,13 @@ func (c *ProfileContent) Encode() []byte {
|
||||||
buffer := new(bytes.Buffer)
|
buffer := new(bytes.Buffer)
|
||||||
buffer.WriteByte(MessageTypeProfileContent)
|
buffer.WriteByte(MessageTypeProfileContent)
|
||||||
buffer.WriteByte(1)
|
buffer.WriteByte(1)
|
||||||
writer := gzip.NewWriter(buffer)
|
gWriter := gzip.NewWriter(buffer)
|
||||||
rw.WriteVString(writer, c.Name)
|
writer := bufio.NewWriter(gWriter)
|
||||||
|
varbin.Write(writer, binary.BigEndian, c.Name)
|
||||||
binary.Write(writer, binary.BigEndian, c.Type)
|
binary.Write(writer, binary.BigEndian, c.Type)
|
||||||
rw.WriteVString(writer, c.Config)
|
varbin.Write(writer, binary.BigEndian, c.Config)
|
||||||
if c.Type != ProfileTypeLocal {
|
if c.Type != ProfileTypeLocal {
|
||||||
rw.WriteVString(writer, c.RemotePath)
|
varbin.Write(writer, binary.BigEndian, c.RemotePath)
|
||||||
}
|
}
|
||||||
if c.Type == ProfileTypeRemote {
|
if c.Type == ProfileTypeRemote {
|
||||||
binary.Write(writer, binary.BigEndian, c.AutoUpdate)
|
binary.Write(writer, binary.BigEndian, c.AutoUpdate)
|
||||||
|
@ -189,29 +190,31 @@ func (c *ProfileContent) Encode() []byte {
|
||||||
binary.Write(writer, binary.BigEndian, c.LastUpdated)
|
binary.Write(writer, binary.BigEndian, c.LastUpdated)
|
||||||
}
|
}
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
writer.Close()
|
gWriter.Flush()
|
||||||
|
gWriter.Close()
|
||||||
return buffer.Bytes()
|
return buffer.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeProfileContent(data []byte) (*ProfileContent, error) {
|
func DecodeProfileContent(data []byte) (*ProfileContent, error) {
|
||||||
var reader io.Reader = bytes.NewReader(data)
|
reader := bytes.NewReader(data)
|
||||||
messageType, err := rw.ReadByte(reader)
|
messageType, err := reader.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if messageType != MessageTypeProfileContent {
|
if messageType != MessageTypeProfileContent {
|
||||||
return nil, E.New("invalid message")
|
return nil, E.New("invalid message")
|
||||||
}
|
}
|
||||||
version, err := rw.ReadByte(reader)
|
version, err := reader.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reader, err = gzip.NewReader(reader)
|
gReader, err := gzip.NewReader(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "unsupported profile")
|
return nil, E.Cause(err, "unsupported profile")
|
||||||
}
|
}
|
||||||
|
bReader := varbin.StubReader(gReader)
|
||||||
var content ProfileContent
|
var content ProfileContent
|
||||||
content.Name, err = rw.ReadVString(reader)
|
content.Name, err = varbin.ReadValue[string](bReader, binary.BigEndian)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -219,12 +222,12 @@ func DecodeProfileContent(data []byte) (*ProfileContent, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
content.Config, err = rw.ReadVString(reader)
|
content.Config, err = varbin.ReadValue[string](bReader, binary.BigEndian)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if content.Type != ProfileTypeLocal {
|
if content.Type != ProfileTypeLocal {
|
||||||
content.RemotePath, err = rw.ReadVString(reader)
|
content.RemotePath, err = varbin.ReadValue[string](bReader, binary.BigEndian)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package libbox
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
|
"runtime/debug"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -21,6 +22,11 @@ var (
|
||||||
sTVOS bool
|
sTVOS bool
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
debug.SetPanicOnFault(true)
|
||||||
|
debug.SetTraceback("all")
|
||||||
|
}
|
||||||
|
|
||||||
func Setup(basePath string, workingPath string, tempPath string, isTVOS bool) {
|
func Setup(basePath string, workingPath string, tempPath string, isTVOS bool) {
|
||||||
sBasePath = basePath
|
sBasePath = basePath
|
||||||
sWorkingPath = workingPath
|
sWorkingPath = workingPath
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -26,7 +26,7 @@ require (
|
||||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f
|
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f
|
||||||
github.com/sagernet/quic-go v0.45.1-beta.2
|
github.com/sagernet/quic-go v0.45.1-beta.2
|
||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
||||||
github.com/sagernet/sing v0.4.2
|
github.com/sagernet/sing v0.5.0-alpha.13
|
||||||
github.com/sagernet/sing-dns v0.2.3
|
github.com/sagernet/sing-dns v0.2.3
|
||||||
github.com/sagernet/sing-mux v0.2.0
|
github.com/sagernet/sing-mux v0.2.0
|
||||||
github.com/sagernet/sing-quic v0.2.0-beta.12
|
github.com/sagernet/sing-quic v0.2.0-beta.12
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -106,8 +106,8 @@ github.com/sagernet/quic-go v0.45.1-beta.2/go.mod h1:+N3FqM9DAzOWfe64uxXuBejVJwX
|
||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||||
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
||||||
github.com/sagernet/sing v0.4.2 h1:jzGNJdZVRI0xlAfFugsIQUPvyB9SuWvbJK7zQCXc4QM=
|
github.com/sagernet/sing v0.5.0-alpha.13 h1:fpR4TFZfu/9V3LbHSAnnnwcaXGMF8ijmAAPoY2WHSKw=
|
||||||
github.com/sagernet/sing v0.4.2/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls=
|
github.com/sagernet/sing v0.5.0-alpha.13/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||||
github.com/sagernet/sing-dns v0.2.3 h1:YzeBUn2tR38F7HtvGEQ0kLRLmZWMEgi/+7wqa4Twb1k=
|
github.com/sagernet/sing-dns v0.2.3 h1:YzeBUn2tR38F7HtvGEQ0kLRLmZWMEgi/+7wqa4Twb1k=
|
||||||
github.com/sagernet/sing-dns v0.2.3/go.mod h1:BJpJv6XLnrUbSyIntOT6DG9FW0f4fETmPAHvNjOprLg=
|
github.com/sagernet/sing-dns v0.2.3/go.mod h1:BJpJv6XLnrUbSyIntOT6DG9FW0f4fETmPAHvNjOprLg=
|
||||||
github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo=
|
github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo=
|
||||||
|
|
|
@ -12,10 +12,7 @@ import (
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing/common/auth"
|
"github.com/sagernet/sing/common/auth"
|
||||||
"github.com/sagernet/sing/common/buf"
|
|
||||||
"github.com/sagernet/sing/common/bufio"
|
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
"github.com/sagernet/sing/common/rw"
|
|
||||||
"github.com/sagernet/sing/protocol/http"
|
"github.com/sagernet/sing/protocol/http"
|
||||||
"github.com/sagernet/sing/protocol/socks"
|
"github.com/sagernet/sing/protocol/socks"
|
||||||
"github.com/sagernet/sing/protocol/socks/socks4"
|
"github.com/sagernet/sing/protocol/socks/socks4"
|
||||||
|
@ -51,17 +48,18 @@ func NewMixed(ctx context.Context, router adapter.Router, logger log.ContextLogg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Mixed) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
func (h *Mixed) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||||
headerType, err := rw.ReadByte(conn)
|
reader := std_bufio.NewReader(conn)
|
||||||
|
headerBytes, err := reader.Peek(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
switch headerType {
|
switch headerBytes[0] {
|
||||||
case socks4.Version, socks5.Version:
|
case socks4.Version, socks5.Version:
|
||||||
return socks.HandleConnection0(ctx, conn, headerType, h.authenticator, h.upstreamUserHandler(metadata), adapter.UpstreamMetadata(metadata))
|
return socks.HandleConnection0(ctx, conn, reader, h.authenticator, h.upstreamUserHandler(metadata), adapter.UpstreamMetadata(metadata))
|
||||||
}
|
default:
|
||||||
reader := std_bufio.NewReader(bufio.NewCachedReader(conn, buf.As([]byte{headerType})))
|
|
||||||
return http.HandleConnection(ctx, conn, reader, h.authenticator, h.upstreamUserHandler(metadata), adapter.UpstreamMetadata(metadata))
|
return http.HandleConnection(ctx, conn, reader, h.authenticator, h.upstreamUserHandler(metadata), adapter.UpstreamMetadata(metadata))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Mixed) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
func (h *Mixed) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||||
return os.ErrInvalid
|
return os.ErrInvalid
|
||||||
|
|
|
@ -83,13 +83,12 @@ func NewVLESS(ctx context.Context, router adapter.Router, logger log.ContextLogg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *VLESS) Start() error {
|
func (h *VLESS) Start() error {
|
||||||
err := common.Start(
|
if h.tlsConfig != nil {
|
||||||
h.service,
|
err := h.tlsConfig.Start()
|
||||||
h.tlsConfig,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if h.transport == nil {
|
if h.transport == nil {
|
||||||
return h.myInboundAdapter.Start()
|
return h.myInboundAdapter.Start()
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,13 +93,16 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *VMess) Start() error {
|
func (h *VMess) Start() error {
|
||||||
err := common.Start(
|
err := h.service.Start()
|
||||||
h.service,
|
|
||||||
h.tlsConfig,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if h.tlsConfig != nil {
|
||||||
|
err = h.tlsConfig.Start()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
if h.transport == nil {
|
if h.transport == nil {
|
||||||
return h.myInboundAdapter.Start()
|
return h.myInboundAdapter.Start()
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ type DialerOptions struct {
|
||||||
Inet4BindAddress *ListenAddress `json:"inet4_bind_address,omitempty"`
|
Inet4BindAddress *ListenAddress `json:"inet4_bind_address,omitempty"`
|
||||||
Inet6BindAddress *ListenAddress `json:"inet6_bind_address,omitempty"`
|
Inet6BindAddress *ListenAddress `json:"inet6_bind_address,omitempty"`
|
||||||
ProtectPath string `json:"protect_path,omitempty"`
|
ProtectPath string `json:"protect_path,omitempty"`
|
||||||
RoutingMark int `json:"routing_mark,omitempty"`
|
RoutingMark uint32 `json:"routing_mark,omitempty"`
|
||||||
ReuseAddr bool `json:"reuse_addr,omitempty"`
|
ReuseAddr bool `json:"reuse_addr,omitempty"`
|
||||||
ConnectTimeout Duration `json:"connect_timeout,omitempty"`
|
ConnectTimeout Duration `json:"connect_timeout,omitempty"`
|
||||||
TCPFastOpen bool `json:"tcp_fast_open,omitempty"`
|
TCPFastOpen bool `json:"tcp_fast_open,omitempty"`
|
||||||
|
|
|
@ -10,7 +10,7 @@ type RouteOptions struct {
|
||||||
AutoDetectInterface bool `json:"auto_detect_interface,omitempty"`
|
AutoDetectInterface bool `json:"auto_detect_interface,omitempty"`
|
||||||
OverrideAndroidVPN bool `json:"override_android_vpn,omitempty"`
|
OverrideAndroidVPN bool `json:"override_android_vpn,omitempty"`
|
||||||
DefaultInterface string `json:"default_interface,omitempty"`
|
DefaultInterface string `json:"default_interface,omitempty"`
|
||||||
DefaultMark int `json:"default_mark,omitempty"`
|
DefaultMark uint32 `json:"default_mark,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GeoIPOptions struct {
|
type GeoIPOptions struct {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package outbound
|
package outbound
|
||||||
|
|
||||||
import (
|
import (
|
||||||
std_bufio "bufio"
|
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
@ -11,16 +10,10 @@ import (
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing/common"
|
"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/bufio"
|
|
||||||
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"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
"github.com/sagernet/sing/common/rw"
|
|
||||||
"github.com/sagernet/sing/protocol/http"
|
|
||||||
"github.com/sagernet/sing/protocol/socks"
|
"github.com/sagernet/sing/protocol/socks"
|
||||||
"github.com/sagernet/sing/protocol/socks/socks4"
|
|
||||||
"github.com/sagernet/sing/protocol/socks/socks5"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProxyListener struct {
|
type ProxyListener struct {
|
||||||
|
@ -102,16 +95,7 @@ func (l *ProxyListener) acceptLoop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *ProxyListener) accept(ctx context.Context, conn *net.TCPConn) error {
|
func (l *ProxyListener) accept(ctx context.Context, conn *net.TCPConn) error {
|
||||||
headerType, err := rw.ReadByte(conn)
|
return socks.HandleConnection(ctx, conn, l.authenticator, l, M.Metadata{})
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
switch headerType {
|
|
||||||
case socks4.Version, socks5.Version:
|
|
||||||
return socks.HandleConnection0(ctx, conn, headerType, l.authenticator, l, M.Metadata{})
|
|
||||||
}
|
|
||||||
reader := std_bufio.NewReader(bufio.NewCachedReader(conn, buf.As([]byte{headerType})))
|
|
||||||
return http.HandleConnection(ctx, conn, reader, l.authenticator, l, M.Metadata{})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *ProxyListener) NewConnection(ctx context.Context, conn net.Conn, upstreamMetadata M.Metadata) error {
|
func (l *ProxyListener) NewConnection(ctx context.Context, conn net.Conn, upstreamMetadata M.Metadata) error {
|
||||||
|
|
|
@ -44,10 +44,10 @@ func NewTor(ctx context.Context, router adapter.Router, logger log.ContextLogger
|
||||||
startConf.ExtraArgs = options.ExtraArgs
|
startConf.ExtraArgs = options.ExtraArgs
|
||||||
if options.DataDirectory != "" {
|
if options.DataDirectory != "" {
|
||||||
dataDirAbs, _ := filepath.Abs(startConf.DataDir)
|
dataDirAbs, _ := filepath.Abs(startConf.DataDir)
|
||||||
if geoIPPath := filepath.Join(dataDirAbs, "geoip"); rw.FileExists(geoIPPath) && !common.Contains(options.ExtraArgs, "--GeoIPFile") {
|
if geoIPPath := filepath.Join(dataDirAbs, "geoip"); rw.IsFile(geoIPPath) && !common.Contains(options.ExtraArgs, "--GeoIPFile") {
|
||||||
options.ExtraArgs = append(options.ExtraArgs, "--GeoIPFile", geoIPPath)
|
options.ExtraArgs = append(options.ExtraArgs, "--GeoIPFile", geoIPPath)
|
||||||
}
|
}
|
||||||
if geoIP6Path := filepath.Join(dataDirAbs, "geoip6"); rw.FileExists(geoIP6Path) && !common.Contains(options.ExtraArgs, "--GeoIPv6File") {
|
if geoIP6Path := filepath.Join(dataDirAbs, "geoip6"); rw.IsFile(geoIP6Path) && !common.Contains(options.ExtraArgs, "--GeoIPv6File") {
|
||||||
options.ExtraArgs = append(options.ExtraArgs, "--GeoIPv6File", geoIP6Path)
|
options.ExtraArgs = append(options.ExtraArgs, "--GeoIPv6File", geoIP6Path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,8 +58,12 @@ func NewTor(ctx context.Context, router adapter.Router, logger log.ContextLogger
|
||||||
}
|
}
|
||||||
if startConf.DataDir != "" {
|
if startConf.DataDir != "" {
|
||||||
torrcFile := filepath.Join(startConf.DataDir, "torrc")
|
torrcFile := filepath.Join(startConf.DataDir, "torrc")
|
||||||
if !rw.FileExists(torrcFile) {
|
err := rw.MkdirParent(torrcFile)
|
||||||
err := rw.WriteFile(torrcFile, []byte(""))
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !rw.IsFile(torrcFile) {
|
||||||
|
err := os.WriteFile(torrcFile, []byte(""), 0o600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ type Router struct {
|
||||||
interfaceFinder *control.DefaultInterfaceFinder
|
interfaceFinder *control.DefaultInterfaceFinder
|
||||||
autoDetectInterface bool
|
autoDetectInterface bool
|
||||||
defaultInterface string
|
defaultInterface string
|
||||||
defaultMark int
|
defaultMark uint32
|
||||||
networkMonitor tun.NetworkUpdateMonitor
|
networkMonitor tun.NetworkUpdateMonitor
|
||||||
interfaceMonitor tun.DefaultInterfaceMonitor
|
interfaceMonitor tun.DefaultInterfaceMonitor
|
||||||
packageManager tun.PackageManager
|
packageManager tun.PackageManager
|
||||||
|
@ -1136,7 +1136,7 @@ func (r *Router) DefaultInterface() string {
|
||||||
return r.defaultInterface
|
return r.defaultInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) DefaultMark() int {
|
func (r *Router) DefaultMark() uint32 {
|
||||||
return r.defaultMark
|
return r.defaultMark
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ func (r *Router) prepareGeoIPDatabase() error {
|
||||||
geoPath = foundPath
|
geoPath = foundPath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !rw.FileExists(geoPath) {
|
if !rw.IsFile(geoPath) {
|
||||||
geoPath = filemanager.BasePath(r.ctx, geoPath)
|
geoPath = filemanager.BasePath(r.ctx, geoPath)
|
||||||
}
|
}
|
||||||
if stat, err := os.Stat(geoPath); err == nil {
|
if stat, err := os.Stat(geoPath); err == nil {
|
||||||
|
@ -61,7 +61,7 @@ func (r *Router) prepareGeoIPDatabase() error {
|
||||||
os.Remove(geoPath)
|
os.Remove(geoPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !rw.FileExists(geoPath) {
|
if !rw.IsFile(geoPath) {
|
||||||
r.logger.Warn("geoip database not exists: ", geoPath)
|
r.logger.Warn("geoip database not exists: ", geoPath)
|
||||||
var err error
|
var err error
|
||||||
for attempts := 0; attempts < 3; attempts++ {
|
for attempts := 0; attempts < 3; attempts++ {
|
||||||
|
@ -96,7 +96,7 @@ func (r *Router) prepareGeositeDatabase() error {
|
||||||
geoPath = foundPath
|
geoPath = foundPath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !rw.FileExists(geoPath) {
|
if !rw.IsFile(geoPath) {
|
||||||
geoPath = filemanager.BasePath(r.ctx, geoPath)
|
geoPath = filemanager.BasePath(r.ctx, geoPath)
|
||||||
}
|
}
|
||||||
if stat, err := os.Stat(geoPath); err == nil {
|
if stat, err := os.Stat(geoPath); err == nil {
|
||||||
|
@ -107,7 +107,7 @@ func (r *Router) prepareGeositeDatabase() error {
|
||||||
os.Remove(geoPath)
|
os.Remove(geoPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !rw.FileExists(geoPath) {
|
if !rw.IsFile(geoPath) {
|
||||||
r.logger.Warn("geosite database not exists: ", geoPath)
|
r.logger.Warn("geosite database not exists: ", geoPath)
|
||||||
var err error
|
var err error
|
||||||
for attempts := 0; attempts < 3; attempts++ {
|
for attempts := 0; attempts < 3; attempts++ {
|
||||||
|
|
|
@ -29,11 +29,15 @@ func (r *abstractDefaultRule) Type() string {
|
||||||
|
|
||||||
func (r *abstractDefaultRule) Start() error {
|
func (r *abstractDefaultRule) Start() error {
|
||||||
for _, item := range r.allItems {
|
for _, item := range r.allItems {
|
||||||
err := common.Start(item)
|
if starter, isStarter := item.(interface {
|
||||||
|
Start() error
|
||||||
|
}); isStarter {
|
||||||
|
err := starter.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,8 +187,13 @@ func (r *abstractLogicalRule) UpdateGeosite() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *abstractLogicalRule) Start() error {
|
func (r *abstractLogicalRule) Start() error {
|
||||||
for _, rule := range common.FilterIsInstance(r.rules, func(it adapter.HeadlessRule) (common.Starter, bool) {
|
for _, rule := range common.FilterIsInstance(r.rules, func(it adapter.HeadlessRule) (interface {
|
||||||
rule, loaded := it.(common.Starter)
|
Start() error
|
||||||
|
}, bool,
|
||||||
|
) {
|
||||||
|
rule, loaded := it.(interface {
|
||||||
|
Start() error
|
||||||
|
})
|
||||||
return rule, loaded
|
return rule, loaded
|
||||||
}) {
|
}) {
|
||||||
err := rule.Start()
|
err := rule.Start()
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package trojan
|
package trojan
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
std_bufio "bufio"
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
"github.com/sagernet/sing/common/bufio"
|
||||||
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/rw"
|
|
||||||
"github.com/sagernet/sing/common/task"
|
"github.com/sagernet/sing/common/task"
|
||||||
"github.com/sagernet/smux"
|
"github.com/sagernet/smux"
|
||||||
)
|
)
|
||||||
|
@ -33,27 +35,36 @@ func HandleMuxConnection(ctx context.Context, conn net.Conn, metadata M.Metadata
|
||||||
return group.Run(ctx)
|
return group.Run(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMuxConnection(ctx context.Context, stream net.Conn, metadata M.Metadata, handler Handler) {
|
func newMuxConnection(ctx context.Context, conn net.Conn, metadata M.Metadata, handler Handler) {
|
||||||
err := newMuxConnection0(ctx, stream, metadata, handler)
|
err := newMuxConnection0(ctx, conn, metadata, handler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handler.NewError(ctx, E.Cause(err, "process trojan-go multiplex connection"))
|
handler.NewError(ctx, E.Cause(err, "process trojan-go multiplex connection"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMuxConnection0(ctx context.Context, stream net.Conn, metadata M.Metadata, handler Handler) error {
|
func newMuxConnection0(ctx context.Context, conn net.Conn, metadata M.Metadata, handler Handler) error {
|
||||||
command, err := rw.ReadByte(stream)
|
reader := std_bufio.NewReader(conn)
|
||||||
|
command, err := reader.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "read command")
|
return E.Cause(err, "read command")
|
||||||
}
|
}
|
||||||
metadata.Destination, err = M.SocksaddrSerializer.ReadAddrPort(stream)
|
metadata.Destination, err = M.SocksaddrSerializer.ReadAddrPort(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "read destination")
|
return E.Cause(err, "read destination")
|
||||||
}
|
}
|
||||||
|
if reader.Buffered() > 0 {
|
||||||
|
buffer := buf.NewSize(reader.Buffered())
|
||||||
|
_, err = buffer.ReadFullFrom(reader, buffer.Len())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
conn = bufio.NewCachedConn(conn, buffer)
|
||||||
|
}
|
||||||
switch command {
|
switch command {
|
||||||
case CommandTCP:
|
case CommandTCP:
|
||||||
return handler.NewConnection(ctx, stream, metadata)
|
return handler.NewConnection(ctx, conn, metadata)
|
||||||
case CommandUDP:
|
case CommandUDP:
|
||||||
return handler.NewPacketConnection(ctx, &PacketConn{Conn: stream}, metadata)
|
return handler.NewPacketConnection(ctx, &PacketConn{Conn: conn}, metadata)
|
||||||
default:
|
default:
|
||||||
return E.New("unknown command ", command)
|
return E.New("unknown command ", command)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package trojan
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/binary"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/sagernet/sing/common/auth"
|
"github.com/sagernet/sing/common/auth"
|
||||||
|
@ -76,7 +77,8 @@ func (s *Service[K]) NewConnection(ctx context.Context, conn net.Conn, metadata
|
||||||
return E.Cause(err, "skip crlf")
|
return E.Cause(err, "skip crlf")
|
||||||
}
|
}
|
||||||
|
|
||||||
command, err := rw.ReadByte(conn)
|
var command byte
|
||||||
|
err = binary.Read(conn, binary.BigEndian, &command)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "read command")
|
return E.Cause(err, "read command")
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/baderror"
|
"github.com/sagernet/sing/common/baderror"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
"github.com/sagernet/sing/common/rw"
|
N "github.com/sagernet/sing/common/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ net.Conn = (*GRPCConn)(nil)
|
var _ net.Conn = (*GRPCConn)(nil)
|
||||||
|
@ -90,7 +90,7 @@ func (c *GRPCConn) Upstream() any {
|
||||||
return c.GunService
|
return c.GunService
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ rw.WriteCloser = (*clientConnWrapper)(nil)
|
var _ N.WriteCloser = (*clientConnWrapper)(nil)
|
||||||
|
|
||||||
type clientConnWrapper struct {
|
type clientConnWrapper struct {
|
||||||
GunService_TunClient
|
GunService_TunClient
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
"github.com/sagernet/sing/common/baderror"
|
"github.com/sagernet/sing/common/baderror"
|
||||||
"github.com/sagernet/sing/common/buf"
|
"github.com/sagernet/sing/common/buf"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/varbin"
|
||||||
)
|
)
|
||||||
|
|
||||||
// kanged from: https://github.com/Qv2ray/gun-lite
|
// kanged from: https://github.com/Qv2ray/gun-lite
|
||||||
|
@ -96,7 +96,7 @@ func (c *GunConn) read(b []byte) (n int, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GunConn) Write(b []byte) (n int, err error) {
|
func (c *GunConn) Write(b []byte) (n int, err error) {
|
||||||
varLen := rw.UVariantLen(uint64(len(b)))
|
varLen := varbin.UvarintLen(uint64(len(b)))
|
||||||
buffer := buf.NewSize(6 + varLen + len(b))
|
buffer := buf.NewSize(6 + varLen + len(b))
|
||||||
header := buffer.Extend(6 + varLen)
|
header := buffer.Extend(6 + varLen)
|
||||||
header[0] = 0x00
|
header[0] = 0x00
|
||||||
|
@ -117,13 +117,13 @@ func (c *GunConn) Write(b []byte) (n int, err error) {
|
||||||
func (c *GunConn) WriteBuffer(buffer *buf.Buffer) error {
|
func (c *GunConn) WriteBuffer(buffer *buf.Buffer) error {
|
||||||
defer buffer.Release()
|
defer buffer.Release()
|
||||||
dataLen := buffer.Len()
|
dataLen := buffer.Len()
|
||||||
varLen := rw.UVariantLen(uint64(dataLen))
|
varLen := varbin.UvarintLen(uint64(dataLen))
|
||||||
header := buffer.ExtendHeader(6 + varLen)
|
header := buffer.ExtendHeader(6 + varLen)
|
||||||
header[0] = 0x00
|
header[0] = 0x00
|
||||||
binary.BigEndian.PutUint32(header[1:5], uint32(1+varLen+dataLen))
|
binary.BigEndian.PutUint32(header[1:5], uint32(1+varLen+dataLen))
|
||||||
header[5] = 0x0A
|
header[5] = 0x0A
|
||||||
binary.PutUvarint(header[6:], uint64(dataLen))
|
binary.PutUvarint(header[6:], uint64(dataLen))
|
||||||
err := rw.WriteBytes(c.writer, buffer.Bytes())
|
err := common.Error(c.writer.Write(buffer.Bytes()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return baderror.WrapH2(err)
|
return baderror.WrapH2(err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue