diff options
author | Anton Luka Šijanec <anton@sijanec.eu> | 2023-08-06 15:56:08 +0200 |
---|---|---|
committer | Anton Luka Šijanec <anton@sijanec.eu> | 2023-08-06 15:56:08 +0200 |
commit | 4b65846d2e369636e1c947c98c31507d4c08af10 (patch) | |
tree | ba8d82c0c1ca0e54943b86ca68f665cfd66a078f /prog/6 | |
parent | raw6 (diff) | |
download | r-4b65846d2e369636e1c947c98c31507d4c08af10.tar r-4b65846d2e369636e1c947c98c31507d4c08af10.tar.gz r-4b65846d2e369636e1c947c98c31507d4c08af10.tar.bz2 r-4b65846d2e369636e1c947c98c31507d4c08af10.tar.lz r-4b65846d2e369636e1c947c98c31507d4c08af10.tar.xz r-4b65846d2e369636e1c947c98c31507d4c08af10.tar.zst r-4b65846d2e369636e1c947c98c31507d4c08af10.zip |
Diffstat (limited to '')
-rw-r--r-- | prog/6/.gitignore | 2 | ||||
-rw-r--r-- | prog/6/6d.conf | 28 | ||||
-rw-r--r-- | prog/6/client.c | 10 | ||||
-rw-r--r-- | prog/6/conf.c | 88 | ||||
-rw-r--r-- | prog/6/daemon.c | 118 | ||||
-rw-r--r-- | prog/6/makefile | 37 |
6 files changed, 283 insertions, 0 deletions
diff --git a/prog/6/.gitignore b/prog/6/.gitignore new file mode 100644 index 0000000..4f3b7ce --- /dev/null +++ b/prog/6/.gitignore @@ -0,0 +1,2 @@ +6d +6c diff --git a/prog/6/6d.conf b/prog/6/6d.conf new file mode 100644 index 0000000..39e751c --- /dev/null +++ b/prog/6/6d.conf @@ -0,0 +1,28 @@ +the example configuration file for 6d +this is where you define your zones/networks and static entries +syntax description: +- all lines that are unparsable are considered comments and ignored +- zones/networks are defined with a space separated list of the following items on the same line + 1) an ipv6 network address (see `man inet_pton`) and a netmask with a '/' in between + 2) the admin email address of the dns administrator + 3) a space-separated list of FQDNs of nameservers for this zone, the first entry being the master +- static PTRs for hosts are defined by an IPv6 address and FQDN, separated by a single space on a single line +- NS delegations for subnetworks are defined by an IPv6 subnetwork (address+mask) and nameserver FQDNs, with everything separated by a single space +- the order of configuration lines does not matter + +the following defines a dns zone. there can be many such lines for different networks. +those are authoritative zones for which on-the-fly generation will occur. +all nameservers, provided here, must be 6d nameservers or at least 6d nameservers behind a DNS proxy, such as bind. +there can be as many nameservers (but at least one) after the admin email +2001:db8::/32 dns@t-2.net.example dns1.t-2.net.example dns2.t-2.net.example + +the following line defines a static PTR FQDN for a single host +2001:db8:0:d::b90a tranzistor.sijanec.eu.example + +the following line defines static NS records for a subnetwork. +this subnetwork must be a subnetwork of a zone that 6d will generate records for. +when 6d will be asked for an address that is part of this subnetwork, it will state that some other server is authoritative for this subnetwork and direct the client to the server provided. +there can be as many nameservers (but at least one) after the network name +2001:db8:e77:5500::/56 ns1.sijanec.org.example ns2.sijanec.org.example + +you can run `6d dry <config file>` to parse the configuration file, output it and exit without starting the daemon diff --git a/prog/6/client.c b/prog/6/client.c new file mode 100644 index 0000000..e182dd2 --- /dev/null +++ b/prog/6/client.c @@ -0,0 +1,10 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/udp.h> +int main (int argc, char ** argv) { + if (argc < 3) { + fprintf(stderr, "%s ipv6 fqdn\n", argv[0]); + } +} diff --git a/prog/6/conf.c b/prog/6/conf.c new file mode 100644 index 0000000..6945876 --- /dev/null +++ b/prog/6/conf.c @@ -0,0 +1,88 @@ +#include <stdio.h> +#include <search.h> +#include <string.h> +#include <arpa/inet.h> +int ipv6_compare (const struct in6_addr * a, const struct in6_addr * b) { + return memcmp(a->s6_addr, b->s6_addr, sizeof a->s6_addr); +} +struct zone { + struct in6_addr addr; + int mask; + char * email; + char ** ns; + int nslen; + struct zone * next; +}; +struct ns { + struct in6_addr addr; + int mask; + char ** ns; + int nslen; + struct ns * next; +}; +struct ptr { + struct in6_addr addr; + int mask; + char ptr; + time_t created; +}; +struct config { + struct * zone; // linked list TODO use https://en.wikipedia.org/wiki/Trie instead + struct * ns; // linked list TODO use https://en.wikipedia.org/wiki/Trie instead + void * ptrrp; // ptr root pointer for tsearch(3) +}; +struct config config (FILE * file) { + char line[1024]; + while (!ferror(file) && !feof(file)) { + char * ret = fgets(line, sizeof line, file); + if (!ret) + break; + char * cp = strchr(line, '/'); + int mask = -1; + if (cp) { + cp = '\0'; + if (cp[1] <= '9' && cp[1] >= '0') + mask = strtol(cp+1, &cp, 10); + else + cp++; + } else { + cp = line; + for (; strchr("0123456789abcdefABCDEF:", *cp); cp++); + if (!*cp) + continue; + cp++; + } + struct in6_addr addr; + switch (inet_pton(AF_INET6, line, addr.s6_addr)) { + case 0: + continue; + case -1: + perror("inet_pton"); + exit(EXIT_FAILURE); + } + line = cp; + char * saveptr = NULL; + cp = strtok_r(line, "\t\r\n ", &saveptr); + if (!cp) + continue; + if (mask == -1) { // ptr record + struct ; + continue; + } + } +} +/* +int main (int argc, char ** argv) { + if (argc != 2) { + fprintf(stderr, "6d configuration file checker\n" + " usage: %s configfile\n" + "an example configuration file can be found in the following locations:\n" + " /etc/6d\n" + " /usr/share/doc/6d/conf\n" + " http://ni.šijanec.eu/sijanec/r/tree/prog/6/6d.conf\n" + , argv[0]); + return 1; + } + config_file(); +} +*/ diff --git a/prog/6/daemon.c b/prog/6/daemon.c new file mode 100644 index 0000000..849ebb3 --- /dev/null +++ b/prog/6/daemon.c @@ -0,0 +1,118 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/udp.h> +#include <poll.h> +#include <arpa/nameser.h> +#include <sys/uio.h> +#include <netdb.h> +#include <sys/types.h> +#include <resolv.h> +#include <errno.h> +#define DEBUG 1 +int handle (unsigned char * packet, int bytes) { + HEADER * header = (HEADER *) packet; + ns_msg handle; + if (ns_initparse(packet, bytes, &handle) == -1) + return -1; + if (header->qr) // response + return -1; + header->qr = 1; + header->tc = 0; + header->aa = 0; + header->ra = 0; + if (header->opcode) { + header->rcode = NOTIMP; + return bytes; + } + if (header->qdcount != 1) { + header->rcode = FORMERR; + return bytes; + } + ns_rr rr; + if (ns_parserr(handle, ms_s_qd, 0, &rr) == -1) { + header->rcode = FORMERR; + return bytes; + } + +} +int main (int argc, char ** argv) { + if (argc != 3) { + fprintf(stderr, "%s port config\n" + " port: 53 (UDP listening port) (configurable to allow many daemons)\n" + " config: file name of the configuration file (use 6c to check syntax)\n" + "creates PTR and AAAA records with on-the-fly method (RFC 8501, section 2.5)\n" + "an example of records created for IPv6 2001:db8:1\n" + " 1.0.[...].0.8.B.D.0.1.0.0.2.IP6.ARPA. 127800 IN PTR 1.0.[...].0.8.B.D.0.1.0.0.2.IP6.ARPA.\n" + " 1.0.[...].0.8.B.D.0.1.0.0.2.IP6.ARPA. 127800 IN AAAA 2001:db8::1\n" + "more information:\n" + " - SOA serial will be the number of days since 2023-08-06\n" + " - refresh, retry and expire in SOA will have values conforming to standard, but\n" + " they are irrelevant, as potential 6d slaves are not real DNS slaves\n" + " - negative cache TTL is 1337, this is irrelevant, as nxdomains aren't expected\n" + " - to exit after reading and printing out the configuration, run %s dry <config>\n" + , argv[0]); + return 1; + } + int sock = socket(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); + if (sock == -1) { + perror("socket(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0)"); + return 2; + } + struct sockaddr_in6 listen = { + .sin6_family = AF_INET6, + .sin6_port = htons(53), + .sin6_addr = IN6ADDR_ANY_INIT + }; + if (bind(sock, (struct sockaddr *) &listen, sizeof listen) == -1) { + perror("bind(sock, &listen, sizeof listen)"); + return 3; + } + struct pollfd pfd = { + .fd = sock, + .events = POLLIN + }; + while (poll(&pfd, 1, -1) != -1) { + if (pfd.revents & POLLERR) { + fprintf(stderr, "POLLERR\n"); + return 5; + } + if (pfd.revents & POLLHUP) { + fprintf(stderr, "POLLHUP\n"); + return 6; + } + if (pfd.revents & POLLNVAL) { + fprintf(stderr, "POLLNVAL\n"); + return 7; + } + struct sockaddr_in6 sender; + unsigned char packet[512]; + struct iovec parts[] = { + { + .iov_base = packet, + .iov_len = sizeof packet + } + }; + struct msghdr msg = { + .msg_name = &sender, + .msg_namelen = sizeof sender, + .msg_iov = parts, + .msg_iovlen = sizeof parts/sizeof parts[0] + }; + int bytes = recvmsg(sock, &msg, MSG_DONTWAIT | MSG_TRUNC); + if (bytes == -1) { + perror("recvmsg"); + return 8; + } + int len = handle(packet, bytes); + if (len >= 0) { + if (sendto(sock, packet, len, MSG_DONTWAIT | MSG_NOSIGNAL, (struct sockaddr *) &sender, sizeof sender) == -1 && errno != EACCES) { + perror("sendto"); + return 9; + } + } + } + perror("poll"); + return 4; // there really is no successful exit code, this program should run indefinitely +} diff --git a/prog/6/makefile b/prog/6/makefile new file mode 100644 index 0000000..8a847a2 --- /dev/null +++ b/prog/6/makefile @@ -0,0 +1,37 @@ +DESTDIR=/ +CC=cc +MYCFLAGS=-O0 -Wall -Wextra -Wformat -pedantic -g +MYLDFLAGS=-lresolv + +default: 6d 6c + +6d: daemon.c + $(CC) $(MYCFLAGS) $(CFLAGS) $< -o$@ $(MYLDFLAGS) $(LDFLAGS) + +6c: client.c + $(CC) $(MYCFLAGS) $(CFLAGS) $< -o$@ $(MYLDFLAGS) $(LDFLAGS) + +install: 6d 6c + mkdir -p $(DESTDIR)/usr/bin/ + cp 6d $(DESTDIR)/usr/bin/ + cp 6c $(DESTDIR)/usr/bin/ + +uninstall: + rm -fr $(DESTDIR)/usr/bin/6d + rm -fr $(DESTDIR)/usr/bin/6c + +distclean: clean + +clean: + rm -fr 6d 6c + +valgrind: + valgrind --error-exitcode=59 --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind-out.txt $(CMD) + +# tests if code compiles under gcc, clang and tcc +cc: + make -e CC=tcc + make -e CC=gcc + make -e CC=clang + +.PHONY: default, install, distclean, clean, valgrind, cc, uninstall |