"Fossies" - the Fresh Open Source Software Archive

Member "xymon-4.3.30/xymonnet/dns2.c" (23 Jul 2019, 15653 Bytes) of package /linux/privat/xymon-4.3.30.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dns2.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.3.29_vs_4.3.30.

    1 /*----------------------------------------------------------------------------*/
    2 /* Xymon monitor network test tool.                                           */
    3 /*                                                                            */
    4 /* Copyright (C) 2004-2011 Henrik Storner <henrik@hswn.dk>                    */
    5 /*                                                                            */
    6 /* This program is released under the GNU General Public License (GPL),       */
    7 /* version 2. See the file "COPYING" for details.                             */
    8 /*                                                                            */
    9 /*----------------------------------------------------------------------------*/
   10 
   11 static char rcsid[] = "$Id: dns2.c 8069 2019-07-23 15:29:06Z jccleaver $";
   12 
   13 /*
   14  * All of the code for parsing DNS responses and formatting these into
   15  * text were taken from the "adig.c" source-file included with the
   16  * C-ARES 1.2.0 library. This file carries the following copyright
   17  * notice, reproduced in full:
   18  *
   19  * --------------------------------------------------------------------
   20  * Copyright 1998 by the Massachusetts Institute of Technology.
   21  *
   22  * Permission to use, copy, modify, and distribute this
   23  * software and its documentation for any purpose and without
   24  * fee is hereby granted, provided that the above copyright
   25  * notice appear in all copies and that both that copyright
   26  * notice and this permission notice appear in supporting
   27  * documentation, and that the name of M.I.T. not be used in
   28  * advertising or publicity pertaining to distribution of the
   29  * software without specific, written prior permission.
   30  * M.I.T. makes no representations about the suitability of
   31  * this software for any purpose.  It is provided "as is"
   32  * without express or implied warranty.
   33  * --------------------------------------------------------------------
   34  */
   35 
   36 #include <sys/types.h>
   37 #include <netinet/in.h>
   38 #include <arpa/inet.h>
   39 #include <arpa/nameser.h>
   40 #include <unistd.h>
   41 #include <stdlib.h>
   42 #include <stdio.h>
   43 #include <string.h>
   44 #include <netdb.h>
   45 
   46 #include "libxymon.h"
   47 
   48 #include <ares.h>
   49 #include <ares_dns.h>
   50 #include <ares_version.h>
   51 
   52 #include "dns2.h"
   53 
   54 /* Some systems (AIX, HP-UX) don't know the DNS T_SRV record */
   55 #ifndef T_SRV
   56 #define T_SRV 33
   57 #endif
   58 
   59 static char msg[1024];
   60 
   61 static const unsigned char *display_question(const unsigned char *aptr,
   62                          const unsigned char *abuf, int alen,
   63                          dns_resp_t *response);
   64 static const unsigned char *display_rr(const unsigned char *aptr,
   65                        const unsigned char *abuf, int alen,
   66                        dns_resp_t *response);
   67 static const char *type_name(int type);
   68 static const char *class_name(int dnsclass);
   69 
   70 struct nv {
   71   const char *name;
   72   int value;
   73 };
   74 
   75 static const struct nv flags[] = {
   76   { "usevc",        ARES_FLAG_USEVC },
   77   { "primary",      ARES_FLAG_PRIMARY },
   78   { "igntc",        ARES_FLAG_IGNTC },
   79   { "norecurse",    ARES_FLAG_NORECURSE },
   80   { "stayopen",     ARES_FLAG_STAYOPEN },
   81   { "noaliases",    ARES_FLAG_NOALIASES }
   82 };
   83 static const int nflags = sizeof(flags) / sizeof(flags[0]);
   84 
   85 static const struct nv classes[] = {
   86   { "IN",   C_IN },
   87   { "CHAOS",    C_CHAOS },
   88   { "HS",   C_HS },
   89   { "ANY",  C_ANY }
   90 };
   91 static const int nclasses = sizeof(classes) / sizeof(classes[0]);
   92 
   93 static const struct nv types[] = {
   94   { "A",    T_A },
   95   { "NS",   T_NS },
   96   { "MD",   T_MD },
   97   { "MF",   T_MF },
   98   { "CNAME",    T_CNAME },
   99   { "SOA",  T_SOA },
  100   { "MB",   T_MB },
  101   { "MG",   T_MG },
  102   { "MR",   T_MR },
  103   { "NULL", T_NULL },
  104   { "WKS",  T_WKS },
  105   { "PTR",  T_PTR },
  106   { "HINFO",    T_HINFO },
  107   { "MINFO",    T_MINFO },
  108   { "MX",   T_MX },
  109   { "TXT",  T_TXT },
  110   { "RP",   T_RP },
  111   { "AFSDB",    T_AFSDB },
  112   { "X25",  T_X25 },
  113   { "ISDN", T_ISDN },
  114   { "RT",   T_RT },
  115   { "NSAP", T_NSAP },
  116   { "NSAP_PTR", T_NSAP_PTR },
  117   { "SIG",  T_SIG },
  118   { "KEY",  T_KEY },
  119   { "PX",   T_PX },
  120   { "GPOS", T_GPOS },
  121   { "AAAA", T_AAAA },
  122   { "LOC",  T_LOC },
  123   { "SRV",  T_SRV },
  124   { "AXFR", T_AXFR },
  125   { "MAILB",    T_MAILB },
  126   { "MAILA",    T_MAILA },
  127   { "ANY",  T_ANY }
  128 };
  129 static const int ntypes = sizeof(types) / sizeof(types[0]);
  130 
  131 static const char *opcodes[] = {
  132   "QUERY", "IQUERY", "STATUS", "(reserved)", "NOTIFY",
  133   "(unknown)", "(unknown)", "(unknown)", "(unknown)",
  134   "UPDATEA", "UPDATED", "UPDATEDA", "UPDATEM", "UPDATEMA",
  135   "ZONEINIT", "ZONEREF"
  136 };
  137 
  138 static const char *rcodes[] = {
  139   "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED",
  140   "(unknown)", "(unknown)", "(unknown)", "(unknown)", "(unknown)",
  141   "(unknown)", "(unknown)", "(unknown)", "(unknown)", "NOCHANGE"
  142 };
  143 
  144 void dns_detail_callback(void *arg, int status, int timeouts, unsigned char *abuf, int alen)
  145 {
  146     int id, qr, opcode, aa, tc, rd, ra, rcode;
  147     unsigned int qdcount, ancount, nscount, arcount, i;
  148     const unsigned char *aptr;
  149     dns_resp_t *response = (dns_resp_t *) arg;
  150 
  151     clearstrbuffer(response->msgbuf);
  152     response->msgstatus = status;
  153 
  154     /*
  155      * Display an error message if there was an error, but only stop if
  156      * we actually didn't get an answer buffer.
  157      */
  158     switch (status) {
  159       case ARES_SUCCESS: 
  160           break;
  161       case ARES_ENODATA:
  162           addtobuffer(response->msgbuf, "No data returned from server\n");
  163           if (!abuf) return;
  164           break;
  165       case ARES_EFORMERR:
  166           addtobuffer(response->msgbuf, "Server could not understand query\n");
  167           if (!abuf) return;
  168           break;
  169       case ARES_ESERVFAIL:
  170           addtobuffer(response->msgbuf, "Server failed\n");
  171           if (!abuf) return;
  172           break;
  173       case ARES_ENOTFOUND:
  174           addtobuffer(response->msgbuf, "Name not found\n");
  175           if (!abuf) return;
  176           break;
  177       case ARES_ENOTIMP:
  178           addtobuffer(response->msgbuf, "Not implemented\n");
  179           if (!abuf) return;
  180           break;
  181       case ARES_EREFUSED:
  182           addtobuffer(response->msgbuf, "Server refused query\n");
  183           if (!abuf) return;
  184           break;
  185       case ARES_EBADNAME:
  186           addtobuffer(response->msgbuf, "Invalid name in query\n");
  187           if (!abuf) return;
  188           break;
  189       case ARES_ETIMEOUT:
  190           addtobuffer(response->msgbuf, "Timeout\n");
  191           if (!abuf) return;
  192           break;
  193       case ARES_ECONNREFUSED:
  194           addtobuffer(response->msgbuf, "Server unavailable\n");
  195           if (!abuf) return;
  196           break;
  197       case ARES_ENOMEM:
  198           addtobuffer(response->msgbuf, "Out of memory\n");
  199           if (!abuf) return;
  200           break;
  201       case ARES_EDESTRUCTION:
  202           addtobuffer(response->msgbuf, "Timeout (channel destroyed)\n");
  203           if (!abuf) return;
  204           break;
  205       default:
  206           addtobuffer(response->msgbuf, "Undocumented ARES return code\n");
  207           if (!abuf) return;
  208           break;
  209     }
  210 
  211     /* Won't happen, but check anyway, for safety. */
  212     if (alen < HFIXEDSZ) return;
  213 
  214     /* Parse the answer header. */
  215     id = DNS_HEADER_QID(abuf);
  216     qr = DNS_HEADER_QR(abuf);
  217     opcode = DNS_HEADER_OPCODE(abuf);
  218     aa = DNS_HEADER_AA(abuf);
  219     tc = DNS_HEADER_TC(abuf);
  220     rd = DNS_HEADER_RD(abuf);
  221     ra = DNS_HEADER_RA(abuf);
  222     rcode = DNS_HEADER_RCODE(abuf);
  223     qdcount = DNS_HEADER_QDCOUNT(abuf);
  224     ancount = DNS_HEADER_ANCOUNT(abuf);
  225     nscount = DNS_HEADER_NSCOUNT(abuf);
  226     arcount = DNS_HEADER_ARCOUNT(abuf);
  227 
  228     /* Display the answer header. */
  229     snprintf(msg, sizeof(msg), "id: %d\n", id);
  230     addtobuffer(response->msgbuf, msg);
  231     snprintf(msg, sizeof(msg), "flags: %s%s%s%s%s\n",
  232         qr ? "qr " : "",
  233         aa ? "aa " : "",
  234         tc ? "tc " : "",
  235         rd ? "rd " : "",
  236         ra ? "ra " : "");
  237     addtobuffer(response->msgbuf, msg);
  238     snprintf(msg, sizeof(msg), "opcode: %s\n", opcodes[opcode]);
  239     addtobuffer(response->msgbuf, msg);
  240     snprintf(msg, sizeof(msg), "rcode: %s\n", rcodes[rcode]);
  241     addtobuffer(response->msgbuf, msg);
  242 
  243     /* Display the questions. */
  244     addtobuffer(response->msgbuf, "Questions:\n");
  245     aptr = abuf + HFIXEDSZ;
  246     for (i = 0; i < qdcount; i++) {
  247         aptr = display_question(aptr, abuf, alen, response);
  248         if (aptr == NULL) return;
  249     }
  250 
  251     /* Display the answers. */
  252     addtobuffer(response->msgbuf, "Answers:\n");
  253     for (i = 0; i < ancount; i++) {
  254         aptr = display_rr(aptr, abuf, alen, response);
  255         if (aptr == NULL) return;
  256     }
  257 
  258     /* Display the NS records. */
  259     addtobuffer(response->msgbuf, "NS records:\n");
  260     for (i = 0; i < nscount; i++) {
  261         aptr = display_rr(aptr, abuf, alen, response);
  262         if (aptr == NULL) return;
  263     }
  264 
  265     /* Display the additional records. */
  266     addtobuffer(response->msgbuf, "Additional records:\n");
  267     for (i = 0; i < arcount; i++) {
  268         aptr = display_rr(aptr, abuf, alen, response);
  269         if (aptr == NULL) return;
  270     }
  271 
  272     return;
  273 }
  274 
  275 static const unsigned char *display_question(const unsigned char *aptr,
  276                          const unsigned char *abuf, int alen,
  277                          dns_resp_t *response)
  278 {
  279     char *name;
  280     int type, dnsclass, status;
  281     long len;
  282 
  283     /* Parse the question name. */
  284     status = ares_expand_name(aptr, abuf, alen, &name, &len);
  285     if (status != ARES_SUCCESS) return NULL;
  286     aptr += len;
  287 
  288     /* Make sure there's enough data after the name for the fixed part
  289      * of the question.
  290      */
  291     if (aptr + QFIXEDSZ > abuf + alen) {
  292         xfree(name);
  293         return NULL;
  294     }
  295 
  296     /* Parse the question type and class. */
  297     type = DNS_QUESTION_TYPE(aptr);
  298     dnsclass = DNS_QUESTION_CLASS(aptr);
  299     aptr += QFIXEDSZ;
  300 
  301     /*
  302      * Display the question, in a format sort of similar to how we will
  303      * display RRs.
  304      */
  305     snprintf(msg, sizeof(msg), "\t%-15s.\t", name);
  306     addtobuffer(response->msgbuf, msg);
  307     if (dnsclass != C_IN) {
  308         snprintf(msg, sizeof(msg), "\t%s", class_name(dnsclass));
  309         addtobuffer(response->msgbuf, msg);
  310     }
  311     snprintf(msg, sizeof(msg), "\t%s\n", type_name(type));
  312     addtobuffer(response->msgbuf, msg);
  313     xfree(name);
  314     return aptr;
  315 }
  316 
  317 static const unsigned char *display_rr(const unsigned char *aptr,
  318                        const unsigned char *abuf, int alen,
  319                        dns_resp_t *response)
  320 {
  321     const unsigned char *p;
  322     char *name;
  323     int type, dnsclass, ttl, dlen, status;
  324     long len;
  325     struct in_addr addr;
  326     struct in6_addr addr6;
  327 
  328     /* Parse the RR name. */
  329     status = ares_expand_name(aptr, abuf, alen, &name, &len);
  330     if (status != ARES_SUCCESS) return NULL;
  331     aptr += len;
  332 
  333     /* Make sure there is enough data after the RR name for the fixed
  334     * part of the RR.
  335     */
  336     if (aptr + RRFIXEDSZ > abuf + alen) {
  337         xfree(name);
  338         return NULL;
  339     }
  340 
  341     /* Parse the fixed part of the RR, and advance to the RR data field. */
  342     type = DNS_RR_TYPE(aptr);
  343     dnsclass = DNS_RR_CLASS(aptr);
  344     ttl = DNS_RR_TTL(aptr);
  345     dlen = DNS_RR_LEN(aptr);
  346     aptr += RRFIXEDSZ;
  347     if (aptr + dlen > abuf + alen) {
  348         xfree(name);
  349         return NULL;
  350     }
  351 
  352     /* Display the RR name, class, and type. */
  353     snprintf(msg, sizeof(msg), "\t%-15s.\t%d", name, ttl);
  354     addtobuffer(response->msgbuf, msg);
  355     if (dnsclass != C_IN) {
  356         snprintf(msg, sizeof(msg), "\t%s", class_name(dnsclass));
  357         addtobuffer(response->msgbuf, msg);
  358     }
  359     snprintf(msg, sizeof(msg), "\t%s", type_name(type));
  360     addtobuffer(response->msgbuf, msg);
  361     xfree(name);
  362 
  363     /* Display the RR data.  Don't touch aptr. */
  364     switch (type) {
  365       case T_CNAME:
  366       case T_MB:
  367       case T_MD:
  368       case T_MF:
  369       case T_MG:
  370       case T_MR:
  371       case T_NS:
  372       case T_PTR:
  373         /* For these types, the RR data is just a domain name. */
  374         status = ares_expand_name(aptr, abuf, alen, &name, &len);
  375         if (status != ARES_SUCCESS) return NULL;
  376         snprintf(msg, sizeof(msg), "\t%s.", name);
  377         addtobuffer(response->msgbuf, msg);
  378         xfree(name);
  379         break;
  380 
  381       case T_HINFO:
  382         /* The RR data is two length-counted character strings. */
  383         p = aptr;
  384         len = *p;
  385         if (p + len + 1 > aptr + dlen) return NULL;
  386         snprintf(msg, sizeof(msg), "\t%.*s", (int) len, p + 1);
  387         addtobuffer(response->msgbuf, msg);
  388         p += len + 1;
  389         len = *p;
  390         if (p + len + 1 > aptr + dlen) return NULL;
  391         snprintf(msg, sizeof(msg), "\t%.*s", (int) len, p + 1);
  392         addtobuffer(response->msgbuf, msg);
  393         break;
  394 
  395       case T_MINFO:
  396         /* The RR data is two domain names. */
  397         p = aptr;
  398         status = ares_expand_name(p, abuf, alen, &name, &len);
  399         if (status != ARES_SUCCESS) return NULL;
  400         snprintf(msg, sizeof(msg), "\t%s.", name);
  401         addtobuffer(response->msgbuf, msg);
  402         xfree(name);
  403         p += len;
  404         status = ares_expand_name(p, abuf, alen, &name, &len);
  405         if (status != ARES_SUCCESS) return NULL;
  406         snprintf(msg, sizeof(msg), "\t%s.", name);
  407         addtobuffer(response->msgbuf, msg);
  408         xfree(name);
  409         break;
  410 
  411       case T_MX:
  412         /* The RR data is two bytes giving a preference ordering, and then a domain name.  */
  413         if (dlen < 2) return NULL;
  414         snprintf(msg, sizeof(msg), "\t%d", (aptr[0] << 8) | aptr[1]);
  415         addtobuffer(response->msgbuf, msg);
  416         status = ares_expand_name(aptr + 2, abuf, alen, &name, &len);
  417         if (status != ARES_SUCCESS) return NULL;
  418         snprintf(msg, sizeof(msg), "\t%s.", name);
  419         addtobuffer(response->msgbuf, msg);
  420         xfree(name);
  421         break;
  422 
  423       case T_SOA:
  424         /*
  425          * The RR data is two domain names and then five four-byte
  426          * numbers giving the serial number and some timeouts.
  427          */
  428         p = aptr;
  429         status = ares_expand_name(p, abuf, alen, &name, &len);
  430         if (status != ARES_SUCCESS) return NULL;
  431         snprintf(msg, sizeof(msg), "\t%s.\n", name);
  432         addtobuffer(response->msgbuf, msg);
  433         xfree(name);
  434         p += len;
  435         status = ares_expand_name(p, abuf, alen, &name, &len);
  436         if (status != ARES_SUCCESS) return NULL;
  437         snprintf(msg, sizeof(msg), "\t\t\t\t\t\t%s.\n", name);
  438         addtobuffer(response->msgbuf, msg);
  439         xfree(name);
  440         p += len;
  441         if (p + 20 > aptr + dlen) return NULL;
  442         snprintf(msg, sizeof(msg), "\t\t\t\t\t\t( %d %d %d %d %d )",
  443             (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3],
  444             (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7],
  445             (p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11],
  446             (p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15],
  447             (p[16] << 24) | (p[17] << 16) | (p[18] << 8) | p[19]);
  448         addtobuffer(response->msgbuf, msg);
  449         break;
  450 
  451       case T_TXT:
  452         /* The RR data is one or more length-counted character strings. */
  453         p = aptr;
  454         while (p < aptr + dlen) {
  455             len = *p;
  456             if (p + len + 1 > aptr + dlen) return NULL;
  457             snprintf(msg, sizeof(msg), "\t%.*s", (int)len, p + 1);
  458             addtobuffer(response->msgbuf, msg);
  459             p += len + 1;
  460         }
  461         break;
  462 
  463       case T_A:
  464         /* The RR data is a four-byte Internet address. */
  465         if (dlen != 4) return NULL;
  466         memcpy(&addr, aptr, sizeof(struct in_addr));
  467         snprintf(msg, sizeof(msg), "\t%s", inet_ntoa(addr));
  468         addtobuffer(response->msgbuf, msg);
  469         break;
  470 
  471       case T_AAAA:
  472         /* The RR data is a 16-byte IPv6 address. */
  473         if (dlen != 16) return NULL;
  474         memcpy(&addr6, aptr, sizeof(struct in6_addr));
  475         addtobuffer_many(response->msgbuf, "\t", inet_ntop(AF_INET6,&addr6,msg,sizeof(msg)), NULL);
  476         break;
  477 
  478       case T_WKS:
  479         /* Not implemented yet */
  480         break;
  481 
  482       case T_SRV:
  483         /*
  484          * The RR data is three two-byte numbers representing the
  485          * priority, weight, and port, followed by a domain name.
  486          */
  487       
  488         snprintf(msg, sizeof(msg), "\t%d", DNS__16BIT(aptr));
  489         addtobuffer(response->msgbuf, msg);
  490         snprintf(msg, sizeof(msg), " %d", DNS__16BIT(aptr + 2));
  491         addtobuffer(response->msgbuf, msg);
  492         snprintf(msg, sizeof(msg), " %d", DNS__16BIT(aptr + 4));
  493         addtobuffer(response->msgbuf, msg);
  494       
  495         status = ares_expand_name(aptr + 6, abuf, alen, &name, &len);
  496         if (status != ARES_SUCCESS) return NULL;
  497         snprintf(msg, sizeof(msg), "\t%s.", name);
  498         addtobuffer(response->msgbuf, msg);
  499         xfree(name);
  500         break;
  501       
  502       default:
  503         snprintf(msg, sizeof(msg), "\t[Unknown RR; cannot parse]");
  504         addtobuffer(response->msgbuf, msg);
  505     }
  506     snprintf(msg, sizeof(msg), "\n");
  507     addtobuffer(response->msgbuf, msg);
  508 
  509     return aptr + dlen;
  510 }
  511 
  512 static const char *type_name(int type)
  513 {
  514     int i;
  515 
  516     for (i = 0; i < ntypes; i++) {
  517         if (types[i].value == type) return types[i].name;
  518     }
  519     return "(unknown)";
  520 }
  521 
  522 static const char *class_name(int dnsclass)
  523 {
  524     int i;
  525 
  526     for (i = 0; i < nclasses; i++) {
  527         if (classes[i].value == dnsclass) return classes[i].name;
  528     }
  529     return "(unknown)";
  530 }
  531 
  532 int dns_name_type(char *name)
  533 {
  534     int i;
  535 
  536     for (i = 0; i < ntypes; i++) {
  537         if (strcasecmp(types[i].name, name) == 0) return types[i].value;
  538     }
  539     return T_A;
  540 }
  541