@@ -14,6 +14,9 @@ import (
1414 "github.com/libp2p/go-libp2p/core/network"
1515 "github.com/libp2p/go-libp2p/core/peer"
1616
17+ "encoding/binary"
18+
19+ "github.com/anywherelan/awl/awldns"
1720 "github.com/anywherelan/awl/awlevent"
1821 "github.com/anywherelan/awl/config"
1922 "github.com/anywherelan/awl/metrics"
@@ -270,6 +273,19 @@ func (t *Tunnel) HandleReadPackets(packets []*vpn.Packet) {
270273 continue
271274 }
272275
276+ // Intercept Magic DNS queries
277+ if ! packet .IsIPv6 && packet .IPProtocol == vpn .IPProtocolUDP && packet .Dst .Equal (MagicDNSIP ) {
278+ ipHeaderLen := int ((packet .Packet [0 ] & 0x0F ) * 4 )
279+ if len (packet .Packet ) >= ipHeaderLen + 8 {
280+ dstPort := binary .BigEndian .Uint16 (packet .Packet [ipHeaderLen + 2 : ipHeaderLen + 4 ])
281+ if dstPort == 53 {
282+ t .handleMagicDNSForward (packet )
283+ packets [i ] = nil
284+ continue
285+ }
286+ }
287+ }
288+
273289 // P2P broadcast/unicast lookup
274290 vpnPeer , isP2P := t .netIPToPeer [packet .Dst .String ()]
275291 if isP2P {
@@ -793,6 +809,94 @@ func isNonRoutableIP(ip net.IP) bool {
793809 return ip .IsLoopback () || ip .IsLinkLocalUnicast () || ip .IsLinkLocalMulticast () || ip .IsMulticast ()
794810}
795811
812+ // MagicDNSIP is a dummy IP used on Android to force DNS queries into the TUN interface.
813+ // When the tunnel reads a UDP packet destined to MagicDNSIP:53, it intercepts it
814+ // and proxies the query to the local awldns UDP server.
815+ var MagicDNSIP = net .ParseIP (awldns .MagicDNSIP ).To4 ()
816+
817+ func (t * Tunnel ) handleMagicDNSForward (packet * vpn.Packet ) {
818+ // Extract the original DNS query payload
819+ ipHeaderLen := int ((packet .Packet [0 ] & 0x0F ) * 4 )
820+ udpHeaderOffset := ipHeaderLen
821+ if len (packet .Packet ) <= udpHeaderOffset + 8 {
822+ t .device .PutTempPacket (packet )
823+ return
824+ }
825+ originalSrcIP := make (net.IP , len (packet .Src ))
826+ copy (originalSrcIP , packet .Src )
827+ originalSrcPort := binary .BigEndian .Uint16 (packet .Packet [udpHeaderOffset : udpHeaderOffset + 2 ])
828+ payload := packet .Packet [udpHeaderOffset + 8 :]
829+
830+ dnsPayload := make ([]byte , len (payload ))
831+ copy (dnsPayload , payload )
832+ t .device .PutTempPacket (packet )
833+
834+ dnsAddr := t .conf .DNS .ListenAddress
835+
836+ go func () {
837+ conn , err := net .Dial ("udp" , dnsAddr )
838+ if err != nil {
839+ t .logger .Warnf ("failed to dial local dns %s: %v" , dnsAddr , err )
840+ return
841+ }
842+ defer conn .Close ()
843+
844+ _ = conn .SetDeadline (time .Now ().Add (5 * time .Second ))
845+ _ , err = conn .Write (dnsPayload )
846+ if err != nil {
847+ return
848+ }
849+
850+ respBuf := make ([]byte , 1500 )
851+ n , err := conn .Read (respBuf )
852+ if err != nil || n == 0 {
853+ return
854+ }
855+ respPayload := respBuf [:n ]
856+
857+ // Craft the return IPv4 UDP packet
858+ respPacket := t .device .GetTempPacket ()
859+ totalLen := 20 + 8 + len (respPayload )
860+ if totalLen > len (respPacket .Buffer )- vpn .TunPacketOffset {
861+ t .device .PutTempPacket (respPacket )
862+ return
863+ }
864+
865+ buf := respPacket .Buffer [vpn .TunPacketOffset : vpn .TunPacketOffset + totalLen ]
866+ respPacket .Packet = buf
867+ respPacket .IsIPv6 = false
868+
869+ // IPv4 Header (20 bytes)
870+ buf [0 ] = 0x45 // Version 4, IHL 5
871+ buf [1 ] = 0x00 // TOS
872+ binary .BigEndian .PutUint16 (buf [2 :4 ], uint16 (totalLen ))
873+ binary .BigEndian .PutUint16 (buf [4 :6 ], 0 ) // ID
874+ binary .BigEndian .PutUint16 (buf [6 :8 ], 0 ) // Flags/Frag
875+ buf [8 ] = 64 // TTL
876+ buf [9 ] = vpn .IPProtocolUDP
877+ binary .BigEndian .PutUint16 (buf [10 :12 ], 0 ) // Checksum (computed later)
878+ copy (buf [12 :16 ], MagicDNSIP )
879+ copy (buf [16 :20 ], originalSrcIP .To4 ())
880+
881+ // Calculate IP Checksum
882+ ipChecksum := vpn .ChecksumIPv4Header (buf [:20 ])
883+ binary .BigEndian .PutUint16 (buf [10 :12 ], ipChecksum )
884+
885+ // UDP Header (8 bytes)
886+ binary .BigEndian .PutUint16 (buf [20 :22 ], 53 )
887+ binary .BigEndian .PutUint16 (buf [22 :24 ], originalSrcPort )
888+ binary .BigEndian .PutUint16 (buf [24 :26 ], uint16 (8 + len (respPayload )))
889+ binary .BigEndian .PutUint16 (buf [26 :28 ], 0 ) // Optional for IPv4 UDP
890+
891+ // Payload
892+ copy (buf [28 :], respPayload )
893+
894+ // Write back to TUN
895+ _ = t .device .WriteBufs ([][]byte {respPacket .Buf ()})
896+ t .device .PutTempPacket (respPacket )
897+ }()
898+ }
899+
796900func readBatchFromChan (ch chan * vpn.Packet , buf []* vpn.Packet , offset int ) []* vpn.Packet {
797901 i := offset
798902 for {
0 commit comments