diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2021-01-12 10:03:51 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2021-01-12 10:03:51 +0000 |
commit | fe49776280489a3bb9405f2d7651d1b16e4fe2e6 (patch) | |
tree | 7748b5950bd6cf3092c378cc17de6838372db75d | |
parent | 54e0e8469f9465877a155308cc2a8cc5b85fbfad (diff) | |
download | dnsfunnel-fe49776280489a3bb9405f2d7651d1b16e4fe2e6.tar.gz dnsfunnel-fe49776280489a3bb9405f2d7651d1b16e4fe2e6.tar.xz dnsfunnel-fe49776280489a3bb9405f2d7651d1b16e4fe2e6.zip |
First big batch of fixes, remove dnsfunnel-daemon, etc.
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | COPYING | 2 | ||||
-rw-r--r-- | INSTALL | 2 | ||||
-rw-r--r-- | NEWS | 2 | ||||
-rwxr-xr-x | configure | 6 | ||||
-rw-r--r-- | doc/dnsfunnel-daemon.html | 115 | ||||
-rw-r--r-- | doc/dnsfunnel-translate.html | 6 | ||||
-rw-r--r-- | doc/dnsfunneld.html | 107 | ||||
-rw-r--r-- | doc/index.html | 8 | ||||
-rw-r--r-- | package/deps.mak | 7 | ||||
-rw-r--r-- | package/modes | 1 | ||||
-rw-r--r-- | package/targets.mak | 1 | ||||
-rw-r--r-- | src/dnsfunnel/deps-exe/dnsfunnel-daemon | 1 | ||||
-rw-r--r-- | src/dnsfunnel/deps-exe/dnsfunneld | 2 | ||||
-rw-r--r-- | src/dnsfunnel/dnsfunnel-daemon.c | 150 | ||||
-rw-r--r-- | src/dnsfunnel/dnsfunnel-translate.c | 4 | ||||
-rw-r--r-- | src/dnsfunnel/dnsfunneld.c | 178 |
17 files changed, 219 insertions, 374 deletions
diff --git a/.gitignore b/.gitignore index 8c7ef95..4f88017 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,5 @@ *.so.* /config.mak /src/include/dnsfunnel/config.h -/dnsfunnel-daemon /dnsfunneld /dnsfunnel-translate diff --git a/COPYING b/COPYING index 6b16aad..f262571 100644 --- a/COPYING +++ b/COPYING @@ -1,4 +1,4 @@ -Copyright (c) 2020 Laurent Bercot <ska-skaware@skarnet.org> +Copyright (c) 2020-2021 Laurent Bercot <ska-skaware@skarnet.org> Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above diff --git a/INSTALL b/INSTALL index 2c3583d..fa107a5 100644 --- a/INSTALL +++ b/INSTALL @@ -7,7 +7,7 @@ Build Instructions - A POSIX-compliant C development environment - GNU make version 3.81 or later - skalibs version 2.10.0.0 or later: https://skarnet.org/software/skalibs/ - - s6-dns version 2.3.3.0 or later: https://skarnet.org/software/s6-dns/ + - s6-dns version 2.3.4.0 or later: https://skarnet.org/software/s6-dns/ This software will run on any operating system that implements POSIX.1-2008, available at: diff --git a/NEWS b/NEWS index 8c45fe2..7bc99b1 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -Changelog for mdevd. +Changelog for dnsfunnel. In 0.0.1.0 ---------- diff --git a/configure b/configure index 664a43f..7dffc35 100755 --- a/configure +++ b/configure @@ -45,8 +45,6 @@ Optional features: --enable-slashpackage[=ROOT] assume /package installation at ROOT [disabled] --enable-absolute-paths do not rely on PATH to access this package's binaries, hardcode absolute BINDIR/foobar paths instead [disabled] - - --with-cachelist=FILE use FILE as default cache list [/run/dnsfunnel-caches] EOF exit 0 } @@ -159,7 +157,6 @@ addlibdpath='' vpaths='' vpathd='' build= -cachelist=/run/dnsfunnel-caches for arg ; do case "$arg" in @@ -190,7 +187,6 @@ for arg ; do --disable-slashpackage) sproot= ; slashpackage=false ;; --enable-absolute-paths|--enable-absolute-paths=yes) abspath=true ;; --disable-absolute-paths|--enable-absolute-paths=no) abspath=false ;; - --with-cachelist=*) cachelist=${arg#*=} ;; --enable-*|--disable-*|--with-*|--without-*|--*dir=*) ;; --host=*|--target=*) target=${arg#*=} ;; --build=*) build=${arg#*=} ;; @@ -468,8 +464,6 @@ else fi echo "#define ${package_macro_name}_LIBEXECPREFIX \"$libexecdir/\"" echo -echo "#define ${package_macro_name}_DEFAULT_CACHELIST \"$cachelist\"" -echo echo "#endif" exec 1>&3 3>&- echo " ... done." diff --git a/doc/dnsfunnel-daemon.html b/doc/dnsfunnel-daemon.html deleted file mode 100644 index b779635..0000000 --- a/doc/dnsfunnel-daemon.html +++ /dev/null @@ -1,115 +0,0 @@ -<html> - <head> - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> - <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> - <meta http-equiv="Content-Language" content="en" /> - <title>dnsfunnel: the dnsfunnel-daemon program</title> - <meta name="Description" content="dnsfunnel: the dnsfunnel-daemon program" /> - <meta name="Keywords" content="dnsfunnel daemon /etc/resolv.conf local cache resolver 127.0.0.1" /> - <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> --> - </head> -<body> - -<p> -<a href="index.html">dnsfunnel</a><br /> -<a href="//skarnet.org/software/">Software</a><br /> -<a href="//skarnet.org/">skarnet.org</a> -</p> - -<h1> The <tt>dnsfunnel-daemon</tt> program </h1> - -<p> -<tt>dnsfunnel-daemon</tt> binds to a local UDP socket, drops its -privileges, then executes into <a href="dnsfunneld.html">dnsfunneld</a>. -It is the high-level entry point to invoke in scripts that want to launch -<a href="dnsfunneld.html">dnsfunneld</a>. - -</p> - -<h2> Interface </h2> - -<pre> - dnsfunnel-daemon [ -v verbosity ] [ -d notif ] [ -U | -u uid -g gid ] [ -i ip:port ] [ -R root ] [ -b bufsize ] [ -f cachelist ] [ -T | -t ] [ -N | -n ] -</pre> - -<ul> - <li> dnsfunnel-daemon creates a UDP inet domain socket and binds it -to IPv4 address <em>ip</em> (normally 127.0.0.1) and port <em>port</em> -(normally 53). </li> - <li> Depending on the options it has been given, it may chroot and lose -privileges on its gid and uid. </li> - <li> It execs into <a href="dnsfunneld.html">dnsfunneld</a> with the -UDP socket as its standard input. </li> -</ul> - -<p> - The point of <tt>dnsfunnel-daemon</tt> is to separate the administrative -operations of starting a daemon from the actual serving part, which is -handled by <a href="dnsfunneld.html">dnsfunneld</a>. -</p> - -<h2> Exit codes </h2> - -<ul> - <li> 100: wrong usage </li> - <li> 111: system call failed </li> - <li> 126: failed to exec <a href="dnsfunneld.html">dnsfunneld</a> </li> - <li> 127: could not find the <a href="dnsfunneld.html">dnsfunneld</a> executable </li> -</ul> - -<h2> Options </h2> - -<ul> - <li> <tt>-v <em>verbosity</em></tt> : verbosity of the -<a href="dnsfunneld.html">dnsfunneld</a> program. This option is passed as is -to <a href="dnsfunneld.html">dnsfunneld</a>. Default is 1. 0 suppresses warning -messages. Higher values may give more informational messages. </li> - <li> <tt>-d <em>notif</em></tt> : readiness notification. This option -is passed as is to <a href="dnsfunneld.html">dnsfunneld</a>, which will print a -newline to descriptor <em>notif</em> when it is ready. Default is no readiness -notification. </li> - <li> <tt>-U</tt> : read an uid in the UID environment variable and a gid -in the GID environment variable, and drop privileges to that uid/gid. </li> - <li> <tt>-u <em>uid</em></tt> : drop privileges to numerical uid -<em>uid</em>. </li> - <li> <tt>-g <em>gid</em></tt> : drop privileges to numerical gid -<em>gid</em>. </li> - <li> <tt>-i <em>ip</em>:<em>port</em></tt> : bind the socket to -IPv4 <em>ip</em> and port <em>port</em>. Default for <em>ip</em> is -<tt>127.0.0.1</tt>; default for <em>port</em> is 53. </li> - <li> <tt>-R <em>root</em></tt> : chroot to <em>root</em>. Note that -this option only increases security if you also drop privileges. </li> - <li> <tt>-b <em>bufsize</em></tt> : try and reserve a kernel buffer -size of <em>bufsize</em> bytes for the socket. Default is 131072. If the given -<em>bufsize</em> is 0, then <tt>dnsfunnel-daemon</tt> will use whatever the -default is for your kernel. </li> - <li> <tt>-f <em>cachelist</em></tt> : Use <em>cachelist</em> as the -file that <a href="dnsfunneld.html">dnsfunneld</a> reads its cache addresses -from. Default is <tt>/run/dnsfunnel-caches</tt>, or <em>file</em> -if the <tt>--with-cachelist=<em>file</em></tt> option has been given to the -configure script at build time. </li> -</ul> - -<p> - The other options control the activation or deactivation of various -<a href="dnsfunneld.html">dnsfunneld</a> features: -</p> - <li> <tt>-T</tt> : Do not activate truncation of responses. This is -the default. </li> - <li> <tt>-t</tt> : If a DNS response is bigger than 510 bytes, -truncate its last resource records until it fits into 510 bytes and can -be sent in a UDP packet. </li> - <li> <tt>-N</tt> : Do not activate nxdomain workaround. This is the -default. </li> - <li> <tt>-n</tt> : Activate nxdomain workaround. When receiving an A -(resp. AAAA) query to forward, also make an AAAA (resp. A) query, and adjust -the response accordingly. Some DNS servers incorrectly answer NXDOMAIN when -they should just answer NODATA, and querying for another, existing, record -type for the same domain allows dnsfunneld to tell the difference between a -real NXDOMAIN (in which case that response is forwarded to the client) and -an incorrect one (in which case NODATA is answered to the client instead). </li> - <li> Other options may be added in the future. </li> -</ul> - -</body> -</html> diff --git a/doc/dnsfunnel-translate.html b/doc/dnsfunnel-translate.html index 9dde27d..112a615 100644 --- a/doc/dnsfunnel-translate.html +++ b/doc/dnsfunnel-translate.html @@ -56,14 +56,12 @@ get printed to <tt>outputfile</tt> <li> <tt>-i <em>inputfile</em></tt> : process <em>inputfile</em>. Default is <tt>/etc/resolv.conf</tt>. </li> <li> <tt>-o <em>outputfile</em></tt> : write the result to -<em>outputfile</em>. Default is <tt>/run/dnsfunnel-caches</tt>, or <em>file</em> -if the <tt>--with-cachelist=<em>file</em></tt> option has been given to the -configure script at build time. </li> +<em>outputfile</em>. Default is <tt>/run/dnsfunnel/root/caches</tt>. </li> <li> <tt>-x <em>ignoredip</em></tt> : ignore the <em>ignoredip</em> IPv4 address if it shows up as a <tt>nameserver</tt> in <em>inputfile</em>. Default is <tt>127.0.0.1</tt>. The point of this option is to avoid copying to <tt>outputfile</tt> the IPv4 address that the -<a href="dnsfunnel-daemon.html">dnsfunnel-daemon</a> daemon will be bound to. </li> +<a href="dnsfunneld.html">dnsfunneld</a> daemon will be bound to. </li> </ul> </body> diff --git a/doc/dnsfunneld.html b/doc/dnsfunneld.html index 006a6d6..5181db1 100644 --- a/doc/dnsfunneld.html +++ b/doc/dnsfunneld.html @@ -3,9 +3,9 @@ <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Language" content="en" /> - <title>dnsfunnel: the dnsfunnel-daemon program</title> - <meta name="Description" content="dnsfunnel: the dnsfunnel-daemon program" /> - <meta name="Keywords" content="dnsfunnel daemon /etc/resolv.conf local cache resolver 127.0.0.1" /> + <title>dnsfunnel: the dnsfunneld program</title> + <meta name="Description" content="dnsfunnel: the dnsfunneld program" /> + <meta name="Keywords" content="dnsfunnel daemon dnsfunneld /etc/resolv.conf local cache resolver 127.0.0.1" /> <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> --> </head> <body> @@ -29,19 +29,25 @@ queries, the responses, or both. <h2> Interface </h2> <pre> - dnsfunneld [ -v verbosity ] [ -d notif ] [ -o ops ] cachelist + dnsfunneld [ -v <em>verbosity</em> ] [ -1 ] [ -U | -u <em>uid</em> -g <em>gid</em> ] [ -i <em>ip</em>:<em>port</em> ] [ -R <em>root</em> ] [ -b <em>bufsize</em> ] [ -T | -t ] [ -N | -n ] </pre> <ul> - <li> dnsfunneld reads the <em>cachelist</em> file, expecting to find + <li> dnsfunneld creates a UDP inet domain socket and binds it +to IPv4 address <em>ip</em> (normally 127.0.0.1) and port <em>port</em> +(normally 53). </li> + <li> Depending on the options it has been given, it may chroot and lose +privileges on its gid and uid. </li> + <li> It reads the <tt>caches</tt> file (relative to its current +directory, which is either the directory it has been run from or, if +requested, the one it has chrooted into), expecting to find a list of IP (v4 or v6) addresses, one per line. These addresses are the DNS caches it will forward the queries to. </li> - <li> dnsfunneld expects to have a bound UDP inet domain socket as -its standard input. It expects to receive packets no more than 512 + <li> dnsfunneld expects to receive packets no more than 512 bytes long, only containing DNS normal queries (QUERY) for the IN -class. </li> - <li> Depending on <em>ops</em>, dnsfunneld may send additional queries -to the caches listed in <em>cachelist</em>. It handles the answers +class, on its socket. </li> + <li> Depending on options, dnsfunneld may send additional queries +to the caches listed in <tt>caches</tt>. It handles the answers internally: the additional queries are invisible to clients. </li> <li> dnsfunneld is a long-lived process. </li> </ul> @@ -49,7 +55,7 @@ internally: the additional queries are invisible to clients. </li> <h2> Signals </h2> <ul> - <li> SIGHUP: read the <em>cachelist</em> file again, updating its + <li> SIGHUP: read the <tt>caches</tt> file again, updating its in-memory cache list. In-flight queries are still handled by the old list; the new list will only apply for queries arriving after the SIGHUP. </li> <li> SIGTERM: enter lame-duck mode, do not accept any more queries. When @@ -70,20 +76,51 @@ all in-flight queries have been answered, exit 0. <li> <tt>-v <em>verbosity</em></tt> : verbosity. Default is 1. 0 suppresses warning messages. Higher values may give more informational messages in the future. </li> - <li> <tt>-d <em>notif</em></tt> : readiness notification. When -dnsfunneld is ready to process queries, write a newline to file descriptor -<em>notif</em>. <em>notif</em> must be 3 or greater. Default is no notification -at all. </li> - <li> <tt>-o <em>ops</em></tt> : perform various operations on -queries. <em>ops</em> is a decimal integer that is treated as a bitfield. -Default is 0. Operations are listed below. </li> + <li> <tt>-1</tt> : readiness notification. When +dnsfunneld is ready to process queries, write a newline to stdout, then +close it. Default is no notification at all. </li> + <li> <tt>-U</tt> : read an uid in the UID environment variable and a gid +in the GID environment variable, and drop privileges to that uid/gid. </li> + <li> <tt>-u <em>uid</em></tt> : drop privileges to numerical uid +<em>uid</em>. </li> + <li> <tt>-g <em>gid</em></tt> : drop privileges to numerical gid +<em>gid</em>. </li> + <li> <tt>-i <em>ip</em>:<em>port</em></tt> : bind the socket to +IPv4 <em>ip</em> and port <em>port</em>. Default for <em>ip</em> is +<tt>127.0.0.1</tt>; default for <em>port</em> is 53. </li> + <li> <tt>-R <em>root</em></tt> : chroot to <em>root</em>. Default +is <tt>/run/dnsfunnel/root</tt>. Note that chrooting only increases security +if privileges are also dropped via the <tt>-U</tt> or <tt>-u</tt> and <tt>-g</tt> +options. Chrooting is only supported on platforms that have the <tt>chroot()</tt> +primitive. You can also disable it by passing an empty string as the argument +to <tt>-R</tt>. </li> + <li> <tt>-b <em>bufsize</em></tt> : try and reserve a kernel buffer +size of <em>bufsize</em> bytes for the socket. The default is whatever the +default is for your kernel. </li> +</ul> + +<p> + The other options control the activation or deactivation of various +features. See below for the detail of operations. +</p> + +<ul> + <li> <tt>-T</tt> : Do not activate truncation of responses. This is +the default. </li> + <li> <tt>-t</tt> : If a DNS response is bigger than 510 bytes, +truncate its last resource records until it fits into 510 bytes and can +be sent in a UDP packet. </li> + <li> <tt>-N</tt> : Do not activate NXDOMAIN workaround. This is the +default. </li> + <li> <tt>-n</tt> : Activate NXDOMAIN workaround. </li> + <li> Other options may be added in the future. </li> </ul> <h2> DNS forwarding behaviour </h2> <ul> <li> When it receives a query, dnsfunneld forwards it to the first DNS cache -in the list it has read from the <em>cachelist</em> file. </li> +in the list it has read from the <tt>caches</tt> file. </li> <li> If it receives a response with the TC bit, it resends the query over TCP. </li> <li> If it receives a suitable response within a given time frame, it forwards it to the client. </li> @@ -112,29 +149,37 @@ time to resolve; </li> <h2> dnsfunneld operations </h2> <p> - <em>ops</em> is an integer used as a bitfield. Depending on which bits are set, -various operations are performed on queries or answers, slightly modifying the -behaviour described above. + Depending on the options it has been given, dnsfunneld may perform the +following operations on the queries or responses it receives: </p> -<ul> - <li> bit 0: activate truncation. If a DNS response is more than 510 bytes +<h3> Truncation </h3> + +<p> + If a DNS response is more than 510 bytes long, dnsfunneld will truncate the <em>last</em> resource records in the response, until it fits into 510 bytes and can be given to the client in a UDP packet. The structure of a DNS packet makes it so the RRs are listed in order of decreasing importance, so keeping as many RRs as will fit in 510 bytes -without reordering them is the natural way of truncating a response. </li> - <li> bit 1: activate workaround for some servers that incorrectly report -NXDOMAIN when they're asked for an AAAA record, and no such record exists -for the domain but an A record exists. When that bit is set in <em>ops</em>, -for every A or AAAA query dnsfunneld receives and forwards, it also sends +without reordering them is the natural way of truncating a response. +</p> + +<h3> NXDOMAIN workaround </h3> + +<p> + Some DNS servers incorrectly answer NXDOMAIN when +they should just answer NODATA, and querying for another, existing, record +type for the same domain allows dnsfunneld to tell the difference between a +real NXDOMAIN. + When that operation is requested, for every A or AAAA query dnsfunneld +receives and forwards, it also sends an additional AAAA or A query for the same domain. If the main query returns NXDOMAIN, dnsfunneld waits for the response to the auxiliary query: if this response is not NXDOMAIN, then dnsfunneld answers NODATA to the client instead of NXDOMAIN. Be aware that activating this workaround can practically double the number of queries sent to the DNS caches, and may cause additional delays -before the clients get their answers. </li> -</ul> +before the clients get their answers. +</p> <h2> Notes </h2> diff --git a/doc/index.html b/doc/index.html index fe8e8d4..b52f70a 100644 --- a/doc/index.html +++ b/doc/index.html @@ -42,15 +42,14 @@ TCP DNS transport. It was originally written to be used in the <h3> Requirements </h3> <ul> - <li> A POSIX-compliant system with a standard C development environment. -The system must also support <tt>chroot()</tt> </li> + <li> A POSIX-compliant system with a standard C development environment. </li> <li> GNU make, version 3.81 or later </li> <li> <a href="//skarnet.org/software/skalibs/">skalibs</a> version 2.10.0.0 or later. It's a build-time requirement. It's also a run-time requirement if you link against the shared version of the skalibs library. </li> <li> <a href="//skarnet.org/software/s6-dns/">s6-dns</a> version -2.3.3.0 or later. It's a build-time requirement. It's also a run-time +2.3.4.0 or later. It's a build-time requirement. It's also a run-time requirement if you link against the shared version of the s6dns library. </li> @@ -67,7 +66,7 @@ library. </li> <ul> <li> The current released version of dnsfunnel is -<a href="dnsfunnel-0.0.1.0.tar.gz">0.0.1.0</a>. +<!--<a href="dnsfunnel-0.0.1.0.tar.gz">-->0.0.1.0<!--</a>-->. (This is a lie. dnsfunnel is in alpha development at the moment, and only available through git.) </li> @@ -100,7 +99,6 @@ the previous versions of dnsfunnel and the current one. </li> <h3> Commands </h3> <ul> -<li><a href="dnsfunnel-daemon.html">The <tt>dnsfunnel-daemon</tt> program</a></li> <li><a href="dnsfunneld.html">The <tt>dnsfunneld</tt> program</a></li> <li><a href="dnsfunnel-translate.html">The <tt>dnsfunnel-translate</tt> program</a></li> </ul> diff --git a/package/deps.mak b/package/deps.mak index 29eaab1..a25cbd4 100644 --- a/package/deps.mak +++ b/package/deps.mak @@ -2,15 +2,12 @@ # This file has been generated by tools/gen-deps.sh # -src/dnsfunnel/dnsfunnel-daemon.o src/dnsfunnel/dnsfunnel-daemon.lo: src/dnsfunnel/dnsfunnel-daemon.c src/include/dnsfunnel/config.h -src/dnsfunnel/dnsfunnel-translate.o src/dnsfunnel/dnsfunnel-translate.lo: src/dnsfunnel/dnsfunnel-translate.c src/include/dnsfunnel/config.h +src/dnsfunnel/dnsfunnel-translate.o src/dnsfunnel/dnsfunnel-translate.lo: src/dnsfunnel/dnsfunnel-translate.c src/dnsfunnel/dnsfunneld.o src/dnsfunnel/dnsfunneld.lo: src/dnsfunnel/dnsfunneld.c src/dnsfunnel/dnsfunneld.h src/dnsfunnel/dnsfunneld_answer.o src/dnsfunnel/dnsfunneld_answer.lo: src/dnsfunnel/dnsfunneld_answer.c src/dnsfunnel/dnsfunneld.h src/dnsfunnel/dnsfunneld_process.o src/dnsfunnel/dnsfunneld_process.lo: src/dnsfunnel/dnsfunneld_process.c src/dnsfunnel/dnsfunneld.h -dnsfunnel-daemon: EXTRA_LIBS := -lskarnet -dnsfunnel-daemon: src/dnsfunnel/dnsfunnel-daemon.o dnsfunnel-translate: EXTRA_LIBS := -lskarnet dnsfunnel-translate: src/dnsfunnel/dnsfunnel-translate.o -dnsfunneld: EXTRA_LIBS := -ls6dns -lskarnet +dnsfunneld: EXTRA_LIBS := -ls6dns -lskarnet ${SOCKET_LIB} ${SYSCLOCK_LIB} dnsfunneld: src/dnsfunnel/dnsfunneld.o src/dnsfunnel/dnsfunneld_answer.o src/dnsfunnel/dnsfunneld_process.o diff --git a/package/modes b/package/modes index d42c9a1..ed68da3 100644 --- a/package/modes +++ b/package/modes @@ -1,3 +1,2 @@ -dnsfunnel-daemon 0755 dnsfunneld 0755 dnsfunnel-translate 0755 diff --git a/package/targets.mak b/package/targets.mak index 1a65a56..6d51bf5 100644 --- a/package/targets.mak +++ b/package/targets.mak @@ -1,5 +1,4 @@ BIN_TARGETS := \ -dnsfunnel-daemon \ dnsfunneld \ dnsfunnel-translate diff --git a/src/dnsfunnel/deps-exe/dnsfunnel-daemon b/src/dnsfunnel/deps-exe/dnsfunnel-daemon deleted file mode 100644 index e7187fe..0000000 --- a/src/dnsfunnel/deps-exe/dnsfunnel-daemon +++ /dev/null @@ -1 +0,0 @@ --lskarnet diff --git a/src/dnsfunnel/deps-exe/dnsfunneld b/src/dnsfunnel/deps-exe/dnsfunneld index 90302a1..88d6d31 100644 --- a/src/dnsfunnel/deps-exe/dnsfunneld +++ b/src/dnsfunnel/deps-exe/dnsfunneld @@ -2,3 +2,5 @@ dnsfunneld_answer.o dnsfunneld_process.o -ls6dns -lskarnet +${SOCKET_LIB} +${SYSCLOCK_LIB} diff --git a/src/dnsfunnel/dnsfunnel-daemon.c b/src/dnsfunnel/dnsfunnel-daemon.c deleted file mode 100644 index 1df6a38..0000000 --- a/src/dnsfunnel/dnsfunnel-daemon.c +++ /dev/null @@ -1,150 +0,0 @@ -/* ISC license. */ - -#include <skalibs/sysdeps.h> - -#ifndef SKALIBS_HASCHROOT -# error "this program can only be built on systems that provide a chroot() function" -#endif - -#include <skalibs/nonposix.h> /* chroot */ -#include <stdint.h> -#include <unistd.h> -#include <sys/types.h> -#include <stdlib.h> - -#include <skalibs/uint16.h> -#include <skalibs/types.h> -#include <skalibs/fmtscan.h> -#include <skalibs/sgetopt.h> -#include <skalibs/strerr2.h> -#include <skalibs/djbunix.h> -#include <skalibs/socket.h> -#include <skalibs/exec.h> - -#include <dnsfunnel/config.h> - -#define USAGE "dnsfunnel-daemon [ -v verbosity ] [ -d notif ] [ -U | -u uid -g gid ] [ -i ip:port ] [ -R root ] [ -b bufsize ] [ -f cachelist ] [ -T | -t ] [ -N | -n ] " -#define dieusage() strerr_dieusage(100, USAGE) - -int main (int argc, char const *const *argv) -{ - int notif = 0 ; - unsigned int verbosity = 1 ; - unsigned int bufsize = 131072 ; - int flagU = 0 ; - uid_t uid = -1 ; - gid_t gid = -1 ; - char const *ipport = "127.0.0.1:53" ; - char const *newroot = 0 ; - char const *cachelist = DNSFUNNEL_DEFAULT_CACHELIST ; - uint32_t ops = 0 ; - PROG = "dnsfunnel-daemon" ; - { - subgetopt_t l = SUBGETOPT_ZERO ; - for (;;) - { - int opt = subgetopt_r(argc, argv, "v:d:Uu:g:i:R:b:f:TtNn", &l) ; - if (opt == -1) break ; - switch (opt) - { - case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ; - case 'd' : if (!uint0_scan(l.arg, (unsigned int *)¬if)) dieusage() ; break ; - case 'U' : flagU = 1 ; break ; - case 'u' : if (!uid0_scan(l.arg, &uid)) dieusage() ; break ; - case 'g' : if (!gid0_scan(l.arg, &gid)) dieusage() ; break ; - case 'i' : ipport = l.arg ; break ; - case 'R' : newroot = l.arg ; break ; - case 'b' : if (!uint0_scan(l.arg, &bufsize)) dieusage() ; break ; - case 'f' : cachelist = l.arg ; break ; - case 'T' : ops &= ~1 ; break ; - case 't' : ops |= 1 ; break ; - case 'N' : ops &= ~2 ; break ; - case 'n' : ops |= 2 ; break ; - default : dieusage() ; - } - } - argc -= l.ind ; argv += l.ind ; - } - - { - int fd ; - char ip[4] ; - uint16_t port ; - size_t pos = ip4_scan(ipport, ip) ; - if (!pos) dieusage() ; - if (ipport[pos] != ':') dieusage() ; - if (!uint160_scan(ipport + pos + 1, &port)) dieusage() ; - fd = socket_udp4() ; - if (fd < 0) strerr_diefu1sys(111, "create UDP socket") ; - if (socket_bind4_reuse(fd, ip, port) < 0) - { - char fmti[IP4_FMT] ; - char fmtp[UINT16_FMT] ; - fmti[ip4_fmt(fmti, ip)] = 0 ; - fmtp[uint16_fmt(fmtp, port)] = 0 ; - strerr_diefu4sys(111, "bind on ip ", fmti, " port ", fmtp) ; - } - if (bufsize) socket_tryreservein(fd, bufsize) ; - if (fd_move(0, fd) < 0) - strerr_diefu1sys(111, "move file descriptors") ; - } - - if (newroot) - { - if (chdir(newroot) < 0 || chroot(".") < 0) - strerr_diefu2sys(111, "chroot to ", newroot) ; - } - - if (flagU) - { - char const *x = getenv("UID") ; - if (x && !uid0_scan(x, &uid)) - strerr_dieinvalid(100, "UID") ; - x = getenv("GID") ; - if (x && !gid0_scan(x, &gid)) - strerr_dieinvalid(100, "GID") ; - } - if (gid != (gid_t)-1 && setgid(gid) < 0) - { - char fmt[GID_FMT] ; - fmt[gid_fmt(fmt, gid)] = 0 ; - strerr_diefu2sys(111, "setgid to ", fmt) ; - } - if (uid != (uid_t)-1 && setuid(uid) < 0) - { - char fmt[UID_FMT] ; - fmt[uid_fmt(fmt, uid)] = 0 ; - strerr_diefu2sys(111, "setuid to ", fmt) ; - } - - { - char const *newargv[10] = { "dnsfunneld" } ; - char const *newenvp[1] = { 0 } ; - unsigned int m = 1 ; - char fmtv[UINT_FMT] ; - char fmtn[UINT_FMT] ; - char fmto[UINT_FMT] ; - if (verbosity != 1) - { - fmtv[uint_fmt(fmtv, verbosity)] = 0 ; - newargv[m++] = "-v" ; - newargv[m++] = fmtv ; - } - if (notif) - { - fmtn[uint_fmt(fmtn, notif)] = 0 ; - newargv[m++] = "-d" ; - newargv[m++] = fmtn ; - } - if (ops) - { - fmto[uint_fmt(fmto, ops)] = 0 ; - newargv[m++] = "-o" ; - newargv[m++] = fmto ; - } - newargv[m++] = "--" ; - newargv[m++] = cachelist ; - newargv[m++] = 0 ; - xexec_ae(DNSFUNNEL_BINPREFIX "dnsfunneld", newargv, newenvp) ; - } -} diff --git a/src/dnsfunnel/dnsfunnel-translate.c b/src/dnsfunnel/dnsfunnel-translate.c index 70610b8..d842629 100644 --- a/src/dnsfunnel/dnsfunnel-translate.c +++ b/src/dnsfunnel/dnsfunnel-translate.c @@ -12,8 +12,6 @@ #include <s6-dns/s6dns-constants.h> -#include <dnsfunnel/config.h> - #define USAGE "dnsfunnel-translate [ -i resolvconf ] [ -o cachelist ] [ -x ignoredip ]" #define dieusage() strerr_dieusage(100, USAGE) @@ -48,7 +46,7 @@ int main (int argc, char const *const *argv) { ip46_t list[S6DNS_MAX_SERVERS] = { IP46_ZERO } ; char const *resolvconf = "/etc/resolv.conf" ; - char const *cachelist = DNSFUNNEL_DEFAULT_CACHELIST ; + char const *cachelist = "/run/dnsfunnel/root/caches" ; char ignore[4] = "\177\0\0\1" ; size_t n ; PROG = "dnsfunnel-translate" ; diff --git a/src/dnsfunnel/dnsfunneld.c b/src/dnsfunnel/dnsfunneld.c index bd4dc89..12e9866 100644 --- a/src/dnsfunnel/dnsfunneld.c +++ b/src/dnsfunnel/dnsfunneld.c @@ -1,12 +1,22 @@ /* ISC license. */ +#include <skalibs/sysdeps.h> + +#ifdef SKALIBS_HASCHROOT +# include <skalibs/nonposix.h> +#endif + #include <stdint.h> #include <string.h> #include <signal.h> #include <fcntl.h> #include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <skalibs/uint16.h> #include <skalibs/uint32.h> +#include <skalibs/fmtscan.h> #include <skalibs/types.h> #include <skalibs/allreadwrite.h> #include <skalibs/error.h> @@ -26,7 +36,7 @@ #include "dnsfunneld.h" -#define USAGE "dnsfunneld [ -v verbosity ] [ -d notif ] [ -o operations ] cachelist" +#define USAGE "dnsfunneld [ -v verbosity ] [ -1 ] [ -U | -u uid -g gid ] [ -i ip:port ] [ -R root ] [ -b bufsize ] [ -T | -t ] [ -N | -n ]" #define dieusage() strerr_dieusage(100, USAGE) #define DNSFUNNELD_INPUT_MAX 64 @@ -34,7 +44,6 @@ unsigned int verbosity = 1 ; static tain_t globaltto = TAIN_INFINITE_RELATIVE ; static int cont = 1 ; -static char const *cachelistfile = 0 ; static s6dns_ip46list_t cachelist ; static uint32_t ops = 0 ; @@ -61,7 +70,7 @@ static int load_cachelist (int initial) char buf[4096] ; ip46full_t list[S6DNS_MAX_SERVERS] ; size_t n ; - ssize_t r = openreadnclose_nb(cachelistfile, buf, 4095) ; + ssize_t r = openreadnclose_nb("caches", buf, 4095) ; if (r < 0) return -1 ; buf[r++] = 0 ; ip46_scanlist(list, S6DNS_MAX_SERVERS, buf, &n) ; @@ -84,8 +93,8 @@ static inline void handle_signals (void) switch (load_cachelist(0)) { case 0 : query_process_reload() ; break ; - case -1 : strerr_warnwu2sys("read ", cachelistfile) ; break ; - case -2 : strerr_warnw2x("invalid cache list in ", cachelistfile) ; break ; + case -1 : strerr_warnwu1sys("read ./caches") ; break ; + case -2 : strerr_warnw1x("invalid cache list in ./caches") ; break ; default : X() ; } break ; @@ -147,64 +156,137 @@ static inline void sanitize_and_new (char const *buf, unsigned int len, char con int main (int argc, char const *const *argv) { int spfd = -1 ; - int notif = -1 ; PROG = "dnsfunneld" ; + { + unsigned int bufsize = 131072 ; + int flagU = 0 ; + uid_t uid = -1 ; + gid_t gid = -1 ; + char const *ipport = "127.0.0.1:53" ; + char const *root = "/run/dnsfunnel/root" ; + int notif = 0 ; + int fd ; + char ip[4] ; + size_t pos ; + uint16_t port ; subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) { - int opt = subgetopt_r(argc, argv, "v:d:o:", &l) ; + int opt = subgetopt_r(argc, argv, "v:1Uu:g:i:R:b:TtNn", &l) ; if (opt == -1) break ; switch (opt) { case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ; - case 'd' : if (!uint0_scan(l.arg, (unsigned int *)¬if)) dieusage() ; break ; - case 'o' : if (!uint320_scan(l.arg, &ops)) dieusage() ; break ; + case '1' : notif = 1 ; break ; + case 'U' : flagU = 1 ; break ; + case 'u' : if (!uid0_scan(l.arg, &uid)) dieusage() ; break ; + case 'g' : if (!gid0_scan(l.arg, &gid)) dieusage() ; break ; + case 'i' : ipport = l.arg ; break ; + case 'R' : root = l.arg ; break ; + case 'b' : if (!uint0_scan(l.arg, &bufsize)) dieusage() ; break ; + case 'T' : ops &= ~1 ; break ; + case 't' : ops |= 1 ; break ; + case 'N' : ops &= ~2 ; break ; + case 'n' : ops |= 2 ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; - if (!argc) dieusage() ; - } - if (notif >= 0) - { - if (notif < 3) strerr_dief1x(100, "notification fd must be 3 or more") ; - if (fcntl(notif, F_GETFD) < 0) strerr_dief1sys(100, "invalid notification fd") ; - } - if (ndelay_on(0) < 0) strerr_diefu1sys(111, "turn stdin non-blocking") ; - if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ; - cachelistfile = argv[0] ; - switch (load_cachelist(1)) - { - case 0 : break ; - case -1 : strerr_diefu2sys(111, "read ", cachelistfile) ; - case -2 : strerr_dief2x(100, "invalid cache list in ", cachelistfile) ; - default : X() ; - } - if (!s6dns_init()) strerr_diefu1sys(111, "s6dns_init") ; - spfd = selfpipe_init() ; - if (spfd < 0) strerr_diefu1sys(111, "init selfpipe") ; - { - sigset_t set ; - sigemptyset(&set) ; - sigaddset(&set, SIGTERM) ; - sigaddset(&set, SIGHUP) ; - if (selfpipe_trapset(&set) < 0) strerr_diefu1sys(111, "trap signals") ; - } - if (!gensetdyn_new(&queries, &sentinel)) - strerr_diefu1sys(111, "initialize query structure") ; - *QUERY(sentinel) = dfquery_zero ; - QUERY(sentinel)->next = sentinel ; - if (!query_process_init()) - strerr_diefu1sys(111, "initialize query processing") ; - tain_now_set_stopwatch_g() ; - - if (notif >= 0) - { - fd_write(notif, "\n", 1) ; - fd_close(notif) ; + pos = ip4_scan(ipport, ip) ; + if (!pos) dieusage() ; + if (ipport[pos] != ':') dieusage() ; + if (!uint160_scan(ipport + pos + 1, &port)) dieusage() ; + if (fcntl(1, F_GETFD) < 0) + { + if (notif) strerr_dief1sys(100, "option -1 given but stdout unavailable") ; + } + else if (!notif) close(1) ; + fd = socket_udp4() ; + if (fd < 0) strerr_diefu1sys(111, "create UDP socket") ; + if (socket_bind4_reuse(fd, ip, port) < 0) + { + char fmti[IP4_FMT] ; + char fmtp[UINT16_FMT] ; + fmti[ip4_fmt(fmti, ip)] = 0 ; + fmtp[uint16_fmt(fmtp, port)] = 0 ; + strerr_diefu4sys(111, "bind on ip ", fmti, " port ", fmtp) ; + } + if (bufsize) socket_tryreservein(fd, bufsize) ; + if (fd_move(0, fd) < 0) + strerr_diefu1sys(111, "move file descriptors") ; + if (ndelay_on(0) < 0) strerr_diefu1sys(111, "turn stdin non-blocking") ; + if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ; + if (!s6dns_init()) strerr_diefu1sys(111, "s6dns_init") ; + + if (root[0]) + { +#ifdef SKALIBS_HASCHROOT + if (chdir(root) < 0 || chroot(".") < 0) + strerr_diefu2sys(111, "chroot to ", root) ; +#else + errno = ENOSYS ; + strerr_warnwu2sys("chroot to ", root) ; +#endif + } + + if (flagU) + { + char const *x = getenv("UID") ; + if (x && !uid0_scan(x, &uid)) + strerr_dieinvalid(100, "UID") ; + x = getenv("GID") ; + if (x && !gid0_scan(x, &gid)) + strerr_dieinvalid(100, "GID") ; + } + if (gid != (gid_t)-1 && setgid(gid) < 0) + { + char fmt[GID_FMT] ; + fmt[gid_fmt(fmt, gid)] = 0 ; + strerr_diefu2sys(111, "setgid to ", fmt) ; + } + if (uid != (uid_t)-1 && setuid(uid) < 0) + { + char fmt[UID_FMT] ; + fmt[uid_fmt(fmt, uid)] = 0 ; + strerr_diefu2sys(111, "setuid to ", fmt) ; + } + + switch (load_cachelist(1)) + { + case 0 : break ; + case -1 : strerr_diefu1sys(111, "read ./caches") ; + case -2 : strerr_dief1x(100, "invalid cache list in ./caches") ; + default : X() ; + } + spfd = selfpipe_init() ; + if (spfd < 0) strerr_diefu1sys(111, "init selfpipe") ; + { + sigset_t set ; + sigemptyset(&set) ; + sigaddset(&set, SIGTERM) ; + sigaddset(&set, SIGHUP) ; + if (selfpipe_trapset(&set) < 0) strerr_diefu1sys(111, "trap signals") ; + } + if (!gensetdyn_new(&queries, &sentinel)) + strerr_diefu1sys(111, "initialize query structure") ; + *QUERY(sentinel) = dfquery_zero ; + QUERY(sentinel)->next = sentinel ; + if (!query_process_init()) + strerr_diefu1sys(111, "initialize query processing") ; + tain_now_set_stopwatch_g() ; + + if (notif) + { + fd_write(1, "\n", 1) ; + close(1) ; + } } + + + /* The main loop is here */ for (;;) { |