res_debug.c revision 7700f0f5c0ab90bf052e33fa0ddd2f2aa7e7893e
1/*
2 * Copyright (c) 1985
3 *    The Regents of the University of California.  All rights reserved.
4 *
5 * Portions copyright (c) 1999, 2000
6 * Intel Corporation.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * 3. All advertising materials mentioning features or use of this software
21 *    must display the following acknowledgement:
22 *
23 *    This product includes software developed by the University of
24 *    California, Berkeley, Intel Corporation, and its contributors.
25 *
26 * 4. Neither the name of University, Intel Corporation, or their respective
27 *    contributors may be used to endorse or promote products derived from
28 *    this software without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS, INTEL CORPORATION AND
31 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
32 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
33 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS,
34 * INTEL CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
40 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 *
42 */
43
44/*
45 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
46 *
47 * Permission to use, copy, modify, and distribute this software for any
48 * purpose with or without fee is hereby granted, provided that the above
49 * copyright notice and this permission notice appear in all copies, and that
50 * the name of Digital Equipment Corporation not be used in advertising or
51 * publicity pertaining to distribution of the document or software without
52 * specific, written prior permission.
53 *
54 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
55 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
56 * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
57 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
58 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
59 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
60 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
61 * SOFTWARE.
62 */
63
64/*
65 * Portions Copyright (c) 1995 by International Business Machines, Inc.
66 *
67 * International Business Machines, Inc. (hereinafter called IBM) grants
68 * permission under its copyrights to use, copy, modify, and distribute this
69 * Software with or without fee, provided that the above copyright notice and
70 * all paragraphs of this notice appear in all copies, and that the name of IBM
71 * not be used in connection with the marketing of any product incorporating
72 * the Software or modifications thereof, without specific, written prior
73 * permission.
74 *
75 * To the extent it has a right to do so, IBM grants an immunity from suit
76 * under its patents, if any, for the use, sale or manufacture of products to
77 * the extent that such products are used for performing Domain Name System
78 * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
79 * granted for any product per se or for any other function of any product.
80 *
81 * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
82 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
83 * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
84 * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
85 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
86 * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
87 */
88
89/*
90 * Portions Copyright (c) 1996 by Internet Software Consortium.
91 *
92 * Permission to use, copy, modify, and distribute this software for any
93 * purpose with or without fee is hereby granted, provided that the above
94 * copyright notice and this permission notice appear in all copies.
95 *
96 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
97 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
98 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
99 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
100 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
101 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
102 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
103 * SOFTWARE.
104 */
105
106#if defined(LIBC_SCCS) && !defined(lint)
107static char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93";
108static char rcsid[] = "$Id: res_debug.c,v 1.1.1.1 2003/11/19 01:51:36 kyu3 Exp $";
109#endif /* LIBC_SCCS and not lint */
110
111#include <sys/types.h>
112#include <sys/param.h>
113#include <sys/socket.h>
114
115#include <netinet/in.h>
116#include <arpa/inet.h>
117#include <arpa/nameser.h>
118
119#include <ctype.h>
120#include <errno.h>
121#include <math.h>
122#include <netdb.h>
123#include <resolv.h>
124#include <stdio.h>
125#include <stdlib.h>
126#include <string.h>
127#include <time.h>
128
129#define SPRINTF(x) sprintf x
130
131extern const char *_res_opcodes[];
132extern const char *_res_resultcodes[];
133extern const char *_res_sectioncodes[];
134
135/*
136 * Print the current options.
137 */
138void
139fp_resstat(struct __res_state *statp, FILE *file) {
140    u_long mask;
141
142    fprintf(file, ";; res options:");
143    if (!statp)
144        statp = &_res;
145    for (mask = 1;  mask != 0;  mask <<= 1)
146        if (statp->options & mask)
147            fprintf(file, " %s", p_option(mask));
148    putc('\n', file);
149}
150
151static void
152do_section(ns_msg *handle, ns_sect section, int pflag, FILE *file) {
153    int n, sflag, rrnum;
154    ns_opcode opcode;
155    ns_rr rr;
156
157    /*
158     * Print answer records.
159     */
160    sflag = (int)(_res.pfcode & pflag);
161    if (_res.pfcode && !sflag)
162        return;
163
164    opcode = ns_msg_getflag(*handle, ns_f_opcode);
165    rrnum = 0;
166    for (;;) {
167        if (ns_parserr(handle, section, rrnum, &rr)) {
168            if (errno != ENODEV)
169                fprintf(file, ";; ns_parserr: %s\n",
170                    strerror(errno));
171            else if (rrnum > 0 && sflag != 0 &&
172                 (_res.pfcode & RES_PRF_HEAD1))
173                putc('\n', file);
174            return;
175        }
176        if (rrnum == 0 && sflag != 0 && (_res.pfcode & RES_PRF_HEAD1))
177            fprintf(file, ";; %s SECTION:\n",
178                p_section(section, opcode));
179        if (section == ns_s_qd)
180            fprintf(file, ";;\t%s, type = %s, class = %s\n",
181                ns_rr_name(rr),
182                p_type(ns_rr_type(rr)),
183                p_class(ns_rr_class(rr)));
184        else {
185            char *buf;
186            buf = (char*)malloc(2024);
187            if (buf) {
188                n = ns_sprintrr(handle, &rr, NULL, NULL,
189                        buf, sizeof buf);
190                if (n < 0) {
191                    fprintf(file, ";; ns_sprintrr: %s\n",
192                        strerror(errno));
193                    free(buf);
194                    return;
195                }
196                fputs(buf, file);
197                fputc('\n', file);
198                free(buf);
199            }
200        }
201        rrnum++;
202    }
203}
204
205void
206p_query(const u_char *msg) {
207    fp_query(msg, stdout);
208}
209
210void
211fp_query(const u_char *msg, FILE *file) {
212    fp_nquery(msg, PACKETSZ, file);
213}
214
215/*
216 * Print the contents of a query.
217 * This is intended to be primarily a debugging routine.
218 */
219void
220fp_nquery(const u_char *msg, int len, FILE *file) {
221    ns_msg handle;
222    int qdcount, ancount, nscount, arcount;
223    u_int opcode, rcode, id;
224
225    if ((_res.options & RES_INIT) == 0 && res_init() == -1)
226        return;
227
228    if (ns_initparse(msg, len, &handle) < 0) {
229        fprintf(file, ";; ns_initparse: %s\n", strerror(errno));
230        return;
231    }
232    opcode = ns_msg_getflag(handle, ns_f_opcode);
233    rcode = ns_msg_getflag(handle, ns_f_rcode);
234    id = ns_msg_id(handle);
235    qdcount = ns_msg_count(handle, ns_s_qd);
236    ancount = ns_msg_count(handle, ns_s_an);
237    nscount = ns_msg_count(handle, ns_s_ns);
238    arcount = ns_msg_count(handle, ns_s_ar);
239
240    /*
241     * Print header fields.
242     */
243    if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX) || rcode)
244        fprintf(file,
245            ";; ->>HEADER<<- opcode: %s, status: %s, id: %d\n",
246            _res_opcodes[opcode], _res_resultcodes[rcode], (int)id);
247    if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX))
248        putc(';', file);
249    if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD2)) {
250        fprintf(file, "; flags:");
251        if (ns_msg_getflag(handle, ns_f_qr))
252            fprintf(file, " qr");
253        if (ns_msg_getflag(handle, ns_f_aa))
254            fprintf(file, " aa");
255        if (ns_msg_getflag(handle, ns_f_tc))
256            fprintf(file, " tc");
257        if (ns_msg_getflag(handle, ns_f_rd))
258            fprintf(file, " rd");
259        if (ns_msg_getflag(handle, ns_f_ra))
260            fprintf(file, " ra");
261        if (ns_msg_getflag(handle, ns_f_z))
262            fprintf(file, " ??");
263        if (ns_msg_getflag(handle, ns_f_ad))
264            fprintf(file, " ad");
265        if (ns_msg_getflag(handle, ns_f_cd))
266            fprintf(file, " cd");
267    }
268    if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD1)) {
269        fprintf(file, "; %s: %d",
270            p_section(ns_s_qd, (int)opcode), qdcount);
271        fprintf(file, ", %s: %d",
272            p_section(ns_s_an, (int)opcode), ancount);
273        fprintf(file, ", %s: %d",
274            p_section(ns_s_ns, (int)opcode), nscount);
275        fprintf(file, ", %s: %d",
276            p_section(ns_s_ar, (int)opcode), arcount);
277    }
278    if ((!_res.pfcode) || (_res.pfcode &
279        (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
280        putc('\n',file);
281    }
282    /*
283     * Print the various sections.
284     */
285    do_section(&handle, ns_s_qd, RES_PRF_QUES, file);
286    do_section(&handle, ns_s_an, RES_PRF_ANS, file);
287    do_section(&handle, ns_s_ns, RES_PRF_AUTH, file);
288    do_section(&handle, ns_s_ar, RES_PRF_ADD, file);
289    if (qdcount == 0 && ancount == 0 &&
290        nscount == 0 && arcount == 0)
291        putc('\n', file);
292}
293
294const u_char *
295p_cdnname(const u_char *cp, const u_char *msg, int len, FILE *file) {
296    char name[MAXDNAME];
297    int n;
298
299    if ((n = dn_expand(msg, msg + len, cp, name, sizeof name)) < 0)
300        return (NULL);
301    if (name[0] == '\0')
302        putc('.', file);
303    else
304        fputs(name, file);
305    return (cp + n);
306}
307
308const u_char *
309p_cdname(const u_char *cp, const u_char *msg, FILE *file) {
310    return (p_cdnname(cp, msg, PACKETSZ, file));
311}
312
313/* Return a fully-qualified domain name from a compressed name (with
314   length supplied).  */
315
316const u_char *
317p_fqnname(
318    const u_char *cp,
319    const u_char *msg,
320    int msglen,
321    char *name,
322    int namelen
323    )
324{
325    int n, newlen;
326
327    if ((n = dn_expand(msg, cp + msglen, cp, name, namelen)) < 0)
328        return (NULL);
329    newlen = (int)strlen(name);
330    if (newlen == 0 || name[newlen - 1] != '.') {
331        if (newlen + 1 >= namelen)  /* Lack space for final dot */
332            return (NULL);
333        else
334            strcpy(name + newlen, ".");
335    }
336    return (cp + n);
337}
338
339/* XXX: the rest of these functions need to become length-limited, too. */
340
341const u_char *
342p_fqname(const u_char *cp, const u_char *msg, FILE *file) {
343    char name[MAXDNAME];
344    const u_char *n;
345
346    n = p_fqnname(cp, msg, MAXCDNAME, name, sizeof name);
347    if (n == NULL)
348        return (NULL);
349    fputs(name, file);
350    return (n);
351}
352
353/*
354 * Names of RR classes and qclasses.  Classes and qclasses are the same, except
355 * that C_ANY is a qclass but not a class.  (You can ask for records of class
356 * C_ANY, but you can't have any records of that class in the database.)
357 */
358const struct res_sym __p_class_syms[] = {
359    {C_IN,      "IN"},
360    {C_CHAOS,   "CHAOS"},
361    {C_HS,      "HS"},
362    {C_HS,      "HESIOD"},
363    {C_ANY,     "ANY"},
364    {C_NONE,    "NONE"},
365    {C_IN,      (char *)0}
366};
367
368/*
369 * Names of message sections.
370 */
371const struct res_sym __p_default_section_syms[] = {
372    {ns_s_qd,   "QUERY"},
373    {ns_s_an,   "ANSWER"},
374    {ns_s_ns,   "AUTHORITY"},
375    {ns_s_ar,   "ADDITIONAL"},
376    {0,             (char *)0}
377};
378
379const struct res_sym __p_update_section_syms[] = {
380    {S_ZONE,    "ZONE"},
381    {S_PREREQ,  "PREREQUISITE"},
382    {S_UPDATE,  "UPDATE"},
383    {S_ADDT,    "ADDITIONAL"},
384    {0,             (char *)0}
385};
386
387/*
388 * Names of RR types and qtypes.  Types and qtypes are the same, except
389 * that T_ANY is a qtype but not a type.  (You can ask for records of type
390 * T_ANY, but you can't have any records of that type in the database.)
391 */
392const struct res_sym __p_type_syms[] = {
393    {T_A,       "A",        "address"},
394    {T_NS,      "NS",       "name server"},
395    {T_MD,      "MD",       "mail destination (deprecated)"},
396    {T_MF,      "MF",       "mail forwarder (deprecated)"},
397    {T_CNAME,   "CNAME",    "canonical name"},
398    {T_SOA,     "SOA",      "start of authority"},
399    {T_MB,      "MB",       "mailbox"},
400    {T_MG,      "MG",       "mail group member"},
401    {T_MR,      "MR",       "mail rename"},
402    {T_NULL,    "NULL",     "null"},
403    {T_WKS,     "WKS",      "well-known service (deprecated)"},
404    {T_PTR,     "PTR",      "domain name pointer"},
405    {T_HINFO,   "HINFO",    "host information"},
406    {T_MINFO,   "MINFO",    "mailbox information"},
407    {T_MX,      "MX",       "mail exchanger"},
408    {T_TXT,     "TXT",      "text"},
409    {T_RP,      "RP",       "responsible person"},
410    {T_AFSDB,   "AFSDB",    "DCE or AFS server"},
411    {T_X25,     "X25",      "X25 address"},
412    {T_ISDN,    "ISDN",     "ISDN address"},
413    {T_RT,      "RT",       "router"},
414    {T_NSAP,    "NSAP",     "nsap address"},
415    {T_NSAP_PTR,    "NSAP_PTR", "domain name pointer"},
416    {T_SIG,     "SIG",      "signature"},
417    {T_KEY,     "KEY",      "key"},
418    {T_PX,      "PX",       "mapping information"},
419    {T_GPOS,    "GPOS",     "geographical position (withdrawn)"},
420    {T_AAAA,    "AAAA",     "IPv6 address"},
421    {T_LOC,     "LOC",      "location"},
422    {T_NXT,     "NXT",      "next valid name (unimplemented)"},
423    {T_EID,     "EID",      "endpoint identifier (unimplemented)"},
424    {T_NIMLOC,  "NIMLOC",   "NIMROD locator (unimplemented)"},
425    {T_SRV,     "SRV",      "server selection"},
426    {T_ATMA,    "ATMA",     "ATM address (unimplemented)"},
427    {T_IXFR,    "IXFR",     "incremental zone transfer"},
428    {T_AXFR,    "AXFR",     "zone transfer"},
429    {T_MAILB,   "MAILB",    "mailbox-related data (deprecated)"},
430    {T_MAILA,   "MAILA",    "mail agent (deprecated)"},
431    {T_NAPTR,   "NAPTR",    "URN Naming Authority"},
432    {T_ANY,     "ANY",      "\"any\""},
433    {0,         NULL,       NULL}
434};
435
436int
437sym_ston(const struct res_sym *syms, const char *name, int *success) {
438    for ((void)NULL; syms->name != 0; syms++) {
439        if (strcasecmp (name, syms->name) == 0) {
440            if (success)
441                *success = 1;
442            return (syms->number);
443        }
444    }
445    if (success)
446        *success = 0;
447    return (syms->number);      /* The default value. */
448}
449
450const char *
451sym_ntos(const struct res_sym *syms, int number, int *success) {
452    static char unname[20];
453
454    for ((void)NULL; syms->name != 0; syms++) {
455        if (number == syms->number) {
456            if (success)
457                *success = 1;
458            return (syms->name);
459        }
460    }
461
462    sprintf(unname, "%d", number);
463    if (success)
464        *success = 0;
465    return (unname);
466}
467
468const char *
469sym_ntop(const struct res_sym *syms, int number, int *success) {
470    static char unname[20];
471
472    for ((void)NULL; syms->name != 0; syms++) {
473        if (number == syms->number) {
474            if (success)
475                *success = 1;
476            return (syms->humanname);
477        }
478    }
479    sprintf(unname, "%d", number);
480    if (success)
481        *success = 0;
482    return (unname);
483}
484
485/*
486 * Return a string for the type.
487 */
488const char *
489p_type(int type) {
490    return (sym_ntos(__p_type_syms, type, (int *)0));
491}
492
493/*
494 * Return a string for the type.
495 */
496const char *
497p_section(int section, int opcode) {
498    const struct res_sym *symbols;
499
500    switch (opcode) {
501    case ns_o_update:
502        symbols = __p_update_section_syms;
503        break;
504    default:
505        symbols = __p_default_section_syms;
506        break;
507    }
508    return (sym_ntos(symbols, section, (int *)0));
509}
510
511/*
512 * Return a mnemonic for class.
513 */
514const char *
515p_class(int class) {
516    return (sym_ntos(__p_class_syms, class, (int *)0));
517}
518
519/*
520 * Return a mnemonic for an option
521 */
522const char *
523p_option(u_long option) {
524    static char nbuf[40];
525
526    switch (option) {
527    case RES_INIT:      return "init";
528    case RES_DEBUG:     return "debug";
529    case RES_AAONLY:    return "aaonly(unimpl)";
530    case RES_USEVC:     return "usevc";
531    case RES_PRIMARY:   return "primry(unimpl)";
532    case RES_IGNTC:     return "igntc";
533    case RES_RECURSE:   return "recurs";
534    case RES_DEFNAMES:  return "defnam";
535    case RES_STAYOPEN:  return "styopn";
536    case RES_DNSRCH:    return "dnsrch";
537    case RES_INSECURE1: return "insecure1";
538    case RES_INSECURE2: return "insecure2";
539    default:        sprintf(nbuf, "?0x%Lx?", (u_long)option);
540                return (nbuf);
541    }
542}
543
544/*
545 * Return a mnemonic for a time to live.
546 */
547const char *
548p_time(u_int32_t value) {
549    static char nbuf[40];
550
551    if (ns_format_ttl(value, nbuf, sizeof nbuf) < 0)
552        sprintf(nbuf, "%u", value);
553    return (nbuf);
554}
555
556
557/*
558 * routines to convert between on-the-wire RR format and zone file format.
559 * Does not contain conversion to/from decimal degrees; divide or multiply
560 * by 60*60*1000 for that.
561 */
562
563static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
564                      1000000,10000000,100000000,1000000000};
565
566/* takes an XeY precision/size value, returns a string representation. */
567static const char *
568precsize_ntoa(
569    u_int8_t prec
570    )
571{
572    static char retbuf[sizeof "90000000.00"];
573    unsigned long val;
574    int mantissa, exponent;
575
576    mantissa = (int)((prec >> 4) & 0x0f) % 10;
577    exponent = (int)((prec >> 0) & 0x0f) % 10;
578
579    val = mantissa * poweroften[exponent];
580
581    (void) sprintf(retbuf, "%ld.%.2ld", val/100, val%100);
582    return (retbuf);
583}
584
585/* converts ascii size/precision X * 10**Y(cm) to 0xXY.  moves pointer. */
586static u_int8_t
587precsize_aton(
588    char **strptr
589    )
590{
591    unsigned int mval = 0, cmval = 0;
592    u_int8_t retval = 0;
593    char *cp;
594    int exponent;
595    int mantissa;
596
597    cp = *strptr;
598
599    while (isdigit(*cp))
600        mval = mval * 10 + (*cp++ - '0');
601
602    if (*cp == '.') {       /* centimeters */
603        cp++;
604        if (isdigit(*cp)) {
605            cmval = (*cp++ - '0') * 10;
606            if (isdigit(*cp)) {
607                cmval += (*cp++ - '0');
608            }
609        }
610    }
611    cmval = (mval * 100) + cmval;
612
613    for (exponent = 0; exponent < 9; exponent++)
614        if (cmval < poweroften[exponent+1])
615            break;
616
617    mantissa = cmval / poweroften[exponent];
618    if (mantissa > 9)
619        mantissa = 9;
620
621    retval = (u_int8_t)((mantissa << 4) | exponent);
622
623    *strptr = cp;
624
625    return (retval);
626}
627
628/* converts ascii lat/lon to unsigned encoded 32-bit number.  moves pointer. */
629static u_int32_t
630latlon2ul(
631    char **latlonstrptr,
632    int *which
633    )
634{
635    char *cp;
636    u_int32_t retval;
637    int deg = 0, min = 0, secs = 0, secsfrac = 0;
638
639    cp = *latlonstrptr;
640
641    while (isdigit(*cp))
642        deg = deg * 10 + (*cp++ - '0');
643
644    while (isspace(*cp))
645        cp++;
646
647    if (!(isdigit(*cp)))
648        goto fndhemi;
649
650    while (isdigit(*cp))
651        min = min * 10 + (*cp++ - '0');
652
653    while (isspace(*cp))
654        cp++;
655
656    if (!(isdigit(*cp)))
657        goto fndhemi;
658
659    while (isdigit(*cp))
660        secs = secs * 10 + (*cp++ - '0');
661
662    if (*cp == '.') {       /* decimal seconds */
663        cp++;
664        if (isdigit(*cp)) {
665            secsfrac = (*cp++ - '0') * 100;
666            if (isdigit(*cp)) {
667                secsfrac += (*cp++ - '0') * 10;
668                if (isdigit(*cp)) {
669                    secsfrac += (*cp++ - '0');
670                }
671            }
672        }
673    }
674
675    while (!isspace(*cp))   /* if any trailing garbage */
676        cp++;
677
678    while (isspace(*cp))
679        cp++;
680
681 fndhemi:
682    switch (*cp) {
683    case 'N': case 'n':
684    case 'E': case 'e':
685        retval = ((unsigned)1<<31)
686            + (((((deg * 60) + min) * 60) + secs) * 1000)
687            + secsfrac;
688        break;
689    case 'S': case 's':
690    case 'W': case 'w':
691        retval = ((unsigned)1<<31)
692            - (((((deg * 60) + min) * 60) + secs) * 1000)
693            - secsfrac;
694        break;
695    default:
696        retval = 0; /* invalid value -- indicates error */
697        break;
698    }
699
700    switch (*cp) {
701    case 'N': case 'n':
702    case 'S': case 's':
703        *which = 1; /* latitude */
704        break;
705    case 'E': case 'e':
706    case 'W': case 'w':
707        *which = 2; /* longitude */
708        break;
709    default:
710        *which = 0; /* error */
711        break;
712    }
713
714    cp++;           /* skip the hemisphere */
715
716    while (!isspace(*cp))   /* if any trailing garbage */
717        cp++;
718
719    while (isspace(*cp))    /* move to next field */
720        cp++;
721
722    *latlonstrptr = cp;
723
724    return (retval);
725}
726
727/* converts a zone file representation in a string to an RDATA on-the-wire
728 * representation. */
729int
730loc_aton(
731    const char *ascii,
732    u_char *binary
733    )
734{
735    const char *cp, *maxcp;
736    u_char *bcp;
737
738    u_int32_t latit = 0, longit = 0, alt = 0;
739    u_int32_t lltemp1 = 0, lltemp2 = 0;
740    int altmeters = 0, altfrac = 0, altsign = 1;
741    u_int8_t hp = 0x16; /* default = 1e6 cm = 10000.00m = 10km */
742    u_int8_t vp = 0x13; /* default = 1e3 cm = 10.00m */
743    u_int8_t siz = 0x12;    /* default = 1e2 cm = 1.00m */
744    int which1 = 0, which2 = 0;
745
746    cp = ascii;
747    maxcp = cp + strlen(ascii);
748
749    lltemp1 = latlon2ul((char **)&cp, &which1);
750
751    lltemp2 = latlon2ul((char **)&cp, &which2);
752
753    switch (which1 + which2) {
754    case 3:         /* 1 + 2, the only valid combination */
755        if ((which1 == 1) && (which2 == 2)) { /* normal case */
756            latit = lltemp1;
757            longit = lltemp2;
758        } else if ((which1 == 2) && (which2 == 1)) { /* reversed */
759            longit = lltemp1;
760            latit = lltemp2;
761        } else {    /* some kind of brokenness */
762            return (0);
763        }
764        break;
765    default:        /* we didn't get one of each */
766        return (0);
767    }
768
769    /* altitude */
770    if (*cp == '-') {
771        altsign = -1;
772        cp++;
773    }
774
775    if (*cp == '+')
776        cp++;
777
778    while (isdigit(*cp))
779        altmeters = altmeters * 10 + (*cp++ - '0');
780
781    if (*cp == '.') {       /* decimal meters */
782        cp++;
783        if (isdigit(*cp)) {
784            altfrac = (*cp++ - '0') * 10;
785            if (isdigit(*cp)) {
786                altfrac += (*cp++ - '0');
787            }
788        }
789    }
790
791    alt = (10000000 + (altsign * (altmeters * 100 + altfrac)));
792
793    while (!isspace(*cp) && (cp < maxcp)) /* if trailing garbage or m */
794        cp++;
795
796    while (isspace(*cp) && (cp < maxcp))
797        cp++;
798
799    if (cp >= maxcp)
800        goto defaults;
801
802    siz = precsize_aton((char **)&cp);
803
804    while (!isspace(*cp) && (cp < maxcp))   /* if trailing garbage or m */
805        cp++;
806
807    while (isspace(*cp) && (cp < maxcp))
808        cp++;
809
810    if (cp >= maxcp)
811        goto defaults;
812
813    hp = precsize_aton((char **)&cp);
814
815    while (!isspace(*cp) && (cp < maxcp))   /* if trailing garbage or m */
816        cp++;
817
818    while (isspace(*cp) && (cp < maxcp))
819        cp++;
820
821    if (cp >= maxcp)
822        goto defaults;
823
824    vp = precsize_aton((char **)&cp);
825
826 defaults:
827
828    bcp = binary;
829    *bcp++ = (u_int8_t) 0;  /* version byte */
830    *bcp++ = siz;
831    *bcp++ = hp;
832    *bcp++ = vp;
833    PUTLONG(latit,bcp);
834    PUTLONG(longit,bcp);
835    PUTLONG(alt,bcp);
836
837    return (16);        /* size of RR in octets */
838}
839
840/* takes an on-the-wire LOC RR and formats it in a human readable format. */
841const char *
842loc_ntoa(
843    const u_char *binary,
844    char *ascii
845    )
846{
847    static char *error = "?";
848    const u_char *cp = binary;
849
850    int latdeg, latmin, latsec, latsecfrac;
851    int longdeg, longmin, longsec, longsecfrac;
852    char northsouth, eastwest;
853    int altmeters, altfrac, altsign;
854
855    const u_int32_t referencealt = 100000 * 100;
856
857    int32_t latval, longval, altval;
858    u_int32_t templ;
859    u_int8_t sizeval, hpval, vpval, versionval;
860
861    char *sizestr, *hpstr, *vpstr;
862
863    versionval = *cp++;
864
865    if (versionval) {
866        (void) sprintf(ascii, "; error: unknown LOC RR version");
867        return (ascii);
868    }
869
870    sizeval = *cp++;
871
872    hpval = *cp++;
873    vpval = *cp++;
874
875    GETLONG(templ, cp);
876    latval = (templ - ((unsigned)1<<31));
877
878    GETLONG(templ, cp);
879    longval = (templ - ((unsigned)1<<31));
880
881    GETLONG(templ, cp);
882    if (templ < referencealt) { /* below WGS 84 spheroid */
883        altval = referencealt - templ;
884        altsign = -1;
885    } else {
886        altval = templ - referencealt;
887        altsign = 1;
888    }
889
890    if (latval < 0) {
891        northsouth = 'S';
892        latval = -latval;
893    } else
894        northsouth = 'N';
895
896    latsecfrac = latval % 1000;
897    latval = latval / 1000;
898    latsec = latval % 60;
899    latval = latval / 60;
900    latmin = latval % 60;
901    latval = latval / 60;
902    latdeg = latval;
903
904    if (longval < 0) {
905        eastwest = 'W';
906        longval = -longval;
907    } else
908        eastwest = 'E';
909
910    longsecfrac = longval % 1000;
911    longval = longval / 1000;
912    longsec = longval % 60;
913    longval = longval / 60;
914    longmin = longval % 60;
915    longval = longval / 60;
916    longdeg = longval;
917
918    altfrac = altval % 100;
919    altmeters = (altval / 100) * altsign;
920
921    if ((sizestr = strdup(precsize_ntoa(sizeval))) == NULL)
922        sizestr = error;
923    if ((hpstr = strdup(precsize_ntoa(hpval))) == NULL)
924        hpstr = error;
925    if ((vpstr = strdup(precsize_ntoa(vpval))) == NULL)
926        vpstr = error;
927
928    sprintf(ascii,
929          "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %d.%.2dm %sm %sm %sm",
930        latdeg, latmin, latsec, latsecfrac, northsouth,
931        longdeg, longmin, longsec, longsecfrac, eastwest,
932        altmeters, altfrac, sizestr, hpstr, vpstr);
933
934    if (sizestr != error)
935        free(sizestr);
936    if (hpstr != error)
937        free(hpstr);
938    if (vpstr != error)
939        free(vpstr);
940
941    return (ascii);
942}
943
944
945/* Return the number of DNS hierarchy levels in the name. */
946int
947dn_count_labels(const char *name) {
948    int i, len, count;
949
950    len = (int)strlen(name);
951    for (i = 0, count = 0; i < len; i++) {
952        /* XXX need to check for \. or use named's nlabels(). */
953        if (name[i] == '.')
954            count++;
955    }
956
957    /* don't count initial wildcard */
958    if (name[0] == '*')
959        if (count)
960            count--;
961
962    /* don't count the null label for root. */
963    /* if terminating '.' not found, must adjust */
964    /* count to include last label */
965    if (len > 0 && name[len-1] != '.')
966        count++;
967    return (count);
968}
969
970
971/*
972 * Make dates expressed in seconds-since-Jan-1-1970 easy to read.
973 * SIG records are required to be printed like this, by the Secure DNS RFC.
974 */
975char *
976p_secstodate (u_long secs) {
977    static char output[15];     /* YYYYMMDDHHMMSS and null */
978    time_t clock = (time_t)secs;
979    struct tm *time;
980
981    time = gmtime(&clock);
982    time->tm_year += 1900;
983    time->tm_mon += 1;
984    sprintf(output, "%04d%02d%02d%02d%02d%02d",
985        time->tm_year, time->tm_mon, time->tm_mday,
986        time->tm_hour, time->tm_min, time->tm_sec);
987    return (output);
988}
989