/* * Copyright 2005 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Niels Provos. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dnsres.h" #include "resolv.h" struct simple_arg { struct dnsres *res; char *domain; int fail_one; int fail_two; }; int callback_expected = 0; int callback_called = 0; void SimpleTest_cb2(struct dnsres_hostent *he, int dr_errno, void *arg) { struct simple_arg *sa = arg; struct dnsres *res = sa->res; char *domain = sa->domain; int fail_two = sa->fail_two; callback_called++; if (he == NULL) fprintf(stderr, "\tdnsres_gethostbyaddr failed: %s -> %d\n", domain, res->dr_errno); if ((he == NULL && !fail_two) || (he != NULL && fail_two)) errx(1, "%s: test two on %s did not pass", __func__, domain); if (fail_two) goto out; fprintf(stderr, "\tGot: %s -> %s\n", domain, he->h_name); out: free(sa); } void SimpleTest_cb(struct dnsres_hostent *he, int dr_errno, void *arg) { struct simple_arg *sa = arg; struct dnsres *res = sa->res; char *domain = sa->domain; int fail_one = sa->fail_one; callback_called++; if (he == NULL) fprintf(stderr, "\tdnsres_gethostbyname failed on %s\n", domain); if ((he == NULL && !fail_one) || (he != NULL && fail_one)) errx(1, "%s: test one on %s did not pass", __func__, domain); if (fail_one) { free(sa); return; } fprintf(stderr, "\tGot: %s -> %s\n", domain, he->h_name); callback_expected++; dnsres_gethostbyaddr(res, he->h_addr_list[0], he->h_length, he->h_addrtype, SimpleTest_cb2, arg); } void SimpleTest(struct dnsres *res, char *domain, int fail_one, int fail_two) { struct simple_arg *sa = calloc(1, sizeof(struct simple_arg)); if (sa == NULL) err(1, "%s: calloc", __func__); sa->res = res; sa->domain = domain; sa->fail_one = fail_one; sa->fail_two = fail_two; callback_expected++; dnsres_gethostbyname(res, domain, SimpleTest_cb, sa); } void TestCase(struct dnsres *res, int usetcp) { callback_expected = callback_called = 0; if (usetcp) { res->options |= RES_USEVC; } else { res->options &= ~RES_USEVC; } fprintf(stderr, "Running SimpleTest%s...\n", usetcp ? "(TCP)" : "(UDP)"); SimpleTest(res, "gw.provos.org", 0, 0); SimpleTest(res, "www.citi.umich.edu", 0, 0); SimpleTest(res, "www.google.com", 0, 1); SimpleTest(res, "gws.provos.org", 1, 1); SimpleTest(res, "localhost", 0, 0); event_dispatch(); if (callback_called != callback_expected) errx(1, "Missed some callbacks: %d", callback_expected - callback_called); fprintf(stderr, "OK\n"); } int CompareAI(struct addrinfo *ai, struct addrinfo *ai2) { if (!ai || !ai2) { if ((ai && !ai2) ||(!ai && ai2)) return (0); return (1); } if (ai->ai_flags != ai2->ai_flags || ai->ai_family != ai2->ai_family || ai->ai_protocol != ai2->ai_protocol || ai->ai_addrlen != ai2->ai_addrlen) return (0); if (memcmp(ai->ai_addr, ai2->ai_addr, ai->ai_addrlen)) return (0); if (ai->ai_next || ai2->ai_next) { if ((ai->ai_next && !ai2->ai_next) || (!ai->ai_next && ai2->ai_next)) return 0; return (CompareAI(ai->ai_next, ai2->ai_next)); } return (1); } void AddrinfoLookup_cb(struct addrinfo *ai, int res, void *arg) { char abuf[32], pbuf[20]; char *name = arg; struct addrinfo hints, *ai2 = NULL; int res2; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; res2 = getaddrinfo(name, NULL, &hints, &ai2); if (!CompareAI(ai, ai2)) errx(1, "%s: FAILED on %s\n", __func__, name); if (ai != NULL) { if (getnameinfo(ai->ai_addr, ai->ai_addrlen, abuf, sizeof(abuf), pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { strlcpy(abuf, "?", sizeof(abuf)); strlcpy(pbuf, "?", sizeof(pbuf)); } } else { strlcpy(abuf, "failed", sizeof(abuf)); pbuf[0] = '\0'; } fprintf(stderr, "\t%s: %s %s\n", name, abuf, pbuf); } void AddrinfoLookup(struct dnsres *res, char *name) { struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; dnsres_getaddrinfo(res, name, NULL, &hints, AddrinfoLookup_cb, name); } void TestCaseAddrinfo(struct dnsres *res, int usetcp) { if (usetcp) { res->options |= RES_USEVC; } else { res->options &= ~RES_USEVC; } fprintf(stderr, "Running AddrinfoLookup%s...\n", usetcp ? "(TCP)" : "(UDP)"); AddrinfoLookup(res, "ftp.netbsd.org"); AddrinfoLookup(res, "ftp.openbsd.org"); AddrinfoLookup(res, "mordant.info.xzy"); event_dispatch(); fprintf(stderr, "OK\n"); } int main(int argc, char **argv) { struct dnsres res; /* This might have to go away sometime or not */ dnsres_init(&res); event_init(); TestCase(&res, 0); TestCase(&res, 1); TestCaseAddrinfo(&res, 0); TestCaseAddrinfo(&res, 1); exit(0); }