Related
I am very new to coding and I'm trying to learn how a compiler thinks.
Anyway, I wrote this code for school where the code is supposed to gather random data from an input.txt file, sort by insertion and then write the sorted version to an output.txt file. Also, the data needs to be 64-bits. I have two problems with the code. One is that during the function that writes it says '.exe has triggered a break point'. I don't understand why this is.
The second is that it says I haven't defined the variable key, even though I think I did. Below is my code. Any help would be appreciated as I'm very new to this.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
typedef uint64_t u64;
struct file_contents
{
u64 *Data;
u64 Size;
};
file_contents
ReadFile(const char* FileName)
{
file_contents Contents = {};
FILE* File = fopen(FileName, "rb");
if (File)
{
fseek(File, 0, SEEK_END);
Contents.Size = ftell(File);
fseek(File, 0, SEEK_SET);
Contents.Data = (u64*)malloc(Contents.Size);
if (Contents.Data)
{
fread(Contents.Data, 1, Contents.Size, File);
}
fclose(File);
}
return Contents;
}
u64*
SortFile(file_contents Contents)
{
u64 key;
for (int i = 1; i < 100; ++i)
{
Contents.Data[i] = key;
int j;
j = i - 1;
while (i >= 0 && Contents.Data[j] > key)
{
j = j - 1;
key = Contents.Data[j + 1];
}
}
return Contents.Data;
}
void
WriteFile(const char* FileName, file_contents Contents)
{
FILE* File = fopen(FileName, "w");
if (File)
{
if (Contents.Data)
{
fwrite(Contents.Data, 1, Contents.Size, File);
}
fclose(File);
}
}
void
CloseFile(file_contents Contents)
{
if (Contents.Data)
{
free(Contents.Data);
Contents.Data = 0;
Contents.Size = 0;
}
}
void
WriteSortedFile(const char* InputFileName, const char* OutputFileName)
{
file_contents File = ReadFile(InputFileName);
SortFile(File);
WriteFile(OutputFileName, File);
CloseFile(File);
}
int main()
{
file_contents Contents = ReadFile("input.txt");
WriteSortedFile("input.txt", "output.txt");
}
I submitted this problem set, but I'm unable to get a full mark grade because the exit code "is expected to be 0 and not a 1". However, if you take a look at the code (the recover.c file), the exit code is 0. What is wrong? The program accomplishes everything it was made for, which is to read through bits in a corrupted file and find the bits that make up a JPG file and write them in a separate file. The only problem I'm having is this aforementioned exit code issue. Please help!
recover.c file
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
#include "bmp.h"
int main (void){
FILE* card_ptr = fopen("card.raw","r");
if (card_ptr == NULL){
fprintf(stderr,"File Not Found!");
return 1;
}
BYTE buffer[512];
bool found_jpg = false;
FILE* new_jpg_ptr;
int file_counter = 0;
while(fread(buffer,1,512,card_ptr)!=0x00){
if(buffer[0]== 0xff && buffer[1]== 0xd8 && buffer[2]==0xff && (buffer[3] & 0xf0)== 0xe0){
if(!found_jpg){
char filename[8];
sprintf(filename, "%03i.jpg", file_counter++);
found_jpg = true;
new_jpg_ptr = fopen(filename,"w");
if(new_jpg_ptr == NULL){
return 2;
}
fwrite(buffer,1,512,new_jpg_ptr);
}
else {
fclose(new_jpg_ptr);
char filename[8];
sprintf(filename, "%03i.jpg", file_counter++);
found_jpg = true;
new_jpg_ptr = fopen(filename,"w");
if(new_jpg_ptr == NULL){
return 3;
}
fwrite(buffer,1,512, new_jpg_ptr);
}
}
else {
if(found_jpg){
fwrite(buffer,1,512, new_jpg_ptr);
}
}
}
fclose(new_jpg_ptr);
fclose(card_ptr);
return 0;
}
bmp.h file
/**
* BMP-related data types based on Microsoft's own.
*/
#include <stdint.h>
/**
* Common Data Types
*
* The data types in this section are essentially aliases for C/C++
* primitive data types.
*
* Adapted from https://msdn.microsoft.com/en-us/library/cc230309.aspx.
* See http://en.wikipedia.org/wiki/Stdint.h for more on stdint.h.
*/
typedef uint8_t BYTE;
typedef uint32_t DWORD;
typedef int32_t LONG;
typedef uint16_t WORD;
/**
* BITMAPFILEHEADER
*
* The BITMAPFILEHEADER structure contains information about the type, size,
* and layout of a file that contains a DIB [device-independent bitmap].
*
* Adapted from https://msdn.microsoft.com/en-us/library/dd183374(v=vs.85).aspx.
*/
typedef struct
{
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} __attribute__((__packed__))
BITMAPFILEHEADER;
/**
* BITMAPINFOHEADER
*
* The BITMAPINFOHEADER structure contains information about the
* dimensions and color format of a DIB [device-independent bitmap].
*
* Adapted from https://msdn.microsoft.com/en-us/library/dd183376(v=vs.85).aspx.
*/
typedef struct
{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} __attribute__((__packed__))
BITMAPINFOHEADER;
/**
* RGBTRIPLE
*
* This structure describes a color consisting of relative intensities of
* red, green, and blue.
*
* Adapted from https://msdn.microsoft.com/en-us/library/dd162939(v=vs.85).aspx.
*/
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
I experienced the same problem. My program worked as expected with no obvious reasons for a return code of 1. As you have, I had also included a header file with some definitions in it. Placing those definitions in the core file solved my problem. Perhaps if you move the needed definitions from your bmp.h file into recover.c, check50 will be able to compile.
My solution if you're interested.
// Recover any forgotten JPEGS from a given forensic image
# include <stdio.h>
# include <stdbool.h>
# include <stdint.h>
typedef uint8_t BYTE;
typedef struct
{
BYTE byte_1;
BYTE byte_2;
BYTE byte_3;
BYTE byte_4_min;
BYTE byte_4_max;
} __attribute__((__packed__))
SIG;
// declare helper function prototypes
int check_args(int argc, char *argv[]);
bool signature_is_present(BYTE potential_sig[4], SIG jpeg_sig);
SIG set_jpeg_signature(void);
// main program
int main (int argc, char *argv[])
{
// check input for validity
int check_args_value = check_args(argc, argv);
if (check_args_value != 0)
{
return check_args_value;
}
// call function to set default jpeg signature
SIG jpeg_sig = set_jpeg_signature();
// open buffers and declare other necessary variables for later use
BYTE FAT_block[512];
BYTE first_byte[1];
int signature_offset = -4;
int counter = 0;
// open forensic image
FILE * inptr = fopen(argv[1], "r");
FILE * outptr = NULL;
// loop through file searching for first '255'
while (fread(first_byte, sizeof(BYTE), 1, inptr) == 1)
{
// check if byte is 255, the first byte of a jpeg signature
if (*first_byte == jpeg_sig.byte_1)
{
// check for signature
BYTE possible_sig[4];
// back pointer up one byte to compensate for already discovered 255
fseek(inptr, -1, SEEK_CUR);
// read four bytes from file that could potentially be a signature.
fread(possible_sig, sizeof(possible_sig), 1, inptr);
if (signature_is_present(possible_sig, jpeg_sig))
{
// close previously open write file, if any.
if (outptr != NULL)
{
fclose(outptr);
//Increment counter for image signatures found.
counter++;
}
// setup name for image file
char file_name[8] = {};
snprintf(file_name, 8, "%.3i.jpg\n", counter);
// move pointer back 4 bytes after checking what they contain
fseek(inptr, signature_offset, SEEK_CUR);
//read FAT block from forensic image into buffer
fread(FAT_block, sizeof(FAT_block), 1, inptr);
// open new output file based on current signature
outptr = fopen(file_name, "w");
// write FAT block buffer to file
fwrite(FAT_block, sizeof(FAT_block), 1, outptr);
}
else // byte is 255 but not part of a signature
{
if (outptr != NULL)
{
// move pointer back 4 bytes after checking what they contain
fseek(inptr, signature_offset, SEEK_CUR);
//read FAT block from forensic image into buffer
fread(FAT_block, sizeof(FAT_block), 1, inptr);
// write FAT block buffer to file
fwrite(FAT_block, sizeof(FAT_block), 1, outptr);
}
}
}
else // if byte is not 255
{
if (outptr != NULL)
{
//back up one byte
fseek(inptr, -1, SEEK_CUR);
//read FAT block from forensic image into buffer
fread(FAT_block, sizeof(FAT_block), 1, inptr);
// write FAT block buffer to file
fwrite(FAT_block, sizeof(FAT_block), 1, outptr);
}
}
}
// close files
fclose(inptr);
if (outptr != NULL)
{
fclose(outptr);
}
return 0;
}
// helper functions
int check_args(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Invalid Input.\nForensic image file must be provided.\n");
return 1;
}
FILE *inptr = fopen(argv[1], "r");
if (inptr == NULL)
{
fprintf(stderr, "File does not exist.\n");
return 2;
}
fclose(inptr);
return 0;
}
bool signature_is_present(BYTE potential_sig[4], SIG jpeg_sig)
{
if( potential_sig[0] == jpeg_sig.byte_1 &&
potential_sig[1] == jpeg_sig.byte_2 &&
potential_sig[2] == jpeg_sig.byte_3 &&
potential_sig[3] >= jpeg_sig.byte_4_min &&
potential_sig[3] <= jpeg_sig.byte_4_max )
{
return true;
}
return false;
}
SIG set_jpeg_signature(void)
{
SIG jpeg_sig;
jpeg_sig.byte_1 = 255;
jpeg_sig.byte_2 = 216;
jpeg_sig.byte_3 = 255;
jpeg_sig.byte_4_min = 224;
jpeg_sig.byte_4_max = 239;
return jpeg_sig;
}
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.
I have a kernel module creating an entry in proc-fs and a userspace-program that reads the file.
My proc read-function looks like:
typedef struct {
int integer;
unsigned long ulong;
char string[100];
float floatt;
bool booll;
u16 crc;
} struktur;
static int round = 0, len = 0, temp = 0, err;
struktur *pde_data_p;
int proc_read(struct file *filp, char *buf, size_t count, loff_t *offp) {
int i;
unsigned char *crcbuf;
struktur struct_buf;
pde_data_p = PDE_DATA(file_inode(filp));
crcbuf = (unsigned char*)pde_data_p;
memcpy(&struct_buf, pde_data_p, sizeof(struktur));
if (pde_data_p == NULL) {
printk(KERN_ERR "pde->data == NULL\n");
round = 0;
return 0;
}
if (round == 0)
temp = sizeof(struktur);
if (count > temp)
count = temp;
struct_buf.crc = crc16(struct_buf.crc, crcbuf, sizeof(struktur)-sizeof(unsigned short));
err = copy_to_user(buf, pde_data_p, count);
//if (err == 0) { // copy_to_user finished
round = 0;
temp = 0; // taking this line out makes it work in the prog but not with my cat
return temp;
//} else { // copy_to_user failed -> return number of bytes that have not been copied
//temp = err;
//round++;
//return temp;
//}
}
My program code is:
typedef struct {
int integer;
unsigned long ulong;
char string[100];
float floatt;
bool booll;
unsigned short crc;
} struktur;
int main(void) {
int i;
struktur str_inp;
unsigned short crc = 0;
unsigned char *str_p = (unsigned char*)&str_inp;
FILE *fp = fopen("/proc/sen/entry", "r");
fread(&str_inp, 1, sizeof(struktur), fp);
fclose(fp);
}
As you can see my proc read-function returns the number of bytes read, not zero.
This way my program works fine but when I try to read via cat (cat /proc/sen/entry) it never finishes because it never returns 0.
When I change my code and return 0 after copy_to_user has finished, reading via cat works fine but my program seems reads random memory. When I return half of the number of copied bytes, just half of the data read by the user-space program is correct.
What has to be returned by your proc_read function depends on the position which is handed over in *offp. If it is only required to work for your given userspace program code and for cat (not for partial reads of struktur) it suffices to
if (*offp) return 0; // no more data to return
else *offp = sizeof (struktur); // file position after data returned
- this statement goes before the copy_to_user().
I have written a piece of code that attempts to search a directory and its subfolders for two AIFF files and using the LibAIFF library to import and then perform some processing operations on them.
Part 1: Searching the directory for the files
For this part of the program, I need to look for the files (which can be thought of as identical AIFF files except for a difference in their filenames) with known names (for example SineSweepA.aiff and SineSweepB.aiff) and then construct the absolute path to it (the length of which I am unaware of (since my program needs to work on different computers where the AIFFs can be located within different subfolders within a MainDirectory - see code below) but know will be less than 200 characters in length). I am able to do this successfully and consistently using the following piece of code:
void file_search(char* parentDir, char* subFolder, char* filenamePrefix, char* tempString, char* tempFilepath, int* foundFlag, int* level);
int32_t *import_sweeps(char* sweepFilepath, uint64_t* numSamples, int* numChannels, double* samplingRate, int* bitDepth, int* segmentSize, int* importFlag);
int main()
{
...
char MainDirectory[200] = "/Users/rrr/Documents/Foldername1/";
char tempFilepath[200], tempFilepathR[200], parentDir[200], filenamePrefix[200], subFolder[200], tempString[200];
int level = 0, foundFlag = 0;
int numChannels = 0;
int bitDepth;
int segmentSize;
int importFlag = 0;
int32_t *sweepRfile = NULL;
uint64_t numSamples = 0, numSamplesR = 0;
unsigned long templen;
double samplingRate = 0.0;
char *sweepFilepath = NULL, *sweepFilepathR = NULL; // Allocated to specific size later
strcpy(parentDir, MainDirectory);
strcat(parentDir, "SubFolderName1/");
strcpy(tempFilepathR, parentDir);
strcpy(filenamePrefix, "KnownFilenamePrefix1");
// file_search() searches for a specific file with a known name and constructs the absolute path to the file and stores it in tempFilepathR. The function is shown further below.
file_search(parentDir, subFolder, filenamePrefix, tempString, tempFilepath, &foundFlag, &level);
if (foundFlag)
{
sprintf(tempFilepath, "%s%s/KnownFilenamePrefix1%s.aiff", parentDir, subFolder, subFolder);
sprintf(tempFilepathR, "%s%s/KnownFilenamePrefix2%s.aiff", parentDir, subFolder, subFolder);
}
...
(to be continued in Part 2 of my question below)
}
void file_search(char* dir, char* subfolder, char* fileprefix, char* filename, char* filepath, int*flag, int* level)
{
DIR *dp;
struct dirent *entry; // entry is a pointer to the structure "dirent" defined in <dirent.h>
struct stat statbuf; // the structure "stat" is defined in <stat.h>
if((dp = opendir(dir)) == NULL) {
fprintf(stderr,"Cannot open directory: %s\n", dir);
return;
}
chdir(dir); // this sets the working directory to the string pointed to by "dir"
while((entry = readdir(dp)) != NULL)
{
lstat(entry->d_name, &statbuf);
if(S_ISDIR(statbuf.st_mode)) // Tests for a directory
{
// Found a directory
if(strcmp(".",entry->d_name) == 0 || strcmp("..",entry->d_name) == 0)
{
// Ignore . and ..
continue;
}
if(level[0] < 1)
{
// Proceed down one level and search again
strcpy(subfolder,entry->d_name);
level[0] = level[0] + 1;
// Recursive function call
file_search(entry->d_name, subfolder, fileprefix, filename, filepath, postfilepath, flag, level);
level[0] = level[0] - 1;
if(flag[0] == 1)
{
// Exit loop if a file was found at a lower level
break;
}
}
}
else
{
sprintf(filename, "%s%s.aiff", fileprefix, subfolder);
if(strcmp(entry->d_name,filename) == 0)
{
// File found. Construct absolute path to file
sprintf(filepath, "%s%s/%s", filepath, subfolder, filename); // Pass filepath outside
flag[0] = 1; //Appropriate file found
break;
}
}
}
chdir("..");
closedir(dp);
}
So by using the above code, I am able to successfully search for two AIFF files with given filenames by searching through subfolders with a known MainDirectory, construct their absolute paths and store them in tempFilepath and tempFilepathR. The next step is to import these two files and this is where I run into a problem.
Part 2: Importing the files
The problem I run into is as follows: I implemented the LibAIFF library to import the files. The issue is that if I run the program, say N times, then on some of the runs, the first file gets imported but not the second, on other runs the second gets imported but not the first (note that if the first doesn't get imported, the program stops). Before I explain the error, please know that there is no issue with the AIFF files, for the sake of this problem you can assume they are identical and that even their absolute paths and filenames are identical except one has a suffix A.aiff and the other B.aiff. These file paths are stored as strings in identically defined variables (tempFilepath and tempFilepathR).
Here is the rest of the necessary part of my code continued from above
int main()
{
// Continued from above
...
// Copy over exact file paths (I had to do this because the function AIFF_OpenFile which is part of the LibAIFF library and shown below refused to accept a statically allocated char variable such as tempFilepath)
templen = strlen(tempFilepathR); // tempFilepath and tempFilepathR always have the same length
sweepFilepath = malloc(templen + 1);
strcpy(sweepFilepath, tempFilepath);
// Proceed to import the FIRST AIFF (returned to sweepRfile from import_sweeps())
sweepRfile = import_sweeps(sweepFilepath, &numSamples, &numChannels, &samplingRate, &bitDepth, &segmentSize, &importFlag);
if (importFlag) // The import was successful
{
free(sweepFilepath);
// Do some processing with the successfully imported AIFF
free(sweepRfile);
}
else // The import was unsuccessful and sweepRfile (which is usually malloc'ed in the import_sweeps() function is not malloc'ed
{
free(sweepFilepath);
}
// Now for the SECOND AIFF (I can overwrite a lot of the variables used for the first AIFF because I don't need them)
sweepFilepathR = malloc(templen + 1); // templen is assigned above
strcpy(sweepFilepathR, tempFilepathR);
// Proceed to import the SECOND AIFF (returned to sweepRfile from import_sweeps())
sweepRfile = import_sweeps(sweepFilepathR, &numSamplesR, &numChannels, &samplingRate, &bitDepth, &segmentSize, &importFlag);
if (importFlag) // The import was successful
{
free(sweepFilepathR);
// Do some processing with the successfully imported AIFF
free(sweepRfile);
}
else // The import was unsuccessful and sweepRfile (which is usually malloc'ed in the import_sweeps() function is not malloc'ed
{
free(sweepFilepathR);
}
...
// Rest of code in main is irrelevant because it doesn't even get there.
}
The break always occurs within the import_sweeps() function (sometimes for the first AIFF and sometimes for the second). The function is shown below
int32_t *import_sweeps(char* sweepFilepath, uint64_t* numSamples, int* numChannels, double* samplingRate, int* bitDepth, int* segmentSize, int* importFlag)
{
// Initialize files for importing */
AIFF_Ref fileref;
// Import Routine */
fileref = AIFF_OpenFile(sweepFilepath, F_RDONLY);
if(fileref)
{
// File opened successfully. Proceed to intialize files for getting information about AIFF file
uint64_t nSamples;
int nSamplePts, channels, bitsPerSample, segSize, temp;
double smpr;
// Get AIFF file format details
temp = AIFF_GetAudioFormat(fileref, &nSamples, &channels, &smpr, &bitsPerSample, &segSize);
if (temp < 1) {
fprintf(stderr,"Error getting audio format.\n");
AIFF_CloseFile(fileref);
return (int32_t) 0;
}
else
{
numSamples[0] = nSamples;
samplingRate[0] = smpr;
numChannels[0] = channels;
bitDepth[0] = bitsPerSample;
segmentSize[0] = segSize;
nSamplePts = ((int) nSamples)*channels;
int32_t *samples = malloc((nSamplePts+1) * sizeof(int32_t));
// Read AIFF
temp = AIFF_ReadSamples32Bit(fileref, samples, nSamplePts);
if (temp != -1)
{
AIFF_CloseFile(fileref);
importFlag[0] = 1;
return samples;
}
else
{
fprintf(stderr,"Unable to read AIFF.\n");
AIFF_CloseFile(fileref);
return (int32_t) 0;
}
}
}
else
{
fprintf(stderr,"Unable to open AIFF file.\n");
}
return (int32_t) 0;
}
Inside import_sweeps() above, the AIFF file is ALWAYS successfully read by calling the function AIFF_ReadSamples32Bit(fileref, samples, nSamplePts);. Therefore, the temp value is never -1. Whenever an error (as described above and I will give the actual error message below) happens, it ALWAYS occurs when it tries to call AIFF_CloseFile(fileref);.
Shown below are the functions AIFF_ReadSamples32Bit and AIFF_CloseFile as defined in the LibAIFF library.
int AIFF_ReadSamples32Bit(AIFF_Ref r, int32_t * samples, int nSamplePoints)
{
int n = nSamplePoints;
void *buffer;
int i, j;
size_t h;
size_t len;
int segmentSize;
int32_t *dwords;
int16_t *words;
int8_t *sbytes;
uint8_t *inbytes;
uint8_t *outbytes;
uint8_t x, y, z;
if (!r || !(r->flags & F_RDONLY))
return -1;
if (n % (r->nChannels) != 0)
return 0;
if (n < 1 || r->segmentSize == 0) {
if (r->buffer) {
free(r->buffer);
r->buffer = NULL;
r->buflen = 0;
}
return -1;
}
segmentSize = r->segmentSize;
len = (size_t) n * segmentSize;
if ((r->buflen) < len) {
if (r->buffer)
free(r->buffer);
r->buffer = malloc(len);
if (!(r->buffer)) {
return -1;
}
r->buflen = len;
}
buffer = r->buffer;
h = AIFF_ReadSamples(r, buffer, len);
if (h < (size_t) segmentSize) {
free(r->buffer);
r->buffer = NULL;
r->buflen = 0;
return 0;
}
n = (int) h;
if (n % segmentSize != 0) {
free(r->buffer);
r->buffer = NULL;
r->buflen = 0;
return -1;
}
n /= segmentSize;
switch (segmentSize) {
case 4:
dwords = (int32_t *) buffer;
for (i = 0; i < n; ++i)
samples[i] = dwords[i];
break;
case 3:
inbytes = (uint8_t *) buffer;
outbytes = (uint8_t *) samples;
n <<= 2; /* n *= 4 */
j = 0;
for (i = 0; i < n; i += 4) {
x = inbytes[j++];
y = inbytes[j++];
z = inbytes[j++];
#ifdef WORDS_BIGENDIAN
outbytes[i] = x;
outbytes[i + 1] = y;
outbytes[i + 2] = z;
outbytes[i + 3] = 0;
#else
outbytes[i] = 0;
outbytes[i + 1] = x;
outbytes[i + 2] = y;
outbytes[i + 3] = z;
#endif
}
n >>= 2;
break;
case 2:
words = (int16_t *) buffer;
for (i = 0; i < n; ++i) {
samples[i] = (int32_t) (words[i]) << 16;
}
break;
case 1:
sbytes = (int8_t *) buffer;
for (i = 0; i < n; ++i) {
samples[i] = (int32_t) (sbytes[i]) << 24;
}
break;
}
return n;
}
and
int AIFF_CloseFile(AIFF_Ref ref)
{
int r;
if (!ref)
return -1;
if (ref->flags & F_RDONLY) {
AIFF_ReadClose(ref); // BREAK OCCURS HERE EVERYTIME
r = 1;
} else if (ref->flags & F_WRONLY) {
r = AIFF_WriteClose(ref);
} else {
r = -1;
}
return r;
}
The break occurs at AIFF_ReadClose(ref); EVERYTIME. So I have also shown this function below.
static void AIFF_ReadClose(AIFF_Ref r)
{
if (r->buffer)
free(r->buffer);
if (r->buffer2)
free(r->buffer2); // THIS IS WHERE THE BREAK OCCURS EVERYTIME
Unprepare(r);
fclose(r->fd);
free(r);
return;
}
The break always occurs as shown above. The following is the error message: (25693,0x7fff7db87310) malloc: * error for object 0x4000000000000000: pointer being freed was not allocated
* set a breakpoint in malloc_error_break to debug
So basically, the above error occurs unpredictably. When it doesn't occur, my code works perfectly. Any help as to how I might solve this problem is much appreciated.
IF ANYONE IS WILLING TO DOWNLOAD THE LIBAIFF LIBRARY TO INVESTIGATE FURTHER AND HELP ME OUT, the link to the library is: http://aifftools.sourceforge.net/libaiff/.
Thanks in advance for any suggestions!
1, please confirm buffer2 has been initialized with NULL before using. In all your pasted codes, I can not find any assignment or memory allocation for buffer2.
2, please assign the pointer with NULL after calling free, like:
if (r->buffer)
{
free(r->buffer);
r->buffer = NULL;
}
if (r->buffer2)
{
free(r->buffer2);
r->buffer2 = NULL;
}
If all this can not resolve you problem, please give more code about buffer2.