|
Packit Bot |
f49f79 |
/*
|
|
Packit Bot |
f49f79 |
* Copyright 2011 Oracle. All rights reserved.
|
|
Packit Bot |
f49f79 |
*
|
|
Packit Bot |
f49f79 |
* This file is part of fedfs-utils.
|
|
Packit Bot |
f49f79 |
*
|
|
Packit Bot |
f49f79 |
* fedfs-utils is free software; you can redistribute it and/or modify
|
|
Packit Bot |
f49f79 |
* it under the terms of the GNU General Public License version 2.0 as
|
|
Packit Bot |
f49f79 |
* published by the Free Software Foundation.
|
|
Packit Bot |
f49f79 |
*
|
|
Packit Bot |
f49f79 |
* fedfs-utils is distributed in the hope that it will be useful, but
|
|
Packit Bot |
f49f79 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Bot |
f49f79 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Bot |
f49f79 |
* GNU General Public License version 2.0 for more details.
|
|
Packit Bot |
f49f79 |
*
|
|
Packit Bot |
f49f79 |
* You should have received a copy of the GNU General Public License
|
|
Packit Bot |
f49f79 |
* version 2.0 along with fedfs-utils. If not, see:
|
|
Packit Bot |
f49f79 |
*
|
|
Packit Bot |
f49f79 |
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
|
Packit Bot |
f49f79 |
*/
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
#ifdef HAVE_CONFIG_H
|
|
Packit Bot |
f49f79 |
#include <config.h>
|
|
Packit Bot |
f49f79 |
#endif
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
#include <sys/types.h>
|
|
Packit Bot |
f49f79 |
#include <sys/socket.h>
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
#include <stdbool.h>
|
|
Packit Bot |
f49f79 |
#include <string.h>
|
|
Packit Bot |
f49f79 |
#include <unistd.h>
|
|
Packit Bot |
f49f79 |
#include <stdlib.h>
|
|
Packit Bot |
f49f79 |
#include <stdint.h>
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
#include <stdio.h>
|
|
Packit Bot |
f49f79 |
#include <errno.h>
|
|
Packit Bot |
f49f79 |
#include <netdb.h>
|
|
Packit Bot |
f49f79 |
#include <netinet/in.h>
|
|
Packit Bot |
f49f79 |
#include <arpa/inet.h>
|
|
Packit Bot |
f49f79 |
#include <arpa/nameser.h>
|
|
Packit Bot |
f49f79 |
#include <arpa/nameser_compat.h>
|
|
Packit Bot |
f49f79 |
#include <resolv.h>
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
#include "fedfs-getsrvinfo.h"
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
/**
|
|
Packit Bot |
f49f79 |
* Parsing overlay for DNS query result record header. Fields are
|
|
Packit Bot |
f49f79 |
* in network byte order.
|
|
Packit Bot |
f49f79 |
*/
|
|
Packit Bot |
f49f79 |
struct rechdr {
|
|
Packit Bot |
f49f79 |
uint16_t type;
|
|
Packit Bot |
f49f79 |
uint16_t class;
|
|
Packit Bot |
f49f79 |
uint32_t ttl;
|
|
Packit Bot |
f49f79 |
uint16_t length;
|
|
Packit Bot |
f49f79 |
} __attribute__((__packed__));
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
/**
|
|
Packit Bot |
f49f79 |
* Parsing overlay for DNS query result SRV record data. Fields
|
|
Packit Bot |
f49f79 |
* are in network byte order.
|
|
Packit Bot |
f49f79 |
*/
|
|
Packit Bot |
f49f79 |
struct srv {
|
|
Packit Bot |
f49f79 |
uint16_t priority;
|
|
Packit Bot |
f49f79 |
uint16_t weight;
|
|
Packit Bot |
f49f79 |
uint16_t port;
|
|
Packit Bot |
f49f79 |
unsigned char *target;
|
|
Packit Bot |
f49f79 |
} __attribute__((__packed__));
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
/**
|
|
Packit Bot |
f49f79 |
* Return C string matching error value of "status"
|
|
Packit Bot |
f49f79 |
*
|
|
Packit Bot |
f49f79 |
* @param status error status returned by getsrvinfo
|
|
Packit Bot |
f49f79 |
* @return pointer to static NUL-terminated C string containing error message
|
|
Packit Bot |
f49f79 |
*/
|
|
Packit Bot |
f49f79 |
const char *
|
|
Packit Bot |
f49f79 |
gsi_strerror(int status)
|
|
Packit Bot |
f49f79 |
{
|
|
Packit Bot |
f49f79 |
static char buf[256];
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
switch (status) {
|
|
Packit Bot |
f49f79 |
case ESI_SUCCESS:
|
|
Packit Bot |
f49f79 |
return "Success";
|
|
Packit Bot |
f49f79 |
case ESI_NONAME:
|
|
Packit Bot |
f49f79 |
return "Name not found";
|
|
Packit Bot |
f49f79 |
case ESI_AGAIN:
|
|
Packit Bot |
f49f79 |
return "Temporary failure in name resolution";
|
|
Packit Bot |
f49f79 |
case ESI_FAIL:
|
|
Packit Bot |
f49f79 |
return "Non-recoverable failure in name resolution";
|
|
Packit Bot |
f49f79 |
case ESI_NODATA:
|
|
Packit Bot |
f49f79 |
return "No SRV record returned";
|
|
Packit Bot |
f49f79 |
case ESI_SERVICE:
|
|
Packit Bot |
f49f79 |
return "Service is not available";
|
|
Packit Bot |
f49f79 |
case ESI_MEMORY:
|
|
Packit Bot |
f49f79 |
return "Memory allocation failure";
|
|
Packit Bot |
f49f79 |
case ESI_SYSTEM:
|
|
Packit Bot |
f49f79 |
snprintf(buf, sizeof(buf), "System error (%d): %s",
|
|
Packit Bot |
f49f79 |
status, strerror(errno));
|
|
Packit Bot |
f49f79 |
return buf;
|
|
Packit Bot |
f49f79 |
case ESI_PARSE:
|
|
Packit Bot |
f49f79 |
return "Failed to parse server response";
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
snprintf(buf, sizeof(buf), "Unknown error (%d)", status);
|
|
Packit Bot |
f49f79 |
return buf;
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
/**
|
|
Packit Bot |
f49f79 |
* Release a list of SRV records allocated by getsrvinfo()
|
|
Packit Bot |
f49f79 |
*
|
|
Packit Bot |
f49f79 |
* @param si pointer to first element of a list of struct srvinfo
|
|
Packit Bot |
f49f79 |
*
|
|
Packit Bot |
f49f79 |
*/
|
|
Packit Bot |
f49f79 |
void freesrvinfo(struct srvinfo *si)
|
|
Packit Bot |
f49f79 |
{
|
|
Packit Bot |
f49f79 |
struct srvinfo *tmp;
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
while (si != NULL) {
|
|
Packit Bot |
f49f79 |
tmp = si;
|
|
Packit Bot |
f49f79 |
si = si->si_next;
|
|
Packit Bot |
f49f79 |
free(tmp->si_target);
|
|
Packit Bot |
f49f79 |
free(tmp);
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
/**
|
|
Packit Bot |
f49f79 |
* Ordering predicate for srvinfo lists
|
|
Packit Bot |
f49f79 |
*
|
|
Packit Bot |
f49f79 |
* @param a a srvinfo list element to compare
|
|
Packit Bot |
f49f79 |
* @param b another srvinfo list element to compare
|
|
Packit Bot |
f49f79 |
* @return true if "b" should fall later in the list than "a"
|
|
Packit Bot |
f49f79 |
*
|
|
Packit Bot |
f49f79 |
* See RFC 2782. The list is ordered as follows:
|
|
Packit Bot |
f49f79 |
*
|
|
Packit Bot |
f49f79 |
* o Lowest priority first.
|
|
Packit Bot |
f49f79 |
* o In each priority class, highest weight first.
|
|
Packit Bot |
f49f79 |
*/
|
|
Packit Bot |
f49f79 |
static _Bool
|
|
Packit Bot |
f49f79 |
srvinfo_is_after(const struct srvinfo *a, const struct srvinfo *b)
|
|
Packit Bot |
f49f79 |
{
|
|
Packit Bot |
f49f79 |
if (a->si_priority > b->si_priority)
|
|
Packit Bot |
f49f79 |
return true;
|
|
Packit Bot |
f49f79 |
if (a->si_priority < b->si_priority)
|
|
Packit Bot |
f49f79 |
return false;
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
if (a->si_weight < b->si_weight)
|
|
Packit Bot |
f49f79 |
return true;
|
|
Packit Bot |
f49f79 |
return false;
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
/**
|
|
Packit Bot |
f49f79 |
* Insert a srvinfo element into a list
|
|
Packit Bot |
f49f79 |
*
|
|
Packit Bot |
f49f79 |
* @param head pointer to head of list of elements
|
|
Packit Bot |
f49f79 |
* @param entry new list element to insert
|
|
Packit Bot |
f49f79 |
*
|
|
Packit Bot |
f49f79 |
*/
|
|
Packit Bot |
f49f79 |
static void
|
|
Packit Bot |
f49f79 |
insert_srvinfo(struct srvinfo **head, struct srvinfo *entry)
|
|
Packit Bot |
f49f79 |
{
|
|
Packit Bot |
f49f79 |
entry->si_next = *head;
|
|
Packit Bot |
f49f79 |
*head = entry;
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
/**
|
|
Packit Bot |
f49f79 |
* Insert a srvinfo element into a list, in order
|
|
Packit Bot |
f49f79 |
*
|
|
Packit Bot |
f49f79 |
* @param head pointer to head of list of elements
|
|
Packit Bot |
f49f79 |
* @param entry new list element to insert
|
|
Packit Bot |
f49f79 |
*
|
|
Packit Bot |
f49f79 |
*/
|
|
Packit Bot |
f49f79 |
static void
|
|
Packit Bot |
f49f79 |
insert_srvinfo_sorted(struct srvinfo **head, struct srvinfo *entry)
|
|
Packit Bot |
f49f79 |
{
|
|
Packit Bot |
f49f79 |
struct srvinfo *spot, *back;
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
spot = *head;
|
|
Packit Bot |
f49f79 |
back = NULL;
|
|
Packit Bot |
f49f79 |
while (spot && srvinfo_is_after(spot, entry)) {
|
|
Packit Bot |
f49f79 |
back = spot;
|
|
Packit Bot |
f49f79 |
spot = spot->si_next;
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
if (spot == (*head))
|
|
Packit Bot |
f49f79 |
insert_srvinfo(head, entry);
|
|
Packit Bot |
f49f79 |
else {
|
|
Packit Bot |
f49f79 |
insert_srvinfo(&spot, entry);
|
|
Packit Bot |
f49f79 |
/* off the end of the list? */
|
|
Packit Bot |
f49f79 |
if (spot == entry)
|
|
Packit Bot |
f49f79 |
back->si_next = entry;
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
/**
|
|
Packit Bot |
f49f79 |
* Retrieve list of SRV records from DNS service
|
|
Packit Bot |
f49f79 |
*
|
|
Packit Bot |
f49f79 |
* @param srvname NUL-terminated C string containing record type to look up
|
|
Packit Bot |
f49f79 |
* @param domainname NUL-terminated C string containing domain name to look up
|
|
Packit Bot |
f49f79 |
* @param si OUT: list of SRV record information retrieved
|
|
Packit Bot |
f49f79 |
* @return zero on success, or an ESI_ status code describing the error
|
|
Packit Bot |
f49f79 |
*
|
|
Packit Bot |
f49f79 |
* Caller must free list of records using freesrvinfo().
|
|
Packit Bot |
f49f79 |
*/
|
|
Packit Bot |
f49f79 |
int
|
|
Packit Bot |
f49f79 |
getsrvinfo(const char *srvname, const char *domainname, struct srvinfo **si)
|
|
Packit Bot |
f49f79 |
{
|
|
Packit Bot |
f49f79 |
unsigned char *msg, *eom, *comp_dn;
|
|
Packit Bot |
f49f79 |
struct srvinfo *results;
|
|
Packit Bot |
f49f79 |
unsigned short count, i;
|
|
Packit Bot |
f49f79 |
int status, len;
|
|
Packit Bot |
f49f79 |
char *exp_dn;
|
|
Packit Bot |
f49f79 |
HEADER *hdr;
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
msg = calloc(1, NS_MAXMSG);
|
|
Packit Bot |
f49f79 |
exp_dn = calloc(1, NS_MAXDNAME);
|
|
Packit Bot |
f49f79 |
if (msg == NULL || exp_dn == NULL) {
|
|
Packit Bot |
f49f79 |
status = ESI_MEMORY;
|
|
Packit Bot |
f49f79 |
goto out;
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
_res.options |= RES_AAONLY;
|
|
Packit Bot |
f49f79 |
len = res_querydomain(srvname, domainname, C_IN, T_SRV, msg, NS_MAXMSG);
|
|
Packit Bot |
f49f79 |
if (len == -1) {
|
|
Packit Bot |
f49f79 |
switch (h_errno) {
|
|
Packit Bot |
f49f79 |
case HOST_NOT_FOUND:
|
|
Packit Bot |
f49f79 |
status = ESI_NONAME;
|
|
Packit Bot |
f49f79 |
break;
|
|
Packit Bot |
f49f79 |
case TRY_AGAIN:
|
|
Packit Bot |
f49f79 |
status = ESI_AGAIN;
|
|
Packit Bot |
f49f79 |
break;
|
|
Packit Bot |
f49f79 |
case NO_RECOVERY:
|
|
Packit Bot |
f49f79 |
status = ESI_FAIL;
|
|
Packit Bot |
f49f79 |
break;
|
|
Packit Bot |
f49f79 |
case NO_DATA:
|
|
Packit Bot |
f49f79 |
status = ESI_NODATA;
|
|
Packit Bot |
f49f79 |
break;
|
|
Packit Bot |
f49f79 |
default:
|
|
Packit Bot |
f49f79 |
fprintf(stderr, "SRV query failed for %s.%s: %s\n",
|
|
Packit Bot |
f49f79 |
srvname, domainname, hstrerror(h_errno));
|
|
Packit Bot |
f49f79 |
status = ESI_FAIL;
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
goto out;
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
hdr = (HEADER *)msg;
|
|
Packit Bot |
f49f79 |
count = ntohs(hdr->ancount);
|
|
Packit Bot |
f49f79 |
if (count == 0) {
|
|
Packit Bot |
f49f79 |
status = ESI_NODATA;
|
|
Packit Bot |
f49f79 |
goto out;
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
eom = msg + len;
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
comp_dn = &msg[HFIXEDSZ];
|
|
Packit Bot |
f49f79 |
comp_dn += dn_skipname(comp_dn, eom) + QFIXEDSZ;
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
results = NULL;
|
|
Packit Bot |
f49f79 |
for (i = 0; i < count; i++) {
|
|
Packit Bot |
f49f79 |
struct srvinfo *new;
|
|
Packit Bot |
f49f79 |
struct srv *record;
|
|
Packit Bot |
f49f79 |
int l;
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
l = dn_expand(msg, eom, comp_dn, exp_dn, NS_MAXDNAME);
|
|
Packit Bot |
f49f79 |
if (l == -1) {
|
|
Packit Bot |
f49f79 |
status = ESI_PARSE;
|
|
Packit Bot |
f49f79 |
goto out_free;
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
comp_dn += l;
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
record = (struct srv *)&comp_dn[10];
|
|
Packit Bot |
f49f79 |
comp_dn += 16;
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
l = dn_expand(msg, eom, comp_dn, exp_dn, NS_MAXDNAME);
|
|
Packit Bot |
f49f79 |
if (l == -1) {
|
|
Packit Bot |
f49f79 |
status = ESI_PARSE;
|
|
Packit Bot |
f49f79 |
goto out_free;
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
comp_dn += l;
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
if (count == 1 && strcmp(exp_dn, ".") == 0) {
|
|
Packit Bot |
f49f79 |
status = ESI_SERVICE;
|
|
Packit Bot |
f49f79 |
goto out_free;
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
new = calloc(1, sizeof(*new));
|
|
Packit Bot |
f49f79 |
if (new == NULL) {
|
|
Packit Bot |
f49f79 |
status = ESI_MEMORY;
|
|
Packit Bot |
f49f79 |
goto out;
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
new->si_target = strdup(exp_dn);
|
|
Packit Bot |
f49f79 |
if (new->si_target == NULL) {
|
|
Packit Bot |
f49f79 |
free(new);
|
|
Packit Bot |
f49f79 |
status = ESI_MEMORY;
|
|
Packit Bot |
f49f79 |
goto out;
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
new->si_priority = ntohs(record->priority);
|
|
Packit Bot |
f49f79 |
new->si_weight = ntohs(record->weight);
|
|
Packit Bot |
f49f79 |
new->si_port = ntohs(record->port);
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
insert_srvinfo_sorted(&results, new);
|
|
Packit Bot |
f49f79 |
}
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
status = ESI_SUCCESS;
|
|
Packit Bot |
f49f79 |
*si = results;
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
out:
|
|
Packit Bot |
f49f79 |
free(exp_dn);
|
|
Packit Bot |
f49f79 |
free(msg);
|
|
Packit Bot |
f49f79 |
return status;
|
|
Packit Bot |
f49f79 |
|
|
Packit Bot |
f49f79 |
out_free:
|
|
Packit Bot |
f49f79 |
freesrvinfo(results);
|
|
Packit Bot |
f49f79 |
goto out;
|
|
Packit Bot |
f49f79 |
}
|