Getting IPs from a DNS response - c

I'm trying to write a program that will scrape one IP address out of a DNS reply without using any DNS functions in c. For some reason this code works but only for google, facebook and imgur.com. As in, if I enter in "www.facebook.com" it gives the right IP address and same with the other two sites but any other site entered gives a wrong IP address. Does anyone know what I'm doing wrong?
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#define PORT 53
#define SITEMAXLEN 40
#define QUERYMAXLEN SITEMAXLEN + 16
#define DNSRESULTMAXLEN 100
#define IPARRAYLEN 20
typedef unsigned char char_type;
void enter_record(char_type* query, char_type* site, int* let_set);
void print_query(char_type* query, int len);
void send_query(char_type* query, char_type* result, int len, int* answer_set);
char_type* parse_result(char_type* result, int query_len, char_type* ip);
void print_ip(int* ip);
int sock;
struct sockaddr_in server_addr;
struct sockaddr_in from_addr;
int main(int argc, char_type** argv) {
char_type* site;
char_type* query;
char_type* dns_result;
char_type* ip;
int query_len;
int answer_len;
site = (char_type*)malloc(SITEMAXLEN * sizeof(char_type));
query = (char_type*)malloc((QUERYMAXLEN) * sizeof(char_type));
dns_result = (char_type*)malloc(DNSRESULTMAXLEN * sizeof(char_type));
ip = (char_type*)malloc(IPARRAYLEN * sizeof(char_type));
if((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
fprintf(stderr, "error creating socket to the name server\n");
return 1;
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("208.67.220.220");
server_addr.sin_port = htons(PORT);
printf("enter in website name\n");
scanf("%s", site);
enter_record(query, site, &query_len);
print_query(query, query_len);
send_query(query, dns_result, query_len, &answer_len);
printf("\n\nresult is\n");
print_query(dns_result, answer_len);
parse_result(dns_result, query_len, ip);
printf("\n\nip address is: %s", ip);
return 0;
}
void enter_record(char_type* query, char_type* site, int* len_set) {
char_type* loc;
char_type* len;
char_type* tld;
int query_end;
loc = strchr(site, '.'); //. after www
len = strchr(loc + 1, '.'); //. after the hostname
*loc = (char_type)(len - loc - 1);
*len = (char_type)0x0003;
query[0] = 'B';
query[1] = 'L';
query[2] = (char_type)0x0001;
query[3] = (char_type)0x0000;
query[4] = (char_type)0x0000;
query[5] = (char_type)0x0001;
query[6] = (char_type)0x0000;
query[7] = (char_type)0x0000;
query[8] = (char_type)0x0000;
query[9] = (char_type)0x0000;
query[10] = (char_type)0x0000;
query[11] = (char_type)0x0000;
query[12] = (char_type)0x0003;
strncat(query + 13, site, strlen(site));
query_end = 13 + strlen(site);
query[query_end] = 0x0000;
query[query_end + 1] = 0x0000;
query[query_end + 2] = 0x0001;
query[query_end + 3] = 0x0000;
query[query_end + 4] = 0x0001;
*len_set = query_end + 5;
}
void print_query(char_type* query, int len) {
int i;
printf("in hex\n");
for(i = 0; i < len; i++) {
printf("%02hhX ", query[i]);
if(i % 16 == 0 && i != 0) {
printf("\n");
}
}
printf("\nin ascii\n");
for(i = 0; i < len; i++) {
printf("%c ", query[i] < (char_type)0x21 ? '.' : query[i]);
if(i % 16 == 0 && i != 0) {
printf("\n");
}
}
printf("\n");
}
void send_query(char_type* query, char_type* result, int len, int* set_len) {
int from_size;
int response_len;
if(sendto(sock, query, len, 0,
(struct sockaddr*)&server_addr, sizeof(server_addr)) != len) {
//message couldn't be sent
fprintf(stderr, "couldn't send the query\n");
return;
}
from_size = sizeof(from_addr);
while((response_len = recvfrom(sock, result, DNSRESULTMAXLEN, 0,
(struct sockaddr*)&from_addr, &from_size)) < 0) {
}
//null terminate the buffer
//printf("%d\n", response_len);
//result[response_len] = '\0';
*set_len = response_len;
}
char_type* parse_result(char_type* result, int query_len, char_type* ip) {
/*int offset = -1;
//offset = query_len + 32;
int count = 0;
while(count < 3) {
offset++;
if(result[offset] == 0x00C0) {
count++;
}
}
offset += 32;*/
int offset = -1;
int found = 0;
while(found == 0) {
offset++;
if(result[offset] == 0x00C0) {
if(result[offset + 3] == 0x0001 && result[offset + 2] == 0x0000) {
offset = offset + result[offset + 1];
found = 1;
}
}
}
sprintf(ip, "%d.%d.%d.%d\n",
result[offset], result[offset + 1],
result[offset + 2], result[offset + 3]);
return ip;
}

In parse_result() instead of jumping result[offset + 1] bytes, jump 12 bytes.
if(result[offset + 3] == 0x0001 && result[offset + 2] == 0x0000) {
/* ********
offset = offset + result[offset + 1];
******** */
offset = offset + 12;
found = 1;
}
The value at result[offset + 1] is the offset from the beginning of the message to a name, not an ip address. In the case of yahoo, the offset ultimately points to "any-fp.wa1.b.yahoo.com".
It worked for facebook (and others) because the offset to the name in the answer is 12. The offset is 12 when the name in the question is the same as the name in the answer.
Update
Not all DNS answers start each answer section with a pointer (0xC0 0x??). They may have a label instead and your program will fail miserably. Even the pointer's first byte is not required to be 0xC0: the requirement is to have the first 2 bits set.

Related

How to Combine 2 Struct arrays in C

iv tried a lot of solutions to try to get this working (i.e using memcpy etc) I cant seem to find the issue, depending on what I try I either end up with gibberish or SEGV
iv spent a lot of time already googling and trying different ways, i still cant figure out why the arrays won't combine successfully
#include <stdio.h>
#include <stdint.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <unistd.h>
#define log_info printf
typedef struct
{
char* name;
//size_t size;
} entry_t;
/* qsort struct comparison function (C-string field) */
static int struct_cmp_by_name(const void* a, const void* b)
{
entry_t* ia = (entry_t*)a;
entry_t* ib = (entry_t*)b;
return strcmp(ia->name, ib->name);
/* strcmp functions works exactly as expected from comparison function */
}
entry_t* get_item_entries(const char* dirpath, int* count)
{
struct dirent* dent;
char buffer[512]; // fixed buffer
int dfd = 0,
n, r = 1; // item counter, rounds to loop
entry_t* p = NULL; // we fill this struct with items
loop:
n = 0;
printf("loop: %d, count:%d\n", r, *count);
// try to open dir
dfd = open(dirpath, O_RDONLY, 0);
if (dfd < 0)
{
printf("Invalid directory. (%s)\n", dirpath);
*count = -1;
return NULL;
}
else
{
printf("open(%s)\n", dirpath);
}
memset(buffer, 0, sizeof(buffer));
while (syscall(SYS_getdents, dfd, buffer, sizeof(buffer)) != 0)
{
dent = (struct dirent*)buffer;
while (dent->d_fileno)
{ // skip `.` and `..`
if (!strncmp(dent->d_name, "..", 2)
|| !strncmp(dent->d_name, ".", 1)) goto skip_dent;
// deal with filtering outside of this function, we just skip .., .
switch (r)
{ // first round: just count items
case 1:
{
// skip special cases
if (dent->d_fileno == 0) goto skip_dent;
break;
}
// second round: store filenames
case 0: p[n].name = strdup(dent->d_name); break;
}
n++;
skip_dent:
dent = (struct dirent*)((void*)dent + dent->d_reclen);
if (dent == (void*)&buffer[512]) break; // refill buffer
}
memset(buffer, 0, sizeof(buffer));
}
close(dfd);
// on first round, calloc for our list
if (!p)
{ // now n holds total item count, note it
p = calloc(n, sizeof(entry_t));
*count = n;
}
// first round passed, loop
r--; if (!r) goto loop;
// report count
printf("%d items at %p, from 1-%d\n", *count, (void*)p, *count);
/* resort using custom comparision function */
qsort(p, *count, sizeof(entry_t), struct_cmp_by_name);
// report items
//for (int i = 0; i < num; ++i) log_error( "%s", p[i].name);
return p;
}
int main(int argc, char* argv[])
{
int HDD_count = -1;
uint32_t total = -1;
int ext_count = -1;
entry_t* e = NULL;
entry_t *HDD = get_item_entries("/mnt/f/n", &HDD_count);
entry_t* ext = get_item_entries("/mnt/f/dls", &ext_count);
total = ext_count + HDD_count;
e = (entry_t*)malloc(sizeof *e * total);
if (e != NULL)
{
for (int i = 1; i < HDD_count; i++)
{
log_info("HDD[%i].name %s\n", i, HDD[i].name);
e[i].name = strdup(HDD[i].name);
}
for (int i = 1; i < ext_count; i++)
{
log_info("ext[%i].name %s\n", i, ext[i].name);
e[i + HDD_count].name = strdup(ext[i].name);
}
}
else
printf("Failed to Allocate the Array");
char tmp[256];
int i = 1, j;
for(j = 1; j <= total; j++)
{
snprintf(&tmp[0], 255, "%s", e[ j].name);
log_info("%i:%s\n", j , tmp);
}
return 0;
}
Here is a rewrite of a snippet of main() that I mentioned in my comment above:
#define CHECK(p, msg) if(!(p)) { printf("%s:%d: %s", __FILE__, __LINE__, msg); return 1;}
...
entry_t *HDD = get_item_entries("/mnt/f/n", &HDD_count);
CHECK(HDD, "HDD failed to get entries");
entry_t *ext = get_item_entries("/mnt/f/dls", &ext_count);
CHECK(ext, "ext failed to get entries");
uint32_t total = HDD_count + ext_count;
entry_t *e = malloc(total * sizeof(*e));
CHECK(e, "malloc failed");
for(int i = 0; i < HDD_count; i++) {
log_info("HDD[%i].name %s\n", i, HDD[i].name);
e[i].name = strdup(HDD[i].name);
}
// write a function instead of duplicating code?
for (int i = 0; i < ext_count; i++) {
log_info("ext[%i].name %s\n", i, ext[i].name);
e[HDD_count + i].name = strdup(ext[i].name);
}
It looks like a short lived program, but I would still free the values from strdup() and e itself.

C parsing binary through recv

I am Attempting to download a binary file(exe) from a php script. Been stuck for hours.
PHP Script:
header("Content-type: application/octet-stream");
header("Content-Disposition: filename=\"".$path_parts["basename"]."\"");
header("Content-length: $fsize");
header("Cache-control: private"); //use this to open files directly
while(!feof($fd)) {
$buffer = fread($fd, 1048);
echo $buffer;
}
C:
char update[1024] = {0};
FILE *fileo;
fileo = fopen("test.exe", "wb");
instruction = recv(s, update, 1024, 0);
int result =returnBody();//Removes headers
fwrite(body, sizeof(body),1,fileo);
memset(update, 0, 1024);
while ((instruction = recv(s, update, 1024, 0)) > 0)
{
fwrite(update, sizeof(update),1,fileo);
memset(update, 0, 1024);
}
fclose(fileo);
returnbody function:
int returnBody(){
for(int x = 0; x < strlen(message); x++)
{
if(message[x] == '\r')
{
if(message[x + 1] == '\n')
{
if(message[x + 2] == '\r')
{
if(message[x + 3] == '\n')
{
int y = x + 4;
body = (char *)realloc(body, ((strlen(message) - y) * sizeof(char)));
memset(body, 0, sizeof(body));
for(int b = 0; y < strlen(message); y++, b++){
body[b] = message[y];
}
return 1;
}
}
}
}
}
return 0;
}
I succeed in writing the file but it doesn't run. Gets an error, unsupported
16 bit application.
My Question is do I need to parse it as binary before I write it to the file?
As pointed in comments:
you can't use strlen when using binary data
you can't use sizeof when using pointers on array.
Lets see:
/* you should have some static variables to store data */
static void * body = NULL;
size_t body_size = 0;
/* extract body from message */
int returnBody(void *message, size_t message_size){
if (! message || message_size < 5)
{
return 0;
}
/* if your system doesn't have memmem function, see https://stackoverflow.com/a/52989329/1212012 */
void *data = memmem(message, message_size, "\r\n\r\n", 4);
if (data) {
/* header found */
/* data are four bytes after the \r\n\r\n sequence */
data += 4;
size_t header_size = data - message;
body_size = message_size - header_size;
void *p = realloc(body, body_size);
if (!p) {
perror("realloc");
return 0;
}
body = p;
memcpy(body, data, body_size);
return 1;
}
return 0;
}
And your reading writting function should be like:
char update[1024] = {0};
FILE *fileo;
fileo = fopen("test.exe", "wb");
/* you should test `fileo` here */
/* first read */
instruction = recv(s, update, sizeof update, 0);
/* set message and its size for */
int result =returnBody(udpate, instruction);//Removes headers
/* you should test `result` here */
fwrite(body, body_size, 1, fileo);
/* clearing update is not necessary */
/*memset(update, 0, sizeof update); */
while ((instruction = recv(s, update, sizeof update, 0)) > 0)
{
fwrite(update, instruction, 1, fileo);
//memset(update, 0, sizeof update);
}
fclose(fileo);

DNS UDP Socket write() issue

I am trying to send a DNS header and question to a UDP socket. I have already called the following command to establish the connection: socket(PF_INET, SOCK_DGRAM, 0), inet_aton(temp, &servAddr.sin_addr) using port 53, and connect(sock, (const sockaddr*) &servAddr, sizeof(servAddr)).
The problem I am having is writing the message that includes the header and the question of the DNS query. So far, my DNS header struct looks like this:
struct DNS_Header {
uint16_t id;
struct {
uint8_t rd: 1; // recursion desired
uint8_t tc: 1; // message was truncated
uint8_t aa: 1; // authoritative answer
uint8_t opcode: 4; // query type
// 0 a standard query (QUERY); 1 an inverse query (IQUERY);
// 2 a server status request (STATUS);
// 3 - 15 reserved for futre use
uint8_t qr: 1; // query(0) or response (1)
uint8_t rcode: 4; // response code
// 0: No error condition; 1:Format error; 2:Server failure;
// 3: Name Error (authoritative server, name doesn't exist)
// 4: Not implemented; 5: Refused
uint8_t z: 3; // reserved for future use. Must be zero
uint8_t ra: 1; // recursion
} flags;
uint16_t gdcount;
uint16_t ancount;
uint16_t nscount;
uint16_t arcount;
};
I create the DNS query header :
packetHeader.id = htons(1337);
packetHeader.flags.rd = 0;
packetHeader.flags.tc = 0;
packetHeader.flags.aa = 0;
packetHeader.flags.opcode = htons(0);
packetHeader.flags.qr = 0;
packetHeader.flags.rcode = htons(0);
packetHeader.flags.z = htons(0);
packetHeader.flags.ra = 0;
packetHeader.gdcount = htons(1);
packetHeader.ancount = htons(0);
packetHeader.nscount = htons(0);
packetHeader.arcount = htons(0);
I am aware I need to change the hostname to the label/data format for the name portion of DNS question. I have done it this way:
static const char* const hex = "0123456789ABCDEF";
hostname.push_back(' ');
int len = hostname.length();
int segCount = 0;
std::vector<std::string> storage;
std::string temp = "";
for (int i = 0; i < len; i++) {
if (hostname[i] == '.' || hostname[i] == ' ') {
storage.push_back(std::to_string(0));
storage.push_back(std::to_string(segCount));
storage.push_back(temp);
// reset
segCount = 0;
temp = "";
continue;
}
const unsigned char c = hostname[i];
std::cout << c << " : " << hex[c >> 4] << " " << hex[c & 15] << std::endl;
temp.push_back(hex[c >> 4]);
temp.push_back(hex[c & 15]);
segCount ++;
continue;
}
storage.push_back(std::to_string(0));
storage.push_back(std::to_string(0));
for (int i = 0; i < storage.size(); i++) { qname_labelFormat.append(storage[i]); }
std::cout << "The hex representation of qname TOTAL: " << qname_labelFormat << std::endl
I bring everything together for the DNS Query Question using a DNS_Question struct. This struct does not include the DNS Query Question name. I am storing the name in the variable: qname_lableFormat. View the DNS Query Question struct below:
struct DNS_Question {
uint16_t qtype;
uint16_t qclass;
};
To populate the struct DNS_Question, I have done it this way:
int queryTypeNum = 0;
if (queryType == "A") { queryTypeNum = 1; }
if (queryType == "NS") { queryTypeNum = 2; }
if (queryType == "CNAME") { queryTypeNum = 5; }
if (queryType == "SOA") { queryTypeNum = 6; }
if (queryType == "WKS") { queryTypeNum = 11; }
if (queryType == "PTR") { queryTypeNum = 12; }
if (queryType == "MX") { queryTypeNum = 15; }
if (queryType == "SRV") { queryTypeNum = 33; }
if (queryType == "AAAA") { queryTypeNum = 28; }
if (queryType == "") { queryTypeNum = 1; }
packetQuestion.qtype = htons(queryTypeNum);
std::cout << "QType value set to: " << queryTypeNum << std::endl;
packetQuestion.qclass = htons(1);
After I have done all of that, I use the socket write(int fd, const void *buf, size_t count); I believe this is where my error is occurring. No error message is reported but when I call the read(int fd, void *buf, size_t count); command, nothing is being received. My write command is below.
int size = sizeof(struct DNS_Header);
size += sizeof(struct DNS_Question);
char *message [size];
int totalSize = 0;
int stringSize = qname_labelFormat.length() + 1;
char* temp = {0};
temp = (char*)qname_labelFormat.c_str();
std::memcpy(message, (struct DNS_Header*)&packetHeader, sizeof(packetHeader));
totalSize = sizeof(struct DNS_Header);
std::memcpy(message + totalSize, (char*)temp, sizeof(qname_labelFormat));
totalSize += sizeof(qname_labelFormat);
std::memcpy(message + totalSize, (struct DNS_Question*)&packetQuestion, sizeof(packetQuestion));
totalSize += sizeof(packetQuestion);
int bytesSent = 0;
if ((bytesSent = write(sock, message, totalSize)) < 0) {
logger->printLog ("write Failed");
std::string error = strerror(errno);
logger->printLog(error);
}
else {
logger->printLog ("write was successful");
}
If someone is able to help, I would really appreciate it.

UDP Transfer - Implementing CRC-16 [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I'm a complete newbie in C and have an assignment that states I have to implement CRC-16 into a given UDP File Transfer solution. Given code is as follows:
#pragma comment(lib, "ws2_32.lib")
#include "stdafx.h"
#include <winsock2.h>
#include "ws2tcpip.h"
#include <stdio.h>
#define TARGET_IP "10.4.115.122"
//#define TARGET_IP "127.0.0.1"
#define BUFFERS_LEN 1024
#define SIZE_PACKET 10 // we can send up to 9 999 999 999 packets
#define HEADER_LEN (SIZE_PACKET + 5)
#define DATA_LEN (BUFFERS_LEN - HEADER_LEN)
//#define SENDER
#define END {getchar();return 0;}
#define RECEIVER
typedef struct Data
{
int size;
char *data;
}Data;
#ifdef SENDER
#define TARGET_PORT 5005
#define LOCAL_PORT 8888
#endif // SENDER
#ifdef RECEIVER
#define TARGET_PORT 8888
#define LOCAL_PORT 5005
#endif // RECEIVER
void InitWinsock()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
}
void print(char *data, int size)
{
for (int i = 0; i < size; i++)
{
if (data[i] == '\0')
{
printf("\\0");
}
else
{
printf("%c", data[i]);
}
}
printf("\n");
}
void clearBuffer(char *buffer, int size)
{
/* Put NULL character on the array */
for (int i = 0; i < size; i++)
{
buffer[i] = '\0';
}
}
void createHeaderBuffers(char *buffer, int info, int size)
{
// create the array containing the number of the packet and the data length
char temp[HEADER_LEN];
clearBuffer(temp, HEADER_LEN);
sprintf(temp, "%d", info);
int size_temp = strlen(temp);
int begin = size - size_temp;
for (int i = 0; i < size; i++)
{
if (i < begin) // fill the begining of the array with zero
{
buffer[i] = '0';
}
else // add the usefull info at the end e.g : 0000052
{
buffer[i] = temp[i - begin];
}
}
}
int createBuffer( char *buffer, char *data,int numPacket,int dataLength)
{
/* Create the buffer we will send*/
char numPacket_c[SIZE_PACKET+1];
char dataLength_c[5];
clearBuffer(buffer, BUFFERS_LEN);
clearBuffer(numPacket_c, 4);
clearBuffer(dataLength_c, 5);
createHeaderBuffers(numPacket_c, numPacket, SIZE_PACKET); // create the array containing the number of the packet
createHeaderBuffers(dataLength_c, dataLength, 4); // create the array containing the length of the data
for (int i = 0; i < BUFFERS_LEN; i++)
{
char ch;
if (i < SIZE_PACKET) // start by adding the number of the packet byte by byte
{
buffer[i] = numPacket_c[i];
}
else if (i < SIZE_PACKET+4) // then we add the length of the data
{
buffer[i] = dataLength_c[i- SIZE_PACKET];
}
else if (i < HEADER_LEN) // the the flag to say if it(s the end of the file
{
if(dataLength < DATA_LEN -1)
buffer[i] = '1';
else
buffer[i] = '0';
}
else if (i < HEADER_LEN + dataLength) // the the data
{
buffer[i] = data[i - HEADER_LEN];
}
else // fill the rest of the buffer with NULL character
{
buffer[i] = '\0';
}
}
return 0;
}
void copy(char *dest, char *source, int size)
{
/* Copy a buffer in another one byte by byte */
//printf("%s\n", source);
for (int i = 0; i < size; i++)
{
dest[i] = source[i];
//printf("%c\n", source[i]);
}
}
void readFile(char *buffer, int size, char *data, int *numPacket, int *dataLength, int *isEnd)
{
//print(buffer, size);
char isEnd_c[2];
char numPacket_c[SIZE_PACKET + 1];
char dataLength_c[5];
clearBuffer(isEnd_c, 2);
clearBuffer(numPacket_c, SIZE_PACKET + 1);
clearBuffer(dataLength_c, 5);
clearBuffer(data, DATA_LEN + 1);
for (int i = 0; i < size; i++)
{
if (i < SIZE_PACKET) // read the number of the packet
{
numPacket_c[i] = buffer[i];
printf("%c", buffer[i]);
}
else if (i < SIZE_PACKET + 4) // read the length of the data
{
dataLength_c[i - SIZE_PACKET] = buffer[i];
}
else if (i < HEADER_LEN) // read the isEnd FLAG
{
printf("\n%c\n", buffer[i]);
isEnd_c[0] = buffer[i];
}
else // read the data
{
data[i - HEADER_LEN] = buffer[i];
}
}
*numPacket = atoi(numPacket_c);
*isEnd = atoi(isEnd_c);
*dataLength = atoi(dataLength_c);
printf("%d ; %d ; %d\n", *numPacket, *dataLength, *isEnd);
}
unsigned short crc16(const unsigned char* numPacket, unsigned char length) {
unsigned char x;
unsigned short crc = 0xFFFF;
while (length--) {
x = crc >> 8 ^ *numPacket++;
x ^= x >> 4;
crc = (crc << 8) ^ ((unsigned short)(x << 12)) ^ ((unsigned short)(x << 5)) ^ ((unsigned short)x);
}
return crc;
}
//**********************************************************************
int main()
{
SOCKET socketS;
InitWinsock();
struct sockaddr_in local;
struct sockaddr_in from;
int fromlen = sizeof(from);
local.sin_family = AF_INET;
local.sin_port = htons(LOCAL_PORT);
local.sin_addr.s_addr = INADDR_ANY;
socketS = socket(AF_INET, SOCK_DGRAM, 0);
if (bind(socketS, (sockaddr*)&local, sizeof(local)) != 0) {
printf("Binding error!\n");
getchar(); //wait for press Enter
return 1;
}
//**********************************************************************
#ifdef SENDER
FILE *fp, *fp1;
char buffer_tx[BUFFERS_LEN];
int numPacket = 0;
char numberPacket[BUFFERS_LEN];
int isEnd = 0;
char test[100];
char header[HEADER_LEN];
char data[DATA_LEN];
char dataContent[DATA_LEN];
int len;
int num;
char *token;
sockaddr_in addrDest;
addrDest.sin_family = AF_INET;
addrDest.sin_port = htons(TARGET_PORT);
InetPton(AF_INET, _T(TARGET_IP), &addrDest.sin_addr.s_addr);
char *name = "test.jpg";
fp = fopen(name, "rb");
if (fp == NULL)
{
printf("error opening file\n");
}
fseek(fp, 0L, SEEK_END);
int sz = ftell(fp);
rewind(fp);
sz = (int)(sz / DATA_LEN) + 1;
strncpy(buffer_tx, name, BUFFERS_LEN); //put the nam of the file in the buffer
sendto(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send the name of the file
recvfrom(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen); // wait aknowledgment
clearBuffer(buffer_tx, BUFFERS_LEN);
sprintf(buffer_tx, "%d", sz);
sendto(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send size of file
recvfrom(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen); // wait aknowledgment
// This is to be sure that the receiver receive the name and the size correctly in the right order
clearBuffer(buffer_tx, BUFFERS_LEN);
clearBuffer(dataContent, DATA_LEN);
int n = 1;
int dataLength = 0;
while ((n = fread(dataContent, 1, DATA_LEN - 1,fp)) > 0) // read data of the file
{
clearBuffer(buffer_tx, BUFFERS_LEN); // clear the buffer for further utilisation
createBuffer(buffer_tx, dataContent, numPacket++, n); // add the header to the data |numPacket|dataLength|isEnd|data|
sendto(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send the packet
}
fclose(fp);
#endif // SENDER
#ifdef RECEIVER
FILE *fp;
char buffer_rx[BUFFERS_LEN];
Data *data;
int n = 0;
int k;
int how_many = 310;
//strncpy(buffer_rx, "12:1|salut", BUFFERS_LEN);
printf("Waiting for datagram ...\n");
int numPacket = 0;
int isEnd = 0;
int size = 0;
char size_file_c[BUFFERS_LEN];
int size_file = 0;
char header[HEADER_LEN];
char d[DATA_LEN + 1];
char name[BUFFERS_LEN];
char output[30];
char salut[DATA_LEN + 1];
sockaddr_in addrDest;
addrDest.sin_family = AF_INET;
addrDest.sin_port = htons(TARGET_PORT);
InetPton(AF_INET, _T(TARGET_IP), &addrDest.sin_addr.s_addr);
recvfrom(socketS, name, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen); // receiving name of file
sendto(socketS, name, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send aknowledgment
recvfrom(socketS, size_file_c, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen); // receiving size of file
sendto(socketS, size_file_c, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send aknowledgment
size_file = atoi(size_file_c);
// This is to be sure that the receiver receive the name and the size correctly in the right order
data = (Data *)calloc(size_file, sizeof(Data)); // allocate memory for the data
//closesocket(socketS);
//END;
//analyseBuffer(buffer_rx,d, &numPacket, &isEnd);
for (int i = 0; i < size_file; i++)
{
printf("waiting packet\n");
if ((k = recvfrom(socketS, buffer_rx, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen)) == SOCKET_ERROR) // receive a packet
{
printf("error during reception");
getchar();
return -1;
}
else
{
readFile(buffer_rx, BUFFERS_LEN, d, &numPacket, &size, &isEnd); // analyse the pacet to extract the data, the number of the packet, the data lenght and if it's the end
data[numPacket].data = (char*) calloc(size, 1); // allocate only the necessary memory
data[numPacket].size = size;
//print(d, DATA_LEN);
copy(data[numPacket].data, d, data[numPacket].size); // copy only the usefull info (without '\0')
printf("%d ; %d\n", i, size_file);
if (isEnd)
break;
clearBuffer(buffer_rx, BUFFERS_LEN); // clear the buffer for further utilisation
}
}
printf("file name : %s\n", name);
printf("enter the name of new file to be saved\n");
scanf("%s", output); // ask the user to set a file name
fp = fopen(output, "wb");
for (int i = 0; i <size_file; i++)
{
fwrite(data[i].data, data[i].size, 1, fp); // write the data to the file in the right order
}
fclose(fp); // close the file
closesocket(socketS);
#endif // RECEIVER
//**********************************************************************
getchar(); //wait for press Enter
return 0;
}
Notice the CRC-16 function , which is:
unsigned short crc16(const unsigned char* numPacket, unsigned char length) {
unsigned char x;
unsigned short crc = 0xFFFF;
while (length--) {
x = crc >> 8 ^ *numPacket++;
x ^= x >> 4;
crc = (crc << 8) ^ ((unsigned short)(x << 12)) ^ ((unsigned short)(x << 5)) ^ ((unsigned short)x);
}
return crc;
}
My question is : What is the best/easiest way to implement the CRC-16 function I have here? Do I pass a unsigned short crc parameter variable to the createBuffer() function, call the crc16() function inside the createBuffer() function and take the value it returns and assign it to the parameter value and then append it to the buffer?
Or is there a much simpler way to do it that I'm currently not thinking about?
Regarding What is the best/easiest way to implement the CRC-16 function I have here?
First, it appears your CRC-16 function is already implemented. How to use it is illustrated below.
CRC functions are typically used to take a file or buffer of any size as input, and produce a unique value for the purpose of verifying the contents of the file.
Here is a simple example of how I would use this function to read two types of input... (note, bufIn, and buf can be arrays of much larger sizes)
int main(void)
{
unsigned char bufIn[] = {1,45,76,23,245,9,54,55,210,90,23,54,78,14,27,86,34};
char buf[] = {"lkjahsloiwuyhfajsldnaouiyhrqkuhsldajnfdlakdsfa;jsidurfaliu;adjklflkja;sdlkjasdklfauiea;e"};
unsigned short crcOut1, crcOut2;
crcOut1 = crc16(bufIn, sizeof(bufIn)); //for bufIn returns 0x7782
crcOut2 = crc16(buf, sizeof(buf)); //for buf returns 0x98FB
return 0;
}
EDIT to address question in comment...
In your code, one possible way to use this is to call the crc16() function inside your fread while loop:
unsigned short packetCrc;
while ((n = fread(dataContent, 1, DATA_LEN - 1,fp)) > 0) // read data of the file
{
packetCrc = crc16(dataContent, n);
// verify packetCrc value against some expected value perhaps?
clearBuffer(buffer_tx, BUFFERS_LEN); // clear the buffer for further utilisation
createBuffer(buffer_tx, dataContent, numPacket++, n); // add the header to the data |numPacket|dataLength|isEnd|data|
sendto(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send the packet
}

WinDivert issue - redirecting DNS back to self on windows

I was looking at basil00's torwall, and for fun was trying to pare it down to just intercept DNS. (provide an answer back to myself of 127.0.0.1 for webfiltering purposes, learning project)
however, at this point, I have it hijacking the dns packet, but it does not return a correct address. for every "blocked" domain, it's different.
for example, I put cbc.ca in my hosts.deny file (blacklist), and it returns an address of 0.4.114.2
then blacklisting slashdot, it will return 0.4.0.1
this has been quite confusing and frustrating, and after three days of research, I am out of ideas.
Here is the code to the redirect portion of my program, which seems to be where things go awry.
(note some of the comments will be goofy as I was hacking down a program for a different purpose and haven't cleaned it up yet)
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "windivert.h"
#include "domain.h"
#include "main.h"
#include "redirect.h"
#define MAX_PACKET 4096
#define NUM_WORKERS 4
// DNS headers
#define DNS_MAX_NAME 254
struct dnshdr
{
uint16_t id;
uint16_t options;
uint16_t qdcount;
uint16_t ancount;
uint16_t nscount;
uint16_t arcount;
} __attribute__((__packed__));
struct dnsq
{
uint16_t type;
uint16_t class;
} __attribute__((__packed__));
struct dnsa
{
uint16_t name;
uint16_t type;
uint16_t class;
uint32_t ttl;
uint16_t length;
uint32_t addr;
} __attribute__((__packed__));
static DWORD redirect_worker(LPVOID arg);
static int handle_dns(HANDLE handle, PWINDIVERT_ADDRESS addr,
PWINDIVERT_IPHDR iphdr, PWINDIVERT_UDPHDR udphdr, char *data,
size_t data_len);
// State:
static bool redirect_on = false;
static HANDLE handle = INVALID_HANDLE_VALUE;
static HANDLE workers[NUM_WORKERS] = {NULL}; // Worker threads
// Send a packet asynchronously:
static void send_packet(HANDLE handle, void *packet, size_t packet_len,
PWINDIVERT_ADDRESS addr)
{
addr->Direction = WINDIVERT_DIRECTION_INBOUND;
WinDivertHelperCalcChecksums(packet, packet_len, 0);
if (!WinDivertSend(handle, packet, packet_len, addr, NULL))
debug("Send packet failed (err=%d)\n", (int)GetLastError());
}
// Start traffic redirect through Tor:
extern void redirect_start(void)
{
debug("DNS divert START\n");
if (handle != INVALID_HANDLE_VALUE)
return;
handle = WinDivertOpen(
"outbound and udp.DstPort == 53 or inbound and udp.DstPort = 53", 0, 0, 0);
// Launch threads:
redirect_on = true;
for (size_t i = 0; i < NUM_WORKERS; i++)
{
workers[i] = CreateThread(NULL, MAX_PACKET*3,
(LPTHREAD_START_ROUTINE)redirect_worker, (LPVOID)handle, 0, NULL);
if (workers[i] == NULL)
{
exit(EXIT_FAILURE);
}
}
}
// Stop traffic redirect through Tor:
extern void redirect_stop(void)
{
debug("DNS divert STOP\n");
if (handle == INVALID_HANDLE_VALUE)
return;
// Close the WinDivert handle; will cause the workers to exit.
redirect_on = false;
if (!WinDivertClose(handle))
{
exit(EXIT_FAILURE);
}
handle = INVALID_HANDLE_VALUE;
for (size_t i = 0; i < NUM_WORKERS; i++)
{
WaitForSingleObject(workers[i], INFINITE);
workers[i] = NULL;
}
}
// Redirect worker thread:
static DWORD redirect_worker(LPVOID arg)
{
HANDLE handle = (HANDLE)arg;
// Packet processing loop:
char packet[MAX_PACKET];
UINT packet_len;
WINDIVERT_ADDRESS addr;
while (redirect_on)
{
if (!WinDivertRecv(handle, packet, sizeof(packet), &addr, &packet_len))
{
// Silently ignore any error.
continue;
}
PWINDIVERT_IPHDR iphdr = NULL;
PWINDIVERT_TCPHDR tcphdr = NULL;
PWINDIVERT_UDPHDR udphdr = NULL;
PVOID data = NULL;
UINT data_len;
WinDivertHelperParsePacket(packet, packet_len, &iphdr, NULL, NULL,
NULL, &tcphdr, &udphdr, &data, &data_len);
int dnshandle = 0;
if (udphdr != NULL && ntohs(udphdr->DstPort) == 53)
dnshandle = handle_dns(handle, &addr, iphdr, udphdr, data, data_len);
if(dnshandle != 1)
{
if (!WinDivertSend(handle, packet, packet_len, &addr, NULL))
{
}
}
}
return 0;
}
// Handle DNS requests.
// NOTES:
// - If anything goes wrong, we simply drop the packet without error.
// - An alternative approach would be to let Tor resolve the address, however,
// this would be slow.
static int handle_dns(HANDLE handle, PWINDIVERT_ADDRESS addr,
PWINDIVERT_IPHDR iphdr, PWINDIVERT_UDPHDR udphdr, char *data,
size_t data_len)
{
struct dnshdr *dnshdr = (struct dnshdr *)data;
data += sizeof(struct dnshdr);
data_len -= sizeof(struct dnshdr);
char name[DNS_MAX_NAME + 8]; // 8 bytes extra.
size_t i = 0;
while (i < data_len && data[i] != 0)
{
size_t len = data[i];
if (i + len >= DNS_MAX_NAME)
return -1;
name[i++] = '.';
for (size_t j = 0; j < len; j++, i++)
name[i] = data[i];
}
name[i++] = '\0';
// Generate a fake IP address and associate it with this domain name:
uint32_t fake_addr = domain_lookup_addr(name);
if (fake_addr == 0)
{
// This domain is blocked; so ignore the request.
// Construct a query response:
size_t len = sizeof(struct dnshdr) + data_len + sizeof(struct dnsa);
if (len > 512) // Max DNS packet size.
return -1;
len += sizeof(WINDIVERT_IPHDR) + sizeof(WINDIVERT_UDPHDR) + len;
char buf[len + 8]; // 8 bytes extra.
PWINDIVERT_IPHDR riphdr = (PWINDIVERT_IPHDR)buf;
PWINDIVERT_UDPHDR rudphdr = (PWINDIVERT_UDPHDR)(riphdr + 1);
struct dnshdr *rdnshdr = (struct dnshdr *)(rudphdr + 1);
char *rdata = (char *)(rdnshdr + 1);
UINT local_ip;
DivertHelperParseIPv4Address("127.0.0.1",&local_ip);
memset(riphdr, 0, sizeof(WINDIVERT_IPHDR));
riphdr->Version = 4;
riphdr->HdrLength = sizeof(WINDIVERT_IPHDR) / sizeof(uint32_t);
riphdr->Length = htons(len);
riphdr->Id = htons(0xF00D);
WINDIVERT_IPHDR_SET_DF(riphdr, 1);
riphdr->TTL = 64;
riphdr->Protocol = IPPROTO_UDP;
riphdr->SrcAddr = iphdr->DstAddr;
riphdr->DstAddr = iphdr->SrcAddr;
memset(rudphdr, 0, sizeof(WINDIVERT_UDPHDR));
rudphdr->SrcPort = htons(53); // DNS
rudphdr->DstPort = udphdr->SrcPort;
rudphdr->Length = htons(len - sizeof(WINDIVERT_IPHDR));
rdnshdr->id = dnshdr->id;
rdnshdr->options = htons(0x8180); // Standard DNS response.
rdnshdr->qdcount = htons(0x0001);
rdnshdr->ancount = htons(0x0001);
rdnshdr->nscount = 0;
rdnshdr->arcount = 0;
memcpy(rdata, data, data_len);
struct dnsa *rdnsa = (struct dnsa *)(rdata + data_len);
rdnsa->name = htons(0xC00C);
rdnsa->type = htons(0x0001); // (A)
rdnsa->class = htons(0x0001); // (IN)
rdnsa->ttl = htonl(0x00000258) ; // 1 second
rdnsa->length = htons(0x0004);
rdnsa->addr = htonl(local_ip); // Fake address
send_packet(handle, &buf, len, addr);
debug("address: %u\n",addr->Direction);
debug("Intercept DNS %s\n", (name[0] == '.'? name+1: name));
return 1;
}
// Re-inject the matching packet.
/*
/
*/
return 0;
}
Here's the domain lookup side of it (mostly just hacked down to try to get the results I want:
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include "domain.h"
#include "main.h"
#define RATE_LIMIT 8000
#define rand16() \
(rand() & 0xFF) | ((rand() & 0xFF) << 8)
// Domain blacklist:
struct blacklist
{
size_t size;
size_t len;
char **names;
};
static struct blacklist *blacklist = NULL;
// State:
static struct name *names[UINT16_MAX] = {NULL};
static HANDLE names_lock = NULL;
// Prototypes:
static struct blacklist *domain_blacklist_read(const char *filename);
static bool domain_blacklist_lookup(struct blacklist *blacklist,
const char *name);
static int __cdecl domain_blacklist_compare_0(const void *x, const void *y);
static int domain_blacklist_compare(const char *name0, size_t len,
const char *name1);
// Initialize this module:
extern void domain_init(void)
{
// Load the domain blacklist.
blacklist = domain_blacklist_read("hosts.deny");
}
// Lookup an address given a domain name. If the name does not exist then
// create one.
extern uint32_t domain_lookup_addr(const char *name0)
{
if (name0[0] == '.')
name0++;
if (domain_blacklist_lookup(blacklist, name0))
{
debug("Block %s\n", name0);
return 0; // Blocked!
}
return;
}
// Read the blacklist file:
static struct blacklist *domain_blacklist_read(const char *filename)
{
struct blacklist *blacklist =
(struct blacklist *)malloc(sizeof(struct blacklist));
if (blacklist == NULL)
{
exit(EXIT_FAILURE);
}
blacklist->size = 0;
blacklist->len = 0;
blacklist->names = NULL;
FILE *stream = fopen(filename, "r");
if (stream == NULL)
{
return blacklist;
}
// Read blocked domains:
int c;
char buf[256];
while (true)
{
while (isspace(c = getc(stream)))
;
if (c == EOF)
break;
if (c == '#')
{
while ((c = getc(stream)) != '\n' && c != EOF)
;
continue;
}
size_t i = 0;
while (i < sizeof(buf)-1 && (c == '-' || c == '.' || isalnum(c)))
{
buf[i++] = c;
c = getc(stream);
}
if (i >= sizeof(buf)-1 || !isspace(c))
{
exit(EXIT_FAILURE);
}
buf[i] = '\0';
if (blacklist->len >= blacklist->size)
{
blacklist->size = (blacklist->size == 0? 32: 2 * blacklist->size);
blacklist->names = (char **)realloc(blacklist->names,
blacklist->size * sizeof(char *));
if (blacklist->names == NULL)
{
exit(EXIT_FAILURE);
}
}
size_t size = (i+1) * sizeof(char);
char *name = (char *)malloc(size);
if (name == NULL)
{
exit(EXIT_FAILURE);
}
for (size_t j = 0; j < i; j++)
name[j] = buf[i - 1 - j];
name[i] = '\0';
blacklist->names[blacklist->len++] = name;
}
fclose(stream);
qsort(blacklist->names, blacklist->len, sizeof(char *),
domain_blacklist_compare_0);
return blacklist;
}
// Check if a domain matches the blacklist or not:
static bool domain_blacklist_lookup(struct blacklist *blacklist,
const char *name)
{
if (blacklist->len == 0)
return false;
size_t len = strlen(name);
ssize_t lo = 0, hi = blacklist->len-1;
while (lo <= hi)
{
ssize_t mid = (lo + hi) / 2;
int cmp = domain_blacklist_compare(name, len, blacklist->names[mid]);
if (cmp > 0)
hi = mid-1;
else if (cmp < 0)
lo = mid+1;
else
return true;
}
return false;
}
// Domain compare function(s):
static int __cdecl domain_blacklist_compare_0(const void *x, const void *y)
{
const char *name0 = *(const char **)x;
const char *name1 = *(const char **)y;
return strcmp(name0, name1);
}
static int domain_blacklist_compare(const char *name0, size_t len,
const char *name1)
{
size_t i = 0;
ssize_t j = (ssize_t)len - 1;
for (; j >= 0 && name1[i] != '\0'; i++, j--)
{
int cmp = (int)name1[i] - (int)name0[j];
if (cmp != 0)
return cmp;
}
if (j < 0 && name1[i] != '\0')
return 1;
return 0;
}
any assistance is appreciated.
Also, I have uploaded the code to: Github
Thank you.
There's one of two things going on here. You're reading and writing DNS packets incorrectly, and or you're failing to convert the addresses to or from host to network order before working with them.
I'm going to bet on you reading and writing DNS packets incorrectly. I've implemented my own filtering systems using WinDivert where I was hijacking and passing all DNS traffic through my own local DNS server and I've seen these fudged addresses come out exactly as the results you're getting when I was parsing and writing DNS packets incorrectly.
The bad news is, I can't point you to a full DNS library in C/C++ as I know of none that actually make the job easier (maybe, see edits). I personally had my diversion code written in C++ with WinDivert and then use Arsoft.Tools.Net C# DNS library for actually running a local DNS server and manipulating DNS responses.
There is one project in C++ that calls itself boost::net::dns because I think the writer was hoping it would be part of boost, which it isn't and probably won't be. Avoid this library as the internal mechanism for parsing and storing multiple A Records is bugged out and broken and you'll get the same wacky results you're getting here. I tried to work with him to get it fixed but, he was only interested in blaming my code.
I'll have a gander again and update my answer if I can find a decent lib for working with DNS packets in C++. Don't try to do it yourself, we're talking about entire protocols with entire books of RFC's to do this properly yourself.
Update
As promised, here are some results from my search:
Mozilla Necko (Formerly Netlib)
http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/
C-Ares:
https://github.com/bagder/c-ares
A list of alternative libraries C-Ares compiled:
http://c-ares.haxx.se/otherlibs.html
Also, it is linux specific but pretty clean code. You might be able to pilfer through libcrafter's DNS classes and move them to your own project.
https://github.com/pellegre/libcrafter/blob/master/libcrafter/crafter/Protocols/DNS.h
Again, unless your "learning project" is understanding and recreating one of the foundational pillars of the internet, don't implement this yourself. Try and use one of the previously listed libraries to handle your DNS packets.

Resources