mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2024-11-15 13:41:23 +08:00
90 lines
2.0 KiB
Go
90 lines
2.0 KiB
Go
package loopback
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/netip"
|
|
|
|
"github.com/metacubex/mihomo/common/callback"
|
|
"github.com/metacubex/mihomo/component/iface"
|
|
C "github.com/metacubex/mihomo/constant"
|
|
|
|
"github.com/puzpuzpuz/xsync/v3"
|
|
)
|
|
|
|
var ErrReject = errors.New("reject loopback connection")
|
|
|
|
type Detector struct {
|
|
connMap *xsync.MapOf[netip.AddrPort, struct{}]
|
|
packetConnMap *xsync.MapOf[uint16, struct{}]
|
|
}
|
|
|
|
func NewDetector() *Detector {
|
|
return &Detector{
|
|
connMap: xsync.NewMapOf[netip.AddrPort, struct{}](),
|
|
packetConnMap: xsync.NewMapOf[uint16, struct{}](),
|
|
}
|
|
}
|
|
|
|
func (l *Detector) NewConn(conn C.Conn) C.Conn {
|
|
metadata := C.Metadata{}
|
|
if metadata.SetRemoteAddr(conn.LocalAddr()) != nil {
|
|
return conn
|
|
}
|
|
connAddr := metadata.AddrPort()
|
|
if !connAddr.IsValid() {
|
|
return conn
|
|
}
|
|
l.connMap.Store(connAddr, struct{}{})
|
|
return callback.NewCloseCallbackConn(conn, func() {
|
|
l.connMap.Delete(connAddr)
|
|
})
|
|
}
|
|
|
|
func (l *Detector) NewPacketConn(conn C.PacketConn) C.PacketConn {
|
|
metadata := C.Metadata{}
|
|
if metadata.SetRemoteAddr(conn.LocalAddr()) != nil {
|
|
return conn
|
|
}
|
|
connAddr := metadata.AddrPort()
|
|
if !connAddr.IsValid() {
|
|
return conn
|
|
}
|
|
port := connAddr.Port()
|
|
l.packetConnMap.Store(port, struct{}{})
|
|
return callback.NewCloseCallbackPacketConn(conn, func() {
|
|
l.packetConnMap.Delete(port)
|
|
})
|
|
}
|
|
|
|
func (l *Detector) CheckConn(metadata *C.Metadata) error {
|
|
connAddr := metadata.SourceAddrPort()
|
|
if !connAddr.IsValid() {
|
|
return nil
|
|
}
|
|
if _, ok := l.connMap.Load(connAddr); ok {
|
|
return fmt.Errorf("%w to: %s", ErrReject, metadata.RemoteAddress())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (l *Detector) CheckPacketConn(metadata *C.Metadata) error {
|
|
connAddr := metadata.SourceAddrPort()
|
|
if !connAddr.IsValid() {
|
|
return nil
|
|
}
|
|
|
|
isLocalIp, err := iface.IsLocalIp(connAddr.Addr())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !isLocalIp && !connAddr.Addr().IsLoopback() {
|
|
return nil
|
|
}
|
|
|
|
if _, ok := l.packetConnMap.Load(connAddr.Port()); ok {
|
|
return fmt.Errorf("%w to: %s", ErrReject, metadata.RemoteAddress())
|
|
}
|
|
return nil
|
|
}
|