-
Read DNS using sockets
Dear all
I hope you are fine. i have a question regarding socket programming, sorry but i am new in this area.
I am making a program with libpcap filtering the DNS traffic from a client or from my PC. I successfully made the program using C language and libpcap API. But i want to go further and read the kind of Resource Record or data that is being interchanged between the user and the DNS server, in other words the request.
I understand that DNS use UDP as to perform the communications. But I can not find how to read the payload where i can find the Resource Records (RR) (Like A RR, MX RR, etc ).
Could anybody give me an idea how to read that data or which is the correct procedure to read the payload of the filtered traffic, according to the RFC 1035 is a comparison between pre-defined values.
I hope you could help me.
Thank you very much.
ArturoD
-
What exactly are you having trouble with? The RFC you mentioned, RFC 1035, details the DNS protocol, and sounds like it is what you want.
-
i believe you are looking for
Code:
/* Walk through the linked list of DNS records... */
for (pRecord = pRecordList; pRecord != NULL; pRecord = pRecord->pNext)
you get output like
Code:
Enter Hostname to Lookup : http://cboard.cprogramming.com
Sending Packet...Sent
Receiving answer...Received.
The response contains :
1 Questions.
2 Answers.
0 Authoritative Servers.
0 Additional records.
Name : http://cboard.cprogramming.com has IPv4 address : 207.69.131.20
Name : http://cboard.cprogramming.com has IPv4 address : 207.69.131.21
C:\>
as example.
-
Hello Kryptkat and Cactus Hugger
Thank you very much for your answers.
About Cactus Hugger question, yes you are right the RFC is quite detailed about the fields of the DNS packet. My problem is the implementation of a sniffer that can get the information contained there.
About Kryptkat answer. Well, what i know is as i mentioned before, a program that could allowed me to sniff in the packets that are being transmitted using the UDP port 53 (DNS), for that reason I am using libpcap as a filter of such packets.
also i am using libdnet in order to get the UDP header lenght (UDP_HDR_LEN), I already made ap rogram but i have still the problem of sniff the details of the packet.
What i want to read basically is the type Resource Record that was use in that packet, for instance: A Record, PTR Record, NS record or MX record.
Of course the class IN.
That's the information I want to gather from the packet filtering.
I send you the code I have made so far.
Code:
#include </usr/include/pcap.h>
#include </usr/include/stdio.h>
#include </usr/include/time.h>
#include </usr/include/stdlib.h>
#include </usr/include/errno.h>
#define _USE_BSD
#define __FAVOR_BSD
#include </usr/include/memory.h>
#include </usr/include/netinet/ip.h>
#include </usr/include/netinet/tcp.h>
#include </usr/include/linux/udp.h>
#include </usr/include/dnet.h>
/* Offsets of fields in the DNS header. */
#define DNS_ID 0
#define DNS_FLAGS 2
#define DNS_QUEST 4
#define DNS_ANS 6
#define DNS_AUTH 8
#define DNS_ADD 10
/* Length of DNS header. */
#define DNS_HDRLEN 12
//Type field of Query and Answer
#define T_A 1 /* host address */
#define T_NS 2 /* authoritative server */
#define T_CNAME 5 /* canonical name */
#define T_SOA 6 /* start of authority zone */
#define T_PTR 12 /* domain name pointer */
#define T_MX 15 /* mail routing information */
/* I have to define the DNS header because I don't where the hell is!!!! */
//DNS header structure
struct DNS_HEADER
{
unsigned short id; // identification number
unsigned char rd :1; // recursion desired
unsigned char tc :1; // truncated message
unsigned char aa :1; // authoritive answer
unsigned char opcode :4; // purpose of message
unsigned char qr :1; // query/response flag
unsigned char rcode :4; // response code
unsigned char cd :1; // checking disabled
unsigned char ad :1; // authenticated data
unsigned char z :1; // its z! reserved
unsigned char ra :1; // recursion available
unsigned short q_count; // number of question entries
unsigned short ans_count; // number of answer entries
unsigned short auth_count; // number of authority entries
unsigned short add_count; // number of resource entries
};
//Constant sized fields of query structure
struct QUESTION
{
unsigned short qtype;
unsigned short qclass;
};
//Constant sized fields of the resource record structure
struct R_DATA
{
unsigned short type;
unsigned short _class;
unsigned int ttl;
unsigned short data_len;
};
//Pointers to resource record contents
struct RES_RECORD
{
unsigned char *name;
struct R_DATA *resource;
unsigned char *rdata;
};
//Structure of a Query
typedef struct
{
unsigned char *name;
struct QUESTION *ques;
} QUERY;
//Callback function, it will be called everytime a package is received
void my_callback(u_char *useless,const struct pcap_pkthdr* pkthdr,const u_char* packet)
{
struct ether_header *eptr;
struct tcphdr *tcphdr;
struct udphdr *udphdr;
struct DNS_HEADER *DNS_HEADER=&DNS_HEADER;
struct QUESTION *QUESTION=&QUESTION;
struct res_sym *res_sym;
char TYPE;
struct dns *dns;
unsigned offset = 0;
time_t t;
struct tm *tstruct;
t=time(NULL);
tstruct=localtime(&t);
char timer [80];
strftime (timer,80,"%a %b %d %Y %T",tstruct);
/* Buffer needed to store the DNS packet */
struct RES_RECORD answers,auth,addit;
struct QUERY name, ques;
/* The pointer will point to the Ethernet header at the beggining of the packet */
eptr = (struct ether_header *) packet;
/* We extract the IP header, therefore we have to move the processed Ethernet header
in order to find the information we want */
struct ip *ipc;
offset += ETH_HDR_LEN;
ipc = (struct ip *)(packet + offset);
/* We check the TCP protocol, the value of "Protocol" in the IP frame is checked according to the
8 bit value */
switch (ipc->ip_p)
{
case 1:
printf ("ICMP\n");
return; //ICMP protocol
case 6:
printf ("TCP\n");
return; //TCP protocol
case 17:
printf ("UDP\n");
break; //UDP Protocol
default:
printf ("Unknown\n");
return; //Unknown protocol
}
//lenght of the ip header to be added to the ethernet header
offset += (ipc->ip_hl)*4;
udphdr = (struct udphdr *)(packet + offset);
offset += UDP_HDR_LEN;
/* pointing to the DNS */
dns = (struct DNS_HEADER *)(packet + offset);
offset += DNS_HDRLEN;
/*Printing QR Code*/
switch (DNS_HEADER->qr)
{
case 0:
printf("QR Code is Query\t");
break;
case 1:
printf("QR Code is Answer\t");
break;
}
//printf("%s%18s\t%d\t%18s\t%d\t%s\n",timer,inet_ntoa(ipc->ip_src),ntohs(udphdr->source),inet_ntoa(ipc->ip_dst),ntohs(udphdr->dest));
So far I was able to get the Query code. In the filtering I've made in my PC is always Query code, but according to the DNS structure, I have to skip the "name" area in order to get the type and class information.
Could it be possible for you guys to give me clue about how to do it?, I've been going around this specific topic for few days.
Thank you very much.
Regards,
ArturoD
-
it has been a while since i used libpcap and do not recall if it has its own defines like the winapi .... try windns.h
Code:
/* fixdns.c */
#include <windns.h>
/* or equivalent pcapdns.h */
/* set your path in .cfg or ide */
#include <pcap.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <errno.h>
#include <memory.h>
#include <ip.h>
#include <tcp.h>
#include <udp.h>
#include <dnet.h>
#define _USE_BSD
#define __FAVOR_BSD
//Callback function, it will be called everytime a package is received
void my_callback(u_char *useless,const struct pcap_pkthdr* pkthdr,const u_char* packet)
{
struct ether_header *eptr;
struct tcphdr *tcphdr;
struct udphdr *udphdr;
struct DNS_HEADER *DNS_HEADER=&DNS_HEADER;
struct QUESTION *QUESTION=&QUESTION;
struct res_sym *res_sym;
char TYPE;
struct dns *dns;
unsigned offset = 0;
time_t t;
struct tm *tstruct;
t=time(NULL);
tstruct=localtime(&t);
char timer [80];
strftime (timer,80,"%a %b %d %Y %T",tstruct);
/* Buffer needed to store the DNS packet */
struct RES_RECORD answers,auth,addit;
struct QUERY name, ques;
/* The pointer will point to the Ethernet header at the beggining of the packet */
eptr = (struct ether_header *) packet;
/* We extract the IP header, therefore we have to move the processed Ethernet header
in order to find the information we want */
struct ip *ipc;
offset += ETH_HDR_LEN;
ipc = (struct ip *)(packet + offset);
/* We check the TCP protocol, the value of "Protocol" in the IP frame is checked according to the
8 bit value */
switch (ipc->ip_p)
{
case 1:
printf ("ICMP\n");
return; //ICMP protocol
case 6:
printf ("TCP\n");
return; //TCP protocol
case 17:
printf ("UDP\n");
break; //UDP Protocol
default:
printf ("Unknown\n");
return; //Unknown protocol
}
//lenght of the ip header to be added to the ethernet header
offset += (ipc->ip_hl)*4;
udphdr = (struct udphdr *)(packet + offset);
offset += UDP_HDR_LEN;
/* pointing to the DNS */
dns = (struct DNS_HEADER *)(packet + offset);
offset += DNS_HDRLEN;
/*Printing QR Code*/
switch (DNS_HEADER->qr)
{
case 0:
printf("QR Code is Query\t");
break;
case 1:
printf("QR Code is Answer\t");
break;
}
printf("%s%18s\t%d\t%18s\t%d\t%s\n",timer,inet_ntoa(ipc->ip_src),ntohs(udphdr->source),inet_ntoa(ipc->ip_dst),ntohs(udphdr->dest));
also note that i do not have libpcap do to hd crash. oh wait yes i do....
Code:
#ifndef _COMMON_H
#define _COMMON_H
#define FORMAT_CAP 1
#define FORMAT_IVS 2
#define FORMAT_IVS2 3
#define TCPDUMP_MAGIC 0xA1B2C3D4
#define TCPDUMP_CIGAM 0xD4C3B2A1
#define IVSONLY_MAGIC "\xBF\xCA\x84\xD4"
#define IVS2_MAGIC "\xAE\x78\xD1\xFF"
#define IVS2_EXTENSION "ivs"
#define IVS2_VERSION 1
#define PCAP_VERSION_MAJOR 2
#define PCAP_VERSION_MINOR 4
#define LINKTYPE_ETHERNET 1
#define LINKTYPE_IEEE802_11 105
#define LINKTYPE_PRISM_HEADER 119
#define LINKTYPE_RADIOTAP_HDR 127
#define uchar unsigned char
#define ushort unsigned short
#define uint unsigned int
#define ulong unsigned long
#define SWAP32(x) \
x = ( ( ( x >> 24 ) & 0x000000FF ) | \
( ( x >> 8 ) & 0x0000FF00 ) | \
( ( x << 8 ) & 0x00FF0000 ) | \
( ( x << 24 ) & 0xFF000000 ) );
//BSSID const. length of 6 bytes; can be together with all the other types
#define IVS2_BSSID 0x0001
//ESSID var. length; alone, or with BSSID
#define IVS2_ESSID 0x0002
//wpa structure, const. length; alone, or with BSSID
#define IVS2_WPA 0x0004
//IV+IDX+KEYSTREAM, var. length; alone or with BSSID
#define IVS2_XOR 0x0008
/* [IV+IDX][i][l][XOR_1]..[XOR_i][weight] *
* holds i possible keystreams for the same IV with a length of l for each keystream (l max 32) *
* and an array "int weight[16]" at the end */
#define IVS2_PTW 0x0010
//unencrypted packet
#define IVS2_CLR 0x0020
struct pcap_file_header
{
uint magic;
ushort version_major;
ushort version_minor;
int thiszone;
uint sigfigs;
uint snaplen;
uint linktype;
};
struct pcap_pkthdr
{
int tv_sec;
int tv_usec;
uint caplen;
uint len;
};
struct ivs2_filehdr
{
unsigned short version;
};
struct ivs2_pkthdr
{
unsigned short flags;
unsigned short len;
};
#endif /* common.h */
have a look.... you need to go through it an make sure everything matches up.