Program Listing for File dns_packet_constructor.h
↰ Return to documentation for file (include/dns_packet_constructor.h
)
#pragma once
#include <dpdk_wrappers.h>
#include <network_types.h>
#include <rte_ethdev.h>
#include <rte_ether.h>
#include <rte_ip.h>
#include <rte_mbuf.h>
#include "dns_construct_helpers.h"
#include "dns_format.h"
class DNSPacketConstructor {
public:
static inline size_t ConstructIpv4DNSPacket(RTEMbuf<DefaultPacket>& pkt,
const rte_ether_addr& src_mac_addr, const rte_ether_addr& dst_mac_addr,
const uint32_t src_ipv4_addr, const uint32_t dst_ipv4_addr, uint16_t src_port,
uint16_t dns_id, const char* domain_name, const uint16_t len, DnsQType q_type);
static inline size_t ConstructIpv6DNSPacket(RTEMbuf<DefaultPacket>& pkt,
const rte_ether_addr& src_mac_addr, const rte_ether_addr& dst_mac_addr,
const in6_addr& src_ipv6_addr, const in6_addr& dst_ipv6_addr, uint16_t src_port,
uint16_t dns_id, const char* domain_name, const uint16_t len, DnsQType q_type);
static inline size_t GetMinIpv4PacketSize() {
// Add room for NULL terminator
return sizeof(rte_ether_hdr) + sizeof(rte_ipv4_hdr) + sizeof(rte_udp_hdr) +
sizeof(DnsHeader) + sizeof(QuestionInfo) + 1;
}
static inline size_t GetMinIpv6PacketSize() {
// Add room for NULL terminator
return sizeof(rte_ether_hdr) + sizeof(rte_ipv6_hdr) + sizeof(rte_udp_hdr) +
sizeof(DnsHeader) + sizeof(QuestionInfo) + 1;
}
private:
static inline char* ConstructEthHdr(char* buf, const rte_ether_addr& src_addr,
const rte_ether_addr& dst_addr, const uint16_t ether_type);
static inline char* ConstructIpv4Hdr(char* buf, const uint32_t src_addr,
const uint32_t dst_addr, uint16_t l4_len);
static inline char* ConstructIpv6Hdr(char* buf, const in6_addr& src_addr,
const in6_addr& dst_addr, uint16_t l4_len);
static inline char* ConstructUdpHdr(char* buf, const uint16_t src_port,
const uint16_t dst_port, uint16_t l5_len);
static inline char* ConstructDNSHdr(char* buf, const char* host_name, uint16_t host_len,
uint16_t id, DnsQType q_type);
};
inline size_t DNSPacketConstructor::ConstructIpv6DNSPacket(RTEMbuf<DefaultPacket>& pkt,
const rte_ether_addr& src_mac_addr, const rte_ether_addr& dst_mac_addr,
const in6_addr& src_ipv6_addr, const in6_addr& dst_ipv6_addr, uint16_t src_port,
uint16_t dns_id, const char* domain_name, const uint16_t len, DnsQType q_type) {
// Fill buffer
char* buf = &pkt.data<char>();
// First fill DNS packet to easily extract the length
char* dns_start = buf + sizeof(rte_ether_hdr) + sizeof(rte_ipv6_hdr) + sizeof(rte_udp_hdr);
char* dns_end = ConstructDNSHdr(dns_start, domain_name, len, dns_id, q_type);
int dns_len = dns_end - dns_start;
ConstructEthHdr(buf, src_mac_addr, dst_mac_addr, RTE_ETHER_TYPE_IPV6);
ConstructIpv6Hdr(buf + sizeof(rte_ether_hdr), src_ipv6_addr, dst_ipv6_addr,
dns_len + sizeof(rte_udp_hdr));
ConstructUdpHdr(buf + sizeof(rte_ether_hdr) + sizeof(rte_ipv6_hdr), src_port, 53, dns_len);
// Set packet flags
pkt.l2_len = sizeof(rte_ether_hdr);
pkt.l3_len = sizeof(rte_ipv6_hdr);
pkt.l4_len = sizeof(rte_udp_hdr);
pkt.data_len = sizeof(rte_ether_hdr) + sizeof(rte_ipv6_hdr) + sizeof(rte_udp_hdr) + dns_len;
pkt.pkt_len = sizeof(rte_ether_hdr) + sizeof(rte_ipv6_hdr) + sizeof(rte_udp_hdr) + dns_len;
pkt.nb_segs = 1;
return sizeof(rte_ether_hdr) + sizeof(rte_ipv6_hdr) + sizeof(rte_udp_hdr) + dns_len;
}
inline size_t DNSPacketConstructor::ConstructIpv4DNSPacket(RTEMbuf<DefaultPacket>& pkt,
const rte_ether_addr& src_mac_addr, const rte_ether_addr& dst_mac_addr,
const uint32_t src_ipv4_addr, const uint32_t dst_ipv4_addr, uint16_t src_port, uint16_t dns_id,
const char* domain_name, const uint16_t len, DnsQType q_type) {
// Fill buffer
char* buf = &pkt.data<char>();
// First fill DNS packet to easily extract the length
char* dns_start = buf + sizeof(rte_ether_hdr) + sizeof(rte_ipv4_hdr) + sizeof(rte_udp_hdr);
char* dns_end = ConstructDNSHdr(dns_start, domain_name, len, dns_id, q_type);
int dns_len = dns_end - dns_start;
ConstructEthHdr(buf, src_mac_addr, dst_mac_addr, RTE_ETHER_TYPE_IPV4);
ConstructIpv4Hdr(buf + sizeof(rte_ether_hdr), src_ipv4_addr, dst_ipv4_addr,
dns_len + sizeof(rte_udp_hdr));
ConstructUdpHdr(buf + sizeof(rte_ether_hdr) + sizeof(rte_ipv4_hdr), src_port, 53, dns_len);
// Set packet flags
pkt.l2_len = sizeof(rte_ether_hdr);
pkt.l3_len = sizeof(rte_ipv4_hdr);
pkt.l4_len = sizeof(rte_udp_hdr);
pkt.data_len = sizeof(rte_ether_hdr) + sizeof(rte_ipv4_hdr) + sizeof(rte_udp_hdr) + dns_len;
pkt.pkt_len = sizeof(rte_ether_hdr) + sizeof(rte_ipv4_hdr) + sizeof(rte_udp_hdr) + dns_len;
pkt.nb_segs = 1;
return sizeof(rte_ether_hdr) + sizeof(rte_ipv4_hdr) + sizeof(rte_udp_hdr) + dns_len;
}
inline char* DNSPacketConstructor::ConstructEthHdr(char* buf, const rte_ether_addr& src_addr,
const rte_ether_addr& dst_addr, const uint16_t ether_type) {
rte_ether_hdr* eth_hdr = (rte_ether_hdr*) buf;
eth_hdr->src_addr = src_addr;
eth_hdr->dst_addr = dst_addr;
eth_hdr->ether_type = rte_cpu_to_be_16(ether_type);
return (char*) (eth_hdr + 1);
}
inline char* DNSPacketConstructor::ConstructIpv4Hdr(char* buf, const uint32_t src_addr,
const uint32_t dst_addr, uint16_t l4_len) {
rte_ipv4_hdr* ipv4_hdr = (rte_ipv4_hdr*) buf;
ipv4_hdr->ihl = RTE_IPV4_MIN_IHL;
ipv4_hdr->version = IPVERSION;
ipv4_hdr->type_of_service = 0;
ipv4_hdr->fragment_offset = 0;
ipv4_hdr->time_to_live = 64;
ipv4_hdr->next_proto_id = IPPROTO_UDP;
ipv4_hdr->packet_id = 0;
ipv4_hdr->total_length = rte_cpu_to_be_16(l4_len + sizeof(rte_ipv4_hdr));
ipv4_hdr->src_addr = src_addr;
ipv4_hdr->dst_addr = dst_addr;
ipv4_hdr->hdr_checksum = 0;
return (char*) (ipv4_hdr + 1);
}
inline char* DNSPacketConstructor::ConstructIpv6Hdr(char* buf, const in6_addr& src_addr,
const in6_addr& dst_addr, uint16_t l4_len) {
rte_ipv6_hdr* ipv6_hdr = (rte_ipv6_hdr*) buf;
ipv6_hdr->hop_limits = 128;
ipv6_hdr->proto = IPPROTO_UDP;
ipv6_hdr->payload_len = rte_cpu_to_be_16(l4_len + sizeof(rte_ipv6_hdr));
ipv6_hdr->vtc_flow = rte_cpu_to_be_32(0);
memcpy(ipv6_hdr->src_addr, &src_addr, sizeof(in6_addr));
memcpy(ipv6_hdr->dst_addr, &dst_addr, sizeof(in6_addr));
return (char*) (ipv6_hdr + 1);
}
inline char* DNSPacketConstructor::ConstructUdpHdr(char* buf, const uint16_t src_port,
const uint16_t dst_port, uint16_t l5_len) {
rte_udp_hdr* udp_hdr = (rte_udp_hdr*) buf;
udp_hdr->dst_port = rte_cpu_to_be_16(dst_port);
udp_hdr->src_port = rte_cpu_to_be_16(src_port);
udp_hdr->dgram_len = rte_cpu_to_be_16(sizeof(rte_udp_hdr) + l5_len);
udp_hdr->dgram_cksum = 0;
return (char*) (udp_hdr + 1);
}
inline char* DNSPacketConstructor::ConstructDNSHdr(char* buf, const char* host_name,
uint16_t host_len, uint16_t id, DnsQType q_type) {
// Point DNS header pointer to buffer
DnsHeader* dns_hdr = (DnsHeader*) buf;
/*
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 |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
*/
dns_hdr->id = rte_cpu_to_be_16(id);
dns_hdr->qr = 0; // This is a query
dns_hdr->opcode = 0; // This is a standard query
dns_hdr->aa = 0; // Not Authoritative
dns_hdr->tc = 0; // This message is not truncated
dns_hdr->rd = 1; // Recursion Desired
dns_hdr->ra = 0; // Recursion not available
dns_hdr->z = 0;
dns_hdr->ad = 0;
dns_hdr->cd = 0;
dns_hdr->rcode = 0;
dns_hdr->q_count = rte_cpu_to_be_16(1); // we have only 1 question
dns_hdr->ans_count = 0;
dns_hdr->auth_count = 0;
dns_hdr->add_count = 0;
/*
1 1 1 1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| |
/ QNAME /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QTYPE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QCLASS |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
*/
char* qname = (char*) (dns_hdr + 1);
QuestionInfo* qinfo =
(struct QuestionInfo*) DNSHelpers::ChangetoDnsNameFormat(qname, host_name, host_len);
qinfo->qtype = rte_cpu_to_be_16((unsigned short) q_type);
qinfo->qclass = rte_cpu_to_be_16(1); // It's internet
return (char*) (qinfo + 1);
}