mirror of https://github.com/Chizi123/dnscomp.git

Joel Grunbaum
2020-10-18 8ee2bac0af0a194d99fb1073b5362b0cd5c07130
split dns into own file and printing into own function
1 files modified
3 files added
566 ■■■■ changed files
Makefile 12 ●●●●● patch | view | raw | blame | history
dns.c 269 ●●●●● patch | view | raw | blame | history
dns.h 12 ●●●●● patch | view | raw | blame | history
main.c 273 ●●●●● patch | view | raw | blame | history
Makefile
New file
@@ -0,0 +1,12 @@
CC=gcc
OBJ=main.o dns.o
DEPS=dns.h
CFLAGS=-g
default: all
%.o: %.c $(DEPS)
    $(CC) $(CFLAGS) -c -o $@ $<
all: $(OBJ)
    $(CC) $(CFLAGS) $^
dns.c
New file
@@ -0,0 +1,269 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
//#include <netint/in.h>
//#include <netdb.h>
#include <sys/time.h>
#include <unistd.h>
#include "dns.h"
// DNS code copied from
// https://gist.github.com/fffaraz/9d9170b57791c28ccda9255b48315168
/* DNS header struct */
struct DNS_HEADER
{
     unsigned short id;         //ID number
     unsigned char rd :1;       //recursion
     unsigned char tc :1;       //truncated message
     unsigned char aa :1;       //authoritive answer
     unsigned char opcode :4;   //message purpose
     unsigned char qr :1;       //query response
     unsigned char rcode :4;    //response code
     unsigned char cd :1;       //checking disabled
     unsigned char ad :1;       //authenticated data
     unsigned char z :1;        //reserved for future use
     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
};
/* structured for query structure */
struct QUESTION
{
     unsigned short qtype;
     unsigned short qclass;
};
/* Query structure */
struct QUERY
{
     unsigned char* name;
     struct QUESTION* ques;
};
/* Constant sized fields of 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 record components */
struct RES_RECORD
{
     unsigned char* name;
     struct R_DATA* resource;
     unsigned char* rdata;
};
void resolve(char* hostname, char* dns_ip, int query_type, int read)
{
     int s, i, j;
     struct sockaddr_in dest, a;
     unsigned char buf[65536], *qname, *reader;
     struct DNS_HEADER* dns = NULL;
     struct QUESTION* qinfo = NULL;
     s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
     dest.sin_family = AF_INET;
     dest.sin_port = htons(53);
     dest.sin_addr.s_addr = inet_addr(dns_ip);
     //dns packet header
     dns = (struct DNS_HEADER*)&buf;
     dns->id = (unsigned short) htons(getpid());
     dns->qr = 0;               //make query
     dns->opcode = 0;           //standard query
     dns->aa = 0;               //not authoritive
     dns->tc = 0;               //not trucated
     dns->rd = 1;               //want recursion
     dns->ra = 0;               //recursion not available
     dns->z = 0;
     dns->ad = 0;
     dns->cd = 0;
     dns->rcode = 0;
     dns->q_count = htons(1);   //one question
     dns->ans_count = 0;
     dns->auth_count = 0;
     dns->add_count = 0;
     //dns packet query
     qname = (unsigned char*)&buf[sizeof(struct DNS_HEADER)];
     change_to_DNS_name_format(qname, (unsigned char*)hostname);
     qinfo = (struct QUESTION*)&buf[sizeof(struct DNS_HEADER) + strlen((const char*)qname) + 1];
     qinfo->qtype = htons(query_type); //type of query from argument (A,AAAA,MX,CNAME,NS,...)
     qinfo->qclass = htons(1); //internet class
     //send request
     // return less than 0 is a fail
     sendto(s,(char*)buf, sizeof(struct DNS_HEADER)+strlen((const char*)qname)+1+sizeof(struct QUESTION), 0, (struct sockaddr*)&dest, sizeof(dest));
     //receive response
     //negative return is a fail
     i = sizeof(dest);
     recvfrom(s, (char*)buf, 65536, 0, (struct sockaddr*)&dest, (socklen_t*)&i);
     //read response
     if (read) {
          print_packet(buf);
     }
     return;
}
void print_packet(unsigned char* buf)
{
     struct RES_RECORD answers[20], auth[20], addit[20];
     struct DNS_HEADER *dns;
     struct sockaddr_in a;
     char* qname = buf+sizeof(struct DNS_HEADER), *reader;
     int stop, i, j;
     dns = (struct DNS_HEADER*)buf;
     reader = &buf[sizeof(struct DNS_HEADER)+strlen((const char*)qname)+1+sizeof(struct QUESTION)];
     printf("Response contains %d Qs, %d ans, %d auth serv, %d add reconds\n", ntohs(dns->q_count), ntohs(dns->ans_count), ntohs(dns->auth_count), ntohs(dns->add_count));
     stop = 0;
     for (i = 0; i < ntohs(dns->ans_count); i++) {
          answers[i].name = read_name(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) { //IPv4 address
               answers[i].rdata = (unsigned char*)malloc(ntohs(answers[i].resource->data_len));
               for (j = 0; j < ntohs(answers[i].resource->data_len); j++) {
                    answers[i].rdata[j] = reader[j];
               }
               answers[i].rdata[ntohs(answers[i].resource->data_len)] = '\0';
               reader = reader + ntohs(answers[i].resource->data_len);
          } else {
               answers[i].rdata = read_name(reader, buf, &stop);
               reader = reader + stop;
          }
     }
     //read authorities
     for (i = 0; i < ntohs(dns->auth_count); i++) {
          auth[i].name = read_name(reader, buf, &stop);
          reader += stop;
          auth[i].resource = (struct R_DATA*)reader;
          reader += sizeof(struct R_DATA);
          auth[i].rdata = read_name(reader, buf, &stop);
          reader += stop;
     }
     //read additional
     for (i = 0; i < ntohs(dns->add_count); i++) {
          addit[i].name = read_name(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 = 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 = read_name(reader, buf, &stop);
               reader += stop;
          }
     }
     //print answers
     printf("ans recs: %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
               long* p;
               p = (long*)answers[i].rdata;
               a.sin_addr.s_addr=(*p);
               printf("has IPv4 addresss: %s", inet_ntoa(a.sin_addr));
          } else if (ntohs(answers[i].resource->type) == T_CNAME) { //CNAME
               printf("has alias: %s", answers[i].rdata);
          }
          putc('\n', stdout);
     }
     //print authorities
     printf("Auth recs: %d\n", ntohs(dns->auth_count));
     for (i = 0; i < ntohs(dns->auth_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));
          }
          putc('\n', stdout);
     }
}
void change_to_DNS_name_format(unsigned char* dns, unsigned char* host)
{
     int lock = 0;
     char h[300];
     strcpy(h, host);
     strcat((char*)h,".");
     for (int i = 0; i < strlen((char*)h); i++) {
          if (h[i] == '.') {
               *dns++ = i-lock;
               for (;lock<i;lock++) {
                    *dns++ = h[lock];
               }
               lock++;
          }
     }
     *dns++ = '\0';
}
char* read_name(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';
     while (*reader != 0) {
          if (*reader >= 192) {
               offset = (*reader)*256+ *(reader+1) - 49152;
               reader = buffer+offset-1;
               jumped=1;
          } else {
               name[p++]=*reader;
          }
          reader = reader+1;
          if (jumped == 0) {
               *count = *count+1;
          }
     }
     name[p] = '\0';
     if (jumped == 1) {
          *count = *count + 1;
     }
     //convert from dns format to normal
     for (i = 0; i < strlen((const char*)name); i++) {
          p = name[i];
          for (j = 0; j < p; j++) {
               name[i] = name[i+1];
               i++;
          }
          name[i] = '.';
     }
     name[i-1] = '\0';
     return name;
}
dns.h
New file
@@ -0,0 +1,12 @@
// DNS resource records
#define T_A 1 // IPv4 address
#define T_NS // Name Server
#define T_CNAME 5 // Cannonical name
#define T_SOA 6 // State of Authority
#define T_PTR 12 // Domain name pointer
#define T_MX 15 // Mail exchange
void resolve(char* hostname, char* dns_ip, int query_type, int read);
void print_packet(unsigned char* buf);
void change_to_DNS_name_format(unsigned char* dns, unsigned char* host);
char* read_name(unsigned char* reader, unsigned char* buffer, int* count);
main.c
@@ -1,278 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
//#include <netint/in.h>
//#include <netdb.h>
#include <sys/time.h>
#include <unistd.h>
// DNS code copied from
// https://gist.github.com/fffaraz/9d9170b57791c28ccda9255b48315168
// DNS resource records
#define T_A 1 // IPv4 address
#define T_NS // Name Server
#define T_CNAME 5 // Cannonical name
#define T_SOA 6 // State of Authority
#define T_PTR 12 // Domain name pointer
#define T_MX 15 // Mail exchange
/* DNS header struct */
struct DNS_HEADER
{
     unsigned short id;         //ID number
     unsigned char rd :1;       //recursion
     unsigned char tc :1;       //truncated message
     unsigned char aa :1;       //authoritive answer
     unsigned char opcode :4;   //message purpose
     unsigned char qr :1;       //query response
     unsigned char rcode :4;    //response code
     unsigned char cd :1;       //checking disabled
     unsigned char ad :1;       //authenticated data
     unsigned char z :1;        //reserved for future use
     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
};
/* structured for query structure */
struct QUESTION
{
     unsigned short qtype;
     unsigned short qclass;
};
/* Query structure */
struct QUERY
{
     unsigned char* name;
     struct QUESTION* ques;
};
/* Constant sized fields of 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 record components */
struct RES_RECORD
{
     unsigned char* name;
     struct R_DATA* resource;
     unsigned char* rdata;
};
void resolve(char* hostname, char* dns_ip, int query_type, int read);
void change_to_DNS_name_format(unsigned char* dns, unsigned char* host);
u_char* read_name(unsigned char* reader, unsigned char* buffer, int* count);
#include "dns.h"
int main(int argc, char** argv)
{
     resolve("google.com", "1.1.1.1", T_A, 1);
     return 0;
}
void resolve(char* hostname, char* dns_ip, int query_type, int read)
{
     int s, i, j;
     struct sockaddr_in dest, a;
     unsigned char buf[65536], *qname, *reader;
     struct DNS_HEADER* dns = NULL;
     struct QUESTION* qinfo = NULL;
     s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
     dest.sin_family = AF_INET;
     dest.sin_port = htons(53);
     dest.sin_addr.s_addr = inet_addr(dns_ip);
     //dns packet header
     dns = (struct DNS_HEADER*)&buf;
     dns->id = (unsigned short) htons(getpid());
     dns->qr = 0;               //make query
     dns->opcode = 0;           //standard query
     dns->aa = 0;               //not authoritive
     dns->tc = 0;               //not trucated
     dns->rd = 1;               //want recursion
     dns->ra = 0;               //recursion not available
     dns->z = 0;
     dns->ad = 0;
     dns->cd = 0;
     dns->rcode = 0;
     dns->q_count = htons(1);   //one question
     dns->ans_count = 0;
     dns->auth_count = 0;
     dns->add_count = 0;
     //dns packet query
     qname = (unsigned char*)&buf[sizeof(struct DNS_HEADER)];
     change_to_DNS_name_format(qname, (unsigned char*)hostname);
     qinfo = (struct QUESTION*)&buf[sizeof(struct DNS_HEADER) + strlen((const char*)qname) + 1];
     qinfo->qtype = htons(query_type); //type of query from argument (A,AAAA,MX,CNAME,NS,...)
     qinfo->qclass = htons(1); //internet class
     //send request
     // return less than 0 is a fail
     sendto(s,(char*)buf, sizeof(struct DNS_HEADER)+strlen((const char*)qname)+1+sizeof(struct QUESTION), 0, (struct sockaddr*)&dest, sizeof(dest));
     //receive response
     //negative return is a fail
     i = sizeof(dest);
     recvfrom(s, (char*)buf, 65536, 0, (struct sockaddr*)&dest, (socklen_t*)&i);
     //read response
     if (read) {
          struct RES_RECORD answers[20], auth[20], addit[20];
          int stop;
          dns = (struct DNS_HEADER*)buf;
          reader = &buf[sizeof(struct DNS_HEADER)+strlen((const char*)qname)+1+sizeof(struct QUESTION)];
          printf("Response contains %d Qs, %d ans, %d auth serv, %d add reconds\n", ntohs(dns->q_count), ntohs(dns->ans_count), ntohs(dns->auth_count), ntohs(dns->add_count));
          stop = 0;
          for (i = 0; i < ntohs(dns->ans_count); i++) {
               answers[i].name = read_name(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) { //IPv4 address
                    answers[i].rdata = (unsigned char*)malloc(ntohs(answers[i].resource->data_len));
                    for (j = 0; j < ntohs(answers[i].resource->data_len); j++) {
                         answers[i].rdata[j] = reader[j];
                    }
               answers[i].rdata[ntohs(answers[i].resource->data_len)] = '\0';
               reader = reader + ntohs(answers[i].resource->data_len);
               } else {
                    answers[i].rdata = read_name(reader, buf, &stop);
                    reader = reader + stop;
               }
          }
          //read authorities
          for (i = 0; i < ntohs(dns->auth_count); i++) {
               auth[i].name = read_name(reader, buf, &stop);
               reader += stop;
               auth[i].resource = (struct R_DATA*)reader;
               reader += sizeof(struct R_DATA);
               auth[i].rdata = read_name(reader, buf, &stop);
               reader += stop;
          }
          //read additional
          for (i = 0; i < ntohs(dns->add_count); i++) {
               addit[i].name = read_name(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 = 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 = read_name(reader, buf, &stop);
                    reader += stop;
               }
          }
          //print answers
          printf("ans recs: %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
                    long* p;
                    p = (long*)answers[i].rdata;
                    a.sin_addr.s_addr=(*p);
                    printf("has IPv4 addresss: %s", inet_ntoa(a.sin_addr));
               } else if (ntohs(answers[i].resource->type) == T_CNAME) { //CNAME
                    printf("has alias: %s", answers[i].rdata);
               }
               putc('\n', stdout);
          }
          //print authorities
          printf("Auth recs: %d\n", ntohs(dns->auth_count));
          for (i = 0; i < ntohs(dns->auth_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));
               }
               putc('\n', stdout);
          }
     }
     return;
}
void change_to_DNS_name_format(unsigned char* dns, unsigned char* host)
{
     int lock = 0;
     char h[300];
     strcpy(h, host);
     strcat((char*)h,".");
     for (int i = 0; i < strlen((char*)h); i++) {
          if (h[i] == '.') {
               *dns++ = i-lock;
               for (;lock<i;lock++) {
                    *dns++ = h[lock];
               }
               lock++;
          }
     }
     *dns++ = '\0';
}
u_char* read_name(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';
     while (*reader != 0) {
          if (*reader >= 192) {
               offset = (*reader)*256+ *(reader+1) - 49152;
               reader = buffer+offset-1;
               jumped=1;
          } else {
               name[p++]=*reader;
          }
          reader = reader+1;
          if (jumped == 0) {
               *count = *count+1;
          }
     }
     name[p] = '\0';
     if (jumped == 1) {
          *count = *count + 1;
     }
     //convert from dns format to normal
     for (i = 0; i < strlen((const char*)name); i++) {
          p = name[i];
          for (j = 0; j < p; j++) {
               name[i] = name[i+1];
               i++;
          }
          name[i] = '.';
     }
     name[i-1] = '\0';
     return name;
}