diff options
Diffstat (limited to 'contrib/query-loc-0.4.0/loc.c')
-rw-r--r-- | contrib/query-loc-0.4.0/loc.c | 590 |
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; +} |