mirror of
https://github.com/bolucat/Archive.git
synced 2025-09-27 04:30:12 +08:00
Update On Sun May 25 20:34:13 CEST 2025
This commit is contained in:
1
.github/update.log
vendored
1
.github/update.log
vendored
@@ -1009,3 +1009,4 @@ Update On Wed May 21 20:37:50 CEST 2025
|
|||||||
Update On Thu May 22 20:37:12 CEST 2025
|
Update On Thu May 22 20:37:12 CEST 2025
|
||||||
Update On Fri May 23 20:34:50 CEST 2025
|
Update On Fri May 23 20:34:50 CEST 2025
|
||||||
Update On Sat May 24 20:33:25 CEST 2025
|
Update On Sat May 24 20:33:25 CEST 2025
|
||||||
|
Update On Sun May 25 20:34:05 CEST 2025
|
||||||
|
@@ -5,7 +5,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net"
|
"net"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
@@ -203,12 +202,21 @@ func NewBase(opt BaseOption) *Base {
|
|||||||
|
|
||||||
type conn struct {
|
type conn struct {
|
||||||
N.ExtendedConn
|
N.ExtendedConn
|
||||||
chain C.Chain
|
chain C.Chain
|
||||||
actualRemoteDestination string
|
adapterAddr string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conn) RemoteDestination() string {
|
func (c *conn) RemoteDestination() string {
|
||||||
return c.actualRemoteDestination
|
if remoteAddr := c.RemoteAddr(); remoteAddr != nil {
|
||||||
|
m := C.Metadata{}
|
||||||
|
if err := m.SetRemoteAddr(remoteAddr); err != nil {
|
||||||
|
if m.Valid() {
|
||||||
|
return m.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
host, _, _ := net.SplitHostPort(c.adapterAddr)
|
||||||
|
return host
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chains implements C.Connection
|
// Chains implements C.Connection
|
||||||
@@ -241,19 +249,20 @@ func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn {
|
|||||||
if _, ok := c.(syscall.Conn); !ok { // exclusion system conn like *net.TCPConn
|
if _, ok := c.(syscall.Conn); !ok { // exclusion system conn like *net.TCPConn
|
||||||
c = N.NewDeadlineConn(c) // most conn from outbound can't handle readDeadline correctly
|
c = N.NewDeadlineConn(c) // most conn from outbound can't handle readDeadline correctly
|
||||||
}
|
}
|
||||||
return &conn{N.NewExtendedConn(c), []string{a.Name()}, parseRemoteDestination(a.Addr())}
|
return &conn{N.NewExtendedConn(c), []string{a.Name()}, a.Addr()}
|
||||||
}
|
}
|
||||||
|
|
||||||
type packetConn struct {
|
type packetConn struct {
|
||||||
N.EnhancePacketConn
|
N.EnhancePacketConn
|
||||||
chain C.Chain
|
chain C.Chain
|
||||||
adapterName string
|
adapterName string
|
||||||
connID string
|
connID string
|
||||||
actualRemoteDestination string
|
adapterAddr string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *packetConn) RemoteDestination() string {
|
func (c *packetConn) RemoteDestination() string {
|
||||||
return c.actualRemoteDestination
|
host, _, _ := net.SplitHostPort(c.adapterAddr)
|
||||||
|
return host
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chains implements C.Connection
|
// Chains implements C.Connection
|
||||||
@@ -292,19 +301,7 @@ func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn {
|
|||||||
if _, ok := pc.(syscall.Conn); !ok { // exclusion system conn like *net.UDPConn
|
if _, ok := pc.(syscall.Conn); !ok { // exclusion system conn like *net.UDPConn
|
||||||
epc = N.NewDeadlineEnhancePacketConn(epc) // most conn from outbound can't handle readDeadline correctly
|
epc = N.NewDeadlineEnhancePacketConn(epc) // most conn from outbound can't handle readDeadline correctly
|
||||||
}
|
}
|
||||||
return &packetConn{epc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), parseRemoteDestination(a.Addr())}
|
return &packetConn{epc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), a.Addr()}
|
||||||
}
|
|
||||||
|
|
||||||
func parseRemoteDestination(addr string) string {
|
|
||||||
if dst, _, err := net.SplitHostPort(addr); err == nil {
|
|
||||||
return dst
|
|
||||||
} else {
|
|
||||||
if addrError, ok := err.(*net.AddrError); ok && strings.Contains(addrError.Err, "missing port") {
|
|
||||||
return dst
|
|
||||||
} else {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type AddRef interface {
|
type AddRef interface {
|
||||||
|
@@ -20,7 +20,7 @@ type connReadResult struct {
|
|||||||
type Conn struct {
|
type Conn struct {
|
||||||
network.ExtendedConn
|
network.ExtendedConn
|
||||||
deadline atomic.TypedValue[time.Time]
|
deadline atomic.TypedValue[time.Time]
|
||||||
pipeDeadline pipeDeadline
|
pipeDeadline PipeDeadline
|
||||||
disablePipe atomic.Bool
|
disablePipe atomic.Bool
|
||||||
inRead atomic.Bool
|
inRead atomic.Bool
|
||||||
resultCh chan *connReadResult
|
resultCh chan *connReadResult
|
||||||
@@ -34,7 +34,7 @@ func IsConn(conn any) bool {
|
|||||||
func NewConn(conn net.Conn) *Conn {
|
func NewConn(conn net.Conn) *Conn {
|
||||||
c := &Conn{
|
c := &Conn{
|
||||||
ExtendedConn: bufio.NewExtendedConn(conn),
|
ExtendedConn: bufio.NewExtendedConn(conn),
|
||||||
pipeDeadline: makePipeDeadline(),
|
pipeDeadline: MakePipeDeadline(),
|
||||||
resultCh: make(chan *connReadResult, 1),
|
resultCh: make(chan *connReadResult, 1),
|
||||||
}
|
}
|
||||||
c.resultCh <- nil
|
c.resultCh <- nil
|
||||||
@@ -58,7 +58,7 @@ func (c *Conn) Read(p []byte) (n int, err error) {
|
|||||||
c.resultCh <- nil
|
c.resultCh <- nil
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case <-c.pipeDeadline.wait():
|
case <-c.pipeDeadline.Wait():
|
||||||
return 0, os.ErrDeadlineExceeded
|
return 0, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ func (c *Conn) ReadBuffer(buffer *buf.Buffer) (err error) {
|
|||||||
c.resultCh <- nil
|
c.resultCh <- nil
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case <-c.pipeDeadline.wait():
|
case <-c.pipeDeadline.Wait():
|
||||||
return os.ErrDeadlineExceeded
|
return os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ func (c *Conn) SetReadDeadline(t time.Time) error {
|
|||||||
return c.ExtendedConn.SetReadDeadline(t)
|
return c.ExtendedConn.SetReadDeadline(t)
|
||||||
}
|
}
|
||||||
c.deadline.Store(t)
|
c.deadline.Store(t)
|
||||||
c.pipeDeadline.set(t)
|
c.pipeDeadline.Set(t)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -19,7 +19,7 @@ type readResult struct {
|
|||||||
type NetPacketConn struct {
|
type NetPacketConn struct {
|
||||||
net.PacketConn
|
net.PacketConn
|
||||||
deadline atomic.TypedValue[time.Time]
|
deadline atomic.TypedValue[time.Time]
|
||||||
pipeDeadline pipeDeadline
|
pipeDeadline PipeDeadline
|
||||||
disablePipe atomic.Bool
|
disablePipe atomic.Bool
|
||||||
inRead atomic.Bool
|
inRead atomic.Bool
|
||||||
resultCh chan any
|
resultCh chan any
|
||||||
@@ -28,7 +28,7 @@ type NetPacketConn struct {
|
|||||||
func NewNetPacketConn(pc net.PacketConn) net.PacketConn {
|
func NewNetPacketConn(pc net.PacketConn) net.PacketConn {
|
||||||
npc := &NetPacketConn{
|
npc := &NetPacketConn{
|
||||||
PacketConn: pc,
|
PacketConn: pc,
|
||||||
pipeDeadline: makePipeDeadline(),
|
pipeDeadline: MakePipeDeadline(),
|
||||||
resultCh: make(chan any, 1),
|
resultCh: make(chan any, 1),
|
||||||
}
|
}
|
||||||
npc.resultCh <- nil
|
npc.resultCh <- nil
|
||||||
@@ -83,7 +83,7 @@ FOR:
|
|||||||
c.resultCh <- nil
|
c.resultCh <- nil
|
||||||
break FOR
|
break FOR
|
||||||
}
|
}
|
||||||
case <-c.pipeDeadline.wait():
|
case <-c.pipeDeadline.Wait():
|
||||||
return 0, nil, os.ErrDeadlineExceeded
|
return 0, nil, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,7 +122,7 @@ func (c *NetPacketConn) SetReadDeadline(t time.Time) error {
|
|||||||
return c.PacketConn.SetReadDeadline(t)
|
return c.PacketConn.SetReadDeadline(t)
|
||||||
}
|
}
|
||||||
c.deadline.Store(t)
|
c.deadline.Store(t)
|
||||||
c.pipeDeadline.set(t)
|
c.pipeDeadline.Set(t)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -52,7 +52,7 @@ FOR:
|
|||||||
c.netPacketConn.resultCh <- nil
|
c.netPacketConn.resultCh <- nil
|
||||||
break FOR
|
break FOR
|
||||||
}
|
}
|
||||||
case <-c.netPacketConn.pipeDeadline.wait():
|
case <-c.netPacketConn.pipeDeadline.Wait():
|
||||||
return nil, nil, nil, os.ErrDeadlineExceeded
|
return nil, nil, nil, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -69,7 +69,7 @@ FOR:
|
|||||||
c.netPacketConn.resultCh <- nil
|
c.netPacketConn.resultCh <- nil
|
||||||
break FOR
|
break FOR
|
||||||
}
|
}
|
||||||
case <-c.netPacketConn.pipeDeadline.wait():
|
case <-c.netPacketConn.pipeDeadline.Wait():
|
||||||
return M.Socksaddr{}, os.ErrDeadlineExceeded
|
return M.Socksaddr{}, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,7 +146,7 @@ FOR:
|
|||||||
c.netPacketConn.resultCh <- nil
|
c.netPacketConn.resultCh <- nil
|
||||||
break FOR
|
break FOR
|
||||||
}
|
}
|
||||||
case <-c.netPacketConn.pipeDeadline.wait():
|
case <-c.netPacketConn.pipeDeadline.Wait():
|
||||||
return nil, M.Socksaddr{}, os.ErrDeadlineExceeded
|
return nil, M.Socksaddr{}, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,24 +9,24 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// pipeDeadline is an abstraction for handling timeouts.
|
// PipeDeadline is an abstraction for handling timeouts.
|
||||||
type pipeDeadline struct {
|
type PipeDeadline struct {
|
||||||
mu sync.Mutex // Guards timer and cancel
|
mu sync.Mutex // Guards timer and cancel
|
||||||
timer *time.Timer
|
timer *time.Timer
|
||||||
cancel chan struct{} // Must be non-nil
|
cancel chan struct{} // Must be non-nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makePipeDeadline() pipeDeadline {
|
func MakePipeDeadline() PipeDeadline {
|
||||||
return pipeDeadline{cancel: make(chan struct{})}
|
return PipeDeadline{cancel: make(chan struct{})}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set sets the point in time when the deadline will time out.
|
// Set sets the point in time when the deadline will time out.
|
||||||
// A timeout event is signaled by closing the channel returned by waiter.
|
// A timeout event is signaled by closing the channel returned by waiter.
|
||||||
// Once a timeout has occurred, the deadline can be refreshed by specifying a
|
// Once a timeout has occurred, the deadline can be refreshed by specifying a
|
||||||
// t value in the future.
|
// t value in the future.
|
||||||
//
|
//
|
||||||
// A zero value for t prevents timeout.
|
// A zero value for t prevents timeout.
|
||||||
func (d *pipeDeadline) set(t time.Time) {
|
func (d *PipeDeadline) Set(t time.Time) {
|
||||||
d.mu.Lock()
|
d.mu.Lock()
|
||||||
defer d.mu.Unlock()
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
@@ -61,8 +61,8 @@ func (d *pipeDeadline) set(t time.Time) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait returns a channel that is closed when the deadline is exceeded.
|
// Wait returns a channel that is closed when the deadline is exceeded.
|
||||||
func (d *pipeDeadline) wait() chan struct{} {
|
func (d *PipeDeadline) Wait() chan struct{} {
|
||||||
d.mu.Lock()
|
d.mu.Lock()
|
||||||
defer d.mu.Unlock()
|
defer d.mu.Unlock()
|
||||||
return d.cancel
|
return d.cancel
|
||||||
|
@@ -33,8 +33,8 @@ type pipe struct {
|
|||||||
localDone chan struct{}
|
localDone chan struct{}
|
||||||
remoteDone <-chan struct{}
|
remoteDone <-chan struct{}
|
||||||
|
|
||||||
readDeadline pipeDeadline
|
readDeadline PipeDeadline
|
||||||
writeDeadline pipeDeadline
|
writeDeadline PipeDeadline
|
||||||
|
|
||||||
readWaitOptions N.ReadWaitOptions
|
readWaitOptions N.ReadWaitOptions
|
||||||
}
|
}
|
||||||
@@ -56,15 +56,15 @@ func Pipe() (net.Conn, net.Conn) {
|
|||||||
rdRx: cb1, rdTx: cn1,
|
rdRx: cb1, rdTx: cn1,
|
||||||
wrTx: cb2, wrRx: cn2,
|
wrTx: cb2, wrRx: cn2,
|
||||||
localDone: done1, remoteDone: done2,
|
localDone: done1, remoteDone: done2,
|
||||||
readDeadline: makePipeDeadline(),
|
readDeadline: MakePipeDeadline(),
|
||||||
writeDeadline: makePipeDeadline(),
|
writeDeadline: MakePipeDeadline(),
|
||||||
}
|
}
|
||||||
p2 := &pipe{
|
p2 := &pipe{
|
||||||
rdRx: cb2, rdTx: cn2,
|
rdRx: cb2, rdTx: cn2,
|
||||||
wrTx: cb1, wrRx: cn1,
|
wrTx: cb1, wrRx: cn1,
|
||||||
localDone: done2, remoteDone: done1,
|
localDone: done2, remoteDone: done1,
|
||||||
readDeadline: makePipeDeadline(),
|
readDeadline: MakePipeDeadline(),
|
||||||
writeDeadline: makePipeDeadline(),
|
writeDeadline: MakePipeDeadline(),
|
||||||
}
|
}
|
||||||
return p1, p2
|
return p1, p2
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ func (p *pipe) read(b []byte) (n int, err error) {
|
|||||||
return 0, io.ErrClosedPipe
|
return 0, io.ErrClosedPipe
|
||||||
case isClosedChan(p.remoteDone):
|
case isClosedChan(p.remoteDone):
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
case isClosedChan(p.readDeadline.wait()):
|
case isClosedChan(p.readDeadline.Wait()):
|
||||||
return 0, os.ErrDeadlineExceeded
|
return 0, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ func (p *pipe) read(b []byte) (n int, err error) {
|
|||||||
return 0, io.ErrClosedPipe
|
return 0, io.ErrClosedPipe
|
||||||
case <-p.remoteDone:
|
case <-p.remoteDone:
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
case <-p.readDeadline.wait():
|
case <-p.readDeadline.Wait():
|
||||||
return 0, os.ErrDeadlineExceeded
|
return 0, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@ func (p *pipe) write(b []byte) (n int, err error) {
|
|||||||
return 0, io.ErrClosedPipe
|
return 0, io.ErrClosedPipe
|
||||||
case isClosedChan(p.remoteDone):
|
case isClosedChan(p.remoteDone):
|
||||||
return 0, io.ErrClosedPipe
|
return 0, io.ErrClosedPipe
|
||||||
case isClosedChan(p.writeDeadline.wait()):
|
case isClosedChan(p.writeDeadline.Wait()):
|
||||||
return 0, os.ErrDeadlineExceeded
|
return 0, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ func (p *pipe) write(b []byte) (n int, err error) {
|
|||||||
return n, io.ErrClosedPipe
|
return n, io.ErrClosedPipe
|
||||||
case <-p.remoteDone:
|
case <-p.remoteDone:
|
||||||
return n, io.ErrClosedPipe
|
return n, io.ErrClosedPipe
|
||||||
case <-p.writeDeadline.wait():
|
case <-p.writeDeadline.Wait():
|
||||||
return n, os.ErrDeadlineExceeded
|
return n, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,8 +145,8 @@ func (p *pipe) SetDeadline(t time.Time) error {
|
|||||||
if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
|
if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
|
||||||
return io.ErrClosedPipe
|
return io.ErrClosedPipe
|
||||||
}
|
}
|
||||||
p.readDeadline.set(t)
|
p.readDeadline.Set(t)
|
||||||
p.writeDeadline.set(t)
|
p.writeDeadline.Set(t)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ func (p *pipe) SetReadDeadline(t time.Time) error {
|
|||||||
if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
|
if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
|
||||||
return io.ErrClosedPipe
|
return io.ErrClosedPipe
|
||||||
}
|
}
|
||||||
p.readDeadline.set(t)
|
p.readDeadline.Set(t)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ func (p *pipe) SetWriteDeadline(t time.Time) error {
|
|||||||
if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
|
if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
|
||||||
return io.ErrClosedPipe
|
return io.ErrClosedPipe
|
||||||
}
|
}
|
||||||
p.writeDeadline.set(t)
|
p.writeDeadline.Set(t)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +192,7 @@ func (p *pipe) waitReadBuffer() (buffer *buf.Buffer, err error) {
|
|||||||
return nil, io.ErrClosedPipe
|
return nil, io.ErrClosedPipe
|
||||||
case isClosedChan(p.remoteDone):
|
case isClosedChan(p.remoteDone):
|
||||||
return nil, io.EOF
|
return nil, io.EOF
|
||||||
case isClosedChan(p.readDeadline.wait()):
|
case isClosedChan(p.readDeadline.Wait()):
|
||||||
return nil, os.ErrDeadlineExceeded
|
return nil, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
@@ -211,7 +211,7 @@ func (p *pipe) waitReadBuffer() (buffer *buf.Buffer, err error) {
|
|||||||
return nil, io.ErrClosedPipe
|
return nil, io.ErrClosedPipe
|
||||||
case <-p.remoteDone:
|
case <-p.remoteDone:
|
||||||
return nil, io.EOF
|
return nil, io.EOF
|
||||||
case <-p.readDeadline.wait():
|
case <-p.readDeadline.Wait():
|
||||||
return nil, os.ErrDeadlineExceeded
|
return nil, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,6 @@ package statistic
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/metacubex/mihomo/common/atomic"
|
"github.com/metacubex/mihomo/common/atomic"
|
||||||
@@ -116,20 +115,8 @@ func (tt *tcpTracker) Upstream() any {
|
|||||||
return tt.Conn
|
return tt.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseRemoteDestination(addr net.Addr, conn C.Connection) string {
|
|
||||||
if addr != nil {
|
|
||||||
if addrPort, err := netip.ParseAddrPort(addr.String()); err == nil && addrPort.Addr().IsValid() {
|
|
||||||
return addrPort.Addr().String()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if conn != nil {
|
|
||||||
return conn.RemoteDestination()
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64, pushToManager bool) *tcpTracker {
|
func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64, pushToManager bool) *tcpTracker {
|
||||||
metadata.RemoteDst = parseRemoteDestination(conn.RemoteAddr(), conn)
|
metadata.RemoteDst = conn.RemoteDestination()
|
||||||
|
|
||||||
t := &tcpTracker{
|
t := &tcpTracker{
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
@@ -220,7 +207,7 @@ func (ut *udpTracker) Upstream() any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64, pushToManager bool) *udpTracker {
|
func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64, pushToManager bool) *udpTracker {
|
||||||
metadata.RemoteDst = parseRemoteDestination(nil, conn)
|
metadata.RemoteDst = conn.RemoteDestination()
|
||||||
|
|
||||||
ut := &udpTracker{
|
ut := &udpTracker{
|
||||||
PacketConn: conn,
|
PacketConn: conn,
|
||||||
|
@@ -413,11 +413,6 @@ func handleUDPConn(packet C.PacketAdapter) {
|
|||||||
|
|
||||||
pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule, 0, 0, true)
|
pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule, 0, 0, true)
|
||||||
|
|
||||||
if rawPc.Chains().Last() == "REJECT-DROP" {
|
|
||||||
_ = pc.Close()
|
|
||||||
return nil, nil, errors.New("rejected drop packet")
|
|
||||||
}
|
|
||||||
|
|
||||||
oAddrPort := metadata.AddrPort()
|
oAddrPort := metadata.AddrPort()
|
||||||
writeBackProxy := nat.NewWriteBackProxy(packet)
|
writeBackProxy := nat.NewWriteBackProxy(packet)
|
||||||
|
|
||||||
|
8
clash-nyanpasu/backend/Cargo.lock
generated
8
clash-nyanpasu/backend/Cargo.lock
generated
@@ -7858,9 +7858,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-i18n"
|
name = "rust-i18n"
|
||||||
version = "3.1.4"
|
version = "3.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a2b6307cde881492032919adf26e254981604a6657b339ae23cce8358e9ee203"
|
checksum = "fda2551fdfaf6cc5ee283adc15e157047b92ae6535cf80f6d4962d05717dc332"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"globwalk",
|
"globwalk",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -9870,9 +9870,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.45.0"
|
version = "1.45.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165"
|
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
@@ -22,6 +22,6 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/lodash-es": "4.17.12",
|
"@types/lodash-es": "4.17.12",
|
||||||
"@types/react": "19.1.4"
|
"@types/react": "19.1.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -62,16 +62,16 @@
|
|||||||
"@tanstack/react-router-devtools": "1.120.10",
|
"@tanstack/react-router-devtools": "1.120.10",
|
||||||
"@tanstack/router-plugin": "1.120.10",
|
"@tanstack/router-plugin": "1.120.10",
|
||||||
"@tauri-apps/plugin-clipboard-manager": "2.2.2",
|
"@tauri-apps/plugin-clipboard-manager": "2.2.2",
|
||||||
"@tauri-apps/plugin-dialog": "2.2.1",
|
"@tauri-apps/plugin-dialog": "2.2.2",
|
||||||
"@tauri-apps/plugin-fs": "2.2.1",
|
"@tauri-apps/plugin-fs": "2.3.0",
|
||||||
"@tauri-apps/plugin-notification": "2.2.2",
|
"@tauri-apps/plugin-notification": "2.2.2",
|
||||||
"@tauri-apps/plugin-os": "2.2.1",
|
"@tauri-apps/plugin-os": "2.2.1",
|
||||||
"@tauri-apps/plugin-process": "2.2.1",
|
"@tauri-apps/plugin-process": "2.2.1",
|
||||||
"@tauri-apps/plugin-shell": "2.2.1",
|
"@tauri-apps/plugin-shell": "2.2.1",
|
||||||
"@tauri-apps/plugin-updater": "2.7.1",
|
"@tauri-apps/plugin-updater": "2.7.1",
|
||||||
"@types/react": "19.1.4",
|
"@types/react": "19.1.5",
|
||||||
"@types/react-dom": "19.1.5",
|
"@types/react-dom": "19.1.5",
|
||||||
"@types/validator": "13.15.0",
|
"@types/validator": "13.15.1",
|
||||||
"@vitejs/plugin-legacy": "6.1.1",
|
"@vitejs/plugin-legacy": "6.1.1",
|
||||||
"@vitejs/plugin-react": "4.4.1",
|
"@vitejs/plugin-react": "4.4.1",
|
||||||
"@vitejs/plugin-react-swc": "3.9.0",
|
"@vitejs/plugin-react-swc": "3.9.0",
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
"@radix-ui/react-scroll-area": "1.2.9",
|
"@radix-ui/react-scroll-area": "1.2.9",
|
||||||
"@tauri-apps/api": "2.5.0",
|
"@tauri-apps/api": "2.5.0",
|
||||||
"@types/d3": "7.4.3",
|
"@types/d3": "7.4.3",
|
||||||
"@types/react": "19.1.4",
|
"@types/react": "19.1.5",
|
||||||
"@vitejs/plugin-react": "4.4.1",
|
"@vitejs/plugin-react": "4.4.1",
|
||||||
"ahooks": "3.8.5",
|
"ahooks": "3.8.5",
|
||||||
"d3": "7.9.0",
|
"d3": "7.9.0",
|
||||||
|
@@ -2,10 +2,10 @@
|
|||||||
"manifest_version": 1,
|
"manifest_version": 1,
|
||||||
"latest": {
|
"latest": {
|
||||||
"mihomo": "v1.19.9",
|
"mihomo": "v1.19.9",
|
||||||
"mihomo_alpha": "alpha-989f4ec",
|
"mihomo_alpha": "alpha-34de62d",
|
||||||
"clash_rs": "v0.7.8",
|
"clash_rs": "v0.7.8",
|
||||||
"clash_premium": "2023-09-05-gdcc8d87",
|
"clash_premium": "2023-09-05-gdcc8d87",
|
||||||
"clash_rs_alpha": "0.7.8-alpha+sha.5e5a732"
|
"clash_rs_alpha": "0.7.8-alpha+sha.993dda8"
|
||||||
},
|
},
|
||||||
"arch_template": {
|
"arch_template": {
|
||||||
"mihomo": {
|
"mihomo": {
|
||||||
@@ -69,5 +69,5 @@
|
|||||||
"linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf"
|
"linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"updated_at": "2025-05-23T22:21:03.987Z"
|
"updated_at": "2025-05-24T22:20:47.315Z"
|
||||||
}
|
}
|
||||||
|
@@ -65,7 +65,7 @@
|
|||||||
"@tauri-apps/cli": "2.5.0",
|
"@tauri-apps/cli": "2.5.0",
|
||||||
"@types/fs-extra": "11.0.4",
|
"@types/fs-extra": "11.0.4",
|
||||||
"@types/lodash-es": "4.17.12",
|
"@types/lodash-es": "4.17.12",
|
||||||
"@types/node": "22.15.18",
|
"@types/node": "22.15.21",
|
||||||
"@typescript-eslint/eslint-plugin": "8.32.1",
|
"@typescript-eslint/eslint-plugin": "8.32.1",
|
||||||
"@typescript-eslint/parser": "8.32.1",
|
"@typescript-eslint/parser": "8.32.1",
|
||||||
"autoprefixer": "10.4.21",
|
"autoprefixer": "10.4.21",
|
||||||
|
450
clash-nyanpasu/pnpm-lock.yaml
generated
450
clash-nyanpasu/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -2,23 +2,21 @@
|
|||||||
|
|
||||||
#### 已知问题
|
#### 已知问题
|
||||||
- 仅在Ubuntu 22.04/24.04,Fedora 41 **Gnome桌面环境** 做过简单测试,不保证其他其他Linux发行版可用,将在未来做进一步适配和调优
|
- 仅在Ubuntu 22.04/24.04,Fedora 41 **Gnome桌面环境** 做过简单测试,不保证其他其他Linux发行版可用,将在未来做进一步适配和调优
|
||||||
- MacOS 自定义图标与速率显示推荐图标尺寸为 256x256。其他尺寸(可能)会导致不正常图标和速率间隙
|
|
||||||
- MacOS 下 墙贴主要为浅色,Tray 图标深色时图标闪烁;彩色 Tray 速率颜色淡
|
- MacOS 下 墙贴主要为浅色,Tray 图标深色时图标闪烁;彩色 Tray 速率颜色淡
|
||||||
- Linux 下 Clash Verge Rev 内存占用显著高于 Windows / MacOS
|
- 窗口状态管理器已确定上游存在缺陷,暂时移除。当前不再内置窗口大小和位置记忆。
|
||||||
|
|
||||||
### 2.2.4 相对于 2.2.3
|
### 2.2.4 相对于 2.2.3
|
||||||
#### 修复了:
|
#### 修复了:
|
||||||
- 首页“代理模式”快速切换导致的卡死问题
|
- 首页"代理模式"快速切换导致的卡死问题
|
||||||
- 解锁测试报错信息
|
- 解锁测试报错信息
|
||||||
- Macos 快捷键关闭窗口无法启用自动轻量模式
|
- Macos 快捷键关闭窗口无法启用自动轻量模式
|
||||||
- 静默启动异常窗口创建和关闭流程
|
- 静默启动异常窗口创建和关闭流程
|
||||||
- 使用 tauri window-state 管理窗口,尝试解决各种窗口异常
|
- Windows 错误的全局快捷键 `Ctrl+Q` 注册
|
||||||
- Windows 错误的全局快捷键 'Ctrl+Q' 注册
|
|
||||||
- Vless URL 解码时网络类型错误
|
- Vless URL 解码时网络类型错误
|
||||||
- 切换自定义代理地址导致系统代理状态异常
|
- 切换自定义代理地址导致系统代理状态异常
|
||||||
- Macos TUN 默认无效网卡名称
|
- Macos TUN 默认无效网卡名称
|
||||||
- 托盘更改订阅后 UI 不同步的问题
|
- 托盘更改订阅后 UI 不同步的问题
|
||||||
- 修复提权漏洞,改用带认证的 IPC 通信(后续还可以加强完善认证密钥创建和管理机制)
|
- 修复提权漏洞,改用带认证的 IPC 通信
|
||||||
- 编辑器中连字符问题
|
- 编辑器中连字符问题
|
||||||
- 安装服务模式后无法立即开启 TUN 模式
|
- 安装服务模式后无法立即开启 TUN 模式
|
||||||
- 同步更新多语言翻译
|
- 同步更新多语言翻译
|
||||||
@@ -28,14 +26,13 @@
|
|||||||
- 使用外部扩展脚本覆写代理组时首页无法显示代理组
|
- 使用外部扩展脚本覆写代理组时首页无法显示代理组
|
||||||
|
|
||||||
#### 新增了:
|
#### 新增了:
|
||||||
- Mihomo(Meta)内核升级至 1.19.8
|
- Mihomo(Meta)内核升级至 1.19.9
|
||||||
- 允许代理主机地址设置为非 127.0.0.1 对 WSL 代理友好
|
- 允许代理主机地址设置为非 127.0.0.1 对 WSL 代理友好
|
||||||
- 关闭系统代理时关闭已建立的网络连接
|
- 关闭系统代理时关闭已建立的网络连接
|
||||||
- 托盘显示当前轻量模式状态
|
- 托盘显示当前轻量模式状态
|
||||||
- Webdav 请求加入 UA
|
- Webdav 请求加入 UA
|
||||||
- Webdav 支持目录重定向
|
- Webdav 支持目录重定向
|
||||||
- 移除 Webdav 跨平台备份恢复限制
|
- Webdav 备份目录检查和文件上传重试机制
|
||||||
- 增强 Webdav 备份目录检查和文件上传重试机制
|
|
||||||
- 系统代理守卫可检查意外设置变更并恢复
|
- 系统代理守卫可检查意外设置变更并恢复
|
||||||
- 定时自动订阅更新也能自动回退使用代理
|
- 定时自动订阅更新也能自动回退使用代理
|
||||||
- 订阅请求超时机制,防止订阅更新的时候卡死
|
- 订阅请求超时机制,防止订阅更新的时候卡死
|
||||||
@@ -51,7 +48,8 @@
|
|||||||
- 添加了Zashboard的一键跳转URL
|
- 添加了Zashboard的一键跳转URL
|
||||||
- 使用操作系统默认的窗口管理器
|
- 使用操作系统默认的窗口管理器
|
||||||
- 切换、升级、重启内核的状态管理
|
- 切换、升级、重启内核的状态管理
|
||||||
- 更精细化控制自动日志清理,新增1天选项。
|
- 更精细化控制自动日志清理,新增1天选项
|
||||||
|
- Winodws 快捷键名称改为 `Clash Verge`
|
||||||
|
|
||||||
#### 优化了:
|
#### 优化了:
|
||||||
- 系统代理 Bypass 设置
|
- 系统代理 Bypass 设置
|
||||||
@@ -59,7 +57,7 @@
|
|||||||
- 切换到规则页面时自动刷新规则数据
|
- 切换到规则页面时自动刷新规则数据
|
||||||
- 重构更新失败回退机制,使用后端完成更新失败后回退到使用 Clash 代理再次尝试更新
|
- 重构更新失败回退机制,使用后端完成更新失败后回退到使用 Clash 代理再次尝试更新
|
||||||
- 编辑非激活订阅的时候不在触发当前订阅配置重载
|
- 编辑非激活订阅的时候不在触发当前订阅配置重载
|
||||||
- 改进核心功能防止主进程阻塞、改进MihomoManager实现,以及优化窗口创建流程。减少应用程序可能出现的主进程卡死情况
|
- 改进核心功能防止主进程阻塞、改进MihomoManager实现,以及优化窗口创建流程
|
||||||
- 优化系统代理设置更新逻辑
|
- 优化系统代理设置更新逻辑
|
||||||
- 重构前端通知系统分离通知线程防止前端卡死
|
- 重构前端通知系统分离通知线程防止前端卡死
|
||||||
- 优化网络请求和错误处理
|
- 优化网络请求和错误处理
|
||||||
@@ -71,15 +69,20 @@
|
|||||||
- Mihomo 内核默认日志等级为 warn
|
- Mihomo 内核默认日志等级为 warn
|
||||||
- Clash Verge Rev 应用默认日志等级为 warn
|
- Clash Verge Rev 应用默认日志等级为 warn
|
||||||
- 重构了原来的 IP 信息请求重试机制,采用轮询检测,解决了 Network Error 和超时问题
|
- 重构了原来的 IP 信息请求重试机制,采用轮询检测,解决了 Network Error 和超时问题
|
||||||
- 对轮询检测机制进行了优化,引入洗牌算法来增强随机性。
|
- 对轮询检测机制进行了优化,引入洗牌算法来增强随机性
|
||||||
- 对获取系统信息的流程进行了优化,并添加了去重检测机制,确保剔除重复的信息
|
- 对获取系统信息的流程进行了优化,并添加了去重检测机制,确保剔除重复的信息
|
||||||
- 优化窗口状态初始化逻辑和添加缺失的权限设置
|
- 优化窗口状态初始化逻辑和添加缺失的权限设置
|
||||||
- 异步化配置:优化端口查找和配置保存逻辑
|
- 异步化配置:优化端口查找和配置保存逻辑
|
||||||
- 重构事件通知机制到独立线程,避免前端卡死
|
- 重构事件通知机制到独立线程,避免前端卡死
|
||||||
- 优化端口设置,每个端口可随机设置端口号
|
- 优化端口设置,每个端口可随机设置端口号
|
||||||
- 优化了保存机制,使用平滑函数,防止客户端卡死!
|
- 优化了保存机制,使用平滑函数,防止客户端卡死
|
||||||
- 优化端口设置退出和保存机制!
|
- 优化端口设置退出和保存机制
|
||||||
- 强制为 Mihomo 配置补全并覆盖 external-controller-cors 字段,默认不允许跨域和仅本地请求,提升 cors 安全性,升级配置时自动覆盖。
|
- 强制为 Mihomo 配置补全并覆盖 external-controller-cors 字段,默认不允许跨域和仅本地请求,提升 cors 安全性,升级配置时自动覆盖
|
||||||
|
- 修改 端口检测范围 (1111-65536)
|
||||||
|
|
||||||
|
#### 移除了:
|
||||||
|
- 窗口状态管理器
|
||||||
|
- Webdav 跨平台备份恢复限制
|
||||||
|
|
||||||
## v2.2.3
|
## v2.2.3
|
||||||
|
|
||||||
|
@@ -761,10 +761,6 @@ SectionEnd
|
|||||||
|
|
||||||
|
|
||||||
Section Install
|
Section Install
|
||||||
;删除 .window-state.json 文件
|
|
||||||
SetShellVarContext current
|
|
||||||
Delete "$APPDATA\io.github.clash-verge-rev.clash-verge-rev\.window-state.json"
|
|
||||||
|
|
||||||
SetOutPath $INSTDIR
|
SetOutPath $INSTDIR
|
||||||
nsExec::Exec 'netsh int tcp res'
|
nsExec::Exec 'netsh int tcp res'
|
||||||
!insertmacro CheckIfAppIsRunning
|
!insertmacro CheckIfAppIsRunning
|
||||||
@@ -983,16 +979,23 @@ Section Uninstall
|
|||||||
RMDir "$INSTDIR"
|
RMDir "$INSTDIR"
|
||||||
|
|
||||||
!insertmacro DeleteAppUserModelId
|
!insertmacro DeleteAppUserModelId
|
||||||
!insertmacro UnpinShortcut "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk"
|
!insertmacro UnpinShortcut "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk"
|
||||||
!insertmacro UnpinShortcut "$DESKTOP\${MAINBINARYNAME}.lnk"
|
!insertmacro UnpinShortcut "$DESKTOP\${PRODUCTNAME}.lnk"
|
||||||
|
; 兼容旧名称快捷方式
|
||||||
|
!insertmacro UnpinShortcut "$SMPROGRAMS\$AppStartMenuFolder\clash-verge.lnk"
|
||||||
|
!insertmacro UnpinShortcut "$DESKTOP\clash-verge.lnk"
|
||||||
|
|
||||||
; Remove start menu shortcut
|
; Remove start menu shortcut
|
||||||
!insertmacro MUI_STARTMENU_GETFOLDER Application $AppStartMenuFolder
|
!insertmacro MUI_STARTMENU_GETFOLDER Application $AppStartMenuFolder
|
||||||
Delete "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk"
|
Delete "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk"
|
||||||
|
; 兼容旧名称快捷方式
|
||||||
|
Delete "$SMPROGRAMS\$AppStartMenuFolder\clash-verge.lnk"
|
||||||
RMDir "$SMPROGRAMS\$AppStartMenuFolder"
|
RMDir "$SMPROGRAMS\$AppStartMenuFolder"
|
||||||
|
|
||||||
; Remove desktop shortcuts
|
; Remove desktop shortcuts
|
||||||
Delete "$DESKTOP\${MAINBINARYNAME}.lnk"
|
Delete "$DESKTOP\${PRODUCTNAME}.lnk"
|
||||||
|
; 兼容旧名称快捷方式
|
||||||
|
Delete "$DESKTOP\clash-verge.lnk"
|
||||||
|
|
||||||
; Remove registry information for add/remove programs
|
; Remove registry information for add/remove programs
|
||||||
!if "${INSTALLMODE}" == "both"
|
!if "${INSTALLMODE}" == "both"
|
||||||
@@ -1058,12 +1061,12 @@ FunctionEnd
|
|||||||
!macroend
|
!macroend
|
||||||
|
|
||||||
Function CreateDesktopShortcut
|
Function CreateDesktopShortcut
|
||||||
CreateShortcut "$DESKTOP\${MAINBINARYNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe"
|
CreateShortcut "$DESKTOP\${PRODUCTNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe"
|
||||||
!insertmacro SetLnkAppUserModelId "$DESKTOP\${MAINBINARYNAME}.lnk"
|
!insertmacro SetLnkAppUserModelId "$DESKTOP\${PRODUCTNAME}.lnk"
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
Function CreateStartMenuShortcut
|
Function CreateStartMenuShortcut
|
||||||
CreateDirectory "$SMPROGRAMS\$AppStartMenuFolder"
|
CreateDirectory "$SMPROGRAMS\$AppStartMenuFolder"
|
||||||
CreateShortcut "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe"
|
CreateShortcut "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe"
|
||||||
!insertmacro SetLnkAppUserModelId "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk"
|
!insertmacro SetLnkAppUserModelId "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk"
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
@@ -10,7 +10,6 @@ use crate::{
|
|||||||
/// 获取配置文件列表
|
/// 获取配置文件列表
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_profiles() -> CmdResult<IProfiles> {
|
pub fn get_profiles() -> CmdResult<IProfiles> {
|
||||||
let _ = Tray::global().update_menu();
|
|
||||||
Ok(Config::profiles().data().clone())
|
Ok(Config::profiles().data().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,11 +153,25 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
|||||||
match CoreManager::global().update_config().await {
|
match CoreManager::global().update_config().await {
|
||||||
Ok((true, _)) => {
|
Ok((true, _)) => {
|
||||||
logging!(info, Type::Cmd, true, "配置更新成功");
|
logging!(info, Type::Cmd, true, "配置更新成功");
|
||||||
handle::Handle::refresh_clash();
|
|
||||||
let _ = Tray::global().update_tooltip();
|
|
||||||
Config::profiles().apply();
|
Config::profiles().apply();
|
||||||
wrap_err!(Config::profiles().data().save_file())?;
|
handle::Handle::refresh_clash();
|
||||||
|
|
||||||
|
crate::process::AsyncHandler::spawn(|| async move {
|
||||||
|
if let Err(e) = Tray::global().update_tooltip() {
|
||||||
|
log::warn!(target: "app", "异步更新托盘提示失败: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = Tray::global().update_menu() {
|
||||||
|
log::warn!(target: "app", "异步更新托盘菜单失败: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存配置文件
|
||||||
|
if let Err(e) = Config::profiles().data().save_file() {
|
||||||
|
log::warn!(target: "app", "异步保存配置文件失败: {}", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 立即通知前端配置变更
|
||||||
if let Some(current) = ¤t_value {
|
if let Some(current) = ¤t_value {
|
||||||
logging!(info, Type::Cmd, true, "向前端发送配置变更事件: {}", current);
|
logging!(info, Type::Cmd, true, "向前端发送配置变更事件: {}", current);
|
||||||
handle::Handle::notify_profile_changed(current.clone());
|
handle::Handle::notify_profile_changed(current.clone());
|
||||||
@@ -185,7 +198,13 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
|||||||
// 静默恢复,不触发验证
|
// 静默恢复,不触发验证
|
||||||
wrap_err!({ Config::profiles().draft().patch_config(restore_profiles) })?;
|
wrap_err!({ Config::profiles().draft().patch_config(restore_profiles) })?;
|
||||||
Config::profiles().apply();
|
Config::profiles().apply();
|
||||||
wrap_err!(Config::profiles().data().save_file())?;
|
|
||||||
|
crate::process::AsyncHandler::spawn(|| async move {
|
||||||
|
if let Err(e) = Config::profiles().data().save_file() {
|
||||||
|
log::warn!(target: "app", "异步保存恢复配置文件失败: {}", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
logging!(info, Type::Cmd, true, "成功恢复到之前的配置");
|
logging!(info, Type::Cmd, true, "成功恢复到之前的配置");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,24 +1,69 @@
|
|||||||
use super::CmdResult;
|
use super::CmdResult;
|
||||||
use crate::module::mihomo::MihomoManager;
|
use crate::module::mihomo::MihomoManager;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
static LAST_REFRESH_TIME: Lazy<Mutex<Option<Instant>>> = Lazy::new(|| Mutex::new(None));
|
||||||
|
static IS_REFRESHING: AtomicBool = AtomicBool::new(false);
|
||||||
|
const REFRESH_INTERVAL: Duration = Duration::from_secs(5);
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_proxies() -> CmdResult<serde_json::Value> {
|
pub async fn get_proxies() -> CmdResult<serde_json::Value> {
|
||||||
let mannager = MihomoManager::global();
|
let manager = MihomoManager::global();
|
||||||
|
|
||||||
mannager
|
manager
|
||||||
.refresh_proxies()
|
.refresh_proxies()
|
||||||
.await
|
.await
|
||||||
.map(|_| mannager.get_proxies())
|
.map(|_| manager.get_proxies())
|
||||||
.or_else(|_| Ok(mannager.get_proxies()))
|
.or_else(|_| Ok(manager.get_proxies()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_providers_proxies() -> CmdResult<serde_json::Value> {
|
pub async fn get_providers_proxies() -> CmdResult<serde_json::Value> {
|
||||||
let mannager = MihomoManager::global();
|
let manager = MihomoManager::global();
|
||||||
|
let cached_data = manager.get_providers_proxies();
|
||||||
|
|
||||||
mannager
|
let safe_data = if cached_data.is_null() {
|
||||||
.refresh_providers_proxies()
|
serde_json::json!({
|
||||||
.await
|
"providers": {}
|
||||||
.map(|_| mannager.get_providers_proxies())
|
})
|
||||||
.or_else(|_| Ok(mannager.get_providers_proxies()))
|
} else {
|
||||||
|
cached_data
|
||||||
|
};
|
||||||
|
|
||||||
|
// 检查是否需要刷新
|
||||||
|
let should_refresh = {
|
||||||
|
let last_refresh = LAST_REFRESH_TIME.lock();
|
||||||
|
match *last_refresh {
|
||||||
|
Some(last_time) => last_time.elapsed() > REFRESH_INTERVAL,
|
||||||
|
None => true,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if should_refresh && !IS_REFRESHING.load(Ordering::Acquire) {
|
||||||
|
IS_REFRESHING.store(true, Ordering::Release);
|
||||||
|
|
||||||
|
crate::process::AsyncHandler::spawn(|| async move {
|
||||||
|
let manager = MihomoManager::global();
|
||||||
|
match manager.refresh_providers_proxies().await {
|
||||||
|
Ok(_) => {
|
||||||
|
log::debug!(target: "app", "providers_proxies静默后台刷新成功");
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!(target: "app", "providers_proxies后台刷新失败: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut last_refresh = LAST_REFRESH_TIME.lock();
|
||||||
|
*last_refresh = Some(Instant::now());
|
||||||
|
}
|
||||||
|
|
||||||
|
IS_REFRESHING.store(false, Ordering::Release);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(safe_data)
|
||||||
}
|
}
|
||||||
|
@@ -18,15 +18,16 @@ use crate::{
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub use speed_rate::{SpeedRate, Traffic};
|
pub use speed_rate::{SpeedRate, Traffic};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
menu::{CheckMenuItem, IsMenuItem, MenuEvent, MenuItem, PredefinedMenuItem, Submenu},
|
menu::{CheckMenuItem, IsMenuItem, MenuEvent, MenuItem, PredefinedMenuItem, Submenu},
|
||||||
tray::{MouseButton, MouseButtonState, TrayIconEvent},
|
tray::{MouseButton, MouseButtonState, TrayIconEvent},
|
||||||
@@ -46,10 +47,15 @@ pub struct Tray {
|
|||||||
shutdown_tx: Arc<RwLock<Option<broadcast::Sender<()>>>>,
|
shutdown_tx: Arc<RwLock<Option<broadcast::Sender<()>>>>,
|
||||||
is_subscribed: Arc<RwLock<bool>>,
|
is_subscribed: Arc<RwLock<bool>>,
|
||||||
pub rate_cache: Arc<Mutex<Option<Rate>>>,
|
pub rate_cache: Arc<Mutex<Option<Rate>>>,
|
||||||
|
last_menu_update: Mutex<Option<Instant>>,
|
||||||
|
menu_updating: AtomicBool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
pub struct Tray {}
|
pub struct Tray {
|
||||||
|
last_menu_update: Mutex<Option<Instant>>,
|
||||||
|
menu_updating: AtomicBool,
|
||||||
|
}
|
||||||
|
|
||||||
impl TrayState {
|
impl TrayState {
|
||||||
pub fn get_common_tray_icon() -> (bool, Vec<u8>) {
|
pub fn get_common_tray_icon() -> (bool, Vec<u8>) {
|
||||||
@@ -164,10 +170,15 @@ impl Tray {
|
|||||||
shutdown_tx: Arc::new(RwLock::new(None)),
|
shutdown_tx: Arc::new(RwLock::new(None)),
|
||||||
is_subscribed: Arc::new(RwLock::new(false)),
|
is_subscribed: Arc::new(RwLock::new(false)),
|
||||||
rate_cache: Arc::new(Mutex::new(None)),
|
rate_cache: Arc::new(Mutex::new(None)),
|
||||||
|
last_menu_update: Mutex::new(None),
|
||||||
|
menu_updating: AtomicBool::new(false),
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
return TRAY.get_or_init(|| Tray {});
|
return TRAY.get_or_init(|| Tray {
|
||||||
|
last_menu_update: Mutex::new(None),
|
||||||
|
menu_updating: AtomicBool::new(false),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(&self) -> Result<()> {
|
pub fn init(&self) -> Result<()> {
|
||||||
@@ -192,8 +203,28 @@ impl Tray {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 更新托盘菜单
|
/// 更新托盘菜单(带频率限制)
|
||||||
pub fn update_menu(&self) -> Result<()> {
|
pub fn update_menu(&self) -> Result<()> {
|
||||||
|
// 检查是否正在更新或距离上次更新太近
|
||||||
|
const MIN_UPDATE_INTERVAL: Duration = Duration::from_millis(500);
|
||||||
|
|
||||||
|
// 检查是否已有更新任务在执行
|
||||||
|
if self.menu_updating.load(Ordering::Acquire) {
|
||||||
|
log::debug!(target: "app", "托盘菜单正在更新中,跳过本次更新");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查更新频率
|
||||||
|
{
|
||||||
|
let last_update = self.last_menu_update.lock();
|
||||||
|
if let Some(last_time) = *last_update {
|
||||||
|
if last_time.elapsed() < MIN_UPDATE_INTERVAL {
|
||||||
|
log::debug!(target: "app", "托盘菜单更新频率过高,跳过本次更新");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let app_handle = match handle::Handle::global().app_handle() {
|
let app_handle = match handle::Handle::global().app_handle() {
|
||||||
Some(handle) => handle,
|
Some(handle) => handle,
|
||||||
None => {
|
None => {
|
||||||
@@ -202,6 +233,20 @@ impl Tray {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 设置更新状态
|
||||||
|
self.menu_updating.store(true, Ordering::Release);
|
||||||
|
|
||||||
|
let result = self.update_menu_internal(&app_handle);
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut last_update = self.last_menu_update.lock();
|
||||||
|
*last_update = Some(Instant::now());
|
||||||
|
}
|
||||||
|
self.menu_updating.store(false, Ordering::Release);
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
fn update_menu_internal(&self, app_handle: &AppHandle) -> Result<()> {
|
||||||
let verge = Config::verge().latest().clone();
|
let verge = Config::verge().latest().clone();
|
||||||
let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false);
|
let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false);
|
||||||
let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
|
let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
|
||||||
@@ -230,6 +275,7 @@ impl Tray {
|
|||||||
profile_uid_and_name,
|
profile_uid_and_name,
|
||||||
is_lightweight_mode,
|
is_lightweight_mode,
|
||||||
)?));
|
)?));
|
||||||
|
log::debug!(target: "app", "托盘菜单更新成功");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
@@ -71,8 +71,8 @@ export const useClashInfo = () => {
|
|||||||
|
|
||||||
if (patch["redir-port"]) {
|
if (patch["redir-port"]) {
|
||||||
const port = patch["redir-port"];
|
const port = patch["redir-port"];
|
||||||
if (port < 1000) {
|
if (port < 1111) {
|
||||||
throw new Error("The port should not < 1000");
|
throw new Error("The port should not < 1111");
|
||||||
}
|
}
|
||||||
if (port > 65536) {
|
if (port > 65536) {
|
||||||
throw new Error("The port should not > 65536");
|
throw new Error("The port should not > 65536");
|
||||||
@@ -81,8 +81,8 @@ export const useClashInfo = () => {
|
|||||||
|
|
||||||
if (patch["tproxy-port"]) {
|
if (patch["tproxy-port"]) {
|
||||||
const port = patch["tproxy-port"];
|
const port = patch["tproxy-port"];
|
||||||
if (port < 1000) {
|
if (port < 1111) {
|
||||||
throw new Error("The port should not < 1000");
|
throw new Error("The port should not < 1111");
|
||||||
}
|
}
|
||||||
if (port > 65536) {
|
if (port > 65536) {
|
||||||
throw new Error("The port should not > 65536");
|
throw new Error("The port should not > 65536");
|
||||||
@@ -91,8 +91,8 @@ export const useClashInfo = () => {
|
|||||||
|
|
||||||
if (patch["mixed-port"]) {
|
if (patch["mixed-port"]) {
|
||||||
const port = patch["mixed-port"];
|
const port = patch["mixed-port"];
|
||||||
if (port < 1000) {
|
if (port < 1111) {
|
||||||
throw new Error("The port should not < 1000");
|
throw new Error("The port should not < 1111");
|
||||||
}
|
}
|
||||||
if (port > 65536) {
|
if (port > 65536) {
|
||||||
throw new Error("The port should not > 65536");
|
throw new Error("The port should not > 65536");
|
||||||
@@ -101,8 +101,8 @@ export const useClashInfo = () => {
|
|||||||
|
|
||||||
if (patch["socks-port"]) {
|
if (patch["socks-port"]) {
|
||||||
const port = patch["socks-port"];
|
const port = patch["socks-port"];
|
||||||
if (port < 1000) {
|
if (port < 1111) {
|
||||||
throw new Error("The port should not < 1000");
|
throw new Error("The port should not < 1111");
|
||||||
}
|
}
|
||||||
if (port > 65536) {
|
if (port > 65536) {
|
||||||
throw new Error("The port should not > 65536");
|
throw new Error("The port should not > 65536");
|
||||||
@@ -111,8 +111,8 @@ export const useClashInfo = () => {
|
|||||||
|
|
||||||
if (patch["port"]) {
|
if (patch["port"]) {
|
||||||
const port = patch["port"];
|
const port = patch["port"];
|
||||||
if (port < 1000) {
|
if (port < 1111) {
|
||||||
throw new Error("The port should not < 1000");
|
throw new Error("The port should not < 1111");
|
||||||
}
|
}
|
||||||
if (port > 65536) {
|
if (port > 65536) {
|
||||||
throw new Error("The port should not > 65536");
|
throw new Error("The port should not > 65536");
|
||||||
|
@@ -185,6 +185,7 @@ const Layout = () => {
|
|||||||
mutate("getAutotemProxy");
|
mutate("getAutotemProxy");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
||||||
addListener("verge://notice-message", ({ payload }) =>
|
addListener("verge://notice-message", ({ payload }) =>
|
||||||
handleNotice(payload as [string, string]),
|
handleNotice(payload as [string, string]),
|
||||||
),
|
),
|
||||||
|
@@ -297,17 +297,28 @@ const ProfilePage = () => {
|
|||||||
// 监听后端配置变更
|
// 监听后端配置变更
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let unlistenPromise: Promise<() => void> | undefined;
|
let unlistenPromise: Promise<() => void> | undefined;
|
||||||
|
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
||||||
|
|
||||||
const setupListener = async () => {
|
const setupListener = async () => {
|
||||||
unlistenPromise = listen<string>('profile-changed', (event) => {
|
unlistenPromise = listen<string>('profile-changed', (event) => {
|
||||||
console.log('Profile changed event received:', event.payload);
|
console.log('Profile changed event received:', event.payload);
|
||||||
mutateProfiles();
|
if (timeoutId) {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
|
|
||||||
|
timeoutId = setTimeout(() => {
|
||||||
|
mutateProfiles();
|
||||||
|
timeoutId = undefined;
|
||||||
|
}, 300);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
setupListener();
|
setupListener();
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
if (timeoutId) {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
unlistenPromise?.then(unlisten => unlisten());
|
unlistenPromise?.then(unlisten => unlisten());
|
||||||
};
|
};
|
||||||
}, [mutateProfiles, t]);
|
}, [mutateProfiles, t]);
|
||||||
|
@@ -71,6 +71,9 @@ export const AppDataProvider = ({ children }: { children: React.ReactNode }) =>
|
|||||||
getProxyProviders,
|
getProxyProviders,
|
||||||
{
|
{
|
||||||
revalidateOnFocus: false,
|
revalidateOnFocus: false,
|
||||||
|
revalidateOnReconnect: false,
|
||||||
|
refreshInterval: 30000,
|
||||||
|
dedupingInterval: 10000,
|
||||||
suspense: false,
|
suspense: false,
|
||||||
errorRetryCount: 3
|
errorRetryCount: 3
|
||||||
}
|
}
|
||||||
|
@@ -198,6 +198,11 @@ export const getProxyProviders = async () => {
|
|||||||
const response = await invoke<{
|
const response = await invoke<{
|
||||||
providers: Record<string, IProxyProviderItem>;
|
providers: Record<string, IProxyProviderItem>;
|
||||||
}>("get_providers_proxies");
|
}>("get_providers_proxies");
|
||||||
|
if (!response || !response.providers) {
|
||||||
|
console.warn("getProxyProviders: Invalid response structure, returning empty object");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
const providers = response.providers as Record<string, IProxyProviderItem>;
|
const providers = response.providers as Record<string, IProxyProviderItem>;
|
||||||
|
|
||||||
return Object.fromEntries(
|
return Object.fromEntries(
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
LINUX_VERSION-5.15 = .183
|
LINUX_VERSION-5.15 = .184
|
||||||
LINUX_KERNEL_HASH-5.15.183 = d06f7f629a4d61a87ebd0db285ace9ebf4fce0226b10b2c0ec235e3550c58ee8
|
LINUX_KERNEL_HASH-5.15.184 = 9c3e98c6dcc7dca7c2e9dd51423eaf0581f5e100d0f04c23bc29f21913dac1d9
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
LINUX_VERSION-6.1 = .139
|
LINUX_VERSION-6.1 = .140
|
||||||
LINUX_KERNEL_HASH-6.1.139 = f66affdfee8b6cf8a14cfa00cc7842f79af0e7a70a68604289074f3ecffc9f18
|
LINUX_KERNEL_HASH-6.1.140 = 5779f9caca77f7bfe3c3923b4d760041318db0303de93b2d4691d60e4d41eb74
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
LINUX_VERSION-6.12 = .29
|
LINUX_VERSION-6.12 = .30
|
||||||
LINUX_KERNEL_HASH-6.12.29 = e8b2ec7e2338ccb9c86de7154f6edcaadfce80907493c143e85a82776bb5064d
|
LINUX_KERNEL_HASH-6.12.30 = df046a48971e40ce0b2e003e7e55b6b1e7da2912120eb216d5d6c8450c9cf82e
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
LINUX_VERSION-6.6 = .91
|
LINUX_VERSION-6.6 = .92
|
||||||
LINUX_KERNEL_HASH-6.6.91 = d08d3d175407a52cd0b25fc95e149bbd2fd6922cd37816c8fcfad18f95e254f4
|
LINUX_KERNEL_HASH-6.6.92 = 1d82a82642d281c31d86f7301bc55e12a8a9f9c04532e249ef8ae6fe7dc237ec
|
||||||
|
@@ -12,10 +12,14 @@ include $(INCLUDE_DIR)/package.mk
|
|||||||
define Package/$(PKG_NAME)
|
define Package/$(PKG_NAME)
|
||||||
SECTION:=utils
|
SECTION:=utils
|
||||||
CATEGORY:=Utilities
|
CATEGORY:=Utilities
|
||||||
DEPENDS:=@USB_GADGET_SUPPORT +kmod-usb-gadget +kmod-usb-lib-composite
|
DEPENDS:=@USB_GADGET_SUPPORT +kmod-usb-gadget +kmod-fs-configfs +kmod-usb-lib-composite
|
||||||
TITLE:=init script to create USB gadgets
|
TITLE:=init script to create USB gadgets
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
define Package/$(PKG_NAME)/conffiles
|
||||||
|
/etc/config/usbgadget
|
||||||
|
endef
|
||||||
|
|
||||||
define Build/Compile
|
define Build/Compile
|
||||||
endef
|
endef
|
||||||
|
|
||||||
@@ -35,7 +39,7 @@ define GadgetPreset
|
|||||||
SECTION:=utils
|
SECTION:=utils
|
||||||
CATEGORY:=Utilities
|
CATEGORY:=Utilities
|
||||||
TITLE+= $(2) gadget preset
|
TITLE+= $(2) gadget preset
|
||||||
DEPENDS+= $(3)
|
DEPENDS+= +usbgadget $(3)
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define Package/$(PKG_NAME)-$(1)/description
|
define Package/$(PKG_NAME)-$(1)/description
|
||||||
|
@@ -5,7 +5,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net"
|
"net"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
@@ -203,12 +202,21 @@ func NewBase(opt BaseOption) *Base {
|
|||||||
|
|
||||||
type conn struct {
|
type conn struct {
|
||||||
N.ExtendedConn
|
N.ExtendedConn
|
||||||
chain C.Chain
|
chain C.Chain
|
||||||
actualRemoteDestination string
|
adapterAddr string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conn) RemoteDestination() string {
|
func (c *conn) RemoteDestination() string {
|
||||||
return c.actualRemoteDestination
|
if remoteAddr := c.RemoteAddr(); remoteAddr != nil {
|
||||||
|
m := C.Metadata{}
|
||||||
|
if err := m.SetRemoteAddr(remoteAddr); err != nil {
|
||||||
|
if m.Valid() {
|
||||||
|
return m.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
host, _, _ := net.SplitHostPort(c.adapterAddr)
|
||||||
|
return host
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chains implements C.Connection
|
// Chains implements C.Connection
|
||||||
@@ -241,19 +249,20 @@ func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn {
|
|||||||
if _, ok := c.(syscall.Conn); !ok { // exclusion system conn like *net.TCPConn
|
if _, ok := c.(syscall.Conn); !ok { // exclusion system conn like *net.TCPConn
|
||||||
c = N.NewDeadlineConn(c) // most conn from outbound can't handle readDeadline correctly
|
c = N.NewDeadlineConn(c) // most conn from outbound can't handle readDeadline correctly
|
||||||
}
|
}
|
||||||
return &conn{N.NewExtendedConn(c), []string{a.Name()}, parseRemoteDestination(a.Addr())}
|
return &conn{N.NewExtendedConn(c), []string{a.Name()}, a.Addr()}
|
||||||
}
|
}
|
||||||
|
|
||||||
type packetConn struct {
|
type packetConn struct {
|
||||||
N.EnhancePacketConn
|
N.EnhancePacketConn
|
||||||
chain C.Chain
|
chain C.Chain
|
||||||
adapterName string
|
adapterName string
|
||||||
connID string
|
connID string
|
||||||
actualRemoteDestination string
|
adapterAddr string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *packetConn) RemoteDestination() string {
|
func (c *packetConn) RemoteDestination() string {
|
||||||
return c.actualRemoteDestination
|
host, _, _ := net.SplitHostPort(c.adapterAddr)
|
||||||
|
return host
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chains implements C.Connection
|
// Chains implements C.Connection
|
||||||
@@ -292,19 +301,7 @@ func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn {
|
|||||||
if _, ok := pc.(syscall.Conn); !ok { // exclusion system conn like *net.UDPConn
|
if _, ok := pc.(syscall.Conn); !ok { // exclusion system conn like *net.UDPConn
|
||||||
epc = N.NewDeadlineEnhancePacketConn(epc) // most conn from outbound can't handle readDeadline correctly
|
epc = N.NewDeadlineEnhancePacketConn(epc) // most conn from outbound can't handle readDeadline correctly
|
||||||
}
|
}
|
||||||
return &packetConn{epc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), parseRemoteDestination(a.Addr())}
|
return &packetConn{epc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), a.Addr()}
|
||||||
}
|
|
||||||
|
|
||||||
func parseRemoteDestination(addr string) string {
|
|
||||||
if dst, _, err := net.SplitHostPort(addr); err == nil {
|
|
||||||
return dst
|
|
||||||
} else {
|
|
||||||
if addrError, ok := err.(*net.AddrError); ok && strings.Contains(addrError.Err, "missing port") {
|
|
||||||
return dst
|
|
||||||
} else {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type AddRef interface {
|
type AddRef interface {
|
||||||
|
@@ -20,7 +20,7 @@ type connReadResult struct {
|
|||||||
type Conn struct {
|
type Conn struct {
|
||||||
network.ExtendedConn
|
network.ExtendedConn
|
||||||
deadline atomic.TypedValue[time.Time]
|
deadline atomic.TypedValue[time.Time]
|
||||||
pipeDeadline pipeDeadline
|
pipeDeadline PipeDeadline
|
||||||
disablePipe atomic.Bool
|
disablePipe atomic.Bool
|
||||||
inRead atomic.Bool
|
inRead atomic.Bool
|
||||||
resultCh chan *connReadResult
|
resultCh chan *connReadResult
|
||||||
@@ -34,7 +34,7 @@ func IsConn(conn any) bool {
|
|||||||
func NewConn(conn net.Conn) *Conn {
|
func NewConn(conn net.Conn) *Conn {
|
||||||
c := &Conn{
|
c := &Conn{
|
||||||
ExtendedConn: bufio.NewExtendedConn(conn),
|
ExtendedConn: bufio.NewExtendedConn(conn),
|
||||||
pipeDeadline: makePipeDeadline(),
|
pipeDeadline: MakePipeDeadline(),
|
||||||
resultCh: make(chan *connReadResult, 1),
|
resultCh: make(chan *connReadResult, 1),
|
||||||
}
|
}
|
||||||
c.resultCh <- nil
|
c.resultCh <- nil
|
||||||
@@ -58,7 +58,7 @@ func (c *Conn) Read(p []byte) (n int, err error) {
|
|||||||
c.resultCh <- nil
|
c.resultCh <- nil
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case <-c.pipeDeadline.wait():
|
case <-c.pipeDeadline.Wait():
|
||||||
return 0, os.ErrDeadlineExceeded
|
return 0, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ func (c *Conn) ReadBuffer(buffer *buf.Buffer) (err error) {
|
|||||||
c.resultCh <- nil
|
c.resultCh <- nil
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case <-c.pipeDeadline.wait():
|
case <-c.pipeDeadline.Wait():
|
||||||
return os.ErrDeadlineExceeded
|
return os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ func (c *Conn) SetReadDeadline(t time.Time) error {
|
|||||||
return c.ExtendedConn.SetReadDeadline(t)
|
return c.ExtendedConn.SetReadDeadline(t)
|
||||||
}
|
}
|
||||||
c.deadline.Store(t)
|
c.deadline.Store(t)
|
||||||
c.pipeDeadline.set(t)
|
c.pipeDeadline.Set(t)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -19,7 +19,7 @@ type readResult struct {
|
|||||||
type NetPacketConn struct {
|
type NetPacketConn struct {
|
||||||
net.PacketConn
|
net.PacketConn
|
||||||
deadline atomic.TypedValue[time.Time]
|
deadline atomic.TypedValue[time.Time]
|
||||||
pipeDeadline pipeDeadline
|
pipeDeadline PipeDeadline
|
||||||
disablePipe atomic.Bool
|
disablePipe atomic.Bool
|
||||||
inRead atomic.Bool
|
inRead atomic.Bool
|
||||||
resultCh chan any
|
resultCh chan any
|
||||||
@@ -28,7 +28,7 @@ type NetPacketConn struct {
|
|||||||
func NewNetPacketConn(pc net.PacketConn) net.PacketConn {
|
func NewNetPacketConn(pc net.PacketConn) net.PacketConn {
|
||||||
npc := &NetPacketConn{
|
npc := &NetPacketConn{
|
||||||
PacketConn: pc,
|
PacketConn: pc,
|
||||||
pipeDeadline: makePipeDeadline(),
|
pipeDeadline: MakePipeDeadline(),
|
||||||
resultCh: make(chan any, 1),
|
resultCh: make(chan any, 1),
|
||||||
}
|
}
|
||||||
npc.resultCh <- nil
|
npc.resultCh <- nil
|
||||||
@@ -83,7 +83,7 @@ FOR:
|
|||||||
c.resultCh <- nil
|
c.resultCh <- nil
|
||||||
break FOR
|
break FOR
|
||||||
}
|
}
|
||||||
case <-c.pipeDeadline.wait():
|
case <-c.pipeDeadline.Wait():
|
||||||
return 0, nil, os.ErrDeadlineExceeded
|
return 0, nil, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,7 +122,7 @@ func (c *NetPacketConn) SetReadDeadline(t time.Time) error {
|
|||||||
return c.PacketConn.SetReadDeadline(t)
|
return c.PacketConn.SetReadDeadline(t)
|
||||||
}
|
}
|
||||||
c.deadline.Store(t)
|
c.deadline.Store(t)
|
||||||
c.pipeDeadline.set(t)
|
c.pipeDeadline.Set(t)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -52,7 +52,7 @@ FOR:
|
|||||||
c.netPacketConn.resultCh <- nil
|
c.netPacketConn.resultCh <- nil
|
||||||
break FOR
|
break FOR
|
||||||
}
|
}
|
||||||
case <-c.netPacketConn.pipeDeadline.wait():
|
case <-c.netPacketConn.pipeDeadline.Wait():
|
||||||
return nil, nil, nil, os.ErrDeadlineExceeded
|
return nil, nil, nil, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -69,7 +69,7 @@ FOR:
|
|||||||
c.netPacketConn.resultCh <- nil
|
c.netPacketConn.resultCh <- nil
|
||||||
break FOR
|
break FOR
|
||||||
}
|
}
|
||||||
case <-c.netPacketConn.pipeDeadline.wait():
|
case <-c.netPacketConn.pipeDeadline.Wait():
|
||||||
return M.Socksaddr{}, os.ErrDeadlineExceeded
|
return M.Socksaddr{}, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,7 +146,7 @@ FOR:
|
|||||||
c.netPacketConn.resultCh <- nil
|
c.netPacketConn.resultCh <- nil
|
||||||
break FOR
|
break FOR
|
||||||
}
|
}
|
||||||
case <-c.netPacketConn.pipeDeadline.wait():
|
case <-c.netPacketConn.pipeDeadline.Wait():
|
||||||
return nil, M.Socksaddr{}, os.ErrDeadlineExceeded
|
return nil, M.Socksaddr{}, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,24 +9,24 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// pipeDeadline is an abstraction for handling timeouts.
|
// PipeDeadline is an abstraction for handling timeouts.
|
||||||
type pipeDeadline struct {
|
type PipeDeadline struct {
|
||||||
mu sync.Mutex // Guards timer and cancel
|
mu sync.Mutex // Guards timer and cancel
|
||||||
timer *time.Timer
|
timer *time.Timer
|
||||||
cancel chan struct{} // Must be non-nil
|
cancel chan struct{} // Must be non-nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makePipeDeadline() pipeDeadline {
|
func MakePipeDeadline() PipeDeadline {
|
||||||
return pipeDeadline{cancel: make(chan struct{})}
|
return PipeDeadline{cancel: make(chan struct{})}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set sets the point in time when the deadline will time out.
|
// Set sets the point in time when the deadline will time out.
|
||||||
// A timeout event is signaled by closing the channel returned by waiter.
|
// A timeout event is signaled by closing the channel returned by waiter.
|
||||||
// Once a timeout has occurred, the deadline can be refreshed by specifying a
|
// Once a timeout has occurred, the deadline can be refreshed by specifying a
|
||||||
// t value in the future.
|
// t value in the future.
|
||||||
//
|
//
|
||||||
// A zero value for t prevents timeout.
|
// A zero value for t prevents timeout.
|
||||||
func (d *pipeDeadline) set(t time.Time) {
|
func (d *PipeDeadline) Set(t time.Time) {
|
||||||
d.mu.Lock()
|
d.mu.Lock()
|
||||||
defer d.mu.Unlock()
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
@@ -61,8 +61,8 @@ func (d *pipeDeadline) set(t time.Time) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait returns a channel that is closed when the deadline is exceeded.
|
// Wait returns a channel that is closed when the deadline is exceeded.
|
||||||
func (d *pipeDeadline) wait() chan struct{} {
|
func (d *PipeDeadline) Wait() chan struct{} {
|
||||||
d.mu.Lock()
|
d.mu.Lock()
|
||||||
defer d.mu.Unlock()
|
defer d.mu.Unlock()
|
||||||
return d.cancel
|
return d.cancel
|
||||||
|
@@ -33,8 +33,8 @@ type pipe struct {
|
|||||||
localDone chan struct{}
|
localDone chan struct{}
|
||||||
remoteDone <-chan struct{}
|
remoteDone <-chan struct{}
|
||||||
|
|
||||||
readDeadline pipeDeadline
|
readDeadline PipeDeadline
|
||||||
writeDeadline pipeDeadline
|
writeDeadline PipeDeadline
|
||||||
|
|
||||||
readWaitOptions N.ReadWaitOptions
|
readWaitOptions N.ReadWaitOptions
|
||||||
}
|
}
|
||||||
@@ -56,15 +56,15 @@ func Pipe() (net.Conn, net.Conn) {
|
|||||||
rdRx: cb1, rdTx: cn1,
|
rdRx: cb1, rdTx: cn1,
|
||||||
wrTx: cb2, wrRx: cn2,
|
wrTx: cb2, wrRx: cn2,
|
||||||
localDone: done1, remoteDone: done2,
|
localDone: done1, remoteDone: done2,
|
||||||
readDeadline: makePipeDeadline(),
|
readDeadline: MakePipeDeadline(),
|
||||||
writeDeadline: makePipeDeadline(),
|
writeDeadline: MakePipeDeadline(),
|
||||||
}
|
}
|
||||||
p2 := &pipe{
|
p2 := &pipe{
|
||||||
rdRx: cb2, rdTx: cn2,
|
rdRx: cb2, rdTx: cn2,
|
||||||
wrTx: cb1, wrRx: cn1,
|
wrTx: cb1, wrRx: cn1,
|
||||||
localDone: done2, remoteDone: done1,
|
localDone: done2, remoteDone: done1,
|
||||||
readDeadline: makePipeDeadline(),
|
readDeadline: MakePipeDeadline(),
|
||||||
writeDeadline: makePipeDeadline(),
|
writeDeadline: MakePipeDeadline(),
|
||||||
}
|
}
|
||||||
return p1, p2
|
return p1, p2
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ func (p *pipe) read(b []byte) (n int, err error) {
|
|||||||
return 0, io.ErrClosedPipe
|
return 0, io.ErrClosedPipe
|
||||||
case isClosedChan(p.remoteDone):
|
case isClosedChan(p.remoteDone):
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
case isClosedChan(p.readDeadline.wait()):
|
case isClosedChan(p.readDeadline.Wait()):
|
||||||
return 0, os.ErrDeadlineExceeded
|
return 0, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ func (p *pipe) read(b []byte) (n int, err error) {
|
|||||||
return 0, io.ErrClosedPipe
|
return 0, io.ErrClosedPipe
|
||||||
case <-p.remoteDone:
|
case <-p.remoteDone:
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
case <-p.readDeadline.wait():
|
case <-p.readDeadline.Wait():
|
||||||
return 0, os.ErrDeadlineExceeded
|
return 0, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@ func (p *pipe) write(b []byte) (n int, err error) {
|
|||||||
return 0, io.ErrClosedPipe
|
return 0, io.ErrClosedPipe
|
||||||
case isClosedChan(p.remoteDone):
|
case isClosedChan(p.remoteDone):
|
||||||
return 0, io.ErrClosedPipe
|
return 0, io.ErrClosedPipe
|
||||||
case isClosedChan(p.writeDeadline.wait()):
|
case isClosedChan(p.writeDeadline.Wait()):
|
||||||
return 0, os.ErrDeadlineExceeded
|
return 0, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ func (p *pipe) write(b []byte) (n int, err error) {
|
|||||||
return n, io.ErrClosedPipe
|
return n, io.ErrClosedPipe
|
||||||
case <-p.remoteDone:
|
case <-p.remoteDone:
|
||||||
return n, io.ErrClosedPipe
|
return n, io.ErrClosedPipe
|
||||||
case <-p.writeDeadline.wait():
|
case <-p.writeDeadline.Wait():
|
||||||
return n, os.ErrDeadlineExceeded
|
return n, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,8 +145,8 @@ func (p *pipe) SetDeadline(t time.Time) error {
|
|||||||
if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
|
if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
|
||||||
return io.ErrClosedPipe
|
return io.ErrClosedPipe
|
||||||
}
|
}
|
||||||
p.readDeadline.set(t)
|
p.readDeadline.Set(t)
|
||||||
p.writeDeadline.set(t)
|
p.writeDeadline.Set(t)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ func (p *pipe) SetReadDeadline(t time.Time) error {
|
|||||||
if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
|
if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
|
||||||
return io.ErrClosedPipe
|
return io.ErrClosedPipe
|
||||||
}
|
}
|
||||||
p.readDeadline.set(t)
|
p.readDeadline.Set(t)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ func (p *pipe) SetWriteDeadline(t time.Time) error {
|
|||||||
if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
|
if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
|
||||||
return io.ErrClosedPipe
|
return io.ErrClosedPipe
|
||||||
}
|
}
|
||||||
p.writeDeadline.set(t)
|
p.writeDeadline.Set(t)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +192,7 @@ func (p *pipe) waitReadBuffer() (buffer *buf.Buffer, err error) {
|
|||||||
return nil, io.ErrClosedPipe
|
return nil, io.ErrClosedPipe
|
||||||
case isClosedChan(p.remoteDone):
|
case isClosedChan(p.remoteDone):
|
||||||
return nil, io.EOF
|
return nil, io.EOF
|
||||||
case isClosedChan(p.readDeadline.wait()):
|
case isClosedChan(p.readDeadline.Wait()):
|
||||||
return nil, os.ErrDeadlineExceeded
|
return nil, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
@@ -211,7 +211,7 @@ func (p *pipe) waitReadBuffer() (buffer *buf.Buffer, err error) {
|
|||||||
return nil, io.ErrClosedPipe
|
return nil, io.ErrClosedPipe
|
||||||
case <-p.remoteDone:
|
case <-p.remoteDone:
|
||||||
return nil, io.EOF
|
return nil, io.EOF
|
||||||
case <-p.readDeadline.wait():
|
case <-p.readDeadline.Wait():
|
||||||
return nil, os.ErrDeadlineExceeded
|
return nil, os.ErrDeadlineExceeded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,6 @@ package statistic
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/metacubex/mihomo/common/atomic"
|
"github.com/metacubex/mihomo/common/atomic"
|
||||||
@@ -116,20 +115,8 @@ func (tt *tcpTracker) Upstream() any {
|
|||||||
return tt.Conn
|
return tt.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseRemoteDestination(addr net.Addr, conn C.Connection) string {
|
|
||||||
if addr != nil {
|
|
||||||
if addrPort, err := netip.ParseAddrPort(addr.String()); err == nil && addrPort.Addr().IsValid() {
|
|
||||||
return addrPort.Addr().String()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if conn != nil {
|
|
||||||
return conn.RemoteDestination()
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64, pushToManager bool) *tcpTracker {
|
func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64, pushToManager bool) *tcpTracker {
|
||||||
metadata.RemoteDst = parseRemoteDestination(conn.RemoteAddr(), conn)
|
metadata.RemoteDst = conn.RemoteDestination()
|
||||||
|
|
||||||
t := &tcpTracker{
|
t := &tcpTracker{
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
@@ -220,7 +207,7 @@ func (ut *udpTracker) Upstream() any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64, pushToManager bool) *udpTracker {
|
func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64, pushToManager bool) *udpTracker {
|
||||||
metadata.RemoteDst = parseRemoteDestination(nil, conn)
|
metadata.RemoteDst = conn.RemoteDestination()
|
||||||
|
|
||||||
ut := &udpTracker{
|
ut := &udpTracker{
|
||||||
PacketConn: conn,
|
PacketConn: conn,
|
||||||
|
@@ -413,11 +413,6 @@ func handleUDPConn(packet C.PacketAdapter) {
|
|||||||
|
|
||||||
pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule, 0, 0, true)
|
pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule, 0, 0, true)
|
||||||
|
|
||||||
if rawPc.Chains().Last() == "REJECT-DROP" {
|
|
||||||
_ = pc.Close()
|
|
||||||
return nil, nil, errors.New("rejected drop packet")
|
|
||||||
}
|
|
||||||
|
|
||||||
oAddrPort := metadata.AddrPort()
|
oAddrPort := metadata.AddrPort()
|
||||||
writeBackProxy := nat.NewWriteBackProxy(packet)
|
writeBackProxy := nat.NewWriteBackProxy(packet)
|
||||||
|
|
||||||
|
8
shadowsocks-rust/Cargo.lock
generated
8
shadowsocks-rust/Cargo.lock
generated
@@ -397,9 +397,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bson"
|
name = "bson"
|
||||||
version = "2.14.0"
|
version = "2.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af8113ff51309e2779e8785a246c10fb783e8c2452f134d6257fd71cc03ccd6c"
|
checksum = "7969a9ba84b0ff843813e7249eed1678d9b6607ce5a3b8f0a47af3fcf7978e6e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"base64",
|
"base64",
|
||||||
@@ -3857,9 +3857,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.45.0"
|
version = "1.45.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165"
|
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
@@ -151,6 +151,7 @@ o:depends("pdnsd_enable", "2")
|
|||||||
o:depends("pdnsd_enable", "3")
|
o:depends("pdnsd_enable", "3")
|
||||||
o.description = translate("Custom DNS Server format as IP:PORT (default: 8.8.4.4:53)")
|
o.description = translate("Custom DNS Server format as IP:PORT (default: 8.8.4.4:53)")
|
||||||
o.datatype = "ip4addrport"
|
o.datatype = "ip4addrport"
|
||||||
|
o.default = "8.8.4.4:53"
|
||||||
|
|
||||||
o = s:option(ListValue, "tunnel_forward_mosdns", translate("Anti-pollution DNS Server"))
|
o = s:option(ListValue, "tunnel_forward_mosdns", translate("Anti-pollution DNS Server"))
|
||||||
o:value("tcp://8.8.4.4:53,tcp://8.8.8.8:53", translate("Google Public DNS"))
|
o:value("tcp://8.8.4.4:53,tcp://8.8.8.8:53", translate("Google Public DNS"))
|
||||||
|
@@ -21,13 +21,13 @@ define Download/geoip
|
|||||||
HASH:=8023379316bca4713dcfa5ba4ea2fe7f4c127fff64a0cb7859d4756142b2c4dc
|
HASH:=8023379316bca4713dcfa5ba4ea2fe7f4c127fff64a0cb7859d4756142b2c4dc
|
||||||
endef
|
endef
|
||||||
|
|
||||||
GEOSITE_VER:=20250523165307
|
GEOSITE_VER:=20250525112927
|
||||||
GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER)
|
GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER)
|
||||||
define Download/geosite
|
define Download/geosite
|
||||||
URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/
|
URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/
|
||||||
URL_FILE:=dlc.dat
|
URL_FILE:=dlc.dat
|
||||||
FILE:=$(GEOSITE_FILE)
|
FILE:=$(GEOSITE_FILE)
|
||||||
HASH:=b1d02c3b4f90830e8b4bda83a552da6d218407fe6833ddc8bb2c8b5372998c9f
|
HASH:=564c9a35b05a1a3a5febfd9ee66235bc732d4dd7675f7f1e1c917b2ece409742
|
||||||
endef
|
endef
|
||||||
|
|
||||||
GEOSITE_IRAN_VER:=202505230820
|
GEOSITE_IRAN_VER:=202505230820
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>7.12.4</Version>
|
<Version>7.12.5</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
@@ -388,7 +388,7 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
|||||||
|
|
||||||
private async void MenuClose_Click(object? sender, RoutedEventArgs e)
|
private async void MenuClose_Click(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (await UI.ShowYesNo(this, ResUI.menuExitTips) == ButtonResult.No)
|
if (await UI.ShowYesNo(this, ResUI.menuExitTips) != ButtonResult.Yes)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -138,7 +138,7 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.ShowYesNo:
|
case EViewAction.ShowYesNo:
|
||||||
if (await UI.ShowYesNo(_window, ResUI.RemoveServer) == ButtonResult.No)
|
if (await UI.ShowYesNo(_window, ResUI.RemoveServer) != ButtonResult.Yes)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -80,14 +80,14 @@ public partial class RoutingRuleSettingWindow : ReactiveWindow<RoutingRuleSettin
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.ShowYesNo:
|
case EViewAction.ShowYesNo:
|
||||||
if (await UI.ShowYesNo(this, ResUI.RemoveServer) == ButtonResult.No)
|
if (await UI.ShowYesNo(this, ResUI.RemoveServer) != ButtonResult.Yes)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.AddBatchRoutingRulesYesNo:
|
case EViewAction.AddBatchRoutingRulesYesNo:
|
||||||
if (await UI.ShowYesNo(this, ResUI.AddBatchRoutingRulesYesNo) == ButtonResult.No)
|
if (await UI.ShowYesNo(this, ResUI.AddBatchRoutingRulesYesNo) != ButtonResult.Yes)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -68,7 +68,7 @@ public partial class RoutingSettingWindow : ReactiveWindow<RoutingSettingViewMod
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.ShowYesNo:
|
case EViewAction.ShowYesNo:
|
||||||
if (await UI.ShowYesNo(this, ResUI.RemoveRules) == ButtonResult.No)
|
if (await UI.ShowYesNo(this, ResUI.RemoveRules) != ButtonResult.Yes)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -45,7 +45,7 @@ public partial class SubSettingWindow : ReactiveWindow<SubSettingViewModel>
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.ShowYesNo:
|
case EViewAction.ShowYesNo:
|
||||||
if (await UI.ShowYesNo(this, ResUI.RemoveServer) == ButtonResult.No)
|
if (await UI.ShowYesNo(this, ResUI.RemoveServer) != ButtonResult.Yes)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -12,8 +12,8 @@ android {
|
|||||||
applicationId = "com.v2ray.ang"
|
applicationId = "com.v2ray.ang"
|
||||||
minSdk = 21
|
minSdk = 21
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 653
|
versionCode = 654
|
||||||
versionName = "1.10.3"
|
versionName = "1.10.4"
|
||||||
multiDexEnabled = true
|
multiDexEnabled = true
|
||||||
|
|
||||||
val abiFilterList = (properties["ABI_FILTERS"] as? String)?.split(';')
|
val abiFilterList = (properties["ABI_FILTERS"] as? String)?.split(';')
|
||||||
|
@@ -148,7 +148,7 @@
|
|||||||
|
|
||||||
<string name="title_mux_settings">سامووا Mux</string>
|
<string name="title_mux_settings">سامووا Mux</string>
|
||||||
<string name="title_pref_mux_enabled">ر وندن Mux</string>
|
<string name="title_pref_mux_enabled">ر وندن Mux</string>
|
||||||
<string name="summary_pref_mux_enabled">زل تر، ٱما گاشڌ منپیز زی قت بۊ بارت دؽوۉداری، TCP، UDP و QUIC ن ای لم سفارشی کۊنین.</string>
|
<string name="summary_pref_mux_enabled">زل تر، ٱما گاشڌ منپیز زی قت بۊ\nمخزن ترافیک TCP وا 8 منپیز پؽش فرز، بارت دؽوۉداری UDP وو QUIC ن ای لم سفارشی کۊنین.</string>
|
||||||
<string name="title_pref_mux_concurency">منپیزا TCP (تلایه منجا 1-1024)</string>
|
<string name="title_pref_mux_concurency">منپیزا TCP (تلایه منجا 1-1024)</string>
|
||||||
<string name="title_pref_mux_xudp_concurency">منپیزا XUDP (تلایه منجا 1-1024)</string>
|
<string name="title_pref_mux_xudp_concurency">منپیزا XUDP (تلایه منجا 1-1024)</string>
|
||||||
<string name="title_pref_mux_xudp_quic">دؽوۉداری QUIC من تۊنل mux</string>
|
<string name="title_pref_mux_xudp_quic">دؽوۉداری QUIC من تۊنل mux</string>
|
||||||
@@ -324,7 +324,7 @@
|
|||||||
<string name="update_new_version_found">نوسخه نۊ ن جوست: %s</string>
|
<string name="update_new_version_found">نوسخه نۊ ن جوست: %s</string>
|
||||||
<string name="update_now">سکو ورۊ رسۊوی کۊنین</string>
|
<string name="update_now">سکو ورۊ رسۊوی کۊنین</string>
|
||||||
<string name="update_check_pre_release">واجۊری نوسخه یل پؽش ز تیجنیڌن</string>
|
<string name="update_check_pre_release">واجۊری نوسخه یل پؽش ز تیجنیڌن</string>
|
||||||
<string name="update_checking_for_update">Checking for update…</string>
|
<string name="update_checking_for_update">ورۊ رسۊوی ن هونی واجۊری اکونه...</string>
|
||||||
|
|
||||||
<string-array name="share_method">
|
<string-array name="share_method">
|
||||||
<item>QRcode</item>
|
<item>QRcode</item>
|
||||||
|
@@ -321,7 +321,7 @@
|
|||||||
<string name="update_new_version_found">نسخه جدید پیدا شد: %s</string>
|
<string name="update_new_version_found">نسخه جدید پیدا شد: %s</string>
|
||||||
<string name="update_now">اکنون به روز رسانی کنید</string>
|
<string name="update_now">اکنون به روز رسانی کنید</string>
|
||||||
<string name="update_check_pre_release">بررسی نسخه پیش از انتشار</string>
|
<string name="update_check_pre_release">بررسی نسخه پیش از انتشار</string>
|
||||||
<string name="update_checking_for_update">Checking for update…</string>
|
<string name="update_checking_for_update">در حال بررسی برای بهروزرسانی…</string>
|
||||||
|
|
||||||
<string-array name="share_method">
|
<string-array name="share_method">
|
||||||
<item>QRcode</item>
|
<item>QRcode</item>
|
||||||
|
@@ -323,7 +323,7 @@
|
|||||||
<string name="update_new_version_found">Найдена новая версия: %s</string>
|
<string name="update_new_version_found">Найдена новая версия: %s</string>
|
||||||
<string name="update_now">Обновить</string>
|
<string name="update_now">Обновить</string>
|
||||||
<string name="update_check_pre_release">Искать предварительный выпуск</string>
|
<string name="update_check_pre_release">Искать предварительный выпуск</string>
|
||||||
<string name="update_checking_for_update">Checking for update…</string>
|
<string name="update_checking_for_update">Проверка обновления…</string>
|
||||||
|
|
||||||
<string-array name="share_method">
|
<string-array name="share_method">
|
||||||
<item>QR-код</item>
|
<item>QR-код</item>
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
[versions]
|
[versions]
|
||||||
agp = "8.9.3"
|
agp = "8.10.0"
|
||||||
desugarJdkLibs = "2.1.5"
|
desugarJdkLibs = "2.1.5"
|
||||||
gradleLicensePlugin = "0.9.8"
|
gradleLicensePlugin = "0.9.8"
|
||||||
kotlin = "2.1.21"
|
kotlin = "2.1.21"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
#Thu Nov 14 12:42:51 BDT 2024
|
#Thu Nov 14 12:42:51 BDT 2024
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
Reference in New Issue
Block a user