Provide a gmake Makefile for distro builds and packagers.
Define _GNU_SOURCE in the CFLAGS. Update the README. Remove the duplicate Gentoo init script ndhc.sh that is in the root. Remove DESIGN -- it's outdated.
This commit is contained in:
parent
efe50a30a6
commit
2aff36a274
@ -2,8 +2,8 @@ project (ndhcp)
|
||||
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s -std=gnu99 -pedantic -Wall -lcap -DHAVE_CLEARENV -DLINUX")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -s -std=gnu99 -pedantic -Wall -lcap -DHAVE_CLEARENV -DLINUX")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s -std=gnu99 -pedantic -Wall -lcap -D_GNU_SOURCE -DHAVE_CLEARENV -DLINUX")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -s -std=gnu99 -pedantic -Wall -lcap -D_GNU_SOURCE -DHAVE_CLEARENV -DLINUX")
|
||||
|
||||
include_directories("${PROJECT_SOURCE_DIR}/ncmlib")
|
||||
add_subdirectory(ncmlib)
|
||||
|
70
DESIGN
70
DESIGN
@ -1,70 +0,0 @@
|
||||
Goals:
|
||||
|
||||
1. Security
|
||||
|
||||
a. Divide into seperate processes that each have the minimal
|
||||
system access necessary to complete their task.
|
||||
|
||||
b. Use a well defined IPC mechanism to facilitate cooperation
|
||||
between processes. In this case, UNIX domain sockets are
|
||||
used, since they allow for UNIX DAC (on Linux, at least).
|
||||
|
||||
c. Write each program to be secure; don't rely on the
|
||||
privilege seperations for security.
|
||||
|
||||
d. Simple error handling is favored rather than complex error
|
||||
handling that may possibly be caused to "recover" in an
|
||||
exploitable way.
|
||||
|
||||
e. Don't make stupid assumptions. Implement only the minimal
|
||||
functionality necessary to perform a task. Expect brain
|
||||
damaged or malicious inputs.
|
||||
|
||||
f. Run inside a chroot, with minimal privileges via
|
||||
capabilities or MAC.
|
||||
|
||||
2. Reliability
|
||||
|
||||
a. Don't try to handle severe errors.
|
||||
|
||||
b. Log errors if program state is still sane.
|
||||
|
||||
c. Recover from predictable problems if necessary. Make sure
|
||||
that recovery behavior is well understood and defined.
|
||||
|
||||
d. Complicated or unsafe recoveries should not be performed;
|
||||
instead the program should promptly exit. Dead programs
|
||||
don't cause exploits.
|
||||
|
||||
3. Portability
|
||||
|
||||
a. Portability is good, but portability may not be as wide as
|
||||
a less secure program. Capabilities or MAC are not well
|
||||
standardized, but remain necessary features.
|
||||
|
||||
4. Miscellaneous
|
||||
|
||||
a. Speed: If we aren't required to sacrifice anything more
|
||||
important, it's always good to be fast.
|
||||
|
||||
a. Size: If we aren't required to sacrifice anything more
|
||||
important, it's always good to be frugal.
|
||||
|
||||
Layout:
|
||||
|
||||
ndhc daemon (root -> chroot -> drop all !(CAP_NET_BROADCAST|CAP_NET_RAW)
|
||||
-> nopriv)
|
||||
|
||||
* handles dhcp protocol issues, netlink hw link notifications, and ARP checks
|
||||
* keeps track of leases
|
||||
* talks to ifchd to perform tasks that require
|
||||
higher privileges than CAP_NET_BROADCAST or CAP_NET_RAW
|
||||
|
||||
ifchd daemon (root -> openfd -> chroot -> drop all !CAP_NET_ADMIN -> nopriv)
|
||||
|
||||
* listens for interface change requests via UNIX domain socket
|
||||
* restricts valid IP ranges that will be accepted
|
||||
* performs interface changes
|
||||
* keeps rw fds for system files (such as /etc/resolv.conf) that must
|
||||
be modified outside the chroot
|
||||
|
42
Makefile
Normal file
42
Makefile
Normal file
@ -0,0 +1,42 @@
|
||||
# This is a pretty basic makefile. I generally use CMake, so this is mostly
|
||||
# for distros that want to avoid build dependencies. Produced exes will be
|
||||
# at './build/ndhc' and './build/ifchd'.
|
||||
|
||||
NCM_SRCS = $(sort $(wildcard ncmlib/*.c))
|
||||
IFCHD_SRCS = $(sort $(wildcard ifchd/*.c))
|
||||
NDHC_SRCS = $(sort $(wildcard ndhc/*.c))
|
||||
NCM_OBJS = $(NCM_SRCS:.c=.o)
|
||||
IFCHD_OBJS = $(IFCHD_SRCS:.c=.o)
|
||||
NDHC_OBJS = $(NDHC_SRCS:.c=.o)
|
||||
NCM_INC = -I./ncmlib
|
||||
BUILD_DIR = build
|
||||
OBJ_DIR = objs
|
||||
|
||||
CC = gcc
|
||||
AR = ar
|
||||
RANLIB = ranlib
|
||||
CFLAGS = -O2 -s -std=gnu99 -pedantic -Wall -D_GNU_SOURCE -DHAVE_CLEARENV -DLINUX
|
||||
|
||||
all: makedir ncmlib.a ifchd ndhc
|
||||
|
||||
clean:
|
||||
rm -Rf $(OBJ_DIR) $(BUILD_DIR)
|
||||
|
||||
makedir:
|
||||
mkdir -p $(OBJ_DIR)/ndhc $(OBJ_DIR)/ifchd $(OBJ_DIR)/ncmlib $(BUILD_DIR)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(NCM_INC) -c -o $(OBJ_DIR)/$@ $<
|
||||
|
||||
ncmlib.a: $(NCM_OBJS)
|
||||
$(AR) rc $(BUILD_DIR)/$@ $(subst ncmlib/,$(OBJ_DIR)/ncmlib/,$(NCM_OBJS))
|
||||
$(RANLIB) $(BUILD_DIR)/$@
|
||||
|
||||
ifchd: $(IFCHD_OBJS)
|
||||
$(CC) $(CFLAGS) $(NCM_INC) -o $(BUILD_DIR)/$@ $(subst ifchd/,$(OBJ_DIR)/ifchd/,$(IFCHD_OBJS)) $(BUILD_DIR)/ncmlib.a -lcap
|
||||
|
||||
ndhc: $(NDHC_OBJS)
|
||||
$(CC) $(CFLAGS) $(NCM_INC) -o $(BUILD_DIR)/$@ $(subst ndhc/,$(OBJ_DIR)/ndhc/,$(NDHC_OBJS)) $(BUILD_DIR)/ncmlib.a -lcap
|
||||
|
||||
.PHONY: all clean
|
||||
|
140
README
140
README
@ -1,4 +1,4 @@
|
||||
ifchd, copyright (c) 2004-2011 Nicholas Kain. Licensed under GNU GPL.
|
||||
ndhc + ifchd, copyright (c) 2004-2011 Nicholas Kain. Licensed under GNU GPL2.
|
||||
|
||||
Requirements:
|
||||
|
||||
@ -47,12 +47,19 @@ taken to prevent unintentional ARP flooding under any circumstance.
|
||||
|
||||
ndhc also monitors hardware link status via netlink events and reacts
|
||||
appropriately when interface carrier status changes or an interface is
|
||||
explicitly deconfigured.
|
||||
explicitly deconfigured. This functionality can be useful on wired networks
|
||||
when transient carrier downtimes occur (or cables are changed), but it is
|
||||
particularly useful on wireless networks.
|
||||
|
||||
USAGE
|
||||
-----
|
||||
|
||||
1) Compile and install ifchd and ndhc.
|
||||
a) gmake
|
||||
b) Install the build/ifchd and build/ndhc executables in a normal place. I
|
||||
would suggest /usr/sbin or /usr/local/sbin.
|
||||
|
||||
1alt) Compile and install ifchd and ndhc.
|
||||
a) Create a build directory:
|
||||
mkdir build && cd build
|
||||
b) Create the makefiles:
|
||||
@ -129,8 +136,7 @@ esac
|
||||
directions, the script will of course require modifications.
|
||||
|
||||
4o) If you encounter problems, I suggest running both ifchd and ndhc in the
|
||||
foreground, and perhaps compiling ndhc with extra debugging output
|
||||
(uncomment DEBUG=1 in the Makefile).
|
||||
foreground and examining the printed output.
|
||||
|
||||
|
||||
BEHAVIOR NOTES
|
||||
@ -144,31 +150,38 @@ ifchd can be set such that it only allows clients to configure particular
|
||||
network interfaces. The --interface (-i) argument does the trick, and may
|
||||
be used multiple times to allow multiple interfaces.
|
||||
|
||||
GRSECURITY NOTES
|
||||
----------------
|
||||
|
||||
Make sure that CONFIG_GRKERNSEC_CHROOT_CAPS is disabled. Otherwise, ifchd will
|
||||
lose its capabilities (in particular, the ability to reconfigure interfaces)
|
||||
when it chroots.
|
||||
|
||||
|
||||
PORTING NOTES
|
||||
-------------
|
||||
|
||||
There are seven major functions that ifchd depends upon that are not generally
|
||||
portable. First, it uses the SO_PEERCRED flag of getsockopt() to discriminate
|
||||
authorized connections by uid, gid, and pid. Similar functionality exists in
|
||||
at least the BSDs; however, it has a different API. Second, ifchd takes
|
||||
advantage of Linux capabilities so that it does not need full root privileges.
|
||||
Capabilities were a proposed POSIX feature that was not made part of the
|
||||
official standard, so any implemention that may exist will be system-dependent.
|
||||
Third and fourth, ifchd configures network interfaces and routes. Interface
|
||||
and route configuration is entirely non-portable, usually requiring calls to
|
||||
the catch-all ioctl(), and will almost certainly require platform-dependent
|
||||
code. Fifth and sixth, both ifchd and ndhc use epoll() and signalfd(), which
|
||||
are Linux-specific. Seventh, ndhc uses netlink sockets extensively for
|
||||
both fetching data and hardware link state change notification events.
|
||||
ndhc is rather platform-dependent, and it extensively uses Linux-specific
|
||||
features. Some of these features are also available on the BSDs.
|
||||
|
||||
1) Both ndhc and ifchd use the SO_PEERCRED flag of getsockopt() to discriminate
|
||||
authorized connections by uid, gid, and pid. Similar functionality exists in
|
||||
at least the BSDs; however, it has a different API.
|
||||
|
||||
2) ifchd takes advantage of Linux capabilities so that it does not need full
|
||||
root privileges. Capabilities were a proposed POSIX feature that was not made
|
||||
part of the official standard, so any implemention that may exist will be
|
||||
system-dependent.
|
||||
|
||||
3) ifchd configures network interfaces and routes. Interface and route
|
||||
configuration is entirely non-portable, usually requiring calls to the
|
||||
catch-all ioctl(), or even more unusual mechanisms like netlink sockets.
|
||||
|
||||
4) ndhc uses netlink sockets extensively for both fetching data and hardware
|
||||
link state change notification events.
|
||||
|
||||
5) ndhc uses the Berkeley Packet Filter / Linux Packet Filter interfaces to
|
||||
drop unwanted packets in kernelspace. This functionality is available on
|
||||
most modern unix systems, but it is not standard.
|
||||
|
||||
6) ndhc uses epoll() and signalfd(). These are Linux-specific.
|
||||
|
||||
7) Numerous socket options are used, and the AF_PACKET socket family is used
|
||||
for raw sockets and ARP. These are largely Linux-specific, too.
|
||||
|
||||
8) ndhc uses strlcpy() and strlcat(). Native versions are provided.
|
||||
Some standard C libraries include a native implementation of strlcpy() and
|
||||
strlcat(). Such defines may conflict with my implementations in strl.c/strl.h.
|
||||
It is up to the user whether the standard C library implementations should be
|
||||
@ -177,3 +190,80 @@ nonstandard semantics (notably Solaris). On these systems, using the
|
||||
system-provided implementations may lead to security problems. Such problems
|
||||
are the fault of the vendor. If you are unsure whether your system is correct
|
||||
or not, I suggest using the implementation that I provide.
|
||||
|
||||
HISTORY
|
||||
-------
|
||||
|
||||
I started writing ndhc back in 2004. My ISP at the time required a dhcp
|
||||
client for connection authentication, and I was not comfortable with any
|
||||
of the existing clients, which all ran as root and had colorful security
|
||||
histories. DHCP is generally not a routed protocol, and lacks real
|
||||
authentication mechanisms in real world deployments (some largely
|
||||
abandoned RFCs for such behavior do exist), so no program existed to
|
||||
fill the niche of a truly secure DHCP client.
|
||||
|
||||
My router/server at the time ran a custom Linux distro that was designed
|
||||
for extreme security. A root privileged DHCP client would be nearly the
|
||||
only root-owned process running on the machine, so I was highly motivated
|
||||
to develop an alternative.
|
||||
|
||||
ifchd was first written entirely from scratch. It did not take long to write,
|
||||
since it is by design rather simple, and I was already familiar with
|
||||
the quirks of Linux capabilities. That left me with the choice of adapting
|
||||
an existing DHCP client or writing my own from scratch.
|
||||
|
||||
At the time, I just wanted something that would work, so my choice was to
|
||||
adapt udhcpc to work with ifchd. udhcpc was chosen since it was intended to
|
||||
be used with resource-constrained or embedded systems, and was thus very
|
||||
small. ISC dhclient was another alternative, but it is an extremely large
|
||||
program, and it would have been very hard to audit it for correctness.
|
||||
|
||||
udhcpc was not all that great of a choice, since it was designed to be small at
|
||||
all costs, sacrificing correctness when necessary. The code was hard to
|
||||
follow, and had many quirks. Bounds-checking was rare, type aliasing common,
|
||||
and state transitions were convoluted. Not all of the client was asynchronous,
|
||||
and no precautions were taken against conflicting peers. ARP was not used at
|
||||
all.
|
||||
|
||||
However, it was small. With a lot of work, I ripped out the script-calling
|
||||
mechanisms and replaced them with ifchd requests. Bounds-checking was
|
||||
aggressively (and somewhat hamfistedly) retrofitted into the code. It was
|
||||
cleaned to a degree, and importantly it worked for connecting to my ISP.
|
||||
|
||||
Then I changed ISPs. My new ISP used PPPoE, not dhcp. Around the same time, I
|
||||
also switched to using Gentoo rather than a hand-built distribution. I didn't
|
||||
have time to maintain the old custom setup, and it was very hard keeping up
|
||||
with library vulnerabilties in eg, zlib or openssl, and ensuring that all
|
||||
installed binaries, dynamic and static, were updated. ndhc was abandoned for
|
||||
many years. It wasn't needed on my server, and it was "too much effort" to
|
||||
deviate from the stock distro dhcp clients on other machines.
|
||||
|
||||
Then, around 2008, I changed ISPs again. This time my new ISP used dhcp and
|
||||
not PPPoE. So, after a few months, I decided to dust off the old ndhc/ifchd
|
||||
project and adapt it to my modern standards and machines.
|
||||
|
||||
ifchd was in good shape and required little work. I ended up rewriting
|
||||
ndhc. The only parts that remained from the original were the parts that
|
||||
I had already rewritten before, and some of those were rewritten, too.
|
||||
|
||||
The end result is a modern DHCP client is largely RFC-compliant, except where
|
||||
the RFCs dictate behavior that would be problematic, overly complex, useless,
|
||||
or exploitable. DHCP is poorly specified, and real-world servers and clients
|
||||
vary a lot from the RFCs, so these conditions are necessary for a useful
|
||||
program.
|
||||
|
||||
Although ndhc's implementation and behavior are different, I have to credit
|
||||
the idea of using netlink events to discover hardware link status transitions
|
||||
to Stefan Rompf and his 'dhcpclient' program. The Linux netlink events that
|
||||
are used are otherwise rather obscure and poorly documented, and I wouldn't
|
||||
have known about them otherwise.
|
||||
|
||||
GRSECURITY NOTES
|
||||
----------------
|
||||
|
||||
Make sure that CONFIG_GRKERNSEC_CHROOT_CAPS is disabled. Otherwise, ifchd will
|
||||
lose its capabilities (in particular, the ability to reconfigure interfaces)
|
||||
when it chroots.
|
||||
|
||||
|
||||
|
||||
|
@ -38,7 +38,6 @@
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <getopt.h>
|
||||
|
||||
#include "ifchd-defines.h"
|
||||
|
93
ndhc.sh
93
ndhc.sh
@ -1,93 +0,0 @@
|
||||
# Copyright (c) 2007-2008 Roy Marples <roy@marples.name>
|
||||
# All rights reserved. Released under the 2-clause BSD license.
|
||||
|
||||
ndhc_depend()
|
||||
{
|
||||
program start /sbin/ndhc
|
||||
after interface
|
||||
provide dhcp
|
||||
}
|
||||
|
||||
_config_vars="$_config_vars dhcp ndhc"
|
||||
|
||||
ndhc_start()
|
||||
{
|
||||
local args= opt= opts= pidfile="/var/run/ndhc-${IFACE}.pid"
|
||||
local sendhost=true
|
||||
local leasefile="/var/state/${IFACE}.lease"
|
||||
|
||||
eval args=\$ndhc_${IFVAR}
|
||||
|
||||
# Get our options
|
||||
eval opts=\$dhcp_${IFVAR}
|
||||
[ -z "${opts}" ] && opts=${dhcp}
|
||||
|
||||
# # Map some generic options to ndhc
|
||||
# for opt in ${opts}; do
|
||||
# case "${opt}" in
|
||||
# nodns) args="${args} --env PEER_DNS=no";;
|
||||
# nontp) args="${args} --env PEER_NTP=no";;
|
||||
# nogateway) args="${args} --env PEER_ROUTERS=no";;
|
||||
# nosendhost) sendhost=false;
|
||||
# esac
|
||||
# done
|
||||
|
||||
# [ "${metric:-0}" != "0" ] && args="${args} --env IF_METRIC=${metric}"
|
||||
|
||||
ebegin "Running ndhc"
|
||||
|
||||
case " ${args} " in
|
||||
*" --quit "*|*" -q "*) x="/sbin/ndhc";;
|
||||
*) x="start-stop-daemon --start --exec /sbin/ndhc \
|
||||
--pidfile ${pidfile} --";;
|
||||
esac
|
||||
|
||||
case " ${args} " in
|
||||
*" --hostname="*|*" -h "*|*" -H "*);;
|
||||
*)
|
||||
if ${sendhost}; then
|
||||
local hname="$(hostname)"
|
||||
if [ "${hname}" != "(none)" ] && [ "${hname}" != "localhost" ]; then
|
||||
args="${args} --hostname='${hname}'"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# delay until carrier is up
|
||||
ip link set "${IFACE}" up
|
||||
ip link show "${IFACE}" | grep NO-CARRIER >/dev/null 2>&1
|
||||
while [ "$?" != "1" ]; do
|
||||
sleep 1
|
||||
ip link show "${IFACE}" | grep NO-CARRIER >/dev/null 2>&1
|
||||
done
|
||||
|
||||
eval "${x}" "${args}" -r `cat /etc/firewall/tmp/OLDEXTIP` \
|
||||
-n -i "${IFACE}" -u "ndhc" -C "/var/lib/ndhc" \
|
||||
-p "${pidfile}" -l "${leasefile}" >/dev/null
|
||||
eend $? || return 1
|
||||
|
||||
_show_address
|
||||
return 0
|
||||
}
|
||||
|
||||
ndhc_stop()
|
||||
{
|
||||
local pidfile="/var/lib/ndhc/var/run/ndhc-${IFACE}.pid" opts=
|
||||
[ ! -f "${pidfile}" ] && return 0
|
||||
|
||||
# Get our options
|
||||
eval opts=\$dhcp_${IFVAR}
|
||||
[ -z "${opts}" ] && opts=${dhcp}
|
||||
|
||||
ebegin "Stopping ndhc on ${IFACE}"
|
||||
case " ${opts} " in
|
||||
*" release "*)
|
||||
start-stop-daemon --stop --quiet --oknodo --signal USR2 \
|
||||
--exec /sbin/ndhc --pidfile "${pidfile}"
|
||||
;;
|
||||
esac
|
||||
|
||||
start-stop-daemon --stop --exec /sbin/ndhc --pidfile "${pidfile}"
|
||||
eend $?
|
||||
}
|
Loading…
Reference in New Issue
Block a user