etc/services - sync with NetBSD-8
[minix.git] / external / bsd / bind / dist / contrib / query-loc-0.4.0 / loc.c
blob7e356f40acc508005ef623ebb927513ac238be0f
1 /* $NetBSD: loc.c,v 1.5 2014/12/10 04:37:56 christos Exp $ */
3 #include "loc.h"
5 /* Id: loc.c,v 1.1 2008/02/15 01:47:15 marka Exp */
7 /* Global variables */
9 short rr_errno;
12 Prints the actual usage
14 void
15 usage ()
17 (void) fprintf (stderr,
18 "Usage: %s: [-v] [-d nnn] hostname\n", progname);
19 exit (2);
23 Panics
25 void
26 panic (message)
27 char *message;
29 (void) fprintf (stderr,
30 "%s: %s\n", progname, message);
31 exit (2);
35 ** IN_ADDR_ARPA -- Convert dotted quad string to reverse in-addr.arpa
36 ** ------------------------------------------------------------------
38 ** Returns:
39 ** Pointer to appropriate reverse in-addr.arpa name
40 ** with trailing dot to force absolute domain name.
41 ** NULL in case of invalid dotted quad input string.
44 #ifndef ARPA_ROOT
45 #define ARPA_ROOT "in-addr.arpa"
46 #endif
48 char *
49 in_addr_arpa (dottedquad)
50 char *dottedquad; /* input string with dotted quad */
52 static char addrbuf[4 * 4 + sizeof (ARPA_ROOT) + 2];
53 unsigned int a[4];
54 register int n;
56 n = sscanf (dottedquad, "%u.%u.%u.%u", &a[0], &a[1], &a[2], &a[3]);
57 switch (n)
59 case 4:
60 (void) sprintf (addrbuf, "%u.%u.%u.%u.%s.",
61 a[3] & 0xff, a[2] & 0xff, a[1] & 0xff, a[0] & 0xff, ARPA_ROOT);
62 break;
64 case 3:
65 (void) sprintf (addrbuf, "%u.%u.%u.%s.",
66 a[2] & 0xff, a[1] & 0xff, a[0] & 0xff, ARPA_ROOT);
67 break;
69 case 2:
70 (void) sprintf (addrbuf, "%u.%u.%s.",
71 a[1] & 0xff, a[0] & 0xff, ARPA_ROOT);
72 break;
74 case 1:
75 (void) sprintf (addrbuf, "%u.%s.",
76 a[0] & 0xff, ARPA_ROOT);
77 break;
79 default:
80 return (NULL);
83 while (--n >= 0)
84 if (a[n] > 255)
85 return (NULL);
87 return (addrbuf);
90 /*
91 Returns a human-readable version of the LOC information or
92 NULL if it failed. Argument is a name (of a network or a machine)
93 and a boolean telling is it is a network name or a machine name.
95 char *
96 getlocbyname (name, is_network)
97 const char *name;
98 short is_network;
100 char *result;
101 struct list_in_addr *list, *p;
102 result = findRR (name, T_LOC);
103 if (result != NULL)
105 if (debug >= 2)
106 printf ("LOC record found for the name %s\n", name);
107 return result;
109 else
111 if (!is_network)
113 list = findA (name);
114 if (debug >= 2)
115 printf ("No LOC record found for the name %s, trying addresses\n", name);
116 if (list != NULL)
118 for (p = list; p != NULL; p = p->next)
120 if (debug >= 2)
121 printf ("Trying address %s\n", inet_ntoa (p->addr));
122 result = getlocbyaddr (p->addr, NULL);
123 if (result != NULL)
124 return result;
126 return NULL;
128 else
130 if (debug >= 2)
131 printf (" No A record found for %s\n", name);
132 return NULL;
135 else
137 if (debug >= 2)
138 printf ("No LOC record found for the network name %s\n", name);
139 return NULL;
145 Returns a human-readable version of the LOC information or
146 NULL if it failed. Argument is an IP address.
148 char *
149 getlocbyaddr (addr, mask)
150 const struct in_addr addr;
151 const struct in_addr *mask;
153 struct in_addr netaddr;
154 u_int32_t a;
155 struct in_addr themask;
156 char text_addr[sizeof("255.255.255.255")],
157 text_mask[sizeof("255.255.255.255")];
159 if (mask == NULL)
161 themask.s_addr = (u_int32_t) 0;
163 else
165 themask = *mask;
168 strcpy (text_addr, inet_ntoa (addr));
169 strcpy (text_mask, inet_ntoa (themask));
171 if (debug >= 2)
172 printf ("Testing address %s/%s\n", text_addr, text_mask);
174 if (mask == NULL)
176 a = ntohl (addr.s_addr);
177 if (IN_CLASSA (a))
179 netaddr.s_addr = htonl (a & IN_CLASSA_NET);
180 themask.s_addr = htonl(IN_CLASSA_NET);
182 else if (IN_CLASSB (a))
184 netaddr.s_addr = htonl (a & IN_CLASSB_NET);
185 themask.s_addr = htonl(IN_CLASSB_NET);
187 else if (IN_CLASSC (a))
189 netaddr.s_addr = htonl (a & IN_CLASSC_NET);
190 themask.s_addr = htonl(IN_CLASSC_NET);
192 else
194 /* Error */
195 return NULL;
197 return getlocbynet (in_addr_arpa (inet_ntoa (netaddr)), addr, &themask);
199 else
201 netaddr.s_addr = addr.s_addr & themask.s_addr;
202 return getlocbynet (in_addr_arpa (inet_ntoa (netaddr)), addr, mask);
207 Returns a human-readable LOC.
208 Argument is a network name in the 0.z.y.x.in-addr.arpa format
209 and the original address
211 char *
212 getlocbynet (name, addr, mask)
213 char *name;
214 struct in_addr addr;
215 struct in_addr *mask;
217 char *network;
218 char *result;
219 struct list_in_addr *list;
220 struct in_addr newmask;
221 u_int32_t a;
222 char newname[4 * 4 + sizeof (ARPA_ROOT) + 2];
224 if (debug >= 2)
225 printf ("Testing network %s with mask %s\n", name, inet_ntoa(*mask));
227 /* Check if this network has an A RR */
228 list = findA (name);
229 if (list != NULL)
231 /* Yes, it does. This A record will be used as the
232 * new mask for recursion if it is longer than
233 * the actual mask. */
234 if (mask != NULL && mask->s_addr < list->addr.s_addr)
236 /* compute the new arguments for recursion
237 * - compute the new network by applying the new mask
238 * to the address and get the in_addr_arpa representation
239 * of it.
240 * - the address remains unchanged
241 * - the new mask is the one given in the A record
243 a = ntohl(addr.s_addr); /* start from host address */
244 a &= ntohl(list->addr.s_addr); /* apply new mask */
245 newname[sizeof newname - 1] = 0;
246 strncpy(
247 newname,
248 in_addr_arpa(inet_ntoa(inet_makeaddr(a, 0))),
249 sizeof newname);
250 newmask = inet_makeaddr(ntohl(list->addr.s_addr), 0);
251 result = getlocbynet (newname, addr, &newmask);
252 if (result != NULL)
254 return result;
257 /* couldn't find a LOC. Fall through and try with name */
260 /* Check if this network has a name */
261 network = findRR (name, T_PTR);
262 if (network == NULL)
264 if (debug >= 2)
265 printf ("No name for network %s\n", name);
266 return NULL;
268 else
270 return getlocbyname (network, TRUE);
275 The code for these two functions is stolen from the examples in Liu and Albitz
276 book "DNS and BIND" (O'Reilly).
279 /****************************************************************
280 * skipName -- This routine skips over a domain name. If the *
281 * domain name expansion fails, it crashes. *
282 * dn_skipname() is probably not on your manual *
283 * page; it is similar to dn_expand() except that it just *
284 * skips over the name. dn_skipname() is in res_comp.c if *
285 * you need to find it. *
286 ****************************************************************/
288 skipName (cp, endOfMsg)
289 u_char *cp;
290 u_char *endOfMsg;
292 int n;
294 if ((n = dn_skipname (cp, endOfMsg)) < 0)
296 panic ("dn_skipname failed\n");
298 return (n);
301 /****************************************************************
302 * skipToData -- This routine advances the cp pointer to the *
303 * start of the resource record data portion. On the way, *
304 * it fills in the type, class, ttl, and data length *
305 ****************************************************************/
307 skipToData (cp, type, class, ttl, dlen, endOfMsg)
308 u_char *cp;
309 u_short *type;
310 u_short *class;
311 u_int32_t *ttl;
312 u_short *dlen;
313 u_char *endOfMsg;
315 u_char *tmp_cp = cp; /* temporary version of cp */
317 /* Skip the domain name; it matches the name we looked up */
318 tmp_cp += skipName (tmp_cp, endOfMsg);
321 * Grab the type, class, and ttl. GETSHORT and GETLONG
322 * are macros defined in arpa/nameser.h.
324 GETSHORT (*type, tmp_cp);
325 GETSHORT (*class, tmp_cp);
326 GETLONG (*ttl, tmp_cp);
327 GETSHORT (*dlen, tmp_cp);
329 return (tmp_cp - cp);
334 Returns a human-readable version of a DNS RR (resource record)
335 associated with the name 'domain'.
336 If it does not find, ir returns NULL and sets rr_errno to explain why.
338 The code for this function is stolen from the examples in Liu and Albitz
339 book "DNS and BIND" (O'Reilly).
341 char *
342 findRR (domain, requested_type)
343 char *domain;
344 int requested_type;
346 char *result, *message;
348 union
350 HEADER hdr; /* defined in resolv.h */
351 u_char buf[PACKETSZ]; /* defined in arpa/nameser.h */
353 response; /* response buffers */
354 short found = 0;
355 int responseLen; /* buffer length */
357 u_char *cp; /* character pointer to parse DNS packet */
358 u_char *endOfMsg; /* need to know the end of the message */
359 u_short class; /* classes defined in arpa/nameser.h */
360 u_short type; /* types defined in arpa/nameser.h */
361 u_int32_t ttl; /* resource record time to live */
362 u_short dlen; /* size of resource record data */
364 int i, count, dup; /* misc variables */
366 char *ptrList[1];
367 int ptrNum = 0;
368 struct in_addr addr;
370 result = (char *) malloc (256);
371 message = (char *) malloc (256);
373 * Look up the records for the given domain name.
374 * We expect the domain to be a fully qualified name, so
375 * we use res_query(). If we wanted the resolver search
376 * algorithm, we would have used res_search() instead.
378 if ((responseLen =
379 res_query (domain, /* the domain we care about */
380 C_IN, /* Internet class records */
381 requested_type, /* Look up name server records */
382 (u_char *) & response, /*response buffer */
383 sizeof (response))) /*buffer size */
384 < 0)
385 { /*If negative */
386 rr_errno = h_errno;
387 return NULL;
391 * Keep track of the end of the message so we don't
392 * pass it while parsing the response. responseLen is
393 * the value returned by res_query.
395 endOfMsg = response.buf + responseLen;
398 * Set a pointer to the start of the question section,
399 * which begins immediately AFTER the header.
401 cp = response.buf + sizeof (HEADER);
404 * Skip over the whole question section. The question
405 * section is comprised of a name, a type, and a class.
406 * QFIXEDSZ (defined in arpa/nameser.h) is the size of
407 * the type and class portions, which is fixed. Therefore,
408 * we can skip the question section by skipping the
409 * name (at the beginning) and then advancing QFIXEDSZ.
410 * After this calculation, cp points to the start of the
411 * answer section, which is a list of NS records.
413 cp += skipName (cp, endOfMsg) + QFIXEDSZ;
415 count = ntohs (response.hdr.ancount) +
416 ntohs (response.hdr.nscount);
417 while ((--count >= 0) /* still more records */
418 && (cp < endOfMsg))
419 { /* still inside the packet */
422 /* Skip to the data portion of the resource record */
423 cp += skipToData (cp, &type, &class, &ttl, &dlen, endOfMsg);
425 if (type == requested_type)
427 switch (requested_type)
429 case (T_LOC):
430 loc_ntoa (cp, result);
431 return result;
432 break;
433 case (T_PTR):
434 ptrList[ptrNum] = (char *) malloc (MAXDNAME);
435 if (ptrList[ptrNum] == NULL)
437 panic ("Malloc failed");
440 if (dn_expand (response.buf, /* Start of the packet */
441 endOfMsg, /* End of the packet */
442 cp, /* Position in the packet */
443 (char *) ptrList[ptrNum], /* Result */
444 MAXDNAME) /* size of ptrList buffer */
445 < 0)
446 { /* Negative: error */
447 panic ("dn_expand failed");
451 * Check the name we've just unpacked and add it to
452 * the list if it is not a duplicate.
453 * If it is a duplicate, just ignore it.
455 for (i = 0, dup = 0; (i < ptrNum) && !dup; i++)
456 dup = !strcasecmp (ptrList[i], ptrList[ptrNum]);
457 if (dup)
458 free (ptrList[ptrNum]);
459 else
460 ptrNum++;
461 strcpy (result, ptrList[0]);
462 return result;
463 break;
464 case (T_A):
465 bcopy ((char *) cp, (char *) &addr, INADDRSZ);
466 strcat (result, " ");
467 strcat (result, inet_ntoa (addr));
468 found = 1;
469 break;
470 default:
471 sprintf (message, "Unexpected type %u", requested_type);
472 panic (message);
476 /* Advance the pointer over the resource record data */
477 cp += dlen;
479 } /* end of while */
480 if (found)
481 return result;
482 else
483 return NULL;
486 struct list_in_addr *
487 findA (domain)
488 char *domain;
491 struct list_in_addr *result, *end;
493 union
495 HEADER hdr; /* defined in resolv.h */
496 u_char buf[PACKETSZ]; /* defined in arpa/nameser.h */
498 response; /* response buffers */
499 int responseLen; /* buffer length */
501 u_char *cp; /* character pointer to parse DNS packet */
502 u_char *endOfMsg; /* need to know the end of the message */
503 u_short class; /* classes defined in arpa/nameser.h */
504 u_short type; /* types defined in arpa/nameser.h */
505 u_int32_t ttl; /* resource record time to live */
506 u_short dlen; /* size of resource record data */
508 int count; /* misc variables */
510 struct in_addr addr;
512 end = NULL;
513 result = NULL;
516 * Look up the records for the given domain name.
517 * We expect the domain to be a fully qualified name, so
518 * we use res_query(). If we wanted the resolver search
519 * algorithm, we would have used res_search() instead.
521 if ((responseLen =
522 res_query (domain, /* the domain we care about */
523 C_IN, /* Internet class records */
524 T_A,
525 (u_char *) & response, /*response buffer */
526 sizeof (response))) /*buffer size */
527 < 0)
528 { /*If negative */
529 rr_errno = h_errno;
530 return NULL;
534 * Keep track of the end of the message so we don't
535 * pass it while parsing the response. responseLen is
536 * the value returned by res_query.
538 endOfMsg = response.buf + responseLen;
541 * Set a pointer to the start of the question section,
542 * which begins immediately AFTER the header.
544 cp = response.buf + sizeof (HEADER);
547 * Skip over the whole question section. The question
548 * section is comprised of a name, a type, and a class.
549 * QFIXEDSZ (defined in arpa/nameser.h) is the size of
550 * the type and class portions, which is fixed. Therefore,
551 * we can skip the question section by skipping the
552 * name (at the beginning) and then advancing QFIXEDSZ.
553 * After this calculation, cp points to the start of the
554 * answer section, which is a list of NS records.
556 cp += skipName (cp, endOfMsg) + QFIXEDSZ;
558 count = ntohs (response.hdr.ancount) +
559 ntohs (response.hdr.nscount);
560 while ((--count >= 0) /* still more records */
561 && (cp < endOfMsg))
562 { /* still inside the packet */
565 /* Skip to the data portion of the resource record */
566 cp += skipToData (cp, &type, &class, &ttl, &dlen, endOfMsg);
568 if (type == T_A)
570 bcopy ((char *) cp, (char *) &addr, INADDRSZ);
571 if (end == NULL)
573 result = (void *) malloc (sizeof (struct list_in_addr));
574 result->addr = addr;
575 result->next = NULL;
576 end = result;
578 else
580 end->next = (void *) malloc (sizeof (struct list_in_addr));
581 end = end->next;
582 end->addr = addr;
583 end->next = NULL;
587 /* Advance the pointer over the resource record data */
588 cp += dlen;
590 } /* end of while */
591 return result;