/* ** Copyright (c) 2005-2007 Sendmail, Inc. and its suppliers. ** All rights reserved. */ #ifndef lint static char manual_c_id[] = "@(#)$Id: manual.c,v 1.4 2007/04/21 18:30:07 msk Exp $"; #endif /* !lint */ /* system includes */ #include #include #include #include #ifdef DARWIN # include #endif /* DARWIN */ #include #include #include #include #include /* 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 */ #define BUFRSZ 1024 #define SERVICE "domain" #define PROTOCOL "udp" /* ** AR_RES_PARSE -- read resolv.conf and determine the nameservers ** ** Parameters: ** nscount -- count of nameservers to load (in/out) ** out -- location of array to populate ** retry -- maximum retry count (returned) ** retrans -- retransmission timeout (returned) ** ** Return value: ** 0 on success, -1 on failure. ** ** Notes: ** Includes 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 sockaddr_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) return -1; clearerr(f); while (fgets(buf, sizeof buf, f) != NULL) { /* chomp at \n, #, or ; */ for (p = buf; *p != '\0'; p++) { if (*p == '\n' || *p == ';' || *p == '#') { *p = '\0'; break; } } /* now eat leading and trailing spaces */ data = 0; r = NULL; for (p = buf, q = buf; *p != '\0'; p++) { if (data == 0 && isascii(*p) && isspace(*p)) continue; data = 1; *q = *p; if (!(isascii(*p) && isspace(*p))) r = q; q++; } if (r != NULL) *(r + 1) = '\0'; /* use the data */ if (strncasecmp(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 != '\0'; p++) { if (!isascii(*p) || !isspace(*p)) break; } if (*p == '\0') 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_addr) == 1) { sin6 = (struct sockaddr_in6 *) sa; memcpy(&sin6->sin6_addr, &addr6.s6_addr, sizeof sin6->sin6_addr); sin6->sin6_family = AF_INET6; sin6->sin6_port = srv->s_port; ns++; } #else /* AF_INET6 */ addr = inet_addr(p); if (addr == INADDR_NONE) continue; memcpy(&out[ns].sin_addr.s_addr, &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; *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_storage nsaddrs[MAXNS]; # else /* AF_INET6 */ struct sockaddr_in nsaddrs[MAXNS]; # endif /* AF_INET6 */ char buf[256]; memset(nsaddrs, '\0', sizeof nsaddrs); ar_res_parse(MAXNS, (void *) nsaddrs); for (c = 0; c < MAXNS; c++) { memset(buf, '\0', sizeof buf); sa = (struct sockaddr *) &nsaddrs[c]; switch (sa->sa_family) { case AF_INET: sin = (struct sockaddr_in *) &nsaddrs[c]; printf("IPv4: %s:%u\n", 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 *) &nsaddrs[c]; printf("IPv6: %s:%u\n", inet_ntop(AF_INET6, (void *) &sin6->sin6_addr, buf, sizeof buf), ntohs(sin6->sin6_port)); break; } # endif /* AF_INET6 */ } } #endif /* TEST */