Removed submodules

This commit is contained in:
2026-05-31 14:34:00 -04:00
commit 46c36b11da
352 changed files with 14792 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
*.swp
*.swo
# Ignore all compiled files regardless of location
build/*.o
tests/*.o
# Ignore executables for this project
digduke
testsuite
# Ignore test outputs
tests/ckstyle
tests/itests.txt
tests/outputs
tests/style.txt
tests/valgrind
tests/utests.txt
# Ignore all vscode stuff and NFS files
**/.nfs*
**/.vscode
+59
View File
@@ -0,0 +1,59 @@
#
# Simple Makefile
# Mike Lam, James Madison University, August 2016
#
# This makefile builds a simple application that contains a main module
# (specified by the EXE variable) and a predefined list of additional modules
# (specified by the MODS variable). If there are any external library
# dependencies (e.g., the math library, "-lm"), list them in the LIBS variable.
# If there are any precompiled object files, list them in the OBJS variable.
#
# By default, this makefile will build the project with debugging symbols and
# without optimization. To change this, edit or remove the "-g" and "-O0"
# options in CFLAGS and LDFLAGS accordingly.
#
# By default, this makefile build the application using the GNU C compiler,
# adhering to the C99 standard with all warnings enabled.
# application-specific settings and run target
EXE=digduke
MODS=client.o dns.o utils.o
OBJS=port_utils.o
LIBS=-lm
default: build $(EXE)
build:
mkdir build
test: build $(EXE)
make -C tests test
style: $(EXE)
make -C tests style
# compiler/linker settings
CC=gcc
CFLAGS=-g -O0 -Wall -Werror --std=gnu99 -pedantic
LDFLAGS=-g -O0 -pthread
# build targets
BUILD=$(addprefix build/, $(MODS))
$(EXE): $(BUILD) $(OBJS)
$(CC) $(LDFLAGS) -o $(EXE) $^ $(LIBS)
build/%.o: src/%.c
$(CC) -c $(CFLAGS) -o $@ $<
clean:
rm -rf $(EXE) build
make -C tests clean
.PHONY: default clean
+39
View File
@@ -0,0 +1,39 @@
Answer the following questions to describe your code submission. Please keep
all lines to a maximum of 80 characters wide.
1 - Your implementation must send an array of bytes to the server. Explain the
meaning of these bytes and how the server interprets them.
The bytes we send form a complete DNS request, which is hardcoded. The first
12 bytes make up the DNS header, which includes a transaction ID, flags, and
counts of questions, answers, authority, and additional records. After the
header, we include the question section, which specifies the domain name
(which is a 0 length label which mean root server), the record type (A = IPv4),
and the class (IN = Internet). The server interprets these bytes as a query
asking for the IPv4 address of the root domain, and responds with the A
record containing the IP address of one of the root servers a.root-servers.net.
or b.root-servers.net.
2 - Show (in pseudocode) how you set up your socket to send your message,
including a description of how you specified the address and port number.
What would you have to change to send an HTTP message (which uses TCP) to
a server?
const char *hostname = "127.0.0.1";
const char *port = get_port ();
struct addrinfo *server_list
= get_server_list (hostname, port, false, false);
int sockfd = socket (server_list->ai_family, server_list->ai_socktype, 0);
We do this to specify the hostname and port.
To send an HTTP message to a server we would hardcode the port to be 80
and create the socket using SOCK_STREAM. We would have to call connect() to
establish the TCP handshake and then use send() to send the query and recv()
to get the response.
+26
View File
@@ -0,0 +1,26 @@
Answer the following questions to describe your code submission. Please keep
all lines to a maximum of 80 characters wide.
1 - Explain the algorithm that your code uses to convert a domain name from its
DNS (binary) format to the standard dotted notation for humans to read.
(I.e., how do you convert the bytes "01 61 01 62 00" into "a.b"?)
The algorithm we use reads from a pointer to the front of the domain name. The first
byte gives the length of the next label. The code copies that many bytes
as text, appends a period, and moves forward by that label length. It
repeats until it encounters a 0x00 byte using a while loop, which is the null byte and the end of the
domain name.
2 - Consider the following data:
12 34 81 80 00 01 00 01 00 00 00 00 03 6e 6f 74 02 68 69 03 6d 6f
6d 00 00 01 00 01 c0 10 00 01 00 01 00 00 03 84 04 01 02 03 04
What is the domain name in the response? What is the IP address?
The domain name is not.hi.mom
The IP address is 1.2.3.4
+24
View File
@@ -0,0 +1,24 @@
Answer the following questions to describe your code submission. Please keep
all lines to a maximum of 80 characters wide.
1 - If a record is sought by there are no answers, what status code(s) are
returned and what does the RFC indicate these mean?
The status code would be NOERROR and this means the question went through and was
processed fully but there was no corresponding data to return. The status code could also be NXDOMAIN
which indicates a domain name that does not exist and is an error.
2 - Consider the following data:
12 34 81 80 00 01 00 02 00 00 00 00 03 6e 6f 74 02 68 69 03 6d 6f
6d 00 00 01 00 01 05 68 6f 77 64 79 c0 13 00 01 00 01 00 00 12 34
04 0a 00 00 01 c0 1c 00 1c 00 01 00 00 12 34 10 10 00 00 00 00 00
00 01
What are the domains name in the response? What are the IP addresses?
howdy.mom. 10.0.0.1
howdy.mom. 1010::1
+30
View File
@@ -0,0 +1,30 @@
Answer the following questions to describe your code submission. Please keep
all lines to a maximum of 80 characters wide.
1 - Explain how you convert the IP address 1.2.3.4 into the correct format for
a PTR request.
We reversed the IP address to 4.3.2.1 by tokenizing at the periods and
then putting them back in correct order. Then concatenated the string portion on to the end of that
in-addr.arpa. , to give 4.3.2.1.in-addr.arpa.
2 - Explain the fields of an SOA record. Which of these would be interpreted as
an email address and how so?
There are 7 different fields:
MNAME (The primary master name),
RNAME (The email address),
SERIAL (The version number of the zone data),
REFRESH (How often secondary servers check for updates),
RETRY (How long to wait before retrying after a failed refresh),
EXPIRE (How long secondary servers keep data if updates fail),
MINIMUM (Default TTL for negative responses).
The RNAME would be interpreted as the email address and you would replace
the first . with an @ to turn into the normal email address structure.
Binary file not shown.
+255
View File
@@ -0,0 +1,255 @@
#include <arpa/inet.h>
#include <assert.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include "dns.h"
#include "port_utils.h"
#include "utils.h"
#define BUFFER_MAX_SIZE 4096
const char *HOSTNAME = "127.0.0.1";
ssize_t
query_dns (unsigned char *query, size_t size, unsigned char **response)
{
// hardcoded for dukens server
const char *port_str = get_port (); // same port dukens listens on
int port = strtol (port_str, NULL, 10);
if (port <= 0 || port > 65535)
{
fprintf (stderr, "Invalid port: %s\n", port_str);
exit (EXIT_FAILURE);
}
struct sockaddr_in addr = { 0 };
addr.sin_family = AF_INET;
addr.sin_port = htons (port);
if (inet_aton (HOSTNAME, &addr.sin_addr) != 1)
{
fprintf (stderr, "Invalid IPv4 address: %s\n", HOSTNAME);
exit (EXIT_FAILURE);
}
// create socket
int sockfd = socket (AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
perror ("socket");
exit (EXIT_FAILURE);
}
ssize_t sent = sendto (sockfd, query, size, 0, (struct sockaddr *)&addr,
sizeof (addr));
if (sent < 0)
{
perror ("sendto");
close (sockfd);
exit (EXIT_FAILURE);
}
// receive and print response
*response = calloc (BUFFER_MAX_SIZE, sizeof (unsigned char));
ssize_t received
= recvfrom (sockfd, *response, BUFFER_MAX_SIZE, 0, NULL, NULL);
if (received < 0)
{
perror ("recvfrom");
close (sockfd);
exit (EXIT_FAILURE);
}
// cleanup
close (sockfd);
return received;
}
void
phase_one ()
{
// hard coded DNS request
unsigned char query[17]
= { 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01 };
unsigned char *res_bytes;
ssize_t received = query_dns (query, sizeof (query), &res_bytes);
printf ("Sending %zu bytes to %s:\n", sizeof (query), HOSTNAME);
print_byte_block (query, sizeof (query));
printf ("\nReceived %zd bytes from %s:\n", received, HOSTNAME);
print_byte_block (res_bytes, received);
printf ("\n");
dns_response_t res = { 0 };
parse_dns_response (res_bytes, sizeof (query), &res);
dns_answer_t answer = res.answers[0];
printf ("Domain name: %s\n", answer.domain);
printf ("Record type: %s %s\n", qclass_to_str (answer.qclass),
record_to_str (answer.qtype));
printf ("TTL: %d\n", answer.ttl);
printf ("IPv4 address: %s\n", answer.rdata);
free (res_bytes);
}
void
not_phase_one (int argc, char *argv[])
{
// building query
uint16_t xid = strtol (argv[2], NULL, 10);
uint16_t record = get_record_from_str (argv[4]);
char domain_name[BUFFER_LENGTH];
if (record == PTR)
{
ptr_ip (domain_name, BUFFER_LENGTH, argv[3]);
}
else
{
strncpy (domain_name, argv[3], sizeof (domain_name) - 1);
domain_name[sizeof (domain_name) - 1] = '\0';
}
unsigned char query_bytes[512];
size_t offset = 0;
// DNS Header
query_bytes[offset++] = (xid >> 8) & 0xFF;
query_bytes[offset++] = xid & 0xFF;
query_bytes[offset++] = 0x01; // flags
query_bytes[offset++] = 0x00;
query_bytes[offset++] = 0x00; // QDCOUNT high
query_bytes[offset++] = 0x01; // QDCOUNT low
// rest zeros (ANCOUNT, NSCOUNT, ARCOUNT)
for (int i = 0; i < 6; i++)
query_bytes[offset++] = 0x00;
// Question section: domain name
char *token = strtok (domain_name, ".");
while (token)
{
size_t len = strlen (token);
query_bytes[offset++] = (unsigned char)len;
memcpy (&query_bytes[offset], token, len);
offset += len;
token = strtok (NULL, ".");
}
query_bytes[offset++] = 0x00; // end of domain
query_bytes[offset++] = record >> 8;
query_bytes[offset++] = record & 0xff;
query_bytes[offset++] = 0x00; // QCLASS = IN
query_bytes[offset++] = 0x01;
unsigned char *res_bytes;
query_dns (query_bytes, offset, &res_bytes);
dns_query_t query = { 0 };
parse_dns_query (&query_bytes[0], &query);
dns_response_t response = { 0 };
parse_dns_response (&res_bytes[0], offset, &response);
// print header
print_dns_header (&response.query.header);
// print question section
print_question_section (&query);
uint8_t status = (response.query.header.flags >> 0) & 0xF;
if (status == 0 && response.query.header.ancount > 0)
{
printf ("\n;; ANSWER SECTION:\n");
for (size_t i = 0; i < response.query.header.ancount; i++)
{
dns_answer_t answer = response.answers[i];
print_answer_section (&answer);
}
}
if (response.query.header.nscount > 0)
{
printf ("\n;; AUTHORITY SECTION:\n");
for (size_t i = 0; i < response.query.header.nscount; i++)
{
dns_answer_t authority = response.authorities[i];
print_answer_section (&authority);
}
}
if (response.query.header.arcount > 0)
{
printf ("\n;; ADDITIONAL SECTION:\n");
for (size_t i = 0; i < response.query.header.arcount; i++)
{
dns_answer_t additional = response.additionals[i];
print_answer_section (&additional);
}
}
free (res_bytes);
}
static bool
get_args (int argc, char **argv, bool *opendns, bool *xflag)
{
int ch = 0;
while ((ch = getopt (argc, argv, "ox")) != -1)
{
switch (ch)
{
case 'o':
*opendns = true;
break;
case 'x':
*xflag = true;
break;
default:
return false;
}
}
return true;
}
int
main (int argc, char *argv[])
{
bool opendns = false;
bool xflag = false;
if (!get_args (argc, argv, &opendns, &xflag))
{
fprintf (stderr, "ERROR: Show usage\n");
return EXIT_FAILURE;
}
if (!xflag)
{
phase_one ();
}
else
{
not_phase_one (argc, argv);
}
return EXIT_SUCCESS;
}
+393
View File
@@ -0,0 +1,393 @@
#include <arpa/inet.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "dns.h"
#define BUFFER_MAX_SIZE 4096
// SUGGESTION: Use this file for DNS-related functionality
const char *
opcode_to_str (uint8_t opcode)
{
switch (opcode)
{
case 0:
return "QUERY";
case 1:
return "IQUERY";
case 2:
return "STATUS";
default:
return "UNKNOWN";
}
}
const char *
status_to_str (uint8_t status)
{
switch (status)
{
case 0:
return "NOERROR";
case 1:
return "FORMERR";
case 2:
return "SERVFAIL";
case 3:
return "NXDOMAIN";
case 4:
return "NOTIMP";
case 5:
return "REFUSED";
default:
return "UNKNOWN";
}
}
const char *
record_to_str (uint16_t record)
{
switch (record)
{
case 1:
return "A";
case 2:
return "NS";
case 5:
return "CNAME";
case 6:
return "SOA";
case 12:
return "PTR";
case 15:
return "MX";
case 28:
return "AAAA";
default:
return "UNKNOWN";
}
}
const char *
qclass_to_str (uint16_t qclass_bytes)
{
switch (qclass_bytes)
{
case 1:
return "IN";
default:
return "UNKNOWN";
}
}
uint16_t
get_record_from_str (const char *record_str)
{
if (strcasecmp (record_str, "A") == 0)
return A;
else if (strcasecmp (record_str, "AAAA") == 0)
return AAAA;
else if (strcasecmp (record_str, "CNAME") == 0)
return CNAME;
else if (strcasecmp (record_str, "MX") == 0)
return MX;
else if (strcasecmp (record_str, "NS") == 0)
return NS;
else if (strcasecmp (record_str, "SOA") == 0)
return SOA;
else if (strcasecmp (record_str, "PTR") == 0)
return PTR;
else
{
fprintf (stderr, "Unsupported record type: %s\n", record_str);
return 0;
}
}
uint32_t
merge_32 (unsigned char *bytes)
{
return ((uint32_t)bytes[0] << 24) | ((uint32_t)bytes[1] << 16)
| ((uint32_t)bytes[2] << 8) | ((uint32_t)bytes[3]);
}
void
recursive_domain_parse (unsigned char *bytes, ssize_t *pointer, char **domain)
{
if (bytes[*pointer] == 0x00)
{
(*pointer)++;
return;
}
bool is_compressed = (bytes[*pointer] & 0xc0) == 0xc0;
if (!is_compressed)
{
size_t len = (size_t)bytes[(*pointer)++];
strncat (*domain, (char *)&bytes[*pointer], len);
strncat (*domain, ".", 2);
*pointer += len;
recursive_domain_parse (bytes, pointer, domain);
}
else
{
ssize_t offset = (bytes[*pointer] << 8 | bytes[*pointer + 1]) & 0x3fff;
recursive_domain_parse (bytes, &offset, domain);
*pointer += 2;
}
}
void
parse_domain (unsigned char *bytes, ssize_t *pointer, char **domain)
{
recursive_domain_parse (bytes, pointer, domain);
if (strlen (*domain) == 0)
{
strncat (*domain, ".", 2);
}
}
char *
parse_ip_addr (unsigned char *bytes, uint16_t rdlen)
{
char ip_addr[INET6_ADDRSTRLEN];
uint8_t ip_ver = rdlen == 4 ? AF_INET : AF_INET6;
if (inet_ntop (ip_ver, bytes, ip_addr, sizeof (ip_addr)) == NULL)
{
perror ("inet_ntop");
exit (EXIT_FAILURE);
}
return strdup (ip_addr);
}
void
print_dns_header (dns_header_t *header)
{
// switch endianness
uint16_t xid = header->xid;
uint16_t flags = header->flags;
uint16_t qdcount = header->qdcount;
uint16_t ancount = header->ancount;
uint16_t nscount = header->nscount;
uint16_t arcount = header->arcount;
// find flags
uint8_t qr = (flags >> 15) & 0x1;
uint8_t opcode = (flags >> 11) & 0xF;
uint8_t aa = (flags >> 10) & 0x1;
uint8_t tc = (flags >> 9) & 0x1;
uint8_t rd = (flags >> 8) & 0x1;
uint8_t ra = (flags >> 7) & 0x1;
uint8_t status = (flags >> 0) & 0xF;
// get string equivalent for opcode and status
const char *opcode_str = opcode_to_str (opcode);
const char *status_str = status_to_str (status);
// print first line of header
printf (";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n", opcode_str,
status_str, xid);
// print set flags
printf (";; flags:");
if (qr)
printf (" qr");
if (aa)
printf (" aa");
if (tc)
printf (" tc");
if (rd)
printf (" rd");
if (ra)
printf (" ra");
// print the last line
printf ("; QUERY: %u, ANSWER: %u, AUTHORITY: %u, ADDITIONAL: %u\n\n",
qdcount, ancount, nscount, arcount);
}
// print question section
void
print_question_section (dns_query_t *query)
{
// print first line
printf (";; QUESTION SECTION:\n");
char *domain = calloc (BUFFER_MAX_SIZE, sizeof (char));
ssize_t pointer = 0;
parse_domain (query->domain, &pointer, &domain);
printf (";%s %s %s\n", domain, qclass_to_str (query->qclass),
record_to_str (query->qtype));
free (domain);
}
// print the answer section
void
print_answer_section (dns_answer_t *answer)
{
char buf[BUFFER_LENGTH] = { 0 };
snprintf (buf, sizeof (buf), "%s %s %u.", qclass_to_str (answer->qclass),
record_to_str (answer->qtype), answer->ttl);
printf ("%-30s %-16s %s\n", answer->domain, buf, answer->rdata);
}
ssize_t
parse_dns_header (unsigned char *bytes, dns_header_t *header)
{
memcpy (header, bytes, sizeof (dns_header_t));
header->xid = ntohs (header->xid);
header->flags = ntohs (header->flags);
header->qdcount = ntohs (header->qdcount);
header->ancount = ntohs (header->ancount);
header->nscount = ntohs (header->nscount);
header->arcount = ntohs (header->arcount);
return sizeof (dns_header_t);
}
ssize_t
parse_dns_query (unsigned char *bytes, dns_query_t *query)
{
ssize_t pointer = parse_dns_header (bytes, &(query->header));
query->domain = &bytes[pointer];
while (bytes[pointer++] != 0x00)
;
query->qtype = (bytes[pointer] << 8) | bytes[pointer + 1];
pointer += 2;
query->qclass = (bytes[pointer] << 8) | bytes[pointer + 1];
pointer += 2;
return pointer;
}
void
parse_dns_answer (unsigned char *bytes, ssize_t *pointer, dns_answer_t *answer)
{
answer->domain = calloc (BUFFER_MAX_SIZE, sizeof (char));
parse_domain (bytes, pointer, &(answer->domain));
answer->qtype = (bytes[*pointer] << 8) | bytes[*pointer + 1];
*pointer += 2;
answer->qclass = (bytes[*pointer] << 8) | bytes[*pointer + 1];
*pointer += 2;
for (int i = 3; i >= 0; i--)
{
answer->ttl |= bytes[(*pointer)++] << (8 * i);
}
answer->rdlen = (bytes[*pointer] << 8) | bytes[*pointer + 1];
*pointer += 2;
answer->rdata = calloc (BUFFER_MAX_SIZE, sizeof (char));
if (answer->qtype == A || answer->qtype == AAAA)
{
answer->rdata = parse_ip_addr (&bytes[*pointer], answer->rdlen);
*pointer += answer->rdlen;
return;
}
if (answer->qtype == NS || answer->qtype == CNAME || answer->qtype == PTR)
{
parse_domain (bytes, pointer, &(answer->rdata));
return;
}
if (answer->qtype == MX)
{
uint16_t preference = (bytes[*pointer] << 8) | bytes[*pointer + 1];
*pointer += 2;
char *exchange = calloc (BUFFER_LENGTH, sizeof (char));
parse_domain (bytes, pointer, &exchange);
snprintf (answer->rdata, BUFFER_MAX_SIZE, "%u %s", preference, exchange);
free (exchange);
return;
}
if (answer->qtype == SOA)
{
char *mname = calloc (BUFFER_LENGTH, sizeof (char));
parse_domain (bytes, pointer, &mname);
char *rname = calloc (BUFFER_LENGTH, sizeof (char));
parse_domain (bytes, pointer, &rname);
uint32_t serial = merge_32 (&bytes[*pointer]);
uint32_t refresh = merge_32 (&bytes[*pointer + 4]);
uint32_t retry = merge_32 (&bytes[*pointer + 8]);
uint32_t expire = merge_32 (&bytes[*pointer + 12]);
uint32_t minimum = merge_32 (&bytes[*pointer + 16]);
*pointer += 20;
snprintf (answer->rdata, BUFFER_MAX_SIZE, "%s %s %u %u %u %u %u", mname,
rname, serial, refresh, retry, expire, minimum);
free (mname);
free (rname);
return;
}
}
ssize_t
parse_dns_response (unsigned char *bytes, ssize_t query_len,
dns_response_t *response)
{
ssize_t pointer = parse_dns_query (bytes, &(response->query));
response->answers
= calloc (response->query.header.ancount, sizeof (dns_answer_t));
for (size_t i = 0; i < response->query.header.ancount; i++)
{
dns_answer_t answer = { 0 };
parse_dns_answer (bytes, &pointer, &answer);
memcpy (&(response->answers[i]), &answer, sizeof (dns_answer_t));
}
response->authorities
= calloc (response->query.header.nscount, sizeof (dns_answer_t));
for (size_t i = 0; i < response->query.header.nscount; i++)
{
dns_answer_t authoritative = { 0 };
parse_dns_answer (bytes, &pointer, &authoritative);
memcpy (&(response->authorities[i]), &authoritative,
sizeof (dns_answer_t));
}
response->additionals
= calloc (response->query.header.arcount, sizeof (dns_answer_t));
for (size_t i = 0; i < response->query.header.arcount; i++)
{
dns_answer_t additional = { 0 };
parse_dns_answer (bytes, &pointer, &additional);
memcpy (&(response->additionals[i]), &additional, sizeof (dns_answer_t));
}
return pointer;
}
+62
View File
@@ -0,0 +1,62 @@
#ifndef __cs361_dns_h__
#define __cs361_dns_h__
#include <stdint.h>
// Maximum buffer lengths allows
#define BUFFER_LENGTH 512
// Structure of the bytes for a DNS header
typedef struct
{
uint16_t xid;
uint16_t flags;
uint16_t qdcount;
uint16_t ancount;
uint16_t nscount;
uint16_t arcount;
} dns_header_t;
typedef struct
{
dns_header_t header;
unsigned char *domain;
uint16_t qtype;
uint16_t qclass;
} dns_query_t;
typedef struct
{
char *domain;
uint16_t qtype;
uint16_t qclass;
uint32_t ttl;
uint16_t rdlen;
char *rdata;
} dns_answer_t;
typedef struct
{
dns_query_t query;
dns_answer_t *answers;
dns_answer_t *authorities;
dns_answer_t *additionals;
} dns_response_t;
// Supported record types
#define A 1
#define NS 2
#define CNAME 5
#define SOA 6
#define PTR 12
#define MX 15
#define AAAA 28
void print_dns_header (dns_header_t *);
void print_question_section (dns_query_t *query);
void print_answer_section (dns_answer_t *answer);
ssize_t parse_dns_query (unsigned char *bytes, dns_query_t *query);
ssize_t parse_dns_response (unsigned char *bytes, ssize_t query_len,
dns_response_t *response);
#endif
+6
View File
@@ -0,0 +1,6 @@
#ifndef __cs361_port_utils_h__
#define __cs361_port_utils_h__
char *get_port (void);
#endif
+53
View File
@@ -0,0 +1,53 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dns.h"
#include "port_utils.h"
#include "utils.h"
// SUGGESTION: Use this file for any network-related functionality, such as
// sending or receiving messages.
void
ptr_ip (char *dst, size_t dst_size, const char *ip)
{
char tmp[64];
strncpy (tmp, ip, sizeof (tmp));
tmp[sizeof (tmp) - 1] = '\0';
char *octets[4];
char *token = strtok (tmp, ".");
int count = 0;
while (token && count < 4)
{
octets[count++] = token;
token = strtok (NULL, ".");
}
if (count != 4)
{
fprintf (stderr, "Invalid PTR IP");
exit (EXIT_FAILURE);
}
snprintf (dst, dst_size, "%s.%s.%s.%s.in-addr.arpa.", octets[3], octets[2],
octets[1], octets[0]);
}
void
print_byte_block (uint8_t *bytes, size_t length)
{
printf (" ");
for (int i = 0; i < length; i++)
{
printf ("%02x", bytes[i]);
if (i == length - 1)
printf ("\n");
else if ((i + 1) % 16 == 0)
printf ("\n ");
else if ((i % 2) != 0)
printf (" ");
}
}
+9
View File
@@ -0,0 +1,9 @@
#ifndef __cs361_utils_h__
#define __cs361_utils_h__
#include <stdint.h>
void ptr_ip (char *dst, size_t dst_size, const char *ip);
void print_byte_block (uint8_t *, size_t);
#endif
+87
View File
@@ -0,0 +1,87 @@
#
# Simple Test Makefile
# Mike Lam, James Madison University, August 2016
#
# This version of the Makefile includes support for building a test suite. The
# recommended framework is Check (http://check.sourceforge.net/). To build and
# run the test suite, execute the "test" target. The test suite must be located
# in a module called "testsuite". The MODS, LIBS, and OBJS variables work as
# they do in the main Makefile.
#
# To change the default build target (which executes when you just type
# "make"), change the right-hand side of the definition of the "default"
# target.
#
# By default, this makefile will build the project with debugging symbols and
# without optimization. To change this, edit or remove the "-g" and "-O0"
# options in CFLAGS and LDFLAGS accordingly.
#
# By default, this makefile build the application using the GNU C compiler,
# adhering to the C99 standard with all warnings enabled.
# application-specific settings and run target
EXE=../digduke
TEST=testsuite
MODS=public.o
OBJS=../port_utils.o
LIBS=
UTESTOUT=utests.txt
ITESTOUT=itests.txt
SCHECKOUT=style.txt
default: $(TEST)
$(EXE):
make -C ../
test: itest style
@echo "========================================"
utest: $(EXE) $(TEST)
@echo "========================================"
@echo " UNIT TESTS"
@./$(TEST) 2>/dev/null >$(UTESTOUT)
@cat $(UTESTOUT) | sed -n -e '/Checks/,$$p' | sed -e 's/^private.*:[EF]://g'
itest: $(EXE)
@echo "========================================"
@echo " INTEGRATION TESTS"
@./integration.sh | tee $(ITESTOUT)
style: $(EXE)
@echo "========================================"
@echo " CODING STYLE CHECK"
@./style.sh 2>/dev/null >$(SCHECKOUT)
@cat $(SCHECKOUT)
# compiler/linker settings
CC=gcc
CFLAGS=-g -O0 -Wall --std=gnu99 -pedantic
LDFLAGS=-g -O0
CFLAGS=
LIBS+=-lcheck -lm -lpthread
ifeq ($(shell uname -s),Linux)
LIBS+=-lrt -lsubunit
endif
# build targets
$(TEST): $(TEST).o $(MODS) $(OBJS)
$(CC) $(LDFLAGS) -o $(TEST) $^ $(LIBS)
%.o: %.c
$(CC) -c $(CFLAGS) $<
clean:
rm -rf $(TEST) $(TEST).o $(MODS) $(UTESTOUT) $(ITESTOUT) $(SCHECKOUT) outputs valgrind ckstyle
.PHONY: default clean test unittest inttest
BIN
View File
Binary file not shown.
+9
View File
@@ -0,0 +1,9 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32412
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;stu. IN A
;; ANSWER SECTION:
stu. IN CNAME 0. stu.cs.jmu.edu.
stu.cs.jmu.edu. IN A 0. 127.0.1.1
@@ -0,0 +1,11 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51120
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; QUESTION SECTION:
;www.jmu.edu. IN CNAME
;; ANSWER SECTION:
www.jmu.edu. IN CNAME 592. it-www1.jmu.edu.
;; ADDITIONAL SECTION:
it-www1.jmu.edu. IN A 900. 134.126.126.99
+8
View File
@@ -0,0 +1,8 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49602
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;stu.cs.jmu.edu. IN CNAME
;; ANSWER SECTION:
stu.cs.jmu.edu. IN CNAME 1769. student.cs.jmu.edu.
+8
View File
@@ -0,0 +1,8 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 52173
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;example.com. IN SOA
;; ANSWER SECTION:
example.com. IN SOA 1803. ns.icann.org. noc.dns.icann.org. 2025011715 7200 3600 1209600 3600
+8
View File
@@ -0,0 +1,8 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62055
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;jmu.edu. IN SOA
;; ANSWER SECTION:
jmu.edu. IN SOA 3600. it-ns.jmu.edu. network.jmu.edu. 735142168 86400 7200 3600000 3600
@@ -0,0 +1,11 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 61906
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0
;; QUESTION SECTION:
;www.jmu.edu. IN AAAA
;; ANSWER SECTION:
www.jmu.edu. IN CNAME 592. it-www1.jmu.edu.
;; AUTHORITY SECTION:
jmu.edu. IN SOA 3600. it-ns.jmu.edu. network.jmu.edu. 735142168 86400 7200 3600000 3600
@@ -0,0 +1,8 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10099
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
;; QUESTION SECTION:
;fac.cs.jmu.edu. IN AAAA
;; AUTHORITY SECTION:
cs.jmu.edu. IN SOA 900. it-nios-gm.jmu.edu. network.jmu.edu. 14 10800 3600 2419200 900
+8
View File
@@ -0,0 +1,8 @@
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 56769
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
;; QUESTION SECTION:
;5.67.101.151.in-addr.arpa. IN PTR
;; AUTHORITY SECTION:
151.in-addr.arpa. IN SOA 3600. pri.authdns.ripe.net. dns.ripe.net. 1752675523 3600 600 864000 3600
+8
View File
@@ -0,0 +1,8 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 870
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;221.141.126.134.in-addr.arpa. IN PTR
;; ANSWER SECTION:
221.141.126.134.in-addr.arpa. IN PTR 3542. student.cs.jmu.edu.
+12
View File
@@ -0,0 +1,12 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 45675
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; QUESTION SECTION:
;1.1.0.127.in-addr.arpa. IN PTR
;; ANSWER SECTION:
1.1.0.127.in-addr.arpa. IN PTR 0. stu.cs.jmu.edu.
1.1.0.127.in-addr.arpa. IN PTR 0. stu.
;; ADDITIONAL SECTION:
1.1.0.127.in-addr.arpa. IN CNAME 1769. student.cs.jmu.edu.
+13
View File
@@ -0,0 +1,13 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57548
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;99.126.126.134.in-addr.arpa. IN PTR
;; ANSWER SECTION:
99.126.126.134.in-addr.arpa. IN PTR 1483. it-www1.jmu.edu.
99.126.126.134.in-addr.arpa. IN PTR 1483. spcecoms.jmu.edu.
99.126.126.134.in-addr.arpa. IN PTR 1483. groups.jmu.edu.
99.126.126.134.in-addr.arpa. IN PTR 1483. groups.dukes.jmu.edu.
99.126.126.134.in-addr.arpa. IN PTR 1483. it-www2.jmu.edu.
99.126.126.134.in-addr.arpa. IN PTR 1483. athletics.jmu.edu.
+13
View File
@@ -0,0 +1,13 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7059
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;example.com. IN A
;; ANSWER SECTION:
example.com. IN A 300. 96.7.128.198
example.com. IN A 300. 23.215.0.136
example.com. IN A 300. 23.192.228.80
example.com. IN A 300. 23.192.228.84
example.com. IN A 300. 96.7.128.175
example.com. IN A 300. 23.215.0.138
+13
View File
@@ -0,0 +1,13 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4801
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;example.com. IN AAAA
;; ANSWER SECTION:
example.com. IN AAAA 21. 2600:1406:3a00:21::173e:2e65
example.com. IN AAAA 21. 2600:1406:bc00:53::b81e:94c8
example.com. IN AAAA 21. 2600:1408:ec00:36::1736:7f24
example.com. IN AAAA 21. 2600:1406:3a00:21::173e:2e66
example.com. IN AAAA 21. 2600:1408:ec00:36::1736:7f31
example.com. IN AAAA 21. 2600:1406:bc00:53::b81e:94ce
@@ -0,0 +1,9 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42937
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;example.com. IN NS
;; ANSWER SECTION:
example.com. IN NS 84682. b.iana-servers.net.
example.com. IN NS 84682. a.iana-servers.net.
+8
View File
@@ -0,0 +1,8 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57867
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;example.com. IN MX
;; ANSWER SECTION:
example.com. IN MX 86400. 0 .
+8
View File
@@ -0,0 +1,8 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 13835
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;jmu.edu. IN MX
;; ANSWER SECTION:
jmu.edu. IN MX 1538. 0 jmu-edu.mail.protection.outlook.com.
+9
View File
@@ -0,0 +1,9 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 23379
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;jmu.edu. IN NS
;; ANSWER SECTION:
jmu.edu. IN NS 1798. it-ns2-19.jmu.edu.
jmu.edu. IN NS 1798. it-ns1-19.jmu.edu.
+5
View File
@@ -0,0 +1,5 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54920
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;localhost. IN AAAA
+8
View File
@@ -0,0 +1,8 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;jmu.edu. IN A
;; ANSWER SECTION:
jmu.edu. IN A 900. 134.126.126.99
+8
View File
@@ -0,0 +1,8 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 46412
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;google.com. IN A
;; ANSWER SECTION:
google.com. IN A 194. 142.250.31.113
+8
View File
@@ -0,0 +1,8 @@
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39713
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;localhost. IN A
;; ANSWER SECTION:
localhost. IN A 0. 127.0.0.1
+5
View File
@@ -0,0 +1,5 @@
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 22016
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;asdf. IN A
+14
View File
@@ -0,0 +1,14 @@
Sending 17 bytes to 127.0.0.1:
0001 0100 0001 0000 0000 0000 0000 0100
01
Received 51 bytes from 127.0.0.1:
0001 8180 0001 0001 0000 0000 0000 0100
0101 620c 726f 6f74 2d73 6572 7665 7273
036e 6574 0000 0100 0100 008c a000 04aa
f7aa 02
Domain name: b.root-servers.net.
Record type: IN A
TTL: 36000
IPv4 address: 170.247.170.2
+14
View File
@@ -0,0 +1,14 @@
Sending 17 bytes to 127.0.0.1:
0001 0100 0001 0000 0000 0000 0000 0100
01
Received 51 bytes from 127.0.0.1:
0001 8180 0001 0001 0000 0000 0000 0100
0101 610c 726f 6f74 2d73 6572 7665 7273
036e 6574 0000 0100 0100 0000 0a00 04c6
2900 04
Domain name: a.root-servers.net.
Record type: IN A
TTL: 10
IPv4 address: 198.41.0.4
+97
View File
@@ -0,0 +1,97 @@
#!/bin/bash
EXE="../digduke"
function run_test {
# parameters
TAG=$1
shift
ARGS=$1
shift
PTAG=$(printf '%-30s' "$TAG")
if [[ $(echo $TAG | cut -d'_' -f1) == $SKIP_C ||
$(echo $TAG | cut -d'_' -f1) == $SKIP_B ||
$(echo $TAG | cut -d'_' -f1) == $SKIP_A ]] ; then
echo "$PTAG SKIPPED (previous phases not complete)"
return
fi
# file paths
OUTPUT=outputs/$TAG.txt
DIFF=outputs/$TAG.diff
EXPECT=expected/$TAG.txt
VALGRND=valgrind/$TAG.txt
# run test and compare output to the expected version
./dukens -s 2 >/dev/null 2>&1 &
sleep 1
$EXE $ARGS 2>/dev/null >"$OUTPUT"
for ARG in "$@" ; do
$EXE $ARG 2>/dev/null >>"$OUTPUT"
done
diff -u "$OUTPUT" "$EXPECT" >"$DIFF"
passed=false
EFILES=$(find expected -type f -name "$TAG-*.txt")
if [ ! -s "$DIFF" ]; then
passed=true
elif [ "$EFILES" != "" ]; then
for EF in $EFILES ; do
DF=$(echo $EF | sed 's/^expected/outputs/' | sed 's/txt$/diff/')
diff -u "$OUTPUT" "$EF" >"$DF"
if [ ! -s "$DF" ]; then
passed=true
fi
done
fi
if [[ $passed = true ]] ; then
echo "$PTAG pass"
rm outputs/$TAG*diff
else
echo "$PTAG FAIL - Command line: $EXE $ARGS"
if [ "$EFILES" != "" ] ; then
echo "$(printf '%30s' ' ') *WARNING* This test has more than one possible output file."
echo "$(printf '%30s' ' ') *WARNING* Please inspect each manually for comparison."
else
echo "$(printf '%30s' ' ') See $DIFF for diff with expected output"
fi
echo ""
if [[ $(echo $PTAG | cut -d'_' -f1) == 'D' ]] ; then
SKIP_C="C"
SKIP_B="B"
SKIP_A="A"
elif [[ $(echo $PTAG | cut -d'_' -f1) == 'C' ]] ; then
SKIP_B="B"
SKIP_A="A"
elif [[ $(echo $PTAG | cut -d'_' -f1) == 'B' ]] ; then
SKIP_A="A"
fi
fi
# run valgrind
#./dukens -s 2 >/dev/null 2>&1 &
# sleep 1
# valgrind $EXE $ARGS >"$VALGRND" 2>&1
}
# initialize output folders
mkdir -p outputs
mkdir -p valgrind
rm -f outputs/* valgrind/*
# run individual tests
source itests.include
# check for memory leaks
#LEAK=`cat valgrind/*.txt | grep 'definitely lost' | grep -v ' 0 bytes in 0 blocks'`
LEAK=
if [ -z "$LEAK" ]; then
echo "No memory leak found."
else
echo "Memory leak(s) found. See files listed below for details."
grep 'definitely lost' valgrind/*.txt | sed -e 's/:.*$//g' | sed -e 's/^/ - /g'
fi
+32
View File
@@ -0,0 +1,32 @@
# list of integration tests
# format: run_test <TAG> <ARGS>
# <TAG> used as the root for all filenames (i.e., "expected/$TAG.txt")
# <ARGS> command-line arguments to test
# sends a message to the server and prints the response in a formatted way
run_test D_ping ""
run_test C_a_basic "-x 2 jmu.edu A"
run_test C_a_compressed "-x 46412 google.com A"
run_test C_a_localhost "-x 39713 localhost A"
run_test C_bad_domain "-x 22016 asdf A"
run_test B_a_multiple "-x 7059 example.com A"
run_test B_aaaa "-x 4801 example.com AAAA"
run_test B_jmu_ns "-x 23379 jmu.edu NS"
run_test B_jmu_mx "-x 13835 jmu.edu MX"
run_test B_double_compress "-x 42937 example.com NS"
run_test B_empty_domain "-x 57867 example.com MX"
run_test B_no_ipv6 "-x 54920 localhost AAAA"
run_test A_cname_basic "-x 49602 stu.cs.jmu.edu CNAME"
run_test A_cname_additional "-x 51120 www.jmu.edu CNAME"
run_test A_cname_a "-x 32412 stu A"
run_test A_jmu_soa "-x 62055 jmu.edu SOA"
run_test A_example_soa "-x 52173 example.com SOA"
run_test A_ptr_basic "-x 870 134.126.141.221 PTR"
run_test A_ptr_multiple "-x 57548 134.126.126.99 PTR"
run_test A_ptr_mixed "-x 45675 127.0.1.1 PTR"
run_test A_no_ptr "-x 56769 151.101.67.5 PTR"
run_test A_no_ipv6_authority "-x 61906 www.jmu.edu AAAA"
run_test A_no_ipv6_subauth "-x 10099 fac.cs.jmu.edu AAAA"
Binary file not shown.
+53
View File
@@ -0,0 +1,53 @@
#!/bin/bash
STYLE="gnu"
IGNORE=()
FAIL=0
function comp_file {
SRC=$1
SRC_NAME=$2
# file paths
FORMAT=ckstyle/${SRC_NAME}.$STYLE
DIFF=ckstyle/${SRC_NAME}.diff
# run clang-format and compare results
clang-format --style=$STYLE $source > $FORMAT
diff -u $SRC $FORMAT >$DIFF
PTAG=$(printf '%-30s' "$SRC_NAME")
if [ -s $DIFF ]; then
echo "$PTAG FAIL (see $DIFF for details)"
FAIL=1
else
echo "$PTAG pass"
rm $DIFF
fi
rm $FORMAT
}
mkdir -p ckstyle
rm -f ckstyle/*
for source in $(ls ../src/*.c ../src/*.h) ; do
SKIP=0
src=$(basename $source)
for ignore in ${IGNORE[*]} ; do
if [ "$src" = "$ignore" ] ; then
SKIP=1
fi
done
if [ $SKIP = 0 ] ; then
comp_file $source $src
fi
done
if [ $FAIL != 0 ] ; then
echo "Code that does not adhere to GNU standards will not be accepted."
echo "You must fix these files before submission."
else
echo "Code correctly adheres to required style."
fi
View File