How to use DPDK to implement DNS Spoofing

Similar to How to use DPDK to implement ICMP Spoofing, we can build DNS packets to achieve DNS Spoofing. In this scenario, DPDK need get the domain name from DNS query and send the response.

Ethernet, IP and UDP header build remains the same because DPDK provides the struct. So I will focus on DNS part.

DNS Packet Format


Firstly, let's go through a DNS standard query:

The first field after the UDP header is transaction ID. For a pair of query and response, they have same transaction ID.
Flags means this is a standard query.
Questions means there is only one query.
Answers RRs and Authority RRs and Additional RRs should be zero for a query.
In Queries section, we can see the detailed information includes domain name, query type and class.
A domain name represented as a sequence of labels, where each label consists of a length octet followed by that number of octets. The domain name terminates with the zero length octet for the null label of the root. Note that this field may be an odd number of octets; no padding is used.
i.e. -> 03 77 77 77 05 62 61 69 64 75 03 63 6f 6d 00


Then look through standard query response:

The difference between query and response is response has Answer RR apart from Questions.
The answer, authority, and additional sections all share the same format: a variable number of resource records.
Resource record has name, type, TTL and target value.
Please note: In order to reduce the size of messages, the domain system utilizes a compression scheme which eliminates the repetition of domain names in a message. In this scheme, an entire domain name or a list of labels at the end of a domain name is replaced with a pointer to a prior occurance of the same name.RFC 1035

Code Logic

After DPDK receives the DNS query, we need get the domain name from the query packet.

transaction_id = ntohs(*((unsigned short*)pp));
printf("Transaction_id: %d\n",transaction_id);
pp += 4; /* Move to Question in DNS Query */
int question = ntohs(*((unsigned short*)pp));
printf("Question: %d\n",question);
pp += 8; /* Move to Query in DNS Query */
bzero(domain , sizeof(domain));
for (;;){
    unsigned short t = (int)pp[0];
    pp ++;

    if (t == 0)
    rte_memcpy(dns , pp , t);
    dns += t;
    pp += t;
    if((int)pp[0] != 0)
        rte_memcpy(dns , "." , 1);
    dns ++;
printf("Domain: %s, length is %ld\n",domain, strlen((char *)domain)+2);

Then we need calculate the size of response packet and allocate mbuf.
To calculate the size, we need know the domain name and the target value.

For example, ->
Answer: +
Length of the first "" is 13 Bytes.(11+2) First Byte = label count. Last Byte = 00;
Other "" is 2 Bytes :pointer that point to the first  -> 4 Bytes

Length of each field

Transaction_id 2
Flags 2
Questions summary 2
Answer summary 2
Authority RR 2
Additional RR 2
Query: Name(domain_len)+ type 2 + class 2
Answer: Name(pointer(2)) +Type 2 + class 2 + TTL 4 + Data length 2 + Value(4 for IP address)

Total lenth = 34+ domain name length

Then allocate mbuf and build the packet layer by layer.
Don't remember to convert the byte order. TTL is 4 Bytes field so that we should use htonl() instead of htons().

You can review the code at

At last, run DPDK application and run dig command on client.

[ec2-user@ip-172-31-27-54 ~]$ dig @

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.amzn2.5 <<>> @
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 47471
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;                   IN      A

;; ANSWER SECTION:            600     IN      A

;; Query time: 0 msec
;; WHEN: Fri Apr 15 07:20:58 UTC 2022
;; MSG SIZE  rcvd: 45


  • OωO
  • |´・ω・)ノ
  • ヾ(≧∇≦*)ゝ
  • (☆ω☆)
  • (╯‵□′)╯︵┴─┴
  •  ̄﹃ ̄
  • (/ω\)
  • ∠(ᐛ」∠)_
  • (๑•̀ㅁ•́ฅ)
  • →_→
  • ୧(๑•̀⌄•́๑)૭
  • ٩(ˊᗜˋ*)و
  • (ノ°ο°)ノ
  • (´இ皿இ`)
  • ⌇●﹏●⌇
  • (ฅ´ω`ฅ)
  • (╯°A°)╯︵○○○
  • φ( ̄∇ ̄o)
  • (งᵒ̌皿ᵒ̌)ง⁼³₌₃
  • (ó﹏ò。)
  • Σ(っ°Д°;)っ
  • ╮(╯▽╰)╭
  • o(*
  • >﹏<
  • (。•ˇ‸ˇ•。)
  • 泡泡
  • 颜文字