in OSNetworkRequirementChecker-HLApp/src/dns-helper.c [102:237]
int ProcessMessageBySection(char *buf, ssize_t len, ns_msg msg, ns_sect section,
ServiceInstanceDetails **instanceDetails)
{
char displayBuf[DISPLAY_BUF_SIZE];
ns_rr rr;
int messageCount = ns_msg_count(msg, section);
if (!(*instanceDetails)) {
// Allocate for ServiceInstanceDetails and initialize its members.
*instanceDetails = malloc(sizeof(ServiceInstanceDetails));
if (!(*instanceDetails)) {
Log_Debug("ERROR: recvfrom: %s (%d)\n", strerror(errno), errno);
return -1;
}
(*instanceDetails)->name = NULL;
(*instanceDetails)->host = NULL;
(*instanceDetails)->ipv4Address.s_addr = INADDR_NONE;
(*instanceDetails)->port = 0;
(*instanceDetails)->txtData = NULL;
(*instanceDetails)->txtDataLength = 0;
(*instanceDetails)->alias = NULL;
}
// Parse each message
for (int i = 0; i < messageCount; ++i) {
if (ns_parserr(&msg, section, i, &rr)) {
Log_Debug("ERROR: ns_parserr: %s (%d)\n", strerror(errno), errno);
return -1;
}
switch (ns_rr_type(rr)) {
case ns_t_ptr: {
int compressedNameLength =
dn_expand(buf, buf + len, ns_rr_rdata(rr), displayBuf, sizeof(displayBuf));
if (compressedNameLength > 0 && !(*instanceDetails)->name) {
(*instanceDetails)->name = strdup(displayBuf);
if (!(*instanceDetails)->name) {
Log_Debug("ERROR: strdup for instance name failed: %s (%d)\n", strerror(errno),
errno);
return -1;
}
}
break;
}
case ns_t_srv: {
// Parse the SRV record and populate the port and host fields in instance details as per
// DNS SRV record specification: https://tools.ietf.org/rfc/rfc2782.txt
// SRV record format: Priority| Weight | Port | Target
// (2 Bytes)|(2 Bytes)|(2 Bytes)|(Remaining Bytes)
const char *data = ns_rr_rdata(rr);
int compressedTargetDomainNameLength = dn_expand(
buf, buf + len, data + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t),
displayBuf, sizeof(displayBuf));
if ((*instanceDetails)->port == 0 && compressedTargetDomainNameLength > 0 &&
!(*instanceDetails)->host) {
(*instanceDetails)->port =
(uint16_t)ns_get16(data + sizeof(uint16_t) + sizeof(uint16_t));
(*instanceDetails)->host = strdup(displayBuf);
if (!(*instanceDetails)->host) {
Log_Debug("ERROR: strdup: %s (%d)\n", strerror(errno), errno);
return -1;
}
}
break;
}
case ns_t_txt: {
// Populate name field in instance details if it hasn't been set
if (!(*instanceDetails)->name) {
(*instanceDetails)->name = strdup(ns_rr_name(rr));
if (!(*instanceDetails)->name) {
Log_Debug("ERROR: strdup(ns_rr_name(rr)): %s (%d)\n", strerror(errno), errno);
return -1;
}
}
// Get TXT record, populate txtData and txtDataLength fields in instance details
if (!(*instanceDetails)->txtData) {
(*instanceDetails)->txtData =
malloc(sizeof(unsigned char) * (size_t)(ns_rr_rdlen(rr)));
if (!(*instanceDetails)->txtData) {
Log_Debug("ERROR: malloc: %s (%d)\n", strerror(errno), errno);
return -1;
}
memcpy((*instanceDetails)->txtData, ns_rr_rdata(rr), ns_rr_rdlen(rr));
(*instanceDetails)->txtDataLength = ns_rr_rdlen(rr);
}
break;
}
case ns_t_a: {
// Get A record (host address), populate ipv4Address field in instance details
if (ns_rr_rdlen(rr) == sizeof((*instanceDetails)->ipv4Address)) {
if ((*instanceDetails)->ipv4Address.s_addr == INADDR_NONE) {
memcpy(&(*instanceDetails)->ipv4Address.s_addr, ns_rr_rdata(rr),
ns_rr_rdlen(rr));
}
} else {
Log_Debug("ERROR: Invalid DNS A record length: %d\n", ns_rr_rdlen(rr));
}
break;
}
case ns_t_cname: {
char answerBuf[ANSWER_BUF_SIZE];
const char *rd = ns_rr_rdata(rr);
// Uncompress original name
int n = ns_name_uncompress(ns_msg_base(msg), ns_msg_end(msg), rd, answerBuf,
sizeof(answerBuf));
if (n < 0) {
Log_Debug(
"ERROR: Fail to uncompress original name from cname record. bufsize: %d, "
"errno: %s (%d)\n",
sizeof(answerBuf), strerror(errno), errno);
}
(*instanceDetails)->name = strdup(answerBuf);
// Aggregate alias information
if (!((*instanceDetails)->alias)) {
(*instanceDetails)->alias = strdup(ns_rr_name(rr));
} else {
char *indent = "\n\t\t";
char *original = (*instanceDetails)->alias;
size_t suffixLen = strlen(ns_rr_name(rr));
size_t originLen = strlen(original);
size_t indentLen = strlen(indent);
char *updated = (char *)malloc(suffixLen + originLen + indentLen + 1);
memcpy(updated, original, originLen);
memcpy(updated + originLen, indent, indentLen);
memcpy(updated + originLen + indentLen, ns_rr_name(rr), suffixLen);
updated[suffixLen + originLen + indentLen] = '\0';
(*instanceDetails)->alias = updated;
}
break;
}
default:
break;
}
}
return 0;
}