Skip to content
Extraits de code Groupes Projets
Valider 3583eb1a rédigé par François De Keersmaeker's avatar François De Keersmaeker
Parcourir les fichiers

Updated DNS lib

parent cb710ac9
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
/**
* @file include/dns.h
* @file include/parsers/dns.h
* @author François De Keersmaeker (francois.dekeersmaeker@uclouvain.be)
* @brief DNS message parser
* @date 2022-09-09
*
......@@ -15,6 +16,9 @@
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "packet_utils.h"
#include "dns_map.h"
......@@ -71,7 +75,7 @@ typedef struct dns_header {
*/
typedef struct dns_question {
char *qname;
dns_rr_type_t qtype;
uint16_t qtype;
uint16_t qclass;
} dns_question_t;
......@@ -89,7 +93,7 @@ typedef union {
*/
typedef struct dns_resource_record {
char *name;
dns_rr_type_t rtype;
uint16_t rtype;
uint16_t rclass;
uint32_t ttl;
uint16_t rdlength;
......@@ -187,10 +191,10 @@ dns_question_t* dns_get_question(dns_question_t *questions, uint16_t qdcount, ch
/**
* @brief Retrieve the IP addresses corresponding to a given domain name in a DNS Answers list.
*
*
* Searches a DNS Answer list for a specific domain name and returns the corresponding IP address.
* Processes each Answer recursively if the Answer Type is a CNAME.
*
*
* @param answers DNS Answers list to search in
* @param ancount number of Answers in the list
* @param domain_name domain name to search for
......@@ -199,6 +203,34 @@ dns_question_t* dns_get_question(dns_question_t *questions, uint16_t qdcount, ch
ip_list_t dns_get_ip_from_name(dns_resource_record_t *answers, uint16_t ancount, char *domain_name);
///// COMMUNICATE /////
/**
* @brief Convert domain name to message format.
*
* @param dst converted domain name
* @param src domain name to convert
*/
void dns_convert_qname(char *dst, char *src, uint16_t len);
/**
* @brief Send a DNS query for the given domain name.
*
* @param qname domain name to query for
* @param sockfd socket file descriptor
* @param server_addr DNS server IPv4 address
*/
void dns_send_query(char *qname, int sockfd, struct sockaddr_in *server_addr);
/**
* @brief Receive a DNS response
*
* @param sockfd socket file descriptor
* @param server_addr DNS server IPv4 address
*/
dns_message_t dns_receive_response(int sockfd, struct sockaddr_in *server_addr);
///// DESTROY /////
/**
......
/**
* @file src/dns.c
* @file src/parsers/dns.c
* @author François De Keersmaeker (francois.dekeersmaeker@uclouvain.be)
* @brief DNS message parser
* @date 2022-09-09
*
......@@ -191,7 +192,7 @@ dns_resource_record_t* dns_parse_rrs(uint16_t count, uint8_t *data, uint16_t *of
// Parse domain name
(rrs + i)->name = dns_parse_domain_name(data, offset);
// Parse rtype, rclass and TTL
dns_rr_type_t rtype = ntohs(*((uint16_t *) (data + *offset)));
uint16_t rtype = ntohs(*((uint16_t *) (data + *offset)));
(rrs + i)->rtype = rtype;
(rrs + i)->rclass = ntohs(*((uint16_t *) (data + *offset + 2))) & DNS_CLASS_MASK;
(rrs + i)->ttl = ntohl(*((uint32_t *) (data + *offset + 4)));
......@@ -199,7 +200,7 @@ dns_resource_record_t* dns_parse_rrs(uint16_t count, uint8_t *data, uint16_t *of
uint16_t rdlength = ntohs(*((uint16_t *) (data + *offset + 8)));
(rrs + i)->rdlength = rdlength;
*offset += 10;
(rrs + i)->rdata = dns_parse_rdata(rtype, rdlength, data, offset);
(rrs + i)->rdata = dns_parse_rdata((dns_rr_type_t) rtype, rdlength, data, offset);
}
return rrs;
}
......@@ -326,39 +327,48 @@ dns_question_t* dns_get_question(dns_question_t *questions, uint16_t qdcount, ch
/**
* @brief Retrieve the IP addresses corresponding to a given domain name in a DNS Answers list.
*
*
* Searches a DNS Answer list for a specific domain name and returns the corresponding IP address.
* Processes each Answer recursively if the Answer Type is a CNAME.
*
*
* @param answers DNS Answers list to search in
* @param ancount number of Answers in the list
* @param domain_name domain name to search for
* @return struct ip_list representing the list of corresponding IP addresses
*/
ip_list_t dns_get_ip_from_name(dns_resource_record_t *answers, uint16_t ancount, char *domain_name) {
ip_list_t dns_get_ip_from_name(dns_resource_record_t *answers, uint16_t ancount, char *domain_name)
{
ip_list_t ip_list;
ip_list.ip_count = 0;
ip_list.ip_addresses = NULL;
char *cname = domain_name;
for (uint16_t i = 0; i < ancount; i++) {
if (strcmp((answers + i)->name, cname) == 0) {
for (uint16_t i = 0; i < ancount; i++)
{
if (strcmp((answers + i)->name, cname) == 0)
{
dns_rr_type_t rtype = (answers + i)->rtype;
if (rtype == A || rtype == AAAA)
{
// Handle IP list length
if (ip_list.ip_addresses == NULL) {
ip_list.ip_addresses = (ip_addr_t *) malloc(sizeof(ip_addr_t));
} else {
if (ip_list.ip_addresses == NULL)
{
ip_list.ip_addresses = (ip_addr_t *)malloc(sizeof(ip_addr_t));
}
else
{
void *realloc_ptr = realloc(ip_list.ip_addresses, (ip_list.ip_count + 1) * sizeof(ip_addr_t));
if (realloc_ptr == NULL) {
if (realloc_ptr == NULL)
{
// Handle realloc error
free(ip_list.ip_addresses);
fprintf(stderr, "Error reallocating memory for IP list.\n");
ip_list.ip_count = 0;
ip_list.ip_addresses = NULL;
return ip_list;
} else {
ip_list.ip_addresses = (ip_addr_t*) realloc_ptr;
}
else
{
ip_list.ip_addresses = (ip_addr_t *)realloc_ptr;
}
}
// Handle IP version and value
......@@ -375,6 +385,113 @@ ip_list_t dns_get_ip_from_name(dns_resource_record_t *answers, uint16_t ancount,
}
///// COMMUNICATE /////
/**
* @brief Convert domain name to message format.
*
* @param dst converted domain name
* @param src domain name to convert
*/
void dns_convert_qname(char *dst, char *src, uint16_t len) {
int lock = 0; // Points to the next index to fill in the output array
// Start by iterating over each character in the input domain name
for (int i = 0; i < len; i++)
{
int segment_len = 0; // Length of the current segment
// Count the length of the current segment until we hit a dot or the end of the string
while (*(src + i) != '.' && *(src + i) != '\0')
{
*(dst + lock + 1 + segment_len) = *(src + i);
segment_len++;
i++;
}
*(dst + lock) = segment_len; // Prefix the segment with its length
lock += segment_len + 1; // Move the index past the current segment
}
*(dst + lock) = '\0'; // Null terminate the DNS label format string
}
/**
* @brief Send a DNS query for the given domain name.
*
* @param qname domain name to query for
* @param sockfd socket file descriptor
* @param server_addr DNS server IPv4 address
*/
void dns_send_query(char *qname, int sockfd, struct sockaddr_in *server_addr) {
// Buffer that will contain the message
uint16_t qname_len = strlen(qname);
uint16_t qname_labels_len = qname_len + sizeof(uint8_t) * 2;
uint16_t dns_questions_size = qname_labels_len + sizeof(uint16_t) * 2;
uint16_t dns_message_size = DNS_HEADER_SIZE + dns_questions_size;
uint8_t *buffer = (uint8_t *) malloc(dns_message_size);
// Populate DNS Header fields
dns_header_t dns_header;
dns_header.id = htons((uint16_t) getpid());
dns_header.flags = htons((uint16_t) (0b0000000100000000));
dns_header.qr = 0; // Query: qr = 0
dns_header.qdcount = htons((uint16_t) 1); // Only 1 question
dns_header.ancount = 0;
dns_header.nscount = 0;
dns_header.arcount = 0;
// Populate DNS Question fields
dns_question_t dns_question;
dns_question.qname = (char *)malloc(qname_labels_len);
dns_convert_qname(dns_question.qname, qname, qname_len);
dns_question.qtype = htons((uint16_t) A);
dns_question.qclass = htons((uint16_t) 1);
// Copy all DNS fields
memcpy(buffer, &dns_header, sizeof(uint16_t) * 2);
memcpy(buffer + sizeof(uint16_t) * 2, &(dns_header.qdcount), sizeof(uint16_t) * 4);
memcpy(buffer + DNS_HEADER_SIZE, dns_question.qname, qname_labels_len);
memcpy(buffer + DNS_HEADER_SIZE + qname_labels_len, &(dns_question.qtype), sizeof(uint16_t) * 2);
// Send DNS message
if (sendto(sockfd, buffer, dns_message_size, 0, (struct sockaddr *)server_addr, sizeof(*server_addr)) < 0)
{
perror("Failed sending DNS query.");
}
// Free memory
free(dns_question.qname);
free(buffer);
}
/**
* @brief Receive a DNS response.
*
* @param sockfd socket file descriptor
* @param server_addr DNS server IPv4 address
* @return received DNS message
*/
dns_message_t dns_receive_response(int sockfd, struct sockaddr_in *server_addr)
{
// Receiving buffer
int bufsize = 65536;
uint8_t *buffer = (uint8_t *)malloc(bufsize);
// Await response
int n = recvfrom(sockfd, (char *)buffer, bufsize, 0, NULL, NULL);
if (n < 0)
{
perror("Failed receiving DNS response.");
exit(-1);
}
// Parse received DNS message
dns_message_t dns_message = dns_parse_message(buffer);
free(buffer);
return dns_message;
}
///// DESTROY /////
/**
......@@ -410,7 +527,7 @@ static void dns_free_rrs(dns_resource_record_t *rrs, uint16_t count) {
dns_resource_record_t rr = *(rrs + i);
if (rr.rdlength > 0) {
free(rr.name);
dns_free_rdata(rr.rdata, rr.rtype);
dns_free_rdata(rr.rdata, (dns_rr_type_t) rr.rtype);
}
}
free(rrs);
......@@ -539,7 +656,7 @@ void dns_print_rr(char* section_name, dns_resource_record_t rr) {
printf(" Class: %hd\n", rr.rclass);
printf(" TTL [s]: %d\n", rr.ttl);
printf(" Data length: %hd\n", rr.rdlength);
printf(" RDATA: %s\n", dns_rdata_to_str(rr.rtype, rr.rdlength, rr.rdata));
printf(" RDATA: %s\n", dns_rdata_to_str((dns_rr_type_t) rr.rtype, rr.rdlength, rr.rdata));
}
/**
......
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter