Removed submodules
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef __cs361_port_utils_h__
|
||||
#define __cs361_port_utils_h__
|
||||
|
||||
char *get_port (void);
|
||||
|
||||
#endif
|
||||
@@ -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 (" ");
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Executable
BIN
Binary file not shown.
@@ -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
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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 .
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Executable
+97
@@ -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
|
||||
|
||||
@@ -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.
Executable
+53
@@ -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
|
||||
Reference in New Issue
Block a user