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