Chore: IpToAddr
This commit is contained in:
parent
42d853a7e6
commit
6c4791480e
14 changed files with 136 additions and 119 deletions
53
common/nnip/netip.go
Normal file
53
common/nnip/netip.go
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
package nnip
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IpToAddr converts the net.IP to netip.Addr.
|
||||||
|
// If slice's length is not 4 or 16, IpToAddr returns netip.Addr{}
|
||||||
|
func IpToAddr(slice net.IP) netip.Addr {
|
||||||
|
ip := slice
|
||||||
|
if len(ip) != 4 {
|
||||||
|
if ip = slice.To4(); ip == nil {
|
||||||
|
ip = slice
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if addr, ok := netip.AddrFromSlice(ip); ok {
|
||||||
|
return addr
|
||||||
|
}
|
||||||
|
return netip.Addr{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnMasked returns p's last IP address.
|
||||||
|
// If p is invalid, UnMasked returns netip.Addr{}
|
||||||
|
func UnMasked(p netip.Prefix) netip.Addr {
|
||||||
|
if !p.IsValid() {
|
||||||
|
return netip.Addr{}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := p.Addr().As16()
|
||||||
|
|
||||||
|
hi := binary.BigEndian.Uint64(buf[:8])
|
||||||
|
lo := binary.BigEndian.Uint64(buf[8:])
|
||||||
|
|
||||||
|
bits := p.Bits()
|
||||||
|
if bits <= 32 {
|
||||||
|
bits += 96
|
||||||
|
}
|
||||||
|
|
||||||
|
hi = hi | ^uint64(0)>>bits
|
||||||
|
lo = lo | ^(^uint64(0) << (128 - bits))
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint64(buf[:8], hi)
|
||||||
|
binary.BigEndian.PutUint64(buf[8:], lo)
|
||||||
|
|
||||||
|
addr := netip.AddrFrom16(buf)
|
||||||
|
if p.Addr().Is4() {
|
||||||
|
return addr.Unmap()
|
||||||
|
}
|
||||||
|
return addr
|
||||||
|
}
|
|
@ -1,12 +1,11 @@
|
||||||
package fakeip
|
package fakeip
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
"errors"
|
||||||
"math/bits"
|
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/clash/common/nnip"
|
||||||
"github.com/Dreamacro/clash/component/profile/cachefile"
|
"github.com/Dreamacro/clash/component/profile/cachefile"
|
||||||
"github.com/Dreamacro/clash/component/trie"
|
"github.com/Dreamacro/clash/component/trie"
|
||||||
)
|
)
|
||||||
|
@ -16,11 +15,6 @@ const (
|
||||||
cycleKey = "key-cycle-fake-ip"
|
cycleKey = "key-cycle-fake-ip"
|
||||||
)
|
)
|
||||||
|
|
||||||
type uint128 struct {
|
|
||||||
hi uint64
|
|
||||||
lo uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type store interface {
|
type store interface {
|
||||||
GetByHost(host string) (netip.Addr, bool)
|
GetByHost(host string) (netip.Addr, bool)
|
||||||
PutByHost(host string, ip netip.Addr)
|
PutByHost(host string, ip netip.Addr)
|
||||||
|
@ -122,7 +116,7 @@ func (p *Pool) FlushFakeIP() error {
|
||||||
err := p.store.FlushFakeIP()
|
err := p.store.FlushFakeIP()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
p.cycle = false
|
p.cycle = false
|
||||||
p.offset = p.first
|
p.offset = p.first.Prev()
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -173,10 +167,10 @@ func New(options Options) (*Pool, error) {
|
||||||
hostAddr = options.IPNet.Masked().Addr()
|
hostAddr = options.IPNet.Masked().Addr()
|
||||||
gateway = hostAddr.Next()
|
gateway = hostAddr.Next()
|
||||||
first = gateway.Next().Next()
|
first = gateway.Next().Next()
|
||||||
last = add(hostAddr, 1<<uint64(hostAddr.BitLen()-options.IPNet.Bits())-1)
|
last = nnip.UnMasked(*options.IPNet)
|
||||||
)
|
)
|
||||||
|
|
||||||
if !options.IPNet.IsValid() || !first.Less(last) || !options.IPNet.Contains(last) {
|
if !options.IPNet.IsValid() || !first.IsValid() || !first.Less(last) {
|
||||||
return nil, errors.New("ipnet don't have valid ip")
|
return nil, errors.New("ipnet don't have valid ip")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,29 +195,3 @@ func New(options Options) (*Pool, error) {
|
||||||
|
|
||||||
return pool, nil
|
return pool, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// add returns addr + n.
|
|
||||||
func add(addr netip.Addr, n uint64) netip.Addr {
|
|
||||||
buf := addr.As16()
|
|
||||||
|
|
||||||
u := uint128{
|
|
||||||
binary.BigEndian.Uint64(buf[:8]),
|
|
||||||
binary.BigEndian.Uint64(buf[8:]),
|
|
||||||
}
|
|
||||||
|
|
||||||
lo, carry := bits.Add64(u.lo, n, 0)
|
|
||||||
|
|
||||||
u.hi = u.hi + carry
|
|
||||||
u.lo = lo
|
|
||||||
|
|
||||||
binary.BigEndian.PutUint64(buf[:8], u.hi)
|
|
||||||
binary.BigEndian.PutUint64(buf[8:], u.lo)
|
|
||||||
|
|
||||||
a := netip.AddrFrom16(buf)
|
|
||||||
|
|
||||||
if addr.Is4() {
|
|
||||||
return a.Unmap()
|
|
||||||
}
|
|
||||||
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
|
@ -240,13 +240,15 @@ func TestPool_FlushFileCache(t *testing.T) {
|
||||||
err = pool.FlushFakeIP()
|
err = pool.FlushFakeIP()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
baz := pool.Lookup("foo.com")
|
|
||||||
next := pool.Lookup("baz.com")
|
next := pool.Lookup("baz.com")
|
||||||
|
baz := pool.Lookup("foo.com")
|
||||||
nero := pool.Lookup("foo.com")
|
nero := pool.Lookup("foo.com")
|
||||||
|
|
||||||
assert.True(t, foo == fox)
|
assert.True(t, foo == fox)
|
||||||
|
assert.True(t, foo == next)
|
||||||
assert.False(t, foo == baz)
|
assert.False(t, foo == baz)
|
||||||
assert.True(t, bar == bax)
|
assert.True(t, bar == bax)
|
||||||
|
assert.True(t, bar == baz)
|
||||||
assert.False(t, bar == next)
|
assert.False(t, bar == next)
|
||||||
assert.True(t, baz == nero)
|
assert.True(t, baz == nero)
|
||||||
}
|
}
|
||||||
|
@ -267,13 +269,15 @@ func TestPool_FlushMemoryCache(t *testing.T) {
|
||||||
err := pool.FlushFakeIP()
|
err := pool.FlushFakeIP()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
baz := pool.Lookup("foo.com")
|
|
||||||
next := pool.Lookup("baz.com")
|
next := pool.Lookup("baz.com")
|
||||||
|
baz := pool.Lookup("foo.com")
|
||||||
nero := pool.Lookup("foo.com")
|
nero := pool.Lookup("foo.com")
|
||||||
|
|
||||||
assert.True(t, foo == fox)
|
assert.True(t, foo == fox)
|
||||||
|
assert.True(t, foo == next)
|
||||||
assert.False(t, foo == baz)
|
assert.False(t, foo == baz)
|
||||||
assert.True(t, bar == bax)
|
assert.True(t, bar == bax)
|
||||||
|
assert.True(t, bar == baz)
|
||||||
assert.False(t, bar == next)
|
assert.False(t, bar == next)
|
||||||
assert.True(t, baz == nero)
|
assert.True(t, baz == nero)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/cache"
|
"github.com/Dreamacro/clash/common/cache"
|
||||||
|
"github.com/Dreamacro/clash/common/nnip"
|
||||||
"github.com/Dreamacro/clash/component/fakeip"
|
"github.com/Dreamacro/clash/component/fakeip"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
)
|
)
|
||||||
|
@ -29,7 +30,7 @@ func (h *ResolverEnhancer) IsExistFakeIP(ip net.IP) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
if pool := h.fakePool; pool != nil {
|
if pool := h.fakePool; pool != nil {
|
||||||
return pool.Exist(ipToAddr(ip))
|
return pool.Exist(nnip.IpToAddr(ip))
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
@ -40,7 +41,7 @@ func (h *ResolverEnhancer) IsFakeIP(ip net.IP) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
addr := ipToAddr(ip)
|
addr := nnip.IpToAddr(ip)
|
||||||
|
|
||||||
if pool := h.fakePool; pool != nil {
|
if pool := h.fakePool; pool != nil {
|
||||||
return pool.IPNet().Contains(addr) && addr != pool.Gateway() && addr != pool.Broadcast()
|
return pool.IPNet().Contains(addr) && addr != pool.Gateway() && addr != pool.Broadcast()
|
||||||
|
@ -55,14 +56,14 @@ func (h *ResolverEnhancer) IsFakeBroadcastIP(ip net.IP) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
if pool := h.fakePool; pool != nil {
|
if pool := h.fakePool; pool != nil {
|
||||||
return pool.Broadcast() == ipToAddr(ip)
|
return pool.Broadcast() == nnip.IpToAddr(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ResolverEnhancer) FindHostByIP(ip net.IP) (string, bool) {
|
func (h *ResolverEnhancer) FindHostByIP(ip net.IP) (string, bool) {
|
||||||
addr := ipToAddr(ip)
|
addr := nnip.IpToAddr(ip)
|
||||||
if pool := h.fakePool; pool != nil {
|
if pool := h.fakePool; pool != nil {
|
||||||
if host, existed := pool.LookBack(addr); existed {
|
if host, existed := pool.LookBack(addr); existed {
|
||||||
return host, true
|
return host, true
|
||||||
|
@ -80,7 +81,7 @@ func (h *ResolverEnhancer) FindHostByIP(ip net.IP) (string, bool) {
|
||||||
|
|
||||||
func (h *ResolverEnhancer) InsertHostByIP(ip net.IP, host string) {
|
func (h *ResolverEnhancer) InsertHostByIP(ip net.IP, host string) {
|
||||||
if mapping := h.mapping; mapping != nil {
|
if mapping := h.mapping; mapping != nil {
|
||||||
h.mapping.Set(ipToAddr(ip), host)
|
h.mapping.Set(nnip.IpToAddr(ip), host)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/cache"
|
"github.com/Dreamacro/clash/common/cache"
|
||||||
|
"github.com/Dreamacro/clash/common/nnip"
|
||||||
"github.com/Dreamacro/clash/component/fakeip"
|
"github.com/Dreamacro/clash/component/fakeip"
|
||||||
"github.com/Dreamacro/clash/component/trie"
|
"github.com/Dreamacro/clash/component/trie"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
@ -101,7 +102,7 @@ func withMapping(mapping *cache.LruCache[netip.Addr, string]) middleware {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
mapping.SetWithExpire(ipToAddr(ip), host, time.Now().Add(time.Second*time.Duration(ttl)))
|
mapping.SetWithExpire(nnip.IpToAddr(ip), host, time.Now().Add(time.Second*time.Duration(ttl)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return msg, nil
|
return msg, nil
|
||||||
|
|
17
dns/util.go
17
dns/util.go
|
@ -5,7 +5,6 @@ import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/cache"
|
"github.com/Dreamacro/clash/common/cache"
|
||||||
|
@ -115,22 +114,6 @@ func msgToIP(msg *D.Msg) []net.IP {
|
||||||
return ips
|
return ips
|
||||||
}
|
}
|
||||||
|
|
||||||
func ipToAddr(ip net.IP) netip.Addr {
|
|
||||||
if ip == nil {
|
|
||||||
return netip.Addr{}
|
|
||||||
}
|
|
||||||
|
|
||||||
l := len(ip)
|
|
||||||
|
|
||||||
if l == 4 {
|
|
||||||
return netip.AddrFrom4(*(*[4]byte)(ip))
|
|
||||||
} else if l == 16 {
|
|
||||||
return netip.AddrFrom16(*(*[16]byte)(ip))
|
|
||||||
} else {
|
|
||||||
return netip.Addr{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type wrapPacketConn struct {
|
type wrapPacketConn struct {
|
||||||
net.PacketConn
|
net.PacketConn
|
||||||
rAddr net.Addr
|
rAddr net.Addr
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/clash/common/nnip"
|
||||||
"github.com/Dreamacro/clash/listener/tun/device"
|
"github.com/Dreamacro/clash/listener/tun/device"
|
||||||
"github.com/Dreamacro/clash/listener/tun/device/tun"
|
"github.com/Dreamacro/clash/listener/tun/device/tun"
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
|
@ -226,7 +227,7 @@ func cleanupAddressesOnDisconnectedInterfaces(family winipcfg.AddressFamily, add
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for address := iface.FirstUnicastAddress; address != nil; address = address.Next {
|
for address := iface.FirstUnicastAddress; address != nil; address = address.Next {
|
||||||
if ip, _ := netip.AddrFromSlice(address.Address.IP()); addrHash[ip] {
|
if ip := nnip.IpToAddr(address.Address.IP()); addrHash[ip] {
|
||||||
prefix := netip.PrefixFrom(ip, int(address.OnLinkPrefixLength))
|
prefix := netip.PrefixFrom(ip, int(address.OnLinkPrefixLength))
|
||||||
log.Infoln("[TUN] cleaning up stale address %s from interface ‘%s’", prefix.String(), iface.FriendlyName())
|
log.Infoln("[TUN] cleaning up stale address %s from interface ‘%s’", prefix.String(), iface.FriendlyName())
|
||||||
_ = iface.LUID.DeleteIPAddress(prefix)
|
_ = iface.LUID.DeleteIPAddress(prefix)
|
||||||
|
@ -260,7 +261,7 @@ func getAutoDetectInterfaceByFamily(family winipcfg.AddressFamily) (string, erro
|
||||||
}
|
}
|
||||||
|
|
||||||
for gatewayAddress := iface.FirstGatewayAddress; gatewayAddress != nil; gatewayAddress = gatewayAddress.Next {
|
for gatewayAddress := iface.FirstGatewayAddress; gatewayAddress != nil; gatewayAddress = gatewayAddress.Next {
|
||||||
nextHop, _ := netip.AddrFromSlice(gatewayAddress.Address.IP())
|
nextHop := nnip.IpToAddr(gatewayAddress.Address.IP())
|
||||||
|
|
||||||
if _, err = iface.LUID.Route(destination, nextHop); err == nil {
|
if _, err = iface.LUID.Route(destination, nextHop); err == nil {
|
||||||
return ifname, nil
|
return ifname, nil
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/adapter/inbound"
|
"github.com/Dreamacro/clash/adapter/inbound"
|
||||||
|
"github.com/Dreamacro/clash/common/nnip"
|
||||||
"github.com/Dreamacro/clash/common/pool"
|
"github.com/Dreamacro/clash/common/pool"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
D "github.com/Dreamacro/clash/listener/tun/ipstack/commons"
|
D "github.com/Dreamacro/clash/listener/tun/ipstack/commons"
|
||||||
|
@ -33,20 +34,22 @@ func (gh *GVHandler) HandleTCP(tunConn adapter.TCPConn) {
|
||||||
Zone: "",
|
Zone: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
addrIp, _ := netip.AddrFromSlice(rAddr.IP)
|
addrPort := netip.AddrPortFrom(nnip.IpToAddr(rAddr.IP), id.LocalPort)
|
||||||
addrPort := netip.AddrPortFrom(addrIp, id.LocalPort)
|
|
||||||
|
|
||||||
if D.ShouldHijackDns(gh.DNSAdds, addrPort) {
|
if D.ShouldHijackDns(gh.DNSAdds, addrPort) {
|
||||||
go func() {
|
go func() {
|
||||||
log.Debugln("[TUN] hijack dns tcp: %s", addrPort.String())
|
log.Debugln("[TUN] hijack dns tcp: %s", addrPort.String())
|
||||||
|
|
||||||
defer tunConn.Close()
|
|
||||||
|
|
||||||
buf := pool.Get(pool.UDPBufferSize)
|
buf := pool.Get(pool.UDPBufferSize)
|
||||||
defer pool.Put(buf)
|
defer func() {
|
||||||
|
_ = pool.Put(buf)
|
||||||
|
_ = tunConn.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
tunConn.SetReadDeadline(time.Now().Add(D.DefaultDnsReadTimeout))
|
if tunConn.SetReadDeadline(time.Now().Add(D.DefaultDnsReadTimeout)) != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
length := uint16(0)
|
length := uint16(0)
|
||||||
if err := binary.Read(tunConn, binary.BigEndian, &length); err != nil {
|
if err := binary.Read(tunConn, binary.BigEndian, &length); err != nil {
|
||||||
|
@ -86,8 +89,7 @@ func (gh *GVHandler) HandleUDP(tunConn adapter.UDPConn) {
|
||||||
Zone: "",
|
Zone: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
addrIp, _ := netip.AddrFromSlice(rAddr.IP)
|
addrPort := netip.AddrPortFrom(nnip.IpToAddr(rAddr.IP), id.LocalPort)
|
||||||
addrPort := netip.AddrPortFrom(addrIp, id.LocalPort)
|
|
||||||
target := socks5.ParseAddrToSocksAddr(rAddr)
|
target := socks5.ParseAddrToSocksAddr(rAddr)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -96,7 +98,7 @@ func (gh *GVHandler) HandleUDP(tunConn adapter.UDPConn) {
|
||||||
|
|
||||||
n, addr, err := tunConn.ReadFrom(buf)
|
n, addr, err := tunConn.ReadFrom(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pool.Put(buf)
|
_ = pool.Put(buf)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +106,9 @@ func (gh *GVHandler) HandleUDP(tunConn adapter.UDPConn) {
|
||||||
|
|
||||||
if D.ShouldHijackDns(gh.DNSAdds, addrPort) {
|
if D.ShouldHijackDns(gh.DNSAdds, addrPort) {
|
||||||
go func() {
|
go func() {
|
||||||
defer pool.Put(buf)
|
defer func() {
|
||||||
|
_ = pool.Put(buf)
|
||||||
|
}()
|
||||||
|
|
||||||
msg, err1 := D.RelayDnsPacket(payload)
|
msg, err1 := D.RelayDnsPacket(payload)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
|
|
|
@ -13,8 +13,8 @@ type StackListener struct {
|
||||||
udp *nat.UDP
|
udp *nat.UDP
|
||||||
}
|
}
|
||||||
|
|
||||||
func StartListener(device io.ReadWriteCloser, gateway netip.Addr, portal netip.Addr) (*StackListener, error) {
|
func StartListener(device io.ReadWriteCloser, gateway, portal, broadcast netip.Addr) (*StackListener, error) {
|
||||||
tcp, udp, err := nat.Start(device, gateway, portal)
|
tcp, udp, err := nat.Start(device, gateway, portal, broadcast)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,7 @@ import (
|
||||||
"github.com/Dreamacro/clash/listener/tun/ipstack/system/mars/tcpip"
|
"github.com/Dreamacro/clash/listener/tun/ipstack/system/mars/tcpip"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Start(
|
func Start(device io.ReadWriter, gateway, portal, broadcast netip.Addr) (*TCP, *UDP, error) {
|
||||||
device io.ReadWriter,
|
|
||||||
gateway netip.Addr,
|
|
||||||
portal netip.Addr,
|
|
||||||
) (*TCP, *UDP, error) {
|
|
||||||
if !portal.Is4() || !gateway.Is4() {
|
if !portal.Is4() || !gateway.Is4() {
|
||||||
return nil, nil, net.InvalidAddrError("only ipv4 supported")
|
return nil, nil, net.InvalidAddrError("only ipv4 supported")
|
||||||
}
|
}
|
||||||
|
@ -37,8 +33,10 @@ func Start(
|
||||||
gatewayPort := uint16(listener.Addr().(*net.TCPAddr).Port)
|
gatewayPort := uint16(listener.Addr().(*net.TCPAddr).Port)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer tcp.Close()
|
defer func() {
|
||||||
defer udp.Close()
|
_ = tcp.Close()
|
||||||
|
_ = udp.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
buf := make([]byte, pool.RelayBufferSize)
|
buf := make([]byte, pool.RelayBufferSize)
|
||||||
|
|
||||||
|
@ -72,7 +70,7 @@ func Start(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if ipv4.Offset() != 0 {
|
if ipv4.FragmentOffset() != 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +90,12 @@ func Start(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destinationIP := ip.DestinationIP()
|
||||||
|
|
||||||
|
if !destinationIP.IsGlobalUnicast() || destinationIP == broadcast {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
switch ip.Protocol() {
|
switch ip.Protocol() {
|
||||||
case tcpip.TCP:
|
case tcpip.TCP:
|
||||||
t := tcpip.TCPPacket(ip.Payload())
|
t := tcpip.TCPPacket(ip.Payload())
|
||||||
|
@ -99,7 +103,7 @@ func Start(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if ip.DestinationIP() == portal {
|
if destinationIP == portal {
|
||||||
if ip.SourceIP() == gateway && t.SourcePort() == gatewayPort {
|
if ip.SourceIP() == gateway && t.SourcePort() == gatewayPort {
|
||||||
tup := tab.tupleOf(t.DestinationPort())
|
tup := tab.tupleOf(t.DestinationPort())
|
||||||
if tup == zeroTuple {
|
if tup == zeroTuple {
|
||||||
|
@ -120,7 +124,7 @@ func Start(
|
||||||
} else {
|
} else {
|
||||||
tup := tuple{
|
tup := tuple{
|
||||||
SourceAddr: netip.AddrPortFrom(ip.SourceIP(), t.SourcePort()),
|
SourceAddr: netip.AddrPortFrom(ip.SourceIP(), t.SourcePort()),
|
||||||
DestinationAddr: netip.AddrPortFrom(ip.DestinationIP(), t.DestinationPort()),
|
DestinationAddr: netip.AddrPortFrom(destinationIP, t.DestinationPort()),
|
||||||
}
|
}
|
||||||
|
|
||||||
port := tab.portOf(tup)
|
port := tab.portOf(tup)
|
||||||
|
@ -158,10 +162,8 @@ func Start(
|
||||||
|
|
||||||
i.SetType(tcpip.ICMPTypePingResponse)
|
i.SetType(tcpip.ICMPTypePingResponse)
|
||||||
|
|
||||||
source := ip.SourceIP()
|
ip.SetDestinationIP(ip.SourceIP())
|
||||||
destination := ip.DestinationIP()
|
ip.SetSourceIP(destinationIP)
|
||||||
ip.SetSourceIP(destination)
|
|
||||||
ip.SetDestinationIP(source)
|
|
||||||
|
|
||||||
ip.ResetChecksum()
|
ip.ResetChecksum()
|
||||||
i.ResetChecksum()
|
i.ResetChecksum()
|
||||||
|
@ -176,10 +178,8 @@ func Start(
|
||||||
|
|
||||||
i.SetType(tcpip.ICMPv6EchoReply)
|
i.SetType(tcpip.ICMPv6EchoReply)
|
||||||
|
|
||||||
source := ip.SourceIP()
|
ip.SetDestinationIP(ip.SourceIP())
|
||||||
destination := ip.DestinationIP()
|
ip.SetSourceIP(destinationIP)
|
||||||
ip.SetSourceIP(destination)
|
|
||||||
ip.SetDestinationIP(source)
|
|
||||||
|
|
||||||
ip.ResetChecksum()
|
ip.ResetChecksum()
|
||||||
i.ResetChecksum(ip.PseudoSum())
|
i.ResetChecksum(ip.PseudoSum())
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/clash/common/nnip"
|
||||||
"github.com/Dreamacro/clash/common/pool"
|
"github.com/Dreamacro/clash/common/pool"
|
||||||
"github.com/Dreamacro/clash/listener/tun/ipstack/system/mars/tcpip"
|
"github.com/Dreamacro/clash/listener/tun/ipstack/system/mars/tcpip"
|
||||||
)
|
)
|
||||||
|
@ -71,11 +72,8 @@ func (u *UDP) WriteTo(buf []byte, local net.Addr, remote net.Addr) (int, error)
|
||||||
return 0, net.InvalidAddrError("invalid addr")
|
return 0, net.InvalidAddrError("invalid addr")
|
||||||
}
|
}
|
||||||
|
|
||||||
srcIP, _ := netip.AddrFromSlice(srcAddr.IP)
|
srcAddrPort := netip.AddrPortFrom(nnip.IpToAddr(srcAddr.IP), uint16(srcAddr.Port))
|
||||||
dstIp, _ := netip.AddrFromSlice(dstAddr.IP)
|
dstAddrPort := netip.AddrPortFrom(nnip.IpToAddr(dstAddr.IP), uint16(dstAddr.Port))
|
||||||
|
|
||||||
srcAddrPort := netip.AddrPortFrom(srcIP.Unmap(), uint16(srcAddr.Port))
|
|
||||||
dstAddrPort := netip.AddrPortFrom(dstIp.Unmap(), uint16(dstAddr.Port))
|
|
||||||
|
|
||||||
if !srcAddrPort.Addr().Is4() || !dstAddrPort.Addr().Is4() {
|
if !srcAddrPort.Addr().Is4() || !dstAddrPort.Addr().Is4() {
|
||||||
return 0, net.InvalidAddrError("invalid ip version")
|
return 0, net.InvalidAddrError("invalid ip version")
|
||||||
|
|
|
@ -118,12 +118,6 @@ func (p IPv4Packet) SetFlags(flags byte) {
|
||||||
p[6] |= flags << 5
|
p[6] |= flags << 5
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p IPv4Packet) Offset() uint16 {
|
|
||||||
offset := binary.BigEndian.Uint16(p[6:8])
|
|
||||||
|
|
||||||
return (offset & 0x1fff) * 8
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p IPv4Packet) SourceIP() netip.Addr {
|
func (p IPv4Packet) SourceIP() netip.Addr {
|
||||||
return netip.AddrFrom4([4]byte{p[12], p[13], p[14], p[15]})
|
return netip.AddrFrom4([4]byte{p[12], p[13], p[14], p[15]})
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/adapter/inbound"
|
"github.com/Dreamacro/clash/adapter/inbound"
|
||||||
|
"github.com/Dreamacro/clash/common/nnip"
|
||||||
"github.com/Dreamacro/clash/common/pool"
|
"github.com/Dreamacro/clash/common/pool"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/context"
|
"github.com/Dreamacro/clash/context"
|
||||||
|
@ -45,11 +46,12 @@ func (s *sysStack) Close() error {
|
||||||
|
|
||||||
func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Prefix, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (ipstack.Stack, error) {
|
func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Prefix, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (ipstack.Stack, error) {
|
||||||
var (
|
var (
|
||||||
gateway = tunAddress.Masked().Addr().Next()
|
gateway = tunAddress.Masked().Addr().Next()
|
||||||
portal = gateway.Next()
|
portal = gateway.Next()
|
||||||
|
broadcast = nnip.UnMasked(tunAddress)
|
||||||
)
|
)
|
||||||
|
|
||||||
stack, err := mars.StartListener(device, gateway, portal)
|
stack, err := mars.StartListener(device, gateway, portal, broadcast)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = device.Close()
|
_ = device.Close()
|
||||||
|
|
||||||
|
@ -81,24 +83,26 @@ func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Pref
|
||||||
lAddr := conn.LocalAddr().(*net.TCPAddr)
|
lAddr := conn.LocalAddr().(*net.TCPAddr)
|
||||||
rAddr := conn.RemoteAddr().(*net.TCPAddr)
|
rAddr := conn.RemoteAddr().(*net.TCPAddr)
|
||||||
|
|
||||||
rAddrIp, _ := netip.AddrFromSlice(rAddr.IP)
|
rAddrPort := netip.AddrPortFrom(nnip.IpToAddr(rAddr.IP), uint16(rAddr.Port))
|
||||||
rAddrPort := netip.AddrPortFrom(rAddrIp, uint16(rAddr.Port))
|
|
||||||
|
if rAddrPort.Addr().IsLoopback() {
|
||||||
|
_ = conn.Close()
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if D.ShouldHijackDns(dnsAddr, rAddrPort) {
|
if D.ShouldHijackDns(dnsAddr, rAddrPort) {
|
||||||
go func() {
|
go func() {
|
||||||
log.Debugln("[TUN] hijack dns tcp: %s", rAddrPort.String())
|
log.Debugln("[TUN] hijack dns tcp: %s", rAddrPort.String())
|
||||||
|
|
||||||
defer func(conn net.Conn) {
|
|
||||||
_ = conn.Close()
|
|
||||||
}(conn)
|
|
||||||
|
|
||||||
buf := pool.Get(pool.UDPBufferSize)
|
buf := pool.Get(pool.UDPBufferSize)
|
||||||
defer func(buf []byte) {
|
defer func() {
|
||||||
_ = pool.Put(buf)
|
_ = pool.Put(buf)
|
||||||
}(buf)
|
_ = conn.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if err = conn.SetReadDeadline(time.Now().Add(C.DefaultTCPTimeout)); err != nil {
|
if conn.SetReadDeadline(time.Now().Add(C.DefaultTCPTimeout)) != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,8 +166,13 @@ func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Pref
|
||||||
lAddr := lRAddr.(*net.UDPAddr)
|
lAddr := lRAddr.(*net.UDPAddr)
|
||||||
rAddr := rRAddr.(*net.UDPAddr)
|
rAddr := rRAddr.(*net.UDPAddr)
|
||||||
|
|
||||||
rAddrIp, _ := netip.AddrFromSlice(rAddr.IP)
|
rAddrPort := netip.AddrPortFrom(nnip.IpToAddr(rAddr.IP), uint16(rAddr.Port))
|
||||||
rAddrPort := netip.AddrPortFrom(rAddrIp, uint16(rAddr.Port))
|
|
||||||
|
if rAddrPort.Addr().IsLoopback() {
|
||||||
|
_ = pool.Put(buf)
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if D.ShouldHijackDns(dnsAddr, rAddrPort) {
|
if D.ShouldHijackDns(dnsAddr, rAddrPort) {
|
||||||
go func() {
|
go func() {
|
||||||
|
|
|
@ -149,7 +149,8 @@ func setAtLatest(stackType C.TUNStack, devName string) {
|
||||||
|
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "darwin":
|
case "darwin":
|
||||||
_, _ = cmd.ExecCmd("sysctl net.inet.ip.forwarding=1")
|
// _, _ = cmd.ExecCmd("sysctl -w net.inet.ip.forwarding=1")
|
||||||
|
// _, _ = cmd.ExecCmd("sysctl -w net.inet6.ip6.forwarding=1")
|
||||||
case "windows":
|
case "windows":
|
||||||
_, _ = cmd.ExecCmd("ipconfig /renew")
|
_, _ = cmd.ExecCmd("ipconfig /renew")
|
||||||
case "linux":
|
case "linux":
|
||||||
|
|
Loading…
Reference in a new issue