diff options
Diffstat (limited to 'utils')
-rw-r--r-- | utils/dns.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/utils/dns.c b/utils/dns.c new file mode 100644 index 0000000..e365e73 --- /dev/null +++ b/utils/dns.c @@ -0,0 +1,116 @@ +#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"); +} |