Commit Graph
100 Commits
Author SHA1 Message Date
Nicholas J. Kain 95c70ba2a7 Properly force a restart if scriptd exists and dies.
Also use designated initializers for the poll structure.
2022-09-08 07:21:57 -04:00
Nicholas J. Kain 26f81272ee scriptd: Signal handlers don't need SA_NOCLDWAIT set. 2022-09-08 07:17:11 -04:00
Nicholas J. Kain 5eccd4893a Set FD_CLOEXEC on scriptd(Sock|Stream).
These have no reason to be inherited by the script when it is
run by posix_spawn().
2022-09-07 17:25:22 -04:00
Nicholas J. Kain f7db9fd5e7 Correct regression introduced by previous commit.
safe_recv(..., len), when used on a blocking fd, will attempt
to call recv and collect data until either EOF, a hard error,
or len bytes are collected.

The previous commit used safe_recv() in a blocking mode to read
a single byte into a buffer that was larger than a byte.  This
would cause ndhc to stall as safe_recv() would try to fill that
buffer when no more data would ever be sent.

This issue would only happen if ndhc is supposed to run a script.

Introduce and use safe_recv_once() that will correct this problem and
fill the semantic gap for blocking fds.  I add a new call because in
some cases the above behavior might be required for a blocking fd, too.

Note that the above issue is not a problem for nonblocking fds; the
EAGAIN or EWOULDBLOCK path will return a short read.
2022-09-07 17:08:43 -04:00
Nicholas J. Kain ebd2c4c01a scriptd: Wait to notify s6 until script completes.
The motivation here is to be safe in cases where the script
is setting up firewall rules or tunnels and where subsequent
tasks require these to be complete before starting.

I expect that this is a common case where a script is used.

The implementation behaves almost identically to how ifchd works.
2022-09-07 04:45:30 -04:00
Nicholas J. Kain 4d739acbdd Use a helper to ensure xid always changes when we advance it.
The purpose of the changing xid is to prevent misinterpreting
delayed messages, and the rare chance where it's randomly the
same breaks this sequence-id property.
2022-08-28 04:41:11 -04:00
Nicholas J. Kain 9b8e2facbf Advance the xid before we send each DHCPDISCOVER. 2022-08-28 04:06:15 -04:00
Nicholas J. Kain c755902fbc Reseed the PRNG whenever we reset the DHCP state. 2022-08-28 04:00:06 -04:00
Nicholas J. Kain 1f0a8f29de Use the HWRNG for generating DUIDs and IAIDs.
Before these were generated from a freshly seeded PRNG which reduces the
state space of possible DUIDs and skews the distribution of both DUIDs
and IAIDs as a function of the PRNG choice.

None of this really matters much in practice, but do things right.
2022-08-28 04:00:06 -04:00
Nicholas J. Kain d43fc12306 Advance the xid after we consume a DHCPACK or DHCPNAK.
This isn't strictly required by the RFC but it is good practice.
2022-08-28 04:00:02 -04:00
Nicholas J. Kain 6446f80a02 privs: Don't use libc isdigit()
Avoid locale dependence and UB risk from integer promotion
2022-08-27 10:29:11 -04:00
Nicholas J. Kain 7fb968e861 Use memccpy() and memcpy() instead of nstr{cpy,lcpy,cat}.
These are standard, either in POSIX or C23.

The semantics are slightly different as the error path does not
enforce null-termination in the function itself, so enforce that
by hand.  As a nice side effect, this makes those error paths
easier to audit.
2022-08-27 04:11:12 -04:00
Nicholas J. Kain e223b4c5a8 Use {O,SOCK}_CLOEXEC more consistently. 2022-08-13 00:42:27 -04:00
Nicholas J. Kain 867b70e83e nk/privs.c: Fix a trivial warning. 2022-08-10 12:10:55 -04:00
Nicholas J. Kain 6c44f536ad Build with -Wstrict-overflow=5 and fix revealed warnings.
Some of these are actual bugs, but none are security-sensitive.
2022-08-10 11:32:30 -04:00
Nicholas J. Kain 9338aa37c2 Use libc snprintf and nstr{cpy,cat}.
We don't need async-safe snprintf anymore, and nstr{cpy,cat} are
more ergonomic and efficient where they can used.
2022-08-09 14:17:31 -04:00
Nicholas J. Kain 898765e0a8 scriptd: Use posix_spawn rather than fork/exec.
Also don't bother providing an artificial environment.
2022-08-09 13:40:10 -04:00
Nicholas J. Kain 45e8e0bad2 Remove an obsolete comment. 2022-08-06 12:41:35 -04:00
Nicholas J. Kain cee287a522 Add Codeberg as a git source. 2022-08-03 20:58:19 -04:00
Nicholas J. Kain cd859ce8c3 nk/privs: Make capabilities conditional on __linux__ define. 2022-03-08 23:35:12 -05:00
Nicholas J. Kain 9998790488 nk/privs: Use NO_NEW_PRIVS by default when setting non-empty capset.
There's no need to gate it behind a #define anymore given that
Linux 3.5 was released in 2012.
2022-03-08 14:54:57 -05:00
Nicholas J. Kain b21edf205a nk/hwrng: Use libc wrapper for getrandom by default. 2022-03-08 13:46:23 -05:00
Nicholas J. Kain 0b53d93648 Update documentation and add more configuration examples. 2022-03-08 12:38:27 -05:00
Nicholas J. Kain 5bca0a3d48 Add example config file and s6 run file. 2022-03-08 12:23:05 -05:00
Nicholas J. Kain 484a9c516b Use stb_snprintf instead of libc snprintf.
This gives us consistent behavior and stb_snprintf is async signal
safe.
2022-03-07 20:42:00 -05:00
Nicholas J. Kain 3773acf64d When rfkill is disabled, resync the carrier state to be safe.
This change guards against possible regressions introduced by
f3766990f9 if rfkill were to
prevent netlink carrier up events from being delivered while
rfkill is in effect for the interface.
2022-03-07 14:00:59 -05:00
Nicholas J. Kain f6dfd9a58a nk/exec.c: Update documentation comment 2022-02-25 07:10:07 -05:00
Nicholas J. Kain 9cd65f35d9 Get rid of nk/copy_cmdarg.h 2022-02-25 07:01:55 -05:00
Nicholas J. Kain 12631c59bb Update to latest nk/exec.c; see ncron repo for changes.
Notably, nk_generate_env() no longer calls malloc().
2022-02-25 06:43:42 -05:00
Nicholas J. Kain 7572e2eb8b snprintf() truncation checks were one byte too conservative. 2022-02-25 06:18:08 -05:00
Nicholas J. Kain ba8f674e15 nk/exec: Simplify and remove double null termination.
The current code pads with an extra character that is then rewritten
into a null character.  This isn't necessary with post-C99
implementations of standardized snprintf, so get rid of it.

Also add a note warning that nk_generate_env() and nk_execute()
are not async signal safe and are thus unsuitable for use in
multithreaded processes.

nk_execute() could be rewritten to be async signal safe without much
trouble, as the only problem point is snprintf() which is not guaranteed
to be async signal safe by POSIX.

However, nk_generate_env() performs chroot() if a chroot_path is
specified, and chroot() is not async signal safe in POSIX.
Additionally, malloc() can be called in rare cases where user
information fields are very long, and malloc() is obviously not async
signal safe.  Finally, snprintf() is used here, too, but it could be
replaced.

Converting to posix_spawn() is a no-go because posix_spawn() has no
facility for changing rlimits or chroot on the spawned process.

In summary, I don't think the gains are worth it.  Multithreaded
processes should just not fork().
2022-02-25 04:53:02 -05:00
Nicholas J. Kain 62aef529f4 Use safe_write() in nk/exec.c 2022-02-25 00:05:57 -05:00
Nicholas J. Kain 286b86d62c Preserve errno across signals. 2022-02-24 06:57:49 -05:00
Nicholas J. Kain a9874d4959 Support running an executable file when a new lease is acquired.
If no 'script-file = SCRIPTFILE' is specified in the configuration
file and if no '-X SCRIPTFILE' or '--script-file SCRIPTFILE'
command argument is provided, then this functionality is entirely
inactive and no associated subprocess is spawned.

Otherwise, ndhc will spawn a subprocess that runs as root that has the
sole job of forking off a subprocess that exec's the specified script in
a sanitized and fixed-state environment whenever a new DHCPv4 lease is
acquired.

Note that this script is provided no information about ndhc or the
DHCP state in the environment or in any argument fields; it is the
responsibility of this script to gather whatever information it needs
from either the filesystem or syscalls.  This design is intended to
avoid the historical problems that are associated with dhcp clients
invoking scripts.

The path of the scriptfile cannot be changed after ndhc is initially
run; ndhc forks off the privsep script subprocess that executes scripts
after it has read the configuration file and command arguments, but
before it begins processing network data; thus, it is impossible for the
network-handling process to modify or influence the script assuming
proper OS memory protection.

The privsep channel communicates that the script should be run by simply
writing a newline; anything else will result in ndhc terminating itself.

Before the recommended way to update system state after a change in
lease information was to run the fcactus program and watch the
associated leasefile for the interface for modification; now no external
program is needed for this job.
2022-02-24 03:58:37 -05:00
Nicholas J. Kain 2fb16567f1 Support s6 service startup notification
This can be enabled via the s6-notify configure option; see
http://www.skarnet.org/software/s6/notifywhenup.html for details.

ndhc will signal that it is ready when the first valid lease is
obtained.  Programs dependent on a working network interface
can then simply use s6-wait on the associated ndhc service dir.

A typical command line option assuming the s6 service directory
notification-fd contains '3' would be '--s6-notify 3', and
a typical configure file option would be 's6-notify 3'.
2022-02-13 05:25:17 -05:00
Nicholas J. Kain d67e1599df Update the manpage a bit. 2022-02-12 12:57:10 -05:00
Nicholas J. Kain 416bed7eec Minor README update 2022-02-06 21:02:14 -05:00
Nicholas J. Kain 1732bccccc Relicense as MIT.
It's a lot more common than BSD 2-clause it is both compatible
and nearly identical in effect.
2022-02-06 20:05:29 -05:00
Nicholas J. Kain 9fddfbda61 Simplify Makefile 2022-01-23 19:37:40 -05:00
Nicholas J. Kain 6f85b2aaf2 Update Makefile to generate dependency info 2022-01-23 18:42:40 -05:00
Nicholas J. Kain 8db8c5589d Replace CMake with GNU Make.
There was previously support for both build systems, but ndhc is
undemanding and there is no point in maintaining a complex
CMake build.
2022-01-22 18:39:41 -05:00
Nicholas J. Kain 1055c27bcf Update Makefile build flags 2022-01-22 15:49:16 -05:00
Nicholas J. Kain a71b95ad34 CMake: Update to latest policies 2022-01-21 19:01:37 -05:00
Nicholas J. Kain 6ec0a5c731 Replace mostly obsolete -[static 1] with reliable old *-.
This notation originally had the sole advantage of implying
that the pointer was non-NULL, but it has seen little use and
now clang presents warnings about it in certain contexts.
2022-01-11 22:35:19 -05:00
Nicholas J. Kain 6047f04a12 Guard against carrier being spuriously set down.
Corrects a possible regression introduced by the previous patch.
2022-01-11 22:16:44 -05:00
Nicholas J. Kain f3766990f9 Speed up interface carrier checking.
This is done by performing one synchronous query for carrier state at
the start of the program; after that, we just monitor the nlsocket for
carrier state changes and update the cached state accordingly.

The benefit is that ifchd needs to do a lot less work and this should
reduce the CPU cycle consumption; prior to this commit, the CPU time
ends up being a few CPU-minutes per month.
2021-04-25 05:55:01 -04:00
Nicholas J. Kain ad1546ecb0 ifchd: Minor corrections in informative prints 2021-04-25 05:45:21 -04:00
Nicholas J. Kain d61902cad4 ifchd: Better handle incomplete command buffers.
Before the handling would constantly acculmulate a prefix of previous
incomplete commands.  Now it still has a latent defect where the entire
buffer will be discarded given a spurious command, but ndhc shouldn't
generate such commands so it shouldn't matter.
2021-04-25 05:45:21 -04:00
Nicholas J. Kain eb463ab086 poll() revents bits are reset by poll() 2021-04-25 05:45:21 -04:00
Nicholas J. Kain c8eb238f31 ifchd-parse: Simplify leftover-buffer copying. 2021-04-24 20:50:08 -04:00
Nicholas J. Kain b8bffa16c5 Build without -fno-strict-overflow.
I only built with this flag to mitigate accidental UB.  Now that
UBSan exists, there's no point as UBSan does better and actually
allows offending code to be located and fixed easily.
2020-11-25 04:44:26 -05:00
Nicholas J. Kain 28e1b34bac Simplify logging and fix some format specifiers. 2020-11-24 21:02:51 -05:00
Nicholas J. Kain 2e3c504cc5 Add and use safe_ftruncate() wrapper. 2020-11-06 18:47:51 -05:00
Nicholas J. Kain a91b1d34ac Check and clear events from poll() even if interrupted by signal. 2020-11-06 18:32:38 -05:00
Nicholas J. Kain 1e60b4b8e7 Optimize internet checksum to use 32-bit fetches.
It's actually not very hard to do everything with 32-bit fetches
and 32-bit registers, aside from the necessary bit fetches for
tails.
2020-11-01 01:06:58 -04:00
Nicholas J. Kain ff8b910222 Rename net_checksum161c to net_checksum16.
How many characters are summed at a time is an irrelevant
implementation detail.
2020-10-27 14:45:15 -04:00
Nicholas J. Kain 918555219b Make fingerprinting more robust with rapid carrier state changes.
The existing code tracked the fingerprinting completion state with
a bool, which is insufficient; what is required is a tristate
(none|inprogress|done) where the inprogress state reverts to
none on carrier down, but done state stays done on carrier down.
2020-10-27 14:14:18 -04:00
Nicholas J. Kain d07469a5fa Optimize internet checksum to use 16-bit fetches.
We could use 32-bit fetches with the same technique on 64-bit
architectures, or SIMD could be used to do very fast 128-bit
fetches, but this isn't a performance bottleneck and this
method is very simple and relatively fast.
2020-10-24 17:14:20 -04:00
Nicholas J. Kain 5fdf3bd83e Remove unused definitions from CMakeLists.txt. 2020-10-24 15:45:57 -04:00
Nicholas J. Kain b86735c478 Minor signal handling fixes. 2020-10-21 09:49:22 -04:00
Nicholas J. Kain d58338b70b serverid checks for RENEW and REBIND DHCP(ACK|NAK) were too strict.
Use the same test that is already used for the DHCPACK sent by
the server in the REQUESTING state.
2020-10-21 06:47:11 -04:00
Nicholas J. Kain b07ebb60a2 Revert bb7841f3ee.
That trivial warning fix causes warnings with -Wcast-qual, which
is a more valid warning than whatever was causing the warnings
under -Wall -pedantic with the normal Makefile.
2020-10-20 07:55:47 -04:00
Nicholas J. Kain 48bbb0b805 Add a missing newline to an error message.
I'm almost certain I remember adding this before, but I guess
it somehow got lost.
2020-10-20 07:53:23 -04:00
Nicholas J. Kain bb7841f3ee Trivial warning fix. 2020-10-20 07:18:49 -04:00
Nicholas J. Kain e6b5247d54 Update the plain Makefile. 2020-10-20 07:18:19 -04:00
Nicholas J. Kain 1ba7c9a2ba Documentation update -- signalfd and epoll aren't used anymore. 2020-10-20 07:06:19 -04:00
Nicholas J. Kain f1e20305ba Don't depend on external ncmlib. 2020-10-20 07:00:20 -04:00
Nicholas J. Kain 4575f74164 Remove legacy support for exiting after obtaining a DHCP lease. 2020-10-20 06:55:04 -04:00
Nicholas J. Kain ade4e988af Remove legacy support for forking to background. 2020-10-20 06:55:04 -04:00
Nicholas J. Kain 58067200d6 Remove legacy support for writing a pidfile. 2020-10-20 06:55:04 -04:00
Nicholas J. Kain 4d33c00e04 Use poll() instead of epoll() for ndhc-master. 2020-10-20 05:58:29 -04:00
Nicholas J. Kain af9d45719f Use poll() instead of epoll() for ifchd and sockd.
poll() is simpler, portable, and the scalability advantages of
epoll are inapplicable here.
2020-10-20 05:41:09 -04:00
Nicholas J. Kain 06a541261e Stop using signalfd and audit signal handling code.
There's really no advantage to using signalfd in ndhc, particularly
since the normal POSIX signal API is now used for handling SIGCHLD in
ndhc-master.  So just use the tried and true volatile sig_atomic_t set
and check approach.

The only intended behavior change is in the dhcp RELEASE state --
before there would be a spurious attempt at renewing a nonexistent
lease when the RENEW signal was received.
2020-10-20 04:42:58 -04:00
Nicholas J. Kain 8d89ca9f19 Reliably force restart when a subprocess has a fatal error.
Suppose a system call such as bind() fails in the sockd subprocess in
request_sockd_fd().  sockd will suicide().  This will send a SIGCHLD to
the master process, which the master process should respond to by
calling suicide(), forcing a process supervisor to respawn the entire
ndhc program.

But, this doesn't reliably happen prior to this commit because of the
interaction between request_sock_fd() and signalfd() [or equivalently
self-pipe-trick] signal handling.

request_sock_fd() makes ndhc-master synchronously wait for a response
from sockd via safe_recvmsg().  The normal goto-like signal handling
path is suppressed when using signalfd() , so when SIGCHLD is received,
it will not be handled until io is dispatched for the signalfd or pipe.
But such code will never be reached because ndhc-master is waiting in
safe_recvmsg() and thus never polls signal fd status.

So, revert to using traditional POSIX sigaction() for SIGCHLD, which
provides exactly the required behavior for proper functioning.
2020-10-20 04:41:51 -04:00
Nicholas J. Kain f0340b1475 Correct ba046c02c7.
Apparently I had forgotten the counter-intuitive semantics of
signalfd(): it's necessary to BLOCK the signals that will be
handled exclusively by signalfd() so that the default POSIX
signal handling mechanism won't intercept the signals first.

The lack of response to ctrl+c is a legitimate bug that is
now properly fixed; ba046c02c7 fixed that issue, but
regressed the handling of other signals.
2020-10-19 13:03:35 -04:00
Nicholas J. Kain 32bc422d0e Add a heuristic to detect when server ignores dhcp renews.
If we get no response to three renews (unicast), switch to sending
rebinds (broadcast).  Servers are supposed to always reply with
a DHCPACK or DHCPNAK even if the server doesn't update its internal
lease duration database, so this behavior should be RFC compliant.
2020-10-19 07:03:03 -04:00
Nicholas J. Kain f4365897bc Make renew and rebinding directly track whether DHCPREQUEST was sent.
Before it was inferred by examining timeouts.  Also, simplify
the associated timeout code so that there are no longer effectively
two redundant paths.
2020-10-19 06:36:26 -04:00
Nicholas J. Kain 4df035ced3 Make sure xids in packets sent conform to RFC2131 pg36 table5. 2020-10-19 05:48:52 -04:00
Nicholas J. Kain 5dc35eca6d Merge send_renew() and send_rebind() into send_renew_or_rebind(). 2020-10-19 05:26:47 -04:00
Nicholas J. Kain 23d23c108a DHCPREQUEST in REBINDING state shouldn't have reqip option.
See RFC2131 pg31 paragraph 6.
2020-10-19 05:13:47 -04:00
Nicholas J. Kain 9b8c63d998 Give up on fingerprinting router/gateway if it doesn't reply. 2020-10-19 04:28:06 -04:00
Nicholas J. Kain 87ac82fa45 Add back project() for CMake. Corrects regression in c5a1edd5f6. 2020-10-19 04:28:06 -04:00
Nicholas J. Kain b2af308647 Trivial refactoring. 2020-10-19 04:28:06 -04:00
Nicholas J. Kain 7bd551d564 Give up on fingerprinting relay agent/server if it doesn't reply.
Try to send/wait three times; then if there's no response, then
assume that the relay agent is ignoring or firewalled from
receiving ARP requests.
2020-10-19 04:28:06 -04:00
Nicholas J. Kain ba046c02c7 Make custom SIGUSR signals work again.
These were broken long ago when converting from signal()
to sigprocmask().  This change also makes ctrl+c work again.
2020-09-02 21:04:59 -04:00
Nicholas J. Kain fb143995d2 Silence unused variable warnings in Ragel-generated code. 2019-01-01 01:10:34 -05:00
Nicholas J. Kain 253a97662d sockd: Preserve a const qualifier. 2018-10-26 13:07:37 -04:00
Nicholas J. Kain 3f5285b7ce options.c: Remove an unnecessary cast. 2018-10-26 13:07:19 -04:00
Nicholas J. Kain c5a1edd5f6 Use more modern CMake syntax. 2018-10-26 13:07:05 -04:00
Nicholas J. Kain 56b6ae2cd3 Quit using NULL macro. 2018-10-26 07:17:39 -04:00
Nicholas J. Kain 05a075aeb2 Replace '(c)' with 'Copyright'.
'(c)' may not be a valid substitute for 'Copyright' in some legal
domains/interpretations.  So be safe, since I obviously am asserting
copyright on my legal work.
2018-10-26 07:11:16 -04:00
Nicholas J. Kain 8983df3c86 Update copyright dates. 2018-02-18 08:25:10 -05:00
Nicholas J. Kain a66f007931 Trivial documentation updates. 2018-02-18 08:25:10 -05:00
Nicholas J. Kain e08d3b15b5 Remove seccomp support.
It breaks with the existing whitelists on the latest glibc and is
just too much maintenance burden.  It also causes the most questions
for new users.

Something like openbsd's pledge() would be fine, but I have no
intention of maintaining such a thing.

Most of the value-gain would come from disallowing high-risk
syscalls like ptrace() and the perf syscalls, anyway.

ndhc already uses extensive defense-in-depth and wasn't using
seccomp on non-(x86|x86-64) platforms, so it's not a huge loss.
2018-02-09 03:33:04 -05:00
Nicholas J. Kain e8d97205e9 Compile cleanly with -Wsign-conversion.
I didn't notice anything that worried me.
2018-02-09 03:16:59 -05:00
Nicholas J. Kain c8dd123a5d README.md: Trivial fix to download links. 2017-10-04 05:33:36 -04:00
Nicholas J. Kain 3e4812eb35 README.md: Cosmetic improvements. 2017-09-23 15:17:59 -04:00
Nicholas J. Kain 8bb00c9c36 Convert the README to Markdown README.md. 2017-09-23 12:18:28 -04:00
Nicholas J. Kain b6dda8f4f8 Update README. Mention the ncmlib requirement and make it more succinct. 2017-08-24 14:06:56 -04:00
Nicholas J. Kain 759b6bd831 Update to the new ncmlib random API. 2017-08-24 02:36:31 -04:00