/* program to do DNS access * uses the new struct and new commands * to handle IPv6 and to be thread safe */ #include #include #include #include #include #include #include int main(int argc, char **argv) /* argv[1] is domain name */ { struct addrinfo hints; // man getaddrinfo for details // hints is a struct filled with criteria // for socket address structs wanted struct addrinfo *firsthost = NULL; struct addrinfo *currenthost = NULL; struct sockaddr_in *address4; // to hold return address struct sockaddr_in6 *address6; // to hold return address int error; /* buffer to hold readable IP address */ char addrbuf[INET6_ADDRSTRLEN]; // man inet_ntop for details /* check that we have the correct number of args * generate an error message and exit */ if (argc != 2) { printf("usage: dnsaccess IPaddr|hostname \n"); exit(1); } /* 0 memory so that debugging does not find trash */ memset(&hints, 0, sizeof(hints)); /* set the flags in the addrinfo struct */ /* these are important as when 0, various options are invoked * as the system gives back info for everything, e.g., UDP, TCP, ... */ hints.ai_flags = AI_CANONNAME; // want canonical name hints.ai_family = AF_UNSPEC; // any protocol family hints.ai_socktype = SOCK_DGRAM; // TCP Socket, need to be there or // multiple addresses /* do the call to get dns info for the host */ error = getaddrinfo(argv[1], NULL, &hints, &firsthost); /* if call failed, error and die */ if (error) { errx(1, "getaddrinfo error"); } /* have the dns info, start by printing first name, * which is the canonical name */ printf("Canonical hostname: %s\n", firsthost->ai_canonname); /* print out the other names by climbing down the list of hosts * that is created by getaddrinfo */ for (currenthost = firsthost; currenthost != NULL; currenthost = currenthost->ai_next) { /* want to handle both v6 and v4 addresses */ switch (currenthost->ai_family) { case AF_INET: address4 = (struct sockaddr_in*)currenthost->ai_addr; inet_ntop(AF_INET, &address4->sin_addr, addrbuf, sizeof(addrbuf)); break; case AF_INET6: address6 = (struct sockaddr_in6*)currenthost->ai_addr; inet_ntop(AF_INET6, &address6->sin6_addr, addrbuf, sizeof(addrbuf)); break; default: addrbuf[0] = 0; } /* print the friggen address */ printf("An Address: %s\n", addrbuf); /* for fun, print it all out */ printf("Address: %s\n\tsocktype: %d\n\tprotocol: %d\n\tfamily: %d\n\tflags: %d\n\taddr: %p\n\tcanonname: %s\n\n", addrbuf, currenthost->ai_socktype, currenthost->ai_protocol, currenthost->ai_family, currenthost->ai_flags, currenthost->ai_addr, currenthost->ai_canonname); } /* another version of the climbing down the list of hosts * this one uses getnameinfo which provides for selecting between * v4 and v6 without the switch statement */ for (currenthost = firsthost; currenthost != NULL; currenthost = currenthost->ai_next) { /* want to handle both v6 and v4 addresses */ getnameinfo(currenthost->ai_addr, currenthost->ai_addrlen, addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); /* print the friggen address */ printf("getname Address: %s\n", addrbuf); } /*free the memory allocated by getaddrinfo */ freeaddrinfo(firsthost); /*we are done */ printf("That's All Folks \n"); return 0; }