Aluf

DNS Query Code in C with linux sockets

Jan 25th, 2015
327
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.61 KB | None | 0 0
  1.  
  2. DNS Query Code in C with linux sockets
  3. --------------------------------------
  4.  
  5. //DNS Query Program on Linux
  6. //Author : Silver Moon ([email protected])
  7. //Dated : 29/4/2009
  8.  
  9. //Header Files
  10. #include<stdio.h> //printf
  11. #include<string.h> //strlen
  12. #include<stdlib.h> //malloc
  13. #include<sys/socket.h> //you know what this is for
  14. #include<arpa/inet.h> //inet_addr , inet_ntoa , ntohs etc
  15. #include<netinet/in.h>
  16. #include<unistd.h> //getpid
  17.  
  18. //List of DNS Servers registered on the system
  19. char dns_servers[10][100];
  20. int dns_server_count = 0;
  21. //Types of DNS resource records :)
  22.  
  23. #define T_A 1 //Ipv4 address
  24. #define T_NS 2 //Nameserver
  25. #define T_CNAME 5 // canonical name
  26. #define T_SOA 6 /* start of authority zone */
  27. #define T_PTR 12 /* domain name pointer */
  28. #define T_MX 15 //Mail server
  29.  
  30. //Function Prototypes
  31. void ngethostbyname (unsigned char* , int);
  32. void ChangetoDnsNameFormat (unsigned char*,unsigned char*);
  33. unsigned char* ReadName (unsigned char*,unsigned char*,int*);
  34. void get_dns_servers();
  35.  
  36. //DNS header structure
  37. struct DNS_HEADER
  38. {
  39. unsigned short id; // identification number
  40.  
  41. unsigned char rd :1; // recursion desired
  42. unsigned char tc :1; // truncated message
  43. unsigned char aa :1; // authoritive answer
  44. unsigned char opcode :4; // purpose of message
  45. unsigned char qr :1; // query/response flag
  46.  
  47. unsigned char rcode :4; // response code
  48. unsigned char cd :1; // checking disabled
  49. unsigned char ad :1; // authenticated data
  50. unsigned char z :1; // its z! reserved
  51. unsigned char ra :1; // recursion available
  52.  
  53. unsigned short q_count; // number of question entries
  54. unsigned short ans_count; // number of answer entries
  55. unsigned short auth_count; // number of authority entries
  56. unsigned short add_count; // number of resource entries
  57. };
  58.  
  59. //Constant sized fields of query structure
  60. struct QUESTION
  61. {
  62. unsigned short qtype;
  63. unsigned short qclass;
  64. };
  65.  
  66. //Constant sized fields of the resource record structure
  67. #pragma pack(push, 1)
  68. struct R_DATA
  69. {
  70. unsigned short type;
  71. unsigned short _class;
  72. unsigned int ttl;
  73. unsigned short data_len;
  74. };
  75. #pragma pack(pop)
  76.  
  77. //Pointers to resource record contents
  78. struct RES_RECORD
  79. {
  80. unsigned char *name;
  81. struct R_DATA *resource;
  82. unsigned char *rdata;
  83. };
  84.  
  85. //Structure of a Query
  86. typedef struct
  87. {
  88. unsigned char *name;
  89. struct QUESTION *ques;
  90. } QUERY;
  91.  
  92. int main( int argc , char *argv[])
  93. {
  94. unsigned char hostname[100];
  95.  
  96. //Get the DNS servers from the resolv.conf file
  97. get_dns_servers();
  98.  
  99. //Get the hostname from the terminal
  100. printf("Enter Hostname to Lookup : ");
  101. scanf("%s" , hostname);
  102.  
  103. //Now get the ip of this hostname , A record
  104. ngethostbyname(hostname , T_A);
  105.  
  106. return 0;
  107. }
  108.  
  109. /*
  110. * Perform a DNS query by sending a packet
  111. * */
  112. void ngethostbyname(unsigned char *host , int query_type)
  113. {
  114. unsigned char buf[65536],*qname,*reader;
  115. int i , j , stop , s;
  116.  
  117. struct sockaddr_in a;
  118.  
  119. struct RES_RECORD answers[20],auth[20],addit[20]; //the replies from the DNS server
  120. struct sockaddr_in dest;
  121.  
  122. struct DNS_HEADER *dns = NULL;
  123. struct QUESTION *qinfo = NULL;
  124.  
  125. printf("Resolving %s" , host);
  126.  
  127. s = socket(AF_INET , SOCK_DGRAM , IPPROTO_UDP); //UDP packet for DNS queries
  128.  
  129. dest.sin_family = AF_INET;
  130. dest.sin_port = htons(53);
  131. dest.sin_addr.s_addr = inet_addr(dns_servers[0]); //dns servers
  132.  
  133. //Set the DNS structure to standard queries
  134. dns = (struct DNS_HEADER *)&buf;
  135.  
  136. dns->id = (unsigned short) htons(getpid());
  137. dns->qr = 0; //This is a query
  138. dns->opcode = 0; //This is a standard query
  139. dns->aa = 0; //Not Authoritative
  140. dns->tc = 0; //This message is not truncated
  141. dns->rd = 1; //Recursion Desired
  142. dns->ra = 0; //Recursion not available! hey we dont have it (lol)
  143. dns->z = 0;
  144. dns->ad = 0;
  145. dns->cd = 0;
  146. dns->rcode = 0;
  147. dns->q_count = htons(1); //we have only 1 question
  148. dns->ans_count = 0;
  149. dns->auth_count = 0;
  150. dns->add_count = 0;
  151.  
  152. //point to the query portion
  153. qname =(unsigned char*)&buf[sizeof(struct DNS_HEADER)];
  154.  
  155. ChangetoDnsNameFormat(qname , host);
  156. qinfo =(struct QUESTION*)&buf[sizeof(struct DNS_HEADER) + (strlen((const char*)qname) + 1)]; //fill it
  157.  
  158. qinfo->qtype = htons( query_type ); //type of the query , A , MX , CNAME , NS etc
  159. qinfo->qclass = htons(1); //its internet (lol)
  160.  
  161. printf("\nSending Packet...");
  162. if( sendto(s,(char*)buf,sizeof(struct DNS_HEADER) + (strlen((const char*)qname)+1) + sizeof(struct QUESTION),0,(struct sockaddr*)&dest,sizeof(dest)) < 0)
  163. {
  164. perror("sendto failed");
  165. }
  166. printf("Done");
  167.  
  168. //Receive the answer
  169. i = sizeof dest;
  170. printf("\nReceiving answer...");
  171. if(recvfrom (s,(char*)buf , 65536 , 0 , (struct sockaddr*)&dest , (socklen_t*)&i ) < 0)
  172. {
  173. perror("recvfrom failed");
  174. }
  175. printf("Done");
  176.  
  177. dns = (struct DNS_HEADER*) buf;
  178.  
  179. //move ahead of the dns header and the query field
  180. reader = &buf[sizeof(struct DNS_HEADER) + (strlen((const char*)qname)+1) + sizeof(struct QUESTION)];
  181.  
  182. printf("\nThe response contains : ");
  183. printf("\n %d Questions.",ntohs(dns->q_count));
  184. printf("\n %d Answers.",ntohs(dns->ans_count));
  185. printf("\n %d Authoritative Servers.",ntohs(dns->auth_count));
  186. printf("\n %d Additional records.\n\n",ntohs(dns->add_count));
  187.  
  188. //Start reading answers
  189. stop=0;
  190.  
  191. for(i=0;i<ntohs(dns->ans_count);i++)
  192. {
  193. answers[i].name=ReadName(reader,buf,&stop);
  194. reader = reader + stop;
  195.  
  196. answers[i].resource = (struct R_DATA*)(reader);
  197. reader = reader + sizeof(struct R_DATA);
  198.  
  199. if(ntohs(answers[i].resource->type) == 1) //if its an ipv4 address
  200. {
  201. answers[i].rdata = (unsigned char*)malloc(ntohs(answers[i].resource->data_len));
  202.  
  203. for(j=0 ; j<ntohs(answers[i].resource->data_len) ; j++)
  204. {
  205. answers[i].rdata[j]=reader[j];
  206. }
  207.  
  208. answers[i].rdata[ntohs(answers[i].resource->data_len)] = '\0';
  209.  
  210. reader = reader + ntohs(answers[i].resource->data_len);
  211. }
  212. else
  213. {
  214. answers[i].rdata = ReadName(reader,buf,&stop);
  215. reader = reader + stop;
  216. }
  217. }
  218.  
  219. //read authorities
  220. for(i=0;i<ntohs(dns->auth_count);i++)
  221. {
  222. auth[i].name=ReadName(reader,buf,&stop);
  223. reader+=stop;
  224.  
  225. auth[i].resource=(struct R_DATA*)(reader);
  226. reader+=sizeof(struct R_DATA);
  227.  
  228. auth[i].rdata=ReadName(reader,buf,&stop);
  229. reader+=stop;
  230. }
  231.  
  232. //read additional
  233. for(i=0;i<ntohs(dns->add_count);i++)
  234. {
  235. addit[i].name=ReadName(reader,buf,&stop);
  236. reader+=stop;
  237.  
  238. addit[i].resource=(struct R_DATA*)(reader);
  239. reader+=sizeof(struct R_DATA);
  240.  
  241. if(ntohs(addit[i].resource->type)==1)
  242. {
  243. addit[i].rdata = (unsigned char*)malloc(ntohs(addit[i].resource->data_len));
  244. for(j=0;j<ntohs(addit[i].resource->data_len);j++)
  245. addit[i].rdata[j]=reader[j];
  246.  
  247. addit[i].rdata[ntohs(addit[i].resource->data_len)]='\0';
  248. reader+=ntohs(addit[i].resource->data_len);
  249. }
  250. else
  251. {
  252. addit[i].rdata=ReadName(reader,buf,&stop);
  253. reader+=stop;
  254. }
  255. }
  256.  
  257. //print answers
  258. printf("\nAnswer Records : %d \n" , ntohs(dns->ans_count) );
  259. for(i=0 ; i < ntohs(dns->ans_count) ; i++)
  260. {
  261. printf("Name : %s ",answers[i].name);
  262.  
  263. if( ntohs(answers[i].resource->type) == T_A) //IPv4 address
  264. {
  265. long *p;
  266. p=(long*)answers[i].rdata;
  267. a.sin_addr.s_addr=(*p); //working without ntohl
  268. printf("has IPv4 address : %s",inet_ntoa(a.sin_addr));
  269. }
  270.  
  271. if(ntohs(answers[i].resource->type)==5)
  272. {
  273. //Canonical name for an alias
  274. printf("has alias name : %s",answers[i].rdata);
  275. }
  276.  
  277. printf("\n");
  278. }
  279.  
  280. //print authorities
  281. printf("\nAuthoritive Records : %d \n" , ntohs(dns->auth_count) );
  282. for( i=0 ; i < ntohs(dns->auth_count) ; i++)
  283. {
  284.  
  285. printf("Name : %s ",auth[i].name);
  286. if(ntohs(auth[i].resource->type)==2)
  287. {
  288. printf("has nameserver : %s",auth[i].rdata);
  289. }
  290. printf("\n");
  291. }
  292.  
  293. //print additional resource records
  294. printf("\nAdditional Records : %d \n" , ntohs(dns->add_count) );
  295. for(i=0; i < ntohs(dns->add_count) ; i++)
  296. {
  297. printf("Name : %s ",addit[i].name);
  298. if(ntohs(addit[i].resource->type)==1)
  299. {
  300. long *p;
  301. p=(long*)addit[i].rdata;
  302. a.sin_addr.s_addr=(*p);
  303. printf("has IPv4 address : %s",inet_ntoa(a.sin_addr));
  304. }
  305. printf("\n");
  306. }
  307. return;
  308. }
  309.  
  310. /*
  311. *
  312. * */
  313. u_char* ReadName(unsigned char* reader,unsigned char* buffer,int* count)
  314. {
  315. unsigned char *name;
  316. unsigned int p=0,jumped=0,offset;
  317. int i , j;
  318.  
  319. *count = 1;
  320. name = (unsigned char*)malloc(256);
  321.  
  322. name[0]='\0';
  323.  
  324. //read the names in 3www6google3com format
  325. while(*reader!=0)
  326. {
  327. if(*reader>=192)
  328. {
  329. offset = (*reader)*256 + *(reader+1) - 49152; //49152 = 11000000 00000000 ;)
  330. reader = buffer + offset - 1;
  331. jumped = 1; //we have jumped to another location so counting wont go up!
  332. }
  333. else
  334. {
  335. name[p++]=*reader;
  336. }
  337.  
  338. reader = reader+1;
  339.  
  340. if(jumped==0)
  341. {
  342. *count = *count + 1; //if we havent jumped to another location then we can count up
  343. }
  344. }
  345.  
  346. name[p]='\0'; //string complete
  347. if(jumped==1)
  348. {
  349. *count = *count + 1; //number of steps we actually moved forward in the packet
  350. }
  351.  
  352. //now convert 3www6google3com0 to www.google.com
  353. for(i=0;i<(int)strlen((const char*)name);i++)
  354. {
  355. p=name[i];
  356. for(j=0;j<(int)p;j++)
  357. {
  358. name[i]=name[i+1];
  359. i=i+1;
  360. }
  361. name[i]='.';
  362. }
  363. name[i-1]='\0'; //remove the last dot
  364. return name;
  365. }
  366.  
  367. /*
  368. * Get the DNS servers from /etc/resolv.conf file on Linux
  369. * */
  370. void get_dns_servers()
  371. {
  372. FILE *fp;
  373. char line[200] , *p;
  374. if((fp = fopen("/etc/resolv.conf" , "r")) == NULL)
  375. {
  376. printf("Failed opening /etc/resolv.conf file \n");
  377. }
  378.  
  379. while(fgets(line , 200 , fp))
  380. {
  381. if(line[0] == '#')
  382. {
  383. continue;
  384. }
  385. if(strncmp(line , "nameserver" , 10) == 0)
  386. {
  387. p = strtok(line , " ");
  388. p = strtok(NULL , " ");
  389.  
  390. //p now is the dns ip :)
  391. //????
  392. }
  393. }
  394.  
  395. strcpy(dns_servers[0] , "208.67.222.222");
  396. strcpy(dns_servers[1] , "208.67.220.220");
  397. }
  398.  
  399. /*
  400. * This will convert www.google.com to 3www6google3com
  401. * got it :)
  402. * */
  403. void ChangetoDnsNameFormat(unsigned char* dns,unsigned char* host)
  404. {
  405. int lock = 0 , i;
  406. strcat((char*)host,".");
  407.  
  408. for(i = 0 ; i < strlen((char*)host) ; i++)
  409. {
  410. if(host[i]=='.')
  411. {
  412. *dns++ = i-lock;
  413. for(;lock<i;lock++)
  414. {
  415. *dns++=host[lock];
  416. }
  417. lock++; //or lock=i+1;
  418. }
  419. }
  420. *dns++='\0';
  421. }
  422. Compile
  423.  
  424. $ gcc dns.c
  425. Output
  426.  
  427. $ ./a.out
  428. Enter Hostname to Lookup : www.google.com
  429. Resolving www.google.com
  430. Sending Packet...Done
  431. Receiving answer...Done
  432. The response contains :
  433. 1 Questions.
  434. 6 Answers.
  435. 4 Authoritative Servers.
  436. 4 Additional records.
  437.  
  438.  
  439. Answer Records : 6
  440. Name : www.google.com has alias name : www.l.google.com
  441. Name : www.l.google.com has IPv4 address : 74.125.235.16
  442. Name : www.l.google.com has IPv4 address : 74.125.235.17
  443. Name : www.l.google.com has IPv4 address : 74.125.235.18
  444. Name : www.l.google.com has IPv4 address : 74.125.235.19
  445. Name : www.l.google.com has IPv4 address : 74.125.235.20
  446.  
  447. Authoritive Records : 4
  448. Name : google.com has nameserver : ns2.google.com
  449. Name : google.com has nameserver : ns1.google.com
  450. Name : google.com has nameserver : ns3.google.com
  451. Name : google.com has nameserver : ns4.google.com
  452.  
  453. Additional Records : 4
  454. Name : ns1.google.com has IPv4 address : 216.239.32.10
  455. Name : ns2.google.com has IPv4 address : 216.239.34.10
  456. Name : ns3.google.com has IPv4 address : 216.239.36.10
  457. Name : ns4.google.com has IPv4 address : 216.239.38.10
Advertisement
Add Comment
Please, Sign In to add comment