Back to index

opendkim  2.6.4
manual.c
Go to the documentation of this file.
00001 /*
00002 **  Copyright (c) 2005-2009 Sendmail, Inc. and its suppliers.
00003 **    All rights reserved.
00004 **
00005 **  Copyright (c) 2009, The OpenDKIM Project.  All rights reserved.
00006 */
00007 
00008 #ifndef lint
00009 static char manual_c_id[] = "@(#)$Id: manual.c,v 1.4 2009/12/10 22:17:30 cm-msk Exp $";
00010 #endif /* !lint */
00011 
00012 /* system includes */
00013 #include <sys/types.h>
00014 #include <sys/socket.h>
00015 #include <netinet/in.h>
00016 #include <arpa/inet.h>
00017 #include <stdio.h>
00018 #ifdef DARWIN
00019 # include <arpa/nameser.h>
00020 #endif /* DARWIN */
00021 #include <resolv.h>
00022 #include <netdb.h>
00023 #include <ctype.h>
00024 #include <string.h>
00025 #include <assert.h>
00026 #include <time.h>
00027 
00028 /* macros */
00029 #ifndef _PATH_RESCONF
00030 # define _PATH_RESCONF      "/etc/resolv.conf"
00031 #endif /* ! _PATH_RESCONF */
00032 #ifndef RES_RETRY
00033 # define RES_RETRY   4
00034 #endif /* ! RES_RETRY */
00035 #ifndef RES_TIMEOUT
00036 # define RES_TIMEOUT 5
00037 #endif /* ! RES_TIMEOUT */
00038 #ifndef INADDR_NONE
00039 # define INADDR_NONE 0xffffffff
00040 #endif /* INADDR_NONE */
00041 
00042 #define BUFRSZ              1024
00043 
00044 #define       SERVICE              "domain"
00045 #define       PROTOCOL      "udp"
00046 
00047 /*
00048 **  AR_RES_PARSE -- read resolv.conf and determine the nameservers
00049 **
00050 **  Parameters:
00051 **     nscount -- count of nameservers to load (in/out)
00052 **     out -- location of array to populate
00053 **     retry -- maximum retry count (returned)
00054 **     retrans -- retransmission timeout (returned)
00055 **
00056 **  Return value:
00057 **     0 on success, -1 on failure.
00058 **
00059 **  Notes:
00060 **     Includes IPv6 support if AF_INET6 is defined.  This presumes
00061 **     further that there's a "struct sockaddr_storage" defined
00062 **     in the system include files.  I haven't seen anything yet
00063 **     yet that guarantees this is a valid assumption, but
00064 **     so far so good...
00065 */
00066 
00067 int
00068 #ifdef AF_INET6
00069 ar_res_parse(int *nscount, struct sockaddr_storage *out,
00070 #else /* AF_INET6 */
00071 ar_res_parse(int *nscount, struct sockaddr_in *out,
00072 #endif /* AF_INET6 */
00073              int *retry, long *retrans)
00074 {
00075        int data;
00076        int ns = 0;
00077        FILE *f;
00078        char *p;
00079        char *q;
00080        char *r;
00081        struct servent *srv;
00082        char buf[BUFRSZ];
00083 
00084        assert(out != NULL);
00085        assert(retry != NULL);
00086        assert(retrans != NULL);
00087 
00088        srv = getservbyname(SERVICE, PROTOCOL);
00089        if (srv == NULL)
00090               return -1;
00091 
00092        f = fopen(_PATH_RESCONF, "r");
00093        if (f == NULL)
00094        {
00095               struct sockaddr *sa;
00096               struct sockaddr_in *sin;
00097 
00098               /* apply defaults */
00099 #ifdef AF_INET6
00100               sa = (struct sockaddr *) &out[0];
00101               sin = (struct sockaddr_in *) sa;
00102               sin->sin_family = AF_INET;
00103               sin->sin_port = srv->s_port;
00104               sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
00105 #else /* AF_INET6 */
00106               out[0].sin_family = AF_INET;
00107               out[0].sin_port = srv->s_port;
00108               out[0].sin_addr.s_addr = htonl(INADDR_LOOPBACK);
00109 #endif /* AF_INET6 */
00110 
00111               ns = 1;
00112 
00113               *nscount = ns;
00114 
00115               return 0;
00116        }
00117 
00118        clearerr(f);
00119        while (fgets(buf, sizeof buf, f) != NULL)
00120        {
00121               /* chomp at \n, #, or ; */
00122               for (p = buf; *p != '\0'; p++)
00123               {
00124                      if (*p == '\n' || *p == ';' || *p == '#')
00125                      {
00126                             *p = '\0';
00127                             break;
00128                      }
00129               }
00130 
00131               /* now eat leading and trailing spaces */
00132               data = 0;
00133               r = NULL;
00134               for (p = buf, q = buf; *p != '\0'; p++)
00135               {
00136                      if (data == 0 && isascii(*p) && isspace(*p))
00137                             continue;
00138 
00139                      data = 1;
00140                      *q = *p;
00141                      if (!(isascii(*p) && isspace(*p)))
00142                             r = q;
00143                      q++;
00144               }
00145               if (r != NULL)
00146                      *(r + 1) = '\0';
00147 
00148               /* use the data */
00149               if (strncasecmp(buf, "nameserver", 10) == 0)
00150               {
00151                      struct in_addr addr;
00152 #ifdef AF_INET6
00153                      struct in6_addr addr6;
00154                      struct sockaddr *sa;
00155                      struct sockaddr_in *sin;
00156                      struct sockaddr_in6 *sin6;
00157 #endif /* AF_INET6 */
00158 
00159                      for (p = &buf[10]; *p != '\0'; p++)
00160                      {
00161                             if (!isascii(*p) || !isspace(*p))
00162                                    break;
00163                      }
00164 
00165                      if (*p == '\0')
00166                             continue;
00167 
00168 #ifdef AF_INET6
00169                      sa = (struct sockaddr *) &out[ns];
00170                      if (inet_pton(AF_INET, p, (void *) &addr) == 1)
00171                      {
00172                             sin = (struct sockaddr_in *) sa;
00173 
00174                             memcpy(&sin->sin_addr, &addr,
00175                                    sizeof sin->sin_addr);
00176                             sin->sin_family = AF_INET;
00177                             sin->sin_port = srv->s_port;
00178                             ns++;
00179                      }
00180                      else if (inet_pton(AF_INET6, p,
00181                                         (void *) &addr6.s6_addr) == 1)
00182                      {
00183                             sin6 = (struct sockaddr_in6 *) sa;
00184 
00185                             memcpy(&sin6->sin6_addr, &addr6.s6_addr,
00186                                    sizeof sin6->sin6_addr);
00187                             sin6->sin6_family = AF_INET6;
00188                             sin6->sin6_port = srv->s_port;
00189                             ns++;
00190                      }
00191 #else /* AF_INET6 */
00192                      addr.s_addr = inet_addr(p);
00193                      if (addr.s_addr == INADDR_NONE)
00194                             continue;
00195 
00196                      memcpy(&out[ns].sin_addr.s_addr,
00197                             &addr.s_addr,
00198                             sizeof out[ns].sin_addr.s_addr);
00199                      out[ns].sin_family = AF_INET;
00200                      out[ns].sin_port = srv->s_port;
00201 
00202                      ns++;
00203 #endif /* AF_INET6 */
00204                      if (ns == *nscount)
00205                             break;
00206               }
00207        }
00208 
00209        fclose(f);
00210 
00211        *retry = RES_RETRY;
00212        *retrans = RES_TIMEOUT;
00213 
00214        /* if no "nameserver" lines were found, add a default one */
00215        if (ns == 0)
00216        {
00217 #ifdef AF_INET6
00218               struct sockaddr *sa;
00219               struct sockaddr_in *sin;
00220 
00221               sa = (struct sockaddr *) &out[0];
00222               sin = (struct sockaddr_in *) sa;
00223               sin->sin_family = AF_INET;
00224               sin->sin_port = srv->s_port;
00225               sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
00226 #else /* AF_INET6 */
00227               out[0].sin_family = AF_INET;
00228               out[0].sin_port = srv->s_port;
00229               out[0].sin_addr.s_addr = htonl(INADDR_LOOPBACK);
00230 #endif /* AF_INET6 */
00231 
00232               ns = 1;
00233        }
00234 
00235        *nscount = ns;
00236 
00237        return 0;
00238 }
00239 
00240 #ifdef TEST
00241 int
00242 main()
00243 {
00244        int c;
00245        struct sockaddr *sa;
00246        struct sockaddr_in *sin;
00247 # ifdef AF_INET6
00248        struct sockaddr_in6 *sin6;
00249        struct sockaddr_storage nsaddrs[MAXNS];
00250 # else /* AF_INET6 */
00251        struct sockaddr_in nsaddrs[MAXNS];
00252 # endif /* AF_INET6 */
00253        char buf[256];
00254 
00255        memset(nsaddrs, '\0', sizeof nsaddrs);
00256 
00257        ar_res_parse(MAXNS, (void *) nsaddrs);
00258 
00259        for (c = 0; c < MAXNS; c++)
00260        {
00261               memset(buf, '\0', sizeof buf);
00262 
00263               sa = (struct sockaddr *) &nsaddrs[c];
00264 
00265               switch (sa->sa_family)
00266               {
00267                 case AF_INET:
00268                      sin = (struct sockaddr_in *) &nsaddrs[c];
00269                      printf("IPv4: %s:%u\n", inet_ntop(AF_INET,
00270                             (void *) &sin->sin_addr, buf, sizeof buf),
00271                             ntohs(sin->sin_port));
00272                      break;
00273 
00274 # ifdef AF_INET6
00275                 case AF_INET6:
00276                      sin6 = (struct sockaddr_in6 *) &nsaddrs[c];
00277                      printf("IPv6: %s:%u\n", inet_ntop(AF_INET6,
00278                             (void *) &sin6->sin6_addr, buf, sizeof buf),
00279                             ntohs(sin6->sin6_port));
00280                      break;
00281               }
00282 # endif /* AF_INET6 */
00283        }
00284 }
00285 #endif /* TEST */