mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-07-22 23:33:29 +03:00
Fix lint errors
This commit is contained in:
2
Makefile
2
Makefile
@@ -46,7 +46,7 @@ lint:
|
|||||||
GOOS=android golangci-lint run ./...
|
GOOS=android golangci-lint run ./...
|
||||||
GOOS=windows golangci-lint run ./...
|
GOOS=windows golangci-lint run ./...
|
||||||
GOOS=darwin golangci-lint run ./...
|
GOOS=darwin golangci-lint run ./...
|
||||||
GOOS=freebsd golangci-lint run ./...
|
# GOOS=freebsd golangci-lint run ./...
|
||||||
|
|
||||||
lint_install:
|
lint_install:
|
||||||
go install -v github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
go install -v github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ func GetRuntimeEnv(key string) (string, error) {
|
|||||||
if readErr != nil {
|
if readErr != nil {
|
||||||
return "", readErr
|
return "", readErr
|
||||||
}
|
}
|
||||||
envStrings := strings.Split(string(data), "\n")
|
envStrings := strings.SplitSeq(string(data), "\n")
|
||||||
for _, envItem := range envStrings {
|
for envItem := range envStrings {
|
||||||
envItem = strings.TrimSuffix(envItem, "\r")
|
envItem = strings.TrimSuffix(envItem, "\r")
|
||||||
envKeyValue := strings.Split(envItem, "=")
|
envKeyValue := strings.Split(envItem, "=")
|
||||||
if strings.EqualFold(strings.TrimSpace(envKeyValue[0]), key) {
|
if strings.EqualFold(strings.TrimSpace(envKeyValue[0]), key) {
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func main() {
|
|||||||
common.Must(os.Chdir(androidPath))
|
common.Must(os.Chdir(androidPath))
|
||||||
localProps := common.Must1(os.ReadFile("version.properties"))
|
localProps := common.Must1(os.ReadFile("version.properties"))
|
||||||
var propsList [][]string
|
var propsList [][]string
|
||||||
for _, propLine := range strings.Split(string(localProps), "\n") {
|
for propLine := range strings.SplitSeq(string(localProps), "\n") {
|
||||||
propsList = append(propsList, strings.Split(propLine, "="))
|
propsList = append(propsList, strings.Split(propLine, "="))
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -61,16 +61,17 @@ func geoipExport(countryCode string) error {
|
|||||||
outputFile *os.File
|
outputFile *os.File
|
||||||
outputWriter io.Writer
|
outputWriter io.Writer
|
||||||
)
|
)
|
||||||
if flagGeoipExportOutput == "stdout" {
|
switch flagGeoipExportOutput {
|
||||||
|
case "stdout":
|
||||||
outputWriter = os.Stdout
|
outputWriter = os.Stdout
|
||||||
} else if flagGeoipExportOutput == flagGeoipExportDefaultOutput {
|
case flagGeoipExportDefaultOutput:
|
||||||
outputFile, err = os.Create("geoip-" + countryCode + ".json")
|
outputFile, err = os.Create("geoip-" + countryCode + ".json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer outputFile.Close()
|
defer outputFile.Close()
|
||||||
outputWriter = outputFile
|
outputWriter = outputFile
|
||||||
} else {
|
default:
|
||||||
outputFile, err = os.Create(flagGeoipExportOutput)
|
outputFile, err = os.Create(flagGeoipExportOutput)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -43,16 +43,17 @@ func geositeExport(category string) error {
|
|||||||
outputFile *os.File
|
outputFile *os.File
|
||||||
outputWriter io.Writer
|
outputWriter io.Writer
|
||||||
)
|
)
|
||||||
if commandGeositeExportOutput == "stdout" {
|
switch commandGeositeExportOutput {
|
||||||
|
case "stdout":
|
||||||
outputWriter = os.Stdout
|
outputWriter = os.Stdout
|
||||||
} else if commandGeositeExportOutput == commandGeositeExportDefaultOutput {
|
case commandGeositeExportDefaultOutput:
|
||||||
outputFile, err = os.Create("geosite-" + category + ".json")
|
outputFile, err = os.Create("geosite-" + category + ".json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer outputFile.Close()
|
defer outputFile.Close()
|
||||||
outputWriter = outputFile
|
outputWriter = outputFile
|
||||||
} else {
|
default:
|
||||||
outputFile, err = os.Create(commandGeositeExportOutput)
|
outputFile, err = os.Create(commandGeositeExportOutput)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -112,9 +112,7 @@ func IsValid(versionName string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Parse(versionName string) (version Version) {
|
func Parse(versionName string) (version Version) {
|
||||||
if strings.HasPrefix(versionName, "v") {
|
versionName = strings.TrimPrefix(versionName, "v")
|
||||||
versionName = versionName[1:]
|
|
||||||
}
|
|
||||||
if strings.Contains(versionName, "-") {
|
if strings.Contains(versionName, "-") {
|
||||||
parts := strings.Split(versionName, "-")
|
parts := strings.Split(versionName, "-")
|
||||||
versionName = parts[0]
|
versionName = parts[0]
|
||||||
|
|||||||
@@ -63,9 +63,7 @@ parseLine:
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(ruleLine, "|") {
|
ruleLine = strings.TrimSuffix(ruleLine, "|")
|
||||||
ruleLine = ruleLine[:len(ruleLine)-1]
|
|
||||||
}
|
|
||||||
var (
|
var (
|
||||||
isExclude bool
|
isExclude bool
|
||||||
isSuffix bool
|
isSuffix bool
|
||||||
@@ -76,7 +74,7 @@ parseLine:
|
|||||||
)
|
)
|
||||||
if !strings.HasPrefix(ruleLine, "/") && strings.Contains(ruleLine, "$") {
|
if !strings.HasPrefix(ruleLine, "/") && strings.Contains(ruleLine, "$") {
|
||||||
params := common.SubstringAfter(ruleLine, "$")
|
params := common.SubstringAfter(ruleLine, "$")
|
||||||
for _, param := range strings.Split(params, ",") {
|
for param := range strings.SplitSeq(params, ",") {
|
||||||
paramParts := strings.Split(param, "=")
|
paramParts := strings.Split(param, "=")
|
||||||
var ignored bool
|
var ignored bool
|
||||||
if len(paramParts) > 0 && len(paramParts) <= 2 {
|
if len(paramParts) > 0 && len(paramParts) <= 2 {
|
||||||
@@ -106,9 +104,7 @@ parseLine:
|
|||||||
ruleLine = ruleLine[2:]
|
ruleLine = ruleLine[2:]
|
||||||
isExclude = true
|
isExclude = true
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(ruleLine, "|") {
|
ruleLine = strings.TrimSuffix(ruleLine, "|")
|
||||||
ruleLine = ruleLine[:len(ruleLine)-1]
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(ruleLine, "||") {
|
if strings.HasPrefix(ruleLine, "||") {
|
||||||
ruleLine = ruleLine[2:]
|
ruleLine = ruleLine[2:]
|
||||||
isSuffix = true
|
isSuffix = true
|
||||||
@@ -414,18 +410,18 @@ func ignoreIPCIDRRegexp(ruleLine string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parseAdGuardHostLine(ruleLine string) (string, error) {
|
func parseAdGuardHostLine(ruleLine string) (string, error) {
|
||||||
idx := strings.Index(ruleLine, " ")
|
before, after, ok := strings.Cut(ruleLine, " ")
|
||||||
if idx == -1 {
|
if !ok {
|
||||||
return "", os.ErrInvalid
|
return "", os.ErrInvalid
|
||||||
}
|
}
|
||||||
address, err := netip.ParseAddr(ruleLine[:idx])
|
address, err := netip.ParseAddr(before)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if !address.IsUnspecified() {
|
if !address.IsUnspecified() {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
domain := ruleLine[idx+1:]
|
domain := after
|
||||||
if !M.IsDomainName(domain) {
|
if !M.IsDomainName(domain) {
|
||||||
return "", E.New("invalid domain name: ", domain)
|
return "", E.New("invalid domain name: ", domain)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,18 +136,16 @@ func (d *DefaultDialer) dialParallelInterfaceFastFallback(ctx context.Context, d
|
|||||||
go startRacer(fallbackCtx, false, iif)
|
go startRacer(fallbackCtx, false, iif)
|
||||||
}
|
}
|
||||||
var errors []error
|
var errors []error
|
||||||
for {
|
for res := range results {
|
||||||
select {
|
if res.error == nil {
|
||||||
case res := <-results:
|
return res.Conn, res.primary, nil
|
||||||
if res.error == nil {
|
}
|
||||||
return res.Conn, res.primary, nil
|
errors = append(errors, res.error)
|
||||||
}
|
if len(errors) == len(primaryInterfaces)+len(fallbackInterfaces) {
|
||||||
errors = append(errors, res.error)
|
return nil, false, E.Errors(errors...)
|
||||||
if len(errors) == len(primaryInterfaces)+len(fallbackInterfaces) {
|
|
||||||
return nil, false, E.Errors(errors...)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil, false, E.Errors(errors...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DefaultDialer) listenSerialInterfacePacket(ctx context.Context, listener net.ListenConfig, network string, addr string, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, error) {
|
func (d *DefaultDialer) listenSerialInterfacePacket(ctx context.Context, listener net.ListenConfig, network string, addr string, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, error) {
|
||||||
|
|||||||
@@ -19,11 +19,6 @@ func oldWriteString(writer varbin.Writer, value string) error {
|
|||||||
return varbin.Write(writer, binary.BigEndian, value)
|
return varbin.Write(writer, binary.BigEndian, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func oldWriteItem(writer varbin.Writer, item Item) error {
|
|
||||||
//nolint:staticcheck
|
|
||||||
return varbin.Write(writer, binary.BigEndian, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
func oldReadString(reader varbin.Reader) (string, error) {
|
func oldReadString(reader varbin.Reader) (string, error) {
|
||||||
//nolint:staticcheck
|
//nolint:staticcheck
|
||||||
return varbin.ReadValue[string](reader, binary.BigEndian)
|
return varbin.ReadValue[string](reader, binary.BigEndian)
|
||||||
@@ -224,7 +219,7 @@ func TestGeositeWriteReadCompat(t *testing.T) {
|
|||||||
|
|
||||||
func generateLargeItems(count int) map[string][]Item {
|
func generateLargeItems(count int) map[string][]Item {
|
||||||
items := make([]Item, count)
|
items := make([]Item, count)
|
||||||
for i := 0; i < count; i++ {
|
for i := range count {
|
||||||
items[i] = Item{
|
items[i] = Item{
|
||||||
Type: ItemType(i % 4),
|
Type: ItemType(i % 4),
|
||||||
Value: strings.Repeat("x", i%200) + ".com",
|
Value: strings.Repeat("x", i%200) + ".com",
|
||||||
|
|||||||
@@ -48,12 +48,6 @@ func NewReader(readSeeker io.ReadSeeker) (*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 {
|
||||||
counter := &readCounter{Reader: r.reader}
|
counter := &readCounter{Reader: r.reader}
|
||||||
reader := bufio.NewReader(counter)
|
reader := bufio.NewReader(counter)
|
||||||
@@ -101,6 +95,9 @@ func (r *Reader) readMetadata() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Reader) Read(code string) ([]Item, error) {
|
func (r *Reader) Read(code string) ([]Item, error) {
|
||||||
|
r.access.Lock()
|
||||||
|
defer r.access.Unlock()
|
||||||
|
|
||||||
index, exists := r.domainIndex[code]
|
index, exists := r.domainIndex[code]
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil, E.New("code ", code, " not exists!")
|
return nil, E.New("code ", code, " not exists!")
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ func (j *ClientHello) parseHandshake(hs []byte) error {
|
|||||||
return &ParseError{LengthErr, 7}
|
return &ParseError{LengthErr, 7}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < numCiphers; i++ {
|
for i := range numCiphers {
|
||||||
cipherSuite := uint16(cs[2+i<<1])<<8 | uint16(cs[3+i<<1])
|
cipherSuite := uint16(cs[2+i<<1])<<8 | uint16(cs[3+i<<1])
|
||||||
cipherSuites = append(cipherSuites, cipherSuite)
|
cipherSuites = append(cipherSuites, cipherSuite)
|
||||||
}
|
}
|
||||||
@@ -234,7 +234,7 @@ func (j *ClientHello) parseExtensions(exs []byte) error {
|
|||||||
return &ParseError{LengthErr, 16}
|
return &ParseError{LengthErr, 16}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < numCurves; i++ {
|
for i := range numCurves {
|
||||||
ecType := uint16(sex[i*2])<<8 | uint16(sex[1+i*2])
|
ecType := uint16(sex[i*2])<<8 | uint16(sex[1+i*2])
|
||||||
ellipticCurves = append(ellipticCurves, ecType)
|
ellipticCurves = append(ellipticCurves, ecType)
|
||||||
}
|
}
|
||||||
@@ -256,7 +256,7 @@ func (j *ClientHello) parseExtensions(exs []byte) error {
|
|||||||
return &ParseError{LengthErr, 18}
|
return &ParseError{LengthErr, 18}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < numPF; i++ {
|
for i := range numPF {
|
||||||
ellipticCurvePF[i] = uint8(sex[i])
|
ellipticCurvePF[i] = uint8(sex[i])
|
||||||
}
|
}
|
||||||
case versionExtensionType:
|
case versionExtensionType:
|
||||||
|
|||||||
@@ -6,48 +6,7 @@
|
|||||||
|
|
||||||
package ktls
|
package ktls
|
||||||
|
|
||||||
import (
|
import "golang.org/x/crypto/cryptobyte"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/cryptobyte"
|
|
||||||
)
|
|
||||||
|
|
||||||
// The marshalingFunction type is an adapter to allow the use of ordinary
|
|
||||||
// functions as cryptobyte.MarshalingValue.
|
|
||||||
type marshalingFunction func(b *cryptobyte.Builder) error
|
|
||||||
|
|
||||||
func (f marshalingFunction) Marshal(b *cryptobyte.Builder) error {
|
|
||||||
return f(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// addBytesWithLength appends a sequence of bytes to the cryptobyte.Builder. If
|
|
||||||
// the length of the sequence is not the value specified, it produces an error.
|
|
||||||
func addBytesWithLength(b *cryptobyte.Builder, v []byte, n int) {
|
|
||||||
b.AddValue(marshalingFunction(func(b *cryptobyte.Builder) error {
|
|
||||||
if len(v) != n {
|
|
||||||
return fmt.Errorf("invalid value length: expected %d, got %d", n, len(v))
|
|
||||||
}
|
|
||||||
b.AddBytes(v)
|
|
||||||
return nil
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
// addUint64 appends a big-endian, 64-bit value to the cryptobyte.Builder.
|
|
||||||
func addUint64(b *cryptobyte.Builder, v uint64) {
|
|
||||||
b.AddUint32(uint32(v >> 32))
|
|
||||||
b.AddUint32(uint32(v))
|
|
||||||
}
|
|
||||||
|
|
||||||
// readUint64 decodes a big-endian, 64-bit value into out and advances over it.
|
|
||||||
// It reports whether the read was successful.
|
|
||||||
func readUint64(s *cryptobyte.String, out *uint64) bool {
|
|
||||||
var hi, lo uint32
|
|
||||||
if !s.ReadUint32(&hi) || !s.ReadUint32(&lo) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
*out = uint64(hi)<<32 | uint64(lo)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// readUint8LengthPrefixed acts like s.ReadUint8LengthPrefixed, but targets a
|
// readUint8LengthPrefixed acts like s.ReadUint8LengthPrefixed, but targets a
|
||||||
// []byte instead of a cryptobyte.String.
|
// []byte instead of a cryptobyte.String.
|
||||||
@@ -61,12 +20,6 @@ func readUint16LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
|
|||||||
return s.ReadUint16LengthPrefixed((*cryptobyte.String)(out))
|
return s.ReadUint16LengthPrefixed((*cryptobyte.String)(out))
|
||||||
}
|
}
|
||||||
|
|
||||||
// readUint24LengthPrefixed acts like s.ReadUint24LengthPrefixed, but targets a
|
|
||||||
// []byte instead of a cryptobyte.String.
|
|
||||||
func readUint24LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
|
|
||||||
return s.ReadUint24LengthPrefixed((*cryptobyte.String)(out))
|
|
||||||
}
|
|
||||||
|
|
||||||
type keyUpdateMsg struct {
|
type keyUpdateMsg struct {
|
||||||
updateRequested bool
|
updateRequested bool
|
||||||
}
|
}
|
||||||
@@ -125,11 +78,6 @@ const (
|
|||||||
typeMessageHash uint8 = 254 // synthetic message
|
typeMessageHash uint8 = 254 // synthetic message
|
||||||
)
|
)
|
||||||
|
|
||||||
// TLS compression types.
|
|
||||||
const (
|
|
||||||
compressionNone uint8 = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
// TLS extension numbers
|
// TLS extension numbers
|
||||||
const (
|
const (
|
||||||
extensionServerName uint16 = 0
|
extensionServerName uint16 = 0
|
||||||
|
|||||||
@@ -77,78 +77,5 @@ func (c *Conn) writeRecordLocked(typ uint16, data []byte) (n int, err error) {
|
|||||||
if !c.kernelTx {
|
if !c.kernelTx {
|
||||||
return c.rawConn.WriteRecordLocked(typ, data)
|
return c.rawConn.WriteRecordLocked(typ, data)
|
||||||
}
|
}
|
||||||
/*for len(data) > 0 {
|
|
||||||
m := len(data)
|
|
||||||
if maxPayload := c.maxPayloadSizeForWrite(typ); m > maxPayload {
|
|
||||||
m = maxPayload
|
|
||||||
}
|
|
||||||
_, err = c.writeKernelRecord(typ, data[:m])
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
n += m
|
|
||||||
data = data[m:]
|
|
||||||
}*/
|
|
||||||
return c.writeKernelRecord(typ, data)
|
return c.writeKernelRecord(typ, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
// tcpMSSEstimate is a conservative estimate of the TCP maximum segment
|
|
||||||
// size (MSS). A constant is used, rather than querying the kernel for
|
|
||||||
// the actual MSS, to avoid complexity. The value here is the IPv6
|
|
||||||
// minimum MTU (1280 bytes) minus the overhead of an IPv6 header (40
|
|
||||||
// bytes) and a TCP header with timestamps (32 bytes).
|
|
||||||
tcpMSSEstimate = 1208
|
|
||||||
|
|
||||||
// recordSizeBoostThreshold is the number of bytes of application data
|
|
||||||
// sent after which the TLS record size will be increased to the
|
|
||||||
// maximum.
|
|
||||||
recordSizeBoostThreshold = 128 * 1024
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Conn) maxPayloadSizeForWrite(typ uint16) int {
|
|
||||||
if /*c.config.DynamicRecordSizingDisabled ||*/ typ != recordTypeApplicationData {
|
|
||||||
return maxPlaintext
|
|
||||||
}
|
|
||||||
|
|
||||||
if *c.rawConn.PacketsSent >= recordSizeBoostThreshold {
|
|
||||||
return maxPlaintext
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subtract TLS overheads to get the maximum payload size.
|
|
||||||
payloadBytes := tcpMSSEstimate - recordHeaderLen - c.rawConn.Out.ExplicitNonceLen()
|
|
||||||
if rawCipher := *c.rawConn.Out.Cipher; rawCipher != nil {
|
|
||||||
switch ciph := rawCipher.(type) {
|
|
||||||
case cipher.Stream:
|
|
||||||
payloadBytes -= (*c.rawConn.Out.Mac).Size()
|
|
||||||
case cipher.AEAD:
|
|
||||||
payloadBytes -= ciph.Overhead()
|
|
||||||
/*case cbcMode:
|
|
||||||
blockSize := ciph.BlockSize()
|
|
||||||
// The payload must fit in a multiple of blockSize, with
|
|
||||||
// room for at least one padding byte.
|
|
||||||
payloadBytes = (payloadBytes & ^(blockSize - 1)) - 1
|
|
||||||
// The RawMac is appended before padding so affects the
|
|
||||||
// payload size directly.
|
|
||||||
payloadBytes -= c.out.mac.Size()*/
|
|
||||||
default:
|
|
||||||
panic("unknown cipher type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if *c.rawConn.Vers == tls.VersionTLS13 {
|
|
||||||
payloadBytes-- // encrypted ContentType
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow packet growth in arithmetic progression up to max.
|
|
||||||
pkt := *c.rawConn.PacketsSent
|
|
||||||
*c.rawConn.PacketsSent++
|
|
||||||
if pkt > 1000 {
|
|
||||||
return maxPlaintext // avoid overflow in multiply below
|
|
||||||
}
|
|
||||||
|
|
||||||
n := payloadBytes * int(pkt+1)
|
|
||||||
if n > maxPlaintext {
|
|
||||||
n = maxPlaintext
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ func (f *darwinConnectionFinder) find(network string, source netip.AddrPort, des
|
|||||||
source = normalizeDarwinAddrPort(source)
|
source = normalizeDarwinAddrPort(source)
|
||||||
destination = normalizeDarwinAddrPort(destination)
|
destination = normalizeDarwinAddrPort(destination)
|
||||||
var lastOwner *adapter.ConnectionOwner
|
var lastOwner *adapter.ConnectionOwner
|
||||||
for attempt := 0; attempt < 2; attempt++ {
|
for attempt := range 2 {
|
||||||
snapshot, fromCache, err := f.loadSnapshot(networkName, attempt > 0)
|
snapshot, fromCache, err := f.loadSnapshot(networkName, attempt > 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
//go:build linux
|
//go:build linux
|
||||||
|
|
||||||
|
//nolint:unused
|
||||||
package process
|
package process
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -117,7 +118,7 @@ func (c *socketDiagConn) query(source netip.AddrPort, destination netip.AddrPort
|
|||||||
c.access.Lock()
|
c.access.Lock()
|
||||||
defer c.access.Unlock()
|
defer c.access.Unlock()
|
||||||
request := packSocketDiagRequest(c.family, c.protocol, source, destination, false)
|
request := packSocketDiagRequest(c.family, c.protocol, source, destination, false)
|
||||||
for attempt := 0; attempt < 2; attempt++ {
|
for range 2 {
|
||||||
err = c.ensureOpenLocked()
|
err = c.ensureOpenLocked()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, E.Cause(err, "dial netlink")
|
return 0, 0, E.Cause(err, "dial netlink")
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ func getInterfaceDisplayName(name string) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
for _, deviceSpan := range strings.Split(string(content), "Ethernet Address") {
|
for deviceSpan := range strings.SplitSeq(string(content), "Ethernet Address") {
|
||||||
if strings.Contains(deviceSpan, "Device: "+name) {
|
if strings.Contains(deviceSpan, "Device: "+name) {
|
||||||
substr := "Hardware Port: "
|
substr := "Hardware Port: "
|
||||||
deviceSpan = deviceSpan[strings.Index(deviceSpan, substr)+len(substr):]
|
deviceSpan = deviceSpan[strings.Index(deviceSpan, substr)+len(substr):]
|
||||||
|
|||||||
@@ -40,14 +40,14 @@ func (m *connmanMonitor) ReadWIFIState() adapter.WIFIState {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
cmObj := m.conn.Object("net.connman", "/")
|
cmObj := m.conn.Object("net.connman", "/")
|
||||||
var services []interface{}
|
var services []any
|
||||||
err := cmObj.CallWithContext(ctx, "net.connman.Manager.GetServices", 0).Store(&services)
|
err := cmObj.CallWithContext(ctx, "net.connman.Manager.GetServices", 0).Store(&services)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return adapter.WIFIState{}
|
return adapter.WIFIState{}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, service := range services {
|
for _, service := range services {
|
||||||
servicePair, ok := service.([]interface{})
|
servicePair, ok := service.([]any)
|
||||||
if !ok || len(servicePair) != 2 {
|
if !ok || len(servicePair) != 2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
//nolint:unused
|
||||||
package settings
|
package settings
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -73,13 +74,13 @@ func (m *wpaSupplicantMonitor) ReadWIFIState() adapter.WIFIState {
|
|||||||
scanner := bufio.NewScanner(strings.NewReader(status))
|
scanner := bufio.NewScanner(strings.NewReader(status))
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
line := scanner.Text()
|
line := scanner.Text()
|
||||||
if strings.HasPrefix(line, "wpa_state=") {
|
if after, ok := strings.CutPrefix(line, "wpa_state="); ok {
|
||||||
state := strings.TrimPrefix(line, "wpa_state=")
|
state := after
|
||||||
connected = state == "COMPLETED"
|
connected = state == "COMPLETED"
|
||||||
} else if strings.HasPrefix(line, "ssid=") {
|
} else if after, ok := strings.CutPrefix(line, "ssid="); ok {
|
||||||
ssid = strings.TrimPrefix(line, "ssid=")
|
ssid = after
|
||||||
} else if strings.HasPrefix(line, "bssid=") {
|
} else if after, ok := strings.CutPrefix(line, "bssid="); ok {
|
||||||
bssid = strings.TrimPrefix(line, "bssid=")
|
bssid = after
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
//go:build !linux && !windows
|
//go:build !linux && !windows
|
||||||
|
|
||||||
|
//nolint:unused
|
||||||
package settings
|
package settings
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -54,9 +54,8 @@ type xorNonceAEAD struct {
|
|||||||
aead cipher.AEAD
|
aead cipher.AEAD
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *xorNonceAEAD) NonceSize() int { return 8 } // 64-bit sequence number
|
func (f *xorNonceAEAD) NonceSize() int { return 8 } // 64-bit sequence number
|
||||||
func (f *xorNonceAEAD) Overhead() int { return f.aead.Overhead() }
|
func (f *xorNonceAEAD) Overhead() int { return f.aead.Overhead() }
|
||||||
func (f *xorNonceAEAD) explicitNonceLen() int { return 0 }
|
|
||||||
|
|
||||||
func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
|
func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
|
||||||
for i, b := range nonce {
|
for i, b := range nonce {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package sniff
|
package sniff
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"slices"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/ja3"
|
"github.com/sagernet/sing-box/common/ja3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,15 +17,8 @@ const (
|
|||||||
// Note: uQUIC with Chromium mimicry cannot be reliably distinguished from real Chromium
|
// Note: uQUIC with Chromium mimicry cannot be reliably distinguished from real Chromium
|
||||||
// since it uses the same TLS fingerprint, so it will be identified as Chromium.
|
// since it uses the same TLS fingerprint, so it will be identified as Chromium.
|
||||||
func isQUICGo(fingerprint *ja3.ClientHello) bool {
|
func isQUICGo(fingerprint *ja3.ClientHello) bool {
|
||||||
for _, curve := range fingerprint.EllipticCurves {
|
if slices.Contains(fingerprint.EllipticCurves, x25519Kyber768Draft00) {
|
||||||
if curve == x25519Kyber768Draft00 {
|
return true
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for _, ext := range fingerprint.Extensions {
|
return slices.Contains(fingerprint.Extensions, extensionRenegotiationInfo)
|
||||||
if ext == extensionRenegotiationInfo {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func TestSniffQUICQuicGoFingerprint(t *testing.T) {
|
|||||||
go func() {
|
go func() {
|
||||||
var packets [][]byte
|
var packets [][]byte
|
||||||
udpConn.SetReadDeadline(time.Now().Add(3 * time.Second))
|
udpConn.SetReadDeadline(time.Now().Add(3 * time.Second))
|
||||||
for i := 0; i < 10; i++ {
|
for range 10 {
|
||||||
buf := make([]byte, 2048)
|
buf := make([]byte, 2048)
|
||||||
n, _, err := udpConn.ReadFromUDP(buf)
|
n, _, err := udpConn.ReadFromUDP(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -104,7 +104,7 @@ func TestSniffQUICInitialFromQuicGo(t *testing.T) {
|
|||||||
go func() {
|
go func() {
|
||||||
var packets [][]byte
|
var packets [][]byte
|
||||||
udpConn.SetReadDeadline(time.Now().Add(3 * time.Second))
|
udpConn.SetReadDeadline(time.Now().Add(3 * time.Second))
|
||||||
for i := 0; i < 5; i++ { // Capture up to 5 packets
|
for range 5 { // Capture up to 5 packets
|
||||||
buf := make([]byte, 2048)
|
buf := make([]byte, 2048)
|
||||||
n, _, err := udpConn.ReadFromUDP(buf)
|
n, _, err := udpConn.ReadFromUDP(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ func Read(reader io.Reader, recover bool) (ruleSetCompat option.PlainRuleSetComp
|
|||||||
}
|
}
|
||||||
ruleSetCompat.Version = version
|
ruleSetCompat.Version = version
|
||||||
ruleSetCompat.Options.Rules = make([]option.HeadlessRule, length)
|
ruleSetCompat.Options.Rules = make([]option.HeadlessRule, length)
|
||||||
for i := uint64(0); i < length; i++ {
|
for i := range length {
|
||||||
ruleSetCompat.Options.Rules[i], err = readRule(bReader, recover)
|
ruleSetCompat.Options.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, "]")
|
||||||
@@ -644,7 +644,7 @@ func readLogicalRule(reader varbin.Reader, recovery bool) (logicalRule option.Lo
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
logicalRule.Rules = make([]option.HeadlessRule, length)
|
logicalRule.Rules = make([]option.HeadlessRule, length)
|
||||||
for i := uint64(0); i < length; i++ {
|
for i := range length {
|
||||||
logicalRule.Rules[i], err = readRule(reader, recovery)
|
logicalRule.Rules[i], err = readRule(reader, recovery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = E.Cause(err, "read logical rule [", i, "]")
|
err = E.Cause(err, "read logical rule [", i, "]")
|
||||||
|
|||||||
@@ -450,7 +450,7 @@ func buildIPSet(cidrs ...string) *netipx.IPSet {
|
|||||||
|
|
||||||
func buildLargeIPSet(count int) *netipx.IPSet {
|
func buildLargeIPSet(count int) *netipx.IPSet {
|
||||||
var builder netipx.IPSetBuilder
|
var builder netipx.IPSetBuilder
|
||||||
for i := 0; i < count; i++ {
|
for i := range count {
|
||||||
prefix := netip.PrefixFrom(netip.AddrFrom4([4]byte{10, byte(i / 256), byte(i % 256), 0}), 24)
|
prefix := netip.PrefixFrom(netip.AddrFrom4([4]byte{10, byte(i / 256), byte(i % 256), 0}), 24)
|
||||||
builder.AddPrefix(prefix)
|
builder.AddPrefix(prefix)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -267,8 +267,8 @@ type realityVerifier struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *realityVerifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
func (c *realityVerifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||||
p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates")
|
p, _ := reflect.TypeFor[utls.Conn]().FieldByName("peerCertificates")
|
||||||
certs := *(*([]*x509.Certificate))(unsafe.Pointer(uintptr(unsafe.Pointer(c.Conn)) + p.Offset))
|
certs := *(*([]*x509.Certificate))(unsafe.Add(unsafe.Pointer(c.Conn), p.Offset))
|
||||||
if pub, ok := certs[0].PublicKey.(ed25519.PublicKey); ok {
|
if pub, ok := certs[0].PublicKey.(ed25519.PublicKey); ok {
|
||||||
h := hmac.New(sha512.New, c.authKey)
|
h := hmac.New(sha512.New, c.authKey)
|
||||||
h.Write(pub)
|
h.Write(pub)
|
||||||
|
|||||||
@@ -141,13 +141,14 @@ func (c *STDServerConfig) startWatcher() error {
|
|||||||
|
|
||||||
func (c *STDServerConfig) certificateUpdated(path string) error {
|
func (c *STDServerConfig) certificateUpdated(path string) error {
|
||||||
if path == c.certificatePath || path == c.keyPath {
|
if path == c.certificatePath || path == c.keyPath {
|
||||||
if path == c.certificatePath {
|
switch path {
|
||||||
|
case c.certificatePath:
|
||||||
certificate, err := os.ReadFile(c.certificatePath)
|
certificate, err := os.ReadFile(c.certificatePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "reload certificate from ", c.certificatePath)
|
return E.Cause(err, "reload certificate from ", c.certificatePath)
|
||||||
}
|
}
|
||||||
c.certificate = certificate
|
c.certificate = certificate
|
||||||
} else if path == c.keyPath {
|
case c.keyPath:
|
||||||
key, err := os.ReadFile(c.keyPath)
|
key, err := os.ReadFile(c.keyPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "reload key from ", c.keyPath)
|
return E.Cause(err, "reload key from ", c.keyPath)
|
||||||
@@ -338,9 +339,10 @@ func NewSTDServer(ctx context.Context, logger log.ContextLogger, options option.
|
|||||||
}
|
}
|
||||||
tlsConfig.ClientCAs = clientCertificateCA
|
tlsConfig.ClientCAs = clientCertificateCA
|
||||||
} else if len(options.ClientCertificatePublicKeySHA256) > 0 {
|
} else if len(options.ClientCertificatePublicKeySHA256) > 0 {
|
||||||
if tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert {
|
switch tlsConfig.ClientAuth {
|
||||||
|
case tls.RequireAndVerifyClientCert:
|
||||||
tlsConfig.ClientAuth = tls.RequireAnyClientCert
|
tlsConfig.ClientAuth = tls.RequireAnyClientCert
|
||||||
} else if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven {
|
case tls.VerifyClientCertIfGiven:
|
||||||
tlsConfig.ClientAuth = tls.RequestClientCert
|
tlsConfig.ClientAuth = tls.RequestClientCert
|
||||||
}
|
}
|
||||||
tlsConfig.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
tlsConfig.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||||
|
|||||||
@@ -603,10 +603,7 @@ func (s *StartedService) URLTest(ctx context.Context, request *URLTestRequest) (
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
_, isGroup := it.(adapter.OutboundGroup)
|
_, isGroup := it.(adapter.OutboundGroup)
|
||||||
if isGroup {
|
return !isGroup
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
})
|
||||||
b, _ := batch.New(boxService.ctx, batch.WithConcurrencyNum[any](10))
|
b, _ := batch.New(boxService.ctx, batch.WithConcurrencyNum[any](10))
|
||||||
for _, detour := range outbounds {
|
for _, detour := range outbounds {
|
||||||
|
|||||||
@@ -70,10 +70,7 @@ func NewClient(options ClientOptions) *Client {
|
|||||||
if client.timeout == 0 {
|
if client.timeout == 0 {
|
||||||
client.timeout = C.DNSTimeout
|
client.timeout = C.DNSTimeout
|
||||||
}
|
}
|
||||||
cacheCapacity := options.CacheCapacity
|
cacheCapacity := max(options.CacheCapacity, 1024)
|
||||||
if cacheCapacity < 1024 {
|
|
||||||
cacheCapacity = 1024
|
|
||||||
}
|
|
||||||
if !client.disableCache {
|
if !client.disableCache {
|
||||||
if !client.independentCache {
|
if !client.independentCache {
|
||||||
client.cache = common.Must1(freelru.NewSharded[dns.Question, *dns.Msg](cacheCapacity, maphash.NewHasher[dns.Question]().Hash32))
|
client.cache = common.Must1(freelru.NewSharded[dns.Question, *dns.Msg](cacheCapacity, maphash.NewHasher[dns.Question]().Hash32))
|
||||||
@@ -334,9 +331,10 @@ func (c *Client) Lookup(ctx context.Context, transport adapter.DNSTransport, dom
|
|||||||
if options.LookupStrategy != C.DomainStrategyAsIS {
|
if options.LookupStrategy != C.DomainStrategyAsIS {
|
||||||
lookupOptions.Strategy = strategy
|
lookupOptions.Strategy = strategy
|
||||||
}
|
}
|
||||||
if strategy == C.DomainStrategyIPv4Only {
|
switch strategy {
|
||||||
|
case C.DomainStrategyIPv4Only:
|
||||||
return c.lookupToExchange(ctx, transport, dnsName, dns.TypeA, lookupOptions, responseChecker)
|
return c.lookupToExchange(ctx, transport, dnsName, dns.TypeA, lookupOptions, responseChecker)
|
||||||
} else if strategy == C.DomainStrategyIPv6Only {
|
case C.DomainStrategyIPv6Only:
|
||||||
return c.lookupToExchange(ctx, transport, dnsName, dns.TypeAAAA, lookupOptions, responseChecker)
|
return c.lookupToExchange(ctx, transport, dnsName, dns.TypeAAAA, lookupOptions, responseChecker)
|
||||||
}
|
}
|
||||||
var response4 []netip.Addr
|
var response4 []netip.Addr
|
||||||
@@ -500,10 +498,7 @@ func (c *Client) loadResponse(question dns.Question, transport adapter.DNSTransp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nowTTL := int(expireAt.Sub(timeNow).Seconds())
|
nowTTL := max(int(expireAt.Sub(timeNow).Seconds()), 0)
|
||||||
if nowTTL < 0 {
|
|
||||||
nowTTL = 0
|
|
||||||
}
|
|
||||||
response = response.Copy()
|
response = response.Copy()
|
||||||
if originTTL > 0 {
|
if originTTL > 0 {
|
||||||
duration := uint32(originTTL - nowTTL)
|
duration := uint32(originTTL - nowTTL)
|
||||||
@@ -551,18 +546,6 @@ func MessageToAddresses(response *dns.Msg) []netip.Addr {
|
|||||||
return addresses
|
return addresses
|
||||||
}
|
}
|
||||||
|
|
||||||
func wrapError(err error) error {
|
|
||||||
switch dnsErr := err.(type) {
|
|
||||||
case *net.DNSError:
|
|
||||||
if dnsErr.IsNotFound {
|
|
||||||
return RcodeNameError
|
|
||||||
}
|
|
||||||
case *net.AddrError:
|
|
||||||
return RcodeNameError
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
type transportKey struct{}
|
type transportKey struct{}
|
||||||
|
|
||||||
func contextWithTransportTag(ctx context.Context, transportTag string) context.Context {
|
func contextWithTransportTag(ctx context.Context, transportTag string) context.Context {
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ func (t *Transport) fetchServers0(ctx context.Context, iface *control.Interface)
|
|||||||
packetConn net.PacketConn
|
packetConn net.PacketConn
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
for i := 0; i < 5; i++ {
|
for range 5 {
|
||||||
packetConn, err = listener.ListenPacket(t.ctx, "udp4", listenAddr)
|
packetConn, err = listener.ListenPacket(t.ctx, "udp4", listenAddr)
|
||||||
if err == nil || !errors.Is(err, syscall.EADDRINUSE) {
|
if err == nil || !errors.Is(err, syscall.EADDRINUSE) {
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ func (t *Transport) tryOneName(ctx context.Context, servers []M.Socksaddr, fqdn
|
|||||||
sLen := len(servers)
|
sLen := len(servers)
|
||||||
var lastErr error
|
var lastErr error
|
||||||
for i := 0; i < t.attempts; i++ {
|
for i := 0; i < t.attempts; i++ {
|
||||||
for j := 0; j < sLen; j++ {
|
for j := range sLen {
|
||||||
server := servers[j]
|
server := servers[j]
|
||||||
question := message.Question[0]
|
question := message.Question[0]
|
||||||
question.Name = fqdn
|
question.Name = fqdn
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
//go:build !linux
|
//go:build !linux
|
||||||
|
|
||||||
|
//nolint:unused
|
||||||
package local
|
package local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ func (t *Transport) tryOneName(ctx context.Context, config *dnsConfig, fqdn stri
|
|||||||
sLen := uint32(len(config.servers))
|
sLen := uint32(len(config.servers))
|
||||||
var lastErr error
|
var lastErr error
|
||||||
for i := 0; i < config.attempts; i++ {
|
for i := 0; i < config.attempts; i++ {
|
||||||
for j := uint32(0); j < sLen; j++ {
|
for j := range sLen {
|
||||||
server := config.servers[(serverOffset+j)%sLen]
|
server := config.servers[(serverOffset+j)%sLen]
|
||||||
question := message.Question[0]
|
question := message.Question[0]
|
||||||
question.Name = fqdn
|
question.Name = fqdn
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
//nolint:unused
|
||||||
package local
|
package local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
//nolint:unused
|
||||||
package local
|
package local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg,
|
|||||||
err error
|
err error
|
||||||
response *mDNS.Msg
|
response *mDNS.Msg
|
||||||
)
|
)
|
||||||
for i := 0; i < 2; i++ {
|
for range 2 {
|
||||||
conn, _, err = t.connection.Acquire(ctx, func(ctx context.Context) (*quic.Conn, error) {
|
conn, _, err = t.connection.Acquire(ctx, func(ctx context.Context) (*quic.Conn, error) {
|
||||||
rawConn, err := t.dialer.DialContext(ctx, N.NetworkUDP, t.serverAddr)
|
rawConn, err := t.dialer.DialContext(ctx, N.NetworkUDP, t.serverAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ func (t *TLSTransport) Reset() {
|
|||||||
|
|
||||||
func (t *TLSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
func (t *TLSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||||
var lastErr error
|
var lastErr error
|
||||||
for attempt := 0; attempt < 2; attempt++ {
|
for range 2 {
|
||||||
conn, created, err := t.connections.Acquire(ctx, func(ctx context.Context) (*tlsDNSConn, error) {
|
conn, created, err := t.connections.Acquire(ctx, func(ctx context.Context) (*tlsDNSConn, error) {
|
||||||
tlsConn, err := t.dialer.DialTLSContext(ctx, t.serverAddr)
|
tlsConn, err := t.dialer.DialTLSContext(ctx, t.serverAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ func (c *CacheFile) Start(stage adapter.StartStage) error {
|
|||||||
db *bbolt.DB
|
db *bbolt.DB
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
for i := 0; i < 10; i++ {
|
for range 10 {
|
||||||
db, err = bbolt.Open(c.path, fileMode, &options)
|
db, err = bbolt.Open(c.path, fileMode, &options)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ func (s *Server) Start(stage adapter.StartStage) error {
|
|||||||
listener net.Listener
|
listener net.Listener
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
for i := 0; i < 3; i++ {
|
for range 3 {
|
||||||
listener, err = net.Listen("tcp", s.httpServer.Addr)
|
listener, err = net.Listen("tcp", s.httpServer.Addr)
|
||||||
if runtime.GOOS == "android" && errors.Is(err, syscall.EADDRINUSE) {
|
if runtime.GOOS == "android" && errors.Is(err, syscall.EADDRINUSE) {
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ func (c *CommandClient) dialWithRetry(target string, contextDialer func(context.
|
|||||||
var client daemon.StartedServiceClient
|
var client daemon.StartedServiceClient
|
||||||
var lastError error
|
var lastError error
|
||||||
|
|
||||||
for attempt := 0; attempt < commandClientDialAttempts; attempt++ {
|
for attempt := range commandClientDialAttempts {
|
||||||
if connection == nil {
|
if connection == nil {
|
||||||
options := []grpc.DialOption{
|
options := []grpc.DialOption{
|
||||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ func (s *CommandServer) Start() error {
|
|||||||
if sCommandServerListenPort == 0 {
|
if sCommandServerListenPort == 0 {
|
||||||
sockPath := filepath.Join(sBasePath, "command.sock")
|
sockPath := filepath.Join(sBasePath, "command.sock")
|
||||||
os.Remove(sockPath)
|
os.Remove(sockPath)
|
||||||
for i := 0; i < 30; i++ {
|
for range 30 {
|
||||||
listener, err = net.ListenUnix("unix", &net.UnixAddr{
|
listener, err = net.ListenUnix("unix", &net.UnixAddr{
|
||||||
Name: sockPath,
|
Name: sockPath,
|
||||||
Net: "unix",
|
Net: "unix",
|
||||||
|
|||||||
@@ -418,13 +418,3 @@ func systemProxyStatusFromGRPC(status *daemon.SystemProxyStatus) *SystemProxySta
|
|||||||
Enabled: status.Enabled,
|
Enabled: status.Enabled,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func systemProxyStatusToGRPC(status *SystemProxyStatus) *daemon.SystemProxyStatus {
|
|
||||||
if status == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &daemon.SystemProxyStatus{
|
|
||||||
Available: status.Available,
|
|
||||||
Enabled: status.Enabled,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ import (
|
|||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
)
|
)
|
||||||
|
|
||||||
var crashOutputFile *os.File
|
|
||||||
|
|
||||||
func RedirectStderr(path string) error {
|
func RedirectStderr(path string) error {
|
||||||
if stats, err := os.Stat(path); err == nil && stats.Size() > 0 {
|
if stats, err := os.Stat(path); err == nil && stats.Size() > 0 {
|
||||||
_ = os.Rename(path, path+".old")
|
_ = os.Rename(path, path+".old")
|
||||||
@@ -32,6 +30,5 @@ func RedirectStderr(path string) error {
|
|||||||
os.Remove(outputFile.Name())
|
os.Remove(outputFile.Name())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
crashOutputFile = outputFile
|
return outputFile.Close()
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ var (
|
|||||||
type platformDefaultInterfaceMonitor struct {
|
type platformDefaultInterfaceMonitor struct {
|
||||||
*platformInterfaceWrapper
|
*platformInterfaceWrapper
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
element *list.Element[tun.NetworkUpdateCallback]
|
|
||||||
callbacks list.List[tun.DefaultInterfaceUpdateCallback]
|
callbacks list.List[tun.DefaultInterfaceUpdateCallback]
|
||||||
myInterface string
|
myInterface string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import C "github.com/sagernet/sing-box/constant"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
|
||||||
"github.com/sagernet/sing-box/option"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PlatformInterface interface {
|
type PlatformInterface interface {
|
||||||
LocalDNSTransport() LocalDNSTransport
|
LocalDNSTransport() LocalDNSTransport
|
||||||
@@ -98,37 +95,3 @@ type OnDemandRuleIterator interface {
|
|||||||
Next() OnDemandRule
|
Next() OnDemandRule
|
||||||
HasNext() bool
|
HasNext() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type onDemandRule struct {
|
|
||||||
option.OnDemandRule
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *onDemandRule) Target() int32 {
|
|
||||||
if r.OnDemandRule.Action == nil {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return int32(*r.OnDemandRule.Action)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *onDemandRule) DNSSearchDomainMatch() StringIterator {
|
|
||||||
return newIterator(r.OnDemandRule.DNSSearchDomainMatch)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *onDemandRule) DNSServerAddressMatch() StringIterator {
|
|
||||||
return newIterator(r.OnDemandRule.DNSServerAddressMatch)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *onDemandRule) InterfaceTypeMatch() int32 {
|
|
||||||
if r.OnDemandRule.InterfaceTypeMatch == nil {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return int32(*r.OnDemandRule.InterfaceTypeMatch)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *onDemandRule) SSIDMatch() StringIterator {
|
|
||||||
return newIterator(r.OnDemandRule.SSIDMatch)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *onDemandRule) ProbeURL() string {
|
|
||||||
return r.OnDemandRule.ProbeURL
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const utunControlName = "com.apple.net.utun_control"
|
|||||||
func GetTunnelFileDescriptor() int32 {
|
func GetTunnelFileDescriptor() int32 {
|
||||||
ctlInfo := &unix.CtlInfo{}
|
ctlInfo := &unix.CtlInfo{}
|
||||||
copy(ctlInfo.Name[:], utunControlName)
|
copy(ctlInfo.Name[:], utunControlName)
|
||||||
for fd := 0; fd < 1024; fd++ {
|
for fd := range 1024 {
|
||||||
addr, err := unix.Getpeername(fd)
|
addr, err := unix.Getpeername(fd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -4,14 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing/common/random"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
random.InitializeSeed()
|
|
||||||
}
|
|
||||||
|
|
||||||
type idKey struct{}
|
type idKey struct{}
|
||||||
|
|
||||||
type ID struct {
|
type ID struct {
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ func (v *NetworkList) UnmarshalJSON(content []byte) error {
|
|||||||
for _, networkName := range networkList {
|
for _, networkName := range networkList {
|
||||||
switch networkName {
|
switch networkName {
|
||||||
case N.NetworkTCP, N.NetworkUDP:
|
case N.NetworkTCP, N.NetworkUDP:
|
||||||
break
|
|
||||||
default:
|
default:
|
||||||
return E.New("unknown network: " + networkName)
|
return E.New("unknown network: " + networkName)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,186 +0,0 @@
|
|||||||
package direct
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"net/netip"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
|
||||||
N "github.com/sagernet/sing/common/network"
|
|
||||||
)
|
|
||||||
|
|
||||||
type loopBackDetector struct {
|
|
||||||
networkManager adapter.NetworkManager
|
|
||||||
connAccess sync.RWMutex
|
|
||||||
packetConnAccess sync.RWMutex
|
|
||||||
connMap map[netip.AddrPort]netip.AddrPort
|
|
||||||
packetConnMap map[uint16]uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
func newLoopBackDetector(networkManager adapter.NetworkManager) *loopBackDetector {
|
|
||||||
return &loopBackDetector{
|
|
||||||
networkManager: networkManager,
|
|
||||||
connMap: make(map[netip.AddrPort]netip.AddrPort),
|
|
||||||
packetConnMap: make(map[uint16]uint16),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *loopBackDetector) NewConn(conn net.Conn) net.Conn {
|
|
||||||
source := M.AddrPortFromNet(conn.LocalAddr())
|
|
||||||
if !source.IsValid() {
|
|
||||||
return conn
|
|
||||||
}
|
|
||||||
if udpConn, isUDPConn := conn.(abstractUDPConn); isUDPConn {
|
|
||||||
if !source.Addr().IsLoopback() {
|
|
||||||
_, err := l.networkManager.InterfaceFinder().ByAddr(source.Addr())
|
|
||||||
if err != nil {
|
|
||||||
return conn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !N.IsPublicAddr(source.Addr()) {
|
|
||||||
return conn
|
|
||||||
}
|
|
||||||
l.packetConnAccess.Lock()
|
|
||||||
l.packetConnMap[source.Port()] = M.AddrPortFromNet(conn.RemoteAddr()).Port()
|
|
||||||
l.packetConnAccess.Unlock()
|
|
||||||
return &loopBackDetectUDPWrapper{abstractUDPConn: udpConn, detector: l, connPort: source.Port()}
|
|
||||||
} else {
|
|
||||||
l.connAccess.Lock()
|
|
||||||
l.connMap[source] = M.AddrPortFromNet(conn.RemoteAddr())
|
|
||||||
l.connAccess.Unlock()
|
|
||||||
return &loopBackDetectWrapper{Conn: conn, detector: l, connAddr: source}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *loopBackDetector) NewPacketConn(conn N.NetPacketConn, destination M.Socksaddr) N.NetPacketConn {
|
|
||||||
source := M.AddrPortFromNet(conn.LocalAddr())
|
|
||||||
if !source.IsValid() {
|
|
||||||
return conn
|
|
||||||
}
|
|
||||||
if !source.Addr().IsLoopback() {
|
|
||||||
_, err := l.networkManager.InterfaceFinder().ByAddr(source.Addr())
|
|
||||||
if err != nil {
|
|
||||||
return conn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
l.packetConnAccess.Lock()
|
|
||||||
l.packetConnMap[source.Port()] = destination.AddrPort().Port()
|
|
||||||
l.packetConnAccess.Unlock()
|
|
||||||
return &loopBackDetectPacketWrapper{NetPacketConn: conn, detector: l, connPort: source.Port()}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *loopBackDetector) CheckConn(source netip.AddrPort, local netip.AddrPort) bool {
|
|
||||||
l.connAccess.RLock()
|
|
||||||
defer l.connAccess.RUnlock()
|
|
||||||
destination, loaded := l.connMap[source]
|
|
||||||
return loaded && destination != local
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *loopBackDetector) CheckPacketConn(source netip.AddrPort, local netip.AddrPort) bool {
|
|
||||||
if !source.IsValid() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if !source.Addr().IsLoopback() {
|
|
||||||
_, err := l.networkManager.InterfaceFinder().ByAddr(source.Addr())
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if N.IsPublicAddr(source.Addr()) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
l.packetConnAccess.RLock()
|
|
||||||
defer l.packetConnAccess.RUnlock()
|
|
||||||
destinationPort, loaded := l.packetConnMap[source.Port()]
|
|
||||||
return loaded && destinationPort != local.Port()
|
|
||||||
}
|
|
||||||
|
|
||||||
type loopBackDetectWrapper struct {
|
|
||||||
net.Conn
|
|
||||||
detector *loopBackDetector
|
|
||||||
connAddr netip.AddrPort
|
|
||||||
closeOnce sync.Once
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *loopBackDetectWrapper) Close() error {
|
|
||||||
w.closeOnce.Do(func() {
|
|
||||||
w.detector.connAccess.Lock()
|
|
||||||
delete(w.detector.connMap, w.connAddr)
|
|
||||||
w.detector.connAccess.Unlock()
|
|
||||||
})
|
|
||||||
return w.Conn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *loopBackDetectWrapper) ReaderReplaceable() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *loopBackDetectWrapper) WriterReplaceable() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *loopBackDetectWrapper) Upstream() any {
|
|
||||||
return w.Conn
|
|
||||||
}
|
|
||||||
|
|
||||||
type loopBackDetectPacketWrapper struct {
|
|
||||||
N.NetPacketConn
|
|
||||||
detector *loopBackDetector
|
|
||||||
connPort uint16
|
|
||||||
closeOnce sync.Once
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *loopBackDetectPacketWrapper) Close() error {
|
|
||||||
w.closeOnce.Do(func() {
|
|
||||||
w.detector.packetConnAccess.Lock()
|
|
||||||
delete(w.detector.packetConnMap, w.connPort)
|
|
||||||
w.detector.packetConnAccess.Unlock()
|
|
||||||
})
|
|
||||||
return w.NetPacketConn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *loopBackDetectPacketWrapper) ReaderReplaceable() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *loopBackDetectPacketWrapper) WriterReplaceable() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *loopBackDetectPacketWrapper) Upstream() any {
|
|
||||||
return w.NetPacketConn
|
|
||||||
}
|
|
||||||
|
|
||||||
type abstractUDPConn interface {
|
|
||||||
net.Conn
|
|
||||||
net.PacketConn
|
|
||||||
}
|
|
||||||
|
|
||||||
type loopBackDetectUDPWrapper struct {
|
|
||||||
abstractUDPConn
|
|
||||||
detector *loopBackDetector
|
|
||||||
connPort uint16
|
|
||||||
closeOnce sync.Once
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *loopBackDetectUDPWrapper) Close() error {
|
|
||||||
w.closeOnce.Do(func() {
|
|
||||||
w.detector.packetConnAccess.Lock()
|
|
||||||
delete(w.detector.packetConnMap, w.connPort)
|
|
||||||
w.detector.packetConnAccess.Unlock()
|
|
||||||
})
|
|
||||||
return w.abstractUDPConn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *loopBackDetectUDPWrapper) ReaderReplaceable() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *loopBackDetectUDPWrapper) WriterReplaceable() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *loopBackDetectUDPWrapper) Upstream() any {
|
|
||||||
return w.abstractUDPConn
|
|
||||||
}
|
|
||||||
@@ -41,7 +41,6 @@ type Outbound struct {
|
|||||||
domainStrategy C.DomainStrategy
|
domainStrategy C.DomainStrategy
|
||||||
fallbackDelay time.Duration
|
fallbackDelay time.Duration
|
||||||
isEmpty bool
|
isEmpty bool
|
||||||
// loopBack *loopBackDetector
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.DirectOutboundOptions) (adapter.Outbound, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.DirectOutboundOptions) (adapter.Outbound, error) {
|
||||||
@@ -67,7 +66,6 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||||||
fallbackDelay: time.Duration(options.FallbackDelay),
|
fallbackDelay: time.Duration(options.FallbackDelay),
|
||||||
dialer: outboundDialer.(dialer.ParallelInterfaceDialer),
|
dialer: outboundDialer.(dialer.ParallelInterfaceDialer),
|
||||||
isEmpty: reflect.DeepEqual(options.DialerOptions, option.DialerOptions{UDPFragmentDefault: true}),
|
isEmpty: reflect.DeepEqual(options.DialerOptions, option.DialerOptions{UDPFragmentDefault: true}),
|
||||||
// loopBack: newLoopBackDetector(router),
|
|
||||||
}
|
}
|
||||||
//nolint:staticcheck
|
//nolint:staticcheck
|
||||||
if options.ProxyProtocol != 0 {
|
if options.ProxyProtocol != 0 {
|
||||||
@@ -87,11 +85,6 @@ func (h *Outbound) DialContext(ctx context.Context, network string, destination
|
|||||||
case N.NetworkUDP:
|
case N.NetworkUDP:
|
||||||
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||||
}
|
}
|
||||||
/*conn, err := h.dialer.DialContext(ctx, network, destination)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return h.loopBack.NewConn(conn), nil*/
|
|
||||||
return h.dialer.DialContext(ctx, network, destination)
|
return h.dialer.DialContext(ctx, network, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +97,6 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// conn = h.loopBack.NewPacketConn(bufio.NewPacketConn(conn), destination)
|
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,18 +153,3 @@ func (h *Outbound) ListenSerialNetworkPacket(ctx context.Context, destination M.
|
|||||||
func (h *Outbound) IsEmpty() bool {
|
func (h *Outbound) IsEmpty() bool {
|
||||||
return h.isEmpty
|
return h.isEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
/*func (h *Outbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
|
||||||
if h.loopBack.CheckConn(metadata.Source.AddrPort(), M.AddrPortFromNet(conn.LocalAddr())) {
|
|
||||||
return E.New("reject loopback connection to ", metadata.Destination)
|
|
||||||
}
|
|
||||||
return NewConnection(ctx, h, conn, metadata)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Outbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
|
||||||
if h.loopBack.CheckPacketConn(metadata.Source.AddrPort(), M.AddrPortFromNet(conn.LocalAddr())) {
|
|
||||||
return E.New("reject loopback packet connection to ", metadata.Destination)
|
|
||||||
}
|
|
||||||
return NewPacketConnection(ctx, h, conn, metadata)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ func NewDNSPacketConnection(ctx context.Context, router adapter.DNSRouter, conn
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
fastClose, cancel := common.ContextWithCancelCause(ctx)
|
fastClose, cancel := context.WithCancelCause(ctx)
|
||||||
timeout := canceler.New(fastClose, cancel, C.DNSTimeout)
|
timeout := canceler.New(fastClose, cancel, C.DNSTimeout)
|
||||||
var group task.Group
|
var group task.Group
|
||||||
group.Append0(func(_ context.Context) error {
|
group.Append0(func(_ context.Context) error {
|
||||||
@@ -150,7 +150,7 @@ func NewDNSPacketConnection(ctx context.Context, router adapter.DNSRouter, conn
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newDNSPacketConnection(ctx context.Context, router adapter.DNSRouter, conn N.PacketConn, readWaiter N.PacketReadWaiter, readCounters []N.CountFunc, cached []*N.PacketBuffer, metadata adapter.InboundContext) error {
|
func newDNSPacketConnection(ctx context.Context, router adapter.DNSRouter, conn N.PacketConn, readWaiter N.PacketReadWaiter, readCounters []N.CountFunc, cached []*N.PacketBuffer, metadata adapter.InboundContext) error {
|
||||||
fastClose, cancel := common.ContextWithCancelCause(ctx)
|
fastClose, cancel := context.WithCancelCause(ctx)
|
||||||
timeout := canceler.New(fastClose, cancel, C.DNSTimeout)
|
timeout := canceler.New(fastClose, cancel, C.DNSTimeout)
|
||||||
var group task.Group
|
var group task.Group
|
||||||
group.Append0(func(_ context.Context) error {
|
group.Append0(func(_ context.Context) error {
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ var _ adapter.OutboundGroup = (*URLTest)(nil)
|
|||||||
type URLTest struct {
|
type URLTest struct {
|
||||||
outbound.Adapter
|
outbound.Adapter
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
router adapter.Router
|
|
||||||
outbound adapter.OutboundManager
|
outbound adapter.OutboundManager
|
||||||
connection adapter.ConnectionManager
|
connection adapter.ConnectionManager
|
||||||
logger log.ContextLogger
|
logger log.ContextLogger
|
||||||
@@ -51,7 +50,6 @@ func NewURLTest(ctx context.Context, router adapter.Router, logger log.ContextLo
|
|||||||
outbound := &URLTest{
|
outbound := &URLTest{
|
||||||
Adapter: outbound.NewAdapter(C.TypeURLTest, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.Outbounds),
|
Adapter: outbound.NewAdapter(C.TypeURLTest, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.Outbounds),
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
router: router,
|
|
||||||
outbound: service.FromContext[adapter.OutboundManager](ctx),
|
outbound: service.FromContext[adapter.OutboundManager](ctx),
|
||||||
connection: service.FromContext[adapter.ConnectionManager](ctx),
|
connection: service.FromContext[adapter.ConnectionManager](ctx),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
@@ -188,7 +186,6 @@ func (s *URLTest) NewDirectRouteConnection(metadata adapter.InboundContext, rout
|
|||||||
|
|
||||||
type URLTestGroup struct {
|
type URLTestGroup struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
router adapter.Router
|
|
||||||
outbound adapter.OutboundManager
|
outbound adapter.OutboundManager
|
||||||
pause pause.Manager
|
pause pause.Manager
|
||||||
pauseCallback *list.Element[pause.Callback]
|
pauseCallback *list.Element[pause.Callback]
|
||||||
@@ -267,9 +264,10 @@ func (g *URLTestGroup) Touch() {
|
|||||||
g.lastActive.Store(time.Now())
|
g.lastActive.Store(time.Now())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
g.ticker = time.NewTicker(g.interval)
|
ticker := time.NewTicker(g.interval)
|
||||||
go g.loopCheck()
|
g.ticker = ticker
|
||||||
g.pauseCallback = pause.RegisterTicker(g.pause, g.ticker, g.interval, nil)
|
g.pauseCallback = pause.RegisterTicker(g.pause, ticker, g.interval, nil)
|
||||||
|
go g.loopCheck(ticker, g.close)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *URLTestGroup) Close() error {
|
func (g *URLTestGroup) Close() error {
|
||||||
@@ -279,7 +277,9 @@ func (g *URLTestGroup) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
g.ticker.Stop()
|
g.ticker.Stop()
|
||||||
|
g.ticker = nil
|
||||||
g.pause.UnregisterCallback(g.pauseCallback)
|
g.pause.UnregisterCallback(g.pauseCallback)
|
||||||
|
g.pauseCallback = nil
|
||||||
close(g.close)
|
close(g.close)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -328,23 +328,25 @@ func (g *URLTestGroup) Select(network string) (adapter.Outbound, bool) {
|
|||||||
return minOutbound, true
|
return minOutbound, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *URLTestGroup) loopCheck() {
|
func (g *URLTestGroup) loopCheck(ticker *time.Ticker, closeChan <-chan struct{}) {
|
||||||
if time.Since(g.lastActive.Load()) > g.interval {
|
if time.Since(g.lastActive.Load()) > g.interval {
|
||||||
g.lastActive.Store(time.Now())
|
g.lastActive.Store(time.Now())
|
||||||
g.CheckOutbounds(false)
|
g.CheckOutbounds(false)
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-g.close:
|
case <-closeChan:
|
||||||
return
|
return
|
||||||
case <-g.ticker.C:
|
case <-ticker.C:
|
||||||
}
|
}
|
||||||
if time.Since(g.lastActive.Load()) > g.idleTimeout {
|
if time.Since(g.lastActive.Load()) > g.idleTimeout {
|
||||||
g.access.Lock()
|
g.access.Lock()
|
||||||
g.ticker.Stop()
|
if g.ticker == ticker {
|
||||||
g.ticker = nil
|
g.ticker.Stop()
|
||||||
g.pause.UnregisterCallback(g.pauseCallback)
|
g.ticker = nil
|
||||||
g.pauseCallback = nil
|
g.pause.UnregisterCallback(g.pauseCallback)
|
||||||
|
g.pauseCallback = nil
|
||||||
|
}
|
||||||
g.access.Unlock()
|
g.access.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ func generatePaddingHeader() string {
|
|||||||
paddingLen := rand.Intn(32) + 30
|
paddingLen := rand.Intn(32) + 30
|
||||||
padding := make([]byte, paddingLen)
|
padding := make([]byte, paddingLen)
|
||||||
bits := rand.Uint64()
|
bits := rand.Uint64()
|
||||||
for i := 0; i < 16; i++ {
|
for i := range 16 {
|
||||||
padding[i] = "!#$()+<>?@[]^`{}"[bits&15]
|
padding[i] = "!#$()+<>?@[]^`{}"[bits&15]
|
||||||
bits >>= 4
|
bits >>= 4
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
singTun "github.com/sagernet/sing-tun"
|
singTun "github.com/sagernet/sing-tun"
|
||||||
"github.com/sagernet/sing/common"
|
|
||||||
"github.com/sagernet/sing/common/logger"
|
"github.com/sagernet/sing/common/logger"
|
||||||
wgTun "github.com/sagernet/wireguard-go/tun"
|
wgTun "github.com/sagernet/wireguard-go/tun"
|
||||||
)
|
)
|
||||||
@@ -57,7 +56,7 @@ func (a *tunDeviceAdapter) Read(bufs [][]byte, sizes []int, offset int) (count i
|
|||||||
if a.linuxTUN != nil {
|
if a.linuxTUN != nil {
|
||||||
n, err := a.linuxTUN.BatchRead(bufs, offset-singTun.PacketOffset, sizes)
|
n, err := a.linuxTUN.BatchRead(bufs, offset-singTun.PacketOffset, sizes)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for i := 0; i < n; i++ {
|
for i := range n {
|
||||||
a.debugPacket("read", bufs[i][offset:offset+sizes[i]])
|
a.debugPacket("read", bufs[i][offset:offset+sizes[i]])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,7 +91,7 @@ func (a *tunDeviceAdapter) Write(bufs [][]byte, offset int) (count int, err erro
|
|||||||
for _, packet := range bufs {
|
for _, packet := range bufs {
|
||||||
a.debugPacket("write", packet[offset:])
|
a.debugPacket("write", packet[offset:])
|
||||||
if singTun.PacketOffset > 0 {
|
if singTun.PacketOffset > 0 {
|
||||||
common.ClearArray(packet[offset-singTun.PacketOffset : offset])
|
clear(packet[offset-singTun.PacketOffset : offset])
|
||||||
singTun.PacketFillHeader(packet[offset-singTun.PacketOffset:], singTun.PacketIPVersion(packet[offset:]))
|
singTun.PacketFillHeader(packet[offset-singTun.PacketOffset:], singTun.PacketIPVersion(packet[offset:]))
|
||||||
}
|
}
|
||||||
_, err = a.tun.Write(packet[offset-singTun.PacketOffset:])
|
_, err = a.tun.Write(packet[offset-singTun.PacketOffset:])
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package route
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
@@ -78,10 +79,8 @@ func (r *Router) isLocalSource(source netip.Addr) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if r.platformInterface != nil {
|
if r.platformInterface != nil {
|
||||||
for _, addr := range r.platformInterface.MyInterfaceAddress() {
|
if slices.Contains(r.platformInterface.MyInterfaceAddress(), source) {
|
||||||
if addr == source {
|
return true
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, netInterface := range r.network.InterfaceFinder().Interfaces() {
|
for _, netInterface := range r.network.InterfaceFinder().Interfaces() {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import (
|
|||||||
|
|
||||||
// Deprecated: use RouteConnectionEx instead.
|
// Deprecated: use RouteConnectionEx instead.
|
||||||
func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||||
done := make(chan interface{})
|
done := make(chan any)
|
||||||
err := r.routeConnection(ctx, conn, metadata, N.OnceClose(func(it error) {
|
err := r.routeConnection(ctx, conn, metadata, N.OnceClose(func(it error) {
|
||||||
close(done)
|
close(done)
|
||||||
}))
|
}))
|
||||||
@@ -161,7 +161,7 @@ func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata ad
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||||
done := make(chan interface{})
|
done := make(chan any)
|
||||||
err := r.routePacketConnection(ctx, conn, metadata, N.OnceClose(func(it error) {
|
err := r.routePacketConnection(ctx, conn, metadata, N.OnceClose(func(it error) {
|
||||||
close(done)
|
close(done)
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -42,11 +42,11 @@ func (s ruleMatchStateSet) combine(other ruleMatchStateSet) ruleMatchStateSet {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
var combined ruleMatchStateSet
|
var combined ruleMatchStateSet
|
||||||
for left := ruleMatchState(0); left < 16; left++ {
|
for left := range ruleMatchState(16) {
|
||||||
if !s.contains(left) {
|
if !s.contains(left) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for right := ruleMatchState(0); right < 16; right++ {
|
for right := range ruleMatchState(16) {
|
||||||
if !other.contains(right) {
|
if !other.contains(right) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ func (s ruleMatchStateSet) withBase(base ruleMatchState) ruleMatchStateSet {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
var withBase ruleMatchStateSet
|
var withBase ruleMatchStateSet
|
||||||
for state := ruleMatchState(0); state < 16; state++ {
|
for state := range ruleMatchState(16) {
|
||||||
if !s.contains(state) {
|
if !s.contains(state) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ func (s ruleMatchStateSet) withBase(base ruleMatchState) ruleMatchStateSet {
|
|||||||
|
|
||||||
func (s ruleMatchStateSet) filter(allowed func(ruleMatchState) bool) ruleMatchStateSet {
|
func (s ruleMatchStateSet) filter(allowed func(ruleMatchState) bool) ruleMatchStateSet {
|
||||||
var filtered ruleMatchStateSet
|
var filtered ruleMatchStateSet
|
||||||
for state := ruleMatchState(0); state < 16; state++ {
|
for state := range ruleMatchState(16) {
|
||||||
if !s.contains(state) {
|
if !s.contains(state) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -91,10 +91,6 @@ type ruleStateMatcherWithBase interface {
|
|||||||
matchStatesWithBase(metadata *adapter.InboundContext, base ruleMatchState) ruleMatchStateSet
|
matchStatesWithBase(metadata *adapter.InboundContext, base ruleMatchState) ruleMatchStateSet
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchHeadlessRuleStates(rule adapter.HeadlessRule, metadata *adapter.InboundContext) ruleMatchStateSet {
|
|
||||||
return matchHeadlessRuleStatesWithBase(rule, metadata, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func matchHeadlessRuleStatesWithBase(rule adapter.HeadlessRule, metadata *adapter.InboundContext, base ruleMatchState) ruleMatchStateSet {
|
func matchHeadlessRuleStatesWithBase(rule adapter.HeadlessRule, metadata *adapter.InboundContext, base ruleMatchState) ruleMatchStateSet {
|
||||||
if matcher, isStateMatcher := rule.(ruleStateMatcherWithBase); isStateMatcher {
|
if matcher, isStateMatcher := rule.(ruleStateMatcherWithBase); isStateMatcher {
|
||||||
return matcher.matchStatesWithBase(metadata, base)
|
return matcher.matchStatesWithBase(metadata, base)
|
||||||
@@ -108,10 +104,6 @@ func matchHeadlessRuleStatesWithBase(rule adapter.HeadlessRule, metadata *adapte
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchRuleItemStates(item RuleItem, metadata *adapter.InboundContext) ruleMatchStateSet {
|
|
||||||
return matchRuleItemStatesWithBase(item, metadata, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func matchRuleItemStatesWithBase(item RuleItem, metadata *adapter.InboundContext, base ruleMatchState) ruleMatchStateSet {
|
func matchRuleItemStatesWithBase(item RuleItem, metadata *adapter.InboundContext, base ruleMatchState) ruleMatchStateSet {
|
||||||
if matcher, isStateMatcher := item.(ruleStateMatcherWithBase); isStateMatcher {
|
if matcher, isStateMatcher := item.(ruleStateMatcherWithBase); isStateMatcher {
|
||||||
return matcher.matchStatesWithBase(metadata, base)
|
return matcher.matchStatesWithBase(metadata, base)
|
||||||
|
|||||||
@@ -141,7 +141,6 @@ func TestAbstractLogicalRule_And_WithRuleSetInvert(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
testCase := testCase
|
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
logicalRule := &abstractLogicalRule{
|
logicalRule := &abstractLogicalRule{
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package rule
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
@@ -80,12 +81,7 @@ func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool {
|
|||||||
return r.ipSet.Contains(metadata.Destination.Addr)
|
return r.ipSet.Contains(metadata.Destination.Addr)
|
||||||
}
|
}
|
||||||
if len(metadata.DestinationAddresses) > 0 {
|
if len(metadata.DestinationAddresses) > 0 {
|
||||||
for _, address := range metadata.DestinationAddresses {
|
return slices.ContainsFunc(metadata.DestinationAddresses, r.ipSet.Contains)
|
||||||
if r.ipSet.Contains(address) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
return metadata.IPCIDRAcceptEmpty
|
return metadata.IPCIDRAcceptEmpty
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package rule
|
package rule
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
@@ -16,15 +17,11 @@ type DomainItem struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewDomainItem(domains []string, domainSuffixes []string) (*DomainItem, error) {
|
func NewDomainItem(domains []string, domainSuffixes []string) (*DomainItem, error) {
|
||||||
for _, domainItem := range domains {
|
if slices.Contains(domains, "") {
|
||||||
if domainItem == "" {
|
return nil, E.New("domain: empty item is not allowed")
|
||||||
return nil, E.New("domain: empty item is not allowed")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for _, domainSuffixItem := range domainSuffixes {
|
if slices.Contains(domainSuffixes, "") {
|
||||||
if domainSuffixItem == "" {
|
return nil, E.New("domain_suffix: empty item is not allowed")
|
||||||
return nil, E.New("domain_suffix: empty item is not allowed")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var description string
|
var description string
|
||||||
if dLen := len(domains); dLen > 0 {
|
if dLen := len(domains); dLen > 0 {
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ func TestRouteRuleSetMergeDestinationAddressGroup(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
testCase := testCase
|
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
ruleSet := newLocalRuleSetForTest("merge-destination", testCase.inner)
|
ruleSet := newLocalRuleSetForTest("merge-destination", testCase.inner)
|
||||||
@@ -223,7 +222,6 @@ func TestRouteRuleSetOuterGroupedStateMergesIntoSameGroup(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
testCase := testCase
|
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
ruleSet := newLocalRuleSetForTest("outer-merge-"+testCase.name, headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
ruleSet := newLocalRuleSetForTest("outer-merge-"+testCase.name, headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||||
@@ -652,7 +650,6 @@ func TestDNSInvertAddressLimitPreLookupRegression(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
testCase := testCase
|
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
rule := dnsRuleForTest(func(rule *abstractDefaultRule) {
|
rule := dnsRuleForTest(func(rule *abstractDefaultRule) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build !darwin
|
//go:build !darwin || !cgo
|
||||||
|
|
||||||
package ccm
|
package ccm
|
||||||
|
|
||||||
|
|||||||
@@ -124,8 +124,6 @@ type Service struct {
|
|||||||
userManager *UserManager
|
userManager *UserManager
|
||||||
accessMutex sync.RWMutex
|
accessMutex sync.RWMutex
|
||||||
usageTracker *AggregatedUsage
|
usageTracker *AggregatedUsage
|
||||||
trackingGroup sync.WaitGroup
|
|
||||||
shuttingDown bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(ctx context.Context, logger log.ContextLogger, tag string, options option.CCMServiceOptions) (adapter.Service, error) {
|
func NewService(ctx context.Context, logger log.ContextLogger, tag string, options option.CCMServiceOptions) (adapter.Service, error) {
|
||||||
@@ -283,8 +281,8 @@ func (s *Service) getAccessToken() (string, error) {
|
|||||||
|
|
||||||
func detectContextWindow(betaHeader string, totalInputTokens int64) int {
|
func detectContextWindow(betaHeader string, totalInputTokens int64) int {
|
||||||
if totalInputTokens > premiumContextThreshold {
|
if totalInputTokens > premiumContextThreshold {
|
||||||
features := strings.Split(betaHeader, ",")
|
features := strings.SplitSeq(betaHeader, ",")
|
||||||
for _, feature := range features {
|
for feature := range features {
|
||||||
if strings.HasPrefix(strings.TrimSpace(feature), "context-1m") {
|
if strings.HasPrefix(strings.TrimSpace(feature), "context-1m") {
|
||||||
return contextWindowPremium
|
return contextWindowPremium
|
||||||
}
|
}
|
||||||
@@ -507,8 +505,8 @@ func (s *Service) handleResponseWithTracking(writer http.ResponseWriter, respons
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if bytes.HasPrefix(line, []byte("data: ")) {
|
if after, ok0 := bytes.CutPrefix(line, []byte("data: ")); ok0 {
|
||||||
eventData := bytes.TrimPrefix(line, []byte("data: "))
|
eventData := after
|
||||||
if bytes.Equal(eventData, []byte("[DONE]")) {
|
if bytes.Equal(eventData, []byte("[DONE]")) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -556,8 +556,8 @@ func (s *Service) handleResponseWithTracking(writer http.ResponseWriter, respons
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if bytes.HasPrefix(line, []byte("data: ")) {
|
if after, ok0 := bytes.CutPrefix(line, []byte("data: ")); ok0 {
|
||||||
eventData := bytes.TrimPrefix(line, []byte("data: "))
|
eventData := after
|
||||||
if bytes.Equal(eventData, []byte("[DONE]")) {
|
if bytes.Equal(eventData, []byte("[DONE]")) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -851,10 +851,7 @@ func normalizeGPT5Model(model string) string {
|
|||||||
func calculateCost(stats UsageStats, model string, serviceTier string, contextWindow int) float64 {
|
func calculateCost(stats UsageStats, model string, serviceTier string, contextWindow int) float64 {
|
||||||
pricing := getPricing(model, serviceTier, contextWindow)
|
pricing := getPricing(model, serviceTier, contextWindow)
|
||||||
|
|
||||||
regularInputTokens := stats.InputTokens - stats.CachedTokens
|
regularInputTokens := max(stats.InputTokens-stats.CachedTokens, 0)
|
||||||
if regularInputTokens < 0 {
|
|
||||||
regularInputTokens = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
cost := (float64(regularInputTokens)*pricing.InputPrice +
|
cost := (float64(regularInputTokens)*pricing.InputPrice +
|
||||||
float64(stats.OutputTokens)*pricing.OutputPrice +
|
float64(stats.OutputTokens)*pricing.OutputPrice +
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ func (s *Service) Start(stage adapter.StartStage) error {
|
|||||||
|
|
||||||
if s.hasTimerMode {
|
if s.hasTimerMode {
|
||||||
s.adaptiveTimer = newAdaptiveTimer(s.logger, s.router, s.timerConfig)
|
s.adaptiveTimer = newAdaptiveTimer(s.logger, s.router, s.timerConfig)
|
||||||
|
s.adaptiveTimer.start(false)
|
||||||
if s.memoryLimit > 0 {
|
if s.memoryLimit > 0 {
|
||||||
s.logger.Info("started memory monitor with limit: ", s.memoryLimit/(1024*1024), " MiB")
|
s.logger.Info("started memory monitor with limit: ", s.memoryLimit/(1024*1024), " MiB")
|
||||||
} else {
|
} else {
|
||||||
@@ -164,7 +165,7 @@ func goMemoryPressureCallback(status C.ulong) {
|
|||||||
if isCritical {
|
if isCritical {
|
||||||
s.logger.Warn("memory pressure: ", level, ", usage: ", usage/(1024*1024), " MiB")
|
s.logger.Warn("memory pressure: ", level, ", usage: ", usage/(1024*1024), " MiB")
|
||||||
if s.adaptiveTimer != nil {
|
if s.adaptiveTimer != nil {
|
||||||
s.adaptiveTimer.startNow()
|
s.adaptiveTimer.start(true)
|
||||||
}
|
}
|
||||||
} else if isWarning {
|
} else if isWarning {
|
||||||
s.logger.Warn("memory pressure: ", level, ", usage: ", usage/(1024*1024), " MiB")
|
s.logger.Warn("memory pressure: ", level, ", usage: ", usage/(1024*1024), " MiB")
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ func (s *Service) Start(stage adapter.StartStage) error {
|
|||||||
return E.New("memory pressure monitoring is not available on this platform without memory_limit")
|
return E.New("memory pressure monitoring is not available on this platform without memory_limit")
|
||||||
}
|
}
|
||||||
s.adaptiveTimer = newAdaptiveTimer(s.logger, s.router, s.timerConfig)
|
s.adaptiveTimer = newAdaptiveTimer(s.logger, s.router, s.timerConfig)
|
||||||
s.adaptiveTimer.start(0)
|
s.adaptiveTimer.start(false)
|
||||||
if s.useAvailable {
|
if s.useAvailable {
|
||||||
s.logger.Info("started memory monitor with available memory detection")
|
s.logger.Info("started memory monitor with available memory detection")
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -55,17 +55,13 @@ func newAdaptiveTimer(logger log.ContextLogger, router adapter.Router, config ti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *adaptiveTimer) start(_ uint64) {
|
func (t *adaptiveTimer) start(immediate bool) {
|
||||||
t.access.Lock()
|
|
||||||
defer t.access.Unlock()
|
|
||||||
t.startLocked()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *adaptiveTimer) startNow() {
|
|
||||||
t.access.Lock()
|
t.access.Lock()
|
||||||
t.startLocked()
|
t.startLocked()
|
||||||
t.access.Unlock()
|
t.access.Unlock()
|
||||||
t.poll()
|
if immediate {
|
||||||
|
t.poll()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *adaptiveTimer) startLocked() {
|
func (t *adaptiveTimer) startLocked() {
|
||||||
@@ -90,12 +86,6 @@ func (t *adaptiveTimer) stopLocked() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *adaptiveTimer) running() bool {
|
|
||||||
t.access.Lock()
|
|
||||||
defer t.access.Unlock()
|
|
||||||
return t.timer != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *adaptiveTimer) poll() {
|
func (t *adaptiveTimer) poll() {
|
||||||
t.access.Lock()
|
t.access.Lock()
|
||||||
defer t.access.Unlock()
|
defer t.access.Unlock()
|
||||||
@@ -144,13 +134,8 @@ func (t *adaptiveTimer) poll() {
|
|||||||
interval = t.maxInterval
|
interval = t.maxInterval
|
||||||
} else {
|
} else {
|
||||||
timeToLimit := time.Duration(float64(remaining) / float64(delta) * float64(t.lastInterval))
|
timeToLimit := time.Duration(float64(remaining) / float64(delta) * float64(t.lastInterval))
|
||||||
interval = timeToLimit / time.Duration(t.checksBeforeLimit)
|
interval = max(timeToLimit/time.Duration(t.checksBeforeLimit), t.minInterval)
|
||||||
if interval < t.minInterval {
|
interval = min(interval, t.maxInterval)
|
||||||
interval = t.minInterval
|
|
||||||
}
|
|
||||||
if interval > t.maxInterval {
|
|
||||||
interval = t.maxInterval
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t.lastInterval = interval
|
t.lastInterval = interval
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
@@ -127,7 +128,7 @@ func (t *resolve1Manager) createMetadata(sender dbus.Sender) adapter.InboundCont
|
|||||||
var uidFound bool
|
var uidFound bool
|
||||||
statusContent, err := os.ReadFile(F.ToString("/proc/", senderPid, "/status"))
|
statusContent, err := os.ReadFile(F.ToString("/proc/", senderPid, "/status"))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for _, line := range strings.Split(string(statusContent), "\n") {
|
for line := range strings.SplitSeq(string(statusContent), "\n") {
|
||||||
line = strings.TrimSpace(line)
|
line = strings.TrimSpace(line)
|
||||||
if strings.HasPrefix(line, "Uid:") {
|
if strings.HasPrefix(line, "Uid:") {
|
||||||
fields := strings.Fields(line)
|
fields := strings.Fields(line)
|
||||||
@@ -255,8 +256,8 @@ func (t *resolve1Manager) ResolveAddress(sender dbus.Sender, ifIndex int32, fami
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var nibbles []string
|
var nibbles []string
|
||||||
for i := len(address) - 1; i >= 0; i-- {
|
for _, v := range slices.Backward(address) {
|
||||||
b := address[i]
|
b := v
|
||||||
nibbles = append(nibbles, fmt.Sprintf("%x", b&0x0F))
|
nibbles = append(nibbles, fmt.Sprintf("%x", b&0x0F))
|
||||||
nibbles = append(nibbles, fmt.Sprintf("%x", b>>4))
|
nibbles = append(nibbles, fmt.Sprintf("%x", b>>4))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ func (t *Transport) tryOneName(ctx context.Context, servers *LinkServers, messag
|
|||||||
sLen := uint32(len(servers.Servers))
|
sLen := uint32(len(servers.Servers))
|
||||||
var lastErr error
|
var lastErr error
|
||||||
for i := 0; i < t.attempts; i++ {
|
for i := 0; i < t.attempts; i++ {
|
||||||
for j := uint32(0); j < sLen; j++ {
|
for j := range sLen {
|
||||||
server := servers.Servers[(serverOffset+j)%sLen]
|
server := servers.Servers[(serverOffset+j)%sLen]
|
||||||
question := message.Question[0]
|
question := message.Question[0]
|
||||||
question.Name = fqdn
|
question.Name = fqdn
|
||||||
|
|||||||
@@ -105,15 +105,3 @@ func ParsePluginOptions(s string) (opts Args, err error) {
|
|||||||
}
|
}
|
||||||
return opts, nil
|
return opts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Escape backslashes and all the bytes that are in set.
|
|
||||||
func backslashEscape(s string, set []byte) string {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
for _, b := range []byte(s) {
|
|
||||||
if b == '\\' || bytes.IndexByte(set, b) != -1 {
|
|
||||||
buf.WriteByte('\\')
|
|
||||||
}
|
|
||||||
buf.WriteByte(b)
|
|
||||||
}
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/tls"
|
"github.com/sagernet/sing-box/common/tls"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing/common"
|
|
||||||
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"
|
||||||
|
|
||||||
@@ -100,7 +99,7 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
client := NewGunServiceClient(clientConn).(GunServiceCustomNameClient)
|
client := NewGunServiceClient(clientConn).(GunServiceCustomNameClient)
|
||||||
ctx, cancel := common.ContextWithCancelCause(ctx)
|
ctx, cancel := context.WithCancelCause(ctx)
|
||||||
stream, err := client.TunCustomName(ctx, c.serviceName)
|
stream, err := client.TunCustomName(ctx, c.serviceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cancel(err)
|
cancel(err)
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ import (
|
|||||||
type requestInfoKey struct{}
|
type requestInfoKey struct{}
|
||||||
|
|
||||||
// NewRequestInfoContext creates a context with ri.
|
// NewRequestInfoContext creates a context with ri.
|
||||||
func NewRequestInfoContext(ctx context.Context, ri interface{}) context.Context {
|
func NewRequestInfoContext(ctx context.Context, ri any) context.Context {
|
||||||
return context.WithValue(ctx, requestInfoKey{}, ri)
|
return context.WithValue(ctx, requestInfoKey{}, ri)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequestInfoFromContext extracts the RequestInfo from ctx.
|
// RequestInfoFromContext extracts the RequestInfo from ctx.
|
||||||
func RequestInfoFromContext(ctx context.Context) interface{} {
|
func RequestInfoFromContext(ctx context.Context) any {
|
||||||
return ctx.Value(requestInfoKey{})
|
return ctx.Value(requestInfoKey{})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,11 +39,11 @@ func RequestInfoFromContext(ctx context.Context) interface{} {
|
|||||||
type clientHandshakeInfoKey struct{}
|
type clientHandshakeInfoKey struct{}
|
||||||
|
|
||||||
// ClientHandshakeInfoFromContext extracts the ClientHandshakeInfo from ctx.
|
// ClientHandshakeInfoFromContext extracts the ClientHandshakeInfo from ctx.
|
||||||
func ClientHandshakeInfoFromContext(ctx context.Context) interface{} {
|
func ClientHandshakeInfoFromContext(ctx context.Context) any {
|
||||||
return ctx.Value(clientHandshakeInfoKey{})
|
return ctx.Value(clientHandshakeInfoKey{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClientHandshakeInfoContext creates a context with chi.
|
// NewClientHandshakeInfoContext creates a context with chi.
|
||||||
func NewClientHandshakeInfoContext(ctx context.Context, chi interface{}) context.Context {
|
func NewClientHandshakeInfoContext(ctx context.Context, chi any) context.Context {
|
||||||
return context.WithValue(ctx, clientHandshakeInfoKey{}, chi)
|
return context.WithValue(ctx, clientHandshakeInfoKey{}, chi)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,16 +20,15 @@ package credentials
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
const alpnProtoStrH2 = "h2"
|
const alpnProtoStrH2 = "h2"
|
||||||
|
|
||||||
// AppendH2ToNextProtos appends h2 to next protos.
|
// AppendH2ToNextProtos appends h2 to next protos.
|
||||||
func AppendH2ToNextProtos(ps []string) []string {
|
func AppendH2ToNextProtos(ps []string) []string {
|
||||||
for _, p := range ps {
|
if slices.Contains(ps, alpnProtoStrH2) {
|
||||||
if p == alpnProtoStrH2 {
|
return ps
|
||||||
return ps
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ret := make([]string, 0, len(ps)+1)
|
ret := make([]string, 0, len(ps)+1)
|
||||||
ret = append(ret, ps...)
|
ret = append(ret, ps...)
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ func (s *Server) Tun(server GunService_TunServer) error {
|
|||||||
if grpcMetadata, loaded := gM.FromIncomingContext(server.Context()); loaded {
|
if grpcMetadata, loaded := gM.FromIncomingContext(server.Context()); loaded {
|
||||||
forwardFrom := strings.Join(grpcMetadata.Get("X-Forwarded-For"), ",")
|
forwardFrom := strings.Join(grpcMetadata.Get("X-Forwarded-For"), ",")
|
||||||
if forwardFrom != "" {
|
if forwardFrom != "" {
|
||||||
for _, from := range strings.Split(forwardFrom, ",") {
|
for from := range strings.SplitSeq(forwardFrom, ",") {
|
||||||
originAddr := M.ParseSocksaddr(from)
|
originAddr := M.ParseSocksaddr(from)
|
||||||
if originAddr.IsValid() {
|
if originAddr.IsValid() {
|
||||||
source = originAddr.Unwrap()
|
source = originAddr.Unwrap()
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ func (c *ClientBind) receive(packets [][]byte, sizes []int, eps []conn.Endpoint)
|
|||||||
sizes[0] = n
|
sizes[0] = n
|
||||||
if n > 3 {
|
if n > 3 {
|
||||||
b := packets[0]
|
b := packets[0]
|
||||||
common.ClearArray(b[1:4])
|
clear(b[1:4])
|
||||||
}
|
}
|
||||||
eps[0] = remoteEndpoint(M.SocksaddrFromNet(addr).Unwrap().AddrPort())
|
eps[0] = remoteEndpoint(M.SocksaddrFromNet(addr).Unwrap().AddrPort())
|
||||||
count = 1
|
count = 1
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/gvisor/pkg/buffer"
|
"github.com/sagernet/gvisor/pkg/buffer"
|
||||||
@@ -42,6 +43,7 @@ type stackDevice struct {
|
|||||||
outbound chan *stack.PacketBuffer
|
outbound chan *stack.PacketBuffer
|
||||||
packetOutbound chan *buf.Buffer
|
packetOutbound chan *buf.Buffer
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
|
closeOnce sync.Once
|
||||||
dispatcher stack.NetworkDispatcher
|
dispatcher stack.NetworkDispatcher
|
||||||
inet4Address netip.Addr
|
inet4Address netip.Addr
|
||||||
inet6Address netip.Addr
|
inet6Address netip.Addr
|
||||||
@@ -146,11 +148,17 @@ func (w *stackDevice) ListenPacket(ctx context.Context, destination M.Socksaddr)
|
|||||||
}
|
}
|
||||||
var networkProtocol tcpip.NetworkProtocolNumber
|
var networkProtocol tcpip.NetworkProtocolNumber
|
||||||
if destination.IsIPv4() {
|
if destination.IsIPv4() {
|
||||||
|
if !w.inet4Address.IsValid() {
|
||||||
|
return nil, E.New("missing IPv4 local address")
|
||||||
|
}
|
||||||
networkProtocol = header.IPv4ProtocolNumber
|
networkProtocol = header.IPv4ProtocolNumber
|
||||||
bind.Addr = tun.AddressFromAddr(w.inet4Address)
|
bind.Addr = tun.AddressFromAddr(w.inet4Address)
|
||||||
} else {
|
} else {
|
||||||
|
if !w.inet6Address.IsValid() {
|
||||||
|
return nil, E.New("missing IPv6 local address")
|
||||||
|
}
|
||||||
networkProtocol = header.IPv6ProtocolNumber
|
networkProtocol = header.IPv6ProtocolNumber
|
||||||
bind.Addr = tun.AddressFromAddr(w.inet4Address)
|
bind.Addr = tun.AddressFromAddr(w.inet6Address)
|
||||||
}
|
}
|
||||||
udpConn, err := gonet.DialUDP(w.stack, &bind, nil, networkProtocol)
|
udpConn, err := gonet.DialUDP(w.stack, &bind, nil, networkProtocol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -244,13 +252,15 @@ func (w *stackDevice) Events() <-chan wgTun.Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *stackDevice) Close() error {
|
func (w *stackDevice) Close() error {
|
||||||
close(w.done)
|
w.closeOnce.Do(func() {
|
||||||
close(w.events)
|
close(w.done)
|
||||||
w.stack.Close()
|
close(w.events)
|
||||||
for _, endpoint := range w.stack.CleanupEndpoints() {
|
w.stack.Close()
|
||||||
endpoint.Abort()
|
for _, endpoint := range w.stack.CleanupEndpoints() {
|
||||||
}
|
endpoint.Abort()
|
||||||
w.stack.Wait()
|
}
|
||||||
|
w.stack.Wait()
|
||||||
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ func (w *systemDevice) Start() error {
|
|||||||
}
|
}
|
||||||
err = tunInterface.Start()
|
err = tunInterface.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
tunInterface.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
w.options.Logger.Info("started at ", w.options.Name)
|
w.options.Logger.Info("started at ", w.options.Name)
|
||||||
@@ -147,7 +148,7 @@ func (w *systemDevice) Write(bufs [][]byte, offset int) (count int, err error) {
|
|||||||
} else {
|
} else {
|
||||||
for _, packet := range bufs {
|
for _, packet := range bufs {
|
||||||
if tun.PacketOffset > 0 {
|
if tun.PacketOffset > 0 {
|
||||||
common.ClearArray(packet[offset-tun.PacketOffset : offset])
|
clear(packet[offset-tun.PacketOffset : offset])
|
||||||
tun.PacketFillHeader(packet[offset-tun.PacketOffset:], tun.PacketIPVersion(packet[offset:]))
|
tun.PacketFillHeader(packet[offset-tun.PacketOffset:], tun.PacketIPVersion(packet[offset:]))
|
||||||
}
|
}
|
||||||
_, err = w.device.Write(packet[offset-tun.PacketOffset:])
|
_, err = w.device.Write(packet[offset-tun.PacketOffset:])
|
||||||
@@ -177,8 +178,14 @@ func (w *systemDevice) Events() <-chan wgTun.Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *systemDevice) Close() error {
|
func (w *systemDevice) Close() error {
|
||||||
close(w.events)
|
var err error
|
||||||
return w.device.Close()
|
w.closeOnce.Do(func() {
|
||||||
|
close(w.events)
|
||||||
|
if w.device != nil {
|
||||||
|
err = w.device.Close()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *systemDevice) BatchSize() int {
|
func (w *systemDevice) BatchSize() int {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package wireguard
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/gvisor/pkg/buffer"
|
"github.com/sagernet/gvisor/pkg/buffer"
|
||||||
@@ -20,7 +21,6 @@ import (
|
|||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing-tun"
|
"github.com/sagernet/sing-tun"
|
||||||
"github.com/sagernet/sing-tun/ping"
|
"github.com/sagernet/sing-tun/ping"
|
||||||
"github.com/sagernet/sing/common"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/logger"
|
"github.com/sagernet/sing/common/logger"
|
||||||
"github.com/sagernet/wireguard-go/device"
|
"github.com/sagernet/wireguard-go/device"
|
||||||
@@ -35,6 +35,7 @@ type systemStackDevice struct {
|
|||||||
stack *stack.Stack
|
stack *stack.Stack
|
||||||
endpoint *deviceEndpoint
|
endpoint *deviceEndpoint
|
||||||
writeBufs [][]byte
|
writeBufs [][]byte
|
||||||
|
closeOnce sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSystemStackDevice(options DeviceOptions) (*systemStackDevice, error) {
|
func newSystemStackDevice(options DeviceOptions) (*systemStackDevice, error) {
|
||||||
@@ -104,13 +105,13 @@ func (w *systemStackDevice) Write(bufs [][]byte, offset int) (count int, err err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(w.writeBufs) > 0 {
|
if len(w.writeBufs) > 0 {
|
||||||
return w.batchDevice.BatchWrite(bufs, offset)
|
return w.batchDevice.BatchWrite(w.writeBufs, offset)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, packet := range bufs {
|
for _, packet := range bufs {
|
||||||
if !w.writeStack(packet[offset:]) {
|
if !w.writeStack(packet[offset:]) {
|
||||||
if tun.PacketOffset > 0 {
|
if tun.PacketOffset > 0 {
|
||||||
common.ClearArray(packet[offset-tun.PacketOffset : offset])
|
clear(packet[offset-tun.PacketOffset : offset])
|
||||||
tun.PacketFillHeader(packet[offset-tun.PacketOffset:], tun.PacketIPVersion(packet[offset:]))
|
tun.PacketFillHeader(packet[offset-tun.PacketOffset:], tun.PacketIPVersion(packet[offset:]))
|
||||||
}
|
}
|
||||||
_, err = w.device.Write(packet[offset-tun.PacketOffset:])
|
_, err = w.device.Write(packet[offset-tun.PacketOffset:])
|
||||||
@@ -125,13 +126,17 @@ func (w *systemStackDevice) Write(bufs [][]byte, offset int) (count int, err err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *systemStackDevice) Close() error {
|
func (w *systemStackDevice) Close() error {
|
||||||
close(w.endpoint.done)
|
var err error
|
||||||
w.stack.Close()
|
w.closeOnce.Do(func() {
|
||||||
for _, endpoint := range w.stack.CleanupEndpoints() {
|
close(w.endpoint.done)
|
||||||
endpoint.Abort()
|
w.stack.Close()
|
||||||
}
|
for _, endpoint := range w.stack.CleanupEndpoints() {
|
||||||
w.stack.Wait()
|
endpoint.Abort()
|
||||||
return w.systemDevice.Close()
|
}
|
||||||
|
w.stack.Wait()
|
||||||
|
err = w.systemDevice.Close()
|
||||||
|
})
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *systemStackDevice) writeStack(packet []byte) bool {
|
func (w *systemStackDevice) writeStack(packet []byte) bool {
|
||||||
|
|||||||
@@ -182,10 +182,10 @@ func (e *Endpoint) Start(resolve bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger := &device.Logger{
|
logger := &device.Logger{
|
||||||
Verbosef: func(format string, args ...interface{}) {
|
Verbosef: func(format string, args ...any) {
|
||||||
e.options.Logger.Debug(fmt.Sprintf(strings.ToLower(format), args...))
|
e.options.Logger.Debug(fmt.Sprintf(strings.ToLower(format), args...))
|
||||||
},
|
},
|
||||||
Errorf: func(format string, args ...interface{}) {
|
Errorf: func(format string, args ...any) {
|
||||||
e.options.Logger.Error(fmt.Sprintf(strings.ToLower(format), args...))
|
e.options.Logger.Error(fmt.Sprintf(strings.ToLower(format), args...))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -197,13 +197,15 @@ func (e *Endpoint) Start(resolve bool) error {
|
|||||||
}
|
}
|
||||||
wgDevice := device.NewDevice(e.options.Context, deviceInput, bind, logger, e.options.Workers)
|
wgDevice := device.NewDevice(e.options.Context, deviceInput, bind, logger, e.options.Workers)
|
||||||
e.tunDevice.SetDevice(wgDevice)
|
e.tunDevice.SetDevice(wgDevice)
|
||||||
ipcConf := e.ipcConf
|
var ipcConf strings.Builder
|
||||||
|
ipcConf.WriteString(e.ipcConf)
|
||||||
for _, peer := range e.peers {
|
for _, peer := range e.peers {
|
||||||
ipcConf += peer.GenerateIpcLines()
|
ipcConf.WriteString(peer.GenerateIpcLines())
|
||||||
}
|
}
|
||||||
err = wgDevice.IpcSet(ipcConf)
|
err = wgDevice.IpcSet(ipcConf.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "setup wireguard: \n", ipcConf)
|
wgDevice.Close()
|
||||||
|
return E.Cause(err, "setup wireguard: \n", ipcConf.String())
|
||||||
}
|
}
|
||||||
e.device = wgDevice
|
e.device = wgDevice
|
||||||
e.pause = service.FromContext[pause.Manager](e.options.Context)
|
e.pause = service.FromContext[pause.Manager](e.options.Context)
|
||||||
@@ -231,10 +233,12 @@ func (e *Endpoint) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
|
|||||||
func (e *Endpoint) Close() error {
|
func (e *Endpoint) Close() error {
|
||||||
if e.pauseCallback != nil {
|
if e.pauseCallback != nil {
|
||||||
e.pause.UnregisterCallback(e.pauseCallback)
|
e.pause.UnregisterCallback(e.pauseCallback)
|
||||||
|
e.pauseCallback = nil
|
||||||
}
|
}
|
||||||
if e.device != nil {
|
if e.device != nil {
|
||||||
e.device.Down()
|
e.device.Down()
|
||||||
e.device.Close()
|
e.device.Close()
|
||||||
|
e.device = nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -273,18 +277,19 @@ type peerConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c peerConfig) GenerateIpcLines() string {
|
func (c peerConfig) GenerateIpcLines() string {
|
||||||
ipcLines := "\npublic_key=" + c.publicKeyHex
|
var ipcLines strings.Builder
|
||||||
|
ipcLines.WriteString("\npublic_key=" + c.publicKeyHex)
|
||||||
if c.endpoint.IsValid() {
|
if c.endpoint.IsValid() {
|
||||||
ipcLines += "\nendpoint=" + c.endpoint.String()
|
ipcLines.WriteString("\nendpoint=" + c.endpoint.String())
|
||||||
}
|
}
|
||||||
if c.preSharedKeyHex != "" {
|
if c.preSharedKeyHex != "" {
|
||||||
ipcLines += "\npreshared_key=" + c.preSharedKeyHex
|
ipcLines.WriteString("\npreshared_key=" + c.preSharedKeyHex)
|
||||||
}
|
}
|
||||||
for _, allowedIP := range c.allowedIPs {
|
for _, allowedIP := range c.allowedIPs {
|
||||||
ipcLines += "\nallowed_ip=" + allowedIP.String()
|
ipcLines.WriteString("\nallowed_ip=" + allowedIP.String())
|
||||||
}
|
}
|
||||||
if c.keepalive > 0 {
|
if c.keepalive > 0 {
|
||||||
ipcLines += "\npersistent_keepalive_interval=" + F.ToString(c.keepalive)
|
ipcLines.WriteString("\npersistent_keepalive_interval=" + F.ToString(c.keepalive))
|
||||||
}
|
}
|
||||||
return ipcLines
|
return ipcLines.String()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user