/*  **  Copyright (c) 2005-2009 Sendmail, Inc. and its suppliers.
**    All rights reserved.  */

#ifndef lint static char manual_c_id[] = "@(#)$Id: manual.c,v 1.8
2009/02/20 00:59:11 msk Exp $"; #endif /* !lint */

/*  system includes */ #include <sys/types.h> #include <sys/sock-
et.h> #include  <netinet/in.h>  #include  <arpa/inet.h>  #include
<stdio.h> #ifdef DARWIN # include <arpa/nameser.h> #endif /* DAR-
WIN */ #include <resolv.h> #include <netdb.h> #include  <ctype.h>
#include <string.h> #include <assert.h>

/*     macros     */     #ifndef     _PATH_RESCONF    #    define
_PATH_RESCONF  "/etc/resolv.conf" #endif /*  !  _PATH_RESCONF  */
#ifndef RES_RETRY # define RES_RETRY      4 #endif /* ! RES_RETRY
*/ #ifndef RES_TIMEOUT #  define  RES_TIMEOUT    5  #endif  /*  !
RES_TIMEOUT    */    #ifndef    INADDR_NONE    #   define   INAD-
DR_NONE    0xffffffff #endif /* INADDR_NONE */

#define BUFRSZ          1024

#define SERVICE         "domain" #define PROTOCOL        "udp"

/* **  AR_RES_PARSE -- read resolv.conf and determine  the  name-
servers  **  **   Parameters:  **       nscount -- count of name-
servers to load (in/out) **      out -- location of array to pop-
ulate **      retry -- maximum retry count (returned) **      re-
trans -- retransmission timeout (returned) ** **   Return  value:
**      0  on  success, -1 on failure.  ** **  Notes: **      In-
cludes IPv6 support if AF_INET6 is  defined.   This  presumes  **
    further  that  there's a "struct sockaddr_storage" defined **
    in the system include files.  I haven't seen anything yet  **
    yet  that  guarantees  this  is  a  valid  assumption, but **
    so far so good...  */

int #ifdef AF_INET6  ar_res_parse(int  *nscount,  struct  sockad-
dr_storage *out,
             int  *retry,  int  *retrans)  #else  /*  AF_INET6 */
ar_res_parse(int *nscount, struct sockaddr_in *out,  int  *retry,
int   *retrans)   #endif  /*  AF_INET6  */  {          int  data;
        int  ns  =   0;           FILE   *f;           char   *p;
        char  *q;          char  *r;         struct servent *srv;
        char buf[BUFRSZ];

        assert(out  !=  NULL);          assert(retry  !=   NULL);
        assert(retrans != NULL);

        srv  =  getservbyname(SERVICE, PROTOCOL);         if (srv
== NULL)                 return -1;

        f = fopen(_PATH_RESCONF, "r");          if  (f  ==  NULL)
        {                        struct       sockaddr       *sa;
                struct sockaddr_in *sin;

                /*   apply   defaults    */    #ifdef    AF_INET6
                sa     =    (struct    sockaddr    *)    &out[0];
                sin    =    (struct    sockaddr_in     *)     sa;
                sin->sin_family             =            AF_INET;
                sin->sin_port           =            srv->s_port;
                sin->sin_addr.s_addr   =  htonl(INADDR_LOOPBACK);
#else /* AF_INET6 */                 out[0].sin_family = AF_INET;
                out[0].sin_port           =          srv->s_port;
                out[0].sin_addr.s_addr =  htonl(INADDR_LOOPBACK);
#endif /* AF_INET6 */

                ns = 1;

                *nscount = ns;

                return 0;         }

        clearerr(f);          while (fgets(buf, sizeof buf, f) !=
NULL)          {                  /*  chomp  at  0  #,  or  ;  */
                for  (p  = buf; *p != ' '; p++)                 {
                        if (*p == '0 || *p == ';' || *p  ==  '#')
                        {                                   *p  =
' ';                                                       break;
                        }                 }

                /*   now  eat  leading  and  trailing  spaces  */
                data   =    0;                    r    =    NULL;
                for   (p  =  buf,  q  =  buf;  *p  !=  ' ';  p++)
                {                         if (data == 0 &&  isas-
cii(*p) && isspace(*p))                                 continue;

                        data =  1;                          *q  =
*p;                          if  (!(isascii(*p)  && isspace(*p)))
                                r              =               q;
                        q++;                 }                 if
(r != NULL)                         *(r + 1) = ' ';

                /* use  the  data  */                  if  (strn-
casecmp(buf,    "nameserver",   10)   ==   0)                   {
                        struct  in_addr  addr;  #ifdef   AF_INET6
                        struct           in6_addr          addr6;
                        struct           sockaddr            *sa;
                        struct          sockaddr_in         *sin;
                        struct  sockaddr_in6  *sin6;  #endif   /*
AF_INET6 */

                        for  (p  =  &buf[10];  *p  !=  ' ';  p++)
                        {                                      if
(!isascii(*p)                   ||                  !isspace(*p))
                                        break;
                        }

                        if          (*p          ==          ' ')
                                continue;

#ifdef AF_INET6                         sa = (struct sockaddr  *)
&out[ns];                         if (inet_pton(AF_INET, p, (void
*)       &addr)       ==       1)                               {
                                sin = (struct sockaddr_in *) sa;

                                memcpy(&sin->sin_addr,     &addr,
                                         sizeof   sin->sin_addr);
                                sin->sin_family     =    AF_INET;
                                sin->sin_port   =    srv->s_port;
                                ns++;                           }
                        else    if    (inet_pton(AF_INET6,     p,
                                           (void *) &addr6.s6_ad-
dr)           ==           1)                                   {
                                sin6  =  (struct  sockaddr_in6 *)
sa;

                                memcpy(&sin6->sin6_addr,     &ad-
dr6.s6_addr,                                               sizeof
sin6->sin6_addr);                                 sin6->sin6_fam-
ily = AF_INET6;                                 sin6->sin6_port =
srv->s_port;                                                ns++;
                        }      #else      /*      AF_INET6     */
                        addr.s_addr        =        inet_addr(p);
                        if     (addr.s_addr    ==    INADDR_NONE)
                                continue;

                        memcpy(&out[ns].sin_addr.s_addr,
                                                    &addr.s_addr,
                                sizeof  out[ns].sin_addr.s_addr);
                        out[ns].sin_family       =       AF_INET;
                        out[ns].sin_port = srv->s_port;

                        ns++;    #endif    /*     AF_INET6     */
                        if         (ns        ==        *nscount)
                                break;                          }
        }

        fclose(f);

        *retry = RES_RETRY;         *retrans = RES_TIMEOUT;

        /* if no "nameserver" lines were found, add a default one
*/           if   (ns   ==   0)           {    #ifdef    AF_INET6
                struct sockaddr *sa;                 struct sock-
addr_in *sin;

                sa    =    (struct    sockaddr    *)     &out[0];
                sin     =     (struct    sockaddr_in    *)    sa;
                sin->sin_family            =             AF_INET;
                sin->sin_port            =           srv->s_port;
                sin->sin_addr.s_addr  =   htonl(INADDR_LOOPBACK);
#else /* AF_INET6 */                 out[0].sin_family = AF_INET;
                out[0].sin_port          =           srv->s_port;
                out[0].sin_addr.s_addr  = htonl(INADDR_LOOPBACK);
#endif /* AF_INET6 */

                ns = 1;         }

        *nscount = ns;

        return 0; }

#ifdef TEST int main() {         int c;          struct  sockaddr
*sa;           struct   sockaddr_in   *sin;   #   ifdef  AF_INET6
        struct sockaddr_in6 *sin6;         struct  sockaddr_stor-
age  nsaddrs[MAXNS]; # else /* AF_INET6 */         struct sockad-
dr_in  nsaddrs[MAXNS];  #  endif  /*  AF_INET6  */           char
buf[256];

        memset(nsaddrs, ' ', sizeof nsaddrs);

        ar_res_parse(MAXNS, (void *) nsaddrs);

        for    (c    =    0;    c   <   MAXNS;   c++)           {
                memset(buf, ' ', sizeof buf);

                sa = (struct sockaddr *) &nsaddrs[c];

                switch     (sa->sa_family)                      {
                   case  AF_INET:                          sin  =
(struct           sockaddr_in           *)           &nsaddrs[c];
                        printf("IPv4:  %s:%u0, inet_ntop(AF_INET,
                                (void  *)  &sin->sin_addr,   buf,
sizeof               buf),
ntohs(sin->sin_port));                         break;

#    ifdef    AF_INET6                         case     AF_INET6:
                        sin6  =  (struct  sockaddr_in6  *) &nsad-
drs[c];                           printf("IPv6:    %s:%u0,    in-
et_ntop(AF_INET6,                                      (void   *)
&sin6->sin6_addr,  buf,  sizeof  buf),
ntohs(sin6->sin6_port));                                   break;
                } # endif /* AF_INET6 */         }  }  #endif  /*
TEST */





























































