#include <stdio.h> // example of an asyncronous resolver that resolves
#include <stdlib.h> // a SRV record to obtain address:port combinations
#include <sys/socket.h> // of useful nodes
#include <netinet/in.h> // BUGS: does not handle CNAMES - this is
#include <arpa/nameser.h> // technically against the standard, but would be
#include <resolv.h> // nice if the domain pointed to by the SRV record
#include <arpa/inet.h> // travnik.sijanec.eu suddenly becomes a CNAME,
#include <error.h> // since it's not under my control
#include <errno.h>
#include <unistd.h>
#include <sys/poll.h>
#include <string.h>
#include <signal.h>
#define S0(x) (x ? x : "")
int main (int argc, char ** argv) { // does not free/close on error
alarm(1);
if (argc != 1+1)
error_at_line(1, 0, __FILE__, __LINE__, "%s: _dht._udp.travnik.sijanec.eu", S0(argv[0]));
struct __res_state state;
if (res_ninit(&state) == -1)
error_at_line(2, 0, __FILE__, __LINE__, "res_ninit");
int sock = socket(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
if (!sock)
error_at_line(3, errno, __FILE__, __LINE__, "socket");
struct sockaddr_in6 a = {
.sin6_family = AF_INET6,
.sin6_addr = in6addr_any
};
if (bind(sock, (struct sockaddr *) &a, sizeof a) == -1)
error_at_line(4, errno, __FILE__, __LINE__, "bind");
unsigned char packet[65536];
int size = res_nmkquery(&state, QUERY, argv[1], ns_c_in, ns_t_srv, NULL, 0, NULL, packet, 65536);
if (size == -1)
error_at_line(5, 0, __FILE__, __LINE__, "res_mkquery");
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
for (int i = 0; i < state.nscount; i++)
if (state.nsaddr_list[i].sin_family == AF_INET) // leider only ipv4
if (sendto(sock, packet, size, MSG_DONTWAIT | MSG_NOSIGNAL, &state.nsaddr_list[i], sizeof (state.nsaddr_list[i])) == -1)
error_at_line(6, errno, __FILE__, __LINE__, "sendto(AF_INET)");
/* for (int i = 0; i < state._u._ext.nscount6; i++)
if (sendto(sock, packet, size, MSG_DONTWAIT | MSG_NOSIGNAL, &state._u._ext.nsaddrs[i], sizeof (state._u._ext.nsaddrs[i])) == -1)
error_at_line(7, errno, __FILE__, __LINE__, "sendto(AF_INET6)"); */ // does not work
#pragma GCC diagnostic pop
struct pollfd pollfd = {
.fd = sock,
.events = POLLIN
};
r:
;
int status = poll(&pollfd, 1, -1);
if (status == 1) {
socklen_t l = sizeof a;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
int len = recvfrom(sock, packet, 65536, MSG_DONTWAIT | MSG_TRUNC, &a, &l);
#pragma GCC diagnostic pop
if (len == -1)
error_at_line(8, errno, __FILE__, __LINE__, "recvfrom");
ns_msg handle;
char remote[INET6_ADDRSTRLEN+7];
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
if (!inet_ntop(AF_INET6, &a.sin6_addr, remote, INET6_ADDRSTRLEN+7))
error_at_line(9, errno, __FILE__, __LINE__, "inet_pton");
#pragma GCC diagnostic pop
sprintf(remote+strlen(remote), ":%u", ntohs(a.sin6_port));
if (ns_initparse(packet, len, &handle) == -1)
error_at_line(10, 0, __FILE__, __LINE__, "ns_initparse %s", remote);
for (int i = 0; i < ns_msg_count(handle, ns_s_an); i++) {
struct __ns_rr rr;
if (ns_parserr(&handle, ns_s_an, i, &rr) == -1)
break;
if (rr.type != ns_t_srv && rr.type != ns_t_a && rr.type != ns_t_aaaa)
continue;
char target[NS_MAXDNAME];
char address[INET_ADDRSTRLEN+INET6_ADDRSTRLEN+7];
switch (rr.rdlength) {
case 4:
if (!inet_ntop(AF_INET, rr.rdata, address, INET6_ADDRSTRLEN+INET_ADDRSTRLEN+7))
error_at_line(11, errno, __FILE__, __LINE__, "inet_ntop(AF_INET)");
sprintf(address+strlen(address), ":%u", ntohs(*((uint16_t *) packet)));
printf("%s\tA\t%s\n", remote, address);
break;
case 16:
if (!inet_ntop(AF_INET6, rr.rdata, address, INET6_ADDRSTRLEN+INET_ADDRSTRLEN+7))
error_at_line(12, errno, __FILE__, __LINE__, "inet_ntop(AF_INET6)");
sprintf(address+strlen(address), ":%u", ntohs(*((uint16_t *) packet)));
printf("%s\tAAAA\t%s\n", remote, address);
break;
default:
if (rr.rdlength < 3*2+3)
continue;
if (ns_name_uncompress(packet, packet+len, rr.rdata+3*2, target, NS_MAXDNAME) == -1)
error_at_line(13, 0, __FILE__, __LINE__, "ns_name_uncompress %s", remote);
// printf("%s\tSRV\t%u\t%s\n", remote, htons(*((uint16_t *) (rr.rdata + 4))), target);
for (int j = 0; j <= 1; j++) {
size = res_nmkquery(&state, QUERY, target, ns_c_in, j ? ns_t_a : ns_t_aaaa, NULL, 0, NULL, packet, 65536);
if (size == -1)
error_at_line(14, 0, __FILE__, __LINE__, "res_mkquery(A)");
memcpy(packet, rr.rdata+4, 2);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
if (sendto(sock, packet, size, MSG_DONTWAIT | MSG_NOSIGNAL, &a, l) == -1)
error_at_line(15, errno, __FILE__, __LINE__, "sendto");
}
break;
}
#pragma GCC diagnostic pop
}
goto r;
}
res_nclose(&state);
if (close(sock) == -1)
error_at_line(16, errno, __FILE__, __LINE__, "close");
}