Chore: embed the RuleExtra into Base

This commit is contained in:
yaling888
2022-03-13 01:21:23 +08:00
parent 8fbf93ccc8
commit 46b9a1092d
47 changed files with 1995 additions and 471 deletions

View File

@ -1,57 +0,0 @@
//go:build windows
// +build windows
package commons
import (
"fmt"
"net"
"strconv"
"strings"
)
type IPCidr struct {
IP net.IP
Cidr uint8
}
func (r *IPCidr) String() string {
return fmt.Sprintf("%s/%d", r.IP.String(), r.Cidr)
}
func (r *IPCidr) Bits() uint8 {
if r.IP.To4() != nil {
return 32
}
return 128
}
func (r *IPCidr) IPNet() net.IPNet {
return net.IPNet{
IP: r.IP,
Mask: net.CIDRMask(int(r.Cidr), int(r.Bits())),
}
}
func (r *IPCidr) MaskSelf() {
bits := int(r.Bits())
mask := net.CIDRMask(int(r.Cidr), bits)
for i := 0; i < bits/8; i++ {
r.IP[i] &= mask[i]
}
}
func ParseIPCidr(ipcidr string) *IPCidr {
s := strings.Split(ipcidr, "/")
if len(s) != 2 {
return nil
}
cidr, err := strconv.Atoi(s[1])
if err != nil {
return nil
}
return &IPCidr{
IP: net.ParseIP(s[0]),
Cidr: uint8(cidr),
}
}

View File

@ -0,0 +1,42 @@
package mars
import (
"io"
"net/netip"
"github.com/Dreamacro/clash/listener/tun/ipstack/system/mars/nat"
)
type StackListener struct {
device io.Closer
tcp *nat.TCP
udp *nat.UDP
}
func StartListener(device io.ReadWriteCloser, gateway netip.Addr, portal netip.Addr) (*StackListener, error) {
tcp, udp, err := nat.Start(device, gateway, portal)
if err != nil {
return nil, err
}
return &StackListener{
device: device,
tcp: tcp,
udp: udp,
}, nil
}
func (t *StackListener) Close() error {
_ = t.tcp.Close()
_ = t.udp.Close()
return t.device.Close()
}
func (t *StackListener) TCP() *nat.TCP {
return t.tcp
}
func (t *StackListener) UDP() *nat.UDP {
return t.udp
}

View File

@ -0,0 +1,196 @@
package nat
import (
"io"
"net"
"net/netip"
"github.com/Dreamacro/clash/listener/tun/ipstack/system/mars/tcpip"
)
func Start(
device io.ReadWriter,
gateway netip.Addr,
portal netip.Addr,
) (*TCP, *UDP, error) {
if !portal.Is4() || !gateway.Is4() {
return nil, nil, net.InvalidAddrError("only ipv4 supported")
}
listener, err := net.ListenTCP("tcp4", nil)
if err != nil {
return nil, nil, err
}
tab := newTable()
udp := &UDP{
calls: map[*call]struct{}{},
device: device,
buf: [65535]byte{},
}
tcp := &TCP{
listener: listener,
portal: portal,
table: tab,
}
gatewayPort := uint16(listener.Addr().(*net.TCPAddr).Port)
go func() {
defer tcp.Close()
defer udp.Close()
buf := make([]byte, 65535)
for {
n, err := device.Read(buf)
if err != nil {
return
}
raw := buf[:n]
var (
ipVersion int
ip tcpip.IP
)
ipVersion = tcpip.IPVersion(raw)
switch ipVersion {
case tcpip.IPv4Version:
ipv4 := tcpip.IPv4Packet(raw)
if !ipv4.Valid() {
continue
}
if ipv4.TimeToLive() == 0x00 {
continue
}
if ipv4.Flags()&tcpip.FlagMoreFragment != 0 {
continue
}
if ipv4.Offset() != 0 {
continue
}
ip = ipv4
case tcpip.IPv6Version:
ipv6 := tcpip.IPv6Packet(raw)
if !ipv6.Valid() {
continue
}
if ipv6.HopLimit() == 0x00 {
continue
}
ip = ipv6
default:
continue
}
switch ip.Protocol() {
case tcpip.TCP:
t := tcpip.TCPPacket(ip.Payload())
if !t.Valid() {
continue
}
if ip.DestinationIP() == portal {
if ip.SourceIP() == gateway && t.SourcePort() == gatewayPort {
tup := tab.tupleOf(t.DestinationPort())
if tup == zeroTuple {
continue
}
ip.SetSourceIP(tup.DestinationAddr.Addr())
t.SetSourcePort(tup.DestinationAddr.Port())
ip.SetDestinationIP(tup.SourceAddr.Addr())
t.SetDestinationPort(tup.SourceAddr.Port())
ip.DecTimeToLive()
ip.ResetChecksum()
t.ResetChecksum(ip.PseudoSum())
_, _ = device.Write(raw)
}
} else {
tup := tuple{
SourceAddr: netip.AddrPortFrom(ip.SourceIP(), t.SourcePort()),
DestinationAddr: netip.AddrPortFrom(ip.DestinationIP(), t.DestinationPort()),
}
port := tab.portOf(tup)
if port == 0 {
if t.Flags() != tcpip.TCPSyn {
continue
}
port = tab.newConn(tup)
}
ip.SetSourceIP(portal)
ip.SetDestinationIP(gateway)
t.SetSourcePort(port)
t.SetDestinationPort(gatewayPort)
ip.DecTimeToLive()
ip.ResetChecksum()
t.ResetChecksum(ip.PseudoSum())
_, _ = device.Write(raw)
}
case tcpip.UDP:
u := tcpip.UDPPacket(ip.Payload())
if !u.Valid() {
continue
}
udp.handleUDPPacket(ip, u)
case tcpip.ICMP:
i := tcpip.ICMPPacket(ip.Payload())
if i.Type() != tcpip.ICMPTypePingRequest || i.Code() != 0 {
continue
}
i.SetType(tcpip.ICMPTypePingResponse)
source := ip.SourceIP()
destination := ip.DestinationIP()
ip.SetSourceIP(destination)
ip.SetDestinationIP(source)
ip.DecTimeToLive()
ip.ResetChecksum()
i.ResetChecksum()
_, _ = device.Write(raw)
case tcpip.ICMPv6:
i := tcpip.ICMPv6Packet(ip.Payload())
if i.Type() != tcpip.ICMPv6EchoRequest || i.Code() != 0 {
continue
}
i.SetType(tcpip.ICMPv6EchoReply)
source := ip.SourceIP()
destination := ip.DestinationIP()
ip.SetSourceIP(destination)
ip.SetDestinationIP(source)
ip.DecTimeToLive()
ip.ResetChecksum()
i.ResetChecksum(ip.PseudoSum())
_, _ = device.Write(raw)
}
}
}()
return tcp, udp, nil
}

View File

@ -0,0 +1,83 @@
package nat
import (
"container/list"
"net/netip"
)
const (
portBegin = 30000
portLength = 4096
)
var zeroTuple = tuple{}
type tuple struct {
SourceAddr netip.AddrPort
DestinationAddr netip.AddrPort
}
type binding struct {
tuple tuple
offset uint16
}
type table struct {
tuples map[tuple]*list.Element
ports [portLength]*list.Element
available *list.List
}
func (t *table) tupleOf(port uint16) tuple {
offset := port - portBegin
if offset > portLength {
return zeroTuple
}
elm := t.ports[offset]
t.available.MoveToFront(elm)
return elm.Value.(*binding).tuple
}
func (t *table) portOf(tuple tuple) uint16 {
elm := t.tuples[tuple]
if elm == nil {
return 0
}
t.available.MoveToFront(elm)
return portBegin + elm.Value.(*binding).offset
}
func (t *table) newConn(tuple tuple) uint16 {
elm := t.available.Back()
b := elm.Value.(*binding)
delete(t.tuples, b.tuple)
t.tuples[tuple] = elm
b.tuple = tuple
t.available.MoveToFront(elm)
return portBegin + b.offset
}
func newTable() *table {
result := &table{
tuples: make(map[tuple]*list.Element, portLength),
ports: [portLength]*list.Element{},
available: list.New(),
}
for idx := range result.ports {
result.ports[idx] = result.available.PushFront(&binding{
tuple: tuple{},
offset: uint16(idx),
})
}
return result
}

View File

@ -0,0 +1,69 @@
package nat
import (
"net"
"net/netip"
"time"
)
type TCP struct {
listener *net.TCPListener
portal netip.Addr
table *table
}
type conn struct {
net.Conn
tuple tuple
}
func (t *TCP) Accept() (net.Conn, error) {
c, err := t.listener.AcceptTCP()
if err != nil {
return nil, err
}
addr := c.RemoteAddr().(*net.TCPAddr)
tup := t.table.tupleOf(uint16(addr.Port))
if !addr.IP.Equal(t.portal.AsSlice()) || tup == zeroTuple {
_ = c.Close()
return nil, net.InvalidAddrError("unknown remote addr")
}
// _ = c.SetKeepAlive(false)
addition(c)
return &conn{
Conn: c,
tuple: tup,
}, nil
}
func (t *TCP) Close() error {
return t.listener.Close()
}
func (t *TCP) Addr() net.Addr {
return t.listener.Addr()
}
func (t *TCP) SetDeadline(time time.Time) error {
return t.listener.SetDeadline(time)
}
func (c *conn) LocalAddr() net.Addr {
return &net.TCPAddr{
IP: c.tuple.SourceAddr.Addr().AsSlice(),
Port: int(c.tuple.SourceAddr.Port()),
}
}
func (c *conn) RemoteAddr() net.Addr {
return &net.TCPAddr{
IP: c.tuple.DestinationAddr.Addr().AsSlice(),
Port: int(c.tuple.DestinationAddr.Port()),
}
}

View File

@ -0,0 +1,15 @@
package nat
import (
"net"
"syscall"
)
func addition(c *net.TCPConn) {
sys, err := c.SyscallConn()
if err == nil {
_ = sys.Control(func(fd uintptr) {
_ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_NO_CHECK, 1)
})
}
}

View File

@ -0,0 +1,7 @@
//go:build !linux
package nat
import "net"
func addition(*net.TCPConn) {}

View File

@ -0,0 +1,140 @@
package nat
import (
"io"
"math/rand"
"net"
"net/netip"
"sync"
"github.com/Dreamacro/clash/listener/tun/ipstack/system/mars/tcpip"
)
type call struct {
cond *sync.Cond
buf []byte
n int
source net.Addr
destination net.Addr
}
type UDP struct {
closed bool
lock sync.Mutex
calls map[*call]struct{}
device io.Writer
bufLock sync.Mutex
buf [65535]byte
}
func (u *UDP) ReadFrom(buf []byte) (int, net.Addr, net.Addr, error) {
u.lock.Lock()
defer u.lock.Unlock()
for !u.closed {
c := &call{
cond: sync.NewCond(&u.lock),
buf: buf,
n: -1,
source: nil,
destination: nil,
}
u.calls[c] = struct{}{}
c.cond.Wait()
if c.n >= 0 {
return c.n, c.source, c.destination, nil
}
}
return -1, nil, nil, net.ErrClosed
}
func (u *UDP) WriteTo(buf []byte, local net.Addr, remote net.Addr) (int, error) {
u.bufLock.Lock()
defer u.bufLock.Unlock()
if len(buf) > 0xffff {
return 0, net.InvalidAddrError("invalid ip version")
}
srcAddr, srcOk := local.(*net.UDPAddr)
dstAddr, dstOk := remote.(*net.UDPAddr)
if !srcOk || !dstOk {
return 0, net.InvalidAddrError("invalid addr")
}
srcIP, _ := netip.AddrFromSlice(srcAddr.IP)
dstIp, _ := netip.AddrFromSlice(dstAddr.IP)
srcAddrPort := netip.AddrPortFrom(srcIP, uint16(srcAddr.Port))
dstAddrPort := netip.AddrPortFrom(dstIp, uint16(dstAddr.Port))
if !srcAddrPort.Addr().Is4() || !dstAddrPort.Addr().Is4() {
return 0, net.InvalidAddrError("invalid ip version")
}
ip := tcpip.IPv4Packet(u.buf[:])
tcpip.SetIPv4(ip)
ip.SetHeaderLen(tcpip.IPv4HeaderSize)
ip.SetTotalLength(tcpip.IPv4HeaderSize + tcpip.UDPHeaderSize + uint16(len(buf)))
ip.SetTypeOfService(0)
ip.SetIdentification(uint16(rand.Uint32()))
ip.SetFragmentOffset(0)
ip.SetTimeToLive(64)
ip.SetProtocol(tcpip.UDP)
ip.SetSourceIP(srcAddrPort.Addr())
ip.SetDestinationIP(dstAddrPort.Addr())
udp := tcpip.UDPPacket(ip.Payload())
udp.SetLength(tcpip.UDPHeaderSize + uint16(len(buf)))
udp.SetSourcePort(srcAddrPort.Port())
udp.SetDestinationPort(dstAddrPort.Port())
copy(udp.Payload(), buf)
ip.ResetChecksum()
udp.ResetChecksum(ip.PseudoSum())
return u.device.Write(u.buf[:ip.TotalLen()])
}
func (u *UDP) Close() error {
u.lock.Lock()
defer u.lock.Unlock()
u.closed = true
for c := range u.calls {
c.cond.Signal()
}
return nil
}
func (u *UDP) handleUDPPacket(ip tcpip.IP, pkt tcpip.UDPPacket) {
var c *call
u.lock.Lock()
for c = range u.calls {
delete(u.calls, c)
break
}
u.lock.Unlock()
if c != nil {
c.source = &net.UDPAddr{
IP: ip.SourceIP().AsSlice(),
Port: int(pkt.SourcePort()),
}
c.destination = &net.UDPAddr{
IP: ip.DestinationIP().AsSlice(),
Port: int(pkt.DestinationPort()),
}
c.n = copy(c.buf, pkt.Payload())
c.cond.Signal()
}
}

View File

@ -0,0 +1,40 @@
package tcpip
import (
"encoding/binary"
)
type ICMPType = byte
const (
ICMPTypePingRequest byte = 0x8
ICMPTypePingResponse byte = 0x0
)
type ICMPPacket []byte
func (p ICMPPacket) Type() ICMPType {
return p[0]
}
func (p ICMPPacket) SetType(v ICMPType) {
p[0] = v
}
func (p ICMPPacket) Code() byte {
return p[1]
}
func (p ICMPPacket) Checksum() uint16 {
return binary.BigEndian.Uint16(p[2:])
}
func (p ICMPPacket) SetChecksum(sum [2]byte) {
p[2] = sum[0]
p[3] = sum[1]
}
func (p ICMPPacket) ResetChecksum() {
p.SetChecksum(zeroChecksum)
p.SetChecksum(Checksum(0, p))
}

View File

@ -0,0 +1,172 @@
package tcpip
import (
"encoding/binary"
)
type ICMPv6Packet []byte
const (
ICMPv6HeaderSize = 4
ICMPv6MinimumSize = 8
ICMPv6PayloadOffset = 8
ICMPv6EchoMinimumSize = 8
ICMPv6ErrorHeaderSize = 8
ICMPv6DstUnreachableMinimumSize = ICMPv6MinimumSize
ICMPv6PacketTooBigMinimumSize = ICMPv6MinimumSize
ICMPv6ChecksumOffset = 2
icmpv6PointerOffset = 4
icmpv6MTUOffset = 4
icmpv6IdentOffset = 4
icmpv6SequenceOffset = 6
NDPHopLimit = 255
)
type ICMPv6Type byte
const (
ICMPv6DstUnreachable ICMPv6Type = 1
ICMPv6PacketTooBig ICMPv6Type = 2
ICMPv6TimeExceeded ICMPv6Type = 3
ICMPv6ParamProblem ICMPv6Type = 4
ICMPv6EchoRequest ICMPv6Type = 128
ICMPv6EchoReply ICMPv6Type = 129
ICMPv6RouterSolicit ICMPv6Type = 133
ICMPv6RouterAdvert ICMPv6Type = 134
ICMPv6NeighborSolicit ICMPv6Type = 135
ICMPv6NeighborAdvert ICMPv6Type = 136
ICMPv6RedirectMsg ICMPv6Type = 137
ICMPv6MulticastListenerQuery ICMPv6Type = 130
ICMPv6MulticastListenerReport ICMPv6Type = 131
ICMPv6MulticastListenerDone ICMPv6Type = 132
)
func (typ ICMPv6Type) IsErrorType() bool {
return typ&0x80 == 0
}
type ICMPv6Code byte
const (
ICMPv6NetworkUnreachable ICMPv6Code = 0
ICMPv6Prohibited ICMPv6Code = 1
ICMPv6BeyondScope ICMPv6Code = 2
ICMPv6AddressUnreachable ICMPv6Code = 3
ICMPv6PortUnreachable ICMPv6Code = 4
ICMPv6Policy ICMPv6Code = 5
ICMPv6RejectRoute ICMPv6Code = 6
)
const (
ICMPv6HopLimitExceeded ICMPv6Code = 0
ICMPv6ReassemblyTimeout ICMPv6Code = 1
)
const (
ICMPv6ErroneousHeader ICMPv6Code = 0
ICMPv6UnknownHeader ICMPv6Code = 1
ICMPv6UnknownOption ICMPv6Code = 2
)
const ICMPv6UnusedCode ICMPv6Code = 0
func (b ICMPv6Packet) Type() ICMPv6Type {
return ICMPv6Type(b[0])
}
func (b ICMPv6Packet) SetType(t ICMPv6Type) {
b[0] = byte(t)
}
func (b ICMPv6Packet) Code() ICMPv6Code {
return ICMPv6Code(b[1])
}
func (b ICMPv6Packet) SetCode(c ICMPv6Code) {
b[1] = byte(c)
}
func (b ICMPv6Packet) TypeSpecific() uint32 {
return binary.BigEndian.Uint32(b[icmpv6PointerOffset:])
}
func (b ICMPv6Packet) SetTypeSpecific(val uint32) {
binary.BigEndian.PutUint32(b[icmpv6PointerOffset:], val)
}
func (b ICMPv6Packet) Checksum() uint16 {
return binary.BigEndian.Uint16(b[ICMPv6ChecksumOffset:])
}
func (b ICMPv6Packet) SetChecksum(sum [2]byte) {
_ = b[ICMPv6ChecksumOffset+1]
b[ICMPv6ChecksumOffset] = sum[0]
b[ICMPv6ChecksumOffset+1] = sum[1]
}
func (ICMPv6Packet) SourcePort() uint16 {
return 0
}
func (ICMPv6Packet) DestinationPort() uint16 {
return 0
}
func (ICMPv6Packet) SetSourcePort(uint16) {
}
func (ICMPv6Packet) SetDestinationPort(uint16) {
}
func (b ICMPv6Packet) MTU() uint32 {
return binary.BigEndian.Uint32(b[icmpv6MTUOffset:])
}
func (b ICMPv6Packet) SetMTU(mtu uint32) {
binary.BigEndian.PutUint32(b[icmpv6MTUOffset:], mtu)
}
func (b ICMPv6Packet) Ident() uint16 {
return binary.BigEndian.Uint16(b[icmpv6IdentOffset:])
}
func (b ICMPv6Packet) SetIdent(ident uint16) {
binary.BigEndian.PutUint16(b[icmpv6IdentOffset:], ident)
}
func (b ICMPv6Packet) Sequence() uint16 {
return binary.BigEndian.Uint16(b[icmpv6SequenceOffset:])
}
func (b ICMPv6Packet) SetSequence(sequence uint16) {
binary.BigEndian.PutUint16(b[icmpv6SequenceOffset:], sequence)
}
func (b ICMPv6Packet) MessageBody() []byte {
return b[ICMPv6HeaderSize:]
}
func (b ICMPv6Packet) Payload() []byte {
return b[ICMPv6PayloadOffset:]
}
func (b ICMPv6Packet) ResetChecksum(psum uint32) {
b.SetChecksum(zeroChecksum)
b.SetChecksum(Checksum(psum, b))
}

View File

@ -0,0 +1,215 @@
package tcpip
import (
"encoding/binary"
"errors"
"net/netip"
)
type IPProtocol = byte
type IP interface {
Payload() []byte
SourceIP() netip.Addr
DestinationIP() netip.Addr
SetSourceIP(ip netip.Addr)
SetDestinationIP(ip netip.Addr)
Protocol() IPProtocol
DecTimeToLive()
ResetChecksum()
PseudoSum() uint32
}
// IPProtocol type
const (
ICMP IPProtocol = 0x01
TCP IPProtocol = 0x06
UDP IPProtocol = 0x11
ICMPv6 IPProtocol = 0x3a
)
const (
FlagDontFragment = 1 << 1
FlagMoreFragment = 1 << 2
)
const (
IPv4HeaderSize = 20
IPv4Version = 4
IPv4OptionsOffset = 20
IPv4PacketMinLength = IPv4OptionsOffset
)
var (
ErrInvalidLength = errors.New("invalid packet length")
ErrInvalidIPVersion = errors.New("invalid ip version")
ErrInvalidChecksum = errors.New("invalid checksum")
)
type IPv4Packet []byte
func (p IPv4Packet) TotalLen() uint16 {
return binary.BigEndian.Uint16(p[2:])
}
func (p IPv4Packet) SetTotalLength(length uint16) {
binary.BigEndian.PutUint16(p[2:], length)
}
func (p IPv4Packet) HeaderLen() uint16 {
return uint16(p[0]&0xf) * 4
}
func (p IPv4Packet) SetHeaderLen(length uint16) {
p[0] &= 0xF0
p[0] |= byte(length / 4)
}
func (p IPv4Packet) TypeOfService() byte {
return p[1]
}
func (p IPv4Packet) SetTypeOfService(tos byte) {
p[1] = tos
}
func (p IPv4Packet) Identification() uint16 {
return binary.BigEndian.Uint16(p[4:])
}
func (p IPv4Packet) SetIdentification(id uint16) {
binary.BigEndian.PutUint16(p[4:], id)
}
func (p IPv4Packet) FragmentOffset() uint16 {
return binary.BigEndian.Uint16([]byte{p[6] & 0x7, p[7]}) * 8
}
func (p IPv4Packet) SetFragmentOffset(offset uint32) {
flags := p.Flags()
binary.BigEndian.PutUint16(p[6:], uint16(offset/8))
p.SetFlags(flags)
}
func (p IPv4Packet) DataLen() uint16 {
return p.TotalLen() - p.HeaderLen()
}
func (p IPv4Packet) Payload() []byte {
return p[p.HeaderLen():p.TotalLen()]
}
func (p IPv4Packet) Protocol() IPProtocol {
return p[9]
}
func (p IPv4Packet) SetProtocol(protocol IPProtocol) {
p[9] = protocol
}
func (p IPv4Packet) Flags() byte {
return p[6] >> 5
}
func (p IPv4Packet) SetFlags(flags byte) {
p[6] &= 0x1F
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 {
return netip.AddrFrom4([4]byte{p[12], p[13], p[14], p[15]})
}
func (p IPv4Packet) SetSourceIP(ip netip.Addr) {
if ip.Is4() {
copy(p[12:16], ip.AsSlice())
}
}
func (p IPv4Packet) DestinationIP() netip.Addr {
return netip.AddrFrom4([4]byte{p[16], p[17], p[18], p[19]})
}
func (p IPv4Packet) SetDestinationIP(ip netip.Addr) {
if ip.Is4() {
copy(p[16:20], ip.AsSlice())
}
}
func (p IPv4Packet) Checksum() uint16 {
return binary.BigEndian.Uint16(p[10:])
}
func (p IPv4Packet) SetChecksum(sum [2]byte) {
p[10] = sum[0]
p[11] = sum[1]
}
func (p IPv4Packet) TimeToLive() uint8 {
return p[8]
}
func (p IPv4Packet) SetTimeToLive(ttl uint8) {
p[8] = ttl
}
func (p IPv4Packet) DecTimeToLive() {
p[8] = p[8] - uint8(1)
}
func (p IPv4Packet) ResetChecksum() {
p.SetChecksum(zeroChecksum)
p.SetChecksum(Checksum(0, p[:p.HeaderLen()]))
}
// PseudoSum for tcp checksum
func (p IPv4Packet) PseudoSum() uint32 {
sum := Sum(p[12:20])
sum += uint32(p.Protocol())
sum += uint32(p.DataLen())
return sum
}
func (p IPv4Packet) Valid() bool {
return len(p) >= IPv4HeaderSize && uint16(len(p)) >= p.TotalLen()
}
func (p IPv4Packet) Verify() error {
if len(p) < IPv4PacketMinLength {
return ErrInvalidLength
}
checksum := []byte{p[10], p[11]}
headerLength := uint16(p[0]&0xF) * 4
packetLength := binary.BigEndian.Uint16(p[2:])
if p[0]>>4 != 4 {
return ErrInvalidIPVersion
}
if uint16(len(p)) < packetLength || packetLength < headerLength {
return ErrInvalidLength
}
p[10] = 0
p[11] = 0
defer copy(p[10:12], checksum)
answer := Checksum(0, p[:headerLength])
if answer[0] != checksum[0] || answer[1] != checksum[1] {
return ErrInvalidChecksum
}
return nil
}
var _ IP = (*IPv4Packet)(nil)

View File

@ -0,0 +1,141 @@
package tcpip
import (
"encoding/binary"
"net/netip"
)
const (
versTCFL = 0
IPv6PayloadLenOffset = 4
IPv6NextHeaderOffset = 6
hopLimit = 7
v6SrcAddr = 8
v6DstAddr = v6SrcAddr + IPv6AddressSize
IPv6FixedHeaderSize = v6DstAddr + IPv6AddressSize
)
const (
versIHL = 0
tos = 1
ipVersionShift = 4
ipIHLMask = 0x0f
IPv4IHLStride = 4
)
type IPv6Packet []byte
const (
IPv6MinimumSize = IPv6FixedHeaderSize
IPv6AddressSize = 16
IPv6Version = 6
IPv6MinimumMTU = 1280
)
func (b IPv6Packet) PayloadLength() uint16 {
return binary.BigEndian.Uint16(b[IPv6PayloadLenOffset:])
}
func (b IPv6Packet) HopLimit() uint8 {
return b[hopLimit]
}
func (b IPv6Packet) NextHeader() byte {
return b[IPv6NextHeaderOffset]
}
func (b IPv6Packet) Protocol() IPProtocol {
return b.NextHeader()
}
func (b IPv6Packet) Payload() []byte {
return b[IPv6MinimumSize:][:b.PayloadLength()]
}
func (b IPv6Packet) SourceIP() netip.Addr {
addr, _ := netip.AddrFromSlice(b[v6SrcAddr:][:IPv6AddressSize])
return addr
}
func (b IPv6Packet) DestinationIP() netip.Addr {
addr, _ := netip.AddrFromSlice(b[v6DstAddr:][:IPv6AddressSize])
return addr
}
func (IPv6Packet) Checksum() uint16 {
return 0
}
func (b IPv6Packet) TOS() (uint8, uint32) {
v := binary.BigEndian.Uint32(b[versTCFL:])
return uint8(v >> 20), v & 0xfffff
}
func (b IPv6Packet) SetTOS(t uint8, l uint32) {
vtf := (6 << 28) | (uint32(t) << 20) | (l & 0xfffff)
binary.BigEndian.PutUint32(b[versTCFL:], vtf)
}
func (b IPv6Packet) SetPayloadLength(payloadLength uint16) {
binary.BigEndian.PutUint16(b[IPv6PayloadLenOffset:], payloadLength)
}
func (b IPv6Packet) SetSourceIP(addr netip.Addr) {
if addr.Is6() {
copy(b[v6SrcAddr:][:IPv6AddressSize], addr.AsSlice())
}
}
func (b IPv6Packet) SetDestinationIP(addr netip.Addr) {
if addr.Is6() {
copy(b[v6DstAddr:][:IPv6AddressSize], addr.AsSlice())
}
}
func (b IPv6Packet) SetHopLimit(v uint8) {
b[hopLimit] = v
}
func (b IPv6Packet) SetNextHeader(v byte) {
b[IPv6NextHeaderOffset] = v
}
func (b IPv6Packet) SetProtocol(p IPProtocol) {
b.SetNextHeader(p)
}
func (b IPv6Packet) DecTimeToLive() {
b[hopLimit] = b[hopLimit] - uint8(1)
}
func (IPv6Packet) SetChecksum(uint16) {
}
func (IPv6Packet) ResetChecksum() {
}
func (b IPv6Packet) PseudoSum() uint32 {
sum := Sum(b[v6SrcAddr:IPv6FixedHeaderSize])
sum += uint32(b.Protocol())
sum += uint32(b.PayloadLength())
return sum
}
func (b IPv6Packet) Valid() bool {
return len(b) >= IPv6MinimumSize && len(b) >= int(b.PayloadLength())+IPv6MinimumSize
}
func IPVersion(b []byte) int {
if len(b) < versIHL+1 {
return -1
}
return int(b[versIHL] >> ipVersionShift)
}
var _ IP = (*IPv6Packet)(nil)

View File

@ -0,0 +1,90 @@
package tcpip
import (
"encoding/binary"
"net"
)
const (
TCPFin uint16 = 1 << 0
TCPSyn uint16 = 1 << 1
TCPRst uint16 = 1 << 2
TCPPuh uint16 = 1 << 3
TCPAck uint16 = 1 << 4
TCPUrg uint16 = 1 << 5
TCPEce uint16 = 1 << 6
TCPEwr uint16 = 1 << 7
TCPNs uint16 = 1 << 8
)
const TCPHeaderSize = 20
type TCPPacket []byte
func (p TCPPacket) SourcePort() uint16 {
return binary.BigEndian.Uint16(p)
}
func (p TCPPacket) SetSourcePort(port uint16) {
binary.BigEndian.PutUint16(p, port)
}
func (p TCPPacket) DestinationPort() uint16 {
return binary.BigEndian.Uint16(p[2:])
}
func (p TCPPacket) SetDestinationPort(port uint16) {
binary.BigEndian.PutUint16(p[2:], port)
}
func (p TCPPacket) Flags() uint16 {
return uint16(p[13] | (p[12] & 0x1))
}
func (p TCPPacket) Checksum() uint16 {
return binary.BigEndian.Uint16(p[16:])
}
func (p TCPPacket) SetChecksum(sum [2]byte) {
p[16] = sum[0]
p[17] = sum[1]
}
func (p TCPPacket) ResetChecksum(psum uint32) {
p.SetChecksum(zeroChecksum)
p.SetChecksum(Checksum(psum, p))
}
func (p TCPPacket) Valid() bool {
return len(p) >= TCPHeaderSize
}
func (p TCPPacket) Verify(sourceAddress net.IP, targetAddress net.IP) error {
var checksum [2]byte
checksum[0] = p[16]
checksum[1] = p[17]
// reset checksum
p[16] = 0
p[17] = 0
// restore checksum
defer func() {
p[16] = checksum[0]
p[17] = checksum[1]
}()
// check checksum
s := uint32(0)
s += Sum(sourceAddress)
s += Sum(targetAddress)
s += uint32(TCP)
s += uint32(len(p))
check := Checksum(s, p)
if checksum[0] != check[0] || checksum[1] != check[1] {
return ErrInvalidChecksum
}
return nil
}

View File

@ -0,0 +1,24 @@
package tcpip
var zeroChecksum = [2]byte{0x00, 0x00}
var SumFnc = SumCompat
func Sum(b []byte) uint32 {
return SumFnc(b)
}
// Checksum for Internet Protocol family headers
func Checksum(sum uint32, b []byte) (answer [2]byte) {
sum += Sum(b)
sum = (sum >> 16) + (sum & 0xffff)
sum += sum >> 16
sum = ^sum
answer[0] = byte(sum >> 8)
answer[1] = byte(sum)
return
}
func SetIPv4(packet []byte) {
packet[0] = (packet[0] & 0x0f) | (4 << 4)
}

View File

@ -0,0 +1,27 @@
//go:build !noasm
// +build !noasm
package tcpip
import (
"unsafe"
"golang.org/x/sys/cpu"
)
//go:noescape
func sumAsmAvx2(data unsafe.Pointer, length uintptr) uintptr
func SumAVX2(data []byte) uint32 {
if len(data) == 0 {
return 0
}
return uint32(sumAsmAvx2(unsafe.Pointer(&data[0]), uintptr(len(data))))
}
func init() {
if cpu.X86.HasAVX2 {
SumFnc = SumAVX2
}
}

View File

@ -0,0 +1,140 @@
#include "textflag.h"
DATA endian_swap_mask<>+0(SB)/8, $0x607040502030001
DATA endian_swap_mask<>+8(SB)/8, $0xE0F0C0D0A0B0809
DATA endian_swap_mask<>+16(SB)/8, $0x607040502030001
DATA endian_swap_mask<>+24(SB)/8, $0xE0F0C0D0A0B0809
GLOBL endian_swap_mask<>(SB), RODATA, $32
// func sumAsmAvx2(data unsafe.Pointer, length uintptr) uintptr
//
// args (8 bytes aligned):
// data unsafe.Pointer - 8 bytes - 0 offset
// length uintptr - 8 bytes - 8 offset
// result uintptr - 8 bytes - 16 offset
#define PDATA AX
#define LENGTH CX
#define RESULT BX
TEXT ·sumAsmAvx2(SB),NOSPLIT,$0-24
MOVQ data+0(FP), PDATA
MOVQ length+8(FP), LENGTH
XORQ RESULT, RESULT
#define VSUM Y0
#define ENDIAN_SWAP_MASK Y1
BEGIN:
VMOVDQU endian_swap_mask<>(SB), ENDIAN_SWAP_MASK
VPXOR VSUM, VSUM, VSUM
#define LOADED_0 Y2
#define LOADED_1 Y3
#define LOADED_2 Y4
#define LOADED_3 Y5
BATCH_64:
CMPQ LENGTH, $64
JB BATCH_32
VPMOVZXWD (PDATA), LOADED_0
VPMOVZXWD 16(PDATA), LOADED_1
VPMOVZXWD 32(PDATA), LOADED_2
VPMOVZXWD 48(PDATA), LOADED_3
VPSHUFB ENDIAN_SWAP_MASK, LOADED_0, LOADED_0
VPSHUFB ENDIAN_SWAP_MASK, LOADED_1, LOADED_1
VPSHUFB ENDIAN_SWAP_MASK, LOADED_2, LOADED_2
VPSHUFB ENDIAN_SWAP_MASK, LOADED_3, LOADED_3
VPADDD LOADED_0, VSUM, VSUM
VPADDD LOADED_1, VSUM, VSUM
VPADDD LOADED_2, VSUM, VSUM
VPADDD LOADED_3, VSUM, VSUM
ADDQ $-64, LENGTH
ADDQ $64, PDATA
JMP BATCH_64
#undef LOADED_0
#undef LOADED_1
#undef LOADED_2
#undef LOADED_3
#define LOADED_0 Y2
#define LOADED_1 Y3
BATCH_32:
CMPQ LENGTH, $32
JB BATCH_16
VPMOVZXWD (PDATA), LOADED_0
VPMOVZXWD 16(PDATA), LOADED_1
VPSHUFB ENDIAN_SWAP_MASK, LOADED_0, LOADED_0
VPSHUFB ENDIAN_SWAP_MASK, LOADED_1, LOADED_1
VPADDD LOADED_0, VSUM, VSUM
VPADDD LOADED_1, VSUM, VSUM
ADDQ $-32, LENGTH
ADDQ $32, PDATA
JMP BATCH_32
#undef LOADED_0
#undef LOADED_1
#define LOADED Y2
BATCH_16:
CMPQ LENGTH, $16
JB COLLECT
VPMOVZXWD (PDATA), LOADED
VPSHUFB ENDIAN_SWAP_MASK, LOADED, LOADED
VPADDD LOADED, VSUM, VSUM
ADDQ $-16, LENGTH
ADDQ $16, PDATA
JMP BATCH_16
#undef LOADED
#define EXTRACTED Y2
#define EXTRACTED_128 X2
#define TEMP_64 DX
COLLECT:
VEXTRACTI128 $0, VSUM, EXTRACTED_128
VPEXTRD $0, EXTRACTED_128, TEMP_64
ADDL TEMP_64, RESULT
VPEXTRD $1, EXTRACTED_128, TEMP_64
ADDL TEMP_64, RESULT
VPEXTRD $2, EXTRACTED_128, TEMP_64
ADDL TEMP_64, RESULT
VPEXTRD $3, EXTRACTED_128, TEMP_64
ADDL TEMP_64, RESULT
VEXTRACTI128 $1, VSUM, EXTRACTED_128
VPEXTRD $0, EXTRACTED_128, TEMP_64
ADDL TEMP_64, RESULT
VPEXTRD $1, EXTRACTED_128, TEMP_64
ADDL TEMP_64, RESULT
VPEXTRD $2, EXTRACTED_128, TEMP_64
ADDL TEMP_64, RESULT
VPEXTRD $3, EXTRACTED_128, TEMP_64
ADDL TEMP_64, RESULT
#undef EXTRACTED
#undef EXTRACTED_128
#undef TEMP_64
#define TEMP DX
#define TEMP2 SI
BATCH_2:
CMPQ LENGTH, $2
JB BATCH_1
XORQ TEMP, TEMP
MOVW (PDATA), TEMP
MOVQ TEMP, TEMP2
SHRW $8, TEMP2
SHLW $8, TEMP
ORW TEMP2, TEMP
ADDL TEMP, RESULT
ADDQ $-2, LENGTH
ADDQ $2, PDATA
JMP BATCH_2
#undef TEMP
#define TEMP DX
BATCH_1:
CMPQ LENGTH, $0
JZ RETURN
XORQ TEMP, TEMP
MOVB (PDATA), TEMP
SHLW $8, TEMP
ADDL TEMP, RESULT
#undef TEMP
RETURN:
MOVQ RESULT, result+16(FP)
RET

View File

@ -0,0 +1,51 @@
package tcpip
import (
"crypto/rand"
"testing"
"golang.org/x/sys/cpu"
)
func Test_SumAVX2(t *testing.T) {
if !cpu.X86.HasAVX2 {
t.Skipf("AVX2 unavailable")
}
bytes := make([]byte, chunkSize)
for size := 0; size <= chunkSize; size++ {
for count := 0; count < chunkCount; count++ {
_, err := rand.Reader.Read(bytes[:size])
if err != nil {
t.Skipf("Rand read failed: %v", err)
}
compat := SumCompat(bytes[:size])
avx := SumAVX2(bytes[:size])
if compat != avx {
t.Errorf("Sum of length=%d mismatched", size)
}
}
}
}
func Benchmark_SumAVX2(b *testing.B) {
if !cpu.X86.HasAVX2 {
b.Skipf("AVX2 unavailable")
}
bytes := make([]byte, chunkSize)
_, err := rand.Reader.Read(bytes)
if err != nil {
b.Skipf("Rand read failed: %v", err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
SumAVX2(bytes)
}
}

View File

@ -0,0 +1,24 @@
package tcpip
import (
"unsafe"
"golang.org/x/sys/cpu"
)
//go:noescape
func sumAsmNeon(data unsafe.Pointer, length uintptr) uintptr
func SumNeon(data []byte) uint32 {
if len(data) == 0 {
return 0
}
return uint32(sumAsmNeon(unsafe.Pointer(&data[0]), uintptr(len(data))))
}
func init() {
if cpu.ARM64.HasASIMD {
SumFnc = SumNeon
}
}

View File

@ -0,0 +1,118 @@
#include "textflag.h"
// func sumAsmNeon(data unsafe.Pointer, length uintptr) uintptr
//
// args (8 bytes aligned):
// data unsafe.Pointer - 8 bytes - 0 offset
// length uintptr - 8 bytes - 8 offset
// result uintptr - 8 bytes - 16 offset
#define PDATA R0
#define LENGTH R1
#define RESULT R2
#define VSUM V0
TEXT ·sumAsmNeon(SB),NOSPLIT,$0-24
MOVD data+0(FP), PDATA
MOVD length+8(FP), LENGTH
MOVD $0, RESULT
VMOVQ $0, $0, VSUM
#define LOADED_0 V1
#define LOADED_1 V2
#define LOADED_2 V3
#define LOADED_3 V4
BATCH_32:
CMP $32, LENGTH
BLO BATCH_16
VLD1 (PDATA), [LOADED_0.B8, LOADED_1.B8, LOADED_2.B8, LOADED_3.B8]
VREV16 LOADED_0.B8, LOADED_0.B8
VREV16 LOADED_1.B8, LOADED_1.B8
VREV16 LOADED_2.B8, LOADED_2.B8
VREV16 LOADED_3.B8, LOADED_3.B8
VUSHLL $0, LOADED_0.H4, LOADED_0.S4
VUSHLL $0, LOADED_1.H4, LOADED_1.S4
VUSHLL $0, LOADED_2.H4, LOADED_2.S4
VUSHLL $0, LOADED_3.H4, LOADED_3.S4
VADD LOADED_0.S4, VSUM.S4, VSUM.S4
VADD LOADED_1.S4, VSUM.S4, VSUM.S4
VADD LOADED_2.S4, VSUM.S4, VSUM.S4
VADD LOADED_3.S4, VSUM.S4, VSUM.S4
ADD $-32, LENGTH
ADD $32, PDATA
B BATCH_32
#undef LOADED_0
#undef LOADED_1
#undef LOADED_2
#undef LOADED_3
#define LOADED_0 V1
#define LOADED_1 V2
BATCH_16:
CMP $16, LENGTH
BLO BATCH_8
VLD1 (PDATA), [LOADED_0.B8, LOADED_1.B8]
VREV16 LOADED_0.B8, LOADED_0.B8
VREV16 LOADED_1.B8, LOADED_1.B8
VUSHLL $0, LOADED_0.H4, LOADED_0.S4
VUSHLL $0, LOADED_1.H4, LOADED_1.S4
VADD LOADED_0.S4, VSUM.S4, VSUM.S4
VADD LOADED_1.S4, VSUM.S4, VSUM.S4
ADD $-16, LENGTH
ADD $16, PDATA
B BATCH_16
#undef LOADED_0
#undef LOADED_1
#define LOADED_0 V1
BATCH_8:
CMP $8, LENGTH
BLO BATCH_2
VLD1 (PDATA), [LOADED_0.B8]
VREV16 LOADED_0.B8, LOADED_0.B8
VUSHLL $0, LOADED_0.H4, LOADED_0.S4
VADD LOADED_0.S4, VSUM.S4, VSUM.S4
ADD $-8, LENGTH
ADD $8, PDATA
B BATCH_8
#undef LOADED_0
#define LOADED_L R3
#define LOADED_H R4
BATCH_2:
CMP $2, LENGTH
BLO BATCH_1
MOVBU (PDATA), LOADED_H
MOVBU 1(PDATA), LOADED_L
LSL $8, LOADED_H
ORR LOADED_H, LOADED_L, LOADED_L
ADD LOADED_L, RESULT, RESULT
ADD $2, PDATA
ADD $-2, LENGTH
B BATCH_2
#undef LOADED_H
#undef LOADED_L
#define LOADED R3
BATCH_1:
CMP $1, LENGTH
BLO COLLECT
MOVBU (PDATA), LOADED
LSL $8, LOADED
ADD LOADED, RESULT, RESULT
#define EXTRACTED R3
COLLECT:
VMOV VSUM.S[0], EXTRACTED
ADD EXTRACTED, RESULT
VMOV VSUM.S[1], EXTRACTED
ADD EXTRACTED, RESULT
VMOV VSUM.S[2], EXTRACTED
ADD EXTRACTED, RESULT
VMOV VSUM.S[3], EXTRACTED
ADD EXTRACTED, RESULT
#undef VSUM
#undef PDATA
#undef LENGTH
RETURN:
MOVD RESULT, result+16(FP)
RET

View File

@ -0,0 +1,51 @@
package tcpip
import (
"crypto/rand"
"testing"
"golang.org/x/sys/cpu"
)
func Test_SumNeon(t *testing.T) {
if !cpu.ARM64.HasASIMD {
t.Skipf("Neon unavailable")
}
bytes := make([]byte, chunkSize)
for size := 0; size <= chunkSize; size++ {
for count := 0; count < chunkCount; count++ {
_, err := rand.Reader.Read(bytes[:size])
if err != nil {
t.Skipf("Rand read failed: %v", err)
}
compat := SumCompat(bytes[:size])
neon := sumNeon(bytes[:size])
if compat != neon {
t.Errorf("Sum of length=%d mismatched", size)
}
}
}
}
func Benchmark_SumNeon(b *testing.B) {
if !cpu.ARM64.HasASIMD {
b.Skipf("Neon unavailable")
}
bytes := make([]byte, chunkSize)
_, err := rand.Reader.Read(bytes)
if err != nil {
b.Skipf("Rand read failed: %v", err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
sumNeon(bytes)
}
}

View File

@ -0,0 +1,14 @@
package tcpip
func SumCompat(b []byte) (sum uint32) {
n := len(b)
if n&1 != 0 {
n--
sum += uint32(b[n]) << 8
}
for i := 0; i < n; i += 2 {
sum += (uint32(b[i]) << 8) | uint32(b[i+1])
}
return
}

View File

@ -0,0 +1,26 @@
package tcpip
import (
"crypto/rand"
"testing"
)
const (
chunkSize = 9000
chunkCount = 10
)
func Benchmark_SumCompat(b *testing.B) {
bytes := make([]byte, chunkSize)
_, err := rand.Reader.Read(bytes)
if err != nil {
b.Skipf("Rand read failed: %v", err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
SumCompat(bytes)
}
}

View File

@ -0,0 +1,55 @@
package tcpip
import (
"encoding/binary"
)
const UDPHeaderSize = 8
type UDPPacket []byte
func (p UDPPacket) Length() uint16 {
return binary.BigEndian.Uint16(p[4:])
}
func (p UDPPacket) SetLength(length uint16) {
binary.BigEndian.PutUint16(p[4:], length)
}
func (p UDPPacket) SourcePort() uint16 {
return binary.BigEndian.Uint16(p)
}
func (p UDPPacket) SetSourcePort(port uint16) {
binary.BigEndian.PutUint16(p, port)
}
func (p UDPPacket) DestinationPort() uint16 {
return binary.BigEndian.Uint16(p[2:])
}
func (p UDPPacket) SetDestinationPort(port uint16) {
binary.BigEndian.PutUint16(p[2:], port)
}
func (p UDPPacket) Payload() []byte {
return p[UDPHeaderSize:p.Length()]
}
func (p UDPPacket) Checksum() uint16 {
return binary.BigEndian.Uint16(p[6:])
}
func (p UDPPacket) SetChecksum(sum [2]byte) {
p[6] = sum[0]
p[7] = sum[1]
}
func (p UDPPacket) ResetChecksum(psum uint32) {
p.SetChecksum(zeroChecksum)
p.SetChecksum(Checksum(psum, p))
}
func (p UDPPacket) Valid() bool {
return len(p) >= UDPHeaderSize && uint16(len(p)) >= p.Length()
}

View File

@ -15,10 +15,9 @@ import (
"github.com/Dreamacro/clash/listener/tun/device"
"github.com/Dreamacro/clash/listener/tun/ipstack"
D "github.com/Dreamacro/clash/listener/tun/ipstack/commons"
"github.com/Dreamacro/clash/listener/tun/ipstack/system/mars"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/transport/socks5"
"github.com/Kr328/tun2socket"
)
type sysStack struct {
@ -42,7 +41,7 @@ func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Pref
portal := tunAddress.Addr()
gateway := portal
stack, err := tun2socket.StartTun2Socket(device, gateway, portal)
stack, err := mars.StartListener(device, gateway, portal)
if err != nil {
_ = device.Close()
@ -66,18 +65,18 @@ func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Pref
lAddr := conn.LocalAddr().(*net.TCPAddr)
rAddr := conn.RemoteAddr().(*net.TCPAddr)
addrIp, _ := netip.AddrFromSlice(rAddr.IP)
addrPort := netip.AddrPortFrom(addrIp, uint16(rAddr.Port))
rAddrIp, _ := netip.AddrFromSlice(rAddr.IP)
rAddrPort := netip.AddrPortFrom(rAddrIp, uint16(rAddr.Port))
if ipv4LoopBack.Contains(addrIp) {
if ipv4LoopBack.Contains(rAddrIp) {
conn.Close()
continue
}
if D.ShouldHijackDns(dnsAddr, addrPort) {
if D.ShouldHijackDns(dnsAddr, rAddrPort) {
go func() {
log.Debugln("[TUN] hijack dns tcp: %s", addrPort.String())
log.Debugln("[TUN] hijack dns tcp: %s", rAddrPort.String())
defer conn.Close()
@ -144,16 +143,16 @@ func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Pref
lAddr := lRAddr.(*net.UDPAddr)
rAddr := rRAddr.(*net.UDPAddr)
addrIp, _ := netip.AddrFromSlice(rAddr.IP)
addrPort := netip.AddrPortFrom(addrIp, uint16(rAddr.Port))
rAddrIp, _ := netip.AddrFromSlice(rAddr.IP)
rAddrPort := netip.AddrPortFrom(rAddrIp, uint16(rAddr.Port))
if ipv4LoopBack.Contains(addrIp) {
if ipv4LoopBack.Contains(rAddrIp) {
pool.Put(buf)
continue
}
if D.ShouldHijackDns(dnsAddr, addrPort) {
if D.ShouldHijackDns(dnsAddr, rAddrPort) {
go func() {
defer pool.Put(buf)
@ -164,7 +163,7 @@ func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Pref
_, _ = stack.UDP().WriteTo(msg, rAddr, lAddr)
log.Debugln("[TUN] hijack dns udp: %s", addrPort.String())
log.Debugln("[TUN] hijack dns udp: %s", rAddrPort.String())
}()
continue