#include // example of an asyncronous resolver that resolves #include // a SRV record to obtain address:port combinations #include // of useful nodes #include // BUGS: does not handle CNAMES - this is #include // technically against the standard, but would be #include // nice if the domain pointed to by the SRV record #include // travnik.sijanec.eu suddenly becomes a CNAME, #include // since it's not under my control #include #include #include #include #include #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"); }