Back to doug's directory

File information
Filename: dns.c Uploaded: Sat, 6th Mar 2010 21:58:28
Size (bytes): 20.8 KiB md5 checksum: fe80ded8a7ad67018f1e81fe7e997625
Uploader doug Download: dns.c
Description:

Simple DNS query implementation. It's not completed to what I want it to do once I've completely finished it, but it is working properly now. Mail me if you spot anything error wise. I'm already aware of certain insecurities in the code. This is just to show how it works at the moment.

Updated 2009-08-02: Added switches rcCtTh and added ability to do things like reverse lookups.

/*
 * author: kay ~ irc.nullnetwork.net
 * date: 2006-08-31
 *
 * simple DNS query implementation. it's not completed to what i want it to
 * do once i've completely finished it, but it is working properly now. mail
 * me if you spot anything error wise. i'm already aware of certain
 * insecurities in the code. this is just to show how it works at the moment.
 *
 * Updated 2009-08-02: Added switches rcCtTh and added ability to do things like
 *   reverse lookups.
 *
 * Example usage:
 * ./dns nullnetwork.net
 * ./dns -r 89.200.138.209
 * ./dns -t 12 -C 1 209.138.200.89.in-addr.arpa
 * ./dns -T PTR -C IN 209.138.200.89.in-addr.arpa
 */
 
 
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <unistd.h>
 
#define PORT	       53
#define NS	           "208.67.222.222"
#define BUFLEN	       511
 
#define QTYPE_A        1
#define QTYPE_NS       2
#define QTYPE_MD       3
#define QTYPE_MF       4
#define QTYPE_CNAME    5
#define QTYPE_SOA      6
#define QTYPE_MB       7
#define QTYPE_MG       8
#define QTYPE_MR       9
#define QTYPE_NULL     10
#define QTYPE_WKS      11
#define QTYPE_PTR      12
#define QTYPE_HINFO    13
#define QTYPE_MINFO    14
#define QTYPE_MX       15
#define QTYPE_TXT      16
#define QTYPE_AXFR     252
#define QTYPE_MAILB    253
#define QTYPE_MAILA    254
#define QTYPE_OTHER    255
 
#define QCLASS_IN      1
#define QCLASS_CS      2
#define QCLASS_CH      3
#define QCLASS_HS      4
#define QCLASS_OTHER   255
 
#define PGREEN(x)      fwrite("\x1B[01;32m" x "\x1B[00m\n", 1, 14+sizeof(x), stdout);
#define PRED(x)        fwrite("\x1B[01;31m" x "\x1B[00m\n", 1, 14+sizeof(x), stdout);
#define PGREY(x)       fwrite("\x1B[01;30m" x "\x1B[00m\n", 1, 14+sizeof(x), stdout);
#define PWHITE(x)      fwrite("\x1B[01;29m" x "\x1B[00m\n", 1, 14+sizeof(x), stdout);
#define PYELLOW(x)     fwrite("\x1B[01;33m" x "\x1B[00m\n", 1, 14+sizeof(x), stdout);
#define PBLUE(x)       fwrite("\x1B[01;34m" x "\x1B[00m\n", 1, 14+sizeof(x), stdout);
#define PPURPLE(x)     fwrite("\x1B[01;35m" x "\x1B[00m\n", 1, 14+sizeof(x), stdout);
 
struct dns_header {
	short int id; // 2 bytes
	short int flags;
	/* bit n | meaning
	   0     | QR: query responce
	   1-4   | Opcode: query opcode (0 - standard query, 1 - inverse query, 2 = server status req., 3-15 reserved)
	   5     | AA: authoritive answer
	   6     | TC: Truncation
	   7     | RD: Recursion desired
	   8     | RA: recursion available
	   9-11  | Z: Reserved
	   12-15 | RCODE: responce code (0 - no error, 1 - format error, 2 - server failure, 3 - name error, 4 - not implemented, 5 - refused, 6-16 - reserved)
	*/
	short int qdcount;
	short int ancount;
	short int nscount;
	short int arcount;
};
 
struct dns_question {
	char * qname; // query name
	short int qtype;
	short int qclass;
};
 
struct dns_resource {
 
	char * name; // if name & 0xC0 == 0xC0 then its a pointer to name & 0x3FFF
	short int type;
	short int class;
	unsigned int ttl;
	unsigned short int rdlength;
	char * rdata; // note this is variable length, given by rdlength
};
 
 
typedef struct dns_header dns_header;
typedef struct dns_question dns_question;
typedef struct dns_resource dns_answer;
typedef struct dns_resource dns_authority;
typedef struct dns_resource dns_additional;
 
#define SET_QR(x) x|=0x8
#define UNSET_QR(x) x~=0x8
 
struct rdata_mx {
	short int preference;
	char * exchange;
};
 
struct rdata_soa {
	char * mname;
	char * rname;
	unsigned int serial;
	int refresh;
	int retry;
	int expire;
	unsigned int minimum;
};
 
 
int sendallto(int fd, char * data, int datalen, struct sockaddr_in * dest) {
int sendlen = datalen, num_of_bytes;	
	while (sendlen > 0) {
 
		if ((num_of_bytes = sendto(fd, data + (datalen - sendlen), sendlen, 0, (struct sockaddr *)dest, sizeof(struct sockaddr))) == -1) {
			return -1;
		}
		sendlen -= num_of_bytes;
	}
	return 0;
}
 
 
int make_query(int fd, short int flags, struct sockaddr_in dest_addr, dns_question query) {
    dns_header qhead;
    char buf[BUFLEN];
    int buflen     = 0;
    int octetlen   = 0;
    char * dotptr  = NULL;
    char * hostptr = query.qname;
 
	memset(buf, 0, BUFLEN);
 
	qhead.id      = htons(0x1337);
	qhead.flags   = htons(flags);
	qhead.qdcount = htons(0x0001);
	qhead.ancount = 0;
	qhead.nscount = 0;
	qhead.arcount = 0;
 
	buflen = sizeof(qhead);
	memcpy(buf, (void*)&qhead, buflen);
 
	do {
		dotptr = strchr(hostptr, '.');
 
		if (!dotptr)
			octetlen = strchr(hostptr,'\0') - hostptr;
		else 
			octetlen = dotptr - hostptr;
 
		buf[buflen++] = octetlen;
		strncpy(buf + buflen, hostptr, octetlen);
		buflen += octetlen;
		hostptr = dotptr + 1;
	} while(dotptr);
 
	memset(buf + buflen, 0, 2);
	buflen += 2;
	//qtype
	query.qtype = query.qtype;
	query.qclass = query.qclass;
	memcpy((void*)buf + buflen, (void*)&(query.qtype), sizeof(short));
	buflen += 2;
	//qclass
	memcpy((void*)buf + buflen, (void*)&(query.qclass), sizeof(short));
	buflen += 2;
 
	sendallto(fd, buf, buflen, &dest_addr);
 
	return 0;
}
 
char * translate_qtype(int qt) {
	switch(qt) {
	    case QTYPE_A:     return "A";
	    case QTYPE_NS:    return "NS";
	    case QTYPE_MD:    return "MD";
	    case QTYPE_MF:    return "MF";
	    case QTYPE_CNAME: return "CNAME";
	    case QTYPE_SOA:   return "SOA";
	    case QTYPE_MB:    return "MB";
	    case QTYPE_MG:    return "MG";
	    case QTYPE_MR:    return "MR";
	    case QTYPE_NULL:  return "NULL";
	    case QTYPE_WKS:   return "WKS";
	    case QTYPE_PTR:   return "PTR";
	    case QTYPE_HINFO: return "HINFO";
	    case QTYPE_MINFO: return "MINFO";
	    case QTYPE_MX:    return "MX";
	    case QTYPE_TXT:   return "TXT";
	    case QTYPE_AXFR:  return "AXFR";
	    case QTYPE_MAILB: return "MAILB";
	    case QTYPE_MAILA: return "MAILA";
	    case QTYPE_OTHER: return "*";
	    default:          return NULL;
	}
}
 
int translate_from_qtype(char * type) {
 
	if (strcmp(type, "A") == 0) {
		return QTYPE_A;
	} else if (strcmp(type, "NS") == 0) {
		return QTYPE_NS;
	} else if (strcmp(type, "MD") == 0) {
		return QTYPE_MD;
	} else if (strcmp(type, "MF") == 0) {
		return QTYPE_MF;
	} else if (strcmp(type, "CNAME") == 0) {
		return QTYPE_CNAME;
	} else if (strcmp(type, "SOA") == 0) {
		return QTYPE_SOA;
	} else if (strcmp(type, "MB") == 0) {
		return QTYPE_MB;
	} else if (strcmp(type, "MG") == 0) {
		return QTYPE_MG;
	} else if (strcmp(type, "MR") == 0) {
		return QTYPE_MR;
	} else if (strcmp(type, "NULL") == 0) {
		return QTYPE_NULL;
	} else if (strcmp(type, "WKS") == 0) {
		return QTYPE_WKS;
	} else if (strcmp(type, "PTR") == 0) {
		return QTYPE_PTR;
	} else if (strcmp(type, "HINFO") == 0) {
		return QTYPE_HINFO;
	} else if (strcmp(type, "MINFO") == 0) {
		return QTYPE_MINFO;
	} else if (strcmp(type, "MX") == 0) {
		return QTYPE_MX;
	} else if (strcmp(type, "TXT") == 0) {
		return QTYPE_TXT;
	} else if (strcmp(type, "AXFR") == 0) {
		return QTYPE_AXFR;
	} else if (strcmp(type, "MAILB") == 0) {
		return QTYPE_MAILB;
	} else if (strcmp(type, "MAILA") == 0) {
		return QTYPE_MAILA;
	} else if (strcmp(type, "*") == 0) {
		return QTYPE_OTHER;
	} else {
		return -1;
	}
}
 
char * translate_qclass(int qc) {
	switch(qc) {
	    case QCLASS_IN:    return "IN";
	    case QCLASS_CS:    return "CS";
	    case QCLASS_CH:    return "CH";
	    case QCLASS_HS:    return "HS";
	    case QCLASS_OTHER: return "*";
	    default:           return NULL;
	}
 
}
 
int translate_from_qclass(char * class) {
 
	if (strcmp(class, "IN") == 0) {
		return QCLASS_IN;
	} else if (strcmp(class, "CS") == 0) {
		return QCLASS_CS;
	} else if (strcmp(class, "CH") == 0) {
		return QCLASS_CH;
	} else if (strcmp(class, "HS") == 0) {
		return QCLASS_HS;
	} else if (strcmp(class, "*") == 0) {
		return QCLASS_OTHER;
	} else {
		return -1;
	}
}
 
char * translate_rcode(int rc) {
	switch(rc) {
	    case 0: return "No Error";
	    case 1: return "Format Error";
	    case 2: return "Server Failure";
	    case 3: return "Name Error";
	    case 4: return "Not Implemented";
	    case 5: return "Refused";
	    default:
		    return "Reserved";
	}
}
 
char * translate_opcode(int oc) {
	switch(oc) {
	    case 0: return "Standard Query";
	    case 1: return "Inverse Query";
	    case 2: return "Server Status Request";
	    default:
		    return "Reserved";
	}
}
 
// ---[data extraction routines]---
 
char * get_charstring(char * buf, int * offset) {
char * str = (char*)malloc(256);
int length;
 
	length = buf[(*offset)++];
	strncpy(str, buf + (*offset), length);
	*offset += length;
	return str;
}
 
char * get_name(char * data, int * start) {
    char * name                 = (char*)malloc(64);
    int name_len                = 0;
    short int offset            = *start;
    unsigned short int octetlen = 0;
    short int ptroffset         = 0;
    int set_start               = 1;
 
	if(!name) {
        return NULL;
	}
 
	memset(name, 0, 64);
 
	do {
 
		if ((data[offset] & 0xC0) == 0xC0) {
			ptroffset = 0;
			ptroffset |= (data[offset++] & 0x3F);
			ptroffset <<= 8;
			ptroffset |= (data[offset++] & 0xFF);
			if (set_start) {
                *start = offset;
            }
			offset = ptroffset;
			set_start = 0;
		}
		octetlen = data[offset++];
		if (octetlen) {
			if (name_len) {
			    name[name_len++] = '.';
	        }
			strncpy(name + name_len, data + offset, octetlen);
			name_len += octetlen;
			offset += octetlen;
		}
	} while(octetlen);
 
	if (set_start) {
        *start = offset;
    }
	return name;
}
 
// polymorphism, where for art thou
 
short int readshortintvalue(char * buf, int * offset) {
    short int bufint = 0;
	memcpy((void*)&(bufint), buf + *offset, sizeof(short int));
	*offset += sizeof(short int);
	return ntohs(bufint);
}
int readintvalue(char * buf, int * offset) {
    int bufint = 0;
	memcpy((void*)&(bufint), buf + *offset, sizeof(int));
	*offset += sizeof(int);
	return ntohl(bufint);
}
 
// ---[ rdata functions ]---
 
struct rdata_mx * get_rdata_mx(char * buf, int * offset) {
    struct rdata_mx * mx = (struct rdata_mx *)calloc(1, sizeof(struct rdata_mx));
	if (!mx) {
	    return NULL;
	}
	memcpy((void*)&(mx->preference), buf + *offset, sizeof(short));
	*offset += sizeof(short);
	mx->exchange = get_name(buf, offset);
	return mx;
}
 
 
struct rdata_soa * get_rdata_soa(char * buf, int * offset) {
    struct rdata_soa * soa = (struct rdata_soa *)calloc(1, sizeof(struct rdata_soa));
	if (!soa) {
	    return NULL;
	}
 
	soa->mname   = get_name(buf, offset);
	soa->rname   = get_name(buf, offset);
	soa->serial  = readintvalue(buf, offset);
	soa->refresh = readintvalue(buf, offset);
	soa->retry   = readintvalue(buf, offset);
	soa->expire  = readintvalue(buf, offset);
	soa->minimum = readintvalue(buf, offset);
 
	return soa;
}
 
 
struct dns_resource * get_resource(char * buf, int * start) {
    struct dns_resource * dns_res = (struct dns_resource *)calloc(1, sizeof(struct dns_resource));
    int offset = * start;
    char * name, * txt;
    struct in_addr inet_addr;
    struct rdata_mx * mx;
    struct rdata_soa * soa;
 
	if(!dns_res) {
	    return NULL;
	}
 
	name = get_name(buf, &offset);
	dns_res->name = name;
	dns_res->type = readshortintvalue(buf, &offset);
	dns_res->class = readshortintvalue(buf, &offset);
	dns_res->ttl = readintvalue(buf, &offset);
	dns_res->rdlength = readshortintvalue(buf, &offset);
 
	printf("dns_res {\n");
	printf("  name='%s'\n", dns_res->name);
	printf("  type=%d (Type: %s)\n", dns_res->type, translate_qtype(dns_res->type));
	printf("  class=0x%X (Class: %s)\n", dns_res->class, translate_qclass(dns_res->class));
	printf("  ttl=%d seconds\n", dns_res->ttl);
	printf("  rdlength=0x%X\n", dns_res->rdlength);
 
	//dns_ans.rdata 
	switch (dns_res->type) {
	case QTYPE_MB:
	case QTYPE_MD:
	case QTYPE_MF:
	case QTYPE_MG:
	case QTYPE_MR:
	case QTYPE_NS:
	case QTYPE_PTR:
	case QTYPE_CNAME:
		// domain-name
		name = get_name(buf, &offset);
		printf("  rdatas='%s' when type is %s\n", name, translate_qtype(dns_res->type));
		dns_res->rdata = name;
		break;
	case QTYPE_WKS:
		//
		break;
	case QTYPE_A:
		memcpy((void*)&(inet_addr.s_addr), buf + offset, sizeof(int));
		offset += sizeof(int);
		printf("  rdata=0x%X (%s)\n", inet_addr.s_addr, inet_ntoa(inet_addr));
		dns_res->rdata = (char*)inet_addr.s_addr;
		break;
	case QTYPE_TXT:
		txt = get_charstring(buf, &offset);
		printf("  rdata='%s'\n", txt);
		break;
	case QTYPE_SOA:
		soa = get_rdata_soa(buf, &offset);
		dns_res->rdata = (char*)soa;
		printf("  rdata {\n");
		printf("    mname='%s'\n", soa->mname);
		printf("    rname='%s'\n", soa->rname);
		printf("    serial=%d\n", soa->serial);
		printf("    refresh=%d seconds\n", soa->refresh);
		printf("    retry=%d seconds\n", soa->retry);
		printf("    expire=%d seconds\n", soa->expire);
		printf("    minimum=%d seconds\n", soa->minimum);
		printf("  }\n");
		break;
	case QTYPE_NULL:
		// this is an experimental type, so I'll just ignore it
		printf("  # rdata ignored due to type being experimental\n");
		break;
	case QTYPE_MX:
		// preference
		// exchange (domain-name)
		mx = get_rdata_mx(buf, &offset);
		dns_res->rdata = (char*)mx;
		printf("  rdata {\n");
		printf("    preference=%d\n", mx->preference);
		printf("    exchange='%s'\n", mx->exchange);
		printf("  }\n");
		break;
	case QTYPE_MINFO:
		// rmailbx (domain-name)
		// emailbx (domain-name)
		break;
	case QTYPE_HINFO:
		// cpu (char-string)
		// os (char-string)
		break;
	default:
		printf("Unknown type\n");
	}
	printf("}\n");
	*start = offset;
 
	return dns_res;
}
 
int read_responce(int fd, struct sockaddr_in dest_addr) {
    int               num_of_bytes = 0;
    char              buf[BUFLEN];
    unsigned int      buflen = 0;
    dns_header        dns_head;
    dns_question      dns_quest;
    dns_authority *   dns_auth;
    dns_answer *      dns_ans;
    dns_additional *  dns_add;
    int               offset = 0;
    char *            name;
    int               i;
    unsigned short int qr, opcode, aa, tc, rd, ra, z, rcode;
 
	if ((num_of_bytes = recvfrom(fd, buf, BUFLEN, 0, (struct sockaddr *)&dest_addr, &buflen)) == -1) {
		perror("recvfrom() error");
		return 1;
	}
	printf("%d bytes received\n", num_of_bytes);
 
	memcpy((void*)&dns_head, buf, sizeof(dns_header));
	dns_head.id      = ntohs(dns_head.id);
	dns_head.flags   = ntohs(dns_head.flags);
	dns_head.qdcount = ntohs(dns_head.qdcount);
	dns_head.ancount = ntohs(dns_head.ancount);
	dns_head.nscount = ntohs(dns_head.nscount);
	dns_head.arcount = ntohs(dns_head.arcount);
 
	qr     = (dns_head.flags & 0x8000);
	opcode = (dns_head.flags & 0x7800) >> 11;
	aa     = (dns_head.flags & 0x0400);
	tc     = (dns_head.flags & 0x0200);
	rd     = (dns_head.flags & 0x0100);
	ra     = (dns_head.flags & 0x0080);
	z      = (dns_head.flags & 0x0070) >> 4;
	rcode  = (dns_head.flags & 0x000F);
 
	printf("dns_head {\n");
	printf("  id=0x%X\n",            dns_head.id);
	printf("  flags=0x%hX {\n",      dns_head.flags);
	printf("    qr=%u (%s)\n",       (qr ? 1 : 0), (qr ? "is a Query Responce" : "is not a Query Responce"));
	printf("    opcode=0x%X (%s)\n", opcode, translate_opcode(opcode));
	printf("    aa=%u (%s)\n",       (aa ? 1 : 0), (aa ? "is the Authoritive Server" : "is not the Authoritive Server"));
	printf("    tc=%u%s\n",          (tc ? 1 : 0), (tc ? " ( is Truncated)" : ""));
	printf("    rd=%u%s\n",          (rd ? 1 : 0), (rd ? " (Recursion Desired)" : ""));
	printf("    ra=%u%s\n",          (ra ? 1 : 0), (ra ? " (Recursion available)" : ""));
	printf("    z=0x%X\n",           z);
	printf("    rcode=0x%X (%s)\n",  rcode, translate_rcode(rcode));
	printf("  }\n");
	printf("  qdcount=%u\n",         dns_head.qdcount);
	printf("  ancount=%u\n",         dns_head.ancount);
	printf("  nscount=%u\n",         dns_head.nscount);
	printf("  arcount=%u\n",         dns_head.arcount);
	printf("}\n");
 
	/* bit n | meaning
	   0     | QR: query responce
	   1-4   | Opcode: query opcode (0 - standard query, 1 - inverse query, 2 = server status req., 3-15 reserved)
	   5     | AA: authoritive answer
	   6     | TC: Truncation
	   7     | RD: Recursion desired
	   8     | RA: recursion available
	   9-11  | Z: Reserved
	   12-15 | RCODE: responce code (0 - no error, 1 - format error, 2 - server failure, 3 - name error, 4 - not implemented, 5 - refused, 6-16 - reserved)
	*/	
 
	// get question information
	offset = sizeof(dns_header);
 
	// lets get qname
	name = get_name(buf, &offset);
	dns_quest.qname = name;
	//add_qname(name, offset);
 
	// get qtype and qclass
	memcpy((void*)&(dns_quest.qtype), buf + offset, sizeof(short int));
	offset += sizeof(short int);
	dns_quest.qtype = ntohs(dns_quest.qtype);
 
 
	memcpy((void*)&(dns_quest.qclass), buf + offset, sizeof(short int));
	offset += sizeof(short int);
	dns_quest.qclass = ntohs(dns_quest.qclass);
 
	printf("dns_quest {\n");
	printf("  qname='%s'\n", dns_quest.qname);
	printf("  qtype=%d (Type: %s)\n", dns_quest.qtype, translate_qtype(dns_quest.qtype));
	printf("  qclass=%d (Class: %s)\n", dns_quest.qclass, translate_qclass(dns_quest.qclass));
	printf("}\n");
	PBLUE("Answers:");
	for(i =0; i < dns_head.ancount; i++) {
		//get Answers
		dns_ans = get_resource(buf, &offset);
	}
	PPURPLE("Authoritative nameservers:");
	for(i =0; i < dns_head.arcount; i++) {
		//get Authoritative Nameservers
		dns_auth = get_resource(buf, &offset);
	}
	PPURPLE("Additional records:");
	for(i =0; i < dns_head.arcount; i++) {
		//get Additional Records
		dns_add = get_resource(buf, &offset);
	}
	return 0;
}
 
void usage(char * arg0) {
	printf("Usage: %s [-r] [-t type] [-c class] name...\n", arg0);
	printf("       -r Perform a reverse lookup. In this instance the name\n");
	printf("          argument should be an IP address.\n");
	printf("       -t Manually specify a DNS query type using a numeric argument.\n");
	printf("       -T Manually specify a DNS query type using a string argument.\n");
	printf("          Valid inputs are: A, NS, MD, MF, CNAME, SOA, MB, MG, MR,\n");
	printf("          NULL, WKS, PTR, HINFO, MINFO, MX, TXT, AXFR, MAILB, MAILA,\n");
	printf("          and '*'\n");
	printf("       -c Manually specify a DNS query class using a numeric argument.\n");
	printf("       -C Manually specify a DNS query class using a string argument.\n");
	printf("          Valid inputs are: IN, CS, CH, HS, and '*'\n");
	printf("       -h Display this help.\n");
 
}
 
int main(int argc, char ** argv) {
 
	int                fd;
	struct sockaddr_in dest_addr;
	dns_question       q;
	int                c;
	char *             name;
	int                index;
	short int          qclass = QCLASS_IN;
	short int          qtype  = QTYPE_A;
	short int          flags  = 0x0100;
	int                opt_r  = 0;
 
	if (argc < 2) {
		printf("Not enough arguments. Please supply domain to lookup\n");
		exit(1);
	}
 
 
	/* 
	 * flags bits:
	   bit n | meaning
	   0     | QR: query responce
	   1-4   | Opcode: query opcode (0 - standard query, 1 - inverse query, 2 = server status req., 3-15 reserved)
	   5     | AA: authoritive answer
	   6     | TC: Truncation
	   7     | RD: Recursion desired
	   8     | RA: recursion available
	   9-11  | Z: Reserved
	   12-15 | RCODE: responce code (0 - no error, 1 - format error, 2 - server failure, 3 - name error, 4 - not implemented, 5 - refused, 6-16 - reserved)
	*/
 
	//0000100100000000
	while ((c = getopt (argc, argv, "rt:T:c:C:n:h")) != -1) {
		switch (c) {
		    case 'r':
			    opt_r = 1;
			    qtype = QTYPE_PTR;
			    break;
 
		    case 't':
			    qtype = atoi(optarg);
			    break;
 
		    case 'T':
			    qtype = translate_from_qtype(optarg);
			    if (qtype == -1) {
				    usage(argv[0]);
				    printf("Error: Failed to translate qtype '%s'\n", optarg);
			    }
			    break;
 
		    case 'c':
			    qclass = atoi(optarg);
			    break;
 
		    case 'C':
			    qclass = translate_from_qclass(optarg);
			    if (qclass == -1) {
				    usage(argv[0]);
				    printf("Error: Failed to translate qclass '%s'\n", optarg);
			    }
			    break;
 
		    case 'n':
			    name = optarg;
			    break;
 
		    case 'h':
			    usage(argv[0]);
			    return 1;
		}
	}
 
	PGREEN("My DNS Implementation");
 
	for (index = optind; index < argc; index++) {
 
		if (opt_r) {
			int name_len = strlen(argv[index]);
 
			struct in_addr inp;
			unsigned long int s_addr;
			unsigned long int s_addr_out = 0;
 
			inet_aton(argv[index], &inp);
			s_addr = inp.s_addr;
 
			s_addr_out |= (s_addr & 0xFF000000) >> 24;
			s_addr_out |= (s_addr & 0x00FF0000) >> 8;
			s_addr_out |= (s_addr & 0x0000FF00) << 8;
			s_addr_out |= (s_addr & 0x000000FF) << 24;
 
			inp.s_addr = s_addr_out;
 
			name = (char*)calloc(name_len + 13 + 1, sizeof(char));
			strncpy(name, (char*)inet_ntoa(inp), name_len);
			strncat(name, ".in-addr.arpa", 13);
 
		} else {
			name = argv[index];
		}
 
 
		fd = socket( AF_INET, SOCK_DGRAM, 0 );
		if (fd <= 0) {
			perror("socket() error");
			return 1;
		}
 
		dest_addr.sin_family = AF_INET;
		dest_addr.sin_port   = htons(PORT);
		dest_addr.sin_addr.s_addr = inet_addr( NS );
		memset(&(dest_addr.sin_zero), '\0', 8);
		q.qtype = qtype;
		q.qclass = qclass;
		q.qname = name;
		make_query(fd, flags, dest_addr, q);
		read_responce(fd, dest_addr);
		close(fd);
	}
 
	return 0;
}
 
Powered by Debian, Guinness, and excessive quantities of caffeine and sugar.