diff --git a/Makefile b/Makefile index 79247cc5..50677a4b 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,7 @@ bench \ carray \ checksum \ disked \ +dnsconfig \ editor \ ext \ games \ diff --git a/dnsconfig/.gitignore b/dnsconfig/.gitignore new file mode 100644 index 00000000..bf7aadfe --- /dev/null +++ b/dnsconfig/.gitignore @@ -0,0 +1 @@ +dnsconfig diff --git a/dnsconfig/Makefile b/dnsconfig/Makefile new file mode 100644 index 00000000..db9266f2 --- /dev/null +++ b/dnsconfig/Makefile @@ -0,0 +1,30 @@ +SOFTWARE_MEANT_FOR_SORTIX=1 +include ../build-aux/platform.mak +include ../build-aux/compiler.mak +include ../build-aux/version.mak +include ../build-aux/dirs.mak + +OPTLEVEL?=$(DEFAULT_OPTLEVEL) +CFLAGS?=$(OPTLEVEL) + +CFLAGS += -Wall -Wextra + +BINARIES = dnsconfig +MANPAGES8 = dnsconfig.8 + +all: $(BINARIES) + +.PHONY: all install clean + +install: all + mkdir -p $(DESTDIR)$(SBINDIR) + install $(BINARIES) $(DESTDIR)$(SBINDIR) + mkdir -p $(DESTDIR)$(MANDIR)/man8 + cp $(MANPAGES8) $(DESTDIR)$(MANDIR)/man8 + +%: %.c + $(CC) -std=gnu11 $(CFLAGS) $(CPPFLAGS) $< -o $@ + +clean: + rm -f $(BINARIES) + diff --git a/dnsconfig/dnsconfig.8 b/dnsconfig/dnsconfig.8 new file mode 100644 index 00000000..aab27305 --- /dev/null +++ b/dnsconfig/dnsconfig.8 @@ -0,0 +1,86 @@ +.Dd October 7, 2021 +.Dt DNSCONFIG 8 +.Os +.Sh NAME +.Nm dnsconfig +.Nd configure kernel DNS resolver list +.Sh SYNOPSIS +.Nm +.Nm +.Ar resolver ... +.Nm +.Fl s +.Op Ar resolver ... +.Nm +.Fl a +.Op Ar resolver ... +.Nm +.Fl d +.Op Ar resolver ... +.Sh DESCRIPTION +.Nm +writes the current kernel DNS resolver list, or modifies it if any resolvers are +specified. +.Pp +The options are as follows: +.Bl -tag -width "12345678" +.It Fl a +Append resolvers to the list. +.It Fl d +Delete resolvers from the list. +.It Fl s +Set the resolver list. +This option is the default if +.Nm +is invoked with any resolvers. +.El +.Sh EXIT STATUS +.Nm +will exit 0 on success and non-zero otherwise. +.Sh EXAMPLES +Get the resolvers: +.Bd -literal +$ dnsconfig +192.0.2.1 +.Ed +.Pp +Set two resolvers: +.Bd -literal +# dnsconfig 192.0.2.15 192.0.2.100 +# dnsconfig +192.0.2.15 +192.0.2.100 +.Ed +.Pp +Set the resolvers to the empty list: +.Bd -literal +# dnsconfig -s +# dnsconfig +.Ed +.Pp +Append a resolver: +.Bd -literal +# dnsconfig 192.0.2.128 +# dnsconfig -a 192.0.2.40 +# dnsconfig +192.0.2.128 +192.0.2.40 +.Ed +.Pp +Delete a resolver: +.Bd -literal +# dnsconfig -d 192.0.2.128 +# dnsconfig +192.0.2.40 +.Ed +.Sh SEE ALSO +.Xr getdnsconfig 2 , +.Xr setdnsconfig 2 +.Sh HISTORY +.Nm +originally appeared in Sortix 1.1. +.Sh CAVEATS +The kernel DNS resolver list is global state. +Changes made with +.Nm +may be overwritten by other programs. diff --git a/dnsconfig/dnsconfig.c b/dnsconfig/dnsconfig.c new file mode 100644 index 00000000..dd8fc88e --- /dev/null +++ b/dnsconfig/dnsconfig.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2021 Juhani 'nortti' Krekelä. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * dnsconfig.c + * Configure kernel DNS resolver list. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + bool append = false; + bool delete = false; + bool set = false; + + int opt; + while ( (opt = getopt(argc, argv, "ads")) != -1 ) + { + switch ( opt ) + { + case 'a': append = true; break; + case 'd': delete = true; break; + case 's': set = true; break; + } + } + + if ( append + delete + set > 1 ) + errx(1, "-a, -d, -s are mutually exclusive"); + + // If no mode is provided but there are arguments, default to set. + if ( !append && !delete && !set && optind < argc ) + set = true; + + struct dnsconfig dnsconfig = {0}; + if ( !set && getdnsconfig(&dnsconfig) < 0 ) + err(1, "getdnsconfig"); + + if ( append || delete || set ) + { + for ( int i = optind; i < argc; i++ ) + { + struct dnsconfig_server server = {0}; + if ( inet_pton(AF_INET, argv[i], &server.addr.in) ) + { + server.family = AF_INET; + server.addrsize = sizeof(server.addr.in); + } + else if ( inet_pton(AF_INET6, argv[i], &server.addr.in6) ) + { + server.family = AF_INET6; + server.addrsize = sizeof(server.addr.in6); + } + else + errx(1, "Invalid address: %s", argv[i]); + + if ( !delete ) + { + size_t index = dnsconfig.servers_count++; + if ( dnsconfig.servers_count > DNSCONFIG_MAX_SERVERS ) + errx(1, "Too many DNS resolvers (%zu max)", + (size_t) DNSCONFIG_MAX_SERVERS); + dnsconfig.servers[index] = server; + } + else + { + // Search for a matching entry. + bool found = false; + for ( size_t j = 0; j < dnsconfig.servers_count; j++ ) + { + if ( dnsconfig.servers[j].family != server.family || + memcmp(&dnsconfig.servers[j].addr, &server.addr, + server.addrsize) ) + continue; + + for ( size_t k = j + 1; k < dnsconfig.servers_count; k++ ) + dnsconfig.servers[k - 1] = dnsconfig.servers[k]; + dnsconfig.servers_count--; + memset(&dnsconfig.servers[dnsconfig.servers_count], 0, + sizeof(struct dnsconfig_server)); + found = true; + break; + } + + if ( !found ) + errx(1, "Resolver not in the list: %s", argv[i]); + } + + } + + if ( setdnsconfig(&dnsconfig) < 0 ) + err(1, "setdnsconfig"); + } + else + { + for ( size_t i = 0; i < dnsconfig.servers_count; i++ ) + { + char address[INET6_ADDRSTRLEN]; + if ( !inet_ntop(dnsconfig.servers[i].family, + &dnsconfig.servers[i].addr, + address, sizeof(address)) ) + err(1, "inet_ntop"); + if ( printf("%s\n", address) < 0 ) + err(1, "stdout"); + } + if ( fflush(stdout) ) + err(1, "stdout"); + } + + return 0; +}