Skip to content

Instantly share code, notes, and snippets.

@fumiyas
Last active October 1, 2021 10:10
Show Gist options
  • Select an option

  • Save fumiyas/a462843421be93c8288f001f24e93045 to your computer and use it in GitHub Desktop.

Select an option

Save fumiyas/a462843421be93c8288f001f24e93045 to your computer and use it in GitHub Desktop.
Command-line DNS stub resolver
/*
Command-line DNS stub resolver
Copyright (C) 2018-2021 SATOH Fumiyasu @ OSS Technology Corp., Japan
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <netdb.h>
#ifdef _AIX
#include <sys/socket.h>
#endif
#include <arpa/inet.h>
#include <errno.h>
const char *progname;
void dnsstubq_error(const char *fmt, ...)
{
va_list ap;
fprintf(stderr, "%s: ERROR: ", progname);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
int dnsstubq_name2addr(const char *name)
{
struct addrinfo ai_hint, *ai_list, *ai_p;
char addr[NI_MAXHOST];
int err;
memset(&ai_hint, 0, sizeof(ai_hint));
ai_hint.ai_family = AF_UNSPEC;
ai_hint.ai_socktype = SOCK_STREAM;
err = getaddrinfo(name, NULL, &ai_hint, &ai_list);
if (err) {
dnsstubq_error("%s\n", gai_strerror(err));
return 1;
}
err = 0;
for (ai_p = ai_list; ai_p; ai_p = ai_p->ai_next) {
void *sa_p;
switch (ai_p->ai_family) {
case AF_INET:
sa_p = &((struct sockaddr_in *)(ai_p->ai_addr))->sin_addr.s_addr;
break;
case AF_INET6:
sa_p = &((struct sockaddr_in6 *)(ai_p->ai_addr))->sin6_addr;
break;
default:
dnsstubq_error("Unknown address family: %d\n", ai_p->ai_family);
err = 1;
continue;
}
if (inet_ntop(ai_p->ai_family, sa_p, addr, sizeof(addr)) == NULL) {
dnsstubq_error("inet_ntop() failed: %s\n", strerror(errno));
err = 1;
continue;
}
printf("%s\n", addr);
}
freeaddrinfo(ai_list);
return err;
}
int dnsstubq_addr2name(const char *addr)
{
const struct sockaddr *sa_p;
socklen_t sa_len;
struct sockaddr_in sa4;
struct sockaddr_in6 sa6;
char name[NI_MAXHOST];
int rc, err;
if (strchr(addr, ':')) {
memset(&sa6, 0, sizeof(sa6));
sa6.sin6_family = AF_INET6;
sa_p = (struct sockaddr *)&sa6;
sa_len = sizeof(sa6);
rc = inet_pton(AF_INET6, addr, &(sa6.sin6_addr));
} else {
memset(&sa4, 0, sizeof(sa4));
sa4.sin_family = AF_INET;
sa_p = (struct sockaddr *)&sa4;
sa_len = sizeof(sa4);
rc = inet_pton(AF_INET, addr, &(sa4.sin_addr));
}
switch (rc) {
case 0:
dnsstubq_error("Invalid address: %s\n", addr);
return 1;
case -1:
dnsstubq_error("%s\n", strerror(errno));
return 1;
}
err = getnameinfo(sa_p, sa_len, name, sizeof(name), NULL, 0, NI_NAMEREQD);
if (err) {
dnsstubq_error("%s\n", gai_strerror(err));
return 1;
}
printf("%s\n", name);
return 0;
}
int main(int argc, char **argv)
{
const char *q;
int q_hostname_p;
int err;
progname = argv[0];
if (argc != 2) {
printf("Usage: %s <HOSTNAME|IP-ADDRESS>\n", progname);
return 1;
}
q = argv[1];
q_hostname_p = 1;
if (strchr(q, ':')) {
// IPv6?
q_hostname_p = 0;
} else {
const char *p;
for (p = q; *p != '\0'; p++) {
if (isdigit(*p) || *p == '.') {
continue;
}
break;
}
if (*p == '\0') {
// IPv4?
q_hostname_p = 0;
}
}
if (q_hostname_p) {
err = dnsstubq_name2addr(q);
} else {
err = dnsstubq_addr2name(q);
}
return err;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment