summaryrefslogtreecommitdiffstats
path: root/utils/dns.c
diff options
context:
space:
mode:
authorAnton Luka Šijanec <anton@sijanec.eu>2022-12-11 21:21:20 +0100
committerAnton Luka Šijanec <anton@sijanec.eu>2022-12-11 21:21:20 +0100
commitcb207e2c31359a6c6259c86d05e474addf2476f0 (patch)
tree92168c070415d94848b74e1393cf25d5becf9ad7 /utils/dns.c
parentuntested for compilation, dht.c -- TODO: DNS+bootstrap (diff)
downloadtravnik-cb207e2c31359a6c6259c86d05e474addf2476f0.tar
travnik-cb207e2c31359a6c6259c86d05e474addf2476f0.tar.gz
travnik-cb207e2c31359a6c6259c86d05e474addf2476f0.tar.bz2
travnik-cb207e2c31359a6c6259c86d05e474addf2476f0.tar.lz
travnik-cb207e2c31359a6c6259c86d05e474addf2476f0.tar.xz
travnik-cb207e2c31359a6c6259c86d05e474addf2476f0.tar.zst
travnik-cb207e2c31359a6c6259c86d05e474addf2476f0.zip
Diffstat (limited to '')
-rw-r--r--utils/dns.c116
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");
+}