Add stateless DNS hijack
This commit is contained in:
parent
1ba7d79118
commit
79084fa798
5 changed files with 113 additions and 6 deletions
89
flow_dns.go
Normal file
89
flow_dns.go
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
package tun
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
|
||||
"github.com/sagernet/sing-tun/gtcpip/checksum"
|
||||
"github.com/sagernet/sing-tun/gtcpip/header"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
func (d *ForwardDispatcher) hijackDNSPacket(packet *forwardPacket) {
|
||||
writer := &dnsResponseWriter{
|
||||
writeback: d.writeback,
|
||||
source: packet.source,
|
||||
}
|
||||
d.handler.NewDNSPacket(header.UDP(packet.transport).Payload(), M.SocksaddrFromNetIP(packet.source), M.SocksaddrFromNetIP(packet.destination), writer)
|
||||
}
|
||||
|
||||
var _ N.PacketWriter = (*dnsResponseWriter)(nil)
|
||||
|
||||
type dnsResponseWriter struct {
|
||||
writeback ForwardWriteback
|
||||
source netip.AddrPort
|
||||
}
|
||||
|
||||
func (w *dnsResponseWriter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
||||
defer buffer.Release()
|
||||
if !destination.IsIP() {
|
||||
return E.New("invalid destination: ", destination)
|
||||
}
|
||||
sourceAddr := w.source.Addr().Unmap()
|
||||
destinationAddr := destination.Addr.Unmap()
|
||||
headroom := w.writeback.ReturnHeadroom()
|
||||
udpLen := header.UDPMinimumSize + buffer.Len()
|
||||
var (
|
||||
packet []byte
|
||||
udpHdr header.UDP
|
||||
ipHdr header.Network
|
||||
)
|
||||
if sourceAddr.Is4() {
|
||||
if !destinationAddr.Is4() {
|
||||
return E.New("send IPv6 packet to IPv4 connection")
|
||||
}
|
||||
size := header.IPv4MinimumSize + udpLen
|
||||
packet = make([]byte, headroom+size)
|
||||
inet4Hdr := header.IPv4(packet[headroom:])
|
||||
inet4Hdr.Encode(&header.IPv4Fields{
|
||||
TotalLength: uint16(size),
|
||||
TTL: synthesizedTTL,
|
||||
Protocol: uint8(header.UDPProtocolNumber),
|
||||
SrcAddr: destinationAddr,
|
||||
DstAddr: sourceAddr,
|
||||
})
|
||||
udpHdr = header.UDP(inet4Hdr.Payload())
|
||||
ipHdr = inet4Hdr
|
||||
} else {
|
||||
if destinationAddr.Is4() {
|
||||
destinationAddr = netip.AddrFrom16(destinationAddr.As16())
|
||||
}
|
||||
size := header.IPv6MinimumSize + udpLen
|
||||
packet = make([]byte, headroom+size)
|
||||
inet6Hdr := header.IPv6(packet[headroom:])
|
||||
inet6Hdr.Encode(&header.IPv6Fields{
|
||||
PayloadLength: uint16(udpLen),
|
||||
TransportProtocol: header.UDPProtocolNumber,
|
||||
HopLimit: synthesizedTTL,
|
||||
SrcAddr: destinationAddr,
|
||||
DstAddr: sourceAddr,
|
||||
})
|
||||
udpHdr = header.UDP(inet6Hdr.Payload())
|
||||
ipHdr = inet6Hdr
|
||||
}
|
||||
udpHdr.Encode(&header.UDPFields{
|
||||
SrcPort: destination.Port,
|
||||
DstPort: w.source.Port(),
|
||||
Length: uint16(udpLen),
|
||||
})
|
||||
copy(udpHdr.Payload(), buffer.Bytes())
|
||||
udpHdr.SetChecksum(^checksum.Checksum(udpHdr.Payload(), udpHdr.CalculateChecksum(
|
||||
header.PseudoHeaderChecksum(header.UDPProtocolNumber, ipHdr.SourceAddressSlice(), ipHdr.DestinationAddressSlice(), uint16(udpLen)),
|
||||
)))
|
||||
if inet4Hdr, isInet4 := ipHdr.(header.IPv4); isInet4 {
|
||||
inet4Hdr.SetChecksum(^inet4Hdr.CalculateChecksum())
|
||||
}
|
||||
return w.writeback.WriteReturnPackets([][]byte{packet})
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue