Commit Graph
100 Commits
Author SHA1 Message Date
Nicholas J. Kain 04ec7c8f4b Update to latest write_pid semantics and don't write pidfile by default.
There was no way to disable writing pidfiles before.

pidfiles are an unreliable method of tracking processes, anyway; process
supervisors are strongly recommended.  If a pidfile is really needed, it
can be explicitly specified.
2016-05-06 15:00:31 -04:00
Nicholas J. Kain a47a2feea1 Support resolv_conf.head and resolv_conf.tail.
These will be used if they exist at initialization.
Operations are all done by acting on pre-opened fds.
2016-05-06 06:45:16 -04:00
Nicholas J. Kain 313da14518 Update nl.[ch] to latest. No functional change for ndhc. 2016-05-06 06:36:01 -04:00
Nicholas J. Kain a4ea869a54 README: Trivial style edits. 2015-12-27 01:00:18 -05:00
Nicholas J. Kain 5ab36719f1 If a fd closes unexpectedly in epoll, print error and exit with failure.
Before the exit code would be success and no error message would print,
and it required a bit of control flow tracing to determine what would
actually happen.

No direct functional change (unless the supervising process cares about
the return code of ndhc on exit).
2015-12-25 02:44:54 -05:00
Nicholas J. Kain ae16e26d00 arp: Fix case where changing interface properties consistently fails.
If changing interface properties fails after getting a lease, it is
possible under some strange conditions for the failure to be
persistent.  This seems to happen if the carrier cycles off and on
several times during ndhc initialization.

Since this issue is very hard to replicate, the most conservative
thing to do here is to simply have ndhc suicide itself so it can
be respawned by a process supervisor.

Logs of the issue in practice:

(carrier is down while the daemon is started here, it seems)

16:57:09.638979845 ndhc-ifch seccomp filter installed.  Please disable seccomp if you
16:57:09.638989136 Discovering DHCP servers...
16:57:09.638991371 (send_dhcp_raw) carrier down; sendto would fail
16:57:09.638993318 Failed to send a discover request packet.
 ...
16:57:13.636519925 Discovering DHCP servers...
16:57:13.651462476 Received IP offer: X from server Y via Z
 ...
16:57:13.912592571  wan0: Gateway router set to: A
16:57:13.912607463  wan0: arp: Searching for dhcp server and gw addresses...
16:57:14.635532676  wan0: Carrier down.
17:04:32.983897760  wan0: arp: Still looking for gateway hardware address...
17:04:32.984158226  wan0: arp: Still looking for DHCP agent hardware address...
17:04:32.984781255  wan0: Interface is back.  Revalidating lease...
17:04:32.985585501  wan0: arp: Gateway hardware address B
17:04:32.985590436  wan0: arp: DHCP agent hardware address C
17:04:38.234857403  wan0: arp: Still waiting for gateway to reply to arp ping...
17:04:38.235109016  wan0: arp: Still waiting for DHCP agent to reply to arp ping...
16:57:24.165620224  wan0: arp: Still waiting for gateway to reply to arp ping...
16:57:29.169621070  wan0: arp: DHCP agent and gateway didn't reply.  Getting new lease.
16:57:29.217710616  wan0: Discovering DHCP servers...
16:57:29.249645130  wan0: Received IP offer: X from server Y via Z
16:57:29.249657203  wan0: Sending a selection request for X...
16:57:29.285632973  wan0: Received ACK: X from server Y via Z
16:57:29.297717159  wan0: arp: Probing for hosts that may conflict with our lease...
16:57:29.360249458  wan0: arp: Probing for hosts that may conflict with our lease...
16:57:29.435114526  wan0: arp: Probing for hosts that may conflict with our lease...
16:57:29.500473345  wan0: Lease of X obtained.  Lease time is D seconds.
16:57:29.500485894  wan0: Failed to set the interface IP address and properties!
 ...
And the final two errors repeat.  Restarting ndhc by hand instantly
fixes the issue.

So there's a lot going on -- bizzare clock skew, and carrier flickering
on and off.
2015-10-28 20:20:21 -04:00
Nicholas J. Kain e0b5ff8eaf perform_carrier() should not cause ifchd to terminate on failure.
This requires execute_buffer() and its callers to distinguish between
fatal and non-fatal errors.  The -99 return value was already used for
non-recoverable errors that should force the daemon to restart, but the
execute_buffer() callers treated any non-success return as a fatal
error.

There a judgement call here on how to handle various error types.  I
choose to assume that failures to set the IP address, netmask, broadcast
address, or default router are fatal errors.  ndhc should be run from
process supervision, and this will trigger a daemon restart, which will
allow the machine to recover as soon as the problem (probably on the
dhcp server or local kernel state outside of ndhc's control) is
corrected.

This change corrects errors such as:

Discovering DHCP servers...
(process_client_socket) received invalid commands: 'carrier:;'
(send_dhcp_raw) carrier down; sendto would fail
Failed to send a discover request packet.

which happened if ndhc is started on a machine where the network
interface is down.  After this change, ndhc should function as intended
by going to sleep until the carrier returns rather than terminating
itself to be restarted by the process supervisor until carrier returns.
2015-07-03 00:49:13 -04:00
Nicholas J. Kain 12d8af4c67 Convert remaining ull time-types to ll.
Thus signed/unsigned conversion issues can't be a problem.

The extra range provided by ull isn't useful, either, since
we're dealing with uint32_t time_t seconds converted to ns,
which doesn't come close to exhausting the amount of post-epoch
ns that will be consumed until after 2100AD.
2015-05-27 23:40:28 -04:00
Nicholas J. Kain 277f0f67c5 When converting timeout from ll to int, also guard against underflow. 2015-05-27 15:00:02 -04:00
Nicholas J. Kain e02d30dcc5 renewTime, rebindTime should be unsigned long long.
While we're at it, rearrange the client state struct to
save some space lost to padding.
2015-05-27 13:11:23 -04:00
Nicholas J. Kain abb1b54bfe Fix an overflow that can cause spuriously short epoll timeouts.
Lease times and arp timeouts are all calculated using long long,
but epoll takes its timeout argument as an int.  Guard against
timeouts > INT_MAX but < UINT_MAX wrapping and causing spuriously
short timeouts when converted to a signed int.

This problem has been observed in the wild.  Thanks to thypon
for a detailed strace that pointed me towards this issue.
2015-05-27 12:58:42 -04:00
Nicholas J. Kain ba875d4b2e Failsafe should only trigger is the new timeout is also zero.
This is what I get for rushing!
2015-05-27 12:35:16 -04:00
Nicholas J. Kain f061a78a18 Fix dumb mistake in patch before last; epoll timeout is in ms, not s. 2015-05-27 12:29:46 -04:00
Nicholas J. Kain 2057d7cd18 Improve compatibility with clang. 2015-05-27 12:23:50 -04:00
Nicholas J. Kain 8273b383ab Add a failsafe to prevent epoll busy-spin. 2015-05-27 12:23:16 -04:00
Nicholas J. Kain 6c136c3f85 Make add_option_(vendor|hostname)() not use ndhc internals.
This change makes it easier to fuzz test, but should have no
functional effect on ndhc's behavior.
2015-02-20 03:58:25 -05:00
Nicholas J. Kain 646931a2bf xid should be regenerated whenever we start a new discover cycle.
Somewhere along the line it quit being set at the start of discovery
and was always 0.  This is clearly not desired behavior.

Found by manual examination of packets while fuzzing the options
parser.
2015-02-20 03:48:13 -05:00
Nicholas J. Kain b8df1b33f5 Fix the timeouts for rebinding and renewing.
Now renew/rebind requests will be sent every 60+/-10s.
2015-02-18 11:03:58 -05:00
Nicholas J. Kain b3bd13d45f Fix the return values of dhcp_packet_get and arp_packet_get.
This corrects a bug where stale dhcp packets would get reprocessed,
causing very bad behavior; an issue that was introduced in the
coroutine conversion.
2015-02-18 11:02:13 -05:00
Nicholas J. Kain a627e9dc9c Minor changes to log messages and comments. 2015-02-18 09:56:38 -05:00
Nicholas J. Kain 3ede5fbe33 Handle the release and renew signals again. 2015-02-18 07:31:19 -05:00
Nicholas J. Kain 731bd14f0a reinit_selecting() can't fail; convert it to void return. 2015-02-18 07:12:35 -05:00
Nicholas J. Kain 89d77313c6 Deconfigure the interface if we've failed a fingerprint check.
We've moved to a new network, so keeping the old information
is counterproductive.
2015-02-18 07:12:22 -05:00
Nicholas J. Kain 29da5d21a4 Tolerate DHCP ACKs in REQUESTING state that don't match the serverid.
Some networks have multiple DHCP servers that don't respect the
serverid that is specified in DHCPREQUESTs.

Instead we simply check to see that the yiaddr matches.

While we're at it, ignore DHCP NAK during REQUESTING state.  It
doesn't really make sense.  Instead we should just wait for
timeout.
2015-02-18 06:52:59 -05:00
Nicholas J. Kain f28495a58b selecting_packet() shouldn't take the xid from the packet.
This change actually has no effect because incoming dhcp packets
that differ from our xid are dropped, so the xid is always changed
to the same value that it already has.
2015-02-18 06:01:43 -05:00
Nicholas J. Kain da7d34a300 Bump version to 2.0.
When the coroutine restructuring is fully tested and debugged, it
will definitely be a significant enough change for a full version
bump.
2015-02-18 05:41:31 -05:00
Nicholas J. Kain 69cf41f1b1 Only process one epoll event at a time.
If ndhc were a high-performance program that handled lots of events,
this change would harm performance.  But it is not, and it implicitly
believes that events come in one at a time.  Processing batches
would make it harder to assure correctness while also never allocating
memory at runtime.

The previous structure was fine when everything was handled
immediately by callbacks, but it isn't now.
2015-02-18 05:36:13 -05:00
Nicholas J. Kain 99ce918a31 Use a coroutine instead of several callback state machines.
This change makes it much easier to reason about ndhc's behavior
and properly handle errors.

It is a very large changeset, but there is no way to make this
sort of change incrementally.  Lease acquisition is tested to
work.

It is highly likely that some bugs were both introduced and
squashed here.  Some obvious code cleanups will quickly follow.
2015-02-18 05:31:13 -05:00
Nicholas J. Kain 37aa866ae4 Move action dispatch out of main epoll loop. 2015-02-15 06:48:49 -05:00
Nicholas J. Kain 61387408d0 Separate event state gathering from action dispatch in main epoll loop.
This is the first step towards using coroutines.
2015-02-15 06:38:03 -05:00
Nicholas J. Kain 658d2954b8 Reduce log spam. 2015-02-15 02:58:51 -05:00
Nicholas J. Kain e874373dcd Check link carrier via ifch and netlink instead of ioctl.
Thus, ioctl can once again be removed from the ndhc seccomp whitelist.
2015-02-15 02:50:29 -05:00
Nicholas J. Kain 6c9ca9eecd If ifchd commands fail, propagate the failure back to ndhc. 2015-02-15 02:29:37 -05:00
Nicholas J. Kain 33aa5b13de Recommend using a process supervisor for high reliability in README. 2015-02-14 20:50:46 -05:00
Nicholas J. Kain 5b82be8b00 If ifchd interactions fail, terminate.
Ideally we would pause and resume state, but for now just bail out.
If ndhc is process-supervised, it will recover to the proper state
quickly.
2015-02-14 20:47:14 -05:00
Nicholas J. Kain 170f87c0e7 Propagate returns through ifchange_(deconfig|bind).
While doing so remove unnecessary argument null checks and
make sure not to alter the stored interface state if the
ifch requests failed.
2015-02-14 19:10:23 -05:00
Nicholas J. Kain 44175bd77c Make ifch requests synchronous just like sockd requests.
This change paves the way for allowing ifch to notify the core ndhc
about failures.  It would be far too difficult to reason about the
state machine if the requests to ifch were asynchronous.

Currently ndhc assumes that ifch requests never fail, but this
is not always true because of eg, rfkill.
2015-02-14 16:49:50 -05:00
Nicholas J. Kain 61a48b0fb6 Fix the rfkill waiting. 2015-02-14 15:33:02 -05:00
Nicholas J. Kain 56cc05599a Add error handling for un-notified carrier downs in ifup_action. 2015-02-14 05:39:15 -05:00
Nicholas J. Kain b6b778831c Add error handling for un-notified carrier downs when sending packets.
If a packet send failed because the carrier went down without a
netlink notification, then assume the hardware carrier was lost while
the machine was suspended (eg, ethernet cable pulled during suspend).

Simulate a netlink carrier down event and freeze the dhcp state
machine until a netlink carrier up event is received.

The ARP code is not yet handling this issue everywhere, but the
window of opportunity for it to happen there is much shorter.
2015-02-14 05:20:04 -05:00
Nicholas J. Kain d0d8bcf3ff options.[ch] must still be valid C++11 because it is used in ndhs.
That means the [static 1] arg specifier cannot be used.
2015-02-14 02:14:30 -05:00
Nicholas J. Kain 00c9479c4c Mark more pointer arguments as never being null. 2015-02-14 01:46:02 -05:00
Nicholas J. Kain 0535b36534 dhcp.c: Make init_packet() not return a struct.
Just work via a pointer to not rely on the compiler being intelligent
and inlining.
2015-02-14 01:41:52 -05:00
Nicholas J. Kain 70c750f50c get_raw_packet: The read length check is stricter than necessary.
Allow reads with excess data beyond the packet to succeed if the
packet is still well-formed.
2015-02-14 01:40:06 -05:00
Nicholas J. Kain a7cb063f0c state.c: cosmetic cleanups and a constification 2015-02-14 00:44:21 -05:00
Nicholas J. Kain 04840c261d Fix some c99 struct initializer uninitialized member warnings
that clang detects and GCC misses.
2015-02-13 23:25:42 -05:00
Nicholas J. Kain 702d8b0c5b Mark pointer arguments that cannot ever be null as [static 1].
Also constify some cases, too.
2015-02-13 23:14:08 -05:00
Nicholas J. Kain cc806acc0b Indicate that client_state_t and client_config_t pointer args
cannot ever be null.

Could possibly improve code generation, and makes the intention clear.
2015-02-13 22:29:03 -05:00
Nicholas J. Kain b6554c2931 Quiet the 'UDP length [] does not match header length' message.
It is triggered frequently when discarding invalid packets that were
received on the DHCP port and it seems to have little significance.
2015-02-13 21:56:34 -05:00
Nicholas J. Kain b4b6ed8fd5 Check for carrier before sendto() or write() on interface fd.
Linux will quietly proceed as if the data were sent even if the carrier
is down and nothing actually happened.  There is still a tiny race
condition where the carrier could drop between the check and the actual
write, but we really can't do anything about that and it is a very
small race.
2015-02-13 21:53:15 -05:00
Nicholas J. Kain 911d4cc58e Fix the dhcp state bootstrapping when rfkill is set #3. 2015-02-13 19:08:50 -05:00
Nicholas J. Kain 2e679ed491 Fix the dhcp state bootstrapping when rfkill is set #2. 2015-02-13 18:35:44 -05:00
Nicholas J. Kain a8af406307 Fix the dhcp state bootstrapping when rfkill is set. 2015-02-13 18:07:14 -05:00
Nicholas J. Kain 79a97131bc Handle the case where the rfkill is set when ndhc is initializing. 2015-02-13 17:50:24 -05:00
Nicholas J. Kain 5b050ba498 If the rfkill switch is enabled, do not react to netlink notifications
until the rfkill is disabled.  They will mostly fail outright.
2015-02-13 17:20:36 -05:00
Nicholas J. Kain cf81573082 Fix a dumb typo in the previous commit. 2015-02-13 16:56:56 -05:00
Nicholas J. Kain e3d4d4c1aa rfkill: Add support for reacting to radio kill switch events.
In order for this to work, the correct rfkill index must be specified
with the rfkill-idx option.

It might be possible to auto-detect the corresponding rfkill-idx option,
but I'm not sure if there's a guaranteed mapping between rfkill name and
interface name, as it seems that rfkills should represent phy devices
and not wlan devices.

The rfkill indexes can be found by checking
/sys/class/rfkill/rfkill<IDX>.
2015-02-13 16:25:36 -05:00
Nicholas J. Kain 3421f0c585 CMAKE_CROSSCOMPILE should be CMAKE_CROSSCOMPILING. 2015-02-13 05:12:55 -05:00
Nicholas J. Kain c58a071f52 Update copyright dates. 2015-02-13 01:54:57 -05:00
Nicholas J. Kain 7cb5506487 Spelling correction in README. 2015-02-13 01:48:00 -05:00
Nicholas J. Kain 27c9e2c553 Improve fingerprinting to support DHCP relay agents.
Mostly reverts the previous commit and instead teaches ndhc to properly
handle the case when it is communicating with a DHCP relay agent on
its local segment rather than directly with a DHCP server.
2015-02-12 23:28:54 -05:00
Nicholas J. Kain a395234a67 Support networks with relay agents that have the DHCP server on a
different segment.

The network fingerprinting would never complete if the DHCP server was
on a different segment before this change, since it would be impossible
for the ARP messages sent by ndhc to ever reach the DHCP server
(and vice-versa).

Now just give up trying to find the hardware address after two tries
and assume that the DHCP server cannot be reached by ARP.

An alternative would be to fingerprint the relay agent instead, but
to do so would require a lot more work as the giaddr field is only
meaningful in the client->server message path, not in the
server->client path.  Thus it would require gathering the source IP
for DHCP replies sent by unicast or broadcast and ferrying along
this information to the ARP checking code where it would be used
in place of the DHCP server address.

This is entirely possible to do, but is quite a bit more work.
2015-02-12 20:49:40 -05:00
Nicholas J. Kain 03fc696267 Update the man page and correct some formatting errors. 2015-02-12 19:03:09 -05:00
Nicholas J. Kain 9d8d653877 CMake: Do not try to test for the glibc version when cross-compiling. 2015-02-12 18:46:44 -05:00
Nicholas J. Kain b792162113 Add CROSSCOMPILE_MACHINENAME environment variable for CMake that
will allow the host machine type detection to be skipped and
the target MACHINENAME to be manually defined.
2015-02-12 13:35:50 -05:00
Nicholas J. Kain 8e4ea0be72 CMake: Only add -lrt link dependency if glibc is detected. 2015-02-12 13:05:30 -05:00
Nicholas J. Kain 6f6aad211e Documentation update. 2015-01-10 18:34:51 -05:00
Nicholas J. Kain 9f87bd8b30 udp_checksum(): Clamp the value of the UDP packet header length.
Without this change, it is possible for malicious UDP packets to
make the function read past the end of a buffer.

If this was ever a possibility in ndhc, the previous commit fixed
that issue, but there is no reason for udp_checksum() to have
such a subtle precondition to proper use.  This change also makes
it easier to audit correctness.
2015-01-06 07:07:08 -05:00
Nicholas J. Kain 6548b5ce54 get_raw_packet(): Perform the UDP checksum after the packet length
checks.

This change makes it easier to verify that there can be no reads
beyond a buffer end by udp_checksum().
2015-01-06 04:32:58 -05:00
Nicholas J. Kain c8dcf5a06b Make sure that received DHCP packets have a valid options end marker. 2015-01-06 04:02:52 -05:00
Nicholas J. Kain 94c107d465 Make sure all sockets are set NONBLOCK so that writes do not block. 2014-08-19 11:09:59 -04:00
Nicholas J. Kain 12114c9bae Add more explicit length checks for get_raw_packet. 2014-07-25 20:34:01 -04:00
Nicholas J. Kain 2518e0a2bc Use SO_LOCK_FILTER to ensure that BPF filters cannot be removed once attached.
This facility was added to Linux in early 2013.  If it is not available,
the BPF will still be installed, but redundant checks will be performed
to guard against the BPF possibly being removed by an attacker.
2014-06-13 22:37:37 -04:00
Nicholas J. Kain 56e30a0923 Fix the return value for nlmsg_get_error(). 2014-06-13 22:35:57 -04:00
Nicholas J. Kain ae03b6dd8f Move the ip checksum code out to ncmlib. 2014-06-08 20:34:34 -04:00
Nicholas J. Kain 4a083d3367 get_dhcp_opt() didx argument should be passed as a reference rather
than relying on the caller re-assigning to didx.  The previous
didx += get_dhcp_opt(...) was wrong and should have used =.
2014-05-10 21:38:45 -04:00
Nicholas J. Kain 99e21004ea arp_min_close_fd() will always force the arp fd to be equal to -1, so
there is no need to check force_reopen twice.
2014-05-10 21:13:24 -04:00
Nicholas J. Kain 3721cc926b Documentation updates. 2014-04-24 18:29:52 -04:00
Nicholas J. Kain 6af0d26351 Remove the obsolete init script for Gentoo's network configuration system.
My own machines use a process supervision system, so this script is
unmaintained and doesn't work anymore.
2014-04-24 18:24:00 -04:00
Nicholas J. Kain 2420bed259 Accept no command line arguments without error. 2014-04-21 12:04:13 -04:00
Nicholas J. Kain dbc91b0811 Background option in config files should be a boolval rathe than a value. 2014-04-21 09:02:58 -04:00
Nicholas J. Kain 034e2bb1db When sockd transfers a file descriptor to ndhc, close the fd in sockd.
Since the transfer is conceptually a move, this is the correct thing to
do and prevents sockets from spuriously hanging around forever and
eventually exhausting the per process limit on fds.
2014-04-17 11:04:00 -04:00
Nicholas J. Kain 07cbd88049 Just use raw sockets for listening to DHCP requests. A UDP SO_BROADCAST
socket was previously used only for receiving RENEWING packets, and it
added needless complexity and was somewhat fragile.
2014-04-16 01:00:36 -04:00
Nicholas J. Kain ca85a6ba9f Style cleanups in dhcp.c. 2014-04-16 00:24:40 -04:00
Nicholas J. Kain d8260b4e63 Print an error message when bind() fails when creating a UDP socket in sockd. 2014-04-16 00:24:13 -04:00
Nicholas J. Kain 0884d96d1e PR_SET_PDEATHSIG is not fully reliable, so instead maintain a pair of
AF_UNIX SOCK_STREAM sockets between the master processes and each subprocess,
and poll for the HUP event.

At the same time, be specific about the events that are checked in epoll
when dispatching on an event.
2014-04-15 23:19:24 -04:00
Nicholas J. Kain e526adce19 Make the signal handling code use safe_read() and unify ifchd and sockd
signals code.
2014-04-15 20:55:13 -04:00
Nicholas J. Kain baa394af9a UDP listen sockets should be requested with 'U' instead of 'u'. 2014-04-15 20:54:35 -04:00
Nicholas J. Kain b3578737df Update the Makefile to build cfg.c from cfg.rl. 2014-04-15 20:50:54 -04:00
Nicholas J. Kain b00444ab8b Bound the subprocess lifetime using prctl(PR_SET_PDEATHSIG, ...).
The pipes wouldn't do this job anymore because they were unused and thus
never performed writes that would generate SIGPIPEs, so the pipes are
removed, too.
2014-04-15 18:01:01 -04:00
Nicholas J. Kain b3ce601f20 state.c: Print error messages if we fail to send DHCP packets. 2014-04-15 17:59:15 -04:00
Nicholas J. Kain 18604c5245 get_udp_unicast_socket() needs to have the client address as an argument
when sending the request to sockd.

Also, print error messages if sockd returns an invalid fd (< 0).
2014-04-15 17:55:28 -04:00
Nicholas J. Kain a9055b5ca5 Update more message prints to prefix with the interface name. 2014-04-15 15:24:22 -04:00
Nicholas J. Kain 58b4ba768c If the IP header length does not match the size of the UDP packet received
via the raw socket, print both lengths in the warning message.
2014-04-15 15:23:52 -04:00
Nicholas J. Kain 730e5ef310 setpgid() can return EPERM if we are already a process group leader. 2014-04-15 15:02:20 -04:00
Nicholas J. Kain e5834da6d3 Permit sendmsg in the seccomp syscall whitelist for all daemons. 2014-04-15 14:57:07 -04:00
Nicholas J. Kain b5f0ccd88d In cfg.rl, when performing clear action, don't clear the cs member in ccfg. 2014-04-15 14:56:35 -04:00
Nicholas J. Kain a777766cc6 Fix stupid typo in ndhc.c that would cause the clientid option to
corrupt the start of the hostname option if both were specified.
2014-04-15 14:55:50 -04:00
Nicholas J. Kain 8a9fbb6f09 Documentation updates. 2014-04-14 18:32:08 -04:00
Nicholas J. Kain 74ad01a086 Update the manual page. 2014-04-14 15:52:39 -04:00