Reputation: 8118
I want to create a DNS response to send to my browser. I've created some structs like in the rfc:
//DNS header
struct DNS_HEADER
{
unsigned short id;
unsigned char rd :1;
unsigned char tc :1;
unsigned char aa :1;
unsigned char opcode :4;
unsigned char qr :1;
unsigned char rcode :4;
unsigned char cd :1;
unsigned char ad :1;
unsigned char z :1;
unsigned char ra :1;
unsigned short q_count;
unsigned short ans_count;
unsigned short auth_count;
unsigned short add_count;
};
#pragma pack(push, 1)
struct R_DATA
{
unsigned short type;
unsigned short _class;
unsigned int ttl;
unsigned short data_len;
};
#pragma pack(pop)
struct RES_RECORD
{
unsigned char *name;
struct R_DATA *resource;
unsigned char *rdata;
};
Now I'm trying to fill in this structs so I could send a valid DNS response. I'm trying to send for example www.google.com with ipaddres 112.12.12.12 (just for fun).
This is what I have:
dns = (DNS_HEADER*)malloc(sizeof(DNS_HEADER));
dns->id = (unsigned short) htons(GetCurrentProcessId()); // ID
dns->qr = 1; // We give a response, Volgens RFC: (= query (0), or a response (1).)
dns->opcode = 0; // default
dns->aa = 0; //Not Authoritative,RFC: (= Authoritative Answer - this bit is valid in responses, and specifies that the responding name server is an authority for the domain name in question section.)
dns->tc = 0; // Not truncated
dns->rd = 1; // Enable recursion
dns->ra = 0; // Nameserver supports recursion?
dns->z = 0; // RFC: (= Reserved for future use. Must be zero in all queries and responses.)
dns->rcode = 0; // No error condition
dns->q_count = 0; // No questions!
dns->ad = 0; // How man resource records?
dns->cd = 0; // !checking
dns->ans_count = 1; // We give 1 answer
dns->auth_count = 0; // How many authority entries?
dns->add_count = 0; // How many resource entries?
But as you can see I'm have some questions about what to fill in. Also the R_Data and res_record I can't find out via the rfc what to fill in for a random response I've made...
Can someone help me with this?
Upvotes: 0
Views: 3418
Reputation: 3993
Your approach is fundamentally flawed. You cannot express a DNS packet with a struct, because the strings in a DNS packet are variable length, i.e. fields following a string will be at different offsets in the packet depending on the length of the preceding strings.
Your struct has char-pointers in place of each string, and each pointer is typically a 32-bit value that points to some other place in memory. Therefore when you try to send the struct as represented in memory, you will be sending more or less random 32-bit values in place of the strings.
Here is a fairly illustrative guide to what the DNS packets should look like: http://www.tcpipguide.com/free/t_DNSMessageProcessingandGeneralMessageFormat.htm
Upvotes: 1
Reputation: 1316
A few pointers at a glance: id
in your response needs to be the id you received in the query. q_count
should be 1 and repeat the query you received (in your example that'd be e.g. \x03www\x06google\x03com\x00\x00\x01\x00\x01
for www.google.com IN A
). What needs to go in rdata
is explained in RFC1035 Section 3.4.1 (in your example it'd be \x70\x0c\x0c\x0c
).
Upvotes: 0