summaryrefslogtreecommitdiffstats
path: root/contrib/query-loc-0.4.0/loc.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/query-loc-0.4.0/loc.c')
-rw-r--r--contrib/query-loc-0.4.0/loc.c590
1 files changed, 590 insertions, 0 deletions
diff --git a/contrib/query-loc-0.4.0/loc.c b/contrib/query-loc-0.4.0/loc.c
new file mode 100644
index 0000000..57e3737
--- /dev/null
+++ b/contrib/query-loc-0.4.0/loc.c
@@ -0,0 +1,590 @@
+#include "loc.h"
+
+/* $Id: loc.c,v 1.1 2008/02/15 01:47:15 marka Exp $ */
+
+/* Global variables */
+
+short rr_errno;
+
+/*
+ Prints the actual usage
+ */
+void
+usage ()
+{
+ (void) fprintf (stderr,
+ "Usage: %s: [-v] [-d nnn] hostname\n", progname);
+ exit (2);
+}
+
+/*
+ Panics
+ */
+void
+panic (message)
+ char *message;
+{
+ (void) fprintf (stderr,
+ "%s: %s\n", progname, message);
+ exit (2);
+}
+
+/*
+ ** IN_ADDR_ARPA -- Convert dotted quad string to reverse in-addr.arpa
+ ** ------------------------------------------------------------------
+ **
+ ** Returns:
+ ** Pointer to appropriate reverse in-addr.arpa name
+ ** with trailing dot to force absolute domain name.
+ ** NULL in case of invalid dotted quad input string.
+ */
+
+#ifndef ARPA_ROOT
+#define ARPA_ROOT "in-addr.arpa"
+#endif
+
+char *
+in_addr_arpa (dottedquad)
+ char *dottedquad; /* input string with dotted quad */
+{
+ static char addrbuf[4 * 4 + sizeof (ARPA_ROOT) + 2];
+ unsigned int a[4];
+ register int n;
+
+ n = sscanf (dottedquad, "%u.%u.%u.%u", &a[0], &a[1], &a[2], &a[3]);
+ switch (n)
+ {
+ case 4:
+ (void) sprintf (addrbuf, "%u.%u.%u.%u.%s.",
+ a[3] & 0xff, a[2] & 0xff, a[1] & 0xff, a[0] & 0xff, ARPA_ROOT);
+ break;
+
+ case 3:
+ (void) sprintf (addrbuf, "%u.%u.%u.%s.",
+ a[2] & 0xff, a[1] & 0xff, a[0] & 0xff, ARPA_ROOT);
+ break;
+
+ case 2:
+ (void) sprintf (addrbuf, "%u.%u.%s.",
+ a[1] & 0xff, a[0] & 0xff, ARPA_ROOT);
+ break;
+
+ case 1:
+ (void) sprintf (addrbuf, "%u.%s.",
+ a[0] & 0xff, ARPA_ROOT);
+ break;
+
+ default:
+ return (NULL);
+ }
+
+ while (--n >= 0)
+ if (a[n] > 255)
+ return (NULL);
+
+ return (addrbuf);
+}
+
+/*
+ Returns a human-readable version of the LOC information or
+ NULL if it failed. Argument is a name (of a network or a machine)
+ and a boolean telling is it is a network name or a machine name.
+ */
+char *
+getlocbyname (name, is_network)
+ const char *name;
+ short is_network;
+{
+ char *result;
+ struct list_in_addr *list, *p;
+ result = findRR (name, T_LOC);
+ if (result != NULL)
+ {
+ if (debug >= 2)
+ printf ("LOC record found for the name %s\n", name);
+ return result;
+ }
+ else
+ {
+ if (!is_network)
+ {
+ list = findA (name);
+ if (debug >= 2)
+ printf ("No LOC record found for the name %s, trying addresses\n", name);
+ if (list != NULL)
+ {
+ for (p = list; p != NULL; p = p->next)
+ {
+ if (debug >= 2)
+ printf ("Trying address %s\n", inet_ntoa (p->addr));
+ result = getlocbyaddr (p->addr, NULL);
+ if (result != NULL)
+ return result;
+ }
+ return NULL;
+ }
+ else
+ {
+ if (debug >= 2)
+ printf (" No A record found for %s\n", name);
+ return NULL;
+ }
+ }
+ else
+ {
+ if (debug >= 2)
+ printf ("No LOC record found for the network name %s\n", name);
+ return NULL;
+ }
+ }
+}
+
+/*
+ Returns a human-readable version of the LOC information or
+ NULL if it failed. Argument is an IP address.
+ */
+char *
+getlocbyaddr (addr, mask)
+ const struct in_addr addr;
+ const struct in_addr *mask;
+{
+ struct in_addr netaddr;
+ u_int32_t a;
+ struct in_addr themask;
+ char *text_addr, *text_mask;
+
+ if (mask == NULL)
+ {
+ themask.s_addr = (u_int32_t) 0;
+ }
+ else
+ {
+ themask = *mask;
+ }
+
+ text_addr = (char *) malloc (256);
+ text_mask = (char *) malloc (256);
+ strcpy (text_addr, inet_ntoa (addr));
+ strcpy (text_mask, inet_ntoa (themask));
+
+ if (debug >= 2)
+ printf ("Testing address %s/%s\n", text_addr, text_mask);
+ if (mask == NULL)
+ {
+ a = ntohl (addr.s_addr);
+ if (IN_CLASSA (a))
+ {
+ netaddr.s_addr = htonl (a & IN_CLASSA_NET);
+ themask.s_addr = htonl(IN_CLASSA_NET);
+ }
+ else if (IN_CLASSB (a))
+ {
+ netaddr.s_addr = htonl (a & IN_CLASSB_NET);
+ themask.s_addr = htonl(IN_CLASSB_NET);
+ }
+ else if (IN_CLASSC (a))
+ {
+ netaddr.s_addr = htonl (a & IN_CLASSC_NET);
+ themask.s_addr = htonl(IN_CLASSC_NET);
+ }
+ else
+ {
+ /* Error */
+ return NULL;
+ }
+ return getlocbynet (in_addr_arpa (inet_ntoa (netaddr)), addr, &themask);
+ }
+ else
+ {
+ netaddr.s_addr = addr.s_addr & themask.s_addr;
+ return getlocbynet (in_addr_arpa (inet_ntoa (netaddr)), addr, mask);
+ }
+}
+
+/*
+ Returns a human-readable LOC.
+ Argument is a network name in the 0.z.y.x.in-addr.arpa format
+ and the original address
+ */
+char *
+getlocbynet (name, addr, mask)
+ char *name;
+ struct in_addr addr;
+ struct in_addr *mask;
+{
+ char *network;
+ char *result;
+ struct list_in_addr *list;
+ struct in_addr newmask;
+ u_int32_t a;
+ char newname[4 * 4 + sizeof (ARPA_ROOT) + 2];
+
+ if (debug >= 2)
+ printf ("Testing network %s with mask %s\n", name, inet_ntoa(*mask));
+
+ /* Check if this network has an A RR */
+ list = findA (name);
+ if (list != NULL)
+ {
+ /* Yes, it does. This A record will be used as the
+ * new mask for recursion if it is longer than
+ * the actual mask. */
+ if (mask != NULL && mask->s_addr < list->addr.s_addr)
+ {
+ /* compute the new arguments for recursion
+ * - compute the new network by applying the new mask
+ * to the address and get the in_addr_arpa representation
+ * of it.
+ * - the address remains unchanged
+ * - the new mask is the one given in the A record
+ */
+ a = ntohl(addr.s_addr); /* start from host address */
+ a &= ntohl(list->addr.s_addr); /* apply new mask */
+ newname[sizeof newname - 1] = 0;
+ strncpy(
+ newname,
+ in_addr_arpa(inet_ntoa(inet_makeaddr(a, 0))),
+ sizeof newname);
+ newmask = inet_makeaddr(ntohl(list->addr.s_addr), 0);
+ result = getlocbynet (newname, addr, &newmask);
+ if (result != NULL)
+ {
+ return result;
+ }
+ }
+ /* couldn't find a LOC. Fall through and try with name */
+ }
+
+ /* Check if this network has a name */
+ network = findRR (name, T_PTR);
+ if (network == NULL)
+ {
+ if (debug >= 2)
+ printf ("No name for network %s\n", name);
+ return NULL;
+ }
+ else
+ {
+ return getlocbyname (network, TRUE);
+ }
+}
+
+/*
+ The code for these two functions is stolen from the examples in Liu and Albitz
+ book "DNS and BIND" (O'Reilly).
+ */
+
+/****************************************************************
+ * skipName -- This routine skips over a domain name. If the *
+ * domain name expansion fails, it crashes. *
+ * dn_skipname() is probably not on your manual *
+ * page; it is similar to dn_expand() except that it just *
+ * skips over the name. dn_skipname() is in res_comp.c if *
+ * you need to find it. *
+ ****************************************************************/
+int
+skipName (cp, endOfMsg)
+ u_char *cp;
+ u_char *endOfMsg;
+{
+ int n;
+
+ if ((n = dn_skipname (cp, endOfMsg)) < 0)
+ {
+ panic ("dn_skipname failed\n");
+ }
+ return (n);
+}
+
+/****************************************************************
+ * skipToData -- This routine advances the cp pointer to the *
+ * start of the resource record data portion. On the way, *
+ * it fills in the type, class, ttl, and data length *
+ ****************************************************************/
+int
+skipToData (cp, type, class, ttl, dlen, endOfMsg)
+ u_char *cp;
+ u_short *type;
+ u_short *class;
+ u_int32_t *ttl;
+ u_short *dlen;
+ u_char *endOfMsg;
+{
+ u_char *tmp_cp = cp; /* temporary version of cp */
+
+ /* Skip the domain name; it matches the name we looked up */
+ tmp_cp += skipName (tmp_cp, endOfMsg);
+
+ /*
+ * Grab the type, class, and ttl. GETSHORT and GETLONG
+ * are macros defined in arpa/nameser.h.
+ */
+ GETSHORT (*type, tmp_cp);
+ GETSHORT (*class, tmp_cp);
+ GETLONG (*ttl, tmp_cp);
+ GETSHORT (*dlen, tmp_cp);
+
+ return (tmp_cp - cp);
+}
+
+
+/*
+ Returns a human-readable version of a DNS RR (resource record)
+ associated with the name 'domain'.
+ If it does not find, ir returns NULL and sets rr_errno to explain why.
+
+ The code for this function is stolen from the examples in Liu and Albitz
+ book "DNS and BIND" (O'Reilly).
+ */
+char *
+findRR (domain, requested_type)
+ char *domain;
+ int requested_type;
+{
+ char *result, *message;
+
+ union
+ {
+ HEADER hdr; /* defined in resolv.h */
+ u_char buf[PACKETSZ]; /* defined in arpa/nameser.h */
+ }
+ response; /* response buffers */
+short found = 0;
+int responseLen; /* buffer length */
+
+ u_char *cp; /* character pointer to parse DNS packet */
+ u_char *endOfMsg; /* need to know the end of the message */
+ u_short class; /* classes defined in arpa/nameser.h */
+ u_short type; /* types defined in arpa/nameser.h */
+ u_int32_t ttl; /* resource record time to live */
+ u_short dlen; /* size of resource record data */
+
+ int i, count, dup; /* misc variables */
+
+ char *ptrList[1];
+ int ptrNum = 0;
+ struct in_addr addr;
+
+ result = (char *) malloc (256);
+ message = (char *) malloc (256);
+ /*
+ * Look up the records for the given domain name.
+ * We expect the domain to be a fully qualified name, so
+ * we use res_query(). If we wanted the resolver search
+ * algorithm, we would have used res_search() instead.
+ */
+ if ((responseLen =
+ res_query (domain, /* the domain we care about */
+ C_IN, /* Internet class records */
+ requested_type, /* Look up name server records */
+ (u_char *) & response, /*response buffer */
+ sizeof (response))) /*buffer size */
+ < 0)
+ { /*If negative */
+ rr_errno = h_errno;
+ return NULL;
+ }
+
+ /*
+ * Keep track of the end of the message so we don't
+ * pass it while parsing the response. responseLen is
+ * the value returned by res_query.
+ */
+ endOfMsg = response.buf + responseLen;
+
+ /*
+ * Set a pointer to the start of the question section,
+ * which begins immediately AFTER the header.
+ */
+ cp = response.buf + sizeof (HEADER);
+
+ /*
+ * Skip over the whole question section. The question
+ * section is comprised of a name, a type, and a class.
+ * QFIXEDSZ (defined in arpa/nameser.h) is the size of
+ * the type and class portions, which is fixed. Therefore,
+ * we can skip the question section by skipping the
+ * name (at the beginning) and then advancing QFIXEDSZ.
+ * After this calculation, cp points to the start of the
+ * answer section, which is a list of NS records.
+ */
+ cp += skipName (cp, endOfMsg) + QFIXEDSZ;
+
+ count = ntohs (response.hdr.ancount) +
+ ntohs (response.hdr.nscount);
+ while ((--count >= 0) /* still more records */
+ && (cp < endOfMsg))
+ { /* still inside the packet */
+
+
+ /* Skip to the data portion of the resource record */
+ cp += skipToData (cp, &type, &class, &ttl, &dlen, endOfMsg);
+
+ if (type == requested_type)
+ {
+ switch (requested_type)
+ {
+ case (T_LOC):
+ loc_ntoa (cp, result);
+ return result;
+ break;
+ case (T_PTR):
+ ptrList[ptrNum] = (char *) malloc (MAXDNAME);
+ if (ptrList[ptrNum] == NULL)
+ {
+ panic ("Malloc failed");
+ }
+
+ if (dn_expand (response.buf, /* Start of the packet */
+ endOfMsg, /* End of the packet */
+ cp, /* Position in the packet */
+ (char *) ptrList[ptrNum], /* Result */
+ MAXDNAME) /* size of ptrList buffer */
+ < 0)
+ { /* Negative: error */
+ panic ("dn_expand failed");
+ }
+
+ /*
+ * Check the name we've just unpacked and add it to
+ * the list if it is not a duplicate.
+ * If it is a duplicate, just ignore it.
+ */
+ for (i = 0, dup = 0; (i < ptrNum) && !dup; i++)
+ dup = !strcasecmp (ptrList[i], ptrList[ptrNum]);
+ if (dup)
+ free (ptrList[ptrNum]);
+ else
+ ptrNum++;
+ strcpy (result, ptrList[0]);
+ return result;
+ break;
+ case (T_A):
+ bcopy ((char *) cp, (char *) &addr, INADDRSZ);
+ strcat (result, " ");
+ strcat (result, inet_ntoa (addr));
+ found = 1;
+ break;
+ default:
+ sprintf (message, "Unexpected type %u", requested_type);
+ panic (message);
+ }
+ }
+
+ /* Advance the pointer over the resource record data */
+ cp += dlen;
+
+ } /* end of while */
+ if (found)
+ return result;
+else
+return NULL;
+}
+
+struct list_in_addr *
+findA (domain)
+ char *domain;
+{
+
+ struct list_in_addr *result, *end;
+
+ union
+ {
+ HEADER hdr; /* defined in resolv.h */
+ u_char buf[PACKETSZ]; /* defined in arpa/nameser.h */
+ }
+ response; /* response buffers */
+ int responseLen; /* buffer length */
+
+ u_char *cp; /* character pointer to parse DNS packet */
+ u_char *endOfMsg; /* need to know the end of the message */
+ u_short class; /* classes defined in arpa/nameser.h */
+ u_short type; /* types defined in arpa/nameser.h */
+ u_int32_t ttl; /* resource record time to live */
+ u_short dlen; /* size of resource record data */
+
+ int count; /* misc variables */
+
+ struct in_addr addr;
+
+ end = NULL;
+ result = NULL;
+
+ /*
+ * Look up the records for the given domain name.
+ * We expect the domain to be a fully qualified name, so
+ * we use res_query(). If we wanted the resolver search
+ * algorithm, we would have used res_search() instead.
+ */
+ if ((responseLen =
+ res_query (domain, /* the domain we care about */
+ C_IN, /* Internet class records */
+ T_A,
+ (u_char *) & response, /*response buffer */
+ sizeof (response))) /*buffer size */
+ < 0)
+ { /*If negative */
+ rr_errno = h_errno;
+ return NULL;
+ }
+
+ /*
+ * Keep track of the end of the message so we don't
+ * pass it while parsing the response. responseLen is
+ * the value returned by res_query.
+ */
+ endOfMsg = response.buf + responseLen;
+
+ /*
+ * Set a pointer to the start of the question section,
+ * which begins immediately AFTER the header.
+ */
+ cp = response.buf + sizeof (HEADER);
+
+ /*
+ * Skip over the whole question section. The question
+ * section is comprised of a name, a type, and a class.
+ * QFIXEDSZ (defined in arpa/nameser.h) is the size of
+ * the type and class portions, which is fixed. Therefore,
+ * we can skip the question section by skipping the
+ * name (at the beginning) and then advancing QFIXEDSZ.
+ * After this calculation, cp points to the start of the
+ * answer section, which is a list of NS records.
+ */
+ cp += skipName (cp, endOfMsg) + QFIXEDSZ;
+
+ count = ntohs (response.hdr.ancount) +
+ ntohs (response.hdr.nscount);
+ while ((--count >= 0) /* still more records */
+ && (cp < endOfMsg))
+ { /* still inside the packet */
+
+
+ /* Skip to the data portion of the resource record */
+ cp += skipToData (cp, &type, &class, &ttl, &dlen, endOfMsg);
+
+ if (type == T_A)
+ {
+ bcopy ((char *) cp, (char *) &addr, INADDRSZ);
+ if (end == NULL)
+ {
+ result = (void *) malloc (sizeof (struct list_in_addr));
+ result->addr = addr;
+ result->next = NULL;
+ end = result;
+ }
+ else
+ {
+ end->next = (void *) malloc (sizeof (struct list_in_addr));
+ end = end->next;
+ end->addr = addr;
+ end->next = NULL;
+ }
+ }
+
+ /* Advance the pointer over the resource record data */
+ cp += dlen;
+
+ } /* end of while */
+ return result;
+}