Add stateless DNS hijack
This commit is contained in:
parent
1ba7d79118
commit
79084fa798
5 changed files with 113 additions and 6 deletions
1
flow.go
1
flow.go
|
|
@ -21,6 +21,7 @@ const (
|
|||
ActionReject
|
||||
ActionDrop
|
||||
ActionBypass
|
||||
ActionHijackDNS
|
||||
)
|
||||
|
||||
type FlowTracker interface {
|
||||
|
|
|
|||
|
|
@ -291,6 +291,13 @@ func (d *ForwardDispatcher) judgeAndInstall(key flowKey, packet *forwardPacket,
|
|||
case ActionDrop:
|
||||
d.installSimple(key, ActionDrop, packet.protocol, now)
|
||||
return true
|
||||
case ActionHijackDNS:
|
||||
if packet.protocol == uint8(header.UDPProtocolNumber) {
|
||||
d.hijackDNSPacket(packet)
|
||||
return true
|
||||
}
|
||||
d.installSimple(key, ActionAccept, packet.protocol, now)
|
||||
return false
|
||||
default:
|
||||
d.installSimple(key, ActionAccept, packet.protocol, now)
|
||||
return false
|
||||
|
|
|
|||
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})
|
||||
}
|
||||
|
|
@ -71,18 +71,26 @@ func (f *UDPForwarder) PreparePacketConnection(source M.Socksaddr, destination M
|
|||
firstPacket = append(firstPacket[:len(firstPacket):len(firstPacket)], view.AsSlice()...)
|
||||
}
|
||||
})
|
||||
var sourceNetwork tcpip.NetworkProtocolNumber
|
||||
if source.Addr.Is4() {
|
||||
sourceNetwork = header.IPv4ProtocolNumber
|
||||
} else {
|
||||
sourceNetwork = header.IPv6ProtocolNumber
|
||||
}
|
||||
switch f.handler.JudgeFlow(uint8(header.UDPProtocolNumber), source.AddrPort(), destination.AddrPort(), firstPacket).Action {
|
||||
case ActionReject:
|
||||
gWriteUnreachable(f.stack, userData.(*stack.PacketBuffer))
|
||||
return false, nil, nil, nil
|
||||
case ActionDrop:
|
||||
return false, nil, nil, nil
|
||||
}
|
||||
var sourceNetwork tcpip.NetworkProtocolNumber
|
||||
if source.Addr.Is4() {
|
||||
sourceNetwork = header.IPv4ProtocolNumber
|
||||
} else {
|
||||
sourceNetwork = header.IPv6ProtocolNumber
|
||||
case ActionHijackDNS:
|
||||
f.handler.NewDNSPacket(firstPacket, source, destination, &UDPBackWriter{
|
||||
stack: f.stack,
|
||||
source: AddressFromAddr(source.Addr),
|
||||
sourcePort: source.Port,
|
||||
sourceNetwork: sourceNetwork,
|
||||
})
|
||||
return false, nil, nil, nil
|
||||
}
|
||||
writer := &UDPBackWriter{
|
||||
stack: f.stack,
|
||||
|
|
|
|||
2
tun.go
2
tun.go
|
|
@ -14,12 +14,14 @@ import (
|
|||
E "github.com/sagernet/sing/common/exceptions"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/ranges"
|
||||
)
|
||||
|
||||
type Handler interface {
|
||||
JudgeFlow(network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) FlowVerdict
|
||||
NewDNSPacket(payload []byte, source M.Socksaddr, destination M.Socksaddr, writer N.PacketWriter)
|
||||
N.TCPConnectionHandlerEx
|
||||
N.UDPConnectionHandlerEx
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue